Repository: fireice-uk/xmr-stak-amd
Branch: master
Commit: 3358f25d55c5
Files: 91
Total size: 1.1 MB
Directory structure:
gitextract_saqq7bck/
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── amd_gpu/
│ ├── gpu.c
│ └── gpu.h
├── cli-miner.cpp
├── config.txt
├── console.cpp
├── console.h
├── crypto/
│ ├── c_blake256.c
│ ├── c_blake256.h
│ ├── c_groestl.c
│ ├── c_groestl.h
│ ├── c_jh.c
│ ├── c_jh.h
│ ├── c_keccak.c
│ ├── c_keccak.h
│ ├── c_skein.c
│ ├── c_skein.h
│ ├── cryptonight.h
│ ├── cryptonight_aesni.h
│ ├── cryptonight_common.cpp
│ ├── groestl_tables.h
│ ├── hash.h
│ ├── int-util.h
│ ├── skein_port.h
│ └── soft_aes.c
├── donate-level.h
├── executor.cpp
├── executor.h
├── httpd.cpp
├── httpd.h
├── jconf.cpp
├── jconf.h
├── jext.h
├── jpsock.cpp
├── jpsock.h
├── libmicrohttpd/
│ └── microhttpd.h
├── minethd.cpp
├── minethd.h
├── msgstruct.h
├── opencl/
│ ├── blake256.cl
│ ├── cryptonight.cl
│ ├── groestl256.cl
│ ├── jh.cl
│ ├── wolf-aes.cl
│ └── wolf-skein.cl
├── rapidjson/
│ ├── allocators.h
│ ├── document.h
│ ├── encodedstream.h
│ ├── encodings.h
│ ├── error/
│ │ ├── en.h
│ │ └── error.h
│ ├── filereadstream.h
│ ├── filewritestream.h
│ ├── fwd.h
│ ├── internal/
│ │ ├── biginteger.h
│ │ ├── diyfp.h
│ │ ├── dtoa.h
│ │ ├── ieee754.h
│ │ ├── itoa.h
│ │ ├── meta.h
│ │ ├── pow10.h
│ │ ├── regex.h
│ │ ├── stack.h
│ │ ├── strfunc.h
│ │ ├── strtod.h
│ │ └── swap.h
│ ├── istreamwrapper.h
│ ├── memorybuffer.h
│ ├── memorystream.h
│ ├── msinttypes/
│ │ ├── inttypes.h
│ │ └── stdint.h
│ ├── ostreamwrapper.h
│ ├── pointer.h
│ ├── prettywriter.h
│ ├── rapidjson.h
│ ├── reader.h
│ ├── schema.h
│ ├── stream.h
│ ├── stringbuffer.h
│ └── writer.h
├── socket.cpp
├── socket.h
├── socks.h
├── thdq.hpp
├── version.h
├── webdesign.cpp
├── webdesign.h
└── xmr-stak-amd.cbp
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
bin/
obj/
xmr-stak-amd.layout
xmr-stak-amd.depend
config-debug.txt
================================================
FILE: CMakeLists.txt
================================================
project(xmr-stak-amd)
cmake_minimum_required(VERSION 3.1.3)
# enforce C++11
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 11)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE PATH "install prefix" FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
# help to find AMD app SDK on systems with a software module system
list(APPEND CMAKE_PREFIX_PATH "$ENV{AMDAPPSDKROOT}")
# allow user to extent CMAKE_PREFIX_PATH via environment variable
list(APPEND CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}")
################################################################################
# CMake user options
################################################################################
# gcc 5.1 is the first GNU version without CoW strings
# https://github.com/fireice-uk/xmr-stak-nvidia/pull/10#issuecomment-290821792
# If you remove this guard to compile with older gcc versions the miner will produce
# a high rate of wrong shares.
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
message(FATAL_ERROR "GCC version must be at least 5.1!")
endif()
endif()
set(BUILD_TYPE "Release;Debug")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE)
endif()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${BUILD_TYPE}")
# option to add static libgcc and libstdc++
option(CMAKE_LINK_STATIC "link as much as possible libraries static" OFF)
###############################################################################
# Find OpenCL
###############################################################################
find_package(OpenCL REQUIRED)
include_directories(SYSTEM ${OpenCL_INCLUDE_DIRS})
set(LIBS ${LIBS} ${OpenCL_LIBRARY})
link_directories(${OpenCL_LIBRARY})
################################################################################
# Find PThreads
################################################################################
find_package(Threads REQUIRED)
set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
################################################################################
# Find microhttpd
################################################################################
option(MICROHTTPD_ENABLE "Enable or disable the requirement of microhttp (http deamon)" ON)
if(MICROHTTPD_ENABLE)
find_library(MHTD NAMES microhttpd)
if("${MHTD}" STREQUAL "MHTD-NOTFOUND")
message(FATAL_ERROR "microhttpd NOT found: use `-DMICROHTTPD_ENABLE=OFF` to build without http deamon support")
else()
set(LIBS ${LIBS} ${MHTD})
endif()
else()
add_definitions("-DCONF_NO_HTTPD")
endif()
###############################################################################
# Find OpenSSL
###############################################################################
option(OpenSSL_ENABLE "Enable or disable the requirement of OpenSSL" ON)
if(OpenSSL_ENABLE)
find_package(OpenSSL)
if(OPENSSL_FOUND)
include_directories(${OPENSSL_INCLUDE_DIR})
set(LIBS ${LIBS} ${OPENSSL_LIBRARIES})
else()
message(FATAL_ERROR "OpenSSL NOT found: use `-DOpenSSL_ENABLE=OFF` to build without SSL support")
endif()
else()
add_definitions("-DCONF_NO_TLS")
endif()
################################################################################
# Compile & Link
################################################################################
include_directories(.)
# activate sse2 and aes-ni
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2 -maes")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2 -maes")
# activate static libgcc and libstdc++ linking
if(CMAKE_LINK_STATIC)
set(BUILD_SHARED_LIBRARIES OFF)
set(DL_LIB ${CMAKE_DL_LIBS})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(LIBS "-static-libgcc -static-libstdc++ ${LIBS}")
endif()
file(GLOB SRCFILES_CPP "*.cpp" "crypto/*.cpp")
file(GLOB SRCFILES_C "crypto/*.c" "amd_gpu/*.c")
add_library(xmr-stak-amd-c
STATIC
${SRCFILES_C}
)
set_property(TARGET xmr-stak-amd-c PROPERTY C_STANDARD 99)
target_link_libraries(xmr-stak-amd-c PUBLIC ${OpenCL_LIBRARY})
add_executable(xmr-stak-amd
${SRCFILES_CPP}
)
set(EXECUTABLE_OUTPUT_PATH "bin")
target_link_libraries(xmr-stak-amd ${LIBS} xmr-stak-amd-c)
################################################################################
# Install
################################################################################
# do not install the binary if the project and install are equal
if( NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "${PROJECT_BINARY_DIR}" )
install(TARGETS xmr-stak-amd
RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif()
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/opencl"
DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
# avoid overwrite of user defined settings
# install `config.txt`if file not exists in `${CMAKE_INSTALL_PREFIX}/bin`
install(CODE " \
if(NOT EXISTS ${CMAKE_INSTALL_PREFIX}/bin/config.txt)\n \
file(INSTALL ${CMAKE_CURRENT_SOURCE_DIR}/config.txt \
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)\n \
endif()"
)
================================================
FILE: LICENSE
================================================
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.
================================================
FILE: README.md
================================================
# XMR-Stak is now supporting CPU, AMD and NVIDIA GPUs in a unified miner.
Our new repository is https://github.com/fireice-uk/xmr-stak.
Please use our new miner, the old version is retired and unsupported.
================================================
FILE: amd_gpu/gpu.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
* 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
#ifdef _WIN32
#include
const char* sSourcePath = "opencl\\cryptonight.cl";
static inline void port_sleep(size_t sec)
{
Sleep(sec * 1000);
}
#else
#include
const char* sSourcePath = "opencl/cryptonight.cl";
static inline void port_sleep(size_t sec)
{
sleep(sec);
}
#endif // _WIN32
static inline long long unsigned int int_port(size_t i)
{
return i;
}
#include "gpu.h"
const char* err_to_str(cl_int ret)
{
switch(ret)
{
case CL_SUCCESS:
return "CL_SUCCESS";
case CL_DEVICE_NOT_FOUND:
return "CL_DEVICE_NOT_FOUND";
case CL_DEVICE_NOT_AVAILABLE:
return "CL_DEVICE_NOT_AVAILABLE";
case CL_COMPILER_NOT_AVAILABLE:
return "CL_COMPILER_NOT_AVAILABLE";
case CL_MEM_OBJECT_ALLOCATION_FAILURE:
return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
case CL_OUT_OF_RESOURCES:
return "CL_OUT_OF_RESOURCES";
case CL_OUT_OF_HOST_MEMORY:
return "CL_OUT_OF_HOST_MEMORY";
case CL_PROFILING_INFO_NOT_AVAILABLE:
return "CL_PROFILING_INFO_NOT_AVAILABLE";
case CL_MEM_COPY_OVERLAP:
return "CL_MEM_COPY_OVERLAP";
case CL_IMAGE_FORMAT_MISMATCH:
return "CL_IMAGE_FORMAT_MISMATCH";
case CL_IMAGE_FORMAT_NOT_SUPPORTED:
return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
case CL_BUILD_PROGRAM_FAILURE:
return "CL_BUILD_PROGRAM_FAILURE";
case CL_MAP_FAILURE:
return "CL_MAP_FAILURE";
case CL_MISALIGNED_SUB_BUFFER_OFFSET:
return "CL_MISALIGNED_SUB_BUFFER_OFFSET";
case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST";
case CL_COMPILE_PROGRAM_FAILURE:
return "CL_COMPILE_PROGRAM_FAILURE";
case CL_LINKER_NOT_AVAILABLE:
return "CL_LINKER_NOT_AVAILABLE";
case CL_LINK_PROGRAM_FAILURE:
return "CL_LINK_PROGRAM_FAILURE";
case CL_DEVICE_PARTITION_FAILED:
return "CL_DEVICE_PARTITION_FAILED";
case CL_KERNEL_ARG_INFO_NOT_AVAILABLE:
return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE";
case CL_INVALID_VALUE:
return "CL_INVALID_VALUE";
case CL_INVALID_DEVICE_TYPE:
return "CL_INVALID_DEVICE_TYPE";
case CL_INVALID_PLATFORM:
return "CL_INVALID_PLATFORM";
case CL_INVALID_DEVICE:
return "CL_INVALID_DEVICE";
case CL_INVALID_CONTEXT:
return "CL_INVALID_CONTEXT";
case CL_INVALID_QUEUE_PROPERTIES:
return "CL_INVALID_QUEUE_PROPERTIES";
case CL_INVALID_COMMAND_QUEUE:
return "CL_INVALID_COMMAND_QUEUE";
case CL_INVALID_HOST_PTR:
return "CL_INVALID_HOST_PTR";
case CL_INVALID_MEM_OBJECT:
return "CL_INVALID_MEM_OBJECT";
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:
return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
case CL_INVALID_IMAGE_SIZE:
return "CL_INVALID_IMAGE_SIZE";
case CL_INVALID_SAMPLER:
return "CL_INVALID_SAMPLER";
case CL_INVALID_BINARY:
return "CL_INVALID_BINARY";
case CL_INVALID_BUILD_OPTIONS:
return "CL_INVALID_BUILD_OPTIONS";
case CL_INVALID_PROGRAM:
return "CL_INVALID_PROGRAM";
case CL_INVALID_PROGRAM_EXECUTABLE:
return "CL_INVALID_PROGRAM_EXECUTABLE";
case CL_INVALID_KERNEL_NAME:
return "CL_INVALID_KERNEL_NAME";
case CL_INVALID_KERNEL_DEFINITION:
return "CL_INVALID_KERNEL_DEFINITION";
case CL_INVALID_KERNEL:
return "CL_INVALID_KERNEL";
case CL_INVALID_ARG_INDEX:
return "CL_INVALID_ARG_INDEX";
case CL_INVALID_ARG_VALUE:
return "CL_INVALID_ARG_VALUE";
case CL_INVALID_ARG_SIZE:
return "CL_INVALID_ARG_SIZE";
case CL_INVALID_KERNEL_ARGS:
return "CL_INVALID_KERNEL_ARGS";
case CL_INVALID_WORK_DIMENSION:
return "CL_INVALID_WORK_DIMENSION";
case CL_INVALID_WORK_GROUP_SIZE:
return "CL_INVALID_WORK_GROUP_SIZE";
case CL_INVALID_WORK_ITEM_SIZE:
return "CL_INVALID_WORK_ITEM_SIZE";
case CL_INVALID_GLOBAL_OFFSET:
return "CL_INVALID_GLOBAL_OFFSET";
case CL_INVALID_EVENT_WAIT_LIST:
return "CL_INVALID_EVENT_WAIT_LIST";
case CL_INVALID_EVENT:
return "CL_INVALID_EVENT";
case CL_INVALID_OPERATION:
return "CL_INVALID_OPERATION";
case CL_INVALID_GL_OBJECT:
return "CL_INVALID_GL_OBJECT";
case CL_INVALID_BUFFER_SIZE:
return "CL_INVALID_BUFFER_SIZE";
case CL_INVALID_MIP_LEVEL:
return "CL_INVALID_MIP_LEVEL";
case CL_INVALID_GLOBAL_WORK_SIZE:
return "CL_INVALID_GLOBAL_WORK_SIZE";
case CL_INVALID_PROPERTY:
return "CL_INVALID_PROPERTY";
case CL_INVALID_IMAGE_DESCRIPTOR:
return "CL_INVALID_IMAGE_DESCRIPTOR";
case CL_INVALID_COMPILER_OPTIONS:
return "CL_INVALID_COMPILER_OPTIONS";
case CL_INVALID_LINKER_OPTIONS:
return "CL_INVALID_LINKER_OPTIONS";
case CL_INVALID_DEVICE_PARTITION_COUNT:
return "CL_INVALID_DEVICE_PARTITION_COUNT";
#ifdef CL_VERSION_2_0
case CL_INVALID_PIPE_SIZE:
return "CL_INVALID_PIPE_SIZE";
case CL_INVALID_DEVICE_QUEUE:
return "CL_INVALID_DEVICE_QUEUE";
#endif
default:
return "UNKNOWN_ERROR";
}
}
void printer_print_msg(const char* fmt, ...);
void printer_print_str(const char* str);
char* LoadTextFile(const char* filename)
{
size_t flen;
char* out;
FILE* kernel = fopen(filename, "rb");
if(kernel == NULL)
return NULL;
fseek(kernel, 0, SEEK_END);
flen = ftell(kernel);
fseek(kernel, 0, SEEK_SET);
out = (char*)malloc(flen+1);
size_t r = fread(out, flen, 1, kernel);
fclose(kernel);
if(r != 1)
{
free(out);
return NULL;
}
out[flen] = '\0';
return out;
}
size_t InitOpenCLGpu(cl_context opencl_ctx, GpuContext* ctx, char* source_code)
{
size_t MaximumWorkSize;
cl_int ret;
if((ret = clGetDeviceInfo(ctx->DeviceID, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), &MaximumWorkSize, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when querying a device's max worksize using clGetDeviceInfo.", err_to_str(ret));
return ERR_OCL_API;
}
printer_print_msg("Device %lu work size %lu / %lu.", ctx->deviceIdx, ctx->workSize, MaximumWorkSize);
#ifdef CL_VERSION_2_0
const cl_queue_properties CommandQueueProperties[] = { 0, 0, 0 };
ctx->CommandQueues = clCreateCommandQueueWithProperties(opencl_ctx, ctx->DeviceID, CommandQueueProperties, &ret);
#else
const cl_command_queue_properties CommandQueueProperties = { 0 };
ctx->CommandQueues = clCreateCommandQueue(opencl_ctx, ctx->DeviceID, CommandQueueProperties, &ret);
#endif
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateCommandQueueWithProperties.", err_to_str(ret));
return ERR_OCL_API;
}
ctx->InputBuffer = clCreateBuffer(opencl_ctx, CL_MEM_READ_ONLY, 88, NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create input buffer.", err_to_str(ret));
return ERR_OCL_API;
}
size_t g_thd = ctx->rawIntensity;
ctx->ExtraBuffers[0] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, (1 << 21) * g_thd, NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create hash scratchpads buffer.", err_to_str(ret));
return ERR_OCL_API;
}
ctx->ExtraBuffers[1] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, 200 * g_thd, NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create hash states buffer.", err_to_str(ret));
return ERR_OCL_API;
}
// Blake-256 branches
ctx->ExtraBuffers[2] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 0 buffer.", err_to_str(ret));
return ERR_OCL_API;
}
// Groestl-256 branches
ctx->ExtraBuffers[3] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 1 buffer.", err_to_str(ret));
return ERR_OCL_API;
}
// JH-256 branches
ctx->ExtraBuffers[4] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 2 buffer.", err_to_str(ret));
return ERR_OCL_API;
}
// Skein-512 branches
ctx->ExtraBuffers[5] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 3 buffer.", err_to_str(ret));
return ERR_OCL_API;
}
// Assume we may find up to 0xFF nonces in one run - it's reasonable
ctx->OutputBuffer = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * 0x100, NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateBuffer to create output buffer.", err_to_str(ret));
return ERR_OCL_API;
}
ctx->Program = clCreateProgramWithSource(opencl_ctx, 1, (const char**)&source_code, NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateProgramWithSource on the contents of cryptonight.cl", err_to_str(ret));
return ERR_OCL_API;
}
char options[32];
snprintf(options, sizeof(options), "-I. -DWORKSIZE=%llu", int_port(ctx->workSize));
ret = clBuildProgram(ctx->Program, 1, &ctx->DeviceID, options, NULL, NULL);
if(ret != CL_SUCCESS)
{
size_t len;
printer_print_msg("Error %s when calling clBuildProgram.", err_to_str(ret));
if((ret = clGetProgramBuildInfo(ctx->Program, ctx->DeviceID, CL_PROGRAM_BUILD_LOG, 0, NULL, &len)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clGetProgramBuildInfo for length of build log output.", err_to_str(ret));
return ERR_OCL_API;
}
char* BuildLog = (char*)malloc(len + 1);
BuildLog[0] = '\0';
if((ret = clGetProgramBuildInfo(ctx->Program, ctx->DeviceID, CL_PROGRAM_BUILD_LOG, len, BuildLog, NULL)) != CL_SUCCESS)
{
free(BuildLog);
printer_print_msg("Error %s when calling clGetProgramBuildInfo for build log.", err_to_str(ret));
return ERR_OCL_API;
}
printer_print_str("Build log:\n");
printer_print_str(BuildLog);
free(BuildLog);
return ERR_OCL_API;
}
cl_build_status status;
do
{
if((ret = clGetProgramBuildInfo(ctx->Program, ctx->DeviceID, CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clGetProgramBuildInfo for status of build.", err_to_str(ret));
return ERR_OCL_API;
}
port_sleep(1);
}
while(status == CL_BUILD_IN_PROGRESS);
const char *KernelNames[] = { "cn0", "cn1", "cn2", "Blake", "Groestl", "JH", "Skein" };
for(int i = 0; i < 7; ++i)
{
ctx->Kernels[i] = clCreateKernel(ctx->Program, KernelNames[i], &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateKernel for kernel %s.", err_to_str(ret), KernelNames[i]);
return ERR_OCL_API;
}
}
ctx->Nonce = 0;
return 0;
}
// RequestedDeviceIdxs is a list of OpenCL device indexes
// NumDevicesRequested is number of devices in RequestedDeviceIdxs list
// Returns 0 on success, -1 on stupid params, -2 on OpenCL API error
size_t InitOpenCL(GpuContext* ctx, size_t num_gpus, size_t platform_idx)
{
cl_context opencl_ctx;
cl_int ret;
cl_uint entries;
if((ret = clGetPlatformIDs(0, NULL, &entries)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clGetPlatformIDs for number of platforms.", err_to_str(ret));
return ERR_OCL_API;
}
// The number of platforms naturally is the index of the last platform plus one.
if(entries <= platform_idx)
{
printer_print_msg("Selected OpenCL platform index %d doesn't exist.", platform_idx);
return ERR_STUPID_PARAMS;
}
/*MSVC skimping on devel costs by shoehorning C99 to be a subset of C++? Noooo... can't be.*/
#ifdef __GNUC__
cl_platform_id PlatformIDList[entries];
#else
cl_platform_id* PlatformIDList = _alloca(entries * sizeof(cl_platform_id));
#endif
if((ret = clGetPlatformIDs(entries, PlatformIDList, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clGetPlatformIDs for platform ID information.", err_to_str(ret));
return ERR_OCL_API;
}
if((ret = clGetDeviceIDs(PlatformIDList[platform_idx], CL_DEVICE_TYPE_GPU, 0, NULL, &entries)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clGetDeviceIDs for number of devices.", err_to_str(ret));
return ERR_OCL_API;
}
// Same as the platform index sanity check, except we must check all requested device indexes
for(int i = 0; i < num_gpus; ++i)
{
if(entries <= ctx[i].deviceIdx)
{
printer_print_msg("Selected OpenCL device index %lu doesn't exist.\n", ctx[i].deviceIdx);
return ERR_STUPID_PARAMS;
}
}
#ifdef __GNUC__
cl_device_id DeviceIDList[entries];
#else
cl_device_id* DeviceIDList = _alloca(entries * sizeof(cl_device_id));
#endif
if((ret = clGetDeviceIDs(PlatformIDList[platform_idx], CL_DEVICE_TYPE_GPU, entries, DeviceIDList, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clGetDeviceIDs for device ID information.", err_to_str(ret));
return ERR_OCL_API;
}
// Indexes sanity checked above
#ifdef __GNUC__
cl_device_id TempDeviceList[num_gpus];
#else
cl_device_id* TempDeviceList = _alloca(entries * sizeof(cl_device_id));
#endif
for(int i = 0; i < num_gpus; ++i)
{
ctx[i].DeviceID = DeviceIDList[ctx[i].deviceIdx];
TempDeviceList[i] = DeviceIDList[ctx[i].deviceIdx];
}
opencl_ctx = clCreateContext(NULL, num_gpus, TempDeviceList, NULL, NULL, &ret);
if(ret != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clCreateContext.", err_to_str(ret));
return ERR_OCL_API;
}
char* source_code = LoadTextFile(sSourcePath);
if(source_code == NULL)
{
printer_print_msg("Couldn't locate GPU source code file at %s.", sSourcePath);
return ERR_STUPID_PARAMS;
}
for(int i = 0; i < num_gpus; ++i)
{
if((ret = InitOpenCLGpu(opencl_ctx, &ctx[i], source_code)) != ERR_SUCCESS)
{
free(source_code);
return ret;
}
}
free(source_code);
return ERR_SUCCESS;
}
size_t XMRSetJob(GpuContext* ctx, uint8_t* input, size_t input_len, uint32_t target)
{
cl_int ret;
if(input_len > 84)
return ERR_STUPID_PARAMS;
input[input_len] = 0x01;
memset(input + input_len + 1, 0, 88 - input_len - 1);
if((ret = clEnqueueWriteBuffer(ctx->CommandQueues, ctx->InputBuffer, CL_TRUE, 0, 88, input, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueWriteBuffer to fill input buffer.", err_to_str(ret));
return ERR_OCL_API;
}
if((ret = clSetKernelArg(ctx->Kernels[0], 0, sizeof(cl_mem), &ctx->InputBuffer)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 0, argument 0.", err_to_str(ret));
return ERR_OCL_API;
}
// Scratchpads
if((ret = clSetKernelArg(ctx->Kernels[0], 1, sizeof(cl_mem), ctx->ExtraBuffers + 0)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 0, argument 1.", err_to_str(ret));
return ERR_OCL_API;
}
// States
if((ret = clSetKernelArg(ctx->Kernels[0], 2, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 0, argument 2.", err_to_str(ret));
return ERR_OCL_API;
}
// CN2 Kernel
// Scratchpads
if((ret = clSetKernelArg(ctx->Kernels[1], 0, sizeof(cl_mem), ctx->ExtraBuffers + 0)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 1, argument 0.", err_to_str(ret));
return ERR_OCL_API;
}
// States
if((ret = clSetKernelArg(ctx->Kernels[1], 1, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 1, argument 1.", err_to_str(ret));
return ERR_OCL_API;
}
// CN3 Kernel
// Scratchpads
if((ret = clSetKernelArg(ctx->Kernels[2], 0, sizeof(cl_mem), ctx->ExtraBuffers + 0)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 0.", err_to_str(ret));
return ERR_OCL_API;
}
// States
if((ret = clSetKernelArg(ctx->Kernels[2], 1, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 1.", err_to_str(ret));
return ERR_OCL_API;
}
// Branch 0
if((ret = clSetKernelArg(ctx->Kernels[2], 2, sizeof(cl_mem), ctx->ExtraBuffers + 2)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 2.", err_to_str(ret));
return ERR_OCL_API;
}
// Branch 1
if((ret = clSetKernelArg(ctx->Kernels[2], 3, sizeof(cl_mem), ctx->ExtraBuffers + 3)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 3.", err_to_str(ret));
return ERR_OCL_API;
}
// Branch 2
if((ret = clSetKernelArg(ctx->Kernels[2], 4, sizeof(cl_mem), ctx->ExtraBuffers + 4)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 4.", err_to_str(ret));
return ERR_OCL_API;
}
// Branch 3
if((ret = clSetKernelArg(ctx->Kernels[2], 5, sizeof(cl_mem), ctx->ExtraBuffers + 5)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 5.", err_to_str(ret));
return ERR_OCL_API;
}
for(int i = 0; i < 4; ++i)
{
// States
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 0, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 0);
return ERR_OCL_API;
}
// Nonce buffer
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 1, sizeof(cl_mem), ctx->ExtraBuffers + (i + 2))) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 1);
return ERR_OCL_API;
}
// Output
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 2, sizeof(cl_mem), &ctx->OutputBuffer)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 2);
return ERR_OCL_API;
}
// Target
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 3, sizeof(cl_uint), &target)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 3);
return ERR_OCL_API;
}
}
return ERR_SUCCESS;
}
size_t XMRRunJob(GpuContext* ctx, cl_uint* HashOutput)
{
cl_int ret;
cl_uint zero = 0;
size_t BranchNonces[4] = {0};
size_t g_thd = ctx->rawIntensity;
size_t w_size = ctx->workSize;
for(int i = 2; i < 6; ++i)
{
if((ret = clEnqueueWriteBuffer(ctx->CommandQueues, ctx->ExtraBuffers[i], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), &zero, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueWriteBuffer to zero branch buffer counter %d.", err_to_str(ret), i - 2);
return ERR_OCL_API;
}
}
if((ret = clEnqueueWriteBuffer(ctx->CommandQueues, ctx->OutputBuffer, CL_FALSE, sizeof(cl_uint) * 0xFF, sizeof(cl_uint), &zero, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
return ERR_OCL_API;
}
clFinish(ctx->CommandQueues);
size_t Nonce[2] = {ctx->Nonce, 1}, gthreads[2] = { g_thd, 8 }, lthreads[2] = { w_size, 8 };
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[0], 2, Nonce, gthreads, lthreads, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), 0);
return ERR_OCL_API;
}
/*for(int i = 1; i < 3; ++i)
{
if((ret = clEnqueueNDRangeKernel(*ctx->CommandQueues, ctx->Kernels[i], 1, &ctx->Nonce, &g_thd, &w_size, 0, NULL, NULL)) != CL_SUCCESS)
{
Log(LOG_CRITICAL, "Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), i);
return(ERR_OCL_API);
}
}*/
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[1], 1, &ctx->Nonce, &g_thd, &w_size, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), 1);
return ERR_OCL_API;
}
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[2], 2, Nonce, gthreads, lthreads, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), 2);
return ERR_OCL_API;
}
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[2], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
return ERR_OCL_API;
}
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[3], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces + 1, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
return ERR_OCL_API;
}
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[4], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces + 2, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
return ERR_OCL_API;
}
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[5], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces + 3, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
return ERR_OCL_API;
}
clFinish(ctx->CommandQueues);
for(int i = 0; i < 4; ++i)
{
if(BranchNonces[i])
{
// Threads
if((clSetKernelArg(ctx->Kernels[i + 3], 4, sizeof(cl_ulong), BranchNonces + i)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 4);
return(ERR_OCL_API);
}
BranchNonces[i] = ((size_t)ceil( (double)BranchNonces[i] / (double)w_size) ) * w_size;
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[i + 3], 1, &ctx->Nonce, BranchNonces + i, &w_size, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), i + 3);
return ERR_OCL_API;
}
}
}
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->OutputBuffer, CL_TRUE, 0, sizeof(cl_uint) * 0x100, HashOutput, 0, NULL, NULL)) != CL_SUCCESS)
{
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
return ERR_OCL_API;
}
clFinish(ctx->CommandQueues);
ctx->Nonce += g_thd;
return ERR_SUCCESS;
}
================================================
FILE: amd_gpu/gpu.h
================================================
#pragma once
#include
#include
#define ERR_SUCCESS (0)
#define ERR_OCL_API (2)
#define ERR_STUPID_PARAMS (1)
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef struct _GpuContext
{
/*Input vars*/
size_t deviceIdx;
size_t rawIntensity;
size_t workSize;
/*Output vars*/
cl_device_id DeviceID;
cl_command_queue CommandQueues;
cl_mem InputBuffer;
cl_mem OutputBuffer;
cl_mem ExtraBuffers[6];
cl_program Program;
cl_kernel Kernels[7];
size_t Nonce;
} GpuContext;
size_t InitOpenCL(GpuContext* ctx, size_t num_gpus, size_t platform_idx);
size_t XMRSetJob(GpuContext* ctx, uint8_t* input, size_t input_len, uint32_t target);
size_t XMRRunJob(GpuContext* ctx, cl_uint* HashOutput);
#ifdef __cplusplus
}
#endif // __cplusplus
================================================
FILE: cli-miner.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
#include "executor.h"
#include "minethd.h"
#include "jconf.h"
#include "console.h"
#include "donate-level.h"
#include "version.h"
#ifndef CONF_NO_HTTPD
# include "httpd.h"
#endif
#include
#include
#include
#ifndef CONF_NO_TLS
#include
#include
#endif
//Do a press any key for the windows folk. *insert any key joke here*
#ifdef _WIN32
void win_exit()
{
printer::inst()->print_str("Press any key to exit.");
get_key();
return;
}
#define strcasecmp _stricmp
#else
void win_exit() { return; }
#endif // _WIN32
void do_benchmark();
int main(int argc, char *argv[])
{
#ifndef CONF_NO_TLS
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
OpenSSL_add_all_digests();
#endif
const char* sFilename = "config.txt";
bool benchmark_mode = false;
if(argc >= 2)
{
if(strcmp(argv[1], "-h") == 0)
{
printer::inst()->print_msg(L0, "Usage %s [CONFIG FILE]", argv[0]);
win_exit();
return 0;
}
if(argc >= 3 && strcasecmp(argv[1], "-c") == 0)
{
sFilename = argv[2];
}
else if(argc >= 3 && strcasecmp(argv[1], "benchmark_mode") == 0)
{
sFilename = argv[2];
benchmark_mode = true;
}
else
sFilename = argv[1];
}
if(!jconf::inst()->parse_config(sFilename))
{
win_exit();
return 0;
}
if(!minethd::init_gpus())
{
win_exit();
return 0;
}
if(benchmark_mode)
{
do_benchmark();
win_exit();
return 0;
}
#ifndef CONF_NO_HTTPD
if(jconf::inst()->GetHttpdPort() != 0)
{
if (!httpd::inst()->start_daemon())
{
win_exit();
return 0;
}
}
#endif
printer::inst()->print_str("-------------------------------------------------------------------\n");
printer::inst()->print_str( XMR_STAK_NAME" " XMR_STAK_VERSION " mining software, AMD Version.\n");
printer::inst()->print_str("AMD mining code was written by wolf9466.\n");
printer::inst()->print_str("Brought to you by fireice_uk under GPLv3.\n\n");
char buffer[64];
snprintf(buffer, sizeof(buffer), "Configurable dev donation level is set to %.1f %%\n\n", fDevDonationLevel * 100.0);
printer::inst()->print_str(buffer);
printer::inst()->print_str("You can use following keys to display reports:\n");
printer::inst()->print_str("'h' - hashrate\n");
printer::inst()->print_str("'r' - results\n");
printer::inst()->print_str("'c' - connection\n");
printer::inst()->print_str("-------------------------------------------------------------------\n");
if(strlen(jconf::inst()->GetOutputFile()) != 0)
printer::inst()->open_logfile(jconf::inst()->GetOutputFile());
executor::inst()->ex_start(jconf::inst()->DaemonMode());
using namespace std::chrono;
uint64_t lastTime = time_point_cast(high_resolution_clock::now()).time_since_epoch().count();
int key;
while(true)
{
key = get_key();
switch(key)
{
case 'h':
executor::inst()->push_event(ex_event(EV_USR_HASHRATE));
break;
case 'r':
executor::inst()->push_event(ex_event(EV_USR_RESULTS));
break;
case 'c':
executor::inst()->push_event(ex_event(EV_USR_CONNSTAT));
break;
default:
break;
}
uint64_t currentTime = time_point_cast(high_resolution_clock::now()).time_since_epoch().count();
/* Hard guard to make sure we never get called more than twice per second */
if( currentTime - lastTime < 500)
std::this_thread::sleep_for(std::chrono::milliseconds(500 - (currentTime - lastTime)));
lastTime = currentTime;
}
return 0;
}
void do_benchmark()
{
using namespace std::chrono;
std::vector* pvThreads;
printer::inst()->print_msg(L0, "Running a 60 second benchmark...");
uint8_t work[76] = {0};
minethd::miner_work oWork = minethd::miner_work("", work, sizeof(work), 0, 0, 0);
pvThreads = minethd::thread_starter(oWork);
uint64_t iStartStamp = time_point_cast(high_resolution_clock::now()).time_since_epoch().count();
std::this_thread::sleep_for(std::chrono::seconds(60));
oWork = minethd::miner_work();
minethd::switch_work(oWork);
double fTotalHps = 0.0;
for (uint32_t i = 0; i < pvThreads->size(); i++)
{
double fHps = pvThreads->at(i)->iHashCount;
fHps /= (pvThreads->at(i)->iTimestamp - iStartStamp) / 1000.0;
printer::inst()->print_msg(L0, "Thread %u: %.1f H/S", i, fHps);
fTotalHps += fHps;
}
printer::inst()->print_msg(L0, "Total: %.1f H/S", fTotalHps);
}
================================================
FILE: config.txt
================================================
/*
* Number of GPUs that you have in your system. Each GPU will get its own CPU thread.
*/
"gpu_thread_num" : 6,
/*
* GPU configuration. You should play around with intensity and worksize as the fastest settings will vary.
* index - GPU index number usually starts from 0
* intensity - Number of parallel GPU threads (nothing to do with CPU threads)
* worksize - Number of local GPU threads (nothing to do with CPU threads)
* affine_to_cpu - This will affine the thread to a CPU. This can make a GPU miner play along nicer with a CPU miner.
*/
"gpu_threads_conf" : [
{ "index" : 0, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
{ "index" : 1, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
{ "index" : 2, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
{ "index" : 3, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
{ "index" : 4, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
{ "index" : 5, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
],
/*
* Platform index. This will be 0 unless you have different OpenCL platform - eg. AMD and Intel.
*/
"platform_index" : 0,
/*
* TLS Settings
* If you need real security, make sure tls_secure_algo is enabled (otherwise MITM attack can downgrade encryption
* to trivially breakable stuff like DES and MD5), and verify the server's fingerprint through a trusted channel.
*
* use_tls - This option will make us connect using Transport Layer Security.
* tls_secure_algo - Use only secure algorithms. This will make us quit with an error if we can't negotiate a secure algo.
* tls_fingerprint - Server's SHA256 fingerprint. If this string is non-empty then we will check the server's cert against it.
*/
"use_tls" : false,
"tls_secure_algo" : true,
"tls_fingerprint" : "",
/*
* pool_address - Pool address should be in the form "pool.supportxmr.com:3333". Only stratum pools are supported.
* wallet_address - Your wallet, or pool login.
* pool_password - Can be empty in most cases or "x".
*/
"pool_address" : "pool.supportxmr.com:3333",
"wallet_address" : "",
"pool_password" : "",
/*
* Network timeouts.
* Because of the way this client is written it doesn't need to constantly talk (keep-alive) to the server to make
* sure it is there. We detect a buggy / overloaded server by the call timeout. The default values will be ok for
* nearly all cases. If they aren't the pool has most likely overload issues. Low call timeout values are preferable -
* long timeouts mean that we waste hashes on potentially stale jobs. Connection report will tell you how long the
* server usually takes to process our calls.
*
* call_timeout - How long should we wait for a response from the server before we assume it is dead and drop the connection.
* retry_time - How long should we wait before another connection attempt.
* Both values are in seconds.
* giveup_limit - Limit how many times we try to reconnect to the pool. Zero means no limit. Note that stak miners
* don't mine while the connection is lost, so your computer's power usage goes down to idle.
*/
"call_timeout" : 10,
"retry_time" : 10,
"giveup_limit" : 0,
/*
* Output control.
* Since most people are used to miners printing all the time, that's what we do by default too. This is suboptimal
* really, since you cannot see errors under pages and pages of text and performance stats. Given that we have internal
* performance monitors, there is very little reason to spew out pages of text instead of concise reports.
* Press 'h' (hashrate), 'r' (results) or 'c' (connection) to print reports.
*
* verbose_level - 0 - Don't print anything.
* 1 - Print intro, connection event, disconnect event
* 2 - All of level 1, and new job (block) event if the difficulty is different from the last job
* 3 - All of level 1, and new job (block) event in all cases, result submission event.
* 4 - All of level 3, and automatic hashrate report printing
*/
"verbose_level" : 3,
/*
* Automatic hashrate report
*
* h_print_time - How often, in seconds, should we print a hashrate report if verbose_level is set to 4.
* This option has no effect if verbose_level is not 4.
*/
"h_print_time" : 60,
/*
* Daemon mode
*
* If you are running the process in the background and you don't need the keyboard reports, set this to true.
* This should solve the hashrate problems on some emulated terminals.
*/
"daemon_mode" : false,
/*
* Output file
*
* output_file - This option will log all output to a file.
*
*/
"output_file" : "",
/*
* Built-in web server
* I like checking my hashrate on my phone. Don't you?
* Keep in mind that you will need to set up port forwarding on your router if you want to access it from
* outside of your home network. Ports lower than 1024 on Linux systems will require root.
*
* httpd_port - Port we should listen on. Default, 0, will switch off the server.
*/
"httpd_port" : 0,
/*
* prefer_ipv4 - IPv6 preference. If the host is available on both IPv4 and IPv6 net, which one should be choose?
* This setting will only be needed in 2020's. No need to worry about it now.
*/
"prefer_ipv4" : true,
================================================
FILE: console.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
#include "console.h"
#include
#include
#include
#include
#ifdef _WIN32
#include
int get_key()
{
DWORD mode, rd;
HANDLE h;
if ((h = GetStdHandle(STD_INPUT_HANDLE)) == NULL)
return -1;
GetConsoleMode( h, &mode );
SetConsoleMode( h, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT) );
int c = 0;
ReadConsole( h, &c, 1, &rd, NULL );
SetConsoleMode( h, mode );
return c;
}
void set_colour(out_colours cl)
{
WORD attr = 0;
switch(cl)
{
case K_RED:
attr = FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
case K_GREEN:
attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
case K_BLUE:
attr = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break;
case K_YELLOW:
attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
case K_CYAN:
attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
case K_MAGENTA:
attr = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
case K_WHITE:
attr = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
default:
break;
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attr);
}
void reset_colour()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
#else
#include
#include
#include
int get_key()
{
struct termios oldattr, newattr;
int ch;
tcgetattr( STDIN_FILENO, &oldattr );
newattr = oldattr;
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
return ch;
}
void set_colour(out_colours cl)
{
switch(cl)
{
case K_RED:
fputs("\x1B[1;31m", stdout);
break;
case K_GREEN:
fputs("\x1B[1;32m", stdout);
break;
case K_BLUE:
fputs("\x1B[1;34m", stdout);
break;
case K_YELLOW:
fputs("\x1B[1;33m", stdout);
break;
case K_CYAN:
fputs("\x1B[1;36m", stdout);
break;
case K_MAGENTA:
fputs("\x1B[1;35m", stdout);
break;
case K_WHITE:
fputs("\x1B[1;37m", stdout);
break;
default:
break;
}
}
void reset_colour()
{
fputs("\x1B[0m", stdout);
}
#endif // _WIN32
inline void comp_localtime(const time_t* ctime, tm* stime)
{
#ifdef _WIN32
localtime_s(stime, ctime);
#else
localtime_r(ctime, stime);
#endif // __WIN32
}
printer* printer::oInst = nullptr;
printer::printer()
{
verbose_level = LINF;
logfile = nullptr;
}
bool printer::open_logfile(const char* file)
{
logfile = fopen(file, "ab+");
return logfile != nullptr;
}
void printer::print_msg(verbosity verbose, const char* fmt, ...)
{
if(verbose > verbose_level)
return;
char buf[1024];
size_t bpos;
tm stime;
time_t now = time(nullptr);
comp_localtime(&now, &stime);
strftime(buf, sizeof(buf), "[%F %T] : ", &stime);
bpos = strlen(buf);
va_list args;
va_start(args, fmt);
vsnprintf(buf+bpos, sizeof(buf)-bpos, fmt, args);
va_end(args);
bpos = strlen(buf);
if(bpos+2 >= sizeof(buf))
return;
buf[bpos] = '\n';
buf[bpos+1] = '\0';
std::unique_lock lck(print_mutex);
fputs(buf, stdout);
if(logfile != nullptr)
{
fputs(buf, logfile);
fflush(logfile);
}
}
void printer::print_str(const char* str)
{
std::unique_lock lck(print_mutex);
fputs(str, stdout);
if(logfile != nullptr)
{
fputs(str, logfile);
fflush(logfile);
}
}
extern "C" void printer_print_msg(const char* fmt, ...)
{
char buf[1024];
size_t bpos;
tm stime;
time_t now = time(nullptr);
comp_localtime(&now, &stime);
strftime(buf, sizeof(buf), "[%F %T] : ", &stime);
bpos = strlen(buf);
va_list args;
va_start(args, fmt);
vsnprintf(buf+bpos, sizeof(buf)-bpos, fmt, args);
va_end(args);
bpos = strlen(buf);
if(bpos+2 >= sizeof(buf))
return;
buf[bpos] = '\n';
buf[bpos+1] = '\0';
printer::inst()->print_str(buf);
}
extern "C" void printer_print_str(const char* str)
{
printer::inst()->print_str(str);
}
================================================
FILE: console.h
================================================
#pragma once
#include
enum out_colours { K_RED, K_GREEN, K_BLUE, K_YELLOW, K_CYAN, K_MAGENTA, K_WHITE, K_NONE };
// Warning - on Linux get_key will detect control keys, but not on Windows.
// We will only use it for alphanum keys anyway.
int get_key();
void set_colour(out_colours cl);
void reset_colour();
// on MSVC sizeof(long int) = 4, gcc sizeof(long int) = 8, this is the workaround
// now we can use %llu on both compilers
inline long long unsigned int int_port(size_t i)
{
return i;
}
enum verbosity : size_t { L0 = 0, L1 = 1, L2 = 2, L3 = 3, L4 = 4, LINF = 100};
class printer
{
public:
static inline printer* inst()
{
if (oInst == nullptr) oInst = new printer;
return oInst;
};
inline void set_verbose_level(size_t level) { verbose_level = (verbosity)level; }
void print_msg(verbosity verbose, const char* fmt, ...);
void print_str(const char* str);
bool open_logfile(const char* file);
private:
printer();
static printer* oInst;
std::mutex print_mutex;
verbosity verbose_level;
FILE* logfile;
};
================================================
FILE: crypto/c_blake256.c
================================================
/*
* The blake256_* and blake224_* functions are largely copied from
* blake256_light.c and blake224_light.c from the BLAKE website:
*
* http://131002.net/blake/
*
* The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224.
* HMAC is specified by RFC 2104.
*/
#include
#include
#include
#include "c_blake256.h"
#define U8TO32(p) \
(((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \
((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) ))
#define U32TO8(p, v) \
(p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \
(p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) );
const uint8_t sigma[][16] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
{14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3},
{11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4},
{ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8},
{ 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13},
{ 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9},
{12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11},
{13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10},
{ 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5},
{10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0},
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
{14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3},
{11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4},
{ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}
};
const uint32_t cst[16] = {
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917
};
static const uint8_t padding[] = {
0x80,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
};
void blake256_compress(state *S, const uint8_t *block) {
uint32_t v[16], m[16], i;
#define ROT(x,n) (((x)<<(32-n))|((x)>>(n)))
#define G(a,b,c,d,e) \
v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \
v[d] = ROT(v[d] ^ v[a],16); \
v[c] += v[d]; \
v[b] = ROT(v[b] ^ v[c],12); \
v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \
v[d] = ROT(v[d] ^ v[a], 8); \
v[c] += v[d]; \
v[b] = ROT(v[b] ^ v[c], 7);
for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4);
for (i = 0; i < 8; ++i) v[i] = S->h[i];
v[ 8] = S->s[0] ^ 0x243F6A88;
v[ 9] = S->s[1] ^ 0x85A308D3;
v[10] = S->s[2] ^ 0x13198A2E;
v[11] = S->s[3] ^ 0x03707344;
v[12] = 0xA4093822;
v[13] = 0x299F31D0;
v[14] = 0x082EFA98;
v[15] = 0xEC4E6C89;
if (S->nullt == 0) {
v[12] ^= S->t[0];
v[13] ^= S->t[0];
v[14] ^= S->t[1];
v[15] ^= S->t[1];
}
for (i = 0; i < 14; ++i) {
G(0, 4, 8, 12, 0);
G(1, 5, 9, 13, 2);
G(2, 6, 10, 14, 4);
G(3, 7, 11, 15, 6);
G(3, 4, 9, 14, 14);
G(2, 7, 8, 13, 12);
G(0, 5, 10, 15, 8);
G(1, 6, 11, 12, 10);
}
for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i];
for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4];
}
void blake256_init(state *S) {
S->h[0] = 0x6A09E667;
S->h[1] = 0xBB67AE85;
S->h[2] = 0x3C6EF372;
S->h[3] = 0xA54FF53A;
S->h[4] = 0x510E527F;
S->h[5] = 0x9B05688C;
S->h[6] = 0x1F83D9AB;
S->h[7] = 0x5BE0CD19;
S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
}
void blake224_init(state *S) {
S->h[0] = 0xC1059ED8;
S->h[1] = 0x367CD507;
S->h[2] = 0x3070DD17;
S->h[3] = 0xF70E5939;
S->h[4] = 0xFFC00B31;
S->h[5] = 0x68581511;
S->h[6] = 0x64F98FA7;
S->h[7] = 0xBEFA4FA4;
S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
}
// datalen = number of bits
void blake256_update(state *S, const uint8_t *data, uint64_t datalen) {
int left = S->buflen >> 3;
int fill = 64 - left;
if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) {
memcpy((void *) (S->buf + left), (void *) data, fill);
S->t[0] += 512;
if (S->t[0] == 0) S->t[1]++;
blake256_compress(S, S->buf);
data += fill;
datalen -= (fill << 3);
left = 0;
}
while (datalen >= 512) {
S->t[0] += 512;
if (S->t[0] == 0) S->t[1]++;
blake256_compress(S, data);
data += 64;
datalen -= 512;
}
if (datalen > 0) {
memcpy((void *) (S->buf + left), (void *) data, datalen >> 3);
S->buflen = (left << 3) + datalen;
} else {
S->buflen = 0;
}
}
// datalen = number of bits
void blake224_update(state *S, const uint8_t *data, uint64_t datalen) {
blake256_update(S, data, datalen);
}
void blake256_final_h(state *S, uint8_t *digest, uint8_t pa, uint8_t pb) {
uint8_t msglen[8];
uint32_t lo = S->t[0] + S->buflen, hi = S->t[1];
if (lo < (unsigned) S->buflen) hi++;
U32TO8(msglen + 0, hi);
U32TO8(msglen + 4, lo);
if (S->buflen == 440) { /* one padding byte */
S->t[0] -= 8;
blake256_update(S, &pa, 8);
} else {
if (S->buflen < 440) { /* enough space to fill the block */
if (S->buflen == 0) S->nullt = 1;
S->t[0] -= 440 - S->buflen;
blake256_update(S, padding, 440 - S->buflen);
} else { /* need 2 compressions */
S->t[0] -= 512 - S->buflen;
blake256_update(S, padding, 512 - S->buflen);
S->t[0] -= 440;
blake256_update(S, padding + 1, 440);
S->nullt = 1;
}
blake256_update(S, &pb, 8);
S->t[0] -= 8;
}
S->t[0] -= 64;
blake256_update(S, msglen, 64);
U32TO8(digest + 0, S->h[0]);
U32TO8(digest + 4, S->h[1]);
U32TO8(digest + 8, S->h[2]);
U32TO8(digest + 12, S->h[3]);
U32TO8(digest + 16, S->h[4]);
U32TO8(digest + 20, S->h[5]);
U32TO8(digest + 24, S->h[6]);
U32TO8(digest + 28, S->h[7]);
}
void blake256_final(state *S, uint8_t *digest) {
blake256_final_h(S, digest, 0x81, 0x01);
}
void blake224_final(state *S, uint8_t *digest) {
blake256_final_h(S, digest, 0x80, 0x00);
}
// inlen = number of bytes
void blake256_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
state S;
blake256_init(&S);
blake256_update(&S, in, inlen * 8);
blake256_final(&S, out);
}
// inlen = number of bytes
void blake224_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
state S;
blake224_init(&S);
blake224_update(&S, in, inlen * 8);
blake224_final(&S, out);
}
// keylen = number of bytes
void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
const uint8_t *key = _key;
uint8_t keyhash[32];
uint8_t pad[64];
uint64_t i;
if (keylen > 64) {
blake256_hash(keyhash, key, keylen);
key = keyhash;
keylen = 32;
}
blake256_init(&S->inner);
memset(pad, 0x36, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake256_update(&S->inner, pad, 512);
blake256_init(&S->outer);
memset(pad, 0x5c, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake256_update(&S->outer, pad, 512);
memset(keyhash, 0, 32);
}
// keylen = number of bytes
void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
const uint8_t *key = _key;
uint8_t keyhash[32];
uint8_t pad[64];
uint64_t i;
if (keylen > 64) {
blake256_hash(keyhash, key, keylen);
key = keyhash;
keylen = 28;
}
blake224_init(&S->inner);
memset(pad, 0x36, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake224_update(&S->inner, pad, 512);
blake224_init(&S->outer);
memset(pad, 0x5c, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake224_update(&S->outer, pad, 512);
memset(keyhash, 0, 32);
}
// datalen = number of bits
void hmac_blake256_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
// update the inner state
blake256_update(&S->inner, data, datalen);
}
// datalen = number of bits
void hmac_blake224_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
// update the inner state
blake224_update(&S->inner, data, datalen);
}
void hmac_blake256_final(hmac_state *S, uint8_t *digest) {
uint8_t ihash[32];
blake256_final(&S->inner, ihash);
blake256_update(&S->outer, ihash, 256);
blake256_final(&S->outer, digest);
memset(ihash, 0, 32);
}
void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
uint8_t ihash[32];
blake224_final(&S->inner, ihash);
blake224_update(&S->outer, ihash, 224);
blake224_final(&S->outer, digest);
memset(ihash, 0, 32);
}
// keylen = number of bytes; inlen = number of bytes
void hmac_blake256_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
hmac_state S;
hmac_blake256_init(&S, key, keylen);
hmac_blake256_update(&S, in, inlen * 8);
hmac_blake256_final(&S, out);
}
// keylen = number of bytes; inlen = number of bytes
void hmac_blake224_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
hmac_state S;
hmac_blake224_init(&S, key, keylen);
hmac_blake224_update(&S, in, inlen * 8);
hmac_blake224_final(&S, out);
}
================================================
FILE: crypto/c_blake256.h
================================================
#ifndef _BLAKE256_H_
#define _BLAKE256_H_
#include
typedef struct {
uint32_t h[8], s[4], t[2];
int buflen, nullt;
uint8_t buf[64];
} state;
typedef struct {
state inner;
state outer;
} hmac_state;
void blake256_init(state *);
void blake224_init(state *);
void blake256_update(state *, const uint8_t *, uint64_t);
void blake224_update(state *, const uint8_t *, uint64_t);
void blake256_final(state *, uint8_t *);
void blake224_final(state *, uint8_t *);
void blake256_hash(uint8_t *, const uint8_t *, uint64_t);
void blake224_hash(uint8_t *, const uint8_t *, uint64_t);
/* HMAC functions: */
void hmac_blake256_init(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake224_init(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake256_update(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake224_update(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake256_final(hmac_state *, uint8_t *);
void hmac_blake224_final(hmac_state *, uint8_t *);
void hmac_blake256_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
void hmac_blake224_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
#endif /* _BLAKE256_H_ */
================================================
FILE: crypto/c_groestl.c
================================================
/* hash.c April 2012
* Groestl ANSI C code optimised for 32-bit machines
* Author: Thomas Krinninger
*
* This work is based on the implementation of
* Soeren S. Thomsen and Krystian Matusiewicz
*
*
*/
#include "c_groestl.h"
#include "groestl_tables.h"
#define P_TYPE 0
#define Q_TYPE 1
const uint8_t shift_Values[2][8] = {{0,1,2,3,4,5,6,7},{1,3,5,7,0,2,4,6}};
const uint8_t indices_cyclic[15] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6};
#define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1<<(8*amount_bytes))|(v2>>(8*(4-amount_bytes))); \
v2 = (v2<<(8*amount_bytes))|(v1>>(8*(4-amount_bytes))); \
v1 = temp_var;}
#define COLUMN(x,y,i,c0,c1,c2,c3,c4,c5,c6,c7,tv1,tv2,tu,tl,t) \
tu = T[2*(uint32_t)x[4*c0+0]]; \
tl = T[2*(uint32_t)x[4*c0+0]+1]; \
tv1 = T[2*(uint32_t)x[4*c1+1]]; \
tv2 = T[2*(uint32_t)x[4*c1+1]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \
tu ^= tv1; \
tl ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c2+2]]; \
tv2 = T[2*(uint32_t)x[4*c2+2]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \
tu ^= tv1; \
tl ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c3+3]]; \
tv2 = T[2*(uint32_t)x[4*c3+3]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \
tu ^= tv1; \
tl ^= tv2; \
tl ^= T[2*(uint32_t)x[4*c4+0]]; \
tu ^= T[2*(uint32_t)x[4*c4+0]+1]; \
tv1 = T[2*(uint32_t)x[4*c5+1]]; \
tv2 = T[2*(uint32_t)x[4*c5+1]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \
tl ^= tv1; \
tu ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c6+2]]; \
tv2 = T[2*(uint32_t)x[4*c6+2]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \
tl ^= tv1; \
tu ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c7+3]]; \
tv2 = T[2*(uint32_t)x[4*c7+3]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \
tl ^= tv1; \
tu ^= tv2; \
y[i] = tu; \
y[i+1] = tl;
/* compute one round of P (short variants) */
static void RND512P(uint8_t *x, uint32_t *y, uint32_t r) {
uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
uint32_t* x32 = (uint32_t*)x;
x32[ 0] ^= 0x00000000^r;
x32[ 2] ^= 0x00000010^r;
x32[ 4] ^= 0x00000020^r;
x32[ 6] ^= 0x00000030^r;
x32[ 8] ^= 0x00000040^r;
x32[10] ^= 0x00000050^r;
x32[12] ^= 0x00000060^r;
x32[14] ^= 0x00000070^r;
COLUMN(x,y, 0, 0, 2, 4, 6, 9, 11, 13, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 2, 2, 4, 6, 8, 11, 13, 15, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 4, 4, 6, 8, 10, 13, 15, 1, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 6, 6, 8, 10, 12, 15, 1, 3, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 8, 8, 10, 12, 14, 1, 3, 5, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,10, 10, 12, 14, 0, 3, 5, 7, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,12, 12, 14, 0, 2, 5, 7, 9, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,14, 14, 0, 2, 4, 7, 9, 11, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
}
/* compute one round of Q (short variants) */
static void RND512Q(uint8_t *x, uint32_t *y, uint32_t r) {
uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
uint32_t* x32 = (uint32_t*)x;
x32[ 0] = ~x32[ 0];
x32[ 1] ^= 0xffffffff^r;
x32[ 2] = ~x32[ 2];
x32[ 3] ^= 0xefffffff^r;
x32[ 4] = ~x32[ 4];
x32[ 5] ^= 0xdfffffff^r;
x32[ 6] = ~x32[ 6];
x32[ 7] ^= 0xcfffffff^r;
x32[ 8] = ~x32[ 8];
x32[ 9] ^= 0xbfffffff^r;
x32[10] = ~x32[10];
x32[11] ^= 0xafffffff^r;
x32[12] = ~x32[12];
x32[13] ^= 0x9fffffff^r;
x32[14] = ~x32[14];
x32[15] ^= 0x8fffffff^r;
COLUMN(x,y, 0, 2, 6, 10, 14, 1, 5, 9, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 2, 4, 8, 12, 0, 3, 7, 11, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 4, 6, 10, 14, 2, 5, 9, 13, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 6, 8, 12, 0, 4, 7, 11, 15, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 8, 10, 14, 2, 6, 9, 13, 1, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,10, 12, 0, 4, 8, 11, 15, 3, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,12, 14, 2, 6, 10, 13, 1, 5, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,14, 0, 4, 8, 12, 15, 3, 7, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
}
/* compute compression function (short variants) */
static void F512(uint32_t *h, const uint32_t *m) {
int i;
uint32_t Ptmp[2*COLS512];
uint32_t Qtmp[2*COLS512];
uint32_t y[2*COLS512];
uint32_t z[2*COLS512];
for (i = 0; i < 2*COLS512; i++) {
z[i] = m[i];
Ptmp[i] = h[i]^m[i];
}
/* compute Q(m) */
RND512Q((uint8_t*)z, y, 0x00000000);
RND512Q((uint8_t*)y, z, 0x01000000);
RND512Q((uint8_t*)z, y, 0x02000000);
RND512Q((uint8_t*)y, z, 0x03000000);
RND512Q((uint8_t*)z, y, 0x04000000);
RND512Q((uint8_t*)y, z, 0x05000000);
RND512Q((uint8_t*)z, y, 0x06000000);
RND512Q((uint8_t*)y, z, 0x07000000);
RND512Q((uint8_t*)z, y, 0x08000000);
RND512Q((uint8_t*)y, Qtmp, 0x09000000);
/* compute P(h+m) */
RND512P((uint8_t*)Ptmp, y, 0x00000000);
RND512P((uint8_t*)y, z, 0x00000001);
RND512P((uint8_t*)z, y, 0x00000002);
RND512P((uint8_t*)y, z, 0x00000003);
RND512P((uint8_t*)z, y, 0x00000004);
RND512P((uint8_t*)y, z, 0x00000005);
RND512P((uint8_t*)z, y, 0x00000006);
RND512P((uint8_t*)y, z, 0x00000007);
RND512P((uint8_t*)z, y, 0x00000008);
RND512P((uint8_t*)y, Ptmp, 0x00000009);
/* compute P(h+m) + Q(m) + h */
for (i = 0; i < 2*COLS512; i++) {
h[i] ^= Ptmp[i]^Qtmp[i];
}
}
/* digest up to msglen bytes of input (full blocks only) */
static void Transform(groestlHashState *ctx,
const uint8_t *input,
int msglen) {
/* digest message, one block at a time */
for (; msglen >= SIZE512;
msglen -= SIZE512, input += SIZE512) {
F512(ctx->chaining,(uint32_t*)input);
/* increment block counter */
ctx->block_counter1++;
if (ctx->block_counter1 == 0) ctx->block_counter2++;
}
}
/* given state h, do h <- P(h)+h */
static void OutputTransformation(groestlHashState *ctx) {
int j;
uint32_t temp[2*COLS512];
uint32_t y[2*COLS512];
uint32_t z[2*COLS512];
for (j = 0; j < 2*COLS512; j++) {
temp[j] = ctx->chaining[j];
}
RND512P((uint8_t*)temp, y, 0x00000000);
RND512P((uint8_t*)y, z, 0x00000001);
RND512P((uint8_t*)z, y, 0x00000002);
RND512P((uint8_t*)y, z, 0x00000003);
RND512P((uint8_t*)z, y, 0x00000004);
RND512P((uint8_t*)y, z, 0x00000005);
RND512P((uint8_t*)z, y, 0x00000006);
RND512P((uint8_t*)y, z, 0x00000007);
RND512P((uint8_t*)z, y, 0x00000008);
RND512P((uint8_t*)y, temp, 0x00000009);
for (j = 0; j < 2*COLS512; j++) {
ctx->chaining[j] ^= temp[j];
}
}
/* initialise context */
static void Init(groestlHashState* ctx) {
int i = 0;
/* allocate memory for state and data buffer */
for(;i<(SIZE512/sizeof(uint32_t));i++)
{
ctx->chaining[i] = 0;
}
/* set initial value */
ctx->chaining[2*COLS512-1] = u32BIG((uint32_t)HASH_BIT_LEN);
/* set other variables */
ctx->buf_ptr = 0;
ctx->block_counter1 = 0;
ctx->block_counter2 = 0;
ctx->bits_in_last_byte = 0;
}
/* update state with databitlen bits of input */
static void Update(groestlHashState* ctx,
const BitSequence* input,
DataLength databitlen) {
int index = 0;
int msglen = (int)(databitlen/8);
int rem = (int)(databitlen%8);
/* if the buffer contains data that has not yet been digested, first
add data to buffer until full */
if (ctx->buf_ptr) {
while (ctx->buf_ptr < SIZE512 && index < msglen) {
ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
}
if (ctx->buf_ptr < SIZE512) {
/* buffer still not full, return */
if (rem) {
ctx->bits_in_last_byte = rem;
ctx->buffer[(int)ctx->buf_ptr++] = input[index];
}
return;
}
/* digest buffer */
ctx->buf_ptr = 0;
Transform(ctx, ctx->buffer, SIZE512);
}
/* digest bulk of message */
Transform(ctx, input+index, msglen-index);
index += ((msglen-index)/SIZE512)*SIZE512;
/* store remaining data in buffer */
while (index < msglen) {
ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
}
/* if non-integral number of bytes have been supplied, store
remaining bits in last byte, together with information about
number of bits */
if (rem) {
ctx->bits_in_last_byte = rem;
ctx->buffer[(int)ctx->buf_ptr++] = input[index];
}
}
#define BILB ctx->bits_in_last_byte
/* finalise: process remaining data (including padding), perform
output transformation, and write hash result to 'output' */
static void Final(groestlHashState* ctx,
BitSequence* output) {
int i, j = 0, hashbytelen = HASH_BIT_LEN/8;
uint8_t *s = (BitSequence*)ctx->chaining;
/* pad with '1'-bit and first few '0'-bits */
if (BILB) {
ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB);
BILB = 0;
}
else ctx->buffer[(int)ctx->buf_ptr++] = 0x80;
/* pad with '0'-bits */
if (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
/* padding requires two blocks */
while (ctx->buf_ptr < SIZE512) {
ctx->buffer[(int)ctx->buf_ptr++] = 0;
}
/* digest first padding block */
Transform(ctx, ctx->buffer, SIZE512);
ctx->buf_ptr = 0;
}
while (ctx->buf_ptr < SIZE512-LENGTHFIELDLEN) {
ctx->buffer[(int)ctx->buf_ptr++] = 0;
}
/* length padding */
ctx->block_counter1++;
if (ctx->block_counter1 == 0) ctx->block_counter2++;
ctx->buf_ptr = SIZE512;
while (ctx->buf_ptr > SIZE512-(int)sizeof(uint32_t)) {
ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter1;
ctx->block_counter1 >>= 8;
}
while (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter2;
ctx->block_counter2 >>= 8;
}
/* digest final padding block */
Transform(ctx, ctx->buffer, SIZE512);
/* perform output transformation */
OutputTransformation(ctx);
/* store hash result in output */
for (i = SIZE512-hashbytelen; i < SIZE512; i++,j++) {
output[j] = s[i];
}
/* zeroise relevant variables and deallocate memory */
for (i = 0; i < COLS512; i++) {
ctx->chaining[i] = 0;
}
for (i = 0; i < SIZE512; i++) {
ctx->buffer[i] = 0;
}
}
/* hash bit sequence */
void groestl(const BitSequence* data,
DataLength databitlen,
BitSequence* hashval) {
groestlHashState context;
/* initialise */
Init(&context);
/* process message */
Update(&context, data, databitlen);
/* finalise */
Final(&context, hashval);
}
/*
static int crypto_hash(unsigned char *out,
const unsigned char *in,
unsigned long long len)
{
groestl(in, 8*len, out);
return 0;
}
*/
================================================
FILE: crypto/c_groestl.h
================================================
#ifndef __hash_h
#define __hash_h
/*
#include "crypto_uint8.h"
#include "crypto_uint32.h"
#include "crypto_uint64.h"
#include "crypto_hash.h"
typedef crypto_uint8 uint8_t;
typedef crypto_uint32 uint32_t;
typedef crypto_uint64 uint64_t;
*/
#include
#include "hash.h"
/* some sizes (number of bytes) */
#define ROWS 8
#define LENGTHFIELDLEN ROWS
#define COLS512 8
#define SIZE512 (ROWS*COLS512)
#define ROUNDS512 10
#define HASH_BIT_LEN 256
#define ROTL32(v, n) ((((v)<<(n))|((v)>>(32-(n))))&li_32(ffffffff))
#define li_32(h) 0x##h##u
#define EXT_BYTE(var,n) ((uint8_t)((uint32_t)(var) >> (8*n)))
#define u32BIG(a) \
((ROTL32(a,8) & li_32(00FF00FF)) | \
(ROTL32(a,24) & li_32(FF00FF00)))
/* NIST API begin */
typedef struct {
uint32_t chaining[SIZE512/sizeof(uint32_t)]; /* actual state */
uint32_t block_counter1,
block_counter2; /* message block counter(s) */
BitSequence buffer[SIZE512]; /* data buffer */
int buf_ptr; /* data buffer pointer */
int bits_in_last_byte; /* no. of message bits in last byte of
data buffer */
} groestlHashState;
/*void Init(hashState*);
void Update(hashState*, const BitSequence*, DataLength);
void Final(hashState*, BitSequence*); */
void groestl(const BitSequence*, DataLength, BitSequence*);
/* NIST API end */
/*
int crypto_hash(unsigned char *out,
const unsigned char *in,
unsigned long long len);
*/
#endif /* __hash_h */
================================================
FILE: crypto/c_jh.c
================================================
/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C
--------------------------------
Performance
Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz)
Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic)
Speed for long message:
1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2
2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3
--------------------------------
Last Modified: January 16, 2011
*/
#include "c_jh.h"
#include
#include
/*typedef unsigned long long uint64;*/
typedef uint64_t uint64;
/*define data alignment for different C compilers*/
#if defined(__GNUC__)
#define DATA_ALIGN16(x) x __attribute__ ((aligned(16)))
#else
#define DATA_ALIGN16(x) __declspec(align(16)) x
#endif
typedef struct {
int hashbitlen; /*the message digest size*/
unsigned long long databitlen; /*the message size in bits*/
unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/
DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/
unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/
} hashState;
/*The initial hash value H(0)*/
const unsigned char JH224_H0[128]={0x2d,0xfe,0xdd,0x62,0xf9,0x9a,0x98,0xac,0xae,0x7c,0xac,0xd6,0x19,0xd6,0x34,0xe7,0xa4,0x83,0x10,0x5,0xbc,0x30,0x12,0x16,0xb8,0x60,0x38,0xc6,0xc9,0x66,0x14,0x94,0x66,0xd9,0x89,0x9f,0x25,0x80,0x70,0x6f,0xce,0x9e,0xa3,0x1b,0x1d,0x9b,0x1a,0xdc,0x11,0xe8,0x32,0x5f,0x7b,0x36,0x6e,0x10,0xf9,0x94,0x85,0x7f,0x2,0xfa,0x6,0xc1,0x1b,0x4f,0x1b,0x5c,0xd8,0xc8,0x40,0xb3,0x97,0xf6,0xa1,0x7f,0x6e,0x73,0x80,0x99,0xdc,0xdf,0x93,0xa5,0xad,0xea,0xa3,0xd3,0xa4,0x31,0xe8,0xde,0xc9,0x53,0x9a,0x68,0x22,0xb4,0xa9,0x8a,0xec,0x86,0xa1,0xe4,0xd5,0x74,0xac,0x95,0x9c,0xe5,0x6c,0xf0,0x15,0x96,0xd,0xea,0xb5,0xab,0x2b,0xbf,0x96,0x11,0xdc,0xf0,0xdd,0x64,0xea,0x6e};
const unsigned char JH256_H0[128]={0xeb,0x98,0xa3,0x41,0x2c,0x20,0xd3,0xeb,0x92,0xcd,0xbe,0x7b,0x9c,0xb2,0x45,0xc1,0x1c,0x93,0x51,0x91,0x60,0xd4,0xc7,0xfa,0x26,0x0,0x82,0xd6,0x7e,0x50,0x8a,0x3,0xa4,0x23,0x9e,0x26,0x77,0x26,0xb9,0x45,0xe0,0xfb,0x1a,0x48,0xd4,0x1a,0x94,0x77,0xcd,0xb5,0xab,0x26,0x2,0x6b,0x17,0x7a,0x56,0xf0,0x24,0x42,0xf,0xff,0x2f,0xa8,0x71,0xa3,0x96,0x89,0x7f,0x2e,0x4d,0x75,0x1d,0x14,0x49,0x8,0xf7,0x7d,0xe2,0x62,0x27,0x76,0x95,0xf7,0x76,0x24,0x8f,0x94,0x87,0xd5,0xb6,0x57,0x47,0x80,0x29,0x6c,0x5c,0x5e,0x27,0x2d,0xac,0x8e,0xd,0x6c,0x51,0x84,0x50,0xc6,0x57,0x5,0x7a,0xf,0x7b,0xe4,0xd3,0x67,0x70,0x24,0x12,0xea,0x89,0xe3,0xab,0x13,0xd3,0x1c,0xd7,0x69};
const unsigned char JH384_H0[128]={0x48,0x1e,0x3b,0xc6,0xd8,0x13,0x39,0x8a,0x6d,0x3b,0x5e,0x89,0x4a,0xde,0x87,0x9b,0x63,0xfa,0xea,0x68,0xd4,0x80,0xad,0x2e,0x33,0x2c,0xcb,0x21,0x48,0xf,0x82,0x67,0x98,0xae,0xc8,0x4d,0x90,0x82,0xb9,0x28,0xd4,0x55,0xea,0x30,0x41,0x11,0x42,0x49,0x36,0xf5,0x55,0xb2,0x92,0x48,0x47,0xec,0xc7,0x25,0xa,0x93,0xba,0xf4,0x3c,0xe1,0x56,0x9b,0x7f,0x8a,0x27,0xdb,0x45,0x4c,0x9e,0xfc,0xbd,0x49,0x63,0x97,0xaf,0xe,0x58,0x9f,0xc2,0x7d,0x26,0xaa,0x80,0xcd,0x80,0xc0,0x8b,0x8c,0x9d,0xeb,0x2e,0xda,0x8a,0x79,0x81,0xe8,0xf8,0xd5,0x37,0x3a,0xf4,0x39,0x67,0xad,0xdd,0xd1,0x7a,0x71,0xa9,0xb4,0xd3,0xbd,0xa4,0x75,0xd3,0x94,0x97,0x6c,0x3f,0xba,0x98,0x42,0x73,0x7f};
const unsigned char JH512_H0[128]={0x6f,0xd1,0x4b,0x96,0x3e,0x0,0xaa,0x17,0x63,0x6a,0x2e,0x5,0x7a,0x15,0xd5,0x43,0x8a,0x22,0x5e,0x8d,0xc,0x97,0xef,0xb,0xe9,0x34,0x12,0x59,0xf2,0xb3,0xc3,0x61,0x89,0x1d,0xa0,0xc1,0x53,0x6f,0x80,0x1e,0x2a,0xa9,0x5,0x6b,0xea,0x2b,0x6d,0x80,0x58,0x8e,0xcc,0xdb,0x20,0x75,0xba,0xa6,0xa9,0xf,0x3a,0x76,0xba,0xf8,0x3b,0xf7,0x1,0x69,0xe6,0x5,0x41,0xe3,0x4a,0x69,0x46,0xb5,0x8a,0x8e,0x2e,0x6f,0xe6,0x5a,0x10,0x47,0xa7,0xd0,0xc1,0x84,0x3c,0x24,0x3b,0x6e,0x71,0xb1,0x2d,0x5a,0xc1,0x99,0xcf,0x57,0xf6,0xec,0x9d,0xb1,0xf8,0x56,0xa7,0x6,0x88,0x7c,0x57,0x16,0xb1,0x56,0xe3,0xc2,0xfc,0xdf,0xe6,0x85,0x17,0xfb,0x54,0x5a,0x46,0x78,0xcc,0x8c,0xdd,0x4b};
/*42 round constants, each round constant is 32-byte (256-bit)*/
const unsigned char E8_bitslice_roundconstant[42][32]={
{0x72,0xd5,0xde,0xa2,0xdf,0x15,0xf8,0x67,0x7b,0x84,0x15,0xa,0xb7,0x23,0x15,0x57,0x81,0xab,0xd6,0x90,0x4d,0x5a,0x87,0xf6,0x4e,0x9f,0x4f,0xc5,0xc3,0xd1,0x2b,0x40},
{0xea,0x98,0x3a,0xe0,0x5c,0x45,0xfa,0x9c,0x3,0xc5,0xd2,0x99,0x66,0xb2,0x99,0x9a,0x66,0x2,0x96,0xb4,0xf2,0xbb,0x53,0x8a,0xb5,0x56,0x14,0x1a,0x88,0xdb,0xa2,0x31},
{0x3,0xa3,0x5a,0x5c,0x9a,0x19,0xe,0xdb,0x40,0x3f,0xb2,0xa,0x87,0xc1,0x44,0x10,0x1c,0x5,0x19,0x80,0x84,0x9e,0x95,0x1d,0x6f,0x33,0xeb,0xad,0x5e,0xe7,0xcd,0xdc},
{0x10,0xba,0x13,0x92,0x2,0xbf,0x6b,0x41,0xdc,0x78,0x65,0x15,0xf7,0xbb,0x27,0xd0,0xa,0x2c,0x81,0x39,0x37,0xaa,0x78,0x50,0x3f,0x1a,0xbf,0xd2,0x41,0x0,0x91,0xd3},
{0x42,0x2d,0x5a,0xd,0xf6,0xcc,0x7e,0x90,0xdd,0x62,0x9f,0x9c,0x92,0xc0,0x97,0xce,0x18,0x5c,0xa7,0xb,0xc7,0x2b,0x44,0xac,0xd1,0xdf,0x65,0xd6,0x63,0xc6,0xfc,0x23},
{0x97,0x6e,0x6c,0x3,0x9e,0xe0,0xb8,0x1a,0x21,0x5,0x45,0x7e,0x44,0x6c,0xec,0xa8,0xee,0xf1,0x3,0xbb,0x5d,0x8e,0x61,0xfa,0xfd,0x96,0x97,0xb2,0x94,0x83,0x81,0x97},
{0x4a,0x8e,0x85,0x37,0xdb,0x3,0x30,0x2f,0x2a,0x67,0x8d,0x2d,0xfb,0x9f,0x6a,0x95,0x8a,0xfe,0x73,0x81,0xf8,0xb8,0x69,0x6c,0x8a,0xc7,0x72,0x46,0xc0,0x7f,0x42,0x14},
{0xc5,0xf4,0x15,0x8f,0xbd,0xc7,0x5e,0xc4,0x75,0x44,0x6f,0xa7,0x8f,0x11,0xbb,0x80,0x52,0xde,0x75,0xb7,0xae,0xe4,0x88,0xbc,0x82,0xb8,0x0,0x1e,0x98,0xa6,0xa3,0xf4},
{0x8e,0xf4,0x8f,0x33,0xa9,0xa3,0x63,0x15,0xaa,0x5f,0x56,0x24,0xd5,0xb7,0xf9,0x89,0xb6,0xf1,0xed,0x20,0x7c,0x5a,0xe0,0xfd,0x36,0xca,0xe9,0x5a,0x6,0x42,0x2c,0x36},
{0xce,0x29,0x35,0x43,0x4e,0xfe,0x98,0x3d,0x53,0x3a,0xf9,0x74,0x73,0x9a,0x4b,0xa7,0xd0,0xf5,0x1f,0x59,0x6f,0x4e,0x81,0x86,0xe,0x9d,0xad,0x81,0xaf,0xd8,0x5a,0x9f},
{0xa7,0x5,0x6,0x67,0xee,0x34,0x62,0x6a,0x8b,0xb,0x28,0xbe,0x6e,0xb9,0x17,0x27,0x47,0x74,0x7,0x26,0xc6,0x80,0x10,0x3f,0xe0,0xa0,0x7e,0x6f,0xc6,0x7e,0x48,0x7b},
{0xd,0x55,0xa,0xa5,0x4a,0xf8,0xa4,0xc0,0x91,0xe3,0xe7,0x9f,0x97,0x8e,0xf1,0x9e,0x86,0x76,0x72,0x81,0x50,0x60,0x8d,0xd4,0x7e,0x9e,0x5a,0x41,0xf3,0xe5,0xb0,0x62},
{0xfc,0x9f,0x1f,0xec,0x40,0x54,0x20,0x7a,0xe3,0xe4,0x1a,0x0,0xce,0xf4,0xc9,0x84,0x4f,0xd7,0x94,0xf5,0x9d,0xfa,0x95,0xd8,0x55,0x2e,0x7e,0x11,0x24,0xc3,0x54,0xa5},
{0x5b,0xdf,0x72,0x28,0xbd,0xfe,0x6e,0x28,0x78,0xf5,0x7f,0xe2,0xf,0xa5,0xc4,0xb2,0x5,0x89,0x7c,0xef,0xee,0x49,0xd3,0x2e,0x44,0x7e,0x93,0x85,0xeb,0x28,0x59,0x7f},
{0x70,0x5f,0x69,0x37,0xb3,0x24,0x31,0x4a,0x5e,0x86,0x28,0xf1,0x1d,0xd6,0xe4,0x65,0xc7,0x1b,0x77,0x4,0x51,0xb9,0x20,0xe7,0x74,0xfe,0x43,0xe8,0x23,0xd4,0x87,0x8a},
{0x7d,0x29,0xe8,0xa3,0x92,0x76,0x94,0xf2,0xdd,0xcb,0x7a,0x9,0x9b,0x30,0xd9,0xc1,0x1d,0x1b,0x30,0xfb,0x5b,0xdc,0x1b,0xe0,0xda,0x24,0x49,0x4f,0xf2,0x9c,0x82,0xbf},
{0xa4,0xe7,0xba,0x31,0xb4,0x70,0xbf,0xff,0xd,0x32,0x44,0x5,0xde,0xf8,0xbc,0x48,0x3b,0xae,0xfc,0x32,0x53,0xbb,0xd3,0x39,0x45,0x9f,0xc3,0xc1,0xe0,0x29,0x8b,0xa0},
{0xe5,0xc9,0x5,0xfd,0xf7,0xae,0x9,0xf,0x94,0x70,0x34,0x12,0x42,0x90,0xf1,0x34,0xa2,0x71,0xb7,0x1,0xe3,0x44,0xed,0x95,0xe9,0x3b,0x8e,0x36,0x4f,0x2f,0x98,0x4a},
{0x88,0x40,0x1d,0x63,0xa0,0x6c,0xf6,0x15,0x47,0xc1,0x44,0x4b,0x87,0x52,0xaf,0xff,0x7e,0xbb,0x4a,0xf1,0xe2,0xa,0xc6,0x30,0x46,0x70,0xb6,0xc5,0xcc,0x6e,0x8c,0xe6},
{0xa4,0xd5,0xa4,0x56,0xbd,0x4f,0xca,0x0,0xda,0x9d,0x84,0x4b,0xc8,0x3e,0x18,0xae,0x73,0x57,0xce,0x45,0x30,0x64,0xd1,0xad,0xe8,0xa6,0xce,0x68,0x14,0x5c,0x25,0x67},
{0xa3,0xda,0x8c,0xf2,0xcb,0xe,0xe1,0x16,0x33,0xe9,0x6,0x58,0x9a,0x94,0x99,0x9a,0x1f,0x60,0xb2,0x20,0xc2,0x6f,0x84,0x7b,0xd1,0xce,0xac,0x7f,0xa0,0xd1,0x85,0x18},
{0x32,0x59,0x5b,0xa1,0x8d,0xdd,0x19,0xd3,0x50,0x9a,0x1c,0xc0,0xaa,0xa5,0xb4,0x46,0x9f,0x3d,0x63,0x67,0xe4,0x4,0x6b,0xba,0xf6,0xca,0x19,0xab,0xb,0x56,0xee,0x7e},
{0x1f,0xb1,0x79,0xea,0xa9,0x28,0x21,0x74,0xe9,0xbd,0xf7,0x35,0x3b,0x36,0x51,0xee,0x1d,0x57,0xac,0x5a,0x75,0x50,0xd3,0x76,0x3a,0x46,0xc2,0xfe,0xa3,0x7d,0x70,0x1},
{0xf7,0x35,0xc1,0xaf,0x98,0xa4,0xd8,0x42,0x78,0xed,0xec,0x20,0x9e,0x6b,0x67,0x79,0x41,0x83,0x63,0x15,0xea,0x3a,0xdb,0xa8,0xfa,0xc3,0x3b,0x4d,0x32,0x83,0x2c,0x83},
{0xa7,0x40,0x3b,0x1f,0x1c,0x27,0x47,0xf3,0x59,0x40,0xf0,0x34,0xb7,0x2d,0x76,0x9a,0xe7,0x3e,0x4e,0x6c,0xd2,0x21,0x4f,0xfd,0xb8,0xfd,0x8d,0x39,0xdc,0x57,0x59,0xef},
{0x8d,0x9b,0xc,0x49,0x2b,0x49,0xeb,0xda,0x5b,0xa2,0xd7,0x49,0x68,0xf3,0x70,0xd,0x7d,0x3b,0xae,0xd0,0x7a,0x8d,0x55,0x84,0xf5,0xa5,0xe9,0xf0,0xe4,0xf8,0x8e,0x65},
{0xa0,0xb8,0xa2,0xf4,0x36,0x10,0x3b,0x53,0xc,0xa8,0x7,0x9e,0x75,0x3e,0xec,0x5a,0x91,0x68,0x94,0x92,0x56,0xe8,0x88,0x4f,0x5b,0xb0,0x5c,0x55,0xf8,0xba,0xbc,0x4c},
{0xe3,0xbb,0x3b,0x99,0xf3,0x87,0x94,0x7b,0x75,0xda,0xf4,0xd6,0x72,0x6b,0x1c,0x5d,0x64,0xae,0xac,0x28,0xdc,0x34,0xb3,0x6d,0x6c,0x34,0xa5,0x50,0xb8,0x28,0xdb,0x71},
{0xf8,0x61,0xe2,0xf2,0x10,0x8d,0x51,0x2a,0xe3,0xdb,0x64,0x33,0x59,0xdd,0x75,0xfc,0x1c,0xac,0xbc,0xf1,0x43,0xce,0x3f,0xa2,0x67,0xbb,0xd1,0x3c,0x2,0xe8,0x43,0xb0},
{0x33,0xa,0x5b,0xca,0x88,0x29,0xa1,0x75,0x7f,0x34,0x19,0x4d,0xb4,0x16,0x53,0x5c,0x92,0x3b,0x94,0xc3,0xe,0x79,0x4d,0x1e,0x79,0x74,0x75,0xd7,0xb6,0xee,0xaf,0x3f},
{0xea,0xa8,0xd4,0xf7,0xbe,0x1a,0x39,0x21,0x5c,0xf4,0x7e,0x9,0x4c,0x23,0x27,0x51,0x26,0xa3,0x24,0x53,0xba,0x32,0x3c,0xd2,0x44,0xa3,0x17,0x4a,0x6d,0xa6,0xd5,0xad},
{0xb5,0x1d,0x3e,0xa6,0xaf,0xf2,0xc9,0x8,0x83,0x59,0x3d,0x98,0x91,0x6b,0x3c,0x56,0x4c,0xf8,0x7c,0xa1,0x72,0x86,0x60,0x4d,0x46,0xe2,0x3e,0xcc,0x8,0x6e,0xc7,0xf6},
{0x2f,0x98,0x33,0xb3,0xb1,0xbc,0x76,0x5e,0x2b,0xd6,0x66,0xa5,0xef,0xc4,0xe6,0x2a,0x6,0xf4,0xb6,0xe8,0xbe,0xc1,0xd4,0x36,0x74,0xee,0x82,0x15,0xbc,0xef,0x21,0x63},
{0xfd,0xc1,0x4e,0xd,0xf4,0x53,0xc9,0x69,0xa7,0x7d,0x5a,0xc4,0x6,0x58,0x58,0x26,0x7e,0xc1,0x14,0x16,0x6,0xe0,0xfa,0x16,0x7e,0x90,0xaf,0x3d,0x28,0x63,0x9d,0x3f},
{0xd2,0xc9,0xf2,0xe3,0x0,0x9b,0xd2,0xc,0x5f,0xaa,0xce,0x30,0xb7,0xd4,0xc,0x30,0x74,0x2a,0x51,0x16,0xf2,0xe0,0x32,0x98,0xd,0xeb,0x30,0xd8,0xe3,0xce,0xf8,0x9a},
{0x4b,0xc5,0x9e,0x7b,0xb5,0xf1,0x79,0x92,0xff,0x51,0xe6,0x6e,0x4,0x86,0x68,0xd3,0x9b,0x23,0x4d,0x57,0xe6,0x96,0x67,0x31,0xcc,0xe6,0xa6,0xf3,0x17,0xa,0x75,0x5},
{0xb1,0x76,0x81,0xd9,0x13,0x32,0x6c,0xce,0x3c,0x17,0x52,0x84,0xf8,0x5,0xa2,0x62,0xf4,0x2b,0xcb,0xb3,0x78,0x47,0x15,0x47,0xff,0x46,0x54,0x82,0x23,0x93,0x6a,0x48},
{0x38,0xdf,0x58,0x7,0x4e,0x5e,0x65,0x65,0xf2,0xfc,0x7c,0x89,0xfc,0x86,0x50,0x8e,0x31,0x70,0x2e,0x44,0xd0,0xb,0xca,0x86,0xf0,0x40,0x9,0xa2,0x30,0x78,0x47,0x4e},
{0x65,0xa0,0xee,0x39,0xd1,0xf7,0x38,0x83,0xf7,0x5e,0xe9,0x37,0xe4,0x2c,0x3a,0xbd,0x21,0x97,0xb2,0x26,0x1,0x13,0xf8,0x6f,0xa3,0x44,0xed,0xd1,0xef,0x9f,0xde,0xe7},
{0x8b,0xa0,0xdf,0x15,0x76,0x25,0x92,0xd9,0x3c,0x85,0xf7,0xf6,0x12,0xdc,0x42,0xbe,0xd8,0xa7,0xec,0x7c,0xab,0x27,0xb0,0x7e,0x53,0x8d,0x7d,0xda,0xaa,0x3e,0xa8,0xde},
{0xaa,0x25,0xce,0x93,0xbd,0x2,0x69,0xd8,0x5a,0xf6,0x43,0xfd,0x1a,0x73,0x8,0xf9,0xc0,0x5f,0xef,0xda,0x17,0x4a,0x19,0xa5,0x97,0x4d,0x66,0x33,0x4c,0xfd,0x21,0x6a},
{0x35,0xb4,0x98,0x31,0xdb,0x41,0x15,0x70,0xea,0x1e,0xf,0xbb,0xed,0xcd,0x54,0x9b,0x9a,0xd0,0x63,0xa1,0x51,0x97,0x40,0x72,0xf6,0x75,0x9d,0xbf,0x91,0x47,0x6f,0xe2}};
static void E8(hashState *state); /*The bijective function E8, in bitslice form*/
static void F8(hashState *state); /*The compression function F8 */
/*The API functions*/
static HashReturn Init(hashState *state, int hashbitlen);
static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen);
static HashReturn Final(hashState *state, BitSequence *hashval);
HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval);
/*swapping bit 2i with bit 2i+1 of 64-bit x*/
#define SWAP1(x) (x) = ((((x) & 0x5555555555555555ULL) << 1) | (((x) & 0xaaaaaaaaaaaaaaaaULL) >> 1));
/*swapping bits 4i||4i+1 with bits 4i+2||4i+3 of 64-bit x*/
#define SWAP2(x) (x) = ((((x) & 0x3333333333333333ULL) << 2) | (((x) & 0xccccccccccccccccULL) >> 2));
/*swapping bits 8i||8i+1||8i+2||8i+3 with bits 8i+4||8i+5||8i+6||8i+7 of 64-bit x*/
#define SWAP4(x) (x) = ((((x) & 0x0f0f0f0f0f0f0f0fULL) << 4) | (((x) & 0xf0f0f0f0f0f0f0f0ULL) >> 4));
/*swapping bits 16i||16i+1||......||16i+7 with bits 16i+8||16i+9||......||16i+15 of 64-bit x*/
#define SWAP8(x) (x) = ((((x) & 0x00ff00ff00ff00ffULL) << 8) | (((x) & 0xff00ff00ff00ff00ULL) >> 8));
/*swapping bits 32i||32i+1||......||32i+15 with bits 32i+16||32i+17||......||32i+31 of 64-bit x*/
#define SWAP16(x) (x) = ((((x) & 0x0000ffff0000ffffULL) << 16) | (((x) & 0xffff0000ffff0000ULL) >> 16));
/*swapping bits 64i||64i+1||......||64i+31 with bits 64i+32||64i+33||......||64i+63 of 64-bit x*/
#define SWAP32(x) (x) = (((x) << 32) | ((x) >> 32));
/*The MDS transform*/
#define L(m0,m1,m2,m3,m4,m5,m6,m7) \
(m4) ^= (m1); \
(m5) ^= (m2); \
(m6) ^= (m0) ^ (m3); \
(m7) ^= (m0); \
(m0) ^= (m5); \
(m1) ^= (m6); \
(m2) ^= (m4) ^ (m7); \
(m3) ^= (m4);
/*Two Sboxes are computed in parallel, each Sbox implements S0 and S1, selected by a constant bit*/
/*The reason to compute two Sboxes in parallel is to try to fully utilize the parallel processing power*/
#define SS(m0,m1,m2,m3,m4,m5,m6,m7,cc0,cc1) \
m3 = ~(m3); \
m7 = ~(m7); \
m0 ^= ((~(m2)) & (cc0)); \
m4 ^= ((~(m6)) & (cc1)); \
temp0 = (cc0) ^ ((m0) & (m1));\
temp1 = (cc1) ^ ((m4) & (m5));\
m0 ^= ((m2) & (m3)); \
m4 ^= ((m6) & (m7)); \
m3 ^= ((~(m1)) & (m2)); \
m7 ^= ((~(m5)) & (m6)); \
m1 ^= ((m0) & (m2)); \
m5 ^= ((m4) & (m6)); \
m2 ^= ((m0) & (~(m3))); \
m6 ^= ((m4) & (~(m7))); \
m0 ^= ((m1) | (m3)); \
m4 ^= ((m5) | (m7)); \
m3 ^= ((m1) & (m2)); \
m7 ^= ((m5) & (m6)); \
m1 ^= (temp0 & (m0)); \
m5 ^= (temp1 & (m4)); \
m2 ^= temp0; \
m6 ^= temp1;
/*The bijective function E8, in bitslice form*/
static void E8(hashState *state)
{
uint64 i,roundnumber,temp0,temp1;
for (roundnumber = 0; roundnumber < 42; roundnumber = roundnumber+7) {
/*round 7*roundnumber+0: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP1(state->x[1][i]); SWAP1(state->x[3][i]); SWAP1(state->x[5][i]); SWAP1(state->x[7][i]);
}
/*round 7*roundnumber+1: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP2(state->x[1][i]); SWAP2(state->x[3][i]); SWAP2(state->x[5][i]); SWAP2(state->x[7][i]);
}
/*round 7*roundnumber+2: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP4(state->x[1][i]); SWAP4(state->x[3][i]); SWAP4(state->x[5][i]); SWAP4(state->x[7][i]);
}
/*round 7*roundnumber+3: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP8(state->x[1][i]); SWAP8(state->x[3][i]); SWAP8(state->x[5][i]); SWAP8(state->x[7][i]);
}
/*round 7*roundnumber+4: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP16(state->x[1][i]); SWAP16(state->x[3][i]); SWAP16(state->x[5][i]); SWAP16(state->x[7][i]);
}
/*round 7*roundnumber+5: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP32(state->x[1][i]); SWAP32(state->x[3][i]); SWAP32(state->x[5][i]); SWAP32(state->x[7][i]);
}
/*round 7*roundnumber+6: Sbox and MDS layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
}
/*round 7*roundnumber+6: swapping layer*/
for (i = 1; i < 8; i = i+2) {
temp0 = state->x[i][0]; state->x[i][0] = state->x[i][1]; state->x[i][1] = temp0;
}
}
}
/*The compression function F8 */
static void F8(hashState *state)
{
uint64 i;
/*xor the 512-bit message with the fist half of the 1024-bit hash state*/
for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i];
/*the bijective function E8 */
E8(state);
/*xor the 512-bit message with the second half of the 1024-bit hash state*/
for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i];
}
/*before hashing a message, initialize the hash state as H0 */
static HashReturn Init(hashState *state, int hashbitlen)
{
state->databitlen = 0;
state->datasize_in_buffer = 0;
/*initialize the initial hash value of JH*/
state->hashbitlen = hashbitlen;
/*load the intital hash value into state*/
switch (hashbitlen)
{
case 224: memcpy(state->x,JH224_H0,128); break;
case 256: memcpy(state->x,JH256_H0,128); break;
case 384: memcpy(state->x,JH384_H0,128); break;
case 512: memcpy(state->x,JH512_H0,128); break;
}
return(SUCCESS);
}
/*hash each 512-bit message block, except the last partial block*/
static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen)
{
DataLength index; /*the starting address of the data to be compressed*/
state->databitlen += databitlen;
index = 0;
/*if there is remaining data in the buffer, fill it to a full message block first*/
/*we assume that the size of the data in the buffer is the multiple of 8 bits if it is not at the end of a message*/
/*There is data in the buffer, but the incoming data is insufficient for a full block*/
if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512) ) {
if ( (databitlen & 7) == 0 ) {
memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ;
}
else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ;
state->datasize_in_buffer += databitlen;
databitlen = 0;
}
/*There is data in the buffer, and the incoming data is sufficient for a full block*/
if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512) ) {
memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ;
index = 64-(state->datasize_in_buffer >> 3);
databitlen = databitlen - (512 - state->datasize_in_buffer);
F8(state);
state->datasize_in_buffer = 0;
}
/*hash the remaining full message blocks*/
for ( ; databitlen >= 512; index = index+64, databitlen = databitlen - 512) {
memcpy(state->buffer, data+index, 64);
F8(state);
}
/*store the partial block into buffer, assume that -- if part of the last byte is not part of the message, then that part consists of 0 bits*/
if ( databitlen > 0) {
if ((databitlen & 7) == 0)
memcpy(state->buffer, data+index, (databitlen & 0x1ff) >> 3);
else
memcpy(state->buffer, data+index, ((databitlen & 0x1ff) >> 3)+1);
state->datasize_in_buffer = databitlen;
}
return(SUCCESS);
}
/*pad the message, process the padded block(s), truncate the hash value H to obtain the message digest*/
static HashReturn Final(hashState *state, BitSequence *hashval)
{
unsigned int i;
if ( (state->databitlen & 0x1ff) == 0 ) {
/*pad the message when databitlen is multiple of 512 bits, then process the padded block*/
memset(state->buffer, 0, 64);
state->buffer[0] = 0x80;
state->buffer[63] = state->databitlen & 0xff;
state->buffer[62] = (state->databitlen >> 8) & 0xff;
state->buffer[61] = (state->databitlen >> 16) & 0xff;
state->buffer[60] = (state->databitlen >> 24) & 0xff;
state->buffer[59] = (state->databitlen >> 32) & 0xff;
state->buffer[58] = (state->databitlen >> 40) & 0xff;
state->buffer[57] = (state->databitlen >> 48) & 0xff;
state->buffer[56] = (state->databitlen >> 56) & 0xff;
F8(state);
}
else {
/*set the rest of the bytes in the buffer to 0*/
if ( (state->datasize_in_buffer & 7) == 0)
for (i = (state->databitlen & 0x1ff) >> 3; i < 64; i++) state->buffer[i] = 0;
else
for (i = ((state->databitlen & 0x1ff) >> 3)+1; i < 64; i++) state->buffer[i] = 0;
/*pad and process the partial block when databitlen is not multiple of 512 bits, then hash the padded blocks*/
state->buffer[((state->databitlen & 0x1ff) >> 3)] |= 1 << (7- (state->databitlen & 7));
F8(state);
memset(state->buffer, 0, 64);
state->buffer[63] = state->databitlen & 0xff;
state->buffer[62] = (state->databitlen >> 8) & 0xff;
state->buffer[61] = (state->databitlen >> 16) & 0xff;
state->buffer[60] = (state->databitlen >> 24) & 0xff;
state->buffer[59] = (state->databitlen >> 32) & 0xff;
state->buffer[58] = (state->databitlen >> 40) & 0xff;
state->buffer[57] = (state->databitlen >> 48) & 0xff;
state->buffer[56] = (state->databitlen >> 56) & 0xff;
F8(state);
}
/*truncating the final hash value to generate the message digest*/
switch(state->hashbitlen) {
case 224: memcpy(hashval,(unsigned char*)state->x+64+36,28); break;
case 256: memcpy(hashval,(unsigned char*)state->x+64+32,32); break;
case 384: memcpy(hashval,(unsigned char*)state->x+64+16,48); break;
case 512: memcpy(hashval,(unsigned char*)state->x+64,64); break;
}
return(SUCCESS);
}
/* hash a message,
three inputs: message digest size in bits (hashbitlen); message (data); message length in bits (databitlen)
one output: message digest (hashval)
*/
HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval)
{
hashState state;
if ( hashbitlen == 224 || hashbitlen == 256 || hashbitlen == 384 || hashbitlen == 512 ) {
Init(&state, hashbitlen);
Update(&state, data, databitlen);
Final(&state, hashval);
return SUCCESS;
}
else
return(BAD_HASHLEN);
}
================================================
FILE: crypto/c_jh.h
================================================
/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C
--------------------------------
Performance
Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz)
Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic)
Speed for long message:
1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2
2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3
--------------------------------
Last Modified: January 16, 2011
*/
#pragma once
#include "hash.h"
HashReturn jh_hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval);
================================================
FILE: crypto/c_keccak.c
================================================
// keccak.c
// 19-Nov-11 Markku-Juhani O. Saarinen
// A baseline Keccak (3rd round) implementation.
#include
#include
#define HASH_DATA_AREA 136
#define KECCAK_ROUNDS 24
#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
const uint64_t keccakf_rndc[24] =
{
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};
const int keccakf_rotc[24] =
{
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
};
const int keccakf_piln[24] =
{
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
};
// update the state with given number of rounds
void keccakf(uint64_t st[25], int rounds)
{
int i, j, round;
uint64_t t, bc[5];
for (round = 0; round < rounds; ++round) {
// Theta
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
for (i = 0; i < 5; ++i) {
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
st[i ] ^= t;
st[i + 5] ^= t;
st[i + 10] ^= t;
st[i + 15] ^= t;
st[i + 20] ^= t;
}
// Rho Pi
t = st[1];
for (i = 0; i < 24; ++i) {
bc[0] = st[keccakf_piln[i]];
st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]);
t = bc[0];
}
// Chi
for (j = 0; j < 25; j += 5) {
bc[0] = st[j ];
bc[1] = st[j + 1];
bc[2] = st[j + 2];
bc[3] = st[j + 3];
bc[4] = st[j + 4];
st[j ] ^= (~bc[1]) & bc[2];
st[j + 1] ^= (~bc[2]) & bc[3];
st[j + 2] ^= (~bc[3]) & bc[4];
st[j + 3] ^= (~bc[4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
}
// Iota
st[0] ^= keccakf_rndc[round];
}
}
// compute a keccak hash (md) of given byte length from "in"
typedef uint64_t state_t[25];
void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen)
{
state_t st;
uint8_t temp[144];
int i, rsiz, rsizw;
rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen;
rsizw = rsiz / 8;
memset(st, 0, sizeof(st));
for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) {
for (i = 0; i < rsizw; i++)
st[i] ^= ((uint64_t *) in)[i];
keccakf(st, KECCAK_ROUNDS);
}
// last block and padding
memcpy(temp, in, inlen);
temp[inlen++] = 1;
memset(temp + inlen, 0, rsiz - inlen);
temp[rsiz - 1] |= 0x80;
for (i = 0; i < rsizw; i++)
st[i] ^= ((uint64_t *) temp)[i];
keccakf(st, KECCAK_ROUNDS);
memcpy(md, st, mdlen);
}
void keccak1600(const uint8_t *in, int inlen, uint8_t *md)
{
keccak(in, inlen, md, sizeof(state_t));
}
================================================
FILE: crypto/c_keccak.h
================================================
// keccak.h
// 19-Nov-11 Markku-Juhani O. Saarinen
#ifndef KECCAK_H
#define KECCAK_H
#include
#include
#ifndef KECCAK_ROUNDS
#define KECCAK_ROUNDS 24
#endif
#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
// compute a keccak hash (md) of given byte length from "in"
int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen);
// update the state
void keccakf(uint64_t st[25], int norounds);
void keccak1600(const uint8_t *in, int inlen, uint8_t *md);
#endif
================================================
FILE: crypto/c_skein.c
================================================
/***********************************************************************
**
** Implementation of the Skein hash function.
**
** Source code author: Doug Whiting, 2008.
**
** This algorithm and source code is released to the public domain.
**
************************************************************************/
#define SKEIN_PORT_CODE /* instantiate any code in skein_port.h */
#include /* get size_t definition */
#include /* get the memcpy/memset functions */
#include "c_skein.h" /* get the Skein API definitions */
#define DISABLE_UNUSED 0
#ifndef SKEIN_256_NIST_MAX_HASHBITS
#define SKEIN_256_NIST_MAX_HASHBITS (0)
#endif
#ifndef SKEIN_512_NIST_MAX_HASHBITS
#define SKEIN_512_NIST_MAX_HASHBITS (512)
#endif
#define SKEIN_MODIFIER_WORDS ( 2) /* number of modifier (tweak) words */
#define SKEIN_256_STATE_WORDS ( 4)
#define SKEIN_512_STATE_WORDS ( 8)
#define SKEIN1024_STATE_WORDS (16)
#define SKEIN_MAX_STATE_WORDS (16)
#define SKEIN_256_STATE_BYTES ( 8*SKEIN_256_STATE_WORDS)
#define SKEIN_512_STATE_BYTES ( 8*SKEIN_512_STATE_WORDS)
#define SKEIN1024_STATE_BYTES ( 8*SKEIN1024_STATE_WORDS)
#define SKEIN_256_STATE_BITS (64*SKEIN_256_STATE_WORDS)
#define SKEIN_512_STATE_BITS (64*SKEIN_512_STATE_WORDS)
#define SKEIN1024_STATE_BITS (64*SKEIN1024_STATE_WORDS)
#define SKEIN_256_BLOCK_BYTES ( 8*SKEIN_256_STATE_WORDS)
#define SKEIN_512_BLOCK_BYTES ( 8*SKEIN_512_STATE_WORDS)
#define SKEIN1024_BLOCK_BYTES ( 8*SKEIN1024_STATE_WORDS)
#define SKEIN_RND_SPECIAL (1000u)
#define SKEIN_RND_KEY_INITIAL (SKEIN_RND_SPECIAL+0u)
#define SKEIN_RND_KEY_INJECT (SKEIN_RND_SPECIAL+1u)
#define SKEIN_RND_FEED_FWD (SKEIN_RND_SPECIAL+2u)
typedef struct
{
size_t hashBitLen; /* size of hash result, in bits */
size_t bCnt; /* current byte count in buffer b[] */
u64b_t T[SKEIN_MODIFIER_WORDS]; /* tweak words: T[0]=byte cnt, T[1]=flags */
} Skein_Ctxt_Hdr_t;
typedef struct /* 256-bit Skein hash context structure */
{
Skein_Ctxt_Hdr_t h; /* common header context variables */
u64b_t X[SKEIN_256_STATE_WORDS]; /* chaining variables */
u08b_t b[SKEIN_256_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */
} Skein_256_Ctxt_t;
typedef struct /* 512-bit Skein hash context structure */
{
Skein_Ctxt_Hdr_t h; /* common header context variables */
u64b_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */
u08b_t b[SKEIN_512_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */
} Skein_512_Ctxt_t;
typedef struct /* 1024-bit Skein hash context structure */
{
Skein_Ctxt_Hdr_t h; /* common header context variables */
u64b_t X[SKEIN1024_STATE_WORDS]; /* chaining variables */
u08b_t b[SKEIN1024_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */
} Skein1024_Ctxt_t;
/* Skein APIs for (incremental) "straight hashing" */
#if SKEIN_256_NIST_MAX_HASH_BITS
static int Skein_256_Init (Skein_256_Ctxt_t *ctx, size_t hashBitLen);
#endif
static int Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen);
static int Skein1024_Init (Skein1024_Ctxt_t *ctx, size_t hashBitLen);
static int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
static int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
static int Skein_256_Final (Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
static int Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
static int Skein1024_Final (Skein1024_Ctxt_t *ctx, u08b_t * hashVal);
/*
** Skein APIs for "extended" initialization: MAC keys, tree hashing.
** After an InitExt() call, just use Update/Final calls as with Init().
**
** Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes.
** When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL,
** the results of InitExt() are identical to calling Init().
** The function Init() may be called once to "precompute" the IV for
** a given hashBitLen value, then by saving a copy of the context
** the IV computation may be avoided in later calls.
** Similarly, the function InitExt() may be called once per MAC key
** to precompute the MAC IV, then a copy of the context saved and
** reused for each new MAC computation.
**/
#if 0
static int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
static int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
static int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
#endif
/*
** Skein APIs for MAC and tree hash:
** Final_Pad: pad, do final block, but no OUTPUT type
** Output: do just the output stage
*/
#if 0
static int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
static int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
static int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t * hashVal);
#endif
#ifndef SKEIN_TREE_HASH
#define SKEIN_TREE_HASH (1)
#endif
#if 0
#if SKEIN_TREE_HASH
static int Skein_256_Output (Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
static int Skein_512_Output (Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
static int Skein1024_Output (Skein1024_Ctxt_t *ctx, u08b_t * hashVal);
#endif
#endif
/*****************************************************************
** "Internal" Skein definitions
** -- not needed for sequential hashing API, but will be
** helpful for other uses of Skein (e.g., tree hash mode).
** -- included here so that they can be shared between
** reference and optimized code.
******************************************************************/
/* tweak word T[1]: bit field starting positions */
#define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* offset 64 because it's the second word */
#define SKEIN_T1_POS_TREE_LVL SKEIN_T1_BIT(112) /* bits 112..118: level in hash tree */
#define SKEIN_T1_POS_BIT_PAD SKEIN_T1_BIT(119) /* bit 119 : partial final input byte */
#define SKEIN_T1_POS_BLK_TYPE SKEIN_T1_BIT(120) /* bits 120..125: type field */
#define SKEIN_T1_POS_FIRST SKEIN_T1_BIT(126) /* bits 126 : first block flag */
#define SKEIN_T1_POS_FINAL SKEIN_T1_BIT(127) /* bit 127 : final block flag */
/* tweak word T[1]: flag bit definition(s) */
#define SKEIN_T1_FLAG_FIRST (((u64b_t) 1 ) << SKEIN_T1_POS_FIRST)
#define SKEIN_T1_FLAG_FINAL (((u64b_t) 1 ) << SKEIN_T1_POS_FINAL)
#define SKEIN_T1_FLAG_BIT_PAD (((u64b_t) 1 ) << SKEIN_T1_POS_BIT_PAD)
/* tweak word T[1]: tree level bit field mask */
#define SKEIN_T1_TREE_LVL_MASK (((u64b_t)0x7F) << SKEIN_T1_POS_TREE_LVL)
#define SKEIN_T1_TREE_LEVEL(n) (((u64b_t) (n)) << SKEIN_T1_POS_TREE_LVL)
/* tweak word T[1]: block type field */
#define SKEIN_BLK_TYPE_KEY ( 0) /* key, for MAC and KDF */
#define SKEIN_BLK_TYPE_CFG ( 4) /* configuration block */
#define SKEIN_BLK_TYPE_PERS ( 8) /* personalization string */
#define SKEIN_BLK_TYPE_PK (12) /* public key (for digital signature hashing) */
#define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */
#define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */
#define SKEIN_BLK_TYPE_MSG (48) /* message processing */
#define SKEIN_BLK_TYPE_OUT (63) /* output stage */
#define SKEIN_BLK_TYPE_MASK (63) /* bit field mask */
#define SKEIN_T1_BLK_TYPE(T) (((u64b_t) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE)
#define SKEIN_T1_BLK_TYPE_KEY SKEIN_T1_BLK_TYPE(KEY) /* key, for MAC and KDF */
#define SKEIN_T1_BLK_TYPE_CFG SKEIN_T1_BLK_TYPE(CFG) /* configuration block */
#define SKEIN_T1_BLK_TYPE_PERS SKEIN_T1_BLK_TYPE(PERS) /* personalization string */
#define SKEIN_T1_BLK_TYPE_PK SKEIN_T1_BLK_TYPE(PK) /* public key (for digital signature hashing) */
#define SKEIN_T1_BLK_TYPE_KDF SKEIN_T1_BLK_TYPE(KDF) /* key identifier for KDF */
#define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */
#define SKEIN_T1_BLK_TYPE_MSG SKEIN_T1_BLK_TYPE(MSG) /* message processing */
#define SKEIN_T1_BLK_TYPE_OUT SKEIN_T1_BLK_TYPE(OUT) /* output stage */
#define SKEIN_T1_BLK_TYPE_MASK SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */
#define SKEIN_T1_BLK_TYPE_CFG_FINAL (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL)
#define SKEIN_T1_BLK_TYPE_OUT_FINAL (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL)
#define SKEIN_VERSION (1)
#ifndef SKEIN_ID_STRING_LE /* allow compile-time personalization */
#define SKEIN_ID_STRING_LE (0x33414853) /* "SHA3" (little-endian)*/
#endif
#define SKEIN_MK_64(hi32,lo32) ((lo32) + (((u64b_t) (hi32)) << 32))
#define SKEIN_SCHEMA_VER SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE)
#define SKEIN_KS_PARITY SKEIN_MK_64(0x1BD11BDA,0xA9FC1A22)
#define SKEIN_CFG_STR_LEN (4*8)
/* bit field definitions in config block treeInfo word */
#define SKEIN_CFG_TREE_LEAF_SIZE_POS ( 0)
#define SKEIN_CFG_TREE_NODE_SIZE_POS ( 8)
#define SKEIN_CFG_TREE_MAX_LEVEL_POS (16)
#define SKEIN_CFG_TREE_LEAF_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS)
#define SKEIN_CFG_TREE_NODE_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS)
#define SKEIN_CFG_TREE_MAX_LEVEL_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS)
#define SKEIN_CFG_TREE_INFO(leaf,node,maxLvl) \
( (((u64b_t)(leaf )) << SKEIN_CFG_TREE_LEAF_SIZE_POS) | \
(((u64b_t)(node )) << SKEIN_CFG_TREE_NODE_SIZE_POS) | \
(((u64b_t)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS) )
#define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0,0,0) /* use as treeInfo in InitExt() call for sequential processing */
/*
** Skein macros for getting/setting tweak words, etc.
** These are useful for partial input bytes, hash tree init/update, etc.
**/
#define Skein_Get_Tweak(ctxPtr,TWK_NUM) ((ctxPtr)->h.T[TWK_NUM])
#define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal) {(ctxPtr)->h.T[TWK_NUM] = (tVal);}
#define Skein_Get_T0(ctxPtr) Skein_Get_Tweak(ctxPtr,0)
#define Skein_Get_T1(ctxPtr) Skein_Get_Tweak(ctxPtr,1)
#define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0)
#define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1)
/* set both tweak words at once */
#define Skein_Set_T0_T1(ctxPtr,T0,T1) \
{ \
Skein_Set_T0(ctxPtr,(T0)); \
Skein_Set_T1(ctxPtr,(T1)); \
}
#define Skein_Set_Type(ctxPtr,BLK_TYPE) \
Skein_Set_T1(ctxPtr,SKEIN_T1_BLK_TYPE_##BLK_TYPE)
/* set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; */
#define Skein_Start_New_Type(ctxPtr,BLK_TYPE) \
{ Skein_Set_T0_T1(ctxPtr,0,SKEIN_T1_FLAG_FIRST | SKEIN_T1_BLK_TYPE_##BLK_TYPE); (ctxPtr)->h.bCnt=0; }
#define Skein_Clear_First_Flag(hdr) { (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST; }
#define Skein_Set_Bit_Pad_Flag(hdr) { (hdr).T[1] |= SKEIN_T1_FLAG_BIT_PAD; }
#define Skein_Set_Tree_Level(hdr,height) { (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);}
/*****************************************************************
** "Internal" Skein definitions for debugging and error checking
******************************************************************/
#define Skein_Show_Block(bits,ctx,X,blkPtr,wPtr,ksEvenPtr,ksOddPtr)
#define Skein_Show_Round(bits,ctx,r,X)
#define Skein_Show_R_Ptr(bits,ctx,r,X_ptr)
#define Skein_Show_Final(bits,ctx,cnt,outPtr)
#define Skein_Show_Key(bits,ctx,key,keyBytes)
#ifndef SKEIN_ERR_CHECK /* run-time checks (e.g., bad params, uninitialized context)? */
#define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */
#define Skein_assert(x)
#elif defined(SKEIN_ASSERT)
#include
#define Skein_Assert(x,retCode) assert(x)
#define Skein_assert(x) assert(x)
#else
#include
#define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /* caller error */
#define Skein_assert(x) assert(x) /* internal error */
#endif
/*****************************************************************
** Skein block function constants (shared across Ref and Opt code)
******************************************************************/
enum
{
/* Skein_256 round rotation constants */
R_256_0_0=14, R_256_0_1=16,
R_256_1_0=52, R_256_1_1=57,
R_256_2_0=23, R_256_2_1=40,
R_256_3_0= 5, R_256_3_1=37,
R_256_4_0=25, R_256_4_1=33,
R_256_5_0=46, R_256_5_1=12,
R_256_6_0=58, R_256_6_1=22,
R_256_7_0=32, R_256_7_1=32,
/* Skein_512 round rotation constants */
R_512_0_0=46, R_512_0_1=36, R_512_0_2=19, R_512_0_3=37,
R_512_1_0=33, R_512_1_1=27, R_512_1_2=14, R_512_1_3=42,
R_512_2_0=17, R_512_2_1=49, R_512_2_2=36, R_512_2_3=39,
R_512_3_0=44, R_512_3_1= 9, R_512_3_2=54, R_512_3_3=56,
R_512_4_0=39, R_512_4_1=30, R_512_4_2=34, R_512_4_3=24,
R_512_5_0=13, R_512_5_1=50, R_512_5_2=10, R_512_5_3=17,
R_512_6_0=25, R_512_6_1=29, R_512_6_2=39, R_512_6_3=43,
R_512_7_0= 8, R_512_7_1=35, R_512_7_2=56, R_512_7_3=22,
/* Skein1024 round rotation constants */
R1024_0_0=24, R1024_0_1=13, R1024_0_2= 8, R1024_0_3=47, R1024_0_4= 8, R1024_0_5=17, R1024_0_6=22, R1024_0_7=37,
R1024_1_0=38, R1024_1_1=19, R1024_1_2=10, R1024_1_3=55, R1024_1_4=49, R1024_1_5=18, R1024_1_6=23, R1024_1_7=52,
R1024_2_0=33, R1024_2_1= 4, R1024_2_2=51, R1024_2_3=13, R1024_2_4=34, R1024_2_5=41, R1024_2_6=59, R1024_2_7=17,
R1024_3_0= 5, R1024_3_1=20, R1024_3_2=48, R1024_3_3=41, R1024_3_4=47, R1024_3_5=28, R1024_3_6=16, R1024_3_7=25,
R1024_4_0=41, R1024_4_1= 9, R1024_4_2=37, R1024_4_3=31, R1024_4_4=12, R1024_4_5=47, R1024_4_6=44, R1024_4_7=30,
R1024_5_0=16, R1024_5_1=34, R1024_5_2=56, R1024_5_3=51, R1024_5_4= 4, R1024_5_5=53, R1024_5_6=42, R1024_5_7=41,
R1024_6_0=31, R1024_6_1=44, R1024_6_2=47, R1024_6_3=46, R1024_6_4=19, R1024_6_5=42, R1024_6_6=44, R1024_6_7=25,
R1024_7_0= 9, R1024_7_1=48, R1024_7_2=35, R1024_7_3=52, R1024_7_4=23, R1024_7_5=31, R1024_7_6=37, R1024_7_7=20
};
#ifndef SKEIN_ROUNDS
#define SKEIN_256_ROUNDS_TOTAL (72) /* number of rounds for the different block sizes */
#define SKEIN_512_ROUNDS_TOTAL (72)
#define SKEIN1024_ROUNDS_TOTAL (80)
#else /* allow command-line define in range 8*(5..14) */
#define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5))
#define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/ 10) + 5) % 10) + 5))
#define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS ) + 5) % 10) + 5))
#endif
/*
***************** Pre-computed Skein IVs *******************
**
** NOTE: these values are not "magic" constants, but
** are generated using the Threefish block function.
** They are pre-computed here only for speed; i.e., to
** avoid the need for a Threefish call during Init().
**
** The IV for any fixed hash length may be pre-computed.
** Only the most common values are included here.
**
************************************************************
**/
#define MK_64 SKEIN_MK_64
/* blkSize = 256 bits. hashSize = 128 bits */
const u64b_t SKEIN_256_IV_128[] =
{
MK_64(0xE1111906,0x964D7260),
MK_64(0x883DAAA7,0x7C8D811C),
MK_64(0x10080DF4,0x91960F7A),
MK_64(0xCCF7DDE5,0xB45BC1C2)
};
/* blkSize = 256 bits. hashSize = 160 bits */
const u64b_t SKEIN_256_IV_160[] =
{
MK_64(0x14202314,0x72825E98),
MK_64(0x2AC4E9A2,0x5A77E590),
MK_64(0xD47A5856,0x8838D63E),
MK_64(0x2DD2E496,0x8586AB7D)
};
/* blkSize = 256 bits. hashSize = 224 bits */
const u64b_t SKEIN_256_IV_224[] =
{
MK_64(0xC6098A8C,0x9AE5EA0B),
MK_64(0x876D5686,0x08C5191C),
MK_64(0x99CB88D7,0xD7F53884),
MK_64(0x384BDDB1,0xAEDDB5DE)
};
/* blkSize = 256 bits. hashSize = 256 bits */
const u64b_t SKEIN_256_IV_256[] =
{
MK_64(0xFC9DA860,0xD048B449),
MK_64(0x2FCA6647,0x9FA7D833),
MK_64(0xB33BC389,0x6656840F),
MK_64(0x6A54E920,0xFDE8DA69)
};
/* blkSize = 512 bits. hashSize = 128 bits */
const u64b_t SKEIN_512_IV_128[] =
{
MK_64(0xA8BC7BF3,0x6FBF9F52),
MK_64(0x1E9872CE,0xBD1AF0AA),
MK_64(0x309B1790,0xB32190D3),
MK_64(0xBCFBB854,0x3F94805C),
MK_64(0x0DA61BCD,0x6E31B11B),
MK_64(0x1A18EBEA,0xD46A32E3),
MK_64(0xA2CC5B18,0xCE84AA82),
MK_64(0x6982AB28,0x9D46982D)
};
/* blkSize = 512 bits. hashSize = 160 bits */
const u64b_t SKEIN_512_IV_160[] =
{
MK_64(0x28B81A2A,0xE013BD91),
MK_64(0xC2F11668,0xB5BDF78F),
MK_64(0x1760D8F3,0xF6A56F12),
MK_64(0x4FB74758,0x8239904F),
MK_64(0x21EDE07F,0x7EAF5056),
MK_64(0xD908922E,0x63ED70B8),
MK_64(0xB8EC76FF,0xECCB52FA),
MK_64(0x01A47BB8,0xA3F27A6E)
};
/* blkSize = 512 bits. hashSize = 224 bits */
const u64b_t SKEIN_512_IV_224[] =
{
MK_64(0xCCD06162,0x48677224),
MK_64(0xCBA65CF3,0xA92339EF),
MK_64(0x8CCD69D6,0x52FF4B64),
MK_64(0x398AED7B,0x3AB890B4),
MK_64(0x0F59D1B1,0x457D2BD0),
MK_64(0x6776FE65,0x75D4EB3D),
MK_64(0x99FBC70E,0x997413E9),
MK_64(0x9E2CFCCF,0xE1C41EF7)
};
/* blkSize = 512 bits. hashSize = 256 bits */
const u64b_t SKEIN_512_IV_256[] =
{
MK_64(0xCCD044A1,0x2FDB3E13),
MK_64(0xE8359030,0x1A79A9EB),
MK_64(0x55AEA061,0x4F816E6F),
MK_64(0x2A2767A4,0xAE9B94DB),
MK_64(0xEC06025E,0x74DD7683),
MK_64(0xE7A436CD,0xC4746251),
MK_64(0xC36FBAF9,0x393AD185),
MK_64(0x3EEDBA18,0x33EDFC13)
};
/* blkSize = 512 bits. hashSize = 384 bits */
const u64b_t SKEIN_512_IV_384[] =
{
MK_64(0xA3F6C6BF,0x3A75EF5F),
MK_64(0xB0FEF9CC,0xFD84FAA4),
MK_64(0x9D77DD66,0x3D770CFE),
MK_64(0xD798CBF3,0xB468FDDA),
MK_64(0x1BC4A666,0x8A0E4465),
MK_64(0x7ED7D434,0xE5807407),
MK_64(0x548FC1AC,0xD4EC44D6),
MK_64(0x266E1754,0x6AA18FF8)
};
/* blkSize = 512 bits. hashSize = 512 bits */
const u64b_t SKEIN_512_IV_512[] =
{
MK_64(0x4903ADFF,0x749C51CE),
MK_64(0x0D95DE39,0x9746DF03),
MK_64(0x8FD19341,0x27C79BCE),
MK_64(0x9A255629,0xFF352CB1),
MK_64(0x5DB62599,0xDF6CA7B0),
MK_64(0xEABE394C,0xA9D5C3F4),
MK_64(0x991112C7,0x1A75B523),
MK_64(0xAE18A40B,0x660FCC33)
};
/* blkSize = 1024 bits. hashSize = 384 bits */
const u64b_t SKEIN1024_IV_384[] =
{
MK_64(0x5102B6B8,0xC1894A35),
MK_64(0xFEEBC9E3,0xFE8AF11A),
MK_64(0x0C807F06,0xE32BED71),
MK_64(0x60C13A52,0xB41A91F6),
MK_64(0x9716D35D,0xD4917C38),
MK_64(0xE780DF12,0x6FD31D3A),
MK_64(0x797846B6,0xC898303A),
MK_64(0xB172C2A8,0xB3572A3B),
MK_64(0xC9BC8203,0xA6104A6C),
MK_64(0x65909338,0xD75624F4),
MK_64(0x94BCC568,0x4B3F81A0),
MK_64(0x3EBBF51E,0x10ECFD46),
MK_64(0x2DF50F0B,0xEEB08542),
MK_64(0x3B5A6530,0x0DBC6516),
MK_64(0x484B9CD2,0x167BBCE1),
MK_64(0x2D136947,0xD4CBAFEA)
};
/* blkSize = 1024 bits. hashSize = 512 bits */
const u64b_t SKEIN1024_IV_512[] =
{
MK_64(0xCAEC0E5D,0x7C1B1B18),
MK_64(0xA01B0E04,0x5F03E802),
MK_64(0x33840451,0xED912885),
MK_64(0x374AFB04,0xEAEC2E1C),
MK_64(0xDF25A0E2,0x813581F7),
MK_64(0xE4004093,0x8B12F9D2),
MK_64(0xA662D539,0xC2ED39B6),
MK_64(0xFA8B85CF,0x45D8C75A),
MK_64(0x8316ED8E,0x29EDE796),
MK_64(0x053289C0,0x2E9F91B8),
MK_64(0xC3F8EF1D,0x6D518B73),
MK_64(0xBDCEC3C4,0xD5EF332E),
MK_64(0x549A7E52,0x22974487),
MK_64(0x67070872,0x5B749816),
MK_64(0xB9CD28FB,0xF0581BD1),
MK_64(0x0E2940B8,0x15804974)
};
/* blkSize = 1024 bits. hashSize = 1024 bits */
const u64b_t SKEIN1024_IV_1024[] =
{
MK_64(0xD593DA07,0x41E72355),
MK_64(0x15B5E511,0xAC73E00C),
MK_64(0x5180E5AE,0xBAF2C4F0),
MK_64(0x03BD41D3,0xFCBCAFAF),
MK_64(0x1CAEC6FD,0x1983A898),
MK_64(0x6E510B8B,0xCDD0589F),
MK_64(0x77E2BDFD,0xC6394ADA),
MK_64(0xC11E1DB5,0x24DCB0A3),
MK_64(0xD6D14AF9,0xC6329AB5),
MK_64(0x6A9B0BFC,0x6EB67E0D),
MK_64(0x9243C60D,0xCCFF1332),
MK_64(0x1A1F1DDE,0x743F02D4),
MK_64(0x0996753C,0x10ED0BB8),
MK_64(0x6572DD22,0xF2B4969A),
MK_64(0x61FD3062,0xD00A579A),
MK_64(0x1DE0536E,0x8682E539)
};
#ifndef SKEIN_USE_ASM
#define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */
#endif
#ifndef SKEIN_LOOP
#define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */
#endif
#define BLK_BITS (WCNT*64) /* some useful definitions for code here */
#define KW_TWK_BASE (0)
#define KW_KEY_BASE (3)
#define ks (kw + KW_KEY_BASE)
#define ts (kw + KW_TWK_BASE)
#ifdef SKEIN_DEBUG
#define DebugSaveTweak(ctx) { ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; }
#else
#define DebugSaveTweak(ctx)
#endif
/***************************** Skein_256 ******************************/
#if !(SKEIN_USE_ASM & 256)
static void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd)
{ /* do it in C */
enum
{
WCNT = SKEIN_256_STATE_WORDS
};
#undef RCNT
#define RCNT (SKEIN_256_ROUNDS_TOTAL/8)
#ifdef SKEIN_LOOP /* configure how much to unroll the loop */
#define SKEIN_UNROLL_256 (((SKEIN_LOOP)/100)%10)
#else
#define SKEIN_UNROLL_256 (0)
#endif
#if SKEIN_UNROLL_256
#if (RCNT % SKEIN_UNROLL_256)
#error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */
#endif
size_t r;
u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/
#else
u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */
#endif
u64b_t X0,X1,X2,X3; /* local copy of context vars, for speed */
u64b_t w [WCNT]; /* local copy of input block */
#ifdef SKEIN_DEBUG
const u64b_t *Xptr[4]; /* use for debugging (help compiler put Xn in registers) */
Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3;
#endif
Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */
ts[0] = ctx->h.T[0];
ts[1] = ctx->h.T[1];
do {
/* this implementation only supports 2**64 input bytes (no carry out here) */
ts[0] += byteCntAdd; /* update processed length */
/* precompute the key schedule for this block */
ks[0] = ctx->X[0];
ks[1] = ctx->X[1];
ks[2] = ctx->X[2];
ks[3] = ctx->X[3];
ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY;
ts[2] = ts[0] ^ ts[1];
Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */
DebugSaveTweak(ctx);
Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts);
X0 = w[0] + ks[0]; /* do the first full key injection */
X1 = w[1] + ks[1] + ts[0];
X2 = w[2] + ks[2] + ts[1];
X3 = w[3] + ks[3];
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); /* show starting state values */
blkPtr += SKEIN_256_BLOCK_BYTES;
/* run the rounds */
#define Round256(p0,p1,p2,p3,ROT,rNum) \
X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \
X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \
#if SKEIN_UNROLL_256 == 0
#define R256(p0,p1,p2,p3,ROT,rNum) /* fully unrolled */ \
Round256(p0,p1,p2,p3,ROT,rNum) \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr);
#define I256(R) \
X0 += ks[((R)+1) % 5]; /* inject the key schedule value */ \
X1 += ks[((R)+2) % 5] + ts[((R)+1) % 3]; \
X2 += ks[((R)+3) % 5] + ts[((R)+2) % 3]; \
X3 += ks[((R)+4) % 5] + (R)+1; \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
#else /* looping version */
#define R256(p0,p1,p2,p3,ROT,rNum) \
Round256(p0,p1,p2,p3,ROT,rNum) \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr);
#define I256(R) \
X0 += ks[r+(R)+0]; /* inject the key schedule value */ \
X1 += ks[r+(R)+1] + ts[r+(R)+0]; \
X2 += ks[r+(R)+2] + ts[r+(R)+1]; \
X3 += ks[r+(R)+3] + r+(R) ; \
ks[r + (R)+4 ] = ks[r+(R)-1]; /* rotate key schedule */\
ts[r + (R)+2 ] = ts[r+(R)-1]; \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_256) /* loop thru it */
#endif
{
#define R256_8_rounds(R) \
R256(0,1,2,3,R_256_0,8*(R) + 1); \
R256(0,3,2,1,R_256_1,8*(R) + 2); \
R256(0,1,2,3,R_256_2,8*(R) + 3); \
R256(0,3,2,1,R_256_3,8*(R) + 4); \
I256(2*(R)); \
R256(0,1,2,3,R_256_4,8*(R) + 5); \
R256(0,3,2,1,R_256_5,8*(R) + 6); \
R256(0,1,2,3,R_256_6,8*(R) + 7); \
R256(0,3,2,1,R_256_7,8*(R) + 8); \
I256(2*(R)+1);
R256_8_rounds( 0);
#define R256_Unroll_R(NN) ((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_256 > (NN)))
#if R256_Unroll_R( 1)
R256_8_rounds( 1);
#endif
#if R256_Unroll_R( 2)
R256_8_rounds( 2);
#endif
#if R256_Unroll_R( 3)
R256_8_rounds( 3);
#endif
#if R256_Unroll_R( 4)
R256_8_rounds( 4);
#endif
#if R256_Unroll_R( 5)
R256_8_rounds( 5);
#endif
#if R256_Unroll_R( 6)
R256_8_rounds( 6);
#endif
#if R256_Unroll_R( 7)
R256_8_rounds( 7);
#endif
#if R256_Unroll_R( 8)
R256_8_rounds( 8);
#endif
#if R256_Unroll_R( 9)
R256_8_rounds( 9);
#endif
#if R256_Unroll_R(10)
R256_8_rounds(10);
#endif
#if R256_Unroll_R(11)
R256_8_rounds(11);
#endif
#if R256_Unroll_R(12)
R256_8_rounds(12);
#endif
#if R256_Unroll_R(13)
R256_8_rounds(13);
#endif
#if R256_Unroll_R(14)
R256_8_rounds(14);
#endif
#if (SKEIN_UNROLL_256 > 14)
#error "need more unrolling in Skein_256_Process_Block"
#endif
}
/* do the final "feedforward" xor, update context chaining vars */
ctx->X[0] = X0 ^ w[0];
ctx->X[1] = X1 ^ w[1];
ctx->X[2] = X2 ^ w[2];
ctx->X[3] = X3 ^ w[3];
Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X);
ts[1] &= ~SKEIN_T1_FLAG_FIRST;
}
while (--blkCnt);
ctx->h.T[0] = ts[0];
ctx->h.T[1] = ts[1];
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
static size_t Skein_256_Process_Block_CodeSize(void)
{
return ((u08b_t *) Skein_256_Process_Block_CodeSize) -
((u08b_t *) Skein_256_Process_Block);
}
static uint_t Skein_256_Unroll_Cnt(void)
{
return SKEIN_UNROLL_256;
}
#endif
#endif
/***************************** Skein_512 ******************************/
#if !(SKEIN_USE_ASM & 512)
static void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd)
{ /* do it in C */
enum
{
WCNT = SKEIN_512_STATE_WORDS
};
#undef RCNT
#define RCNT (SKEIN_512_ROUNDS_TOTAL/8)
#ifdef SKEIN_LOOP /* configure how much to unroll the loop */
#define SKEIN_UNROLL_512 (((SKEIN_LOOP)/10)%10)
#else
#define SKEIN_UNROLL_512 (0)
#endif
#if SKEIN_UNROLL_512
#if (RCNT % SKEIN_UNROLL_512)
#error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */
#endif
size_t r;
u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/
#else
u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */
#endif
u64b_t X0,X1,X2,X3,X4,X5,X6,X7; /* local copy of vars, for speed */
u64b_t w [WCNT]; /* local copy of input block */
#ifdef SKEIN_DEBUG
const u64b_t *Xptr[8]; /* use for debugging (help compiler put Xn in registers) */
Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3;
Xptr[4] = &X4; Xptr[5] = &X5; Xptr[6] = &X6; Xptr[7] = &X7;
#endif
Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */
ts[0] = ctx->h.T[0];
ts[1] = ctx->h.T[1];
do {
/* this implementation only supports 2**64 input bytes (no carry out here) */
ts[0] += byteCntAdd; /* update processed length */
/* precompute the key schedule for this block */
ks[0] = ctx->X[0];
ks[1] = ctx->X[1];
ks[2] = ctx->X[2];
ks[3] = ctx->X[3];
ks[4] = ctx->X[4];
ks[5] = ctx->X[5];
ks[6] = ctx->X[6];
ks[7] = ctx->X[7];
ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^
ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY;
ts[2] = ts[0] ^ ts[1];
Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */
DebugSaveTweak(ctx);
Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts);
X0 = w[0] + ks[0]; /* do the first full key injection */
X1 = w[1] + ks[1];
X2 = w[2] + ks[2];
X3 = w[3] + ks[3];
X4 = w[4] + ks[4];
X5 = w[5] + ks[5] + ts[0];
X6 = w[6] + ks[6] + ts[1];
X7 = w[7] + ks[7];
blkPtr += SKEIN_512_BLOCK_BYTES;
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr);
/* run the rounds */
#define Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \
X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \
X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \
X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \
X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \
#if SKEIN_UNROLL_512 == 0
#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) /* unrolled */ \
Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr);
#define I512(R) \
X0 += ks[((R)+1) % 9]; /* inject the key schedule value */ \
X1 += ks[((R)+2) % 9]; \
X2 += ks[((R)+3) % 9]; \
X3 += ks[((R)+4) % 9]; \
X4 += ks[((R)+5) % 9]; \
X5 += ks[((R)+6) % 9] + ts[((R)+1) % 3]; \
X6 += ks[((R)+7) % 9] + ts[((R)+2) % 3]; \
X7 += ks[((R)+8) % 9] + (R)+1; \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
#else /* looping version */
#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \
Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr);
#define I512(R) \
X0 += ks[r+(R)+0]; /* inject the key schedule value */ \
X1 += ks[r+(R)+1]; \
X2 += ks[r+(R)+2]; \
X3 += ks[r+(R)+3]; \
X4 += ks[r+(R)+4]; \
X5 += ks[r+(R)+5] + ts[r+(R)+0]; \
X6 += ks[r+(R)+6] + ts[r+(R)+1]; \
X7 += ks[r+(R)+7] + r+(R) ; \
ks[r + (R)+8] = ks[r+(R)-1]; /* rotate key schedule */ \
ts[r + (R)+2] = ts[r+(R)-1]; \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_512) /* loop thru it */
#endif /* end of looped code definitions */
{
#define R512_8_rounds(R) /* do 8 full rounds */ \
R512(0,1,2,3,4,5,6,7,R_512_0,8*(R)+ 1); \
R512(2,1,4,7,6,5,0,3,R_512_1,8*(R)+ 2); \
R512(4,1,6,3,0,5,2,7,R_512_2,8*(R)+ 3); \
R512(6,1,0,7,2,5,4,3,R_512_3,8*(R)+ 4); \
I512(2*(R)); \
R512(0,1,2,3,4,5,6,7,R_512_4,8*(R)+ 5); \
R512(2,1,4,7,6,5,0,3,R_512_5,8*(R)+ 6); \
R512(4,1,6,3,0,5,2,7,R_512_6,8*(R)+ 7); \
R512(6,1,0,7,2,5,4,3,R_512_7,8*(R)+ 8); \
I512(2*(R)+1); /* and key injection */
R512_8_rounds( 0);
#define R512_Unroll_R(NN) ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_512 > (NN)))
#if R512_Unroll_R( 1)
R512_8_rounds( 1);
#endif
#if R512_Unroll_R( 2)
R512_8_rounds( 2);
#endif
#if R512_Unroll_R( 3)
R512_8_rounds( 3);
#endif
#if R512_Unroll_R( 4)
R512_8_rounds( 4);
#endif
#if R512_Unroll_R( 5)
R512_8_rounds( 5);
#endif
#if R512_Unroll_R( 6)
R512_8_rounds( 6);
#endif
#if R512_Unroll_R( 7)
R512_8_rounds( 7);
#endif
#if R512_Unroll_R( 8)
R512_8_rounds( 8);
#endif
#if R512_Unroll_R( 9)
R512_8_rounds( 9);
#endif
#if R512_Unroll_R(10)
R512_8_rounds(10);
#endif
#if R512_Unroll_R(11)
R512_8_rounds(11);
#endif
#if R512_Unroll_R(12)
R512_8_rounds(12);
#endif
#if R512_Unroll_R(13)
R512_8_rounds(13);
#endif
#if R512_Unroll_R(14)
R512_8_rounds(14);
#endif
#if (SKEIN_UNROLL_512 > 14)
#error "need more unrolling in Skein_512_Process_Block"
#endif
}
/* do the final "feedforward" xor, update context chaining vars */
ctx->X[0] = X0 ^ w[0];
ctx->X[1] = X1 ^ w[1];
ctx->X[2] = X2 ^ w[2];
ctx->X[3] = X3 ^ w[3];
ctx->X[4] = X4 ^ w[4];
ctx->X[5] = X5 ^ w[5];
ctx->X[6] = X6 ^ w[6];
ctx->X[7] = X7 ^ w[7];
Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X);
ts[1] &= ~SKEIN_T1_FLAG_FIRST;
}
while (--blkCnt);
ctx->h.T[0] = ts[0];
ctx->h.T[1] = ts[1];
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
static size_t Skein_512_Process_Block_CodeSize(void)
{
return ((u08b_t *) Skein_512_Process_Block_CodeSize) -
((u08b_t *) Skein_512_Process_Block);
}
static uint_t Skein_512_Unroll_Cnt(void)
{
return SKEIN_UNROLL_512;
}
#endif
#endif
/***************************** Skein1024 ******************************/
#if !(SKEIN_USE_ASM & 1024)
static void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd)
{ /* do it in C, always looping (unrolled is bigger AND slower!) */
enum
{
WCNT = SKEIN1024_STATE_WORDS
};
#undef RCNT
#define RCNT (SKEIN1024_ROUNDS_TOTAL/8)
#ifdef SKEIN_LOOP /* configure how much to unroll the loop */
#define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10)
#else
#define SKEIN_UNROLL_1024 (0)
#endif
#if (SKEIN_UNROLL_1024 != 0)
#if (RCNT % SKEIN_UNROLL_1024)
#error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */
#endif
size_t r;
u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/
#else
u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */
#endif
u64b_t X00,X01,X02,X03,X04,X05,X06,X07, /* local copy of vars, for speed */
X08,X09,X10,X11,X12,X13,X14,X15;
u64b_t w [WCNT]; /* local copy of input block */
#ifdef SKEIN_DEBUG
const u64b_t *Xptr[16]; /* use for debugging (help compiler put Xn in registers) */
Xptr[ 0] = &X00; Xptr[ 1] = &X01; Xptr[ 2] = &X02; Xptr[ 3] = &X03;
Xptr[ 4] = &X04; Xptr[ 5] = &X05; Xptr[ 6] = &X06; Xptr[ 7] = &X07;
Xptr[ 8] = &X08; Xptr[ 9] = &X09; Xptr[10] = &X10; Xptr[11] = &X11;
Xptr[12] = &X12; Xptr[13] = &X13; Xptr[14] = &X14; Xptr[15] = &X15;
#endif
Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */
ts[0] = ctx->h.T[0];
ts[1] = ctx->h.T[1];
do {
/* this implementation only supports 2**64 input bytes (no carry out here) */
ts[0] += byteCntAdd; /* update processed length */
/* precompute the key schedule for this block */
ks[ 0] = ctx->X[ 0];
ks[ 1] = ctx->X[ 1];
ks[ 2] = ctx->X[ 2];
ks[ 3] = ctx->X[ 3];
ks[ 4] = ctx->X[ 4];
ks[ 5] = ctx->X[ 5];
ks[ 6] = ctx->X[ 6];
ks[ 7] = ctx->X[ 7];
ks[ 8] = ctx->X[ 8];
ks[ 9] = ctx->X[ 9];
ks[10] = ctx->X[10];
ks[11] = ctx->X[11];
ks[12] = ctx->X[12];
ks[13] = ctx->X[13];
ks[14] = ctx->X[14];
ks[15] = ctx->X[15];
ks[16] = ks[ 0] ^ ks[ 1] ^ ks[ 2] ^ ks[ 3] ^
ks[ 4] ^ ks[ 5] ^ ks[ 6] ^ ks[ 7] ^
ks[ 8] ^ ks[ 9] ^ ks[10] ^ ks[11] ^
ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY;
ts[2] = ts[0] ^ ts[1];
Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */
DebugSaveTweak(ctx);
Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts);
X00 = w[ 0] + ks[ 0]; /* do the first full key injection */
X01 = w[ 1] + ks[ 1];
X02 = w[ 2] + ks[ 2];
X03 = w[ 3] + ks[ 3];
X04 = w[ 4] + ks[ 4];
X05 = w[ 5] + ks[ 5];
X06 = w[ 6] + ks[ 6];
X07 = w[ 7] + ks[ 7];
X08 = w[ 8] + ks[ 8];
X09 = w[ 9] + ks[ 9];
X10 = w[10] + ks[10];
X11 = w[11] + ks[11];
X12 = w[12] + ks[12];
X13 = w[13] + ks[13] + ts[0];
X14 = w[14] + ks[14] + ts[1];
X15 = w[15] + ks[15];
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr);
#define Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rNum) \
X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \
X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \
X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \
X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \
X##p8 += X##p9; X##p9 = RotL_64(X##p9,ROT##_4); X##p9 ^= X##p8; \
X##pA += X##pB; X##pB = RotL_64(X##pB,ROT##_5); X##pB ^= X##pA; \
X##pC += X##pD; X##pD = RotL_64(X##pD,ROT##_6); X##pD ^= X##pC; \
X##pE += X##pF; X##pF = RotL_64(X##pF,ROT##_7); X##pF ^= X##pE; \
#if SKEIN_UNROLL_1024 == 0
#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rn,Xptr);
#define I1024(R) \
X00 += ks[((R)+ 1) % 17]; /* inject the key schedule value */ \
X01 += ks[((R)+ 2) % 17]; \
X02 += ks[((R)+ 3) % 17]; \
X03 += ks[((R)+ 4) % 17]; \
X04 += ks[((R)+ 5) % 17]; \
X05 += ks[((R)+ 6) % 17]; \
X06 += ks[((R)+ 7) % 17]; \
X07 += ks[((R)+ 8) % 17]; \
X08 += ks[((R)+ 9) % 17]; \
X09 += ks[((R)+10) % 17]; \
X10 += ks[((R)+11) % 17]; \
X11 += ks[((R)+12) % 17]; \
X12 += ks[((R)+13) % 17]; \
X13 += ks[((R)+14) % 17] + ts[((R)+1) % 3]; \
X14 += ks[((R)+15) % 17] + ts[((R)+2) % 3]; \
X15 += ks[((R)+16) % 17] + (R)+1; \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
#else /* looping version */
#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rn,Xptr);
#define I1024(R) \
X00 += ks[r+(R)+ 0]; /* inject the key schedule value */ \
X01 += ks[r+(R)+ 1]; \
X02 += ks[r+(R)+ 2]; \
X03 += ks[r+(R)+ 3]; \
X04 += ks[r+(R)+ 4]; \
X05 += ks[r+(R)+ 5]; \
X06 += ks[r+(R)+ 6]; \
X07 += ks[r+(R)+ 7]; \
X08 += ks[r+(R)+ 8]; \
X09 += ks[r+(R)+ 9]; \
X10 += ks[r+(R)+10]; \
X11 += ks[r+(R)+11]; \
X12 += ks[r+(R)+12]; \
X13 += ks[r+(R)+13] + ts[r+(R)+0]; \
X14 += ks[r+(R)+14] + ts[r+(R)+1]; \
X15 += ks[r+(R)+15] + r+(R) ; \
ks[r + (R)+16] = ks[r+(R)-1]; /* rotate key schedule */ \
ts[r + (R)+ 2] = ts[r+(R)-1]; \
Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr);
for (r=1;r <= 2*RCNT;r+=2*SKEIN_UNROLL_1024) /* loop thru it */
#endif
{
#define R1024_8_rounds(R) /* do 8 full rounds */ \
R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_0,8*(R) + 1); \
R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_1,8*(R) + 2); \
R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_2,8*(R) + 3); \
R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_3,8*(R) + 4); \
I1024(2*(R)); \
R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_4,8*(R) + 5); \
R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_5,8*(R) + 6); \
R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_6,8*(R) + 7); \
R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_7,8*(R) + 8); \
I1024(2*(R)+1);
R1024_8_rounds( 0);
#define R1024_Unroll_R(NN) ((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_1024 > (NN)))
#if R1024_Unroll_R( 1)
R1024_8_rounds( 1);
#endif
#if R1024_Unroll_R( 2)
R1024_8_rounds( 2);
#endif
#if R1024_Unroll_R( 3)
R1024_8_rounds( 3);
#endif
#if R1024_Unroll_R( 4)
R1024_8_rounds( 4);
#endif
#if R1024_Unroll_R( 5)
R1024_8_rounds( 5);
#endif
#if R1024_Unroll_R( 6)
R1024_8_rounds( 6);
#endif
#if R1024_Unroll_R( 7)
R1024_8_rounds( 7);
#endif
#if R1024_Unroll_R( 8)
R1024_8_rounds( 8);
#endif
#if R1024_Unroll_R( 9)
R1024_8_rounds( 9);
#endif
#if R1024_Unroll_R(10)
R1024_8_rounds(10);
#endif
#if R1024_Unroll_R(11)
R1024_8_rounds(11);
#endif
#if R1024_Unroll_R(12)
R1024_8_rounds(12);
#endif
#if R1024_Unroll_R(13)
R1024_8_rounds(13);
#endif
#if R1024_Unroll_R(14)
R1024_8_rounds(14);
#endif
#if (SKEIN_UNROLL_1024 > 14)
#error "need more unrolling in Skein_1024_Process_Block"
#endif
}
/* do the final "feedforward" xor, update context chaining vars */
ctx->X[ 0] = X00 ^ w[ 0];
ctx->X[ 1] = X01 ^ w[ 1];
ctx->X[ 2] = X02 ^ w[ 2];
ctx->X[ 3] = X03 ^ w[ 3];
ctx->X[ 4] = X04 ^ w[ 4];
ctx->X[ 5] = X05 ^ w[ 5];
ctx->X[ 6] = X06 ^ w[ 6];
ctx->X[ 7] = X07 ^ w[ 7];
ctx->X[ 8] = X08 ^ w[ 8];
ctx->X[ 9] = X09 ^ w[ 9];
ctx->X[10] = X10 ^ w[10];
ctx->X[11] = X11 ^ w[11];
ctx->X[12] = X12 ^ w[12];
ctx->X[13] = X13 ^ w[13];
ctx->X[14] = X14 ^ w[14];
ctx->X[15] = X15 ^ w[15];
Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X);
ts[1] &= ~SKEIN_T1_FLAG_FIRST;
blkPtr += SKEIN1024_BLOCK_BYTES;
}
while (--blkCnt);
ctx->h.T[0] = ts[0];
ctx->h.T[1] = ts[1];
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
static size_t Skein1024_Process_Block_CodeSize(void)
{
return ((u08b_t *) Skein1024_Process_Block_CodeSize) -
((u08b_t *) Skein1024_Process_Block);
}
static uint_t Skein1024_Unroll_Cnt(void)
{
return SKEIN_UNROLL_1024;
}
#endif
#endif
#if 0
/*****************************************************************/
/* 256-bit Skein */
/*****************************************************************/
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* init the context for a straight hashing operation */
static int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)
{
union
{
u08b_t b[SKEIN_256_STATE_BYTES];
u64b_t w[SKEIN_256_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
switch (hashBitLen)
{ /* use pre-computed values, where available */
#ifndef SKEIN_NO_PRECOMP
case 256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X)); break;
case 224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X)); break;
case 160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X)); break;
case 128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X)); break;
#endif
default:
/* here if there is no precomputed IV value available */
/* build/process the config block, type == CONFIG (could be precomputed) */
Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
/* compute the initial chaining values from config block */
memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */
Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
break;
}
/* The chaining vars ctx->X are now initialized for the given hashBitLen. */
/* Set up to process the data message portion of the hash (default) */
Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* init the context for a MAC and/or tree hash operation */
/* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
static int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
{
union
{
u08b_t b[SKEIN_256_STATE_BYTES];
u64b_t w[SKEIN_256_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
/* compute the initial chaining values ctx->X[], based on key */
if (keyBytes == 0) /* is there a key? */
{
memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */
}
else /* here to pre-process a key */
{
Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
/* do a mini-Init right here */
ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */
Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */
memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */
Skein_256_Update(ctx,key,keyBytes); /* hash the key */
Skein_256_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */
memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */
#if SKEIN_NEED_SWAP
{
uint_t i;
for (i=0;iX[i] = Skein_Swap64(ctx->X[i]);
}
#endif
}
/* build/process the config block, type == CONFIG (could be precomputed for each key) */
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
Skein_Start_New_Type(ctx,CFG_FINAL);
memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
Skein_Show_Key(256,&ctx->h,key,keyBytes);
/* compute the initial chaining values from config block */
Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
/* The chaining vars ctx->X are now initialized */
/* Set up to process the data message portion of the hash (default) */
ctx->h.bCnt = 0; /* buffer b[] starts out empty */
Skein_Start_New_Type(ctx,MSG);
return SKEIN_SUCCESS;
}
#endif
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* process the input bytes */
static int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
{
size_t n;
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
/* process full blocks, if any */
if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES)
{
if (ctx->h.bCnt) /* finish up any buffered message data */
{
n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */
if (n)
{
Skein_assert(n < msgByteCnt); /* check on our logic here */
memcpy(&ctx->b[ctx->h.bCnt],msg,n);
msgByteCnt -= n;
msg += n;
ctx->h.bCnt += n;
}
Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);
Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES);
ctx->h.bCnt = 0;
}
/* now process any remaining full blocks, directly from input message data */
if (msgByteCnt > SKEIN_256_BLOCK_BYTES)
{
n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES; /* number of full blocks to process */
Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES);
msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;
msg += n * SKEIN_256_BLOCK_BYTES;
}
Skein_assert(ctx->h.bCnt == 0);
}
/* copy any remaining source message data bytes into b[] */
if (msgByteCnt)
{
Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);
memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
ctx->h.bCnt += msgByteCnt;
}
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* finalize the hash computation and output the result */
static int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
{
size_t i,n,byteCnt;
u64b_t X[SKEIN_256_STATE_WORDS];
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */
memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
/* now output the result */
byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
/* run Threefish in "counter mode" to generate output */
memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
for (i=0;i < byteCnt;i += SKEIN_256_BLOCK_BYTES)
{
((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
Skein_Start_New_Type(ctx,OUT_FINAL);
Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
n = byteCnt - i; /* number of output bytes left to go */
if (n >= SKEIN_256_BLOCK_BYTES)
n = SKEIN_256_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal+i,ctx->X,n); /* "output" the ctr mode bytes */
Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
}
return SKEIN_SUCCESS;
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
static size_t Skein_256_API_CodeSize(void)
{
return ((u08b_t *) Skein_256_API_CodeSize) -
((u08b_t *) Skein_256_Init);
}
#endif
/*****************************************************************/
/* 512-bit Skein */
/*****************************************************************/
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* init the context for a straight hashing operation */
static int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)
{
union
{
u08b_t b[SKEIN_512_STATE_BYTES];
u64b_t w[SKEIN_512_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
switch (hashBitLen)
{ /* use pre-computed values, where available */
#ifndef SKEIN_NO_PRECOMP
case 512: memcpy(ctx->X,SKEIN_512_IV_512,sizeof(ctx->X)); break;
case 384: memcpy(ctx->X,SKEIN_512_IV_384,sizeof(ctx->X)); break;
case 256: memcpy(ctx->X,SKEIN_512_IV_256,sizeof(ctx->X)); break;
case 224: memcpy(ctx->X,SKEIN_512_IV_224,sizeof(ctx->X)); break;
#endif
default:
/* here if there is no precomputed IV value available */
/* build/process the config block, type == CONFIG (could be precomputed) */
Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
/* compute the initial chaining values from config block */
memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */
Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
break;
}
/* The chaining vars ctx->X are now initialized for the given hashBitLen. */
/* Set up to process the data message portion of the hash (default) */
Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */
return SKEIN_SUCCESS;
}
#if 0
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* init the context for a MAC and/or tree hash operation */
/* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
static int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
{
union
{
u08b_t b[SKEIN_512_STATE_BYTES];
u64b_t w[SKEIN_512_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
/* compute the initial chaining values ctx->X[], based on key */
if (keyBytes == 0) /* is there a key? */
{
memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */
}
else /* here to pre-process a key */
{
Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
/* do a mini-Init right here */
ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */
Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */
memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */
Skein_512_Update(ctx,key,keyBytes); /* hash the key */
Skein_512_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */
memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */
#if SKEIN_NEED_SWAP
{
uint_t i;
for (i=0;iX[i] = Skein_Swap64(ctx->X[i]);
}
#endif
}
/* build/process the config block, type == CONFIG (could be precomputed for each key) */
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
Skein_Start_New_Type(ctx,CFG_FINAL);
memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
Skein_Show_Key(512,&ctx->h,key,keyBytes);
/* compute the initial chaining values from config block */
Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
/* The chaining vars ctx->X are now initialized */
/* Set up to process the data message portion of the hash (default) */
ctx->h.bCnt = 0; /* buffer b[] starts out empty */
Skein_Start_New_Type(ctx,MSG);
return SKEIN_SUCCESS;
}
#endif
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* process the input bytes */
static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
{
size_t n;
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
/* process full blocks, if any */
if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES)
{
if (ctx->h.bCnt) /* finish up any buffered message data */
{
n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */
if (n)
{
Skein_assert(n < msgByteCnt); /* check on our logic here */
memcpy(&ctx->b[ctx->h.bCnt],msg,n);
msgByteCnt -= n;
msg += n;
ctx->h.bCnt += n;
}
Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);
Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES);
ctx->h.bCnt = 0;
}
/* now process any remaining full blocks, directly from input message data */
if (msgByteCnt > SKEIN_512_BLOCK_BYTES)
{
n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES; /* number of full blocks to process */
Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES);
msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;
msg += n * SKEIN_512_BLOCK_BYTES;
}
Skein_assert(ctx->h.bCnt == 0);
}
/* copy any remaining source message data bytes into b[] */
if (msgByteCnt)
{
Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);
memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
ctx->h.bCnt += msgByteCnt;
}
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* finalize the hash computation and output the result */
static int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
{
size_t i,n,byteCnt;
u64b_t X[SKEIN_512_STATE_WORDS];
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */
memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
/* now output the result */
byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
/* run Threefish in "counter mode" to generate output */
memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
{
((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
Skein_Start_New_Type(ctx,OUT_FINAL);
Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */
if (n >= SKEIN_512_BLOCK_BYTES)
n = SKEIN_512_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
}
return SKEIN_SUCCESS;
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
static size_t Skein_512_API_CodeSize(void)
{
return ((u08b_t *) Skein_512_API_CodeSize) -
((u08b_t *) Skein_512_Init);
}
#endif
/*****************************************************************/
/* 1024-bit Skein */
/*****************************************************************/
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* init the context for a straight hashing operation */
static int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)
{
union
{
u08b_t b[SKEIN1024_STATE_BYTES];
u64b_t w[SKEIN1024_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
switch (hashBitLen)
{ /* use pre-computed values, where available */
#ifndef SKEIN_NO_PRECOMP
case 512: memcpy(ctx->X,SKEIN1024_IV_512 ,sizeof(ctx->X)); break;
case 384: memcpy(ctx->X,SKEIN1024_IV_384 ,sizeof(ctx->X)); break;
case 1024: memcpy(ctx->X,SKEIN1024_IV_1024,sizeof(ctx->X)); break;
#endif
default:
/* here if there is no precomputed IV value available */
/* build/process the config block, type == CONFIG (could be precomputed) */
Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
/* compute the initial chaining values from config block */
memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */
Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
break;
}
/* The chaining vars ctx->X are now initialized for the given hashBitLen. */
/* Set up to process the data message portion of the hash (default) */
Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */
return SKEIN_SUCCESS;
}
#if 0
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* init the context for a MAC and/or tree hash operation */
/* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
static int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
{
union
{
u08b_t b[SKEIN1024_STATE_BYTES];
u64b_t w[SKEIN1024_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
/* compute the initial chaining values ctx->X[], based on key */
if (keyBytes == 0) /* is there a key? */
{
memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */
}
else /* here to pre-process a key */
{
Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
/* do a mini-Init right here */
ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */
Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */
memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */
Skein1024_Update(ctx,key,keyBytes); /* hash the key */
Skein1024_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */
memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */
#if SKEIN_NEED_SWAP
{
uint_t i;
for (i=0;iX[i] = Skein_Swap64(ctx->X[i]);
}
#endif
}
/* build/process the config block, type == CONFIG (could be precomputed for each key) */
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
Skein_Start_New_Type(ctx,CFG_FINAL);
memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
Skein_Show_Key(1024,&ctx->h,key,keyBytes);
/* compute the initial chaining values from config block */
Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
/* The chaining vars ctx->X are now initialized */
/* Set up to process the data message portion of the hash (default) */
ctx->h.bCnt = 0; /* buffer b[] starts out empty */
Skein_Start_New_Type(ctx,MSG);
return SKEIN_SUCCESS;
}
#endif
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* process the input bytes */
static int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
{
size_t n;
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
/* process full blocks, if any */
if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES)
{
if (ctx->h.bCnt) /* finish up any buffered message data */
{
n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */
if (n)
{
Skein_assert(n < msgByteCnt); /* check on our logic here */
memcpy(&ctx->b[ctx->h.bCnt],msg,n);
msgByteCnt -= n;
msg += n;
ctx->h.bCnt += n;
}
Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);
Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES);
ctx->h.bCnt = 0;
}
/* now process any remaining full blocks, directly from input message data */
if (msgByteCnt > SKEIN1024_BLOCK_BYTES)
{
n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES; /* number of full blocks to process */
Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES);
msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;
msg += n * SKEIN1024_BLOCK_BYTES;
}
Skein_assert(ctx->h.bCnt == 0);
}
/* copy any remaining source message data bytes into b[] */
if (msgByteCnt)
{
Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);
memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
ctx->h.bCnt += msgByteCnt;
}
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* finalize the hash computation and output the result */
static int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
{
size_t i,n,byteCnt;
u64b_t X[SKEIN1024_STATE_WORDS];
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */
memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
/* now output the result */
byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
/* run Threefish in "counter mode" to generate output */
memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
{
((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
Skein_Start_New_Type(ctx,OUT_FINAL);
Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */
if (n >= SKEIN1024_BLOCK_BYTES)
n = SKEIN1024_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
}
return SKEIN_SUCCESS;
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
static size_t Skein1024_API_CodeSize(void)
{
return ((u08b_t *) Skein1024_API_CodeSize) -
((u08b_t *) Skein1024_Init);
}
#endif
/**************** Functions to support MAC/tree hashing ***************/
/* (this code is identical for Optimized and Reference versions) */
#if 0
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* finalize the hash computation and output the block, no OUTPUT stage */
static int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
{
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */
memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES); /* "output" the state bytes */
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* finalize the hash computation and output the block, no OUTPUT stage */
static int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
{
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */
memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES); /* "output" the state bytes */
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* finalize the hash computation and output the block, no OUTPUT stage */
static int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
{
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */
memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES); /* "output" the state bytes */
return SKEIN_SUCCESS;
}
#if SKEIN_TREE_HASH
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* just do the OUTPUT stage */
static int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
{
size_t i,n,byteCnt;
u64b_t X[SKEIN_256_STATE_WORDS];
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
/* now output the result */
byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
/* run Threefish in "counter mode" to generate output */
memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
{
((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
Skein_Start_New_Type(ctx,OUT_FINAL);
Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */
if (n >= SKEIN_256_BLOCK_BYTES)
n = SKEIN_256_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
}
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* just do the OUTPUT stage */
static int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
{
size_t i,n,byteCnt;
u64b_t X[SKEIN_512_STATE_WORDS];
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
/* now output the result */
byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
/* run Threefish in "counter mode" to generate output */
memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
{
((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
Skein_Start_New_Type(ctx,OUT_FINAL);
Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */
if (n >= SKEIN_512_BLOCK_BYTES)
n = SKEIN_512_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
}
return SKEIN_SUCCESS;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* just do the OUTPUT stage */
static int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
{
size_t i,n,byteCnt;
u64b_t X[SKEIN1024_STATE_WORDS];
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
/* now output the result */
byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
/* run Threefish in "counter mode" to generate output */
memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
{
((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
Skein_Start_New_Type(ctx,OUT_FINAL);
Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */
if (n >= SKEIN1024_BLOCK_BYTES)
n = SKEIN1024_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
}
return SKEIN_SUCCESS;
}
#endif
#endif
typedef struct
{
uint_t statebits; /* 256, 512, or 1024 */
union
{
Skein_Ctxt_Hdr_t h; /* common header "overlay" */
Skein_256_Ctxt_t ctx_256;
Skein_512_Ctxt_t ctx_512;
Skein1024_Ctxt_t ctx1024;
} u;
}
hashState;
/* "incremental" hashing API */
static SkeinHashReturn Init (hashState *state, int hashbitlen);
static SkeinHashReturn Update(hashState *state, const SkeinBitSequence *data, SkeinDataLength databitlen);
static SkeinHashReturn Final (hashState *state, SkeinBitSequence *hashval);
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* select the context size and init the context */
static SkeinHashReturn Init(hashState *state, int hashbitlen)
{
#if SKEIN_256_NIST_MAX_HASH_BITS
if (hashbitlen <= SKEIN_256_NIST_MAX_HASHBITS)
{
Skein_Assert(hashbitlen > 0,BAD_HASHLEN);
state->statebits = 64*SKEIN_256_STATE_WORDS;
return Skein_256_Init(&state->u.ctx_256,(size_t) hashbitlen);
}
#endif
if (hashbitlen <= SKEIN_512_NIST_MAX_HASHBITS)
{
state->statebits = 64*SKEIN_512_STATE_WORDS;
return Skein_512_Init(&state->u.ctx_512,(size_t) hashbitlen);
}
else
{
state->statebits = 64*SKEIN1024_STATE_WORDS;
return Skein1024_Init(&state->u.ctx1024,(size_t) hashbitlen);
}
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* process data to be hashed */
static SkeinHashReturn Update(hashState *state, const SkeinBitSequence *data, SkeinDataLength databitlen)
{
/* only the final Update() call is allowed do partial bytes, else assert an error */
Skein_Assert((state->u.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || databitlen == 0, SKEIN_FAIL);
Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,SKEIN_FAIL);
if ((databitlen & 7) == 0) /* partial bytes? */
{
switch ((state->statebits >> 8) & 3)
{
case 2: return Skein_512_Update(&state->u.ctx_512,data,databitlen >> 3);
case 1: return Skein_256_Update(&state->u.ctx_256,data,databitlen >> 3);
case 0: return Skein1024_Update(&state->u.ctx1024,data,databitlen >> 3);
default: return SKEIN_FAIL;
}
}
else
{ /* handle partial final byte */
size_t bCnt = (databitlen >> 3) + 1; /* number of bytes to handle (nonzero here!) */
u08b_t b,mask;
mask = (u08b_t) (1u << (7 - (databitlen & 7))); /* partial byte bit mask */
b = (u08b_t) ((data[bCnt-1] & (0-mask)) | mask); /* apply bit padding on final byte */
switch ((state->statebits >> 8) & 3)
{
case 2: Skein_512_Update(&state->u.ctx_512,data,bCnt-1); /* process all but the final byte */
Skein_512_Update(&state->u.ctx_512,&b , 1 ); /* process the (masked) partial byte */
break;
case 1: Skein_256_Update(&state->u.ctx_256,data,bCnt-1); /* process all but the final byte */
Skein_256_Update(&state->u.ctx_256,&b , 1 ); /* process the (masked) partial byte */
break;
case 0: Skein1024_Update(&state->u.ctx1024,data,bCnt-1); /* process all but the final byte */
Skein1024_Update(&state->u.ctx1024,&b , 1 ); /* process the (masked) partial byte */
break;
default: return SKEIN_FAIL;
}
Skein_Set_Bit_Pad_Flag(state->u.h); /* set tweak flag for the final call */
return SKEIN_SUCCESS;
}
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* finalize hash computation and output the result (hashbitlen bits) */
static SkeinHashReturn Final(hashState *state, SkeinBitSequence *hashval)
{
Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,FAIL);
switch ((state->statebits >> 8) & 3)
{
case 2: return Skein_512_Final(&state->u.ctx_512,hashval);
case 1: return Skein_256_Final(&state->u.ctx_256,hashval);
case 0: return Skein1024_Final(&state->u.ctx1024,hashval);
default: return SKEIN_FAIL;
}
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* all-in-one hash function */
SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data, /* all-in-one call */
SkeinDataLength databitlen,SkeinBitSequence *hashval)
{
hashState state;
SkeinHashReturn r = Init(&state,hashbitlen);
if (r == SKEIN_SUCCESS)
{ /* these calls do not fail when called properly */
r = Update(&state,data,databitlen);
Final(&state,hashval);
}
return r;
}
================================================
FILE: crypto/c_skein.h
================================================
#ifndef _SKEIN_H_
#define _SKEIN_H_ 1
/**************************************************************************
**
** Interface declarations and internal definitions for Skein hashing.
**
** Source code author: Doug Whiting, 2008.
**
** This algorithm and source code is released to the public domain.
**
***************************************************************************
**
** The following compile-time switches may be defined to control some
** tradeoffs between speed, code size, error checking, and security.
**
** The "default" note explains what happens when the switch is not defined.
**
** SKEIN_DEBUG -- make callouts from inside Skein code
** to examine/display intermediate values.
** [default: no callouts (no overhead)]
**
** SKEIN_ERR_CHECK -- how error checking is handled inside Skein
** code. If not defined, most error checking
** is disabled (for performance). Otherwise,
** the switch value is interpreted as:
** 0: use assert() to flag errors
** 1: return SKEIN_FAIL to flag errors
**
***************************************************************************/
#include "skein_port.h" /* get platform-specific definitions */
typedef enum
{
SKEIN_SUCCESS = 0, /* return codes from Skein calls */
SKEIN_FAIL = 1,
SKEIN_BAD_HASHLEN = 2
}
SkeinHashReturn;
typedef size_t SkeinDataLength; /* bit count type */
typedef u08b_t SkeinBitSequence; /* bit stream type */
/* "all-in-one" call */
SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data,
SkeinDataLength databitlen, SkeinBitSequence *hashval);
#endif /* ifndef _SKEIN_H_ */
================================================
FILE: crypto/cryptonight.h
================================================
#ifndef __CRYPTONIGHT_H_INCLUDED
#define __CRYPTONIGHT_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#define MEMORY 2097152
typedef struct {
uint8_t hash_state[224]; // Need only 200, explicit align
uint8_t long_state[MEMORY];
} cryptonight_ctx;
void cryptonight_hash_ctx(const void* input, size_t len, void* output, cryptonight_ctx* ctx);
void cryptonight_hash_ctx_soft(const void* input, size_t len, void* output, cryptonight_ctx* ctx);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: crypto/cryptonight_aesni.h
================================================
/*
* 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
* 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 .
*
*/
#pragma once
#include "cryptonight.h"
#include
#include
#ifdef __GNUC__
#include
static inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi)
{
unsigned __int128 r = (unsigned __int128)a * (unsigned __int128)b;
*hi = r >> 64;
return (uint64_t)r;
}
#define _mm256_set_m128i(v0, v1) _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1)
#else
#include
#endif // __GNUC__
#if !defined(_LP64) && !defined(_WIN64)
#error You are trying to do a 32-bit build. This will all end in tears. I know it.
#endif
extern "C"
{
void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen);
void keccakf(uint64_t st[25], int rounds);
extern void(*const extra_hashes[4])(const void *, size_t, char *);
__m128i soft_aesenc(__m128i in, __m128i key);
__m128i soft_aeskeygenassist(__m128i key, uint8_t rcon);
}
// This will shift and xor tmp1 into itself as 4 32-bit vals such as
// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
static inline __m128i sl_xor(__m128i tmp1)
{
__m128i tmp4;
tmp4 = _mm_slli_si128(tmp1, 0x04);
tmp1 = _mm_xor_si128(tmp1, tmp4);
tmp4 = _mm_slli_si128(tmp4, 0x04);
tmp1 = _mm_xor_si128(tmp1, tmp4);
tmp4 = _mm_slli_si128(tmp4, 0x04);
tmp1 = _mm_xor_si128(tmp1, tmp4);
return tmp1;
}
template
static inline void aes_genkey_sub(__m128i* xout0, __m128i* xout2)
{
__m128i xout1 = _mm_aeskeygenassist_si128(*xout2, rcon);
xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
*xout0 = sl_xor(*xout0);
*xout0 = _mm_xor_si128(*xout0, xout1);
xout1 = _mm_aeskeygenassist_si128(*xout0, 0x00);
xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
*xout2 = sl_xor(*xout2);
*xout2 = _mm_xor_si128(*xout2, xout1);
}
static inline void soft_aes_genkey_sub(__m128i* xout0, __m128i* xout2, uint8_t rcon)
{
__m128i xout1 = soft_aeskeygenassist(*xout2, rcon);
xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
*xout0 = sl_xor(*xout0);
*xout0 = _mm_xor_si128(*xout0, xout1);
xout1 = soft_aeskeygenassist(*xout0, 0x00);
xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
*xout2 = sl_xor(*xout2);
*xout2 = _mm_xor_si128(*xout2, xout1);
}
template
static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3,
__m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
{
__m128i xout0, xout2;
xout0 = _mm_load_si128(memory);
xout2 = _mm_load_si128(memory+1);
*k0 = xout0;
*k1 = xout2;
if(SOFT_AES)
soft_aes_genkey_sub(&xout0, &xout2, 0x01);
else
aes_genkey_sub<0x01>(&xout0, &xout2);
*k2 = xout0;
*k3 = xout2;
if(SOFT_AES)
soft_aes_genkey_sub(&xout0, &xout2, 0x02);
else
aes_genkey_sub<0x02>(&xout0, &xout2);
*k4 = xout0;
*k5 = xout2;
if(SOFT_AES)
soft_aes_genkey_sub(&xout0, &xout2, 0x04);
else
aes_genkey_sub<0x04>(&xout0, &xout2);
*k6 = xout0;
*k7 = xout2;
if(SOFT_AES)
soft_aes_genkey_sub(&xout0, &xout2, 0x08);
else
aes_genkey_sub<0x08>(&xout0, &xout2);
*k8 = xout0;
*k9 = xout2;
}
static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
{
*x0 = _mm_aesenc_si128(*x0, key);
*x1 = _mm_aesenc_si128(*x1, key);
*x2 = _mm_aesenc_si128(*x2, key);
*x3 = _mm_aesenc_si128(*x3, key);
*x4 = _mm_aesenc_si128(*x4, key);
*x5 = _mm_aesenc_si128(*x5, key);
*x6 = _mm_aesenc_si128(*x6, key);
*x7 = _mm_aesenc_si128(*x7, key);
}
static inline void soft_aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
{
*x0 = soft_aesenc(*x0, key);
*x1 = soft_aesenc(*x1, key);
*x2 = soft_aesenc(*x2, key);
*x3 = soft_aesenc(*x3, key);
*x4 = soft_aesenc(*x4, key);
*x5 = soft_aesenc(*x5, key);
*x6 = soft_aesenc(*x6, key);
*x7 = soft_aesenc(*x7, key);
}
template
void cn_explode_scratchpad(const __m128i* input, __m128i* output)
{
// This is more than we have registers, compiler will assign 2 keys on the stack
__m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
aes_genkey(input, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
xin0 = _mm_load_si128(input + 4);
xin1 = _mm_load_si128(input + 5);
xin2 = _mm_load_si128(input + 6);
xin3 = _mm_load_si128(input + 7);
xin4 = _mm_load_si128(input + 8);
xin5 = _mm_load_si128(input + 9);
xin6 = _mm_load_si128(input + 10);
xin7 = _mm_load_si128(input + 11);
for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8)
{
if(SOFT_AES)
{
soft_aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
soft_aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
}
else
{
aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
}
_mm_store_si128(output + i + 0, xin0);
_mm_store_si128(output + i + 1, xin1);
_mm_store_si128(output + i + 2, xin2);
_mm_store_si128(output + i + 3, xin3);
_mm_prefetch((const char*)output + i + 0, _MM_HINT_T2);
_mm_store_si128(output + i + 4, xin4);
_mm_store_si128(output + i + 5, xin5);
_mm_store_si128(output + i + 6, xin6);
_mm_store_si128(output + i + 7, xin7);
_mm_prefetch((const char*)output + i + 4, _MM_HINT_T2);
}
}
template
void cn_implode_scratchpad(const __m128i* input, __m128i* output)
{
// This is more than we have registers, compiler will assign 2 keys on the stack
__m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
aes_genkey(output + 2, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
xout0 = _mm_load_si128(output + 4);
xout1 = _mm_load_si128(output + 5);
xout2 = _mm_load_si128(output + 6);
xout3 = _mm_load_si128(output + 7);
xout4 = _mm_load_si128(output + 8);
xout5 = _mm_load_si128(output + 9);
xout6 = _mm_load_si128(output + 10);
xout7 = _mm_load_si128(output + 11);
for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8)
{
_mm_prefetch((const char*)input + i + 0, _MM_HINT_NTA);
xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3);
_mm_prefetch((const char*)input + i + 4, _MM_HINT_NTA);
xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4);
xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5);
xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6);
xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7);
if(SOFT_AES)
{
soft_aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
soft_aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
}
else
{
aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
}
}
_mm_store_si128(output + 4, xout0);
_mm_store_si128(output + 5, xout1);
_mm_store_si128(output + 6, xout2);
_mm_store_si128(output + 7, xout3);
_mm_store_si128(output + 8, xout4);
_mm_store_si128(output + 9, xout5);
_mm_store_si128(output + 10, xout6);
_mm_store_si128(output + 11, xout7);
}
template
void cryptonight_hash(const void* input, size_t len, void* output, cryptonight_ctx* ctx0)
{
keccak((const uint8_t *)input, len, ctx0->hash_state, 200);
// Optim - 99% time boundary
cn_explode_scratchpad((__m128i*)ctx0->hash_state, (__m128i*)ctx0->long_state);
uint8_t* l0 = ctx0->long_state;
uint64_t* h0 = (uint64_t*)ctx0->hash_state;
uint64_t al0 = h0[0] ^ h0[4];
uint64_t ah0 = h0[1] ^ h0[5];
__m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
uint64_t idx0 = h0[0] ^ h0[4];
// Optim - 90% time boundary
for(size_t i = 0; i < ITERATIONS; i++)
{
__m128i cx;
cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]);
if(SOFT_AES)
cx = soft_aesenc(cx, _mm_set_epi64x(ah0, al0));
else
cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
_mm_store_si128((__m128i *)&l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx));
idx0 = _mm_cvtsi128_si64(cx);
bx0 = cx;
if(PREFETCH)
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
uint64_t hi, lo, cl, ch;
cl = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[0];
ch = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[1];
lo = _umul128(idx0, cl, &hi);
al0 += hi;
ah0 += lo;
((uint64_t*)&l0[idx0 & 0x1FFFF0])[0] = al0;
((uint64_t*)&l0[idx0 & 0x1FFFF0])[1] = ah0;
ah0 ^= ch;
al0 ^= cl;
idx0 = al0;
if(PREFETCH)
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
}
// Optim - 90% time boundary
cn_implode_scratchpad((__m128i*)ctx0->long_state, (__m128i*)ctx0->hash_state);
// Optim - 99% time boundary
keccakf((uint64_t*)ctx0->hash_state, 24);
extra_hashes[ctx0->hash_state[0] & 3](ctx0->hash_state, 200, (char*)output);
}
// This lovely creation will do 2 cn hashes at a time. We have plenty of space on silicon
// to fit temporary vars for two contexts. Function will read len*2 from input and write 64 bytes to output
// We are still limited by L3 cache, so doubling will only work with CPUs where we have more than 2MB to core (Xeons)
template
void cryptonight_double_hash(const void* input, size_t len, void* output, cryptonight_ctx* __restrict ctx0, cryptonight_ctx* __restrict ctx1)
{
keccak((const uint8_t *)input, len, ctx0->hash_state, 200);
keccak((const uint8_t *)input+len, len, ctx1->hash_state, 200);
// Optim - 99% time boundary
cn_explode_scratchpad((__m128i*)ctx0->hash_state, (__m128i*)ctx0->long_state);
cn_explode_scratchpad((__m128i*)ctx1->hash_state, (__m128i*)ctx1->long_state);
uint8_t* l0 = ctx0->long_state;
uint64_t* h0 = (uint64_t*)ctx0->hash_state;
uint8_t* l1 = ctx1->long_state;
uint64_t* h1 = (uint64_t*)ctx1->hash_state;
__m128i ax0 = _mm_set_epi64x(h0[1] ^ h0[5], h0[0] ^ h0[4]);
__m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
__m128i ax1 = _mm_set_epi64x(h1[1] ^ h1[5], h1[0] ^ h1[4]);
__m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
uint64_t idx0 = h0[0] ^ h0[4];
uint64_t idx1 = h1[0] ^ h1[4];
// Optim - 90% time boundary
for (size_t i = 0; i < ITERATIONS; i++)
{
__m128i cx;
cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]);
if(SOFT_AES)
cx = soft_aesenc(cx, ax0);
else
cx = _mm_aesenc_si128(cx, ax0);
_mm_store_si128((__m128i *)&l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx));
idx0 = _mm_cvtsi128_si64(cx);
bx0 = cx;
if(PREFETCH)
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
cx = _mm_load_si128((__m128i *)&l1[idx1 & 0x1FFFF0]);
if(SOFT_AES)
cx = soft_aesenc(cx, ax1);
else
cx = _mm_aesenc_si128(cx, ax1);
_mm_store_si128((__m128i *)&l1[idx1 & 0x1FFFF0], _mm_xor_si128(bx1, cx));
idx1 = _mm_cvtsi128_si64(cx);
bx1 = cx;
if(PREFETCH)
_mm_prefetch((const char*)&l1[idx1 & 0x1FFFF0], _MM_HINT_T0);
uint64_t hi, lo;
cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]);
lo = _umul128(idx0, _mm_cvtsi128_si64(cx), &hi);
ax0 = _mm_add_epi64(ax0, _mm_set_epi64x(lo, hi));
_mm_store_si128((__m128i*)&l0[idx0 & 0x1FFFF0], ax0);
ax0 = _mm_xor_si128(ax0, cx);
idx0 = _mm_cvtsi128_si64(ax0);
if(PREFETCH)
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
cx = _mm_load_si128((__m128i *)&l1[idx1 & 0x1FFFF0]);
lo = _umul128(idx1, _mm_cvtsi128_si64(cx), &hi);
ax1 = _mm_add_epi64(ax1, _mm_set_epi64x(lo, hi));
_mm_store_si128((__m128i*)&l1[idx1 & 0x1FFFF0], ax1);
ax1 = _mm_xor_si128(ax1, cx);
idx1 = _mm_cvtsi128_si64(ax1);
if(PREFETCH)
_mm_prefetch((const char*)&l1[idx1 & 0x1FFFF0], _MM_HINT_T0);
}
// Optim - 90% time boundary
cn_implode_scratchpad((__m128i*)ctx0->long_state, (__m128i*)ctx0->hash_state);
cn_implode_scratchpad((__m128i*)ctx1->long_state, (__m128i*)ctx1->hash_state);
// Optim - 99% time boundary
keccakf((uint64_t*)ctx0->hash_state, 24);
extra_hashes[ctx0->hash_state[0] & 3](ctx0->hash_state, 200, (char*)output);
keccakf((uint64_t*)ctx1->hash_state, 24);
extra_hashes[ctx1->hash_state[0] & 3](ctx1->hash_state, 200, (char*)output + 32);
}
================================================
FILE: crypto/cryptonight_common.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
extern "C"
{
#include "c_groestl.h"
#include "c_blake256.h"
#include "c_jh.h"
#include "c_skein.h"
}
#include "cryptonight.h"
#include "cryptonight_aesni.h"
#include
#include
#ifdef __GNUC__
#include
#else
#include
#endif // __GNUC__
#ifdef _WIN32
#include
#else
#include
#include
#include
#endif // _WIN32
void do_blake_hash(const void* input, size_t len, char* output) {
blake256_hash((uint8_t*)output, (const uint8_t*)input, len);
}
void do_groestl_hash(const void* input, size_t len, char* output) {
groestl((const uint8_t*)input, len * 8, (uint8_t*)output);
}
void do_jh_hash(const void* input, size_t len, char* output) {
jh_hash(32 * 8, (const uint8_t*)input, 8 * len, (uint8_t*)output);
}
void do_skein_hash(const void* input, size_t len, char* output) {
skein_hash(8 * 32, (const uint8_t*)input, 8 * len, (uint8_t*)output);
}
void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
void cryptonight_hash_ctx(const void* input, size_t len, void* output, cryptonight_ctx* ctx)
{
cryptonight_hash<0x80000, MEMORY, true, false>(input, len, output, ctx);
}
void cryptonight_hash_ctx_soft(const void* input, size_t len, void* output, cryptonight_ctx* ctx)
{
cryptonight_hash<0x80000, MEMORY, true, true>(input, len, output, ctx);
}
================================================
FILE: crypto/groestl_tables.h
================================================
#ifndef __tables_h
#define __tables_h
const uint32_t T[512] = {0xa5f432c6, 0xc6a597f4, 0x84976ff8, 0xf884eb97, 0x99b05eee, 0xee99c7b0, 0x8d8c7af6, 0xf68df78c, 0xd17e8ff, 0xff0de517, 0xbddc0ad6, 0xd6bdb7dc, 0xb1c816de, 0xdeb1a7c8, 0x54fc6d91, 0x915439fc
, 0x50f09060, 0x6050c0f0, 0x3050702, 0x2030405, 0xa9e02ece, 0xcea987e0, 0x7d87d156, 0x567dac87, 0x192bcce7, 0xe719d52b, 0x62a613b5, 0xb56271a6, 0xe6317c4d, 0x4de69a31, 0x9ab559ec, 0xec9ac3b5
, 0x45cf408f, 0x8f4505cf, 0x9dbca31f, 0x1f9d3ebc, 0x40c04989, 0x894009c0, 0x879268fa, 0xfa87ef92, 0x153fd0ef, 0xef15c53f, 0xeb2694b2, 0xb2eb7f26, 0xc940ce8e, 0x8ec90740, 0xb1de6fb, 0xfb0bed1d
, 0xec2f6e41, 0x41ec822f, 0x67a91ab3, 0xb3677da9, 0xfd1c435f, 0x5ffdbe1c, 0xea256045, 0x45ea8a25, 0xbfdaf923, 0x23bf46da, 0xf7025153, 0x53f7a602, 0x96a145e4, 0xe496d3a1, 0x5bed769b, 0x9b5b2ded
, 0xc25d2875, 0x75c2ea5d, 0x1c24c5e1, 0xe11cd924, 0xaee9d43d, 0x3dae7ae9, 0x6abef24c, 0x4c6a98be, 0x5aee826c, 0x6c5ad8ee, 0x41c3bd7e, 0x7e41fcc3, 0x206f3f5, 0xf502f106, 0x4fd15283, 0x834f1dd1
, 0x5ce48c68, 0x685cd0e4, 0xf4075651, 0x51f4a207, 0x345c8dd1, 0xd134b95c, 0x818e1f9, 0xf908e918, 0x93ae4ce2, 0xe293dfae, 0x73953eab, 0xab734d95, 0x53f59762, 0x6253c4f5, 0x3f416b2a, 0x2a3f5441
, 0xc141c08, 0x80c1014, 0x52f66395, 0x955231f6, 0x65afe946, 0x46658caf, 0x5ee27f9d, 0x9d5e21e2, 0x28784830, 0x30286078, 0xa1f8cf37, 0x37a16ef8, 0xf111b0a, 0xa0f1411, 0xb5c4eb2f, 0x2fb55ec4
, 0x91b150e, 0xe091c1b, 0x365a7e24, 0x2436485a, 0x9bb6ad1b, 0x1b9b36b6, 0x3d4798df, 0xdf3da547, 0x266aa7cd, 0xcd26816a, 0x69bbf54e, 0x4e699cbb, 0xcd4c337f, 0x7fcdfe4c, 0x9fba50ea, 0xea9fcfba
, 0x1b2d3f12, 0x121b242d, 0x9eb9a41d, 0x1d9e3ab9, 0x749cc458, 0x5874b09c, 0x2e724634, 0x342e6872, 0x2d774136, 0x362d6c77, 0xb2cd11dc, 0xdcb2a3cd, 0xee299db4, 0xb4ee7329, 0xfb164d5b, 0x5bfbb616
, 0xf601a5a4, 0xa4f65301, 0x4dd7a176, 0x764decd7, 0x61a314b7, 0xb76175a3, 0xce49347d, 0x7dcefa49, 0x7b8ddf52, 0x527ba48d, 0x3e429fdd, 0xdd3ea142, 0x7193cd5e, 0x5e71bc93, 0x97a2b113, 0x139726a2
, 0xf504a2a6, 0xa6f55704, 0x68b801b9, 0xb96869b8, 0x0, 0x0, 0x2c74b5c1, 0xc12c9974, 0x60a0e040, 0x406080a0, 0x1f21c2e3, 0xe31fdd21, 0xc8433a79, 0x79c8f243, 0xed2c9ab6, 0xb6ed772c
, 0xbed90dd4, 0xd4beb3d9, 0x46ca478d, 0x8d4601ca, 0xd9701767, 0x67d9ce70, 0x4bddaf72, 0x724be4dd, 0xde79ed94, 0x94de3379, 0xd467ff98, 0x98d42b67, 0xe82393b0, 0xb0e87b23, 0x4ade5b85, 0x854a11de
, 0x6bbd06bb, 0xbb6b6dbd, 0x2a7ebbc5, 0xc52a917e, 0xe5347b4f, 0x4fe59e34, 0x163ad7ed, 0xed16c13a, 0xc554d286, 0x86c51754, 0xd762f89a, 0x9ad72f62, 0x55ff9966, 0x6655ccff, 0x94a7b611, 0x119422a7
, 0xcf4ac08a, 0x8acf0f4a, 0x1030d9e9, 0xe910c930, 0x60a0e04, 0x406080a, 0x819866fe, 0xfe81e798, 0xf00baba0, 0xa0f05b0b, 0x44ccb478, 0x7844f0cc, 0xbad5f025, 0x25ba4ad5, 0xe33e754b, 0x4be3963e
, 0xf30eaca2, 0xa2f35f0e, 0xfe19445d, 0x5dfeba19, 0xc05bdb80, 0x80c01b5b, 0x8a858005, 0x58a0a85, 0xadecd33f, 0x3fad7eec, 0xbcdffe21, 0x21bc42df, 0x48d8a870, 0x7048e0d8, 0x40cfdf1, 0xf104f90c
, 0xdf7a1963, 0x63dfc67a, 0xc1582f77, 0x77c1ee58, 0x759f30af, 0xaf75459f, 0x63a5e742, 0x426384a5, 0x30507020, 0x20304050, 0x1a2ecbe5, 0xe51ad12e, 0xe12effd, 0xfd0ee112, 0x6db708bf, 0xbf6d65b7
, 0x4cd45581, 0x814c19d4, 0x143c2418, 0x1814303c, 0x355f7926, 0x26354c5f, 0x2f71b2c3, 0xc32f9d71, 0xe13886be, 0xbee16738, 0xa2fdc835, 0x35a26afd, 0xcc4fc788, 0x88cc0b4f, 0x394b652e, 0x2e395c4b
, 0x57f96a93, 0x93573df9, 0xf20d5855, 0x55f2aa0d, 0x829d61fc, 0xfc82e39d, 0x47c9b37a, 0x7a47f4c9, 0xacef27c8, 0xc8ac8bef, 0xe73288ba, 0xbae76f32, 0x2b7d4f32, 0x322b647d, 0x95a442e6, 0xe695d7a4
, 0xa0fb3bc0, 0xc0a09bfb, 0x98b3aa19, 0x199832b3, 0xd168f69e, 0x9ed12768, 0x7f8122a3, 0xa37f5d81, 0x66aaee44, 0x446688aa, 0x7e82d654, 0x547ea882, 0xabe6dd3b, 0x3bab76e6, 0x839e950b, 0xb83169e
, 0xca45c98c, 0x8cca0345, 0x297bbcc7, 0xc729957b, 0xd36e056b, 0x6bd3d66e, 0x3c446c28, 0x283c5044, 0x798b2ca7, 0xa779558b, 0xe23d81bc, 0xbce2633d, 0x1d273116, 0x161d2c27, 0x769a37ad, 0xad76419a
, 0x3b4d96db, 0xdb3bad4d, 0x56fa9e64, 0x6456c8fa, 0x4ed2a674, 0x744ee8d2, 0x1e223614, 0x141e2822, 0xdb76e492, 0x92db3f76, 0xa1e120c, 0xc0a181e, 0x6cb4fc48, 0x486c90b4, 0xe4378fb8, 0xb8e46b37
, 0x5de7789f, 0x9f5d25e7, 0x6eb20fbd, 0xbd6e61b2, 0xef2a6943, 0x43ef862a, 0xa6f135c4, 0xc4a693f1, 0xa8e3da39, 0x39a872e3, 0xa4f7c631, 0x31a462f7, 0x37598ad3, 0xd337bd59, 0x8b8674f2, 0xf28bff86
, 0x325683d5, 0xd532b156, 0x43c54e8b, 0x8b430dc5, 0x59eb856e, 0x6e59dceb, 0xb7c218da, 0xdab7afc2, 0x8c8f8e01, 0x18c028f, 0x64ac1db1, 0xb16479ac, 0xd26df19c, 0x9cd2236d, 0xe03b7249, 0x49e0923b
, 0xb4c71fd8, 0xd8b4abc7, 0xfa15b9ac, 0xacfa4315, 0x709faf3, 0xf307fd09, 0x256fa0cf, 0xcf25856f, 0xafea20ca, 0xcaaf8fea, 0x8e897df4, 0xf48ef389, 0xe9206747, 0x47e98e20, 0x18283810, 0x10182028
, 0xd5640b6f, 0x6fd5de64, 0x888373f0, 0xf088fb83, 0x6fb1fb4a, 0x4a6f94b1, 0x7296ca5c, 0x5c72b896, 0x246c5438, 0x3824706c, 0xf1085f57, 0x57f1ae08, 0xc7522173, 0x73c7e652, 0x51f36497, 0x975135f3
, 0x2365aecb, 0xcb238d65, 0x7c8425a1, 0xa17c5984, 0x9cbf57e8, 0xe89ccbbf, 0x21635d3e, 0x3e217c63, 0xdd7cea96, 0x96dd377c, 0xdc7f1e61, 0x61dcc27f, 0x86919c0d, 0xd861a91, 0x85949b0f, 0xf851e94
, 0x90ab4be0, 0xe090dbab, 0x42c6ba7c, 0x7c42f8c6, 0xc4572671, 0x71c4e257, 0xaae529cc, 0xccaa83e5, 0xd873e390, 0x90d83b73, 0x50f0906, 0x6050c0f, 0x103f4f7, 0xf701f503, 0x12362a1c, 0x1c123836
, 0xa3fe3cc2, 0xc2a39ffe, 0x5fe18b6a, 0x6a5fd4e1, 0xf910beae, 0xaef94710, 0xd06b0269, 0x69d0d26b, 0x91a8bf17, 0x17912ea8, 0x58e87199, 0x995829e8, 0x2769533a, 0x3a277469, 0xb9d0f727, 0x27b94ed0
, 0x384891d9, 0xd938a948, 0x1335deeb, 0xeb13cd35, 0xb3cee52b, 0x2bb356ce, 0x33557722, 0x22334455, 0xbbd604d2, 0xd2bbbfd6, 0x709039a9, 0xa9704990, 0x89808707, 0x7890e80, 0xa7f2c133, 0x33a766f2
, 0xb6c1ec2d, 0x2db65ac1, 0x22665a3c, 0x3c227866, 0x92adb815, 0x15922aad, 0x2060a9c9, 0xc9208960, 0x49db5c87, 0x874915db, 0xff1ab0aa, 0xaaff4f1a, 0x7888d850, 0x5078a088, 0x7a8e2ba5, 0xa57a518e
, 0x8f8a8903, 0x38f068a, 0xf8134a59, 0x59f8b213, 0x809b9209, 0x980129b, 0x1739231a, 0x1a173439, 0xda751065, 0x65daca75, 0x315384d7, 0xd731b553, 0xc651d584, 0x84c61351, 0xb8d303d0, 0xd0b8bbd3
, 0xc35edc82, 0x82c31f5e, 0xb0cbe229, 0x29b052cb, 0x7799c35a, 0x5a77b499, 0x11332d1e, 0x1e113c33, 0xcb463d7b, 0x7bcbf646, 0xfc1fb7a8, 0xa8fc4b1f, 0xd6610c6d, 0x6dd6da61, 0x3a4e622c, 0x2c3a584e};
#endif /* __tables_h */
================================================
FILE: crypto/hash.h
================================================
#pragma once
typedef unsigned char BitSequence;
typedef unsigned long long DataLength;
typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn;
================================================
FILE: crypto/int-util.h
================================================
// Copyright(c) 2012 - 2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include
#include
#include
#include
#if defined(_MSC_VER)
#include
static inline uint32_t rol32(uint32_t x, int r) {
static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers");
return _rotl(x, r);
}
static inline uint64_t rol64(uint64_t x, int r) {
return _rotl64(x, r);
}
#else
static inline uint32_t rol32(uint32_t x, int r) {
return (x << (r & 31)) | (x >> (-r & 31));
}
static inline uint64_t rol64(uint64_t x, int r) {
return (x << (r & 63)) | (x >> (-r & 63));
}
#endif
static inline uint64_t hi_dword(uint64_t val) {
return val >> 32;
}
static inline uint64_t lo_dword(uint64_t val) {
return val & 0xFFFFFFFF;
}
static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) {
dividend |= ((uint64_t)*remainder) << 32;
*remainder = dividend % divisor;
return dividend / divisor;
}
// Long division with 2^32 base
static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) {
uint64_t dividend_dwords[4];
uint32_t remainder = 0;
dividend_dwords[3] = hi_dword(dividend_hi);
dividend_dwords[2] = lo_dword(dividend_hi);
dividend_dwords[1] = hi_dword(dividend_lo);
dividend_dwords[0] = lo_dword(dividend_lo);
*quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32;
*quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder);
*quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32;
*quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder);
return remainder;
}
#define IDENT32(x) ((uint32_t) (x))
#define IDENT64(x) ((uint64_t) (x))
#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \
(((uint32_t) (x) & 0x0000ff00) << 8) | \
(((uint32_t) (x) & 0x00ff0000) >> 8) | \
(((uint32_t) (x) & 0xff000000) >> 24))
#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \
(((uint64_t) (x) & 0x000000000000ff00) << 40) | \
(((uint64_t) (x) & 0x0000000000ff0000) << 24) | \
(((uint64_t) (x) & 0x00000000ff000000) << 8) | \
(((uint64_t) (x) & 0x000000ff00000000) >> 8) | \
(((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \
(((uint64_t) (x) & 0x00ff000000000000) >> 40) | \
(((uint64_t) (x) & 0xff00000000000000) >> 56))
static inline uint32_t ident32(uint32_t x) { return x; }
static inline uint64_t ident64(uint64_t x) { return x; }
static inline uint32_t swap32(uint32_t x) {
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
return (x << 16) | (x >> 16);
}
static inline uint64_t swap64(uint64_t x) {
x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8);
x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16);
return (x << 32) | (x >> 32);
}
#if defined(__GNUC__)
#define UNUSED __attribute__((unused))
#else
#define UNUSED
#endif
static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { }
#undef UNUSED
static inline void mem_inplace_swap32(void *mem, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint32_t *)mem)[i] = swap32(((const uint32_t *)mem)[i]);
}
}
static inline void mem_inplace_swap64(void *mem, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint64_t *)mem)[i] = swap64(((const uint64_t *)mem)[i]);
}
}
static inline void memcpy_ident32(void *dst, const void *src, size_t n) {
memcpy(dst, src, 4 * n);
}
static inline void memcpy_ident64(void *dst, const void *src, size_t n) {
memcpy(dst, src, 8 * n);
}
static inline void memcpy_swap32(void *dst, const void *src, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint32_t *)dst)[i] = swap32(((const uint32_t *)src)[i]);
}
}
static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint64_t *)dst)[i] = swap64(((const uint64_t *)src)[i]);
}
}
#define SWAP32LE IDENT32
#define SWAP32BE SWAP32
#define swap32le ident32
#define swap32be swap32
#define mem_inplace_swap32le mem_inplace_ident
#define mem_inplace_swap32be mem_inplace_swap32
#define memcpy_swap32le memcpy_ident32
#define memcpy_swap32be memcpy_swap32
#define SWAP64LE IDENT64
#define SWAP64BE SWAP64
#define swap64le ident64
#define swap64be swap64
#define mem_inplace_swap64le mem_inplace_ident
#define mem_inplace_swap64be mem_inplace_swap64
#define memcpy_swap64le memcpy_ident64
#define memcpy_swap64be memcpy_swap64
================================================
FILE: crypto/skein_port.h
================================================
#ifndef _SKEIN_PORT_H_
#define _SKEIN_PORT_H_
#include
#include
#include
#ifndef RETURN_VALUES
# define RETURN_VALUES
# if defined( DLL_EXPORT )
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
# define VOID_RETURN __declspec( dllexport ) void __stdcall
# define INT_RETURN __declspec( dllexport ) int __stdcall
# elif defined( __GNUC__ )
# define VOID_RETURN __declspec( __dllexport__ ) void
# define INT_RETURN __declspec( __dllexport__ ) int
# else
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
# endif
# elif defined( DLL_IMPORT )
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
# define VOID_RETURN __declspec( dllimport ) void __stdcall
# define INT_RETURN __declspec( dllimport ) int __stdcall
# elif defined( __GNUC__ )
# define VOID_RETURN __declspec( __dllimport__ ) void
# define INT_RETURN __declspec( __dllimport__ ) int
# else
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
# endif
# elif defined( __WATCOMC__ )
# define VOID_RETURN void __cdecl
# define INT_RETURN int __cdecl
# else
# define VOID_RETURN void
# define INT_RETURN int
# endif
#endif
/* These defines are used to declare buffers in a way that allows
faster operations on longer variables to be used. In all these
defines 'size' must be a power of 2 and >= 8
dec_unit_type(size,x) declares a variable 'x' of length
'size' bits
dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize'
bytes defined as an array of variables
each of 'size' bits (bsize must be a
multiple of size / 8)
ptr_cast(x,size) casts a pointer to a pointer to a
varaiable of length 'size' bits
*/
#define ui_type(size) uint##size##_t
#define dec_unit_type(size,x) typedef ui_type(size) x
#define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)]
#define ptr_cast(x,size) ((ui_type(size)*)(x))
typedef unsigned int uint_t; /* native unsigned integer */
typedef uint8_t u08b_t; /* 8-bit unsigned integer */
typedef uint64_t u64b_t; /* 64-bit unsigned integer */
#ifndef RotL_64
#define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N))))
#endif
/*
* Skein is "natively" little-endian (unlike SHA-xxx), for optimal
* performance on x86 CPUs. The Skein code requires the following
* definitions for dealing with endianness:
*
* SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian
* Skein_Put64_LSB_First
* Skein_Get64_LSB_First
* Skein_Swap64
*
* If SKEIN_NEED_SWAP is defined at compile time, it is used here
* along with the portable versions of Put64/Get64/Swap64, which
* are slow in general.
*
* Otherwise, an "auto-detect" of endianness is attempted below.
* If the default handling doesn't work well, the user may insert
* platform-specific code instead (e.g., for big-endian CPUs).
*
*/
#ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */
#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
/* special handler for IA64, which may be either endianness (?) */
/* here we assume little-endian, but this may need to be changed */
#if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
# define PLATFORM_MUST_ALIGN (1)
#ifndef PLATFORM_BYTE_ORDER
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#endif
#endif
#ifndef PLATFORM_MUST_ALIGN
# define PLATFORM_MUST_ALIGN (0)
#endif
#if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN
/* here for big-endian CPUs */
#define SKEIN_NEED_SWAP (1)
#elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN
/* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
#define SKEIN_NEED_SWAP (0)
#if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */
#define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt)
#define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt))
#endif
#else
#error "Skein needs endianness setting!"
#endif
#endif /* ifndef SKEIN_NEED_SWAP */
/*
******************************************************************
* Provide any definitions still needed.
******************************************************************
*/
#ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */
#if SKEIN_NEED_SWAP
#define Skein_Swap64(w64) \
( (( ((u64b_t)(w64)) & 0xFF) << 56) | \
(((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \
(((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \
(((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \
(((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \
(((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \
(((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \
(((((u64b_t)(w64)) >>56) & 0xFF) ) )
#else
#define Skein_Swap64(w64) (w64)
#endif
#endif /* ifndef Skein_Swap64 */
#ifndef Skein_Put64_LSB_First
void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt)
#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */
{ /* this version is fully portable (big-endian or little-endian), but slow */
size_t n;
for (n=0;n>3] >> (8*(n&7)));
}
#else
; /* output only the function prototype */
#endif
#endif /* ifndef Skein_Put64_LSB_First */
#ifndef Skein_Get64_LSB_First
void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt)
#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */
{ /* this version is fully portable (big-endian or little-endian), but slow */
size_t n;
for (n=0;n<8*wCnt;n+=8)
dst[n/8] = (((u64b_t) src[n ]) ) +
(((u64b_t) src[n+1]) << 8) +
(((u64b_t) src[n+2]) << 16) +
(((u64b_t) src[n+3]) << 24) +
(((u64b_t) src[n+4]) << 32) +
(((u64b_t) src[n+5]) << 40) +
(((u64b_t) src[n+6]) << 48) +
(((u64b_t) src[n+7]) << 56) ;
}
#else
; /* output only the function prototype */
#endif
#endif /* ifndef Skein_Get64_LSB_First */
#endif /* ifndef _SKEIN_PORT_H_ */
================================================
FILE: crypto/soft_aes.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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
/*
* The orginal author of this AES implementation is Karl Malbrain.
*/
#ifdef __GNUC__
#include
#else
#include
#endif // __GNUC__
#include
#define TABLE_ALIGN 32
#define WPOLY 0x011b
#define N_COLS 4
#define AES_BLOCK_SIZE 16
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
#if defined(_MSC_VER)
#define ALIGN __declspec(align(TABLE_ALIGN))
#elif defined(__GNUC__)
#define ALIGN __attribute__ ((aligned(16)))
#else
#define ALIGN
#endif
#define rf1(r,c) (r)
#define word_in(x,c) (*((uint32_t*)(x)+(c)))
#define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v))
#define s(x,c) x[c]
#define si(y,x,c) (s(y,c) = word_in(x, c))
#define so(y,x,c) word_out(y, c, s(x,c))
#define state_in(y,x) si(y,x,0); si(y,x,1); si(y,x,2); si(y,x,3)
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
#define round(y,x,k) \
y[0] = (k)[0] ^ (t_fn[0][x[0] & 0xff] ^ t_fn[1][(x[1] >> 8) & 0xff] ^ t_fn[2][(x[2] >> 16) & 0xff] ^ t_fn[3][x[3] >> 24]); \
y[1] = (k)[1] ^ (t_fn[0][x[1] & 0xff] ^ t_fn[1][(x[2] >> 8) & 0xff] ^ t_fn[2][(x[3] >> 16) & 0xff] ^ t_fn[3][x[0] >> 24]); \
y[2] = (k)[2] ^ (t_fn[0][x[2] & 0xff] ^ t_fn[1][(x[3] >> 8) & 0xff] ^ t_fn[2][(x[0] >> 16) & 0xff] ^ t_fn[3][x[1] >> 24]); \
y[3] = (k)[3] ^ (t_fn[0][x[3] & 0xff] ^ t_fn[1][(x[0] >> 8) & 0xff] ^ t_fn[2][(x[1] >> 16) & 0xff] ^ t_fn[3][x[2] >> 24]);
#define to_byte(x) ((x) & 0xff)
#define bval(x,n) to_byte((x) >> (8 * (n)))
#define fwd_var(x,r,c)\
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
#define sb_data(w) {\
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
#define rc_data(w) {\
w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
w(0x1b), w(0x36) }
#define bytes2word(b0, b1, b2, b3) (((uint32_t)(b3) << 24) | \
((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
#define h0(x) (x)
#define w0(p) bytes2word(p, 0, 0, 0)
#define w1(p) bytes2word(0, p, 0, 0)
#define w2(p) bytes2word(0, 0, p, 0)
#define w3(p) bytes2word(0, 0, 0, p)
#define u0(p) bytes2word(f2(p), p, p, f3(p))
#define u1(p) bytes2word(f3(p), f2(p), p, p)
#define u2(p) bytes2word(p, f3(p), f2(p), p)
#define u3(p) bytes2word(p, p, f3(p), f2(p))
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) ^ (((x>>5) & 4) * WPOLY))
#define f3(x) (f2(x) ^ x)
#define f9(x) (f8(x) ^ x)
#define fb(x) (f8(x) ^ f2(x) ^ x)
#define fd(x) (f8(x) ^ f4(x) ^ x)
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
#define t_dec(m,n) t_##m##n
#define t_set(m,n) t_##m##n
#define t_use(m,n) t_##m##n
#define d_4(t,n,b,e,f,g,h) ALIGN const t n[4][256] = { b(e), b(f), b(g), b(h) }
#define four_tables(x,tab,vf,rf,c) \
(tab[0][bval(vf(x,0,c),rf(0,c))] \
^ tab[1][bval(vf(x,1,c),rf(1,c))] \
^ tab[2][bval(vf(x,2,c),rf(2,c))] \
^ tab[3][bval(vf(x,3,c),rf(3,c))])
d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3);
__m128i soft_aesenc(__m128i in, __m128i key)
{
uint32_t x0, x1, x2, x3;
x0 = _mm_cvtsi128_si32(in);
x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0x55));
x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0xAA));
x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0xFF));
__m128i out = _mm_set_epi32(
(t_fn[0][x3 & 0xff] ^ t_fn[1][(x0 >> 8) & 0xff] ^ t_fn[2][(x1 >> 16) & 0xff] ^ t_fn[3][x2 >> 24]),
(t_fn[0][x2 & 0xff] ^ t_fn[1][(x3 >> 8) & 0xff] ^ t_fn[2][(x0 >> 16) & 0xff] ^ t_fn[3][x1 >> 24]),
(t_fn[0][x1 & 0xff] ^ t_fn[1][(x2 >> 8) & 0xff] ^ t_fn[2][(x3 >> 16) & 0xff] ^ t_fn[3][x0 >> 24]),
(t_fn[0][x0 & 0xff] ^ t_fn[1][(x1 >> 8) & 0xff] ^ t_fn[2][(x2 >> 16) & 0xff] ^ t_fn[3][x3 >> 24]));
return _mm_xor_si128(out, key);
}
uint8_t Sbox[256] = { // forward s-box
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
static inline void sub_word(uint8_t* key)
{
key[0] = Sbox[key[0]];
key[1] = Sbox[key[1]];
key[2] = Sbox[key[2]];
key[3] = Sbox[key[3]];
}
#ifdef __clang__
uint32_t _rotr(uint32_t value, uint32_t amount)
{
return (value >> amount) | (value << ((32 - amount) & 31));
}
#endif
__m128i soft_aeskeygenassist(__m128i key, uint8_t rcon)
{
uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0x55));
uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0xFF));
sub_word((uint8_t*)&X1);
sub_word((uint8_t*)&X3);
return _mm_set_epi32(_rotr(X3, 8) ^ rcon, X3,_rotr(X1, 8) ^ rcon, X1);
}
================================================
FILE: donate-level.h
================================================
#pragma once
/*
* Dev donation.
* Percentage of your hashing power that you want to donate to the developer, can be 0.0 if you don't want to do that.
* Example of how it works for the default setting of 1.0:
* You miner will mine into your usual pool for 99 minutes, then switch to the developer's pool for 1.0 minute.
* Switching is instant, and only happens after a successful connection, so you never loose any hashes.
*
* If you plan on changing this setting to 0.0 please consider making a one off donation to my wallet:
* 4581HhZkQHgZrZjKeCfCJxZff9E3xCgHGF25zABZz7oR71TnbbgiS7sK9jveE6Dx6uMs2LwszDuvQJgRZQotdpHt1fTdDhk
*
*/
constexpr double fDevDonationLevel = 1.0 / 100.0;
================================================
FILE: executor.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
#include
#include
#include
#include
#include
#include
#include "executor.h"
#include "jpsock.h"
#include "minethd.h"
#include "jconf.h"
#include "console.h"
#include "donate-level.h"
#include "webdesign.h"
#ifdef __GNUC__
#include
#else
#include
#endif // __GNUC__
#ifdef _WIN32
#define strncasecmp _strnicmp
#endif // _WIN32
executor* executor::oInst = NULL;
executor::executor()
{
cpu_ctx = (cryptonight_ctx*)_mm_malloc(sizeof(cryptonight_ctx), 4096);
}
void executor::push_timed_event(ex_event&& ev, size_t sec)
{
std::unique_lock lck(timed_event_mutex);
lTimedEvents.emplace_back(std::move(ev), sec_to_ticks(sec));
}
void executor::ex_clock_thd()
{
size_t iSwitchPeriod = sec_to_ticks(iDevDonatePeriod);
size_t iDevPortion = (size_t)floor(((double)iSwitchPeriod) * fDevDonationLevel);
//No point in bothering with less than 10 sec
if(iDevPortion < sec_to_ticks(10))
iDevPortion = 0;
//Add 2 seconds to compensate for connect
if(iDevPortion != 0)
iDevPortion += sec_to_ticks(2);
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(size_t(iTickTime)));
push_event(ex_event(EV_PERF_TICK));
// Service timed events
std::unique_lock lck(timed_event_mutex);
std::list::iterator ev = lTimedEvents.begin();
while (ev != lTimedEvents.end())
{
ev->ticks_left--;
if(ev->ticks_left == 0)
{
push_event(std::move(ev->event));
ev = lTimedEvents.erase(ev);
}
else
ev++;
}
lck.unlock();
if(iDevPortion == 0)
continue;
iSwitchPeriod--;
if(iSwitchPeriod == 0)
{
push_event(ex_event(EV_SWITCH_POOL, usr_pool_id));
iSwitchPeriod = sec_to_ticks(iDevDonatePeriod);
}
else if(iSwitchPeriod == iDevPortion)
{
push_event(ex_event(EV_SWITCH_POOL, dev_pool_id));
}
}
}
void executor::sched_reconnect()
{
iReconnectAttempts++;
size_t iLimit = jconf::inst()->GetGiveUpLimit();
if(iLimit != 0 && iReconnectAttempts > iLimit)
{
printer::inst()->print_msg(L0, "Give up limit reached. Exitting.");
exit(0);
}
long long unsigned int rt = jconf::inst()->GetNetRetry();
printer::inst()->print_msg(L1, "Pool connection lost. Waiting %lld s before retry (attempt %llu).",
rt, int_port(iReconnectAttempts));
auto work = minethd::miner_work();
minethd::switch_work(work);
push_timed_event(ex_event(EV_RECONNECT, usr_pool_id), rt);
}
void executor::log_socket_error(std::string&& sError)
{
vSocketLog.emplace_back(std::move(sError));
printer::inst()->print_msg(L1, "SOCKET ERROR - %s", vSocketLog.back().msg.c_str());
}
void executor::log_result_error(std::string&& sError)
{
size_t i = 1, ln = vMineResults.size();
for(; i < ln; i++)
{
if(vMineResults[i].compare(sError))
{
vMineResults[i].increment();
break;
}
}
if(i == ln) //Not found
vMineResults.emplace_back(std::move(sError));
else
sError.clear();
}
void executor::log_result_ok(uint64_t iActualDiff)
{
iPoolHashes += iPoolDiff;
size_t ln = iTopDiff.size() - 1;
if(iActualDiff > iTopDiff[ln])
{
iTopDiff[ln] = iActualDiff;
std::sort(iTopDiff.rbegin(), iTopDiff.rend());
}
vMineResults[0].increment();
}
jpsock* executor::pick_pool_by_id(size_t pool_id)
{
assert(pool_id != invalid_pool_id);
if(pool_id == dev_pool_id)
return dev_pool;
else
return usr_pool;
}
void executor::on_sock_ready(size_t pool_id)
{
jpsock* pool = pick_pool_by_id(pool_id);
if(pool_id == dev_pool_id)
{
if(!pool->cmd_login("", ""))
pool->disconnect();
current_pool_id = dev_pool_id;
printer::inst()->print_msg(L1, "Dev pool logged in. Switching work.");
return;
}
printer::inst()->print_msg(L1, "Connected. Logging in...");
if (!pool->cmd_login(jconf::inst()->GetWalletAddress(), jconf::inst()->GetPoolPwd()))
{
if(!pool->have_sock_error())
{
log_socket_error(pool->get_call_error());
pool->disconnect();
}
}
else
{
iReconnectAttempts = 0;
reset_stats();
}
}
void executor::on_sock_error(size_t pool_id, std::string&& sError)
{
jpsock* pool = pick_pool_by_id(pool_id);
if(pool_id == dev_pool_id)
{
pool->disconnect();
if(current_pool_id != dev_pool_id)
return;
printer::inst()->print_msg(L1, "Dev pool connection error. Switching work.");
on_switch_pool(usr_pool_id);
return;
}
log_socket_error(std::move(sError));
pool->disconnect();
sched_reconnect();
}
void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob)
{
if(pool_id != current_pool_id)
return;
jpsock* pool = pick_pool_by_id(pool_id);
minethd::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget, pool_id);
minethd::switch_work(oWork);
if(pool_id == dev_pool_id)
return;
if(iPoolDiff != pool->get_current_diff())
{
iPoolDiff = pool->get_current_diff();
printer::inst()->print_msg(L2, "Difficulty changed. Now: %llu.", int_port(iPoolDiff));
}
printer::inst()->print_msg(L3, "New block detected.");
}
void executor::on_miner_result(size_t pool_id, job_result& oResult)
{
jpsock* pool = pick_pool_by_id(pool_id);
*(uint32_t*)(oResult.bWorkBlob + 39) = oResult.iNonce;
if(jconf::inst()->HaveHardwareAes())
cryptonight_hash_ctx(oResult.bWorkBlob, oResult.iWorkLen, oResult.bResult, cpu_ctx);
else
cryptonight_hash_ctx_soft(oResult.bWorkBlob, oResult.iWorkLen, oResult.bResult, cpu_ctx);
bool bVerified = ((uint32_t*)oResult.bResult)[7] < oResult.iTarget;
if(pool_id == dev_pool_id)
{
//Ignore errors silently
if(pool->is_running() && pool->is_logged_in() && bVerified)
pool->cmd_submit(oResult.sJobID, oResult.iNonce, oResult.bResult);
return;
}
if (!bVerified)
{
log_result_error("[GPU COMPUTE ERROR]");
return;
}
if (!pool->is_running() || !pool->is_logged_in())
{
log_result_error("[NETWORK ERROR]");
return;
}
using namespace std::chrono;
size_t t_start = time_point_cast(high_resolution_clock::now()).time_since_epoch().count();
bool bResult = pool->cmd_submit(oResult.sJobID, oResult.iNonce, oResult.bResult);
size_t t_len = time_point_cast(high_resolution_clock::now()).time_since_epoch().count() - t_start;
if(t_len > 0xFFFF)
t_len = 0xFFFF;
iPoolCallTimes.push_back((uint16_t)t_len);
if(bResult)
{
uint64_t* targets = (uint64_t*)oResult.bResult;
log_result_ok(jpsock::t64_to_diff(targets[3]));
printer::inst()->print_msg(L3, "Result accepted by the pool.");
}
else
{
if(!pool->have_sock_error())
{
printer::inst()->print_msg(L3, "Result rejected by the pool.");
std::string error = pool->get_call_error();
if(strncasecmp(error.c_str(), "Unauthenticated", 15) == 0)
{
printer::inst()->print_msg(L2, "Your miner was unable to find a share in time. Either the pool difficulty is too high, or the pool timeout is too low.");
pool->disconnect();
}
log_result_error(std::move(error));
}
else
log_result_error("[NETWORK ERROR]");
}
}
void executor::on_reconnect(size_t pool_id)
{
jpsock* pool = pick_pool_by_id(pool_id);
std::string error;
if(pool_id == dev_pool_id)
return;
printer::inst()->print_msg(L1, "Connecting to pool %s ...", jconf::inst()->GetPoolAddress());
if(!pool->connect(jconf::inst()->GetPoolAddress(), error))
{
log_socket_error(std::move(error));
sched_reconnect();
}
}
void executor::on_switch_pool(size_t pool_id)
{
if(pool_id == current_pool_id)
return;
jpsock* pool = pick_pool_by_id(pool_id);
if(pool_id == dev_pool_id)
{
std::string error;
// If it fails, it fails, we carry on on the usr pool
// as we never receive further events
printer::inst()->print_msg(L1, "Connecting to dev pool...");
const char* dev_pool_addr = jconf::inst()->GetTlsSetting() ? "donate.xmr-stak.net:6666" : "donate.xmr-stak.net:3333";
if(!pool->connect(dev_pool_addr, error))
printer::inst()->print_msg(L1, "Error connecting to dev pool. Staying with user pool.");
}
else
{
printer::inst()->print_msg(L1, "Switching back to user pool.");
current_pool_id = pool_id;
pool_job oPoolJob;
if(!pool->get_current_job(oPoolJob))
{
pool->disconnect();
return;
}
minethd::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget, pool_id);
minethd::switch_work(oWork);
if(dev_pool->is_running())
push_timed_event(ex_event(EV_DEV_POOL_EXIT), 5);
}
}
void executor::ex_main()
{
assert(1000 % iTickTime == 0);
minethd::miner_work oWork = minethd::miner_work();
pvThreads = minethd::thread_starter(oWork);
telem = new telemetry(pvThreads->size());
current_pool_id = usr_pool_id;
usr_pool = new jpsock(usr_pool_id, jconf::inst()->GetTlsSetting());
dev_pool = new jpsock(dev_pool_id, jconf::inst()->GetTlsSetting());
ex_event ev;
std::thread clock_thd(&executor::ex_clock_thd, this);
//This will connect us to the pool for the first time
push_event(ex_event(EV_RECONNECT, usr_pool_id));
// Place the default success result at postion 0, it needs to
// be here even if our first result is a failure
vMineResults.emplace_back();
// If the user requested it, start the autohash printer
if(jconf::inst()->GetVerboseLevel() >= 4)
push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime());
size_t cnt = 0, i;
while (true)
{
ev = oEventQ.pop();
switch (ev.iName)
{
case EV_SOCK_READY:
on_sock_ready(ev.iPoolId);
break;
case EV_SOCK_ERROR:
on_sock_error(ev.iPoolId, std::move(ev.sSocketError));
break;
case EV_POOL_HAVE_JOB:
on_pool_have_job(ev.iPoolId, ev.oPoolJob);
break;
case EV_MINER_HAVE_RESULT:
on_miner_result(ev.iPoolId, ev.oJobResult);
break;
case EV_RECONNECT:
on_reconnect(ev.iPoolId);
break;
case EV_SWITCH_POOL:
on_switch_pool(ev.iPoolId);
break;
case EV_DEV_POOL_EXIT:
dev_pool->disconnect();
break;
case EV_PERF_TICK:
for (i = 0; i < pvThreads->size(); i++)
telem->push_perf_value(i, pvThreads->at(i)->iHashCount.load(std::memory_order_relaxed),
pvThreads->at(i)->iTimestamp.load(std::memory_order_relaxed));
if((cnt++ & 0xF) == 0) //Every 16 ticks
{
double fHps = 0.0;
for (i = 0; i < pvThreads->size(); i++)
fHps += telem->calc_telemetry_data(10000, i);
if(fHighestHps < fHps)
fHighestHps = fHps;
}
break;
case EV_USR_HASHRATE:
case EV_USR_RESULTS:
case EV_USR_CONNSTAT:
print_report(ev.iName);
break;
case EV_HTML_HASHRATE:
case EV_HTML_RESULTS:
case EV_HTML_CONNSTAT:
http_report(ev.iName);
break;
case EV_HASHRATE_LOOP:
print_report(EV_USR_HASHRATE);
push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime());
break;
case EV_INVALID_VAL:
default:
assert(false);
break;
}
}
}
inline const char* hps_format(double h, char* buf, size_t l)
{
if(std::isnormal(h) || h == 0.0)
{
snprintf(buf, l, " %03.1f", h);
return buf;
}
else
return " (na)";
}
void executor::hashrate_report(std::string& out)
{
char num[32];
size_t nthd = pvThreads->size();
out.reserve(256 + nthd * 64);
double fTotal[3] = { 0.0, 0.0, 0.0};
size_t i;
out.append("HASHRATE REPORT\n");
out.append("| ID | 10s | 60s | 15m |");
if(nthd != 1)
out.append(" ID | 10s | 60s | 15m |\n");
else
out.append(1, '\n');
for (i = 0; i < nthd; i++)
{
double fHps[3];
fHps[0] = telem->calc_telemetry_data(10000, i);
fHps[1] = telem->calc_telemetry_data(60000, i);
fHps[2] = telem->calc_telemetry_data(900000, i);
snprintf(num, sizeof(num), "| %2u |", (unsigned int)i);
out.append(num);
out.append(hps_format(fHps[0], num, sizeof(num))).append(" |");
out.append(hps_format(fHps[1], num, sizeof(num))).append(" |");
out.append(hps_format(fHps[2], num, sizeof(num))).append(1, ' ');
fTotal[0] += fHps[0];
fTotal[1] += fHps[1];
fTotal[2] += fHps[2];
if((i & 0x1) == 1) //Odd i's
out.append("|\n");
}
if((i & 0x1) == 1) //We had odd number of threads
out.append("|\n");
if(nthd != 1)
out.append("-----------------------------------------------------\n");
else
out.append("---------------------------\n");
out.append("Totals: ");
out.append(hps_format(fTotal[0], num, sizeof(num)));
out.append(hps_format(fTotal[1], num, sizeof(num)));
out.append(hps_format(fTotal[2], num, sizeof(num)));
out.append(" H/s\nHighest: ");
out.append(hps_format(fHighestHps, num, sizeof(num)));
out.append(" H/s\n");
}
char* time_format(char* buf, size_t len, std::chrono::system_clock::time_point time)
{
time_t ctime = std::chrono::system_clock::to_time_t(time);
tm stime;
/*
* Oh for god's sake... this feels like we are back to the 90's...
* and don't get me started on lack strcpy_s because NIH - use non-standard strlcpy...
* And of course C++ implements unsafe version because... reasons
*/
#ifdef _WIN32
localtime_s(&stime, &ctime);
#else
localtime_r(&ctime, &stime);
#endif // __WIN32
strftime(buf, len, "%F %T", &stime);
return buf;
}
void executor::result_report(std::string& out)
{
char num[128];
char date[32];
out.reserve(1024);
size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes;
size_t ln = vMineResults.size();
for(size_t i=1; i < ln; i++)
iTotalRes += vMineResults[i].count;
out.append("RESULT REPORT\n");
if(iTotalRes == 0)
{
out.append("You haven't found any results yet.\n");
return;
}
double dConnSec;
{
using namespace std::chrono;
dConnSec = (double)duration_cast(system_clock::now() - tPoolConnTime).count();
}
snprintf(num, sizeof(num), " (%.1f %%)\n", 100.0 * iGoodRes / iTotalRes);
out.append("Difficulty : ").append(std::to_string(iPoolDiff)).append(1, '\n');
out.append("Good results : ").append(std::to_string(iGoodRes)).append(" / ").
append(std::to_string(iTotalRes)).append(num);
if(iPoolCallTimes.size() != 0)
{
// Here we use iPoolCallTimes since it also gets reset when we disconnect
snprintf(num, sizeof(num), "%.1f sec\n", dConnSec / iPoolCallTimes.size());
out.append("Avg result time : ").append(num);
}
out.append("Pool-side hashes : ").append(std::to_string(iPoolHashes)).append(2, '\n');
out.append("Top 10 best results found:\n");
for(size_t i=0; i < 10; i += 2)
{
snprintf(num, sizeof(num), "| %2llu | %16llu | %2llu | %16llu |\n",
int_port(i), int_port(iTopDiff[i]), int_port(i+1), int_port(iTopDiff[i+1]));
out.append(num);
}
out.append("\nError details:\n");
if(ln > 1)
{
out.append("| Count | Error text | Last seen |\n");
for(size_t i=1; i < ln; i++)
{
snprintf(num, sizeof(num), "| %5llu | %-32.32s | %s |\n", int_port(vMineResults[i].count),
vMineResults[i].msg.c_str(), time_format(date, sizeof(date), vMineResults[i].time));
out.append(num);
}
}
else
out.append("Yay! No errors.\n");
}
void executor::connection_report(std::string& out)
{
char num[128];
char date[32];
out.reserve(512);
jpsock* pool = pick_pool_by_id(dev_pool_id + 1);
out.append("CONNECTION REPORT\n");
if (pool->is_running() && pool->is_logged_in())
out.append("Connected since : ").append(time_format(date, sizeof(date), tPoolConnTime)).append(1, '\n');
else
out.append("Connected since : \n");
size_t n_calls = iPoolCallTimes.size();
if (n_calls > 1)
{
//Not-really-but-good-enough median
std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end());
out.append("Pool ping time : ").append(std::to_string(iPoolCallTimes[n_calls/2])).append(" ms\n");
}
else
out.append("Pool ping time : (n/a)\n");
out.append("\nNetwork error log:\n");
size_t ln = vSocketLog.size();
if(ln > 0)
{
out.append("| Date | Error text |\n");
for(size_t i=0; i < ln; i++)
{
snprintf(num, sizeof(num), "| %s | %-54.54s |\n",
time_format(date, sizeof(date), vSocketLog[i].time), vSocketLog[i].msg.c_str());
out.append(num);
}
}
else
out.append("Yay! No errors.\n");
}
void executor::print_report(ex_event_name ev)
{
std::string out;
switch(ev)
{
case EV_USR_HASHRATE:
hashrate_report(out);
break;
case EV_USR_RESULTS:
result_report(out);
break;
case EV_USR_CONNSTAT:
connection_report(out);
break;
default:
assert(false);
break;
}
printer::inst()->print_str(out.c_str());
}
void executor::http_hashrate_report(std::string& out)
{
char num_a[32], num_b[32], num_c[32], num_d[32];
char buffer[4096];
size_t nthd = pvThreads->size();
out.reserve(4096);
snprintf(buffer, sizeof(buffer), sHtmlCommonHeader, "Hashrate Report", "Hashrate Report");
out.append(buffer);
snprintf(buffer, sizeof(buffer), sHtmlHashrateBodyHigh, (unsigned int)nthd + 3);
out.append(buffer);
double fTotal[3] = { 0.0, 0.0, 0.0};
for(size_t i=0; i < nthd; i++)
{
double fHps[3];
fHps[0] = telem->calc_telemetry_data(10000, i);
fHps[1] = telem->calc_telemetry_data(60000, i);
fHps[2] = telem->calc_telemetry_data(900000, i);
num_a[0] = num_b[0] = num_c[0] ='\0';
hps_format(fHps[0], num_a, sizeof(num_a));
hps_format(fHps[1], num_b, sizeof(num_b));
hps_format(fHps[2], num_c, sizeof(num_c));
fTotal[0] += fHps[0];
fTotal[1] += fHps[1];
fTotal[2] += fHps[2];
snprintf(buffer, sizeof(buffer), sHtmlHashrateTableRow, (unsigned int)i, num_a, num_b, num_c);
out.append(buffer);
}
num_a[0] = num_b[0] = num_c[0] = num_d[0] ='\0';
hps_format(fTotal[0], num_a, sizeof(num_a));
hps_format(fTotal[1], num_b, sizeof(num_b));
hps_format(fTotal[2], num_c, sizeof(num_c));
hps_format(fHighestHps, num_d, sizeof(num_d));
snprintf(buffer, sizeof(buffer), sHtmlHashrateBodyLow, num_a, num_b, num_c, num_d);
out.append(buffer);
}
void executor::http_result_report(std::string& out)
{
char date[128];
char buffer[4096];
out.reserve(4096);
snprintf(buffer, sizeof(buffer), sHtmlCommonHeader, "Result Report", "Result Report");
out.append(buffer);
size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes;
size_t ln = vMineResults.size();
for(size_t i=1; i < ln; i++)
iTotalRes += vMineResults[i].count;
double fGoodResPrc = 0.0;
if(iTotalRes > 0)
fGoodResPrc = 100.0 * iGoodRes / iTotalRes;
double fAvgResTime = 0.0;
if(iPoolCallTimes.size() > 0)
{
using namespace std::chrono;
fAvgResTime = ((double)duration_cast(system_clock::now() - tPoolConnTime).count())
/ iPoolCallTimes.size();
}
snprintf(buffer, sizeof(buffer), sHtmlResultBodyHigh,
iPoolDiff, iGoodRes, iTotalRes, fGoodResPrc, fAvgResTime, iPoolHashes,
int_port(iTopDiff[0]), int_port(iTopDiff[1]), int_port(iTopDiff[2]), int_port(iTopDiff[3]),
int_port(iTopDiff[4]), int_port(iTopDiff[5]), int_port(iTopDiff[6]), int_port(iTopDiff[7]),
int_port(iTopDiff[8]), int_port(iTopDiff[9]));
out.append(buffer);
for(size_t i=1; i < vMineResults.size(); i++)
{
snprintf(buffer, sizeof(buffer), sHtmlResultTableRow, vMineResults[i].msg.c_str(),
int_port(vMineResults[i].count), time_format(date, sizeof(date), vMineResults[i].time));
out.append(buffer);
}
out.append(sHtmlResultBodyLow);
}
void executor::http_connection_report(std::string& out)
{
char date[128];
char buffer[4096];
out.reserve(4096);
snprintf(buffer, sizeof(buffer), sHtmlCommonHeader, "Connection Report", "Connection Report");
out.append(buffer);
jpsock* pool = pick_pool_by_id(dev_pool_id + 1);
const char* cdate = "not connected";
if (pool->is_running() && pool->is_logged_in())
cdate = time_format(date, sizeof(date), tPoolConnTime);
size_t n_calls = iPoolCallTimes.size();
unsigned int ping_time = 0;
if (n_calls > 1)
{
//Not-really-but-good-enough median
std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end());
ping_time = iPoolCallTimes[n_calls/2];
}
snprintf(buffer, sizeof(buffer), sHtmlConnectionBodyHigh,
jconf::inst()->GetPoolAddress(),
cdate, ping_time);
out.append(buffer);
for(size_t i=0; i < vSocketLog.size(); i++)
{
snprintf(buffer, sizeof(buffer), sHtmlConnectionTableRow,
time_format(date, sizeof(date), vSocketLog[i].time), vSocketLog[i].msg.c_str());
out.append(buffer);
}
out.append(sHtmlConnectionBodyLow);
}
void executor::http_report(ex_event_name ev)
{
assert(pHttpString != nullptr);
switch(ev)
{
case EV_HTML_HASHRATE:
http_hashrate_report(*pHttpString);
break;
case EV_HTML_RESULTS:
http_result_report(*pHttpString);
break;
case EV_HTML_CONNSTAT:
http_connection_report(*pHttpString);
break;
default:
assert(false);
break;
}
httpReady.set_value();
}
void executor::get_http_report(ex_event_name ev_id, std::string& data)
{
std::lock_guard lck(httpMutex);
assert(pHttpString == nullptr);
assert(ev_id == EV_HTML_HASHRATE || ev_id == EV_HTML_RESULTS || ev_id == EV_HTML_CONNSTAT);
pHttpString = &data;
httpReady = std::promise();
std::future ready = httpReady.get_future();
push_event(ex_event(ev_id));
ready.wait();
pHttpString = nullptr;
}
================================================
FILE: executor.h
================================================
#pragma once
#include "thdq.hpp"
#include "msgstruct.h"
#include
#include
#include
#include
#include "crypto/cryptonight.h"
class jpsock;
class minethd;
class telemetry;
class executor
{
public:
static executor* inst()
{
if (oInst == nullptr) oInst = new executor;
return oInst;
};
void ex_start(bool daemon) { daemon ? ex_main() : std::thread(&executor::ex_main, this).detach(); }
void get_http_report(ex_event_name ev_id, std::string& data);
inline void push_event(ex_event&& ev) { oEventQ.push(std::move(ev)); }
void push_timed_event(ex_event&& ev, size_t sec);
constexpr static size_t invalid_pool_id = 0;
constexpr static size_t dev_pool_id = 1;
constexpr static size_t usr_pool_id = 2;
private:
struct timed_event
{
ex_event event;
size_t ticks_left;
timed_event(ex_event&& ev, size_t ticks) : event(std::move(ev)), ticks_left(ticks) {}
};
cryptonight_ctx* cpu_ctx;
// In miliseconds, has to divide a second (1000ms) into an integer number
constexpr static size_t iTickTime = 500;
// Dev donation time period in seconds. 100 minutes by default.
// We will divide up this period according to the config setting
constexpr static size_t iDevDonatePeriod = 100 * 60;
std::list lTimedEvents;
std::mutex timed_event_mutex;
thdq oEventQ;
telemetry* telem;
std::vector* pvThreads;
size_t current_pool_id;
jpsock* usr_pool;
jpsock* dev_pool;
jpsock* pick_pool_by_id(size_t pool_id);
bool is_dev_time;
executor();
static executor* oInst;
void ex_main();
void ex_clock_thd();
void pool_connect(jpsock* pool);
void hashrate_report(std::string& out);
void result_report(std::string& out);
void connection_report(std::string& out);
void http_hashrate_report(std::string& out);
void http_result_report(std::string& out);
void http_connection_report(std::string& out);
void http_report(ex_event_name ev);
void print_report(ex_event_name ev);
std::string* pHttpString = nullptr;
std::promise httpReady;
std::mutex httpMutex;
size_t iReconnectAttempts = 0;
struct sck_error_log
{
std::chrono::system_clock::time_point time;
std::string msg;
sck_error_log(std::string&& err) : msg(std::move(err))
{
time = std::chrono::system_clock::now();
}
};
std::vector vSocketLog;
// Element zero is always the success element.
// Keep in mind that this is a tally and not a log like above
struct result_tally
{
std::chrono::system_clock::time_point time;
std::string msg;
size_t count;
result_tally() : msg("[OK]"), count(0)
{
time = std::chrono::system_clock::now();
}
result_tally(std::string&& err) : msg(std::move(err)), count(1)
{
time = std::chrono::system_clock::now();
}
void increment()
{
count++;
time = std::chrono::system_clock::now();
}
bool compare(std::string& err)
{
if(msg == err)
{
increment();
return true;
}
else
return false;
}
};
std::vector vMineResults;
//More result statistics
std::array iTopDiff { { } }; //Initialize to zero
std::chrono::system_clock::time_point tPoolConnTime;
size_t iPoolHashes = 0;
uint64_t iPoolDiff = 0;
// Set it to 16 bit so that we can just let it grow
// Maximum realistic growth rate - 5MB / month
std::vector iPoolCallTimes;
//Those stats are reset if we disconnect
inline void reset_stats()
{
iPoolCallTimes.clear();
tPoolConnTime = std::chrono::system_clock::now();
iPoolHashes = 0;
iPoolDiff = 0;
}
double fHighestHps = 0.0;
void log_socket_error(std::string&& sError);
void log_result_error(std::string&& sError);
void log_result_ok(uint64_t iActualDiff);
void sched_reconnect();
void on_sock_ready(size_t pool_id);
void on_sock_error(size_t pool_id, std::string&& sError);
void on_pool_have_job(size_t pool_id, pool_job& oPoolJob);
void on_miner_result(size_t pool_id, job_result& oResult);
void on_reconnect(size_t pool_id);
void on_switch_pool(size_t pool_id);
inline size_t sec_to_ticks(size_t sec) { return sec * (1000 / iTickTime); }
};
================================================
FILE: httpd.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
#ifndef CONF_NO_HTTPD
#include
#include
#include
#include
#include "msgstruct.h"
#include "httpd.h"
#include "console.h"
#include "executor.h"
#include "jconf.h"
#include "webdesign.h"
#ifdef _WIN32
#include "libmicrohttpd/microhttpd.h"
#define strcasecmp _stricmp
#else
#include
#endif // _WIN32
httpd* httpd::oInst = nullptr;
httpd::httpd()
{
}
int httpd::req_handler(void * cls,
MHD_Connection* connection,
const char* url,
const char* method,
const char* version,
const char* upload_data,
size_t* upload_data_size,
void ** ptr)
{
struct MHD_Response * rsp;
if (strcmp(method, "GET") != 0)
return MHD_NO;
*ptr = nullptr;
std::string str;
if(strcasecmp(url, "/style.css") == 0)
{
const char* req_etag = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "If-None-Match");
if(req_etag != NULL && strcmp(req_etag, sHtmlCssEtag) == 0)
{ //Cache hit
rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_PERSISTENT);
int ret = MHD_queue_response(connection, MHD_HTTP_NOT_MODIFIED, rsp);
MHD_destroy_response(rsp);
return ret;
}
rsp = MHD_create_response_from_buffer(sHtmlCssSize, (void*)sHtmlCssFile, MHD_RESPMEM_PERSISTENT);
MHD_add_response_header(rsp, "ETag", sHtmlCssEtag);
MHD_add_response_header(rsp, "Content-Type", "text/css; charset=utf-8");
}
else if(strcasecmp(url, "/h") == 0 || strcasecmp(url, "/hashrate") == 0)
{
executor::inst()->get_http_report(EV_HTML_HASHRATE, str);
rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(rsp, "Content-Type", "text/html; charset=utf-8");
}
else if(strcasecmp(url, "/c") == 0 || strcasecmp(url, "/connection") == 0)
{
executor::inst()->get_http_report(EV_HTML_CONNSTAT, str);
rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(rsp, "Content-Type", "text/html; charset=utf-8");
}
else if(strcasecmp(url, "/r") == 0 || strcasecmp(url, "/results") == 0)
{
executor::inst()->get_http_report(EV_HTML_RESULTS, str);
rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(rsp, "Content-Type", "text/html; charset=utf-8");
}
else
{
//Do a 302 redirect to /h
char loc_path[256];
const char* host_val = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Host");
if(host_val != nullptr)
snprintf(loc_path, sizeof(loc_path), "http://%s/h", host_val);
else
snprintf(loc_path, sizeof(loc_path), "/h");
rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_PERSISTENT);
int ret = MHD_queue_response(connection, MHD_HTTP_TEMPORARY_REDIRECT, rsp);
MHD_add_response_header(rsp, "Location", loc_path);
MHD_destroy_response(rsp);
return ret;
}
int ret = MHD_queue_response(connection, MHD_HTTP_OK, rsp);
MHD_destroy_response(rsp);
return ret;
}
bool httpd::start_daemon()
{
d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
jconf::inst()->GetHttpdPort(), NULL, NULL,
&httpd::req_handler,
NULL, MHD_OPTION_END);
if(d == nullptr)
{
printer::inst()->print_str("HTTP Daemon failed to start.");
return false;
}
return true;
}
#endif
================================================
FILE: httpd.h
================================================
#pragma once
struct MHD_Daemon;
struct MHD_Connection;
class httpd
{
public:
static httpd* inst()
{
if (oInst == nullptr) oInst = new httpd;
return oInst;
};
bool start_daemon();
private:
httpd();
static httpd* oInst;
static int req_handler(void * cls,
MHD_Connection* connection,
const char* url,
const char* method,
const char* version,
const char* upload_data,
size_t* upload_data_size,
void ** ptr);
MHD_Daemon *d;
};
================================================
FILE: jconf.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
#include "jconf.h"
#include "console.h"
#include
#include
#include
#ifdef _WIN32
#define strcasecmp _stricmp
#include
#else
#include
#endif
#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
#include "jext.h"
#include "console.h"
using namespace rapidjson;
/*
* This enum needs to match index in oConfigValues, otherwise we will get a runtime error
*/
enum configEnum { iGpuThreadNum, aGpuThreadsConf, iPlatformIdx,
bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd,
iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime,
bDaemonMode, sOutputFile, iHttpdPort, bPreferIpv4 };
struct configVal {
configEnum iName;
const char* sName;
Type iType;
};
//Same order as in configEnum, as per comment above
configVal oConfigValues[] = {
{ iGpuThreadNum, "gpu_thread_num", kNumberType },
{ aGpuThreadsConf, "gpu_threads_conf", kArrayType },
{ iPlatformIdx, "platform_index", kNumberType },
{ bTlsMode, "use_tls", kTrueType },
{ bTlsSecureAlgo, "tls_secure_algo", kTrueType },
{ sTlsFingerprint, "tls_fingerprint", kStringType },
{ sPoolAddr, "pool_address", kStringType },
{ sWalletAddr, "wallet_address", kStringType },
{ sPoolPwd, "pool_password", kStringType },
{ iCallTimeout, "call_timeout", kNumberType },
{ iNetRetry, "retry_time", kNumberType },
{ iGiveUpLimit, "giveup_limit", kNumberType },
{ iVerboseLevel, "verbose_level", kNumberType },
{ iAutohashTime, "h_print_time", kNumberType },
{ bDaemonMode, "daemon_mode", kTrueType },
{ sOutputFile, "output_file", kStringType },
{ iHttpdPort, "httpd_port", kNumberType },
{ bPreferIpv4, "prefer_ipv4", kTrueType }
};
constexpr size_t iConfigCnt = (sizeof(oConfigValues)/sizeof(oConfigValues[0]));
inline bool checkType(Type have, Type want)
{
if(want == have)
return true;
else if(want == kTrueType && have == kFalseType)
return true;
else if(want == kFalseType && have == kTrueType)
return true;
else
return false;
}
struct jconf::opaque_private
{
Document jsonDoc;
const Value* configValues[iConfigCnt]; //Compile time constant
opaque_private()
{
}
};
jconf* jconf::oInst = nullptr;
jconf::jconf()
{
prv = new opaque_private();
}
bool jconf::GetThreadConfig(size_t id, thd_cfg &cfg)
{
if(id >= prv->configValues[aGpuThreadsConf]->Size())
return false;
const Value& oThdConf = prv->configValues[aGpuThreadsConf]->GetArray()[id];
if(!oThdConf.IsObject())
return false;
const Value *idx, *intensity, *w_size, *aff;
idx = GetObjectMember(oThdConf, "index");
intensity = GetObjectMember(oThdConf, "intensity");
w_size = GetObjectMember(oThdConf, "worksize");
aff = GetObjectMember(oThdConf, "affine_to_cpu");
if(idx == nullptr || intensity == nullptr || w_size == nullptr || aff == nullptr)
return false;
if(!idx->IsUint64() || !intensity->IsUint64() || !w_size->IsUint64())
return false;
if(!aff->IsUint64() && !aff->IsBool())
return false;
cfg.index = idx->GetUint64();
cfg.intensity = intensity->GetUint64();
cfg.w_size = w_size->GetUint64();
if(aff->IsNumber())
cfg.cpu_aff = aff->GetInt64();
else
cfg.cpu_aff = -1;
return true;
}
size_t jconf::GetPlatformIdx()
{
return prv->configValues[iPlatformIdx]->GetUint64();
}
bool jconf::GetTlsSetting()
{
return prv->configValues[bTlsMode]->GetBool();
}
bool jconf::TlsSecureAlgos()
{
return prv->configValues[bTlsSecureAlgo]->GetBool();
}
const char* jconf::GetTlsFingerprint()
{
return prv->configValues[sTlsFingerprint]->GetString();
}
const char* jconf::GetPoolAddress()
{
return prv->configValues[sPoolAddr]->GetString();
}
const char* jconf::GetPoolPwd()
{
return prv->configValues[sPoolPwd]->GetString();
}
const char* jconf::GetWalletAddress()
{
return prv->configValues[sWalletAddr]->GetString();
}
bool jconf::PreferIpv4()
{
return prv->configValues[bPreferIpv4]->GetBool();
}
size_t jconf::GetThreadCount()
{
return prv->configValues[aGpuThreadsConf]->Size();
}
uint64_t jconf::GetCallTimeout()
{
return prv->configValues[iCallTimeout]->GetUint64();
}
uint64_t jconf::GetNetRetry()
{
return prv->configValues[iNetRetry]->GetUint64();
}
uint64_t jconf::GetGiveUpLimit()
{
return prv->configValues[iGiveUpLimit]->GetUint64();
}
uint64_t jconf::GetVerboseLevel()
{
return prv->configValues[iVerboseLevel]->GetUint64();
}
uint64_t jconf::GetAutohashTime()
{
return prv->configValues[iAutohashTime]->GetUint64();
}
uint16_t jconf::GetHttpdPort()
{
return prv->configValues[iHttpdPort]->GetUint();
}
bool jconf::DaemonMode()
{
return prv->configValues[bDaemonMode]->GetBool();
}
const char* jconf::GetOutputFile()
{
return prv->configValues[sOutputFile]->GetString();
}
bool jconf::check_cpu_features()
{
constexpr int AESNI_BIT = 1 << 25;
constexpr int SSE2_BIT = 1 << 26;
int cpu_info[4];
#ifdef _WIN32
__cpuid(cpu_info, 1);
#else
__cpuid(1, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
#endif
bHaveAes = (cpu_info[2] & AESNI_BIT) != 0;
return (cpu_info[3] & SSE2_BIT) != 0;
}
bool jconf::parse_config(const char* sFilename)
{
FILE * pFile;
char * buffer;
size_t flen;
if(!check_cpu_features())
{
printer::inst()->print_msg(L0, "CPU support of SSE2 is required.");
return false;
}
pFile = fopen(sFilename, "rb");
if (pFile == NULL)
{
printer::inst()->print_msg(L0, "Failed to open config file %s.", sFilename);
return false;
}
fseek(pFile,0,SEEK_END);
flen = ftell(pFile);
rewind(pFile);
if(flen >= 64*1024)
{
fclose(pFile);
printer::inst()->print_msg(L0, "Oversized config file - %s.", sFilename);
return false;
}
if(flen <= 16)
{
printer::inst()->print_msg(L0, "File is empty or too short - %s.", sFilename);
return false;
}
buffer = (char*)malloc(flen + 3);
if(fread(buffer+1, flen, 1, pFile) != 1)
{
free(buffer);
fclose(pFile);
printer::inst()->print_msg(L0, "Read error while reading %s.", sFilename);
return false;
}
fclose(pFile);
//Replace Unicode BOM with spaces - we always use UTF-8
unsigned char* ubuffer = (unsigned char*)buffer;
if(ubuffer[1] == 0xEF && ubuffer[2] == 0xBB && ubuffer[3] == 0xBF)
{
buffer[1] = ' ';
buffer[2] = ' ';
buffer[3] = ' ';
}
buffer[0] = '{';
buffer[flen] = '}';
buffer[flen + 1] = '\0';
prv->jsonDoc.Parse(buffer, flen+2);
free(buffer);
if(prv->jsonDoc.HasParseError())
{
printer::inst()->print_msg(L0, "JSON config parse error(offset %llu): %s",
int_port(prv->jsonDoc.GetErrorOffset()), GetParseError_En(prv->jsonDoc.GetParseError()));
return false;
}
if(!prv->jsonDoc.IsObject())
{ //This should never happen as we created the root ourselves
printer::inst()->print_msg(L0, "Invalid config file. No root?\n");
return false;
}
for(size_t i = 0; i < iConfigCnt; i++)
{
if(oConfigValues[i].iName != i)
{
printer::inst()->print_msg(L0, "Code error. oConfigValues are not in order.");
return false;
}
prv->configValues[i] = GetObjectMember(prv->jsonDoc, oConfigValues[i].sName);
if(prv->configValues[i] == nullptr)
{
printer::inst()->print_msg(L0, "Invalid config file. Missing value \"%s\".", oConfigValues[i].sName);
return false;
}
if(!checkType(prv->configValues[i]->GetType(), oConfigValues[i].iType))
{
printer::inst()->print_msg(L0, "Invalid config file. Value \"%s\" has unexpected type.", oConfigValues[i].sName);
return false;
}
}
size_t n_thd = prv->configValues[aGpuThreadsConf]->Size();
if(prv->configValues[iGpuThreadNum]->GetUint64() != n_thd)
{
printer::inst()->print_msg(L0,
"Invalid config file. Your GPU config array has %llu members, while you want to use %llu threads.",
int_port(n_thd), int_port(prv->configValues[iGpuThreadNum]->GetUint64()));
return false;
}
thd_cfg c;
for(size_t i=0; i < n_thd; i++)
{
if(!GetThreadConfig(i, c))
{
printer::inst()->print_msg(L0, "Thread %llu has invalid config.", int_port(i));
return false;
}
}
if(!prv->configValues[iCallTimeout]->IsUint64() ||
!prv->configValues[iNetRetry]->IsUint64() ||
!prv->configValues[iGiveUpLimit]->IsUint64())
{
printer::inst()->print_msg(L0,
"Invalid config file. call_timeout, retry_time and giveup_limit need to be positive integers.");
return false;
}
if(!prv->configValues[iVerboseLevel]->IsUint64() || !prv->configValues[iAutohashTime]->IsUint64())
{
printer::inst()->print_msg(L0,
"Invalid config file. verbose_level and h_print_time need to be positive integers.");
return false;
}
if(!prv->configValues[iHttpdPort]->IsUint() || prv->configValues[iHttpdPort]->GetUint() > 0xFFFF)
{
printer::inst()->print_msg(L0,
"Invalid config file. httpd_port has to be in the range 0 to 65535.");
return false;
}
#ifdef CONF_NO_TLS
if(prv->configValues[bTlsMode]->GetBool())
{
printer::inst()->print_msg(L0,
"Invalid config file. TLS enabled while the application has been compiled without TLS support.");
return false;
}
#endif // CONF_NO_TLS
printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64());
return true;
}
================================================
FILE: jconf.h
================================================
#pragma once
#include
#include
class jconf
{
public:
static jconf* inst()
{
if (oInst == nullptr) oInst = new jconf;
return oInst;
};
bool parse_config(const char* sFilename);
struct thd_cfg {
size_t index;
size_t intensity;
size_t w_size;
long long cpu_aff;
};
size_t GetThreadCount();
bool GetThreadConfig(size_t id, thd_cfg &cfg);
size_t GetPlatformIdx();
bool GetTlsSetting();
bool TlsSecureAlgos();
const char* GetTlsFingerprint();
const char* GetPoolAddress();
const char* GetPoolPwd();
const char* GetWalletAddress();
uint64_t GetVerboseLevel();
uint64_t GetAutohashTime();
const char* GetOutputFile();
uint64_t GetCallTimeout();
uint64_t GetNetRetry();
uint64_t GetGiveUpLimit();
uint16_t GetHttpdPort();
bool DaemonMode();
bool PreferIpv4();
inline bool HaveHardwareAes() { return bHaveAes; }
private:
jconf();
static jconf* oInst;
bool check_cpu_features();
struct opaque_private;
opaque_private* prv;
bool bHaveAes;
};
================================================
FILE: jext.h
================================================
#pragma once
using namespace rapidjson;
/* This macro brings rapidjson more in line with other libs */
inline const Value* GetObjectMember(const Value& obj, const char* key)
{
Value::ConstMemberIterator itr = obj.FindMember(key);
if (itr != obj.MemberEnd())
return &itr->value;
else
return nullptr;
}
================================================
FILE: jpsock.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
#include
#include
#include "jpsock.h"
#include "executor.h"
#include "jconf.h"
#include "rapidjson/document.h"
#include "jext.h"
#include "socks.h"
#include "socket.h"
#include "version.h"
#define AGENTID_STR XMR_STAK_NAME "/" XMR_STAK_VERSION
using namespace rapidjson;
struct jpsock::call_rsp
{
bool bHaveResponse;
uint64_t iCallId;
Value* pCallData;
std::string sCallErr;
call_rsp(Value* val) : pCallData(val)
{
bHaveResponse = false;
iCallId = 0;
sCallErr.clear();
}
};
typedef GenericDocument, MemoryPoolAllocator<>, MemoryPoolAllocator<>> MemDocument;
/*
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* ASSUMPTION - only one calling thread. Multiple calling threads would require better
* thread safety. The calling thread is assumed to be the executor thread.
* If there is a reason to call the pool outside of the executor context, consider
* doing it via an executor event.
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* Call values and allocators are for the calling thread (executor). When processing
* a call, the recv thread will make a copy of the call response and then erase its copy.
*/
struct jpsock::opaque_private
{
Value oCallValue;
MemoryPoolAllocator<> callAllocator;
MemoryPoolAllocator<> recvAllocator;
MemoryPoolAllocator<> parseAllocator;
MemDocument jsonDoc;
call_rsp oCallRsp;
opaque_private(uint8_t* bCallMem, uint8_t* bRecvMem, uint8_t* bParseMem) :
callAllocator(bCallMem, jpsock::iJsonMemSize),
recvAllocator(bRecvMem, jpsock::iJsonMemSize),
parseAllocator(bParseMem, jpsock::iJsonMemSize),
jsonDoc(&recvAllocator, jpsock::iJsonMemSize, &parseAllocator),
oCallRsp(nullptr)
{
}
};
struct jpsock::opq_json_val
{
const Value* val;
opq_json_val(const Value* val) : val(val) {}
};
jpsock::jpsock(size_t id, bool tls) : pool_id(id)
{
sock_init();
bJsonCallMem = (uint8_t*)malloc(iJsonMemSize);
bJsonRecvMem = (uint8_t*)malloc(iJsonMemSize);
bJsonParseMem = (uint8_t*)malloc(iJsonMemSize);
prv = new opaque_private(bJsonCallMem, bJsonRecvMem, bJsonParseMem);
#ifndef CONF_NO_TLS
if(tls)
sck = new tls_socket(this);
else
sck = new plain_socket(this);
#else
sck = new plain_socket(this);
#endif
oRecvThd = nullptr;
bRunning = false;
bLoggedIn = false;
iJobDiff = 0;
memset(&oCurrentJob, 0, sizeof(oCurrentJob));
}
jpsock::~jpsock()
{
delete prv;
prv = nullptr;
free(bJsonCallMem);
free(bJsonRecvMem);
free(bJsonParseMem);
}
std::string&& jpsock::get_call_error()
{
return std::move(prv->oCallRsp.sCallErr);
}
bool jpsock::set_socket_error(const char* a)
{
if(!bHaveSocketError)
{
bHaveSocketError = true;
sSocketError.assign(a);
}
return false;
}
bool jpsock::set_socket_error(const char* a, const char* b)
{
if(!bHaveSocketError)
{
bHaveSocketError = true;
size_t ln_a = strlen(a);
size_t ln_b = strlen(b);
sSocketError.reserve(ln_a + ln_b + 2);
sSocketError.assign(a, ln_a);
sSocketError.append(b, ln_b);
}
return false;
}
bool jpsock::set_socket_error(const char* a, size_t len)
{
if(!bHaveSocketError)
{
bHaveSocketError = true;
sSocketError.assign(a, len);
}
return false;
}
bool jpsock::set_socket_error_strerr(const char* a)
{
char sSockErrText[512];
return set_socket_error(a, sock_strerror(sSockErrText, sizeof(sSockErrText)));
}
bool jpsock::set_socket_error_strerr(const char* a, int res)
{
char sSockErrText[512];
return set_socket_error(a, sock_gai_strerror(res, sSockErrText, sizeof(sSockErrText)));
}
void jpsock::jpsock_thread()
{
jpsock_thd_main();
executor::inst()->push_event(ex_event(std::move(sSocketError), pool_id));
// If a call is wating, send an error to end it
bool bCallWaiting = false;
std::unique_lock mlock(call_mutex);
if(prv->oCallRsp.pCallData != nullptr)
{
prv->oCallRsp.bHaveResponse = true;
prv->oCallRsp.iCallId = 0;
prv->oCallRsp.pCallData = nullptr;
bCallWaiting = true;
}
mlock.unlock();
if(bCallWaiting)
call_cond.notify_one();
bRunning = false;
bLoggedIn = false;
std::unique_lock(job_mutex);
memset(&oCurrentJob, 0, sizeof(oCurrentJob));
}
bool jpsock::jpsock_thd_main()
{
if(!sck->connect())
return false;
executor::inst()->push_event(ex_event(EV_SOCK_READY, pool_id));
char buf[iSockBufferSize];
size_t datalen = 0;
while (true)
{
int ret = sck->recv(buf + datalen, sizeof(buf) - datalen);
if(ret <= 0)
return false;
datalen += ret;
if (datalen >= sizeof(buf))
{
sck->close(false);
return set_socket_error("RECEIVE error: data overflow");
}
char* lnend;
char* lnstart = buf;
while ((lnend = (char*)memchr(lnstart, '\n', datalen)) != nullptr)
{
lnend++;
int lnlen = lnend - lnstart;
if (!process_line(lnstart, lnlen))
{
sck->close(false);
return false;
}
datalen -= lnlen;
lnstart = lnend;
}
//Got leftover data? Move it to the front
if (datalen > 0 && buf != lnstart)
memmove(buf, lnstart, datalen);
}
}
bool jpsock::process_line(char* line, size_t len)
{
prv->jsonDoc.SetNull();
prv->parseAllocator.Clear();
prv->callAllocator.Clear();
/*NULL terminate the line instead of '\n', parsing will add some more NULLs*/
line[len-1] = '\0';
//printf("RECV: %s\n", line);
if (prv->jsonDoc.ParseInsitu(line).HasParseError())
return set_socket_error("PARSE error: Invalid JSON");
if (!prv->jsonDoc.IsObject())
return set_socket_error("PARSE error: Invalid root");
const Value* mt;
if (prv->jsonDoc.HasMember("method"))
{
mt = GetObjectMember(prv->jsonDoc, "method");
if(!mt->IsString())
return set_socket_error("PARSE error: Protocol error 1");
if(strcmp(mt->GetString(), "job") != 0)
return set_socket_error("PARSE error: Unsupported server method ", mt->GetString());
mt = GetObjectMember(prv->jsonDoc, "params");
if(mt == nullptr || !mt->IsObject())
return set_socket_error("PARSE error: Protocol error 2");
opq_json_val v(mt);
return process_pool_job(&v);
}
else
{
uint64_t iCallId;
mt = GetObjectMember(prv->jsonDoc, "id");
if (mt == nullptr || !mt->IsUint64())
return set_socket_error("PARSE error: Protocol error 3");
iCallId = mt->GetUint64();
mt = GetObjectMember(prv->jsonDoc, "error");
const char* sError = nullptr;
size_t iErrorLn = 0;
if (mt == nullptr || mt->IsNull())
{
/* If there was no error we need a result */
if ((mt = GetObjectMember(prv->jsonDoc, "result")) == nullptr)
return set_socket_error("PARSE error: Protocol error 7");
}
else
{
if(!mt->IsObject())
return set_socket_error("PARSE error: Protocol error 5");
const Value* msg = GetObjectMember(*mt, "message");
if(msg == nullptr || !msg->IsString())
return set_socket_error("PARSE error: Protocol error 6");
iErrorLn = msg->GetStringLength();
sError = msg->GetString();
}
std::unique_lock mlock(call_mutex);
if (prv->oCallRsp.pCallData == nullptr)
{
/*Server sent us a call reply without us making a call*/
mlock.unlock();
return set_socket_error("PARSE error: Unexpected call response");
}
prv->oCallRsp.bHaveResponse = true;
prv->oCallRsp.iCallId = iCallId;
if(sError != nullptr)
{
prv->oCallRsp.pCallData = nullptr;
prv->oCallRsp.sCallErr.assign(sError, iErrorLn);
}
else
prv->oCallRsp.pCallData->CopyFrom(*mt, prv->callAllocator);
mlock.unlock();
call_cond.notify_one();
return true;
}
}
bool jpsock::process_pool_job(const opq_json_val* params)
{
if (!params->val->IsObject())
return set_socket_error("PARSE error: Job error 1");
const Value * blob, *jobid, *target;
jobid = GetObjectMember(*params->val, "job_id");
blob = GetObjectMember(*params->val, "blob");
target = GetObjectMember(*params->val, "target");
if (jobid == nullptr || blob == nullptr || target == nullptr ||
!jobid->IsString() || !blob->IsString() || !target->IsString())
{
return set_socket_error("PARSE error: Job error 2");
}
if (jobid->GetStringLength() >= sizeof(pool_job::sJobID)) // Note >=
return set_socket_error("PARSE error: Job error 3");
uint32_t iWorkLn = blob->GetStringLength() / 2;
if (iWorkLn > sizeof(pool_job::bWorkBlob))
return set_socket_error("PARSE error: Invalid job legth. Are you sure you are mining the correct coin?");
pool_job oPoolJob;
if (!hex2bin(blob->GetString(), iWorkLn * 2, oPoolJob.bWorkBlob))
return set_socket_error("PARSE error: Job error 4");
oPoolJob.iWorkLen = iWorkLn;
memset(oPoolJob.sJobID, 0, sizeof(pool_job::sJobID));
memcpy(oPoolJob.sJobID, jobid->GetString(), jobid->GetStringLength()); //Bounds checking at proto error 3
size_t target_slen = target->GetStringLength();
if(target_slen <= 8)
{
uint32_t iTempInt = 0;
char sTempStr[] = "00000000"; // Little-endian CPU FTW
memcpy(sTempStr, target->GetString(), target_slen);
if(!hex2bin(sTempStr, 8, (unsigned char*)&iTempInt) || iTempInt == 0)
return set_socket_error("PARSE error: Invalid target");
oPoolJob.iTarget = iTempInt;
}
else
return set_socket_error("PARSE error: Job error 5");
iJobDiff = t32_to_diff(oPoolJob.iTarget);
executor::inst()->push_event(ex_event(oPoolJob, pool_id));
std::unique_lock(job_mutex);
oCurrentJob = oPoolJob;
return true;
}
bool jpsock::connect(const char* sAddr, std::string& sConnectError)
{
bHaveSocketError = false;
sSocketError.clear();
iJobDiff = 0;
if(sck->set_hostname(sAddr))
{
bRunning = true;
oRecvThd = new std::thread(&jpsock::jpsock_thread, this);
return true;
}
sConnectError = std::move(sSocketError);
return false;
}
void jpsock::disconnect()
{
sck->close(false);
if(oRecvThd != nullptr)
{
oRecvThd->join();
delete oRecvThd;
oRecvThd = nullptr;
}
sck->close(true);
}
bool jpsock::cmd_ret_wait(const char* sPacket, opq_json_val& poResult)
{
//printf("SEND: %s\n", sPacket);
/*Set up the call rsp for the call reply*/
prv->oCallValue.SetNull();
prv->callAllocator.Clear();
std::unique_lock mlock(call_mutex);
prv->oCallRsp = call_rsp(&prv->oCallValue);
mlock.unlock();
if(!sck->send(sPacket))
{
disconnect(); //This will join the other thread;
return false;
}
//Success is true if the server approves, result is true if there was no socket error
bool bSuccess;
mlock.lock();
bool bResult = call_cond.wait_for(mlock, std::chrono::seconds(jconf::inst()->GetCallTimeout()),
[&]() { return prv->oCallRsp.bHaveResponse; });
bSuccess = prv->oCallRsp.pCallData != nullptr;
prv->oCallRsp.pCallData = nullptr;
mlock.unlock();
if(bHaveSocketError)
return false;
//This means that there was no socket error, but the server is not taking to us
if(!bResult)
{
set_socket_error("CALL error: Timeout while waiting for a reply");
disconnect();
return false;
}
if(bSuccess)
poResult.val = &prv->oCallValue;
return bSuccess;
}
bool jpsock::cmd_login(const char* sLogin, const char* sPassword)
{
char cmd_buffer[1024];
snprintf(cmd_buffer, sizeof(cmd_buffer), "{\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"" AGENTID_STR "\"},\"id\":1}\n",
sLogin, sPassword);
opq_json_val oResult(nullptr);
/*Normal error conditions (failed login etc..) will end here*/
if (!cmd_ret_wait(cmd_buffer, oResult))
return false;
if (!oResult.val->IsObject())
{
set_socket_error("PARSE error: Login protocol error 1");
disconnect();
return false;
}
const Value* id = GetObjectMember(*oResult.val, "id");
const Value* job = GetObjectMember(*oResult.val, "job");
if (id == nullptr || job == nullptr || !id->IsString())
{
set_socket_error("PARSE error: Login protocol error 2");
disconnect();
return false;
}
if (id->GetStringLength() >= sizeof(sMinerId))
{
set_socket_error("PARSE error: Login protocol error 3");
disconnect();
return false;
}
memset(sMinerId, 0, sizeof(sMinerId));
memcpy(sMinerId, id->GetString(), id->GetStringLength());
opq_json_val v(job);
if(!process_pool_job(&v))
{
disconnect();
return false;
}
bLoggedIn = true;
return true;
}
bool jpsock::cmd_submit(const char* sJobId, uint32_t iNonce, const uint8_t* bResult)
{
char cmd_buffer[1024];
char sNonce[9];
char sResult[65];
bin2hex((unsigned char*)&iNonce, 4, sNonce);
sNonce[8] = '\0';
bin2hex(bResult, 32, sResult);
sResult[64] = '\0';
snprintf(cmd_buffer, sizeof(cmd_buffer), "{\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"},\"id\":1}\n",
sMinerId, sJobId, sNonce, sResult);
opq_json_val oResult(nullptr);
return cmd_ret_wait(cmd_buffer, oResult);
}
bool jpsock::get_current_job(pool_job& job)
{
std::unique_lock(job_mutex);
if(oCurrentJob.iWorkLen == 0)
return false;
oCurrentJob.iResumeCnt++;
job = oCurrentJob;
return true;
}
inline unsigned char hf_hex2bin(char c, bool &err)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 0xA;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 0xA;
err = true;
return 0;
}
bool jpsock::hex2bin(const char* in, unsigned int len, unsigned char* out)
{
bool error = false;
for (unsigned int i = 0; i < len; i += 2)
{
out[i / 2] = (hf_hex2bin(in[i], error) << 4) | hf_hex2bin(in[i + 1], error);
if (error) return false;
}
return true;
}
inline char hf_bin2hex(unsigned char c)
{
if (c <= 0x9)
return '0' + c;
else
return 'a' - 0xA + c;
}
void jpsock::bin2hex(const unsigned char* in, unsigned int len, char* out)
{
for (unsigned int i = 0; i < len; i++)
{
out[i * 2] = hf_bin2hex((in[i] & 0xF0) >> 4);
out[i * 2 + 1] = hf_bin2hex(in[i] & 0x0F);
}
}
================================================
FILE: jpsock.h
================================================
#pragma once
#include
#include
#include
#include
#include
#include "msgstruct.h"
/* Our pool can have two kinds of errors:
- Parsing or connection error
Those are fatal errors (we drop the connection if we encounter them).
After they are constructed from const char* strings from various places.
(can be from read-only mem), we passs them in an exectutor message
once the recv thread expires.
- Call error
This error happens when the "server says no". Usually because the job was
outdated, or we somehow got the hash wrong. It isn't fatal.
We parse it in-situ in the network buffer, after that we copy it to a
std::string. Executor will move the buffer via an r-value ref.
*/
class base_socket;
class jpsock
{
public:
jpsock(size_t id, bool tls);
~jpsock();
bool connect(const char* sAddr, std::string& sConnectError);
void disconnect();
bool cmd_login(const char* sLogin, const char* sPassword);
bool cmd_submit(const char* sJobId, uint32_t iNonce, const uint8_t* bResult);
static bool hex2bin(const char* in, unsigned int len, unsigned char* out);
static void bin2hex(const unsigned char* in, unsigned int len, char* out);
inline bool is_running() { return bRunning; }
inline bool is_logged_in() { return bLoggedIn; }
std::string&& get_call_error();
bool have_sock_error() { return bHaveSocketError; }
inline static uint64_t t32_to_t64(uint32_t t) { return 0xFFFFFFFFFFFFFFFFULL / (0xFFFFFFFFULL / ((uint64_t)t)); }
inline static uint64_t t64_to_diff(uint64_t t) { return 0xFFFFFFFFFFFFFFFFULL / t; }
inline static uint64_t t32_to_diff(uint32_t t) { return 0xFFFFFFFF / t; }
inline static uint64_t diff_to_t64(uint64_t d) { return 0xFFFFFFFFFFFFFFFFULL / d; }
inline uint64_t get_current_diff() { return iJobDiff; }
bool get_current_job(pool_job& job);
size_t pool_id;
bool set_socket_error(const char* a);
bool set_socket_error(const char* a, const char* b);
bool set_socket_error(const char* a, size_t len);
bool set_socket_error_strerr(const char* a);
bool set_socket_error_strerr(const char* a, int res);
private:
std::atomic bRunning;
std::atomic bLoggedIn;
uint8_t* bJsonRecvMem;
uint8_t* bJsonParseMem;
uint8_t* bJsonCallMem;
static constexpr size_t iJsonMemSize = 4096;
static constexpr size_t iSockBufferSize = 4096;
struct call_rsp;
struct opaque_private;
struct opq_json_val;
void jpsock_thread();
bool jpsock_thd_main();
bool process_line(char* line, size_t len);
bool process_pool_job(const opq_json_val* params);
bool cmd_ret_wait(const char* sPacket, opq_json_val& poResult);
char sMinerId[64];
std::atomic iJobDiff;
std::string sSocketError;
std::atomic bHaveSocketError;
std::mutex call_mutex;
std::condition_variable call_cond;
std::thread* oRecvThd;
std::mutex job_mutex;
pool_job oCurrentJob;
opaque_private* prv;
base_socket* sck;
};
================================================
FILE: libmicrohttpd/microhttpd.h
================================================
/*
This file is part of libmicrohttpd
Copyright (C) 2006-2015 Christian Grothoff (and other contributing authors)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file microhttpd.h
* @brief public interface to libmicrohttpd
* @author Christian Grothoff
* @author Karlson2k (Evgeny Grin)
* @author Chris GauthierDickey
*
* All symbols defined in this header start with MHD. MHD is a small
* HTTP daemon library. As such, it does not have any API for logging
* errors (you can only enable or disable logging to stderr). Also,
* it may not support all of the HTTP features directly, where
* applicable, portions of HTTP may have to be handled by clients of
* the library.
*
* The library is supposed to handle everything that it must handle
* (because the API would not allow clients to do this), such as basic
* connection management; however, detailed interpretations of headers
* -- such as range requests -- and HTTP methods are left to clients.
* The library does understand HEAD and will only send the headers of
* the response and not the body, even if the client supplied a body.
* The library also understands headers that control connection
* management (specifically, "Connection: close" and "Expect: 100
* continue" are understood and handled automatically).
*
* MHD understands POST data and is able to decode certain formats
* (at the moment only "application/x-www-form-urlencoded" and
* "mulitpart/formdata"). Unsupported encodings and large POST
* submissions may require the application to manually process
* the stream, which is provided to the main application (and thus can be
* processed, just not conveniently by MHD).
*
* The header file defines various constants used by the HTTP protocol.
* This does not mean that MHD actually interprets all of these
* values. The provided constants are exported as a convenience
* for users of the library. MHD does not verify that transmitted
* HTTP headers are part of the standard specification; users of the
* library are free to define their own extensions of the HTTP
* standard and use those with MHD.
*
* All functions are guaranteed to be completely reentrant and
* thread-safe (with the exception of #MHD_set_connection_value,
* which must only be used in a particular context).
*
*
* @defgroup event event-loop control
* MHD API to start and stop the HTTP server and manage the event loop.
* @defgroup response generation of responses
* MHD API used to generate responses.
* @defgroup request handling of requests
* MHD API used to access information about requests.
* @defgroup authentication HTTP authentication
* MHD API related to basic and digest HTTP authentication.
* @defgroup logging logging
* MHD API to mange logging and error handling
* @defgroup specialized misc. specialized functions
* This group includes functions that do not fit into any particular
* category and that are rarely used.
*/
#ifndef MHD_MICROHTTPD_H
#define MHD_MICROHTTPD_H
#ifdef __cplusplus
extern "C"
{
#if 0 /* keep Emacsens' auto-indent happy */
}
#endif
#endif
/* While we generally would like users to use a configure-driven
build process which detects which headers are present and
hence works on any platform, we use "standard" includes here
to build out-of-the-box for beginning users on common systems.
If generic headers don't work on your platform, include headers
which define 'va_list', 'size_t', 'ssize_t', 'intptr_t',
'uint16_t', 'uint32_t', 'uint64_t', 'off_t', 'struct sockaddr',
'socklen_t', 'fd_set' and "#define MHD_PLATFORM_H" before
including "microhttpd.h". Then the following "standard"
includes won't be used (which might be a good idea, especially
on platforms where they do not exist).
*/
#ifndef MHD_PLATFORM_H
#include
#include
#include
#if defined(_WIN32) && !defined(__CYGWIN__)
#include
#if defined(_MSC_FULL_VER) && !defined (_SSIZE_T_DEFINED)
#define _SSIZE_T_DEFINED
typedef intptr_t ssize_t;
#endif /* !_SSIZE_T_DEFINED */
#else
#include
#include
#include
#endif
#endif
#if defined(__CYGWIN__) && !defined(_SYS_TYPES_FD_SET)
/* Do not define __USE_W32_SOCKETS under Cygwin! */
#error Cygwin with winsock fd_set is not supported
#endif
/**
* Current version of the library.
* 0x01093001 = 1.9.30-1.
*/
#define MHD_VERSION 0x00095100
/**
* MHD-internal return code for "YES".
*/
#define MHD_YES 1
/**
* MHD-internal return code for "NO".
*/
#define MHD_NO 0
/**
* MHD digest auth internal code for an invalid nonce.
*/
#define MHD_INVALID_NONCE -1
/**
* Constant used to indicate unknown size (use when
* creating a response).
*/
#ifdef UINT64_MAX
#define MHD_SIZE_UNKNOWN UINT64_MAX
#else
#define MHD_SIZE_UNKNOWN ((uint64_t) -1LL)
#endif
#ifdef SIZE_MAX
#define MHD_CONTENT_READER_END_OF_STREAM SIZE_MAX
#define MHD_CONTENT_READER_END_WITH_ERROR (SIZE_MAX - 1)
#else
#define MHD_CONTENT_READER_END_OF_STREAM ((size_t) -1LL)
#define MHD_CONTENT_READER_END_WITH_ERROR (((size_t) -1LL) - 1)
#endif
#ifndef _MHD_EXTERN
#if defined(_WIN32) && defined(MHD_W32LIB)
#define _MHD_EXTERN extern
#elif defined (_WIN32) && defined(MHD_W32DLL)
/* Define MHD_W32DLL when using MHD as W32 .DLL to speed up linker a little */
#define _MHD_EXTERN __declspec(dllimport)
#else
#define _MHD_EXTERN extern
#endif
#endif
#ifndef MHD_SOCKET_DEFINED
/**
* MHD_socket is type for socket FDs
*/
#if !defined(_WIN32) || defined(_SYS_TYPES_FD_SET)
#define MHD_POSIX_SOCKETS 1
typedef int MHD_socket;
#define MHD_INVALID_SOCKET (-1)
#else /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */
#define MHD_WINSOCK_SOCKETS 1
#include
typedef SOCKET MHD_socket;
#define MHD_INVALID_SOCKET (INVALID_SOCKET)
#endif /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */
#define MHD_SOCKET_DEFINED 1
#endif /* MHD_SOCKET_DEFINED */
/**
* Define MHD_NO_DEPRECATION before including "microhttpd.h" to disable deprecation messages
*/
#ifdef MHD_NO_DEPRECATION
#define _MHD_DEPR_MACRO(msg)
#define _MHD_NO_DEPR_IN_MACRO 1
#define _MHD_DEPR_IN_MACRO(msg)
#define _MHD_NO_DEPR_FUNC 1
#define _MHD_DEPR_FUNC(msg)
#endif /* MHD_NO_DEPRECATION */
#ifndef _MHD_DEPR_MACRO
#if defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1500
/* VS 2008 or later */
/* Stringify macros */
#define _MHD_INSTRMACRO(a) #a
#define _MHD_STRMACRO(a) _MHD_INSTRMACRO(a)
/* deprecation message */
#define _MHD_DEPR_MACRO(msg) __pragma(message(__FILE__ "(" _MHD_STRMACRO(__LINE__)"): warning: " msg))
#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg)
#elif defined(__clang__) || defined (__GNUC_PATCHLEVEL__)
/* clang or GCC since 3.0 */
#define _MHD_GCC_PRAG(x) _Pragma (#x)
#if __clang_major__+0 >= 5 || \
(!defined(__apple_build_version__) && (__clang_major__+0 > 3 || (__clang_major__+0 == 3 && __clang_minor__ >= 3))) || \
__GNUC__+0 > 4 || (__GNUC__+0 == 4 && __GNUC_MINOR__+0 >= 8)
/* clang >= 3.3 (or XCode's clang >= 5.0) or
GCC >= 4.8 */
#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG(GCC warning msg)
#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg)
#else /* older clang or GCC */
/* clang < 3.3, XCode's clang < 5.0, 3.0 <= GCC < 4.8 */
#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG(message msg)
#if (__clang_major__+0 > 2 || (__clang_major__+0 == 2 && __clang_minor__ >= 9)) /* FIXME: clang >= 2.9, earlier versions not tested */
/* clang handles inline pragmas better than GCC */
#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg)
#endif /* clang >= 2.9 */
#endif /* older clang or GCC */
/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */
#endif /* clang || GCC >= 3.0 */
#endif /* !_MHD_DEPR_MACRO */
#ifndef _MHD_DEPR_MACRO
#define _MHD_DEPR_MACRO(msg)
#endif /* !_MHD_DEPR_MACRO */
#ifndef _MHD_DEPR_IN_MACRO
#define _MHD_NO_DEPR_IN_MACRO 1
#define _MHD_DEPR_IN_MACRO(msg)
#endif /* !_MHD_DEPR_IN_MACRO */
#ifndef _MHD_DEPR_FUNC
#if defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1400
/* VS 2005 or later */
#define _MHD_DEPR_FUNC(msg) __declspec(deprecated(msg))
#elif defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1310
/* VS .NET 2003 deprecation do not support custom messages */
#define _MHD_DEPR_FUNC(msg) __declspec(deprecated)
#elif (__GNUC__+0 >= 5) || (defined (__clang__) && \
(__clang_major__+0 > 2 || (__clang_major__+0 == 2 && __clang_minor__ >= 9))) /* FIXME: earlier versions not tested */
/* GCC >= 5.0 or clang >= 2.9 */
#define _MHD_DEPR_FUNC(msg) __attribute__((deprecated(msg)))
#elif defined (__clang__) || __GNUC__+0 > 3 || (__GNUC__+0 == 3 && __GNUC_MINOR__+0 >= 1)
/* 3.1 <= GCC < 5.0 or clang < 2.9 */
/* old GCC-style deprecation do not support custom messages */
#define _MHD_DEPR_FUNC(msg) __attribute__((__deprecated__))
/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */
#endif /* clang < 2.9 || GCC >= 3.1 */
#endif /* !_MHD_DEPR_FUNC */
#ifndef _MHD_DEPR_FUNC
#define _MHD_NO_DEPR_FUNC 1
#define _MHD_DEPR_FUNC(msg)
#endif /* !_MHD_DEPR_FUNC */
/**
* Not all architectures and `printf()`'s support the `long long` type.
* This gives the ability to replace `long long` with just a `long`,
* standard `int` or a `short`.
*/
#ifndef MHD_LONG_LONG
/**
* @deprecated use #MHD_UNSIGNED_LONG_LONG instead!
*/
#define MHD_LONG_LONG long long
#define MHD_UNSIGNED_LONG_LONG unsigned long long
#else /* MHD_LONG_LONG */
_MHD_DEPR_MACRO("Macro MHD_LONG_LONG is deprecated, use MHD_UNSIGNED_LONG_LONG")
#endif
/**
* Format string for printing a variable of type #MHD_LONG_LONG.
* You should only redefine this if you also define #MHD_LONG_LONG.
*/
#ifndef MHD_LONG_LONG_PRINTF
/**
* @deprecated use #MHD_UNSIGNED_LONG_LONG_PRINTF instead!
*/
#define MHD_LONG_LONG_PRINTF "ll"
#define MHD_UNSIGNED_LONG_LONG_PRINTF "%llu"
#else /* MHD_LONG_LONG_PRINTF */
_MHD_DEPR_MACRO("Macro MHD_LONG_LONG_PRINTF is deprecated, use MHD_UNSIGNED_LONG_LONG_PRINTF")
#endif
/**
* @defgroup httpcode HTTP response codes.
* These are the status codes defined for HTTP responses.
* @{
*/
#define MHD_HTTP_CONTINUE 100
#define MHD_HTTP_SWITCHING_PROTOCOLS 101
#define MHD_HTTP_PROCESSING 102
#define MHD_HTTP_OK 200
#define MHD_HTTP_CREATED 201
#define MHD_HTTP_ACCEPTED 202
#define MHD_HTTP_NON_AUTHORITATIVE_INFORMATION 203
#define MHD_HTTP_NO_CONTENT 204
#define MHD_HTTP_RESET_CONTENT 205
#define MHD_HTTP_PARTIAL_CONTENT 206
#define MHD_HTTP_MULTI_STATUS 207
#define MHD_HTTP_MULTIPLE_CHOICES 300
#define MHD_HTTP_MOVED_PERMANENTLY 301
#define MHD_HTTP_FOUND 302
#define MHD_HTTP_SEE_OTHER 303
#define MHD_HTTP_NOT_MODIFIED 304
#define MHD_HTTP_USE_PROXY 305
#define MHD_HTTP_SWITCH_PROXY 306
#define MHD_HTTP_TEMPORARY_REDIRECT 307
#define MHD_HTTP_PERMANENT_REDIRECT 308
#define MHD_HTTP_BAD_REQUEST 400
#define MHD_HTTP_UNAUTHORIZED 401
#define MHD_HTTP_PAYMENT_REQUIRED 402
#define MHD_HTTP_FORBIDDEN 403
#define MHD_HTTP_NOT_FOUND 404
#define MHD_HTTP_METHOD_NOT_ALLOWED 405
#define MHD_HTTP_NOT_ACCEPTABLE 406
/** @deprecated */
#define MHD_HTTP_METHOD_NOT_ACCEPTABLE \
_MHD_DEPR_IN_MACRO("Value MHD_HTTP_METHOD_NOT_ACCEPTABLE is deprecated, use MHD_HTTP_NOT_ACCEPTABLE") 406
#define MHD_HTTP_PROXY_AUTHENTICATION_REQUIRED 407
#define MHD_HTTP_REQUEST_TIMEOUT 408
#define MHD_HTTP_CONFLICT 409
#define MHD_HTTP_GONE 410
#define MHD_HTTP_LENGTH_REQUIRED 411
#define MHD_HTTP_PRECONDITION_FAILED 412
#define MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 413
#define MHD_HTTP_REQUEST_URI_TOO_LONG 414
#define MHD_HTTP_UNSUPPORTED_MEDIA_TYPE 415
#define MHD_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416
#define MHD_HTTP_EXPECTATION_FAILED 417
#define MHD_HTTP_UNPROCESSABLE_ENTITY 422
#define MHD_HTTP_LOCKED 423
#define MHD_HTTP_FAILED_DEPENDENCY 424
#define MHD_HTTP_UNORDERED_COLLECTION 425
#define MHD_HTTP_UPGRADE_REQUIRED 426
#define MHD_HTTP_NO_RESPONSE 444
#define MHD_HTTP_RETRY_WITH 449
#define MHD_HTTP_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS 450
#define MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS 451
#define MHD_HTTP_INTERNAL_SERVER_ERROR 500
#define MHD_HTTP_NOT_IMPLEMENTED 501
#define MHD_HTTP_BAD_GATEWAY 502
#define MHD_HTTP_SERVICE_UNAVAILABLE 503
#define MHD_HTTP_GATEWAY_TIMEOUT 504
#define MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED 505
#define MHD_HTTP_VARIANT_ALSO_NEGOTIATES 506
#define MHD_HTTP_INSUFFICIENT_STORAGE 507
#define MHD_HTTP_BANDWIDTH_LIMIT_EXCEEDED 509
#define MHD_HTTP_NOT_EXTENDED 510
/** @} */ /* end of group httpcode */
/**
* Returns the string reason phrase for a response code.
*
* If we don't have a string for a status code, we give the first
* message in that status code class.
*/
_MHD_EXTERN const char *
MHD_get_reason_phrase_for (unsigned int code);
/**
* Flag to be or-ed with MHD_HTTP status code for
* SHOUTcast. This will cause the response to begin
* with the SHOUTcast "ICY" line instad of "HTTP".
* @ingroup specialized
*/
#define MHD_ICY_FLAG ((uint32_t)(((uint32_t)1) << 31))
/**
* @defgroup headers HTTP headers
* These are the standard headers found in HTTP requests and responses.
* @{
*/
/* See also: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html */
#define MHD_HTTP_HEADER_ACCEPT "Accept"
#define MHD_HTTP_HEADER_ACCEPT_CHARSET "Accept-Charset"
#define MHD_HTTP_HEADER_ACCEPT_ENCODING "Accept-Encoding"
#define MHD_HTTP_HEADER_ACCEPT_LANGUAGE "Accept-Language"
#define MHD_HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges"
#define MHD_HTTP_HEADER_AGE "Age"
#define MHD_HTTP_HEADER_ALLOW "Allow"
#define MHD_HTTP_HEADER_AUTHORIZATION "Authorization"
#define MHD_HTTP_HEADER_CACHE_CONTROL "Cache-Control"
#define MHD_HTTP_HEADER_CONNECTION "Connection"
#define MHD_HTTP_HEADER_CONTENT_ENCODING "Content-Encoding"
#define MHD_HTTP_HEADER_CONTENT_LANGUAGE "Content-Language"
#define MHD_HTTP_HEADER_CONTENT_LENGTH "Content-Length"
#define MHD_HTTP_HEADER_CONTENT_LOCATION "Content-Location"
#define MHD_HTTP_HEADER_CONTENT_MD5 "Content-MD5"
#define MHD_HTTP_HEADER_CONTENT_RANGE "Content-Range"
#define MHD_HTTP_HEADER_CONTENT_TYPE "Content-Type"
#define MHD_HTTP_HEADER_COOKIE "Cookie"
#define MHD_HTTP_HEADER_DATE "Date"
#define MHD_HTTP_HEADER_ETAG "ETag"
#define MHD_HTTP_HEADER_EXPECT "Expect"
#define MHD_HTTP_HEADER_EXPIRES "Expires"
#define MHD_HTTP_HEADER_FROM "From"
#define MHD_HTTP_HEADER_HOST "Host"
#define MHD_HTTP_HEADER_IF_MATCH "If-Match"
#define MHD_HTTP_HEADER_IF_MODIFIED_SINCE "If-Modified-Since"
#define MHD_HTTP_HEADER_IF_NONE_MATCH "If-None-Match"
#define MHD_HTTP_HEADER_IF_RANGE "If-Range"
#define MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE "If-Unmodified-Since"
#define MHD_HTTP_HEADER_LAST_MODIFIED "Last-Modified"
#define MHD_HTTP_HEADER_LOCATION "Location"
#define MHD_HTTP_HEADER_MAX_FORWARDS "Max-Forwards"
#define MHD_HTTP_HEADER_PRAGMA "Pragma"
#define MHD_HTTP_HEADER_PROXY_AUTHENTICATE "Proxy-Authenticate"
#define MHD_HTTP_HEADER_PROXY_AUTHORIZATION "Proxy-Authorization"
#define MHD_HTTP_HEADER_RANGE "Range"
/* This is not a typo, see HTTP spec */
#define MHD_HTTP_HEADER_REFERER "Referer"
#define MHD_HTTP_HEADER_RETRY_AFTER "Retry-After"
#define MHD_HTTP_HEADER_SERVER "Server"
#define MHD_HTTP_HEADER_SET_COOKIE "Set-Cookie"
#define MHD_HTTP_HEADER_SET_COOKIE2 "Set-Cookie2"
#define MHD_HTTP_HEADER_TE "TE"
#define MHD_HTTP_HEADER_TRAILER "Trailer"
#define MHD_HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding"
#define MHD_HTTP_HEADER_UPGRADE "Upgrade"
#define MHD_HTTP_HEADER_USER_AGENT "User-Agent"
#define MHD_HTTP_HEADER_VARY "Vary"
#define MHD_HTTP_HEADER_VIA "Via"
#define MHD_HTTP_HEADER_WARNING "Warning"
#define MHD_HTTP_HEADER_WWW_AUTHENTICATE "WWW-Authenticate"
#define MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN "Access-Control-Allow-Origin"
#define MHD_HTTP_HEADER_CONTENT_DISPOSITION "Content-Disposition"
/** @} */ /* end of group headers */
/**
* @defgroup versions HTTP versions
* These strings should be used to match against the first line of the
* HTTP header.
* @{
*/
#define MHD_HTTP_VERSION_1_0 "HTTP/1.0"
#define MHD_HTTP_VERSION_1_1 "HTTP/1.1"
/** @} */ /* end of group versions */
/**
* @defgroup methods HTTP methods
* Standard HTTP methods (as strings).
* @{
*/
#define MHD_HTTP_METHOD_CONNECT "CONNECT"
#define MHD_HTTP_METHOD_DELETE "DELETE"
#define MHD_HTTP_METHOD_GET "GET"
#define MHD_HTTP_METHOD_HEAD "HEAD"
#define MHD_HTTP_METHOD_OPTIONS "OPTIONS"
#define MHD_HTTP_METHOD_POST "POST"
#define MHD_HTTP_METHOD_PUT "PUT"
#define MHD_HTTP_METHOD_PATCH "PATCH"
#define MHD_HTTP_METHOD_TRACE "TRACE"
/** @} */ /* end of group methods */
/**
* @defgroup postenc HTTP POST encodings
* See also: http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
* @{
*/
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED "application/x-www-form-urlencoded"
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data"
/** @} */ /* end of group postenc */
/**
* @brief Handle for the daemon (listening on a socket for HTTP traffic).
* @ingroup event
*/
struct MHD_Daemon;
/**
* @brief Handle for a connection / HTTP request.
*
* With HTTP/1.1, multiple requests can be run over the same
* connection. However, MHD will only show one request per TCP
* connection to the client at any given time.
* @ingroup request
*/
struct MHD_Connection;
/**
* @brief Handle for a response.
* @ingroup response
*/
struct MHD_Response;
/**
* @brief Handle for POST processing.
* @ingroup response
*/
struct MHD_PostProcessor;
/**
* @brief Flags for the `struct MHD_Daemon`.
*
* Note that if neither #MHD_USE_THREAD_PER_CONNECTION nor
* #MHD_USE_SELECT_INTERNALLY is used, the client wants control over
* the process and will call the appropriate microhttpd callbacks.
*
* Starting the daemon may also fail if a particular option is not
* implemented or not supported on the target platform (i.e. no
* support for SSL, threads or IPv6).
*/
enum MHD_FLAG
{
/**
* No options selected.
*/
MHD_NO_FLAG = 0,
/**
* Run in debug mode. If this flag is used, the library should
* print error messages and warnings to `stderr`.
*/
MHD_USE_DEBUG = 1,
/**
* Run in HTTPS mode.
*/
MHD_USE_SSL = 2,
/**
* Run using one thread per connection.
*/
MHD_USE_THREAD_PER_CONNECTION = 4,
/**
* Run using an internal thread (or thread pool) doing `select()`.
*/
MHD_USE_SELECT_INTERNALLY = 8,
/**
* Run using the IPv6 protocol (otherwise, MHD will just support
* IPv4). If you want MHD to support IPv4 and IPv6 using a single
* socket, pass #MHD_USE_DUAL_STACK, otherwise, if you only pass
* this option, MHD will try to bind to IPv6-only (resulting in
* no IPv4 support).
*/
MHD_USE_IPv6 = 16,
/**
* Be pedantic about the protocol (as opposed to as tolerant as
* possible). Specifically, at the moment, this flag causes MHD to
* reject HTTP 1.1 connections without a "Host" header. This is
* required by the standard, but of course in violation of the "be
* as liberal as possible in what you accept" norm. It is
* recommended to turn this ON if you are testing clients against
* MHD, and OFF in production.
*/
MHD_USE_PEDANTIC_CHECKS = 32,
/**
* Use `poll()` instead of `select()`. This allows sockets with `fd >=
* FD_SETSIZE`. This option is not compatible with using an
* 'external' `select()` mode (as there is no API to get the file
* descriptors for the external select from MHD) and must also not
* be used in combination with #MHD_USE_EPOLL.
*/
MHD_USE_POLL = 64,
/**
* Run using an internal thread (or thread pool) doing `poll()`.
*/
MHD_USE_POLL_INTERNALLY = MHD_USE_SELECT_INTERNALLY | MHD_USE_POLL,
/**
* Suppress (automatically) adding the 'Date:' header to HTTP responses.
* This option should ONLY be used on systems that do not have a clock
* and that DO provide other mechanisms for cache control. See also
* RFC 2616, section 14.18 (exception 3).
*/
MHD_SUPPRESS_DATE_NO_CLOCK = 128,
/**
* Run without a listen socket. This option only makes sense if
* #MHD_add_connection is to be used exclusively to connect HTTP
* clients to the HTTP server. This option is incompatible with
* using a thread pool; if it is used, #MHD_OPTION_THREAD_POOL_SIZE
* is ignored.
*/
MHD_USE_NO_LISTEN_SOCKET = 256,
/**
* Use `epoll()` instead of `select()` or `poll()` for the event loop.
* This option is only available on some systems; using the option on
* systems without epoll will cause #MHD_start_daemon to fail. Using
* this option is not supported with #MHD_USE_THREAD_PER_CONNECTION.
* @sa ::MHD_FEATURE_EPOLL
*/
MHD_USE_EPOLL = 512,
/** @deprecated */
#define MHD_USE_EPOLL_LINUX_ONLY \
_MHD_DEPR_IN_MACRO("Value MHD_USE_EPOLL_LINUX_ONLY is deprecated, use MHD_USE_EPOLL") \
MHD_USE_EPOLL
/**
* Run using an internal thread (or thread pool) doing `epoll()`.
* This option is only available on Linux; using the option on
* non-Linux systems will cause #MHD_start_daemon to fail.
*/
MHD_USE_EPOLL_INTERNALLY = MHD_USE_SELECT_INTERNALLY | MHD_USE_EPOLL,
/** @deprecated */
#define MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY \
_MHD_DEPR_IN_MACRO("Value MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY is deprecated, use MHD_USE_EPOLL_INTERNALLY") \
MHD_USE_EPOLL_INTERNALLY
/**
* Force MHD to use a signal pipe to notify the event loop (of
* threads) of our shutdown. This is required if an appliction uses
* #MHD_USE_SELECT_INTERNALLY or #MHD_USE_THREAD_PER_CONNECTION and
* then performs #MHD_quiesce_daemon (which eliminates our ability
* to signal termination via the listen socket). In these modes,
* #MHD_quiesce_daemon will fail if this option was not set. Also,
* use of this option is automatic (as in, you do not even have to
* specify it), if #MHD_USE_NO_LISTEN_SOCKET is specified. In
* "external" `select()` mode, this option is always simply ignored.
* MHD can be build for use a pair of sockets instead of a pipe.
* Pair of sockets is forced on W32.
*
* You must also use this option if you use internal select mode
* or a thread pool in conjunction with #MHD_add_connection.
*/
MHD_USE_PIPE_FOR_SHUTDOWN = 1024,
/**
* Use a single socket for IPv4 and IPv6.
*/
MHD_USE_DUAL_STACK = MHD_USE_IPv6 | 2048,
/**
* Enable `epoll()` turbo. Disables certain calls to `shutdown()`
* and enables aggressive non-blocking optimisitc reads.
* Most effects only happen with #MHD_USE_EPOLL.
* Enalbed always on W32 as winsock does not properly behave
* with `shutdown()` and this then fixes potential problems.
*/
MHD_USE_EPOLL_TURBO = 4096,
/**
* Enable suspend/resume functions, which also implies setting up
* pipes to signal resume.
*/
MHD_USE_SUSPEND_RESUME = 8192 | MHD_USE_PIPE_FOR_SHUTDOWN,
/**
* Enable TCP_FASTOPEN option. This option is only available on Linux with a
* kernel >= 3.6. On other systems, using this option cases #MHD_start_daemon
* to fail.
*/
MHD_USE_TCP_FASTOPEN = 16384
};
/**
* Type of a callback function used for logging by MHD.
*
* @param cls closure
* @param fm format string (`printf()`-style)
* @param ap arguments to @a fm
* @ingroup logging
*/
typedef void
(*MHD_LogCallback)(void *cls,
const char *fm,
va_list ap);
/**
* @brief MHD options.
*
* Passed in the varargs portion of #MHD_start_daemon.
*/
enum MHD_OPTION
{
/**
* No more options / last option. This is used
* to terminate the VARARGs list.
*/
MHD_OPTION_END = 0,
/**
* Maximum memory size per connection (followed by a `size_t`).
* Default is 32 kb (#MHD_POOL_SIZE_DEFAULT).
* Values above 128k are unlikely to result in much benefit, as half
* of the memory will be typically used for IO, and TCP buffers are
* unlikely to support window sizes above 64k on most systems.
*/
MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1,
/**
* Maximum number of concurrent connections to
* accept (followed by an `unsigned int`).
*/
MHD_OPTION_CONNECTION_LIMIT = 2,
/**
* After how many seconds of inactivity should a
* connection automatically be timed out? (followed
* by an `unsigned int`; use zero for no timeout).
*/
MHD_OPTION_CONNECTION_TIMEOUT = 3,
/**
* Register a function that should be called whenever a request has
* been completed (this can be used for application-specific clean
* up). Requests that have never been presented to the application
* (via #MHD_AccessHandlerCallback) will not result in
* notifications.
*
* This option should be followed by TWO pointers. First a pointer
* to a function of type #MHD_RequestCompletedCallback and second a
* pointer to a closure to pass to the request completed callback.
* The second pointer maybe NULL.
*/
MHD_OPTION_NOTIFY_COMPLETED = 4,
/**
* Limit on the number of (concurrent) connections made to the
* server from the same IP address. Can be used to prevent one
* IP from taking over all of the allowed connections. If the
* same IP tries to establish more than the specified number of
* connections, they will be immediately rejected. The option
* should be followed by an `unsigned int`. The default is
* zero, which means no limit on the number of connections
* from the same IP address.
*/
MHD_OPTION_PER_IP_CONNECTION_LIMIT = 5,
/**
* Bind daemon to the supplied `struct sockaddr`. This option should
* be followed by a `struct sockaddr *`. If #MHD_USE_IPv6 is
* specified, the `struct sockaddr*` should point to a `struct
* sockaddr_in6`, otherwise to a `struct sockaddr_in`.
*/
MHD_OPTION_SOCK_ADDR = 6,
/**
* Specify a function that should be called before parsing the URI from
* the client. The specified callback function can be used for processing
* the URI (including the options) before it is parsed. The URI after
* parsing will no longer contain the options, which maybe inconvenient for
* logging. This option should be followed by two arguments, the first
* one must be of the form
*
* void * my_logger(void *cls, const char *uri, struct MHD_Connection *con)
*
* where the return value will be passed as
* (`* con_cls`) in calls to the #MHD_AccessHandlerCallback
* when this request is processed later; returning a
* value of NULL has no special significance (however,
* note that if you return non-NULL, you can no longer
* rely on the first call to the access handler having
* `NULL == *con_cls` on entry;)
* "cls" will be set to the second argument following
* #MHD_OPTION_URI_LOG_CALLBACK. Finally, uri will
* be the 0-terminated URI of the request.
*
* Note that during the time of this call, most of the connection's
* state is not initialized (as we have not yet parsed he headers).
* However, information about the connecting client (IP, socket)
* is available.
*/
MHD_OPTION_URI_LOG_CALLBACK = 7,
/**
* Memory pointer for the private key (key.pem) to be used by the
* HTTPS daemon. This option should be followed by a
* `const char *` argument.
* This should be used in conjunction with #MHD_OPTION_HTTPS_MEM_CERT.
*/
MHD_OPTION_HTTPS_MEM_KEY = 8,
/**
* Memory pointer for the certificate (cert.pem) to be used by the
* HTTPS daemon. This option should be followed by a
* `const char *` argument.
* This should be used in conjunction with #MHD_OPTION_HTTPS_MEM_KEY.
*/
MHD_OPTION_HTTPS_MEM_CERT = 9,
/**
* Daemon credentials type.
* Followed by an argument of type
* `gnutls_credentials_type_t`.
*/
MHD_OPTION_HTTPS_CRED_TYPE = 10,
/**
* Memory pointer to a `const char *` specifying the
* cipher algorithm (default: "NORMAL").
*/
MHD_OPTION_HTTPS_PRIORITIES = 11,
/**
* Pass a listen socket for MHD to use (systemd-style). If this
* option is used, MHD will not open its own listen socket(s). The
* argument passed must be of type `MHD_socket` and refer to an
* existing socket that has been bound to a port and is listening.
*/
MHD_OPTION_LISTEN_SOCKET = 12,
/**
* Use the given function for logging error messages. This option
* must be followed by two arguments; the first must be a pointer to
* a function of type #MHD_LogCallback and the second a pointer
* `void *` which will be passed as the first argument to the log
* callback.
*
* Note that MHD will not generate any log messages
* if it was compiled without the "--enable-messages"
* flag being set.
*/
MHD_OPTION_EXTERNAL_LOGGER = 13,
/**
* Number (`unsigned int`) of threads in thread pool. Enable
* thread pooling by setting this value to to something
* greater than 1. Currently, thread model must be
* #MHD_USE_SELECT_INTERNALLY if thread pooling is enabled
* (#MHD_start_daemon returns NULL for an unsupported thread
* model).
*/
MHD_OPTION_THREAD_POOL_SIZE = 14,
/**
* Additional options given in an array of `struct MHD_OptionItem`.
* The array must be terminated with an entry `{MHD_OPTION_END, 0, NULL}`.
* An example for code using #MHD_OPTION_ARRAY is:
*
* struct MHD_OptionItem ops[] = {
* { MHD_OPTION_CONNECTION_LIMIT, 100, NULL },
* { MHD_OPTION_CONNECTION_TIMEOUT, 10, NULL },
* { MHD_OPTION_END, 0, NULL }
* };
* d = MHD_start_daemon (0, 8080, NULL, NULL, dh, NULL,
* MHD_OPTION_ARRAY, ops,
* MHD_OPTION_END);
*
* For options that expect a single pointer argument, the
* second member of the `struct MHD_OptionItem` is ignored.
* For options that expect two pointer arguments, the first
* argument must be cast to `intptr_t`.
*/
MHD_OPTION_ARRAY = 15,
/**
* Specify a function that should be called for unescaping escape
* sequences in URIs and URI arguments. Note that this function
* will NOT be used by the `struct MHD_PostProcessor`. If this
* option is not specified, the default method will be used which
* decodes escape sequences of the form "%HH". This option should
* be followed by two arguments, the first one must be of the form
*
* size_t my_unescaper(void *cls,
* struct MHD_Connection *c,
* char *s)
*
* where the return value must be "strlen(s)" and "s" should be
* updated. Note that the unescape function must not lengthen "s"
* (the result must be shorter than the input and still be
* 0-terminated). "cls" will be set to the second argument
* following #MHD_OPTION_UNESCAPE_CALLBACK.
*/
MHD_OPTION_UNESCAPE_CALLBACK = 16,
/**
* Memory pointer for the random values to be used by the Digest
* Auth module. This option should be followed by two arguments.
* First an integer of type `size_t` which specifies the size
* of the buffer pointed to by the second argument in bytes.
* Note that the application must ensure that the buffer of the
* second argument remains allocated and unmodified while the
* deamon is running.
*/
MHD_OPTION_DIGEST_AUTH_RANDOM = 17,
/**
* Size of the internal array holding the map of the nonce and
* the nonce counter. This option should be followed by an `unsigend int`
* argument.
*/
MHD_OPTION_NONCE_NC_SIZE = 18,
/**
* Desired size of the stack for threads created by MHD. Followed
* by an argument of type `size_t`. Use 0 for system default.
*/
MHD_OPTION_THREAD_STACK_SIZE = 19,
/**
* Memory pointer for the certificate (ca.pem) to be used by the
* HTTPS daemon for client authentification.
* This option should be followed by a `const char *` argument.
*/
MHD_OPTION_HTTPS_MEM_TRUST = 20,
/**
* Increment to use for growing the read buffer (followed by a
* `size_t`). Must fit within #MHD_OPTION_CONNECTION_MEMORY_LIMIT.
*/
MHD_OPTION_CONNECTION_MEMORY_INCREMENT = 21,
/**
* Use a callback to determine which X.509 certificate should be
* used for a given HTTPS connection. This option should be
* followed by a argument of type `gnutls_certificate_retrieve_function2 *`.
* This option provides an
* alternative to #MHD_OPTION_HTTPS_MEM_KEY,
* #MHD_OPTION_HTTPS_MEM_CERT. You must use this version if
* multiple domains are to be hosted at the same IP address using
* TLS's Server Name Indication (SNI) extension. In this case,
* the callback is expected to select the correct certificate
* based on the SNI information provided. The callback is expected
* to access the SNI data using `gnutls_server_name_get()`.
* Using this option requires GnuTLS 3.0 or higher.
*/
MHD_OPTION_HTTPS_CERT_CALLBACK = 22,
/**
* When using #MHD_USE_TCP_FASTOPEN, this option changes the default TCP
* fastopen queue length of 50. Note that having a larger queue size can
* cause resource exhaustion attack as the TCP stack has to now allocate
* resources for the SYN packet along with its DATA. This option should be
* followed by an `unsigned int` argument.
*/
MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE = 23,
/**
* Memory pointer for the Diffie-Hellman parameters (dh.pem) to be used by the
* HTTPS daemon for key exchange.
* This option must be followed by a `const char *` argument.
*/
MHD_OPTION_HTTPS_MEM_DHPARAMS = 24,
/**
* If present and set to true, allow reusing address:port socket
* (by using SO_REUSEPORT on most platform, or platform-specific ways).
* If present and set to false, disallow reusing address:port socket
* (does nothing on most plaform, but uses SO_EXCLUSIVEADDRUSE on Windows).
* This option must be followed by a `unsigned int` argument.
*/
MHD_OPTION_LISTENING_ADDRESS_REUSE = 25,
/**
* Memory pointer for a password that decrypts the private key (key.pem)
* to be used by the HTTPS daemon. This option should be followed by a
* `const char *` argument.
* This should be used in conjunction with #MHD_OPTION_HTTPS_MEM_KEY.
* @sa ::MHD_FEATURE_HTTPS_KEY_PASSWORD
*/
MHD_OPTION_HTTPS_KEY_PASSWORD = 26,
/**
* Register a function that should be called whenever a connection is
* started or closed.
*
* This option should be followed by TWO pointers. First a pointer
* to a function of type #MHD_NotifyConnectionCallback and second a
* pointer to a closure to pass to the request completed callback.
* The second pointer maybe NULL.
*/
MHD_OPTION_NOTIFY_CONNECTION = 27,
/**
* Allow to change maximum length of the queue of pending connections on
* listen socket. If not present than default platform-specific SOMAXCONN
* value is used. This option should be followed by an `unsigned int`
* argument.
*/
MHD_OPTION_LISTEN_BACKLOG_SIZE = 28
};
/**
* Entry in an #MHD_OPTION_ARRAY.
*/
struct MHD_OptionItem
{
/**
* Which option is being given. Use #MHD_OPTION_END
* to terminate the array.
*/
enum MHD_OPTION option;
/**
* Option value (for integer arguments, and for options requiring
* two pointer arguments); should be 0 for options that take no
* arguments or only a single pointer argument.
*/
intptr_t value;
/**
* Pointer option value (use NULL for options taking no arguments
* or only an integer option).
*/
void *ptr_value;
};
/**
* The `enum MHD_ValueKind` specifies the source of
* the key-value pairs in the HTTP protocol.
*/
enum MHD_ValueKind
{
/**
* Response header
*/
MHD_RESPONSE_HEADER_KIND = 0,
/**
* HTTP header.
*/
MHD_HEADER_KIND = 1,
/**
* Cookies. Note that the original HTTP header containing
* the cookie(s) will still be available and intact.
*/
MHD_COOKIE_KIND = 2,
/**
* POST data. This is available only if a content encoding
* supported by MHD is used (currently only URL encoding),
* and only if the posted content fits within the available
* memory pool. Note that in that case, the upload data
* given to the #MHD_AccessHandlerCallback will be
* empty (since it has already been processed).
*/
MHD_POSTDATA_KIND = 4,
/**
* GET (URI) arguments.
*/
MHD_GET_ARGUMENT_KIND = 8,
/**
* HTTP footer (only for HTTP 1.1 chunked encodings).
*/
MHD_FOOTER_KIND = 16
};
/**
* The `enum MHD_RequestTerminationCode` specifies reasons
* why a request has been terminated (or completed).
* @ingroup request
*/
enum MHD_RequestTerminationCode
{
/**
* We finished sending the response.
* @ingroup request
*/
MHD_REQUEST_TERMINATED_COMPLETED_OK = 0,
/**
* Error handling the connection (resources
* exhausted, other side closed connection,
* application error accepting request, etc.)
* @ingroup request
*/
MHD_REQUEST_TERMINATED_WITH_ERROR = 1,
/**
* No activity on the connection for the number
* of seconds specified using
* #MHD_OPTION_CONNECTION_TIMEOUT.
* @ingroup request
*/
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 2,
/**
* We had to close the session since MHD was being
* shut down.
* @ingroup request
*/
MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3,
/**
* We tried to read additional data, but the other side closed the
* connection. This error is similar to
* #MHD_REQUEST_TERMINATED_WITH_ERROR, but specific to the case where
* the connection died because the other side did not send expected
* data.
* @ingroup request
*/
MHD_REQUEST_TERMINATED_READ_ERROR = 4,
/**
* The client terminated the connection by closing the socket
* for writing (TCP half-closed); MHD aborted sending the
* response according to RFC 2616, section 8.1.4.
* @ingroup request
*/
MHD_REQUEST_TERMINATED_CLIENT_ABORT = 5
};
/**
* The `enum MHD_ConnectionNotificationCode` specifies types
* of connection notifications.
* @ingroup request
*/
enum MHD_ConnectionNotificationCode
{
/**
* A new connection has been started.
* @ingroup request
*/
MHD_CONNECTION_NOTIFY_STARTED = 0,
/**
* A connection is closed.
* @ingroup request
*/
MHD_CONNECTION_NOTIFY_CLOSED = 1
};
/**
* Information about a connection.
*/
union MHD_ConnectionInfo
{
/**
* Cipher algorithm used, of type "enum gnutls_cipher_algorithm".
*/
int /* enum gnutls_cipher_algorithm */ cipher_algorithm;
/**
* Protocol used, of type "enum gnutls_protocol".
*/
int /* enum gnutls_protocol */ protocol;
/**
* The suspended status of a connection.
*/
int /* MHD_YES or MHD_NO */ suspended;
/**
* Connect socket
*/
MHD_socket connect_fd;
/**
* GNUtls session handle, of type "gnutls_session_t".
*/
void * /* gnutls_session_t */ tls_session;
/**
* GNUtls client certificate handle, of type "gnutls_x509_crt_t".
*/
void * /* gnutls_x509_crt_t */ client_cert;
/**
* Address information for the client.
*/
struct sockaddr *client_addr;
/**
* Which daemon manages this connection (useful in case there are many
* daemons running).
*/
struct MHD_Daemon *daemon;
/**
* Socket-specific client context. Points to the same address as
* the "socket_context" of the #MHD_NotifyConnectionCallback.
*/
void **socket_context;
};
/**
* Values of this enum are used to specify what
* information about a connection is desired.
* @ingroup request
*/
enum MHD_ConnectionInfoType
{
/**
* What cipher algorithm is being used.
* Takes no extra arguments.
* @ingroup request
*/
MHD_CONNECTION_INFO_CIPHER_ALGO,
/**
*
* Takes no extra arguments.
* @ingroup request
*/
MHD_CONNECTION_INFO_PROTOCOL,
/**
* Obtain IP address of the client. Takes no extra arguments.
* Returns essentially a `struct sockaddr **` (since the API returns
* a `union MHD_ConnectionInfo *` and that union contains a `struct
* sockaddr *`).
* @ingroup request
*/
MHD_CONNECTION_INFO_CLIENT_ADDRESS,
/**
* Get the gnuTLS session handle.
* @ingroup request
*/
MHD_CONNECTION_INFO_GNUTLS_SESSION,
/**
* Get the gnuTLS client certificate handle. Dysfunctional (never
* implemented, deprecated). Use #MHD_CONNECTION_INFO_GNUTLS_SESSION
* to get the `gnutls_session_t` and then call
* gnutls_certificate_get_peers().
*/
MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT,
/**
* Get the `struct MHD_Daemon *` responsible for managing this connection.
* @ingroup request
*/
MHD_CONNECTION_INFO_DAEMON,
/**
* Request the file descriptor for the listening socket.
* No extra arguments should be passed.
* @ingroup request
*/
MHD_CONNECTION_INFO_CONNECTION_FD,
/**
* Returns the client-specific pointer to a `void *` that was (possibly)
* set during a #MHD_NotifyConnectionCallback when the socket was
* first accepted. Note that this is NOT the same as the "con_cls"
* argument of the #MHD_AccessHandlerCallback. The "con_cls" is
* fresh for each HTTP request, while the "socket_context" is fresh
* for each socket.
*/
MHD_CONNECTION_INFO_SOCKET_CONTEXT,
/**
* Check wheter the connection is suspended.
* @ingroup request
*/
MHD_CONNECTION_INFO_CONNECTION_SUSPENDED
};
/**
* Values of this enum are used to specify what
* information about a deamon is desired.
*/
enum MHD_DaemonInfoType
{
/**
* No longer supported (will return NULL).
*/
MHD_DAEMON_INFO_KEY_SIZE,
/**
* No longer supported (will return NULL).
*/
MHD_DAEMON_INFO_MAC_KEY_SIZE,
/**
* Request the file descriptor for the listening socket.
* No extra arguments should be passed.
*/
MHD_DAEMON_INFO_LISTEN_FD,
/**
* Request the file descriptor for the external epoll.
* No extra arguments should be passed.
*/
MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY,
/**
* Request the number of current connections handled by the daemon.
* No extra arguments should be passed.
*/
MHD_DAEMON_INFO_CURRENT_CONNECTIONS
};
/**
* Callback for serious error condition. The default action is to print
* an error message and `abort()`.
*
* @param cls user specified value
* @param file where the error occured
* @param line where the error occured
* @param reason error detail, may be NULL
* @ingroup logging
*/
typedef void
(*MHD_PanicCallback) (void *cls,
const char *file,
unsigned int line,
const char *reason);
/**
* Allow or deny a client to connect.
*
* @param cls closure
* @param addr address information from the client
* @param addrlen length of @a addr
* @return #MHD_YES if connection is allowed, #MHD_NO if not
*/
typedef int
(*MHD_AcceptPolicyCallback) (void *cls,
const struct sockaddr *addr,
socklen_t addrlen);
/**
* A client has requested the given url using the given method
* (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
* #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback
* must call MHD callbacks to provide content to give back to the
* client and return an HTTP status code (i.e. #MHD_HTTP_OK,
* #MHD_HTTP_NOT_FOUND, etc.).
*
* @param cls argument given together with the function
* pointer when the handler was registered with MHD
* @param url the requested url
* @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
* #MHD_HTTP_METHOD_PUT, etc.)
* @param version the HTTP version string (i.e.
* #MHD_HTTP_VERSION_1_1)
* @param upload_data the data being uploaded (excluding HEADERS,
* for a POST that fits into memory and that is encoded
* with a supported encoding, the POST data will NOT be
* given in upload_data and is instead available as
* part of #MHD_get_connection_values; very large POST
* data *will* be made available incrementally in
* @a upload_data)
* @param upload_data_size set initially to the size of the
* @a upload_data provided; the method must update this
* value to the number of bytes NOT processed;
* @param con_cls pointer that the callback can set to some
* address and that will be preserved by MHD for future
* calls for this request; since the access handler may
* be called many times (i.e., for a PUT/POST operation
* with plenty of upload data) this allows the application
* to easily associate some request-specific state.
* If necessary, this state can be cleaned up in the
* global #MHD_RequestCompletedCallback (which
* can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
* Initially, `*con_cls` will be NULL.
* @return #MHD_YES if the connection was handled successfully,
* #MHD_NO if the socket must be closed due to a serios
* error while handling the request
*/
typedef int
(*MHD_AccessHandlerCallback) (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data,
size_t *upload_data_size,
void **con_cls);
/**
* Signature of the callback used by MHD to notify the
* application about completed requests.
*
* @param cls client-defined closure
* @param connection connection handle
* @param con_cls value as set by the last call to
* the #MHD_AccessHandlerCallback
* @param toe reason for request termination
* @see #MHD_OPTION_NOTIFY_COMPLETED
* @ingroup request
*/
typedef void
(*MHD_RequestCompletedCallback) (void *cls,
struct MHD_Connection *connection,
void **con_cls,
enum MHD_RequestTerminationCode toe);
/**
* Signature of the callback used by MHD to notify the
* application about started/stopped connections
*
* @param cls client-defined closure
* @param connection connection handle
* @param socket_context socket-specific pointer where the
* client can associate some state specific
* to the TCP connection; note that this is
* different from the "con_cls" which is per
* HTTP request. The client can initialize
* during #MHD_CONNECTION_NOTIFY_STARTED and
* cleanup during #MHD_CONNECTION_NOTIFY_CLOSED
* and access in the meantime using
* #MHD_CONNECTION_INFO_SOCKET_CONTEXT.
* @param toe reason for connection notification
* @see #MHD_OPTION_NOTIFY_CONNECTION
* @ingroup request
*/
typedef void
(*MHD_NotifyConnectionCallback) (void *cls,
struct MHD_Connection *connection,
void **socket_context,
enum MHD_ConnectionNotificationCode toe);
/**
* Iterator over key-value pairs. This iterator
* can be used to iterate over all of the cookies,
* headers, or POST-data fields of a request, and
* also to iterate over the headers that have been
* added to a response.
*
* @param cls closure
* @param kind kind of the header we are looking at
* @param key key for the value, can be an empty string
* @param value corresponding value, can be NULL
* @return #MHD_YES to continue iterating,
* #MHD_NO to abort the iteration
* @ingroup request
*/
typedef int
(*MHD_KeyValueIterator) (void *cls,
enum MHD_ValueKind kind,
const char *key,
const char *value);
/**
* Callback used by libmicrohttpd in order to obtain content. The
* callback is to copy at most @a max bytes of content into @a buf. The
* total number of bytes that has been placed into @a buf should be
* returned.
*
* Note that returning zero will cause libmicrohttpd to try again.
* Thus, returning zero should only be used in conjunction
* with MHD_suspend_connection() to avoid busy waiting.
*
* @param cls extra argument to the callback
* @param pos position in the datastream to access;
* note that if a `struct MHD_Response` object is re-used,
* it is possible for the same content reader to
* be queried multiple times for the same data;
* however, if a `struct MHD_Response` is not re-used,
* libmicrohttpd guarantees that "pos" will be
* the sum of all non-negative return values
* obtained from the content reader so far.
* @param buf where to copy the data
* @param max maximum number of bytes to copy to @a buf (size of @a buf)
* @return number of bytes written to @a buf;
* 0 is legal unless we are running in internal select mode (since
* this would cause busy-waiting); 0 in external select mode
* will cause this function to be called again once the external
* select calls MHD again;
* #MHD_CONTENT_READER_END_OF_STREAM (-1) for the regular
* end of transmission (with chunked encoding, MHD will then
* terminate the chunk and send any HTTP footers that might be
* present; without chunked encoding and given an unknown
* response size, MHD will simply close the connection; note
* that while returning #MHD_CONTENT_READER_END_OF_STREAM is not technically
* legal if a response size was specified, MHD accepts this
* and treats it just as #MHD_CONTENT_READER_END_WITH_ERROR;
* #MHD_CONTENT_READER_END_WITH_ERROR (-2) to indicate a server
* error generating the response; this will cause MHD to simply
* close the connection immediately. If a response size was
* given or if chunked encoding is in use, this will indicate
* an error to the client. Note, however, that if the client
* does not know a response size and chunked encoding is not in
* use, then clients will not be able to tell the difference between
* #MHD_CONTENT_READER_END_WITH_ERROR and #MHD_CONTENT_READER_END_OF_STREAM.
* This is not a limitation of MHD but rather of the HTTP protocol.
*/
typedef ssize_t
(*MHD_ContentReaderCallback) (void *cls,
uint64_t pos,
char *buf,
size_t max);
/**
* This method is called by libmicrohttpd if we
* are done with a content reader. It should
* be used to free resources associated with the
* content reader.
*
* @param cls closure
* @ingroup response
*/
typedef void
(*MHD_ContentReaderFreeCallback) (void *cls);
/**
* Iterator over key-value pairs where the value
* maybe made available in increments and/or may
* not be zero-terminated. Used for processing
* POST data.
*
* @param cls user-specified closure
* @param kind type of the value, always #MHD_POSTDATA_KIND when called from MHD
* @param key 0-terminated key for the value
* @param filename name of the uploaded file, NULL if not known
* @param content_type mime-type of the data, NULL if not known
* @param transfer_encoding encoding of the data, NULL if not known
* @param data pointer to @a size bytes of data at the
* specified offset
* @param off offset of data in the overall value
* @param size number of bytes in @a data available
* @return #MHD_YES to continue iterating,
* #MHD_NO to abort the iteration
*/
typedef int
(*MHD_PostDataIterator) (void *cls,
enum MHD_ValueKind kind,
const char *key,
const char *filename,
const char *content_type,
const char *transfer_encoding,
const char *data,
uint64_t off,
size_t size);
/* **************** Daemon handling functions ***************** */
/**
* Start a webserver on the given port.
*
* @param flags combination of `enum MHD_FLAG` values
* @param port port to bind to (in host byte order)
* @param apc callback to call to check which clients
* will be allowed to connect; you can pass NULL
* in which case connections from any IP will be
* accepted
* @param apc_cls extra argument to apc
* @param dh handler called for all requests (repeatedly)
* @param dh_cls extra argument to @a dh
* @param ap list of options (type-value pairs,
* terminated with #MHD_OPTION_END).
* @return NULL on error, handle to daemon on success
* @ingroup event
*/
_MHD_EXTERN struct MHD_Daemon *
MHD_start_daemon_va (unsigned int flags,
uint16_t port,
MHD_AcceptPolicyCallback apc, void *apc_cls,
MHD_AccessHandlerCallback dh, void *dh_cls,
va_list ap);
/**
* Start a webserver on the given port. Variadic version of
* #MHD_start_daemon_va.
*
* @param flags combination of `enum MHD_FLAG` values
* @param port port to bind to
* @param apc callback to call to check which clients
* will be allowed to connect; you can pass NULL
* in which case connections from any IP will be
* accepted
* @param apc_cls extra argument to apc
* @param dh handler called for all requests (repeatedly)
* @param dh_cls extra argument to @a dh
* @return NULL on error, handle to daemon on success
* @ingroup event
*/
_MHD_EXTERN struct MHD_Daemon *
MHD_start_daemon (unsigned int flags,
uint16_t port,
MHD_AcceptPolicyCallback apc, void *apc_cls,
MHD_AccessHandlerCallback dh, void *dh_cls,
...);
/**
* Stop accepting connections from the listening socket. Allows
* clients to continue processing, but stops accepting new
* connections. Note that the caller is responsible for closing the
* returned socket; however, if MHD is run using threads (anything but
* external select mode), it must not be closed until AFTER
* #MHD_stop_daemon has been called (as it is theoretically possible
* that an existing thread is still using it).
*
* Note that some thread modes require the caller to have passed
* #MHD_USE_PIPE_FOR_SHUTDOWN when using this API. If this daemon is
* in one of those modes and this option was not given to
* #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET.
*
* @param daemon daemon to stop accepting new connections for
* @return old listen socket on success, #MHD_INVALID_SOCKET if
* the daemon was already not listening anymore
* @ingroup specialized
*/
_MHD_EXTERN MHD_socket
MHD_quiesce_daemon (struct MHD_Daemon *daemon);
/**
* Shutdown an HTTP daemon.
*
* @param daemon daemon to stop
* @ingroup event
*/
_MHD_EXTERN void
MHD_stop_daemon (struct MHD_Daemon *daemon);
/**
* Add another client connection to the set of connections managed by
* MHD. This API is usually not needed (since MHD will accept inbound
* connections on the server socket). Use this API in special cases,
* for example if your HTTP server is behind NAT and needs to connect
* out to the HTTP client, or if you are building a proxy.
*
* If you use this API in conjunction with a internal select or a
* thread pool, you must set the option
* #MHD_USE_PIPE_FOR_SHUTDOWN to ensure that the freshly added
* connection is immediately processed by MHD.
*
* The given client socket will be managed (and closed!) by MHD after
* this call and must no longer be used directly by the application
* afterwards.
*
* Per-IP connection limits are ignored when using this API.
*
* @param daemon daemon that manages the connection
* @param client_socket socket to manage (MHD will expect
* to receive an HTTP request from this socket next).
* @param addr IP address of the client
* @param addrlen number of bytes in @a addr
* @return #MHD_YES on success, #MHD_NO if this daemon could
* not handle the connection (i.e. `malloc()` failed, etc).
* The socket will be closed in any case; `errno` is
* set to indicate further details about the error.
* @ingroup specialized
*/
_MHD_EXTERN int
MHD_add_connection (struct MHD_Daemon *daemon,
MHD_socket client_socket,
const struct sockaddr *addr,
socklen_t addrlen);
/**
* Obtain the `select()` sets for this daemon.
* Daemon's FDs will be added to fd_sets. To get only
* daemon FDs in fd_sets, call FD_ZERO for each fd_set
* before calling this function. FD_SETSIZE is assumed
* to be platform's default.
*
* @param daemon daemon to get sets from
* @param read_fd_set read set
* @param write_fd_set write set
* @param except_fd_set except set
* @param max_fd increased to largest FD added (if larger
* than existing value); can be NULL
* @return #MHD_YES on success, #MHD_NO if this
* daemon was not started with the right
* options for this call or any FD didn't
* fit fd_set.
* @ingroup event
*/
_MHD_EXTERN int
MHD_get_fdset (struct MHD_Daemon *daemon,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *except_fd_set,
MHD_socket *max_fd);
/**
* Obtain the `select()` sets for this daemon.
* Daemon's FDs will be added to fd_sets. To get only
* daemon FDs in fd_sets, call FD_ZERO for each fd_set
* before calling this function. Passing custom FD_SETSIZE
* as @a fd_setsize allow usage of larger/smaller than
* platform's default fd_sets.
*
* @param daemon daemon to get sets from
* @param read_fd_set read set
* @param write_fd_set write set
* @param except_fd_set except set
* @param max_fd increased to largest FD added (if larger
* than existing value); can be NULL
* @param fd_setsize value of FD_SETSIZE
* @return #MHD_YES on success, #MHD_NO if this
* daemon was not started with the right
* options for this call or any FD didn't
* fit fd_set.
* @ingroup event
*/
_MHD_EXTERN int
MHD_get_fdset2 (struct MHD_Daemon *daemon,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *except_fd_set,
MHD_socket *max_fd,
unsigned int fd_setsize);
/**
* Obtain the `select()` sets for this daemon.
* Daemon's FDs will be added to fd_sets. To get only
* daemon FDs in fd_sets, call FD_ZERO for each fd_set
* before calling this function. Size of fd_set is
* determined by current value of FD_SETSIZE.
*
* @param daemon daemon to get sets from
* @param read_fd_set read set
* @param write_fd_set write set
* @param except_fd_set except set
* @param max_fd increased to largest FD added (if larger
* than existing value); can be NULL
* @return #MHD_YES on success, #MHD_NO if this
* daemon was not started with the right
* options for this call or any FD didn't
* fit fd_set.
* @ingroup event
*/
#define MHD_get_fdset(daemon,read_fd_set,write_fd_set,except_fd_set,max_fd) \
MHD_get_fdset2((daemon),(read_fd_set),(write_fd_set),(except_fd_set),(max_fd),FD_SETSIZE)
/**
* Obtain timeout value for `select()` for this daemon (only needed if
* connection timeout is used). The returned value is how many milliseconds
* `select()` or `poll()` should at most block, not the timeout value set for
* connections. This function MUST NOT be called if MHD is running with
* #MHD_USE_THREAD_PER_CONNECTION.
*
* @param daemon daemon to query for timeout
* @param timeout set to the timeout (in milliseconds)
* @return #MHD_YES on success, #MHD_NO if timeouts are
* not used (or no connections exist that would
* necessiate the use of a timeout right now).
* @ingroup event
*/
_MHD_EXTERN int
MHD_get_timeout (struct MHD_Daemon *daemon,
MHD_UNSIGNED_LONG_LONG *timeout);
/**
* Run webserver operations (without blocking unless in client
* callbacks). This method should be called by clients in combination
* with #MHD_get_fdset if the client-controlled select method is used.
*
* This function is a convenience method, which is useful if the
* fd_sets from #MHD_get_fdset were not directly passed to `select()`;
* with this function, MHD will internally do the appropriate `select()`
* call itself again. While it is always safe to call #MHD_run (in
* external select mode), you should call #MHD_run_from_select if
* performance is important (as it saves an expensive call to
* `select()`).
*
* @param daemon daemon to run
* @return #MHD_YES on success, #MHD_NO if this
* daemon was not started with the right
* options for this call.
* @ingroup event
*/
_MHD_EXTERN int
MHD_run (struct MHD_Daemon *daemon);
/**
* Run webserver operations. This method should be called by clients
* in combination with #MHD_get_fdset if the client-controlled select
* method is used.
*
* You can use this function instead of #MHD_run if you called
* `select()` on the result from #MHD_get_fdset. File descriptors in
* the sets that are not controlled by MHD will be ignored. Calling
* this function instead of #MHD_run is more efficient as MHD will
* not have to call `select()` again to determine which operations are
* ready.
*
* @param daemon daemon to run select loop for
* @param read_fd_set read set
* @param write_fd_set write set
* @param except_fd_set except set (not used, can be NULL)
* @return #MHD_NO on serious errors, #MHD_YES on success
* @ingroup event
*/
_MHD_EXTERN int
MHD_run_from_select (struct MHD_Daemon *daemon,
const fd_set *read_fd_set,
const fd_set *write_fd_set,
const fd_set *except_fd_set);
/* **************** Connection handling functions ***************** */
/**
* Get all of the headers from the request.
*
* @param connection connection to get values from
* @param kind types of values to iterate over, can be a bitmask
* @param iterator callback to call on each header;
* maybe NULL (then just count headers)
* @param iterator_cls extra argument to @a iterator
* @return number of entries iterated over
* @ingroup request
*/
_MHD_EXTERN int
MHD_get_connection_values (struct MHD_Connection *connection,
enum MHD_ValueKind kind,
MHD_KeyValueIterator iterator,
void *iterator_cls);
/**
* This function can be used to add an entry to the HTTP headers of a
* connection (so that the #MHD_get_connection_values function will
* return them -- and the `struct MHD_PostProcessor` will also see
* them). This maybe required in certain situations (see Mantis
* #1399) where (broken) HTTP implementations fail to supply values
* needed by the post processor (or other parts of the application).
*
* This function MUST only be called from within the
* #MHD_AccessHandlerCallback (otherwise, access maybe improperly
* synchronized). Furthermore, the client must guarantee that the key
* and value arguments are 0-terminated strings that are NOT freed
* until the connection is closed. (The easiest way to do this is by
* passing only arguments to permanently allocated strings.).
*
* @param connection the connection for which a
* value should be set
* @param kind kind of the value
* @param key key for the value
* @param value the value itself
* @return #MHD_NO if the operation could not be
* performed due to insufficient memory;
* #MHD_YES on success
* @ingroup request
*/
_MHD_EXTERN int
MHD_set_connection_value (struct MHD_Connection *connection,
enum MHD_ValueKind kind,
const char *key,
const char *value);
/**
* Sets the global error handler to a different implementation. @a cb
* will only be called in the case of typically fatal, serious
* internal consistency issues. These issues should only arise in the
* case of serious memory corruption or similar problems with the
* architecture. While @a cb is allowed to return and MHD will then
* try to continue, this is never safe.
*
* The default implementation that is used if no panic function is set
* simply prints an error message and calls `abort()`. Alternative
* implementations might call `exit()` or other similar functions.
*
* @param cb new error handler
* @param cls passed to @a cb
* @ingroup logging
*/
_MHD_EXTERN void
MHD_set_panic_func (MHD_PanicCallback cb, void *cls);
/**
* Process escape sequences ('%HH') Updates val in place; the
* result should be UTF-8 encoded and cannot be larger than the input.
* The result must also still be 0-terminated.
*
* @param val value to unescape (modified in the process)
* @return length of the resulting val (`strlen(val)` may be
* shorter afterwards due to elimination of escape sequences)
*/
_MHD_EXTERN size_t
MHD_http_unescape (char *val);
/**
* Get a particular header value. If multiple
* values match the kind, return any one of them.
*
* @param connection connection to get values from
* @param kind what kind of value are we looking for
* @param key the header to look for, NULL to lookup 'trailing' value without a key
* @return NULL if no such item was found
* @ingroup request
*/
_MHD_EXTERN const char *
MHD_lookup_connection_value (struct MHD_Connection *connection,
enum MHD_ValueKind kind,
const char *key);
/**
* Queue a response to be transmitted to the client (as soon as
* possible but after #MHD_AccessHandlerCallback returns).
*
* @param connection the connection identifying the client
* @param status_code HTTP status code (i.e. #MHD_HTTP_OK)
* @param response response to transmit
* @return #MHD_NO on error (i.e. reply already sent),
* #MHD_YES on success or if message has been queued
* @ingroup response
*/
_MHD_EXTERN int
MHD_queue_response (struct MHD_Connection *connection,
unsigned int status_code,
struct MHD_Response *response);
/**
* Suspend handling of network data for a given connection. This can
* be used to dequeue a connection from MHD's event loop (external
* select, internal select or thread pool; not applicable to
* thread-per-connection!) for a while.
*
* If you use this API in conjunction with a internal select or a
* thread pool, you must set the option #MHD_USE_PIPE_FOR_SHUTDOWN to
* ensure that a resumed connection is immediately processed by MHD.
*
* Suspended connections continue to count against the total number of
* connections allowed (per daemon, as well as per IP, if such limits
* are set). Suspended connections will NOT time out; timeouts will
* restart when the connection handling is resumed. While a
* connection is suspended, MHD will not detect disconnects by the
* client.
*
* The only safe time to suspend a connection is from the
* #MHD_AccessHandlerCallback.
*
* Finally, it is an API violation to call #MHD_stop_daemon while
* having suspended connections (this will at least create memory and
* socket leaks or lead to undefined behavior). You must explicitly
* resume all connections before stopping the daemon.
*
* @param connection the connection to suspend
*/
_MHD_EXTERN void
MHD_suspend_connection (struct MHD_Connection *connection);
/**
* Resume handling of network data for suspended connection. It is
* safe to resume a suspended connection at any time. Calling this
* function on a connection that was not previously suspended will
* result in undefined behavior.
*
* @param connection the connection to resume
*/
_MHD_EXTERN void
MHD_resume_connection (struct MHD_Connection *connection);
/* **************** Response manipulation functions ***************** */
/**
* Flags for special handling of responses.
*/
enum MHD_ResponseFlags
{
/**
* Default: no special flags.
*/
MHD_RF_NONE = 0,
/**
* Only respond in conservative HTTP 1.0-mode. In particular,
* do not (automatically) sent "Connection" headers and always
* close the connection after generating the response.
*/
MHD_RF_HTTP_VERSION_1_0_ONLY = 1
};
/**
* MHD options (for future extensions).
*/
enum MHD_ResponseOptions
{
/**
* End of the list of options.
*/
MHD_RO_END = 0
};
/**
* Set special flags and options for a response.
*
* @param response the response to modify
* @param flags to set for the response
* @param ... #MHD_RO_END terminated list of options
* @return #MHD_YES on success, #MHD_NO on error
*/
_MHD_EXTERN int
MHD_set_response_options (struct MHD_Response *response,
enum MHD_ResponseFlags flags,
...);
/**
* Create a response object. The response object can be extended with
* header information and then be used any number of times.
*
* @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown
* @param block_size preferred block size for querying crc (advisory only,
* MHD may still call @a crc using smaller chunks); this
* is essentially the buffer size used for IO, clients
* should pick a value that is appropriate for IO and
* memory performance requirements
* @param crc callback to use to obtain response data
* @param crc_cls extra argument to @a crc
* @param crfc callback to call to free @a crc_cls resources
* @return NULL on error (i.e. invalid arguments, out of memory)
* @ingroup response
*/
_MHD_EXTERN struct MHD_Response *
MHD_create_response_from_callback (uint64_t size,
size_t block_size,
MHD_ContentReaderCallback crc, void *crc_cls,
MHD_ContentReaderFreeCallback crfc);
/**
* Create a response object. The response object can be extended with
* header information and then be used any number of times.
*
* @param size size of the @a data portion of the response
* @param data the data itself
* @param must_free libmicrohttpd should free data when done
* @param must_copy libmicrohttpd must make a copy of @a data
* right away, the data maybe released anytime after
* this call returns
* @return NULL on error (i.e. invalid arguments, out of memory)
* @deprecated use #MHD_create_response_from_buffer instead
* @ingroup response
*/
_MHD_DEPR_FUNC("MHD_create_response_from_data() is deprecated, use MHD_create_response_from_buffer()") \
_MHD_EXTERN struct MHD_Response *
MHD_create_response_from_data (size_t size,
void *data,
int must_free,
int must_copy);
/**
* Specification for how MHD should treat the memory buffer
* given for the response.
* @ingroup response
*/
enum MHD_ResponseMemoryMode
{
/**
* Buffer is a persistent (static/global) buffer that won't change
* for at least the lifetime of the response, MHD should just use
* it, not free it, not copy it, just keep an alias to it.
* @ingroup response
*/
MHD_RESPMEM_PERSISTENT,
/**
* Buffer is heap-allocated with `malloc()` (or equivalent) and
* should be freed by MHD after processing the response has
* concluded (response reference counter reaches zero).
* @ingroup response
*/
MHD_RESPMEM_MUST_FREE,
/**
* Buffer is in transient memory, but not on the heap (for example,
* on the stack or non-`malloc()` allocated) and only valid during the
* call to #MHD_create_response_from_buffer. MHD must make its
* own private copy of the data for processing.
* @ingroup response
*/
MHD_RESPMEM_MUST_COPY
};
/**
* Create a response object. The response object can be extended with
* header information and then be used any number of times.
*
* @param size size of the data portion of the response
* @param buffer size bytes containing the response's data portion
* @param mode flags for buffer management
* @return NULL on error (i.e. invalid arguments, out of memory)
* @ingroup response
*/
_MHD_EXTERN struct MHD_Response *
MHD_create_response_from_buffer (size_t size,
void *buffer,
enum MHD_ResponseMemoryMode mode);
/**
* Create a response object. The response object can be extended with
* header information and then be used any number of times.
*
* @param size size of the data portion of the response
* @param fd file descriptor referring to a file on disk with the
* data; will be closed when response is destroyed;
* fd should be in 'blocking' mode
* @return NULL on error (i.e. invalid arguments, out of memory)
* @ingroup response
*/
_MHD_EXTERN struct MHD_Response *
MHD_create_response_from_fd (size_t size,
int fd);
/**
* Create a response object. The response object can be extended with
* header information and then be used any number of times.
*
* @param size size of the data portion of the response;
* sizes larger than 2 GiB may be not supported by OS or
* MHD build; see ::MHD_FEATURE_LARGE_FILE
* @param fd file descriptor referring to a file on disk with the
* data; will be closed when response is destroyed;
* fd should be in 'blocking' mode
* @return NULL on error (i.e. invalid arguments, out of memory)
* @ingroup response
*/
_MHD_EXTERN struct MHD_Response *
MHD_create_response_from_fd64 (uint64_t size,
int fd);
/**
* Create a response object. The response object can be extended with
* header information and then be used any number of times.
*
* @param size size of the data portion of the response
* @param fd file descriptor referring to a file on disk with the
* data; will be closed when response is destroyed;
* fd should be in 'blocking' mode
* @param offset offset to start reading from in the file;
* Be careful! `off_t` may have been compiled to be a
* 64-bit variable for MHD, in which case your application
* also has to be compiled using the same options! Read
* the MHD manual for more details.
* @return NULL on error (i.e. invalid arguments, out of memory)
* @ingroup response
*/
_MHD_DEPR_FUNC("Function MHD_create_response_from_fd_at_offset() is deprecated, use MHD_create_response_from_fd_at_offset64()") \
_MHD_EXTERN struct MHD_Response *
MHD_create_response_from_fd_at_offset (size_t size,
int fd,
off_t offset);
#if !defined(_MHD_NO_DEPR_IN_MACRO) || defined(_MHD_NO_DEPR_FUNC)
/* Substitute MHD_create_response_from_fd_at_offset64() instead of MHD_create_response_from_fd_at_offset()
to minimize potential problems with different off_t sizes */
#define MHD_create_response_from_fd_at_offset(size,fd,offset) \
_MHD_DEPR_IN_MACRO("Usage of MHD_create_response_from_fd_at_offset() is deprecated, use MHD_create_response_from_fd_at_offset64()") \
MHD_create_response_from_fd_at_offset64((size),(fd),(offset))
#endif /* !_MHD_NO_DEPR_IN_MACRO || _MHD_NO_DEPR_FUNC */
/**
* Create a response object. The response object can be extended with
* header information and then be used any number of times.
*
* @param size size of the data portion of the response;
* sizes larger than 2 GiB may be not supported by OS or
* MHD build; see ::MHD_FEATURE_LARGE_FILE
* @param fd file descriptor referring to a file on disk with the
* data; will be closed when response is destroyed;
* fd should be in 'blocking' mode
* @param offset offset to start reading from in the file;
* reading file beyond 2 GiB may be not supported by OS or
* MHD build; see ::MHD_FEATURE_LARGE_FILE
* @return NULL on error (i.e. invalid arguments, out of memory)
* @ingroup response
*/
_MHD_EXTERN struct MHD_Response *
MHD_create_response_from_fd_at_offset64 (uint64_t size,
int fd,
uint64_t offset);
#if 0
/**
* Enumeration for actions MHD should perform on the underlying socket
* of the upgrade. This API is not finalized, and in particular
* the final set of actions is yet to be decided. This is just an
* idea for what we might want.
*/
enum MHD_UpgradeAction
{
/**
* Close the socket, the application is done with it.
*
* Takes no extra arguments.
*/
MHD_UPGRADE_ACTION_CLOSE = 0,
/**
* Uncork the TCP write buffer (that is, tell the OS to transmit all
* bytes in the buffer now, and to not use TCP-CORKing).
*
* Takes no extra arguments.
*
* NOTE: it is unclear if we want to have this in the
* "final" API, this is just an idea right now.
*/
MHD_UPGRADE_ACTION_CORK
};
/**
* Handle given to the application to manage special
* actions relating to MHD responses that "upgrade"
* the HTTP protocol (i.e. to WebSockets).
*/
struct MHD_UpgradeResponseHandle;
/**
* This connection-specific callback is provided by MHD to
* applications (unusual) during the #MHD_UpgradeHandler.
* It allows applications to perform 'special' actions on
* the underlying socket from the upgrade.
*
* @param urh the handle identifying the connection to perform
* the upgrade @a action on.
* @param action which action should be performed
* @param ... arguments to the action (depends on the action)
* @return #MHD_NO on error, #MHD_YES on success
*/
_MHD_EXTERN int
MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
enum MHD_UpgradeAction action,
...);
/**
* Function called after a protocol "upgrade" response was sent
* successfully and the socket should now be controlled by some
* protocol other than HTTP.
*
* Any data received on the socket will be made available in
* 'data_in'. The function should update 'data_in_size' to
* reflect the number of bytes consumed from 'data_in' (the remaining
* bytes will be made available in the next call to the handler).
*
* Any data that should be transmitted on the socket should be
* stored in 'data_out'. '*data_out_size' is initially set to
* the available buffer space in 'data_out'. It should be set to
* the number of bytes stored in 'data_out' (which can be zero).
*
* The return value is a BITMASK that indicates how the function
* intends to interact with the event loop. It can request to be
* notified for reading, writing, request to UNCORK the send buffer
* (which MHD is allowed to ignore, if it is not possible to uncork on
* the local platform), to wait for the 'external' select loop to
* trigger another round. It is also possible to specify "no events"
* to terminate the connection; in this case, the
* #MHD_RequestCompletedCallback will be called and all resources of
* the connection will be released.
*
* Except when in 'thread-per-connection' mode, implementations
* of this function should never block (as it will still be called
* from within the main event loop).
*
* @param cls closure, whatever was given to #MHD_create_response_for_upgrade().
* @param connection original HTTP connection handle,
* giving the function a last chance
* to inspect the original HTTP request
* @param extra_in if we happened to have read bytes after the
* HTTP header already (because the client sent
* more than the HTTP header of the request before
* we sent the upgrade response),
* these are the extra bytes already read from @a sock
* by MHD. The application should treat these as if
* it had read them from @a sock.
* @param extra_in_size number of bytes in @a extra_in
* @param sock socket to use for bi-directional communication
* with the client. For HTTPS, this may not be a socket
* that is directly connected to the client and thus certain
* operations (TCP-specific setsockopt(), getsockopt(), etc.)
* may not work as expected (as the socket could be from a
* socketpair() or a TCP-loopback)
* @param urh argument for #MHD_upgrade_action()s on this @a connection.
* Applications must eventually use this callback to perform the
* close() action on the @a sock.
*/
typedef void
(*MHD_UpgradeHandler)(void *cls,
struct MHD_Connection *connection,
const char *extra_in,
size_t extra_in_size,
MHD_SOCKET sock,
struct MHD_UpgradeResponseHandle *urh);
/**
* Create a response object that can be used for 101 UPGRADE
* responses, for example to implement WebSockets. After sending the
* response, control over the data stream is given to the callback (which
* can then, for example, start some bi-directional communication).
* If the response is queued for multiple connections, the callback
* will be called for each connection. The callback
* will ONLY be called after the response header was successfully passed
* to the OS; if there are communication errors before, the usual MHD
* connection error handling code will be performed.
*
* Setting the correct HTTP code (i.e. MHD_HTTP_SWITCHING_PROTOCOLS)
* and setting correct HTTP headers for the upgrade must be done
* manually (this way, it is possible to implement most existing
* WebSocket versions using this API; in fact, this API might be useful
* for any protocol switch, not just WebSockets). Note that
* draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this
* way as the header "HTTP/1.1 101 WebSocket Protocol Handshake"
* cannot be generated; instead, MHD will always produce "HTTP/1.1 101
* Switching Protocols" (if the response code 101 is used).
*
* As usual, the response object can be extended with header
* information and then be used any number of times (as long as the
* header information is not connection-specific).
*
* @param upgrade_handler function to call with the 'upgraded' socket
* @param upgrade_handler_cls closure for @a upgrade_handler
* @return NULL on error (i.e. invalid arguments, out of memory)
*/
_MHD_EXTERN struct MHD_Response *
MHD_create_response_for_upgrade (MHD_UpgradeHandler upgrade_handler,
void *upgrade_handler_cls);
#endif
/**
* Destroy a response object and associated resources. Note that
* libmicrohttpd may keep some of the resources around if the response
* is still in the queue for some clients, so the memory may not
* necessarily be freed immediatley.
*
* @param response response to destroy
* @ingroup response
*/
_MHD_EXTERN void
MHD_destroy_response (struct MHD_Response *response);
/**
* Add a header line to the response.
*
* @param response response to add a header to
* @param header the header to add
* @param content value to add
* @return #MHD_NO on error (i.e. invalid header or content format),
* or out of memory
* @ingroup response
*/
_MHD_EXTERN int
MHD_add_response_header (struct MHD_Response *response,
const char *header,
const char *content);
/**
* Add a footer line to the response.
*
* @param response response to remove a header from
* @param footer the footer to delete
* @param content value to delete
* @return #MHD_NO on error (i.e. invalid footer or content format).
* @ingroup response
*/
_MHD_EXTERN int
MHD_add_response_footer (struct MHD_Response *response,
const char *footer,
const char *content);
/**
* Delete a header (or footer) line from the response.
*
* @param response response to remove a header from
* @param header the header to delete
* @param content value to delete
* @return #MHD_NO on error (no such header known)
* @ingroup response
*/
_MHD_EXTERN int
MHD_del_response_header (struct MHD_Response *response,
const char *header,
const char *content);
/**
* Get all of the headers (and footers) added to a response.
*
* @param response response to query
* @param iterator callback to call on each header;
* maybe NULL (then just count headers)
* @param iterator_cls extra argument to @a iterator
* @return number of entries iterated over
* @ingroup response
*/
_MHD_EXTERN int
MHD_get_response_headers (struct MHD_Response *response,
MHD_KeyValueIterator iterator, void *iterator_cls);
/**
* Get a particular header (or footer) from the response.
*
* @param response response to query
* @param key which header to get
* @return NULL if header does not exist
* @ingroup response
*/
_MHD_EXTERN const char *
MHD_get_response_header (struct MHD_Response *response,
const char *key);
/* ********************** PostProcessor functions ********************** */
/**
* Create a `struct MHD_PostProcessor`.
*
* A `struct MHD_PostProcessor` can be used to (incrementally) parse
* the data portion of a POST request. Note that some buggy browsers
* fail to set the encoding type. If you want to support those, you
* may have to call #MHD_set_connection_value with the proper encoding
* type before creating a post processor (if no supported encoding
* type is set, this function will fail).
*
* @param connection the connection on which the POST is
* happening (used to determine the POST format)
* @param buffer_size maximum number of bytes to use for
* internal buffering (used only for the parsing,
* specifically the parsing of the keys). A
* tiny value (256-1024) should be sufficient.
* Do NOT use a value smaller than 256. For good
* performance, use 32 or 64k (i.e. 65536).
* @param iter iterator to be called with the parsed data,
* Must NOT be NULL.
* @param iter_cls first argument to @a iter
* @return NULL on error (out of memory, unsupported encoding),
* otherwise a PP handle
* @ingroup request
*/
_MHD_EXTERN struct MHD_PostProcessor *
MHD_create_post_processor (struct MHD_Connection *connection,
size_t buffer_size,
MHD_PostDataIterator iter, void *iter_cls);
/**
* Parse and process POST data. Call this function when POST data is
* available (usually during an #MHD_AccessHandlerCallback) with the
* "upload_data" and "upload_data_size". Whenever possible, this will
* then cause calls to the #MHD_PostDataIterator.
*
* @param pp the post processor
* @param post_data @a post_data_len bytes of POST data
* @param post_data_len length of @a post_data
* @return #MHD_YES on success, #MHD_NO on error
* (out-of-memory, iterator aborted, parse error)
* @ingroup request
*/
_MHD_EXTERN int
MHD_post_process (struct MHD_PostProcessor *pp,
const char *post_data, size_t post_data_len);
/**
* Release PostProcessor resources.
*
* @param pp the PostProcessor to destroy
* @return #MHD_YES if processing completed nicely,
* #MHD_NO if there were spurious characters / formatting
* problems; it is common to ignore the return
* value of this function
* @ingroup request
*/
_MHD_EXTERN int
MHD_destroy_post_processor (struct MHD_PostProcessor *pp);
/* ********************* Digest Authentication functions *************** */
/**
* Constant to indicate that the nonce of the provided
* authentication code was wrong.
* @ingroup authentication
*/
#define MHD_INVALID_NONCE -1
/**
* Get the username from the authorization header sent by the client
*
* @param connection The MHD connection structure
* @return NULL if no username could be found, a pointer
* to the username if found
* @ingroup authentication
*/
_MHD_EXTERN char *
MHD_digest_auth_get_username (struct MHD_Connection *connection);
/**
* Authenticates the authorization header sent by the client
*
* @param connection The MHD connection structure
* @param realm The realm presented to the client
* @param username The username needs to be authenticated
* @param password The password used in the authentication
* @param nonce_timeout The amount of time for a nonce to be
* invalid in seconds
* @return #MHD_YES if authenticated, #MHD_NO if not,
* #MHD_INVALID_NONCE if nonce is invalid
* @ingroup authentication
*/
_MHD_EXTERN int
MHD_digest_auth_check (struct MHD_Connection *connection,
const char *realm,
const char *username,
const char *password,
unsigned int nonce_timeout);
/**
* Queues a response to request authentication from the client
*
* @param connection The MHD connection structure
* @param realm The realm presented to the client
* @param opaque string to user for opaque value
* @param response reply to send; should contain the "access denied"
* body; note that this function will set the "WWW Authenticate"
* header and that the caller should not do this
* @param signal_stale #MHD_YES if the nonce is invalid to add
* 'stale=true' to the authentication header
* @return #MHD_YES on success, #MHD_NO otherwise
* @ingroup authentication
*/
_MHD_EXTERN int
MHD_queue_auth_fail_response (struct MHD_Connection *connection,
const char *realm,
const char *opaque,
struct MHD_Response *response,
int signal_stale);
/**
* Get the username and password from the basic authorization header sent by the client
*
* @param connection The MHD connection structure
* @param password a pointer for the password
* @return NULL if no username could be found, a pointer
* to the username if found
* @ingroup authentication
*/
_MHD_EXTERN char *
MHD_basic_auth_get_username_password (struct MHD_Connection *connection,
char** password);
/**
* Queues a response to request basic authentication from the client
* The given response object is expected to include the payload for
* the response; the "WWW-Authenticate" header will be added and the
* response queued with the 'UNAUTHORIZED' status code.
*
* @param connection The MHD connection structure
* @param realm the realm presented to the client
* @param response response object to modify and queue
* @return #MHD_YES on success, #MHD_NO otherwise
* @ingroup authentication
*/
_MHD_EXTERN int
MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection,
const char *realm,
struct MHD_Response *response);
/* ********************** generic query functions ********************** */
/**
* Obtain information about the given connection.
*
* @param connection what connection to get information about
* @param info_type what information is desired?
* @param ... depends on @a info_type
* @return NULL if this information is not available
* (or if the @a info_type is unknown)
* @ingroup specialized
*/
_MHD_EXTERN const union MHD_ConnectionInfo *
MHD_get_connection_info (struct MHD_Connection *connection,
enum MHD_ConnectionInfoType info_type,
...);
/**
* MHD connection options. Given to #MHD_set_connection_option to
* set custom options for a particular connection.
*/
enum MHD_CONNECTION_OPTION
{
/**
* Set a custom timeout for the given connection. Specified
* as the number of seconds, given as an `unsigned int`. Use
* zero for no timeout.
*/
MHD_CONNECTION_OPTION_TIMEOUT
};
/**
* Set a custom option for the given connection, overriding defaults.
*
* @param connection connection to modify
* @param option option to set
* @param ... arguments to the option, depending on the option type
* @return #MHD_YES on success, #MHD_NO if setting the option failed
* @ingroup specialized
*/
_MHD_EXTERN int
MHD_set_connection_option (struct MHD_Connection *connection,
enum MHD_CONNECTION_OPTION option,
...);
/**
* Information about an MHD daemon.
*/
union MHD_DaemonInfo
{
/**
* Size of the key, no longer supported.
* @deprecated
*/
size_t key_size;
/**
* Size of the mac key, no longer supported.
* @deprecated
*/
size_t mac_key_size;
/**
* Listen socket file descriptor, for #MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
* and #MHD_DAEMON_INFO_LISTEN_FD.
*/
MHD_socket listen_fd;
/**
* Number of active connections, for #MHD_DAEMON_INFO_CURRENT_CONNECTIONS.
*/
unsigned int num_connections;
};
/**
* Obtain information about the given daemon
* (not fully implemented!).
*
* @param daemon what daemon to get information about
* @param info_type what information is desired?
* @param ... depends on @a info_type
* @return NULL if this information is not available
* (or if the @a info_type is unknown)
* @ingroup specialized
*/
_MHD_EXTERN const union MHD_DaemonInfo *
MHD_get_daemon_info (struct MHD_Daemon *daemon,
enum MHD_DaemonInfoType info_type,
...);
/**
* Obtain the version of this library
*
* @return static version string, e.g. "0.9.9"
* @ingroup specialized
*/
_MHD_EXTERN const char*
MHD_get_version (void);
/**
* Types of information about MHD features,
* used by #MHD_is_feature_supported().
*/
enum MHD_FEATURE
{
/**
* Get whether messages are supported. If supported then in debug
* mode messages can be printed to stderr or to external logger.
*/
MHD_FEATURE_MESSGES = 1,
/**
* Get whether HTTPS is supported. If supported then flag
* #MHD_USE_SSL and options #MHD_OPTION_HTTPS_MEM_KEY,
* #MHD_OPTION_HTTPS_MEM_CERT, #MHD_OPTION_HTTPS_MEM_TRUST,
* #MHD_OPTION_HTTPS_MEM_DHPARAMS, #MHD_OPTION_HTTPS_CRED_TYPE,
* #MHD_OPTION_HTTPS_PRIORITIES can be used.
*/
MHD_FEATURE_SSL = 2,
/**
* Get whether option #MHD_OPTION_HTTPS_CERT_CALLBACK is
* supported.
*/
MHD_FEATURE_HTTPS_CERT_CALLBACK = 3,
/**
* Get whether IPv6 is supported. If supported then flag
* #MHD_USE_IPv6 can be used.
*/
MHD_FEATURE_IPv6 = 4,
/**
* Get whether IPv6 without IPv4 is supported. If not supported
* then IPv4 is always enabled in IPv6 sockets and
* flag #MHD_USE_DUAL_STACK if always used when #MHD_USE_IPv6 is
* specified.
*/
MHD_FEATURE_IPv6_ONLY = 5,
/**
* Get whether `poll()` is supported. If supported then flag
* #MHD_USE_POLL can be used.
*/
MHD_FEATURE_POLL = 6,
/**
* Get whether `epoll()` is supported. If supported then Flags
* #MHD_USE_EPOLL and
* #MHD_USE_EPOLL_INTERNALLY can be used.
*/
MHD_FEATURE_EPOLL = 7,
/**
* Get whether shutdown on listen socket to signal other
* threads is supported. If not supported flag
* #MHD_USE_PIPE_FOR_SHUTDOWN is automatically forced.
*/
MHD_FEATURE_SHUTDOWN_LISTEN_SOCKET = 8,
/**
* Get whether socketpair is used internally instead of pipe to
* signal other threads.
*/
MHD_FEATURE_SOCKETPAIR = 9,
/**
* Get whether TCP Fast Open is supported. If supported then
* flag #MHD_USE_TCP_FASTOPEN and option
* #MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE can be used.
*/
MHD_FEATURE_TCP_FASTOPEN = 10,
/**
* Get whether HTTP Basic authorization is supported. If supported
* then functions #MHD_basic_auth_get_username_password and
* #MHD_queue_basic_auth_fail_response can be used.
*/
MHD_FEATURE_BASIC_AUTH = 11,
/**
* Get whether HTTP Digest authorization is supported. If
* supported then options #MHD_OPTION_DIGEST_AUTH_RANDOM,
* #MHD_OPTION_NONCE_NC_SIZE and
* #MHD_digest_auth_check() can be used.
*/
MHD_FEATURE_DIGEST_AUTH = 12,
/**
* Get whether postprocessor is supported. If supported then
* functions #MHD_create_post_processor(), #MHD_post_process() and
* #MHD_destroy_post_processor() can
* be used.
*/
MHD_FEATURE_POSTPROCESSOR = 13,
/**
* Get whether password encrypted private key for HTTPS daemon is
* supported. If supported then option
* ::MHD_OPTION_HTTPS_KEY_PASSWORD can be used.
*/
MHD_FEATURE_HTTPS_KEY_PASSWORD = 14,
/**
* Get whether reading files beyond 2 GiB boundary is supported.
* If supported then #MHD_create_response_from_fd(),
* #MHD_create_response_from_fd64 #MHD_create_response_from_fd_at_offset()
* and #MHD_create_response_from_fd_at_offset64() can be used with sizes and
* offsets larger than 2 GiB. If not supported value of size+offset is
* limited to 2 GiB.
*/
MHD_FEATURE_LARGE_FILE = 15,
/**
* Get whether MHD set names on generated threads.
*/
MHD_THREAD_NAMES = 16
};
/**
* Get information about supported MHD features.
* Indicate that MHD was compiled with or without support for
* particular feature. Some features require additional support
* by kernel. Kernel support is not checked by this function.
*
* @param feature type of requested information
* @return #MHD_YES if feature is supported by MHD, #MHD_NO if
* feature is not supported or feature is unknown.
* @ingroup specialized
*/
_MHD_EXTERN int
MHD_is_feature_supported (enum MHD_FEATURE feature);
#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: minethd.cpp
================================================
/*
* 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
* 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 .
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with OpenSSL (or a modified version of that library), containing parts
* covered by the terms of OpenSSL License and SSLeay License, the licensors
* of this Program grant you additional permission to convey the resulting work.
*
*/
#include
#include
#include
#include
#include "console.h"
#ifdef _WIN32
#include
void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id)
{
SetThreadAffinityMask(h, 1ULL << cpu_id);
}
#else
#include
#if defined(__APPLE__)
#include
#include
#define SYSCTL_CORE_COUNT "machdep.cpu.core_count"
#endif
void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id)
{
#if defined(__APPLE__)
thread_port_t mach_thread;
thread_affinity_policy_data_t policy = { cpu_id };
mach_thread = pthread_mach_thread_np(h);
thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1);
#else
cpu_set_t mn;
CPU_ZERO(&mn);
CPU_SET(cpu_id, &mn);
pthread_setaffinity_np(h, sizeof(cpu_set_t), &mn);
#endif
}
#endif // _WIN32
#include "executor.h"
#include "minethd.h"
#include "jconf.h"
#include "crypto/cryptonight.h"
telemetry::telemetry(size_t iThd)
{
ppHashCounts = new uint64_t*[iThd];
ppTimestamps = new uint64_t*[iThd];
iBucketTop = new uint32_t[iThd];
for (size_t i = 0; i < iThd; i++)
{
ppHashCounts[i] = new uint64_t[iBucketSize];
ppTimestamps[i] = new uint64_t[iBucketSize];
iBucketTop[i] = 0;
memset(ppHashCounts[0], 0, sizeof(uint64_t) * iBucketSize);
memset(ppTimestamps[0], 0, sizeof(uint64_t) * iBucketSize);
}
}
double telemetry::calc_telemetry_data(size_t iLastMilisec, size_t iThread)
{
using namespace std::chrono;
uint64_t iTimeNow = time_point_cast(high_resolution_clock::now()).time_since_epoch().count();
uint64_t iEarliestHashCnt = 0;
uint64_t iEarliestStamp = 0;
uint64_t iLastestStamp = 0;
uint64_t iLastestHashCnt = 0;
bool bHaveFullSet = false;
//Start at 1, buckettop points to next empty
for (size_t i = 1; i < iBucketSize; i++)
{
size_t idx = (iBucketTop[iThread] - i) & iBucketMask; //overflow expected here
if (ppTimestamps[iThread][idx] == 0)
break; //That means we don't have the data yet
if (iLastestStamp == 0)
{
iLastestStamp = ppTimestamps[iThread][idx];
iLastestHashCnt = ppHashCounts[iThread][idx];
}
if (iTimeNow - ppTimestamps[iThread][idx] > iLastMilisec)
{
bHaveFullSet = true;
break; //We are out of the requested time period
}
iEarliestStamp = ppTimestamps[iThread][idx];
iEarliestHashCnt = ppHashCounts[iThread][idx];
}
if (!bHaveFullSet || iEarliestStamp == 0 || iLastestStamp == 0)
return nan("");
double fHashes, fTime;
fHashes = iLastestHashCnt - iEarliestHashCnt;
fTime = iLastestStamp - iEarliestStamp;
fTime /= 1000.0;
return fHashes / fTime;
}
void telemetry::push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp)
{
size_t iTop = iBucketTop[iThd];
ppHashCounts[iThd][iTop] = iHashCount;
ppTimestamps[iThd][iTop] = iTimestamp;
iBucketTop[iThd] = (iTop + 1) & iBucketMask;
}
minethd::minethd(miner_work& pWork, size_t iNo, GpuContext* ctx)
{
oWork = pWork;
bQuit = 0;
iThreadNo = (uint8_t)iNo;
iJobNo = 0;
iHashCount = 0;
iTimestamp = 0;
pGpuCtx = ctx;
oWorkThd = std::thread(&minethd::work_main, this);
}
bool minethd::init_gpus()
{
size_t i, n = jconf::inst()->GetThreadCount();
printer::inst()->print_msg(L1, "Compiling code and initializing GPUs. This will take a while...");
vGpuData.resize(n);
jconf::thd_cfg cfg;
for(i = 0; i < n; i++)
{
jconf::inst()->GetThreadConfig(i, cfg);
vGpuData[i].deviceIdx = cfg.index;
vGpuData[i].rawIntensity = cfg.intensity;
vGpuData[i].workSize = cfg.w_size;
}
return InitOpenCL(vGpuData.data(), n, jconf::inst()->GetPlatformIdx()) == ERR_SUCCESS;
}
std::atomic minethd::iGlobalJobNo;
std::atomic minethd::iConsumeCnt; //Threads get jobs as they are initialized
minethd::miner_work minethd::oGlobalWork;
uint64_t minethd::iThreadCount = 0;
std::vector minethd::vGpuData;
std::vector* minethd::thread_starter(miner_work& pWork)
{
iGlobalJobNo = 0;
iConsumeCnt = 0;
std::vector* pvThreads = new std::vector;
size_t i, n = jconf::inst()->GetThreadCount();
pvThreads->reserve(n);
jconf::thd_cfg cfg;
for (i = 0; i < n; i++)
{
jconf::inst()->GetThreadConfig(i, cfg);
minethd* thd = new minethd(pWork, i, &vGpuData[i]);
if(cfg.cpu_aff >= 0)
{
#if defined(__APPLE__)
printer::inst()->print_msg(L1, "WARNING on MacOS thread affinity is only advisory.");
#endif
thd_setaffinity(thd->oWorkThd.native_handle(), cfg.cpu_aff);
}
pvThreads->push_back(thd);
if(cfg.cpu_aff >= 0)
printer::inst()->print_msg(L1, "Starting GPU thread, affinity: %d.", (int)cfg.cpu_aff);
else
printer::inst()->print_msg(L1, "Starting GPU thread, no affinity.");
}
iThreadCount = n;
return pvThreads;
}
void minethd::switch_work(miner_work& pWork)
{
// iConsumeCnt is a basic lock-like polling mechanism just in case we happen to push work
// faster than threads can consume them. This should never happen in real life.
// Pool cant physically send jobs faster than every 250ms or so due to net latency.
while (iConsumeCnt.load(std::memory_order_seq_cst) < iThreadCount)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
oGlobalWork = pWork;
iConsumeCnt.store(0, std::memory_order_seq_cst);
iGlobalJobNo++;
}
void minethd::consume_work()
{
memcpy(&oWork, &oGlobalWork, sizeof(miner_work));
iJobNo++;
iConsumeCnt++;
if(!oWork.bStall)
{
pGpuCtx->Nonce = calc_start_nonce(oWork.iResumeCnt);
XMRSetJob(pGpuCtx, oWork.bWorkBlob, oWork.iWorkSize, oWork.iTarget);
}
}
void minethd::work_main()
{
uint64_t iCount = 0;
iConsumeCnt++;
while (bQuit == 0)
{
if (oWork.bStall)
{
/* We are stalled here because the executor didn't find a job for us yet,
either because of network latency, or a socket problem. Since we are
raison d'etre of this software it us sensible to just wait until we have something*/
while (iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
consume_work();
continue;
}
assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID));
while(iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
{
cl_uint results[0x100] = { 0 };
XMRRunJob(pGpuCtx, results);
for(size_t i = 0; i < results[0xFF]; i++)
{
executor::inst()->push_event(ex_event(job_result(oWork.sJobID, oWork.bWorkBlob,
oWork.iWorkSize, oWork.iTarget, results[i]), oWork.iPoolId));
}
iCount += pGpuCtx->rawIntensity;
using namespace std::chrono;
uint64_t iStamp = time_point_cast(high_resolution_clock::now()).time_since_epoch().count();
iHashCount.store(iCount, std::memory_order_relaxed);
iTimestamp.store(iStamp, std::memory_order_relaxed);
std::this_thread::yield();
}
consume_work();
}
}
================================================
FILE: minethd.h
================================================
#pragma once
#include
#include
#include "amd_gpu/gpu.h"
class telemetry
{
public:
telemetry(size_t iThd);
void push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp);
double calc_telemetry_data(size_t iLastMilisec, size_t iThread);
private:
constexpr static size_t iBucketSize = 2 << 11; //Power of 2 to simplify calculations
constexpr static size_t iBucketMask = iBucketSize - 1;
uint32_t* iBucketTop;
uint64_t** ppHashCounts;
uint64_t** ppTimestamps;
};
class minethd
{
public:
struct miner_work
{
char sJobID[64];
uint8_t bWorkBlob[88];
uint32_t iWorkSize;
uint32_t iResumeCnt;
uint32_t iTarget;
bool bStall;
size_t iPoolId;
miner_work() : iWorkSize(0), bStall(true), iPoolId(0) { }
miner_work(const char* sJobID, const uint8_t* bWork, uint32_t iWorkSize, uint32_t iResumeCnt,
uint64_t iTarget, size_t iPoolId) : iWorkSize(iWorkSize), iResumeCnt(iResumeCnt),
iTarget(iTarget), bStall(false), iPoolId(iPoolId)
{
assert(iWorkSize <= sizeof(bWorkBlob));
memcpy(this->sJobID, sJobID, sizeof(miner_work::sJobID));
memcpy(this->bWorkBlob, bWork, iWorkSize);
}
miner_work(miner_work const&) = delete;
miner_work& operator=(miner_work const& from)
{
assert(this != &from);
iWorkSize = from.iWorkSize;
iResumeCnt = from.iResumeCnt;
iTarget = from.iTarget;
bStall = from.bStall;
iPoolId = from.iPoolId;
assert(iWorkSize <= sizeof(bWorkBlob));
memcpy(sJobID, from.sJobID, sizeof(sJobID));
memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
return *this;
}
miner_work(miner_work&& from) : iWorkSize(from.iWorkSize), iTarget(from.iTarget),
bStall(from.bStall), iPoolId(from.iPoolId)
{
assert(iWorkSize <= sizeof(bWorkBlob));
memcpy(sJobID, from.sJobID, sizeof(sJobID));
memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
}
miner_work& operator=(miner_work&& from)
{
assert(this != &from);
iWorkSize = from.iWorkSize;
iResumeCnt = from.iResumeCnt;
iTarget = from.iTarget;
bStall = from.bStall;
iPoolId = from.iPoolId;
assert(iWorkSize <= sizeof(bWorkBlob));
memcpy(sJobID, from.sJobID, sizeof(sJobID));
memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
return *this;
}
};
static void switch_work(miner_work& pWork);
static std::vector* thread_starter(miner_work& pWork);
static bool init_gpus();
std::atomic iHashCount;
std::atomic iTimestamp;
private:
minethd(miner_work& pWork, size_t iNo, GpuContext* ctx);
// We use the top 8 bits of the nonce for thread and resume
// This allows us to resume up to 64 threads 4 times before
// we get nonce collisions
// Bottom 24 bits allow for an hour of work at 4000 H/s
inline uint32_t calc_start_nonce(uint32_t resume)
{ return (resume * iThreadCount + iThreadNo) << 24; }
void work_main();
void double_work_main();
void consume_work();
static std::atomic iGlobalJobNo;
static std::atomic iConsumeCnt;
static uint64_t iThreadCount;
uint64_t iJobNo;
static miner_work oGlobalWork;
miner_work oWork;
std::thread oWorkThd;
uint8_t iThreadNo;
bool bQuit;
bool bNoPrefetch;
//Mutable ptr to vector below, different for each thread
GpuContext* pGpuCtx;
// WARNING - this vector (but not its contents) must be immutable
// once the threads are started
static std::vector vGpuData;
};
================================================
FILE: msgstruct.h
================================================
#pragma once
#include
#include
#include
// Structures that we use to pass info between threads constructors are here just to make
// the stack allocation take up less space, heap is a shared resouce that needs locks too of course
struct pool_job
{
char sJobID[64];
uint8_t bWorkBlob[88];
uint32_t iTarget;
uint32_t iWorkLen;
uint32_t iResumeCnt;
pool_job() : iWorkLen(0), iResumeCnt(0) {}
pool_job(const char* sJobID, uint64_t iTarget, const uint8_t* bWorkBlob, uint32_t iWorkLen) :
iTarget(iTarget), iWorkLen(iWorkLen), iResumeCnt(0)
{
assert(iWorkLen <= sizeof(pool_job::bWorkBlob));
memcpy(this->sJobID, sJobID, sizeof(pool_job::sJobID));
memcpy(this->bWorkBlob, bWorkBlob, iWorkLen);
}
};
struct job_result
{
uint8_t bResult[32];
char sJobID[64];
uint8_t bWorkBlob[88];
uint32_t iTarget;
uint32_t iWorkLen;
uint32_t iNonce;
job_result() {}
job_result(const char* sJobID, uint8_t* bWorkBlob, uint32_t iWorkLen, uint32_t iTarget, uint32_t iNonce) :
iTarget(iTarget), iWorkLen(iWorkLen), iNonce(iNonce)
{
assert(iWorkLen <= sizeof(job_result::bWorkBlob));
memcpy(this->sJobID, sJobID, sizeof(job_result::sJobID));
memcpy(this->bWorkBlob, bWorkBlob, iWorkLen);
memset(this->bResult, 0, sizeof(job_result::bResult));
}
};
enum ex_event_name { EV_INVALID_VAL, EV_SOCK_READY, EV_SOCK_ERROR,
EV_POOL_HAVE_JOB, EV_MINER_HAVE_RESULT, EV_PERF_TICK, EV_RECONNECT,
EV_SWITCH_POOL, EV_DEV_POOL_EXIT, EV_USR_HASHRATE, EV_USR_RESULTS, EV_USR_CONNSTAT,
EV_HASHRATE_LOOP, EV_HTML_HASHRATE, EV_HTML_RESULTS, EV_HTML_CONNSTAT };
/*
This is how I learned to stop worrying and love c++11 =).
Ghosts of endless heap allocations have finally been exorcised. Thanks
to the nifty magic of move semantics, string will only be allocated
once on the heap. Considering that it makes a jorney across stack,
heap alloced queue, to another stack before being finally processed
I think it is kind of nifty, don't you?
Also note that for non-arg events we only copy two qwords
*/
struct ex_event
{
ex_event_name iName;
size_t iPoolId;
union
{
pool_job oPoolJob;
job_result oJobResult;
std::string sSocketError;
};
ex_event() { iName = EV_INVALID_VAL; iPoolId = 0;}
ex_event(std::string&& err, size_t id) : iName(EV_SOCK_ERROR), iPoolId(id), sSocketError(std::move(err)) { }
ex_event(job_result dat, size_t id) : iName(EV_MINER_HAVE_RESULT), iPoolId(id), oJobResult(dat) {}
ex_event(pool_job dat, size_t id) : iName(EV_POOL_HAVE_JOB), iPoolId(id), oPoolJob(dat) {}
ex_event(ex_event_name ev, size_t id = 0) : iName(ev), iPoolId(id) {}
// Delete the copy operators to make sure we are moving only what is needed
ex_event(ex_event const&) = delete;
ex_event& operator=(ex_event const&) = delete;
ex_event(ex_event&& from)
{
iName = from.iName;
iPoolId = from.iPoolId;
switch(iName)
{
case EV_SOCK_ERROR:
new (&sSocketError) std::string(std::move(from.sSocketError));
break;
case EV_MINER_HAVE_RESULT:
oJobResult = from.oJobResult;
break;
case EV_POOL_HAVE_JOB:
oPoolJob = from.oPoolJob;
break;
default:
break;
}
}
ex_event& operator=(ex_event&& from)
{
assert(this != &from);
if(iName == EV_SOCK_ERROR)
sSocketError.~basic_string();
iName = from.iName;
iPoolId = from.iPoolId;
switch(iName)
{
case EV_SOCK_ERROR:
new (&sSocketError) std::string();
sSocketError = std::move(from.sSocketError);
break;
case EV_MINER_HAVE_RESULT:
oJobResult = from.oJobResult;
break;
case EV_POOL_HAVE_JOB:
oPoolJob = from.oPoolJob;
break;
default:
break;
}
return *this;
}
~ex_event()
{
if(iName == EV_SOCK_ERROR)
sSocketError.~basic_string();
}
};
================================================
FILE: opencl/blake256.cl
================================================
/*
* blake256 kernel implementation.
*
* ==========================(LICENSE BEGIN)============================
* Copyright (c) 2014 djm34
* Copyright (c) 2014 tpruvot
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author djm34
*/
__constant static const int sigma[16][16] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }
};
__constant static const sph_u32 c_IV256[8] = {
0x6A09E667, 0xBB67AE85,
0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C,
0x1F83D9AB, 0x5BE0CD19
};
/* Second part (64-80) msg never change, store it */
__constant static const sph_u32 c_Padding[16] = {
0, 0, 0, 0,
0x80000000, 0, 0, 0,
0, 0, 0, 0,
0, 1, 0, 640,
};
__constant static const sph_u32 c_u256[16] = {
0x243F6A88, 0x85A308D3,
0x13198A2E, 0x03707344,
0xA4093822, 0x299F31D0,
0x082EFA98, 0xEC4E6C89,
0x452821E6, 0x38D01377,
0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD,
0x3F84D5B5, 0xB5470917
};
#define GS(a,b,c,d,x) { \
const sph_u32 idx1 = sigma[r][x]; \
const sph_u32 idx2 = sigma[r][x+1]; \
v[a] += (m[idx1] ^ c_u256[idx2]) + v[b]; \
v[d] ^= v[a]; \
v[d] = rotate(v[d], 16U); \
v[c] += v[d]; \
v[b] ^= v[c]; \
v[b] = rotate(v[b], 20U); \
\
v[a] += (m[idx2] ^ c_u256[idx1]) + v[b]; \
v[d] ^= v[a]; \
v[d] = rotate(v[d], 24U); \
v[c] += v[d]; \
v[b] ^= v[c]; \
v[b] = rotate(v[b], 25U); \
}
================================================
FILE: opencl/cryptonight.cl
================================================
/*
* 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
* 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 .
*/
#pragma OPENCL EXTENSION cl_amd_media_ops2 : enable
#include "opencl/wolf-aes.cl"
#include "opencl/wolf-skein.cl"
#include "opencl/jh.cl"
#include "opencl/blake256.cl"
#include "opencl/groestl256.cl"
static const __constant ulong keccakf_rndc[24] =
{
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};
static const __constant uchar sbox[256] =
{
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
void keccakf1600(ulong *s)
{
for(int i = 0; i < 24; ++i)
{
ulong bc[5], tmp1, tmp2;
bc[0] = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20] ^ rotate(s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22], 1UL);
bc[1] = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21] ^ rotate(s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23], 1UL);
bc[2] = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22] ^ rotate(s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24], 1UL);
bc[3] = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23] ^ rotate(s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20], 1UL);
bc[4] = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24] ^ rotate(s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21], 1UL);
tmp1 = s[1] ^ bc[0];
s[0] ^= bc[4];
s[1] = rotate(s[6] ^ bc[0], 44UL);
s[6] = rotate(s[9] ^ bc[3], 20UL);
s[9] = rotate(s[22] ^ bc[1], 61UL);
s[22] = rotate(s[14] ^ bc[3], 39UL);
s[14] = rotate(s[20] ^ bc[4], 18UL);
s[20] = rotate(s[2] ^ bc[1], 62UL);
s[2] = rotate(s[12] ^ bc[1], 43UL);
s[12] = rotate(s[13] ^ bc[2], 25UL);
s[13] = rotate(s[19] ^ bc[3], 8UL);
s[19] = rotate(s[23] ^ bc[2], 56UL);
s[23] = rotate(s[15] ^ bc[4], 41UL);
s[15] = rotate(s[4] ^ bc[3], 27UL);
s[4] = rotate(s[24] ^ bc[3], 14UL);
s[24] = rotate(s[21] ^ bc[0], 2UL);
s[21] = rotate(s[8] ^ bc[2], 55UL);
s[8] = rotate(s[16] ^ bc[0], 35UL);
s[16] = rotate(s[5] ^ bc[4], 36UL);
s[5] = rotate(s[3] ^ bc[2], 28UL);
s[3] = rotate(s[18] ^ bc[2], 21UL);
s[18] = rotate(s[17] ^ bc[1], 15UL);
s[17] = rotate(s[11] ^ bc[0], 10UL);
s[11] = rotate(s[7] ^ bc[1], 6UL);
s[7] = rotate(s[10] ^ bc[4], 3UL);
s[10] = rotate(tmp1, 1UL);
tmp1 = s[0]; tmp2 = s[1]; s[0] = bitselect(s[0] ^ s[2], s[0], s[1]); s[1] = bitselect(s[1] ^ s[3], s[1], s[2]); s[2] = bitselect(s[2] ^ s[4], s[2], s[3]); s[3] = bitselect(s[3] ^ tmp1, s[3], s[4]); s[4] = bitselect(s[4] ^ tmp2, s[4], tmp1);
tmp1 = s[5]; tmp2 = s[6]; s[5] = bitselect(s[5] ^ s[7], s[5], s[6]); s[6] = bitselect(s[6] ^ s[8], s[6], s[7]); s[7] = bitselect(s[7] ^ s[9], s[7], s[8]); s[8] = bitselect(s[8] ^ tmp1, s[8], s[9]); s[9] = bitselect(s[9] ^ tmp2, s[9], tmp1);
tmp1 = s[10]; tmp2 = s[11]; s[10] = bitselect(s[10] ^ s[12], s[10], s[11]); s[11] = bitselect(s[11] ^ s[13], s[11], s[12]); s[12] = bitselect(s[12] ^ s[14], s[12], s[13]); s[13] = bitselect(s[13] ^ tmp1, s[13], s[14]); s[14] = bitselect(s[14] ^ tmp2, s[14], tmp1);
tmp1 = s[15]; tmp2 = s[16]; s[15] = bitselect(s[15] ^ s[17], s[15], s[16]); s[16] = bitselect(s[16] ^ s[18], s[16], s[17]); s[17] = bitselect(s[17] ^ s[19], s[17], s[18]); s[18] = bitselect(s[18] ^ tmp1, s[18], s[19]); s[19] = bitselect(s[19] ^ tmp2, s[19], tmp1);
tmp1 = s[20]; tmp2 = s[21]; s[20] = bitselect(s[20] ^ s[22], s[20], s[21]); s[21] = bitselect(s[21] ^ s[23], s[21], s[22]); s[22] = bitselect(s[22] ^ s[24], s[22], s[23]); s[23] = bitselect(s[23] ^ tmp1, s[23], s[24]); s[24] = bitselect(s[24] ^ tmp2, s[24], tmp1);
s[0] ^= keccakf_rndc[i];
}
}
static const __constant uint keccakf_rotc[24] =
{
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
};
static const __constant uint keccakf_piln[24] =
{
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
};
void keccakf1600_1(ulong *st)
{
int i, round;
ulong t, bc[5];
#pragma unroll 1
for(round = 0; round < 24; ++round)
{
// Theta
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
#pragma unroll 1
for (i = 0; i < 5; ++i) {
t = bc[(i + 4) % 5] ^ rotate(bc[(i + 1) % 5], 1UL);
st[i ] ^= t;
st[i + 5] ^= t;
st[i + 10] ^= t;
st[i + 15] ^= t;
st[i + 20] ^= t;
}
// Rho Pi
t = st[1];
#pragma unroll
for (i = 0; i < 24; ++i) {
bc[0] = st[keccakf_piln[i]];
st[keccakf_piln[i]] = rotate(t, (ulong)keccakf_rotc[i]);
t = bc[0];
}
//ulong tmp1 = st[0]; ulong tmp2 = st[1]; st[0] = bitselect(st[0] ^ st[2], st[0], st[1]); st[1] = bitselect(st[1] ^ st[3], st[1], st[2]); st[2] = bitselect(st[2] ^ st[4], st[2], st[3]); st[3] = bitselect(st[3] ^ tmp1, st[3], st[4]); st[4] = bitselect(st[4] ^ tmp2, st[4], tmp1);
//tmp1 = st[5]; tmp2 = st[6]; st[5] = bitselect(st[5] ^ st[7], st[5], st[6]); st[6] = bitselect(st[6] ^ st[8], st[6], st[7]); st[7] = bitselect(st[7] ^ st[9], st[7], st[8]); st[8] = bitselect(st[8] ^ tmp1, st[8], st[9]); st[9] = bitselect(st[9] ^ tmp2, st[9], tmp1);
//tmp1 = st[10]; tmp2 = st[11]; st[10] = bitselect(st[10] ^ st[12], st[10], st[11]); st[11] = bitselect(st[11] ^ st[13], st[11], st[12]); st[12] = bitselect(st[12] ^ st[14], st[12], st[13]); st[13] = bitselect(st[13] ^ tmp1, st[13], st[14]); st[14] = bitselect(st[14] ^ tmp2, st[14], tmp1);
//tmp1 = st[15]; tmp2 = st[16]; st[15] = bitselect(st[15] ^ st[17], st[15], st[16]); st[16] = bitselect(st[16] ^ st[18], st[16], st[17]); st[17] = bitselect(st[17] ^ st[19], st[17], st[18]); st[18] = bitselect(st[18] ^ tmp1, st[18], st[19]); st[19] = bitselect(st[19] ^ tmp2, st[19], tmp1);
//tmp1 = st[20]; tmp2 = st[21]; st[20] = bitselect(st[20] ^ st[22], st[20], st[21]); st[21] = bitselect(st[21] ^ st[23], st[21], st[22]); st[22] = bitselect(st[22] ^ st[24], st[22], st[23]); st[23] = bitselect(st[23] ^ tmp1, st[23], st[24]); st[24] = bitselect(st[24] ^ tmp2, st[24], tmp1);
#pragma unroll 1
for(int i = 0; i < 25; i += 5)
{
ulong tmp[5];
#pragma unroll 1
for(int x = 0; x < 5; ++x)
tmp[x] = bitselect(st[i + x] ^ st[i + ((x + 2) % 5)], st[i + x], st[i + ((x + 1) % 5)]);
#pragma unroll 1
for(int x = 0; x < 5; ++x) st[i + x] = tmp[x];
}
// Iota
st[0] ^= keccakf_rndc[round];
}
}
void keccakf1600_2(ulong *st)
{
int i, round;
ulong t, bc[5];
#pragma unroll 1
for(round = 0; round < 24; ++round)
{
// Theta
//bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
//bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
//bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
//bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
//bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
/*
#pragma unroll
for (i = 0; i < 5; ++i) {
t = bc[(i + 4) % 5] ^ rotate(bc[(i + 1) % 5], 1UL);
st[i ] ^= t;
st[i + 5] ^= t;
st[i + 10] ^= t;
st[i + 15] ^= t;
st[i + 20] ^= t;
}
*/
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20] ^ rotate(st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22], 1UL);
bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21] ^ rotate(st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23], 1UL);
bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22] ^ rotate(st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24], 1UL);
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23] ^ rotate(st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20], 1UL);
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24] ^ rotate(st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21], 1UL);
st[0] ^= bc[4];
st[5] ^= bc[4];
st[10] ^= bc[4];
st[15] ^= bc[4];
st[20] ^= bc[4];
st[1] ^= bc[0];
st[6] ^= bc[0];
st[11] ^= bc[0];
st[16] ^= bc[0];
st[21] ^= bc[0];
st[2] ^= bc[1];
st[7] ^= bc[1];
st[12] ^= bc[1];
st[17] ^= bc[1];
st[22] ^= bc[1];
st[3] ^= bc[2];
st[8] ^= bc[2];
st[13] ^= bc[2];
st[18] ^= bc[2];
st[23] ^= bc[2];
st[4] ^= bc[3];
st[9] ^= bc[3];
st[14] ^= bc[3];
st[19] ^= bc[3];
st[24] ^= bc[3];
// Rho Pi
t = st[1];
#pragma unroll
for (i = 0; i < 24; ++i) {
bc[0] = st[keccakf_piln[i]];
st[keccakf_piln[i]] = rotate(t, (ulong)keccakf_rotc[i]);
t = bc[0];
}
/*ulong tmp1 = st[1] ^ bc[0];
st[0] ^= bc[4];
st[1] = rotate(st[6] ^ bc[0], 44UL);
st[6] = rotate(st[9] ^ bc[3], 20UL);
st[9] = rotate(st[22] ^ bc[1], 61UL);
st[22] = rotate(st[14] ^ bc[3], 39UL);
st[14] = rotate(st[20] ^ bc[4], 18UL);
st[20] = rotate(st[2] ^ bc[1], 62UL);
st[2] = rotate(st[12] ^ bc[1], 43UL);
st[12] = rotate(st[13] ^ bc[2], 25UL);
st[13] = rotate(st[19] ^ bc[3], 8UL);
st[19] = rotate(st[23] ^ bc[2], 56UL);
st[23] = rotate(st[15] ^ bc[4], 41UL);
st[15] = rotate(st[4] ^ bc[3], 27UL);
st[4] = rotate(st[24] ^ bc[3], 14UL);
st[24] = rotate(st[21] ^ bc[0], 2UL);
st[21] = rotate(st[8] ^ bc[2], 55UL);
st[8] = rotate(st[16] ^ bc[0], 35UL);
st[16] = rotate(st[5] ^ bc[4], 36UL);
st[5] = rotate(st[3] ^ bc[2], 28UL);
st[3] = rotate(st[18] ^ bc[2], 21UL);
st[18] = rotate(st[17] ^ bc[1], 15UL);
st[17] = rotate(st[11] ^ bc[0], 10UL);
st[11] = rotate(st[7] ^ bc[1], 6UL);
st[7] = rotate(st[10] ^ bc[4], 3UL);
st[10] = rotate(tmp1, 1UL);
*/
//ulong tmp1 = st[0]; ulong tmp2 = st[1]; st[0] = bitselect(st[0] ^ st[2], st[0], st[1]); st[1] = bitselect(st[1] ^ st[3], st[1], st[2]); st[2] = bitselect(st[2] ^ st[4], st[2], st[3]); st[3] = bitselect(st[3] ^ tmp1, st[3], st[4]); st[4] = bitselect(st[4] ^ tmp2, st[4], tmp1);
//tmp1 = st[5]; tmp2 = st[6]; st[5] = bitselect(st[5] ^ st[7], st[5], st[6]); st[6] = bitselect(st[6] ^ st[8], st[6], st[7]); st[7] = bitselect(st[7] ^ st[9], st[7], st[8]); st[8] = bitselect(st[8] ^ tmp1, st[8], st[9]); st[9] = bitselect(st[9] ^ tmp2, st[9], tmp1);
//tmp1 = st[10]; tmp2 = st[11]; st[10] = bitselect(st[10] ^ st[12], st[10], st[11]); st[11] = bitselect(st[11] ^ st[13], st[11], st[12]); st[12] = bitselect(st[12] ^ st[14], st[12], st[13]); st[13] = bitselect(st[13] ^ tmp1, st[13], st[14]); st[14] = bitselect(st[14] ^ tmp2, st[14], tmp1);
//tmp1 = st[15]; tmp2 = st[16]; st[15] = bitselect(st[15] ^ st[17], st[15], st[16]); st[16] = bitselect(st[16] ^ st[18], st[16], st[17]); st[17] = bitselect(st[17] ^ st[19], st[17], st[18]); st[18] = bitselect(st[18] ^ tmp1, st[18], st[19]); st[19] = bitselect(st[19] ^ tmp2, st[19], tmp1);
//tmp1 = st[20]; tmp2 = st[21]; st[20] = bitselect(st[20] ^ st[22], st[20], st[21]); st[21] = bitselect(st[21] ^ st[23], st[21], st[22]); st[22] = bitselect(st[22] ^ st[24], st[22], st[23]); st[23] = bitselect(st[23] ^ tmp1, st[23], st[24]); st[24] = bitselect(st[24] ^ tmp2, st[24], tmp1);
#pragma unroll
for(int i = 0; i < 25; i += 5)
{
ulong tmp1 = st[i], tmp2 = st[i + 1];
st[i] = bitselect(st[i] ^ st[i + 2], st[i], st[i + 1]);
st[i + 1] = bitselect(st[i + 1] ^ st[i + 3], st[i + 1], st[i + 2]);
st[i + 2] = bitselect(st[i + 2] ^ st[i + 4], st[i + 2], st[i + 3]);
st[i + 3] = bitselect(st[i + 3] ^ tmp1, st[i + 3], st[i + 4]);
st[i + 4] = bitselect(st[i + 4] ^ tmp2, st[i + 4], tmp1);
}
// Iota
st[0] ^= keccakf_rndc[round];
}
}
void CNKeccak(ulong *output, ulong *input)
{
ulong st[25];
// Copy 72 bytes
for(int i = 0; i < 9; ++i) st[i] = input[i];
// Last four and '1' bit for padding
//st[9] = as_ulong((uint2)(((uint *)input)[18], 0x00000001U));
st[9] = (input[9] & 0x00000000FFFFFFFFUL) | 0x0000000100000000UL;
for(int i = 10; i < 25; ++i) st[i] = 0x00UL;
// Last bit of padding
st[16] = 0x8000000000000000UL;
keccakf1600_1(st);
for(int i = 0; i < 25; ++i) output[i] = st[i];
}
static const __constant uchar rcon[8] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 };
#pragma OPENCL EXTENSION cl_amd_media_ops2 : enable
#define BYTE(x, y) (amd_bfe((x), (y) << 3U, 8U))
#define SubWord(inw) ((sbox[BYTE(inw, 3)] << 24) | (sbox[BYTE(inw, 2)] << 16) | (sbox[BYTE(inw, 1)] << 8) | sbox[BYTE(inw, 0)])
void AESExpandKey256(uint *keybuf)
{
//#pragma unroll 4
for(uint c = 8, i = 1; c < 60; ++c)
{
// For 256-bit keys, an sbox permutation is done every other 4th uint generated, AND every 8th
uint t = ((!(c & 7)) || ((c & 7) == 4)) ? SubWord(keybuf[c - 1]) : keybuf[c - 1];
// If the uint we're generating has an index that is a multiple of 8, rotate and XOR with the round constant,
// then XOR this with previously generated uint. If it's 4 after a multiple of 8, only the sbox permutation
// is done, followed by the XOR. If neither are true, only the XOR with the previously generated uint is done.
keybuf[c] = keybuf[c - 8] ^ ((!(c & 7)) ? rotate(t, 24U) ^ as_uint((uchar4)(rcon[i++], 0U, 0U, 0U)) : t);
}
}
#define IDX(x) (x)
__attribute__((reqd_work_group_size(WORKSIZE, 8, 1)))
__kernel void cn0(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states)
{
ulong State[25];
uint ExpandedKey1[256];
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
uint4 text;
states += (25 * (get_global_id(0) - get_global_offset(0)));
Scratchpad += ((get_global_id(0) - get_global_offset(0))) * (0x80000 >> 2);
for(int i = get_local_id(0); i < 256; i += WORKSIZE)
{
const uint tmp = AES0_C[i];
AES0[i] = tmp;
AES1[i] = rotate(tmp, 8U);
AES2[i] = rotate(tmp, 16U);
AES3[i] = rotate(tmp, 24U);
}
barrier(CLK_LOCAL_MEM_FENCE);
((ulong8 *)State)[0] = vload8(0, input);
State[8] = input[8];
State[9] = input[9];
State[10] = input[10];
((uint *)State)[9] &= 0x00FFFFFFU;
((uint *)State)[9] |= ((get_global_id(0)) & 0xFF) << 24;
((uint *)State)[10] &= 0xFF000000U;
((uint *)State)[10] |= ((get_global_id(0) >> 8));
for(int i = 11; i < 25; ++i) State[i] = 0x00UL;
// Last bit of padding
State[16] = 0x8000000000000000UL;
keccakf1600_2(State);
mem_fence(CLK_GLOBAL_MEM_FENCE);
#pragma unroll
for(int i = 0; i < 25; ++i) states[i] = State[i];
text = vload4(get_local_id(1) + 4, (__global uint *)(states));
#pragma unroll
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey1)[i] = states[i];
AESExpandKey256(ExpandedKey1);
mem_fence(CLK_LOCAL_MEM_FENCE);
#pragma unroll 2
for(int i = 0; i < 0x4000; ++i)
{
#pragma unroll
for(int j = 0; j < 10; ++j)
text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey1)[j]);
Scratchpad[IDX((i << 3) + get_local_id(1))] = text;
}
mem_fence(CLK_GLOBAL_MEM_FENCE);
}
__attribute__((reqd_work_group_size(WORKSIZE, 1, 1)))
__kernel void cn1(__global uint4 *Scratchpad, __global ulong *states)
{
ulong a[2], b[2];
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
Scratchpad += ((get_global_id(0) - get_global_offset(0))) * (0x80000 >> 2);
states += (25 * (get_global_id(0) - get_global_offset(0)));
for(int i = get_local_id(0); i < 256; i += WORKSIZE)
{
const uint tmp = AES0_C[i];
AES0[i] = tmp;
AES1[i] = rotate(tmp, 8U);
AES2[i] = rotate(tmp, 16U);
AES3[i] = rotate(tmp, 24U);
}
barrier(CLK_LOCAL_MEM_FENCE);
a[0] = states[0] ^ states[4];
b[0] = states[2] ^ states[6];
a[1] = states[1] ^ states[5];
b[1] = states[3] ^ states[7];
uint4 b_x = ((uint4 *)b)[0];
mem_fence(CLK_LOCAL_MEM_FENCE);
#pragma unroll 8
for(int i = 0; i < 0x80000; ++i)
{
ulong c[2];
((uint4 *)c)[0] = Scratchpad[IDX((a[0] & 0x1FFFF0) >> 4)];
((uint4 *)c)[0] = AES_Round(AES0, AES1, AES2, AES3, ((uint4 *)c)[0], ((uint4 *)a)[0]);
//b_x ^= ((uint4 *)c)[0];
Scratchpad[IDX((a[0] & 0x1FFFF0) >> 4)] = b_x ^ ((uint4 *)c)[0];
uint4 tmp;
tmp = Scratchpad[IDX((c[0] & 0x1FFFF0) >> 4)];
a[1] += c[0] * as_ulong2(tmp).s0;
a[0] += mul_hi(c[0], as_ulong2(tmp).s0);
Scratchpad[IDX((c[0] & 0x1FFFF0) >> 4)] = ((uint4 *)a)[0];
((uint4 *)a)[0] ^= tmp;
b_x = ((uint4 *)c)[0];
}
mem_fence(CLK_GLOBAL_MEM_FENCE);
}
__attribute__((reqd_work_group_size(WORKSIZE, 8, 1)))
__kernel void cn2(__global uint4 *Scratchpad, __global ulong *states, __global uint *Branch0, __global uint *Branch1, __global uint *Branch2, __global uint *Branch3)
{
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
uint ExpandedKey2[256];
ulong State[25];
uint4 text;
Scratchpad += ((get_global_id(0) - get_global_offset(0))) * (0x80000 >> 2);
states += (25 * (get_global_id(0) - get_global_offset(0)));
for(int i = get_local_id(0); i < 256; i += WORKSIZE)
{
const uint tmp = AES0_C[i];
AES0[i] = tmp;
AES1[i] = rotate(tmp, 8U);
AES2[i] = rotate(tmp, 16U);
AES3[i] = rotate(tmp, 24U);
}
barrier(CLK_LOCAL_MEM_FENCE);
#if defined(__Tahiti__) || defined(__Pitcairn__)
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey2)[i] = states[i + 4];
text = vload4(get_local_id(1) + 4, (__global uint *)states);
#else
text = vload4(get_local_id(1) + 4, (__global uint *)states);
((uint8 *)ExpandedKey2)[0] = vload8(1, (__global uint *)states);
#endif
AESExpandKey256(ExpandedKey2);
barrier(CLK_LOCAL_MEM_FENCE);
#pragma unroll 2
for(int i = 0; i < 0x4000; ++i)
{
text ^= Scratchpad[IDX((i << 3) + get_local_id(1))];
#pragma unroll
for(int j = 0; j < 10; ++j)
text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]);
}
vstore2(as_ulong2(text), get_local_id(1) + 4, states);
barrier(CLK_GLOBAL_MEM_FENCE);
if(!get_local_id(1))
{
for(int i = 0; i < 25; ++i) State[i] = states[i];
keccakf1600_2(State);
for(int i = 0; i < 25; ++i) states[i] = State[i];
switch(State[0] & 3)
{
case 0:
Branch0[atomic_inc(Branch0 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
break;
case 1:
Branch1[atomic_inc(Branch1 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
break;
case 2:
Branch2[atomic_inc(Branch2 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
break;
case 3:
Branch3[atomic_inc(Branch3 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
break;
}
}
mem_fence(CLK_GLOBAL_MEM_FENCE);
}
/*
__kernel void cryptonight(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, __global uint *Branch0, __global uint *Branch1, __global uint *Branch2, __global uint *Branch3, ulong ThreadCount)
{
uchar State[200];
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
uchar ExpandedKey1[256], ExpandedKey2[256];
ulong inbuf[10], a[2], b[2];
uint4 text[8];
for(int i = 0; i < 256; ++i)
{
const uint tmp = AES0_C[i];
AES0[i] = tmp;
AES1[i] = rotate(tmp, 8U);
AES2[i] = rotate(tmp, 16U);
AES3[i] = rotate(tmp, 24U);
}
((ulong8 *)inbuf)[0] = vload8(0, input);
inbuf[8] = input[8];
inbuf[9] = (ulong)((__global uint *)input)[18];
((uint *)(((uchar *)inbuf) + 39))[0] = get_global_id(0);
CNKeccak((ulong *)State, inbuf);
a[0] = ((ulong *)State)[0] ^ ((ulong *)State)[4];
b[0] = ((ulong *)State)[2] ^ ((ulong *)State)[6];
a[1] = ((ulong *)State)[1] ^ ((ulong *)State)[5];
b[1] = ((ulong *)State)[3] ^ ((ulong *)State)[7];
for(uint i = 0; i < 8; ++i) text[i] = vload4(i + 4, (uint *)(State));
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey1)[i] = ((ulong *)State)[i];
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey2)[i] = ((ulong *)State)[i + 4];
AESExpandKey256(ExpandedKey1);
AESExpandKey256(ExpandedKey2);
mem_fence(CLK_LOCAL_MEM_FENCE);
Scratchpad += ((1 << 17) * (get_global_id(0) - get_global_offset(0)));
//#pragma unroll 1
for(int i = 0; i < (1 << 17); i += 8)
{
#pragma unroll
for(int j = 0; j < 10; ++j)
{
#pragma unroll
for(int x = 0; x < 8; ++x)
text[x] = AES_Round(AES0, AES1, AES2, AES3, text[x], ((uint4 *)ExpandedKey1)[j]);
}
for(int j = 0; j < 8; ++j) *(Scratchpad + i + j) = text[j];
}
uint4 b_x = ((uint4 *)b)[0];
//#pragma unroll 1
for(int i = 0; i < 0x80000; ++i)
{
ulong c[2];
((uint4 *)c)[0] = Scratchpad[(a[0] & 0x1FFFF0) >> 4];
((uint4 *)c)[0] = AES_Round(AES0, AES1, AES2, AES3, ((uint4 *)c)[0], ((uint4 *)a)[0]);
b_x ^= ((uint4 *)c)[0];
Scratchpad[(a[0] & 0x1FFFF0) >> 4] = b_x;
uint4 tmp;
tmp = Scratchpad[(c[0] & 0x1FFFF0) >> 4];
a[1] += c[0] * as_ulong2(tmp).s0;
a[0] += mul_hi(c[0], as_ulong2(tmp).s0);
Scratchpad[(c[0] & 0x1FFFF0) >> 4] = ((uint4 *)a)[0];
((uint4 *)a)[0] ^= tmp;
b_x = ((uint4 *)c)[0];
}
for(uint i = 0; i < 8; ++i) text[i] = vload4(i + 4, (uint *)(State));
for(int i = 0; i < (1 << 17); i += 8)
{
#pragma unroll
for(int j = 0; j < 8; ++j) text[j] ^= Scratchpad[i + j];
#pragma unroll 1
for(int j = 0; j < 10; ++j)
{
#pragma unroll
for(int x = 0; x < 8; ++x)
text[x] = AES_Round(AES0, AES1, AES2, AES3, text[x], ((uint4 *)ExpandedKey2)[j]);
}
}
for(uint i = 0; i < 8; ++i) vstore4(text[i], i + 4, (uint *)(State));
keccakf1600((ulong *)State);
states += (25 * (get_global_id(0) - get_global_offset(0)));
for(int i = 0; i < 25; ++i) states[i] = ((ulong *)State)[i];
switch(State[0] & 3)
{
case 0:
Branch0[atomic_inc(Branch0 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
break;
case 1:
Branch1[atomic_inc(Branch1 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
break;
case 2:
Branch2[atomic_inc(Branch2 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
break;
case 3:
Branch3[atomic_inc(Branch3 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
break;
}
}
*/
#define VSWAP8(x) (((x) >> 56) | (((x) >> 40) & 0x000000000000FF00UL) | (((x) >> 24) & 0x0000000000FF0000UL) \
| (((x) >> 8) & 0x00000000FF000000UL) | (((x) << 8) & 0x000000FF00000000UL) \
| (((x) << 24) & 0x0000FF0000000000UL) | (((x) << 40) & 0x00FF000000000000UL) | (((x) << 56) & 0xFF00000000000000UL))
#define VSWAP4(x) ((((x) >> 24) & 0xFFU) | (((x) >> 8) & 0xFF00U) | (((x) << 8) & 0xFF0000U) | (((x) << 24) & 0xFF000000U))
__kernel void Skein(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
{
const ulong idx = get_global_id(0) - get_global_offset(0);
if(idx >= Threads) return;
states += 25 * BranchBuf[idx];
// skein
ulong8 h = vload8(0, SKEIN512_256_IV);
// Type field begins with final bit, first bit, then six bits of type; the last 96
// bits are input processed (including in the block to be processed with that tweak)
// The output transform is only one run of UBI, since we need only 256 bits of output
// The tweak for the output transform is Type = Output with the Final bit set
// T[0] for the output is 8, and I don't know why - should be message size...
ulong t[3] = { 0x00UL, 0x7000000000000000UL, 0x00UL };
ulong8 p, m;
for(uint i = 0; i < 4; ++i)
{
if(i < 3) t[0] += 0x40UL;
else t[0] += 0x08UL;
t[2] = t[0] ^ t[1];
m = (i < 3) ? vload8(i, states) : (ulong8)(states[24], 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
const ulong h8 = h.s0 ^ h.s1 ^ h.s2 ^ h.s3 ^ h.s4 ^ h.s5 ^ h.s6 ^ h.s7 ^ SKEIN_KS_PARITY;
p = Skein512Block(m, h, h8, t);
h = m ^ p;
if(i < 2) t[1] = 0x3000000000000000UL;
else t[1] = 0xB000000000000000UL;
}
t[0] = 0x08UL;
t[1] = 0xFF00000000000000UL;
t[2] = t[0] ^ t[1];
p = (ulong8)(0);
const ulong h8 = h.s0 ^ h.s1 ^ h.s2 ^ h.s3 ^ h.s4 ^ h.s5 ^ h.s6 ^ h.s7 ^ SKEIN_KS_PARITY;
p = Skein512Block(p, h, h8, t);
//vstore8(p, 0, output);
if(as_uint16(p).s7 <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
mem_fence(CLK_GLOBAL_MEM_FENCE);
}
#define SWAP8(x) as_ulong(as_uchar8(x).s76543210)
__kernel void JH(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
{
const uint idx = get_global_id(0) - get_global_offset(0);
if(idx >= Threads) return;
states += 25 * BranchBuf[idx];
sph_u64 h0h = 0xEBD3202C41A398EBUL, h0l = 0xC145B29C7BBECD92UL, h1h = 0xFAC7D4609151931CUL, h1l = 0x038A507ED6820026UL, h2h = 0x45B92677269E23A4UL, h2l = 0x77941AD4481AFBE0UL, h3h = 0x7A176B0226ABB5CDUL, h3l = 0xA82FFF0F4224F056UL;
sph_u64 h4h = 0x754D2E7F8996A371UL, h4l = 0x62E27DF70849141DUL, h5h = 0x948F2476F7957627UL, h5l = 0x6C29804757B6D587UL, h6h = 0x6C0D8EAC2D275E5CUL, h6l = 0x0F7A0557C6508451UL, h7h = 0xEA12247067D3E47BUL, h7l = 0x69D71CD313ABE389UL;
sph_u64 tmp;
for(int i = 0; i < 5; ++i)
{
ulong input[8];
if(i < 3)
{
for(int x = 0; x < 8; ++x) input[x] = (states[(i << 3) + x]);
}
else if(i == 3)
{
input[0] = (states[24]);
input[1] = 0x80UL;
for(int x = 2; x < 8; ++x) input[x] = 0x00UL;
}
else
{
input[7] = 0x4006000000000000UL;
for(int x = 0; x < 7; ++x) input[x] = 0x00UL;
}
h0h ^= input[0];
h0l ^= input[1];
h1h ^= input[2];
h1l ^= input[3];
h2h ^= input[4];
h2l ^= input[5];
h3h ^= input[6];
h3l ^= input[7];
E8;
h4h ^= input[0];
h4l ^= input[1];
h5h ^= input[2];
h5l ^= input[3];
h6h ^= input[4];
h6l ^= input[5];
h7h ^= input[6];
h7l ^= input[7];
}
//output[0] = h6h;
//output[1] = h6l;
//output[2] = h7h;
//output[3] = h7l;
if(as_uint2(h7l).s1 <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
}
#define SWAP4(x) as_uint(as_uchar4(x).s3210)
__kernel void Blake(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
{
const uint idx = get_global_id(0) - get_global_offset(0);
if(idx >= Threads) return;
states += 25 * BranchBuf[idx];
unsigned int m[16];
unsigned int v[16];
uint h[8];
((uint8 *)h)[0] = vload8(0U, c_IV256);
for(uint i = 0, bitlen = 0; i < 4; ++i)
{
if(i < 3)
{
((uint16 *)m)[0] = vload16(i, (__global uint *)states);
for(int i = 0; i < 16; ++i) m[i] = SWAP4(m[i]);
bitlen += 512;
}
else
{
m[0] = SWAP4(((__global uint *)states)[48]);
m[1] = SWAP4(((__global uint *)states)[49]);
m[2] = 0x80000000U;
for(int i = 3; i < 13; ++i) m[i] = 0x00U;
m[13] = 1U;
m[14] = 0U;
m[15] = 0x640;
bitlen += 64;
}
((uint16 *)v)[0].lo = ((uint8 *)h)[0];
((uint16 *)v)[0].hi = vload8(0U, c_u256);
//v[12] ^= (i < 3) ? (i + 1) << 9 : 1600U;
//v[13] ^= (i < 3) ? (i + 1) << 9 : 1600U;
v[12] ^= bitlen;
v[13] ^= bitlen;
for(int r = 0; r < 14; r++)
{
GS(0, 4, 0x8, 0xC, 0x0);
GS(1, 5, 0x9, 0xD, 0x2);
GS(2, 6, 0xA, 0xE, 0x4);
GS(3, 7, 0xB, 0xF, 0x6);
GS(0, 5, 0xA, 0xF, 0x8);
GS(1, 6, 0xB, 0xC, 0xA);
GS(2, 7, 0x8, 0xD, 0xC);
GS(3, 4, 0x9, 0xE, 0xE);
}
((uint8 *)h)[0] ^= ((uint8 *)v)[0] ^ ((uint8 *)v)[1];
}
for(int i = 0; i < 8; ++i) h[i] = SWAP4(h[i]);
//for(int i = 0; i < 4; ++i) output[i] = ((ulong *)h)[i];
if(h[7] <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
}
__kernel void Groestl(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
{
const uint idx = get_global_id(0) - get_global_offset(0);
if(idx >= Threads) return;
states += 25 * BranchBuf[idx];
ulong State[8];
for(int i = 0; i < 7; ++i) State[i] = 0UL;
State[7] = 0x0001000000000000UL;
for(uint i = 0; i < 4; ++i)
{
ulong H[8], M[8];
if(i < 3)
{
((ulong8 *)M)[0] = vload8(i, states);
}
else
{
M[0] = states[24];
M[1] = 0x80UL;
for(int x = 2; x < 7; ++x) M[x] = 0UL;
M[7] = 0x0400000000000000UL;
}
for(int x = 0; x < 8; ++x) H[x] = M[x] ^ State[x];
PERM_SMALL_P(H);
PERM_SMALL_Q(M);
for(int x = 0; x < 8; ++x) State[x] ^= H[x] ^ M[x];
}
ulong tmp[8];
for(int i = 0; i < 8; ++i) tmp[i] = State[i];
PERM_SMALL_P(State);
for(int i = 0; i < 8; ++i) State[i] ^= tmp[i];
//for(int i = 0; i < 4; ++i) output[i] = State[i + 4];
if(as_uint2(State[7]).s1 <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
}
================================================
FILE: opencl/groestl256.cl
================================================
/* $Id: groestl.c 260 2011-07-21 01:02:38Z tp $ */
/*
* Groestl256
*
* ==========================(LICENSE BEGIN)============================
* Copyright (c) 2014 djm34
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin
*/
#define SPH_C64(x) x
#define SPH_ROTL64(x, y) rotate((x), (ulong)(y))
#define C64e(x) ((SPH_C64(x) >> 56) \
| ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \
| ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \
| ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \
| ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \
| ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \
| ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \
| ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000)))
#define B64_0(x) ((x) & 0xFF)
#define B64_1(x) (((x) >> 8) & 0xFF)
#define B64_2(x) (((x) >> 16) & 0xFF)
#define B64_3(x) (((x) >> 24) & 0xFF)
#define B64_4(x) (((x) >> 32) & 0xFF)
#define B64_5(x) (((x) >> 40) & 0xFF)
#define B64_6(x) (((x) >> 48) & 0xFF)
#define B64_7(x) ((x) >> 56)
#define R64 SPH_ROTL64
#define PC64(j, r) ((sph_u64)((j) + (r)))
#define QC64(j, r) (((sph_u64)(r) << 56) ^ (~((sph_u64)(j) << 56)))
static const __constant ulong T0_G[] =
{
0xc6a597f4a5f432c6UL, 0xf884eb9784976ff8UL, 0xee99c7b099b05eeeUL, 0xf68df78c8d8c7af6UL,
0xff0de5170d17e8ffUL, 0xd6bdb7dcbddc0ad6UL, 0xdeb1a7c8b1c816deUL, 0x915439fc54fc6d91UL,
0x6050c0f050f09060UL, 0x0203040503050702UL, 0xcea987e0a9e02eceUL, 0x567dac877d87d156UL,
0xe719d52b192bcce7UL, 0xb56271a662a613b5UL, 0x4de69a31e6317c4dUL, 0xec9ac3b59ab559ecUL,
0x8f4505cf45cf408fUL, 0x1f9d3ebc9dbca31fUL, 0x894009c040c04989UL, 0xfa87ef92879268faUL,
0xef15c53f153fd0efUL, 0xb2eb7f26eb2694b2UL, 0x8ec90740c940ce8eUL, 0xfb0bed1d0b1de6fbUL,
0x41ec822fec2f6e41UL, 0xb3677da967a91ab3UL, 0x5ffdbe1cfd1c435fUL, 0x45ea8a25ea256045UL,
0x23bf46dabfdaf923UL, 0x53f7a602f7025153UL, 0xe496d3a196a145e4UL, 0x9b5b2ded5bed769bUL,
0x75c2ea5dc25d2875UL, 0xe11cd9241c24c5e1UL, 0x3dae7ae9aee9d43dUL, 0x4c6a98be6abef24cUL,
0x6c5ad8ee5aee826cUL, 0x7e41fcc341c3bd7eUL, 0xf502f1060206f3f5UL, 0x834f1dd14fd15283UL,
0x685cd0e45ce48c68UL, 0x51f4a207f4075651UL, 0xd134b95c345c8dd1UL, 0xf908e9180818e1f9UL,
0xe293dfae93ae4ce2UL, 0xab734d9573953eabUL, 0x6253c4f553f59762UL, 0x2a3f54413f416b2aUL,
0x080c10140c141c08UL, 0x955231f652f66395UL, 0x46658caf65afe946UL, 0x9d5e21e25ee27f9dUL,
0x3028607828784830UL, 0x37a16ef8a1f8cf37UL, 0x0a0f14110f111b0aUL, 0x2fb55ec4b5c4eb2fUL,
0x0e091c1b091b150eUL, 0x2436485a365a7e24UL, 0x1b9b36b69bb6ad1bUL, 0xdf3da5473d4798dfUL,
0xcd26816a266aa7cdUL, 0x4e699cbb69bbf54eUL, 0x7fcdfe4ccd4c337fUL, 0xea9fcfba9fba50eaUL,
0x121b242d1b2d3f12UL, 0x1d9e3ab99eb9a41dUL, 0x5874b09c749cc458UL, 0x342e68722e724634UL,
0x362d6c772d774136UL, 0xdcb2a3cdb2cd11dcUL, 0xb4ee7329ee299db4UL, 0x5bfbb616fb164d5bUL,
0xa4f65301f601a5a4UL, 0x764decd74dd7a176UL, 0xb76175a361a314b7UL, 0x7dcefa49ce49347dUL,
0x527ba48d7b8ddf52UL, 0xdd3ea1423e429fddUL, 0x5e71bc937193cd5eUL, 0x139726a297a2b113UL,
0xa6f55704f504a2a6UL, 0xb96869b868b801b9UL, 0x0000000000000000UL, 0xc12c99742c74b5c1UL,
0x406080a060a0e040UL, 0xe31fdd211f21c2e3UL, 0x79c8f243c8433a79UL, 0xb6ed772ced2c9ab6UL,
0xd4beb3d9bed90dd4UL, 0x8d4601ca46ca478dUL, 0x67d9ce70d9701767UL, 0x724be4dd4bddaf72UL,
0x94de3379de79ed94UL, 0x98d42b67d467ff98UL, 0xb0e87b23e82393b0UL, 0x854a11de4ade5b85UL,
0xbb6b6dbd6bbd06bbUL, 0xc52a917e2a7ebbc5UL, 0x4fe59e34e5347b4fUL, 0xed16c13a163ad7edUL,
0x86c51754c554d286UL, 0x9ad72f62d762f89aUL, 0x6655ccff55ff9966UL, 0x119422a794a7b611UL,
0x8acf0f4acf4ac08aUL, 0xe910c9301030d9e9UL, 0x0406080a060a0e04UL, 0xfe81e798819866feUL,
0xa0f05b0bf00baba0UL, 0x7844f0cc44ccb478UL, 0x25ba4ad5bad5f025UL, 0x4be3963ee33e754bUL,
0xa2f35f0ef30eaca2UL, 0x5dfeba19fe19445dUL, 0x80c01b5bc05bdb80UL, 0x058a0a858a858005UL,
0x3fad7eecadecd33fUL, 0x21bc42dfbcdffe21UL, 0x7048e0d848d8a870UL, 0xf104f90c040cfdf1UL,
0x63dfc67adf7a1963UL, 0x77c1ee58c1582f77UL, 0xaf75459f759f30afUL, 0x426384a563a5e742UL,
0x2030405030507020UL, 0xe51ad12e1a2ecbe5UL, 0xfd0ee1120e12effdUL, 0xbf6d65b76db708bfUL,
0x814c19d44cd45581UL, 0x1814303c143c2418UL, 0x26354c5f355f7926UL, 0xc32f9d712f71b2c3UL,
0xbee16738e13886beUL, 0x35a26afda2fdc835UL, 0x88cc0b4fcc4fc788UL, 0x2e395c4b394b652eUL,
0x93573df957f96a93UL, 0x55f2aa0df20d5855UL, 0xfc82e39d829d61fcUL, 0x7a47f4c947c9b37aUL,
0xc8ac8befacef27c8UL, 0xbae76f32e73288baUL, 0x322b647d2b7d4f32UL, 0xe695d7a495a442e6UL,
0xc0a09bfba0fb3bc0UL, 0x199832b398b3aa19UL, 0x9ed12768d168f69eUL, 0xa37f5d817f8122a3UL,
0x446688aa66aaee44UL, 0x547ea8827e82d654UL, 0x3bab76e6abe6dd3bUL, 0x0b83169e839e950bUL,
0x8cca0345ca45c98cUL, 0xc729957b297bbcc7UL, 0x6bd3d66ed36e056bUL, 0x283c50443c446c28UL,
0xa779558b798b2ca7UL, 0xbce2633de23d81bcUL, 0x161d2c271d273116UL, 0xad76419a769a37adUL,
0xdb3bad4d3b4d96dbUL, 0x6456c8fa56fa9e64UL, 0x744ee8d24ed2a674UL, 0x141e28221e223614UL,
0x92db3f76db76e492UL, 0x0c0a181e0a1e120cUL, 0x486c90b46cb4fc48UL, 0xb8e46b37e4378fb8UL,
0x9f5d25e75de7789fUL, 0xbd6e61b26eb20fbdUL, 0x43ef862aef2a6943UL, 0xc4a693f1a6f135c4UL,
0x39a872e3a8e3da39UL, 0x31a462f7a4f7c631UL, 0xd337bd5937598ad3UL, 0xf28bff868b8674f2UL,
0xd532b156325683d5UL, 0x8b430dc543c54e8bUL, 0x6e59dceb59eb856eUL, 0xdab7afc2b7c218daUL,
0x018c028f8c8f8e01UL, 0xb16479ac64ac1db1UL, 0x9cd2236dd26df19cUL, 0x49e0923be03b7249UL,
0xd8b4abc7b4c71fd8UL, 0xacfa4315fa15b9acUL, 0xf307fd090709faf3UL, 0xcf25856f256fa0cfUL,
0xcaaf8feaafea20caUL, 0xf48ef3898e897df4UL, 0x47e98e20e9206747UL, 0x1018202818283810UL,
0x6fd5de64d5640b6fUL, 0xf088fb83888373f0UL, 0x4a6f94b16fb1fb4aUL, 0x5c72b8967296ca5cUL,
0x3824706c246c5438UL, 0x57f1ae08f1085f57UL, 0x73c7e652c7522173UL, 0x975135f351f36497UL,
0xcb238d652365aecbUL, 0xa17c59847c8425a1UL, 0xe89ccbbf9cbf57e8UL, 0x3e217c6321635d3eUL,
0x96dd377cdd7cea96UL, 0x61dcc27fdc7f1e61UL, 0x0d861a9186919c0dUL, 0x0f851e9485949b0fUL,
0xe090dbab90ab4be0UL, 0x7c42f8c642c6ba7cUL, 0x71c4e257c4572671UL, 0xccaa83e5aae529ccUL,
0x90d83b73d873e390UL, 0x06050c0f050f0906UL, 0xf701f5030103f4f7UL, 0x1c12383612362a1cUL,
0xc2a39ffea3fe3cc2UL, 0x6a5fd4e15fe18b6aUL, 0xaef94710f910beaeUL, 0x69d0d26bd06b0269UL,
0x17912ea891a8bf17UL, 0x995829e858e87199UL, 0x3a2774692769533aUL, 0x27b94ed0b9d0f727UL,
0xd938a948384891d9UL, 0xeb13cd351335deebUL, 0x2bb356ceb3cee52bUL, 0x2233445533557722UL,
0xd2bbbfd6bbd604d2UL, 0xa9704990709039a9UL, 0x07890e8089808707UL, 0x33a766f2a7f2c133UL,
0x2db65ac1b6c1ec2dUL, 0x3c22786622665a3cUL, 0x15922aad92adb815UL, 0xc92089602060a9c9UL,
0x874915db49db5c87UL, 0xaaff4f1aff1ab0aaUL, 0x5078a0887888d850UL, 0xa57a518e7a8e2ba5UL,
0x038f068a8f8a8903UL, 0x59f8b213f8134a59UL, 0x0980129b809b9209UL, 0x1a1734391739231aUL,
0x65daca75da751065UL, 0xd731b553315384d7UL, 0x84c61351c651d584UL, 0xd0b8bbd3b8d303d0UL,
0x82c31f5ec35edc82UL, 0x29b052cbb0cbe229UL, 0x5a77b4997799c35aUL, 0x1e113c3311332d1eUL,
0x7bcbf646cb463d7bUL, 0xa8fc4b1ffc1fb7a8UL, 0x6dd6da61d6610c6dUL, 0x2c3a584e3a4e622cUL
};
static const __constant ulong T4_G[] =
{
0xA5F432C6C6A597F4UL, 0x84976FF8F884EB97UL, 0x99B05EEEEE99C7B0UL, 0x8D8C7AF6F68DF78CUL,
0x0D17E8FFFF0DE517UL, 0xBDDC0AD6D6BDB7DCUL, 0xB1C816DEDEB1A7C8UL, 0x54FC6D91915439FCUL,
0x50F090606050C0F0UL, 0x0305070202030405UL, 0xA9E02ECECEA987E0UL, 0x7D87D156567DAC87UL,
0x192BCCE7E719D52BUL, 0x62A613B5B56271A6UL, 0xE6317C4D4DE69A31UL, 0x9AB559ECEC9AC3B5UL,
0x45CF408F8F4505CFUL, 0x9DBCA31F1F9D3EBCUL, 0x40C04989894009C0UL, 0x879268FAFA87EF92UL,
0x153FD0EFEF15C53FUL, 0xEB2694B2B2EB7F26UL, 0xC940CE8E8EC90740UL, 0x0B1DE6FBFB0BED1DUL,
0xEC2F6E4141EC822FUL, 0x67A91AB3B3677DA9UL, 0xFD1C435F5FFDBE1CUL, 0xEA25604545EA8A25UL,
0xBFDAF92323BF46DAUL, 0xF702515353F7A602UL, 0x96A145E4E496D3A1UL, 0x5BED769B9B5B2DEDUL,
0xC25D287575C2EA5DUL, 0x1C24C5E1E11CD924UL, 0xAEE9D43D3DAE7AE9UL, 0x6ABEF24C4C6A98BEUL,
0x5AEE826C6C5AD8EEUL, 0x41C3BD7E7E41FCC3UL, 0x0206F3F5F502F106UL, 0x4FD15283834F1DD1UL,
0x5CE48C68685CD0E4UL, 0xF407565151F4A207UL, 0x345C8DD1D134B95CUL, 0x0818E1F9F908E918UL,
0x93AE4CE2E293DFAEUL, 0x73953EABAB734D95UL, 0x53F597626253C4F5UL, 0x3F416B2A2A3F5441UL,
0x0C141C08080C1014UL, 0x52F66395955231F6UL, 0x65AFE94646658CAFUL, 0x5EE27F9D9D5E21E2UL,
0x2878483030286078UL, 0xA1F8CF3737A16EF8UL, 0x0F111B0A0A0F1411UL, 0xB5C4EB2F2FB55EC4UL,
0x091B150E0E091C1BUL, 0x365A7E242436485AUL, 0x9BB6AD1B1B9B36B6UL, 0x3D4798DFDF3DA547UL,
0x266AA7CDCD26816AUL, 0x69BBF54E4E699CBBUL, 0xCD4C337F7FCDFE4CUL, 0x9FBA50EAEA9FCFBAUL,
0x1B2D3F12121B242DUL, 0x9EB9A41D1D9E3AB9UL, 0x749CC4585874B09CUL, 0x2E724634342E6872UL,
0x2D774136362D6C77UL, 0xB2CD11DCDCB2A3CDUL, 0xEE299DB4B4EE7329UL, 0xFB164D5B5BFBB616UL,
0xF601A5A4A4F65301UL, 0x4DD7A176764DECD7UL, 0x61A314B7B76175A3UL, 0xCE49347D7DCEFA49UL,
0x7B8DDF52527BA48DUL, 0x3E429FDDDD3EA142UL, 0x7193CD5E5E71BC93UL, 0x97A2B113139726A2UL,
0xF504A2A6A6F55704UL, 0x68B801B9B96869B8UL, 0x0000000000000000UL, 0x2C74B5C1C12C9974UL,
0x60A0E040406080A0UL, 0x1F21C2E3E31FDD21UL, 0xC8433A7979C8F243UL, 0xED2C9AB6B6ED772CUL,
0xBED90DD4D4BEB3D9UL, 0x46CA478D8D4601CAUL, 0xD970176767D9CE70UL, 0x4BDDAF72724BE4DDUL,
0xDE79ED9494DE3379UL, 0xD467FF9898D42B67UL, 0xE82393B0B0E87B23UL, 0x4ADE5B85854A11DEUL,
0x6BBD06BBBB6B6DBDUL, 0x2A7EBBC5C52A917EUL, 0xE5347B4F4FE59E34UL, 0x163AD7EDED16C13AUL,
0xC554D28686C51754UL, 0xD762F89A9AD72F62UL, 0x55FF99666655CCFFUL, 0x94A7B611119422A7UL,
0xCF4AC08A8ACF0F4AUL, 0x1030D9E9E910C930UL, 0x060A0E040406080AUL, 0x819866FEFE81E798UL,
0xF00BABA0A0F05B0BUL, 0x44CCB4787844F0CCUL, 0xBAD5F02525BA4AD5UL, 0xE33E754B4BE3963EUL,
0xF30EACA2A2F35F0EUL, 0xFE19445D5DFEBA19UL, 0xC05BDB8080C01B5BUL, 0x8A858005058A0A85UL,
0xADECD33F3FAD7EECUL, 0xBCDFFE2121BC42DFUL, 0x48D8A8707048E0D8UL, 0x040CFDF1F104F90CUL,
0xDF7A196363DFC67AUL, 0xC1582F7777C1EE58UL, 0x759F30AFAF75459FUL, 0x63A5E742426384A5UL,
0x3050702020304050UL, 0x1A2ECBE5E51AD12EUL, 0x0E12EFFDFD0EE112UL, 0x6DB708BFBF6D65B7UL,
0x4CD45581814C19D4UL, 0x143C24181814303CUL, 0x355F792626354C5FUL, 0x2F71B2C3C32F9D71UL,
0xE13886BEBEE16738UL, 0xA2FDC83535A26AFDUL, 0xCC4FC78888CC0B4FUL, 0x394B652E2E395C4BUL,
0x57F96A9393573DF9UL, 0xF20D585555F2AA0DUL, 0x829D61FCFC82E39DUL, 0x47C9B37A7A47F4C9UL,
0xACEF27C8C8AC8BEFUL, 0xE73288BABAE76F32UL, 0x2B7D4F32322B647DUL, 0x95A442E6E695D7A4UL,
0xA0FB3BC0C0A09BFBUL, 0x98B3AA19199832B3UL, 0xD168F69E9ED12768UL, 0x7F8122A3A37F5D81UL,
0x66AAEE44446688AAUL, 0x7E82D654547EA882UL, 0xABE6DD3B3BAB76E6UL, 0x839E950B0B83169EUL,
0xCA45C98C8CCA0345UL, 0x297BBCC7C729957BUL, 0xD36E056B6BD3D66EUL, 0x3C446C28283C5044UL,
0x798B2CA7A779558BUL, 0xE23D81BCBCE2633DUL, 0x1D273116161D2C27UL, 0x769A37ADAD76419AUL,
0x3B4D96DBDB3BAD4DUL, 0x56FA9E646456C8FAUL, 0x4ED2A674744EE8D2UL, 0x1E223614141E2822UL,
0xDB76E49292DB3F76UL, 0x0A1E120C0C0A181EUL, 0x6CB4FC48486C90B4UL, 0xE4378FB8B8E46B37UL,
0x5DE7789F9F5D25E7UL, 0x6EB20FBDBD6E61B2UL, 0xEF2A694343EF862AUL, 0xA6F135C4C4A693F1UL,
0xA8E3DA3939A872E3UL, 0xA4F7C63131A462F7UL, 0x37598AD3D337BD59UL, 0x8B8674F2F28BFF86UL,
0x325683D5D532B156UL, 0x43C54E8B8B430DC5UL, 0x59EB856E6E59DCEBUL, 0xB7C218DADAB7AFC2UL,
0x8C8F8E01018C028FUL, 0x64AC1DB1B16479ACUL, 0xD26DF19C9CD2236DUL, 0xE03B724949E0923BUL,
0xB4C71FD8D8B4ABC7UL, 0xFA15B9ACACFA4315UL, 0x0709FAF3F307FD09UL, 0x256FA0CFCF25856FUL,
0xAFEA20CACAAF8FEAUL, 0x8E897DF4F48EF389UL, 0xE920674747E98E20UL, 0x1828381010182028UL,
0xD5640B6F6FD5DE64UL, 0x888373F0F088FB83UL, 0x6FB1FB4A4A6F94B1UL, 0x7296CA5C5C72B896UL,
0x246C54383824706CUL, 0xF1085F5757F1AE08UL, 0xC752217373C7E652UL, 0x51F36497975135F3UL,
0x2365AECBCB238D65UL, 0x7C8425A1A17C5984UL, 0x9CBF57E8E89CCBBFUL, 0x21635D3E3E217C63UL,
0xDD7CEA9696DD377CUL, 0xDC7F1E6161DCC27FUL, 0x86919C0D0D861A91UL, 0x85949B0F0F851E94UL,
0x90AB4BE0E090DBABUL, 0x42C6BA7C7C42F8C6UL, 0xC457267171C4E257UL, 0xAAE529CCCCAA83E5UL,
0xD873E39090D83B73UL, 0x050F090606050C0FUL, 0x0103F4F7F701F503UL, 0x12362A1C1C123836UL,
0xA3FE3CC2C2A39FFEUL, 0x5FE18B6A6A5FD4E1UL, 0xF910BEAEAEF94710UL, 0xD06B026969D0D26BUL,
0x91A8BF1717912EA8UL, 0x58E87199995829E8UL, 0x2769533A3A277469UL, 0xB9D0F72727B94ED0UL,
0x384891D9D938A948UL, 0x1335DEEBEB13CD35UL, 0xB3CEE52B2BB356CEUL, 0x3355772222334455UL,
0xBBD604D2D2BBBFD6UL, 0x709039A9A9704990UL, 0x8980870707890E80UL, 0xA7F2C13333A766F2UL,
0xB6C1EC2D2DB65AC1UL, 0x22665A3C3C227866UL, 0x92ADB81515922AADUL, 0x2060A9C9C9208960UL,
0x49DB5C87874915DBUL, 0xFF1AB0AAAAFF4F1AUL, 0x7888D8505078A088UL, 0x7A8E2BA5A57A518EUL,
0x8F8A8903038F068AUL, 0xF8134A5959F8B213UL, 0x809B92090980129BUL, 0x1739231A1A173439UL,
0xDA75106565DACA75UL, 0x315384D7D731B553UL, 0xC651D58484C61351UL, 0xB8D303D0D0B8BBD3UL,
0xC35EDC8282C31F5EUL, 0xB0CBE22929B052CBUL, 0x7799C35A5A77B499UL, 0x11332D1E1E113C33UL,
0xCB463D7B7BCBF646UL, 0xFC1FB7A8A8FC4B1FUL, 0xD6610C6D6DD6DA61UL, 0x3A4E622C2C3A584EUL
};
#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \
t[d] = T0_G[B64_0(a[b0])] \
^ R64(T0_G[B64_1(a[b1])], 8) \
^ R64(T0_G[B64_2(a[b2])], 16) \
^ R64(T0_G[B64_3(a[b3])], 24) \
^ T4_G[B64_4(a[b4])] \
^ R64(T4_G[B64_5(a[b5])], 8) \
^ R64(T4_G[B64_6(a[b6])], 16) \
^ R64(T4_G[B64_7(a[b7])], 24); \
} while (0)
#define ROUND_SMALL_P(a, r) do { \
ulong t[8]; \
a[0] ^= PC64(0x00, r); \
a[1] ^= PC64(0x10, r); \
a[2] ^= PC64(0x20, r); \
a[3] ^= PC64(0x30, r); \
a[4] ^= PC64(0x40, r); \
a[5] ^= PC64(0x50, r); \
a[6] ^= PC64(0x60, r); \
a[7] ^= PC64(0x70, r); \
RSTT(0, a, 0, 1, 2, 3, 4, 5, 6, 7); \
RSTT(1, a, 1, 2, 3, 4, 5, 6, 7, 0); \
RSTT(2, a, 2, 3, 4, 5, 6, 7, 0, 1); \
RSTT(3, a, 3, 4, 5, 6, 7, 0, 1, 2); \
RSTT(4, a, 4, 5, 6, 7, 0, 1, 2, 3); \
RSTT(5, a, 5, 6, 7, 0, 1, 2, 3, 4); \
RSTT(6, a, 6, 7, 0, 1, 2, 3, 4, 5); \
RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \
a[0] = t[0]; \
a[1] = t[1]; \
a[2] = t[2]; \
a[3] = t[3]; \
a[4] = t[4]; \
a[5] = t[5]; \
a[6] = t[6]; \
a[7] = t[7]; \
} while (0)
#define ROUND_SMALL_Pf(a,r) do { \
a[0] ^= PC64(0x00, r); \
a[1] ^= PC64(0x10, r); \
a[2] ^= PC64(0x20, r); \
a[3] ^= PC64(0x30, r); \
a[4] ^= PC64(0x40, r); \
a[5] ^= PC64(0x50, r); \
a[6] ^= PC64(0x60, r); \
a[7] ^= PC64(0x70, r); \
RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \
a[7] = t[7]; \
} while (0)
#define ROUND_SMALL_Q(a, r) do { \
ulong t[8]; \
a[0] ^= QC64(0x00, r); \
a[1] ^= QC64(0x10, r); \
a[2] ^= QC64(0x20, r); \
a[3] ^= QC64(0x30, r); \
a[4] ^= QC64(0x40, r); \
a[5] ^= QC64(0x50, r); \
a[6] ^= QC64(0x60, r); \
a[7] ^= QC64(0x70, r); \
RSTT(0, a, 1, 3, 5, 7, 0, 2, 4, 6); \
RSTT(1, a, 2, 4, 6, 0, 1, 3, 5, 7); \
RSTT(2, a, 3, 5, 7, 1, 2, 4, 6, 0); \
RSTT(3, a, 4, 6, 0, 2, 3, 5, 7, 1); \
RSTT(4, a, 5, 7, 1, 3, 4, 6, 0, 2); \
RSTT(5, a, 6, 0, 2, 4, 5, 7, 1, 3); \
RSTT(6, a, 7, 1, 3, 5, 6, 0, 2, 4); \
RSTT(7, a, 0, 2, 4, 6, 7, 1, 3, 5); \
a[0] = t[0]; \
a[1] = t[1]; \
a[2] = t[2]; \
a[3] = t[3]; \
a[4] = t[4]; \
a[5] = t[5]; \
a[6] = t[6]; \
a[7] = t[7]; \
} while (0)
#define PERM_SMALL_P(a) do { \
for (int r = 0; r < 10; r ++) \
ROUND_SMALL_P(a, r); \
} while (0)
#define PERM_SMALL_Pf(a) do { \
for (int r = 0; r < 9; r ++) { \
ROUND_SMALL_P(a, r);} \
ROUND_SMALL_Pf(a,9); \
} while (0)
#define PERM_SMALL_Q(a) do { \
for (int r = 0; r < 10; r ++) \
ROUND_SMALL_Q(a, r); \
} while (0)
================================================
FILE: opencl/jh.cl
================================================
/* $Id: jh.c 255 2011-06-07 19:50:20Z tp $ */
/*
* JH implementation.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin
*/
#define SPH_JH_64 1
#define SPH_LITTLE_ENDIAN 1
#define SPH_C32(x) x
#define SPH_C64(x) x
typedef uint sph_u32;
typedef ulong sph_u64;
/*
* The internal bitslice representation may use either big-endian or
* little-endian (true bitslice operations do not care about the bit
* ordering, and the bit-swapping linear operations in JH happen to
* be invariant through endianness-swapping). The constants must be
* defined according to the chosen endianness; we use some
* byte-swapping macros for that.
*/
#if SPH_LITTLE_ENDIAN
#define C32e(x) ((SPH_C32(x) >> 24) \
| ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \
| ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \
| ((SPH_C32(x) << 24) & SPH_C32(0xFF000000)))
#define dec32e_aligned sph_dec32le_aligned
#define enc32e sph_enc32le
#define C64e(x) ((SPH_C64(x) >> 56) \
| ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \
| ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \
| ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \
| ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \
| ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \
| ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \
| ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000)))
#define dec64e_aligned sph_dec64le_aligned
#define enc64e sph_enc64le
#else
#define C32e(x) SPH_C32(x)
#define dec32e_aligned sph_dec32be_aligned
#define enc32e sph_enc32be
#define C64e(x) SPH_C64(x)
#define dec64e_aligned sph_dec64be_aligned
#define enc64e sph_enc64be
#endif
#define Sb(x0, x1, x2, x3, c) do { \
x3 = ~x3; \
x0 ^= (c) & ~x2; \
tmp = (c) ^ (x0 & x1); \
x0 ^= x2 & x3; \
x3 ^= ~x1 & x2; \
x1 ^= x0 & x2; \
x2 ^= x0 & ~x3; \
x0 ^= x1 | x3; \
x3 ^= x1 & x2; \
x1 ^= tmp & x0; \
x2 ^= tmp; \
} while (0)
#define Lb(x0, x1, x2, x3, x4, x5, x6, x7) do { \
x4 ^= x1; \
x5 ^= x2; \
x6 ^= x3 ^ x0; \
x7 ^= x0; \
x0 ^= x5; \
x1 ^= x6; \
x2 ^= x7 ^ x4; \
x3 ^= x4; \
} while (0)
static const __constant ulong C[] =
{
0x67F815DFA2DED572UL, 0x571523B70A15847BUL, 0xF6875A4D90D6AB81UL, 0x402BD1C3C54F9F4EUL,
0x9CFA455CE03A98EAUL, 0x9A99B26699D2C503UL, 0x8A53BBF2B4960266UL, 0x31A2DB881A1456B5UL,
0xDB0E199A5C5AA303UL, 0x1044C1870AB23F40UL, 0x1D959E848019051CUL, 0xDCCDE75EADEB336FUL,
0x416BBF029213BA10UL, 0xD027BBF7156578DCUL, 0x5078AA3739812C0AUL, 0xD3910041D2BF1A3FUL,
0x907ECCF60D5A2D42UL, 0xCE97C0929C9F62DDUL, 0xAC442BC70BA75C18UL, 0x23FCC663D665DFD1UL,
0x1AB8E09E036C6E97UL, 0xA8EC6C447E450521UL, 0xFA618E5DBB03F1EEUL, 0x97818394B29796FDUL,
0x2F3003DB37858E4AUL, 0x956A9FFB2D8D672AUL, 0x6C69B8F88173FE8AUL, 0x14427FC04672C78AUL,
0xC45EC7BD8F15F4C5UL, 0x80BB118FA76F4475UL, 0xBC88E4AEB775DE52UL, 0xF4A3A6981E00B882UL,
0x1563A3A9338FF48EUL, 0x89F9B7D524565FAAUL, 0xFDE05A7C20EDF1B6UL, 0x362C42065AE9CA36UL,
0x3D98FE4E433529CEUL, 0xA74B9A7374F93A53UL, 0x86814E6F591FF5D0UL, 0x9F5AD8AF81AD9D0EUL,
0x6A6234EE670605A7UL, 0x2717B96EBE280B8BUL, 0x3F1080C626077447UL, 0x7B487EC66F7EA0E0UL,
0xC0A4F84AA50A550DUL, 0x9EF18E979FE7E391UL, 0xD48D605081727686UL, 0x62B0E5F3415A9E7EUL,
0x7A205440EC1F9FFCUL, 0x84C9F4CE001AE4E3UL, 0xD895FA9DF594D74FUL, 0xA554C324117E2E55UL,
0x286EFEBD2872DF5BUL, 0xB2C4A50FE27FF578UL, 0x2ED349EEEF7C8905UL, 0x7F5928EB85937E44UL,
0x4A3124B337695F70UL, 0x65E4D61DF128865EUL, 0xE720B95104771BC7UL, 0x8A87D423E843FE74UL,
0xF2947692A3E8297DUL, 0xC1D9309B097ACBDDUL, 0xE01BDC5BFB301B1DUL, 0xBF829CF24F4924DAUL,
0xFFBF70B431BAE7A4UL, 0x48BCF8DE0544320DUL, 0x39D3BB5332FCAE3BUL, 0xA08B29E0C1C39F45UL,
0x0F09AEF7FD05C9E5UL, 0x34F1904212347094UL, 0x95ED44E301B771A2UL, 0x4A982F4F368E3BE9UL,
0x15F66CA0631D4088UL, 0xFFAF52874B44C147UL, 0x30C60AE2F14ABB7EUL, 0xE68C6ECCC5B67046UL,
0x00CA4FBD56A4D5A4UL, 0xAE183EC84B849DDAUL, 0xADD1643045CE5773UL, 0x67255C1468CEA6E8UL,
0x16E10ECBF28CDAA3UL, 0x9A99949A5806E933UL, 0x7B846FC220B2601FUL, 0x1885D1A07FACCED1UL,
0xD319DD8DA15B5932UL, 0x46B4A5AAC01C9A50UL, 0xBA6B04E467633D9FUL, 0x7EEE560BAB19CAF6UL,
0x742128A9EA79B11FUL, 0xEE51363B35F7BDE9UL, 0x76D350755AAC571DUL, 0x01707DA3FEC2463AUL,
0x42D8A498AFC135F7UL, 0x79676B9E20ECED78UL, 0xA8DB3AEA15638341UL, 0x832C83324D3BC3FAUL,
0xF347271C1F3B40A7UL, 0x9A762DB734F04059UL, 0xFD4F21D26C4E3EE7UL, 0xEF5957DC398DFDB8UL,
0xDAEB492B490C9B8DUL, 0x0D70F36849D7A25BUL, 0x84558D7AD0AE3B7DUL, 0x658EF8E4F0E9A5F5UL,
0x533B1036F4A2B8A0UL, 0x5AEC3E759E07A80CUL, 0x4F88E85692946891UL, 0x4CBCBAF8555CB05BUL,
0x7B9487F3993BBBE3UL, 0x5D1C6B72D6F4DA75UL, 0x6DB334DC28ACAE64UL, 0x71DB28B850A5346CUL,
0x2A518D10F2E261F8UL, 0xFC75DD593364DBE3UL, 0xA23FCE43F1BCAC1CUL, 0xB043E8023CD1BB67UL,
0x75A12988CA5B0A33UL, 0x5C5316B44D19347FUL, 0x1E4D790EC3943B92UL, 0x3FAFEEB6D7757479UL,
0x21391ABEF7D4A8EAUL, 0x5127234C097EF45CUL, 0xD23C32BA5324A326UL, 0xADD5A66D4A17A344UL,
0x08C9F2AFA63E1DB5UL, 0x563C6B91983D5983UL, 0x4D608672A17CF84CUL, 0xF6C76E08CC3EE246UL,
0x5E76BCB1B333982FUL, 0x2AE6C4EFA566D62BUL, 0x36D4C1BEE8B6F406UL, 0x6321EFBC1582EE74UL,
0x69C953F40D4EC1FDUL, 0x26585806C45A7DA7UL, 0x16FAE0061614C17EUL, 0x3F9D63283DAF907EUL,
0x0CD29B00E3F2C9D2UL, 0x300CD4B730CEAA5FUL, 0x9832E0F216512A74UL, 0x9AF8CEE3D830EB0DUL,
0x9279F1B57B9EC54BUL, 0xD36886046EE651FFUL, 0x316796E6574D239BUL, 0x05750A17F3A6E6CCUL,
0xCE6C3213D98176B1UL, 0x62A205F88452173CUL, 0x47154778B3CB2BF4UL, 0x486A9323825446FFUL,
0x65655E4E0758DF38UL, 0x8E5086FC897CFCF2UL, 0x86CA0BD0442E7031UL, 0x4E477830A20940F0UL,
0x8338F7D139EEA065UL, 0xBD3A2CE437E95EF7UL, 0x6FF8130126B29721UL, 0xE7DE9FEFD1ED44A3UL,
0xD992257615DFA08BUL, 0xBE42DC12F6F7853CUL, 0x7EB027AB7CECA7D8UL, 0xDEA83EAADA7D8D53UL,
0xD86902BD93CE25AAUL, 0xF908731AFD43F65AUL, 0xA5194A17DAEF5FC0UL, 0x6A21FD4C33664D97UL,
0x701541DB3198B435UL, 0x9B54CDEDBB0F1EEAUL, 0x72409751A163D09AUL, 0xE26F4791BF9D75F6UL
};
#define Ceven_hi(r) (C[((r) << 2) + 0])
#define Ceven_lo(r) (C[((r) << 2) + 1])
#define Codd_hi(r) (C[((r) << 2) + 2])
#define Codd_lo(r) (C[((r) << 2) + 3])
#define S(x0, x1, x2, x3, cb, r) do { \
Sb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, cb ## hi(r)); \
Sb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, cb ## lo(r)); \
} while (0)
#define L(x0, x1, x2, x3, x4, x5, x6, x7) do { \
Lb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, \
x4 ## h, x5 ## h, x6 ## h, x7 ## h); \
Lb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, \
x4 ## l, x5 ## l, x6 ## l, x7 ## l); \
} while (0)
#define Wz(x, c, n) do { \
sph_u64 t = (x ## h & (c)) << (n); \
x ## h = ((x ## h >> (n)) & (c)) | t; \
t = (x ## l & (c)) << (n); \
x ## l = ((x ## l >> (n)) & (c)) | t; \
} while (0)
#define W0(x) Wz(x, SPH_C64(0x5555555555555555), 1)
#define W1(x) Wz(x, SPH_C64(0x3333333333333333), 2)
#define W2(x) Wz(x, SPH_C64(0x0F0F0F0F0F0F0F0F), 4)
#define W3(x) Wz(x, SPH_C64(0x00FF00FF00FF00FF), 8)
#define W4(x) Wz(x, SPH_C64(0x0000FFFF0000FFFF), 16)
#define W5(x) Wz(x, SPH_C64(0x00000000FFFFFFFF), 32)
#define W6(x) do { \
sph_u64 t = x ## h; \
x ## h = x ## l; \
x ## l = t; \
} while (0)
#define SL(ro) SLu(r + ro, ro)
#define SLu(r, ro) do { \
S(h0, h2, h4, h6, Ceven_, r); \
S(h1, h3, h5, h7, Codd_, r); \
L(h0, h2, h4, h6, h1, h3, h5, h7); \
W ## ro(h1); \
W ## ro(h3); \
W ## ro(h5); \
W ## ro(h7); \
} while (0)
#if SPH_SMALL_FOOTPRINT_JH
/*
* The "small footprint" 64-bit version just uses a partially unrolled
* loop.
*/
#define E8 do { \
unsigned r; \
for (r = 0; r < 42; r += 7) { \
SL(0); \
SL(1); \
SL(2); \
SL(3); \
SL(4); \
SL(5); \
SL(6); \
} \
} while (0)
#else
/*
* On a "true 64-bit" architecture, we can unroll at will.
*/
#define E8 do { \
SLu( 0, 0); \
SLu( 1, 1); \
SLu( 2, 2); \
SLu( 3, 3); \
SLu( 4, 4); \
SLu( 5, 5); \
SLu( 6, 6); \
SLu( 7, 0); \
SLu( 8, 1); \
SLu( 9, 2); \
SLu(10, 3); \
SLu(11, 4); \
SLu(12, 5); \
SLu(13, 6); \
SLu(14, 0); \
SLu(15, 1); \
SLu(16, 2); \
SLu(17, 3); \
SLu(18, 4); \
SLu(19, 5); \
SLu(20, 6); \
SLu(21, 0); \
SLu(22, 1); \
SLu(23, 2); \
SLu(24, 3); \
SLu(25, 4); \
SLu(26, 5); \
SLu(27, 6); \
SLu(28, 0); \
SLu(29, 1); \
SLu(30, 2); \
SLu(31, 3); \
SLu(32, 4); \
SLu(33, 5); \
SLu(34, 6); \
SLu(35, 0); \
SLu(36, 1); \
SLu(37, 2); \
SLu(38, 3); \
SLu(39, 4); \
SLu(40, 5); \
SLu(41, 6); \
} while (0)
#endif
================================================
FILE: opencl/wolf-aes.cl
================================================
#ifndef WOLF_AES_CL
#define WOLF_AES_CL
// AES table - the other three are generated on the fly
static const __constant uint AES0_C[256] =
{
0xA56363C6U, 0x847C7CF8U, 0x997777EEU, 0x8D7B7BF6U,
0x0DF2F2FFU, 0xBD6B6BD6U, 0xB16F6FDEU, 0x54C5C591U,
0x50303060U, 0x03010102U, 0xA96767CEU, 0x7D2B2B56U,
0x19FEFEE7U, 0x62D7D7B5U, 0xE6ABAB4DU, 0x9A7676ECU,
0x45CACA8FU, 0x9D82821FU, 0x40C9C989U, 0x877D7DFAU,
0x15FAFAEFU, 0xEB5959B2U, 0xC947478EU, 0x0BF0F0FBU,
0xECADAD41U, 0x67D4D4B3U, 0xFDA2A25FU, 0xEAAFAF45U,
0xBF9C9C23U, 0xF7A4A453U, 0x967272E4U, 0x5BC0C09BU,
0xC2B7B775U, 0x1CFDFDE1U, 0xAE93933DU, 0x6A26264CU,
0x5A36366CU, 0x413F3F7EU, 0x02F7F7F5U, 0x4FCCCC83U,
0x5C343468U, 0xF4A5A551U, 0x34E5E5D1U, 0x08F1F1F9U,
0x937171E2U, 0x73D8D8ABU, 0x53313162U, 0x3F15152AU,
0x0C040408U, 0x52C7C795U, 0x65232346U, 0x5EC3C39DU,
0x28181830U, 0xA1969637U, 0x0F05050AU, 0xB59A9A2FU,
0x0907070EU, 0x36121224U, 0x9B80801BU, 0x3DE2E2DFU,
0x26EBEBCDU, 0x6927274EU, 0xCDB2B27FU, 0x9F7575EAU,
0x1B090912U, 0x9E83831DU, 0x742C2C58U, 0x2E1A1A34U,
0x2D1B1B36U, 0xB26E6EDCU, 0xEE5A5AB4U, 0xFBA0A05BU,
0xF65252A4U, 0x4D3B3B76U, 0x61D6D6B7U, 0xCEB3B37DU,
0x7B292952U, 0x3EE3E3DDU, 0x712F2F5EU, 0x97848413U,
0xF55353A6U, 0x68D1D1B9U, 0x00000000U, 0x2CEDEDC1U,
0x60202040U, 0x1FFCFCE3U, 0xC8B1B179U, 0xED5B5BB6U,
0xBE6A6AD4U, 0x46CBCB8DU, 0xD9BEBE67U, 0x4B393972U,
0xDE4A4A94U, 0xD44C4C98U, 0xE85858B0U, 0x4ACFCF85U,
0x6BD0D0BBU, 0x2AEFEFC5U, 0xE5AAAA4FU, 0x16FBFBEDU,
0xC5434386U, 0xD74D4D9AU, 0x55333366U, 0x94858511U,
0xCF45458AU, 0x10F9F9E9U, 0x06020204U, 0x817F7FFEU,
0xF05050A0U, 0x443C3C78U, 0xBA9F9F25U, 0xE3A8A84BU,
0xF35151A2U, 0xFEA3A35DU, 0xC0404080U, 0x8A8F8F05U,
0xAD92923FU, 0xBC9D9D21U, 0x48383870U, 0x04F5F5F1U,
0xDFBCBC63U, 0xC1B6B677U, 0x75DADAAFU, 0x63212142U,
0x30101020U, 0x1AFFFFE5U, 0x0EF3F3FDU, 0x6DD2D2BFU,
0x4CCDCD81U, 0x140C0C18U, 0x35131326U, 0x2FECECC3U,
0xE15F5FBEU, 0xA2979735U, 0xCC444488U, 0x3917172EU,
0x57C4C493U, 0xF2A7A755U, 0x827E7EFCU, 0x473D3D7AU,
0xAC6464C8U, 0xE75D5DBAU, 0x2B191932U, 0x957373E6U,
0xA06060C0U, 0x98818119U, 0xD14F4F9EU, 0x7FDCDCA3U,
0x66222244U, 0x7E2A2A54U, 0xAB90903BU, 0x8388880BU,
0xCA46468CU, 0x29EEEEC7U, 0xD3B8B86BU, 0x3C141428U,
0x79DEDEA7U, 0xE25E5EBCU, 0x1D0B0B16U, 0x76DBDBADU,
0x3BE0E0DBU, 0x56323264U, 0x4E3A3A74U, 0x1E0A0A14U,
0xDB494992U, 0x0A06060CU, 0x6C242448U, 0xE45C5CB8U,
0x5DC2C29FU, 0x6ED3D3BDU, 0xEFACAC43U, 0xA66262C4U,
0xA8919139U, 0xA4959531U, 0x37E4E4D3U, 0x8B7979F2U,
0x32E7E7D5U, 0x43C8C88BU, 0x5937376EU, 0xB76D6DDAU,
0x8C8D8D01U, 0x64D5D5B1U, 0xD24E4E9CU, 0xE0A9A949U,
0xB46C6CD8U, 0xFA5656ACU, 0x07F4F4F3U, 0x25EAEACFU,
0xAF6565CAU, 0x8E7A7AF4U, 0xE9AEAE47U, 0x18080810U,
0xD5BABA6FU, 0x887878F0U, 0x6F25254AU, 0x722E2E5CU,
0x241C1C38U, 0xF1A6A657U, 0xC7B4B473U, 0x51C6C697U,
0x23E8E8CBU, 0x7CDDDDA1U, 0x9C7474E8U, 0x211F1F3EU,
0xDD4B4B96U, 0xDCBDBD61U, 0x868B8B0DU, 0x858A8A0FU,
0x907070E0U, 0x423E3E7CU, 0xC4B5B571U, 0xAA6666CCU,
0xD8484890U, 0x05030306U, 0x01F6F6F7U, 0x120E0E1CU,
0xA36161C2U, 0x5F35356AU, 0xF95757AEU, 0xD0B9B969U,
0x91868617U, 0x58C1C199U, 0x271D1D3AU, 0xB99E9E27U,
0x38E1E1D9U, 0x13F8F8EBU, 0xB398982BU, 0x33111122U,
0xBB6969D2U, 0x70D9D9A9U, 0x898E8E07U, 0xA7949433U,
0xB69B9B2DU, 0x221E1E3CU, 0x92878715U, 0x20E9E9C9U,
0x49CECE87U, 0xFF5555AAU, 0x78282850U, 0x7ADFDFA5U,
0x8F8C8C03U, 0xF8A1A159U, 0x80898909U, 0x170D0D1AU,
0xDABFBF65U, 0x31E6E6D7U, 0xC6424284U, 0xB86868D0U,
0xC3414182U, 0xB0999929U, 0x772D2D5AU, 0x110F0F1EU,
0xCBB0B07BU, 0xFC5454A8U, 0xD6BBBB6DU, 0x3A16162CU
};
#define BYTE(x, y) (amd_bfe((x), (y) << 3U, 8U))
uint4 AES_Round(const __local uint *AES0, const __local uint *AES1, const __local uint *AES2, const __local uint *AES3, const uint4 X, const uint4 key)
{
uint4 Y;
Y.s0 = AES0[BYTE(X.s0, 0)] ^ AES1[BYTE(X.s1, 1)] ^ AES2[BYTE(X.s2, 2)] ^ AES3[BYTE(X.s3, 3)];
Y.s1 = AES0[BYTE(X.s1, 0)] ^ AES1[BYTE(X.s2, 1)] ^ AES2[BYTE(X.s3, 2)] ^ AES3[BYTE(X.s0, 3)];
Y.s2 = AES0[BYTE(X.s2, 0)] ^ AES1[BYTE(X.s3, 1)] ^ AES2[BYTE(X.s0, 2)] ^ AES3[BYTE(X.s1, 3)];
Y.s3 = AES0[BYTE(X.s3, 0)] ^ AES1[BYTE(X.s0, 1)] ^ AES2[BYTE(X.s1, 2)] ^ AES3[BYTE(X.s2, 3)];
Y ^= key;
return(Y);
}
#endif
================================================
FILE: opencl/wolf-skein.cl
================================================
#ifndef WOLF_SKEIN_CL
#define WOLF_SKEIN_CL
// Vectorized Skein implementation macros and functions by Wolf
#define SKEIN_KS_PARITY 0x1BD11BDAA9FC1A22
static const __constant ulong SKEIN256_IV[8] =
{
0xCCD044A12FDB3E13UL, 0xE83590301A79A9EBUL,
0x55AEA0614F816E6FUL, 0x2A2767A4AE9B94DBUL,
0xEC06025E74DD7683UL, 0xE7A436CDC4746251UL,
0xC36FBAF9393AD185UL, 0x3EEDBA1833EDFC13UL
};
static const __constant ulong SKEIN512_256_IV[8] =
{
0xCCD044A12FDB3E13UL, 0xE83590301A79A9EBUL,
0x55AEA0614F816E6FUL, 0x2A2767A4AE9B94DBUL,
0xEC06025E74DD7683UL, 0xE7A436CDC4746251UL,
0xC36FBAF9393AD185UL, 0x3EEDBA1833EDFC13UL
};
#define SKEIN_INJECT_KEY(p, s) do { \
p += h; \
p.s5 += t[s % 3]; \
p.s6 += t[(s + 1) % 3]; \
p.s7 += s; \
} while(0)
ulong SKEIN_ROT(const uint2 x, const uint y)
{
if(y < 32) return(as_ulong(amd_bitalign(x, x.s10, 32 - y)));
else return(as_ulong(amd_bitalign(x.s10, x, 32 - (y - 32))));
}
void SkeinMix8(ulong4 *pv0, ulong4 *pv1, const uint rc0, const uint rc1, const uint rc2, const uint rc3)
{
*pv0 += *pv1;
(*pv1).s0 = SKEIN_ROT(as_uint2((*pv1).s0), rc0);
(*pv1).s1 = SKEIN_ROT(as_uint2((*pv1).s1), rc1);
(*pv1).s2 = SKEIN_ROT(as_uint2((*pv1).s2), rc2);
(*pv1).s3 = SKEIN_ROT(as_uint2((*pv1).s3), rc3);
*pv1 ^= *pv0;
}
ulong8 SkeinEvenRound(ulong8 p, const ulong8 h, const ulong *t, const uint s)
{
SKEIN_INJECT_KEY(p, s);
ulong4 pv0 = p.even, pv1 = p.odd;
SkeinMix8(&pv0, &pv1, 46, 36, 19, 37);
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
SkeinMix8(&pv0, &pv1, 33, 27, 14, 42);
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
SkeinMix8(&pv0, &pv1, 17, 49, 36, 39);
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
SkeinMix8(&pv0, &pv1, 44, 9, 54, 56);
return(shuffle2(pv0, pv1, (ulong8)(1, 4, 2, 7, 3, 6, 0, 5)));
}
ulong8 SkeinOddRound(ulong8 p, const ulong8 h, const ulong *t, const uint s)
{
SKEIN_INJECT_KEY(p, s);
ulong4 pv0 = p.even, pv1 = p.odd;
SkeinMix8(&pv0, &pv1, 39, 30, 34, 24);
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
SkeinMix8(&pv0, &pv1, 13, 50, 10, 17);
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
SkeinMix8(&pv0, &pv1, 25, 29, 39, 43);
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
SkeinMix8(&pv0, &pv1, 8, 35, 56, 22);
return(shuffle2(pv0, pv1, (ulong8)(1, 4, 2, 7, 3, 6, 0, 5)));
}
ulong8 Skein512Block(ulong8 p, ulong8 h, ulong h8, const ulong *t)
{
#pragma unroll
for(int i = 0; i < 18; ++i)
{
p = SkeinEvenRound(p, h, t, i);
++i;
ulong tmp = h.s0;
h = shuffle(h, (ulong8)(1, 2, 3, 4, 5, 6, 7, 0));
h.s7 = h8;
h8 = tmp;
p = SkeinOddRound(p, h, t, i);
tmp = h.s0;
h = shuffle(h, (ulong8)(1, 2, 3, 4, 5, 6, 7, 0));
h.s7 = h8;
h8 = tmp;
}
SKEIN_INJECT_KEY(p, 18);
return(p);
}
#endif
================================================
FILE: rapidjson/allocators.h
================================================
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Allocator
/*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static.
So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block.
\code
concept Allocator {
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
// Allocate a memory block.
// \param size of the memory block in bytes.
// \returns pointer to the memory block.
void* Malloc(size_t size);
// Resize a memory block.
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
// \param newSize the new size in bytes.
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
// Free a memory block.
// \param pointer to the memory block. Null pointer is permitted.
static void Free(void *ptr);
};
\endcode
*/
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
//! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines.
\note implements Allocator concept
*/
class CrtAllocator {
public:
static const bool kNeedFree = true;
void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
return std::malloc(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize;
if (newSize == 0) {
std::free(originalPtr);
return NULL;
}
return std::realloc(originalPtr, newSize);
}
static void Free(void *ptr) { std::free(ptr); }
};
///////////////////////////////////////////////////////////////////////////////
// MemoryPoolAllocator
//! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
It does not free memory blocks. And Realloc() only allocate new memory.
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
User may also supply a buffer as the first chunk.
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
The user-buffer is not deallocated by this allocator.
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
\note implements Allocator concept
*/
template
class MemoryPoolAllocator {
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{
}
//! Constructor with user-supplied buffer.
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
The user buffer will not be deallocated when this allocator is destructed.
\param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{
RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_ = reinterpret_cast(buffer);
chunkHead_->capacity = size - sizeof(ChunkHeader);
chunkHead_->size = 0;
chunkHead_->next = 0;
}
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
~MemoryPoolAllocator() {
Clear();
RAPIDJSON_DELETE(ownBaseAllocator_);
}
//! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() {
while (chunkHead_ && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_);
chunkHead_ = next;
}
if (chunkHead_ && chunkHead_ == userBuffer_)
chunkHead_->size = 0; // Clear user buffer
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
size_t Capacity() const {
size_t capacity = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
size_t Size() const {
size_t size = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
size += c->size;
return size;
}
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size;
return buffer;
}
//! Resizes a memory block (concept Allocator)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
if (originalPtr == 0)
return Malloc(newSize);
if (newSize == 0)
return NULL;
originalSize = RAPIDJSON_ALIGN(originalSize);
newSize = RAPIDJSON_ALIGN(newSize);
// Do not shrink if new size is smaller than original
if (originalSize >= newSize)
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
size_t increment = static_cast(newSize - originalSize);
if (chunkHead_->size + increment <= chunkHead_->capacity) {
chunkHead_->size += increment;
return originalPtr;
}
}
// Realloc process: allocate and copy memory, do not free original buffer.
if (void* newBuffer = Malloc(newSize)) {
if (originalSize)
std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
}
else
return NULL;
}
//! Frees a memory block (concept Allocator)
static void Free(void *ptr) { (void)ptr; } // Do nothing
private:
//! Copy constructor is not permitted.
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
//! Copy assignment operator is not permitted.
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
\return true if success.
*/
bool AddChunk(size_t capacity) {
if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
chunk->capacity = capacity;
chunk->size = 0;
chunk->next = chunkHead_;
chunkHead_ = chunk;
return true;
}
else
return false;
}
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
*/
struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list.
};
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_
================================================
FILE: rapidjson/document.h
================================================
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_DOCUMENT_H_
#define RAPIDJSON_DOCUMENT_H_
/*! \file document.h */
#include "reader.h"
#include "internal/meta.h"
#include "internal/strfunc.h"
#include "memorystream.h"
#include "encodedstream.h"
#include // placement new
#include
RAPIDJSON_DIAG_PUSH
#ifdef _MSC_VER
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
#ifdef _MINWINDEF_ // see: http://stackoverflow.com/questions/22744262/cant-call-stdmax-because-minwindef-h-defines-max
#ifndef NOMINMAX
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif
#endif
#endif
#ifdef __clang__
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_OFF(effc++)
#if __GNUC__ >= 6
RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions
#endif
#endif // __GNUC__
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#include // std::iterator, std::random_access_iterator_tag
#endif
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include // std::move
#endif
RAPIDJSON_NAMESPACE_BEGIN
// Forward declaration.
template
class GenericValue;
template
class GenericDocument;
//! Name-value pair in a JSON object value.
/*!
This class was internal to GenericValue. It used to be a inner struct.
But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
https://code.google.com/p/rapidjson/issues/detail?id=64
*/
template
struct GenericMember {
GenericValue name; //!< name of member (must be a string)
GenericValue value; //!< value of member.
};
///////////////////////////////////////////////////////////////////////////////
// GenericMemberIterator
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
//! (Constant) member iterator for a JSON object value
/*!
\tparam Const Is this a constant iterator?
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
\tparam Allocator Allocator type for allocating memory of object, array and string.
This class implements a Random Access Iterator for GenericMember elements
of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
\note This iterator implementation is mainly intended to avoid implicit
conversions from iterator values to \c NULL,
e.g. from GenericValue::FindMember.
\note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
pointer-based implementation, if your platform doesn't provide
the C++ header.
\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
*/
template
class GenericMemberIterator
: public std::iterator >::Type> {
friend class GenericValue;
template friend class GenericMemberIterator;
typedef GenericMember PlainType;
typedef typename internal::MaybeAddConst::Type ValueType;
typedef std::iterator BaseType;
public:
//! Iterator type itself
typedef GenericMemberIterator Iterator;
//! Constant iterator type
typedef GenericMemberIterator ConstIterator;
//! Non-constant iterator type
typedef GenericMemberIterator NonConstIterator;
//! Pointer to (const) GenericMember
typedef typename BaseType::pointer Pointer;
//! Reference to (const) GenericMember
typedef typename BaseType::reference Reference;
//! Signed integer type (e.g. \c ptrdiff_t)
typedef typename BaseType::difference_type DifferenceType;
//! Default constructor (singular value)
/*! Creates an iterator pointing to no element.
\note All operations, except for comparisons, are undefined on such values.
*/
GenericMemberIterator() : ptr_() {}
//! Iterator conversions to more const
/*!
\param it (Non-const) iterator to copy from
Allows the creation of an iterator from another GenericMemberIterator
that is "less const". Especially, creating a non-constant iterator
from a constant iterator are disabled:
\li const -> non-const (not ok)
\li const -> const (ok)
\li non-const -> const (ok)
\li non-const -> non-const (ok)
\note If the \c Const template parameter is already \c false, this
constructor effectively defines a regular copy-constructor.
Otherwise, the copy constructor is implicitly defined.
*/
GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
//! @name stepping
//@{
Iterator& operator++(){ ++ptr_; return *this; }
Iterator& operator--(){ --ptr_; return *this; }
Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; }
Iterator operator--(int){ Iterator old(*this); --ptr_; return old; }
//@}
//! @name increment/decrement
//@{
Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
//@}
//! @name relations
//@{
bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
//@}
//! @name dereference
//@{
Reference operator*() const { return *ptr_; }
Pointer operator->() const { return ptr_; }
Reference operator[](DifferenceType n) const { return ptr_[n]; }
//@}
//! Distance
DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
private:
//! Internal constructor from plain pointer
explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
Pointer ptr_; //!< raw pointer
};
#else // RAPIDJSON_NOMEMBERITERATORCLASS
// class-based member iterator implementation disabled, use plain pointers
template
struct GenericMemberIterator;
//! non-const GenericMemberIterator
template
struct GenericMemberIterator {
//! use plain pointer as iterator type
typedef GenericMember* Iterator;
};
//! const GenericMemberIterator
template
struct GenericMemberIterator {
//! use plain const pointer as iterator type
typedef const GenericMember* Iterator;
};
#endif // RAPIDJSON_NOMEMBERITERATORCLASS
///////////////////////////////////////////////////////////////////////////////
// GenericStringRef
//! Reference to a constant string (not taking a copy)
/*!
\tparam CharType character type of the string
This helper class is used to automatically infer constant string
references for string literals, especially from \c const \b (!)
character arrays.
The main use is for creating JSON string values without copying the
source string via an \ref Allocator. This requires that the referenced
string pointers have a sufficient lifetime, which exceeds the lifetime
of the associated GenericValue.
\b Example
\code
Value v("foo"); // ok, no need to copy & calculate length
const char foo[] = "foo";
v.SetString(foo); // ok
const char* bar = foo;
// Value x(bar); // not ok, can't rely on bar's lifetime
Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
Value y(StringRef(bar, 3)); // ok, explicitly pass length
\endcode
\see StringRef, GenericValue::SetString
*/
template
struct GenericStringRef {
typedef CharType Ch; //!< character type of the string
//! Create string reference from \c const character array
#ifndef __clang__ // -Wdocumentation
/*!
This constructor implicitly creates a constant string reference from
a \c const character array. It has better performance than
\ref StringRef(const CharType*) by inferring the string \ref length
from the array length, and also supports strings containing null
characters.
\tparam N length of the string, automatically inferred
\param str Constant character array, lifetime assumed to be longer
than the use of the string in e.g. a GenericValue
\post \ref s == str
\note Constant complexity.
\note There is a hidden, private overload to disallow references to
non-const character arrays to be created via this constructor.
By this, e.g. function-scope arrays used to be filled via
\c snprintf are excluded from consideration.
In such cases, the referenced string should be \b copied to the
GenericValue instead.
*/
#endif
template
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
: s(str), length(N-1) {}
//! Explicitly create string reference from \c const character pointer
#ifndef __clang__ // -Wdocumentation
/*!
This constructor can be used to \b explicitly create a reference to
a constant string pointer.
\see StringRef(const CharType*)
\param str Constant character pointer, lifetime assumed to be longer
than the use of the string in e.g. a GenericValue
\post \ref s == str
\note There is a hidden, private overload to disallow references to
non-const character arrays to be created via this constructor.
By this, e.g. function-scope arrays used to be filled via
\c snprintf are excluded from consideration.
In such cases, the referenced string should be \b copied to the
GenericValue instead.
*/
#endif
explicit GenericStringRef(const CharType* str)
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
//! Create constant string reference from pointer and length
#ifndef __clang__ // -Wdocumentation
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\param len length of the string, excluding the trailing NULL terminator
\post \ref s == str && \ref length == len
\note Constant complexity.
*/
#endif
GenericStringRef(const CharType* str, SizeType len)
: s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
//! implicit conversion to plain CharType pointer
operator const Ch *() const { return s; }
const Ch* const s; //!< plain CharType pointer
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
private:
//! Disallow construction from non-const array
template
GenericStringRef(CharType (&str)[N]) /* = delete */;
//! Copy assignment operator not permitted - immutable type
GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
};
//! Mark a character pointer as constant string
/*! Mark a plain character pointer as a "string literal". This function
can be used to avoid copying a character string to be referenced as a
value in a JSON GenericValue object, if the string's lifetime is known
to be valid long enough.
\tparam CharType Character type of the string
\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\return GenericStringRef string reference object
\relatesalso GenericStringRef
\see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
*/
template
inline GenericStringRef StringRef(const CharType* str) {
return GenericStringRef(str, internal::StrLen(str));
}
//! Mark a character pointer as constant string
/*! Mark a plain character pointer as a "string literal". This function
can be used to avoid copying a character string to be referenced as a
value in a JSON GenericValue object, if the string's lifetime is known
to be valid long enough.
This version has better performance with supplied length, and also
supports string containing null characters.
\tparam CharType character type of the string
\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\param length The length of source string.
\return GenericStringRef string reference object
\relatesalso GenericStringRef
*/
template
inline GenericStringRef StringRef(const CharType* str, size_t length) {
return GenericStringRef(str, SizeType(length));
}
#if RAPIDJSON_HAS_STDSTRING
//! Mark a string object as constant string
/*! Mark a string object (e.g. \c std::string) as a "string literal".
This function can be used to avoid copying a string to be referenced as a
value in a JSON GenericValue object, if the string's lifetime is known
to be valid long enough.
\tparam CharType character type of the string
\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\return GenericStringRef string reference object
\relatesalso GenericStringRef
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
template
inline GenericStringRef StringRef(const std::basic_string& str) {
return GenericStringRef(str.data(), SizeType(str.size()));
}
#endif
///////////////////////////////////////////////////////////////////////////////
// GenericValue type traits
namespace internal {
template
struct IsGenericValueImpl : FalseType {};
// select candidates according to nested encoding and allocator types
template struct IsGenericValueImpl::Type, typename Void::Type>
: IsBaseOf, T>::Type {};
// helper to match arbitrary GenericValue instantiations, including derived classes
template struct IsGenericValue : IsGenericValueImpl::Type {};
} // namespace internal
///////////////////////////////////////////////////////////////////////////////
// TypeHelper
namespace internal {
template
struct TypeHelper {};
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsBool(); }
static bool Get(const ValueType& v) { return v.GetBool(); }
static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
};
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsInt(); }
static int Get(const ValueType& v) { return v.GetInt(); }
static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
};
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsUint(); }
static unsigned Get(const ValueType& v) { return v.GetUint(); }
static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
};
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsInt64(); }
static int64_t Get(const ValueType& v) { return v.GetInt64(); }
static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
};
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsUint64(); }
static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
};
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsDouble(); }
static double Get(const ValueType& v) { return v.GetDouble(); }
static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
};
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsFloat(); }
static float Get(const ValueType& v) { return v.GetFloat(); }
static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
};
template