Dateien nach "/" hochladen
This commit is contained in:
71
Makefile
Normal file
71
Makefile
Normal file
@@ -0,0 +1,71 @@
|
||||
# Copyright 2013-2018 Alexander Peslyak
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
|
||||
CC = gcc
|
||||
LD = $(CC)
|
||||
RM = rm -f
|
||||
OMPFLAGS = -fopenmp
|
||||
CFLAGS = -Wall -O2 -fomit-frame-pointer
|
||||
#CFLAGS = -Wall -msse -O2 -fomit-frame-pointer
|
||||
#CFLAGS = -Wall -msse2 -O2 -fomit-frame-pointer
|
||||
#CFLAGS = -Wall -O2 -march=native -fomit-frame-pointer
|
||||
# -lrt is for benchmark's use of clock_gettime()
|
||||
LDFLAGS = -s -lrt
|
||||
|
||||
PROJ = tests benchmark
|
||||
OBJS_CORE = yespower-opt.o
|
||||
OBJS_COMMON = sha256.o
|
||||
OBJS_TESTS = $(OBJS_CORE) $(OBJS_COMMON) tests.o
|
||||
OBJS_BENCHMARK = $(OBJS_CORE) $(OBJS_COMMON) benchmark.o
|
||||
OBJS_RM = yespower-*.o
|
||||
|
||||
all: $(PROJ)
|
||||
|
||||
check: tests
|
||||
@echo 'Running tests'
|
||||
@time ./tests | tee TESTS-OUT
|
||||
@diff -U0 TESTS-OK TESTS-OUT && echo PASSED || echo FAILED
|
||||
|
||||
ref:
|
||||
$(MAKE) $(PROJ) OBJS_CORE=yespower-ref.o
|
||||
|
||||
check-ref:
|
||||
$(MAKE) check OBJS_CORE=yespower-ref.o
|
||||
|
||||
tests: $(OBJS_TESTS)
|
||||
$(LD) $(LDFLAGS) $(OBJS_TESTS) -o $@
|
||||
|
||||
benchmark: $(OBJS_BENCHMARK)
|
||||
$(LD) $(LDFLAGS) $(OMPFLAGS) -lpthread $(OBJS_BENCHMARK) -o $@
|
||||
|
||||
benchmark.o: benchmark.c
|
||||
$(CC) -c $(CFLAGS) $(OMPFLAGS) $*.c
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $*.c
|
||||
|
||||
yespower-ref.o: yespower.h
|
||||
yespower-opt.o: yespower-platform.c yespower.h
|
||||
tests.o: yespower.h
|
||||
benchmark.o: yespower.h
|
||||
|
||||
clean:
|
||||
$(RM) $(PROJ)
|
||||
$(RM) $(OBJS_TESTS) $(OBJS_BENCHMARK)
|
||||
$(RM) $(OBJS_RM)
|
||||
$(RM) TESTS-OUT
|
||||
95
PERFORMANCE
Normal file
95
PERFORMANCE
Normal file
@@ -0,0 +1,95 @@
|
||||
Included with yespower is the "benchmark" program, which is built by
|
||||
simply invoking "make". When invoked without parameters, it tests
|
||||
yespower 0.5 at N = 2048, r = 8, which appears to be the lowest setting
|
||||
in use by existing cryptocurrencies. On an i7-4770K with 4x DDR3-1600
|
||||
(on two memory channels) running CentOS 7 for x86-64 (and built with
|
||||
CentOS 7's default version of gcc) and with thread affinity set, this
|
||||
reports between 3700 and 3800 hashes per second for both SSE2 and AVX
|
||||
builds, e.g.:
|
||||
|
||||
$ GOMP_CPU_AFFINITY=0-7 OMP_NUM_THREADS=4 ./benchmark
|
||||
version=0.5 N=2048 r=8
|
||||
Will use 2048.00 KiB RAM
|
||||
a5 9f ec 4c 4f dd a1 6e 3b 14 05 ad da 66 d5 25 b6 8e 7c ad fc fe 6a c0 66 c7 ad 11 8c d8 05 90
|
||||
Benchmarking 1 thread ...
|
||||
1018 H/s real, 1018 H/s virtual (2047 hashes in 2.01 seconds)
|
||||
Benchmarking 4 threads ...
|
||||
3773 H/s real, 950 H/s virtual (8188 hashes in 2.17 seconds)
|
||||
min 0.984 ms, avg 1.052 ms, max 1.074 ms
|
||||
|
||||
Running 8 threads (to match the logical rather than the physical CPU
|
||||
core count) results in very slightly worse performance on this system,
|
||||
but this might be the other way around on another and/or with other
|
||||
parameters. Upgrading to yespower 1.0, performance at these parameters
|
||||
improves to almost 4000 hashes per second:
|
||||
|
||||
$ GOMP_CPU_AFFINITY=0-7 OMP_NUM_THREADS=4 ./benchmark 10
|
||||
version=1.0 N=2048 r=8
|
||||
Will use 2048.00 KiB RAM
|
||||
d0 78 cd d4 cf 3f 5a a8 4e 3c 4a 58 66 29 81 d8 2d 27 e5 67 36 37 c4 be 77 63 61 32 24 c1 8a 93
|
||||
Benchmarking 1 thread ...
|
||||
1080 H/s real, 1080 H/s virtual (4095 hashes in 3.79 seconds)
|
||||
Benchmarking 4 threads ...
|
||||
3995 H/s real, 1011 H/s virtual (16380 hashes in 4.10 seconds)
|
||||
min 0.923 ms, avg 0.989 ms, max 1.137 ms
|
||||
|
||||
Running 8 threads results in substantial slowdown with this new version
|
||||
(to between 3200 and 3400 hashes per second) because of cache thrashing.
|
||||
|
||||
For higher settings such as those achieving 8 MiB instead of the 2 MiB
|
||||
above, this system performs at around 800 hashes per second for yespower
|
||||
0.5 and at around 830 hashes per second for yespower 1.0:
|
||||
|
||||
$ GOMP_CPU_AFFINITY=0-7 OMP_NUM_THREADS=4 ./benchmark 5 2048 32
|
||||
version=0.5 N=2048 r=32
|
||||
Will use 8192.00 KiB RAM
|
||||
56 0a 89 1b 5c a2 e1 c6 36 11 1a 9f f7 c8 94 a5 d0 a2 60 2f 43 fd cf a5 94 9b 95 e2 2f e4 46 1e
|
||||
Benchmarking 1 thread ...
|
||||
265 H/s real, 265 H/s virtual (1023 hashes in 3.85 seconds)
|
||||
Benchmarking 4 threads ...
|
||||
803 H/s real, 200 H/s virtual (4092 hashes in 5.09 seconds)
|
||||
min 4.924 ms, avg 4.980 ms, max 5.074 ms
|
||||
|
||||
$ GOMP_CPU_AFFINITY=0-7 OMP_NUM_THREADS=4 ./benchmark 10 2048 32
|
||||
version=1.0 N=2048 r=32
|
||||
Will use 8192.00 KiB RAM
|
||||
f7 69 26 ae 4a dc 56 53 90 2f f0 22 78 ea aa 39 eb 99 84 11 ac 3e a6 24 2e 19 6d fb c4 3d 68 25
|
||||
Benchmarking 1 thread ...
|
||||
275 H/s real, 275 H/s virtual (1023 hashes in 3.71 seconds)
|
||||
Benchmarking 4 threads ...
|
||||
831 H/s real, 209 H/s virtual (4092 hashes in 4.92 seconds)
|
||||
min 3.614 ms, avg 4.769 ms, max 5.011 ms
|
||||
|
||||
Again, running 8 threads results in a slowdown, albeit not as bad as can
|
||||
be seen for lower settings.
|
||||
|
||||
On x86(-64), the following code versions may reasonably be built: SSE2,
|
||||
AVX, and XOP. (There's no reason to build for AVX2 and higher, which is
|
||||
unsuitable for and thus unused by current yespower anyway. There's also
|
||||
no reason to build yespower as-is for SSE4, although there's a disabled
|
||||
by default 32-bit specific SSE4 code version that may be re-enabled and
|
||||
given a try if someone is so inclined; it may perform slightly slower or
|
||||
slightly faster across different systems.)
|
||||
|
||||
yescrypt and especially yespower 1.0 have been designed to fit the SSE2
|
||||
instruction set almost perfectly, so there's very little benefit from
|
||||
the AVX and XOP builds, yet even at yespower 1.0 there may be
|
||||
performance differences between SSE2, AVX, and XOP builds within 2% or
|
||||
so (and it is unclear which is the fastest on a given system until
|
||||
tested, except that where XOP is supported it is almost always faster
|
||||
than AVX).
|
||||
|
||||
Proper setting of thread affinities to run exactly one thread per
|
||||
physical CPU core is non-trivial. In the above examples, it so happened
|
||||
that the first 4 logical CPU numbers corresponded to different physical
|
||||
cores, but this won't always be the case. This can vary even between
|
||||
apparently similar systems. On Linux, the mapping of logical CPUs to
|
||||
physical cores may be obtained from /proc/cpuinfo (on x86[-64] and MIC)
|
||||
or sysfs, which an optimized implementation of e.g. a cryptocurrency
|
||||
miner could use. If you do not bother obtaining this information from
|
||||
the operating system, you might be better off not setting thread
|
||||
affinities at all (in order to avoid the risk of doing this incorrectly,
|
||||
which would have a greater negative performance impact) and/or running
|
||||
as many threads as there are logical CPUs. Also, there's no certainty
|
||||
whether different and future CPUs will run yespower faster using one or
|
||||
maybe more threads per physical core.
|
||||
203
README
Normal file
203
README
Normal file
@@ -0,0 +1,203 @@
|
||||
What is yespower?
|
||||
|
||||
yespower is a proof-of-work (PoW) focused fork of yescrypt. While
|
||||
yescrypt is a password-based key derivation function (KDF) and password
|
||||
hashing scheme, and thus is meant for processing passwords, yespower is
|
||||
meant for processing trial inputs such as block headers (including
|
||||
nonces) in PoW-based blockchains.
|
||||
|
||||
On its own, yespower isn't a complete proof-of-work system. Rather, in
|
||||
the blockchain use case, yespower's return value is meant to be checked
|
||||
for being numerically no greater than the blockchain's current target
|
||||
(which is related to mining difficulty) or else the proof attempt
|
||||
(yespower invocation) is to be repeated (with a different nonce) until
|
||||
the condition is finally met (allowing a new block to be mined). This
|
||||
process isn't specific to yespower and isn't part of yespower itself
|
||||
(rather, it is similar in many PoW-based blockchains and is to be
|
||||
defined and implemented externally to yespower) and thus isn't described
|
||||
in here any further.
|
||||
|
||||
|
||||
Why or why not yespower?
|
||||
|
||||
Different proof-of-work schemes in existence vary in many aspects,
|
||||
including in friendliness to different types of hardware. There's
|
||||
demand for all sorts of hardware (un)friendliness in those - for
|
||||
different use cases and by different communities.
|
||||
|
||||
yespower in particular is designed to be CPU-friendly, GPU-unfriendly,
|
||||
and FPGA/ASIC-neutral. In other words, it's meant to be relatively
|
||||
efficient to compute on current CPUs and relatively inefficient on
|
||||
current GPUs. Unfortunately, being GPU-unfriendly also means that
|
||||
eventual FPGA and ASIC implementations will only compete with CPUs, and
|
||||
at least ASICs will win over the CPUs (FPGAs might not because of this
|
||||
market's peculiarities - large FPGAs are even more "over-priced" than
|
||||
large CPUs are), albeit by far not to the extent they did e.g. for
|
||||
Bitcoin and Litecoin.
|
||||
|
||||
There's a lot of talk about "ASIC resistance". What is (or should be)
|
||||
meant by that is limiting the advantage of specialized ASICs. While
|
||||
limiting the advantage at KDF to e.g. 10x and at password hashing to
|
||||
e.g. 100x (talking orders of magnitude here, in whatever terms) may be
|
||||
considered "ASIC resistant" (as compared to e.g. 100,000x we'd have
|
||||
without trying), similar improvement factors are practically not "ASIC
|
||||
resistant" for cryptocurrency mining where they can make all the
|
||||
difference between CPU mining being profitable and not. There might
|
||||
also exist in-between PoW use cases where moderate ASIC advantage is OK,
|
||||
such as with non-cryptocurrency and/or private/permissioned blockchains.
|
||||
|
||||
Thus, current yespower may be considered either a short-term choice
|
||||
(valid until one of its uses provides sufficient perceived incentive to
|
||||
likely result in specialized ASICs) or a deliberate choice of a pro-CPU,
|
||||
anti-GPU, moderately-pro-ASIC PoW scheme. It is also possible to
|
||||
respond to known improvements in future GPUs/implementations and/or to
|
||||
ASICs with new versions of yespower that users would need to switch to.
|
||||
|
||||
|
||||
yespower versions.
|
||||
|
||||
yespower includes optimized and specialized re-implementation of the
|
||||
obsolete yescrypt 0.5 (based off its first submission to Password
|
||||
Hashing Competition back in 2014) now re-released as yespower 0.5, and
|
||||
brand new proof-of-work specific variation known as yespower 1.0.
|
||||
|
||||
yespower 0.5 is intended as a compatible upgrade for cryptocurrencies
|
||||
that already use yescrypt 0.5 (providing a few percent speedup), and
|
||||
yespower 1.0 may be used as a further upgrade or a new choice of PoW by
|
||||
those and other cryptocurrencies and other projects.
|
||||
|
||||
There are many significant differences between yespower 0.5 and 1.0
|
||||
under the hood, but the main user visible difference is yespower 1.0
|
||||
greatly improving on GPU-unfriendliness in light of improvements seen in
|
||||
modern GPUs (up to and including NVIDIA Volta) and GPU implementations
|
||||
of yescrypt 0.5. This is achieved mostly through greater use of CPUs'
|
||||
L2 cache.
|
||||
|
||||
The version of algorithm to use is requested through parameters,
|
||||
allowing for both algorithms to co-exist in client and miner
|
||||
implementations (such as in preparation for a cryptocurrency hard-fork
|
||||
and/or supporting multiple cryptocurrencies in one program).
|
||||
|
||||
|
||||
Parameter selection.
|
||||
|
||||
For new uses of yespower, set the requested version to the highest
|
||||
supported, and set N*r to the highest you can reasonably afford in terms
|
||||
of proof verification time (which might in turn be determined by desired
|
||||
share rate per mining pool server), using one of the following options:
|
||||
|
||||
1 MiB: N = 1024, r = 8
|
||||
2 MiB: N = 2048, r = 8
|
||||
4 MiB: N = 1024, r = 32
|
||||
8 MiB: N = 2048, r = 32
|
||||
16 MiB: N = 4096, r = 32
|
||||
|
||||
and so on for higher N keeping r=32.
|
||||
|
||||
You may also set the personalization string to your liking, but that is
|
||||
not required (you can set its pointer to NULL and its length to 0). Its
|
||||
support is provided mostly for compatibility with existing modifications
|
||||
of yescrypt 0.5.
|
||||
|
||||
|
||||
Performance.
|
||||
|
||||
Please refer to PERFORMANCE for some benchmarks and performance tuning.
|
||||
|
||||
|
||||
How to test yespower for proper operation.
|
||||
|
||||
On a Unix-like system, invoke "make check". This will build and run a
|
||||
program called "tests", and check its output against the supplied file
|
||||
TESTS-OK. If everything matches, the final line of output should be the
|
||||
word "PASSED".
|
||||
|
||||
We do most of our testing on Linux systems with gcc. The supplied
|
||||
Makefile assumes that you use gcc.
|
||||
|
||||
|
||||
Alternate code versions and make targets.
|
||||
|
||||
Two implementations of yespower are included: reference and optimized.
|
||||
By default, the optimized implementation is built. Internally, the
|
||||
optimized implementation uses conditional compilation to choose between
|
||||
usage of various SIMD instruction sets where supported and scalar code.
|
||||
|
||||
The reference implementation is unoptimized and is very slow, but it has
|
||||
simpler and shorter source code. Its purpose is to provide a simple
|
||||
human- and machine-readable specification that implementations intended
|
||||
for actual use should be tested against. It is deliberately mostly not
|
||||
optimized, and it is not meant to be used in production.
|
||||
|
||||
Similarly to "make check", there's "make check-ref" to build and test
|
||||
the reference implementation. There's also "make ref" to build the
|
||||
reference implementation and have the "benchmark" program use it.
|
||||
|
||||
"make clean" may need to be run between making different builds.
|
||||
|
||||
|
||||
How to integrate yespower in a program.
|
||||
|
||||
Although yespower.h provides several functions, chances are that you
|
||||
will only need to use yespower_tls(). Please see the comment on this
|
||||
function in yespower.h and its example usage in tests.c and benchmark.c,
|
||||
including parameter sets requesting yescrypt 0.5 as used by certain
|
||||
existing cryptocurrencies.
|
||||
|
||||
To integrate yespower in an altcoin based on Bitcoin Core, you might
|
||||
invoke yespower_tls() from either a maybe-new (depending on where you
|
||||
fork from) CBlockHeader::GetPoWHash() (and invoke that where PoW is
|
||||
needed like e.g. Litecoin does for scrypt) or CBlockHeader::GetHash()
|
||||
(easier, but inefficient and you'll be stuck with that inefficiency).
|
||||
|
||||
You'll also want to implement caching of the computed PoW hashes like
|
||||
e.g. YACoin does for scrypt. Caching is especially important if you
|
||||
invoke yespower from CBlockHeader::GetHash(). However, even if you use
|
||||
or introduce CBlockHeader::GetPoWHash() caching may still be desirable
|
||||
as the PoW hash is commonly requested 4 times per block fetched during a
|
||||
node's initial blockchain sync (once during prefetch of block headers,
|
||||
and 3 times more during validation of a fully fetched block). On the
|
||||
other hand, you'll likely want to bypass the cache when PoW is computed
|
||||
by the node's built-in miner.
|
||||
|
||||
Further detail on this (generating new genesis blocks, etc.) is even
|
||||
farther from being yespower-specific and thus is not provided here.
|
||||
Just like (and even more so than) yespower itself, the above guidance is
|
||||
provided as-is and without guarantee of being correct and safe to
|
||||
follow. You're supposed to know what you're doing.
|
||||
|
||||
|
||||
Credits.
|
||||
|
||||
scrypt has been designed by Colin Percival. yescrypt and yespower have
|
||||
been designed by Solar Designer building upon scrypt.
|
||||
|
||||
The following other people and projects have also indirectly helped make
|
||||
yespower what it is:
|
||||
|
||||
- Bill Cox
|
||||
- Rich Felker
|
||||
- Anthony Ferrara
|
||||
- Christian Forler
|
||||
- Taylor Hornby
|
||||
- Dmitry Khovratovich
|
||||
- Samuel Neves
|
||||
- Marcos Simplicio
|
||||
- Ken T Takusagawa
|
||||
- Jakob Wenzel
|
||||
- Christian Winnerlein
|
||||
|
||||
- DARPA Cyber Fast Track
|
||||
- Password Hashing Competition
|
||||
|
||||
|
||||
Contact info.
|
||||
|
||||
First, please check the yespower homepage for new versions, etc.:
|
||||
|
||||
https://www.openwall.com/yespower/
|
||||
|
||||
If you have anything valuable to add or a non-trivial question to ask,
|
||||
you may contact the maintainer of yespower at:
|
||||
|
||||
Solar Designer <solar at openwall.com>
|
||||
16
TESTS-OK
Normal file
16
TESTS-OK
Normal file
@@ -0,0 +1,16 @@
|
||||
yespower(5, 2048, 8, "Client Key") = a5 9f ec 4c 4f dd a1 6e 3b 14 05 ad da 66 d5 25 b6 8e 7c ad fc fe 6a c0 66 c7 ad 11 8c d8 05 90
|
||||
yespower(5, 2048, 8, BSTY) = 5e a2 b2 95 6a 9e ac e3 0a 32 37 ff 1d 44 1e de e1 dc 25 aa b8 f0 ea 15 c1 21 65 f8 3a 7b c2 65
|
||||
yespower(5, 4096, 16, "Client Key") = 92 7e 72 d0 de d3 d8 04 75 47 3f 40 f1 74 3c 67 28 9d 45 3d 52 42 d4 f5 5a f4 e3 25 e0 66 99 c5
|
||||
yespower(5, 4096, 24, "Jagaricoin") = 0e 13 66 97 32 11 e7 fe a8 ad 9d 81 98 9c 84 a2 54 d9 68 c9 d3 33 dd 8f f0 99 32 4f 38 61 1e 04
|
||||
yespower(5, 4096, 32, "WaviBanana") = 3a e0 5a bb 3c 5c f6 f7 54 15 a9 25 54 c9 8d 50 e3 8e c9 55 2c fa 78 37 36 16 f4 80 b2 4e 55 9f
|
||||
yespower(5, 2048, 32, "Client Key") = 56 0a 89 1b 5c a2 e1 c6 36 11 1a 9f f7 c8 94 a5 d0 a2 60 2f 43 fd cf a5 94 9b 95 e2 2f e4 46 1e
|
||||
yespower(5, 1024, 32, "Client Key") = 2a 79 e5 3d 1b e6 66 9b c5 56 cc c4 17 bc e3 d2 2a 74 a2 32 f5 6b 8e 1d 39 b4 57 92 67 5d e1 08
|
||||
yespower(5, 2048, 8, NULL) = 5e cb d8 e8 d7 c9 0b ae d4 bb f8 91 6a 12 25 dc c3 c6 5f 5c 91 65 ba e8 1c dd e3 cf fa d1 28 e8
|
||||
yespower(10, 2048, 8, NULL) = 69 e0 e8 95 b3 df 7a ee b8 37 d7 1f e1 99 e9 d3 4f 7e c4 6e cb ca 7a 2c 43 08 e5 18 57 ae 9b 46
|
||||
yespower(10, 4096, 16, NULL) = 33 fb 8f 06 38 24 a4 a0 20 f6 3d ca 53 5f 5c a6 6a b5 57 64 68 c7 5d 1c ca ac 75 42 f7 64 95 ac
|
||||
yespower(10, 4096, 32, NULL) = 77 1a ee fd a8 fe 79 a0 82 5b c7 f2 ae e1 62 ab 55 78 57 46 39 ff c6 ca 37 23 cc 18 e5 e3 e2 85
|
||||
yespower(10, 2048, 32, NULL) = d5 ef b8 13 cd 26 3e 9b 34 54 01 30 23 3c bb c6 a9 21 fb ff 34 31 e5 ec 1a 1a bd e2 ae a6 ff 4d
|
||||
yespower(10, 1024, 32, NULL) = 50 1b 79 2d b4 2e 38 8f 6e 7d 45 3c 95 d0 3a 12 a3 60 16 a5 15 4a 68 83 90 dd c6 09 a4 0c 67 99
|
||||
yespower(10, 1024, 32, "personality test") = 1f 02 69 ac f5 65 c4 9a dc 0e f9 b8 f2 6a b3 80 8c dc 38 39 4a 25 4f dd ee dc c3 aa cf f6 ad 9d
|
||||
XOR of yespower(5, ...) = ae f1 32 91 87 0f 55 70 47 f4 2e 9b ef a6 16 df e5 f1 96 77 e1 3f 8b a6 92 f7 c5 97 55 a0 f5 0e
|
||||
XOR of yespower(10, ...) = 8d 13 c5 fb 07 30 96 75 d1 b8 48 92 77 ba 4b e4 40 33 be df ae 7a 60 43 8a 9b e2 1f 3a 7b 12 37
|
||||
147
arm_optimized.c
Normal file
147
arm_optimized.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*-
|
||||
* Copyright 2009 Colin Percival
|
||||
* Copyright 2013-2018 Alexander Peslyak
|
||||
* Copyright 2024 Worgon12
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Worgon12 project and incorporates code from
|
||||
* the Yespower project (https://github.com/openwall/yespower).
|
||||
*/
|
||||
|
||||
#include "yespower.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> // Für memcpy
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#if defined(__aarch64__) || defined(__ARM_NEON)
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) || defined(__ARM_NEON)
|
||||
// ARM-Werte
|
||||
int extra_rounds = 1;
|
||||
#define MEM_OPS(thread_id) 2500
|
||||
#define MEM_PASSES(thread_id) 2
|
||||
#else
|
||||
// Nicht-ARM: Begrenzung der Single-Thread-Performance
|
||||
#define EXTRA_ROUNDS(thread_id) ((thread_id == 0) ? 10 : 10)
|
||||
#define MEM_OPS(thread_id) ((thread_id == 0) ? 250000 : 300000)
|
||||
#define MEM_PASSES(thread_id) ((thread_id == 0) ? 15 : 12)
|
||||
#endif
|
||||
|
||||
// Speicherzugriffslogik
|
||||
void perform_memory_access(uint32_t *data, size_t length, int thread_id) {
|
||||
unsigned long long seed = (unsigned long long)(uintptr_t)data + thread_id; // Unterschiedliche Seeds pro Thread
|
||||
uint32_t sum = 0;
|
||||
|
||||
for (int pass = 0; pass < MEM_PASSES(thread_id); pass++) {
|
||||
for (int mem_i = 0; mem_i < MEM_OPS(thread_id); mem_i++) {
|
||||
seed = (seed * 6364136223846793005ULL + 1ULL);
|
||||
size_t idx = (size_t)(seed % length);
|
||||
uint32_t val = data[idx];
|
||||
val ^= (uint32_t)mem_i;
|
||||
data[idx] = val;
|
||||
sum += val;
|
||||
}
|
||||
}
|
||||
data[0] ^= sum;
|
||||
}
|
||||
|
||||
// ARM-optimierte Transformation
|
||||
void arm_optimized_transform(uint32_t *data, size_t length) {
|
||||
#if defined(__aarch64__) || defined(__ARM_NEON)
|
||||
size_t vec_length = length - (length % 4);
|
||||
uint32x4_t mask = vdupq_n_u32(0x9E3779B9);
|
||||
uint32x4_t mul_val = vdupq_n_u32(0x7FEB352D);
|
||||
|
||||
for (size_t i = 0; i < vec_length; i += 4) {
|
||||
uint32x4_t block = vld1q_u32(&data[i]);
|
||||
block = veorq_u32(block, mask);
|
||||
|
||||
uint32x4_t left_shifted = vshlq_n_u32(block, 7);
|
||||
uint32x4_t right_shifted = vshrq_n_u32(block, 25);
|
||||
block = vorrq_u32(left_shifted, right_shifted);
|
||||
|
||||
block = vmulq_u32(block, mul_val);
|
||||
vst1q_u32(&data[i], block);
|
||||
}
|
||||
|
||||
for (size_t i = vec_length; i < length; i++) {
|
||||
uint32_t x = data[i] ^ 0x9E3779B9;
|
||||
x = (x << 7) | (x >> (32 - 7));
|
||||
x *= 0x7FEB352D;
|
||||
data[i] = x;
|
||||
}
|
||||
#else
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
uint32_t x = data[i] ^ 0x9E3779B9;
|
||||
x = (x << 7) | (x >> (32 - 7));
|
||||
x *= 0x7FEB352D;
|
||||
data[i] = x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// yespower mit ARM-Optimierung
|
||||
int yespower_with_arm(const uint32_t *header, size_t header_len, uint8_t *output, int thread_id) {
|
||||
if (header == NULL || output == NULL) {
|
||||
printf("Error: NULL pointer passed to yespower_with_arm\n");
|
||||
return -1;
|
||||
}
|
||||
if (header_len % sizeof(uint32_t) != 0 || header_len > 1024) {
|
||||
printf("Error: Invalid header_len %zu\n", header_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t *temp = malloc(header_len);
|
||||
if (temp == NULL) {
|
||||
printf("Error: Memory allocation for temp failed\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(temp, header, header_len);
|
||||
|
||||
#if defined(__aarch64__) || defined(__ARM_NEON)
|
||||
arm_optimized_transform(temp, header_len / sizeof(uint32_t));
|
||||
#else
|
||||
for (int r = 0; r < EXTRA_ROUNDS(thread_id); r++) {
|
||||
arm_optimized_transform(temp, header_len / sizeof(uint32_t));
|
||||
}
|
||||
perform_memory_access(temp, header_len / sizeof(uint32_t), thread_id);
|
||||
#endif
|
||||
|
||||
yespower_params_t params = { .version = YESPOWER_1_0, .N = 2048, .r = 8 };
|
||||
yespower_binary_t result;
|
||||
|
||||
int res = yespower_tls((const uint8_t *)temp, header_len, ¶ms, &result);
|
||||
if (res != 0) {
|
||||
printf("Error: yespower_tls failed with result %d\n", res);
|
||||
free(temp);
|
||||
return res;
|
||||
}
|
||||
|
||||
memcpy(output, result.uc, sizeof(result.uc));
|
||||
free(temp);
|
||||
return 0;
|
||||
}
|
||||
82
benchmark.c
Normal file
82
benchmark.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "arm_optimized.c"
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define NUM_ITERATIONS 1000
|
||||
|
||||
typedef struct {
|
||||
uint32_t *header;
|
||||
size_t header_size;
|
||||
uint8_t *output;
|
||||
int iterations;
|
||||
int thread_id;
|
||||
double hashes_per_second;
|
||||
} ThreadArgs;
|
||||
|
||||
void *yespower_thread(void *args) {
|
||||
ThreadArgs *threadArgs = (ThreadArgs *)args;
|
||||
clock_t thread_start = clock();
|
||||
|
||||
for (int i = 0; i < threadArgs->iterations; i++) {
|
||||
int result = yespower_with_arm(threadArgs->header, threadArgs->header_size, threadArgs->output, threadArgs->thread_id);
|
||||
if (result != 0) {
|
||||
printf("Thread %d: Fehler bei Iteration %d\n", threadArgs->thread_id, i);
|
||||
pthread_exit((void *)1);
|
||||
}
|
||||
}
|
||||
|
||||
clock_t thread_end = clock();
|
||||
double elapsed_time = (double)(thread_end - thread_start) / CLOCKS_PER_SEC;
|
||||
threadArgs->hashes_per_second = threadArgs->iterations / elapsed_time;
|
||||
|
||||
printf("Thread %d: %.2f H/s (%.2f Sekunden)\n", threadArgs->thread_id, threadArgs->hashes_per_second, elapsed_time);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void benchmark_yespower(int num_threads) {
|
||||
uint32_t header[6] = {1, 0, 0x12345678, 1672531200, 0x00000FFF, 0};
|
||||
uint8_t output[32];
|
||||
pthread_t threads[num_threads];
|
||||
ThreadArgs threadArgs[num_threads];
|
||||
double total_hashes_per_second = 0.0;
|
||||
|
||||
printf("Benchmark gestartet mit %d Thread(s)...\n", num_threads);
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
for (int t = 0; t < num_threads; t++) {
|
||||
threadArgs[t].header = header;
|
||||
threadArgs[t].header_size = sizeof(header);
|
||||
threadArgs[t].output = output;
|
||||
threadArgs[t].iterations = NUM_ITERATIONS / num_threads;
|
||||
threadArgs[t].thread_id = t;
|
||||
threadArgs[t].hashes_per_second = 0.0;
|
||||
|
||||
if (pthread_create(&threads[t], NULL, yespower_thread, &threadArgs[t]) != 0) {
|
||||
perror("Thread-Erstellung fehlgeschlagen");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (int t = 0; t < num_threads; t++) {
|
||||
pthread_join(threads[t], NULL);
|
||||
total_hashes_per_second += threadArgs[t].hashes_per_second;
|
||||
}
|
||||
|
||||
clock_t end = clock();
|
||||
double total_time = (double)(end - start) / CLOCKS_PER_SEC;
|
||||
|
||||
printf("Gesamte Hashing-Zeit: %.2f Sekunden\n", total_time);
|
||||
printf("Gesamte Hashrate: %.2f H/s\n", total_hashes_per_second);
|
||||
printf("Durchschnittliche Hashrate pro Thread: %.2f H/s\n", total_hashes_per_second / num_threads);
|
||||
}
|
||||
|
||||
int main() {
|
||||
benchmark_yespower(1); // Single Thread Benchmark
|
||||
benchmark_yespower(sysconf(_SC_NPROCESSORS_ONLN)); // Multi-Thread Benchmark
|
||||
return 0;
|
||||
}
|
||||
1
insecure_memzero.h
Normal file
1
insecure_memzero.h
Normal file
@@ -0,0 +1 @@
|
||||
#define insecure_memzero(buf, len) /* empty */
|
||||
652
sha256.c
Normal file
652
sha256.c
Normal file
@@ -0,0 +1,652 @@
|
||||
/*-
|
||||
* Copyright 2005-2016 Colin Percival
|
||||
* Copyright 2016-2018,2021 Alexander Peslyak
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "insecure_memzero.h"
|
||||
#include "sysendian.h"
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
#ifdef __ICC
|
||||
/* Miscompile with icc 14.0.0 (at least), so don't use restrict there */
|
||||
#define restrict
|
||||
#elif __STDC_VERSION__ >= 199901L
|
||||
/* Have restrict */
|
||||
#elif defined(__GNUC__)
|
||||
#define restrict __restrict
|
||||
#else
|
||||
#define restrict
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Encode a length len*2 vector of (uint32_t) into a length len*8 vector of
|
||||
* (uint8_t) in big-endian form.
|
||||
*/
|
||||
static void
|
||||
be32enc_vect(uint8_t * dst, const uint32_t * src, size_t len)
|
||||
{
|
||||
|
||||
/* Encode vector, two words at a time. */
|
||||
do {
|
||||
be32enc(&dst[0], src[0]);
|
||||
be32enc(&dst[4], src[1]);
|
||||
src += 2;
|
||||
dst += 8;
|
||||
} while (--len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode a big-endian length len*8 vector of (uint8_t) into a length
|
||||
* len*2 vector of (uint32_t).
|
||||
*/
|
||||
static void
|
||||
be32dec_vect(uint32_t * dst, const uint8_t * src, size_t len)
|
||||
{
|
||||
|
||||
/* Decode vector, two words at a time. */
|
||||
do {
|
||||
dst[0] = be32dec(&src[0]);
|
||||
dst[1] = be32dec(&src[4]);
|
||||
src += 8;
|
||||
dst += 2;
|
||||
} while (--len);
|
||||
}
|
||||
|
||||
/* SHA256 round constants. */
|
||||
static const uint32_t Krnd[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
/* Elementary functions used by SHA256 */
|
||||
#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
|
||||
#if 1 /* Explicit caching/reuse of common subexpression between rounds */
|
||||
#define Maj(x, y, z) (y ^ ((x_xor_y = x ^ y) & y_xor_z))
|
||||
#else /* Let the compiler cache/reuse or not */
|
||||
#define Maj(x, y, z) (y ^ ((x ^ y) & (y ^ z)))
|
||||
#endif
|
||||
#define SHR(x, n) (x >> n)
|
||||
#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
|
||||
#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
|
||||
#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
|
||||
#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
|
||||
#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
|
||||
|
||||
/* SHA256 round function */
|
||||
#define RND(a, b, c, d, e, f, g, h, k) \
|
||||
h += S1(e) + Ch(e, f, g) + k; \
|
||||
d += h; \
|
||||
h += S0(a) + Maj(a, b, c); \
|
||||
y_xor_z = x_xor_y;
|
||||
|
||||
/* Adjusted round function for rotating state */
|
||||
#define RNDr(S, W, i, ii) \
|
||||
RND(S[(64 - i) % 8], S[(65 - i) % 8], \
|
||||
S[(66 - i) % 8], S[(67 - i) % 8], \
|
||||
S[(68 - i) % 8], S[(69 - i) % 8], \
|
||||
S[(70 - i) % 8], S[(71 - i) % 8], \
|
||||
W[i + ii] + Krnd[i + ii])
|
||||
|
||||
/* Message schedule computation */
|
||||
#define MSCH(W, ii, i) \
|
||||
W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii]
|
||||
|
||||
/*
|
||||
* SHA256 block compression function. The 256-bit state is transformed via
|
||||
* the 512-bit input block to produce a new state.
|
||||
*/
|
||||
static void
|
||||
SHA256_Transform(uint32_t state[static restrict 8],
|
||||
const uint8_t block[static restrict 64],
|
||||
uint32_t W[static restrict 64], uint32_t S[static restrict 8])
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 1. Prepare the first part of the message schedule W. */
|
||||
be32dec_vect(W, block, 8);
|
||||
|
||||
/* 2. Initialize working variables. */
|
||||
memcpy(S, state, 32);
|
||||
|
||||
/* 3. Mix. */
|
||||
for (i = 0; i < 64; i += 16) {
|
||||
uint32_t x_xor_y, y_xor_z = S[(65 - i) % 8] ^ S[(66 - i) % 8];
|
||||
RNDr(S, W, 0, i);
|
||||
RNDr(S, W, 1, i);
|
||||
RNDr(S, W, 2, i);
|
||||
RNDr(S, W, 3, i);
|
||||
RNDr(S, W, 4, i);
|
||||
RNDr(S, W, 5, i);
|
||||
RNDr(S, W, 6, i);
|
||||
RNDr(S, W, 7, i);
|
||||
RNDr(S, W, 8, i);
|
||||
RNDr(S, W, 9, i);
|
||||
RNDr(S, W, 10, i);
|
||||
RNDr(S, W, 11, i);
|
||||
RNDr(S, W, 12, i);
|
||||
RNDr(S, W, 13, i);
|
||||
RNDr(S, W, 14, i);
|
||||
RNDr(S, W, 15, i);
|
||||
|
||||
if (i == 48)
|
||||
break;
|
||||
MSCH(W, 0, i);
|
||||
MSCH(W, 1, i);
|
||||
MSCH(W, 2, i);
|
||||
MSCH(W, 3, i);
|
||||
MSCH(W, 4, i);
|
||||
MSCH(W, 5, i);
|
||||
MSCH(W, 6, i);
|
||||
MSCH(W, 7, i);
|
||||
MSCH(W, 8, i);
|
||||
MSCH(W, 9, i);
|
||||
MSCH(W, 10, i);
|
||||
MSCH(W, 11, i);
|
||||
MSCH(W, 12, i);
|
||||
MSCH(W, 13, i);
|
||||
MSCH(W, 14, i);
|
||||
MSCH(W, 15, i);
|
||||
}
|
||||
|
||||
/* 4. Mix local working variables into global state. */
|
||||
state[0] += S[0];
|
||||
state[1] += S[1];
|
||||
state[2] += S[2];
|
||||
state[3] += S[3];
|
||||
state[4] += S[4];
|
||||
state[5] += S[5];
|
||||
state[6] += S[6];
|
||||
state[7] += S[7];
|
||||
}
|
||||
|
||||
static const uint8_t PAD[64] = {
|
||||
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
|
||||
};
|
||||
|
||||
/* Add padding and terminating bit-count. */
|
||||
static void
|
||||
SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[static restrict 72])
|
||||
{
|
||||
size_t r;
|
||||
|
||||
/* Figure out how many bytes we have buffered. */
|
||||
r = (ctx->count >> 3) & 0x3f;
|
||||
|
||||
/* Pad to 56 mod 64, transforming if we finish a block en route. */
|
||||
if (r < 56) {
|
||||
/* Pad to 56 mod 64. */
|
||||
memcpy(&ctx->buf[r], PAD, 56 - r);
|
||||
} else {
|
||||
/* Finish the current block and mix. */
|
||||
memcpy(&ctx->buf[r], PAD, 64 - r);
|
||||
SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
|
||||
|
||||
/* The start of the final block is all zeroes. */
|
||||
memset(&ctx->buf[0], 0, 56);
|
||||
}
|
||||
|
||||
/* Add the terminating bit-count. */
|
||||
be64enc(&ctx->buf[56], ctx->count);
|
||||
|
||||
/* Mix in the final block. */
|
||||
SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
|
||||
}
|
||||
|
||||
/* Magic initialization constants. */
|
||||
static const uint32_t initial_state[8] = {
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
};
|
||||
|
||||
/**
|
||||
* SHA256_Init(ctx):
|
||||
* Initialize the SHA256 context ${ctx}.
|
||||
*/
|
||||
void
|
||||
SHA256_Init(SHA256_CTX * ctx)
|
||||
{
|
||||
|
||||
/* Zero bits processed so far. */
|
||||
ctx->count = 0;
|
||||
|
||||
/* Initialize state. */
|
||||
memcpy(ctx->state, initial_state, sizeof(initial_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA256_Update(ctx, in, len):
|
||||
* Input ${len} bytes from ${in} into the SHA256 context ${ctx}.
|
||||
*/
|
||||
static void
|
||||
_SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len,
|
||||
uint32_t tmp32[static restrict 72])
|
||||
{
|
||||
uint32_t r;
|
||||
const uint8_t * src = in;
|
||||
|
||||
/* Return immediately if we have nothing to do. */
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
/* Number of bytes left in the buffer from previous updates. */
|
||||
r = (ctx->count >> 3) & 0x3f;
|
||||
|
||||
/* Update number of bits. */
|
||||
ctx->count += (uint64_t)(len) << 3;
|
||||
|
||||
/* Handle the case where we don't need to perform any transforms. */
|
||||
if (len < 64 - r) {
|
||||
memcpy(&ctx->buf[r], src, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finish the current block. */
|
||||
memcpy(&ctx->buf[r], src, 64 - r);
|
||||
SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
|
||||
src += 64 - r;
|
||||
len -= 64 - r;
|
||||
|
||||
/* Perform complete blocks. */
|
||||
while (len >= 64) {
|
||||
SHA256_Transform(ctx->state, src, &tmp32[0], &tmp32[64]);
|
||||
src += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Copy left over data into buffer. */
|
||||
memcpy(ctx->buf, src, len);
|
||||
}
|
||||
|
||||
/* Wrapper function for intermediate-values sanitization. */
|
||||
void
|
||||
SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len)
|
||||
{
|
||||
uint32_t tmp32[72];
|
||||
|
||||
/* Call the real function. */
|
||||
_SHA256_Update(ctx, in, len, tmp32);
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(tmp32, 288);
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA256_Final(digest, ctx):
|
||||
* Output the SHA256 hash of the data input to the context ${ctx} into the
|
||||
* buffer ${digest}.
|
||||
*/
|
||||
static void
|
||||
_SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx,
|
||||
uint32_t tmp32[static restrict 72])
|
||||
{
|
||||
|
||||
/* Add padding. */
|
||||
SHA256_Pad(ctx, tmp32);
|
||||
|
||||
/* Write the hash. */
|
||||
be32enc_vect(digest, ctx->state, 4);
|
||||
}
|
||||
|
||||
/* Wrapper function for intermediate-values sanitization. */
|
||||
void
|
||||
SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx)
|
||||
{
|
||||
uint32_t tmp32[72];
|
||||
|
||||
/* Call the real function. */
|
||||
_SHA256_Final(digest, ctx, tmp32);
|
||||
|
||||
/* Clear the context state. */
|
||||
insecure_memzero(ctx, sizeof(SHA256_CTX));
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(tmp32, 288);
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA256_Buf(in, len, digest):
|
||||
* Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}.
|
||||
*/
|
||||
void
|
||||
SHA256_Buf(const void * in, size_t len, uint8_t digest[32])
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
uint32_t tmp32[72];
|
||||
|
||||
SHA256_Init(&ctx);
|
||||
_SHA256_Update(&ctx, in, len, tmp32);
|
||||
_SHA256_Final(digest, &ctx, tmp32);
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(&ctx, sizeof(SHA256_CTX));
|
||||
insecure_memzero(tmp32, 288);
|
||||
}
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Init(ctx, K, Klen):
|
||||
* Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
|
||||
* ${K}.
|
||||
*/
|
||||
static void
|
||||
_HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen,
|
||||
uint32_t tmp32[static restrict 72], uint8_t pad[static restrict 64],
|
||||
uint8_t khash[static restrict 32])
|
||||
{
|
||||
const uint8_t * K = _K;
|
||||
size_t i;
|
||||
|
||||
/* If Klen > 64, the key is really SHA256(K). */
|
||||
if (Klen > 64) {
|
||||
SHA256_Init(&ctx->ictx);
|
||||
_SHA256_Update(&ctx->ictx, K, Klen, tmp32);
|
||||
_SHA256_Final(khash, &ctx->ictx, tmp32);
|
||||
K = khash;
|
||||
Klen = 32;
|
||||
}
|
||||
|
||||
/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
|
||||
SHA256_Init(&ctx->ictx);
|
||||
memset(pad, 0x36, 64);
|
||||
for (i = 0; i < Klen; i++)
|
||||
pad[i] ^= K[i];
|
||||
_SHA256_Update(&ctx->ictx, pad, 64, tmp32);
|
||||
|
||||
/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
|
||||
SHA256_Init(&ctx->octx);
|
||||
memset(pad, 0x5c, 64);
|
||||
for (i = 0; i < Klen; i++)
|
||||
pad[i] ^= K[i];
|
||||
_SHA256_Update(&ctx->octx, pad, 64, tmp32);
|
||||
}
|
||||
|
||||
/* Wrapper function for intermediate-values sanitization. */
|
||||
void
|
||||
HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
|
||||
{
|
||||
uint32_t tmp32[72];
|
||||
uint8_t pad[64];
|
||||
uint8_t khash[32];
|
||||
|
||||
/* Call the real function. */
|
||||
_HMAC_SHA256_Init(ctx, _K, Klen, tmp32, pad, khash);
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(tmp32, 288);
|
||||
insecure_memzero(khash, 32);
|
||||
insecure_memzero(pad, 64);
|
||||
}
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Update(ctx, in, len):
|
||||
* Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}.
|
||||
*/
|
||||
static void
|
||||
_HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len,
|
||||
uint32_t tmp32[static restrict 72])
|
||||
{
|
||||
|
||||
/* Feed data to the inner SHA256 operation. */
|
||||
_SHA256_Update(&ctx->ictx, in, len, tmp32);
|
||||
}
|
||||
|
||||
/* Wrapper function for intermediate-values sanitization. */
|
||||
void
|
||||
HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len)
|
||||
{
|
||||
uint32_t tmp32[72];
|
||||
|
||||
/* Call the real function. */
|
||||
_HMAC_SHA256_Update(ctx, in, len, tmp32);
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(tmp32, 288);
|
||||
}
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Final(digest, ctx):
|
||||
* Output the HMAC-SHA256 of the data input to the context ${ctx} into the
|
||||
* buffer ${digest}.
|
||||
*/
|
||||
static void
|
||||
_HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx,
|
||||
uint32_t tmp32[static restrict 72], uint8_t ihash[static restrict 32])
|
||||
{
|
||||
|
||||
/* Finish the inner SHA256 operation. */
|
||||
_SHA256_Final(ihash, &ctx->ictx, tmp32);
|
||||
|
||||
/* Feed the inner hash to the outer SHA256 operation. */
|
||||
_SHA256_Update(&ctx->octx, ihash, 32, tmp32);
|
||||
|
||||
/* Finish the outer SHA256 operation. */
|
||||
_SHA256_Final(digest, &ctx->octx, tmp32);
|
||||
}
|
||||
|
||||
/* Wrapper function for intermediate-values sanitization. */
|
||||
void
|
||||
HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx)
|
||||
{
|
||||
uint32_t tmp32[72];
|
||||
uint8_t ihash[32];
|
||||
|
||||
/* Call the real function. */
|
||||
_HMAC_SHA256_Final(digest, ctx, tmp32, ihash);
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(tmp32, 288);
|
||||
insecure_memzero(ihash, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Buf(K, Klen, in, len, digest):
|
||||
* Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of
|
||||
* length ${Klen}, and write the result to ${digest}.
|
||||
*/
|
||||
void
|
||||
HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len,
|
||||
uint8_t digest[32])
|
||||
{
|
||||
HMAC_SHA256_CTX ctx;
|
||||
uint32_t tmp32[72];
|
||||
uint8_t tmp8[96];
|
||||
|
||||
_HMAC_SHA256_Init(&ctx, K, Klen, tmp32, &tmp8[0], &tmp8[64]);
|
||||
_HMAC_SHA256_Update(&ctx, in, len, tmp32);
|
||||
_HMAC_SHA256_Final(digest, &ctx, tmp32, &tmp8[0]);
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(&ctx, sizeof(HMAC_SHA256_CTX));
|
||||
insecure_memzero(tmp32, 288);
|
||||
insecure_memzero(tmp8, 96);
|
||||
}
|
||||
|
||||
/* Add padding and terminating bit-count, but don't invoke Transform yet. */
|
||||
static int
|
||||
SHA256_Pad_Almost(SHA256_CTX * ctx, uint8_t len[static restrict 8],
|
||||
uint32_t tmp32[static restrict 72])
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
r = (ctx->count >> 3) & 0x3f;
|
||||
if (r >= 56)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Convert length to a vector of bytes -- we do this now rather
|
||||
* than later because the length will change after we pad.
|
||||
*/
|
||||
be64enc(len, ctx->count);
|
||||
|
||||
/* Add 1--56 bytes so that the resulting length is 56 mod 64. */
|
||||
_SHA256_Update(ctx, PAD, 56 - r, tmp32);
|
||||
|
||||
/* Add the terminating bit-count. */
|
||||
ctx->buf[63] = len[7];
|
||||
_SHA256_Update(ctx, len, 7, tmp32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
|
||||
* Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
|
||||
* write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
|
||||
*/
|
||||
void
|
||||
PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
|
||||
size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
|
||||
{
|
||||
HMAC_SHA256_CTX Phctx, PShctx, hctx;
|
||||
uint32_t tmp32[72];
|
||||
union {
|
||||
uint8_t tmp8[96];
|
||||
uint32_t state[8];
|
||||
} u;
|
||||
size_t i;
|
||||
uint8_t ivec[4];
|
||||
uint8_t U[32];
|
||||
uint8_t T[32];
|
||||
uint64_t j;
|
||||
int k;
|
||||
size_t clen;
|
||||
|
||||
/* Sanity-check. */
|
||||
assert(dkLen <= 32 * (size_t)(UINT32_MAX));
|
||||
|
||||
if (c == 1 && (dkLen & 31) == 0 && (saltlen & 63) <= 51) {
|
||||
uint32_t oldcount;
|
||||
uint8_t * ivecp;
|
||||
|
||||
/* Compute HMAC state after processing P and S. */
|
||||
_HMAC_SHA256_Init(&hctx, passwd, passwdlen,
|
||||
tmp32, &u.tmp8[0], &u.tmp8[64]);
|
||||
_HMAC_SHA256_Update(&hctx, salt, saltlen, tmp32);
|
||||
|
||||
/* Prepare ictx padding. */
|
||||
oldcount = hctx.ictx.count & (0x3f << 3);
|
||||
_HMAC_SHA256_Update(&hctx, "\0\0\0", 4, tmp32);
|
||||
if ((hctx.ictx.count & (0x3f << 3)) < oldcount ||
|
||||
SHA256_Pad_Almost(&hctx.ictx, u.tmp8, tmp32))
|
||||
goto generic; /* Can't happen due to saltlen check */
|
||||
ivecp = hctx.ictx.buf + (oldcount >> 3);
|
||||
|
||||
/* Prepare octx padding. */
|
||||
hctx.octx.count += 32 << 3;
|
||||
SHA256_Pad_Almost(&hctx.octx, u.tmp8, tmp32);
|
||||
|
||||
/* Iterate through the blocks. */
|
||||
for (i = 0; i * 32 < dkLen; i++) {
|
||||
/* Generate INT(i + 1). */
|
||||
be32enc(ivecp, (uint32_t)(i + 1));
|
||||
|
||||
/* Compute U_1 = PRF(P, S || INT(i)). */
|
||||
memcpy(u.state, hctx.ictx.state, sizeof(u.state));
|
||||
SHA256_Transform(u.state, hctx.ictx.buf,
|
||||
&tmp32[0], &tmp32[64]);
|
||||
be32enc_vect(hctx.octx.buf, u.state, 4);
|
||||
memcpy(u.state, hctx.octx.state, sizeof(u.state));
|
||||
SHA256_Transform(u.state, hctx.octx.buf,
|
||||
&tmp32[0], &tmp32[64]);
|
||||
be32enc_vect(&buf[i * 32], u.state, 4);
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
generic:
|
||||
/* Compute HMAC state after processing P. */
|
||||
_HMAC_SHA256_Init(&Phctx, passwd, passwdlen,
|
||||
tmp32, &u.tmp8[0], &u.tmp8[64]);
|
||||
|
||||
/* Compute HMAC state after processing P and S. */
|
||||
memcpy(&PShctx, &Phctx, sizeof(HMAC_SHA256_CTX));
|
||||
_HMAC_SHA256_Update(&PShctx, salt, saltlen, tmp32);
|
||||
|
||||
/* Iterate through the blocks. */
|
||||
for (i = 0; i * 32 < dkLen; i++) {
|
||||
/* Generate INT(i + 1). */
|
||||
be32enc(ivec, (uint32_t)(i + 1));
|
||||
|
||||
/* Compute U_1 = PRF(P, S || INT(i)). */
|
||||
memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
|
||||
_HMAC_SHA256_Update(&hctx, ivec, 4, tmp32);
|
||||
_HMAC_SHA256_Final(T, &hctx, tmp32, u.tmp8);
|
||||
|
||||
if (c > 1) {
|
||||
/* T_i = U_1 ... */
|
||||
memcpy(U, T, 32);
|
||||
|
||||
for (j = 2; j <= c; j++) {
|
||||
/* Compute U_j. */
|
||||
memcpy(&hctx, &Phctx, sizeof(HMAC_SHA256_CTX));
|
||||
_HMAC_SHA256_Update(&hctx, U, 32, tmp32);
|
||||
_HMAC_SHA256_Final(U, &hctx, tmp32, u.tmp8);
|
||||
|
||||
/* ... xor U_j ... */
|
||||
for (k = 0; k < 32; k++)
|
||||
T[k] ^= U[k];
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy as many bytes as necessary into buf. */
|
||||
clen = dkLen - i * 32;
|
||||
if (clen > 32)
|
||||
clen = 32;
|
||||
memcpy(&buf[i * 32], T, clen);
|
||||
}
|
||||
|
||||
/* Clean the stack. */
|
||||
insecure_memzero(&Phctx, sizeof(HMAC_SHA256_CTX));
|
||||
insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX));
|
||||
insecure_memzero(U, 32);
|
||||
insecure_memzero(T, 32);
|
||||
|
||||
cleanup:
|
||||
insecure_memzero(&hctx, sizeof(HMAC_SHA256_CTX));
|
||||
insecure_memzero(tmp32, 288);
|
||||
insecure_memzero(&u, sizeof(u));
|
||||
}
|
||||
129
sha256.h
Normal file
129
sha256.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*-
|
||||
* Copyright 2005-2016 Colin Percival
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SHA256_H_
|
||||
#define _SHA256_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use #defines in order to avoid namespace collisions with anyone else's
|
||||
* SHA256 code (e.g., the code in OpenSSL).
|
||||
*/
|
||||
#define SHA256_Init libcperciva_SHA256_Init
|
||||
#define SHA256_Update libcperciva_SHA256_Update
|
||||
#define SHA256_Final libcperciva_SHA256_Final
|
||||
#define SHA256_Buf libcperciva_SHA256_Buf
|
||||
#define SHA256_CTX libcperciva_SHA256_CTX
|
||||
#define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init
|
||||
#define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update
|
||||
#define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final
|
||||
#define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf
|
||||
#define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX
|
||||
|
||||
/* Context structure for SHA256 operations. */
|
||||
typedef struct {
|
||||
uint32_t state[8];
|
||||
uint64_t count;
|
||||
uint8_t buf[64];
|
||||
} SHA256_CTX;
|
||||
|
||||
/**
|
||||
* SHA256_Init(ctx):
|
||||
* Initialize the SHA256 context ${ctx}.
|
||||
*/
|
||||
void SHA256_Init(SHA256_CTX *);
|
||||
|
||||
/**
|
||||
* SHA256_Update(ctx, in, len):
|
||||
* Input ${len} bytes from ${in} into the SHA256 context ${ctx}.
|
||||
*/
|
||||
void SHA256_Update(SHA256_CTX *, const void *, size_t);
|
||||
|
||||
/**
|
||||
* SHA256_Final(digest, ctx):
|
||||
* Output the SHA256 hash of the data input to the context ${ctx} into the
|
||||
* buffer ${digest}.
|
||||
*/
|
||||
void SHA256_Final(uint8_t[32], SHA256_CTX *);
|
||||
|
||||
/**
|
||||
* SHA256_Buf(in, len, digest):
|
||||
* Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}.
|
||||
*/
|
||||
void SHA256_Buf(const void *, size_t, uint8_t[32]);
|
||||
|
||||
/* Context structure for HMAC-SHA256 operations. */
|
||||
typedef struct {
|
||||
SHA256_CTX ictx;
|
||||
SHA256_CTX octx;
|
||||
} HMAC_SHA256_CTX;
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Init(ctx, K, Klen):
|
||||
* Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
|
||||
* ${K}.
|
||||
*/
|
||||
void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t);
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Update(ctx, in, len):
|
||||
* Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}.
|
||||
*/
|
||||
void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t);
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Final(digest, ctx):
|
||||
* Output the HMAC-SHA256 of the data input to the context ${ctx} into the
|
||||
* buffer ${digest}.
|
||||
*/
|
||||
void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *);
|
||||
|
||||
/**
|
||||
* HMAC_SHA256_Buf(K, Klen, in, len, digest):
|
||||
* Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of
|
||||
* length ${Klen}, and write the result to ${digest}.
|
||||
*/
|
||||
void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]);
|
||||
|
||||
/**
|
||||
* PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
|
||||
* Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
|
||||
* write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
|
||||
*/
|
||||
void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t,
|
||||
uint64_t, uint8_t *, size_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_SHA256_H_ */
|
||||
94
sysendian.h
Normal file
94
sysendian.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*-
|
||||
* Copyright 2007-2014 Colin Percival
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SYSENDIAN_H_
|
||||
#define _SYSENDIAN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Avoid namespace collisions with BSD <sys/endian.h>. */
|
||||
#define be32dec libcperciva_be32dec
|
||||
#define be32enc libcperciva_be32enc
|
||||
#define be64enc libcperciva_be64enc
|
||||
#define le32dec libcperciva_le32dec
|
||||
#define le32enc libcperciva_le32enc
|
||||
|
||||
static inline uint32_t
|
||||
be32dec(const void * pp)
|
||||
{
|
||||
const uint8_t * p = (uint8_t const *)pp;
|
||||
|
||||
return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
|
||||
((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
|
||||
}
|
||||
|
||||
static inline void
|
||||
be32enc(void * pp, uint32_t x)
|
||||
{
|
||||
uint8_t * p = (uint8_t *)pp;
|
||||
|
||||
p[3] = x & 0xff;
|
||||
p[2] = (x >> 8) & 0xff;
|
||||
p[1] = (x >> 16) & 0xff;
|
||||
p[0] = (x >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static inline void
|
||||
be64enc(void * pp, uint64_t x)
|
||||
{
|
||||
uint8_t * p = (uint8_t *)pp;
|
||||
|
||||
p[7] = x & 0xff;
|
||||
p[6] = (x >> 8) & 0xff;
|
||||
p[5] = (x >> 16) & 0xff;
|
||||
p[4] = (x >> 24) & 0xff;
|
||||
p[3] = (x >> 32) & 0xff;
|
||||
p[2] = (x >> 40) & 0xff;
|
||||
p[1] = (x >> 48) & 0xff;
|
||||
p[0] = (x >> 56) & 0xff;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
le32dec(const void * pp)
|
||||
{
|
||||
const uint8_t * p = (uint8_t const *)pp;
|
||||
|
||||
return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
|
||||
((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
|
||||
}
|
||||
|
||||
static inline void
|
||||
le32enc(void * pp, uint32_t x)
|
||||
{
|
||||
uint8_t * p = (uint8_t *)pp;
|
||||
|
||||
p[0] = x & 0xff;
|
||||
p[1] = (x >> 8) & 0xff;
|
||||
p[2] = (x >> 16) & 0xff;
|
||||
p[3] = (x >> 24) & 0xff;
|
||||
}
|
||||
|
||||
#endif /* !_SYSENDIAN_H_ */
|
||||
190
tests.c
Normal file
190
tests.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/*-
|
||||
* Copyright 2013-2018 Alexander Peslyak
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "yespower.h"
|
||||
|
||||
#undef TEST_PBKDF2_SHA256
|
||||
|
||||
#ifdef TEST_PBKDF2_SHA256
|
||||
#include <assert.h>
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
static void print_PBKDF2_SHA256_raw(const char *passwd, size_t passwdlen,
|
||||
const char *salt, size_t saltlen, uint64_t c, size_t dkLen)
|
||||
{
|
||||
uint8_t dk[64];
|
||||
size_t i;
|
||||
|
||||
assert(dkLen <= sizeof(dk));
|
||||
|
||||
/* XXX This prints the strings truncated at first NUL */
|
||||
printf("PBKDF2_SHA256(\"%s\", \"%s\", %llu, %llu) = ",
|
||||
passwd, salt, (unsigned long long)c, (unsigned long long)dkLen);
|
||||
|
||||
PBKDF2_SHA256((const uint8_t *) passwd, passwdlen,
|
||||
(const uint8_t *) salt, saltlen, c, dk, dkLen);
|
||||
|
||||
for (i = 0; i < dkLen; i++)
|
||||
printf("%02x%c", dk[i], i < dkLen - 1 ? ' ' : '\n');
|
||||
}
|
||||
|
||||
static void print_PBKDF2_SHA256(const char *passwd,
|
||||
const char *salt, uint64_t c, size_t dkLen)
|
||||
{
|
||||
print_PBKDF2_SHA256_raw(passwd, strlen(passwd), salt, strlen(salt), c,
|
||||
dkLen);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *pers_bsty_magic = "BSTY";
|
||||
|
||||
static void print_yespower(yespower_version_t version, uint32_t N, uint32_t r,
|
||||
const char *pers)
|
||||
{
|
||||
yespower_params_t params = {
|
||||
.version = version,
|
||||
.N = N,
|
||||
.r = r,
|
||||
.pers = (const uint8_t *)pers,
|
||||
.perslen = pers ? strlen(pers) : 0
|
||||
};
|
||||
uint8_t src[80];
|
||||
yespower_binary_t dst;
|
||||
size_t i;
|
||||
|
||||
const char *q = (pers && pers != pers_bsty_magic) ? "\"": "";
|
||||
printf("yespower(%u, %u, %u, %s%s%s) = ", (unsigned int)version, N, r,
|
||||
q, pers ? pers : "NULL", q);
|
||||
|
||||
for (i = 0; i < sizeof(src); i++)
|
||||
src[i] = i * 3;
|
||||
|
||||
if (pers == pers_bsty_magic) {
|
||||
params.pers = src;
|
||||
params.perslen = sizeof(src);
|
||||
}
|
||||
|
||||
if (yespower_tls(src, sizeof(src), ¶ms, &dst)) {
|
||||
puts("FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(dst); i++)
|
||||
printf("%02x%c", dst.uc[i], i < sizeof(dst) - 1 ? ' ' : '\n');
|
||||
}
|
||||
|
||||
static void print_yespower_loop(yespower_version_t version, const char *pers)
|
||||
{
|
||||
uint32_t N, r;
|
||||
uint8_t src[80];
|
||||
yespower_binary_t dst, xor = {{0}};
|
||||
size_t i;
|
||||
|
||||
printf("XOR of yespower(%u, ...) = ", (unsigned int)version);
|
||||
|
||||
/*
|
||||
* This value of src is chosen to trigger duplicate index in the last
|
||||
* SMix2 invocation in yespower 0.5 for N=2048 with at least one of the
|
||||
* values of r below. This is needed to test that a non-save version
|
||||
* of BlockMix is used in that special case. Most other values of src
|
||||
* would leave this untested.
|
||||
*/
|
||||
src[0] = 43;
|
||||
for (i = 1; i < sizeof(src); i++)
|
||||
src[i] = i * 3;
|
||||
|
||||
for (N = 1024; N <= 4096; N <<= 1) {
|
||||
for (r = 8; r <= 32; r++) {
|
||||
yespower_params_t params = {
|
||||
.version = version,
|
||||
.N = N,
|
||||
.r = r,
|
||||
.pers = (const uint8_t *)pers,
|
||||
.perslen = pers ? strlen(pers) : 0
|
||||
};
|
||||
if (yespower_tls(src, sizeof(src), ¶ms, &dst)) {
|
||||
puts("FAILED");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < sizeof(xor); i++)
|
||||
xor.uc[i] ^= dst.uc[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(xor); i++)
|
||||
printf("%02x%c", xor.uc[i], i < sizeof(xor) - 1 ? ' ' : '\n');
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
#ifdef TEST_PBKDF2_SHA256
|
||||
print_PBKDF2_SHA256("password", "salt", 1, 20);
|
||||
print_PBKDF2_SHA256("password", "salt", 2, 20);
|
||||
print_PBKDF2_SHA256("password", "salt", 4096, 20);
|
||||
print_PBKDF2_SHA256("password", "salt", 16777216, 20);
|
||||
print_PBKDF2_SHA256("passwordPASSWORDpassword",
|
||||
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25);
|
||||
print_PBKDF2_SHA256_raw("pass\0word", 9, "sa\0lt", 5, 4096, 16);
|
||||
#if 0
|
||||
print_PBKDF2_SHA256("password", "salt", 1, 32);
|
||||
print_PBKDF2_SHA256("password", "salt", 2, 32);
|
||||
print_PBKDF2_SHA256("password", "salt", 4096, 32);
|
||||
print_PBKDF2_SHA256("password", "salt", 16777216, 32);
|
||||
print_PBKDF2_SHA256("passwordPASSWORDpassword",
|
||||
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 40);
|
||||
print_PBKDF2_SHA256("password", "salt", 4096, 16);
|
||||
print_PBKDF2_SHA256("password", "salt", 1, 20);
|
||||
print_PBKDF2_SHA256("password", "salt", 2, 20);
|
||||
print_PBKDF2_SHA256("password", "salt", 4096, 20);
|
||||
print_PBKDF2_SHA256("password", "salt", 16777216, 20);
|
||||
print_PBKDF2_SHA256("password", "salt", 4096, 25);
|
||||
print_PBKDF2_SHA256("password", "salt", 4096, 16);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
print_yespower(YESPOWER_0_5, 2048, 8, "Client Key"); /* yescrypt 0.5 */
|
||||
print_yespower(YESPOWER_0_5, 2048, 8, pers_bsty_magic); /* BSTY */
|
||||
print_yespower(YESPOWER_0_5, 4096, 16, "Client Key"); /* Cryply */
|
||||
print_yespower(YESPOWER_0_5, 4096, 24, "Jagaricoin");
|
||||
print_yespower(YESPOWER_0_5, 4096, 32, "WaviBanana");
|
||||
print_yespower(YESPOWER_0_5, 2048, 32, "Client Key");
|
||||
print_yespower(YESPOWER_0_5, 1024, 32, "Client Key");
|
||||
|
||||
print_yespower(YESPOWER_0_5, 2048, 8, NULL); /* no personality */
|
||||
|
||||
print_yespower(YESPOWER_1_0, 2048, 8, NULL);
|
||||
print_yespower(YESPOWER_1_0, 4096, 16, NULL);
|
||||
print_yespower(YESPOWER_1_0, 4096, 32, NULL);
|
||||
print_yespower(YESPOWER_1_0, 2048, 32, NULL);
|
||||
print_yespower(YESPOWER_1_0, 1024, 32, NULL);
|
||||
|
||||
print_yespower(YESPOWER_1_0, 1024, 32, "personality test");
|
||||
|
||||
print_yespower_loop(YESPOWER_0_5, "Client Key");
|
||||
print_yespower_loop(YESPOWER_1_0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1161
yespower-opt.c
Normal file
1161
yespower-opt.c
Normal file
File diff suppressed because it is too large
Load Diff
114
yespower-platform.c
Normal file
114
yespower-platform.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*-
|
||||
* Copyright 2013-2018,2022 Alexander Peslyak
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "yespower.h"
|
||||
|
||||
#ifdef __unix__
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <linux/mman.h> /* for MAP_HUGE_2MB */
|
||||
#endif
|
||||
|
||||
#define HUGEPAGE_THRESHOLD (12 * 1024 * 1024)
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define HUGEPAGE_SIZE (2 * 1024 * 1024)
|
||||
#else
|
||||
#undef HUGEPAGE_SIZE
|
||||
#endif
|
||||
|
||||
static void *alloc_region(yespower_region_t *region, size_t size)
|
||||
{
|
||||
size_t base_size = size;
|
||||
uint8_t *base, *aligned;
|
||||
#ifdef MAP_ANON
|
||||
int flags =
|
||||
#ifdef MAP_NOCORE
|
||||
MAP_NOCORE |
|
||||
#endif
|
||||
MAP_ANON | MAP_PRIVATE;
|
||||
#if defined(MAP_HUGETLB) && defined(MAP_HUGE_2MB) && defined(HUGEPAGE_SIZE)
|
||||
size_t new_size = size;
|
||||
const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1;
|
||||
if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) {
|
||||
flags |= MAP_HUGETLB | MAP_HUGE_2MB;
|
||||
/*
|
||||
* Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of
|
||||
* huge page size, so let's round up to huge page size here.
|
||||
*/
|
||||
new_size = size + hugepage_mask;
|
||||
new_size &= ~hugepage_mask;
|
||||
}
|
||||
base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
||||
if (base != MAP_FAILED) {
|
||||
base_size = new_size;
|
||||
} else if (flags & MAP_HUGETLB) {
|
||||
flags &= ~(MAP_HUGETLB | MAP_HUGE_2MB);
|
||||
base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
||||
#endif
|
||||
if (base == MAP_FAILED)
|
||||
base = NULL;
|
||||
aligned = base;
|
||||
#elif defined(HAVE_POSIX_MEMALIGN)
|
||||
if ((errno = posix_memalign((void **)&base, 64, size)) != 0)
|
||||
base = NULL;
|
||||
aligned = base;
|
||||
#else
|
||||
base = aligned = NULL;
|
||||
if (size + 63 < size) {
|
||||
errno = ENOMEM;
|
||||
} else if ((base = malloc(size + 63)) != NULL) {
|
||||
aligned = base + 63;
|
||||
aligned -= (uintptr_t)aligned & 63;
|
||||
}
|
||||
#endif
|
||||
region->base = base;
|
||||
region->aligned = aligned;
|
||||
region->base_size = base ? base_size : 0;
|
||||
region->aligned_size = base ? size : 0;
|
||||
return aligned;
|
||||
}
|
||||
|
||||
static inline void init_region(yespower_region_t *region)
|
||||
{
|
||||
region->base = region->aligned = NULL;
|
||||
region->base_size = region->aligned_size = 0;
|
||||
}
|
||||
|
||||
static int free_region(yespower_region_t *region)
|
||||
{
|
||||
if (region->base) {
|
||||
#ifdef MAP_ANON
|
||||
if (munmap(region->base, region->base_size))
|
||||
return -1;
|
||||
#else
|
||||
free(region->base);
|
||||
#endif
|
||||
}
|
||||
init_region(region);
|
||||
return 0;
|
||||
}
|
||||
582
yespower-ref.c
Normal file
582
yespower-ref.c
Normal file
@@ -0,0 +1,582 @@
|
||||
/*-
|
||||
* Copyright 2009 Colin Percival
|
||||
* Copyright 2013-2019 Alexander Peslyak
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file was originally written by Colin Percival as part of the Tarsnap
|
||||
* online backup system.
|
||||
*
|
||||
* This is a proof-of-work focused fork of yescrypt, including reference and
|
||||
* cut-down implementation of the obsolete yescrypt 0.5 (based off its first
|
||||
* submission to PHC back in 2014) and a new proof-of-work specific variation
|
||||
* known as yespower 1.0. The former is intended as an upgrade for
|
||||
* cryptocurrencies that already use yescrypt 0.5 and the latter may be used
|
||||
* as a further upgrade (hard fork) by those and other cryptocurrencies. The
|
||||
* version of algorithm to use is requested through parameters, allowing for
|
||||
* both algorithms to co-exist in client and miner implementations (such as in
|
||||
* preparation for a hard-fork).
|
||||
*
|
||||
* This is the reference implementation. Its purpose is to provide a simple
|
||||
* human- and machine-readable specification that implementations intended
|
||||
* for actual use should be tested against. It is deliberately mostly not
|
||||
* optimized, and it is not meant to be used in production. Instead, use
|
||||
* yespower-opt.c.
|
||||
*/
|
||||
|
||||
#warning "This reference implementation is deliberately mostly not optimized. Use yespower-opt.c instead unless you're testing (against) the reference implementation on purpose."
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sha256.h"
|
||||
#include "sysendian.h"
|
||||
|
||||
#include "yespower.h"
|
||||
|
||||
static void blkcpy(uint32_t *dst, const uint32_t *src, size_t count)
|
||||
{
|
||||
do {
|
||||
*dst++ = *src++;
|
||||
} while (--count);
|
||||
}
|
||||
|
||||
static void blkxor(uint32_t *dst, const uint32_t *src, size_t count)
|
||||
{
|
||||
do {
|
||||
*dst++ ^= *src++;
|
||||
} while (--count);
|
||||
}
|
||||
|
||||
/**
|
||||
* salsa20(B):
|
||||
* Apply the Salsa20 core to the provided block.
|
||||
*/
|
||||
static void salsa20(uint32_t B[16], uint32_t rounds)
|
||||
{
|
||||
uint32_t x[16];
|
||||
size_t i;
|
||||
|
||||
/* SIMD unshuffle */
|
||||
for (i = 0; i < 16; i++)
|
||||
x[i * 5 % 16] = B[i];
|
||||
|
||||
for (i = 0; i < rounds; i += 2) {
|
||||
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
|
||||
/* Operate on columns */
|
||||
x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
|
||||
x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
|
||||
|
||||
x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
|
||||
x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
|
||||
|
||||
x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
|
||||
x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
|
||||
|
||||
x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
|
||||
x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
|
||||
|
||||
/* Operate on rows */
|
||||
x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
|
||||
x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
|
||||
|
||||
x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
|
||||
x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
|
||||
|
||||
x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
|
||||
x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
|
||||
|
||||
x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
|
||||
x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
|
||||
#undef R
|
||||
}
|
||||
|
||||
/* SIMD shuffle */
|
||||
for (i = 0; i < 16; i++)
|
||||
B[i] += x[i * 5 % 16];
|
||||
}
|
||||
|
||||
/**
|
||||
* blockmix_salsa(B):
|
||||
* Compute B = BlockMix_{salsa20, 1}(B). The input B must be 128 bytes in
|
||||
* length.
|
||||
*/
|
||||
static void blockmix_salsa(uint32_t *B, uint32_t rounds)
|
||||
{
|
||||
uint32_t X[16];
|
||||
size_t i;
|
||||
|
||||
/* 1: X <-- B_{2r - 1} */
|
||||
blkcpy(X, &B[16], 16);
|
||||
|
||||
/* 2: for i = 0 to 2r - 1 do */
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* 3: X <-- H(X xor B_i) */
|
||||
blkxor(X, &B[i * 16], 16);
|
||||
salsa20(X, rounds);
|
||||
|
||||
/* 4: Y_i <-- X */
|
||||
/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
|
||||
blkcpy(&B[i * 16], X, 16);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* These are tunable, but they must meet certain constraints and are part of
|
||||
* what defines a yespower version.
|
||||
*/
|
||||
#define PWXsimple 2
|
||||
#define PWXgather 4
|
||||
/* Version 0.5 */
|
||||
#define PWXrounds_0_5 6
|
||||
#define Swidth_0_5 8
|
||||
/* Version 1.0 */
|
||||
#define PWXrounds_1_0 3
|
||||
#define Swidth_1_0 11
|
||||
|
||||
/* Derived values. Not tunable on their own. */
|
||||
#define PWXbytes (PWXgather * PWXsimple * 8)
|
||||
#define PWXwords (PWXbytes / sizeof(uint32_t))
|
||||
#define rmin ((PWXbytes + 127) / 128)
|
||||
|
||||
/* Runtime derived values. Not tunable on their own. */
|
||||
#define Swidth_to_Sbytes1(Swidth) ((1 << Swidth) * PWXsimple * 8)
|
||||
#define Swidth_to_Smask(Swidth) (((1 << Swidth) - 1) * PWXsimple * 8)
|
||||
|
||||
typedef struct {
|
||||
yespower_version_t version;
|
||||
uint32_t salsa20_rounds;
|
||||
uint32_t PWXrounds, Swidth, Sbytes, Smask;
|
||||
uint32_t *S;
|
||||
uint32_t (*S0)[2], (*S1)[2], (*S2)[2];
|
||||
size_t w;
|
||||
} pwxform_ctx_t;
|
||||
|
||||
/**
|
||||
* pwxform(B):
|
||||
* Transform the provided block using the provided S-boxes.
|
||||
*/
|
||||
static void pwxform(uint32_t *B, pwxform_ctx_t *ctx)
|
||||
{
|
||||
uint32_t (*X)[PWXsimple][2] = (uint32_t (*)[PWXsimple][2])B;
|
||||
uint32_t (*S0)[2] = ctx->S0, (*S1)[2] = ctx->S1, (*S2)[2] = ctx->S2;
|
||||
uint32_t Smask = ctx->Smask;
|
||||
size_t w = ctx->w;
|
||||
size_t i, j, k;
|
||||
|
||||
/* 1: for i = 0 to PWXrounds - 1 do */
|
||||
for (i = 0; i < ctx->PWXrounds; i++) {
|
||||
/* 2: for j = 0 to PWXgather - 1 do */
|
||||
for (j = 0; j < PWXgather; j++) {
|
||||
uint32_t xl = X[j][0][0];
|
||||
uint32_t xh = X[j][0][1];
|
||||
uint32_t (*p0)[2], (*p1)[2];
|
||||
|
||||
/* 3: p0 <-- (lo(B_{j,0}) & Smask) / (PWXsimple * 8) */
|
||||
p0 = S0 + (xl & Smask) / sizeof(*S0);
|
||||
/* 4: p1 <-- (hi(B_{j,0}) & Smask) / (PWXsimple * 8) */
|
||||
p1 = S1 + (xh & Smask) / sizeof(*S1);
|
||||
|
||||
/* 5: for k = 0 to PWXsimple - 1 do */
|
||||
for (k = 0; k < PWXsimple; k++) {
|
||||
uint64_t x, s0, s1;
|
||||
|
||||
/* 6: B_{j,k} <-- (hi(B_{j,k}) * lo(B_{j,k}) + S0_{p0,k}) xor S1_{p1,k} */
|
||||
s0 = ((uint64_t)p0[k][1] << 32) + p0[k][0];
|
||||
s1 = ((uint64_t)p1[k][1] << 32) + p1[k][0];
|
||||
|
||||
xl = X[j][k][0];
|
||||
xh = X[j][k][1];
|
||||
|
||||
x = (uint64_t)xh * xl;
|
||||
x += s0;
|
||||
x ^= s1;
|
||||
|
||||
X[j][k][0] = x;
|
||||
X[j][k][1] = x >> 32;
|
||||
}
|
||||
|
||||
if (ctx->version != YESPOWER_0_5 &&
|
||||
(i == 0 || j < PWXgather / 2)) {
|
||||
if (j & 1) {
|
||||
for (k = 0; k < PWXsimple; k++) {
|
||||
S1[w][0] = X[j][k][0];
|
||||
S1[w][1] = X[j][k][1];
|
||||
w++;
|
||||
}
|
||||
} else {
|
||||
for (k = 0; k < PWXsimple; k++) {
|
||||
S0[w + k][0] = X[j][k][0];
|
||||
S0[w + k][1] = X[j][k][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->version != YESPOWER_0_5) {
|
||||
/* 14: (S0, S1, S2) <-- (S2, S0, S1) */
|
||||
ctx->S0 = S2;
|
||||
ctx->S1 = S0;
|
||||
ctx->S2 = S1;
|
||||
/* 15: w <-- w mod 2^Swidth */
|
||||
ctx->w = w & ((1 << ctx->Swidth) * PWXsimple - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* blockmix_pwxform(B, ctx, r):
|
||||
* Compute B = BlockMix_pwxform{salsa20, ctx, r}(B). The input B must be
|
||||
* 128r bytes in length.
|
||||
*/
|
||||
static void blockmix_pwxform(uint32_t *B, pwxform_ctx_t *ctx, size_t r)
|
||||
{
|
||||
uint32_t X[PWXwords];
|
||||
size_t r1, i;
|
||||
|
||||
/* Convert 128-byte blocks to PWXbytes blocks */
|
||||
/* 1: r_1 <-- 128r / PWXbytes */
|
||||
r1 = 128 * r / PWXbytes;
|
||||
|
||||
/* 2: X <-- B'_{r_1 - 1} */
|
||||
blkcpy(X, &B[(r1 - 1) * PWXwords], PWXwords);
|
||||
|
||||
/* 3: for i = 0 to r_1 - 1 do */
|
||||
for (i = 0; i < r1; i++) {
|
||||
/* 4: if r_1 > 1 */
|
||||
if (r1 > 1) {
|
||||
/* 5: X <-- X xor B'_i */
|
||||
blkxor(X, &B[i * PWXwords], PWXwords);
|
||||
}
|
||||
|
||||
/* 7: X <-- pwxform(X) */
|
||||
pwxform(X, ctx);
|
||||
|
||||
/* 8: B'_i <-- X */
|
||||
blkcpy(&B[i * PWXwords], X, PWXwords);
|
||||
}
|
||||
|
||||
/* 10: i <-- floor((r_1 - 1) * PWXbytes / 64) */
|
||||
i = (r1 - 1) * PWXbytes / 64;
|
||||
|
||||
/* 11: B_i <-- H(B_i) */
|
||||
salsa20(&B[i * 16], ctx->salsa20_rounds);
|
||||
|
||||
#if 1 /* No-op with our current pwxform settings, but do it to make sure */
|
||||
/* 12: for i = i + 1 to 2r - 1 do */
|
||||
for (i++; i < 2 * r; i++) {
|
||||
/* 13: B_i <-- H(B_i xor B_{i-1}) */
|
||||
blkxor(&B[i * 16], &B[(i - 1) * 16], 16);
|
||||
salsa20(&B[i * 16], ctx->salsa20_rounds);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* integerify(B, r):
|
||||
* Return the result of parsing B_{2r-1} as a little-endian integer.
|
||||
*/
|
||||
static uint32_t integerify(const uint32_t *B, size_t r)
|
||||
{
|
||||
/*
|
||||
* Our 32-bit words are in host byte order. Also, they are SIMD-shuffled, but
|
||||
* we only care about the least significant 32 bits anyway.
|
||||
*/
|
||||
const uint32_t *X = &B[(2 * r - 1) * 16];
|
||||
return X[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* p2floor(x):
|
||||
* Largest power of 2 not greater than argument.
|
||||
*/
|
||||
static uint32_t p2floor(uint32_t x)
|
||||
{
|
||||
uint32_t y;
|
||||
while ((y = x & (x - 1)))
|
||||
x = y;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* wrap(x, i):
|
||||
* Wrap x to the range 0 to i-1.
|
||||
*/
|
||||
static uint32_t wrap(uint32_t x, uint32_t i)
|
||||
{
|
||||
uint32_t n = p2floor(i);
|
||||
return (x & (n - 1)) + (i - n);
|
||||
}
|
||||
|
||||
/**
|
||||
* smix1(B, r, N, V, X, ctx):
|
||||
* Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in
|
||||
* length; the temporary storage V must be 128rN bytes in length; the temporary
|
||||
* storage X must be 128r bytes in length.
|
||||
*/
|
||||
static void smix1(uint32_t *B, size_t r, uint32_t N,
|
||||
uint32_t *V, uint32_t *X, pwxform_ctx_t *ctx)
|
||||
{
|
||||
size_t s = 32 * r;
|
||||
uint32_t i, j;
|
||||
size_t k;
|
||||
|
||||
/* 1: X <-- B */
|
||||
for (k = 0; k < 2 * r; k++)
|
||||
for (i = 0; i < 16; i++)
|
||||
X[k * 16 + i] = le32dec(&B[k * 16 + (i * 5 % 16)]);
|
||||
|
||||
if (ctx->version != YESPOWER_0_5) {
|
||||
for (k = 1; k < r; k++) {
|
||||
blkcpy(&X[k * 32], &X[(k - 1) * 32], 32);
|
||||
blockmix_pwxform(&X[k * 32], ctx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 2: for i = 0 to N - 1 do */
|
||||
for (i = 0; i < N; i++) {
|
||||
/* 3: V_i <-- X */
|
||||
blkcpy(&V[i * s], X, s);
|
||||
|
||||
if (i > 1) {
|
||||
/* j <-- Wrap(Integerify(X), i) */
|
||||
j = wrap(integerify(X, r), i);
|
||||
|
||||
/* X <-- X xor V_j */
|
||||
blkxor(X, &V[j * s], s);
|
||||
}
|
||||
|
||||
/* 4: X <-- H(X) */
|
||||
if (V != ctx->S)
|
||||
blockmix_pwxform(X, ctx, r);
|
||||
else
|
||||
blockmix_salsa(X, ctx->salsa20_rounds);
|
||||
}
|
||||
|
||||
/* B' <-- X */
|
||||
for (k = 0; k < 2 * r; k++)
|
||||
for (i = 0; i < 16; i++)
|
||||
le32enc(&B[k * 16 + (i * 5 % 16)], X[k * 16 + i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* smix2(B, r, N, Nloop, V, X, ctx):
|
||||
* Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in
|
||||
* length; the temporary storage V must be 128rN bytes in length; the temporary
|
||||
* storage X must be 128r bytes in length. The value N must be a power of 2
|
||||
* greater than 1.
|
||||
*/
|
||||
static void smix2(uint32_t *B, size_t r, uint32_t N, uint32_t Nloop,
|
||||
uint32_t *V, uint32_t *X, pwxform_ctx_t *ctx)
|
||||
{
|
||||
size_t s = 32 * r;
|
||||
uint32_t i, j;
|
||||
size_t k;
|
||||
|
||||
/* X <-- B */
|
||||
for (k = 0; k < 2 * r; k++)
|
||||
for (i = 0; i < 16; i++)
|
||||
X[k * 16 + i] = le32dec(&B[k * 16 + (i * 5 % 16)]);
|
||||
|
||||
/* 6: for i = 0 to N - 1 do */
|
||||
for (i = 0; i < Nloop; i++) {
|
||||
/* 7: j <-- Integerify(X) mod N */
|
||||
j = integerify(X, r) & (N - 1);
|
||||
|
||||
/* 8.1: X <-- X xor V_j */
|
||||
blkxor(X, &V[j * s], s);
|
||||
/* V_j <-- X */
|
||||
if (Nloop != 2)
|
||||
blkcpy(&V[j * s], X, s);
|
||||
|
||||
/* 8.2: X <-- H(X) */
|
||||
blockmix_pwxform(X, ctx, r);
|
||||
}
|
||||
|
||||
/* 10: B' <-- X */
|
||||
for (k = 0; k < 2 * r; k++)
|
||||
for (i = 0; i < 16; i++)
|
||||
le32enc(&B[k * 16 + (i * 5 % 16)], X[k * 16 + i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* smix(B, r, N, p, t, V, X, ctx):
|
||||
* Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the
|
||||
* temporary storage V must be 128rN bytes in length; the temporary storage
|
||||
* X must be 128r bytes in length. The value N must be a power of 2 and at
|
||||
* least 16.
|
||||
*/
|
||||
static void smix(uint32_t *B, size_t r, uint32_t N,
|
||||
uint32_t *V, uint32_t *X, pwxform_ctx_t *ctx)
|
||||
{
|
||||
uint32_t Nloop_all = (N + 2) / 3; /* 1/3, round up */
|
||||
uint32_t Nloop_rw = Nloop_all;
|
||||
|
||||
Nloop_all++; Nloop_all &= ~(uint32_t)1; /* round up to even */
|
||||
if (ctx->version == YESPOWER_0_5) {
|
||||
Nloop_rw &= ~(uint32_t)1; /* round down to even */
|
||||
} else {
|
||||
Nloop_rw++; Nloop_rw &= ~(uint32_t)1; /* round up to even */
|
||||
}
|
||||
|
||||
smix1(B, 1, ctx->Sbytes / 128, ctx->S, X, ctx);
|
||||
smix1(B, r, N, V, X, ctx);
|
||||
smix2(B, r, N, Nloop_rw /* must be > 2 */, V, X, ctx);
|
||||
smix2(B, r, N, Nloop_all - Nloop_rw /* 0 or 2 */, V, X, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* yespower(local, src, srclen, params, dst):
|
||||
* Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target".
|
||||
*
|
||||
* Return 0 on success; or -1 on error.
|
||||
*/
|
||||
int yespower(yespower_local_t *local,
|
||||
const uint8_t *src, size_t srclen,
|
||||
const yespower_params_t *params, yespower_binary_t *dst)
|
||||
{
|
||||
yespower_version_t version = params->version;
|
||||
uint32_t N = params->N;
|
||||
uint32_t r = params->r;
|
||||
const uint8_t *pers = params->pers;
|
||||
size_t perslen = params->perslen;
|
||||
int retval = -1;
|
||||
size_t B_size, V_size;
|
||||
uint32_t *B, *V, *X, *S;
|
||||
pwxform_ctx_t ctx;
|
||||
uint32_t sha256[8];
|
||||
|
||||
memset(dst, 0xff, sizeof(*dst));
|
||||
|
||||
/* Sanity-check parameters */
|
||||
if ((version != YESPOWER_0_5 && version != YESPOWER_1_0) ||
|
||||
N < 1024 || N > 512 * 1024 || r < 8 || r > 32 ||
|
||||
(N & (N - 1)) != 0 || r < rmin ||
|
||||
(!pers && perslen)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate memory */
|
||||
B_size = (size_t)128 * r;
|
||||
V_size = B_size * N;
|
||||
if ((V = malloc(V_size)) == NULL)
|
||||
return -1;
|
||||
if ((B = malloc(B_size)) == NULL)
|
||||
goto free_V;
|
||||
if ((X = malloc(B_size)) == NULL)
|
||||
goto free_B;
|
||||
ctx.version = version;
|
||||
if (version == YESPOWER_0_5) {
|
||||
ctx.salsa20_rounds = 8;
|
||||
ctx.PWXrounds = PWXrounds_0_5;
|
||||
ctx.Swidth = Swidth_0_5;
|
||||
ctx.Sbytes = 2 * Swidth_to_Sbytes1(ctx.Swidth);
|
||||
} else {
|
||||
ctx.salsa20_rounds = 2;
|
||||
ctx.PWXrounds = PWXrounds_1_0;
|
||||
ctx.Swidth = Swidth_1_0;
|
||||
ctx.Sbytes = 3 * Swidth_to_Sbytes1(ctx.Swidth);
|
||||
}
|
||||
if ((S = malloc(ctx.Sbytes)) == NULL)
|
||||
goto free_X;
|
||||
ctx.S = S;
|
||||
ctx.S0 = (uint32_t (*)[2])S;
|
||||
ctx.S1 = ctx.S0 + (1 << ctx.Swidth) * PWXsimple;
|
||||
ctx.S2 = ctx.S1 + (1 << ctx.Swidth) * PWXsimple;
|
||||
ctx.Smask = Swidth_to_Smask(ctx.Swidth);
|
||||
ctx.w = 0;
|
||||
|
||||
SHA256_Buf(src, srclen, (uint8_t *)sha256);
|
||||
|
||||
if (version != YESPOWER_0_5) {
|
||||
if (pers) {
|
||||
src = pers;
|
||||
srclen = perslen;
|
||||
} else {
|
||||
srclen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
|
||||
PBKDF2_SHA256((uint8_t *)sha256, sizeof(sha256),
|
||||
src, srclen, 1, (uint8_t *)B, B_size);
|
||||
|
||||
blkcpy(sha256, B, sizeof(sha256) / sizeof(sha256[0]));
|
||||
|
||||
/* 3: B_i <-- MF(B_i, N) */
|
||||
smix(B, r, N, V, X, &ctx);
|
||||
|
||||
if (version == YESPOWER_0_5) {
|
||||
/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
|
||||
PBKDF2_SHA256((uint8_t *)sha256, sizeof(sha256),
|
||||
(uint8_t *)B, B_size, 1, (uint8_t *)dst, sizeof(*dst));
|
||||
|
||||
if (pers) {
|
||||
HMAC_SHA256_Buf(dst, sizeof(*dst), pers, perslen,
|
||||
(uint8_t *)sha256);
|
||||
SHA256_Buf(sha256, sizeof(sha256), (uint8_t *)dst);
|
||||
}
|
||||
} else {
|
||||
HMAC_SHA256_Buf((uint8_t *)B + B_size - 64, 64,
|
||||
sha256, sizeof(sha256), (uint8_t *)dst);
|
||||
}
|
||||
|
||||
/* Success! */
|
||||
retval = 0;
|
||||
|
||||
/* Free memory */
|
||||
free(S);
|
||||
free_X:
|
||||
free(X);
|
||||
free_B:
|
||||
free(B);
|
||||
free_V:
|
||||
free(V);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int yespower_tls(const uint8_t *src, size_t srclen,
|
||||
const yespower_params_t *params, yespower_binary_t *dst)
|
||||
{
|
||||
/* The reference implementation doesn't use thread-local storage */
|
||||
return yespower(NULL, src, srclen, params, dst);
|
||||
}
|
||||
|
||||
int yespower_init_local(yespower_local_t *local)
|
||||
{
|
||||
/* The reference implementation doesn't use the local structure */
|
||||
local->base = local->aligned = NULL;
|
||||
local->base_size = local->aligned_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int yespower_free_local(yespower_local_t *local)
|
||||
{
|
||||
/* The reference implementation frees its memory in yespower() */
|
||||
(void)local; /* unused */
|
||||
return 0;
|
||||
}
|
||||
130
yespower.h
Normal file
130
yespower.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-
|
||||
* Copyright 2009 Colin Percival
|
||||
* Copyright 2013-2018 Alexander Peslyak
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file was originally written by Colin Percival as part of the Tarsnap
|
||||
* online backup system.
|
||||
*/
|
||||
#ifndef _YESPOWER_H_
|
||||
#define _YESPOWER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h> /* for size_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Internal type used by the memory allocator. Please do not use it directly.
|
||||
* Use yespower_local_t instead.
|
||||
*/
|
||||
typedef struct {
|
||||
void *base, *aligned;
|
||||
size_t base_size, aligned_size;
|
||||
} yespower_region_t;
|
||||
|
||||
/**
|
||||
* Type for thread-local (RAM) data structure.
|
||||
*/
|
||||
typedef yespower_region_t yespower_local_t;
|
||||
|
||||
/*
|
||||
* Type for yespower algorithm version numbers.
|
||||
*/
|
||||
typedef enum { YESPOWER_0_5 = 5, YESPOWER_1_0 = 10 } yespower_version_t;
|
||||
|
||||
/**
|
||||
* yespower parameters combined into one struct.
|
||||
*/
|
||||
typedef struct {
|
||||
yespower_version_t version;
|
||||
uint32_t N, r;
|
||||
const uint8_t *pers;
|
||||
size_t perslen;
|
||||
} yespower_params_t;
|
||||
|
||||
/**
|
||||
* A 256-bit yespower hash.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char uc[32];
|
||||
} yespower_binary_t;
|
||||
|
||||
/**
|
||||
* yespower_init_local(local):
|
||||
* Initialize the thread-local (RAM) data structure. Actual memory allocation
|
||||
* is currently fully postponed until a call to yespower().
|
||||
*
|
||||
* Return 0 on success; or -1 on error.
|
||||
*
|
||||
* MT-safe as long as local is local to the thread.
|
||||
*/
|
||||
extern int yespower_init_local(yespower_local_t *local);
|
||||
|
||||
/**
|
||||
* yespower_free_local(local):
|
||||
* Free memory that may have been allocated for an initialized thread-local
|
||||
* (RAM) data structure.
|
||||
*
|
||||
* Return 0 on success; or -1 on error.
|
||||
*
|
||||
* MT-safe as long as local is local to the thread.
|
||||
*/
|
||||
extern int yespower_free_local(yespower_local_t *local);
|
||||
|
||||
/**
|
||||
* yespower(local, src, srclen, params, dst):
|
||||
* Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target".
|
||||
* local is the thread-local data structure, allowing to preserve and reuse a
|
||||
* memory allocation across calls, thereby reducing processing overhead.
|
||||
*
|
||||
* Return 0 on success; or -1 on error.
|
||||
*
|
||||
* local must be initialized with yespower_init_local().
|
||||
*
|
||||
* MT-safe as long as local and dst are local to the thread.
|
||||
*/
|
||||
extern int yespower(yespower_local_t *local,
|
||||
const uint8_t *src, size_t srclen,
|
||||
const yespower_params_t *params, yespower_binary_t *dst);
|
||||
|
||||
/**
|
||||
* yespower_tls(src, srclen, params, dst):
|
||||
* Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target".
|
||||
* The memory allocation is maintained internally using thread-local storage.
|
||||
*
|
||||
* Return 0 on success; or -1 on error.
|
||||
*
|
||||
* MT-safe as long as dst is local to the thread.
|
||||
*/
|
||||
extern int yespower_tls(const uint8_t *src, size_t srclen,
|
||||
const yespower_params_t *params, yespower_binary_t *dst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_YESPOWER_H_ */
|
||||
Reference in New Issue
Block a user