1
1
mirror of https://github.com/BLAKE2/BLAKE2 synced 2024-09-07 07:10:35 +02:00

Release 2013-01-31

This commit is contained in:
CodesInChaos 2013-02-01 16:44:36 +01:00
commit fb714d2c83
60 changed files with 42049 additions and 0 deletions

121
COPYING Normal file
View File

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

19
README Normal file
View File

@ -0,0 +1,19 @@
this is the reference source code package of BLAKE2, which includes
ref/
C implementations of blake2b, blake2bp, blake2s, blake2sp, aimed at
portability and simplicity
sse/
C implementations of blake2b, blake2bp, blake2s, blake2sp, optimized
for speed on CPUs supporting SSE2, SSSE3, SSE4.1, AVX, or XOP
csharp/
C# implementation of blake2b
b2sum/
command line tool to hash files, based on the sse/ implementations
bench/
benchmark tool to measure cycles-per-byte speeds and produce graphs

312
b2sum/b2sum.c Normal file
View File

@ -0,0 +1,312 @@
/*
BLAKE2 reference source code package - b2sum tool
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <getopt.h>
#include "blake2.h"
/* This will help compatibility with coreutils */
int blake2s_stream( FILE *stream, void *resstream )
{
int ret = -1;
size_t sum, n;
blake2s_state S[1];
static const size_t buffer_length = 32768;
uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
if( !buffer ) return -1;
blake2s_init( S, BLAKE2S_OUTBYTES );
while( 1 )
{
sum = 0;
while( 1 )
{
n = fread( buffer + sum, 1, buffer_length - sum, stream );
sum += n;
if( buffer_length == sum )
break;
if( 0 == n )
{
if( ferror( stream ) )
goto cleanup_buffer;
goto final_process;
}
if( feof( stream ) )
goto final_process;
}
blake2s_update( S, buffer, buffer_length );
}
final_process:;
if( sum > 0 ) blake2s_update( S, buffer, sum );
blake2s_final( S, resstream, BLAKE2S_OUTBYTES );
ret = 0;
cleanup_buffer:
free( buffer );
return ret;
}
int blake2b_stream( FILE *stream, void *resstream )
{
int ret = -1;
size_t sum, n;
blake2b_state S[1];
static const size_t buffer_length = 32768;
uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
if( !buffer ) return -1;
blake2b_init( S, BLAKE2B_OUTBYTES );
while( 1 )
{
sum = 0;
while( 1 )
{
n = fread( buffer + sum, 1, buffer_length - sum, stream );
sum += n;
if( buffer_length == sum )
break;
if( 0 == n )
{
if( ferror( stream ) )
goto cleanup_buffer;
goto final_process;
}
if( feof( stream ) )
goto final_process;
}
blake2b_update( S, buffer, buffer_length );
}
final_process:;
if( sum > 0 ) blake2b_update( S, buffer, sum );
blake2b_final( S, resstream, BLAKE2B_OUTBYTES );
ret = 0;
cleanup_buffer:
free( buffer );
return ret;
}
int blake2sp_stream( FILE *stream, void *resstream )
{
int ret = -1;
size_t sum, n;
blake2sp_state S[1];
static const size_t buffer_length = 16 * ( 1UL << 20 );
uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
if( !buffer ) return -1;
blake2sp_init( S, BLAKE2S_OUTBYTES );
while( 1 )
{
sum = 0;
while( 1 )
{
n = fread( buffer + sum, 1, buffer_length - sum, stream );
sum += n;
if( buffer_length == sum )
break;
if( 0 == n )
{
if( ferror( stream ) )
goto cleanup_buffer;
goto final_process;
}
if( feof( stream ) )
goto final_process;
}
blake2sp_update( S, buffer, buffer_length );
}
final_process:;
if( sum > 0 ) blake2sp_update( S, buffer, sum );
blake2sp_final( S, resstream, BLAKE2S_OUTBYTES );
ret = 0;
cleanup_buffer:
free( buffer );
return ret;
}
int blake2bp_stream( FILE *stream, void *resstream )
{
int ret = -1;
size_t sum, n;
blake2bp_state S[1];
static const size_t buffer_length = 16 * ( 1UL << 20 );
uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
if( !buffer ) return -1;
blake2bp_init( S, BLAKE2B_OUTBYTES );
while( 1 )
{
sum = 0;
while( 1 )
{
n = fread( buffer + sum, 1, buffer_length - sum, stream );
sum += n;
if( buffer_length == sum )
break;
if( 0 == n )
{
if( ferror( stream ) )
goto cleanup_buffer;
goto final_process;
}
if( feof( stream ) )
goto final_process;
}
blake2bp_update( S, buffer, buffer_length );
}
final_process:;
if( sum > 0 ) blake2bp_update( S, buffer, sum );
blake2bp_final( S, resstream, BLAKE2B_OUTBYTES );
ret = 0;
cleanup_buffer:
free( buffer );
return ret;
}
typedef int ( *blake2fn )( FILE *, void * );
static void usage( char **argv )
{
fprintf( stderr, "Usage: %s [-a HASH] [FILE]...\n", argv[0] );
fprintf( stderr, "\tHASH in blake2b blake2s blake2bp blake2sp\n" );
exit( 111 );
}
int main( int argc, char **argv )
{
blake2fn blake2_stream = blake2b_stream;
size_t outlen = BLAKE2B_OUTBYTES;
unsigned char hash[BLAKE2B_OUTBYTES] = {0};
int c;
opterr = 1;
if ( argc == 1 ) usage( argv ); /* show usage upon no-argument */
while( ( c = getopt( argc, argv, "a:" ) ) != -1 )
{
switch( c )
{
case 'a':
if( 0 == strcmp( optarg, "blake2b" ) )
{
blake2_stream = blake2b_stream;
outlen = BLAKE2B_OUTBYTES;
}
else if ( 0 == strcmp( optarg, "blake2s" ) )
{
blake2_stream = blake2s_stream;
outlen = BLAKE2S_OUTBYTES;
}
else if ( 0 == strcmp( optarg, "blake2bp" ) )
{
blake2_stream = blake2bp_stream;
outlen = BLAKE2B_OUTBYTES;
}
else if ( 0 == strcmp( optarg, "blake2sp" ) )
{
blake2_stream = blake2sp_stream;
outlen = BLAKE2S_OUTBYTES;
}
else
{
printf( "Invalid function name: `%s'\n", optarg );
usage( argv );
}
break;
}
}
for( int i = optind; i < argc; ++i )
{
FILE *f = NULL;
f = fopen( argv[i], "rb" );
if( !f )
{
fprintf( stderr, "Could not open `%s': %s\n", argv[i], strerror( errno ) );
goto end0;
}
if( blake2_stream( f, hash ) < 0 )
{
fprintf( stderr, "Failed to hash `%s'\n", argv[i] );
goto end1;
}
for( int j = 0; j < outlen; ++j )
printf( "%02x", hash[j] );
printf( " %s\n", argv[i] );
end1:
fclose( f );
end0: ;
}
return 0;
}

10
b2sum/makefile Normal file
View File

@ -0,0 +1,10 @@
CC=gcc
CFLAGS=-std=c99 -O3 -march=native -I../sse -static -fopenmp
LIBS=
#FILES=blake2sum.c ../ref/blake2b-ref.c ../ref/blake2s-ref.c ../ref/blake2bp-ref.c ../ref/blake2sp-ref.c
FILES=b2sum.c ../sse/blake2b.c ../sse/blake2s.c ../sse/blake2bp.c ../sse/blake2sp.c
all: $(FILES)
$(CC) $(FILES) $(CFLAGS) $(LIBS) -o b2sum
clean:
rm -f b2sum

20
bench/amd64cpuinfo.c Normal file
View File

@ -0,0 +1,20 @@
/*
BLAKE2 reference source code package - benchmark tool
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
unsigned long long cpucycles( void )
{
unsigned long long result;
asm volatile( ".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax"
: "=a" ( result ) :: "%rdx" );
return result;
}

68
bench/bench.c Normal file
View File

@ -0,0 +1,68 @@
/*
BLAKE2 reference source code package - benchmark tool
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int crypto_hash( unsigned char *out, const unsigned char *in, unsigned long long inlen );
static int bench_cmp( const void *x, const void *y )
{
const int64_t *ix = ( const int64_t * )x;
const int64_t *iy = ( const int64_t * )y;
return *ix - *iy;
}
unsigned long long cpucycles( void );
void bench()
{
#define BENCH_TRIALS 32
#define BENCH_MAXLEN 1536
static unsigned char in[4096];
static unsigned long long median[4096 + 1];
int i, j;
printf( "#bytes median per byte\n" );
/* 1 ... BENCH_MAXLEN */
for( j = 0; j <= 4096; ++j )
{
uint64_t cycles[BENCH_TRIALS + 1];
for( i = 0; i <= BENCH_TRIALS; ++i )
{
cycles[i] = cpucycles();
crypto_hash( in, in, j );
}
for( i = 0; i < BENCH_TRIALS; ++i )
cycles[i] = cycles[i + 1] - cycles[i];
qsort( cycles, BENCH_TRIALS, sizeof( uint64_t ), bench_cmp );
median[j] = cycles[BENCH_TRIALS / 2];
}
for( j = 0; j <= BENCH_MAXLEN; j += 8 )
printf( "%5d, %7.2f\n", j, ( double )median[j] / j );
printf( "#2048 %6llu %7.2f\n", median[2048], ( double )median[2048] / 2048.0 );
printf( "#4096 %6llu %7.2f\n", median[4096], ( double )median[4096] / 4096.0 );
printf( "#long long %7.2f\n", ( double )( median[4096] - median[2048] ) / 2048.0 );
}
int main()
{
bench();
return 0;
}

16
bench/do.gplot Normal file
View File

@ -0,0 +1,16 @@
maxx = 256
set xrange [1:maxx]
set xlabel "bytes "
set ylabel "cycles"
set xtics 0,32,maxx
set grid
set key left
plot "blake2b.data" using 1:2 with lines title "BLAKE2b"
replot "blake2s.data" using 1:2 with lines title "BLAKE2s"
replot "md5.data" using 1:2 with lines title "MD5"
#pause -1 "hit return to continue"
#set terminal png
#set output "plotcycles.png"
set terminal pdfcairo
set output "plotcycles.pdf"
replot

16
bench/makefile Normal file
View File

@ -0,0 +1,16 @@
CC=gcc
# std to gnu99 to support inline asm
CFLAGS=-std=gnu99 -O3 -march=native -DSUPERCOP # -DHAVE_XOP # uncomment on XOP-enabled CPUs
FILES=amd64cpuinfo.c bench.c
all:
$(CC) $(FILES) $(CFLAGS) ../sse/blake2b.c -o blake2b
$(CC) $(FILES) $(CFLAGS) ../sse/blake2s.c -o blake2s
$(CC) $(FILES) $(CFLAGS) md5.c -o md5 -lcrypto -lz
./blake2b > blake2b.data
./blake2s > blake2s.data
./md5 > md5.data
gnuplot do.gplot
clean:
rm -f blake2b blake2s md5 plotcycles.pdf blake2b.data blake2s.data md5.data

21
bench/md5.c Normal file
View File

@ -0,0 +1,21 @@
/*
BLAKE2 reference source code package - benchmark tool
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stddef.h>
#include <openssl/md5.h>
//#include "crypto_hash.h"
int crypto_hash( unsigned char *out, const unsigned char *in, unsigned long long inlen )
{
MD5( in, inlen, out );
return 0;
}

19
bench/x86cpuinfo.c Normal file
View File

@ -0,0 +1,19 @@
/*
BLAKE2 reference source code package - benchmark tool
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
unsigned long long cpucycles( void )
{
unsigned long long result;
asm volatile( ".byte 15;.byte 49" : "=A" ( result ) );
return result;
}

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{17466328-5736-4EA1-A88D-CE016CCA2E80}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Blake2Sharp.CompressionCodeGen</RootNamespace>
<AssemblyName>Blake2Sharp.CompressionCodeGen</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,93 @@

/// BLAKE2 reference source code package - C# implementation
/// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
/// To the extent possible under law, the author(s) have dedicated all copyright
/// and related and neighboring rights to this software to the public domain
/// worldwide. This software is distributed without any warranty.
/// You should have received a copy of the CC0 Public Domain Dedication along with
/// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Blake2Sharp.CompressionCodeGen
{
class Program
{
private const int NumberOfRounds = 12;
private static readonly int[] Sigma = new int[NumberOfRounds * 16] {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3
};
static void Round(int r)
{
Console.WriteLine("// ##### Round({0}) #####", r);
G(r, 0, 0, 4, 8, 12);
G(r, 1, 1, 5, 9, 13);
G(r, 2, 2, 6, 10, 14);
G(r, 3, 3, 7, 11, 15);
G(r, 4, 0, 5, 10, 15);
G(r, 5, 1, 6, 11, 12);
G(r, 6, 2, 7, 8, 13);
G(r, 7, 3, 4, 9, 14);
Console.WriteLine();
}
static void G(int r, int i, int a, int b, int c, int d)
{
int p = (r << 4) + 2 * i;
int p0 = Sigma[p];
int p1 = Sigma[p + 1];
string s = @"// G(r, i, a, b, c, d)
a = a + b + m[" + p0 + @"];
d ^= a;
d = " + RotateRight("d", 32) + @";
c = c + d;
b ^= c;
b = " + RotateRight("b", 24) + @";
a = a + b + m[" + p1 + @"];
d ^= a;
d = " + RotateRight("d", 16) + @";
c = c + d;
b ^= c;
b = " + RotateRight("b", 63) + @";";
s = s.Replace("a", "v" + a);
s = s.Replace("b", "v" + b);
s = s.Replace("c", "v" + c);
s = s.Replace("d", "v" + d);
s = s.Replace("r", r.ToString());
s = s.Replace("i", i.ToString());
s = s.Replace("\t", "");
Console.WriteLine(s);
Console.WriteLine();
}
static string RotateRight(string name, int offset)
{
return "((" + name + " >>" + offset + ")|(" + name + " << (64-" + offset + ")))";
}
static void Main(string[] args)
{
for (int r = 0; r < NumberOfRounds; r++)
Round(r);
}
}
}

View File

@ -0,0 +1,47 @@

/// BLAKE2 reference source code package - C# implementation
/// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
/// To the extent possible under law, the author(s) have dedicated all copyright
/// and related and neighboring rights to this software to the public domain
/// worldwide. This software is distributed without any warranty.
/// You should have received a copy of the CC0 Public Domain Dedication along with
/// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Blake2Sharp.CompressionCodeGen")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Blake2Sharp.CompressionCodeGen")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4af5636c-d52d-464f-a707-94464397988a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A32451B3-03A3-4CB3-AD9F-1408143D6AB7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Blake2Sharp.Tests</RootNamespace>
<AssemblyName>Blake2Sharp.Tests</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="DebugNodeHasher.cs" />
<Compile Include="SequentialTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestVectors.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Blake2Sharp\Blake2Sharp.csproj">
<Project>{e21ab364-9130-4f14-abe1-18fa0c089130}</Project>
<Name>Blake2Sharp</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,39 @@

/// BLAKE2 reference source code package - C# implementation
/// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
/// To the extent possible under law, the author(s) have dedicated all copyright
/// and related and neighboring rights to this software to the public domain
/// worldwide. This software is distributed without any warranty.
/// You should have received a copy of the CC0 Public Domain Dedication along with
/// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Blake2Sharp.Tests
{
/*class DebugNodeHasher : NodeHasher
{
StringBuilder data = new StringBuilder();
public override void Init(int depth, long nodeOffset)
{
data.AppendFormat("({0}-{1}", depth, nodeOffset);
}
public override byte[] Finish(bool isEndOfLayer)
{
data.Append(")");
return Encoding.ASCII.GetBytes(data.ToString());
}
public override void Update(byte[] data, int start, int count)
{
data.Append(Encoding.ASCII.GetString(data, start, count));
}
}*/
}

View File

@ -0,0 +1,47 @@

/// BLAKE2 reference source code package - C# implementation
/// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
/// To the extent possible under law, the author(s) have dedicated all copyright
/// and related and neighboring rights to this software to the public domain
/// worldwide. This software is distributed without any warranty.
/// You should have received a copy of the CC0 Public Domain Dedication along with
/// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Blake2Sharp.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Blake2Sharp.Tests")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4e74ef44-28bc-4b91-9ae9-355e132081ad")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,76 @@

/// BLAKE2 reference source code package - C# implementation
/// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
/// To the extent possible under law, the author(s) have dedicated all copyright
/// and related and neighboring rights to this software to the public domain
/// worldwide. This software is distributed without any warranty.
/// You should have received a copy of the CC0 Public Domain Dedication along with
/// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Blake2Sharp.Tests
{
[TestClass]
public class SequentialTests
{
byte[] input = Enumerable.Range(0, 256).Select(i => (byte)i).ToArray();
[TestMethod]
public void CheckTestVectors()
{
for (int len = 0; len < TestVectors.UnkeyedBlake2B.Length; len++)
{
var input = Enumerable.Range(0, len).Select(i => (byte)i).ToArray();
var hash = Blake2B.ComputeHash(input);
string actual = BitConverter.ToString(hash).Replace("-", "");
string expected = TestVectors.UnkeyedBlake2B[len];
Assert.AreEqual(expected, actual);
}
}
[TestMethod]
public void CheckKeyedTestVectors()
{
var key = Enumerable.Range(0, 64).Select(i => (byte)i).ToArray();
for (int len = 0; len < TestVectors.KeyedBlake2B.Length; len++)
{
var input = Enumerable.Range(0, len).Select(i => (byte)i).ToArray();
var hash = Blake2B.ComputeHash(input, new Blake2BConfig { Key = key });
string actual = BitConverter.ToString(hash).Replace("-", "");
string expected = TestVectors.KeyedBlake2B[len];
Assert.AreEqual(expected, actual);
}
}
[TestMethod]
public void Splits()
{
var hasher = Blake2B.Create();
for (int len = 0; len <= 256; len++)
{
hasher.Init();
hasher.Update(input, 0, len);
string hash0 = BitConverter.ToString(hasher.Finish());
for (int split1 = 0; split1 <= len; split1++)
{
for (int split2 = split1; split2 <= len; split2++)
{
hasher.Init();
hasher.Update(input, 0, split1);
hasher.Update(input, split1, split2 - split1);
hasher.Update(input, split2, len - split2);
string hash1 = BitConverter.ToString(hasher.Finish());
Assert.AreEqual(hash0, hash1);
}
}
}
}
}
}

View File

@ -0,0 +1,539 @@

/// BLAKE2 reference source code package - C# implementation
/// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
/// To the extent possible under law, the author(s) have dedicated all copyright
/// and related and neighboring rights to this software to the public domain
/// worldwide. This software is distributed without any warranty.
/// You should have received a copy of the CC0 Public Domain Dedication along with
/// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Blake2Sharp.Tests
{
internal static class TestVectors
{
public static string[] UnkeyedBlake2B = new string[]{
"786A02F742015903C6C6FD852552D272912F4740E15847618A86E217F71F5419D25E1031AFEE585313896444934EB04B903A685B1448B755D56F701AFE9BE2CE",
"2FA3F686DF876995167E7C2E5D74C4C7B6E48F8068FE0E44208344D480F7904C36963E44115FE3EB2A3AC8694C28BCB4F5A0F3276F2E79487D8219057A506E4B",
"1C08798DC641ABA9DEE435E22519A4729A09B2BFE0FF00EF2DCD8ED6F8A07D15EAF4AEE52BBF18AB5608A6190F70B90486C8A7D4873710B1115D3DEBBB4327B5",
"40A374727302D9A4769C17B5F409FF32F58AA24FF122D7603E4FDA1509E919D4107A52C57570A6D94E50967AEA573B11F86F473F537565C66F7039830A85D186",
"77DDF4B14425EB3D053C1E84E3469D92C4CD910ED20F92035E0C99D8A7A86CECAF69F9663C20A7AA230BC82F60D22FB4A00B09D3EB8FC65EF547FE63C8D3DDCE",
"CBAA0BA7D482B1F301109AE41051991A3289BC1198005AF226C5E4F103B66579F461361044C8BA3439FF12C515FB29C52161B7EB9C2837B76A5DC33F7CB2E2E8",
"F95D45CF69AF5C2023BDB505821E62E85D7CAEDF7BEDA12C0248775B0C88205EEB35AF3A90816F6608CE7DD44EC28DB1140614E1DDEBF3AA9CD1843E0FAD2C36",
"8F945BA700F2530E5C2A7DF7D5DCE0F83F9EFC78C073FE71AE1F88204A4FD1CF70A073F5D1F942ED623AA16E90A871246C90C45B621B3401A5DDBD9DF6264165",
"E998E0DC03EC30EB99BB6BFAAF6618ACC620320D7220B3AF2B23D112D8E9CB1262F3C0D60D183B1EE7F096D12DAE42C958418600214D04F5ED6F5E718BE35566",
"6A9A090C61B3410AEDE7EC9138146CEB2C69662F460C3DA53C6515C1EB31F41CA3D280E567882F95CF664A94147D78F42CFC714A40D22EF19470E053493508A2",
"29102511D749DB3CC9B4E335FA1F5E8FACA8421D558F6A3F3321D50D044A248BA595CFC3EFD3D2ADC97334DA732413F5CBF4751C362BA1D53862AC1E8DABEEE8",
"C97A4779D47E6F77729B5917D0138ABB35980AB641BD73A8859EB1AC98C05362ED7D608F2E9587D6BA9E271D343125D40D933A8ED04EC1FE75EC407C7A53C34E",
"10F0DC91B9F845FB95FAD6860E6CE1ADFA002C7FC327116D44D047CD7D5870D772BB12B5FAC00E02B08AC2A0174D0446C36AB35F14CA31894CD61C78C849B48A",
"DEA9101CAC62B8F6A3C650F90EEA5BFAE2653A4EAFD63A6D1F0F132DB9E4F2B1B662432EC85B17BCAC41E775637881F6AAB38DD66DCBD080F0990A7A6E9854FE",
"441FFAA08CD79DFF4AFC9B9E5B5620EEC086730C25F661B1D6FBFBD1CEC3148DD72258C65641F2FCA5EB155FADBCABB13C6E21DC11FAF72C2A281B7D56145F19",
"444B240FE3ED86D0E2EF4CE7D851EDDE22155582AA0914797B726CD058B6F45932E0E129516876527B1DD88FC66D7119F4AB3BED93A61A0E2D2D2AEAC336D958",
"BFBABBEF45554CCFA0DC83752A19CC35D5920956B301D558D772282BC867009168E9E98606BB5BA73A385DE5749228C925A85019B71F72FE29B3CD37CA52EFE6",
"9C4D0C3E1CDBBF485BEC86F41CEC7C98373F0E09F392849AAA229EBFBF397B22085529CB7EF39F9C7C2222A514182B1EFFAA178CC3687B1B2B6CBCB6FDEB96F8",
"477176B3BFCBADD7657C23C24625E4D0D674D1868F006006398AF97AA41877C8E70D3D14C3BBC9BBCDCEA801BD0E1599AF1F3EEC67405170F4E26C964A57A8B7",
"A78C490EDA3173BB3F10DEE52F110FB1C08E0302230B85DDD7C11257D92DE148785EF00C039C0BB8EB9808A35B2D8C080F572859714C9D4069C5BCAF090E898E",
"58D023397BEB5B4145CB2255B07D74290B36D9FD1E594AFBD8EEA47C205B2EFBFE6F46190FAF95AF504AB072E36F6C85D767A321BFD7F22687A4ABBF494A689C",
"4001EC74D5A46FD29C2C3CDBE5D1B9F20E51A941BE98D2A4E1E2FBF866A672121DB6F81A514CFD10E7358D571BDBA48E4CE708B9D124894BC0B5ED554935F73A",
"CCD1B22DAB6511225D2401EA2D8625D206A12473CC732B615E5640CEFFF0A4ADF971B0E827A619E0A80F5DB9CCD0962329010D07E34A2064E731C520817B2183",
"B4A0A9E3574EDB9E1E72AA31E39CC5F30DBF943F8CABC408449654A39131E66D718A18819143E3EA96B4A1895988A1C0056CF2B6E04F9AC19D657383C2910C44",
"447BECAB16630608D39F4F058B16F7AF95B85A76AA0FA7CEA2B80755FB76E9C804F2CA78F02643C915FBF2FCE5E19DE86000DE03B18861815A83126071F8A37B",
"54E6DAB9977380A5665822DB93374EDA528D9BEB626F9B94027071CB26675E112B4A7FEC941EE60A81E4D2EA3FF7BC52CFC45DFBFE735A1C646B2CF6D6A49B62",
"3EA62625949E3646704D7E3C906F82F6C028F540F5F72A794B0C57BF97B7649BFEB90B01D3CA3E829DE21B3826E6F87014D3C77350CB5A15FF5D468A81BEC160",
"213CFE145C54A33691569980E5938C8883A46D84D149C8FF1A67CD287B4D49C6DA69D3A035443DB085983D0EFE63706BD5B6F15A7DA459E8D50A19093DB55E80",
"5716C4A38F38DB104E494A0A27CBE89A26A6BB6F499EC01C8C01AA7CB88497E75148CD6EEE12A7168B6F78AB74E4BE749251A1A74C38C86D6129177E2889E0B6",
"030460A98BDF9FF17CD96404F28FC304F2B7C04EAADE53677FD28F788CA22186B8BC80DD21D17F8549C711AFF0E514E19D4E15F5990252A03E082F28DC2052F6",
"19E7F1CCEE88A10672333E390CF22013A8C734C6CB9EAB41F17C3C8032A2E4ACA0569EA36F0860C7A1AF28FA476840D66011168859334A9E4EF9CC2E61A0E29E",
"29F8B8C78C80F2FCB4BDF7825ED90A70D625FF785D262677E250C04F3720C888D03F8045E4EDF3F5285BD39D928A10A7D0A5DF00B8484AC2868142A1E8BEA351",
"5C52920A7263E39D57920CA0CB752AC6D79A04FEF8A7A216A1ECB7115CE06D89FD7D735BD6F4272555DBA22C2D1C96E6352322C62C5630FDE0F4777A76C3DE2C",
"83B098F262251BF660064A9D3511CE7687A09E6DFBB878299C30E93DFB43A9314DB9A600337DB26EBEEDAF2256A96DABE9B29E7573AD11C3523D874DDE5BE7ED",
"9447D98AA5C9331352F43D3E56D0A9A9F9581865998E2885CC56DD0A0BD5A7B50595BD10F7529BCD31F37DC16A1465D594079667DA2A3FCB70401498837CEDEB",
"867732F2FEEB23893097561AC710A4BFF453BE9CFBEDBA8BA324F9D312A82D732E1B83B829FDCD177B882CA0C1BF544B223BE529924A246A63CF059BFDC50A1B",
"F15AB26D4CDFCF56E196BB6BA170A8FCCC414DE9285AFD98A3D3CF2FB88FCBC0F19832AC433A5B2CC2392A4CE34332987D8D2C2BEF6C3466138DB0C6E42FA47B",
"2813516D68ED4A08B39D648AA6AACD81E9D655ECD5F0C13556C60FDF0D333EA38464B36C02BACCD746E9575E96C63014F074AE34A0A25B320F0FBEDD6ACF7665",
"D3259AFCA8A48962FA892E145ACF547F26923AE8D4924C8A531581526B04B44C7AF83C643EF5A0BC282D36F3FB04C84E28B351F40C74B69DC7840BC717B6F15F",
"F14B061AE359FA31B989E30332BFE8DE8CC8CDB568E14BE214A2223B84CAAB7419549ECFCC96CE2ACEC119485D87D157D3A8734FC426597D64F36570CEAF224D",
"55E70B01D1FBF8B23B57FB62E26C2CE54F13F8FA2464E6EB98D16A6117026D8B90819012496D4071EBE2E59557ECE3519A7AA45802F9615374877332B73490B3",
"25261EB296971D6E4A71B2928E64839C67D422872BF9F3C31993615222DE9F8F0B2C4BE8548559B4B354E736416E3218D4E8A1E219A4A6D43E1A9A521D0E75FC",
"08307F347C41294E34BB54CB42B1522D22F824F7B6E5DB50FDA096798E181A8F026FA27B4AE45D52A62CAF9D5198E24A4913C6671775B2D723C1239BFBF016D7",
"1E5C62E7E9BFA1B118747A2DE08B3CA10112AF96A46E4B22C3FC06F9BFEE4EB5C49E057A4A4886234324572576BB9B5ECFDE0D99B0DE4F98EC16E4D1B85FA947",
"C74A77395FB8BC126447454838E561E962853DC7EB49A1E3CB67C3D0851F3E39517BE8C350AC910903D49CD2BFDF545C99316D0346170B739F0ADD5D533C2CFC",
"0DD57B423CC01EB2861391EB886A0D17079B933FC76EB3FC08A19F8A74952CB68F6BCDC644F77370966E4D13E80560BCF082EF0479D48FBBAB4DF03B53A4E178",
"4D8DC3923EDCCDFCE70072398B8A3DA5C31FCB3EE3B645C85F717CBAEB4B673A19394425A585BFB464D92F1597D0B754D163F97CED343B25DB5A70EF48EBB34F",
"F0A50553E4DFB0C4E3E3D3BA82034857E3B1E50918F5B8A7D698E10D242B0FB544AF6C92D0C3AAF9932220416117B4E78ECB8A8F430E13B82A5915290A5819C5",
"B15543F3F736086627CC5365E7E8988C2EF155C0FD4F428961B00D1526F04D6D6A658B4B8ED32C5D8621E7F4F8E8A933D9ECC9DD1B8333CBE28CFC37D9719E1C",
"7B4FA158E415FEF023247264CBBE15D16D91A44424A8DB707EB1E2033C30E9E1E7C8C0864595D2CB8C580EB47E9D16ABBD7E44E824F7CEDB7DEF57130E52CFE9",
"60424FF23234C34DC9687AD502869372CC31A59380186BC2361C835D972F49666EB1AC69629DE646F03F9B4DB9E2ACE093FBFDF8F20AB5F98541978BE8EF549F",
"7406018CE704D84F5EB9C79FEA97DA345699468A350EE0B2D0F3A4BF2070304EA862D72A51C57D3064947286F531E0EAF7563702262E6C724ABF5ED8C8398D17",
"14EF5C6D647B3BD1E6E32006C231199810DE5C4DC88E70240273B0EA18E651A3EB4F5CA3114B8A56716969C7CDA27E0C8DB832AD5E89A2DC6CB0ADBE7D93ABD1",
"38CF6C24E3E08BCF1F6CF3D1B1F65B905239A3118033249E448113EC632EA6DC346FEEB2571C38BD9A7398B2221280328002B23E1A45ADAFFE66D93F6564EAA2",
"6CD7208A4BC7E7E56201BBBA02A0F489CD384ABE40AFD4222F158B3D986EE72A54C50FB64FD4ED2530EDA2C8AF2928A0DA6D4F830AE1C9DB469DFD970F12A56F",
"659858F0B5C9EDAB5B94FD732F6E6B17C51CC096104F09BEB3AFC3AA467C2ECF885C4C6541EFFA9023D3B5738AE5A14D867E15DB06FE1F9D1127B77E1AABB516",
"26CCA0126F5D1A813C62E5C71001C046F9C92095704550BE5873A495A999AD010A4F79491F24F286500ADCE1A137BC2084E4949F5B7294CEFE51ECAFF8E95CBA",
"4147C1F55172788C5567C561FEEF876F621FFF1CE87786B8467637E70DFBCD0DBDB6415CB600954AB9C04C0E457E625B407222C0FE1AE21B2143688ADA94DC58",
"5B1BF154C62A8AF6E93D35F18F7F90ABB16A6EF0E8D1AECD118BF70167BAB2AF08935C6FDC0663CE74482D17A8E54B546D1C296631C65F3B522A515839D43D71",
"9F600419A4E8F4FB834C24B0F7FC13BF4E279D98E8A3C765EE934917403E3A66097182EA21453CB63EBBE8B73A9C2167596446438C57627F330BADD4F569F7D6",
"457EF6466A8924FD8011A34471A5A1AC8CCD9BD0D07A97414AC943021CE4B9E4B9C8DB0A28F016ED43B1542481990022147B313E194671131E708DD43A3ED7DC",
"9997B2194D9AF6DFCB9143F41C0ED83D3A3F4388361103D38C2A49B280A581212715FD908D41C651F5C715CA38C0CE2830A37E00E508CED1BCDC320E5E4D1E2E",
"5C6BBF16BAA180F986BD40A1287ED4C549770E7284858FC47BC21AB95EBBF3374B4EE3FD9F2AF60F3395221B2ACC76F2D34C132954049F8A3A996F1E32EC84E5",
"D10BF9A15B1C9FC8D41F89BB140BF0BE08D2F3666176D13BAAC4D381358AD074C9D4748C300520EB026DAEAEA7C5B158892FDE4E8EC17DC998DCD507DF26EB63",
"2FC6E69FA26A89A5ED269092CB9B2A449A4409A7A44011EECAD13D7C4B0456602D402FA5844F1A7A758136CE3D5D8D0E8B86921FFFF4F692DD95BDC8E5FF0052",
"FCBE8BE7DCB49A32DBDF239459E26308B84DFF1EA480DF8D104EEFF34B46FAE98627B450C2267D48C0946A697C5B59531452AC0484F1C84E3A33D0C339BB2E28",
"A19093A6E3BCF5952F850F2030F69B9606F147F90B8BAEE3362DA71D9F35B44EF9D8F0A7712BA1877FDDCD2D8EA8F1E5A773D0B745D4725605983A2DE901F803",
"3C2006423F73E268FA59D2920377EB29A4F9A8B462BE15983EE3B85AE8A78E992633581A9099893B63DB30241C34F643027DC878279AF5850D7E2D4A2653073A",
"D0F2F2E3787653F77CCE2FA24835785BBD0C433FC779465A115149905A9DD1CB827A628506D457FCF124A0C2AEF9CE2D2A0A0F63545570D8667FF9E2EBA07334",
"78A9FC048E25C6DCB5DE45667DE8FFDD3A93711141D594E9FA62A959475DA6075EA8F0916E84E45AD911B75467077EE52D2C9AEBF4D58F20CE4A3A00458B05D4",
"45813F441769AB6ED37D349FF6E72267D76AE6BB3E3C612EC05C6E02A12AF5A37C918B52BF74267C3F6A3F183A8064FF84C07B193D08066789A01ACCDB6F9340",
"956DA1C68D83A7B881E01B9A966C3C0BF27F68606A8B71D457BD016D4C41DD8A380C709A296CB4C6544792920FD788835771A07D4A16FB52ED48050331DC4C8B",
"DF186C2DC09CAA48E14E942F75DE5AC1B7A21E4F9F072A5B371E09E07345B0740C76177B01278808FEC025EDED9822C122AFD1C63E6F0CE2E32631041063145C",
"87475640966A9FDCD6D3A3B5A2CCA5C08F0D882B10243C0EC1BF3C6B1C37F2CD3212F19A057864477D5EAF8FAED73F2937C768A0AF415E84BBCE6BD7DE23B660",
"C3B573BBE10949A0FBD4FF884C446F2229B76902F9DFDBB8A0353DA5C83CA14E8151BBAAC82FD1576A009ADC6F1935CF26EDD4F1FB8DA483E6C5CD9D8923ADC3",
"B09D8D0BBA8A7286E43568F7907550E42036D674E3C8FC34D8CA46F771D6466B70FB605875F6A863C877D12F07063FDC2E90CCD459B1910DCD52D8F10B2B0A15",
"AF3A22BF75B21ABFB0ACD54422BA1B7300A952EFF02EBEB65B5C234471A98DF32F4F9643CE1904108A168767924280BD76C83F8C82D9A79D9259B195362A2A04",
"BF4FF2221B7E6957A724CD964AA3D5D0D9941F540413752F4699D8101B3E537508BF09F8508B317736FFD265F2847AA7D84BD2D97569C49D632AED9945E5FA5E",
"9C6B6B78199B1BDACB4300E31479FA622A6B5BC80D4678A6078F88A8268CD7206A2799E8D4621A464EF6B43DD8ADFFE97CAF221B22B6B8778B149A822AEFBB09",
"890656F09C99D280B5ECB381F56427B813751BC652C7828078B23A4AF83B4E3A61FDBAC61F89BEE84EA6BEE760C047F25C6B0A201C69A38FD6FD971AF18588BB",
"31A046F7882FFE6F83CE472E9A0701832EC7B3F76FBCFD1DF60FE3EA48FDE1651254247C3FD95E100F9172731E17FD5297C11F4BB328363CA361624A81AF797C",
"27A60B2D00E7A671D47D0AEC2A686A0AC04B52F40AB6629028EB7D13F4BAA99AC0FE46EE6C814944F2F4B4D20E9378E4847EA44C13178091E277B87EA7A55711",
"8B5CCEF194162C1F19D68F91E0B0928F289EC5283720840C2F73D253111238DCFE94AF2B59C2C1CA2591901A7BC060E7459B6C47DF0F71701A35CC0AA831B5B6",
"57AB6C4B2229AEB3B70476D803CD63812F107CE6DA17FED9B17875E8F86C724F49E024CBF3A1B8B119C50357652B81879D2ADE2D588B9E4F7CEDBA0E4644C9EE",
"0190A8DAC320A739F322E15731AA140DDAF5BED294D5C82E54FEF29F214E18AAFAA84F8BE99AF62950266B8F901F15DD4C5D35516FC35B4CAB2E96E4695BBE1C",
"D14D7C4C415EEB0E10B159224BEA127EBD84F9591C702A330F5BB7BB7AA44EA39DE6ED01F18DA7ADF40CFB97C5D152C27528824B21E239526AF8F36B214E0CFB",
"BE28C4BE706970488FAC7D29C3BD5C4E986085C4C3332F1F3FD30973DB614164BA2F31A78875FFDC150325C88327A9443ED04FDFE5BE93876D1628560C764A80",
"031DA1069E3A2E9C3382E436FFD79DF74B1CA6A8ADB2DEABE676AB45994CBC054F037D2F0EACE858D32C14E2D1C8B46077308E3BDC2C1B53172ECF7A8C14E349",
"4665CEF8BA4DB4D0ACB118F2987F0BB09F8F86AA445AA3D5FC9A8B346864787489E8FCECC125D17E9B56E12988EAC5ECC7286883DB0661B8FF05DA2AFFF30FE4",
"63B7032E5F930CC9939517F9E986816CFBEC2BE59B9568B13F2EAD05BAE7777CAB620C6659404F7409E4199A3BE5F7865AA7CBDF8C4253F7E8219B1BD5F46FEA",
"9F09BF093A2B0FF8C2634B49E37F1B2135B447AA9144C9787DBFD92129316C99E88AAB8A21FDEF2372D1189AEC500F95775F1F92BFB45545E4259FB9B7B02D14",
"F9F8493C68088807DF7F6A2693D64EA59F03E9E05A223E68524CA32195A4734B654FCEA4D2734C866CF95C889FB10C49159BE2F5043DC98BB55E02EF7BDCB082",
"3C9A7359AB4FEBCE07B20AC447B06A240B7FE1DAE5439C49B60B5819F7812E4C172406C1AAC316713CF0DDED1038077258E2EFF5B33913D9D95CAEB4E6C6B970",
"AD6AAB8084510E822CFCE8625D62CF4DE655F4763884C71E80BAB9AC9D5318DBA4A6033ED29084E65216C031606CA17615DCFE3BA11D26851AE0999CA6E232CF",
"156E9E6261374C9DC884F36E70F0FE1AB9297997B836FA7D170A9C9EBF575B881E7BCEA44D6C0248D35597907154828955BE19135852F9228815ECA024A8ADFB",
"4215407633F4CCA9B6788BE93E6AA3D963C7D6CE4B147247099F46A3ACB500A30038CB3E788C3D29F132AD844E80E9E99251F6DB96ACD8A091CFC770AF53847B",
"1C077E279DE6548523502B6DF800FFDAB5E2C3E9442EB838F58C295F3B147CEF9D701C41C321283F00C71AFFA0619310399126295B78DD4D1A74572EF9ED5135",
"F07A555F49FE481CF4CD0A87B71B82E4A95064D06677FDD90A0EB598877BA1C83D4677B393C3A3B6661C421F5B12CB99D20376BA7275C2F3A8F5A9B7821720DA",
"B5911B380D20C7B04323E4026B38E200F534259233B581E02C1E3E2D8438D6C66D5A4EB201D5A8B75072C4EC29106334DA70BC79521B0CED2CFD533F5FF84F95",
"01F070A09BAE911296361F91AA0E8E0D09A7725478536D9D48C5FE1E5E7C3C5B9B9D6EB07796F6DA57AE562A7D70E882E37ADFDE83F0C433C2CD363536BB22C8",
"6F793EB4374A48B0775ACAF9ADCF8E45E54270C9475F004AD8D5973E2ACA52747FF4ED04AE967275B9F9EB0E1FF75FB4F794FA8BE9ADD7A41304868D103FAB10",
"965F20F139765FCC4CE4BA3794675863CAC24DB472CD2B799D035BCE3DBEA502DA7B524865F6B811D8C5828D3A889646FE64A380DA1AA7C7044E9F245DCED128",
"EC295B5783601244C30E4641E3B45BE222C4DCE77A58700F53BC8EC52A941690B4D0B087FB6FCB3F39832B9DE8F75EC20BD43079811749CDC907EDB94157D180",
"61C72F8CCC91DBB54CA6750BC489672DE09FAEDB8FDD4F94FF2320909A303F5D5A98481C0BC1A625419FB4DEBFBF7F8A53BB07EC3D985E8EA11E72D559940780",
"AFD8145B259EEFC8D12620C3C5B03E1ED8FD2CCEFE0365078C80FD42C1770E28B44948F27E65A1886690110DB814397B68E43D80D1BA16DFA358E739C898CFA3",
"552FC7893CF1CE933ADA35C0DA98844E41545E244C3157A1428D7B4C21F9CD7E4071AED77B7CA9F1C38FBA32237412EF21A342742EC8324378F21E507FAFDD88",
"467A33FBADF5EBC52596EF86AAAEFC6FABA8EE651B1CE04DE368A03A5A9040EF2835E00ADB09ABB3FBD2BCE818A2413D0B0253B5BDA4FC5B2F6F85F3FD5B55F2",
"22EFF8E6DD5236F5F57D94EDE874D6C9428E8F5D566F17CD6D1848CD752FE13C655CB10FBAAFF76872F2BF2DA99E15DC624075E1EC2F58A3F64072121838569E",
"9CEC6BBF62C4BCE4138ABAE1CBEC8DAD31950444E90321B1347196834C114B864AF3F3CC3508F83751FFB4EDA7C84D140734BB4263C3625C00F04F4C8068981B",
"A8B60FA4FC2442F6F1514AD7402626920CC7C2C9F72124B8CBA8EE2CB7C4586F658A4410CFFCC0AB88343955E094C6AF0D20D0C714FB0A988F543F300F58D389",
"8271CC45DFA5E4170E847E8630B952CF9C2AA777D06F26A7585B8381F188DACC7337391CFCC94B053DC4EC29CC17F077870428F1AC23FDDDA165EF5A3F155F39",
"BF23C0C25C8060E4F6995F1623A3BEBECAA96E308680000A8AA3CD56BB1A6DA099E10D9231B37F4519B2EFD2C24DE72F31A5F19535241B4A59FA3C03CEB790E7",
"877FD652C05281009C0A5250E7A3A671F8B18C108817FE4A874DE22DA8E45DB11958A600C5F62E67D36CBF84474CF244A9C2B03A9FB9DC711CD1A2CAB6F3FAE0",
"29DF4D87EA444BAF5BCDF5F4E41579E28A67DE84149F06C03F110EA84F572A9F676ADDD04C4878F49C5C00ACCDA441B1A387CACEB2E993BB7A10CD8C2D6717E1",
"710DACB166844639CD7B637C274209424E2449DC35D790BBFA4F76177054A36B3B76FAC0CA6E61DF1E687000678AC0746DF75D0A3954897681FD393A155A1BB4",
"C1D5F93B8DEA1F2571BABCCBC01764541A0CDA87E444D673C50966CA559C33354B3ACB26E5D5781FFB28847A4B4754D77008C62A835835F500DEA7C3B58BDAE2",
"A41E41271CDAB8AF4D72B104BFB2AD041AC4DF14677DA671D85640C4B187F50C2B66513C4619FBD5D5DC4FE65DD37B9042E9848DDA556A504CAA2B1C6AFE4730",
"E7BCBACDC379C43D81EBADCB37781552FC1D753E8CF310D968392D06C91F1D64CC9E90CE1D22C32D277FC6CDA433A4D442C762E9EACF2C259F32D64CF9DA3A22",
"51755B4AC5456B13218A19C5B9242F57C4A981E4D4ECDCE09A3193362B808A579345D4881C2607A56534DD7F21956AFF72C2F4173A6E7B6CC2212BA0E3DAEE1F",
"DCC2C4BEB9C1F2607B786C20C631972347034C1CC02FCC7D02FF01099CFE1C6989840AC213923629113AA8BAD713CCF0FE4CE13264FB32B8B0FE372DA382544A",
"3D55176ACEA4A7E3A65FFA9FB10A7A1767199CF077CEE9F71532D67CD7C73C9F93CFC37CCDCC1FDEF50AAD46A504A650D298D597A3A9FA95C6C40CB71FA5E725",
"D07713C005DE96DD21D2EB8BBECA66746EA51A31AE922A3E74864889540A48DB27D7E4C90311638B224BF0201B501891754848113C266108D0ADB13DB71909C7",
"58983C21433D950CAA23E4BC18543B8E601C204318532152DAF5E159A0CD1480183D29285C05F129CB0CC3164687928086FFE380158DF1D394C6AC0D4288BCA8",
"8100A8DC528D2B682AB4250801BA33F02A3E94C54DAC0AE1482AA21F51EF3A82F3807E6FACB0AEB05947BF7AA2ADCB034356F90FA4560EDE02201A37E411EC1A",
"07025F1BB6C784F3FE49DE5C14B936A5ACACACAAB33F6AC4D0E00AB6A12483D6BEC00B4FE67C7CA5CC508C2A53EFB5BFA5398769D843FF0D9E8B14D36A01A77F",
"BA6AEFD972B6186E027A76273A4A723321A3F580CFA894DA5A9CE8E721C828552C64DACEE3A7FD2D743B5C35AD0C8EFA71F8CE99BF96334710E2C2346E8F3C52",
"E0721E02517AEDFA4E7E9BA503E025FD46E714566DC889A84CBFE56A55DFBE2FC4938AC4120588335DEAC8EF3FA229ADC9647F54AD2E3472234F9B34EFC46543",
"B6292669CCD38D5F01CAAE96BA272C76A879A45743AFA0725D83B9EBB26665B731F1848C52F11972B6644F554C064FA90780DBBBF3A89D4FC31F67DF3E5857EF",
"2319E3789C47E2DAA5FE807F61BEC2A1A6537FA03F19FF32E87EECBFD64B7E0E8CCFF439AC333B040F19B0C4DDD11A61E24AC1FE0F10A039806C5DCC0DA3D115",
"F59711D44A031D5F97A9413C065D1E614C417EDE998590325F49BAD2FD444D3E4418BE19AEC4E11449AC1A57207898BC57D76A1BCF3566292C20C683A5C4648F",
"DF0A9D0C212843A6A934E3902B2DD30D17FBA5F969D2030B12A546D8A6A45E80CF5635F071F0452E9C919275DA99BED51EB1173C1AF0518726B75B0EC3BAE2B5",
"A3EB6E6C7BF2FB8B28BFE8B15E15BB500F781ECC86F778C3A4E655FC5869BF2846A245D4E33B7B14436A17E63BE79B36655C226A50FFBC7124207B0202342DB5",
"56D4CBCD070563426A017069425C2CD2AE540668287A5FB9DAC432EB8AB1A353A30F2FE1F40D83333AFE696A267795408A92FE7DA07A0C1814CF77F36E105EE8",
"E59B9987D428B3EDA37D80ABDB16CD2B0AEF674C2B1DDA4432EA91EE6C935C684B48B4428A8CC740E579A30DEFF35A803013820DD23F14AE1D8413B5C8672AEC",
"CD9FCC99F99D4CC16D031900B2A736E1508DB4B586814E6345857F354A70CCECB1DF3B50A19ADAF43C278EFA423FF4BB6C523EC7FD7859B97B168A7EBFF8467C",
"0602185D8C3A78738B99164B8BC6FFB21C7DEBEBBF806372E0DA44D121545597B9C662A255DC31542CF995ECBE6A50FB5E6E0EE4EF240FE557EDED1188087E86",
"C08AFA5B927BF08097AFC5FFF9CA4E7800125C1F52F2AF3553FA2B89E1E3015C4F87D5E0A48956AD31450B083DAD147FFB5EC03434A26830CF37D103AB50C5DA",
"36F1E1C11D6EF6BC3B536D505D544A871522C5C2A253067EC9933B6EC25464DAF985525F5B9560A16D890259AC1BB5CC67C0C469CDE133DEF000EA1D686F4F5D",
"BF2AB2E2470F5438C3B689E66E7686FFFA0CB1E1798AD3A86FF99075BF6138E33D9C0CE59AFB24AC67A02AF34428191A9A0A6041C07471B7C3B1A752D6FC0B8B",
"D400601F9728CCC4C92342D9787D8D28AB323AF375CA5624B4BB91D17271FBAE862E413BE73F1F68E615B8C5C391BE0DBD9144746EB339AD541547BA9C468A17",
"79FE2FE157EB85A038ABB8EBBC647731D2C83F51B0AC6EE14AA284CB6A3549A4DCCEB300740A825F52F5FB30B03B8C4D8B0F4AA67A63F4A94E3303C4EDA4C02B",
"75351313B52A8529298D8C186B1768666DCCA8595317D7A4816EB88C062020C0C8EFC554BB341B64688DB5CCAFC35F3C3CD09D6564B36D7B04A248E146980D4B",
"E3128B1D311D02179D7F25F97A5A8BEE2CC8C86303644FCD664E157D1FEF00F23E46F9A5E8E5C890CE565BB6ABD4302CE06469D52A5BD53E1C5A54D04649DC03",
"C2382A72D2D3ACE9D5933D00B60827ED380CDA08D0BA5F6DD41E29EE6DBE8ECB9235F06BE95D83B6816A2FB7A5AD47035E8A4B69A4884B99E4BECE58CAB25D44",
"6B1C69460BBD50AC2ED6F32E6E887CFED407D47DCF0AAA60387FE320D780BD03EAB6D7BAEB2A07D10CD552A300341354EA9A5F03183A623F92A2D4D9F00926AF",
"6CDA206C80CDC9C44BA990E0328C314F819B142D00630404C48C05DC76D1B00CE4D72FC6A48E1469DDEF609412C364820854214B4869AF090F00D3C1BA443E1B",
"7FFC8C26FBD6A0F7A609E6E1939F6A9EDF1B0B066641FB76C4F9602ED748D11602496B35355B1AA255850A509D2F8EE18C8F3E1D7DCBC37A136598F56A59ED17",
"70DE1F08DD4E09D5FC151F17FC991A23ABFC05104290D50468882EFAF582B6EC2F14F577C0D68C3AD06626916E3C86E6DAAB6C53E5163E82B6BD0CE49FC0D8DF",
"4F81935756ED35EE2058EE0C6A6110D6FAC5CB6A4F46AA9411603F99965823B6DA4838276C5C06BC7880E376D92758369EE7305BCEC8D3CFD28CCABB7B4F0579",
"ABCB61CB3683D18F27AD527908ED2D32A0426CB7BB4BF18061903A7DC42E7E76F982382304D18AF8C80D91DD58DD47AF76F8E2C36E28AF2476B4BCCF82E89FDF",
"02D261AD56A526331B643DD2186DE9A82E72A58223CD1E723686C53D869B83B94632B7B647AB2AFC0D522E29DA3A5615B741D82852E0DF41B66007DBCBA90543",
"C5832741FA30C5436823015383D297FF4C4A5D7276C3F902122066E04BE5431B1A85FAF73B918434F9300963D1DEA9E8AC3924EF490226EDEEA5F743E410669F",
"CFAEAB268CD075A5A6AED515023A032D54F2F2FF733CE0CBC78DB51DB4504D675923F82746D6594606AD5D67734B11A67CC6A468C2032E43CA1A94C6273A985E",
"860850F92EB268272B67D133609BD64E34F61BF03F4C1738645C17FEC818465D7ECD2BE2907641130025FDA79470AB731646E7F69440E8367EA76AC4CEE8A1DF",
"84B154ED29BBEDEFA648286839046F4B5AA34430E2D67F7496E4C39F2C7EA78995F69E1292200016F16AC3B37700E6C7E7861AFC396B64A59A1DBF47A55C4BBC",
"AEEEC260A5D8EFF5CCAB8B95DA435A63ED7A21EA7FC7559413FD617E33609F8C290E64BBACC528F6C080262288B0F0A3219BE223C991BEE92E72349593E67638",
"8AD78A9F26601D127E8D2F2F976E63D19A054A17DCF59E0F013AB54A6887BBDFFDE7AAAE117E0FBF3271016595B9D9C712C01B2C53E9655A382BC4522E616645",
"8934159DADE1AC74147DFA282C75954FCEF443EF25F80DFE9FB6EA633B8545111D08B34EF43FFF17026C7964F5DEAC6D2B3C29DACF2747F022DF5967DFDC1A0A",
"CD36DD0B240614CF2FA2B9E959679DCDD72EC0CD58A43DA3790A92F6CDEB9E1E795E478A0A47D371100D340C5CEDCDBBC9E68B3F460818E5BDFF7B4CDA4C2744",
"00DF4E099B807137A85990F49D3A94315E5A5F7F7A6076B303E96B056FB93800111F479628E2F8DB59AEB6AC70C3B61F51F9B46E80FFDEAE25EBDDB4AF6CB4EE",
"2B9C955E6CAED4B7C9E246B86F9A1726E810C59D126CEE66ED71BF015B83558A4B6D84D18DC3FF4620C2FFB722359FDEF85BA0D4E2D22ECBE0ED784F99AFE587",
"181DF0A261A2F7D29EA5A15772715105D450A4B6C236F699F462D60CA76487FEEDFC9F5EB92DF838E8FB5DC3694E84C5E0F4A10B761F506762BE052C745A6EE8",
"21FB203458BF3A7E9A80439F9A902899CD5DE0139DFD56F7110C9DEC8437B26BDA63DE2F565926D85EDB1D6C6825669743DD9992653D13979544D5DC8228BFAA",
"EF021F29C5FFB830E64B9AA9058DD660FD2FCB81C497A7E698BCFBF59DE5AD4A86FF93C10A4B9D1AE5774725F9072DCDE9E1F199BAB91F8BFF921864AA502EEE",
"B3CFDA40526B7F1D37569BDFCDF911E5A6EFE6B2EC90A0454C47B2C046BF130FC3B352B34DF4813D48D33AB8E269B69B075676CB6D00A8DCF9E1F967EC191B2C",
"B4C6C3B267071EEFB9C8C72E0E2B941293641F8673CB70C1CC26AD1E73CF141755860AD19B34C2F34ED35BB52EC4507CC1FE59047743A5F0C6FEBDE625E26091",
"57A34F2BCCA60D4B85103B830C9D7952A416BE5263AE429C9E5E53FE8590A8F78EC65A51109EA85DCDF7B6223F9F2B340539FAD81923DBF8EDABF95129E4DFF6",
"9CF46662FCD61A232277B685663B8B5DA832DFD9A3B8CCFEEC993EC6AC415AD07E048ADFE414DF272770DBA867DA5C1224C6FD0AA0C2187D426AC647E9887361",
"5CE1042AB4D542C2F9EE9D17262AF8164098935BEF173D0E18489B04841746CD2F2DF866BD7DA6E5EF9024C648023EC723AB9C62FD80285739D84F15D2AB515A",
"8488396BD4A8729B7A473178F232DADF3F0F8E22678BA5A43E041E72DA1E2CF82194C307207A54CB8156293339EAEC693FF66BFCD5EFC65E95E4ECAF54530ABD",
"F598DA901C3835BCA560779037DFDE9F0C51DC61C0B760FC1522D7B470EE63F5BDC6498476E86049AD86E4E21AF2854A984CC905427D2F17F66B1F41C3DA6F61",
"5F93269798CF02132107337660A8D7A177354C0212EB93E555E7C37A08AEF3D8DCE01217011CD965C04DD2C105F2E2B6CAE5E4E6BCAF09DFBEE3E0A6A6357C37",
"0ECF581D47BAC9230986FAABD70C2F5B80E91066F0EC55A842937882286D2CA007BB4E973B0B091D52167FF7C4009C7AB4AD38FFF1DCEACDB7BE81EF4A452952",
"5AECA8ABE1528582B2A307B4009585498A3D467CA6101CB0C5126F9976056E9FFC123CC20C302B2A737F492C75D21F01512C90CA0541DFA56E950A321DCB28D8",
"732FBF8F1CB2B8329263EDE27858FE46F8D3354D376BCDA0548E7CE1FA9DD11F85EB661FE950B543AA635CA4D3F04EDE5B32D6B656E5CE1C44D35C4A6C56CFF8",
"D5E938735D63788C80100AEFD18648D18CF272F69F20FF24CFE2895C088AD08B0104DA1672A4EB26FC52545CC7D7A01B266CF546C403C45BD129EB41BDD9200B",
"65A245B49352EE297D91AF8C8BE00528AC6E046DD83AC7BD465A98816DD68F3E00E1AE8F895327A7E9A8C9326598379A29C9FC91EC0C6EEF08F3E2B216C11008",
"C95654B63019130AB45DD0FB4941B98AEB3AF2A123913ECA2CE99B3E97410A7BF8661CC7FBAA2BC1CF2B13113B1ED40A0118B88E5FFFC3542759EA007ED4C58D",
"1EB262F38FA494431F017DAD44C0DFB69324AC032F04B657FC91A88647BB74760F24E7C956514F0CF002990B182C1642B9B2426E96A61187E4E012F00E217D84",
"3B955AEEBFA5151AC1AB8E3F5CC1E3767084C842A575D36269836E97353D41622B731DDDCD5F269550A3A5B87BE1E90326340B6E0E62555815D9600597AC6EF9",
"68289F6605473BA0E4F241BAF7477A9885426A858F19EF2A18B0D40EF8E41282ED5526B519799E270F13881327918278755711071D8511FE963E3B5606AA3716",
"80A33787542612C38F6BCD7CD86CAB460227509B1CBAD5EC408A91413D51155A0476DADBF3A2518E4A6E77CC346622E347A469BF8BAA5F04EB2D98705355D063",
"34629BC6D831391C4CDF8AF1B4B7B6B8E8EE17CF98C70E5DD586CD99F14B11DF945166236A9571E6D591BB83EE4D164D46F6B9D8EF86FF865A81BFB91B00424B",
"8B7CC339163863BB4383E542B0EF0E7CF36B84AD932CDF5A80419EC9AD692E7A7E784D2C7CB3796A18B8F800035F3AA06C824100611120A7BDEB35618CCB81B7",
"4F084E4939DD5A7F5A658FAD58A18A15C25C32EC1C7FD5C5C6C3E892B3971AEAAC308304EF17B1C47239EA4BB398B3FD6D4528D8DE8E768AE0F1A5A5C6B5C297",
"48F407A1AF5B8009B2051742E8CF5CD5656669E7D722EE8E7BD202060849442168D8FACC117C012BFB7BF449D99BEFFF6A34AEA203F1D8D352722BE5014EC818",
"A6AA82CD1E426F9A73BFA39A29037876114655B8C22D6D3FF8B638AE7DEA6B17843E09E52EB66FA1E475E4A8A3DE429B7D0F4A776FCB8BDC9B9FEDE7D52E815F",
"5817027D6BDD00C5DD10AC593CD560372270775A18526D7E6F13872A2E20EAB664625BE7168AC4BD7C9E0CE7FC4099E0F48442E2C767191C6E1284E9B2CCEA8C",
"08E41028340A45C74E4052B3A8D6389E22E043A1ADAB5E28D97619450D723469B620CAA519B81C14523854F619FD3027E3847BD03276E60604A80DDB4DE876D6",
"130B8420537EB07D72ABDA07C85ACBD8B9A44F16321DD0422145F809673D30F2B5321326E2BFF317EF3FEF983C51C4F8AB24A325D298E34AFCE569A82555774C",
"AC49B844AFAA012E31C474CA263648844FD2F6307992C2F752ACA02C3828965175794DEEE2D2EE95C61CD284F6B5A2D75E2EF2B29EE8149E77FB81447B2FD04B",
"B9D7CA81CC60BB9578E44024E5A0A0BE80F27336A6A9F4E53DF3999CB191280B090E2AC2D29C5BAAD9D71415BDC129E69AA2667AF6A7FD5E189FCCDCEE817340",
"A755E113386572C75CED61D719706070B9146048E42A9F8CD35667A088B42F08808ABDF77E618ABD959AFC757379CA2C00BCC1A48390FA2BFF618B1E0078A613",
"A73C7DEBED326F1C0DB0795EE7D6E3946894B826B1F8101C56C823BA17168312E7F53FC7DBE52C3E11E69852C40485E2EF182477862EA6A34EC136E2DFEEA6F4",
"6CB8F9D52C56D82CAC28F39EA1593E8BB2506293AC0D68376A1709B62A46DF14A4AE64B2D8FAB76733A1CED2D548E3F3C6FCB49D40C3D5808E449CD83D1C2AA2",
"683FA2B2369A10162C1C1C7B24BC970EE67DA220564F32203F625696C0352A0B9AD96624362D952D84463C1106A2DBA7A092599884B35A0B89C8F1B6A9B5A61E",
"AAD9AD44610118B77D508AEB1BBCD1C1B7D0171397FB510A401BBC0EC34623670D86A2DC3C8F3AB5A2044DF730256727545F0860CE21A1EAC717DFC48F5D228E",
"C42578DE23B4C987D5E1AC4D689ED5DE4B0417F9704BC6BCE969FA13471585D62C2CB1212A944F397FC9CA2C3747C3BEB694EC4C5BE68828DDA53EF43FAEC6C0",
"470F00841EE8244E63ED2C7EA30E2E419897C197462ECCCECF713B42A5065FFF5914BC9B79AFFE8F6B657875E789AE213BD914CD35BD174D46E9D18BD843773D",
"34FC4213730F47A5E9A3580F643E12945CFCB31BF206F6AD450CE528DA3FA432E005D6B0ECCE10DCA7C5995F6AACC5150E1B009E19751E8309F8859531844374",
"FB3C1F0F56A56F8E316FDF5D853C8C872C39635D083634C3904FC3AC07D1B578E85FF0E480E92D44ADE33B62E893EE32343E79DDF6EF292E89B582D312502314",
"C7C97FC65DD2B9E3D3D607D31598D3F84261E9919251E9C8E57BB5F829377D5F73EABBED55C6C381180F29AD02E5BE797FFEC7E57BDECBC50AD3D062F0993AB0",
"A57A49CDBE67AE7D9F797BB5CC7EFC2DF07F4E1B15955F85DAE74B76E2ECB85AFB6CD9EEED8888D5CA3EC5AB65D27A7B19E578475760A045AC3C92E13A938E77",
"C7143FCE9614A17FD653AEB140726DC9C3DBB1DE6CC581B2726897EC24B7A50359AD492243BE66D9EDD8C933B5B80E0B91BB61EA98056006516976FAE8D99A35",
"65BB58D07F937E2D3C7E65385F9C54730B704105CCDB691F6E146D4EE8F6C086F49511035110A9AD6031FDCEB943E0F9613BCB276DD40F0624EF0F924F809783",
"E540277F683B1186DD3B5B3F61433396581A35FEB12002BE8C6A6231FC40FFA70F08081BC58B2D94F7649543614A435FAA2D62110E13DABC7B86629B63AF9C24",
"418500878C5FBCB584C432F4285E05E49F2E3E075399A0DBFCF874EBF8C03D02BF16BC6989D161C77CA0786B05053C6C709433712319192128835CF0B660595B",
"889090DBB1944BDC9433EE5EF1010C7A4A24A8E71ECEA8E12A31318CE49DCAB0ACA5C3802334AAB2CC84B14C6B9321FE586BF3F876F19CD406EB1127FB944801",
"53B6A28910AA92E27E536FB549CF9B9918791060898E0B9FE183577FF43B5E9C7689C745B32E412269837C31B89E6CC12BF76E13CAD366B74ECE48BB85FD09E9",
"7C092080C6A80D672409D081D3D177106BCD63567785140719490950AE07AE8FCAABBAAAB330CFBCF7374482C220AF2EADEEB73DCBB35ED823344E144E7D4899",
"9CCDE566D2400509181111F32DDE4CD63209FE59A30C114546AD2776D889A41BAD8FA1BB468CB2F9D42CA9928A7770FEF8E8BA4D0C812D9A1E75C3D8D2CCD75A",
"6E293BF5D03FE43977CFE3F57CCDB3AE282A85455DCA33F37F4B74F8398CC612433D755CBEC412F8F82A3BD3BC4A278F7ECD0DFA9BBDC40BE7A787C8F159B2DF",
"C56546FB2178456F336164C18B90DEFFC83AE2B5A3ACA77B6884D36D2C1DB39501B3E65E36C758C66E3188451FDB3515EE162C001F06C3E8CB573ADF30F7A101",
"6F82F89F299EBCA2FE014B59BFFE1AA84E88B1915FE256AFB646FD8448AF2B8891A7FAB37A4EA6F9A50E6C317039D8CF878F4C8E1A0DD464F0B4D6FF1C7EA853",
"2B8599FF9C3D6198637AD51E57D1998B0D75313FE2DD61A533C964A6DD9607C6F723E9452CE46E014B1C1D6DE77BA5B88C914D1C597BF1EAE13474B4290E89B2",
"08BF346D38E1DF06C8260EDB1DA75579275948D5C0A0AA9ED2886F8856DE5417A156998758F5B17E52F101CA957A71137473DFD18D7D209C4C10D9233C93691D",
"6DF2156D773114D310B63DB9EE5350D77E6BCF25B05FCD910F9B31BC42BB13FE8225EBCB2A23A62280777B6BF74E2CD0917C7640B43DEFE468CD1E18C943C66A",
"7C7038BC13A91151828A5BA82B4A96040F258A4DFB1B1373F0D359168AFB0517A20B28A12D3644046BE66B8D08D8AE7F6A923EA1C00187C6D11DC502BAC71305",
"BCD1B30D808FB739B987CBF154BEA00DA9D40380B861D4C1D6377122DADD61C0E59018B71941CFB62E00DCD70AEB9ABF0473E80F0A7ECA6B6DEA246AB229DD2B",
"7ED4468D968530FE7AB2C33540B26D8C3BD3ED44B34FBE8C2A9D7F805B5ADA0EA252EEADE4FCE97F89728AD85BC8BB2430B1BEF2CDDD32C8446E59B8E8BA3C67",
"6D30B7C6CE8A3236C0CA2F8D728B1088CA06983A8043E621D5DCF0C537D13B08791EDEB01A3CF0943EC1C890AB6E29B146A236CD46BCB9D93BF516FB67C63FE5",
"97FE03CEF31438508911BDED975980A66029305DC5E3FA8AD1B4FB22FCDF5A19A733320327D8F71CCF496CB3A44A77AF56E3DDE73D3A5F176896CC57C9A5AD99",
"785A9D0FBD21136DBCE8FA7EAFD63C9DAD220052978416B31D9753EAA149097847ED9B30A65C70507EFF01879149ED5CF0471D37798EDC05ABD56AD4A2CCCB1D",
"AD408D2ABDDFD37B3BF34794C1A3371D928ED7FC8D966225333584C5665817832A37C07F0DC7CB5AA874CD7D20FE8FAB8EABCB9B33D2E0841F6E200960899D95",
"97668F745B6032FC815D9579322769DCCD9501A5080029B8AE826BEFB6742331BD9F76EFEB3E2B8E81A9786B282F5068A3A2424697A77C41876B7E753F4C7767",
"26BB985F47E7FEE0CFD252D4EF96BED42B9C370C1C6A3E8C9EB04EF7F7818B833A0D1F043EBAFB911DC779E02740A02A44D3A1EA45ED4AD55E686C927CAFE97E",
"5BFE2B1DCF7FE9B95088ACEDB575C19016C743B2E763BF5851AC407C9EDA43715EDFA48B4825492C5179593FFF21351B76E8B7E034E4C53C79F61F29C479BD08",
"C76509EF72F4A6F9C9C40618ED52B2084F83502232E0AC8BDAF3264368E4D0180F6854C4ABF4F6509C79CAAFC44CF3194AFC57BD077BD7B3C9BDA3D4B8775816",
"D66F2BEAB990E354CCB910E4E9C7AC618C7B63EF292A96B552341DE78DC46D3EC8CFABC699B50AF41FDA39CF1B0173660923510AD67FAEDEF5207CFFE8641D20",
"7D8F0672992B79BE3A364D8E5904F4AB713BBC8AB01B4F309AD8CCF223CE1034A860DCB0B00550612CC2FA17F2969E18F22E1427D254B4A82B3A03A3EB394ADF",
"A56D6725BFB3DE47C1414ADF25FC8F0FC9846F6987722BC06366D5CA4E89722925EBBC881418844075397A0CA89842C7B9E9E07E1D9D183EBEB39E120B483BF7",
"AF5E03D7FE60C67E10313344434E79485A03A758D6DCE985574745763C1C5C77D4FB3E6FB12230368370993BF90FEED0C5D1607524562D7C09C0C210ED393D7C",
"7A20540CC07BF72B582421FC342E82F52134B69841EC28ED189E2EA6A29DD2F82A640352D222B52F2911DC72A7DAB31CAADD80C6118F13C56B2A1E4373BE0EA3",
"486F02C63E5467EA1FDDE7E82BFACC2C1BA5D636D9F3D08B210DA3F372F706EC218CC17FF60AEF703BBE0C15C38AE55D286A684F864C78211CCAB4178C92ADBA",
"1C7A5C1DEDCD04A921788F7EB23361CA1953B04B9C7AEC35D65EA3E4996DB26F281278EA4AE666AD81027D98AF57262CDBFA4C085F4210568C7E15EEC7805114",
"9CE3FA9A860BDBD5378FD6D7B8B671C6CB7692910CE8F9B6CB4122CBCBE6AC06CA0422CEF1225935053B7D193A81B9E972EB85A1D3074F14CBB5EC9F0573892D",
"A91187BE5C371C4265C174FD4653B8AB708551F83D1FEE1CC1479581BC006D6FB78FCC9A5DEE1DB3666F508F9780A37593EBCCCF5FBED39667DC6361E921F779",
"4625767D7B1D3D3ED2FBC674AF14E0244152F2A4021FCF3311505D89BD81E2F9F9A500C3B199914DB49500B3C98D03EA93286751A686A3B875DAAB0CCD63B44F",
"43DFDFE1B014FED3A2ACABB7F3E9A182F2AA18019D27E3E6CDCF31A15B428E91E7B08CF5E5C376FCE2D8A28FF85AB0A0A1656EDB4A0A91532620096D9A5A652D",
"279E3202BE3989BA3112772585177487E4FE3EE3EAB49C2F7FA7FE87CFE7B80D3E0355EDFF6D031E6C96C795DB1C6F041880EC3824DEFACF9263820A8E7327DE",
"EA2D066AC229D4D4B616A8BEDEC734325224E4B4E58F1AE6DAD7E40C2DA29196C3B1EA9571DACC81E87328CAA0211E09027B0524AA3F4A849917B3586747EBBB",
"49F014F5C61822C899AB5CAE51BE4044A4495E777DEB7DA9B6D8490EFBB87530ADF293DAF079F94C33B7044EF62E2E5BB3EB11E17304F8453EE6CE24F033DDB0",
"9233490344E5B0DC5912671B7AE54CEE7730DBE1F4C7D92A4D3E3AAB50571708DB51DCF9C2944591DB651DB32D22935B86944969BE77D5B5FEAE6C3840A8DB26",
"B6E75E6F4C7F453B7465D25B5AC8C7196902EAA953875228C8634E16E2AE1F38BC3275304335F5989ECCC1E34167D4E68D7719968FBA8E2FE67947C35C48E806",
"CC14CA665AF1483EFBC3AF80080E650D5046A3932F4F51F3FE90A0705EC25104ADF07839265DC51D43401411246E474F0D5E5637AF94767283D53E0617E981F4",
"230A1C857CB2E7852E41B647E90E4585D2D881E1734DC38955356E8DD7BFF39053092C6B38E236E1899525647073DDDF6895D64206325E7647F275567B255909",
"CBB65321AC436E2FFDAB2936359CE49023F7DEE7614EF28D173C3D27C5D1BFFA51553D433F8EE3C9E49C05A2B883CCE954C9A8093B80612A0CDD4732E041F995",
"3E7E570074337275EFB51315588034C3CF0DDDCA20B4612E0BD5B881E7E5476D319CE4FE9F19186E4C0826F44F131EB048E65BE242B1172C63BADB123AB0CBE8",
"D32E9EC02D38D4E1B8249DF8DCB00C5B9C68EB8922672E3505393B6A210BA56F9496E5EE0490EF387C3CDEC061F06BC0382D9304CAFBB8E0CD33D57029E62DF2",
"8C1512466089F05B3775C262B62D22B83854A83218130B4EC91B3CCBD293D2A54302CECAAB9B100C68D1E6DDC8F07CDDBDFE6FDAAAF099CC09D6B725879C6369",
"91A7F61C97C2911E4C812EF71D780AD8FA788794561D08303FD1C1CB608A46A12563086EC5B39D471AED94FB0F6C678A43B8792932F9028D772A22768EA23A9B",
"4F6BB222A395E8B18F6BA155477AED3F0729AC9E83E16D31A2A8BC655422B837C891C6199E6F0D75799E3B691525C581953517F252C4B9E3A27A28FBAF49644C",
"5D06C07E7A646C413A501C3F4BB2FC38127DE7509B7077C4D9B5613201C1AA02FD5F79D2745915DD57FBCB4CE08695F6EFC0CB3D2D330E19B4B0E6004EA6471E",
"B96756E57909968F14B796A5D30F4C9D671472CF82C8CFB2CACA7AC7A44CA0A14C9842D00C82E337502C94D5960ACA4C492EA7B0DF919DDF1AADA2A275BB10D4",
"FF0A015E98DB9C99F03977710AAC3E658C0D896F6D71D618BA79DC6CF72AC75B7C038EB6862DEDE4543E145413A6368D69F5722C827BA3EF25B6AE6440D39276",
"5B21C5FD8868367612474FA2E70E9CFA2201FFEEE8FAFAB5797AD58FEFA17C9B5B107DA4A3DB6320BAAF2C8617D5A51DF914AE88DA3867C2D41F0CC14FA67928"
};
public static string[] KeyedBlake2B = new string[]{
"10EBB67700B1868EFB4417987ACF4690AE9D972FB7A590C2F02871799AAA4786B5E996E8F0F4EB981FC214B005F42D2FF4233499391653DF7AEFCBC13FC51568",
"961F6DD1E4DD30F63901690C512E78E4B45E4742ED197C3C5E45C549FD25F2E4187B0BC9FE30492B16B0D0BC4EF9B0F34C7003FAC09A5EF1532E69430234CEBD",
"DA2CFBE2D8409A0F38026113884F84B50156371AE304C4430173D08A99D9FB1B983164A3770706D537F49E0C916D9F32B95CC37A95B99D857436F0232C88A965",
"33D0825DDDF7ADA99B0E7E307104AD07CA9CFD9692214F1561356315E784F3E5A17E364AE9DBB14CB2036DF932B77F4B292761365FB328DE7AFDC6D8998F5FC1",
"BEAA5A3D08F3807143CF621D95CD690514D0B49EFFF9C91D24B59241EC0EEFA5F60196D407048BBA8D2146828EBCB0488D8842FD56BB4F6DF8E19C4B4DAAB8AC",
"098084B51FD13DEAE5F4320DE94A688EE07BAEA2800486689A8636117B46C1F4C1F6AF7F74AE7C857600456A58A3AF251DC4723A64CC7C0A5AB6D9CAC91C20BB",
"6044540D560853EB1C57DF0077DD381094781CDB9073E5B1B3D3F6C7829E12066BBACA96D989A690DE72CA3133A83652BA284A6D62942B271FFA2620C9E75B1F",
"7A8CFE9B90F75F7ECB3ACC053AAED6193112B6F6A4AEEB3F65D3DE541942DEB9E2228152A3C4BBBE72FC3B12629528CFBB09FE630F0474339F54ABF453E2ED52",
"380BEAF6EA7CC9365E270EF0E6F3A64FB902ACAE51DD5512F84259AD2C91F4BC4108DB73192A5BBFB0CBCF71E46C3E21AEE1C5E860DC96E8EB0B7B8426E6ABE9",
"60FE3C4535E1B59D9A61EA8500BFAC41A69DFFB1CEADD9ACA323E9A625B64DA5763BAD7226DA02B9C8C4F1A5DE140AC5A6C1124E4F718CE0B28EA47393AA6637",
"4FE181F54AD63A2983FEAAF77D1E7235C2BEB17FA328B6D9505BDA327DF19FC37F02C4B6F0368CE23147313A8E5738B5FA2A95B29DE1C7F8264EB77B69F585CD",
"F228773CE3F3A42B5F144D63237A72D99693ADB8837D0E112A8A0F8FFFF2C362857AC49C11EC740D1500749DAC9B1F4548108BF3155794DCC9E4082849E2B85B",
"962452A8455CC56C8511317E3B1F3B2C37DF75F588E94325FDD77070359CF63A9AE6E930936FDF8E1E08FFCA440CFB72C28F06D89A2151D1C46CD5B268EF8563",
"43D44BFA18768C59896BF7ED1765CB2D14AF8C260266039099B25A603E4DDC5039D6EF3A91847D1088D401C0C7E847781A8A590D33A3C6CB4DF0FAB1C2F22355",
"DCFFA9D58C2A4CA2CDBB0C7AA4C4C1D45165190089F4E983BB1C2CAB4AAEFF1FA2B5EE516FECD780540240BF37E56C8BCCA7FAB980E1E61C9400D8A9A5B14AC6",
"6FBF31B45AB0C0B8DAD1C0F5F4061379912DDE5AA922099A030B725C73346C524291ADEF89D2F6FD8DFCDA6D07DAD811A9314536C2915ED45DA34947E83DE34E",
"A0C65BDDDE8ADEF57282B04B11E7BC8AAB105B99231B750C021F4A735CB1BCFAB87553BBA3ABB0C3E64A0B6955285185A0BD35FB8CFDE557329BEBB1F629EE93",
"F99D815550558E81ECA2F96718AED10D86F3F1CFB675CCE06B0EFF02F617C5A42C5AA760270F2679DA2677C5AEB94F1142277F21C7F79F3C4F0CCE4ED8EE62B1",
"95391DA8FC7B917A2044B3D6F5374E1CA072B41454D572C7356C05FD4BC1E0F40B8BB8B4A9F6BCE9BE2C4623C399B0DCA0DAB05CB7281B71A21B0EBCD9E55670",
"04B9CD3D20D221C09AC86913D3DC63041989A9A1E694F1E639A3BA7E451840F750C2FC191D56AD61F2E7936BC0AC8E094B60CAEED878C18799045402D61CEAF9",
"EC0E0EF707E4ED6C0C66F9E089E4954B058030D2DD86398FE84059631F9EE591D9D77375355149178C0CF8F8E7C49ED2A5E4F95488A2247067C208510FADC44C",
"9A37CCE273B79C09913677510EAF7688E89B3314D3532FD2764C39DE022A2945B5710D13517AF8DDC0316624E73BEC1CE67DF15228302036F330AB0CB4D218DD",
"4CF9BB8FB3D4DE8B38B2F262D3C40F46DFE747E8FC0A414C193D9FCF753106CE47A18F172F12E8A2F1C26726545358E5EE28C9E2213A8787AAFBC516D2343152",
"64E0C63AF9C808FD893137129867FD91939D53F2AF04BE4FA268006100069B2D69DAA5C5D8ED7FDDCB2A70EEECDF2B105DD46A1E3B7311728F639AB489326BC9",
"5E9C93158D659B2DEF06B0C3C7565045542662D6EEE8A96A89B78ADE09FE8B3DCC096D4FE48815D88D8F82620156602AF541955E1F6CA30DCE14E254C326B88F",
"7775DFF889458DD11AEF417276853E21335EB88E4DEC9CFB4E9EDB49820088551A2CA60339F12066101169F0DFE84B098FDDB148D9DA6B3D613DF263889AD64B",
"F0D2805AFBB91F743951351A6D024F9353A23C7CE1FC2B051B3A8B968C233F46F50F806ECB1568FFAA0B60661E334B21DDE04F8FA155AC740EEB42E20B60D764",
"86A2AF316E7D7754201B942E275364AC12EA8962AB5BD8D7FB276DC5FBFFC8F9A28CAE4E4867DF6780D9B72524160927C855DA5B6078E0B554AA91E31CB9CA1D",
"10BDF0CAA0802705E706369BAF8A3F79D72C0A03A80675A7BBB00BE3A45E516424D1EE88EFB56F6D5777545AE6E27765C3A8F5E493FC308915638933A1DFEE55",
"B01781092B1748459E2E4EC178696627BF4EBAFEBBA774ECF018B79A68AEB84917BF0B84BB79D17B743151144CD66B7B33A4B9E52C76C4E112050FF5385B7F0B",
"C6DBC61DEC6EAEAC81E3D5F755203C8E220551534A0B2FD105A91889945A638550204F44093DD998C076205DFFAD703A0E5CD3C7F438A7E634CD59FEDEDB539E",
"EBA51ACFFB4CEA31DB4B8D87E9BF7DD48FE97B0253AE67AA580F9AC4A9D941F2BEA518EE286818CC9F633F2A3B9FB68E594B48CDD6D515BF1D52BA6C85A203A7",
"86221F3ADA52037B72224F105D7999231C5E5534D03DA9D9C0A12ACB68460CD375DAF8E24386286F9668F72326DBF99BA094392437D398E95BB8161D717F8991",
"5595E05C13A7EC4DC8F41FB70CB50A71BCE17C024FF6DE7AF618D0CC4E9C32D9570D6D3EA45B86525491030C0D8F2B1836D5778C1CE735C17707DF364D054347",
"CE0F4F6ACA89590A37FE034DD74DD5FA65EB1CBD0A41508AADDC09351A3CEA6D18CB2189C54B700C009F4CBF0521C7EA01BE61C5AE09CB54F27BC1B44D658C82",
"7EE80B06A215A3BCA970C77CDA8761822BC103D44FA4B33F4D07DCB997E36D55298BCEAE12241B3FA07FA63BE5576068DA387B8D5859AEAB701369848B176D42",
"940A84B6A84D109AAB208C024C6CE9647676BA0AAA11F86DBB7018F9FD2220A6D901A9027F9ABCF935372727CBF09EBD61A2A2EEB87653E8ECAD1BAB85DC8327",
"2020B78264A82D9F4151141ADBA8D44BF20C5EC062EEE9B595A11F9E84901BF148F298E0C9F8777DCDBC7CC4670AAC356CC2AD8CCB1629F16F6A76BCEFBEE760",
"D1B897B0E075BA68AB572ADF9D9C436663E43EB3D8E62D92FC49C9BE214E6F27873FE215A65170E6BEA902408A25B49506F47BABD07CECF7113EC10C5DD31252",
"B14D0C62ABFA469A357177E594C10C194243ED2025AB8AA5AD2FA41AD318E0FF48CD5E60BEC07B13634A711D2326E488A985F31E31153399E73088EFC86A5C55",
"4169C5CC808D2697DC2A82430DC23E3CD356DC70A94566810502B8D655B39ABF9E7F902FE717E0389219859E1945DF1AF6ADA42E4CCDA55A197B7100A30C30A1",
"258A4EDB113D66C839C8B1C91F15F35ADE609F11CD7F8681A4045B9FEF7B0B24C82CDA06A5F2067B368825E3914E53D6948EDE92EFD6E8387FA2E537239B5BEE",
"79D2D8696D30F30FB34657761171A11E6C3F1E64CBE7BEBEE159CB95BFAF812B4F411E2F26D9C421DC2C284A3342D823EC293849E42D1E46B0A4AC1E3C86ABAA",
"8B9436010DC5DEE992AE38AEA97F2CD63B946D94FEDD2EC9671DCDE3BD4CE9564D555C66C15BB2B900DF72EDB6B891EBCADFEFF63C9EA4036A998BE7973981E7",
"C8F68E696ED28242BF997F5B3B34959508E42D613810F1E2A435C96ED2FF560C7022F361A9234B9837FEEE90BF47922EE0FD5F8DDF823718D86D1E16C6090071",
"B02D3EEE4860D5868B2C39CE39BFE81011290564DD678C85E8783F29302DFC1399BA95B6B53CD9EBBF400CCA1DB0AB67E19A325F2D115812D25D00978AD1BCA4",
"7693EA73AF3AC4DAD21CA0D8DA85B3118A7D1C6024CFAF557699868217BC0C2F44A199BC6C0EDD519798BA05BD5B1B4484346A47C2CADF6BF30B785CC88B2BAF",
"A0E5C1C0031C02E48B7F09A5E896EE9AEF2F17FC9E18E997D7F6CAC7AE316422C2B1E77984E5F3A73CB45DEED5D3F84600105E6EE38F2D090C7D0442EA34C46D",
"41DAA6ADCFDB69F1440C37B596440165C15ADA596813E2E22F060FCD551F24DEE8E04BA6890387886CEEC4A7A0D7FC6B44506392EC3822C0D8C1ACFC7D5AEBE8",
"14D4D40D5984D84C5CF7523B7798B254E275A3A8CC0A1BD06EBC0BEE726856ACC3CBF516FF667CDA2058AD5C3412254460A82C92187041363CC77A4DC215E487",
"D0E7A1E2B9A447FEE83E2277E9FF8010C2F375AE12FA7AAA8CA5A6317868A26A367A0B69FBC1CF32A55D34EB370663016F3D2110230EBA754028A56F54ACF57C",
"E771AA8DB5A3E043E8178F39A0857BA04A3F18E4AA05743CF8D222B0B095825350BA422F63382A23D92E4149074E816A36C1CD28284D146267940B31F8818EA2",
"FEB4FD6F9E87A56BEF398B3284D2BDA5B5B0E166583A66B61E538457FF0584872C21A32962B9928FFAB58DE4AF2EDD4E15D8B35570523207FF4E2A5AA7754CAA",
"462F17BF005FB1C1B9E671779F665209EC2873E3E411F98DABF240A1D5EC3F95CE6796B6FC23FE171903B502023467DEC7273FF74879B92967A2A43A5A183D33",
"D3338193B64553DBD38D144BEA71C5915BB110E2D88180DBC5DB364FD6171DF317FC7268831B5AEF75E4342B2FAD8797BA39EDDCEF80E6EC08159350B1AD696D",
"E1590D585A3D39F7CB599ABD479070966409A6846D4377ACF4471D065D5DB94129CC9BE92573B05ED226BE1E9B7CB0CABE87918589F80DADD4EF5EF25A93D28E",
"F8F3726AC5A26CC80132493A6FEDCB0E60760C09CFC84CAD178175986819665E76842D7B9FEDF76DDDEBF5D3F56FAAAD4477587AF21606D396AE570D8E719AF2",
"30186055C07949948183C850E9A756CC09937E247D9D928E869E20BAFC3CD9721719D34E04A0899B92C736084550186886EFBA2E790D8BE6EBF040B209C439A4",
"F3C4276CB863637712C241C444C5CC1E3554E0FDDB174D035819DD83EB700B4CE88DF3AB3841BA02085E1A99B4E17310C5341075C0458BA376C95A6818FBB3E2",
"0AA007C4DD9D5832393040A1583C930BCA7DC5E77EA53ADD7E2B3F7C8E231368043520D4A3EF53C969B6BBFD025946F632BD7F765D53C21003B8F983F75E2A6A",
"08E9464720533B23A04EC24F7AE8C103145F765387D738777D3D343477FD1C58DB052142CAB754EA674378E18766C53542F71970171CC4F81694246B717D7564",
"D37FF7AD297993E7EC21E0F1B4B5AE719CDC83C5DB687527F27516CBFFA822888A6810EE5C1CA7BFE3321119BE1AB7BFA0A502671C8329494DF7AD6F522D440F",
"DD9042F6E464DCF86B1262F6ACCFAFBD8CFD902ED3ED89ABF78FFA482DBDEEB6969842394C9A1168AE3D481A017842F660002D42447C6B22F7B72F21AAE021C9",
"BD965BF31E87D70327536F2A341CEBC4768ECA275FA05EF98F7F1B71A0351298DE006FBA73FE6733ED01D75801B4A928E54231B38E38C562B2E33EA1284992FA",
"65676D800617972FBD87E4B9514E1C67402B7A331096D3BFAC22F1ABB95374ABC942F16E9AB0EAD33B87C91968A6E509E119FF07787B3EF483E1DCDCCF6E3022",
"939FA189699C5D2C81DDD1FFC1FA207C970B6A3685BB29CE1D3E99D42F2F7442DA53E95A72907314F4588399A3FF5B0A92BEB3F6BE2694F9F86ECF2952D5B41C",
"C516541701863F91005F314108CEECE3C643E04FC8C42FD2FF556220E616AAA6A48AEB97A84BAD74782E8DFF96A1A2FA949339D722EDCAA32B57067041DF88CC",
"987FD6E0D6857C553EAEBB3D34970A2C2F6E89A3548F492521722B80A1C21A153892346D2CBA6444212D56DA9A26E324DCCBC0DCDE85D4D2EE4399EEC5A64E8F",
"AE56DEB1C2328D9C4017706BCE6E99D41349053BA9D336D677C4C27D9FD50AE6AEE17E853154E1F4FE7672346DA2EAA31EEA53FCF24A22804F11D03DA6ABFC2B",
"49D6A608C9BDE4491870498572AC31AAC3FA40938B38A7818F72383EB040AD39532BC06571E13D767E6945AB77C0BDC3B0284253343F9F6C1244EBF2FF0DF866",
"DA582AD8C5370B4469AF862AA6467A2293B2B28BD80AE0E91F425AD3D47249FDF98825CC86F14028C3308C9804C78BFEEEEE461444CE243687E1A50522456A1D",
"D5266AA3331194AEF852EED86D7B5B2633A0AF1C735906F2E13279F14931A9FC3B0EAC5CE9245273BD1AA92905ABE16278EF7EFD47694789A7283B77DA3C70F8",
"2962734C28252186A9A1111C732AD4DE4506D4B4480916303EB7991D659CCDA07A9911914BC75C418AB7A4541757AD054796E26797FEAF36E9F6AD43F14B35A4",
"E8B79EC5D06E111BDFAFD71E9F5760F00AC8AC5D8BF768F9FF6F08B8F026096B1CC3A4C973333019F1E3553E77DA3F98CB9F542E0A90E5F8A940CC58E59844B3",
"DFB320C44F9D41D1EFDCC015F08DD5539E526E39C87D509AE6812A969E5431BF4FA7D91FFD03B981E0D544CF72D7B1C0374F8801482E6DEA2EF903877EBA675E",
"D88675118FDB55A5FB365AC2AF1D217BF526CE1EE9C94B2F0090B2C58A06CA58187D7FE57C7BED9D26FCA067B4110EEFCD9A0A345DE872ABE20DE368001B0745",
"B893F2FC41F7B0DD6E2F6AA2E0370C0CFF7DF09E3ACFCC0E920B6E6FAD0EF747C40668417D342B80D2351E8C175F20897A062E9765E6C67B539B6BA8B9170545",
"6C67EC5697ACCD235C59B486D7B70BAEEDCBD4AA64EBD4EEF3C7EAC189561A726250AEC4D48CADCAFBBE2CE3C16CE2D691A8CCE06E8879556D4483ED7165C063",
"F1AA2B044F8F0C638A3F362E677B5D891D6FD2AB0765F6EE1E4987DE057EAD357883D9B405B9D609EEA1B869D97FB16D9B51017C553F3B93C0A1E0F1296FEDCD",
"CBAA259572D4AEBFC1917ACDDC582B9F8DFAA928A198CA7ACD0F2AA76A134A90252E6298A65B08186A350D5B7626699F8CB721A3EA5921B753AE3A2DCE24BA3A",
"FA1549C9796CD4D303DCF452C1FBD5744FD9B9B47003D920B92DE34839D07EF2A29DED68F6FC9E6C45E071A2E48BD50C5084E96B657DD0404045A1DDEFE282ED",
"5CF2AC897AB444DCB5C8D87C495DBDB34E1838B6B629427CAA51702AD0F9688525F13BEC503A3C3A2C80A65E0B5715E8AFAB00FFA56EC455A49A1AD30AA24FCD",
"9AAF80207BACE17BB7AB145757D5696BDE32406EF22B44292EF65D4519C3BB2AD41A59B62CC3E94B6FA96D32A7FAADAE28AF7D35097219AA3FD8CDA31E40C275",
"AF88B163402C86745CB650C2988FB95211B94B03EF290EED9662034241FD51CF398F8073E369354C43EAE1052F9B63B08191CAA138AA54FEA889CC7024236897",
"48FA7D64E1CEEE27B9864DB5ADA4B53D00C9BC7626555813D3CD6730AB3CC06FF342D727905E33171BDE6E8476E77FB1720861E94B73A2C538D254746285F430",
"0E6FD97A85E904F87BFE85BBEB34F69E1F18105CF4ED4F87AEC36C6E8B5F68BD2A6F3DC8A9ECB2B61DB4EEDB6B2EA10BF9CB0251FB0F8B344ABF7F366B6DE5AB",
"06622DA5787176287FDC8FED440BAD187D830099C94E6D04C8E9C954CDA70C8BB9E1FC4A6D0BAA831B9B78EF6648681A4867A11DA93EE36E5E6A37D87FC63F6F",
"1DA6772B58FABF9C61F68D412C82F182C0236D7D575EF0B58DD22458D643CD1DFC93B03871C316D8430D312995D4197F0874C99172BA004A01EE295ABAC24E46",
"3CD2D9320B7B1D5FB9AAB951A76023FA667BE14A9124E394513918A3F44096AE4904BA0FFC150B63BC7AB1EEB9A6E257E5C8F000A70394A5AFD842715DE15F29",
"04CDC14F7434E0B4BE70CB41DB4C779A88EAEF6ACCEBCB41F2D42FFFE7F32A8E281B5C103A27021D0D08362250753CDF70292195A53A48728CEB5844C2D98BAB",
"9071B7A8A075D0095B8FB3AE5113785735AB98E2B52FAF91D5B89E44AAC5B5D4EBBF91223B0FF4C71905DA55342E64655D6EF8C89A4768C3F93A6DC0366B5BC8",
"EBB30240DD96C7BC8D0ABE49AA4EDCBB4AFDC51FF9AAF720D3F9E7FBB0F9C6D6571350501769FC4EBD0B2141247FF400D4FD4BE414EDF37757BB90A32AC5C65A",
"8532C58BF3C8015D9D1CBE00EEF1F5082F8F3632FBE9F1ED4F9DFB1FA79E8283066D77C44C4AF943D76B300364AECBD0648C8A8939BD204123F4B56260422DEC",
"FE9846D64F7C7708696F840E2D76CB4408B6595C2F81EC6A28A7F2F20CB88CFE6AC0B9E9B8244F08BD7095C350C1D0842F64FB01BB7F532DFCD47371B0AEEB79",
"28F17EA6FB6C42092DC264257E29746321FB5BDAEA9873C2A7FA9D8F53818E899E161BC77DFE8090AFD82BF2266C5C1BC930A8D1547624439E662EF695F26F24",
"EC6B7D7F030D4850ACAE3CB615C21DD25206D63E84D1DB8D957370737BA0E98467EA0CE274C66199901EAEC18A08525715F53BFDB0AACB613D342EBDCEEDDC3B",
"B403D3691C03B0D3418DF327D5860D34BBFCC4519BFBCE36BF33B208385FADB9186BC78A76C489D89FD57E7DC75412D23BCD1DAE8470CE9274754BB8585B13C5",
"31FC79738B8772B3F55CD8178813B3B52D0DB5A419D30BA9495C4B9DA0219FAC6DF8E7C23A811551A62B827F256ECDB8124AC8A6792CCFECC3B3012722E94463",
"BB2039EC287091BCC9642FC90049E73732E02E577E2862B32216AE9BEDCD730C4C284EF3968C368B7D37584F97BD4B4DC6EF6127ACFE2E6AE2509124E66C8AF4",
"F53D68D13F45EDFCB9BD415E2831E938350D5380D3432278FC1C0C381FCB7C65C82DAFE051D8C8B0D44E0974A0E59EC7BF7ED0459F86E96F329FC79752510FD3",
"8D568C7984F0ECDF7640FBC483B5D8C9F86634F6F43291841B309A350AB9C1137D24066B09DA9944BAC54D5BB6580D836047AAC74AB724B887EBF93D4B32ECA9",
"C0B65CE5A96FF774C456CAC3B5F2C4CD359B4FF53EF93A3DA0778BE4900D1E8DA1601E769E8F1B02D2A2F8C5B9FA10B44F1C186985468FEEB008730283A6657D",
"4900BBA6F5FB103ECE8EC96ADA13A5C3C85488E05551DA6B6B33D988E611EC0FE2E3C2AA48EA6AE8986A3A231B223C5D27CEC2EADDE91CE07981EE652862D1E4",
"C7F5C37C7285F927F76443414D4357FF789647D7A005A5A787E03C346B57F49F21B64FA9CF4B7E45573E23049017567121A9C3D4B2B73EC5E9413577525DB45A",
"EC7096330736FDB2D64B5653E7475DA746C23A4613A82687A28062D3236364284AC01720FFB406CFE265C0DF626A188C9E5963ACE5D3D5BB363E32C38C2190A6",
"82E744C75F4649EC52B80771A77D475A3BC091989556960E276A5F9EAD92A03F718742CDCFEAEE5CB85C44AF198ADC43A4A428F5F0C2DDB0BE36059F06D7DF73",
"2834B7A7170F1F5B68559AB78C1050EC21C919740B784A9072F6E5D69F828D70C919C5039FB148E39E2C8A52118378B064CA8D5001CD10A5478387B966715ED6",
"16B4ADA883F72F853BB7EF253EFCAB0C3E2161687AD61543A0D2824F91C1F81347D86BE709B16996E17F2DD486927B0288AD38D13063C4A9672C39397D3789B6",
"78D048F3A69D8B54AE0ED63A573AE350D89F7C6CF1F3688930DE899AFA037697629B314E5CD303AA62FEEA72A25BF42B304B6C6BCB27FAE21C16D925E1FBDAC3",
"0F746A48749287ADA77A82961F05A4DA4ABDB7D77B1220F836D09EC814359C0EC0239B8C7B9FF9E02F569D1B301EF67C4612D1DE4F730F81C12C40CC063C5CAA",
"F0FC859D3BD195FBDC2D591E4CDAC15179EC0F1DC821C11DF1F0C1D26E6260AAA65B79FAFACAFD7D3AD61E600F250905F5878C87452897647A35B995BCADC3A3",
"2620F687E8625F6A412460B42E2CEF67634208CE10A0CBD4DFF7044A41B7880077E9F8DC3B8D1216D3376A21E015B58FB279B521D83F9388C7382C8505590B9B",
"227E3AED8D2CB10B918FCB04F9DE3E6D0A57E08476D93759CD7B2ED54A1CBF0239C528FB04BBF288253E601D3BC38B21794AFEF90B17094A182CAC557745E75F",
"1A929901B09C25F27D6B35BE7B2F1C4745131FDEBCA7F3E2451926720434E0DB6E74FD693AD29B777DC3355C592A361C4873B01133A57C2E3B7075CBDB86F4FC",
"5FD7968BC2FE34F220B5E3DC5AF9571742D73B7D60819F2888B629072B96A9D8AB2D91B82D0A9AABA61BBD39958132FCC4257023D1ECA591B3054E2DC81C8200",
"DFCCE8CF32870CC6A503EADAFC87FD6F78918B9B4D0737DB6810BE996B5497E7E5CC80E312F61E71FF3E9624436073156403F735F56B0B01845C18F6CAF772E6",
"02F7EF3A9CE0FFF960F67032B296EFCA3061F4934D690749F2D01C35C81C14F39A67FA350BC8A0359BF1724BFFC3BCA6D7C7BBA4791FD522A3AD353C02EC5AA8",
"64BE5C6ABA65D594844AE78BB022E5BEBE127FD6B6FFA5A13703855AB63B624DCD1A363F99203F632EC386F3EA767FC992E8ED9686586AA27555A8599D5B808F",
"F78585505C4EAA54A8B5BE70A61E735E0FF97AF944DDB3001E35D86C4E2199D976104B6AE31750A36A726ED285064F5981B503889FEF822FCDC2898DDDB7889A",
"E4B5566033869572EDFD87479A5BB73C80E8759B91232879D96B1DDA36C012076EE5A2ED7AE2DE63EF8406A06AEA82C188031B560BEAFB583FB3DE9E57952A7E",
"E1B3E7ED867F6C9484A2A97F7715F25E25294E992E41F6A7C161FFC2ADC6DAAEB7113102D5E6090287FE6AD94CE5D6B739C6CA240B05C76FB73F25DD024BF935",
"85FD085FDC12A080983DF07BD7012B0D402A0F4043FCB2775ADF0BAD174F9B08D1676E476985785C0A5DCC41DBFF6D95EF4D66A3FBDC4A74B82BA52DA0512B74",
"AED8FA764B0FBFF821E05233D2F7B0900EC44D826F95E93C343C1BC3BA5A24374B1D616E7E7ABA453A0ADA5E4FAB5382409E0D42CE9C2BC7FB39A99C340C20F0",
"7BA3B2E297233522EEB343BD3EBCFD835A04007735E87F0CA300CBEE6D416565162171581E4020FF4CF176450F1291EA2285CB9EBFFE4C56660627685145051C",
"DE748BCF89EC88084721E16B85F30ADB1A6134D664B5843569BABC5BBD1A15CA9B61803C901A4FEF32965A1749C9F3A4E243E173939DC5A8DC495C671AB52145",
"AAF4D2BDF200A919706D9842DCE16C98140D34BC433DF320ABA9BD429E549AA7A3397652A4D768277786CF993CDE2338673ED2E6B66C961FEFB82CD20C93338F",
"C408218968B788BF864F0997E6BC4C3DBA68B276E2125A4843296052FF93BF5767B8CDCE7131F0876430C1165FEC6C4F47ADAA4FD8BCFACEF463B5D3D0FA61A0",
"76D2D819C92BCE55FA8E092AB1BF9B9EAB237A25267986CACF2B8EE14D214D730DC9A5AA2D7B596E86A1FD8FA0804C77402D2FCD45083688B218B1CDFA0DCBCB",
"72065EE4DD91C2D8509FA1FC28A37C7FC9FA7D5B3F8AD3D0D7A25626B57B1B44788D4CAF806290425F9890A3A2A35A905AB4B37ACFD0DA6E4517B2525C9651E4",
"64475DFE7600D7171BEA0B394E27C9B00D8E74DD1E416A79473682AD3DFDBB706631558055CFC8A40E07BD015A4540DCDEA15883CBBF31412DF1DE1CD4152B91",
"12CD1674A4488A5D7C2B3160D2E2C4B58371BEDAD793418D6F19C6EE385D70B3E06739369D4DF910EDB0B0A54CBFF43D54544CD37AB3A06CFA0A3DDAC8B66C89",
"60756966479DEDC6DD4BCFF8EA7D1D4CE4D4AF2E7B097E32E3763518441147CC12B3C0EE6D2ECABF1198CEC92E86A3616FBA4F4E872F5825330ADBB4C1DEE444",
"A7803BCB71BC1D0F4383DDE1E0612E04F872B715AD30815C2249CF34ABB8B024915CB2FC9F4E7CC4C8CFD45BE2D5A91EAB0941C7D270E2DA4CA4A9F7AC68663A",
"B84EF6A7229A34A750D9A98EE2529871816B87FBE3BC45B45FA5AE82D5141540211165C3C5D7A7476BA5A4AA06D66476F0D9DC49A3F1EE72C3ACABD498967414",
"FAE4B6D8EFC3F8C8E64D001DABEC3A21F544E82714745251B2B4B393F2F43E0DA3D403C64DB95A2CB6E23EBB7B9E94CDD5DDAC54F07C4A61BD3CB10AA6F93B49",
"34F7286605A122369540141DED79B8957255DA2D4155ABBF5A8DBB89C8EB7EDE8EEEF1DAA46DC29D751D045DC3B1D658BB64B80FF8589EDDB3824B13DA235A6B",
"3B3B48434BE27B9EABABBA43BF6B35F14B30F6A88DC2E750C358470D6B3AA3C18E47DB4017FA55106D8252F016371A00F5F8B070B74BA5F23CFFC5511C9F09F0",
"BA289EBD6562C48C3E10A8AD6CE02E73433D1E93D7C9279D4D60A7E879EE11F441A000F48ED9F7C4ED87A45136D7DCCDCA482109C78A51062B3BA4044ADA2469",
"022939E2386C5A37049856C850A2BB10A13DFEA4212B4C732A8840A9FFA5FAF54875C5448816B2785A007DA8A8D2BC7D71A54E4E6571F10B600CBDB25D13EDE3",
"E6FEC19D89CE8717B1A087024670FE026F6C7CBDA11CAEF959BB2D351BF856F8055D1C0EBDAAA9D1B17886FC2C562B5E99642FC064710C0D3488A02B5ED7F6FD",
"94C96F02A8F576ACA32BA61C2B206F907285D9299B83AC175C209A8D43D53BFE683DD1D83E7549CB906C28F59AB7C46F8751366A28C39DD5FE2693C9019666C8",
"31A0CD215EBD2CB61DE5B9EDC91E6195E31C59A5648D5C9F737E125B2605708F2E325AB3381C8DCE1A3E958886F1ECDC60318F882CFE20A24191352E617B0F21",
"91AB504A522DCE78779F4C6C6BA2E6B6DB5565C76D3E7E7C920CAF7F757EF9DB7C8FCF10E57F03379EA9BF75EB59895D96E149800B6AAE01DB778BB90AFBC989",
"D85CABC6BD5B1A01A5AFD8C6734740DA9FD1C1ACC6DB29BFC8A2E5B668B028B6B3154BFB8703FA3180251D589AD38040CEB707C4BAD1B5343CB426B61EAA49C1",
"D62EFBEC2CA9C1F8BD66CE8B3F6A898CB3F7566BA6568C618AD1FEB2B65B76C3CE1DD20F7395372FAF28427F61C9278049CF0140DF434F5633048C86B81E0399",
"7C8FDC6175439E2C3DB15BAFA7FB06143A6A23BC90F449E79DEEF73C3D492A671715C193B6FEA9F036050B946069856B897E08C00768F5EE5DDCF70B7CD6D0E0",
"58602EE7468E6BC9DF21BD51B23C005F72D6CB013F0A1B48CBEC5ECA299299F97F09F54A9A01483EAEB315A6478BAD37BA47CA1347C7C8FC9E6695592C91D723",
"27F5B79ED256B050993D793496EDF4807C1D85A7B0A67C9C4FA99860750B0AE66989670A8FFD7856D7CE411599E58C4D77B232A62BEF64D15275BE46A68235FF",
"3957A976B9F1887BF004A8DCA942C92D2B37EA52600F25E0C9BC5707D0279C00C6E85A839B0D2D8EB59C51D94788EBE62474A791CADF52CCCF20F5070B6573FC",
"EAA2376D55380BF772ECCA9CB0AA4668C95C707162FA86D518C8CE0CA9BF7362B9F2A0ADC3FF59922DF921B94567E81E452F6C1A07FC817CEBE99604B3505D38",
"C1E2C78B6B2734E2480EC550434CB5D613111ADCC21D475545C3B1B7E6FF12444476E5C055132E2229DC0F807044BB919B1A5662DD38A9EE65E243A3911AED1A",
"8AB48713389DD0FCF9F965D3CE66B1E559A1F8C58741D67683CD971354F452E62D0207A65E436C5D5D8F8EE71C6ABFE50E669004C302B31A7EA8311D4A916051",
"24CE0ADDAA4C65038BD1B1C0F1452A0B128777AABC94A29DF2FD6C7E2F85F8AB9AC7EFF516B0E0A825C84A24CFE492EAAD0A6308E46DD42FE8333AB971BB30CA",
"5154F929EE03045B6B0C0004FA778EDEE1D139893267CC84825AD7B36C63DE32798E4A166D24686561354F63B00709A1364B3C241DE3FEBF0754045897467CD4",
"E74E907920FD87BD5AD636DD11085E50EE70459C443E1CE5809AF2BC2EBA39F9E6D7128E0E3712C316DA06F4705D78A4838E28121D4344A2C79C5E0DB307A677",
"BF91A22334BAC20F3FD80663B3CD06C4E8802F30E6B59F90D3035CC9798A217ED5A31ABBDA7FA6842827BDF2A7A1C21F6FCFCCBB54C6C52926F32DA816269BE1",
"D9D5C74BE5121B0BD742F26BFFB8C89F89171F3F934913492B0903C271BBE2B3395EF259669BEF43B57F7FCC3027DB01823F6BAEE66E4F9FEAD4D6726C741FCE",
"50C8B8CF34CD879F80E2FAAB3230B0C0E1CC3E9DCADEB1B9D97AB923415DD9A1FE38ADDD5C11756C67990B256E95AD6D8F9FEDCE10BF1C90679CDE0ECF1BE347",
"0A386E7CD5DD9B77A035E09FE6FEE2C8CE61B5383C87EA43205059C5E4CD4F4408319BB0A82360F6A58E6C9CE3F487C446063BF813BC6BA535E17FC1826CFC91",
"1F1459CB6B61CBAC5F0EFE8FC487538F42548987FCD56221CFA7BEB22504769E792C45ADFB1D6B3D60D7B749C8A75B0BDF14E8EA721B95DCA538CA6E25711209",
"E58B3836B7D8FEDBB50CA5725C6571E74C0785E97821DAB8B6298C10E4C079D4A6CDF22F0FEDB55032925C16748115F01A105E77E00CEE3D07924DC0D8F90659",
"B929CC6505F020158672DEDA56D0DB081A2EE34C00C1100029BDF8EA98034FA4BF3E8655EC697FE36F40553C5BB46801644A627D3342F4FC92B61F03290FB381",
"72D353994B49D3E03153929A1E4D4F188EE58AB9E72EE8E512F29BC773913819CE057DDD7002C0433EE0A16114E3D156DD2C4A7E80EE53378B8670F23E33EF56",
"C70EF9BFD775D408176737A0736D68517CE1AAAD7E81A93C8C1ED967EA214F56C8A377B1763E676615B60F3988241EAE6EAB9685A5124929D28188F29EAB06F7",
"C230F0802679CB33822EF8B3B21BF7A9A28942092901D7DAC3760300831026CF354C9232DF3E084D9903130C601F63C1F4A4A4B8106E468CD443BBE5A734F45F",
"6F43094CAFB5EBF1F7A4937EC50F56A4C9DA303CBB55AC1F27F1F1976CD96BEDA9464F0E7B9C54620B8A9FBA983164B8BE3578425A024F5FE199C36356B88972",
"3745273F4C38225DB2337381871A0C6AAFD3AF9B018C88AA02025850A5DC3A42A1A3E03E56CBF1B0876D63A441F1D2856A39B8801EB5AF325201C415D65E97FE",
"C50C44CCA3EC3EDAAE779A7E179450EBDDA2F97067C690AA6C5A4AC7C30139BB27C0DF4DB3220E63CB110D64F37FFE078DB72653E2DAACF93AE3F0A2D1A7EB2E",
"8AEF263E385CBC61E19B28914243262AF5AFE8726AF3CE39A79C27028CF3ECD3F8D2DFD9CFC9AD91B58F6F20778FD5F02894A3D91C7D57D1E4B866A7F364B6BE",
"28696141DE6E2D9BCB3235578A66166C1448D3E905A1B482D423BE4BC5369BC8C74DAE0ACC9CC123E1D8DDCE9F97917E8C019C552DA32D39D2219B9ABF0FA8C8",
"2FB9EB2085830181903A9DAFE3DB428EE15BE7662224EFD643371FB25646AEE716E531ECA69B2BDC8233F1A8081FA43DA1500302975A77F42FA592136710E9DC",
"66F9A7143F7A3314A669BF2E24BBB35014261D639F495B6C9C1F104FE8E320ACA60D4550D69D52EDBD5A3CDEB4014AE65B1D87AA770B69AE5C15F4330B0B0AD8",
"F4C4DD1D594C3565E3E25CA43DAD82F62ABEA4835ED4CD811BCD975E46279828D44D4C62C3679F1B7F7B9DD4571D7B49557347B8C5460CBDC1BEF690FB2A08C0",
"8F1DC9649C3A84551F8F6E91CAC68242A43B1F8F328EE92280257387FA7559AA6DB12E4AEADC2D26099178749C6864B357F3F83B2FB3EFA8D2A8DB056BED6BCC",
"3139C1A7F97AFD1675D460EBBC07F2728AA150DF849624511EE04B743BA0A833092F18C12DC91B4DD243F333402F59FE28ABDBBBAE301E7B659C7A26D5C0F979",
"06F94A2996158A819FE34C40DE3CF0379FD9FB85B3E363BA3926A0E7D960E3F4C2E0C70C7CE0CCB2A64FC29869F6E7AB12BD4D3F14FCE943279027E785FB5C29",
"C29C399EF3EEE8961E87565C1CE263925FC3D0CE267D13E48DD9E732EE67B0F69FAD56401B0F10FCAAC119201046CCA28C5B14ABDEA3212AE65562F7F138DB3D",
"4CEC4C9DF52EEF05C3F6FAAA9791BC7445937183224ECC37A1E58D0132D35617531D7E795F52AF7B1EB9D147DE1292D345FE341823F8E6BC1E5BADCA5C656108",
"898BFBAE93B3E18D00697EAB7D9704FA36EC339D076131CEFDF30EDBE8D9CC81C3A80B129659B163A323BAB9793D4FEED92D54DAE966C77529764A09BE88DB45",
"EE9BD0469D3AAF4F14035BE48A2C3B84D9B4B1FFF1D945E1F1C1D38980A951BE197B25FE22C731F20AEACC930BA9C4A1F4762227617AD350FDABB4E80273A0F4",
"3D4D3113300581CD96ACBF091C3D0F3C310138CD6979E6026CDE623E2DD1B24D4A8638BED1073344783AD0649CC6305CCEC04BEB49F31C633088A99B65130267",
"95C0591AD91F921AC7BE6D9CE37E0663ED8011C1CFD6D0162A5572E94368BAC02024485E6A39854AA46FE38E97D6C6B1947CD272D86B06BB5B2F78B9B68D559D",
"227B79DED368153BF46C0A3CA978BFDBEF31F3024A5665842468490B0FF748AE04E7832ED4C9F49DE9B1706709D623E5C8C15E3CAECAE8D5E433430FF72F20EB",
"5D34F3952F0105EEF88AE8B64C6CE95EBFADE0E02C69B08762A8712D2E4911AD3F941FC4034DC9B2E479FDBCD279B902FAF5D838BB2E0C6495D372B5B7029813",
"7F939BF8353ABCE49E77F14F3750AF20B7B03902E1A1E7FB6AAF76D0259CD401A83190F15640E74F3E6C5A90E839C7821F6474757F75C7BF9002084DDC7A62DC",
"062B61A2F9A33A71D7D0A06119644C70B0716A504DE7E5E1BE49BD7B86E7ED6817714F9F0FC313D06129597E9A2235EC8521DE36F7290A90CCFC1FFA6D0AEE29",
"F29E01EEAE64311EB7F1C6422F946BF7BEA36379523E7B2BBABA7D1D34A22D5EA5F1C5A09D5CE1FE682CCED9A4798D1A05B46CD72DFF5C1B355440B2A2D476BC",
"EC38CD3BBAB3EF35D7CB6D5C914298351D8A9DC97FCEE051A8A02F58E3ED6184D0B7810A5615411AB1B95209C3C810114FDEB22452084E77F3F847C6DBAAFE16",
"C2AEF5E0CA43E82641565B8CB943AA8BA53550CAEF793B6532FAFAD94B816082F0113A3EA2F63608AB40437ECC0F0229CB8FA224DCF1C478A67D9B64162B92D1",
"15F534EFFF7105CD1C254D074E27D5898B89313B7D366DC2D7D87113FA7D53AAE13F6DBA487AD8103D5E854C91FDB6E1E74B2EF6D1431769C30767DDE067A35C",
"89ACBCA0B169897A0A2714C2DF8C95B5B79CB69390142B7D6018BB3E3076B099B79A964152A9D912B1B86412B7E372E9CECAD7F25D4CBAB8A317BE36492A67D7",
"E3C0739190ED849C9C962FD9DBB55E207E624FCAC1EB417691515499EEA8D8267B7E8F1287A63633AF5011FDE8C4DDF55BFDF722EDF88831414F2CFAED59CB9A",
"8D6CF87C08380D2D1506EEE46FD4222D21D8C04E585FBFD08269C98F702833A156326A0724656400EE09351D57B440175E2A5DE93CC5F80DB6DAF83576CF75FA",
"DA24BEDE383666D563EEED37F6319BAF20D5C75D1635A6BA5EF4CFA1AC95487E96F8C08AF600AAB87C986EBAD49FC70A58B4890B9C876E091016DAF49E1D322E",
"F9D1D1B1E87EA7AE753A029750CC1CF3D0157D41805E245C5617BB934E732F0AE3180B78E05BFE76C7C3051E3E3AC78B9B50C05142657E1E03215D6EC7BFD0FC",
"11B7BC1668032048AA43343DE476395E814BBBC223678DB951A1B03A021EFAC948CFBE215F97FE9A72A2F6BC039E3956BFA417C1A9F10D6D7BA5D3D32FF323E5",
"B8D9000E4FC2B066EDB91AFEE8E7EB0F24E3A201DB8B6793C0608581E628ED0BCC4E5AA6787992A4BCC44E288093E63EE83ABD0BC3EC6D0934A674A4DA13838A",
"CE325E294F9B6719D6B61278276AE06A2564C03BB0B783FAFE785BDF89C7D5ACD83E78756D301B445699024EAEB77B54D477336EC2A4F332F2B3F88765DDB0C3",
"29ACC30E9603AE2FCCF90BF97E6CC463EBE28C1B2F9B4B765E70537C25C702A29DCBFBF14C99C54345BA2B51F17B77B5F15DB92BBAD8FA95C471F5D070A137CC",
"3379CBAAE562A87B4C0425550FFDD6BFE1203F0D666CC7EA095BE407A5DFE61EE91441CD5154B3E53B4F5FB31AD4C7A9AD5C7AF4AE679AA51A54003A54CA6B2D",
"3095A349D245708C7CF550118703D7302C27B60AF5D4E67FC978F8A4E60953C7A04F92FCF41AEE64321CCB707A895851552B1E37B00BC5E6B72FA5BCEF9E3FFF",
"07262D738B09321F4DBCCEC4BB26F48CB0F0ED246CE0B31B9A6E7BC683049F1F3E5545F28CE932DD985C5AB0F43BD6DE0770560AF329065ED2E49D34624C2CBB",
"B6405ECA8EE3316C87061CC6EC18DBA53E6C250C63BA1F3BAE9E55DD3498036AF08CD272AA24D713C6020D77AB2F3919AF1A32F307420618AB97E73953994FB4",
"7EE682F63148EE45F6E5315DA81E5C6E557C2C34641FC509C7A5701088C38A74756168E2CD8D351E88FD1A451F360A01F5B2580F9B5A2E8CFC138F3DD59A3FFC",
"1D263C179D6B268F6FA016F3A4F29E943891125ED8593C81256059F5A7B44AF2DCB2030D175C00E62ECAF7EE96682AA07AB20A611024A28532B1C25B86657902",
"106D132CBDB4CD2597812846E2BC1BF732FEC5F0A5F65DBB39EC4E6DC64AB2CE6D24630D0F15A805C3540025D84AFA98E36703C3DBEE713E72DDE8465BC1BE7E",
"0E79968226650667A8D862EA8DA4891AF56A4E3A8B6D1750E394F0DEA76D640D85077BCEC2CC86886E506751B4F6A5838F7F0B5FEF765D9DC90DCDCBAF079F08",
"521156A82AB0C4E566E5844D5E31AD9AAF144BBD5A464FDCA34DBD5717E8FF711D3FFEBBFA085D67FE996A34F6D3E4E60B1396BF4B1610C263BDBB834D560816",
"1ABA88BEFC55BC25EFBCE02DB8B9933E46F57661BAEABEB21CC2574D2A518A3CBA5DC5A38E49713440B25F9C744E75F6B85C9D8F4681F676160F6105357B8406",
"5A9949FCB2C473CDA968AC1B5D08566DC2D816D960F57E63B898FA701CF8EBD3F59B124D95BFBBEDC5F1CF0E17D5EAED0C02C50B69D8A402CABCCA4433B51FD4",
"B0CEAD09807C672AF2EB2B0F06DDE46CF5370E15A4096B1A7D7CBB36EC31C205FBEFCA00B7A4162FA89FB4FB3EB78D79770C23F44E7206664CE3CD931C291E5D",
"BB6664931EC97044E45B2AE420AE1C551A8874BC937D08E969399C3964EBDBA8346CDD5D09CAAFE4C28BA7EC788191CECA65DDD6F95F18583E040D0F30D0364D",
"65BC770A5FAA3792369803683E844B0BE7EE96F29F6D6A35568006BD5590F9A4EF639B7A8061C7B0424B66B60AC34AF3119905F33A9D8C3AE18382CA9B689900",
"EA9B4DCA333336AAF839A45C6EAA48B8CB4C7DDABFFEA4F643D6357EA6628A480A5B45F2B052C1B07D1FEDCA918B6F1139D80F74C24510DCBAA4BE70EACC1B06",
"E6342FB4A780AD975D0E24BCE149989B91D360557E87994F6B457B895575CC02D0C15BAD3CE7577F4C63927FF13F3E381FF7E72BDBE745324844A9D27E3F1C01",
"3E209C9B33E8E461178AB46B1C64B49A07FB745F1C8BC95FBFB94C6B87C69516651B264EF980937FAD41238B91DDC011A5DD777C7EFD4494B4B6ECD3A9C22AC0",
"FD6A3D5B1875D80486D6E69694A56DBB04A99A4D051F15DB2689776BA1C4882E6D462A603B7015DC9F4B7450F05394303B8652CFB404A266962C41BAE6E18A94",
"951E27517E6BAD9E4195FC8671DEE3E7E9BE69CEE1422CB9FECFCE0DBA875F7B310B93EE3A3D558F941F635F668FF832D2C1D033C5E2F0997E4C66F147344E02",
"8EBA2F874F1AE84041903C7C4253C82292530FC8509550BFDC34C95C7E2889D5650B0AD8CB988E5C4894CB87FBFBB19612EA93CCC4C5CAD17158B9763464B492",
"16F712EAA1B7C6354719A8E7DBDFAF55E4063A4D277D947550019B38DFB564830911057D50506136E2394C3B28945CC964967D54E3000C2181626CFB9B73EFD2",
"C39639E7D5C7FB8CDD0FD3E6A52096039437122F21C78F1679CEA9D78A734C56ECBEB28654B4F18E342C331F6F7229EC4B4BC281B2D80A6EB50043F31796C88C",
"72D081AF99F8A173DCC9A0AC4EB3557405639A29084B54A40172912A2F8A395129D5536F0918E902F9E8FA6000995F4168DDC5F893011BE6A0DBC9B8A1A3F5BB",
"C11AA81E5EFD24D5FC27EE586CFD8847FBB0E27601CCECE5ECCA0198E3C7765393BB74457C7E7A27EB9170350E1FB53857177506BE3E762CC0F14D8C3AFE9077",
"C28F2150B452E6C0C424BCDE6F8D72007F9310FED7F2F87DE0DBB64F4479D6C1441BA66F44B2ACCEE61609177ED340128B407ECEC7C64BBE50D63D22D8627727",
"F63D88122877EC30B8C8B00D22E89000A966426112BD44166E2F525B769CCBE9B286D437A0129130DDE1A86C43E04BEDB594E671D98283AFE64CE331DE9828FD",
"348B0532880B88A6614A8D7408C3F913357FBB60E995C60205BE9139E74998AEDE7F4581E42F6B52698F7FA1219708C14498067FD1E09502DE83A77DD281150C",
"5133DC8BEF725359DFF59792D85EAF75B7E1DCD1978B01C35B1B85FCEBC63388AD99A17B6346A217DC1A9622EBD122ECF6913C4D31A6B52A695B86AF00D741A0",
"2753C4C0E98ECAD806E88780EC27FCCD0F5C1AB547F9E4BF1659D192C23AA2CC971B58B6802580BAEF8ADC3B776EF7086B2545C2987F348EE3719CDEF258C403",
"B1663573CE4B9D8CAEFC865012F3E39714B9898A5DA6CE17C25A6A47931A9DDB9BBE98ADAA553BEED436E89578455416C2A52A525CF2862B8D1D49A2531B7391",
"64F58BD6BFC856F5E873B2A2956EA0EDA0D6DB0DA39C8C7FC67C9F9FEEFCFF3072CDF9E6EA37F69A44F0C61AA0DA3693C2DB5B54960C0281A088151DB42B11E8",
"0764C7BE28125D9065C4B98A69D60AEDE703547C66A12E17E1C618994132F5EF82482C1E3FE3146CC65376CC109F0138ED9A80E49F1F3C7D610D2F2432F20605",
"F748784398A2FF03EBEB07E155E66116A839741A336E32DA71EC696001F0AD1B25CD48C69CFCA7265ECA1DD71904A0CE748AC4124F3571076DFA7116A9CF00E9",
"3F0DBC0186BCEB6B785BA78D2A2A013C910BE157BDAFFAE81BB6663B1A73722F7F1228795F3ECADA87CF6EF0078474AF73F31ECA0CC200ED975B6893F761CB6D",
"D4762CD4599876CA75B2B8FE249944DBD27ACE741FDAB93616CBC6E425460FEB51D4E7ADCC38180E7FC47C89024A7F56191ADB878DFDE4EAD62223F5A2610EFE",
"CD36B3D5B4C91B90FCBBA79513CFEE1907D8645A162AFD0CD4CF4192D4A5F4C892183A8EACDB2B6B6A9D9AA8C11AC1B261B380DBEE24CA468F1BFD043C58EEFE",
"98593452281661A53C48A9D8CD790826C1A1CE567738053D0BEE4A91A3D5BD92EEFDBABEBE3204F2031CA5F781BDA99EF5D8AE56E5B04A9E1ECD21B0EB05D3E1",
"771F57DD2775CCDAB55921D3E8E30CCF484D61FE1C1B9C2AE819D0FB2A12FAB9BE70C4A7A138DA84E8280435DAADE5BBE66AF0836A154F817FB17F3397E725A3",
"C60897C6F828E21F16FBB5F15B323F87B6C8955EABF1D38061F707F608ABDD993FAC3070633E286CF8339CE295DD352DF4B4B40B2F29DA1DD50B3A05D079E6BB",
"8210CD2C2D3B135C2CF07FA0D1433CD771F325D075C6469D9C7F1BA0943CD4AB09808CABF4ACB9CE5BB88B498929B4B847F681AD2C490D042DB2AEC94214B06B",
"1D4EDFFFD8FD80F7E4107840FA3AA31E32598491E4AF7013C197A65B7F36DD3AC4B478456111CD4309D9243510782FA31B7C4C95FA951520D020EB7E5C36E4EF",
"AF8E6E91FAB46CE4873E1A50A8EF448CC29121F7F74DEEF34A71EF89CC00D9274BC6C2454BBB3230D8B2EC94C62B1DEC85F3593BFA30EA6F7A44D7C09465A253",
"29FD384ED4906F2D13AA9FE7AF905990938BED807F1832454A372AB412EEA1F5625A1FCC9AC8343B7C67C5ABA6E0B1CC4644654913692C6B39EB9187CEACD3EC",
"A268C7885D9874A51C44DFFED8EA53E94F78456E0B2ED99FF5A3924760813826D960A15EDBEDBB5DE5226BA4B074E71B05C55B9756BB79E55C02754C2C7B6C8A",
"0CF8545488D56A86817CD7ECB10F7116B7EA530A45B6EA497B6C72C997E09E3D0DA8698F46BB006FC977C2CD3D1177463AC9057FDD1662C85D0C126443C10473",
"B39614268FDD8781515E2CFEBF89B4D5402BAB10C226E6344E6B9AE000FB0D6C79CB2F3EC80E80EAEB1980D2F8698916BD2E9F747236655116649CD3CA23A837",
"74BEF092FC6F1E5DBA3663A3FB003B2A5BA257496536D99F62B9D73F8F9EB3CE9FF3EEC709EB883655EC9EB896B9128F2AFC89CF7D1AB58A72F4A3BF034D2B4A",
"3A988D38D75611F3EF38B8774980B33E573B6C57BEE0469BA5EED9B44F29945E7347967FBA2C162E1C3BE7F310F2F75EE2381E7BFD6B3F0BAEA8D95DFB1DAFB1",
"58AEDFCE6F67DDC85A28C992F1C0BD0969F041E66F1EE88020A125CBFCFEBCD61709C9C4EBA192C15E69F020D462486019FA8DEA0CD7A42921A19D2FE546D43D",
"9347BD291473E6B4E368437B8E561E065F649A6D8ADA479AD09B1999A8F26B91CF6120FD3BFE014E83F23ACFA4C0AD7B3712B2C3C0733270663112CCD9285CD9",
"B32163E7C5DBB5F51FDC11D2EAC875EFBBCB7E7699090A7E7FF8A8D50795AF5D74D9FF98543EF8CDF89AC13D0485278756E0EF00C817745661E1D59FE38E7537",
"1085D78307B1C4B008C57A2E7E5B234658A0A82E4FF1E4AAAC72B312FDA0FE27D233BC5B10E9CC17FDC7697B540C7D95EB215A19A1A0E20E1ABFA126EFD568C7",
"4E5C734C7DDE011D83EAC2B7347B373594F92D7091B9CA34CB9C6F39BDF5A8D2F134379E16D822F6522170CCF2DDD55C84B9E6C64FC927AC4CF8DFB2A17701F2",
"695D83BD990A1117B3D0CE06CC888027D12A054C2677FD82F0D4FBFC93575523E7991A5E35A3752E9B70CE62992E268A877744CDD435F5F130869C9A2074B338",
"A6213743568E3B3158B9184301F3690847554C68457CB40FC9A4B8CFD8D4A118C301A07737AEDA0F929C68913C5F51C80394F53BFF1C3E83B2E40CA97EBA9E15",
"D444BFA2362A96DF213D070E33FA841F51334E4E76866B8139E8AF3BB3398BE2DFADDCBC56B9146DE9F68118DC5829E74B0C28D7711907B121F9161CB92B69A9",
"142709D62E28FCCCD0AF97FAD0F8465B971E82201DC51070FAA0372AA43E92484BE1C1E73BA10906D5D1853DB6A4106E0A7BF9800D373D6DEE2D46D62EF2A461"
};
}
}

34
csharp/Blake2Sharp.sln Normal file
View File

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{98C3F5AC-1FDF-4AAF-B067-A9E9C663D87B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blake2Sharp", "Blake2Sharp\Blake2Sharp.csproj", "{E21AB364-9130-4F14-ABE1-18FA0C089130}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blake2Sharp.Tests", "Blake2Sharp.Tests\Blake2Sharp.Tests.csproj", "{A32451B3-03A3-4CB3-AD9F-1408143D6AB7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blake2Sharp.CompressionCodeGen", "Blake2Sharp.CompressionCodeGen\Blake2Sharp.CompressionCodeGen.csproj", "{17466328-5736-4EA1-A88D-CE016CCA2E80}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E21AB364-9130-4F14-ABE1-18FA0C089130}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E21AB364-9130-4F14-ABE1-18FA0C089130}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E21AB364-9130-4F14-ABE1-18FA0C089130}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E21AB364-9130-4F14-ABE1-18FA0C089130}.Release|Any CPU.Build.0 = Release|Any CPU
{A32451B3-03A3-4CB3-AD9F-1408143D6AB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A32451B3-03A3-4CB3-AD9F-1408143D6AB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A32451B3-03A3-4CB3-AD9F-1408143D6AB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A32451B3-03A3-4CB3-AD9F-1408143D6AB7}.Release|Any CPU.Build.0 = Release|Any CPU
{17466328-5736-4EA1-A88D-CE016CCA2E80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17466328-5736-4EA1-A88D-CE016CCA2E80}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17466328-5736-4EA1-A88D-CE016CCA2E80}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17466328-5736-4EA1-A88D-CE016CCA2E80}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,72 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
namespace Blake2Sharp
{
public static class Blake2B
{
public static Hasher Create()
{
return Create(new Blake2BConfig());
}
public static Hasher Create(Blake2BConfig config)
{
return new Blake2BHasher(config);
}
/*public static Hasher CreateParallel(int parallelism = 4)
{
return CreateParallel(null, parallelism);
}
public static Hasher CreateParallel(Blake2Config config, int parallelism = 4)
{
if (parallelism < 2)
throw new ArgumentOutOfRangeException("parallelism", "parallism must be at least 2");
throw new NotImplementedException();
}
public static Hasher CreateTreeHasher(Blake2BConfig config, Blake2TreeConfig treeConfig)
{
}
public static NodeHasher CreateNodeHasher(Blake2BConfig config, Blake2TreeConfig treeConfig)
{
}*/
public static byte[] ComputeHash(byte[] data, int start, int count)
{
return ComputeHash(data, start, count, null);
}
public static byte[] ComputeHash(byte[] data)
{
return ComputeHash(data, 0, data.Length, null);
}
public static byte[] ComputeHash(byte[] data, Blake2BConfig config)
{
return ComputeHash(data, 0, data.Length, config);
}
public static byte[] ComputeHash(byte[] data, int start, int count, Blake2BConfig config)
{
var hasher = Create(config);
hasher.Update(data, start, count);
return hasher.Finish();
}
//public static byte[] ComputeParallelHash(byte[] data);
//public static byte[] ComputeParallelHash(byte[] data, Blake2Config config);
}
}

View File

@ -0,0 +1,57 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Text;
namespace Blake2Sharp
{
public sealed class Blake2BConfig : ICloneable
{
public byte[] Personalization { get; set; }
public byte[] Salt { get; set; }
public byte[] Key { get; set; }
public int OutputSizeInBytes { get; set; }
public int OutputSizeInBits
{
get { return OutputSizeInBytes * 8; }
set
{
if (value % 8 == 0)
throw new ArgumentException("Output size must be a multiple of 8 bits");
OutputSizeInBytes = value / 8;
}
}
public Blake2BConfig()
{
OutputSizeInBytes = 64;
}
public Blake2BConfig Clone()
{
var result = new Blake2BConfig();
result.OutputSizeInBytes = OutputSizeInBytes;
if (Key != null)
result.Key = (byte[])Key.Clone();
if (Personalization != null)
result.Personalization = (byte[])Personalization.Clone();
if (Salt != null)
result.Salt = (byte[])Salt.Clone();
return result;
}
object ICloneable.Clone()
{
return Clone();
}
}
}

View File

@ -0,0 +1,1455 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
namespace Blake2Sharp
{
#if true
public sealed partial class Blake2BCore
{
partial void Compress(byte[] block, int start)
{
var h = _h;
var m = _m;
if (BitConverter.IsLittleEndian)
{
Buffer.BlockCopy(block, start, m, 0, BlockSizeInBytes);
}
else
{
for (int i = 0; i < 16; ++i)
m[i] = BytesToUInt64(block, start + (i << 3));
}
/*var m0 = m[0];
var m1 = m[1];
var m2 = m[2];
var m3 = m[3];
var m4 = m[4];
var m5 = m[5];
var m6 = m[6];
var m7 = m[7];
var m8 = m[8];
var m9 = m[9];
var m10 = m[10];
var m11 = m[11];
var m12 = m[12];
var m13 = m[13];
var m14 = m[14];
var m15 = m[15];*/
var v0 = h[0];
var v1 = h[1];
var v2 = h[2];
var v3 = h[3];
var v4 = h[4];
var v5 = h[5];
var v6 = h[6];
var v7 = h[7];
var v8 = IV0;
var v9 = IV1;
var v10 = IV2;
var v11 = IV3;
var v12 = IV4 ^ _counter0;
var v13 = IV5 ^ _counter1;
var v14 = IV6 ^ _finalizationFlag0;
var v15 = IV7 ^ _finalizationFlag1;
// Rounds
//System.Diagnostics.Debugger.Break();
// ##### Round(0) #####
// G(0, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[0];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[1];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(0, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[2];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[3];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(0, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[4];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[5];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(0, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[6];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[7];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(0, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[8];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[9];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(0, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[10];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[11];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(0, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[12];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[13];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(0, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[14];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[15];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(1) #####
// G(1, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[14];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[10];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(1, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[4];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[8];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(1, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[9];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[15];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(1, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[13];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[6];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(1, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[1];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[12];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(1, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[0];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[2];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(1, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[11];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[7];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(1, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[5];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[3];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(2) #####
// G(2, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[11];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[8];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(2, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[12];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[0];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(2, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[5];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[2];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(2, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[15];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[13];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(2, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[10];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[14];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(2, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[3];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[6];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(2, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[7];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[1];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(2, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[9];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[4];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(3) #####
// G(3, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[7];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[9];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(3, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[3];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[1];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(3, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[13];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[12];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(3, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[11];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[14];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(3, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[2];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[6];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(3, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[5];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[10];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(3, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[4];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[0];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(3, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[15];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[8];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(4) #####
// G(4, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[9];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[0];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(4, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[5];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[7];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(4, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[2];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[4];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(4, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[10];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[15];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(4, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[14];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[1];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(4, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[11];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[12];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(4, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[6];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[8];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(4, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[3];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[13];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(5) #####
// G(5, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[2];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[12];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(5, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[6];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[10];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(5, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[0];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[11];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(5, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[8];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[3];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(5, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[4];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[13];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(5, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[7];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[5];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(5, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[15];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[14];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(5, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[1];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[9];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(6) #####
// G(6, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[12];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[5];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(6, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[1];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[15];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(6, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[14];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[13];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(6, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[4];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[10];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(6, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[0];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[7];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(6, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[6];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[3];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(6, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[9];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[2];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(6, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[8];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[11];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(7) #####
// G(7, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[13];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[11];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(7, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[7];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[14];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(7, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[12];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[1];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(7, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[3];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[9];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(7, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[5];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[0];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(7, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[15];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[4];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(7, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[8];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[6];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(7, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[2];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[10];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(8) #####
// G(8, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[6];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[15];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(8, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[14];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[9];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(8, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[11];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[3];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(8, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[0];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[8];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(8, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[12];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[2];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(8, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[13];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[7];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(8, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[1];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[4];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(8, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[10];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[5];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(9) #####
// G(9, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[10];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[2];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(9, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[8];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[4];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(9, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[7];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[6];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(9, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[1];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[5];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(9, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[15];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[11];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(9, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[9];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[14];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(9, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[3];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[12];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(9, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[13];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[0];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(10) #####
// G(10, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[0];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[1];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(10, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[2];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[3];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(10, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[4];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[5];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(10, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[6];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[7];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(10, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[8];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[9];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(10, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[10];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[11];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(10, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[12];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[13];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(10, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[14];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[15];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// ##### Round(11) #####
// G(11, 0, v0, v4, v8, v12)
v0 = v0 + v4 + m[14];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[10];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(11, 1, v1, v5, v9, v13)
v1 = v1 + v5 + m[4];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[8];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(11, 2, v2, v6, v10, v14)
v2 = v2 + v6 + m[9];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[15];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(11, 3, v3, v7, v11, v15)
v3 = v3 + v7 + m[13];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[6];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(11, 4, v0, v5, v10, v15)
v0 = v0 + v5 + m[1];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[12];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(11, 5, v1, v6, v11, v12)
v1 = v1 + v6 + m[0];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[2];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(11, 6, v2, v7, v8, v13)
v2 = v2 + v7 + m[11];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[7];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(11, 7, v3, v4, v9, v14)
v3 = v3 + v4 + m[5];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[3];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
//Finalization
h[0] ^= v0 ^ v8;
h[1] ^= v1 ^ v9;
h[2] ^= v2 ^ v10;
h[3] ^= v3 ^ v11;
h[4] ^= v4 ^ v12;
h[5] ^= v5 ^ v13;
h[6] ^= v6 ^ v14;
h[7] ^= v7 ^ v15;
}
}
#endif
}

View File

@ -0,0 +1,177 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
namespace Blake2Sharp
{
#if false
public sealed partial class Blake2BCore
{
partial void Compress(byte[] block, int start)
{
var h = _h;
var m = _m;
if (BitConverter.IsLittleEndian)
{
Buffer.BlockCopy(block, start, m, 0, BlockSizeInBytes);
}
else
{
for (int i = 0; i < 16; ++i)
m[i] = BytesToUInt64(block, start + (i << 3));
}
var v0 = h[0];
var v1 = h[1];
var v2 = h[2];
var v3 = h[3];
var v4 = h[4];
var v5 = h[5];
var v6 = h[6];
var v7 = h[7];
var v8 = IV0;
var v9 = IV1;
var v10 = IV2;
var v11 = IV3;
var v12 = IV4 ^ _counter0;
var v13 = IV5 ^ _counter1;
var v14 = IV6 ^ _finaliziationFlag0;
var v15 = IV7 ^ _finaliziationFlag1;
for (int r = 0; r < NumberOfRounds; ++r)
{
// G(r,0,v0,v4,v8,v12)
v0 = v0 + v4 + m[Sigma[16 * r + 2 * 0 + 0]];
v12 ^= v0;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v0 = v0 + v4 + m[Sigma[16 * r + 2 * 0 + 1]];
v12 ^= v0;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v8 = v8 + v12;
v4 ^= v8;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
// G(r,1,v1,v5,v9,v13)
v1 = v1 + v5 + m[Sigma[16 * r + 2 * 1 + 0]];
v13 ^= v1;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v1 = v1 + v5 + m[Sigma[16 * r + 2 * 1 + 1]];
v13 ^= v1;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v9 = v9 + v13;
v5 ^= v9;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(r,2,v2,v6,v10,v14)
v2 = v2 + v6 + m[Sigma[16 * r + 2 * 2 + 0]];
v14 ^= v2;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v2 = v2 + v6 + m[Sigma[16 * r + 2 * 2 + 1]];
v14 ^= v2;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v10 = v10 + v14;
v6 ^= v10;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(r,3,v3,v7,v11,v15)
v3 = v3 + v7 + m[Sigma[16 * r + 2 * 3 + 0]];
v15 ^= v3;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v3 = v3 + v7 + m[Sigma[16 * r + 2 * 3 + 1]];
v15 ^= v3;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v11 = v11 + v15;
v7 ^= v11;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(r,4,v0,v5,v10,v15)
v0 = v0 + v5 + m[Sigma[16 * r + 2 * 4 + 0]];
v15 ^= v0;
v15 = ((v15 >> 32) | (v15 << (64 - 32)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 24) | (v5 << (64 - 24)));
v0 = v0 + v5 + m[Sigma[16 * r + 2 * 4 + 1]];
v15 ^= v0;
v15 = ((v15 >> 16) | (v15 << (64 - 16)));
v10 = v10 + v15;
v5 ^= v10;
v5 = ((v5 >> 63) | (v5 << (64 - 63)));
// G(r,5,v1,v6,v11,v12)
v1 = v1 + v6 + m[Sigma[16 * r + 2 * 5 + 0]];
v12 ^= v1;
v12 = ((v12 >> 32) | (v12 << (64 - 32)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 24) | (v6 << (64 - 24)));
v1 = v1 + v6 + m[Sigma[16 * r + 2 * 5 + 1]];
v12 ^= v1;
v12 = ((v12 >> 16) | (v12 << (64 - 16)));
v11 = v11 + v12;
v6 ^= v11;
v6 = ((v6 >> 63) | (v6 << (64 - 63)));
// G(r,6,v2,v7,v8,v13)
v2 = v2 + v7 + m[Sigma[16 * r + 2 * 6 + 0]];
v13 ^= v2;
v13 = ((v13 >> 32) | (v13 << (64 - 32)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 24) | (v7 << (64 - 24)));
v2 = v2 + v7 + m[Sigma[16 * r + 2 * 6 + 1]];
v13 ^= v2;
v13 = ((v13 >> 16) | (v13 << (64 - 16)));
v8 = v8 + v13;
v7 ^= v8;
v7 = ((v7 >> 63) | (v7 << (64 - 63)));
// G(r,7,v3,v4,v9,v14)
v3 = v3 + v4 + m[Sigma[16 * r + 2 * 7 + 0]];
v14 ^= v3;
v14 = ((v14 >> 32) | (v14 << (64 - 32)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 24) | (v4 << (64 - 24)));
v3 = v3 + v4 + m[Sigma[16 * r + 2 * 7 + 1]];
v14 ^= v3;
v14 = ((v14 >> 16) | (v14 << (64 - 16)));
v9 = v9 + v14;
v4 ^= v9;
v4 = ((v4 >> 63) | (v4 << (64 - 63)));
}
h[0] ^= v0 ^ v8;
h[1] ^= v1 ^ v9;
h[2] ^= v2 ^ v10;
h[3] ^= v3 ^ v11;
h[4] ^= v4 ^ v12;
h[5] ^= v5 ^ v13;
h[6] ^= v6 ^ v14;
h[7] ^= v7 ^ v15;
}
}
#endif
}

View File

@ -0,0 +1,88 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
namespace Blake2Sharp
{
#if false
public sealed partial class Blake2BCore
{
private ulong[] _v = new ulong[16];
private static ulong RotateRight(ulong value, int nBits)
{
return (value >> nBits) | (value << (64 - nBits));
}
private void G(int a, int b, int c, int d, int r, int i)
{
int p = (r << 4) + i;
int p0 = Sigma[p];
int p1 = Sigma[p + 1];
var v = _v;
var m = _m;
v[a] += v[b] + m[p0];
v[d] = RotateRight(v[d] ^ v[a], 32);
v[c] += v[d];
v[b] = RotateRight(v[b] ^ v[c], 24);
v[a] += v[b] + m[p1];
v[d] = RotateRight(v[d] ^ v[a], 16);
v[c] += v[d];
v[b] = RotateRight(v[b] ^ v[c], 63);
}
partial void Compress(byte[] block, int start)
{
var v = _v;
var h = _h;
var m = _m;
for (int i = 0; i < 16; ++i)
m[i] = BytesToUInt64(block, start + (i << 3));
v[0] = h[0];
v[1] = h[1];
v[2] = h[2];
v[3] = h[3];
v[4] = h[4];
v[5] = h[5];
v[6] = h[6];
v[7] = h[7];
v[8] = IV0;
v[9] = IV1;
v[10] = IV2;
v[11] = IV3;
v[12] = IV4 ^ _counter0;
v[13] = IV5 ^ _counter1;
v[14] = IV6 ^ _finaliziationFlag0;
v[15] = IV7 ^ _finaliziationFlag1;
for (int r = 0; r < NumberOfRounds; ++r)
{
G(0, 4, 8, 12, r, 0);
G(1, 5, 9, 13, r, 2);
G(2, 6, 10, 14, r, 4);
G(3, 7, 11, 15, r, 6);
G(3, 4, 9, 14, r, 14);
G(2, 7, 8, 13, r, 12);
G(0, 5, 10, 15, r, 8);
G(1, 6, 11, 12, r, 10);
}
for (int i = 0; i < 8; ++i)
h[i] ^= v[i] ^ v[i + 8];
}
}
#endif
}

View File

@ -0,0 +1,198 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//
/*
Based on BlakeSharp
by Dominik Reichl <dominik.reichl@t-online.de>
Web: http://www.dominik-reichl.de/
If you're using this class, it would be nice if you'd mention
me somewhere in the documentation of your program, but it's
not required.
BLAKE was designed by Jean-Philippe Aumasson, Luca Henzen,
Willi Meier and Raphael C.-W. Phan.
BlakeSharp was derived from the reference C implementation.
*/
using System;
namespace Blake2Sharp
{
public sealed partial class Blake2BCore
{
private bool _isInitialized = false;
private int _bufferFilled;
private byte[] _buf = new byte[128];
private ulong[] _m = new ulong[16];
private ulong[] _h = new ulong[8];
private ulong _counter0;
private ulong _counter1;
private ulong _finalizationFlag0;
private ulong _finalizationFlag1;
private const int NumberOfRounds = 12;
private const int BlockSizeInBytes = 128;
const ulong IV0 = 0x6A09E667F3BCC908UL;
const ulong IV1 = 0xBB67AE8584CAA73BUL;
const ulong IV2 = 0x3C6EF372FE94F82BUL;
const ulong IV3 = 0xA54FF53A5F1D36F1UL;
const ulong IV4 = 0x510E527FADE682D1UL;
const ulong IV5 = 0x9B05688C2B3E6C1FUL;
const ulong IV6 = 0x1F83D9ABFB41BD6BUL;
const ulong IV7 = 0x5BE0CD19137E2179UL;
private static readonly int[] Sigma = new int[NumberOfRounds * 16] {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3
};
internal static ulong BytesToUInt64(byte[] buf, int offset)
{
return
((ulong)buf[offset + 7] << 7 * 8 |
((ulong)buf[offset + 6] << 6 * 8) |
((ulong)buf[offset + 5] << 5 * 8) |
((ulong)buf[offset + 4] << 4 * 8) |
((ulong)buf[offset + 3] << 3 * 8) |
((ulong)buf[offset + 2] << 2 * 8) |
((ulong)buf[offset + 1] << 1 * 8) |
((ulong)buf[offset]));
}
private static void UInt64ToBytes(ulong value, byte[] buf, int offset)
{
buf[offset + 7] = (byte)(value >> 7 * 8);
buf[offset + 6] = (byte)(value >> 6 * 8);
buf[offset + 5] = (byte)(value >> 5 * 8);
buf[offset + 4] = (byte)(value >> 4 * 8);
buf[offset + 3] = (byte)(value >> 3 * 8);
buf[offset + 2] = (byte)(value >> 2 * 8);
buf[offset + 1] = (byte)(value >> 1 * 8);
buf[offset] = (byte)value;
}
partial void Compress(byte[] block, int start);
public void Initialize(ulong[] config)
{
if (config == null)
throw new ArgumentNullException("config");
if (config.Length != 8)
throw new ArgumentException("config length must be 8 words");
_isInitialized = true;
_h[0] = IV0;
_h[1] = IV1;
_h[2] = IV2;
_h[3] = IV3;
_h[4] = IV4;
_h[5] = IV5;
_h[6] = IV6;
_h[7] = IV7;
_counter0 = 0;
_counter1 = 0;
_finalizationFlag0 = 0;
_finalizationFlag1 = 0;
_bufferFilled = 0;
Array.Clear(_buf, 0, _buf.Length);
for (int i = 0; i < 8; i++)
_h[i] ^= config[i];
}
public void HashCore(byte[] array, int start, int count)
{
if (!_isInitialized)
throw new InvalidOperationException("Not initialized");
if (array == null)
throw new ArgumentNullException("array");
if (start < 0)
throw new ArgumentOutOfRangeException("start");
if (count < 0)
throw new ArgumentOutOfRangeException("count");
if ((long)start + (long)count > array.Length)
throw new ArgumentOutOfRangeException("start+count");
int offset = start;
int bufferRemaining = BlockSizeInBytes - _bufferFilled;
if ((_bufferFilled > 0) && (count > bufferRemaining))
{
Array.Copy(array, offset, _buf, _bufferFilled, bufferRemaining);
_counter0 += BlockSizeInBytes;
if (_counter0 == 0)
_counter1++;
Compress(_buf, 0);
offset += bufferRemaining;
count -= bufferRemaining;
_bufferFilled = 0;
}
while (count > BlockSizeInBytes)
{
_counter0 += BlockSizeInBytes;
if (_counter0 == 0)
_counter1++;
Compress(array, offset);
offset += BlockSizeInBytes;
count -= BlockSizeInBytes;
}
if (count > 0)
{
Array.Copy(array, offset, _buf, _bufferFilled, count);
_bufferFilled += count;
}
}
public byte[] HashFinal()
{
return HashFinal(false);
}
public byte[] HashFinal(bool isEndOfLayer)
{
if (!_isInitialized)
throw new InvalidOperationException("Not initialized");
_isInitialized = false;
//Last compression
_counter0 += (uint)_bufferFilled;
_finalizationFlag0 = ulong.MaxValue;
if (isEndOfLayer)
_finalizationFlag1 = ulong.MaxValue;
for (int i = _bufferFilled; i < _buf.Length; i++)
_buf[i] = 0;
Compress(_buf, 0);
//Output
byte[] hash = new byte[64];
for (int i = 0; i < 8; ++i)
UInt64ToBytes(_h[i], hash, i << 3);
return hash;
}
}
}

View File

@ -0,0 +1,66 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Text;
namespace Blake2Sharp
{
internal class Blake2BHasher : Hasher
{
private readonly Blake2BCore core = new Blake2BCore();
private readonly ulong[] rawConfig;
private readonly byte[] key;
private readonly int outputSizeInBytes;
private static readonly Blake2BConfig DefaultConfig = new Blake2BConfig();
public override void Init()
{
core.Initialize(rawConfig);
if (key != null)
{
core.HashCore(key, 0, key.Length);
}
}
public override byte[] Finish()
{
var fullResult = core.HashFinal();
if (outputSizeInBytes != fullResult.Length)
{
var result = new byte[outputSizeInBytes];
Array.Copy(fullResult, result, result.Length);
return result;
}
else return fullResult;
}
public Blake2BHasher(Blake2BConfig config)
{
if (config == null)
config = DefaultConfig;
rawConfig = Blake2IvBuilder.ConfigB(config, null);
if (config.Key != null && config.Key.Length != 0)
{
key = new byte[128];
Array.Copy(config.Key, key, config.Key.Length);
}
outputSizeInBytes = config.OutputSizeInBytes;
Init();
}
public override void Update(byte[] data, int start, int count)
{
core.HashCore(data, start, count);
}
}
}

View File

@ -0,0 +1,52 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Text;
namespace Blake2Sharp
{
/*public class Blake2BNodeHasher : NodeHasher
{
ulong[] rawConfig;
byte[] key;
Blake2BCore core = new Blake2BCore();
public override void Init(int depth, long nodeOffset)
{
throw new NotImplementedException();
}
public override byte[] Finish(bool isEndOfLayer)
{
throw new NotImplementedException();
}
public override void Update(byte[] data, int start, int count)
{
throw new NotImplementedException();
}
public Blake2BNodeHasher(Blake2BConfig config, Blake2BTreeConfig treeConfig)
{
if (config == null)
config = DefaultConfig;
rawConfig = Blake2IvBuilder.ConfigB(config, null);
if (config.Key != null && config.Key.Length != 0)
{
key = new byte[128];
Array.Copy(config.Key, key, config.Key.Length);
}
Init(0, 0);
}
}*/
}

View File

@ -0,0 +1,52 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
namespace Blake2Sharp
{
public sealed class Blake2BTreeConfig : ICloneable
{
public int IntermediateHashSize { get; set; }
public int MaxHeight { get; set; }
public long LeafSize { get; set; }
public int FanOut { get; set; }
public Blake2BTreeConfig()
{
IntermediateHashSize = 64;
}
public Blake2BTreeConfig Clone()
{
var result = new Blake2BTreeConfig();
result.IntermediateHashSize = IntermediateHashSize;
result.MaxHeight = MaxHeight;
result.LeafSize = LeafSize;
result.FanOut = FanOut;
return result;
}
public static Blake2BTreeConfig CreateInterleaved(int parallelism)
{
var result = new Blake2BTreeConfig();
result.FanOut = parallelism;
result.MaxHeight = 2;
result.IntermediateHashSize = 64;
return result;
}
object ICloneable.Clone()
{
return Clone();
}
}
}

View File

@ -0,0 +1,76 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
namespace Blake2Sharp
{
internal static class Blake2IvBuilder
{
private static readonly Blake2BTreeConfig SequentialTreeConfig = new Blake2BTreeConfig() { IntermediateHashSize = 0, LeafSize = 0, FanOut = 1, MaxHeight = 1 };
public static ulong[] ConfigB(Blake2BConfig config, Blake2BTreeConfig treeConfig)
{
bool isSequential = treeConfig == null;
if (isSequential)
treeConfig = SequentialTreeConfig;
var rawConfig = new ulong[8];
var result = new ulong[8];
//digest length
if (config.OutputSizeInBytes <= 0 | config.OutputSizeInBytes > 64)
throw new ArgumentOutOfRangeException("config.OutputSize");
rawConfig[0] |= (ulong)(uint)config.OutputSizeInBytes;
//Key length
if (config.Key != null)
{
if (config.Key.Length > 64)
throw new ArgumentException("config.Key", "Key too long");
rawConfig[0] |= (ulong)((uint)config.Key.Length << 8);
}
// FanOut
rawConfig[0] |= (uint)treeConfig.FanOut << 16;
// Depth
rawConfig[0] |= (uint)treeConfig.MaxHeight << 24;
// Leaf length
rawConfig[0] |= ((ulong)(uint)treeConfig.LeafSize) << 32;
// Inner length
if (!isSequential && (treeConfig.IntermediateHashSize <= 0 || treeConfig.IntermediateHashSize > 64))
throw new ArgumentOutOfRangeException("treeConfig.TreeIntermediateHashSize");
rawConfig[2] |= (uint)treeConfig.IntermediateHashSize << 8;
// Salt
if (config.Salt != null)
{
if (config.Salt.Length != 16)
throw new ArgumentException("config.Salt has invalid length");
rawConfig[4] = Blake2BCore.BytesToUInt64(config.Salt, 0);
rawConfig[5] = Blake2BCore.BytesToUInt64(config.Salt, 8);
}
// Personalization
if (config.Personalization != null)
{
if (config.Personalization.Length != 16)
throw new ArgumentException("config.Personalization has invalid length");
rawConfig[6] = Blake2BCore.BytesToUInt64(config.Personalization, 0);
rawConfig[6] = Blake2BCore.BytesToUInt64(config.Personalization, 8);
}
return rawConfig;
}
public static void ConfigBSetNode(ulong[] rawConfig, byte depth, ulong nodeOffset)
{
rawConfig[1] = nodeOffset;
rawConfig[2] = (rawConfig[2] & ~0xFFul) | depth;
}
}
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E21AB364-9130-4F14-ABE1-18FA0C089130}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Blake2Sharp</RootNamespace>
<AssemblyName>Blake2Sharp</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Blake2B.cs" />
<Compile Include="Blake2BCore.cs" />
<Compile Include="Blake2BNodeHasher.cs" />
<Compile Include="Blake2BConfig.cs" />
<Compile Include="Blake2BCore-FullyUnrolled.cs" />
<Compile Include="Blake2IvBuilder.cs" />
<Compile Include="Blake2BTreeConfig.cs" />
<Compile Include="Blake2BCore-Simple.cs" />
<Compile Include="Blake2BCore-Inline.cs" />
<Compile Include="Blake2BHasher.cs" />
<Compile Include="NodeHasher.cs" />
<Compile Include="Hasher.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TreeHasher.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,60 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace Blake2Sharp
{
public abstract class Hasher
{
public abstract void Init();
public abstract byte[] Finish();
public abstract void Update(byte[] data, int start, int count);
public void Update(byte[] data)
{
Update(data, 0, data.Length);
}
public HashAlgorithm AsHashAlgorithm()
{
return new HashAlgorithmAdapter(this);
}
internal class HashAlgorithmAdapter : HashAlgorithm
{
private readonly Hasher _hasher;
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
_hasher.Update(array, ibStart, cbSize);
}
protected override byte[] HashFinal()
{
return _hasher.Finish();
}
public override void Initialize()
{
_hasher.Init();
}
public HashAlgorithmAdapter(Hasher hasher)
{
_hasher = hasher;
}
}
}
}

View File

@ -0,0 +1,30 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace Blake2Sharp
{
public abstract class NodeHasher
{
public abstract void Init(int depth, long nodeOffset);
public abstract byte[] Finish(bool isEndOfLayer);
public abstract void Update(byte[] data, int start, int count);
public void Update(byte[] data)
{
Update(data, 0, data.Length);
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Blake2Sharp")]
[assembly: AssemblyDescription("Blake2 Hashfunction")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("CodesInChaos")]
[assembly: AssemblyProduct("Blake2Sharp")]
[assembly: AssemblyCopyright("Public Domain")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b7361e6c-1a16-4653-9afb-134066503c8f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,77 @@
// BLAKE2 reference source code package - C# implementation
// Written in 2012 by Christian Winnerlein <codesinchaos@gmail.com>
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
using System;
using System.Collections.Generic;
using System.Text;
namespace Blake2Sharp
{
/*public class TreeHasher : Hasher
{
NodeHasher nodeHasher;
int maxDepth;
int maxLeafSize;
int currentLeafSize;
int fanOut;
List<byte[]>[] intermediateHashes;
long[] counts;
public override void Init()
{
intermediateHashes = new List<byte[]>[maxDepth];
counts = new long[maxDepth];
}
public override byte[] Finish()
{
for (int layer = 0; layer < intermediateHashes.Length; layer++)
{
if (intermediateHashes[layer].Count > 0)
{
nodeHasher.Init(layer, counts[layer]);
foreach (var hash in intermediateHashes[layer])
nodeHasher.Update(hash);
}
}
intermediateHashes = null;
}
public override void Update(byte[] data, int start, int count)
{
while (count > 0)
{
int toHash = Math.Min(maxLeafSize - currentLeafSize, count);
nodeHasher.Update(data, start, toHash);
start += toHash;
count -= toHash;
if (count > 0)
{
intermediateHashes[0].Add(nodeHasher.Finish(false));
for (int layer = 0; layer < intermediateHashes.Length; layer++)
{
if ((layer + 1 < maxDepth) && (intermediateHashes[layer].Count == fanOut))
{
nodeHasher.Init(layer, counts[layer]);
foreach (var hash in intermediateHashes[layer])
nodeHasher.Update(hash);
intermediateHashes[layer + 1].Add(nodeHasher.Finish);
intermediateHashes[layer].Clear();
counts[layer + 1]++;
}
}
counts[0]++;
nodeHasher.Init(0, counts[0]);
}
}
}
}*/
}

View File

@ -0,0 +1,26 @@
#define ROT(x, y)\
((x >> y)|(x << (64-y)))
#define G(r,i,a,b,c,d) \
YY G(r,i,a,b,c,d) XXX\
a = a + b + m[Sigma[16*r+2*i+0]]; XXX\
d ^= a; XXX\
d = ROT(d, 32); XXX\
c = c + d; XXX\
b ^= c; XXX\
b = ROT(b, 24); XXX\
a = a + b + m[Sigma[16*r+2*i+1]]; XXX\
d ^= a; XXX\
d = ROT(d, 16); XXX\
c = c + d; XXX\
b ^= c; XXX\
b = ROT(b, 63); XXX
G( r, 0, v0, v4, v8, v12 )
G( r, 1, v1, v5, v9, v13 )
G( r, 2, v2, v6, v10, v14 )
G( r, 3, v3, v7, v11, v15 )
G( r, 4, v0, v5, v10, v15 )
G( r, 5, v1, v6, v11, v12 )
G( r, 6, v2, v7, v8, v13 )
G( r, 7, v3, v4, v9, v14 )

133
ref/blake2-impl.h Normal file
View File

@ -0,0 +1,133 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2_IMPL_H__
#define __BLAKE2_IMPL_H__
#include <stdint.h>
static inline uint32_t load32( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
return *( uint32_t * )( src );
#else
const uint8_t *p = ( uint8_t * )src;
uint32_t w = *p++;
w |= ( uint32_t )( *p++ ) << 8;
w |= ( uint32_t )( *p++ ) << 16;
w |= ( uint32_t )( *p++ ) << 24;
return w;
#endif
}
static inline uint64_t load64( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
return *( uint64_t * )( src );
#else
const uint8_t *p = ( uint8_t * )src;
uint64_t w = *p++;
w |= ( uint64_t )( *p++ ) << 8;
w |= ( uint64_t )( *p++ ) << 16;
w |= ( uint64_t )( *p++ ) << 24;
w |= ( uint64_t )( *p++ ) << 32;
w |= ( uint64_t )( *p++ ) << 40;
w |= ( uint64_t )( *p++ ) << 48;
w |= ( uint64_t )( *p++ ) << 56;
return w;
#endif
}
static inline void store32( void *dst, uint32_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
*( uint32_t * )( dst ) = w;
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static inline void store64( void *dst, uint64_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
*( uint64_t * )( dst ) = w;
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static inline uint64_t load48( const void *src )
{
const uint8_t *p = ( const uint8_t * )src;
uint64_t w = *p++;
w |= ( uint64_t )( *p++ ) << 8;
w |= ( uint64_t )( *p++ ) << 16;
w |= ( uint64_t )( *p++ ) << 24;
w |= ( uint64_t )( *p++ ) << 32;
w |= ( uint64_t )( *p++ ) << 40;
return w;
}
static inline void store48( void *dst, uint64_t w )
{
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
}
static inline uint32_t rotl32( const uint32_t w, const unsigned c )
{
return ( w << c ) | ( w >> ( 32 - c ) );
}
static inline uint64_t rotl64( const uint64_t w, const unsigned c )
{
return ( w << c ) | ( w >> ( 64 - c ) );
}
static inline uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
}
static inline uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
}
/* prevents compiler optimizing out memset() */
static inline void secure_zero_memory( void *v, size_t n )
{
volatile uint8_t *p = ( volatile uint8_t * )v;
while( n-- ) *p++ = 0;
}
#endif

16467
ref/blake2-kat.h Normal file

File diff suppressed because it is too large Load Diff

156
ref/blake2.h Normal file
View File

@ -0,0 +1,156 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2_H__
#define __BLAKE2_H__
#include <stddef.h>
#include <stdint.h>
#if defined(_MSC_VER)
#define ALIGN(x) __declspec(align(x))
#else
#define ALIGN(x) __attribute__((aligned(x)))
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32,
BLAKE2S_KEYBYTES = 32,
BLAKE2S_SALTBYTES = 8,
BLAKE2S_PERSONALBYTES = 8
};
enum blake2b_constant
{
BLAKE2B_BLOCKBYTES = 128,
BLAKE2B_OUTBYTES = 64,
BLAKE2B_KEYBYTES = 64,
BLAKE2B_SALTBYTES = 16,
BLAKE2B_PERSONALBYTES = 16
};
#pragma pack(push, 1)
typedef struct __blake2s_param
{
uint8_t digest_length; // 1
uint8_t key_length; // 2
uint8_t fanout; // 3
uint8_t depth; // 4
uint32_t leaf_length; // 8
uint8_t node_offset[6];// 14
uint8_t node_depth; // 15
uint8_t inner_length; // 16
// uint8_t reserved[0];
uint8_t salt[BLAKE2S_SALTBYTES]; // 24
uint8_t personal[BLAKE2S_PERSONALBYTES]; // 32
} blake2s_param;
ALIGN( 64 ) typedef struct __blake2s_state
{
uint32_t h[8];
uint32_t t[2];
uint32_t f[2];
uint8_t buf[2 * BLAKE2S_BLOCKBYTES];
size_t buflen;
uint8_t last_node;
} blake2s_state ;
typedef struct __blake2b_param
{
uint8_t digest_length; // 1
uint8_t key_length; // 2
uint8_t fanout; // 3
uint8_t depth; // 4
uint32_t leaf_length; // 8
uint64_t node_offset; // 16
uint8_t node_depth; // 17
uint8_t inner_length; // 18
uint8_t reserved[14]; // 32
uint8_t salt[BLAKE2B_SALTBYTES]; // 48
uint8_t personal[BLAKE2B_PERSONALBYTES]; // 64
} blake2b_param;
ALIGN( 64 ) typedef struct __blake2b_state
{
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[2 * BLAKE2B_BLOCKBYTES];
size_t buflen;
uint8_t last_node;
} blake2b_state;
typedef struct __blake2sp_state
{
blake2s_state S[8][1];
blake2s_state R[1];
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
} blake2sp_state;
typedef struct __blake2bp_state
{
blake2b_state S[4][1];
blake2b_state R[1];
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
size_t buflen;
} blake2bp_state;
#pragma pack(pop)
// Streaming API
int blake2s_init( blake2s_state *S, const uint8_t outlen );
int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen );
int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen );
int blake2b_init( blake2b_state *S, const uint8_t outlen );
int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen );
int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen );
int blake2sp_init( blake2sp_state *S, const uint8_t outlen );
int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen );
int blake2sp_final( blake2sp_state *S, uint8_t *out, uint8_t outlen );
int blake2bp_init( blake2bp_state *S, const uint8_t outlen );
int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen );
int blake2bp_final( blake2bp_state *S, uint8_t *out, uint8_t outlen );
// Simple API
int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
int blake2sp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
int blake2bp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
static inline int blake2( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
{
return blake2b( out, in, key, outlen, inlen, keylen );
}
#if defined(__cplusplus)
}
#endif
#endif

391
ref/blake2b-ref.c Normal file
View File

@ -0,0 +1,391 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint64_t blake2b_IV[8] =
{
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
static const uint8_t blake2b_sigma[12][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
};
static inline int blake2b_set_lastnode( blake2b_state *S )
{
S->f[1] = ~0ULL;
return 0;
}
static inline int blake2b_clear_lastnode( blake2b_state *S )
{
S->f[1] = 0ULL;
return 0;
}
/* Some helper functions, not necessarily useful */
static inline int blake2b_set_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_set_lastnode( S );
S->f[0] = ~0ULL;
return 0;
}
static inline int blake2b_clear_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_clear_lastnode( S );
S->f[0] = 0ULL;
return 0;
}
static inline int blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
return 0;
}
// Parameter-related functions
static inline int blake2b_param_set_digest_length( blake2b_param *P, const uint8_t digest_length )
{
P->digest_length = digest_length;
return 0;
}
static inline int blake2b_param_set_fanout( blake2b_param *P, const uint8_t fanout )
{
P->fanout = fanout;
return 0;
}
static inline int blake2b_param_set_max_depth( blake2b_param *P, const uint8_t depth )
{
P->depth = depth;
return 0;
}
static inline int blake2b_param_set_leaf_length( blake2b_param *P, const uint32_t leaf_length )
{
store32( &P->leaf_length, leaf_length );
return 0;
}
static inline int blake2b_param_set_node_offset( blake2b_param *P, const uint64_t node_offset )
{
store64( &P->node_offset, node_offset );
return 0;
}
static inline int blake2b_param_set_node_depth( blake2b_param *P, const uint8_t node_depth )
{
P->node_depth = node_depth;
return 0;
}
static inline int blake2b_param_set_inner_length( blake2b_param *P, const uint8_t inner_length )
{
P->inner_length = inner_length;
return 0;
}
static inline int blake2b_param_set_salt( blake2b_param *P, const uint8_t salt[BLAKE2B_SALTBYTES] )
{
memcpy( P->salt, salt, BLAKE2B_SALTBYTES );
return 0;
}
static inline int blake2b_param_set_personal( blake2b_param *P, const uint8_t personal[BLAKE2B_PERSONALBYTES] )
{
memcpy( P->personal, personal, BLAKE2B_PERSONALBYTES );
return 0;
}
static inline int blake2b_init0( blake2b_state *S )
{
memset( S, 0, sizeof( blake2b_state ) );
for( int i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
return 0;
}
/* init xors IV with input parameter block */
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
{
blake2b_init0( S );
uint8_t *p = ( uint8_t * )( P );
/* IV XOR ParamBlock */
for( size_t i = 0; i < 8; ++i )
S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
return 0;
}
int blake2b_init( blake2b_state *S, const uint8_t outlen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
P->digest_length = outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store64( &P->node_offset, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store64( &P->node_offset, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2b_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
static int blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
{
uint64_t m[16];
uint64_t v[16];
int i;
for( i = 0; i < 16; ++i )
m[i] = load64( block + i * sizeof( m[i] ) );
for( i = 0; i < 8; ++i )
v[i] = S->h[i];
v[ 8] = blake2b_IV[0];
v[ 9] = blake2b_IV[1];
v[10] = blake2b_IV[2];
v[11] = blake2b_IV[3];
v[12] = S->t[0] ^ blake2b_IV[4];
v[13] = S->t[1] ^ blake2b_IV[5];
v[14] = S->f[0] ^ blake2b_IV[6];
v[15] = S->f[1] ^ blake2b_IV[7];
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2b_sigma[r][2*i+0]]; \
d = rotr64(d ^ a, 32); \
c = c + d; \
b = rotr64(b ^ c, 24); \
a = a + b + m[blake2b_sigma[r][2*i+1]]; \
d = rotr64(d ^ a, 16); \
c = c + d; \
b = rotr64(b ^ c, 63); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
ROUND( 10 );
ROUND( 11 );
for( i = 0; i < 8; ++i )
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
#undef G
#undef ROUND
return 0;
}
/* inlen now in bytes */
int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen )
{
while( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = 2 * BLAKE2B_BLOCKBYTES - left;
if( inlen > fill )
{
memcpy( S->buf + left, in, fill ); // Fill buffer
S->buflen += fill;
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf ); // Compress
memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); // Shift buffer left
S->buflen -= BLAKE2B_BLOCKBYTES;
in += fill;
inlen -= fill;
}
else // inlen <= fill
{
memcpy( S->buf + left, in, inlen );
S->buflen += inlen; // Be lazy, do not compress
in += inlen;
inlen -= inlen;
}
}
return 0;
}
/* Is this correct? */
int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen )
{
uint8_t buffer[BLAKE2B_OUTBYTES];
if( S->buflen > BLAKE2B_BLOCKBYTES )
{
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf );
S->buflen -= BLAKE2B_BLOCKBYTES;
memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen );
}
blake2b_increment_counter( S, S->buflen );
blake2b_set_lastblock( S );
memset( S->buf + S->buflen, 0, 2 * BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
blake2b_compress( S, S->buf );
for( int i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, outlen );
return 0;
}
/* inlen, at least, should be uint64_t. Others can be size_t. */
int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
{
blake2b_state S[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if( NULL == key ) keylen = 0;
if( keylen > 0 )
{
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2b_init( S, outlen ) < 0 ) return -1;
}
blake2b_update( S, ( uint8_t * )in, inlen );
blake2b_final( S, out, outlen );
return 0;
}
#if defined(BLAKE2B_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

288
ref/blake2bp-ref.c Normal file
View File

@ -0,0 +1,288 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 4
static inline int blake2bp_init_leaf( blake2b_state *S, uint8_t outlen, uint8_t keylen, uint64_t offset )
{
blake2b_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store64( &P->node_offset, offset );
P->node_depth = 0;
P->inner_length = outlen;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
static inline int blake2bp_init_root( blake2b_state *S, uint8_t outlen, uint8_t keylen )
{
blake2b_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store64( &P->node_offset, 0 );
P->node_depth = 1;
P->inner_length = outlen;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2bp_init( blake2bp_state *S, const uint8_t outlen )
{
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2bp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2bp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen )
{
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S->S[id__], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2bp_final( blake2bp_state *S, uint8_t *out, const uint8_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2B_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES;
if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES;
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left );
}
blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES );
}
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES );
blake2b_final( S->R, out, outlen );
return 0;
}
int blake2bp( uint8_t *out, const void *in, const void *key, uint8_t outlen, uint64_t inlen, uint8_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
blake2b_state S[PARALLELISM_DEGREE][1];
blake2b_state FS[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key ) keylen = 0;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; // mark last node
if( keylen > 0 )
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S[id__], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
if( inlen__ > id__ * BLAKE2B_BLOCKBYTES )
{
const size_t left = inlen__ - id__ * BLAKE2B_BLOCKBYTES;
const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES;
blake2b_update( S[id__], in__, len );
}
blake2b_final( S[id__], hash[id__], BLAKE2B_OUTBYTES );
}
if( blake2bp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1; // Mark as last node
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES );
blake2b_final( FS, out, outlen );
return 0;
}
#if defined(BLAKE2BP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2bp( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

380
ref/blake2s-ref.c Normal file
View File

@ -0,0 +1,380 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint32_t blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const uint8_t blake2s_sigma[10][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
static inline int blake2s_set_lastnode( blake2s_state *S )
{
S->f[1] = ~0U;
return 0;
}
static inline int blake2s_clear_lastnode( blake2s_state *S )
{
S->f[1] = 0U;
return 0;
}
/* Some helper functions, not necessarily useful */
static inline int blake2s_set_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_set_lastnode( S );
S->f[0] = ~0U;
return 0;
}
static inline int blake2s_clear_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_clear_lastnode( S );
S->f[0] = 0U;
return 0;
}
static inline int blake2s_increment_counter( blake2s_state *S, const uint32_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
return 0;
}
// Parameter-related functions
static inline int blake2s_param_set_digest_length( blake2s_param *P, const uint8_t digest_length )
{
P->digest_length = digest_length;
return 0;
}
static inline int blake2s_param_set_fanout( blake2s_param *P, const uint8_t fanout )
{
P->fanout = fanout;
return 0;
}
static inline int blake2s_param_set_max_depth( blake2s_param *P, const uint8_t depth )
{
P->depth = depth;
return 0;
}
static inline int blake2s_param_set_leaf_length( blake2s_param *P, const uint32_t leaf_length )
{
store32( &P->leaf_length, leaf_length );
return 0;
}
static inline int blake2s_param_set_node_offset( blake2s_param *P, const uint64_t node_offset )
{
store48( P->node_offset, node_offset );
return 0;
}
static inline int blake2s_param_set_node_depth( blake2s_param *P, const uint8_t node_depth )
{
P->node_depth = node_depth;
return 0;
}
static inline int blake2s_param_set_inner_length( blake2s_param *P, const uint8_t inner_length )
{
P->inner_length = inner_length;
return 0;
}
static inline int blake2s_param_set_salt( blake2s_param *P, const uint8_t salt[BLAKE2S_SALTBYTES] )
{
memcpy( P->salt, salt, BLAKE2S_SALTBYTES );
return 0;
}
static inline int blake2s_param_set_personal( blake2s_param *P, const uint8_t personal[BLAKE2S_PERSONALBYTES] )
{
memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES );
return 0;
}
static inline int blake2s_init0( blake2s_state *S )
{
memset( S, 0, sizeof( blake2s_state ) );
for( int i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];
return 0;
}
/* init2 xors IV with input parameter block */
int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
{
blake2s_init0( S );
uint32_t *p = ( uint32_t * )( P );
/* IV XOR ParamBlock */
for( size_t i = 0; i < 8; ++i )
S->h[i] ^= load32( &p[i] );
return 0;
}
// Sequential blake2s initialization
int blake2s_init( blake2s_state *S, const uint8_t outlen )
{
blake2s_param P[1];
/* Move interval verification here? */
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
P->digest_length = outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store48( &P->node_offset, 0 );
P->node_depth = 0;
P->inner_length = 0;
// memset(P->reserved, 0, sizeof(P->reserved) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
blake2s_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store48( &P->node_offset, 0 );
P->node_depth = 0;
P->inner_length = 0;
// memset(P->reserved, 0, sizeof(P->reserved) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2s_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
blake2s_update( S, block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
static int blake2s_compress( blake2s_state *S, const uint8_t block[BLAKE2S_BLOCKBYTES] )
{
uint32_t m[16];
uint32_t v[16];
for( size_t i = 0; i < 16; ++i )
m[i] = load32( block + i * sizeof( m[i] ) );
for( size_t i = 0; i < 8; ++i )
v[i] = S->h[i];
v[ 8] = blake2s_IV[0];
v[ 9] = blake2s_IV[1];
v[10] = blake2s_IV[2];
v[11] = blake2s_IV[3];
v[12] = S->t[0] ^ blake2s_IV[4];
v[13] = S->t[1] ^ blake2s_IV[5];
v[14] = S->f[0] ^ blake2s_IV[6];
v[15] = S->f[1] ^ blake2s_IV[7];
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2s_sigma[r][2*i+0]]; \
d = rotr32(d ^ a, 16); \
c = c + d; \
b = rotr32(b ^ c, 12); \
a = a + b + m[blake2s_sigma[r][2*i+1]]; \
d = rotr32(d ^ a, 8); \
c = c + d; \
b = rotr32(b ^ c, 7); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
for( size_t i = 0; i < 8; ++i )
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
#undef G
#undef ROUND
return 0;
}
int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen )
{
while( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = 2 * BLAKE2S_BLOCKBYTES - left;
if( inlen > fill )
{
memcpy( S->buf + left, in, fill ); // Fill buffer
S->buflen += fill;
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf ); // Compress
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left
S->buflen -= BLAKE2S_BLOCKBYTES;
in += fill;
inlen -= fill;
}
else // inlen <= fill
{
memcpy( S->buf + left, in, inlen );
S->buflen += inlen; // Be lazy, do not compress
in += inlen;
inlen -= inlen;
}
}
return 0;
}
int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen )
{
uint8_t buffer[BLAKE2S_OUTBYTES];
if( S->buflen > BLAKE2S_BLOCKBYTES )
{
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf );
S->buflen -= BLAKE2S_BLOCKBYTES;
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen );
}
blake2s_increment_counter( S, ( uint32_t )S->buflen );
blake2s_set_lastblock( S );
memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
blake2s_compress( S, S->buf );
for( int i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store32( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, outlen );
return 0;
}
int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
{
blake2s_state S[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key ) keylen = 0; /* Fail here instead if keylen != 0 and key == NULL? */
if( keylen > 0 )
{
if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2s_init( S, outlen ) < 0 ) return -1;
}
blake2s_update( S, ( uint8_t * )in, inlen );
blake2s_final( S, out, outlen );
return 0;
}
#if defined(BLAKE2S_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2s( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

295
ref/blake2sp-ref.c Normal file
View File

@ -0,0 +1,295 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 8
static inline int blake2sp_init_leaf( blake2s_state *S, uint8_t outlen, uint8_t keylen, uint64_t offset )
{
blake2s_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store48( P->node_offset, offset );
P->node_depth = 0;
P->inner_length = outlen;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
static inline int blake2sp_init_root( blake2s_state *S, uint8_t outlen, uint8_t keylen )
{
blake2s_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store48( P->node_offset, 0ULL );
P->node_depth = 1;
P->inner_length = outlen;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2sp_init( blake2sp_state *S, const uint8_t outlen )
{
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen )
{
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S->S[id__], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2sp_final( blake2sp_state *S, uint8_t *out, const uint8_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2S_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
}
blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
}
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
blake2s_final( S->R, out, outlen );
return 0;
}
int blake2sp( uint8_t *out, const void *in, const void *key, uint8_t outlen, uint64_t inlen, uint8_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
blake2s_state S[PARALLELISM_DEGREE][1];
blake2s_state FS[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key ) keylen = 0;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; // mark last node
if( keylen > 0 )
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S[id__], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
if( inlen__ > id__ * BLAKE2S_BLOCKBYTES )
{
const size_t left = inlen__ - id__ * BLAKE2S_BLOCKBYTES;
const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
blake2s_update( S[id__], in__, len );
}
blake2s_final( S[id__], hash[id__], BLAKE2S_OUTBYTES );
}
if( blake2sp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
blake2s_final( FS, out, outlen );
return 0;
}
#if defined(BLAKE2SP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

210
ref/genkat.c Normal file
View File

@ -0,0 +1,210 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "blake2.h"
#define STR_(x) #x
#define STR(x) STR_(x)
#define LENGTH 256
#define MAKE_KAT(name,size_prefix) \
do \
{ \
printf( "static const uint8_t " #name "_kat[KAT_LENGTH][" #size_prefix "_OUTBYTES] = \n{\n" ); \
\
for( size_t i = 0; i < LENGTH; ++i ) \
{ \
name( hash, in, NULL, size_prefix ## _OUTBYTES, i, 0 ); \
printf( "\t{\n\t\t" ); \
\
for( int j = 0; j < size_prefix ## _OUTBYTES; ++j ) \
printf( "0x%02X%s", hash[j], ( j + 1 ) == size_prefix ## _OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " ); \
\
printf( "\t},\n" ); \
} \
\
printf( "};\n\n\n\n\n" ); \
\
} while (0)
#define MAKE_KEYED_KAT(name,size_prefix) \
do \
{ \
printf( "static const uint8_t " #name "_keyed_kat[KAT_LENGTH][" #size_prefix "_OUTBYTES] = \n{\n" ); \
\
for( size_t i = 0; i < LENGTH; ++i ) \
{ \
name( hash, in, key, size_prefix ## _OUTBYTES, i, size_prefix ## _KEYBYTES ); \
printf( "\t{\n\t\t" ); \
\
for( int j = 0; j < size_prefix ## _OUTBYTES; ++j ) \
printf( "0x%02X%s", hash[j], ( j + 1 ) == size_prefix ## _OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " ); \
\
printf( "\t},\n" ); \
} \
\
printf( "};\n\n\n\n\n" ); \
\
} while (0)
int main( int argc, char **argv )
{
uint8_t key[64] = {0};
uint8_t in[LENGTH] = {0};
uint8_t hash[64] = {0};
for( size_t i = 0; i < sizeof( in ); ++i )
in[i] = i;
for( size_t i = 0; i < sizeof( key ); ++i )
key[i] = i;
puts( "#pragma once\n"
"#ifndef __BLAKE2_KAT_H__\n"
"#define __BLAKE2_KAT_H__\n\n\n"
"#include <stdint.h>\n\n"
"#define KAT_LENGTH " STR( LENGTH ) "\n\n\n" );
MAKE_KAT( blake2s, BLAKE2S );
MAKE_KEYED_KAT( blake2s, BLAKE2S );
MAKE_KAT( blake2b, BLAKE2B );
MAKE_KEYED_KAT( blake2b, BLAKE2B );
MAKE_KAT( blake2sp, BLAKE2S );
MAKE_KEYED_KAT( blake2sp, BLAKE2S );
MAKE_KAT( blake2bp, BLAKE2B );
MAKE_KEYED_KAT( blake2bp, BLAKE2B );
/*printf( "static const uint8_t blake2s_kat[KAT_LENGTH][BLAKE2S_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2s( hash, in, NULL, BLAKE2S_OUTBYTES, i, 0 );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2S_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2S_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );
printf( "static const uint8_t blake2s_keyed_kat[KAT_LENGTH][BLAKE2S_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2s( hash, in, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2S_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2S_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );
printf( "static const uint8_t blake2b_kat[KAT_LENGTH][BLAKE2B_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2b( hash, in, NULL, BLAKE2B_OUTBYTES, i, 0 );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2B_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2B_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );
printf( "static const uint8_t blake2b_keyed_kat[KAT_LENGTH][BLAKE2B_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2b( hash, in, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2B_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2B_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );
printf( "static const uint8_t blake2sp_kat[KAT_LENGTH][BLAKE2S_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2sp( hash, in, NULL, BLAKE2S_OUTBYTES, i, 0 );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2S_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2S_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );
printf( "static const uint8_t blake2sp_keyed_kat[KAT_LENGTH][BLAKE2S_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2sp( hash, in, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2S_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2S_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );
printf( "static const uint8_t blake2bp_kat[KAT_LENGTH][BLAKE2B_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2bp( hash, in, NULL, BLAKE2B_OUTBYTES, i, 0 );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2B_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2B_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );
printf( "static const uint8_t blake2bp_keyed_kat[KAT_LENGTH][BLAKE2B_OUTBYTES] = \n{\n" );
for( size_t i = 0; i < LENGTH; ++i )
{
blake2bp( hash, in, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
printf( "\t{\n\t\t" );
for( int j = 0; j < BLAKE2B_OUTBYTES; ++j )
printf( "0x%02X%s", hash[j], ( j + 1 ) == BLAKE2B_OUTBYTES ? "\n" : j && !( ( j + 1 ) % 8 ) ? ",\n\t\t" : ", " );
printf( "\t},\n" );
}
printf( "};\n\n\n\n\n" );*/
puts( "#endif\n\n\n" );
return 0;
}

23
ref/makefile Normal file
View File

@ -0,0 +1,23 @@
CC?=gcc
CFLAGS=-std=c99 -Wall -pedantic
all: blake2s blake2b blake2sp blake2bp
blake2s: blake2s-ref.c
$(CC) blake2s-ref.c -o $@ $(CFLAGS) -DBLAKE2S_SELFTEST
blake2b: blake2b-ref.c
$(CC) blake2b-ref.c -o $@ $(CFLAGS) -DBLAKE2B_SELFTEST
blake2sp: blake2sp-ref.c blake2s-ref.c
$(CC) blake2sp-ref.c -o $@ $(CFLAGS) -DBLAKE2SP_SELFTEST
blake2bp: blake2bp-ref.c blake2b-ref.c
$(CC) blake2bp-ref.c -o $@ $(CFLAGS) -DBLAKE2BP_SELFTEST
kat:
$(CC) $(CFLAGS) -o genkat genkat.c blake2b-ref.c blake2s-ref.c blake2sp-ref.c blake2bp-ref.c
./genkat > blake2-kat.h
clean:
rm -rf *.o genkat blake2s blake2b blake2sp blake2bp

72
sse/blake2-config.h Normal file
View File

@ -0,0 +1,72 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2_CONFIG_H__
#define __BLAKE2_CONFIG_H__
// These don't work everywhere
#if defined(__SSE2__)
#define HAVE_SSE2
#endif
#if defined(__SSSE3__)
#define HAVE_SSSE3
#endif
#if defined(__SSE4_1__)
#define HAVE_SSE41
#endif
#if defined(__AVX__)
#define HAVE_AVX
#endif
#if defined(__XOP__)
#define HAVE_XOP
#endif
#ifdef HAVE_AVX2
#ifndef HAVE_AVX
#define HAVE_AVX
#endif
#endif
#ifdef HAVE_XOP
#ifndef HAVE_AVX
#define HAVE_AVX
#endif
#endif
#ifdef HAVE_AVX
#ifndef HAVE_SSE41
#define HAVE_SSE41
#endif
#endif
#ifdef HAVE_SSE41
#ifndef HAVE_SSSE3
#define HAVE_SSSE3
#endif
#endif
#ifdef HAVE_SSSE3
#define HAVE_SSE2
#endif
#if !defined(HAVE_SSE2)
#error "This code requires at least SSE2."
#endif
#endif

133
sse/blake2-impl.h Normal file
View File

@ -0,0 +1,133 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2_IMPL_H__
#define __BLAKE2_IMPL_H__
#include <stdint.h>
static inline uint32_t load32( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
return *( uint32_t * )( src );
#else
const uint8_t *p = ( uint8_t * )src;
uint32_t w = *p++;
w |= ( uint32_t )( *p++ ) << 8;
w |= ( uint32_t )( *p++ ) << 16;
w |= ( uint32_t )( *p++ ) << 24;
return w;
#endif
}
static inline uint64_t load64( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
return *( uint64_t * )( src );
#else
const uint8_t *p = ( uint8_t * )src;
uint64_t w = *p++;
w |= ( uint64_t )( *p++ ) << 8;
w |= ( uint64_t )( *p++ ) << 16;
w |= ( uint64_t )( *p++ ) << 24;
w |= ( uint64_t )( *p++ ) << 32;
w |= ( uint64_t )( *p++ ) << 40;
w |= ( uint64_t )( *p++ ) << 48;
w |= ( uint64_t )( *p++ ) << 56;
return w;
#endif
}
static inline void store32( void *dst, uint32_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
*( uint32_t * )( dst ) = w;
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static inline void store64( void *dst, uint64_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
*( uint64_t * )( dst ) = w;
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static inline uint64_t load48( const void *src )
{
const uint8_t *p = ( const uint8_t * )src;
uint64_t w = *p++;
w |= ( uint64_t )( *p++ ) << 8;
w |= ( uint64_t )( *p++ ) << 16;
w |= ( uint64_t )( *p++ ) << 24;
w |= ( uint64_t )( *p++ ) << 32;
w |= ( uint64_t )( *p++ ) << 40;
return w;
}
static inline void store48( void *dst, uint64_t w )
{
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
}
static inline uint32_t rotl32( const uint32_t w, const unsigned c )
{
return ( w << c ) | ( w >> ( 32 - c ) );
}
static inline uint64_t rotl64( const uint64_t w, const unsigned c )
{
return ( w << c ) | ( w >> ( 64 - c ) );
}
static inline uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
}
static inline uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
}
/* prevents compiler optimizing out memset() */
static inline void secure_zero_memory( void *v, size_t n )
{
volatile uint8_t *p = ( volatile uint8_t * )v;
while( n-- ) *p++ = 0;
}
#endif

16467
sse/blake2-kat.h Normal file

File diff suppressed because it is too large Load Diff

156
sse/blake2.h Normal file
View File

@ -0,0 +1,156 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2_H__
#define __BLAKE2_H__
#include <stddef.h>
#include <stdint.h>
#if defined(_MSC_VER)
#define ALIGN(x) __declspec(align(x))
#else
#define ALIGN(x) __attribute__ ((__aligned__(x)))
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32,
BLAKE2S_KEYBYTES = 32,
BLAKE2S_SALTBYTES = 8,
BLAKE2S_PERSONALBYTES = 8
};
enum blake2b_constant
{
BLAKE2B_BLOCKBYTES = 128,
BLAKE2B_OUTBYTES = 64,
BLAKE2B_KEYBYTES = 64,
BLAKE2B_SALTBYTES = 16,
BLAKE2B_PERSONALBYTES = 16
};
#pragma pack(push, 1)
typedef struct __blake2s_param
{
uint8_t digest_length; // 1
uint8_t key_length; // 2
uint8_t fanout; // 3
uint8_t depth; // 4
uint32_t leaf_length; // 8
uint8_t node_offset[6];// 14
uint8_t node_depth; // 15
uint8_t inner_length; // 16
// uint8_t reserved[0];
uint8_t salt[BLAKE2S_SALTBYTES]; // 24
uint8_t personal[BLAKE2S_PERSONALBYTES]; // 32
} blake2s_param;
ALIGN( 64 ) typedef struct __blake2s_state
{
uint32_t h[8];
uint32_t t[2];
uint32_t f[2];
uint8_t buf[2 * BLAKE2S_BLOCKBYTES];
size_t buflen;
uint8_t last_node;
} blake2s_state;
typedef struct __blake2b_param
{
uint8_t digest_length; // 1
uint8_t key_length; // 2
uint8_t fanout; // 3
uint8_t depth; // 4
uint32_t leaf_length; // 8
uint64_t node_offset; // 16
uint8_t node_depth; // 17
uint8_t inner_length; // 18
uint8_t reserved[14]; // 32
uint8_t salt[BLAKE2B_SALTBYTES]; // 48
uint8_t personal[BLAKE2B_PERSONALBYTES]; // 64
} blake2b_param;
ALIGN( 64 ) typedef struct __blake2b_state
{
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[2 * BLAKE2B_BLOCKBYTES];
size_t buflen;
uint8_t last_node;
} blake2b_state;
ALIGN( 64 ) typedef struct __blake2sp_state
{
blake2s_state S[8][1];
blake2s_state R[1];
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
} blake2sp_state;
ALIGN( 64 ) typedef struct __blake2bp_state
{
blake2b_state S[4][1];
blake2b_state R[1];
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
size_t buflen;
} blake2bp_state;
#pragma pack(pop)
// Streaming API
int blake2s_init( blake2s_state *S, const uint8_t outlen );
int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen );
int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen );
int blake2b_init( blake2b_state *S, const uint8_t outlen );
int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen );
int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen );
int blake2sp_init( blake2sp_state *S, const uint8_t outlen );
int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen );
int blake2sp_final( blake2sp_state *S, uint8_t *out, uint8_t outlen );
int blake2bp_init( blake2bp_state *S, const uint8_t outlen );
int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen );
int blake2bp_final( blake2bp_state *S, uint8_t *out, uint8_t outlen );
// Simple API
int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
int blake2sp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
int blake2bp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
static inline int blake2( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
{
return blake2b( out, in, key, outlen, inlen, keylen );
}
#if defined(__cplusplus)
}
#endif
#endif

68
sse/blake2b-load-sse2.h Normal file
View File

@ -0,0 +1,68 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2B_LOAD_SSE2_H__
#define __BLAKE2B_LOAD_SSE2_H__
#define LOAD_MSG_0_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4)
#define LOAD_MSG_0_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5)
#define LOAD_MSG_0_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12)
#define LOAD_MSG_0_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13)
#define LOAD_MSG_1_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9)
#define LOAD_MSG_1_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15)
#define LOAD_MSG_1_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11)
#define LOAD_MSG_1_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7)
#define LOAD_MSG_2_1(b0, b1) b0 = _mm_set_epi64x(m12, m11); b1 = _mm_set_epi64x(m15, m5)
#define LOAD_MSG_2_2(b0, b1) b0 = _mm_set_epi64x(m0, m8); b1 = _mm_set_epi64x(m13, m2)
#define LOAD_MSG_2_3(b0, b1) b0 = _mm_set_epi64x(m3, m10); b1 = _mm_set_epi64x(m9, m7)
#define LOAD_MSG_2_4(b0, b1) b0 = _mm_set_epi64x(m6, m14); b1 = _mm_set_epi64x(m4, m1)
#define LOAD_MSG_3_1(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m13)
#define LOAD_MSG_3_2(b0, b1) b0 = _mm_set_epi64x(m1, m9); b1 = _mm_set_epi64x(m14, m12)
#define LOAD_MSG_3_3(b0, b1) b0 = _mm_set_epi64x(m5, m2); b1 = _mm_set_epi64x(m15, m4)
#define LOAD_MSG_3_4(b0, b1) b0 = _mm_set_epi64x(m10, m6); b1 = _mm_set_epi64x(m8, m0)
#define LOAD_MSG_4_1(b0, b1) b0 = _mm_set_epi64x(m5, m9); b1 = _mm_set_epi64x(m10, m2)
#define LOAD_MSG_4_2(b0, b1) b0 = _mm_set_epi64x(m7, m0); b1 = _mm_set_epi64x(m15, m4)
#define LOAD_MSG_4_3(b0, b1) b0 = _mm_set_epi64x(m11, m14); b1 = _mm_set_epi64x(m3, m6)
#define LOAD_MSG_4_4(b0, b1) b0 = _mm_set_epi64x(m12, m1); b1 = _mm_set_epi64x(m13, m8)
#define LOAD_MSG_5_1(b0, b1) b0 = _mm_set_epi64x(m6, m2); b1 = _mm_set_epi64x(m8, m0)
#define LOAD_MSG_5_2(b0, b1) b0 = _mm_set_epi64x(m10, m12); b1 = _mm_set_epi64x(m3, m11)
#define LOAD_MSG_5_3(b0, b1) b0 = _mm_set_epi64x(m7, m4); b1 = _mm_set_epi64x(m1, m15)
#define LOAD_MSG_5_4(b0, b1) b0 = _mm_set_epi64x(m5, m13); b1 = _mm_set_epi64x(m9, m14)
#define LOAD_MSG_6_1(b0, b1) b0 = _mm_set_epi64x(m1, m12); b1 = _mm_set_epi64x(m4, m14)
#define LOAD_MSG_6_2(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m10, m13)
#define LOAD_MSG_6_3(b0, b1) b0 = _mm_set_epi64x(m6, m0); b1 = _mm_set_epi64x(m8, m9)
#define LOAD_MSG_6_4(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m2)
#define LOAD_MSG_7_1(b0, b1) b0 = _mm_set_epi64x(m7, m13); b1 = _mm_set_epi64x(m3, m12)
#define LOAD_MSG_7_2(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m9, m1)
#define LOAD_MSG_7_3(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m2, m8)
#define LOAD_MSG_7_4(b0, b1) b0 = _mm_set_epi64x(m4, m0); b1 = _mm_set_epi64x(m10, m6)
#define LOAD_MSG_8_1(b0, b1) b0 = _mm_set_epi64x(m14, m6); b1 = _mm_set_epi64x(m0, m11)
#define LOAD_MSG_8_2(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m8, m3)
#define LOAD_MSG_8_3(b0, b1) b0 = _mm_set_epi64x(m13, m12); b1 = _mm_set_epi64x(m10, m1)
#define LOAD_MSG_8_4(b0, b1) b0 = _mm_set_epi64x(m7, m2); b1 = _mm_set_epi64x(m5, m4)
#define LOAD_MSG_9_1(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m1, m7)
#define LOAD_MSG_9_2(b0, b1) b0 = _mm_set_epi64x(m4, m2); b1 = _mm_set_epi64x(m5, m6)
#define LOAD_MSG_9_3(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m13, m3)
#define LOAD_MSG_9_4(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m0, m12)
#define LOAD_MSG_10_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4)
#define LOAD_MSG_10_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5)
#define LOAD_MSG_10_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12)
#define LOAD_MSG_10_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13)
#define LOAD_MSG_11_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9)
#define LOAD_MSG_11_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15)
#define LOAD_MSG_11_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11)
#define LOAD_MSG_11_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7)
#endif

402
sse/blake2b-load-sse41.h Normal file
View File

@ -0,0 +1,402 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2B_LOAD_SSE41_H__
#define __BLAKE2B_LOAD_SSE41_H__
#define LOAD_MSG_0_1(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m0, m1); \
b1 = _mm_unpacklo_epi64(m2, m3); \
} while(0)
#define LOAD_MSG_0_2(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m0, m1); \
b1 = _mm_unpackhi_epi64(m2, m3); \
} while(0)
#define LOAD_MSG_0_3(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m4, m5); \
b1 = _mm_unpacklo_epi64(m6, m7); \
} while(0)
#define LOAD_MSG_0_4(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m4, m5); \
b1 = _mm_unpackhi_epi64(m6, m7); \
} while(0)
#define LOAD_MSG_1_1(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m7, m2); \
b1 = _mm_unpackhi_epi64(m4, m6); \
} while(0)
#define LOAD_MSG_1_2(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m5, m4); \
b1 = _mm_alignr_epi8(m3, m7, 8); \
} while(0)
#define LOAD_MSG_1_3(b0, b1) \
do \
{ \
b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \
b1 = _mm_unpackhi_epi64(m5, m2); \
} while(0)
#define LOAD_MSG_1_4(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m6, m1); \
b1 = _mm_unpackhi_epi64(m3, m1); \
} while(0)
#define LOAD_MSG_2_1(b0, b1) \
do \
{ \
b0 = _mm_alignr_epi8(m6, m5, 8); \
b1 = _mm_unpackhi_epi64(m2, m7); \
} while(0)
#define LOAD_MSG_2_2(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m4, m0); \
b1 = _mm_blend_epi16(m1, m6, 0xF0); \
} while(0)
#define LOAD_MSG_2_3(b0, b1) \
do \
{ \
b0 = _mm_blend_epi16(m5, m1, 0xF0); \
b1 = _mm_unpackhi_epi64(m3, m4); \
} while(0)
#define LOAD_MSG_2_4(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m7, m3); \
b1 = _mm_alignr_epi8(m2, m0, 8); \
} while(0)
#define LOAD_MSG_3_1(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m3, m1); \
b1 = _mm_unpackhi_epi64(m6, m5); \
} while(0)
#define LOAD_MSG_3_2(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m4, m0); \
b1 = _mm_unpacklo_epi64(m6, m7); \
} while(0)
#define LOAD_MSG_3_3(b0, b1) \
do \
{ \
b0 = _mm_blend_epi16(m1, m2, 0xF0); \
b1 = _mm_blend_epi16(m2, m7, 0xF0); \
} while(0)
#define LOAD_MSG_3_4(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m3, m5); \
b1 = _mm_unpacklo_epi64(m0, m4); \
} while(0)
#define LOAD_MSG_4_1(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m4, m2); \
b1 = _mm_unpacklo_epi64(m1, m5); \
} while(0)
#define LOAD_MSG_4_2(b0, b1) \
do \
{ \
b0 = _mm_blend_epi16(m0, m3, 0xF0); \
b1 = _mm_blend_epi16(m2, m7, 0xF0); \
} while(0)
#define LOAD_MSG_4_3(b0, b1) \
do \
{ \
b0 = _mm_blend_epi16(m7, m5, 0xF0); \
b1 = _mm_blend_epi16(m3, m1, 0xF0); \
} while(0)
#define LOAD_MSG_4_4(b0, b1) \
do \
{ \
b0 = _mm_alignr_epi8(m6, m0, 8); \
b1 = _mm_blend_epi16(m4, m6, 0xF0); \
} while(0)
#define LOAD_MSG_5_1(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m1, m3); \
b1 = _mm_unpacklo_epi64(m0, m4); \
} while(0)
#define LOAD_MSG_5_2(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m6, m5); \
b1 = _mm_unpackhi_epi64(m5, m1); \
} while(0)
#define LOAD_MSG_5_3(b0, b1) \
do \
{ \
b0 = _mm_blend_epi16(m2, m3, 0xF0); \
b1 = _mm_unpackhi_epi64(m7, m0); \
} while(0)
#define LOAD_MSG_5_4(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m6, m2); \
b1 = _mm_blend_epi16(m7, m4, 0xF0); \
} while(0)
#define LOAD_MSG_6_1(b0, b1) \
do \
{ \
b0 = _mm_blend_epi16(m6, m0, 0xF0); \
b1 = _mm_unpacklo_epi64(m7, m2); \
} while(0)
#define LOAD_MSG_6_2(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m2, m7); \
b1 = _mm_alignr_epi8(m5, m6, 8); \
} while(0)
#define LOAD_MSG_6_3(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m0, m3); \
b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1,0,3,2)); \
} while(0)
#define LOAD_MSG_6_4(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m3, m1); \
b1 = _mm_blend_epi16(m1, m5, 0xF0); \
} while(0)
#define LOAD_MSG_7_1(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m6, m3); \
b1 = _mm_blend_epi16(m6, m1, 0xF0); \
} while(0)
#define LOAD_MSG_7_2(b0, b1) \
do \
{ \
b0 = _mm_alignr_epi8(m7, m5, 8); \
b1 = _mm_unpackhi_epi64(m0, m4); \
} while(0)
#define LOAD_MSG_7_3(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m2, m7); \
b1 = _mm_unpacklo_epi64(m4, m1); \
} while(0)
#define LOAD_MSG_7_4(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m0, m2); \
b1 = _mm_unpacklo_epi64(m3, m5); \
} while(0)
#define LOAD_MSG_8_1(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m3, m7); \
b1 = _mm_alignr_epi8(m0, m5, 8); \
} while(0)
#define LOAD_MSG_8_2(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m7, m4); \
b1 = _mm_alignr_epi8(m4, m1, 8); \
} while(0)
#define LOAD_MSG_8_3(b0, b1) \
do \
{ \
b0 = m6; \
b1 = _mm_alignr_epi8(m5, m0, 8); \
} while(0)
#define LOAD_MSG_8_4(b0, b1) \
do \
{ \
b0 = _mm_blend_epi16(m1, m3, 0xF0); \
b1 = m2; \
} while(0)
#define LOAD_MSG_9_1(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m5, m4); \
b1 = _mm_unpackhi_epi64(m3, m0); \
} while(0)
#define LOAD_MSG_9_2(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m1, m2); \
b1 = _mm_blend_epi16(m3, m2, 0xF0); \
} while(0)
#define LOAD_MSG_9_3(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m7, m4); \
b1 = _mm_unpackhi_epi64(m1, m6); \
} while(0)
#define LOAD_MSG_9_4(b0, b1) \
do \
{ \
b0 = _mm_alignr_epi8(m7, m5, 8); \
b1 = _mm_unpacklo_epi64(m6, m0); \
} while(0)
#define LOAD_MSG_10_1(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m0, m1); \
b1 = _mm_unpacklo_epi64(m2, m3); \
} while(0)
#define LOAD_MSG_10_2(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m0, m1); \
b1 = _mm_unpackhi_epi64(m2, m3); \
} while(0)
#define LOAD_MSG_10_3(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m4, m5); \
b1 = _mm_unpacklo_epi64(m6, m7); \
} while(0)
#define LOAD_MSG_10_4(b0, b1) \
do \
{ \
b0 = _mm_unpackhi_epi64(m4, m5); \
b1 = _mm_unpackhi_epi64(m6, m7); \
} while(0)
#define LOAD_MSG_11_1(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m7, m2); \
b1 = _mm_unpackhi_epi64(m4, m6); \
} while(0)
#define LOAD_MSG_11_2(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m5, m4); \
b1 = _mm_alignr_epi8(m3, m7, 8); \
} while(0)
#define LOAD_MSG_11_3(b0, b1) \
do \
{ \
b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \
b1 = _mm_unpackhi_epi64(m5, m2); \
} while(0)
#define LOAD_MSG_11_4(b0, b1) \
do \
{ \
b0 = _mm_unpacklo_epi64(m6, m1); \
b1 = _mm_unpackhi_epi64(m3, m1); \
} while(0)
#endif

160
sse/blake2b-round.h Normal file
View File

@ -0,0 +1,160 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2B_ROUND_H__
#define __BLAKE2B_ROUND_H__
#define LOAD(p) _mm_load_si128( (__m128i *)(p) )
#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
#define LOADU(p) _mm_loadu_si128( (__m128i *)(p) )
#define STOREU(p,r) _mm_storeu_si128((__m128i *)(p), r)
#define TOF(reg) _mm_castsi128_ps((reg))
#define TOI(reg) _mm_castps_si128((reg))
#define LIKELY(x) __builtin_expect((x),1)
/* Microarchitecture-specific macros */
#ifndef HAVE_XOP
#ifdef HAVE_SSSE3
#define _mm_roti_epi64(x, c) \
(-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \
: (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \
: (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \
: (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \
: _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c))))
#else
#define _mm_roti_epi64(r, c) _mm_xor_si128(_mm_srli_epi64( (r), -(c) ),_mm_slli_epi64( (r), 64-(-c) ))
#endif
#else
/* ... */
#endif
#define G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \
row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \
row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \
\
row4l = _mm_xor_si128(row4l, row1l); \
row4h = _mm_xor_si128(row4h, row1h); \
\
row4l = _mm_roti_epi64(row4l, -32); \
row4h = _mm_roti_epi64(row4h, -32); \
\
row3l = _mm_add_epi64(row3l, row4l); \
row3h = _mm_add_epi64(row3h, row4h); \
\
row2l = _mm_xor_si128(row2l, row3l); \
row2h = _mm_xor_si128(row2h, row3h); \
\
row2l = _mm_roti_epi64(row2l, -24); \
row2h = _mm_roti_epi64(row2h, -24); \
#define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \
row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \
row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \
\
row4l = _mm_xor_si128(row4l, row1l); \
row4h = _mm_xor_si128(row4h, row1h); \
\
row4l = _mm_roti_epi64(row4l, -16); \
row4h = _mm_roti_epi64(row4h, -16); \
\
row3l = _mm_add_epi64(row3l, row4l); \
row3h = _mm_add_epi64(row3h, row4h); \
\
row2l = _mm_xor_si128(row2l, row3l); \
row2h = _mm_xor_si128(row2h, row3h); \
\
row2l = _mm_roti_epi64(row2l, -63); \
row2h = _mm_roti_epi64(row2h, -63); \
#if defined(HAVE_SSSE3)
#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
t0 = _mm_alignr_epi8(row2h, row2l, 8); \
t1 = _mm_alignr_epi8(row2l, row2h, 8); \
row2l = t0; \
row2h = t1; \
\
t0 = row3l; \
row3l = row3h; \
row3h = t0; \
\
t0 = _mm_alignr_epi8(row4h, row4l, 8); \
t1 = _mm_alignr_epi8(row4l, row4h, 8); \
row4l = t1; \
row4h = t0;
#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
t0 = _mm_alignr_epi8(row2l, row2h, 8); \
t1 = _mm_alignr_epi8(row2h, row2l, 8); \
row2l = t0; \
row2h = t1; \
\
t0 = row3l; \
row3l = row3h; \
row3h = t0; \
\
t0 = _mm_alignr_epi8(row4l, row4h, 8); \
t1 = _mm_alignr_epi8(row4h, row4l, 8); \
row4l = t1; \
row4h = t0;
#else
#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
t0 = row4l;\
t1 = row2l;\
row4l = row3l;\
row3l = row3h;\
row3h = row4l;\
row4l = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t0, t0)); \
row4h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row4h, row4h)); \
row2l = _mm_unpackhi_epi64(row2l, _mm_unpacklo_epi64(row2h, row2h)); \
row2h = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(t1, t1))
#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
t0 = row3l;\
row3l = row3h;\
row3h = t0;\
t0 = row2l;\
t1 = row4l;\
row2l = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(row2l, row2l)); \
row2h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row2h, row2h)); \
row4l = _mm_unpackhi_epi64(row4l, _mm_unpacklo_epi64(row4h, row4h)); \
row4h = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t1, t1))
#endif
#if defined(HAVE_SSE41)
#include "blake2b-load-sse41.h"
#else
#include "blake2b-load-sse2.h"
#endif
#define ROUND(r) \
LOAD_MSG_ ##r ##_1(b0, b1); \
G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
LOAD_MSG_ ##r ##_2(b0, b1); \
G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \
LOAD_MSG_ ##r ##_3(b0, b1); \
G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
LOAD_MSG_ ##r ##_4(b0, b1); \
G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h);
#endif

431
sse/blake2b.c Normal file
View File

@ -0,0 +1,431 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
#include "blake2-config.h"
#include <emmintrin.h>
#if defined(HAVE_SSSE3)
#include <tmmintrin.h>
#endif
#if defined(HAVE_SSE41)
#include <smmintrin.h>
#endif
#if defined(HAVE_AVX)
#include <immintrin.h>
#endif
#if defined(HAVE_XOP)
#include <x86intrin.h>
#endif
#include "blake2b-round.h"
ALIGN( 64 ) static const uint64_t blake2b_IV[8] =
{
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
static const uint8_t blake2b_sigma[12][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
};
/* Some helper functions, not necessarily useful */
static inline int blake2b_set_lastnode( blake2b_state *S )
{
S->f[1] = ~0ULL;
return 0;
}
static inline int blake2b_clear_lastnode( blake2b_state *S )
{
S->f[1] = 0ULL;
return 0;
}
static inline int blake2b_set_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_set_lastnode( S );
S->f[0] = ~0ULL;
return 0;
}
static inline int blake2b_clear_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_clear_lastnode( S );
S->f[0] = 0ULL;
return 0;
}
static inline int blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
{
#if __x86_64__
// ADD/ADC chain
__uint128_t t = ( ( __uint128_t )S->t[1] << 64 ) | S->t[0];
t += inc;
S->t[0] = ( uint64_t )( t >> 0 );
S->t[1] = ( uint64_t )( t >> 64 );
#else
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
#endif
return 0;
}
// Parameter-related functions
static inline int blake2b_param_set_digest_length( blake2b_param *P, const uint8_t digest_length )
{
P->digest_length = digest_length;
return 0;
}
static inline int blake2b_param_set_fanout( blake2b_param *P, const uint8_t fanout )
{
P->fanout = fanout;
return 0;
}
static inline int blake2b_param_set_max_depth( blake2b_param *P, const uint8_t depth )
{
P->depth = depth;
return 0;
}
static inline int blake2b_param_set_leaf_length( blake2b_param *P, const uint32_t leaf_length )
{
P->leaf_length = leaf_length;
return 0;
}
static inline int blake2b_param_set_node_offset( blake2b_param *P, const uint64_t node_offset )
{
P->node_offset = node_offset;
return 0;
}
static inline int blake2b_param_set_node_depth( blake2b_param *P, const uint8_t node_depth )
{
P->node_depth = node_depth;
return 0;
}
static inline int blake2b_param_set_inner_length( blake2b_param *P, const uint8_t inner_length )
{
P->inner_length = inner_length;
return 0;
}
static inline int blake2b_param_set_salt( blake2b_param *P, const uint8_t salt[BLAKE2B_SALTBYTES] )
{
memcpy( P->salt, salt, BLAKE2B_SALTBYTES );
return 0;
}
static inline int blake2b_param_set_personal( blake2b_param *P, const uint8_t personal[BLAKE2B_PERSONALBYTES] )
{
memcpy( P->personal, personal, BLAKE2B_PERSONALBYTES );
return 0;
}
static inline int blake2b_init0( blake2b_state *S )
{
memset( S, 0, sizeof( blake2b_state ) );
for( int i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
return 0;
}
/* init xors IV with input parameter block */
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
{
uint8_t *p, *h, *v;
//blake2b_init0( S );
v = ( uint8_t * )( blake2b_IV );
h = ( uint8_t * )( S->h );
p = ( uint8_t * )( P );
/* IV XOR ParamBlock */
memset( S, 0, sizeof( blake2b_state ) );
for( int i = 0; i < BLAKE2B_OUTBYTES; ++i ) h[i] = v[i] ^ p[i];
return 0;
}
/* Some sort of default parameter block initialization, for sequential blake2b */
int blake2b_init( blake2b_state *S, const uint8_t outlen )
{
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
const blake2b_param P =
{
outlen,
0,
1,
1,
0,
0,
0,
0,
{0},
{0},
{0}
};
return blake2b_init_param( S, &P );
}
int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
if ( ( !keylen ) || keylen > BLAKE2B_KEYBYTES ) return -1;
const blake2b_param P =
{
outlen,
keylen,
1,
1,
0,
0,
0,
0,
{0},
{0},
{0}
};
if( blake2b_init_param( S, &P ) < 0 )
return 0;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
static inline int blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
{
__m128i row1l, row1h;
__m128i row2l, row2h;
__m128i row3l, row3h;
__m128i row4l, row4h;
__m128i b0, b1;
__m128i t0, t1;
#if defined(HAVE_SSSE3) && !defined(HAVE_XOP)
const __m128i r16 = _mm_setr_epi8( 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9 );
const __m128i r24 = _mm_setr_epi8( 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10 );
#endif
#if defined(HAVE_SSE41)
const __m128i m0 = LOADU( block + 00 );
const __m128i m1 = LOADU( block + 16 );
const __m128i m2 = LOADU( block + 32 );
const __m128i m3 = LOADU( block + 48 );
const __m128i m4 = LOADU( block + 64 );
const __m128i m5 = LOADU( block + 80 );
const __m128i m6 = LOADU( block + 96 );
const __m128i m7 = LOADU( block + 112 );
#else
const uint64_t m0 = ( ( uint64_t * )block )[ 0];
const uint64_t m1 = ( ( uint64_t * )block )[ 1];
const uint64_t m2 = ( ( uint64_t * )block )[ 2];
const uint64_t m3 = ( ( uint64_t * )block )[ 3];
const uint64_t m4 = ( ( uint64_t * )block )[ 4];
const uint64_t m5 = ( ( uint64_t * )block )[ 5];
const uint64_t m6 = ( ( uint64_t * )block )[ 6];
const uint64_t m7 = ( ( uint64_t * )block )[ 7];
const uint64_t m8 = ( ( uint64_t * )block )[ 8];
const uint64_t m9 = ( ( uint64_t * )block )[ 9];
const uint64_t m10 = ( ( uint64_t * )block )[10];
const uint64_t m11 = ( ( uint64_t * )block )[11];
const uint64_t m12 = ( ( uint64_t * )block )[12];
const uint64_t m13 = ( ( uint64_t * )block )[13];
const uint64_t m14 = ( ( uint64_t * )block )[14];
const uint64_t m15 = ( ( uint64_t * )block )[15];
#endif
row1l = LOAD( &S->h[0] );
row1h = LOAD( &S->h[2] );
row2l = LOAD( &S->h[4] );
row2h = LOAD( &S->h[6] );
row3l = LOAD( &blake2b_IV[0] );
row3h = LOAD( &blake2b_IV[2] );
row4l = _mm_xor_si128( LOAD( &blake2b_IV[4] ), LOAD( &S->t[0] ) );
row4h = _mm_xor_si128( LOAD( &blake2b_IV[6] ), LOAD( &S->f[0] ) );
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
ROUND( 10 );
ROUND( 11 );
row1l = _mm_xor_si128( row3l, row1l );
row1h = _mm_xor_si128( row3h, row1h );
STORE( &S->h[0], _mm_xor_si128( LOAD( &S->h[0] ), row1l ) );
STORE( &S->h[2], _mm_xor_si128( LOAD( &S->h[2] ), row1h ) );
row2l = _mm_xor_si128( row4l, row2l );
row2h = _mm_xor_si128( row4h, row2h );
STORE( &S->h[4], _mm_xor_si128( LOAD( &S->h[4] ), row2l ) );
STORE( &S->h[6], _mm_xor_si128( LOAD( &S->h[6] ), row2h ) );
return 0;
}
int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen )
{
while( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = 2 * BLAKE2B_BLOCKBYTES - left;
if( inlen > fill )
{
memcpy( S->buf + left, in, fill ); // Fill buffer
S->buflen += fill;
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf ); // Compress
memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); // Shift buffer left
S->buflen -= BLAKE2B_BLOCKBYTES;
in += fill;
inlen -= fill;
}
else // inlen <= fill
{
memcpy( S->buf + left, in, inlen );
S->buflen += inlen; // Be lazy, do not compress
in += inlen;
inlen -= inlen;
}
}
return 0;
}
int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen )
{
if( S->buflen > BLAKE2B_BLOCKBYTES )
{
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf );
S->buflen -= BLAKE2B_BLOCKBYTES;
memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen );
}
blake2b_increment_counter( S, S->buflen );
blake2b_set_lastblock( S );
memset( S->buf + S->buflen, 0, 2 * BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
blake2b_compress( S, S->buf );
memcpy( out, &S->h[0], outlen );
return 0;
}
int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
{
blake2b_state S[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if( NULL == key ) keylen = 0;
if( keylen )
{
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2b_init( S, outlen ) < 0 ) return -1;
}
blake2b_update( S, ( uint8_t * )in, inlen );
blake2b_final( S, out, outlen );
return 0;
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2b( out, in, NULL, BLAKE2B_OUTBYTES, inlen, 0 );
}
#endif
#if defined(BLAKE2B_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

296
sse/blake2bp.c Normal file
View File

@ -0,0 +1,296 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 4
static inline int blake2bp_init_leaf( blake2b_state *S, uint8_t outlen, uint8_t keylen, uint64_t offset )
{
blake2b_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
P->leaf_length = 0;
P->node_offset = offset;
P->node_depth = 0;
P->inner_length = outlen;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
static inline int blake2bp_init_root( blake2b_state *S, uint8_t outlen, uint8_t keylen )
{
blake2b_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
P->leaf_length = 0;
P->node_offset = 0;
P->node_depth = 1;
P->inner_length = outlen;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2bp_init( blake2bp_state *S, const uint8_t outlen )
{
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2bp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2bp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen )
{
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S->S[id__], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2bp_final( blake2bp_state *S, uint8_t *out, const uint8_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2B_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES;
if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES;
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left );
}
blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES );
}
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES );
blake2b_final( S->R, out, outlen );
return 0;
}
int blake2bp( uint8_t *out, const void *in, const void *key, uint8_t outlen, uint64_t inlen, uint8_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
blake2b_state S[PARALLELISM_DEGREE][1];
blake2b_state FS[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key ) keylen = 0;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; // mark last node
if( keylen > 0 )
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S[id__], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
if( inlen__ > id__ * BLAKE2B_BLOCKBYTES )
{
const size_t left = inlen__ - id__ * BLAKE2B_BLOCKBYTES;
const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES;
blake2b_update( S[id__], in__, len );
}
blake2b_final( S[id__], hash[id__], BLAKE2B_OUTBYTES );
}
if( blake2bp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1; // Mark as last node
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES );
blake2b_final( FS, out, outlen );
return 0;
}
#if defined(BLAKE2BP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
//blake2bp( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
blake2bp_state S[1];
blake2bp_init_key( S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES );
blake2bp_update( S, buf, i );
blake2bp_final( S, hash, BLAKE2B_OUTBYTES );
if( 0 != memcmp( hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

59
sse/blake2s-load-sse2.h Normal file
View File

@ -0,0 +1,59 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2S_LOAD_SSE2_H__
#define __BLAKE2S_LOAD_SSE2_H__
#define LOAD_MSG_0_1(buf) buf = _mm_set_epi32(m6,m4,m2,m0)
#define LOAD_MSG_0_2(buf) buf = _mm_set_epi32(m7,m5,m3,m1)
#define LOAD_MSG_0_3(buf) buf = _mm_set_epi32(m14,m12,m10,m8)
#define LOAD_MSG_0_4(buf) buf = _mm_set_epi32(m15,m13,m11,m9)
#define LOAD_MSG_1_1(buf) buf = _mm_set_epi32(m13,m9,m4,m14)
#define LOAD_MSG_1_2(buf) buf = _mm_set_epi32(m6,m15,m8,m10)
#define LOAD_MSG_1_3(buf) buf = _mm_set_epi32(m5,m11,m0,m1)
#define LOAD_MSG_1_4(buf) buf = _mm_set_epi32(m3,m7,m2,m12)
#define LOAD_MSG_2_1(buf) buf = _mm_set_epi32(m15,m5,m12,m11)
#define LOAD_MSG_2_2(buf) buf = _mm_set_epi32(m13,m2,m0,m8)
#define LOAD_MSG_2_3(buf) buf = _mm_set_epi32(m9,m7,m3,m10)
#define LOAD_MSG_2_4(buf) buf = _mm_set_epi32(m4,m1,m6,m14)
#define LOAD_MSG_3_1(buf) buf = _mm_set_epi32(m11,m13,m3,m7)
#define LOAD_MSG_3_2(buf) buf = _mm_set_epi32(m14,m12,m1,m9)
#define LOAD_MSG_3_3(buf) buf = _mm_set_epi32(m15,m4,m5,m2)
#define LOAD_MSG_3_4(buf) buf = _mm_set_epi32(m8,m0,m10,m6)
#define LOAD_MSG_4_1(buf) buf = _mm_set_epi32(m10,m2,m5,m9)
#define LOAD_MSG_4_2(buf) buf = _mm_set_epi32(m15,m4,m7,m0)
#define LOAD_MSG_4_3(buf) buf = _mm_set_epi32(m3,m6,m11,m14)
#define LOAD_MSG_4_4(buf) buf = _mm_set_epi32(m13,m8,m12,m1)
#define LOAD_MSG_5_1(buf) buf = _mm_set_epi32(m8,m0,m6,m2)
#define LOAD_MSG_5_2(buf) buf = _mm_set_epi32(m3,m11,m10,m12)
#define LOAD_MSG_5_3(buf) buf = _mm_set_epi32(m1,m15,m7,m4)
#define LOAD_MSG_5_4(buf) buf = _mm_set_epi32(m9,m14,m5,m13)
#define LOAD_MSG_6_1(buf) buf = _mm_set_epi32(m4,m14,m1,m12)
#define LOAD_MSG_6_2(buf) buf = _mm_set_epi32(m10,m13,m15,m5)
#define LOAD_MSG_6_3(buf) buf = _mm_set_epi32(m8,m9,m6,m0)
#define LOAD_MSG_6_4(buf) buf = _mm_set_epi32(m11,m2,m3,m7)
#define LOAD_MSG_7_1(buf) buf = _mm_set_epi32(m3,m12,m7,m13)
#define LOAD_MSG_7_2(buf) buf = _mm_set_epi32(m9,m1,m14,m11)
#define LOAD_MSG_7_3(buf) buf = _mm_set_epi32(m2,m8,m15,m5)
#define LOAD_MSG_7_4(buf) buf = _mm_set_epi32(m10,m6,m4,m0)
#define LOAD_MSG_8_1(buf) buf = _mm_set_epi32(m0,m11,m14,m6)
#define LOAD_MSG_8_2(buf) buf = _mm_set_epi32(m8,m3,m9,m15)
#define LOAD_MSG_8_3(buf) buf = _mm_set_epi32(m10,m1,m13,m12)
#define LOAD_MSG_8_4(buf) buf = _mm_set_epi32(m5,m4,m7,m2)
#define LOAD_MSG_9_1(buf) buf = _mm_set_epi32(m1,m7,m8,m10)
#define LOAD_MSG_9_2(buf) buf = _mm_set_epi32(m5,m6,m4,m2)
#define LOAD_MSG_9_3(buf) buf = _mm_set_epi32(m13,m3,m9,m15)
#define LOAD_MSG_9_4(buf) buf = _mm_set_epi32(m0,m12,m14,m11)
#endif

229
sse/blake2s-load-sse41.h Normal file
View File

@ -0,0 +1,229 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2S_LOAD_SSE41_H__
#define __BLAKE2S_LOAD_SSE41_H__
#define LOAD_MSG_0_1(buf) \
buf = TOI(_mm_shuffle_ps(TOF(m0), TOF(m1), _MM_SHUFFLE(2,0,2,0)));
#define LOAD_MSG_0_2(buf) \
buf = TOI(_mm_shuffle_ps(TOF(m0), TOF(m1), _MM_SHUFFLE(3,1,3,1)));
#define LOAD_MSG_0_3(buf) \
buf = TOI(_mm_shuffle_ps(TOF(m2), TOF(m3), _MM_SHUFFLE(2,0,2,0)));
#define LOAD_MSG_0_4(buf) \
buf = TOI(_mm_shuffle_ps(TOF(m2), TOF(m3), _MM_SHUFFLE(3,1,3,1)));
#define LOAD_MSG_1_1(buf) \
t0 = _mm_blend_epi16(m1, m2, 0x0C); \
t1 = _mm_slli_si128(m3, 4); \
t2 = _mm_blend_epi16(t0, t1, 0xF0); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,0,3));
#define LOAD_MSG_1_2(buf) \
t0 = _mm_shuffle_epi32(m2,_MM_SHUFFLE(0,0,2,0)); \
t1 = _mm_blend_epi16(m1,m3,0xC0); \
t2 = _mm_blend_epi16(t0, t1, 0xF0); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,3,0,1));
#define LOAD_MSG_1_3(buf) \
t0 = _mm_slli_si128(m1, 4); \
t1 = _mm_blend_epi16(m2, t0, 0x30); \
t2 = _mm_blend_epi16(m0, t1, 0xF0); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,3,0,1));
#define LOAD_MSG_1_4(buf) \
t0 = _mm_unpackhi_epi32(m0,m1); \
t1 = _mm_slli_si128(m3, 4); \
t2 = _mm_blend_epi16(t0, t1, 0x0C); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,3,0,1));
#define LOAD_MSG_2_1(buf) \
t0 = _mm_unpackhi_epi32(m2,m3); \
t1 = _mm_blend_epi16(m3,m1,0x0C); \
t2 = _mm_blend_epi16(t0, t1, 0x0F); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2));
#define LOAD_MSG_2_2(buf) \
t0 = _mm_unpacklo_epi32(m2,m0); \
t1 = _mm_blend_epi16(t0, m0, 0xF0); \
t2 = _mm_slli_si128(m3, 8); \
buf = _mm_blend_epi16(t1, t2, 0xC0);
#define LOAD_MSG_2_3(buf) \
t0 = _mm_blend_epi16(m0, m2, 0x3C); \
t1 = _mm_srli_si128(m1, 12); \
t2 = _mm_blend_epi16(t0,t1,0x03); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,0,3,2));
#define LOAD_MSG_2_4(buf) \
t0 = _mm_slli_si128(m3, 4); \
t1 = _mm_blend_epi16(m0, m1, 0x33); \
t2 = _mm_blend_epi16(t1, t0, 0xC0); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(0,1,2,3));
#define LOAD_MSG_3_1(buf) \
t0 = _mm_unpackhi_epi32(m0,m1); \
t1 = _mm_unpackhi_epi32(t0, m2); \
t2 = _mm_blend_epi16(t1, m3, 0x0C); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2));
#define LOAD_MSG_3_2(buf) \
t0 = _mm_slli_si128(m2, 8); \
t1 = _mm_blend_epi16(m3,m0,0x0C); \
t2 = _mm_blend_epi16(t1, t0, 0xC0); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,1,3));
#define LOAD_MSG_3_3(buf) \
t0 = _mm_blend_epi16(m0,m1,0x0F); \
t1 = _mm_blend_epi16(t0, m3, 0xC0); \
buf = _mm_shuffle_epi32(t1, _MM_SHUFFLE(3,0,1,2));
#define LOAD_MSG_3_4(buf) \
t0 = _mm_unpacklo_epi32(m0,m2); \
t1 = _mm_unpackhi_epi32(m1,m2); \
buf = _mm_unpacklo_epi64(t1,t0);
#define LOAD_MSG_4_1(buf) \
t0 = _mm_unpacklo_epi64(m1,m2); \
t1 = _mm_unpackhi_epi64(m0,m2); \
t2 = _mm_blend_epi16(t0,t1,0x33); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,1,3));
#define LOAD_MSG_4_2(buf) \
t0 = _mm_unpackhi_epi64(m1,m3); \
t1 = _mm_unpacklo_epi64(m0,m1); \
buf = _mm_blend_epi16(t0,t1,0x33);
#define LOAD_MSG_4_3(buf) \
t0 = _mm_unpackhi_epi64(m3,m1); \
t1 = _mm_unpackhi_epi64(m2,m0); \
buf = _mm_blend_epi16(t1,t0,0x33);
#define LOAD_MSG_4_4(buf) \
t0 = _mm_blend_epi16(m0,m2,0x03); \
t1 = _mm_slli_si128(t0, 8); \
t2 = _mm_blend_epi16(t1,m3,0x0F); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,2,0,3));
#define LOAD_MSG_5_1(buf) \
t0 = _mm_unpackhi_epi32(m0,m1); \
t1 = _mm_unpacklo_epi32(m0,m2); \
buf = _mm_unpacklo_epi64(t0,t1);
#define LOAD_MSG_5_2(buf) \
t0 = _mm_srli_si128(m2, 4); \
t1 = _mm_blend_epi16(m0,m3,0x03); \
buf = _mm_blend_epi16(t1,t0,0x3C);
#define LOAD_MSG_5_3(buf) \
t0 = _mm_blend_epi16(m1,m0,0x0C); \
t1 = _mm_srli_si128(m3, 4); \
t2 = _mm_blend_epi16(t0,t1,0x30); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,2,3,0));
#define LOAD_MSG_5_4(buf) \
t0 = _mm_unpacklo_epi64(m1,m2); \
t1= _mm_shuffle_epi32(m3, _MM_SHUFFLE(0,2,0,1)); \
buf = _mm_blend_epi16(t0,t1,0x33);
#define LOAD_MSG_6_1(buf) \
t0 = _mm_slli_si128(m1, 12); \
t1 = _mm_blend_epi16(m0,m3,0x33); \
buf = _mm_blend_epi16(t1,t0,0xC0);
#define LOAD_MSG_6_2(buf) \
t0 = _mm_blend_epi16(m3,m2,0x30); \
t1 = _mm_srli_si128(m1, 4); \
t2 = _mm_blend_epi16(t0,t1,0x03); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,3,0));
#define LOAD_MSG_6_3(buf) \
t0 = _mm_unpacklo_epi64(m0,m2); \
t1 = _mm_srli_si128(m1, 4); \
buf = _mm_shuffle_epi32(_mm_blend_epi16(t0,t1,0x0C), _MM_SHUFFLE(2,3,1,0));
#define LOAD_MSG_6_4(buf) \
t0 = _mm_unpackhi_epi32(m1,m2); \
t1 = _mm_unpackhi_epi64(m0,t0); \
buf = _mm_shuffle_epi32(t1, _MM_SHUFFLE(3,0,1,2));
#define LOAD_MSG_7_1(buf) \
t0 = _mm_unpackhi_epi32(m0,m1); \
t1 = _mm_blend_epi16(t0,m3,0x0F); \
buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(2,0,3,1));
#define LOAD_MSG_7_2(buf) \
t0 = _mm_blend_epi16(m2,m3,0x30); \
t1 = _mm_srli_si128(m0,4); \
t2 = _mm_blend_epi16(t0,t1,0x03); \
buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,0,2,3));
#define LOAD_MSG_7_3(buf) \
t0 = _mm_unpackhi_epi64(m0,m3); \
t1 = _mm_unpacklo_epi64(m1,m2); \
t2 = _mm_blend_epi16(t0,t1,0x3C); \
buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(0,2,3,1));
#define LOAD_MSG_7_4(buf) \
t0 = _mm_unpacklo_epi32(m0,m1); \
t1 = _mm_unpackhi_epi32(m1,m2); \
buf = _mm_unpacklo_epi64(t0,t1);
#define LOAD_MSG_8_1(buf) \
t0 = _mm_unpackhi_epi32(m1,m3); \
t1 = _mm_unpacklo_epi64(t0,m0); \
t2 = _mm_blend_epi16(t1,m2,0xC0); \
buf = _mm_shufflehi_epi16(t2,_MM_SHUFFLE(1,0,3,2));
#define LOAD_MSG_8_2(buf) \
t0 = _mm_unpackhi_epi32(m0,m3); \
t1 = _mm_blend_epi16(m2,t0,0xF0); \
buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(0,2,1,3));
#define LOAD_MSG_8_3(buf) \
t0 = _mm_blend_epi16(m2,m0,0x0C); \
t1 = _mm_slli_si128(t0,4); \
buf = _mm_blend_epi16(t1,m3,0x0F);
#define LOAD_MSG_8_4(buf) \
t0 = _mm_blend_epi16(m1,m0,0x30); \
buf = _mm_shuffle_epi32(t0,_MM_SHUFFLE(1,0,3,2));
#define LOAD_MSG_9_1(buf) \
t0 = _mm_blend_epi16(m0,m2,0x03); \
t1 = _mm_blend_epi16(m1,m2,0x30); \
t2 = _mm_blend_epi16(t1,t0,0x0F); \
buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(1,3,0,2));
#define LOAD_MSG_9_2(buf) \
t0 = _mm_slli_si128(m0,4); \
t1 = _mm_blend_epi16(m1,t0,0xC0); \
buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(1,2,0,3));
#define LOAD_MSG_9_3(buf) \
t0 = _mm_unpackhi_epi32(m0,m3); \
t1 = _mm_unpacklo_epi32(m2,m3); \
t2 = _mm_unpackhi_epi64(t0,t1); \
buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(3,0,2,1));
#define LOAD_MSG_9_4(buf) \
t0 = _mm_blend_epi16(m3,m2,0xC0); \
t1 = _mm_unpacklo_epi32(m0,m3); \
t2 = _mm_blend_epi16(t0,t1,0x0F); \
buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(0,1,2,3));
#endif

189
sse/blake2s-load-xop.h Normal file
View File

@ -0,0 +1,189 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2S_LOAD_XOP_H__
#define __BLAKE2S_LOAD_XOP_H__
#define TOB(x) ((x)*4*0x01010101 + 0x03020100) // ..or not TOB
/* Basic VPPERM emulation, for testing purposes */
/*static __m128i _mm_perm_epi8(const __m128i src1, const __m128i src2, const __m128i sel)
{
const __m128i sixteen = _mm_set1_epi8(16);
const __m128i t0 = _mm_shuffle_epi8(src1, sel);
const __m128i s1 = _mm_shuffle_epi8(src2, _mm_sub_epi8(sel, sixteen));
const __m128i mask = _mm_or_si128(_mm_cmpeq_epi8(sel, sixteen),
_mm_cmpgt_epi8(sel, sixteen)); // (>=16) = 0xff : 00
return _mm_blendv_epi8(t0, s1, mask);
}*/
#define LOAD_MSG_0_1(buf) \
buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(6),TOB(4),TOB(2),TOB(0)) );
#define LOAD_MSG_0_2(buf) \
buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(7),TOB(5),TOB(3),TOB(1)) );
#define LOAD_MSG_0_3(buf) \
buf = _mm_perm_epi8(m2, m3, _mm_set_epi32(TOB(6),TOB(4),TOB(2),TOB(0)) );
#define LOAD_MSG_0_4(buf) \
buf = _mm_perm_epi8(m2, m3, _mm_set_epi32(TOB(7),TOB(5),TOB(3),TOB(1)) );
#define LOAD_MSG_1_1(buf) \
t0 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(0),TOB(5),TOB(0),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(5),TOB(2),TOB(1),TOB(6)) );
#define LOAD_MSG_1_2(buf) \
t1 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(2),TOB(0),TOB(4),TOB(6)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(7),TOB(1),TOB(0)) );
#define LOAD_MSG_1_3(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(5),TOB(0),TOB(0),TOB(1)) ); \
buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(7),TOB(1),TOB(0)) );
#define LOAD_MSG_1_4(buf) \
t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(3),TOB(7),TOB(2),TOB(0)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(4)) );
#define LOAD_MSG_2_1(buf) \
t0 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(0),TOB(1),TOB(0),TOB(7)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(7),TOB(2),TOB(4),TOB(0)) );
#define LOAD_MSG_2_2(buf) \
t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(2),TOB(0),TOB(4)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(5),TOB(2),TOB(1),TOB(0)) );
#define LOAD_MSG_2_3(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(7),TOB(3),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(5),TOB(2),TOB(1),TOB(6)) );
#define LOAD_MSG_2_4(buf) \
t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(4),TOB(1),TOB(6),TOB(0)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(6)) );
#define LOAD_MSG_3_1(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(3),TOB(7)) ); \
t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(7),TOB(2),TOB(1),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(5),TOB(1),TOB(0)) );
#define LOAD_MSG_3_2(buf) \
t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(0),TOB(1),TOB(5)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(6),TOB(4),TOB(1),TOB(0)) );
#define LOAD_MSG_3_3(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(4),TOB(5),TOB(2)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(7),TOB(2),TOB(1),TOB(0)) );
#define LOAD_MSG_3_4(buf) \
t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(0),TOB(6)) ); \
buf = _mm_perm_epi8(t1, m2, _mm_set_epi32(TOB(4),TOB(2),TOB(6),TOB(0)) );
#define LOAD_MSG_4_1(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(2),TOB(5),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(6),TOB(2),TOB(1),TOB(5)) );
#define LOAD_MSG_4_2(buf) \
t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(4),TOB(7),TOB(0)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(7),TOB(2),TOB(1),TOB(0)) );
#define LOAD_MSG_4_3(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(3),TOB(6),TOB(0),TOB(0)) ); \
t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(2),TOB(7),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(6)) );
#define LOAD_MSG_4_4(buf) \
t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(4),TOB(0),TOB(1)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(5),TOB(2),TOB(4),TOB(0)) );
#define LOAD_MSG_5_1(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(6),TOB(2)) ); \
buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(4),TOB(2),TOB(1),TOB(0)) );
#define LOAD_MSG_5_2(buf) \
t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(3),TOB(7),TOB(6),TOB(0)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(4)) );
#define LOAD_MSG_5_3(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(1),TOB(0),TOB(7),TOB(4)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(7),TOB(1),TOB(0)) );
#define LOAD_MSG_5_4(buf) \
t1 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(5),TOB(0),TOB(1),TOB(0)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(6),TOB(1),TOB(5)) );
#define LOAD_MSG_6_1(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(4),TOB(0),TOB(1),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(6),TOB(1),TOB(4)) );
#define LOAD_MSG_6_2(buf) \
t1 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(6),TOB(0),TOB(0),TOB(1)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(5),TOB(7),TOB(0)) );
#define LOAD_MSG_6_3(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(6),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(4),TOB(5),TOB(1),TOB(0)) );
#define LOAD_MSG_6_4(buf) \
t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(2),TOB(3),TOB(7)) ); \
buf = _mm_perm_epi8(t1, m2, _mm_set_epi32(TOB(7),TOB(2),TOB(1),TOB(0)) );
#define LOAD_MSG_7_1(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(3),TOB(0),TOB(7),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(4),TOB(1),TOB(5)) );
#define LOAD_MSG_7_2(buf) \
t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(5),TOB(1),TOB(0),TOB(7)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(6),TOB(0)) );
#define LOAD_MSG_7_3(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(2),TOB(0),TOB(0),TOB(5)) ); \
t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(4),TOB(1),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(7),TOB(0)) );
#define LOAD_MSG_7_4(buf) \
t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(6),TOB(4),TOB(0)) ); \
buf = _mm_perm_epi8(t1, m2, _mm_set_epi32(TOB(6),TOB(2),TOB(1),TOB(0)) );
#define LOAD_MSG_8_1(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(0),TOB(6)) ); \
t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(7),TOB(1),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(6),TOB(0)) );
#define LOAD_MSG_8_2(buf) \
t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(4),TOB(3),TOB(5),TOB(0)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(7)) );
#define LOAD_MSG_8_3(buf) \
t0 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(6),TOB(1),TOB(0),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(5),TOB(4)) ); \
#define LOAD_MSG_8_4(buf) \
buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(5),TOB(4),TOB(7),TOB(2)) );
#define LOAD_MSG_9_1(buf) \
t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(1),TOB(7),TOB(0),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(2),TOB(4),TOB(6)) );
#define LOAD_MSG_9_2(buf) \
buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(5),TOB(6),TOB(4),TOB(2)) );
#define LOAD_MSG_9_3(buf) \
t0 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(3),TOB(5),TOB(0)) ); \
buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(5),TOB(2),TOB(1),TOB(7)) );
#define LOAD_MSG_9_4(buf) \
t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(0),TOB(0),TOB(7)) ); \
buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(4),TOB(6),TOB(0)) );
#endif

91
sse/blake2s-round.h Normal file
View File

@ -0,0 +1,91 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2S_ROUND_H__
#define __BLAKE2S_ROUND_H__
#define LOAD(p) _mm_load_si128( (__m128i *)(p) )
#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
#define LOADU(p) _mm_loadu_si128( (__m128i *)(p) )
#define STOREU(p,r) _mm_storeu_si128((__m128i *)(p), r)
#define TOF(reg) _mm_castsi128_ps((reg))
#define TOI(reg) _mm_castps_si128((reg))
#define LIKELY(x) __builtin_expect((x),1)
/* Microarchitecture-specific macros */
#ifndef HAVE_XOP
#ifdef HAVE_SSSE3
#define _mm_roti_epi32(r, c) ( \
(8==-(c)) ? _mm_shuffle_epi8(r,r8) \
: (16==-(c)) ? _mm_shuffle_epi8(r,r16) \
: _mm_xor_si128(_mm_srli_epi32( (r), -(c) ),_mm_slli_epi32( (r), 32-(-(c)) )) )
#else
#define _mm_roti_epi32(r, c) _mm_xor_si128(_mm_srli_epi32( (r), -(c) ),_mm_slli_epi32( (r), 32-(-c) ))
#endif
#else
/* ... */
#endif
#define G1(row1,row2,row3,row4,buf) \
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
row4 = _mm_xor_si128( row4, row1 ); \
row4 = _mm_roti_epi32(row4, -16); \
row3 = _mm_add_epi32( row3, row4 ); \
row2 = _mm_xor_si128( row2, row3 ); \
row2 = _mm_roti_epi32(row2, -12);
#define G2(row1,row2,row3,row4,buf) \
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
row4 = _mm_xor_si128( row4, row1 ); \
row4 = _mm_roti_epi32(row4, -8); \
row3 = _mm_add_epi32( row3, row4 ); \
row2 = _mm_xor_si128( row2, row3 ); \
row2 = _mm_roti_epi32(row2, -7);
#define DIAGONALIZE(row1,row2,row3,row4) \
row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(2,1,0,3) ); \
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(0,3,2,1) );
#define UNDIAGONALIZE(row1,row2,row3,row4) \
row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(0,3,2,1) ); \
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) );
#if defined(HAVE_XOP)
#include "blake2s-load-xop.h"
#elif defined(HAVE_SSE41)
#include "blake2s-load-sse41.h"
#else
#include "blake2s-load-sse2.h"
#endif
#define ROUND(r) \
LOAD_MSG_ ##r ##_1(buf1); \
G1(row1,row2,row3,row4,buf1); \
LOAD_MSG_ ##r ##_2(buf2); \
G2(row1,row2,row3,row4,buf2); \
DIAGONALIZE(row1,row2,row3,row4); \
LOAD_MSG_ ##r ##_3(buf3); \
G1(row1,row2,row3,row4,buf3); \
LOAD_MSG_ ##r ##_4(buf4); \
G2(row1,row2,row3,row4,buf4); \
UNDIAGONALIZE(row1,row2,row3,row4); \
#endif

416
sse/blake2s.c Normal file
View File

@ -0,0 +1,416 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
#include "blake2-config.h"
#include <emmintrin.h>
#if defined(HAVE_SSSE3)
#include <tmmintrin.h>
#endif
#if defined(HAVE_SSE41)
#include <smmintrin.h>
#endif
#if defined(HAVE_AVX)
#include <immintrin.h>
#endif
#if defined(HAVE_XOP)
#include <x86intrin.h>
#endif
#include "blake2s-round.h"
ALIGN( 64 ) static const uint32_t blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const uint8_t blake2s_sigma[10][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
/* Some helper functions, not necessarily useful */
static inline int blake2s_set_lastnode( blake2s_state *S )
{
S->f[1] = ~0U;
return 0;
}
static inline int blake2s_clear_lastnode( blake2s_state *S )
{
S->f[1] = 0U;
return 0;
}
static inline int blake2s_set_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_set_lastnode( S );
S->f[0] = ~0U;
return 0;
}
static inline int blake2s_clear_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_clear_lastnode( S );
S->f[0] = 0U;
return 0;
}
static inline int blake2s_increment_counter( blake2s_state *S, const uint32_t inc )
{
uint64_t t = ( ( uint64_t )S->t[1] << 32 ) | S->t[0];
t += inc;
S->t[0] = ( uint32_t )( t >> 0 );
S->t[1] = ( uint32_t )( t >> 32 );
return 0;
}
// Parameter-related functions
static inline int blake2s_param_set_digest_length( blake2s_param *P, const uint8_t digest_length )
{
P->digest_length = digest_length;
return 0;
}
static inline int blake2s_param_set_fanout( blake2s_param *P, const uint8_t fanout )
{
P->fanout = fanout;
return 0;
}
static inline int blake2s_param_set_max_depth( blake2s_param *P, const uint8_t depth )
{
P->depth = depth;
return 0;
}
static inline int blake2s_param_set_leaf_length( blake2s_param *P, const uint32_t leaf_length )
{
P->leaf_length = leaf_length;
return 0;
}
static inline int blake2s_param_set_node_offset( blake2s_param *P, const uint64_t node_offset )
{
store48( P->node_offset, node_offset );
return 0;
}
static inline int blake2s_param_set_node_depth( blake2s_param *P, const uint8_t node_depth )
{
P->node_depth = node_depth;
return 0;
}
static inline int blake2s_param_set_inner_length( blake2s_param *P, const uint8_t inner_length )
{
P->inner_length = inner_length;
return 0;
}
static inline int blake2s_param_set_salt( blake2s_param *P, const uint8_t salt[BLAKE2S_SALTBYTES] )
{
memcpy( P->salt, salt, BLAKE2S_SALTBYTES );
return 0;
}
static inline int blake2s_param_set_personal( blake2s_param *P, const uint8_t personal[BLAKE2S_PERSONALBYTES] )
{
memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES );
return 0;
}
static inline int blake2s_init0( blake2s_state *S )
{
memset( S, 0, sizeof( blake2s_state ) );
for( int i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];
return 0;
}
/* init2 xors IV with input parameter block */
int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
{
uint8_t *p, *h, *v;
//blake2s_init0( S );
v = ( uint8_t * )( blake2s_IV );
h = ( uint8_t * )( S->h );
p = ( uint8_t * )( P );
/* IV XOR ParamBlock */
memset( S, 0, sizeof( blake2s_state ) );
for( int i = 0; i < BLAKE2S_OUTBYTES; ++i ) h[i] = v[i] ^ p[i];
return 0;
}
/* Some sort of default parameter block initialization, for sequential blake2s */
int blake2s_init( blake2s_state *S, const uint8_t outlen )
{
/* Move interval verification here? */
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
const blake2s_param P =
{
outlen,
0,
1,
1,
0,
{0},
0,
0,
{0},
{0}
};
return blake2s_init_param( S, &P );
}
int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
/* Move interval verification here? */
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
if ( ( !key ) || ( !keylen ) || keylen > BLAKE2S_KEYBYTES ) return -1;
const blake2s_param P =
{
outlen,
keylen,
1,
1,
0,
{0},
0,
0,
{0},
{0}
};
if( blake2s_init_param( S, &P ) < 0 )
return -1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
blake2s_update( S, block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
static inline int blake2s_compress( blake2s_state *S, const uint8_t block[BLAKE2S_BLOCKBYTES] )
{
__m128i row1, row2, row3, row4;
__m128i buf1, buf2, buf3, buf4;
#if defined(HAVE_SSE41)
__m128i t0, t1;
#if !defined(HAVE_XOP)
__m128i t2;
#endif
#endif
__m128i ff0, ff1;
#if defined(HAVE_SSSE3) && !defined(HAVE_XOP)
const __m128i r8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 );
const __m128i r16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 );
#endif
#if defined(HAVE_SSE41)
const __m128i m0 = LOADU( block + 00 );
const __m128i m1 = LOADU( block + 16 );
const __m128i m2 = LOADU( block + 32 );
const __m128i m3 = LOADU( block + 48 );
#else
const uint32_t m0 = ( ( uint32_t * )block )[ 0];
const uint32_t m1 = ( ( uint32_t * )block )[ 1];
const uint32_t m2 = ( ( uint32_t * )block )[ 2];
const uint32_t m3 = ( ( uint32_t * )block )[ 3];
const uint32_t m4 = ( ( uint32_t * )block )[ 4];
const uint32_t m5 = ( ( uint32_t * )block )[ 5];
const uint32_t m6 = ( ( uint32_t * )block )[ 6];
const uint32_t m7 = ( ( uint32_t * )block )[ 7];
const uint32_t m8 = ( ( uint32_t * )block )[ 8];
const uint32_t m9 = ( ( uint32_t * )block )[ 9];
const uint32_t m10 = ( ( uint32_t * )block )[10];
const uint32_t m11 = ( ( uint32_t * )block )[11];
const uint32_t m12 = ( ( uint32_t * )block )[12];
const uint32_t m13 = ( ( uint32_t * )block )[13];
const uint32_t m14 = ( ( uint32_t * )block )[14];
const uint32_t m15 = ( ( uint32_t * )block )[15];
#endif
row1 = ff0 = LOAD( &S->h[0] );
row2 = ff1 = LOAD( &S->h[4] );
row3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A );
row4 = _mm_xor_si128( _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 ), LOAD( &S->t[0] ) );
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
STORE( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row1, row3 ) ) );
STORE( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row2, row4 ) ) );
return 0;
}
/* inlen now in bytes */
int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen )
{
while( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = 2 * BLAKE2S_BLOCKBYTES - left;
if( inlen > fill )
{
memcpy( S->buf + left, in, fill ); // Fill buffer
S->buflen += fill;
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf ); // Compress
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left
S->buflen -= BLAKE2S_BLOCKBYTES;
in += fill;
inlen -= fill;
}
else // inlen <= fill
{
memcpy( S->buf + left, in, inlen );
S->buflen += inlen; // Be lazy, do not compress
in += inlen;
inlen -= inlen;
}
}
return 0;
}
/* Is this correct? */
int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen )
{
uint8_t buffer[BLAKE2S_OUTBYTES];
if( S->buflen > BLAKE2S_BLOCKBYTES )
{
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf );
S->buflen -= BLAKE2S_BLOCKBYTES;
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen );
}
blake2s_increment_counter( S, ( uint32_t )S->buflen );
blake2s_set_lastblock( S );
memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
blake2s_compress( S, S->buf );
for( int i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store32( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, outlen );
return 0;
}
/* inlen, at least, should be uint64_t. Others can be size_t. */
int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
{
blake2s_state S[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key ) keylen = 0; /* Fail here instead if keylen != 0 and key == NULL? */
if( keylen > 0 )
{
if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2s_init( S, outlen ) < 0 ) return -1;
}
blake2s_update( S, ( uint8_t * )in, inlen );
blake2s_final( S, out, outlen );
return 0;
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2s( out, in, NULL, BLAKE2S_OUTBYTES, inlen, 0 );
}
#endif
#if defined(BLAKE2S_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
if( blake2s( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES ) < 0 ||
0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

291
sse/blake2sp.c Normal file
View File

@ -0,0 +1,291 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 8
static inline int blake2sp_init_leaf( blake2s_state *S, uint8_t outlen, uint8_t keylen, uint64_t offset )
{
blake2s_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
P->leaf_length = 0;
store48( P->node_offset, offset );
P->node_depth = 0;
P->inner_length = outlen;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
static inline int blake2sp_init_root( blake2s_state *S, uint8_t outlen, uint8_t keylen )
{
blake2s_param P[1];
P->digest_length = outlen;
P->key_length = keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
P->leaf_length = 0;
store48( P->node_offset, 0ULL );
P->node_depth = 1;
P->inner_length = outlen;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2sp_init( blake2sp_state *S, const uint8_t outlen )
{
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
{
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen )
{
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S->S[id__], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2sp_final( blake2sp_state *S, uint8_t *out, const uint8_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2S_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
}
blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
}
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
blake2s_final( S->R, out, outlen );
return 0;
}
int blake2sp( uint8_t *out, const void *in, const void *key, uint8_t outlen, uint64_t inlen, uint8_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
blake2s_state S[PARALLELISM_DEGREE][1];
blake2s_state FS[1];
/* Verify parameters */
if ( NULL == in ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key ) keylen = 0;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; // mark last node
if( keylen > 0 )
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
#endif
{
#if defined(_OPENMP)
size_t id__ = omp_get_thread_num();
#endif
uint64_t inlen__ = inlen;
const uint8_t *in__ = ( const uint8_t * )in;
in__ += id__ * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S[id__], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
if( inlen__ > id__ * BLAKE2S_BLOCKBYTES )
{
const size_t left = inlen__ - id__ * BLAKE2S_BLOCKBYTES;
const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
blake2s_update( S[id__], in__, len );
}
blake2s_final( S[id__], hash[id__], BLAKE2S_OUTBYTES );
}
if( blake2sp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1;
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
blake2s_final( FS, out, outlen );
return 0;
}
#if defined(BLAKE2SP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( int argc, char **argv )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[KAT_LENGTH];
for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
for( size_t i = 0; i < KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
puts( "error" );
return -1;
}
}
puts( "ok" );
return 0;
}
#endif

19
sse/makefile Normal file
View File

@ -0,0 +1,19 @@
CC=gcc
CFLAGS=-std=c99 -Wall -pedantic -O3 -march=native
all: blake2s blake2b blake2sp blake2bp
blake2s: blake2s.c
$(CC) blake2s.c -o $@ $(CFLAGS) -DBLAKE2S_SELFTEST
blake2b: blake2b.c
$(CC) blake2b.c -o $@ $(CFLAGS) -DBLAKE2B_SELFTEST
blake2sp: blake2sp.c blake2s.c
$(CC) blake2sp.c blake2s.c -o $@ $(CFLAGS) -DBLAKE2SP_SELFTEST
blake2bp: blake2bp.c blake2b.c
$(CC) blake2bp.c blake2b.c -o $@ $(CFLAGS) -DBLAKE2BP_SELFTEST
clean:
rm -rf *.o blake2s blake2b blake2sp blake2bp