stratum code

This commit is contained in:
root 2015-06-24 09:56:21 -04:00 committed by Tanguy Pruvot
parent b6b063e2fd
commit cc92c825ef
174 changed files with 87489 additions and 0 deletions

52
stratum/Makefile Executable file
View file

@ -0,0 +1,52 @@
CC=gcc
CFLAGS=-c -g -I /usr/include/mysql -march=native
LDFLAGS=-g
#CFLAGS=-c -O2 -I /usr/include/mysql
#LDFLAGS=-O2
LDLIBS=iniparser/libiniparser.a algos/libalgos.a sha3/libhash.a -lmysqlclient -lpthread -lm -lstdc++
SOURCES=stratum.cpp db.cpp coind.cpp coind_aux.cpp coind_template.cpp coind_submit.cpp util.cpp list.cpp \
rpc.cpp job.cpp job_send.cpp job_core.cpp merkle.cpp share.cpp socket.cpp coinbase.cpp \
client.cpp client_submit.cpp client_core.cpp client_difficulty.cpp remote.cpp remote_template.cpp \
user.cpp object.cpp json.cpp base58.cpp
OBJECTS=$(SOURCES:.cpp=.o)
OUTPUT=stratum
CODEDIR1=algos
CODEDIR2=sha3
.PHONY: projectcode1 projectcode2
all: projectcode1 projectcode2 $(SOURCES) $(OUTPUT)
projectcode1:
$(MAKE) -C $(CODEDIR1)
projectcode2:
$(MAKE) -C $(CODEDIR2)
$(SOURCES): stratum.h util.h
$(OUTPUT): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@
.cpp.o:
$(CC) $(CFLAGS) $<
.c.o:
$(CC) $(CFLAGS) $<
clean:
rm -f *.o
rm -f algos/*.o
rm -f sha3/*.o
install: all
strip -s stratum
cp stratum /usr/local/bin/

208
stratum/algos/Lyra2.c Normal file
View file

@ -0,0 +1,208 @@
/**
* Implementation of the Lyra2 Password Hashing Scheme (PHS).
*
* Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014.
*
* This software is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "Lyra2.h"
#include "Sponge.h"
/**
* Executes Lyra2 based on the G function from Blake2b. This version supports salts and passwords
* whose combined length is smaller than the size of the memory matrix, (i.e., (nRows x nCols x b) bits,
* where "b" is the underlying sponge's bitrate). In this implementation, the "basil" is composed by all
* integer parameters (treated as type "unsigned int") in the order they are provided, plus the value
* of nCols, (i.e., basil = kLen || pwdlen || saltlen || timeCost || nRows || nCols).
*
* @param K The derived key to be output by the algorithm
* @param kLen Desired key length
* @param pwd User password
* @param pwdlen Password length
* @param salt Salt
* @param saltlen Salt length
* @param timeCost Parameter to determine the processing time (T)
* @param nRows Number or rows of the memory matrix (R)
* @param nCols Number of columns of the memory matrix (C)
*
* @return 0 if the key is generated correctly; -1 if there is an error (usually due to lack of memory for allocation)
*/
int LYRA2(void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void *salt, uint64_t saltlen, uint64_t timeCost, uint64_t nRows, uint64_t nCols) {
//============================= Basic variables ============================//
int64_t row = 2; //index of row to be processed
int64_t prev = 1; //index of prev (last row ever computed/modified)
int64_t rowa = 0; //index of row* (a previous row, deterministically picked during Setup and randomly picked while Wandering)
int64_t tau; //Time Loop iterator
int64_t step = 1; //Visitation step (used during Setup and Wandering phases)
int64_t window = 2; //Visitation window (used to define which rows can be revisited during Setup)
int64_t gap = 1; //Modifier to the step, assuming the values 1 or -1
int64_t i; //auxiliary iteration counter
//==========================================================================/
//========== Initializing the Memory Matrix and pointers to it =============//
//Tries to allocate enough space for the whole memory matrix
i = (int64_t) ((int64_t) nRows * (int64_t) ROW_LEN_BYTES);
uint64_t *wholeMatrix = malloc(i);
if (wholeMatrix == NULL) {
return -1;
}
memset(wholeMatrix, 0, i);
//Allocates pointers to each row of the matrix
uint64_t **memMatrix = malloc(nRows * sizeof (uint64_t*));
if (memMatrix == NULL) {
return -1;
}
//Places the pointers in the correct positions
uint64_t *ptrWord = wholeMatrix;
for (i = 0; i < nRows; i++) {
memMatrix[i] = ptrWord;
ptrWord += ROW_LEN_INT64;
}
//==========================================================================/
//============= Getting the password + salt + basil padded with 10*1 ===============//
//OBS.:The memory matrix will temporarily hold the password: not for saving memory,
//but this ensures that the password copied locally will be overwritten as soon as possible
//First, we clean enough blocks for the password, salt, basil and padding
uint64_t nBlocksInput = ((saltlen + pwdlen + 6 * sizeof (uint64_t)) / BLOCK_LEN_BLAKE2_SAFE_BYTES) + 1;
byte *ptrByte = (byte*) wholeMatrix;
memset(ptrByte, 0, nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES);
//Prepends the password
memcpy(ptrByte, pwd, pwdlen);
ptrByte += pwdlen;
//Concatenates the salt
memcpy(ptrByte, salt, saltlen);
ptrByte += saltlen;
//Concatenates the basil: every integer passed as parameter, in the order they are provided by the interface
memcpy(ptrByte, &kLen, sizeof (uint64_t));
ptrByte += sizeof (uint64_t);
memcpy(ptrByte, &pwdlen, sizeof (uint64_t));
ptrByte += sizeof (uint64_t);
memcpy(ptrByte, &saltlen, sizeof (uint64_t));
ptrByte += sizeof (uint64_t);
memcpy(ptrByte, &timeCost, sizeof (uint64_t));
ptrByte += sizeof (uint64_t);
memcpy(ptrByte, &nRows, sizeof (uint64_t));
ptrByte += sizeof (uint64_t);
memcpy(ptrByte, &nCols, sizeof (uint64_t));
ptrByte += sizeof (uint64_t);
//Now comes the padding
*ptrByte = 0x80; //first byte of padding: right after the password
ptrByte = (byte*) wholeMatrix; //resets the pointer to the start of the memory matrix
ptrByte += nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES - 1; //sets the pointer to the correct position: end of incomplete block
*ptrByte ^= 0x01; //last byte of padding: at the end of the last incomplete block
//==========================================================================/
//======================= Initializing the Sponge State ====================//
//Sponge state: 16 uint64_t, BLOCK_LEN_INT64 words of them for the bitrate (b) and the remainder for the capacity (c)
uint64_t *state = malloc(16 * sizeof (uint64_t));
if (state == NULL) {
return -1;
}
initState(state);
//==========================================================================/
//================================ Setup Phase =============================//
//Absorbing salt, password and basil: this is the only place in which the block length is hard-coded to 512 bits
ptrWord = wholeMatrix;
for (i = 0; i < nBlocksInput; i++) {
absorbBlockBlake2Safe(state, ptrWord); //absorbs each block of pad(pwd || salt || basil)
ptrWord += BLOCK_LEN_BLAKE2_SAFE_BYTES; //goes to next block of pad(pwd || salt || basil)
}
//Initializes M[0] and M[1]
reducedSqueezeRow0(state, memMatrix[0]); //The locally copied password is most likely overwritten here
reducedDuplexRow1(state, memMatrix[0], memMatrix[1]);
do {
//M[row] = rand; //M[row*] = M[row*] XOR rotW(rand)
reducedDuplexRowSetup(state, memMatrix[prev], memMatrix[rowa], memMatrix[row]);
//updates the value of row* (deterministically picked during Setup))
rowa = (rowa + step) & (window - 1);
//update prev: it now points to the last row ever computed
prev = row;
//updates row: goes to the next row to be computed
row++;
//Checks if all rows in the window where visited.
if (rowa == 0) {
step = window + gap; //changes the step: approximately doubles its value
window *= 2; //doubles the size of the re-visitation window
gap = -gap; //inverts the modifier to the step
}
} while (row < nRows);
//==========================================================================/
//============================ Wandering Phase =============================//
row = 0; //Resets the visitation to the first row of the memory matrix
for (tau = 1; tau <= timeCost; tau++) {
//Step is approximately half the number of all rows of the memory matrix for an odd tau; otherwise, it is -1
step = (tau % 2 == 0) ? -1 : nRows / 2 - 1;
do {
//Selects a pseudorandom index row*
//------------------------------------------------------------------------------------------
//rowa = ((unsigned int)state[0]) & (nRows-1); //(USE THIS IF nRows IS A POWER OF 2)
rowa = ((uint64_t) (state[0])) % nRows; //(USE THIS FOR THE "GENERIC" CASE)
//------------------------------------------------------------------------------------------
//Performs a reduced-round duplexing operation over M[row*] XOR M[prev], updating both M[row*] and M[row]
reducedDuplexRow(state, memMatrix[prev], memMatrix[rowa], memMatrix[row]);
//update prev: it now points to the last row ever computed
prev = row;
//updates row: goes to the next row to be computed
//------------------------------------------------------------------------------------------
//row = (row + step) & (nRows-1); //(USE THIS IF nRows IS A POWER OF 2)
row = (row + step) % nRows; //(USE THIS FOR THE "GENERIC" CASE)
//------------------------------------------------------------------------------------------
} while (row != 0);
}
//==========================================================================/
//============================ Wrap-up Phase ===============================//
//Absorbs the last block of the memory matrix
absorbBlock(state, memMatrix[rowa]);
//Squeezes the key
squeeze(state, K, kLen);
//==========================================================================/
//========================= Freeing the memory =============================//
free(memMatrix);
free(wholeMatrix);
//Wiping out the sponge's internal state before freeing it
memset(state, 0, 16 * sizeof (uint64_t));
free(state);
//==========================================================================/
return 0;
}

50
stratum/algos/Lyra2.h Normal file
View file

@ -0,0 +1,50 @@
/**
* Header file for the Lyra2 Password Hashing Scheme (PHS).
*
* Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014.
*
* This software is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LYRA2_H_
#define LYRA2_H_
#include <stdint.h>
typedef unsigned char byte;
//Block length required so Blake2's Initialization Vector (IV) is not overwritten (THIS SHOULD NOT BE MODIFIED)
#define BLOCK_LEN_BLAKE2_SAFE_INT64 8 //512 bits (=64 bytes, =8 uint64_t)
#define BLOCK_LEN_BLAKE2_SAFE_BYTES (BLOCK_LEN_BLAKE2_SAFE_INT64 * 8) //same as above, in bytes
#ifdef BLOCK_LEN_BITS
#define BLOCK_LEN_INT64 (BLOCK_LEN_BITS/64) //Block length: 768 bits (=96 bytes, =12 uint64_t)
#define BLOCK_LEN_BYTES (BLOCK_LEN_BITS/8) //Block length, in bytes
#else //default block lenght: 768 bits
#define BLOCK_LEN_INT64 12 //Block length: 768 bits (=96 bytes, =12 uint64_t)
#define BLOCK_LEN_BYTES (BLOCK_LEN_INT64 * 8) //Block length, in bytes
#endif
#ifndef N_COLS
#define N_COLS 8 //Number of columns in the memory matrix: fixed to 64 by default
#endif
#define ROW_LEN_INT64 (BLOCK_LEN_INT64 * N_COLS) //Total length of a row: N_COLS blocks
#define ROW_LEN_BYTES (ROW_LEN_INT64 * 8) //Number of bytes per row
int LYRA2(void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void *salt, uint64_t saltlen, uint64_t timeCost, uint64_t nRows, uint64_t nCols);
#endif /* LYRA2_H_ */

70
stratum/algos/Lyra2RE.c Normal file
View file

@ -0,0 +1,70 @@
/*-
* Copyright 2009 Colin Percival, 2011 ArtForz, 2013 Neisklar, 2014 James Lovejoy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file was originally written by Colin Percival as part of the Tarsnap
* online backup system.
*/
#include "Lyra2RE.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#include "Lyra2.h"
void lyra2re_hash(const char* input, char* output)
{
sph_blake256_context ctx_blake;
sph_groestl256_context ctx_groestl;
sph_keccak256_context ctx_keccak;
sph_skein256_context ctx_skein;
uint32_t hashA[8], hashB[8];
sph_blake256_init(&ctx_blake);
sph_blake256 (&ctx_blake, input, 80);
sph_blake256_close (&ctx_blake, hashA);
sph_keccak256_init(&ctx_keccak);
sph_keccak256 (&ctx_keccak,hashA, 32);
sph_keccak256_close(&ctx_keccak, hashB);
LYRA2((void*)hashA, 32, (const void*)hashB, 32, (const void*)hashB, 32, 1, 8, 8);
sph_skein256_init(&ctx_skein);
sph_skein256 (&ctx_skein, hashA, 32);
sph_skein256_close(&ctx_skein, hashB);
sph_groestl256_init(&ctx_groestl);
sph_groestl256 (&ctx_groestl, hashB, 32);
sph_groestl256_close(&ctx_groestl, hashA);
memcpy(output, hashA, 32);
}

16
stratum/algos/Lyra2RE.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef LYRA2RE_H
#define LYRA2RE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void lyra2re_hash(const char* input, char* output);
#ifdef __cplusplus
}
#endif
#endif

745
stratum/algos/Sponge.c Normal file
View file

@ -0,0 +1,745 @@
/**
* A simple implementation of Blake2b's internal permutation
* in the form of a sponge.
*
* Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014.
*
* This software is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "Sponge.h"
#include "Lyra2.h"
/**
* Initializes the Sponge State. The first 512 bits are set to zeros and the remainder
* receive Blake2b's IV as per Blake2b's specification. <b>Note:</b> Even though sponges
* typically have their internal state initialized with zeros, Blake2b's G function
* has a fixed point: if the internal state and message are both filled with zeros. the
* resulting permutation will always be a block filled with zeros; this happens because
* Blake2b does not use the constants originally employed in Blake2 inside its G function,
* relying on the IV for avoiding possible fixed points.
*
* @param state The 1024-bit array to be initialized
*/
inline void initState(uint64_t state[/*16*/]) {
//First 512 bis are zeros
memset(state, 0, 64);
//Remainder BLOCK_LEN_BLAKE2_SAFE_BYTES are reserved to the IV
state[8] = blake2b_IV[0];
state[9] = blake2b_IV[1];
state[10] = blake2b_IV[2];
state[11] = blake2b_IV[3];
state[12] = blake2b_IV[4];
state[13] = blake2b_IV[5];
state[14] = blake2b_IV[6];
state[15] = blake2b_IV[7];
}
/**
* Execute Blake2b's G function, with all 12 rounds.
*
* @param v A 1024-bit (16 uint64_t) array to be processed by Blake2b's G function
*/
inline static void blake2bLyra(uint64_t *v) {
ROUND_LYRA(0);
ROUND_LYRA(1);
ROUND_LYRA(2);
ROUND_LYRA(3);
ROUND_LYRA(4);
ROUND_LYRA(5);
ROUND_LYRA(6);
ROUND_LYRA(7);
ROUND_LYRA(8);
ROUND_LYRA(9);
ROUND_LYRA(10);
ROUND_LYRA(11);
}
/**
* Executes a reduced version of Blake2b's G function with only one round
* @param v A 1024-bit (16 uint64_t) array to be processed by Blake2b's G function
*/
inline static void reducedBlake2bLyra(uint64_t *v) {
ROUND_LYRA(0);
}
/**
* Performs a squeeze operation, using Blake2b's G function as the
* internal permutation
*
* @param state The current state of the sponge
* @param out Array that will receive the data squeezed
* @param len The number of bytes to be squeezed into the "out" array
*/
inline void squeeze(uint64_t *state, byte *out, unsigned int len) {
int fullBlocks = len / BLOCK_LEN_BYTES;
byte *ptr = out;
int i;
//Squeezes full blocks
for (i = 0; i < fullBlocks; i++) {
memcpy(ptr, state, BLOCK_LEN_BYTES);
blake2bLyra(state);
ptr += BLOCK_LEN_BYTES;
}
//Squeezes remaining bytes
memcpy(ptr, state, (len % BLOCK_LEN_BYTES));
}
/**
* Performs an absorb operation for a single block (BLOCK_LEN_INT64 words
* of type uint64_t), using Blake2b's G function as the internal permutation
*
* @param state The current state of the sponge
* @param in The block to be absorbed (BLOCK_LEN_INT64 words)
*/
inline void absorbBlock(uint64_t *state, const uint64_t *in) {
//XORs the first BLOCK_LEN_INT64 words of "in" with the current state
state[0] ^= in[0];
state[1] ^= in[1];
state[2] ^= in[2];
state[3] ^= in[3];
state[4] ^= in[4];
state[5] ^= in[5];
state[6] ^= in[6];
state[7] ^= in[7];
state[8] ^= in[8];
state[9] ^= in[9];
state[10] ^= in[10];
state[11] ^= in[11];
//Applies the transformation f to the sponge's state
blake2bLyra(state);
}
/**
* Performs an absorb operation for a single block (BLOCK_LEN_BLAKE2_SAFE_INT64
* words of type uint64_t), using Blake2b's G function as the internal permutation
*
* @param state The current state of the sponge
* @param in The block to be absorbed (BLOCK_LEN_BLAKE2_SAFE_INT64 words)
*/
inline void absorbBlockBlake2Safe(uint64_t *state, const uint64_t *in) {
//XORs the first BLOCK_LEN_BLAKE2_SAFE_INT64 words of "in" with the current state
state[0] ^= in[0];
state[1] ^= in[1];
state[2] ^= in[2];
state[3] ^= in[3];
state[4] ^= in[4];
state[5] ^= in[5];
state[6] ^= in[6];
state[7] ^= in[7];
//Applies the transformation f to the sponge's state
blake2bLyra(state);
}
/**
* Performs a reduced squeeze operation for a single row, from the highest to
* the lowest index, using the reduced-round Blake2b's G function as the
* internal permutation
*
* @param state The current state of the sponge
* @param rowOut Row to receive the data squeezed
*/
inline void reducedSqueezeRow0(uint64_t* state, uint64_t* rowOut) {
uint64_t* ptrWord = rowOut + (N_COLS-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to M[0][C-1]
int i;
//M[row][C-1-col] = H.reduced_squeeze()
for (i = 0; i < N_COLS; i++) {
ptrWord[0] = state[0];
ptrWord[1] = state[1];
ptrWord[2] = state[2];
ptrWord[3] = state[3];
ptrWord[4] = state[4];
ptrWord[5] = state[5];
ptrWord[6] = state[6];
ptrWord[7] = state[7];
ptrWord[8] = state[8];
ptrWord[9] = state[9];
ptrWord[10] = state[10];
ptrWord[11] = state[11];
//Goes to next block (column) that will receive the squeezed data
ptrWord -= BLOCK_LEN_INT64;
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
}
}
/**
* Performs a reduced duplex operation for a single row, from the highest to
* the lowest index, using the reduced-round Blake2b's G function as the
* internal permutation
*
* @param state The current state of the sponge
* @param rowIn Row to feed the sponge
* @param rowOut Row to receive the sponge's output
*/
inline void reducedDuplexRow1(uint64_t *state, uint64_t *rowIn, uint64_t *rowOut) {
uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev
uint64_t* ptrWordOut = rowOut + (N_COLS-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to row
int i;
for (i = 0; i < N_COLS; i++) {
//Absorbing "M[prev][col]"
state[0] ^= (ptrWordIn[0]);
state[1] ^= (ptrWordIn[1]);
state[2] ^= (ptrWordIn[2]);
state[3] ^= (ptrWordIn[3]);
state[4] ^= (ptrWordIn[4]);
state[5] ^= (ptrWordIn[5]);
state[6] ^= (ptrWordIn[6]);
state[7] ^= (ptrWordIn[7]);
state[8] ^= (ptrWordIn[8]);
state[9] ^= (ptrWordIn[9]);
state[10] ^= (ptrWordIn[10]);
state[11] ^= (ptrWordIn[11]);
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[row][C-1-col] = M[prev][col] XOR rand
ptrWordOut[0] = ptrWordIn[0] ^ state[0];
ptrWordOut[1] = ptrWordIn[1] ^ state[1];
ptrWordOut[2] = ptrWordIn[2] ^ state[2];
ptrWordOut[3] = ptrWordIn[3] ^ state[3];
ptrWordOut[4] = ptrWordIn[4] ^ state[4];
ptrWordOut[5] = ptrWordIn[5] ^ state[5];
ptrWordOut[6] = ptrWordIn[6] ^ state[6];
ptrWordOut[7] = ptrWordIn[7] ^ state[7];
ptrWordOut[8] = ptrWordIn[8] ^ state[8];
ptrWordOut[9] = ptrWordIn[9] ^ state[9];
ptrWordOut[10] = ptrWordIn[10] ^ state[10];
ptrWordOut[11] = ptrWordIn[11] ^ state[11];
//Input: next column (i.e., next block in sequence)
ptrWordIn += BLOCK_LEN_INT64;
//Output: goes to previous column
ptrWordOut -= BLOCK_LEN_INT64;
}
}
/**
* Performs a duplexing operation over "M[rowInOut][col] [+] M[rowIn][col]" (i.e.,
* the wordwise addition of two columns, ignoring carries between words). The
* output of this operation, "rand", is then used to make
* "M[rowOut][(N_COLS-1)-col] = M[rowIn][col] XOR rand" and
* "M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)", where rotW is a 64-bit
* rotation to the left and N_COLS is a system parameter.
*
* @param state The current state of the sponge
* @param rowIn Row used only as input
* @param rowInOut Row used as input and to receive output after rotation
* @param rowOut Row receiving the output
*
*/
inline void reducedDuplexRowSetup(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut) {
uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev
uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row*
uint64_t* ptrWordOut = rowOut + (N_COLS-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to row
int i;
for (i = 0; i < N_COLS; i++) {
//Absorbing "M[prev] [+] M[row*]"
state[0] ^= (ptrWordIn[0] + ptrWordInOut[0]);
state[1] ^= (ptrWordIn[1] + ptrWordInOut[1]);
state[2] ^= (ptrWordIn[2] + ptrWordInOut[2]);
state[3] ^= (ptrWordIn[3] + ptrWordInOut[3]);
state[4] ^= (ptrWordIn[4] + ptrWordInOut[4]);
state[5] ^= (ptrWordIn[5] + ptrWordInOut[5]);
state[6] ^= (ptrWordIn[6] + ptrWordInOut[6]);
state[7] ^= (ptrWordIn[7] + ptrWordInOut[7]);
state[8] ^= (ptrWordIn[8] + ptrWordInOut[8]);
state[9] ^= (ptrWordIn[9] + ptrWordInOut[9]);
state[10] ^= (ptrWordIn[10] + ptrWordInOut[10]);
state[11] ^= (ptrWordIn[11] + ptrWordInOut[11]);
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[row][col] = M[prev][col] XOR rand
ptrWordOut[0] = ptrWordIn[0] ^ state[0];
ptrWordOut[1] = ptrWordIn[1] ^ state[1];
ptrWordOut[2] = ptrWordIn[2] ^ state[2];
ptrWordOut[3] = ptrWordIn[3] ^ state[3];
ptrWordOut[4] = ptrWordIn[4] ^ state[4];
ptrWordOut[5] = ptrWordIn[5] ^ state[5];
ptrWordOut[6] = ptrWordIn[6] ^ state[6];
ptrWordOut[7] = ptrWordIn[7] ^ state[7];
ptrWordOut[8] = ptrWordIn[8] ^ state[8];
ptrWordOut[9] = ptrWordIn[9] ^ state[9];
ptrWordOut[10] = ptrWordIn[10] ^ state[10];
ptrWordOut[11] = ptrWordIn[11] ^ state[11];
//M[row*][col] = M[row*][col] XOR rotW(rand)
ptrWordInOut[0] ^= state[11];
ptrWordInOut[1] ^= state[0];
ptrWordInOut[2] ^= state[1];
ptrWordInOut[3] ^= state[2];
ptrWordInOut[4] ^= state[3];
ptrWordInOut[5] ^= state[4];
ptrWordInOut[6] ^= state[5];
ptrWordInOut[7] ^= state[6];
ptrWordInOut[8] ^= state[7];
ptrWordInOut[9] ^= state[8];
ptrWordInOut[10] ^= state[9];
ptrWordInOut[11] ^= state[10];
//Inputs: next column (i.e., next block in sequence)
ptrWordInOut += BLOCK_LEN_INT64;
ptrWordIn += BLOCK_LEN_INT64;
//Output: goes to previous column
ptrWordOut -= BLOCK_LEN_INT64;
}
}
/**
* Performs a duplexing operation over "M[rowInOut][col] [+] M[rowIn][col]" (i.e.,
* the wordwise addition of two columns, ignoring carries between words). The
* output of this operation, "rand", is then used to make
* "M[rowOut][col] = M[rowOut][col] XOR rand" and
* "M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)", where rotW is a 64-bit
* rotation to the left.
*
* @param state The current state of the sponge
* @param rowIn Row used only as input
* @param rowInOut Row used as input and to receive output after rotation
* @param rowOut Row receiving the output
*
*/
inline void reducedDuplexRow(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut) {
uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row*
uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev
uint64_t* ptrWordOut = rowOut; //In Lyra2: pointer to row
int i;
for (i = 0; i < N_COLS; i++) {
//Absorbing "M[prev] [+] M[row*]"
state[0] ^= (ptrWordIn[0] + ptrWordInOut[0]);
state[1] ^= (ptrWordIn[1] + ptrWordInOut[1]);
state[2] ^= (ptrWordIn[2] + ptrWordInOut[2]);
state[3] ^= (ptrWordIn[3] + ptrWordInOut[3]);
state[4] ^= (ptrWordIn[4] + ptrWordInOut[4]);
state[5] ^= (ptrWordIn[5] + ptrWordInOut[5]);
state[6] ^= (ptrWordIn[6] + ptrWordInOut[6]);
state[7] ^= (ptrWordIn[7] + ptrWordInOut[7]);
state[8] ^= (ptrWordIn[8] + ptrWordInOut[8]);
state[9] ^= (ptrWordIn[9] + ptrWordInOut[9]);
state[10] ^= (ptrWordIn[10] + ptrWordInOut[10]);
state[11] ^= (ptrWordIn[11] + ptrWordInOut[11]);
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[rowOut][col] = M[rowOut][col] XOR rand
ptrWordOut[0] ^= state[0];
ptrWordOut[1] ^= state[1];
ptrWordOut[2] ^= state[2];
ptrWordOut[3] ^= state[3];
ptrWordOut[4] ^= state[4];
ptrWordOut[5] ^= state[5];
ptrWordOut[6] ^= state[6];
ptrWordOut[7] ^= state[7];
ptrWordOut[8] ^= state[8];
ptrWordOut[9] ^= state[9];
ptrWordOut[10] ^= state[10];
ptrWordOut[11] ^= state[11];
//M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)
ptrWordInOut[0] ^= state[11];
ptrWordInOut[1] ^= state[0];
ptrWordInOut[2] ^= state[1];
ptrWordInOut[3] ^= state[2];
ptrWordInOut[4] ^= state[3];
ptrWordInOut[5] ^= state[4];
ptrWordInOut[6] ^= state[5];
ptrWordInOut[7] ^= state[6];
ptrWordInOut[8] ^= state[7];
ptrWordInOut[9] ^= state[8];
ptrWordInOut[10] ^= state[9];
ptrWordInOut[11] ^= state[10];
//Goes to next block
ptrWordOut += BLOCK_LEN_INT64;
ptrWordInOut += BLOCK_LEN_INT64;
ptrWordIn += BLOCK_LEN_INT64;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Performs a duplex operation over "M[rowInOut] [+] M[rowIn]", writing the output "rand"
* on M[rowOut] and making "M[rowInOut] = M[rowInOut] XOR rotW(rand)", where rotW is a 64-bit
* rotation to the left.
*
* @param state The current state of the sponge
* @param rowIn Row used only as input
* @param rowInOut Row used as input and to receive output after rotation
* @param rowOut Row receiving the output
*
*/
/*
inline void reducedDuplexRowSetupOLD(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut) {
uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev
uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row*
uint64_t* ptrWordOut = rowOut; //In Lyra2: pointer to row
int i;
for (i = 0; i < N_COLS; i++) {
//Absorbing "M[rowInOut] XOR M[rowIn]"
state[0] ^= ptrWordInOut[0] ^ ptrWordIn[0];
state[1] ^= ptrWordInOut[1] ^ ptrWordIn[1];
state[2] ^= ptrWordInOut[2] ^ ptrWordIn[2];
state[3] ^= ptrWordInOut[3] ^ ptrWordIn[3];
state[4] ^= ptrWordInOut[4] ^ ptrWordIn[4];
state[5] ^= ptrWordInOut[5] ^ ptrWordIn[5];
state[6] ^= ptrWordInOut[6] ^ ptrWordIn[6];
state[7] ^= ptrWordInOut[7] ^ ptrWordIn[7];
state[8] ^= ptrWordInOut[8] ^ ptrWordIn[8];
state[9] ^= ptrWordInOut[9] ^ ptrWordIn[9];
state[10] ^= ptrWordInOut[10] ^ ptrWordIn[10];
state[11] ^= ptrWordInOut[11] ^ ptrWordIn[11];
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[row][col] = rand
ptrWordOut[0] = state[0];
ptrWordOut[1] = state[1];
ptrWordOut[2] = state[2];
ptrWordOut[3] = state[3];
ptrWordOut[4] = state[4];
ptrWordOut[5] = state[5];
ptrWordOut[6] = state[6];
ptrWordOut[7] = state[7];
ptrWordOut[8] = state[8];
ptrWordOut[9] = state[9];
ptrWordOut[10] = state[10];
ptrWordOut[11] = state[11];
//M[row*][col] = M[row*][col] XOR rotW(rand)
ptrWordInOut[0] ^= state[10];
ptrWordInOut[1] ^= state[11];
ptrWordInOut[2] ^= state[0];
ptrWordInOut[3] ^= state[1];
ptrWordInOut[4] ^= state[2];
ptrWordInOut[5] ^= state[3];
ptrWordInOut[6] ^= state[4];
ptrWordInOut[7] ^= state[5];
ptrWordInOut[8] ^= state[6];
ptrWordInOut[9] ^= state[7];
ptrWordInOut[10] ^= state[8];
ptrWordInOut[11] ^= state[9];
//Goes to next column (i.e., next block in sequence)
ptrWordInOut += BLOCK_LEN_INT64;
ptrWordIn += BLOCK_LEN_INT64;
ptrWordOut += BLOCK_LEN_INT64;
}
}
*/
/**
* Performs a duplex operation over "M[rowInOut] XOR M[rowIn]", writing the output "rand"
* on M[rowOut] and making "M[rowInOut] = M[rowInOut] XOR rotW(rand)", where rotW is a 64-bit
* rotation to the left.
*
* @param state The current state of the sponge
* @param rowIn Row used only as input
* @param rowInOut Row used as input and to receive output after rotation
* @param rowOut Row receiving the output
*
*/
/*
inline void reducedDuplexRowSetupv5(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut) {
uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev
uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row*
uint64_t* ptrWordOut = rowOut; //In Lyra2: pointer to row
int i;
for (i = 0; i < N_COLS; i++) {
//Absorbing "M[rowInOut] XOR M[rowIn]"
state[0] ^= ptrWordInOut[0] + ptrWordIn[0];
state[1] ^= ptrWordInOut[1] + ptrWordIn[1];
state[2] ^= ptrWordInOut[2] + ptrWordIn[2];
state[3] ^= ptrWordInOut[3] + ptrWordIn[3];
state[4] ^= ptrWordInOut[4] + ptrWordIn[4];
state[5] ^= ptrWordInOut[5] + ptrWordIn[5];
state[6] ^= ptrWordInOut[6] + ptrWordIn[6];
state[7] ^= ptrWordInOut[7] + ptrWordIn[7];
state[8] ^= ptrWordInOut[8] + ptrWordIn[8];
state[9] ^= ptrWordInOut[9] + ptrWordIn[9];
state[10] ^= ptrWordInOut[10] + ptrWordIn[10];
state[11] ^= ptrWordInOut[11] + ptrWordIn[11];
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[row*][col] = M[row*][col] XOR rotW(rand)
ptrWordInOut[0] ^= state[10];
ptrWordInOut[1] ^= state[11];
ptrWordInOut[2] ^= state[0];
ptrWordInOut[3] ^= state[1];
ptrWordInOut[4] ^= state[2];
ptrWordInOut[5] ^= state[3];
ptrWordInOut[6] ^= state[4];
ptrWordInOut[7] ^= state[5];
ptrWordInOut[8] ^= state[6];
ptrWordInOut[9] ^= state[7];
ptrWordInOut[10] ^= state[8];
ptrWordInOut[11] ^= state[9];
//M[row][col] = rand
ptrWordOut[0] = state[0] ^ ptrWordIn[0];
ptrWordOut[1] = state[1] ^ ptrWordIn[1];
ptrWordOut[2] = state[2] ^ ptrWordIn[2];
ptrWordOut[3] = state[3] ^ ptrWordIn[3];
ptrWordOut[4] = state[4] ^ ptrWordIn[4];
ptrWordOut[5] = state[5] ^ ptrWordIn[5];
ptrWordOut[6] = state[6] ^ ptrWordIn[6];
ptrWordOut[7] = state[7] ^ ptrWordIn[7];
ptrWordOut[8] = state[8] ^ ptrWordIn[8];
ptrWordOut[9] = state[9] ^ ptrWordIn[9];
ptrWordOut[10] = state[10] ^ ptrWordIn[10];
ptrWordOut[11] = state[11] ^ ptrWordIn[11];
//Goes to next column (i.e., next block in sequence)
ptrWordInOut += BLOCK_LEN_INT64;
ptrWordIn += BLOCK_LEN_INT64;
ptrWordOut += BLOCK_LEN_INT64;
}
}
*/
/**
* Performs a duplex operation over "M[rowInOut] XOR M[rowIn]", writing the output "rand"
* on M[rowOut] and making "M[rowInOut] = M[rowInOut] XOR rotW(rand)", where rotW is a 64-bit
* rotation to the left.
*
* @param state The current state of the sponge
* @param rowIn Row used only as input
* @param rowInOut Row used as input and to receive output after rotation
* @param rowOut Row receiving the output
*
*/
/*
inline void reducedDuplexRowSetupv5c(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut) {
uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev
uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row*
uint64_t* ptrWordOut = rowOut;
int i;
for (i = 0; i < N_COLS / 2; i++) {
//Absorbing "M[rowInOut] XOR M[rowIn]"
state[0] ^= ptrWordInOut[0] + ptrWordIn[0];
state[1] ^= ptrWordInOut[1] + ptrWordIn[1];
state[2] ^= ptrWordInOut[2] + ptrWordIn[2];
state[3] ^= ptrWordInOut[3] + ptrWordIn[3];
state[4] ^= ptrWordInOut[4] + ptrWordIn[4];
state[5] ^= ptrWordInOut[5] + ptrWordIn[5];
state[6] ^= ptrWordInOut[6] + ptrWordIn[6];
state[7] ^= ptrWordInOut[7] + ptrWordIn[7];
state[8] ^= ptrWordInOut[8] + ptrWordIn[8];
state[9] ^= ptrWordInOut[9] + ptrWordIn[9];
state[10] ^= ptrWordInOut[10] + ptrWordIn[10];
state[11] ^= ptrWordInOut[11] + ptrWordIn[11];
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[row*][col] = M[row*][col] XOR rotW(rand)
ptrWordInOut[0] ^= state[10];
ptrWordInOut[1] ^= state[11];
ptrWordInOut[2] ^= state[0];
ptrWordInOut[3] ^= state[1];
ptrWordInOut[4] ^= state[2];
ptrWordInOut[5] ^= state[3];
ptrWordInOut[6] ^= state[4];
ptrWordInOut[7] ^= state[5];
ptrWordInOut[8] ^= state[6];
ptrWordInOut[9] ^= state[7];
ptrWordInOut[10] ^= state[8];
ptrWordInOut[11] ^= state[9];
//M[row][col] = rand
ptrWordOut[0] = state[0] ^ ptrWordIn[0];
ptrWordOut[1] = state[1] ^ ptrWordIn[1];
ptrWordOut[2] = state[2] ^ ptrWordIn[2];
ptrWordOut[3] = state[3] ^ ptrWordIn[3];
ptrWordOut[4] = state[4] ^ ptrWordIn[4];
ptrWordOut[5] = state[5] ^ ptrWordIn[5];
ptrWordOut[6] = state[6] ^ ptrWordIn[6];
ptrWordOut[7] = state[7] ^ ptrWordIn[7];
ptrWordOut[8] = state[8] ^ ptrWordIn[8];
ptrWordOut[9] = state[9] ^ ptrWordIn[9];
ptrWordOut[10] = state[10] ^ ptrWordIn[10];
ptrWordOut[11] = state[11] ^ ptrWordIn[11];
//Goes to next column (i.e., next block in sequence)
ptrWordInOut += BLOCK_LEN_INT64;
ptrWordIn += BLOCK_LEN_INT64;
ptrWordOut += 2 * BLOCK_LEN_INT64;
}
ptrWordOut = rowOut + BLOCK_LEN_INT64;
for (i = 0; i < N_COLS / 2; i++) {
//Absorbing "M[rowInOut] XOR M[rowIn]"
state[0] ^= ptrWordInOut[0] + ptrWordIn[0];
state[1] ^= ptrWordInOut[1] + ptrWordIn[1];
state[2] ^= ptrWordInOut[2] + ptrWordIn[2];
state[3] ^= ptrWordInOut[3] + ptrWordIn[3];
state[4] ^= ptrWordInOut[4] + ptrWordIn[4];
state[5] ^= ptrWordInOut[5] + ptrWordIn[5];
state[6] ^= ptrWordInOut[6] + ptrWordIn[6];
state[7] ^= ptrWordInOut[7] + ptrWordIn[7];
state[8] ^= ptrWordInOut[8] + ptrWordIn[8];
state[9] ^= ptrWordInOut[9] + ptrWordIn[9];
state[10] ^= ptrWordInOut[10] + ptrWordIn[10];
state[11] ^= ptrWordInOut[11] + ptrWordIn[11];
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[row*][col] = M[row*][col] XOR rotW(rand)
ptrWordInOut[0] ^= state[10];
ptrWordInOut[1] ^= state[11];
ptrWordInOut[2] ^= state[0];
ptrWordInOut[3] ^= state[1];
ptrWordInOut[4] ^= state[2];
ptrWordInOut[5] ^= state[3];
ptrWordInOut[6] ^= state[4];
ptrWordInOut[7] ^= state[5];
ptrWordInOut[8] ^= state[6];
ptrWordInOut[9] ^= state[7];
ptrWordInOut[10] ^= state[8];
ptrWordInOut[11] ^= state[9];
//M[row][col] = rand
ptrWordOut[0] = state[0] ^ ptrWordIn[0];
ptrWordOut[1] = state[1] ^ ptrWordIn[1];
ptrWordOut[2] = state[2] ^ ptrWordIn[2];
ptrWordOut[3] = state[3] ^ ptrWordIn[3];
ptrWordOut[4] = state[4] ^ ptrWordIn[4];
ptrWordOut[5] = state[5] ^ ptrWordIn[5];
ptrWordOut[6] = state[6] ^ ptrWordIn[6];
ptrWordOut[7] = state[7] ^ ptrWordIn[7];
ptrWordOut[8] = state[8] ^ ptrWordIn[8];
ptrWordOut[9] = state[9] ^ ptrWordIn[9];
ptrWordOut[10] = state[10] ^ ptrWordIn[10];
ptrWordOut[11] = state[11] ^ ptrWordIn[11];
//Goes to next column (i.e., next block in sequence)
ptrWordInOut += BLOCK_LEN_INT64;
ptrWordIn += BLOCK_LEN_INT64;
ptrWordOut += 2 * BLOCK_LEN_INT64;
}
}
*/
/**
* Performs a duplex operation over "M[rowInOut] XOR M[rowIn]", using the output "rand"
* to make "M[rowOut][col] = M[rowOut][col] XOR rand" and "M[rowInOut] = M[rowInOut] XOR rotW(rand)",
* where rotW is a 64-bit rotation to the left.
*
* @param state The current state of the sponge
* @param rowIn Row used only as input
* @param rowInOut Row used as input and to receive output after rotation
* @param rowOut Row receiving the output
*
*/
/*
inline void reducedDuplexRowd(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut) {
uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row*
uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev
uint64_t* ptrWordOut = rowOut; //In Lyra2: pointer to row
int i;
for (i = 0; i < N_COLS; i++) {
//Absorbing "M[rowInOut] XOR M[rowIn]"
state[0] ^= ptrWordInOut[0] + ptrWordIn[0];
state[1] ^= ptrWordInOut[1] + ptrWordIn[1];
state[2] ^= ptrWordInOut[2] + ptrWordIn[2];
state[3] ^= ptrWordInOut[3] + ptrWordIn[3];
state[4] ^= ptrWordInOut[4] + ptrWordIn[4];
state[5] ^= ptrWordInOut[5] + ptrWordIn[5];
state[6] ^= ptrWordInOut[6] + ptrWordIn[6];
state[7] ^= ptrWordInOut[7] + ptrWordIn[7];
state[8] ^= ptrWordInOut[8] + ptrWordIn[8];
state[9] ^= ptrWordInOut[9] + ptrWordIn[9];
state[10] ^= ptrWordInOut[10] + ptrWordIn[10];
state[11] ^= ptrWordInOut[11] + ptrWordIn[11];
//Applies the reduced-round transformation f to the sponge's state
reducedBlake2bLyra(state);
//M[rowOut][col] = M[rowOut][col] XOR rand
ptrWordOut[0] ^= state[0];
ptrWordOut[1] ^= state[1];
ptrWordOut[2] ^= state[2];
ptrWordOut[3] ^= state[3];
ptrWordOut[4] ^= state[4];
ptrWordOut[5] ^= state[5];
ptrWordOut[6] ^= state[6];
ptrWordOut[7] ^= state[7];
ptrWordOut[8] ^= state[8];
ptrWordOut[9] ^= state[9];
ptrWordOut[10] ^= state[10];
ptrWordOut[11] ^= state[11];
//M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)
//Goes to next block
ptrWordOut += BLOCK_LEN_INT64;
ptrWordInOut += BLOCK_LEN_INT64;
ptrWordIn += BLOCK_LEN_INT64;
}
}
*/
/**
Prints an array of unsigned chars
*/
void printArray(unsigned char *array, unsigned int size, char *name) {
int i;
printf("%s: ", name);
for (i = 0; i < size; i++) {
printf("%2x|", array[i]);
}
printf("\n");
}
////////////////////////////////////////////////////////////////////////////////////////////////

115
stratum/algos/Sponge.h Normal file
View file

@ -0,0 +1,115 @@
/**
* Header file for Blake2b's internal permutation in the form of a sponge.
* This code is based on the original Blake2b's implementation provided by
* Samuel Neves (https://blake2.net/)
*
* Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014.
*
* This software is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SPONGE_H_
#define SPONGE_H_
#ifdef __cplusplus
extern "C"{
#endif
#include <stdint.h>
#if defined(__GNUC__)
#define ALIGN __attribute__ ((aligned(32)))
#elif defined(_MSC_VER)
#define ALIGN __declspec(align(32))
#else
#define ALIGN
#endif
/*Blake2b IV Array*/
static const uint64_t blake2b_IV[8] =
{
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
/*Blake2b's rotation*/
static inline uint64_t rotr64( const uint64_t w, const unsigned c ){
return ( w >> c ) | ( w << ( 64 - c ) );
}
/*Blake2b's G function*/
#define G(r,i,a,b,c,d) \
do { \
a = a + b; \
d = rotr64(d ^ a, 32); \
c = c + d; \
b = rotr64(b ^ c, 24); \
a = a + b; \
d = rotr64(d ^ a, 16); \
c = c + d; \
b = rotr64(b ^ c, 63); \
} while(0)
/*One Round of the Blake2b's compression function*/
#define ROUND_LYRA(r) \
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]);
//---- Housekeeping
void initState(uint64_t state[/*16*/]);
//---- Squeezes
void squeeze(uint64_t *state, unsigned char *out, unsigned int len);
void reducedSqueezeRow0(uint64_t* state, uint64_t* row);
//---- Absorbs
void absorbBlock(uint64_t *state, const uint64_t *in);
void absorbBlockBlake2Safe(uint64_t *state, const uint64_t *in);
//---- Duplexes
void reducedDuplexRow1(uint64_t *state, uint64_t *rowIn, uint64_t *rowOut);
void reducedDuplexRowSetup(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut);
void reducedDuplexRow(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut);
//---- Misc
void printArray(unsigned char *array, unsigned int size, char *name);
////////////////////////////////////////////////////////////////////////////////////////////////
////TESTS////
//void reducedDuplexRowc(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut);
//void reducedDuplexRowd(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut);
//void reducedDuplexRowSetupv4(uint64_t *state, uint64_t *rowIn1, uint64_t *rowIn2, uint64_t *rowOut1, uint64_t *rowOut2);
//void reducedDuplexRowSetupv5(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut);
//void reducedDuplexRowSetupv5c(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut);
//void reducedDuplexRowSetupv5d(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut);
/////////////
#endif /* SPONGE_H_ */
#ifdef __cplusplus
}
#endif

16
stratum/algos/blake.c Normal file
View file

@ -0,0 +1,16 @@
#include "blake.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
void blake_hash(const char* input, char* output, uint32_t len)
{
sph_blake256_context ctx_blake;
sph_blake256_init(&ctx_blake);
sph_blake256(&ctx_blake, input, len);
sph_blake256_close(&ctx_blake, output);
}

16
stratum/algos/blake.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef BLAKE_H
#define BLAKE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void blake_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

83
stratum/algos/c11.c Normal file
View file

@ -0,0 +1,83 @@
#include "x11.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_bmw.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#include "../sha3/sph_luffa.h"
#include "../sha3/sph_cubehash.h"
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
void c11_hash(const char* input, char* output, uint32_t len)
{
uint32_t hash[16];
sph_blake512_context ctx_blake;
sph_bmw512_context ctx_bmw;
sph_groestl512_context ctx_groestl;
sph_skein512_context ctx_skein;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
sph_luffa512_context ctx_luffa1;
sph_cubehash512_context ctx_cubehash1;
sph_shavite512_context ctx_shavite1;
sph_simd512_context ctx_simd1;
sph_echo512_context ctx_echo1;
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, input, len);
sph_blake512_close (&ctx_blake, hash);
sph_bmw512_init(&ctx_bmw);
sph_bmw512 (&ctx_bmw, hash, 64);
sph_bmw512_close(&ctx_bmw, hash);
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hash, 64);
sph_groestl512_close(&ctx_groestl, hash);
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hash, 64);
sph_jh512_close(&ctx_jh, hash);
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, hash, 64);
sph_keccak512_close(&ctx_keccak, hash);
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hash, 64);
sph_skein512_close (&ctx_skein, hash);
sph_luffa512_init (&ctx_luffa1);
sph_luffa512 (&ctx_luffa1, hash, 64);
sph_luffa512_close (&ctx_luffa1, hash);
sph_cubehash512_init (&ctx_cubehash1);
sph_cubehash512 (&ctx_cubehash1, hash, 64);
sph_cubehash512_close(&ctx_cubehash1, hash);
sph_shavite512_init (&ctx_shavite1);
sph_shavite512 (&ctx_shavite1, hash, 64);
sph_shavite512_close(&ctx_shavite1, hash);
sph_simd512_init (&ctx_simd1);
sph_simd512 (&ctx_simd1, hash, 64);
sph_simd512_close(&ctx_simd1, hash);
sph_echo512_init (&ctx_echo1);
sph_echo512 (&ctx_echo1, hash, 64);
sph_echo512_close(&ctx_echo1, hash);
memcpy(output, hash, 32);
}

16
stratum/algos/c11.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef C11_H
#define C11_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void c11_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

44
stratum/algos/fresh.c Normal file
View file

@ -0,0 +1,44 @@
#include "fresh.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
void fresh_hash(const char* input, char* output, uint32_t len)
{
sph_shavite512_context ctx_shavite1;
sph_simd512_context ctx_simd1;
sph_echo512_context ctx_echo1;
//these uint512 in the c++ source of the client are backed by an array of uint32
uint32_t hashA[16], hashB[16];
sph_shavite512_init (&ctx_shavite1);
sph_shavite512 (&ctx_shavite1, input, len);
sph_shavite512_close(&ctx_shavite1, hashA);
sph_simd512_init (&ctx_simd1);
sph_simd512 (&ctx_simd1, hashA, 64);
sph_simd512_close(&ctx_simd1, hashB);
sph_shavite512_init (&ctx_shavite1);
sph_shavite512 (&ctx_shavite1, hashB, 64);
sph_shavite512_close(&ctx_shavite1, hashA);
sph_simd512_init (&ctx_simd1);
sph_simd512 (&ctx_simd1, hashA, 64);
sph_simd512_close(&ctx_simd1, hashB);
sph_echo512_init (&ctx_echo1);
sph_echo512 (&ctx_echo1, hashB, 64);
sph_echo512_close(&ctx_echo1, hashA);
memcpy(output, hashA, 32);
}

16
stratum/algos/fresh.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef FRESH_H
#define FRESH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void fresh_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

41
stratum/algos/groestl.c Normal file
View file

@ -0,0 +1,41 @@
#include "groestl.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_groestl.h"
#include "sha256.h"
void groestl_hash(const char* input, char* output, uint32_t len)
{
char hash1[64];
char hash2[64];
sph_groestl512_context ctx_groestl;
sph_groestl512_init(&ctx_groestl);
sph_groestl512(&ctx_groestl, input, len);
sph_groestl512_close(&ctx_groestl, &hash1);
sph_groestl512(&ctx_groestl, hash1, 64);
sph_groestl512_close(&ctx_groestl, &hash2);
memcpy(output, &hash2, 32);
}
void groestlmyriad_hash(const char* input, char* output, uint32_t len)
{
char temp[64];
sph_groestl512_context ctx_groestl;
sph_groestl512_init(&ctx_groestl);
sph_groestl512(&ctx_groestl, input, len);
sph_groestl512_close(&ctx_groestl, &temp);
SHA256_CTX ctx_sha256;
SHA256_Init(&ctx_sha256);
SHA256_Update(&ctx_sha256, &temp, 64);
SHA256_Final((unsigned char*) output, &ctx_sha256);
}

18
stratum/algos/groestl.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef GROESTL_H
#define GROESTL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void groestl_hash(const char* input, char* output, uint32_t len);
void groestlmyriad_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

135
stratum/algos/jha.c Normal file
View file

@ -0,0 +1,135 @@
#include "jha.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
void jha_hash(const char* input, char* output, uint32_t len) {
sph_blake512_context ctx_blake;
sph_groestl512_context ctx_groestl;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
sph_skein512_context ctx_skein;
uint32_t hash[16];
unsigned int round_mask = (
(unsigned int)(((unsigned char *)input)[84]) << 0 |
(unsigned int)(((unsigned char *)input)[85]) << 8 |
(unsigned int)(((unsigned char *)input)[86]) << 16 |
(unsigned int)(((unsigned char *)input)[87]) << 24 );
//
// JHA V7
//
if (round_mask == 7) {
//
// Input Hashing with SHA3 512, 88 bytes
//
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, input, 88);
sph_keccak512_close(&ctx_keccak, hash);
//
// Variable Rounds Loop
//
unsigned int rounds = hash[0] & 7;
unsigned int round;
for (round = 0; round < rounds; round++) {
switch (hash[0] & 3) {
case 0:
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, hash, 64);
sph_blake512_close(&ctx_blake, hash);
break;
case 1:
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hash, 64);
sph_groestl512_close(&ctx_groestl, hash);
break;
case 2:
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hash, 64);
sph_jh512_close(&ctx_jh, hash);
break;
case 3:
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hash, 64);
sph_skein512_close(&ctx_skein, hash);
break;
}
}
//
// Return 256bit(32x8)
//
memcpy(output, hash, 32);
}
//
// JHA V8
//
else if (round_mask == 8) {
//
// Input Hashing with SHA3 512, 80 bytes
//
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, input, 80);
sph_keccak512_close(&ctx_keccak, (&hash));
//
// Heavy & Light Pair Loop
//
unsigned int round;
for (round = 0; round < 3; round++) {
if (hash[0] & 0x01) {
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, (&hash), 64);
sph_groestl512_close(&ctx_groestl, (&hash));
}
else {
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, (&hash), 64);
sph_skein512_close(&ctx_skein, (&hash));
}
if (hash[0] & 0x01) {
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, (&hash), 64);
sph_blake512_close(&ctx_blake, (&hash));
}
else {
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, (&hash), 64);
sph_jh512_close(&ctx_jh, (&hash));
}
}
//
// Return 256bit(32x8)
//
memcpy(output, hash, 32);
}
//
// Wrong Round Mask Data
//
else {
memset(output, 0xFF, 32);
}
}

16
stratum/algos/jha.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef JHA_H__
#define JHA_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void jha_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

32
stratum/algos/keccak.c Normal file
View file

@ -0,0 +1,32 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_types.h"
#include "../sha3/sph_keccak.h"
void keccak_hash(const char *input, char *output, uint32_t len)
{
sph_keccak256_context ctx_keccak;
sph_keccak256_init(&ctx_keccak);
sph_keccak256(&ctx_keccak, input, len);
sph_keccak256_close(&ctx_keccak, output);
}
//void keccak_hash2(const char *input, char *output, uint32_t len)
//{
// uint32_t hashA[16];
//
// sph_keccak512_context ctx_keccak;
// sph_keccak512_init(&ctx_keccak);
//
// sph_keccak512(&ctx_keccak, input, len);
// sph_keccak512_close(&ctx_keccak, hashA);
//
// memcpy(output, hashA, 32);
//}

16
stratum/algos/keccak.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef KECCAK_H
#define KECCAK_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void keccak_hash(const char* input, char* output, uint32_t size);
#ifdef __cplusplus
}
#endif
#endif

32
stratum/algos/makefile Normal file
View file

@ -0,0 +1,32 @@
CC=gcc
#CFLAGS=-c -g -I /usr/include/mysql
#LDFLAGS=-g
CFLAGS=-c -O3 -I /usr/include/mysql -march=native
LDFLAGS=-O2
SOURCES=Lyra2RE.c Lyra2.c Sponge.c blake.c scrypt.c c11.c x11.c x13.c sha256.c keccak.c \
x14.c x15.c nist5.c fresh.c quark.c neoscrypt.c scryptn.c qubit.c skein.c groestl.c
OBJECTS=$(SOURCES:.c=.o)
OUTPUT=libalgos.a
all: $(SOURCES) $(OUTPUT)
$(OUTPUT): $(OBJECTS)
ar rc $@ $(OBJECTS)
.cpp.o:
$(CC) $(CFLAGS) $<
.c.o:
$(CC) $(CFLAGS) $<
# $(CC) $(CFLAGS) -std=gnu99 -Wno-pointer-sign -Wno-pointer-to-int-cast -funroll-loops -fvariable-expansion-in-unroller -fmerge-all-constants -fbranch-target-load-optimize2 -fsched2-use-superblocks -falign-loops=16 -falign-functions=16 -falign-jumps=16 -falign-labels=16 -Ofast -flto -fuse-linker-plugin -ftree-loop-if-convert-stores -DUSE_ASM -pg $<
clean:
rm *.o

962
stratum/algos/neoscrypt.c Normal file
View file

@ -0,0 +1,962 @@
/*
* Copyright (c) 2009 Colin Percival, 2011 ArtForz
* Copyright (c) 2012 Andrew Moon (floodyberry)
* Copyright (c) 2012 Samuel Neves <sneves@dei.uc.pt>
* Copyright (c) 2014 John Doering <ghostlander@phoenixcoin.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "neoscrypt.h"
#if (WINDOWS)
/* sizeof(unsigned long) = 4 for MinGW64 */
typedef unsigned long long ulong;
#else
typedef unsigned long ulong;
#endif
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned int bool;
#define MIN(a, b) ((a) < (b) ? a : b)
#define MAX(a, b) ((a) > (b) ? a : b)
/* SHA-256 */
static const uint32_t sha256_constants[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S0(x) (ROTR32(x, 2) ^ ROTR32(x, 13) ^ ROTR32(x, 22))
#define S1(x) (ROTR32(x, 6) ^ ROTR32(x, 11) ^ ROTR32(x, 25))
#define G0(x) (ROTR32(x, 7) ^ ROTR32(x, 18) ^ (x >> 3))
#define G1(x) (ROTR32(x, 17) ^ ROTR32(x, 19) ^ (x >> 10))
#define W0(in,i) (U8TO32_BE(&in[i * 4]))
#define W1(i) (G1(w[i - 2]) + w[i - 7] + G0(w[i - 15]) + w[i - 16])
#define STEP(i) \
t1 = S0(r[0]) + Maj(r[0], r[1], r[2]); \
t0 = r[7] + S1(r[4]) + Ch(r[4], r[5], r[6]) + sha256_constants[i] + w[i]; \
r[7] = r[6]; \
r[6] = r[5]; \
r[5] = r[4]; \
r[4] = r[3] + t0; \
r[3] = r[2]; \
r[2] = r[1]; \
r[1] = r[0]; \
r[0] = t0 + t1;
typedef struct sha256_hash_state_t {
uint32_t H[8];
uint64_t T;
uint32_t leftover;
uint8_t buffer[SCRYPT_HASH_BLOCK_SIZE];
} sha256_hash_state;
static void sha256_blocks(sha256_hash_state *S, const uint8_t *in, size_t blocks) {
uint32_t r[8], w[64], t0, t1;
size_t i;
for(i = 0; i < 8; i++)
r[i] = S->H[i];
while(blocks--) {
for(i = 0; i < 16; i++) {
w[i] = W0(in, i);
}
for(i = 16; i < 64; i++) {
w[i] = W1(i);
}
for(i = 0; i < 64; i++) {
STEP(i);
}
for(i = 0; i < 8; i++) {
r[i] += S->H[i];
S->H[i] = r[i];
}
S->T += SCRYPT_HASH_BLOCK_SIZE * 8;
in += SCRYPT_HASH_BLOCK_SIZE;
}
}
static void neoscrypt_hash_init_sha256(sha256_hash_state *S) {
S->H[0] = 0x6a09e667;
S->H[1] = 0xbb67ae85;
S->H[2] = 0x3c6ef372;
S->H[3] = 0xa54ff53a;
S->H[4] = 0x510e527f;
S->H[5] = 0x9b05688c;
S->H[6] = 0x1f83d9ab;
S->H[7] = 0x5be0cd19;
S->T = 0;
S->leftover = 0;
}
static void neoscrypt_hash_update_sha256(sha256_hash_state *S, const uint8_t *in, size_t inlen) {
size_t blocks, want;
/* handle the previous data */
if(S->leftover) {
want = (SCRYPT_HASH_BLOCK_SIZE - S->leftover);
want = (want < inlen) ? want : inlen;
memcpy(S->buffer + S->leftover, in, want);
S->leftover += (uint32_t)want;
if(S->leftover < SCRYPT_HASH_BLOCK_SIZE)
return;
in += want;
inlen -= want;
sha256_blocks(S, S->buffer, 1);
}
/* handle the current data */
blocks = (inlen & ~(SCRYPT_HASH_BLOCK_SIZE - 1));
S->leftover = (uint32_t)(inlen - blocks);
if(blocks) {
sha256_blocks(S, in, blocks / SCRYPT_HASH_BLOCK_SIZE);
in += blocks;
}
/* handle leftover data */
if(S->leftover)
memcpy(S->buffer, in, S->leftover);
}
static void neoscrypt_hash_finish_sha256(sha256_hash_state *S, uint8_t *hash) {
uint64_t t = S->T + (S->leftover * 8);
S->buffer[S->leftover] = 0x80;
if(S->leftover <= 55) {
memset(S->buffer + S->leftover + 1, 0, 55 - S->leftover);
} else {
memset(S->buffer + S->leftover + 1, 0, 63 - S->leftover);
sha256_blocks(S, S->buffer, 1);
memset(S->buffer, 0, 56);
}
U64TO8_BE(S->buffer + 56, t);
sha256_blocks(S, S->buffer, 1);
U32TO8_BE(&hash[ 0], S->H[0]);
U32TO8_BE(&hash[ 4], S->H[1]);
U32TO8_BE(&hash[ 8], S->H[2]);
U32TO8_BE(&hash[12], S->H[3]);
U32TO8_BE(&hash[16], S->H[4]);
U32TO8_BE(&hash[20], S->H[5]);
U32TO8_BE(&hash[24], S->H[6]);
U32TO8_BE(&hash[28], S->H[7]);
}
static void neoscrypt_hash_sha256(hash_digest hash, const uint8_t *m, size_t mlen) {
sha256_hash_state st;
neoscrypt_hash_init_sha256(&st);
neoscrypt_hash_update_sha256(&st, m, mlen);
neoscrypt_hash_finish_sha256(&st, hash);
}
/* HMAC for SHA-256 */
typedef struct sha256_hmac_state_t {
sha256_hash_state inner, outer;
} sha256_hmac_state;
static void neoscrypt_hmac_init_sha256(sha256_hmac_state *st, const uint8_t *key, size_t keylen) {
uint8_t pad[SCRYPT_HASH_BLOCK_SIZE] = {0};
size_t i;
neoscrypt_hash_init_sha256(&st->inner);
neoscrypt_hash_init_sha256(&st->outer);
if(keylen <= SCRYPT_HASH_BLOCK_SIZE) {
/* use the key directly if it's <= blocksize bytes */
memcpy(pad, key, keylen);
} else {
/* if it's > blocksize bytes, hash it */
neoscrypt_hash_sha256(pad, key, keylen);
}
/* inner = (key ^ 0x36) */
/* h(inner || ...) */
for(i = 0; i < SCRYPT_HASH_BLOCK_SIZE; i++)
pad[i] ^= 0x36;
neoscrypt_hash_update_sha256(&st->inner, pad, SCRYPT_HASH_BLOCK_SIZE);
/* outer = (key ^ 0x5c) */
/* h(outer || ...) */
for(i = 0; i < SCRYPT_HASH_BLOCK_SIZE; i++)
pad[i] ^= (0x5c ^ 0x36);
neoscrypt_hash_update_sha256(&st->outer, pad, SCRYPT_HASH_BLOCK_SIZE);
}
static void neoscrypt_hmac_update_sha256(sha256_hmac_state *st, const uint8_t *m, size_t mlen) {
/* h(inner || m...) */
neoscrypt_hash_update_sha256(&st->inner, m, mlen);
}
static void neoscrypt_hmac_finish_sha256(sha256_hmac_state *st, hash_digest mac) {
/* h(inner || m) */
hash_digest innerhash;
neoscrypt_hash_finish_sha256(&st->inner, innerhash);
/* h(outer || h(inner || m)) */
neoscrypt_hash_update_sha256(&st->outer, innerhash, sizeof(innerhash));
neoscrypt_hash_finish_sha256(&st->outer, mac);
}
/* PBKDF2 for SHA-256 */
static void neoscrypt_pbkdf2_sha256(const uint8_t *password, size_t password_len,
const uint8_t *salt, size_t salt_len, uint64_t N, uint8_t *output, size_t output_len) {
sha256_hmac_state hmac_pw, hmac_pw_salt, work;
hash_digest ti, u;
uint8_t be[4];
uint32_t i, j, k, blocks;
/* bytes must be <= (0xffffffff - (SCRYPT_HASH_DIGEST_SIZE - 1)), which they will always be under scrypt */
/* hmac(password, ...) */
neoscrypt_hmac_init_sha256(&hmac_pw, password, password_len);
/* hmac(password, salt...) */
hmac_pw_salt = hmac_pw;
neoscrypt_hmac_update_sha256(&hmac_pw_salt, salt, salt_len);
blocks = ((uint32_t)output_len + (SCRYPT_HASH_DIGEST_SIZE - 1)) / SCRYPT_HASH_DIGEST_SIZE;
for(i = 1; i <= blocks; i++) {
/* U1 = hmac(password, salt || be(i)) */
U32TO8_BE(be, i);
work = hmac_pw_salt;
neoscrypt_hmac_update_sha256(&work, be, 4);
neoscrypt_hmac_finish_sha256(&work, ti);
memcpy(u, ti, sizeof(u));
/* T[i] = U1 ^ U2 ^ U3... */
for(j = 0; j < N - 1; j++) {
/* UX = hmac(password, U{X-1}) */
work = hmac_pw;
neoscrypt_hmac_update_sha256(&work, u, SCRYPT_HASH_DIGEST_SIZE);
neoscrypt_hmac_finish_sha256(&work, u);
/* T[i] ^= UX */
for(k = 0; k < sizeof(u); k++)
ti[k] ^= u[k];
}
memcpy(output, ti, (output_len > SCRYPT_HASH_DIGEST_SIZE) ? SCRYPT_HASH_DIGEST_SIZE : output_len);
output += SCRYPT_HASH_DIGEST_SIZE;
output_len -= SCRYPT_HASH_DIGEST_SIZE;
}
}
/* NeoScrypt */
#if defined(ASM)
extern void neoscrypt_salsa(uint *X, uint rounds);
extern void neoscrypt_salsa_tangle(uint *X, uint count);
extern void neoscrypt_chacha(uint *X, uint rounds);
extern void neoscrypt_blkcpy(void *dstp, const void *srcp, uint len);
extern void neoscrypt_blkswp(void *blkAp, void *blkBp, uint len);
extern void neoscrypt_blkxor(void *dstp, const void *srcp, uint len);
#else
/* Salsa20, rounds must be a multiple of 2 */
static void neoscrypt_salsa(uint *X, uint rounds) {
uint x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, t;
x0 = X[0]; x1 = X[1]; x2 = X[2]; x3 = X[3];
x4 = X[4]; x5 = X[5]; x6 = X[6]; x7 = X[7];
x8 = X[8]; x9 = X[9]; x10 = X[10]; x11 = X[11];
x12 = X[12]; x13 = X[13]; x14 = X[14]; x15 = X[15];
#define quarter(a, b, c, d) \
t = a + d; t = ROTL32(t, 7); b ^= t; \
t = b + a; t = ROTL32(t, 9); c ^= t; \
t = c + b; t = ROTL32(t, 13); d ^= t; \
t = d + c; t = ROTL32(t, 18); a ^= t;
for(; rounds; rounds -= 2) {
quarter( x0, x4, x8, x12);
quarter( x5, x9, x13, x1);
quarter(x10, x14, x2, x6);
quarter(x15, x3, x7, x11);
quarter( x0, x1, x2, x3);
quarter( x5, x6, x7, x4);
quarter(x10, x11, x8, x9);
quarter(x15, x12, x13, x14);
}
X[0] += x0; X[1] += x1; X[2] += x2; X[3] += x3;
X[4] += x4; X[5] += x5; X[6] += x6; X[7] += x7;
X[8] += x8; X[9] += x9; X[10] += x10; X[11] += x11;
X[12] += x12; X[13] += x13; X[14] += x14; X[15] += x15;
#undef quarter
}
/* ChaCha20, rounds must be a multiple of 2 */
static void neoscrypt_chacha(uint *X, uint rounds) {
uint x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, t;
x0 = X[0]; x1 = X[1]; x2 = X[2]; x3 = X[3];
x4 = X[4]; x5 = X[5]; x6 = X[6]; x7 = X[7];
x8 = X[8]; x9 = X[9]; x10 = X[10]; x11 = X[11];
x12 = X[12]; x13 = X[13]; x14 = X[14]; x15 = X[15];
#define quarter(a,b,c,d) \
a += b; t = d ^ a; d = ROTL32(t, 16); \
c += d; t = b ^ c; b = ROTL32(t, 12); \
a += b; t = d ^ a; d = ROTL32(t, 8); \
c += d; t = b ^ c; b = ROTL32(t, 7);
for(; rounds; rounds -= 2) {
quarter( x0, x4, x8, x12);
quarter( x1, x5, x9, x13);
quarter( x2, x6, x10, x14);
quarter( x3, x7, x11, x15);
quarter( x0, x5, x10, x15);
quarter( x1, x6, x11, x12);
quarter( x2, x7, x8, x13);
quarter( x3, x4, x9, x14);
}
X[0] += x0; X[1] += x1; X[2] += x2; X[3] += x3;
X[4] += x4; X[5] += x5; X[6] += x6; X[7] += x7;
X[8] += x8; X[9] += x9; X[10] += x10; X[11] += x11;
X[12] += x12; X[13] += x13; X[14] += x14; X[15] += x15;
#undef quarter
}
/* Fast 32-bit / 64-bit memcpy();
* len must be a multiple of 32 bytes */
static void neoscrypt_blkcpy(void *dstp, const void *srcp, uint len) {
ulong *dst = (ulong *) dstp;
ulong *src = (ulong *) srcp;
uint i;
for(i = 0; i < (len / sizeof(ulong)); i += 4) {
dst[i] = src[i];
dst[i + 1] = src[i + 1];
dst[i + 2] = src[i + 2];
dst[i + 3] = src[i + 3];
}
}
/* Fast 32-bit / 64-bit block swapper;
* len must be a multiple of 32 bytes */
static void neoscrypt_blkswp(void *blkAp, void *blkBp, uint len) {
ulong *blkA = (ulong *) blkAp;
ulong *blkB = (ulong *) blkBp;
register ulong t0, t1, t2, t3;
uint i;
for(i = 0; i < (len / sizeof(ulong)); i += 4) {
t0 = blkA[i];
t1 = blkA[i + 1];
t2 = blkA[i + 2];
t3 = blkA[i + 3];
blkA[i] = blkB[i];
blkA[i + 1] = blkB[i + 1];
blkA[i + 2] = blkB[i + 2];
blkA[i + 3] = blkB[i + 3];
blkB[i] = t0;
blkB[i + 1] = t1;
blkB[i + 2] = t2;
blkB[i + 3] = t3;
}
}
/* Fast 32-bit / 64-bit block XOR engine;
* len must be a multiple of 32 bytes */
static void neoscrypt_blkxor(void *dstp, const void *srcp, uint len) {
ulong *dst = (ulong *) dstp;
ulong *src = (ulong *) srcp;
uint i;
for(i = 0; i < (len / sizeof(ulong)); i += 4) {
dst[i] ^= src[i];
dst[i + 1] ^= src[i + 1];
dst[i + 2] ^= src[i + 2];
dst[i + 3] ^= src[i + 3];
}
}
#endif
/* 32-bit / 64-bit optimised memcpy() */
static void neoscrypt_copy(void *dstp, const void *srcp, uint len) {
ulong *dst = (ulong *) dstp;
ulong *src = (ulong *) srcp;
uint i, tail;
for(i = 0; i < (len / sizeof(ulong)); i++)
dst[i] = src[i];
tail = len & (sizeof(ulong) - 1);
if(tail) {
uchar *dstb = (uchar *) dstp;
uchar *srcb = (uchar *) srcp;
for(i = len - tail; i < len; i++)
dstb[i] = srcb[i];
}
}
/* 32-bit / 64-bit optimised memory erase aka memset() to zero */
static void neoscrypt_erase(void *dstp, uint len) {
const ulong null = 0;
ulong *dst = (ulong *) dstp;
uint i, tail;
for(i = 0; i < (len / sizeof(ulong)); i++)
dst[i] = null;
tail = len & (sizeof(ulong) - 1);
if(tail) {
uchar *dstb = (uchar *) dstp;
for(i = len - tail; i < len; i++)
dstb[i] = (uchar)null;
}
}
/* 32-bit / 64-bit optimised XOR engine */
static void neoscrypt_xor(void *dstp, const void *srcp, uint len) {
ulong *dst = (ulong *) dstp;
ulong *src = (ulong *) srcp;
uint i, tail;
for(i = 0; i < (len / sizeof(ulong)); i++)
dst[i] ^= src[i];
tail = len & (sizeof(ulong) - 1);
if(tail) {
uchar *dstb = (uchar *) dstp;
uchar *srcb = (uchar *) srcp;
for(i = len - tail; i < len; i++)
dstb[i] ^= srcb[i];
}
}
/* BLAKE2s */
#define BLAKE2S_BLOCK_SIZE 64U
#define BLAKE2S_OUT_SIZE 32U
#define BLAKE2S_KEY_SIZE 32U
/* Parameter block of 32 bytes */
typedef struct blake2s_param_t {
uchar digest_length;
uchar key_length;
uchar fanout;
uchar depth;
uint leaf_length;
uchar node_offset[6];
uchar node_depth;
uchar inner_length;
uchar salt[8];
uchar personal[8];
} blake2s_param;
/* State block of 180 bytes */
typedef struct blake2s_state_t {
uint h[8];
uint t[2];
uint f[2];
uchar buf[2 * BLAKE2S_BLOCK_SIZE];
uint buflen;
} blake2s_state;
static const uint blake2s_IV[8] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
};
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 void blake2s_compress(blake2s_state *S, const uint *buf) {
uint i;
uint m[16];
uint v[16];
neoscrypt_copy(m, buf, 64);
neoscrypt_copy(v, S, 32);
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(i = 0; i < 8; i++)
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
#undef G
#undef ROUND
}
static void blake2s_update(blake2s_state *S, const uchar *input, uint input_size) {
uint left, fill;
while(input_size > 0) {
left = S->buflen;
fill = 2 * BLAKE2S_BLOCK_SIZE - left;
if(input_size > fill) {
/* Buffer fill */
neoscrypt_copy(S->buf + left, input, fill);
S->buflen += fill;
/* Counter increment */
S->t[0] += BLAKE2S_BLOCK_SIZE;
/* Compress */
blake2s_compress(S, (uint *) S->buf);
/* Shift buffer left */
neoscrypt_copy(S->buf, S->buf + BLAKE2S_BLOCK_SIZE, BLAKE2S_BLOCK_SIZE);
S->buflen -= BLAKE2S_BLOCK_SIZE;
input += fill;
input_size -= fill;
} else {
neoscrypt_copy(S->buf + left, input, input_size);
S->buflen += input_size;
/* Do not compress */
input += input_size;
input_size = 0;
}
}
}
static void neoscrypt_blake2s(const void *input, const uint input_size, const void *key, const uchar key_size,
void *output, const uchar output_size) {
uchar block[BLAKE2S_BLOCK_SIZE];
blake2s_param P[1];
blake2s_state S[1];
/* Initialise */
neoscrypt_erase(P, 32);
P->digest_length = output_size;
P->key_length = key_size;
P->fanout = 1;
P->depth = 1;
neoscrypt_erase(S, 180);
neoscrypt_copy(S, blake2s_IV, 32);
neoscrypt_xor(S, P, 32);
neoscrypt_erase(block, BLAKE2S_BLOCK_SIZE);
neoscrypt_copy(block, key, key_size);
blake2s_update(S, (uchar *) block, BLAKE2S_BLOCK_SIZE);
/* Update */
blake2s_update(S, (uchar *) input, input_size);
/* Finish */
if(S->buflen > BLAKE2S_BLOCK_SIZE) {
S->t[0] += BLAKE2S_BLOCK_SIZE;
blake2s_compress(S, (uint *) S->buf);
S->buflen -= BLAKE2S_BLOCK_SIZE;
neoscrypt_copy(S->buf, S->buf + BLAKE2S_BLOCK_SIZE, S->buflen);
}
S->t[0] += S->buflen;
S->f[0] = ~0U;
neoscrypt_erase(S->buf + S->buflen, 2 * BLAKE2S_BLOCK_SIZE - S->buflen);
blake2s_compress(S, (uint *) S->buf);
/* Write back */
neoscrypt_copy(output, S, output_size);
}
#define FASTKDF_BUFFER_SIZE 256U
/* FastKDF, a fast buffered key derivation function:
* FASTKDF_BUFFER_SIZE must be a power of 2;
* password_len, salt_len and output_len should not exceed FASTKDF_BUFFER_SIZE;
* prf_output_size must be <= prf_key_size; */
static void neoscrypt_fastkdf(const uchar *password, uint password_len, const uchar *salt, uint salt_len,
uint N, uchar *output, uint output_len) {
const uint stack_align = 0x40, kdf_buf_size = FASTKDF_BUFFER_SIZE,
prf_input_size = BLAKE2S_BLOCK_SIZE, prf_key_size = BLAKE2S_KEY_SIZE, prf_output_size = BLAKE2S_OUT_SIZE;
uint bufptr, a, b, i, j;
uchar *A, *B, *prf_input, *prf_key, *prf_output;
/* Align and set up the buffers in stack */
uchar stack[2 * kdf_buf_size + prf_input_size + prf_key_size + prf_output_size + stack_align];
A = &stack[stack_align & ~(stack_align - 1)];
B = &A[kdf_buf_size + prf_input_size];
prf_output = &A[2 * kdf_buf_size + prf_input_size + prf_key_size];
/* Initialise the password buffer */
if(password_len > kdf_buf_size)
password_len = kdf_buf_size;
a = kdf_buf_size / password_len;
for(i = 0; i < a; i++)
neoscrypt_copy(&A[i * password_len], &password[0], password_len);
b = kdf_buf_size - a * password_len;
if(b)
neoscrypt_copy(&A[a * password_len], &password[0], b);
neoscrypt_copy(&A[kdf_buf_size], &password[0], prf_input_size);
/* Initialise the salt buffer */
if(salt_len > kdf_buf_size)
salt_len = kdf_buf_size;
a = kdf_buf_size / salt_len;
for(i = 0; i < a; i++)
neoscrypt_copy(&B[i * salt_len], &salt[0], salt_len);
b = kdf_buf_size - a * salt_len;
if(b)
neoscrypt_copy(&B[a * salt_len], &salt[0], b);
neoscrypt_copy(&B[kdf_buf_size], &salt[0], prf_key_size);
/* The primary iteration */
for(i = 0, bufptr = 0; i < N; i++) {
/* Map the PRF input buffer */
prf_input = &A[bufptr];
/* Map the PRF key buffer */
prf_key = &B[bufptr];
/* PRF */
neoscrypt_blake2s(prf_input, prf_input_size, prf_key, prf_key_size, prf_output, prf_output_size);
/* Calculate the next buffer pointer */
for(j = 0, bufptr = 0; j < prf_output_size; j++)
bufptr += prf_output[j];
bufptr &= (kdf_buf_size - 1);
/* Modify the salt buffer */
neoscrypt_xor(&B[bufptr], &prf_output[0], prf_output_size);
/* Head modified, tail updated */
if(bufptr < prf_key_size)
neoscrypt_copy(&B[kdf_buf_size + bufptr], &B[bufptr], MIN(prf_output_size, prf_key_size - bufptr));
/* Tail modified, head updated */
if((kdf_buf_size - bufptr) < prf_output_size)
neoscrypt_copy(&B[0], &B[kdf_buf_size], prf_output_size - (kdf_buf_size - bufptr));
}
/* Modify and copy into the output buffer */
if(output_len > kdf_buf_size)
output_len = kdf_buf_size;
a = kdf_buf_size - bufptr;
if(a >= output_len) {
neoscrypt_xor(&B[bufptr], &A[0], output_len);
neoscrypt_copy(&output[0], &B[bufptr], output_len);
} else {
neoscrypt_xor(&B[bufptr], &A[0], a);
neoscrypt_xor(&B[0], &A[a], output_len - a);
neoscrypt_copy(&output[0], &B[bufptr], a);
neoscrypt_copy(&output[a], &B[0], output_len - a);
}
}
/* Configurable optimised block mixer */
static void neoscrypt_blkmix(uint *X, uint *Y, uint r, uint mixmode) {
uint i, mixer, rounds;
mixer = mixmode >> 8;
rounds = mixmode & 0xFF;
/* NeoScrypt flow: Scrypt flow:
Xa ^= Xd; M(Xa'); Ya = Xa"; Xa ^= Xb; M(Xa'); Ya = Xa";
Xb ^= Xa"; M(Xb'); Yb = Xb"; Xb ^= Xa"; M(Xb'); Yb = Xb";
Xc ^= Xb"; M(Xc'); Yc = Xc"; Xa" = Ya;
Xd ^= Xc"; M(Xd'); Yd = Xd"; Xb" = Yb;
Xa" = Ya; Xb" = Yc;
Xc" = Yb; Xd" = Yd; */
if(r == 1) {
neoscrypt_blkxor(&X[0], &X[16], SCRYPT_BLOCK_SIZE);
if(mixer)
neoscrypt_chacha(&X[0], rounds);
else
neoscrypt_salsa(&X[0], rounds);
neoscrypt_blkxor(&X[16], &X[0], SCRYPT_BLOCK_SIZE);
if(mixer)
neoscrypt_chacha(&X[16], rounds);
else
neoscrypt_salsa(&X[16], rounds);
return;
}
if(r == 2) {
neoscrypt_blkxor(&X[0], &X[48], SCRYPT_BLOCK_SIZE);
if(mixer)
neoscrypt_chacha(&X[0], rounds);
else
neoscrypt_salsa(&X[0], rounds);
neoscrypt_blkxor(&X[16], &X[0], SCRYPT_BLOCK_SIZE);
if(mixer)
neoscrypt_chacha(&X[16], rounds);
else
neoscrypt_salsa(&X[16], rounds);
neoscrypt_blkxor(&X[32], &X[16], SCRYPT_BLOCK_SIZE);
if(mixer)
neoscrypt_chacha(&X[32], rounds);
else
neoscrypt_salsa(&X[32], rounds);
neoscrypt_blkxor(&X[48], &X[32], SCRYPT_BLOCK_SIZE);
if(mixer)
neoscrypt_chacha(&X[48], rounds);
else
neoscrypt_salsa(&X[48], rounds);
neoscrypt_blkswp(&X[16], &X[32], SCRYPT_BLOCK_SIZE);
return;
}
/* Reference code for any reasonable r */
for(i = 0; i < 2 * r; i++) {
if(i) neoscrypt_blkxor(&X[16 * i], &X[16 * (i - 1)], SCRYPT_BLOCK_SIZE);
else neoscrypt_blkxor(&X[0], &X[16 * (2 * r - 1)], SCRYPT_BLOCK_SIZE);
if(mixer)
neoscrypt_chacha(&X[16 * i], rounds);
else
neoscrypt_salsa(&X[16 * i], rounds);
neoscrypt_blkcpy(&Y[16 * i], &X[16 * i], SCRYPT_BLOCK_SIZE);
}
for(i = 0; i < r; i++)
neoscrypt_blkcpy(&X[16 * i], &Y[16 * 2 * i], SCRYPT_BLOCK_SIZE);
for(i = 0; i < r; i++)
neoscrypt_blkcpy(&X[16 * (i + r)], &Y[16 * (2 * i + 1)], SCRYPT_BLOCK_SIZE);
}
/* NeoScrypt core engine:
* p = 1, salt = password;
* Basic customisation (required):
* profile bit 0:
* 0 = NeoScrypt(128, 2, 1) with Salsa20/20 and ChaCha20/20;
* 1 = Scrypt(1024, 1, 1) with Salsa20/8;
* profile bits 4 to 1:
* 0000 = FastKDF-BLAKE2s;
* 0001 = PBKDF2-HMAC-SHA256;
* Extended customisation (optional):
* profile bit 31:
* 0 = extended customisation absent;
* 1 = extended customisation present;
* profile bits 7 to 5 (rfactor):
* 000 = r of 1;
* 001 = r of 2;
* 010 = r of 4;
* ...
* 111 = r of 128;
* profile bits 12 to 8 (Nfactor):
* 00000 = N of 2;
* 00001 = N of 4;
* 00010 = N of 8;
* .....
* 00110 = N of 128;
* .....
* 01001 = N of 1024;
* .....
* 11110 = N of 2147483648;
* profile bits 30 to 13 are reserved */
void neoscrypt(const uchar *password, uchar *output, uint profile) {
uint N = 128, r = 2, dblmix = 1, mixmode = 0x14, stack_align = 0x40;
uint kdf, i, j;
uint *X, *Y, *Z, *V;
if(profile & 0x1) {
N = 1024; /* N = (1 << (Nfactor + 1)); */
r = 1; /* r = (1 << rfactor); */
dblmix = 0; /* Salsa only */
mixmode = 0x08; /* 8 rounds */
}
if(profile >> 31) {
N = (1 << (((profile >> 8) & 0x1F) + 1));
r = (1 << ((profile >> 5) & 0x7));
}
uchar stack[(N + 3) * r * 2 * SCRYPT_BLOCK_SIZE + stack_align];
/* X = r * 2 * SCRYPT_BLOCK_SIZE */
X = (uint *) &stack[stack_align & ~(stack_align - 1)];
/* Z is a copy of X for ChaCha */
Z = &X[32 * r];
/* Y is an X sized temporal space */
Y = &X[64 * r];
/* V = N * r * 2 * SCRYPT_BLOCK_SIZE */
V = &X[96 * r];
/* X = KDF(password, salt) */
kdf = (profile >> 1) & 0xF;
switch(kdf) {
default:
case(0x0):
neoscrypt_fastkdf(password, 80, password, 80, 32, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE);
break;
case(0x1):
neoscrypt_pbkdf2_sha256(password, 80, password, 80, 1, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE);
break;
}
/* Process ChaCha 1st, Salsa 2nd and XOR them into FastKDF; otherwise Salsa only */
if(dblmix) {
/* blkcpy(Z, X) */
neoscrypt_blkcpy(&Z[0], &X[0], r * 2 * SCRYPT_BLOCK_SIZE);
/* Z = SMix(Z) */
for(i = 0; i < N; i++) {
/* blkcpy(V, Z) */
neoscrypt_blkcpy(&V[i * (32 * r)], &Z[0], r * 2 * SCRYPT_BLOCK_SIZE);
/* blkmix(Z, Y) */
neoscrypt_blkmix(&Z[0], &Y[0], r, (mixmode | 0x0100));
}
for(i = 0; i < N; i++) {
/* integerify(Z) mod N */
j = (32 * r) * (Z[16 * (2 * r - 1)] & (N - 1));
/* blkxor(Z, V) */
neoscrypt_blkxor(&Z[0], &V[j], r * 2 * SCRYPT_BLOCK_SIZE);
/* blkmix(Z, Y) */
neoscrypt_blkmix(&Z[0], &Y[0], r, (mixmode | 0x0100));
}
}
#if (ASM)
/* Must be called before and after SSE2 Salsa */
neoscrypt_salsa_tangle(&X[0], r * 2);
#endif
/* X = SMix(X) */
for(i = 0; i < N; i++) {
/* blkcpy(V, X) */
neoscrypt_blkcpy(&V[i * (32 * r)], &X[0], r * 2 * SCRYPT_BLOCK_SIZE);
/* blkmix(X, Y) */
neoscrypt_blkmix(&X[0], &Y[0], r, mixmode);
}
for(i = 0; i < N; i++) {
/* integerify(X) mod N */
j = (32 * r) * (X[16 * (2 * r - 1)] & (N - 1));
/* blkxor(X, V) */
neoscrypt_blkxor(&X[0], &V[j], r * 2 * SCRYPT_BLOCK_SIZE);
/* blkmix(X, Y) */
neoscrypt_blkmix(&X[0], &Y[0], r, mixmode);
}
#if (ASM)
neoscrypt_salsa_tangle(&X[0], r * 2);
#endif
if(dblmix)
/* blkxor(X, Z) */
neoscrypt_blkxor(&X[0], &Z[0], r * 2 * SCRYPT_BLOCK_SIZE);
/* output = KDF(password, X) */
switch(kdf) {
default:
case(0x0):
neoscrypt_fastkdf(password, 80, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE, 32, output, 32);
break;
case(0x1):
neoscrypt_pbkdf2_sha256(password, 80, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE, 1, output, 32);
break;
}
}

33
stratum/algos/neoscrypt.h Normal file
View file

@ -0,0 +1,33 @@
#if (__cplusplus)
extern "C" {
#endif
void neoscrypt(const unsigned char *input, unsigned char *output, unsigned int profile);
#if (__cplusplus)
}
#else
#define SCRYPT_BLOCK_SIZE 64
#define SCRYPT_HASH_BLOCK_SIZE 64
#define SCRYPT_HASH_DIGEST_SIZE 32
typedef uint8_t hash_digest[SCRYPT_HASH_DIGEST_SIZE];
#define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b)))
#define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b)))
#define U8TO32_BE(p) \
(((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \
((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3])))
#define U32TO8_BE(p, v) \
(p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \
(p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) );
#define U64TO8_BE(p, v) \
U32TO8_BE((p), (uint32_t)((v) >> 32)); \
U32TO8_BE((p) + 4, (uint32_t)((v) ));
#endif

47
stratum/algos/nist5.c Normal file
View file

@ -0,0 +1,47 @@
#include "nist5.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
void nist5_hash(const char* input, char* output, uint32_t len)
{
sph_blake512_context ctx_blake;
sph_groestl512_context ctx_groestl;
sph_skein512_context ctx_skein;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
//these uint512 in the c++ source of the client are backed by an array of uint32
uint32_t hash[16];
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, input, len);
sph_blake512_close (&ctx_blake, hash);
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hash, 64);
sph_groestl512_close(&ctx_groestl, hash);
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hash, 64);
sph_jh512_close(&ctx_jh, hash);
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, hash, 64);
sph_keccak512_close(&ctx_keccak, hash);
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hash, 64);
sph_skein512_close (&ctx_skein, hash);
memcpy(output, hash, 32);
}

16
stratum/algos/nist5.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef NIST5_H
#define NIST5_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void nist5_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

210
stratum/algos/quark.c Normal file
View file

@ -0,0 +1,210 @@
/*-
* Copyright 2009 Colin Percival, 2011 ArtForz, 2013 Neisklar,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file was originally written by Colin Percival as part of the Tarsnap
* online backup system.
*/
#include "quark.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_bmw.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#if 0
static __inline uint32_t
be32dec(const void *pp)
{
const uint8_t *p = (uint8_t const *)pp;
return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
}
static __inline void
be32enc(void *pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[3] = x & 0xff;
p[2] = (x >> 8) & 0xff;
p[1] = (x >> 16) & 0xff;
p[0] = (x >> 24) & 0xff;
}
static __inline uint32_t
le32dec(const void *pp)
{
const uint8_t *p = (uint8_t const *)pp;
return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
}
static __inline void
le32enc(void *pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[0] = x & 0xff;
p[1] = (x >> 8) & 0xff;
p[2] = (x >> 16) & 0xff;
p[3] = (x >> 24) & 0xff;
}
/*
* Encode a length len/4 vector of (uint32_t) into a length len vector of
* (unsigned char) in big-endian form. Assumes len is a multiple of 4.
*/
static void
be32enc_vect(unsigned char *dst, const uint32_t *src, uint32_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
be32enc(dst + i * 4, src[i]);
}
/*
* Decode a big-endian length len vector of (unsigned char) into a length
* len/4 vector of (uint32_t). Assumes len is a multiple of 4.
*/
static void
be32dec_vect(uint32_t *dst, const unsigned char *src, uint32_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
dst[i] = be32dec(src + i * 4);
}
#endif
void quark_hash(const char* input, char* output, uint32_t len)
{
sph_blake512_context ctx_blake;
sph_bmw512_context ctx_bmw;
sph_groestl512_context ctx_groestl;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
sph_skein512_context ctx_skein;
uint32_t mask = 8;
uint32_t zero = 0;
uint32_t hashA[16], hashB[16];
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, input, len);
sph_blake512_close (&ctx_blake, hashA); //0
sph_bmw512_init(&ctx_bmw);
sph_bmw512 (&ctx_bmw, hashA, 64); //0
sph_bmw512_close(&ctx_bmw, hashB); //1
if ((hashB[0] & mask) != zero) //1
{
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hashB, 64); //1
sph_groestl512_close(&ctx_groestl, hashA); //2
}
else
{
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hashB, 64); //1
sph_skein512_close(&ctx_skein, hashA); //2
}
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hashA, 64); //2
sph_groestl512_close(&ctx_groestl, hashB); //3
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hashB, 64); //3
sph_jh512_close(&ctx_jh, hashA); //4
if ((hashA[0] & mask) != zero) //4
{
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, hashA, 64); //
sph_blake512_close(&ctx_blake, hashB); //5
}
else
{
sph_bmw512_init(&ctx_bmw);
sph_bmw512 (&ctx_bmw, hashA, 64); //4
sph_bmw512_close(&ctx_bmw, hashB); //5
}
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak,hashB, 64); //5
sph_keccak512_close(&ctx_keccak, hashA); //6
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hashA, 64); //6
sph_skein512_close(&ctx_skein, hashB); //7
if ((hashB[0] & mask) != zero) //7
{
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, hashB, 64); //
sph_keccak512_close(&ctx_keccak, hashA); //8
}
else
{
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hashB, 64); //7
sph_jh512_close(&ctx_jh, hashA); //8
}
memcpy(output, hashA, 32);
/*
printf("result: ");
for (ii=0; ii < 32; ii++)
{
printf ("%.2x",((uint8_t*)output)[ii]);
}
printf ("\n");
*/
}

16
stratum/algos/quark.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef QUARK_H
#define QUARK_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void quark_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

44
stratum/algos/qubit.c Normal file
View file

@ -0,0 +1,44 @@
#include "qubit.h"
#include <string.h>
#include <stdlib.h>
#include "../sha3/sph_cubehash.h"
#include "../sha3/sph_luffa.h"
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
void qubit_hash(const char* input, char* output, uint32_t len)
{
sph_luffa512_context ctx_luffa;
sph_cubehash512_context ctx_cubehash;
sph_shavite512_context ctx_shavite;
sph_simd512_context ctx_simd;
sph_echo512_context ctx_echo;
char hash1[64];
char hash2[64];
sph_luffa512_init(&ctx_luffa);
sph_luffa512(&ctx_luffa, (const void*) input, len);
sph_luffa512_close(&ctx_luffa, (void*) &hash1); // 1
sph_cubehash512_init(&ctx_cubehash);
sph_cubehash512(&ctx_cubehash, (const void*) &hash1, 64); // 1
sph_cubehash512_close(&ctx_cubehash, (void*) &hash2); // 2
sph_shavite512_init(&ctx_shavite);
sph_shavite512(&ctx_shavite, (const void*) &hash2, 64); // 3
sph_shavite512_close(&ctx_shavite, (void*) &hash1); // 4
sph_simd512_init(&ctx_simd);
sph_simd512(&ctx_simd, (const void*) &hash1, 64); // 4
sph_simd512_close(&ctx_simd, (void*) &hash2); // 5
sph_echo512_init(&ctx_echo);
sph_echo512(&ctx_echo, (const void*) &hash2, 64); // 5
sph_echo512_close(&ctx_echo, (void*) &hash1); // 6
memcpy(output, &hash1, 32);
}

17
stratum/algos/qubit.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef QUBIT_H
#define QUBIT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void qubit_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

681
stratum/algos/scrypt.c Normal file
View file

@ -0,0 +1,681 @@
/*-
* Copyright 2009 Colin Percival, 2011 ArtForz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file was originally written by Colin Percival as part of the Tarsnap
* online backup system.
*/
//#include "scrypt.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
static __inline uint32_t
be32dec(const void *pp)
{
const uint8_t *p = (uint8_t const *)pp;
return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
}
static __inline void
be32enc(void *pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[3] = x & 0xff;
p[2] = (x >> 8) & 0xff;
p[1] = (x >> 16) & 0xff;
p[0] = (x >> 24) & 0xff;
}
static __inline uint32_t
le32dec(const void *pp)
{
const uint8_t *p = (uint8_t const *)pp;
return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
}
static __inline void
le32enc(void *pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[0] = x & 0xff;
p[1] = (x >> 8) & 0xff;
p[2] = (x >> 16) & 0xff;
p[3] = (x >> 24) & 0xff;
}
typedef struct SHA256Context {
uint32_t state[8];
uint32_t count[2];
unsigned char buf[64];
} SHA256_CTX;
typedef struct HMAC_SHA256Context {
SHA256_CTX ictx;
SHA256_CTX octx;
} HMAC_SHA256_CTX;
/*
* Encode a length len/4 vector of (uint32_t) into a length len vector of
* (unsigned char) in big-endian form. Assumes len is a multiple of 4.
*/
static void
be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
be32enc(dst + i * 4, src[i]);
}
/*
* Decode a big-endian length len vector of (unsigned char) into a length
* len/4 vector of (uint32_t). Assumes len is a multiple of 4.
*/
static void
be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
dst[i] = be32dec(src + i * 4);
}
/* Elementary functions used by SHA256 */
#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
#define Maj(x, y, z) ((x & (y | z)) | (y & z))
#define SHR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
/* SHA256 round function */
#define RND(a, b, c, d, e, f, g, h, k) \
t0 = h + S1(e) + Ch(e, f, g) + k; \
t1 = S0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
/* Adjusted round function for rotating state */
#define RNDr(S, W, i, k) \
RND(S[(64 - i) % 8], S[(65 - i) % 8], \
S[(66 - i) % 8], S[(67 - i) % 8], \
S[(68 - i) % 8], S[(69 - i) % 8], \
S[(70 - i) % 8], S[(71 - i) % 8], \
W[i] + k)
/*
* SHA256 block compression function. The 256-bit state is transformed via
* the 512-bit input block to produce a new state.
*/
static void
SHA256_Transform(uint32_t * state, const unsigned char block[64])
{
uint32_t W[64];
uint32_t S[8];
uint32_t t0, t1;
int i;
/* 1. Prepare message schedule W. */
be32dec_vect(W, block, 64);
for (i = 16; i < 64; i++)
W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
/* 2. Initialize working variables. */
memcpy(S, state, 32);
/* 3. Mix. */
RNDr(S, W, 0, 0x428a2f98);
RNDr(S, W, 1, 0x71374491);
RNDr(S, W, 2, 0xb5c0fbcf);
RNDr(S, W, 3, 0xe9b5dba5);
RNDr(S, W, 4, 0x3956c25b);
RNDr(S, W, 5, 0x59f111f1);
RNDr(S, W, 6, 0x923f82a4);
RNDr(S, W, 7, 0xab1c5ed5);
RNDr(S, W, 8, 0xd807aa98);
RNDr(S, W, 9, 0x12835b01);
RNDr(S, W, 10, 0x243185be);
RNDr(S, W, 11, 0x550c7dc3);
RNDr(S, W, 12, 0x72be5d74);
RNDr(S, W, 13, 0x80deb1fe);
RNDr(S, W, 14, 0x9bdc06a7);
RNDr(S, W, 15, 0xc19bf174);
RNDr(S, W, 16, 0xe49b69c1);
RNDr(S, W, 17, 0xefbe4786);
RNDr(S, W, 18, 0x0fc19dc6);
RNDr(S, W, 19, 0x240ca1cc);
RNDr(S, W, 20, 0x2de92c6f);
RNDr(S, W, 21, 0x4a7484aa);
RNDr(S, W, 22, 0x5cb0a9dc);
RNDr(S, W, 23, 0x76f988da);
RNDr(S, W, 24, 0x983e5152);
RNDr(S, W, 25, 0xa831c66d);
RNDr(S, W, 26, 0xb00327c8);
RNDr(S, W, 27, 0xbf597fc7);
RNDr(S, W, 28, 0xc6e00bf3);
RNDr(S, W, 29, 0xd5a79147);
RNDr(S, W, 30, 0x06ca6351);
RNDr(S, W, 31, 0x14292967);
RNDr(S, W, 32, 0x27b70a85);
RNDr(S, W, 33, 0x2e1b2138);
RNDr(S, W, 34, 0x4d2c6dfc);
RNDr(S, W, 35, 0x53380d13);
RNDr(S, W, 36, 0x650a7354);
RNDr(S, W, 37, 0x766a0abb);
RNDr(S, W, 38, 0x81c2c92e);
RNDr(S, W, 39, 0x92722c85);
RNDr(S, W, 40, 0xa2bfe8a1);
RNDr(S, W, 41, 0xa81a664b);
RNDr(S, W, 42, 0xc24b8b70);
RNDr(S, W, 43, 0xc76c51a3);
RNDr(S, W, 44, 0xd192e819);
RNDr(S, W, 45, 0xd6990624);
RNDr(S, W, 46, 0xf40e3585);
RNDr(S, W, 47, 0x106aa070);
RNDr(S, W, 48, 0x19a4c116);
RNDr(S, W, 49, 0x1e376c08);
RNDr(S, W, 50, 0x2748774c);
RNDr(S, W, 51, 0x34b0bcb5);
RNDr(S, W, 52, 0x391c0cb3);
RNDr(S, W, 53, 0x4ed8aa4a);
RNDr(S, W, 54, 0x5b9cca4f);
RNDr(S, W, 55, 0x682e6ff3);
RNDr(S, W, 56, 0x748f82ee);
RNDr(S, W, 57, 0x78a5636f);
RNDr(S, W, 58, 0x84c87814);
RNDr(S, W, 59, 0x8cc70208);
RNDr(S, W, 60, 0x90befffa);
RNDr(S, W, 61, 0xa4506ceb);
RNDr(S, W, 62, 0xbef9a3f7);
RNDr(S, W, 63, 0xc67178f2);
/* 4. Mix local working variables into global state */
for (i = 0; i < 8; i++)
state[i] += S[i];
/* Clean the stack. */
memset(W, 0, 256);
memset(S, 0, 32);
t0 = t1 = 0;
}
static unsigned char PAD[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* SHA-256 initialization. Begins a SHA-256 operation. */
static void
SHA256_Init(SHA256_CTX * ctx)
{
/* Zero bits processed so far */
ctx->count[0] = ctx->count[1] = 0;
/* Magic initialization constants */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
/* Add bytes into the hash */
static void
SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
{
uint32_t bitlen[2];
uint32_t r;
const unsigned char *src = (const unsigned char*)in;
/* Number of bytes left in the buffer from previous updates */
r = (ctx->count[1] >> 3) & 0x3f;
/* Convert the length into a number of bits */
bitlen[1] = ((uint32_t)len) << 3;
bitlen[0] = (uint32_t)(len >> 29);
/* Update number of bits */
if ((ctx->count[1] += bitlen[1]) < bitlen[1])
ctx->count[0]++;
ctx->count[0] += bitlen[0];
/* Handle the case where we don't need to perform any transforms */
if (len < 64 - r) {
memcpy(&ctx->buf[r], src, len);
return;
}
/* Finish the current block */
memcpy(&ctx->buf[r], src, 64 - r);
SHA256_Transform(ctx->state, ctx->buf);
src += 64 - r;
len -= 64 - r;
/* Perform complete blocks */
while (len >= 64) {
SHA256_Transform(ctx->state, src);
src += 64;
len -= 64;
}
/* Copy left over data into buffer */
memcpy(ctx->buf, src, len);
}
/* Add padding and terminating bit-count. */
static void
SHA256_Pad(SHA256_CTX * ctx)
{
unsigned char len[8];
uint32_t r, plen;
/*
* Convert length to a vector of bytes -- we do this now rather
* than later because the length will change after we pad.
*/
be32enc_vect(len, ctx->count, 8);
/* Add 1--64 bytes so that the resulting length is 56 mod 64 */
r = (ctx->count[1] >> 3) & 0x3f;
plen = (r < 56) ? (56 - r) : (120 - r);
SHA256_Update(ctx, PAD, (size_t)plen);
/* Add the terminating bit-count */
SHA256_Update(ctx, len, 8);
}
/*
* SHA-256 finalization. Pads the input data, exports the hash value,
* and clears the context state.
*/
static void
SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
{
/* Add padding */
SHA256_Pad(ctx);
/* Write the hash */
be32enc_vect(digest, ctx->state, 32);
/* Clear the context state */
memset((void *)ctx, 0, sizeof(*ctx));
}
/* Initialize an HMAC-SHA256 operation with the given key. */
static void
HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
{
unsigned char pad[64];
unsigned char khash[32];
const unsigned char * K = (const unsigned char *)_K;
size_t i;
/* If Klen > 64, the key is really SHA256(K). */
if (Klen > 64) {
SHA256_Init(&ctx->ictx);
SHA256_Update(&ctx->ictx, K, Klen);
SHA256_Final(khash, &ctx->ictx);
K = khash;
Klen = 32;
}
/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
SHA256_Init(&ctx->ictx);
memset(pad, 0x36, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
SHA256_Update(&ctx->ictx, pad, 64);
/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
SHA256_Init(&ctx->octx);
memset(pad, 0x5c, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
SHA256_Update(&ctx->octx, pad, 64);
/* Clean the stack. */
memset(khash, 0, 32);
}
/* Add bytes to the HMAC-SHA256 operation. */
static void
HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len)
{
/* Feed data to the inner SHA256 operation. */
SHA256_Update(&ctx->ictx, in, len);
}
/* Finish an HMAC-SHA256 operation. */
static void
HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx)
{
unsigned char ihash[32];
/* Finish the inner SHA256 operation. */
SHA256_Final(ihash, &ctx->ictx);
/* Feed the inner hash to the outer SHA256 operation. */
SHA256_Update(&ctx->octx, ihash, 32);
/* Finish the outer SHA256 operation. */
SHA256_Final(digest, &ctx->octx);
/* Clean the stack. */
memset(ihash, 0, 32);
}
/**
* PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
* Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
* write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
*/
static void
PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
{
HMAC_SHA256_CTX PShctx, hctx;
size_t i;
uint8_t ivec[4];
uint8_t U[32];
uint8_t T[32];
uint64_t j;
int k;
size_t clen;
/* Compute HMAC state after processing P and S. */
HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
HMAC_SHA256_Update(&PShctx, salt, saltlen);
/* Iterate through the blocks. */
for (i = 0; i * 32 < dkLen; i++) {
/* Generate INT(i + 1). */
be32enc(ivec, (uint32_t)(i + 1));
/* Compute U_1 = PRF(P, S || INT(i)). */
memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
HMAC_SHA256_Update(&hctx, ivec, 4);
HMAC_SHA256_Final(U, &hctx);
/* T_i = U_1 ... */
memcpy(T, U, 32);
for (j = 2; j <= c; j++) {
/* Compute U_j. */
HMAC_SHA256_Init(&hctx, passwd, passwdlen);
HMAC_SHA256_Update(&hctx, U, 32);
HMAC_SHA256_Final(U, &hctx);
/* ... xor U_j ... */
for (k = 0; k < 32; k++)
T[k] ^= U[k];
}
/* Copy as many bytes as necessary into buf. */
clen = dkLen - i * 32;
if (clen > 32)
clen = 32;
memcpy(&buf[i * 32], T, clen);
}
/* Clean PShctx, since we never called _Final on it. */
memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));
}
static void blkcpy(void *, void *, size_t);
static void blkxor(void *, void *, size_t);
static void salsa20_8(uint32_t[16]);
static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t);
static uint64_t integerify(void *, size_t);
static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *);
static void
blkcpy(void * dest, void * src, size_t len)
{
size_t * D = (size_t *)dest;
size_t * S = (size_t *)src;
size_t L = len / sizeof(size_t);
size_t i;
for (i = 0; i < L; i++)
D[i] = S[i];
}
static void
blkxor(void * dest, void * src, size_t len)
{
size_t * D = (size_t *)dest;
size_t * S = (size_t *)src;
size_t L = len / sizeof(size_t);
size_t i;
for (i = 0; i < L; i++)
D[i] ^= S[i];
}
/**
* salsa20_8(B):
* Apply the salsa20/8 core to the provided block.
*/
static void
salsa20_8(uint32_t B[16])
{
uint32_t x[16];
size_t i;
blkcpy(x, B, 64);
for (i = 0; i < 8; i += 2) {
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
/* Operate on columns. */
x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
/* Operate on rows. */
x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
#undef R
}
for (i = 0; i < 16; i++)
B[i] += x[i];
}
/**
* blockmix_salsa8(Bin, Bout, X, r):
* Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r
* bytes in length; the output Bout must also be the same size. The
* temporary space X must be 64 bytes.
*/
static void
blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r)
{
size_t i;
/* 1: X <-- B_{2r - 1} */
blkcpy(X, &Bin[(2 * r - 1) * 16], 64);
/* 2: for i = 0 to 2r - 1 do */
for (i = 0; i < 2 * r; i += 2) {
/* 3: X <-- H(X \xor B_i) */
blkxor(X, &Bin[i * 16], 64);
salsa20_8(X);
/* 4: Y_i <-- X */
/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
blkcpy(&Bout[i * 8], X, 64);
/* 3: X <-- H(X \xor B_i) */
blkxor(X, &Bin[i * 16 + 16], 64);
salsa20_8(X);
/* 4: Y_i <-- X */
/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
blkcpy(&Bout[i * 8 + r * 16], X, 64);
}
}
/**
* integerify(B, r):
* Return the result of parsing B_{2r-1} as a little-endian integer.
*/
static uint64_t
integerify(void * B, size_t r)
{
uint32_t * X = (uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64);
return (((uint64_t)(X[1]) << 32) + X[0]);
}
/**
* smix(B, r, N, V, XY):
* Compute B = SMix_r(B, N). The input B must be 128r bytes in length;
* the temporary storage V must be 128rN bytes in length; the temporary
* storage XY must be 256r + 64 bytes in length. The value N must be a
* power of 2 greater than 1. The arrays B, V, and XY must be aligned to a
* multiple of 64 bytes.
*/
static void
smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY)
{
uint32_t * X = XY;
uint32_t * Y = &XY[32 * r];
uint32_t * Z = &XY[64 * r];
uint64_t i;
uint64_t j;
size_t k;
/* 1: X <-- B */
for (k = 0; k < 32 * r; k++)
X[k] = le32dec(&B[4 * k]);
/* 2: for i = 0 to N - 1 do */
for (i = 0; i < N; i += 2) {
/* 3: V_i <-- X */
blkcpy(&V[i * (32 * r)], X, 128 * r);
/* 4: X <-- H(X) */
blockmix_salsa8(X, Y, Z, r);
/* 3: V_i <-- X */
blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);
/* 4: X <-- H(X) */
blockmix_salsa8(Y, X, Z, r);
}
/* 6: for i = 0 to N - 1 do */
for (i = 0; i < N; i += 2) {
/* 7: j <-- Integerify(X) mod N */
j = integerify(X, r) & (N - 1);
/* 8: X <-- H(X \xor V_j) */
blkxor(X, &V[j * (32 * r)], 128 * r);
blockmix_salsa8(X, Y, Z, r);
/* 7: j <-- Integerify(X) mod N */
j = integerify(Y, r) & (N - 1);
/* 8: X <-- H(X \xor V_j) */
blkxor(Y, &V[j * (32 * r)], 128 * r);
blockmix_salsa8(Y, X, Z, r);
}
/* 10: B' <-- X */
for (k = 0; k < 32 * r; k++)
le32enc(&B[4 * k], X[k]);
}
/* cpu and memory intensive function to transform a 80 byte buffer into a 32 byte output
scratchpad size needs to be at least 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) bytes
*/
void scrypt_1024_1_1_256_sp(const unsigned char* input, unsigned char* output, unsigned char* scratchpad)
{
uint8_t * B;
uint32_t * V;
uint32_t * XY;
uint32_t i;
const uint32_t N = 1024;
const uint32_t r = 1;
const uint32_t p = 1;
B = (uint8_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63));
XY = (uint32_t *)(B + (128 * r * p));
V = (uint32_t *)(B + (128 * r * p) + (256 * r + 64));
/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
PBKDF2_SHA256((const uint8_t*)input, 80, (const uint8_t*)input, 80, 1, B, p * 128 * r);
/* 2: for i = 0 to p - 1 do */
for (i = 0; i < p; i++) {
/* 3: B_i <-- MF(B_i, N) */
smix(&B[i * 128 * r], r, N, V, XY);
}
/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
PBKDF2_SHA256((const uint8_t*)input, 80, B, p * 128 * r, 1, (uint8_t*)output, 32);
}
void scrypt_1024_1_1_256(const unsigned char* input, unsigned char* output)
{
unsigned char scratchpad[131583];
scrypt_1024_1_1_256_sp(input, output, scratchpad);
}

257
stratum/algos/scryptn.c Normal file
View file

@ -0,0 +1,257 @@
/*-
* Copyright 2009 Colin Percival, 2011 ArtForz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file was originally written by Colin Percival as part of the Tarsnap
* online backup system.
*/
#include <stdlib.h>
#include <string.h>
#include "scryptn.h"
#include "sha256.h"
static void blkcpy(void *, void *, size_t);
static void blkxor(void *, void *, size_t);
static void salsa20_8(uint32_t[16]);
static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t);
static uint64_t integerify(void *, size_t);
static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *);
static void
blkcpy(void * dest, void * src, size_t len)
{
size_t * D = (size_t *)dest;
size_t * S = (size_t *)src;
size_t L = len / sizeof(size_t);
size_t i;
for (i = 0; i < L; i++)
D[i] = S[i];
}
static void
blkxor(void * dest, void * src, size_t len)
{
size_t * D = (size_t *)dest;
size_t * S = (size_t *)src;
size_t L = len / sizeof(size_t);
size_t i;
for (i = 0; i < L; i++)
D[i] ^= S[i];
}
/**
* salsa20_8(B):
* Apply the salsa20/8 core to the provided block.
*/
static void
salsa20_8(uint32_t B[16])
{
uint32_t x[16];
size_t i;
blkcpy(x, B, 64);
for (i = 0; i < 8; i += 2) {
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
/* Operate on columns. */
x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
/* Operate on rows. */
x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
#undef R
}
for (i = 0; i < 16; i++)
B[i] += x[i];
}
/**
* blockmix_salsa8(Bin, Bout, X, r):
* Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r
* bytes in length; the output Bout must also be the same size. The
* temporary space X must be 64 bytes.
*/
static void
blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r)
{
size_t i;
/* 1: X <-- B_{2r - 1} */
blkcpy(X, &Bin[(2 * r - 1) * 16], 64);
/* 2: for i = 0 to 2r - 1 do */
for (i = 0; i < 2 * r; i += 2) {
/* 3: X <-- H(X \xor B_i) */
blkxor(X, &Bin[i * 16], 64);
salsa20_8(X);
/* 4: Y_i <-- X */
/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
blkcpy(&Bout[i * 8], X, 64);
/* 3: X <-- H(X \xor B_i) */
blkxor(X, &Bin[i * 16 + 16], 64);
salsa20_8(X);
/* 4: Y_i <-- X */
/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
blkcpy(&Bout[i * 8 + r * 16], X, 64);
}
}
/**
* integerify(B, r):
* Return the result of parsing B_{2r-1} as a little-endian integer.
*/
static uint64_t
integerify(void * B, size_t r)
{
uint32_t * X = (uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64);
return (((uint64_t)(X[1]) << 32) + X[0]);
}
/**
* smix(B, r, N, V, XY):
* Compute B = SMix_r(B, N). The input B must be 128r bytes in length;
* the temporary storage V must be 128rN bytes in length; the temporary
* storage XY must be 256r + 64 bytes in length. The value N must be a
* power of 2 greater than 1. The arrays B, V, and XY must be aligned to a
* multiple of 64 bytes.
*/
static void
smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY)
{
uint32_t * X = XY;
uint32_t * Y = &XY[32 * r];
uint32_t * Z = &XY[64 * r];
uint64_t i;
uint64_t j;
size_t k;
/* 1: X <-- B */
for (k = 0; k < 32 * r; k++)
X[k] = le32dec(&B[4 * k]);
/* 2: for i = 0 to N - 1 do */
for (i = 0; i < N; i += 2) {
/* 3: V_i <-- X */
blkcpy(&V[i * (32 * r)], X, 128 * r);
/* 4: X <-- H(X) */
blockmix_salsa8(X, Y, Z, r);
/* 3: V_i <-- X */
blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);
/* 4: X <-- H(X) */
blockmix_salsa8(Y, X, Z, r);
}
/* 6: for i = 0 to N - 1 do */
for (i = 0; i < N; i += 2) {
/* 7: j <-- Integerify(X) mod N */
j = integerify(X, r) & (N - 1);
/* 8: X <-- H(X \xor V_j) */
blkxor(X, &V[j * (32 * r)], 128 * r);
blockmix_salsa8(X, Y, Z, r);
/* 7: j <-- Integerify(X) mod N */
j = integerify(Y, r) & (N - 1);
/* 8: X <-- H(X \xor V_j) */
blkxor(Y, &V[j * (32 * r)], 128 * r);
blockmix_salsa8(Y, X, Z, r);
}
/* 10: B' <-- X */
for (k = 0; k < 32 * r; k++)
le32enc(&B[4 * k], X[k]);
}
/* cpu and memory intensive function to transform a 80 byte buffer into a 32 byte output
scratchpad size needs to be at least 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) bytes
*/
void scrypt_N_R_1_256_sp(const char* input, char* output, char* scratchpad, uint32_t N, uint32_t R, uint32_t len)
{
uint8_t * B;
uint32_t * V;
uint32_t * XY;
uint32_t i;
//const uint32_t N = 1024;
uint32_t r=R;
const uint32_t p = 1;
B = (uint8_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63));
XY = (uint32_t *)(B + (128 * r * p));
V = (uint32_t *)(B + (128 * r * p) + (256 * r + 64));
/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
PBKDF2_SHA256((const uint8_t*)input, len, (const uint8_t*)input, len, 1, B, p * 128 * r);
/* 2: for i = 0 to p - 1 do */
for (i = 0; i < p; i++) {
/* 3: B_i <-- MF(B_i, N) */
smix(&B[i * 128 * r], r, N, V, XY);
}
/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
PBKDF2_SHA256((const uint8_t*)input, len, B, p * 128 * r, 1, (uint8_t*)output, 32);
}
void scrypt_N_R_1_256(const char* input, char* output, uint32_t N, uint32_t R, uint32_t len)
{
//char scratchpad[131583];
char *scratchpad;
// align on 4 byte boundary
scratchpad = (char*)malloc(128*N*R + (128*R)+(256*R)+64+64);
scrypt_N_R_1_256_sp(input, output, scratchpad, N, R, len);
free(scratchpad);
}

16
stratum/algos/scryptn.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef SCRYPTN_H
#define SCRYPTN_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
//void scrypt_N_R_1_256(const char* input, char* output, uint32_t N, uint32_t R, uint32_t len);
//void scrypt_N_R_1_256_sp(const char* input, char* output, char* scratchpad, uint32_t N, uint32_t R, uint32_t len);
//const int scrypt_scratchpad_size = 131583;
#ifdef __cplusplus
}
#endif
#endif

287
stratum/algos/sha256.c Normal file
View file

@ -0,0 +1,287 @@
//#include "stratum.h"
#include <stdio.h>
#include <string.h>
#ifndef uint8
#define uint8 unsigned char
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
typedef struct
{
uint32 total[2];
uint32 state[8];
uint8 buffer[64];
}
sha256_context;
//void sha256_starts( sha256_context *ctx );
//void sha256_update( sha256_context *ctx, uint8 *input, uint32 length );
//void sha256_finish( sha256_context *ctx, uint8 digest[32] );
#define GET_UINT32(n,b,i) \
{ \
(n) = ( (uint32) (b)[(i) ] << 24 ) \
| ( (uint32) (b)[(i) + 1] << 16 ) \
| ( (uint32) (b)[(i) + 2] << 8 ) \
| ( (uint32) (b)[(i) + 3] ); \
}
#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) >> 24 ); \
(b)[(i) + 1] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 3] = (uint8) ( (n) ); \
}
void sha256_starts( sha256_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
void sha256_process( sha256_context *ctx, uint8 data[64] )
{
uint32 temp1, temp2, W[64];
uint32 A, B, C, D, E, F, G, H;
GET_UINT32( W[0], data, 0 );
GET_UINT32( W[1], data, 4 );
GET_UINT32( W[2], data, 8 );
GET_UINT32( W[3], data, 12 );
GET_UINT32( W[4], data, 16 );
GET_UINT32( W[5], data, 20 );
GET_UINT32( W[6], data, 24 );
GET_UINT32( W[7], data, 28 );
GET_UINT32( W[8], data, 32 );
GET_UINT32( W[9], data, 36 );
GET_UINT32( W[10], data, 40 );
GET_UINT32( W[11], data, 44 );
GET_UINT32( W[12], data, 48 );
GET_UINT32( W[13], data, 52 );
GET_UINT32( W[14], data, 56 );
GET_UINT32( W[15], data, 60 );
#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
#define F0(x,y,z) ((x & y) | (z & (x | y)))
#define F1(x,y,z) (z ^ (x & (y ^ z)))
#define R(t) \
( \
W[t] = S1(W[t - 2]) + W[t - 7] + \
S0(W[t - 15]) + W[t - 16] \
)
#define P(a,b,c,d,e,f,g,h,x,K) \
{ \
temp1 = h + S3(e) + F1(e,f,g) + K + x; \
temp2 = S2(a) + F0(a,b,c); \
d += temp1; h = temp1 + temp2; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
F = ctx->state[5];
G = ctx->state[6];
H = ctx->state[7];
P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
ctx->state[5] += F;
ctx->state[6] += G;
ctx->state[7] += H;
}
void sha256_update(sha256_context *ctx, uint8 *input, uint32 length)
{
uint32 left, fill;
if( ! length ) return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += length;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < length )
ctx->total[1]++;
if( left && length >= fill )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, fill );
sha256_process( ctx, ctx->buffer );
length -= fill;
input += fill;
left = 0;
}
while( length >= 64 )
{
sha256_process( ctx, input );
length -= 64;
input += 64;
}
if( length )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, length );
}
}
static uint8 sha256_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void sha256_finish( sha256_context *ctx, uint8 digest[32] )
{
uint32 last, padn;
uint32 high, low;
uint8 msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32( high, msglen, 0 );
PUT_UINT32( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
sha256_update( ctx, sha256_padding, padn );
sha256_update( ctx, msglen, 8 );
PUT_UINT32( ctx->state[0], digest, 0 );
PUT_UINT32( ctx->state[1], digest, 4 );
PUT_UINT32( ctx->state[2], digest, 8 );
PUT_UINT32( ctx->state[3], digest, 12 );
PUT_UINT32( ctx->state[4], digest, 16 );
PUT_UINT32( ctx->state[5], digest, 20 );
PUT_UINT32( ctx->state[6], digest, 24 );
PUT_UINT32( ctx->state[7], digest, 28 );
}
void sha256_hash(const char *input, char *output, unsigned int len)
{
if(!len) len = strlen((const char *)input);
sha256_context ctx;
sha256_starts(&ctx);
sha256_update(&ctx, (uint8 *)input, len);
sha256_finish(&ctx, (unsigned char *)output);
}
void sha256_double_hash(const char *input, char *output, unsigned int len)
{
char output1[32];
sha256_hash(input, output1, len);
sha256_hash(output1, output, 32);
}

440
stratum/algos/sha256.h Normal file
View file

@ -0,0 +1,440 @@
#ifndef SHA256_H
#define SHA256_H
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
#include "stdint.h"
#else
#include <stdint.h>
#endif
#include <string.h>
static __inline uint32_t
be32dec(const void *pp)
{
const uint8_t *p = (uint8_t const *)pp;
return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
}
static __inline void
be32enc(void *pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[3] = x & 0xff;
p[2] = (x >> 8) & 0xff;
p[1] = (x >> 16) & 0xff;
p[0] = (x >> 24) & 0xff;
}
static __inline uint32_t
le32dec(const void *pp)
{
const uint8_t *p = (uint8_t const *)pp;
return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
}
static __inline void
le32enc(void *pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[0] = x & 0xff;
p[1] = (x >> 8) & 0xff;
p[2] = (x >> 16) & 0xff;
p[3] = (x >> 24) & 0xff;
}
typedef struct SHA256Context {
uint32_t state[8];
uint32_t count[2];
unsigned char buf[64];
} SHA256_CTX;
typedef struct HMAC_SHA256Context {
SHA256_CTX ictx;
SHA256_CTX octx;
} HMAC_SHA256_CTX;
/*
* Encode a length len/4 vector of (uint32_t) into a length len vector of
* (unsigned char) in big-endian form. Assumes len is a multiple of 4.
*/
static void
be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
be32enc(dst + i * 4, src[i]);
}
/*
* Decode a big-endian length len vector of (unsigned char) into a length
* len/4 vector of (uint32_t). Assumes len is a multiple of 4.
*/
static void
be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
dst[i] = be32dec(src + i * 4);
}
/* Elementary functions used by SHA256 */
#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
#define Maj(x, y, z) ((x & (y | z)) | (y & z))
#define SHR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
/* SHA256 round function */
#define RND(a, b, c, d, e, f, g, h, k) \
t0 = h + S1(e) + Ch(e, f, g) + k; \
t1 = S0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
/* Adjusted round function for rotating state */
#define RNDr(S, W, i, k) \
RND(S[(64 - i) % 8], S[(65 - i) % 8], \
S[(66 - i) % 8], S[(67 - i) % 8], \
S[(68 - i) % 8], S[(69 - i) % 8], \
S[(70 - i) % 8], S[(71 - i) % 8], \
W[i] + k)
/*
* SHA256 block compression function. The 256-bit state is transformed via
* the 512-bit input block to produce a new state.
*/
static void
SHA256_Transform(uint32_t * state, const unsigned char block[64])
{
uint32_t W[64];
uint32_t S[8];
uint32_t t0, t1;
int i;
/* 1. Prepare message schedule W. */
be32dec_vect(W, block, 64);
for (i = 16; i < 64; i++)
W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
/* 2. Initialize working variables. */
memcpy(S, state, 32);
/* 3. Mix. */
RNDr(S, W, 0, 0x428a2f98);
RNDr(S, W, 1, 0x71374491);
RNDr(S, W, 2, 0xb5c0fbcf);
RNDr(S, W, 3, 0xe9b5dba5);
RNDr(S, W, 4, 0x3956c25b);
RNDr(S, W, 5, 0x59f111f1);
RNDr(S, W, 6, 0x923f82a4);
RNDr(S, W, 7, 0xab1c5ed5);
RNDr(S, W, 8, 0xd807aa98);
RNDr(S, W, 9, 0x12835b01);
RNDr(S, W, 10, 0x243185be);
RNDr(S, W, 11, 0x550c7dc3);
RNDr(S, W, 12, 0x72be5d74);
RNDr(S, W, 13, 0x80deb1fe);
RNDr(S, W, 14, 0x9bdc06a7);
RNDr(S, W, 15, 0xc19bf174);
RNDr(S, W, 16, 0xe49b69c1);
RNDr(S, W, 17, 0xefbe4786);
RNDr(S, W, 18, 0x0fc19dc6);
RNDr(S, W, 19, 0x240ca1cc);
RNDr(S, W, 20, 0x2de92c6f);
RNDr(S, W, 21, 0x4a7484aa);
RNDr(S, W, 22, 0x5cb0a9dc);
RNDr(S, W, 23, 0x76f988da);
RNDr(S, W, 24, 0x983e5152);
RNDr(S, W, 25, 0xa831c66d);
RNDr(S, W, 26, 0xb00327c8);
RNDr(S, W, 27, 0xbf597fc7);
RNDr(S, W, 28, 0xc6e00bf3);
RNDr(S, W, 29, 0xd5a79147);
RNDr(S, W, 30, 0x06ca6351);
RNDr(S, W, 31, 0x14292967);
RNDr(S, W, 32, 0x27b70a85);
RNDr(S, W, 33, 0x2e1b2138);
RNDr(S, W, 34, 0x4d2c6dfc);
RNDr(S, W, 35, 0x53380d13);
RNDr(S, W, 36, 0x650a7354);
RNDr(S, W, 37, 0x766a0abb);
RNDr(S, W, 38, 0x81c2c92e);
RNDr(S, W, 39, 0x92722c85);
RNDr(S, W, 40, 0xa2bfe8a1);
RNDr(S, W, 41, 0xa81a664b);
RNDr(S, W, 42, 0xc24b8b70);
RNDr(S, W, 43, 0xc76c51a3);
RNDr(S, W, 44, 0xd192e819);
RNDr(S, W, 45, 0xd6990624);
RNDr(S, W, 46, 0xf40e3585);
RNDr(S, W, 47, 0x106aa070);
RNDr(S, W, 48, 0x19a4c116);
RNDr(S, W, 49, 0x1e376c08);
RNDr(S, W, 50, 0x2748774c);
RNDr(S, W, 51, 0x34b0bcb5);
RNDr(S, W, 52, 0x391c0cb3);
RNDr(S, W, 53, 0x4ed8aa4a);
RNDr(S, W, 54, 0x5b9cca4f);
RNDr(S, W, 55, 0x682e6ff3);
RNDr(S, W, 56, 0x748f82ee);
RNDr(S, W, 57, 0x78a5636f);
RNDr(S, W, 58, 0x84c87814);
RNDr(S, W, 59, 0x8cc70208);
RNDr(S, W, 60, 0x90befffa);
RNDr(S, W, 61, 0xa4506ceb);
RNDr(S, W, 62, 0xbef9a3f7);
RNDr(S, W, 63, 0xc67178f2);
/* 4. Mix local working variables into global state */
for (i = 0; i < 8; i++)
state[i] += S[i];
/* Clean the stack. */
memset(W, 0, 256);
memset(S, 0, 32);
t0 = t1 = 0;
}
static unsigned char PAD[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* SHA-256 initialization. Begins a SHA-256 operation. */
static void
SHA256_Init(SHA256_CTX * ctx)
{
/* Zero bits processed so far */
ctx->count[0] = ctx->count[1] = 0;
/* Magic initialization constants */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
/* Add bytes into the hash */
static void
SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
{
uint32_t bitlen[2];
uint32_t r;
const unsigned char *src = (const unsigned char *)in;
/* Number of bytes left in the buffer from previous updates */
r = (ctx->count[1] >> 3) & 0x3f;
/* Convert the length into a number of bits */
bitlen[1] = ((uint32_t)len) << 3;
bitlen[0] = (uint32_t)(len >> 29);
/* Update number of bits */
if ((ctx->count[1] += bitlen[1]) < bitlen[1])
ctx->count[0]++;
ctx->count[0] += bitlen[0];
/* Handle the case where we don't need to perform any transforms */
if (len < 64 - r) {
memcpy(&ctx->buf[r], src, len);
return;
}
/* Finish the current block */
memcpy(&ctx->buf[r], src, 64 - r);
SHA256_Transform(ctx->state, ctx->buf);
src += 64 - r;
len -= 64 - r;
/* Perform complete blocks */
while (len >= 64) {
SHA256_Transform(ctx->state, src);
src += 64;
len -= 64;
}
/* Copy left over data into buffer */
memcpy(ctx->buf, src, len);
}
/* Add padding and terminating bit-count. */
static void
SHA256_Pad(SHA256_CTX * ctx)
{
unsigned char len[8];
uint32_t r, plen;
/*
* Convert length to a vector of bytes -- we do this now rather
* than later because the length will change after we pad.
*/
be32enc_vect(len, ctx->count, 8);
/* Add 1--64 bytes so that the resulting length is 56 mod 64 */
r = (ctx->count[1] >> 3) & 0x3f;
plen = (r < 56) ? (56 - r) : (120 - r);
SHA256_Update(ctx, PAD, (size_t)plen);
/* Add the terminating bit-count */
SHA256_Update(ctx, len, 8);
}
/*
* SHA-256 finalization. Pads the input data, exports the hash value,
* and clears the context state.
*/
static void
SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
{
/* Add padding */
SHA256_Pad(ctx);
/* Write the hash */
be32enc_vect(digest, ctx->state, 32);
/* Clear the context state */
memset((void *)ctx, 0, sizeof(*ctx));
}
/* Initialize an HMAC-SHA256 operation with the given key. */
static void
HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
{
unsigned char pad[64];
unsigned char khash[32];
const unsigned char * K = (const unsigned char *)_K;
size_t i;
/* If Klen > 64, the key is really SHA256(K). */
if (Klen > 64) {
SHA256_Init(&ctx->ictx);
SHA256_Update(&ctx->ictx, K, Klen);
SHA256_Final(khash, &ctx->ictx);
K = khash;
Klen = 32;
}
/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
SHA256_Init(&ctx->ictx);
memset(pad, 0x36, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
SHA256_Update(&ctx->ictx, pad, 64);
/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
SHA256_Init(&ctx->octx);
memset(pad, 0x5c, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
SHA256_Update(&ctx->octx, pad, 64);
/* Clean the stack. */
memset(khash, 0, 32);
}
/* Add bytes to the HMAC-SHA256 operation. */
static void
HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len)
{
/* Feed data to the inner SHA256 operation. */
SHA256_Update(&ctx->ictx, in, len);
}
/* Finish an HMAC-SHA256 operation. */
static void
HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx)
{
unsigned char ihash[32];
/* Finish the inner SHA256 operation. */
SHA256_Final(ihash, &ctx->ictx);
/* Feed the inner hash to the outer SHA256 operation. */
SHA256_Update(&ctx->octx, ihash, 32);
/* Finish the outer SHA256 operation. */
SHA256_Final(digest, &ctx->octx);
/* Clean the stack. */
memset(ihash, 0, 32);
}
/**
* PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
* Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
* write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
*/
static void
PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
{
HMAC_SHA256_CTX PShctx, hctx;
size_t i;
uint8_t ivec[4];
uint8_t U[32];
uint8_t T[32];
uint64_t j;
int k;
size_t clen;
/* Compute HMAC state after processing P and S. */
HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
HMAC_SHA256_Update(&PShctx, salt, saltlen);
/* Iterate through the blocks. */
for (i = 0; i * 32 < dkLen; i++) {
/* Generate INT(i + 1). */
be32enc(ivec, (uint32_t)(i + 1));
/* Compute U_1 = PRF(P, S || INT(i)). */
memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
HMAC_SHA256_Update(&hctx, ivec, 4);
HMAC_SHA256_Final(U, &hctx);
/* T_i = U_1 ... */
memcpy(T, U, 32);
for (j = 2; j <= c; j++) {
/* Compute U_j. */
HMAC_SHA256_Init(&hctx, passwd, passwdlen);
HMAC_SHA256_Update(&hctx, U, 32);
HMAC_SHA256_Final(U, &hctx);
/* ... xor U_j ... */
for (k = 0; k < 32; k++)
T[k] ^= U[k];
}
/* Copy as many bytes as necessary into buf. */
clen = dkLen - i * 32;
if (clen > 32)
clen = 32;
memcpy(&buf[i * 32], T, clen);
}
/* Clean PShctx, since we never called _Final on it. */
memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));
}
#endif

27
stratum/algos/skein.c Normal file
View file

@ -0,0 +1,27 @@
#include "skein.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_skein.h"
#include "sha256.h"
#include <stdlib.h>
void skein_hash(const char* input, char* output, uint32_t len)
{
char temp[64];
sph_skein512_context ctx_skien;
sph_skein512_init(&ctx_skien);
sph_skein512(&ctx_skien, input, len);
sph_skein512_close(&ctx_skien, &temp);
SHA256_CTX ctx_sha256;
SHA256_Init(&ctx_sha256);
SHA256_Update(&ctx_sha256, &temp, 64);
SHA256_Final((unsigned char*) output, &ctx_sha256);
}

16
stratum/algos/skein.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef SKEIN_H
#define SKEIN_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void skein_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,44 @@
#include "x15.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_bmw.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#include "../sha3/sph_luffa.h"
#include "../sha3/sph_cubehash.h"
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
#include "../sha3/sph_hamsi.h"
#include "../sha3/sph_fugue.h"
#include "../sha3/sph_shabal.h"
#include "../sha3/sph_whirlpool.h"
void whirlpoolx_hash(const char* input, char* output, uint32_t len)
{
unsigned char hash[64];
memset(hash, 0, sizeof(hash));
sph_whirlpool_context ctx_whirlpool;
sph_whirlpool_init(&ctx_whirlpool);
sph_whirlpool(&ctx_whirlpool, input, len);
sph_whirlpool_close(&ctx_whirlpool, hash);
unsigned char hash_xored[sizeof(hash) / 2];
uint32_t i;
for (i = 0; i < (sizeof(hash) / 2); i++)
{
hash_xored[i] = hash[i] ^ hash[i + ((sizeof(hash) / 2) / 2)];
}
memcpy(output, hash_xored, 32);
}

View file

@ -0,0 +1,16 @@
#ifndef WHIRLPOOLX_H
#define WHIRLPOOLX_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void whirlpoolx_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

85
stratum/algos/x11.c Normal file
View file

@ -0,0 +1,85 @@
#include "x11.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_bmw.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#include "../sha3/sph_luffa.h"
#include "../sha3/sph_cubehash.h"
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
void x11_hash(const char* input, char* output, uint32_t len)
{
sph_blake512_context ctx_blake;
sph_bmw512_context ctx_bmw;
sph_groestl512_context ctx_groestl;
sph_skein512_context ctx_skein;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
sph_luffa512_context ctx_luffa1;
sph_cubehash512_context ctx_cubehash1;
sph_shavite512_context ctx_shavite1;
sph_simd512_context ctx_simd1;
sph_echo512_context ctx_echo1;
//these uint512 in the c++ source of the client are backed by an array of uint32
uint32_t hashA[16], hashB[16];
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, input, len);
sph_blake512_close (&ctx_blake, hashA);
sph_bmw512_init(&ctx_bmw);
sph_bmw512 (&ctx_bmw, hashA, 64);
sph_bmw512_close(&ctx_bmw, hashB);
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hashB, 64);
sph_groestl512_close(&ctx_groestl, hashA);
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hashA, 64);
sph_skein512_close (&ctx_skein, hashB);
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hashB, 64);
sph_jh512_close(&ctx_jh, hashA);
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, hashA, 64);
sph_keccak512_close(&ctx_keccak, hashB);
sph_luffa512_init (&ctx_luffa1);
sph_luffa512 (&ctx_luffa1, hashB, 64);
sph_luffa512_close (&ctx_luffa1, hashA);
sph_cubehash512_init (&ctx_cubehash1);
sph_cubehash512 (&ctx_cubehash1, hashA, 64);
sph_cubehash512_close(&ctx_cubehash1, hashB);
sph_shavite512_init (&ctx_shavite1);
sph_shavite512 (&ctx_shavite1, hashB, 64);
sph_shavite512_close(&ctx_shavite1, hashA);
sph_simd512_init (&ctx_simd1);
sph_simd512 (&ctx_simd1, hashA, 64);
sph_simd512_close(&ctx_simd1, hashB);
sph_echo512_init (&ctx_echo1);
sph_echo512 (&ctx_echo1, hashB, 64);
sph_echo512_close(&ctx_echo1, hashA);
memcpy(output, hashA, 32);
}

16
stratum/algos/x11.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef X11_H
#define X11_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void x11_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

98
stratum/algos/x13.c Normal file
View file

@ -0,0 +1,98 @@
#include "x13.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_bmw.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#include "../sha3/sph_luffa.h"
#include "../sha3/sph_cubehash.h"
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
#include "../sha3/sph_hamsi.h"
#include "../sha3/sph_fugue.h"
void x13_hash(const char* input, char* output, uint32_t len)
{
sph_blake512_context ctx_blake;
sph_bmw512_context ctx_bmw;
sph_groestl512_context ctx_groestl;
sph_skein512_context ctx_skein;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
sph_luffa512_context ctx_luffa1;
sph_cubehash512_context ctx_cubehash1;
sph_shavite512_context ctx_shavite1;
sph_simd512_context ctx_simd1;
sph_echo512_context ctx_echo1;
sph_hamsi512_context ctx_hamsi1;
sph_fugue512_context ctx_fugue1;
//these uint512 in the c++ source of the client are backed by an array of uint32
uint32_t hashA[16], hashB[16];
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, input, len);
sph_blake512_close (&ctx_blake, hashA);
sph_bmw512_init(&ctx_bmw);
sph_bmw512 (&ctx_bmw, hashA, 64);
sph_bmw512_close(&ctx_bmw, hashB);
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hashB, 64);
sph_groestl512_close(&ctx_groestl, hashA);
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hashA, 64);
sph_skein512_close (&ctx_skein, hashB);
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hashB, 64);
sph_jh512_close(&ctx_jh, hashA);
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, hashA, 64);
sph_keccak512_close(&ctx_keccak, hashB);
sph_luffa512_init (&ctx_luffa1);
sph_luffa512 (&ctx_luffa1, hashB, 64);
sph_luffa512_close (&ctx_luffa1, hashA);
sph_cubehash512_init (&ctx_cubehash1);
sph_cubehash512 (&ctx_cubehash1, hashA, 64);
sph_cubehash512_close(&ctx_cubehash1, hashB);
sph_shavite512_init (&ctx_shavite1);
sph_shavite512 (&ctx_shavite1, hashB, 64);
sph_shavite512_close(&ctx_shavite1, hashA);
sph_simd512_init (&ctx_simd1);
sph_simd512 (&ctx_simd1, hashA, 64);
sph_simd512_close(&ctx_simd1, hashB);
sph_echo512_init (&ctx_echo1);
sph_echo512 (&ctx_echo1, hashB, 64);
sph_echo512_close(&ctx_echo1, hashA);
sph_hamsi512_init (&ctx_hamsi1);
sph_hamsi512 (&ctx_hamsi1, hashA, 64);
sph_hamsi512_close(&ctx_hamsi1, hashB);
sph_fugue512_init (&ctx_fugue1);
sph_fugue512 (&ctx_fugue1, hashB, 64);
sph_fugue512_close(&ctx_fugue1, hashA);
memcpy(output, hashA, 32);
}

16
stratum/algos/x13.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef X13_H
#define X13_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void x13_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

102
stratum/algos/x14.c Normal file
View file

@ -0,0 +1,102 @@
#include "x14.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_bmw.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#include "../sha3/sph_luffa.h"
#include "../sha3/sph_cubehash.h"
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
#include "../sha3/sph_hamsi.h"
#include "../sha3/sph_fugue.h"
#include "../sha3/sph_shabal.h"
#include "../sha3/sph_whirlpool.h"
void x14_hash(const char* input, char* output, uint32_t len)
{
sph_blake512_context ctx_blake;
sph_bmw512_context ctx_bmw;
sph_groestl512_context ctx_groestl;
sph_skein512_context ctx_skein;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
sph_luffa512_context ctx_luffa1;
sph_cubehash512_context ctx_cubehash1;
sph_shavite512_context ctx_shavite1;
sph_simd512_context ctx_simd1;
sph_echo512_context ctx_echo1;
sph_hamsi512_context ctx_hamsi1;
sph_fugue512_context ctx_fugue1;
sph_shabal512_context ctx_shabal1;
sph_whirlpool_context ctx_whirlpool1;
//these uint512 in the c++ source of the client are backed by an array of uint32
uint32_t hashA[16], hashB[16];
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, input, len);
sph_blake512_close (&ctx_blake, hashA);
sph_bmw512_init(&ctx_bmw);
sph_bmw512 (&ctx_bmw, hashA, 64);
sph_bmw512_close(&ctx_bmw, hashB);
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hashB, 64);
sph_groestl512_close(&ctx_groestl, hashA);
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hashA, 64);
sph_skein512_close (&ctx_skein, hashB);
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hashB, 64);
sph_jh512_close(&ctx_jh, hashA);
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, hashA, 64);
sph_keccak512_close(&ctx_keccak, hashB);
sph_luffa512_init (&ctx_luffa1);
sph_luffa512 (&ctx_luffa1, hashB, 64);
sph_luffa512_close (&ctx_luffa1, hashA);
sph_cubehash512_init (&ctx_cubehash1);
sph_cubehash512 (&ctx_cubehash1, hashA, 64);
sph_cubehash512_close(&ctx_cubehash1, hashB);
sph_shavite512_init (&ctx_shavite1);
sph_shavite512 (&ctx_shavite1, hashB, 64);
sph_shavite512_close(&ctx_shavite1, hashA);
sph_simd512_init (&ctx_simd1);
sph_simd512 (&ctx_simd1, hashA, 64);
sph_simd512_close(&ctx_simd1, hashB);
sph_echo512_init (&ctx_echo1);
sph_echo512 (&ctx_echo1, hashB, 64);
sph_echo512_close(&ctx_echo1, hashA);
sph_hamsi512_init (&ctx_hamsi1);
sph_hamsi512 (&ctx_hamsi1, hashA, 64);
sph_hamsi512_close(&ctx_hamsi1, hashB);
sph_fugue512_init (&ctx_fugue1);
sph_fugue512 (&ctx_fugue1, hashB, 64);
sph_fugue512_close(&ctx_fugue1, hashA);
sph_shabal512_init (&ctx_shabal1);
sph_shabal512 (&ctx_shabal1, hashA, 64);
sph_shabal512_close(&ctx_shabal1, hashB);
memcpy(output, hashB, 32);
}

16
stratum/algos/x14.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef X14_H
#define X14_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void x14_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

106
stratum/algos/x15.c Normal file
View file

@ -0,0 +1,106 @@
#include "x15.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_bmw.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#include "../sha3/sph_luffa.h"
#include "../sha3/sph_cubehash.h"
#include "../sha3/sph_shavite.h"
#include "../sha3/sph_simd.h"
#include "../sha3/sph_echo.h"
#include "../sha3/sph_hamsi.h"
#include "../sha3/sph_fugue.h"
#include "../sha3/sph_shabal.h"
#include "../sha3/sph_whirlpool.h"
void x15_hash(const char* input, char* output, uint32_t len)
{
sph_blake512_context ctx_blake;
sph_bmw512_context ctx_bmw;
sph_groestl512_context ctx_groestl;
sph_skein512_context ctx_skein;
sph_jh512_context ctx_jh;
sph_keccak512_context ctx_keccak;
sph_luffa512_context ctx_luffa1;
sph_cubehash512_context ctx_cubehash1;
sph_shavite512_context ctx_shavite1;
sph_simd512_context ctx_simd1;
sph_echo512_context ctx_echo1;
sph_hamsi512_context ctx_hamsi1;
sph_fugue512_context ctx_fugue1;
sph_shabal512_context ctx_shabal1;
sph_whirlpool_context ctx_whirlpool1;
//these uint512 in the c++ source of the client are backed by an array of uint32
uint32_t hashA[16], hashB[16];
sph_blake512_init(&ctx_blake);
sph_blake512 (&ctx_blake, input, len);
sph_blake512_close (&ctx_blake, hashA);
sph_bmw512_init(&ctx_bmw);
sph_bmw512 (&ctx_bmw, hashA, 64);
sph_bmw512_close(&ctx_bmw, hashB);
sph_groestl512_init(&ctx_groestl);
sph_groestl512 (&ctx_groestl, hashB, 64);
sph_groestl512_close(&ctx_groestl, hashA);
sph_skein512_init(&ctx_skein);
sph_skein512 (&ctx_skein, hashA, 64);
sph_skein512_close (&ctx_skein, hashB);
sph_jh512_init(&ctx_jh);
sph_jh512 (&ctx_jh, hashB, 64);
sph_jh512_close(&ctx_jh, hashA);
sph_keccak512_init(&ctx_keccak);
sph_keccak512 (&ctx_keccak, hashA, 64);
sph_keccak512_close(&ctx_keccak, hashB);
sph_luffa512_init (&ctx_luffa1);
sph_luffa512 (&ctx_luffa1, hashB, 64);
sph_luffa512_close (&ctx_luffa1, hashA);
sph_cubehash512_init (&ctx_cubehash1);
sph_cubehash512 (&ctx_cubehash1, hashA, 64);
sph_cubehash512_close(&ctx_cubehash1, hashB);
sph_shavite512_init (&ctx_shavite1);
sph_shavite512 (&ctx_shavite1, hashB, 64);
sph_shavite512_close(&ctx_shavite1, hashA);
sph_simd512_init (&ctx_simd1);
sph_simd512 (&ctx_simd1, hashA, 64);
sph_simd512_close(&ctx_simd1, hashB);
sph_echo512_init (&ctx_echo1);
sph_echo512 (&ctx_echo1, hashB, 64);
sph_echo512_close(&ctx_echo1, hashA);
sph_hamsi512_init (&ctx_hamsi1);
sph_hamsi512 (&ctx_hamsi1, hashA, 64);
sph_hamsi512_close(&ctx_hamsi1, hashB);
sph_fugue512_init (&ctx_fugue1);
sph_fugue512 (&ctx_fugue1, hashB, 64);
sph_fugue512_close(&ctx_fugue1, hashA);
sph_shabal512_init (&ctx_shabal1);
sph_shabal512 (&ctx_shabal1, hashA, 64);
sph_shabal512_close(&ctx_shabal1, hashB);
sph_whirlpool_init (&ctx_whirlpool1);
sph_whirlpool (&ctx_whirlpool1, hashB, 64);
sph_whirlpool_close(&ctx_whirlpool1, hashA);
memcpy(output, hashA, 32);
}

16
stratum/algos/x15.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef X15_H
#define X15_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void x15_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

104
stratum/algos/zr5.c Normal file
View file

@ -0,0 +1,104 @@
#include "x15.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "../sha3/sph_blake.h"
#include "../sha3/sph_groestl.h"
#include "../sha3/sph_jh.h"
#include "../sha3/sph_keccak.h"
#include "../sha3/sph_skein.h"
#define ZR_BLAKE 0
#define ZR_GROESTL 1
#define ZR_JH 2
#define ZR_SKEIN 3
#define POK_BOOL_MASK 0x00008000
#define POK_DATA_MASK 0xFFFF0000
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static const int permut[][4] = {
{0, 1, 2, 3},
{0, 1, 3, 2},
{0, 2, 1, 3},
{0, 2, 3, 1},
{0, 3, 1, 2},
{0, 3, 2, 1},
{1, 0, 2, 3},
{1, 0, 3, 2},
{1, 2, 0, 3},
{1, 2, 3, 0},
{1, 3, 0, 2},
{1, 3, 2, 0},
{2, 0, 1, 3},
{2, 0, 3, 1},
{2, 1, 0, 3},
{2, 1, 3, 0},
{2, 3, 0, 1},
{2, 3, 1, 0},
{3, 0, 1, 2},
{3, 0, 2, 1},
{3, 1, 0, 2},
{3, 1, 2, 0},
{3, 2, 0, 1},
{3, 2, 1, 0}
};
void zr5_hash(const char* input, char* output, uint32_t len)
{
sph_keccak512_context ctx_keccak;
sph_blake512_context ctx_blake;
sph_groestl512_context ctx_groestl;
sph_jh512_context ctx_jh;
sph_skein512_context ctx_skein;
uint32_t hash[5][16];
char *ph = (char *)hash;
sph_keccak512_init(&ctx_keccak);
sph_keccak512(&ctx_keccak, (const void*) input, len);
sph_keccak512_close(&ctx_keccak, (void*) &hash[0][0]);
unsigned int norder = hash[0][0] % ARRAY_SIZE(permut); /* % 24 */
int i;
for(i=0; i<len; i++) printf("%02x", (unsigned char)input[i]); printf("\n");
for(i=0; i<32; i++) printf("%02x", (unsigned char)ph[i]); printf("\n");
for(i = 0; i < 4; i++)
{
void* phash = (void*) &(hash[i][0]);
void* pdest = (void*) &(hash[i+1][0]);
printf("permut %d\n", permut[norder][i]);
switch (permut[norder][i]) {
case ZR_BLAKE:
sph_blake512_init(&ctx_blake);
sph_blake512(&ctx_blake, (const void*) phash, 64);
sph_blake512_close(&ctx_blake, pdest);
break;
case ZR_GROESTL:
sph_groestl512_init(&ctx_groestl);
sph_groestl512(&ctx_groestl, (const void*) phash, 64);
sph_groestl512_close(&ctx_groestl, pdest);
break;
case ZR_JH:
sph_jh512_init(&ctx_jh);
sph_jh512(&ctx_jh, (const void*) phash, 64);
sph_jh512_close(&ctx_jh, pdest);
break;
case ZR_SKEIN:
sph_skein512_init(&ctx_skein);
sph_skein512(&ctx_skein, (const void*) phash, 64);
sph_skein512_close(&ctx_skein, pdest);
break;
default:
break;
}
}
memcpy(output, &hash[4], 32);
}

17
stratum/algos/zr5.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef ZR5_H
#define ZR5_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void zr5_hash(const char* input, char* output, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif

99
stratum/base58.cpp Normal file
View file

@ -0,0 +1,99 @@
/*
* Copyright 2012 Luke Dashjr
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details.
*/
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static const int8_t b58digits[] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) {
const unsigned char *b58u = (const unsigned char*)b58;
unsigned char *binu = (unsigned char *)bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = ~((1 << ((bytesleft) * 8)) - 1);
if (!b58sz)
b58sz = strlen(b58);
memset(outi, 0, outisz * sizeof(*outi));
for (i = 0; i < b58sz; ++i)
{
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = b58digits[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
}
for (; j < outisz; ++j)
{
*((uint32_t*)binu) = htonl(outi[j]);
binu += sizeof(uint32_t);
}
return true;
}
bool base58_decode(const char *input, char *output)
{
unsigned char output_bin[25];
bool b = _blkmk_b58tobin(output_bin, sizeof(output_bin), input, 0);
if(!b) return false;
output[0] = 0;
for(int i=1; i < 21; i++)
sprintf(output+strlen(output), "%02x", output_bin[i]);
return true;
}

432
stratum/client.cpp Normal file
View file

@ -0,0 +1,432 @@
#include "stratum.h"
//#define CLIENT_DEBUGLOG_
bool client_suggest_difficulty(YAAMP_CLIENT *client, json_value *json_params)
{
if(json_params->u.array.length>0)
{
double diff = client_normalize_difficulty(json_params->u.array.values[0]->u.dbl);
uint64_t user_target = diff_to_target(diff);
if(user_target >= YAAMP_MINDIFF && user_target <= YAAMP_MAXDIFF)
client->difficulty_actual = diff;
}
client_send_result(client, "true");
return true;
}
bool client_suggest_target(YAAMP_CLIENT *client, json_value *json_params)
{
client_send_result(client, "true");
return true;
}
bool client_subscribe(YAAMP_CLIENT *client, json_value *json_params)
{
if(client_find_my_ip(client->sock->ip)) return false;
get_next_extraonce1(client->extranonce1_default);
client->extranonce2size_default = YAAMP_EXTRANONCE2_SIZE;
client->difficulty_actual = g_stratum_difficulty;
strcpy(client->extranonce1, client->extranonce1_default);
client->extranonce2size = client->extranonce2size_default;
get_random_key(client->notify_id);
if(json_params->u.array.length>0)
{
strncpy(client->version, json_params->u.array.values[0]->u.string.ptr, 1023);
// if(!strcmp(client->version, "stratum-proxy/0.0.1")) return false;
if(strstr(client->version, "NiceHash") || strstr(client->version, "proxy") || strstr(client->version, "/3."))
client->reconnectable = false;
}
if(json_params->u.array.length>1)
{
char notify_id[1024];
strncpy(notify_id, json_params->u.array.values[1]->u.string.ptr, 1023);
YAAMP_CLIENT *client1 = client_find_notify_id(notify_id, true);
if(client1)
{
strncpy(client->notify_id, notify_id, 1023);
client->jobid_locked = client1->jobid_locked;
// client->jobid_next = client1->jobid_next;
client->difficulty_actual = client1->difficulty_actual;
client->extranonce2size_default = client1->extranonce2size_default;
strcpy(client->extranonce1_default, client1->extranonce1_default);
client->extranonce2size = client1->extranonce2size_reconnect;
strcpy(client->extranonce1, client1->extranonce1_reconnect);
client->speed = client1->speed;
client->extranonce1_id = client1->extranonce1_id;
client->userid = client1->userid;
client->workerid = client1->workerid;
memcpy(client->job_history, client1->job_history, sizeof(client->job_history));
client1->lock_count = 0;
#ifdef CLIENT_DEBUGLOG_
debuglog("reconnecting client locked to %x\n", client->jobid_next);
#endif
}
else
{
YAAMP_CLIENT *client1 = client_find_notify_id(notify_id, false);
if(client1)
{
strncpy(client->notify_id, notify_id, 1023);
client->difficulty_actual = client1->difficulty_actual;
client->speed = client1->speed;
memcpy(client->job_history, client1->job_history, sizeof(client->job_history));
client1->lock_count = 0;
#ifdef CLIENT_DEBUGLOG_
debuglog("reconnecting2 client\n");
#endif
}
}
}
strcpy(client->extranonce1_last, client->extranonce1);
client->extranonce2size_last = client->extranonce2size;
#ifdef CLIENT_DEBUGLOG_
debuglog("new client with nonce %s\n", client->extranonce1);
#endif
client_send_result(client, "[[[\"mining.set_difficulty\",\"%s\"],[\"mining.notify\",\"%s\"]],\"%s\",%d]",
client->notify_id, client->notify_id, client->extranonce1, client->extranonce2size);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////
bool client_authorize(YAAMP_CLIENT *client, json_value *json_params)
{
if(json_params->u.array.length>1)
strncpy(client->password, json_params->u.array.values[1]->u.string.ptr, 1023);
if(json_params->u.array.length>0)
{
strncpy(client->username, json_params->u.array.values[0]->u.string.ptr, 1023);
client->username[34] = 0;
strncpy(client->worker, client->username+35, 1023);
// debuglog("%s\n", client->username);
// debuglog("%s\n", client->worker);
}
bool reset = client_initialize_multialgo(client);
if(reset) return false;
client_initialize_difficulty(client);
if(!client->userid || !client->workerid)
{
CommonLock(&g_db_mutex);
db_add_user(g_db, client);
if(client->userid == -1)
{
CommonUnlock(&g_db_mutex);
// client_block_ip(client, "account locked");
clientlog(client, "account locked");
return false;
}
db_add_worker(g_db, client);
CommonUnlock(&g_db_mutex);
}
#ifdef CLIENT_DEBUGLOG_
debuglog("new client %s, %s, %s\n", client->username, client->password, client->version);
#endif
client_send_result(client, "true");
client_send_difficulty(client, client->difficulty_actual);
if(client->jobid_locked)
job_send_jobid(client, client->jobid_locked);
else
job_send_last(client);
g_list_client.AddTail(client);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////
bool client_update_block(YAAMP_CLIENT *client, json_value *json_params)
{
// password, id, block
if(json_params->u.array.length < 3)
{
clientlog(client, "update block, bad params");
return false;
}
if(strcmp(g_tcp_password, json_params->u.array.values[0]->u.string.ptr))
{
clientlog(client, "update block, bad password");
return false;
}
YAAMP_COIND *coind = (YAAMP_COIND *)object_find(&g_list_coind, json_params->u.array.values[1]->u.integer, true);
if(!coind) return false;
#ifdef CLIENT_DEBUGLOG_
debuglog("new block for %s ", coind->name);
debuglog("%s\n", json_params->u.array.values[2]->u.string.ptr);
#endif
coind->newblock = true;
coind->notreportingcounter = 0;
block_confirm(coind->id, json_params->u.array.values[2]->u.string.ptr);
coind_create_job(coind);
object_unlock(coind);
if(coind->isaux) for(CLI li = g_list_coind.first; li; li = li->next)
{
YAAMP_COIND *coind = (YAAMP_COIND *)li->data;
if(!coind_can_mine(coind)) continue;
if(coind->pos) continue;
coind_create_job(coind);
}
job_signal();
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////
//YAAMP_SOURCE *source_init(YAAMP_CLIENT *client)
//{
// YAAMP_SOURCE *source = NULL;
// g_list_source.Enter();
//
// for(CLI li = g_list_source.first; li; li = li->next)
// {
// YAAMP_SOURCE *source1 = (YAAMP_SOURCE *)li->data;
// if(!strcmp(source1->ip, client->sock->ip))
// {
// source = source1;
// break;
// }
// }
//
// if(!source)
// {
// source = new YAAMP_SOURCE;
// memset(source, 0, sizeof(YAAMP_SOURCE));
//
// strncpy(source->ip, client->sock->ip, 1024);
// source->speed = 1;
//
// g_list_source.AddTail(source);
// }
//
// source->count++;
//
// g_list_source.Leave();
// return source;
//}
//
//void source_close(YAAMP_SOURCE *source)
//{
// g_list_source.Enter();
// source->count--;
//
// if(source->count <= 0)
// {
// g_list_source.Delete(source);
// delete source;
// }
//
// g_list_source.Leave();
//}
//
//void source_prune()
//{
//// debuglog("source_prune() %d\n", g_list_source.count);
// g_list_source.Enter();
// for(CLI li = g_list_source.first; li; li = li->next)
// {
// YAAMP_SOURCE *source = (YAAMP_SOURCE *)li->data;
// source->speed *= 0.8;
//
// double idx = source->speed/source->count;
// if(idx < 0.0005)
// {
// stratumlog("disconnect all ip %s, %s, count %d, %f, %f\n", source->ip, g_current_algo->name, source->count, source->speed, idx);
// for(CLI li = g_list_client.first; li; li = li->next)
// {
// YAAMP_CLIENT *client = (YAAMP_CLIENT *)li->data;
// if(client->deleted) continue;
// if(!client->workerid) continue;
//
// if(!strcmp(source->ip, client->sock->ip))
// shutdown(client->sock->sock, SHUT_RDWR);
// }
// }
//
// else if(source->count > 500)
// stratumlog("over 500 ip %s, %s, %d, %f, %f\n", source->ip, g_current_algo->name, source->count, source->speed, idx);
// }
//
// g_list_source.Leave();
//}
///////////////////////////////////////////////////////////////////////////////////////////
void *client_thread(void *p)
{
YAAMP_CLIENT *client = new YAAMP_CLIENT;
memset(client, 0, sizeof(YAAMP_CLIENT));
client->reconnectable = true;
client->speed = 1;
client->created = time(NULL);
client->last_best = time(NULL);
client->sock = socket_initialize((int)(long)p);
// client->source = source_init(client);
client->shares_per_minute = YAAMP_SHAREPERSEC;
client->last_submit_time = current_timestamp();
while(1)
{
if(client->submit_bad > 1024)
{
clientlog(client, "bad submits");
break;
}
json_value *json = socket_nextjson(client->sock, client);
if(!json)
{
// clientlog(client, "bad json");
break;
}
client->id_int = json_get_int(json, "id");
client->id_str = json_get_string(json, "id");
const char *method = json_get_string(json, "method");
if(!method)
{
json_value_free(json);
clientlog(client, "bad json, no method");
break;
}
json_value *json_params = json_get_array(json, "params");
if(!json_params)
{
json_value_free(json);
clientlog(client, "bad json, no params");
break;
}
#ifdef CLIENT_DEBUGLOG_
debuglog("client %s %d %s\n", method, client->id_int, client->id_str? client->id_str: "null");
#endif
bool b = false;
if(!strcmp(method, "mining.subscribe"))
b = client_subscribe(client, json_params);
else if(!strcmp(method, "mining.authorize"))
b = client_authorize(client, json_params);
else if(!strcmp(method, "mining.submit"))
b = client_submit(client, json_params);
else if(!strcmp(method, "mining.suggest_difficulty"))
b = client_suggest_difficulty(client, json_params);
else if(!strcmp(method, "mining.suggest_target"))
b = client_suggest_target(client, json_params);
else if(!strcmp(method, "mining.get_transactions"))
b = client_send_result(client, "[]");
else if(!strcmp(method, "mining.extranonce.subscribe"))
{
client->extranonce_subscribe = true;
b = client_send_result(client, "true");
}
else if(!strcmp(method, "mining.update_block"))
client_update_block(client, json_params);
else if(!strcmp(method, "getwork"))
{
clientlog(client, "using getwork");
break;
}
else
{
b = client_send_error(client, 20, "Not supported");
client->submit_bad++;
stratumlog("unknown method %s %s\n", method, client->sock->ip);
}
json_value_free(json);
if(!b) break;
}
// source_close(client->source);
#ifdef CLIENT_DEBUGLOG_
debuglog("client terminate\n");
#endif
if(client->sock->total_read == 0)
clientlog(client, "no data");
if(g_list_client.Find(client))
{
if(client->workerid && !client->reconnecting)
{
CommonLock(&g_db_mutex);
db_clear_worker(g_db, client);
CommonUnlock(&g_db_mutex);
}
object_delete(client);
}
else
client_delete(client);
pthread_exit(NULL);
}

142
stratum/client.h Normal file
View file

@ -0,0 +1,142 @@
//struct YAAMP_SOURCE
//{
//public:
// int count;
// double speed;
//
// char ip[1024];
//};
struct YAAMP_ALGO
{
char name[1024];
YAAMP_HASH_FUNCTION hash_function;
double diff_multiplier;
double factor;
double profit;
double rent;
bool overflow;
};
struct YAAMP_CLIENT_ALGO
{
double factor;
YAAMP_ALGO *algo;
};
#define YAAMP_JOB_MAXHISTORY 16
class YAAMP_CLIENT: public YAAMP_OBJECT
{
public:
YAAMP_SOCKET *sock;
// YAAMP_SOURCE *source;
char notify_id[1024];
int created;
int last_best;
bool reconnectable;
bool reconnecting;
int userid;
int workerid;
bool logtraffic;
int id_int;
const char *id_str;
char version[1024];
char username[1024];
char password[1024];
char worker[1024];
double difficulty_actual;
double difficulty_remote;
double difficulty_written;
bool difficulty_fixed;
long long last_submit_time;
double shares_per_minute;
char extranonce1[32];
int extranonce2size;
char extranonce1_default[32];
int extranonce2size_default;
char extranonce1_last[32];
int extranonce2size_last;
char extranonce1_reconnect[32];
int extranonce2size_reconnect;
bool extranonce_subscribe;
int submit_bad;
double speed;
int extranonce1_id;
int jobid_next;
int jobid_sent;
int jobid_locked;
YAAMP_CLIENT_ALGO algos_subscribed[YAAMP_MAXALGOS];
int job_history[YAAMP_JOB_MAXHISTORY];
};
inline void client_delete(YAAMP_OBJECT *object)
{
YAAMP_CLIENT *client = (YAAMP_CLIENT *)object;
socket_close(client->sock);
delete client;
}
//////////////////////////////////////////////////////////////////////////
YAAMP_CLIENT *client_find_notify_id(const char *notify_id, bool reconnecting);
void get_next_extraonce1(char *extraonce1);
void get_random_key(char *key);
void client_sort();
void client_block_ip(YAAMP_CLIENT *client, const char *reason);
bool client_reset_multialgo(YAAMP_CLIENT *client, bool first);
bool client_initialize_multialgo(YAAMP_CLIENT *client);
void client_add_job_history(YAAMP_CLIENT *client, int jobid);
bool client_find_job_history(YAAMP_CLIENT *client, int jobid, int startat=1);
bool client_find_my_ip(const char *ip);
//////////////////////////////////////////////////////////////////////////
int client_send_difficulty(YAAMP_CLIENT *client, double difficulty);
double client_normalize_difficulty(double difficulty);
void client_change_difficulty(YAAMP_CLIENT *client, double difficulty);
void client_record_difficulty(YAAMP_CLIENT *client);
void client_adjust_difficulty(YAAMP_CLIENT *client);
void client_initialize_difficulty(YAAMP_CLIENT *client);
//////////////////////////////////////////////////////////////////////////
int client_call(YAAMP_CLIENT *client, const char *method, const char *format, ...);
void client_dump_all();
int client_send_result(YAAMP_CLIENT *client, const char *format, ...);
int client_send_error(YAAMP_CLIENT *client, int error, const char *string);
bool client_submit(YAAMP_CLIENT *client, json_value *json_params);
void *client_thread(void *p);
//void source_prune();

312
stratum/client_core.cpp Normal file
View file

@ -0,0 +1,312 @@
#include "stratum.h"
static int g_extraonce1_counter = 0;
void get_next_extraonce1(char *extraonce1)
{
CommonLock(&g_nonce1_mutex);
g_extraonce1_counter++;
sprintf(extraonce1, "%08x", g_extraonce1_counter|0x81000000);
CommonUnlock(&g_nonce1_mutex);
}
void get_random_key(char *key)
{
int i1 = rand();
int i2 = rand();
int i3 = rand();
int i4 = rand();
sprintf(key, "%08x%08x%08x%08x", i1, i2, i3, i4);
}
YAAMP_CLIENT *client_find_notify_id(const char *notify_id, bool reconnecting)
{
g_list_client.Enter();
for(CLI li = g_list_client.first; li; li = li->next)
{
YAAMP_CLIENT *client = (YAAMP_CLIENT *)li->data;
if(client->reconnecting == reconnecting && !strcmp(client->notify_id, notify_id))
{
g_list_client.Leave();
return client;
}
}
g_list_client.Leave();
return NULL;
}
void client_sort()
{
for(CLI li = g_list_client.first; li && li->next; li = li->next)
{
YAAMP_CLIENT *client1 = (YAAMP_CLIENT *)li->data;
YAAMP_CLIENT *client2 = (YAAMP_CLIENT *)li->next->data;
// if(client2->difficulty_actual > client1->difficulty_actual)
if(client2->speed > client1->speed*1.5)
{
g_list_client.Swap(li, li->next);
client_sort();
return;
}
}
}
int client_send_error(YAAMP_CLIENT *client, int error, const char *string)
{
char buffer3[1024];
if(client->id_str)
sprintf(buffer3, "\"%s\"", client->id_str);
else
sprintf(buffer3, "%d", client->id_int);
return socket_send(client->sock, "{\"id\":%s,\"result\":false,\"error\":[%d,\"%s\",null]}\n", buffer3, error, string);
}
int client_send_result(YAAMP_CLIENT *client, const char *format, ...)
{
char buffer[YAAMP_SMALLBUFSIZE];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
char buffer3[1024];
if(client->id_str)
sprintf(buffer3, "\"%s\"", client->id_str);
else
sprintf(buffer3, "%d", client->id_int);
return socket_send(client->sock, "{\"id\":%s,\"result\":%s,\"error\":null}\n", buffer3, buffer);
}
int client_call(YAAMP_CLIENT *client, const char *method, const char *format, ...)
{
char buffer[YAAMP_SMALLBUFSIZE];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
return socket_send(client->sock, "{\"id\":null,\"method\":\"%s\",\"params\":%s}\n", method, buffer);
}
void client_block_ip(YAAMP_CLIENT *client, const char *reason)
{
char buffer[1024];
sprintf(buffer, "iptables -A INPUT -s %s -j DROP", client->sock->ip);
int s = system(buffer);
stratumlog("%s %s blocked (%s)\n", client->sock->ip, client->username, reason);
}
bool client_reset_multialgo(YAAMP_CLIENT *client, bool first)
{
// return false;
if(!client->algos_subscribed[0].algo) return false;
// debuglog("client_reset_multialgo\n");
YAAMP_CLIENT_ALGO *best = NULL;
YAAMP_CLIENT_ALGO *current = NULL;
for(int i=0; g_algos[i].name[0]; i++)
{
YAAMP_ALGO *algo = &g_algos[i];
for(int j=0; client->algos_subscribed[j].algo; j++)
{
YAAMP_CLIENT_ALGO *candidate = &client->algos_subscribed[j];
if(candidate->algo == algo)
{
if(!best || algo->profit*candidate->factor > best->algo->profit*best->factor)
best = candidate;
}
if(!current && candidate->algo == g_current_algo)
current = candidate;
}
}
if(!best || !current || best == current)
{
client->last_best = time(NULL);
return false;
}
if(!first)
{
int e = time(NULL) - client->last_best;
double d = best->algo->profit*best->factor - current->algo->profit*current->factor;
double p = d/best->algo->profit/best->factor;
// debuglog("current %s %f\n", current->algo->name, current->algo->profit*current->factor);
// debuglog("best %s %f\n", best->algo->name, best->algo->profit*best->factor);
// debuglog(" %d * %f = %f --- percent %f %f\n", e, d, e*d, p, e*p);
if(p < 0.02) return false;
if(e*p < 100) return false;
}
shutdown(client->sock->sock, SHUT_RDWR);
return true;
}
bool client_initialize_multialgo(YAAMP_CLIENT *client)
{
char *p = strstr(client->password, "p=");
if(p)
{
double profit = atof(p+2);
if(profit > g_current_algo->profit)
return true;
}
char tmp[1024];
memset(tmp, 0, 1024);
strncpy(tmp, client->password, 1023);
p = tmp;
while(p)
{
double value = 0;
char *p1 = strchr(p, ',');
if(p1) *p1 = 0;
char *p2 = strchr(p, '=');
if(p2)
{
*p2 = 0;
value = atof(p2+1);
}
for(int i=0; g_algos[i].name[0]; i++)
{
YAAMP_ALGO *algo = &g_algos[i];
if(!strcmp(algo->name, p))
{
int i=0;
for(; i<YAAMP_MAXALGOS-1 && client->algos_subscribed[i].algo; i++);
client->algos_subscribed[i].algo = algo;
client->algos_subscribed[i].factor = value? value: algo->factor;
}
}
p = p1? p1+1: p1;
}
bool reset = client_reset_multialgo(client, true);
return reset;
}
void client_add_job_history(YAAMP_CLIENT *client, int jobid)
{
if(!jobid)
{
debuglog("trying to add jobid 0\n");
return;
}
bool b = client_find_job_history(client, jobid, 0);
if(b)
{
// debuglog("ERROR history already added job %x\n", jobid);
return;
}
for(int i=YAAMP_JOB_MAXHISTORY-1; i>0; i--)
client->job_history[i] = client->job_history[i-1];
client->job_history[0] = jobid;
}
bool client_find_job_history(YAAMP_CLIENT *client, int jobid, int startat)
{
for(int i=startat; i<YAAMP_JOB_MAXHISTORY; i++)
{
if(client->job_history[i] == jobid)
{
// if(!startat)
// debuglog("job %x already sent, index %d\n", jobid, i);
return true;
}
}
return false;
}
int hostname_to_ip(const char *hostname , char* ip)
{
struct hostent *he;
struct in_addr **addr_list;
int i;
if(hostname[0]>='0' && hostname[0]<='9')
{
strcpy(ip, hostname);
return 0;
}
if ( (he = gethostbyname( hostname ) ) == NULL)
{
// get the host info
herror("gethostbyname");
return 1;
}
addr_list = (struct in_addr **) he->h_addr_list;
for(i = 0; addr_list[i] != NULL; i++)
{
//Return the first one;
strcpy(ip, inet_ntoa(*addr_list[i]));
return 0;
}
return 1;
}
bool client_find_my_ip(const char *name)
{
// return false;
char ip[1024] = "";
hostname_to_ip(name, ip);
if(!ip[0]) return false;
char host[NI_MAXHOST];
for(struct ifaddrs *ifa = g_ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if(ifa->ifa_addr == NULL) continue;
host[0] = 0;
getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if(!host[0]) continue;
if(!strcmp(host, ip))
{
debuglog("found my ip %s\n", ip);
return true;
}
}
return false;
}

View file

@ -0,0 +1,105 @@
#include "stratum.h"
double client_normalize_difficulty(double difficulty)
{
if(difficulty <= 0.001) difficulty = 0.001;
else if(difficulty < 1) difficulty = floor(difficulty*1000/2)/1000*2;
else if(difficulty > 1) difficulty = floor(difficulty/2)*2;
return difficulty;
}
void client_record_difficulty(YAAMP_CLIENT *client)
{
if(client->difficulty_remote)
{
client->last_submit_time = current_timestamp();
return;
}
int e = current_timestamp() - client->last_submit_time;
if(e < 500) e = 500;
int p = 5;
client->shares_per_minute = (client->shares_per_minute * (100 - p) + 60*1000*p/e) / 100;
client->last_submit_time = current_timestamp();
// debuglog("client->shares_per_minute %f\n", client->shares_per_minute);
}
void client_change_difficulty(YAAMP_CLIENT *client, double difficulty)
{
if(difficulty <= 0) return;
difficulty = client_normalize_difficulty(difficulty);
if(difficulty <= 0) return;
// debuglog("change diff to %f %f\n", difficulty, client->difficulty_actual);
if(difficulty == client->difficulty_actual) return;
uint64_t user_target = diff_to_target(difficulty);
if(user_target >= YAAMP_MINDIFF && user_target <= YAAMP_MAXDIFF)
{
client->difficulty_actual = difficulty;
client_send_difficulty(client, difficulty);
}
}
void client_adjust_difficulty(YAAMP_CLIENT *client)
{
if(client->difficulty_remote)
{
client_change_difficulty(client, client->difficulty_remote);
return;
}
if(client->shares_per_minute > 600)
client_change_difficulty(client, client->difficulty_actual*4);
else if(client->difficulty_fixed)
return;
else if(client->shares_per_minute > 25)
client_change_difficulty(client, client->difficulty_actual*2);
else if(client->shares_per_minute > 20)
client_change_difficulty(client, client->difficulty_actual*1.5);
else if(client->shares_per_minute < 5)
client_change_difficulty(client, client->difficulty_actual/2);
}
int client_send_difficulty(YAAMP_CLIENT *client, double difficulty)
{
// debuglog("%s diff %f\n", client->sock->ip, difficulty);
client->shares_per_minute = YAAMP_SHAREPERSEC;
if(difficulty >= 1)
client_call(client, "mining.set_difficulty", "[%.0f]", difficulty);
else
client_call(client, "mining.set_difficulty", "[%.3f]", difficulty);
}
void client_initialize_difficulty(YAAMP_CLIENT *client)
{
char *p = strstr(client->password, "d=");
if(!p) return;
double diff = client_normalize_difficulty(atof(p+2));
uint64_t user_target = diff_to_target(diff);
// debuglog("%016llx target\n", user_target);
if(user_target >= YAAMP_MINDIFF && user_target <= YAAMP_MAXDIFF)
{
client->difficulty_actual = diff;
client->difficulty_fixed = true;
}
}

304
stratum/client_submit.cpp Normal file
View file

@ -0,0 +1,304 @@
#include "stratum.h"
//#define DONTSUBMIT
void build_submit_values(YAAMP_JOB_VALUES *submitvalues, YAAMP_JOB_TEMPLATE *templ,
const char *nonce1, const char *nonce2, const char *ntime, const char *nonce)
{
sprintf(submitvalues->coinbase, "%s%s%s%s", templ->coinb1, nonce1, nonce2, templ->coinb2);
int coinbase_len = strlen(submitvalues->coinbase);
unsigned char coinbase_bin[1024];
memset(coinbase_bin, 0, 1024);
binlify(coinbase_bin, submitvalues->coinbase);
char doublehash[128];
memset(doublehash, 0, 128);
sha256_double_hash_hex((char *)coinbase_bin, doublehash, coinbase_len/2);
string merkleroot = merkle_with_first(templ->txsteps, doublehash);
ser_string_be(merkleroot.c_str(), submitvalues->merkleroot_be, 8);
sprintf(submitvalues->header, "%s%s%s%s%s%s", templ->version, templ->prevhash_be, submitvalues->merkleroot_be,
ntime, templ->nbits, nonce);
ser_string_be(submitvalues->header, submitvalues->header_be, 20);
binlify(submitvalues->header_bin, submitvalues->header_be);
// printf("%s\n", submitvalues->header_be);
int header_len = strlen(submitvalues->header)/2;
g_current_algo->hash_function((char *)submitvalues->header_bin, (char *)submitvalues->hash_bin, header_len);
hexlify(submitvalues->hash_hex, submitvalues->hash_bin, 32);
string_be(submitvalues->hash_hex, submitvalues->hash_be);
}
/////////////////////////////////////////////////////////////////////////////////
void client_do_submit(YAAMP_CLIENT *client, YAAMP_JOB *job, YAAMP_JOB_VALUES *submitvalues, char *extranonce2, char *ntime, char *nonce)
{
YAAMP_COIND *coind = job->coind;
YAAMP_JOB_TEMPLATE *templ = job->templ;
if(job->block_found) return;
if(job->deleted) return;
uint64_t hash_int = get_hash_difficulty(submitvalues->hash_bin);
uint64_t coin_target = decode_compact(templ->nbits);
int block_size = YAAMP_SMALLBUFSIZE;
vector<string>::const_iterator i;
for(i = templ->txdata.begin(); i != templ->txdata.end(); ++i)
block_size += strlen((*i).c_str());
char *block_hex = (char *)malloc(block_size);
if(!block_hex) return;
// do aux first
for(int i=0; i<templ->auxs_size; i++)
{
if(!templ->auxs[i]) continue;
YAAMP_COIND *coind_aux = templ->auxs[i]->coind;
unsigned char target_aux[1024];
binlify(target_aux, coind_aux->aux.target);
uint64_t coin_target_aux = get_hash_difficulty(target_aux);
if(hash_int <= coin_target_aux)
{
memset(block_hex, 0, block_size);
strcat(block_hex, submitvalues->coinbase); // parent coinbase
strcat(block_hex, submitvalues->hash_be); // parent hash
////////////////////////////////////////////////// parent merkle steps
sprintf(block_hex+strlen(block_hex), "%02x", (unsigned char)templ->txsteps.size());
vector<string>::const_iterator i;
for(i = templ->txsteps.begin(); i != templ->txsteps.end(); ++i)
sprintf(block_hex + strlen(block_hex), "%s", (*i).c_str());
strcat(block_hex, "00000000");
////////////////////////////////////////////////// auxs merkle steps
vector<string> lresult = coind_aux_merkle_branch(templ->auxs, templ->auxs_size, coind_aux->aux.index);
sprintf(block_hex+strlen(block_hex), "%02x", (unsigned char)lresult.size());
for(i = lresult.begin(); i != lresult.end(); ++i)
sprintf(block_hex+strlen(block_hex), "%s", (*i).c_str());
sprintf(block_hex+strlen(block_hex), "%02x000000", (unsigned char)coind_aux->aux.index);
////////////////////////////////////////////////// parent header
strcat(block_hex, submitvalues->header_be);
bool b = coind_submitgetauxblock(coind_aux, coind_aux->aux.hash, block_hex);
if(b)
{
debuglog("*** ACCEPTED %s %d\n", coind_aux->name, coind_aux->height+1);
block_add(client->userid, coind_aux->id, coind_aux->height, target_to_diff(coin_target_aux),
target_to_diff(hash_int), coind_aux->aux.hash, "");
}
else
debuglog("%s %d rejected\n", coind_aux->name, coind_aux->height+1);
}
}
if(hash_int <= coin_target)
{
memset(block_hex, 0, block_size);
sprintf(block_hex, "%s%02x%s", submitvalues->header_be, (unsigned char)templ->txcount, submitvalues->coinbase);
vector<string>::const_iterator i;
for(i = templ->txdata.begin(); i != templ->txdata.end(); ++i)
sprintf(block_hex+strlen(block_hex), "%s", (*i).c_str());
if(coind->txmessage)
strcat(block_hex, "00");
bool b = coind_submit(coind, block_hex);
if(b)
{
debuglog("*** ACCEPTED %s %d\n", coind->name, templ->height);
job->block_found = true;
char doublehash2[128];
memset(doublehash2, 0, 128);
sha256_double_hash_hex((char *)submitvalues->header_bin, doublehash2, strlen(submitvalues->header_be)/2);
char hash1[1024];
memset(hash1, 0, 1024);
string_be(doublehash2, hash1);
block_add(client->userid, coind->id, templ->height, target_to_diff(coin_target), target_to_diff(hash_int),
hash1, submitvalues->hash_be);
// if(!strcmp(coind->symbol, "HAL"))
// {
// debuglog("--------------------------------------------------------------\n");
// debuglog("hash1 %s\n", hash1);
// debuglog("hash2 %s\n", submitvalues->hash_be);
// }
}
else
debuglog("%s %d rejected\n", coind->name, templ->height);
}
free(block_hex);
}
bool dump_submit_debug(const char *title, YAAMP_CLIENT *client, YAAMP_JOB *job, char *extranonce2, char *ntime, char *nonce)
{
debuglog("ERROR %s, %s subs %d, job %x, %s, id %x, %d, %s, %s %s\n",
title, client->sock->ip, client->extranonce_subscribe, job? job->id: 0, client->extranonce1,
client->extranonce1_id, client->extranonce2size, extranonce2, ntime, nonce);
}
void client_submit_error(YAAMP_CLIENT *client, YAAMP_JOB *job, int id, const char *message, char *extranonce2, char *ntime, char *nonce)
{
// if(job->templ->created+2 > time(NULL))
if(job && job->deleted)
client_send_result(client, "true");
else
{
client_send_error(client, id, message);
share_add(client, job, false, extranonce2, ntime, nonce, id);
client->submit_bad++;
// dump_submit_debug(message, client, job, extranonce2, ntime, nonce);
}
object_unlock(job);
}
bool client_submit(YAAMP_CLIENT *client, json_value *json_params)
{
// submit(worker_name, jobid, extranonce2, ntime, nonce):
if(json_params->u.array.length<5)
{
debuglog("%s - %s bad message\n", client->username, client->sock->ip);
client->submit_bad++;
return false;
}
// char name[1024];
char extranonce2[32];
char ntime[32];
char nonce[32];
memset(extranonce2, 0, 32);
memset(ntime, 0, 32);
memset(nonce, 0, 32);
int jobid = htoi(json_params->u.array.values[1]->u.string.ptr);
strncpy(extranonce2, json_params->u.array.values[2]->u.string.ptr, 31);
strncpy(ntime, json_params->u.array.values[3]->u.string.ptr, 31);
strncpy(nonce, json_params->u.array.values[4]->u.string.ptr, 31);
// debuglog("submit %s %d, %s, %s, %s\n", client->sock->ip, jobid, extranonce2, ntime, nonce);
string_lower(extranonce2);
string_lower(ntime);
string_lower(nonce);
YAAMP_JOB *job = (YAAMP_JOB *)object_find(&g_list_job, jobid, true);
if(!job)
{
client_submit_error(client, NULL, 21, "Invalid job id", extranonce2, ntime, nonce);
return true;
}
if(job->deleted)
{
client_send_result(client, "true");
object_unlock(job);
return true;
}
YAAMP_JOB_TEMPLATE *templ = job->templ;
// dump_submit_debug(client, job, extranonce2, ntime, nonce);
if(strlen(nonce) != YAAMP_NONCE_SIZE*2)
{
client_submit_error(client, job, 20, "Invalid nonce size", extranonce2, ntime, nonce);
return true;
}
// if(strcmp(ntime, templ->ntime))
// {
// client_submit_error(client, job, 23, "Invalid time rolling", extranonce2, ntime, nonce);
// return true;
// }
YAAMP_SHARE *share = share_find(job->id, extranonce2, ntime, nonce, client->extranonce1);
if(share)
{
client_submit_error(client, job, 22, "Duplicate share", extranonce2, ntime, nonce);
return true;
}
if(strlen(extranonce2) != client->extranonce2size*2)
{
client_submit_error(client, job, 24, "Invalid extranonce2 size", extranonce2, ntime, nonce);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////
YAAMP_JOB_VALUES submitvalues;
memset(&submitvalues, 0, sizeof(submitvalues));
build_submit_values(&submitvalues, templ, client->extranonce1, extranonce2, ntime, nonce);
if(submitvalues.hash_bin[30] || submitvalues.hash_bin[31])
{
client_submit_error(client, job, 25, "Invalid share", extranonce2, ntime, nonce);
return true;
}
uint64_t hash_int = get_hash_difficulty(submitvalues.hash_bin);
uint64_t user_target = diff_to_target(client->difficulty_actual);
uint64_t coin_target = decode_compact(templ->nbits);
// debuglog("%016llx actual\n", hash_int);
// debuglog("%016llx target\n", user_target);
// debuglog("%016llx coin\n", coin_target);
if(hash_int > user_target && hash_int > coin_target)
{
client_submit_error(client, job, 26, "Low difficulty share", extranonce2, ntime, nonce);
return true;
}
if(job->coind)
client_do_submit(client, job, &submitvalues, extranonce2, ntime, nonce);
else
remote_submit(client, job, &submitvalues, extranonce2, ntime, nonce);
client_send_result(client, "true");
client_record_difficulty(client);
client->submit_bad = 0;
share_add(client, job, true, extranonce2, ntime, nonce, 0);
object_unlock(job);
return true;
}

139
stratum/coinbase.cpp Normal file
View file

@ -0,0 +1,139 @@
// http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html
// https://en.bitcoin.it/wiki/Merged_mining_specification#Merged_mining_coinbase
#include "stratum.h"
#define TX_VALUE(v, s) ((unsigned int)(v>>s)&0xff)
static void encode_tx_value(char *encoded, json_int_t value)
{
sprintf(encoded, "%02x%02x%02x%02x%02x%02x%02x%02x",
TX_VALUE(value, 0), TX_VALUE(value, 8), TX_VALUE(value, 16), TX_VALUE(value, 24),
TX_VALUE(value, 32), TX_VALUE(value, 40), TX_VALUE(value, 48), TX_VALUE(value, 56));
}
static void job_pack_tx(YAAMP_COIND *coind, char *data, json_int_t amount, char *key)
{
int ol = strlen(data);
char evalue[64];
encode_tx_value(evalue, amount);
sprintf(data+strlen(data), "%s", evalue);
if(coind->pos && !key)
sprintf(data+strlen(data), "2321%sac", coind->pubkey);
else
sprintf(data+strlen(data), "1976a914%s88ac", key? key: coind->script_pubkey);
// debuglog("pack tx %s\n", data+ol);
// debuglog("pack tx %lld\n", amount);
}
void coinbase_aux(YAAMP_JOB_TEMPLATE *templ, char *aux_script)
{
vector<string> hashlist = coind_aux_hashlist(templ->auxs, templ->auxs_size);
while(hashlist.size() > 1)
{
vector<string> l;
for(int i = 0; i < hashlist.size()/2; i++)
{
string s = hashlist[i*2] + hashlist[i*2+1];
char bin[YAAMP_HASHLEN_BIN*2];
char out[YAAMP_HASHLEN_STR];
binlify((unsigned char *)bin, s.c_str());
sha256_double_hash_hex(bin, out, YAAMP_HASHLEN_BIN*2);
l.push_back(out);
}
hashlist = l;
}
char merkle_hash[4*1024];
memset(merkle_hash, 0, 4*1024);
string_be(hashlist[0].c_str(), merkle_hash);
sprintf(aux_script+strlen(aux_script), "fabe6d6d%s%02x00000000000000", merkle_hash, templ->auxs_size);
// debuglog("aux_script is %s\n", aux_script);
}
void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value *json_result)
{
char eheight[64];
ser_number(templ->height, eheight);
char etime[64];
ser_number(time(NULL), etime);
char entime[64];
memset(entime, 0, 64);
if(coind->pos)
ser_string_be(templ->ntime, entime, 1);
char eversion1[64] = "01000000";
if(coind->txmessage)
strcpy(eversion1, "02000000");
char script1[4*1024];
sprintf(script1, "%s%s%s08", eheight, templ->flags, etime);
char script2[4*1024] = "7961616d702e636f6d00"; // yaamp.com
if(!coind->pos && !coind->isaux && templ->auxs_size)
coinbase_aux(templ, script2);
int script_len = strlen(script1)/2 + strlen(script2)/2 + 8;
sprintf(templ->coinb1,
"%s%s010000000000000000000000000000000000000000000000000000000000000000ffffffff%02x%s", // 8+8+74+2 -> height
eversion1, entime, script_len, script1);
sprintf(templ->coinb2, "%s00000000", script2);
json_int_t available = templ->value;
if(strcmp(coind->symbol, "DRK") == 0 || strcmp(coind->symbol, "DASH") == 0)
// if(strcmp(coind->symbol, "DRK") == 0)
{
char charity_payee[1024] = "";
strcpy(charity_payee, json_get_string(json_result, "payee"));
json_int_t charity_amount = json_get_int(json_result, "payee_amount");
bool charity_payments = json_get_bool(json_result, "masternode_payments");
bool charity_enforce = json_get_bool(json_result, "enforce_masternode_payments");
if(charity_payments && charity_enforce)
{
strcat(templ->coinb2, "02");
available -= charity_amount;
char script_payee[1024];
base58_decode(charity_payee, script_payee);
job_pack_tx(coind, templ->coinb2, charity_amount, script_payee);
}
else
strcat(templ->coinb2, "01");
}
else
strcat(templ->coinb2, "01");
job_pack_tx(coind, templ->coinb2, available, NULL);
strcat(templ->coinb2, "00000000"); // locktime
coind->reward = (double)available/100000000*coind->reward_mul;
// debuglog("coinbase %f\n", coind->reward);
// debuglog("new job: %x, %s, %s, %s\n", coind->templ->id, coind->templ->version, coind->templ->nbits, coind->templ->ntime);
// debuglog("coinb1 %s\n", templ->coinb1);
// debuglog("coinb2 %s\n", templ->coinb2);
}

188
stratum/coind.cpp Normal file
View file

@ -0,0 +1,188 @@
#include "stratum.h"
void coind_error(YAAMP_COIND *coind, const char *s)
{
coind->auto_ready = false;
object_delete(coind);
debuglog("%s error %s\n", coind->name, s);
}
double coind_profitability(YAAMP_COIND *coind)
{
if(!coind->difficulty) return 0;
if(coind->pool_ttf > g_stratum_max_ttf) return 0;
// double prof = 24*60*60*1000 / (coind->difficulty / 1000000 * 0x100000000) * reward * coind->price;
// double prof = 24*60*60*1000 / coind->difficulty / 4294.967296 * reward * coind->price;
double prof = 20116.56761169 / coind->difficulty * coind->reward * coind->price;
if(!strcmp(g_current_algo->name, "sha256")) prof *= 1000;
if(!coind->isaux && !coind->pos)
{
for(CLI li = g_list_coind.first; li; li = li->next)
{
YAAMP_COIND *aux = (YAAMP_COIND *)li->data;
if(!coind_can_mine(aux, true)) continue;
prof += coind_profitability(aux);
}
}
return prof;
}
double coind_nethash(YAAMP_COIND *coind)
{
double speed = coind->difficulty * 0x100000000 / 1000000 / max(min(coind->actual_ttf, 60), 30);
// if(!strcmp(g_current_algo->name, "sha256")) speed *= 1000;
return speed;
}
void coind_sort()
{
for(CLI li = g_list_coind.first; li && li->next; li = li->next)
{
YAAMP_COIND *coind1 = (YAAMP_COIND *)li->data;
if(coind1->deleted) continue;
YAAMP_COIND *coind2 = (YAAMP_COIND *)li->next->data;
if(coind2->deleted) continue;
double p1 = coind_profitability(coind1);
double p2 = coind_profitability(coind2);
if(p2 > p1)
{
g_list_coind.Swap(li, li->next);
coind_sort();
return;
}
}
}
bool coind_can_mine(YAAMP_COIND *coind, bool isaux)
{
if(coind->deleted) return false;
if(!coind->enable) return false;
if(!coind->auto_ready) return false;
if(!rpc_connected(&coind->rpc)) return false;
if(!coind->height || !coind->difficulty) return false;
if(coind->isaux != isaux) return false;
// if(isaux && !coind->aux.chainid) return false;
// debuglog("can mine %s\n", coind->name);
return true;
}
///////////////////////////////////////////////////////////////////////////////
bool coind_validate_address(YAAMP_COIND *coind)
{
if(!coind->wallet[0]) return false;
char params[YAAMP_SMALLBUFSIZE];
sprintf(params, "[\"%s\"]", coind->wallet);
json_value *json = rpc_call(&coind->rpc, "validateaddress", params);
if(!json) return false;
json_value *json_result = json_get_object(json, "result");
if(!json_result)
{
json_value_free(json);
return false;
}
bool isvalid = json_get_bool(json_result, "isvalid");
if(!isvalid) stratumlog("%s wallet %s is not valid.\n", coind->name, coind->wallet);
bool ismine = json_get_bool(json_result, "ismine");
if(!ismine) stratumlog("%s wallet %s is not mine.\n", coind->name, coind->wallet);
const char *p = json_get_string(json_result, "pubkey");
if(p) strcpy(coind->pubkey, p);
json_value_free(json);
base58_decode(coind->wallet, coind->script_pubkey);
return isvalid && ismine;
}
void coind_init(YAAMP_COIND *coind)
{
yaamp_create_mutex(&coind->mutex);
bool valid = coind_validate_address(coind);
if(valid) return;
json_value *json = rpc_call(&coind->rpc, "getaccountaddress", "[\"\"]");
if(!json)
{
stratumlog("ERROR getaccountaddress %s\n", coind->name);
return;
}
strcpy(coind->wallet, json->u.object.values[0].value->u.string.ptr);
json_value_free(json);
debuglog(">>>>>>>>>>>>>>>>>>>> using wallet %s\n", coind->wallet);
coind_validate_address(coind);
}
///////////////////////////////////////////////////////////////////////////////
//void coind_signal(YAAMP_COIND *coind)
//{
// debuglog("coind_signal %s\n", coind->symbol);
// CommonLock(&coind->mutex);
// pthread_cond_signal(&coind->cond);
// CommonUnlock(&coind->mutex);
//}
//void coind_terminate(YAAMP_COIND *coind)
//{
// debuglog("disconnecting from coind %s\n", coind->symbol);
// rpc_close(&coind->rpc);
// object_delete(coind);
// pthread_mutex_unlock(&coind->mutex);
// pthread_mutex_destroy(&coind->mutex);
// pthread_cond_destroy(&coind->cond);
// pthread_exit(NULL);
//}
//void *coind_thread(void *p)
//{
// YAAMP_COIND *coind = (YAAMP_COIND *)p;
// debuglog("connecting to coind %s\n", coind->symbol);
// bool b = rpc_connect(&coind->rpc);
// if(!b) coind_terminate(coind);
// coind_init(coind);
// CommonLock(&coind->mutex);
// while(!coind->deleted)
// {
// debuglog("calling coind_getinfo %s\n", coind->symbol);
// job_create_last(coind, true);
// pthread_cond_wait(&coind->cond, &coind->mutex);
// }
// coind_terminate(coind);
//}

97
stratum/coind.h Normal file
View file

@ -0,0 +1,97 @@
struct YAAMP_COIND_AUX
{
YAAMP_COIND *coind;
// int height;
int index;
int chainid;
char hash[1024];
char target[1024];
};
class YAAMP_COIND: public YAAMP_OBJECT
{
public:
bool touch;
bool newcoind;
YAAMP_RPC rpc;
// pthread_t thread;
pthread_mutex_t mutex;
// pthread_cond_t cond;
// bool closing;
char name[1024];
char symbol[1024];
char wallet[1024];
char pubkey[1024];
char script_pubkey[1024];
bool pos;
bool hassubmitblock;
bool txmessage;
char charity_address[1024];
double charity_amount;
double charity_percent;
bool enable;
bool auto_ready;
bool newblock;
int height;
double difficulty;
double reward;
double reward_mul;
double price;
int pool_ttf;
int actual_ttf;
bool isaux;
YAAMP_COIND_AUX aux;
int notreportingcounter;
bool usememorypool;
YAAMP_JOB *job;
// YAAMP_JOB_TEMPLATE *templ;
};
//////////////////////////////////////////////////////////////////////////
inline void coind_delete(YAAMP_OBJECT *object)
{
YAAMP_COIND *coind = (YAAMP_COIND *)object;
object_delete(coind->job);
// if(coind->templ) delete coind->templ;
delete coind;
}
void coind_error(YAAMP_COIND *coind, const char *s);
double coind_profitability(YAAMP_COIND *coind);
double coind_nethash(YAAMP_COIND *coind);
bool coind_can_mine(YAAMP_COIND *coind, bool isaux=false);
void coind_sort();
bool coind_submit(YAAMP_COIND *coind, const char *block);
bool coind_submitgetauxblock(YAAMP_COIND *coind, const char *hash, const char *block);
void coind_init(YAAMP_COIND *coind);
//void coind_getauxblock(YAAMP_COIND *coind);
void coind_create_job(YAAMP_COIND *coind, bool force=false);

107
stratum/coind_aux.cpp Normal file
View file

@ -0,0 +1,107 @@
#include "stratum.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
void coind_aux_build_auxs(YAAMP_JOB_TEMPLATE *templ)
{
int len = 0;
for(CLI li = g_list_coind.first; li; li = li->next)
{
YAAMP_COIND *coind = (YAAMP_COIND *)li->data;
if(!coind_can_mine(coind, true)) continue;
// coind_getauxblock(coind);
len++;
}
templ->auxs_size = 0;
memset(templ->auxs, 0, sizeof(templ->auxs));
if(!len) return;
for(int i=0; i<MAX_AUXS; i++)
{
templ->auxs_size = pow(2, i);
if(templ->auxs_size<len) continue;
bool done = true;
for(CLI li = g_list_coind.first; li; li = li->next)
{
YAAMP_COIND *coind = (YAAMP_COIND *)li->data;
if(!coind_can_mine(coind, true)) continue;
int pos = (int)(int64_t)((1103515245 * coind->aux.chainid + 1103515245 * (int64_t)12345 + 12345) % templ->auxs_size);
if(templ->auxs[pos])
{
templ->auxs_size = 0;
memset(templ->auxs, 0, sizeof(templ->auxs));
done = false;
break;
}
coind->aux.index = pos;
templ->auxs[pos] = &coind->aux;
}
if(done) break;
}
}
vector<string> coind_aux_hashlist(YAAMP_COIND_AUX **auxs, int size)
{
vector<string> hashlist;
for(int i=0; i<size; i++)
{
if(auxs[i])
{
char hash_be[1024];
memset(hash_be, 0, 1024);
string_be(auxs[i]->hash, hash_be);
hashlist.push_back(hash_be);
}
else
hashlist.push_back("0000000000000000000000000000000000000000000000000000000000000000");
}
return hashlist;
}
vector<string> coind_aux_merkle_branch(YAAMP_COIND_AUX **auxs, int size, int index)
{
vector<string> hashlist = coind_aux_hashlist(auxs, size);
vector<string> lresult;
while(hashlist.size() > 1)
{
if(index%2)
lresult.push_back(hashlist[index-1]);
else
lresult.push_back(hashlist[index+1]);
vector<string> l;
for(int i = 0; i < hashlist.size()/2; i++)
{
string s = hashlist[i*2] + hashlist[i*2+1];
char bin[YAAMP_HASHLEN_BIN*2];
char out[YAAMP_HASHLEN_STR];
binlify((unsigned char *)bin, s.c_str());
sha256_double_hash_hex(bin, out, YAAMP_HASHLEN_BIN*2);
l.push_back(out);
}
hashlist = l;
index = index/2;
}
return lresult;
}

113
stratum/coind_submit.cpp Normal file
View file

@ -0,0 +1,113 @@
#include "stratum.h"
bool coind_submitblock(YAAMP_COIND *coind, const char *block)
{
int paramlen = strlen(block);
char *params = (char *)malloc(paramlen+1024);
if(!params) return false;
sprintf(params, "[\"%s\"]", block);
json_value *json = rpc_call(&coind->rpc, "submitblock", params);
free(params);
if(!json) return false;
json_value *json_error = json_get_object(json, "error");
if(json_error && json_error->type != json_null)
{
const char *p = json_get_string(json_error, "message");
if(p) stratumlog("ERROR %s %s\n", coind->name, p);
// job_reset();
json_value_free(json);
return false;
}
json_value *json_result = json_get_object(json, "result");
bool b = json_result && json_result->type == json_null;
json_value_free(json);
return b;
}
bool coind_submitblocktemplate(YAAMP_COIND *coind, const char *block)
{
int paramlen = strlen(block);
char *params = (char *)malloc(paramlen+1024);
if(!params) return false;
sprintf(params, "[{\"mode\": \"submit\", \"data\": \"%s\"}]", block);
json_value *json = rpc_call(&coind->rpc, "getblocktemplate", params);
free(params);
if(!json) return false;
json_value *json_error = json_get_object(json, "error");
if(json_error && json_error->type != json_null)
{
const char *p = json_get_string(json_error, "message");
if(p) stratumlog("ERROR %s %s\n", coind->name, p);
// job_reset();
json_value_free(json);
return false;
}
json_value *json_result = json_get_object(json, "result");
bool b = json_result && json_result->type == json_null;
json_value_free(json);
return b;
}
bool coind_submit(YAAMP_COIND *coind, const char *block)
{
bool b;
if(coind->hassubmitblock)
b = coind_submitblock(coind, block);
else
b = coind_submitblocktemplate(coind, block);
return b;
}
bool coind_submitgetauxblock(YAAMP_COIND *coind, const char *hash, const char *block)
{
int paramlen = strlen(block);
char *params = (char *)malloc(paramlen+1024);
if(!params) return false;
sprintf(params, "[\"%s\",\"%s\"]", hash, block);
json_value *json = rpc_call(&coind->rpc, "getauxblock", params);
free(params);
if(!json) return false;
json_value *json_error = json_get_object(json, "error");
if(json_error && json_error->type != json_null)
{
const char *p = json_get_string(json_error, "message");
if(p) stratumlog("ERROR %s %s\n", coind->name, p);
// job_reset();
json_value_free(json);
return false;
}
json_value *json_result = json_get_object(json, "result");
bool b = json_result && json_result->type == json_boolean && json_result->u.boolean;
json_value_free(json);
return b;
}

309
stratum/coind_template.cpp Normal file
View file

@ -0,0 +1,309 @@
#include "stratum.h"
void coind_getauxblock(YAAMP_COIND *coind)
{
if(!coind->isaux) return;
json_value *json = rpc_call(&coind->rpc, "getauxblock", "[]");
if(!json)
{
coind_error(coind, "coind_getauxblock");
return;
}
json_value *json_result = json_get_object(json, "result");
if(!json_result)
{
coind_error(coind, "coind_getauxblock");
return;
}
// coind->aux.height = coind->height+1;
coind->aux.chainid = json_get_int(json_result, "chainid");
const char *p = json_get_string(json_result, "target");
if(p) strcpy(coind->aux.target, p);
p = json_get_string(json_result, "hash");
if(p) strcpy(coind->aux.hash, p);
// if(strcmp(coind->symbol, "UNO") == 0)
// {
// string_be1(coind->aux.target);
// string_be1(coind->aux.hash);
// }
json_value_free(json);
}
YAAMP_JOB_TEMPLATE *coind_create_template_memorypool(YAAMP_COIND *coind)
{
json_value *json = rpc_call(&coind->rpc, "getmemorypool");
if(!json || json->type == json_null)
{
coind_error(coind, "getmemorypool");
return NULL;
}
json_value *json_result = json_get_object(json, "result");
if(!json_result || json_result->type == json_null)
{
coind_error(coind, "getmemorypool");
json_value_free(json);
return NULL;
}
YAAMP_JOB_TEMPLATE *templ = new YAAMP_JOB_TEMPLATE;
memset(templ, 0, sizeof(YAAMP_JOB_TEMPLATE));
templ->created = time(NULL);
templ->value = json_get_int(json_result, "coinbasevalue");
// templ->height = json_get_int(json_result, "height");
sprintf(templ->version, "%08x", (unsigned int)json_get_int(json_result, "version"));
sprintf(templ->ntime, "%08x", (unsigned int)json_get_int(json_result, "time"));
strcpy(templ->nbits, json_get_string(json_result, "bits"));
strcpy(templ->prevhash_hex, json_get_string(json_result, "previousblockhash"));
json_value_free(json);
json = rpc_call(&coind->rpc, "getinfo", "[]");
if(!json || json->type == json_null)
{
coind_error(coind, "coind_getinfo");
return NULL;
}
json_result = json_get_object(json, "result");
if(!json_result || json_result->type == json_null)
{
coind_error(coind, "coind_getinfo");
json_value_free(json);
return NULL;
}
templ->height = json_get_int(json_result, "blocks")+1;
json_value_free(json);
if(coind->isaux)
coind_getauxblock(coind);
coind->usememorypool = true;
return templ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
YAAMP_JOB_TEMPLATE *coind_create_template(YAAMP_COIND *coind)
{
if(coind->usememorypool)
return coind_create_template_memorypool(coind);
char params[4*1024] = "[{}]";
if(!strcmp(coind->symbol, "PPC")) strcpy(params, "[]");
json_value *json = rpc_call(&coind->rpc, "getblocktemplate", params);
if(!json || json->type == json_null)
{
coind_error(coind, "getblocktemplate");
return NULL;
}
json_value *json_result = json_get_object(json, "result");
if(!json_result || json_result->type == json_null)
{
coind_error(coind, "getblocktemplate");
json_value_free(json);
return NULL;
}
json_value *json_tx = json_get_array(json_result, "transactions");
if(!json_tx)
{
coind_error(coind, "getblocktemplate");
json_value_free(json);
return NULL;
}
json_value *json_coinbaseaux = json_get_object(json_result, "coinbaseaux");
if(!json_coinbaseaux)
{
coind_error(coind, "getblocktemplate");
json_value_free(json);
return NULL;
}
YAAMP_JOB_TEMPLATE *templ = new YAAMP_JOB_TEMPLATE;
memset(templ, 0, sizeof(YAAMP_JOB_TEMPLATE));
templ->created = time(NULL);
templ->value = json_get_int(json_result, "coinbasevalue");
templ->height = json_get_int(json_result, "height");
sprintf(templ->version, "%08x", (unsigned int)json_get_int(json_result, "version"));
sprintf(templ->ntime, "%08x", (unsigned int)json_get_int(json_result, "curtime"));
strcpy(templ->nbits, json_get_string(json_result, "bits"));
strcpy(templ->prevhash_hex, json_get_string(json_result, "previousblockhash"));
strcpy(templ->flags, json_get_string(json_coinbaseaux, "flags"));
// debuglog("%s ntime %s\n", coind->symbol, templ->ntime);
// uint64_t target = decode_compact(json_get_string(json_result, "bits"));
// coind->difficulty = target_to_diff(target);
// string_lower(templ->ntime);
// string_lower(templ->nbits);
// char target[1024];
// strcpy(target, json_get_string(json_result, "target"));
// uint64_t coin_target = decode_compact(templ->nbits);
// debuglog("%s\n", templ->nbits);
// debuglog("%s\n", target);
// debuglog("0000%016llx\n", coin_target);
if(coind->isaux)
{
json_value_free(json);
coind_getauxblock(coind);
return templ;
}
//////////////////////////////////////////////////////////////////////////////////////////
vector<string> txhashes;
txhashes.push_back("");
for(int i = 0; i < json_tx->u.array.length; i++)
{
const char *p = json_get_string(json_tx->u.array.values[i], "hash");
char hash_be[1024];
memset(hash_be, 0, 1024);
string_be(p, hash_be);
txhashes.push_back(hash_be);
const char *d = json_get_string(json_tx->u.array.values[i], "data");
templ->txdata.push_back(d);
}
templ->txmerkles[0] = 0;
templ->txcount = txhashes.size();
templ->txsteps = merkle_steps(txhashes);
vector<string>::const_iterator i;
for(i = templ->txsteps.begin(); i != templ->txsteps.end(); ++i)
sprintf(templ->txmerkles + strlen(templ->txmerkles), "\"%s\",", (*i).c_str());
if(templ->txmerkles[0])
templ->txmerkles[strlen(templ->txmerkles)-1] = 0;
// debuglog("merkle transactions %d [%s]\n", templ->txcount, templ->txmerkles);
ser_string_be2(templ->prevhash_hex, templ->prevhash_be, 8);
if(!coind->pos)
coind_aux_build_auxs(templ);
coinbase_create(coind, templ, json_result);
json_value_free(json);
return templ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void coind_create_job(YAAMP_COIND *coind, bool force)
{
// debuglog("create job %s\n", coind->symbol);
bool b = rpc_connected(&coind->rpc);
if(!b) return;
CommonLock(&coind->mutex);
YAAMP_JOB_TEMPLATE *templ = coind_create_template(coind);
if(!templ)
{
CommonUnlock(&coind->mutex);
return;
}
YAAMP_JOB *job_last = coind->job;
if( !force && job_last && job_last->templ && job_last->templ->created + 45 > time(NULL) &&
templ->height == job_last->templ->height &&
templ->txcount == job_last->templ->txcount &&
strcmp(templ->coinb2, job_last->templ->coinb2) == 0)
{
// debuglog("coind_create_job %s %d same template %x \n", coind->name, coind->height, coind->job->id);
delete templ;
CommonUnlock(&coind->mutex);
return;
}
////////////////////////////////////////////////////////////////////////////////////////
int height = coind->height;
coind->height = templ->height-1;
if(height > coind->height)
{
stratumlog("%s went from %d to %d\n", coind->name, height, coind->height);
// coind->auto_ready = false;
}
if(height < coind->height && !coind->newblock)
{
if(coind->auto_ready && coind->notreportingcounter++ > 5)
stratumlog("%s %d not reporting\n", coind->name, coind->height);
}
uint64_t coin_target = decode_compact(templ->nbits);
coind->difficulty = target_to_diff(coin_target);
coind->newblock = false;
////////////////////////////////////////////////////////////////////////////////////////
object_delete(coind->job);
coind->job = new YAAMP_JOB;
memset(coind->job, 0, sizeof(YAAMP_JOB));
sprintf(coind->job->name, "%s", coind->symbol);
coind->job->id = job_get_jobid();
coind->job->templ = templ;
coind->job->profit = coind_profitability(coind);
coind->job->maxspeed = coind_nethash(coind) *
(g_current_algo->profit? min(1.0, coind_profitability(coind)/g_current_algo->profit): 1);
coind->job->coind = coind;
coind->job->remote = NULL;
g_list_job.AddTail(coind->job);
CommonUnlock(&coind->mutex);
// debuglog("coind_create_job %s %d new job %x\n", coind->name, coind->height, coind->job->id);
}

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4533
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = blake
difficulty = 1
max_ttf = 4000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4133
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = fresh
difficulty = 4
max_ttf = 4000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 5033
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = groestl
difficulty = 0.1
max_ttf = 200000000000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 5133
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = keccak
difficulty = 0.1
max_ttf = 200000000000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4433
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = lyra2
difficulty = 0.1
max_ttf = 40000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4233
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = neoscrypt
difficulty = 32
max_ttf = 400000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 3833
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = nist5
difficulty = 0.032
max_ttf = 4000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4033
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = quark
difficulty = 0.01
max_ttf = 200000000000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4733
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = qubit
difficulty = 0.01
max_ttf = 200000000000000

12
stratum/config.sample/run.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
ulimit -n 10240
ulimit -u 10240
cd /var/stratum
while true; do
./stratum /var/yaamp/config/$1
sleep 2
done
exec bash

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 3433
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = scrypt
difficulty = 128
max_ttf = 40000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4333
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = scryptn
difficulty = 32
max_ttf = 4000000000

View file

@ -0,0 +1,17 @@
[TCP]
server = yaamp.com
port = 3333
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = sha256
difficulty = 512
max_ttf = 40000
reconnect = 1

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 4933
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = skein
difficulty = 0.1
max_ttf = 200000000000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 3533
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = x11
difficulty = 0.016
max_ttf = 40000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 3633
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = x13
difficulty = 0.008
max_ttf = 50000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 3933
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = x14
difficulty = 0.004
max_ttf = 200000000000000

View file

@ -0,0 +1,16 @@
[TCP]
server = yaamp.com
port = 3733
password = tu8tu5
[SQL]
host = yaampdb
database = yaamp
username = root
password = patofpaq
[STRATUM]
algo = x15
difficulty = 0.008
max_ttf = 50000

12
stratum/config/run.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
ulimit -n 10240
ulimit -u 10240
cd /var/stratum
while true; do
./stratum config/$1
sleep 2
done
exec bash

418
stratum/db.cpp Normal file
View file

@ -0,0 +1,418 @@
#include "stratum.h"
#include <signal.h>
void db_reconnect(YAAMP_DB *db)
{
mysql_init(&db->mysql);
for(int i=0; i<6; i++)
{
MYSQL *p = mysql_real_connect(&db->mysql, g_sql_host, g_sql_username, g_sql_password, g_sql_database, 0, 0, 0);
if(p) break;
stratumlog("%d, %s\n", i, mysql_error(&db->mysql));
sleep(10);
mysql_init(&db->mysql);
}
}
YAAMP_DB *db_connect()
{
YAAMP_DB *db = new YAAMP_DB;
db_reconnect(db);
return db;
}
void db_close(YAAMP_DB *db)
{
mysql_close(&db->mysql);
delete db;
}
char *db_clean_string(YAAMP_DB *db, char *string)
{
string[1000] = 0;
char tmp[1024];
unsigned long ret = mysql_real_escape_string(&db->mysql, tmp, string, strlen(string));
strcpy(string, tmp);
return string;
}
void db_query(YAAMP_DB *db, const char *format, ...)
{
va_list arglist;
va_start(arglist, format);
char *buffer = (char *)malloc(YAAMP_SMALLBUFSIZE+strlen(format));
if(!buffer) return;
int len = vsprintf(buffer, format, arglist);
va_end(arglist);
while(1)
{
int res = mysql_query(&db->mysql, buffer);
if(!res) break;
res = mysql_errno(&db->mysql);
stratumlog("SQL ERROR: %d, %s\n", res, mysql_error(&db->mysql));
if(res != CR_SERVER_GONE_ERROR && res != CR_SERVER_LOST) exit(1);
db_reconnect(db);
}
free(buffer);
}
///////////////////////////////////////////////////////////////////////
void db_register_stratum(YAAMP_DB *db)
{
int pid = getpid();
int t = time(NULL);
db_query(db, "insert into stratums (pid, time, algo) values (%d, %d, '%s') on duplicate key update time=%d",
pid, t, g_current_algo->name, t);
}
void db_update_algos(YAAMP_DB *db)
{
if(g_current_algo->overflow)
{
debuglog("setting overflow\n");
g_current_algo->overflow = false;
db_query(db, "update algos set overflow=true where name='%s'", g_current_algo->name);
}
///////////////////////////////////////////////////////////////////////////////////////////
db_query(db, "select name, profit, rent, factor from algos");
MYSQL_RES *result = mysql_store_result(&db->mysql);
if(!result) return;
MYSQL_ROW row;
while((row = mysql_fetch_row(result)) != NULL)
{
YAAMP_ALGO *algo = stratum_find_algo(row[0]);
if(!algo) continue;
if(row[1]) algo->profit = atof(row[1]);
if(row[2]) algo->rent = atof(row[2]);
if(row[3]) algo->factor = atof(row[3]);
}
mysql_free_result(result);
////////////////////
g_list_client.Enter();
for(CLI li = g_list_client.first; li; li = li->next)
{
YAAMP_CLIENT *client = (YAAMP_CLIENT *)li->data;
if(client->deleted) continue;
client_reset_multialgo(client, false);
}
g_list_client.Leave();
}
////////////////////////////////////////////////////////////////////////////////
void db_update_coinds(YAAMP_DB *db)
{
for(CLI li = g_list_coind.first; li; li = li->next)
{
YAAMP_COIND *coind = (YAAMP_COIND *)li->data;
if(coind->deleted) continue;
if(coind->auto_ready) continue;
debuglog("disabling %s\n", coind->symbol);
db_query(db, "update coins set auto_ready=%d where id=%d", coind->auto_ready, coind->id);
}
////////////////////////////////////////////////////////////////////////////////////////
db_query(db, "select id, name, rpchost, rpcport, rpcuser, rpcpasswd, rpcencoding, master_wallet, reward, price, "\
"hassubmitblock, txmessage, enable, auto_ready, algo, pool_ttf, charity_address, charity_amount, charity_percent, "\
"reward_mul, symbol, auxpow, actual_ttf, network_ttf, usememorypool "\
"from coins where enable and auto_ready and algo='%s' order by index_avg", g_stratum_algo);
MYSQL_RES *result = mysql_store_result(&db->mysql);
if(!result) yaamp_error("Cant query database");
MYSQL_ROW row;
g_list_coind.Enter();
while((row = mysql_fetch_row(result)) != NULL)
{
YAAMP_COIND *coind = (YAAMP_COIND *)object_find(&g_list_coind, atoi(row[0]));
if(!coind)
{
coind = new YAAMP_COIND;
memset(coind, 0, sizeof(YAAMP_COIND));
coind->newcoind = true;
coind->newblock = true;
coind->id = atoi(row[0]);
coind->aux.coind = coind;
}
else
coind->newcoind = false;
strcpy(coind->name, row[1]);
if(row[7]) strcpy(coind->wallet, row[7]);
if(row[6]) coind->pos = strcmp(row[6], "POS")? false: true;
if(row[10]) coind->hassubmitblock = atoi(row[10]);
if(row[2]) strcpy(coind->rpc.host, row[2]);
if(row[3]) coind->rpc.port = atoi(row[3]);
if(row[4] && row[5])
{
char buffer[1024];
sprintf(buffer, "%s:%s", row[4], row[5]);
base64_encode(coind->rpc.credential, buffer);
coind->rpc.coind = coind;
}
if(row[8]) coind->reward = atof(row[8]);
if(row[9]) coind->price = atof(row[9]);
if(row[11]) coind->txmessage = atoi(row[11]);
if(row[12]) coind->enable = atoi(row[12]);
if(row[13]) coind->auto_ready = atoi(row[13]);
if(row[15]) coind->pool_ttf = atoi(row[15]);
if(row[16]) strcpy(coind->charity_address, row[16]);
if(row[17]) coind->charity_amount = atof(row[17]);
if(row[18]) coind->charity_percent = atof(row[18]);
if(row[19]) coind->reward_mul = atof(row[19]);
strcpy(coind->symbol, row[20]);
if(row[21]) coind->isaux = atoi(row[21]);
if(row[22] && row[23]) coind->actual_ttf = min(atoi(row[22]), atoi(row[23]));
else if(row[22]) coind->actual_ttf = atoi(row[22]);
coind->actual_ttf = min(coind->actual_ttf, 120);
coind->actual_ttf = max(coind->actual_ttf, 20);
if(row[24]) coind->usememorypool = atoi(row[24]);
////////////////////////////////////////////////////////////////////////////////////////////////////
coind->touch = true;
if(coind->newcoind)
{
debuglog("connecting to coind %s\n", coind->symbol);
bool b = rpc_connect(&coind->rpc);
coind_init(coind);
g_list_coind.AddTail(coind);
usleep(100*YAAMP_MS);
}
coind_create_job(coind);
}
mysql_free_result(result);
for(CLI li = g_list_coind.first; li; li = li->next)
{
YAAMP_COIND *coind = (YAAMP_COIND *)li->data;
if(coind->deleted) continue;
if(!coind->touch)
{
debuglog("remove coind %s\n", coind->name);
rpc_close(&coind->rpc);
object_delete(coind);
continue;
}
coind->touch = false;
}
coind_sort();
g_list_coind.Leave();
}
///////////////////////////////////////////////////////////////////////////////////////////////
void db_update_remotes(YAAMP_DB *db)
{
db_query(db, "select id, speed/1000000, host, port, username, password, time, price, renterid from jobs where active and ready and algo='%s' order by time", g_stratum_algo);
MYSQL_RES *result = mysql_store_result(&db->mysql);
if(!result) yaamp_error("Cant query database");
MYSQL_ROW row;
g_list_remote.Enter();
while((row = mysql_fetch_row(result)) != NULL)
{
if(!row[0] || !row[1] || !row[2] || !row[3] || !row[4] || !row[5] || !row[6] || !row[7]) continue;
bool newremote = false;
YAAMP_REMOTE *remote = (YAAMP_REMOTE *)object_find(&g_list_remote, atoi(row[0]));
if(!remote)
{
remote = new YAAMP_REMOTE;
memset(remote, 0, sizeof(YAAMP_REMOTE));
remote->id = atoi(row[0]);
newremote = true;
}
// else if(remote->reset_balance)
// continue;
else if(row[6] && atoi(row[6]) > remote->updated)
remote->status = YAAMP_REMOTE_RESET;
remote->speed = atof(row[1]);
strcpy(remote->host, row[2]);
remote->port = atoi(row[3]);
strcpy(remote->username, row[4]);
strcpy(remote->password, row[5]);
remote->updated = atoi(row[6]);
remote->price = atof(row[7]);
remote->touch = true;
remote->submit_last = NULL;
int renterid = row[8]? atoi(row[8]): 0;
if(renterid && !remote->renter)
remote->renter = (YAAMP_RENTER *)object_find(&g_list_renter, renterid);
if(newremote)
{
if(remote->renter && remote->renter->balance <= 0.00001000)
{
debuglog("dont load that job %d\n", remote->id);
delete remote;
continue;
}
pthread_t thread;
pthread_create(&thread, NULL, remote_thread, remote);
pthread_detach(thread);
g_list_remote.AddTail(remote);
usleep(100*YAAMP_MS);
}
if(remote->renter)
{
if(!strcmp(g_current_algo->name, "sha256"))
remote->speed = min(remote->speed, max(remote->renter->balance/g_current_algo->rent*100000000, 1));
else
remote->speed = min(remote->speed, max(remote->renter->balance/g_current_algo->rent*100000, 1));
}
}
mysql_free_result(result);
///////////////////////////////////////////////////////////////////////////////////////////
for(CLI li = g_list_remote.first; li; li = li->next)
{
YAAMP_REMOTE *remote = (YAAMP_REMOTE *)li->data;
// if(remote->reset_balance && remote->renter)
// {
// db_query(db, "update renters set balance=0 where id=%d", remote->renter->id);
// db_query(db, "update jobs set ready=false, active=false where renterid=%d", remote->renter->id);
//
// remote->reset_balance = false;
// }
if(remote->deleted) continue;
if(remote->kill)
{
debuglog("******* kill that sucka %s\n", remote->host);
pthread_cancel(remote->thread);
object_delete(remote);
continue;
}
if(remote->sock && remote->sock->last_read && remote->sock->last_read+120<time(NULL))
{
debuglog("****** timeout %s\n", remote->host);
remote->status = YAAMP_REMOTE_TERMINATE;
remote->kill = true;
remote_close(remote);
continue;
}
if(!remote->touch)
{
remote->status = YAAMP_REMOTE_TERMINATE;
continue;
}
remote->touch = false;
if(remote->difficulty_written != remote->difficulty_actual)
{
remote->difficulty_written = remote->difficulty_actual;
db_query(db, "update jobs set difficulty=%f where id=%d", remote->difficulty_actual, remote->id);
}
}
// remote_sort();
g_list_remote.Leave();
}
void db_update_renters(YAAMP_DB *db)
{
db_query(db, "select id, balance, updated from renters");
MYSQL_RES *result = mysql_store_result(&db->mysql);
if(!result) yaamp_error("Cant query database");
MYSQL_ROW row;
g_list_renter.Enter();
while((row = mysql_fetch_row(result)) != NULL)
{
if(!row[0] || !row[1]) continue;
YAAMP_RENTER *renter = (YAAMP_RENTER *)object_find(&g_list_renter, atoi(row[0]));
if(!renter)
{
renter = new YAAMP_RENTER;
memset(renter, 0, sizeof(YAAMP_RENTER));
renter->id = atoi(row[0]);
g_list_renter.AddTail(renter);
}
if(row[1]) renter->balance = atof(row[1]);
if(row[2]) renter->updated = atoi(row[2]);
}
mysql_free_result(result);
g_list_renter.Leave();
}

32
stratum/db.h Normal file
View file

@ -0,0 +1,32 @@
class YAAMP_CLIENT;
struct YAAMP_DB
{
MYSQL mysql;
};
YAAMP_DB *db_connect();
char *db_clean_string(YAAMP_DB *db, char *string);
void db_close(YAAMP_DB *p);
void db_query(YAAMP_DB *db, const char *format, ...);
void db_register_stratum(YAAMP_DB *db);
void db_update_algos(YAAMP_DB *db);
void db_update_coinds(YAAMP_DB *db);
void db_update_remotes(YAAMP_DB *db);
//int db_find_user(YAAMP_DB *db, YAAMP_CLIENT *client);
void db_add_user(YAAMP_DB *db, YAAMP_CLIENT *client);
void db_add_worker(YAAMP_DB *db, YAAMP_CLIENT *client);
void db_clear_worker(YAAMP_DB *db, YAAMP_CLIENT *client);
void db_update_worker(YAAMP_DB *db, YAAMP_CLIENT *client);
void db_update_workers(YAAMP_DB *db);
void db_update_renters(YAAMP_DB *db);

View file

@ -0,0 +1,6 @@
Author: Nicolas Devillard <ndevilla@free.fr>
This tiny library has received countless contributions and I have
not kept track of all the people who contributed. Let them be thanked
for their ideas, code, suggestions, corrections, enhancements!

15
stratum/iniparser/INSTALL Normal file
View file

@ -0,0 +1,15 @@
iniParser installation instructions
-----------------------------------
- Modify the Makefile to suit your environment.
- Type 'make' to make the library.
- Type 'make check' to make the test program.
- Type 'test/iniexample' to launch the test program.
- Type 'test/parse' to launch torture tests.
Enjoy!
N. Devillard
Wed Mar 2 21:14:17 CET 2011

21
stratum/iniparser/LICENSE Normal file
View file

@ -0,0 +1,21 @@
Copyright (c) 2000-2011 by Nicolas Devillard.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

72
stratum/iniparser/Makefile Executable file
View file

@ -0,0 +1,72 @@
#
# iniparser Makefile
#
# Compiler settings
CC ?= gcc
CFLAGS ?= -g -O0
CFLAGS += -fPIC -Wall -ansi -std=c99 -pedantic
# Ar settings to build the library
AR ?= ar
ARFLAGS = rcv
SHLD = ${CC} ${CFLAGS}
LDSHFLAGS = -shared -Wl,-Bsymbolic
LDFLAGS += -Wl,-rpath -Wl,/usr/lib -Wl,-rpath,/usr/lib
# Set RANLIB to ranlib on systems that require it (Sun OS < 4, Mac OSX)
# RANLIB = ranlib
RANLIB = true
RM ?= rm -f
# Implicit rules
SUFFIXES = .o .c .h .a .so .sl
COMPILE.c ?= $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
ifndef V
QUIET_AR = @echo "AR $@";
QUIET_CC = @echo "CC $@";
QUIET_LINK = @echo "LINK $@";
QUIET_RANLIB = @echo "RANLIB $@";
endif
.c.o:
$(QUIET_CC)$(COMPILE.c) $(OUTPUT_OPTION) $<
SRCS = src/iniparser.c \
src/dictionary.c
OBJS = $(SRCS:.c=.o)
default: libiniparser.a libiniparser.so
libiniparser.a: $(OBJS)
$(AR) $(ARFLAGS) $@ $^
$(RANLIB) $@
libiniparser.so: $(OBJS)
$(QUIET_LINK)$(SHLD) $(LDSHFLAGS) $(LDFLAGS) -o $@.0 $(OBJS) \
-Wl,-soname=`basename $@`.0
clean:
$(RM) $(OBJS)
veryclean:
$(RM) $(OBJS) libiniparser.a libiniparser.so*
rm -rf ./html ; mkdir html
cd test ; $(MAKE) veryclean
docs:
@(cd doc ; $(MAKE))
check: default
@(cd test ; $(MAKE))
.PHONY: default clean veryclean docs check

12
stratum/iniparser/README Normal file
View file

@ -0,0 +1,12 @@
Welcome to iniParser -- version 3.1
released 08 Apr 2012
This modules offers parsing of ini files from the C level.
See a complete documentation in HTML format, from this directory
open the file html/index.html with any HTML-capable browser.
Enjoy!
N.Devillard
Sun Apr 8 16:38:09 CEST 2012

View file

@ -0,0 +1,16 @@
#
# iniparser doc Makefile
#
all: html
html:
doxygen iniparser.dox
rm -f ../html/annotated.html
rm -f ../html/classes.html
rm -f ../html/doxygen.gif
rm -f ../html/files.html
rm -f ../html/functions.html
rm -f ../html/globals.html
rm -f ../html/iniparser_main.html

View file

@ -0,0 +1,81 @@
PROJECT_NAME = iniparser
PROJECT_NUMBER = 3.1
OUTPUT_DIRECTORY = ..
OUTPUT_LANGUAGE = English
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
HIDE_UNDOC_MEMBERS = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ALWAYS_DETAILED_SEC = NO
FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
INTERNAL_DOCS = NO
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
VERBATIM_HEADERS = NO
SHOW_INCLUDE_FILES = NO
JAVADOC_AUTOBRIEF = NO
INHERIT_DOCS = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 4
ENABLED_SECTIONS =
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
ALIASES =
MAX_INITIALIZER_LINES = 30
OPTIMIZE_OUTPUT_FOR_C = YES
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
INPUT = iniparser.main ../src
FILE_PATTERNS = iniparser.h
RECURSIVE = NO
EXCLUDE =
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
IMAGE_PATH =
INPUT_FILTER =
FILTER_SOURCE_FILES = NO
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
DISABLE_INDEX = YES
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
GENERATE_LATEX = NO
GENERATE_RTF = NO
GENERATE_MAN = NO
ENABLE_PREPROCESSING = NO
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = NO
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
PERL_PATH = /usr/bin/perl
HAVE_DOT = NO
SEARCHENGINE = NO

View file

@ -0,0 +1,207 @@
/**
@mainpage iniparser documentation
@section welcome Introduction
iniParser is a simple C library offering ini file parsing services.
The library is pretty small (less than 1500 lines of C) and robust, and
does not depend on any other external library to compile. It is written
in ANSI C and should compile on most platforms without difficulty.
@section inidef What is an ini file?
An ini file is an ASCII file describing simple parameters
(character strings, integers, floating-point values or booleans)
in an explicit format, easy to use and modify for users.
An ini file is segmented into Sections, declared by the following
syntax:
@verbatim
[Section Name]
@endverbatim
i.e. the section name enclosed in square brackets, alone on a
line. Sections names are allowed to contain any character but
square brackets or linefeeds.
In any section are zero or more variables, declared with the
following syntax:
@verbatim
Key = value ; comment
@endverbatim
The key is any string (possibly containing blanks). The value is
any character on the right side of the equal sign. Values can be
given enclosed with quotes. If no quotes are present, the value is
understood as containing all characters between the first and the
last non-blank characters before the comment. The following
declarations are identical:
@verbatim
Hello = "this is a long string value" ; comment
Hello = this is a long string value ; comment
@endverbatim
The semicolon and comment at the end of the line are optional. If
there is a comment, it starts from the first character after the
semicolon up to the end of the line.
Multi-line values can be provided by ending the line with a
backslash (\).
@verbatim
Multiple = Line 1 \
Line 2 \
Line 3 \
Line 4 ; comment
@endverbatim
This would yield: "multiple" <- "Line1 Line2 Line3 Line4"
Comments in an ini file are:
- Lines starting with a hash sign
- Blank lines (only blanks or tabs)
- Comments given on value lines after the semicolon (if present)
@section install Compiling/installing the library
Edit the Makefile to indicate the C compiler you want to use, the
options to provide to compile ANSI C, and possibly the options to pass
to the ar program on your machine to build a library (.a) from a set
of object (.o) files.
Defaults are set for the gcc compiler and the standard ar library
builder.
Type 'make', that should do it.
To use the library in your programs, add the following line on top
of your module:
@code
#include "iniparser.h"
@endcode
And link your program with the iniparser library by adding
@c -liniparser.a to the compile line.
See the file test/initest.c for an example.
iniparser is an ANSI C library. If you want to compile it
with a C++ compiler you will likely run into compatibility
issues. Headers probably have to include the extern "C"
hack and function prototypes will want to add some const
here and there to keep the compiler happy. This job is left
to the reader as there are too many C++ compilers around, each
with its own requirements as to what represents acceptable
C code in a C++ environment. You have been warned.
@section reference Library reference
The library is completely documented in its header file. On-line
documentation has been generated and can be consulted here:
- iniparser.h
@section usage Using the parser
Comments are discarded by the parser. Then sections are
identified, and in each section a new entry is created for every
keyword found. The keywords are stored with the following syntax:
@verbatim
[Section]
Keyword = value ; comment
@endverbatim
is converted to the following key pair:
@verbatim
("section:keyword", "value")
@endverbatim
This means that if you want to retrieve the value that was stored
in the section called @c Pizza, in the keyword @c Cheese,
you would make a request to the dictionary for
@c "pizza:cheese". All section and keyword names are converted
to lowercase before storage in the structure. The value side is
conserved as it has been parsed, though.
Section names are also stored in the structure. They are stored
using as key the section name, and a NULL associated value. They
can be queried through iniparser_find_entry().
To launch the parser, use the function called iniparser_load(), which
takes an input file name and returns a newly allocated @e dictionary
structure. This latter object should remain opaque to the user and only
accessed through the following accessor functions:
- iniparser_getstring()
- iniparser_getint()
- iniparser_getdouble()
- iniparser_getboolean()
Finally, discard this structure using iniparser_freedict().
All values parsed from the ini file are stored as strings. The
accessors are just converting these strings to the requested type on
the fly, but you could basically perform this conversion by yourself
after having called the string accessor.
Notice that iniparser_getboolean() will return an integer (0 or 1),
trying to make sense of what was found in the file. Strings starting
with "y", "Y", "t", "T" or "1" are considered true values (return 1),
strings starting with "n", "N", "f", "F", "0" are considered false
(return 0). This allows some flexibility in handling of boolean
answers.
If you want to add extra information into the structure that was not
present in the ini file, you can use iniparser_set() to insert a
string.
If you want to add a section to the structure, add a key
with a NULL value. Example:
@verbatim
iniparser_set(ini, "section", NULL);
iniparser_set(ini, "section:key1", NULL);
iniparser_set(ini, "section:key2", NULL);
@endverbatim
@section implementation A word about the implementation
The dictionary structure is a pretty simple dictionary
implementation which might find some uses in other applications.
If you are curious, look into the source.
@section defects Known defects
The dictionary structure is extremely unefficient for searching
as keys are sorted in the same order as they are read from the
ini file, which is convenient when dumping back to a file. The
simplistic first-approach linear search implemented there can
become a bottleneck if you have a very large number of keys.
People who need to load large amounts of data from an ini file
should definitely turn to more appropriate solutions: sqlite3 or
similar. There are otherwise many other dictionary implementations
available on the net to replace this one.
@section authors Authors
Nicolas Devillard (ndevilla AT free DOT fr).
*/

View file

@ -0,0 +1,545 @@
/* The standard CSS for doxygen */
body, table, div, p, dl {
font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
font-size: 12px;
}
/* @group Heading Levels */
h1 {
text-align: center;
font-size: 150%;
}
h2 {
font-size: 120%;
}
h3 {
font-size: 100%;
}
dt {
font-weight: bold;
}
div.multicol {
-moz-column-gap: 1em;
-webkit-column-gap: 1em;
-moz-column-count: 3;
-webkit-column-count: 3;
}
p.startli, p.startdd, p.starttd {
margin-top: 2px;
}
p.endli {
margin-bottom: 0px;
}
p.enddd {
margin-bottom: 4px;
}
p.endtd {
margin-bottom: 2px;
}
/* @end */
caption {
font-weight: bold;
}
span.legend {
font-size: 70%;
text-align: center;
}
h3.version {
font-size: 90%;
text-align: center;
}
div.qindex, div.navtab{
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
padding: 2px;
}
div.qindex, div.navpath {
width: 100%;
line-height: 140%;
}
div.navtab {
margin-right: 15px;
}
/* @group Link Styling */
a {
color: #153788;
font-weight: normal;
text-decoration: none;
}
.contents a:visited {
color: #1b77c5;
}
a:hover {
text-decoration: underline;
}
a.qindex {
font-weight: bold;
}
a.qindexHL {
font-weight: bold;
background-color: #6666cc;
color: #ffffff;
border: 1px double #9295C2;
}
.contents a.qindexHL:visited {
color: #ffffff;
}
a.el {
font-weight: bold;
}
a.elRef {
}
a.code {
color: #3030f0;
}
a.codeRef {
color: #3030f0;
}
/* @end */
dl.el {
margin-left: -1cm;
}
.fragment {
font-family: monospace, fixed;
font-size: 105%;
}
pre.fragment {
border: 1px solid #CCCCCC;
background-color: #f5f5f5;
padding: 4px 6px;
margin: 4px 8px 4px 2px;
overflow: auto;
word-wrap: break-word;
font-size: 9pt;
line-height: 125%;
}
div.ah {
background-color: black;
font-weight: bold;
color: #ffffff;
margin-bottom: 3px;
margin-top: 3px
}
div.groupHeader {
margin-left: 16px;
margin-top: 12px;
margin-bottom: 6px;
font-weight: bold;
}
div.groupText {
margin-left: 16px;
font-style: italic;
}
body {
background: white;
color: black;
margin-right: 20px;
margin-left: 20px;
}
td.indexkey {
background-color: #e8eef2;
font-weight: bold;
border: 1px solid #CCCCCC;
margin: 2px 0px 2px 0;
padding: 2px 10px;
}
td.indexvalue {
background-color: #e8eef2;
border: 1px solid #CCCCCC;
padding: 2px 10px;
margin: 2px 0px;
}
tr.memlist {
background-color: #f0f0f0;
}
p.formulaDsp {
text-align: center;
}
img.formulaDsp {
}
img.formulaInl {
vertical-align: middle;
}
div.center {
text-align: center;
margin-top: 0px;
margin-bottom: 0px;
padding: 0px;
}
div.center img {
border: 0px;
}
img.footer {
border: 0px;
vertical-align: middle;
}
/* @group Code Colorization */
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
span.vhdldigit {
color: #ff00ff
}
span.vhdlchar {
color: #000000
}
span.vhdlkeyword {
color: #700070
}
span.vhdllogic {
color: #ff0000
}
/* @end */
.search {
color: #003399;
font-weight: bold;
}
form.search {
margin-bottom: 0px;
margin-top: 0px;
}
input.search {
font-size: 75%;
color: #000080;
font-weight: normal;
background-color: #e8eef2;
}
td.tiny {
font-size: 75%;
}
.dirtab {
padding: 4px;
border-collapse: collapse;
border: 1px solid #84b0c7;
}
th.dirtab {
background: #e8eef2;
font-weight: bold;
}
hr {
height: 0px;
border: none;
border-top: 1px solid #666;
}
hr.footer {
height: 1px;
}
/* @group Member Descriptions */
.mdescLeft, .mdescRight,
.memItemLeft, .memItemRight,
.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
background-color: #FAFAFA;
border: none;
margin: 4px;
padding: 1px 0 0 8px;
}
.mdescLeft, .mdescRight {
padding: 0px 8px 4px 8px;
color: #555;
}
.memItemLeft, .memItemRight, .memTemplParams {
border-top: 1px solid #ccc;
}
.memItemLeft, .memTemplItemLeft {
white-space: nowrap;
}
.memTemplParams {
color: #606060;
white-space: nowrap;
}
/* @end */
/* @group Member Details */
/* Styles for detailed member documentation */
.memtemplate {
font-size: 80%;
color: #606060;
font-weight: normal;
margin-left: 3px;
}
.memnav {
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
margin-right: 15px;
padding: 2px;
}
.memitem {
padding: 0;
margin-bottom: 10px;
}
.memname {
white-space: nowrap;
font-weight: bold;
margin-left: 6px;
}
.memproto {
border-top: 1px solid #84b0c7;
border-left: 1px solid #84b0c7;
border-right: 1px solid #84b0c7;
padding: 0;
background-color: #d5e1e8;
font-weight: bold;
/* firefox specific markup */
background-image: -moz-linear-gradient(rgba(228, 233, 245, 1.0) 0%, rgba(193, 205, 232, 1.0) 100%);
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
-moz-border-radius-topright: 8px;
-moz-border-radius-topleft: 8px;
/* webkit specific markup */
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(228, 233, 245, 1.0)), to(rgba(193, 205, 232, 1.0)));
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
-webkit-border-top-right-radius: 8px;
-webkit-border-top-left-radius: 8px;
}
.memdoc {
border-bottom: 1px solid #84b0c7;
border-left: 1px solid #84b0c7;
border-right: 1px solid #84b0c7;
padding: 2px 5px;
background-color: #eef3f5;
border-top-width: 0;
/* firefox specific markup */
-moz-border-radius-bottomleft: 8px;
-moz-border-radius-bottomright: 8px;
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
/* webkit specific markup */
-webkit-border-bottom-left-radius: 8px;
-webkit-border-bottom-right-radius: 8px;
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
}
.paramkey {
text-align: right;
}
.paramtype {
white-space: nowrap;
}
.paramname {
color: #602020;
white-space: nowrap;
}
.paramname em {
font-style: normal;
}
/* @end */
/* @group Directory (tree) */
/* for the tree view */
.ftvtree {
font-family: sans-serif;
margin: 0.5em;
}
/* these are for tree view when used as main index */
.directory {
font-size: 9pt;
font-weight: bold;
}
.directory h3 {
margin: 0px;
margin-top: 1em;
font-size: 11pt;
}
/*
The following two styles can be used to replace the root node title
with an image of your choice. Simply uncomment the next two styles,
specify the name of your image and be sure to set 'height' to the
proper pixel height of your image.
*/
/*
.directory h3.swap {
height: 61px;
background-repeat: no-repeat;
background-image: url("yourimage.gif");
}
.directory h3.swap span {
display: none;
}
*/
.directory > h3 {
margin-top: 0;
}
.directory p {
margin: 0px;
white-space: nowrap;
}
.directory div {
display: none;
margin: 0px;
}
.directory img {
vertical-align: -30%;
}
/* these are for tree view when not used as main index */
.directory-alt {
font-size: 100%;
font-weight: bold;
}
.directory-alt h3 {
margin: 0px;
margin-top: 1em;
font-size: 11pt;
}
.directory-alt > h3 {
margin-top: 0;
}
.directory-alt p {
margin: 0px;
white-space: nowrap;
}
.directory-alt div {
display: none;
margin: 0px;
}
.directory-alt img {
vertical-align: -30%;
}
/* @end */
address {
font-style: normal;
color: #333;
}
table.doxtable {
border-collapse:collapse;
}
table.doxtable td, table.doxtable th {
border: 1px solid #153788;
padding: 3px 7px 2px;
}
table.doxtable th {
background-color: #254798;
color: #FFFFFF;
font-size: 110%;
padding-bottom: 4px;
padding-top: 5px;
text-align:left;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,64 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>iniparser: Data Fields</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<!-- Generated by Doxygen 1.6.3 -->
<div class="tabs">
<ul>
<li><a href="globals.html"><span>All</span></a></li>
<li class="current"><a href="globals_func.html"><span>Functions</span></a></li>
</ul>
</div>
<div class="contents">
&nbsp;<ul>
<li>iniparser_dump()
: <a class="el" href="iniparser_8h.html#a046436b3489cd8854ba8e29109250324">iniparser.h</a>
</li>
<li>iniparser_dump_ini()
: <a class="el" href="iniparser_8h.html#aece0e32de371c9e9592d8333f816dfac">iniparser.h</a>
</li>
<li>iniparser_find_entry()
: <a class="el" href="iniparser_8h.html#a3d67c98bbc0cb5239f024ad54bdc63f1">iniparser.h</a>
</li>
<li>iniparser_freedict()
: <a class="el" href="iniparser_8h.html#a90549ee518523921886b74454ff872eb">iniparser.h</a>
</li>
<li>iniparser_getboolean()
: <a class="el" href="iniparser_8h.html#aa2ea2b34f6f4b3cf93c9d4f8f992811f">iniparser.h</a>
</li>
<li>iniparser_getdouble()
: <a class="el" href="iniparser_8h.html#a480d35322f1252344cf2246ac21ee559">iniparser.h</a>
</li>
<li>iniparser_getint()
: <a class="el" href="iniparser_8h.html#ab813340fa9c9a7fcfe6775d6e5e458c2">iniparser.h</a>
</li>
<li>iniparser_getnsec()
: <a class="el" href="iniparser_8h.html#a0b5d6cdc7587e2d27a30f5cdc4a91931">iniparser.h</a>
</li>
<li>iniparser_getsecname()
: <a class="el" href="iniparser_8h.html#a393212be805f395bbfdeb1bafa8bb72a">iniparser.h</a>
</li>
<li>iniparser_getstring()
: <a class="el" href="iniparser_8h.html#aec2e5539bc2be063d1323cdf65f162a3">iniparser.h</a>
</li>
<li>iniparser_load()
: <a class="el" href="iniparser_8h.html#a45d87791d4d2593781bfdfe2991c3a2d">iniparser.h</a>
</li>
<li>iniparser_set()
: <a class="el" href="iniparser_8h.html#aa5d5787f96d6982a937edb2fd499ba60">iniparser.h</a>
</li>
<li>iniparser_unset()
: <a class="el" href="iniparser_8h.html#a7b1a7f2492a35043867fa801b8f21e52">iniparser.h</a>
</li>
</ul>
</div>
<hr class="footer"/><address style="text-align: right;"><small>Generated on Wed Mar 2 22:04:59 2011 for iniparser by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.3 </small></address>
</body>
</html>

View file

@ -0,0 +1,101 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>iniparser: iniparser documentation</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<!-- Generated by Doxygen 1.6.3 -->
<div class="contents">
<h1>iniparser documentation </h1><h3 class="version">3.0 </h3><h2><a class="anchor" id="welcome">
Introduction</a></h2>
<p>iniParser is a simple C library offering ini file parsing services. The library is pretty small (less than 1500 lines of C) and robust, and does not depend on any other external library to compile. It is written in ANSI C and should compile on most platforms without difficulty.</p>
<h2><a class="anchor" id="inidef">
What is an ini file?</a></h2>
<p>An ini file is an ASCII file describing simple parameters (character strings, integers, floating-point values or booleans) in an explicit format, easy to use and modify for users.</p>
<p>An ini file is segmented into Sections, declared by the following syntax:</p>
<div class="fragment"><pre class="fragment">
[Section Name]
</pre></div><p>i.e. the section name enclosed in square brackets, alone on a line. Sections names are allowed to contain any character but square brackets or linefeeds.</p>
<p>In any section are zero or more variables, declared with the following syntax:</p>
<div class="fragment"><pre class="fragment">
Key = value ; comment
</pre></div><p>The key is any string (possibly containing blanks). The value is any character on the right side of the equal sign. Values can be given enclosed with quotes. If no quotes are present, the value is understood as containing all characters between the first and the last non-blank characters before the comment. The following declarations are identical:</p>
<div class="fragment"><pre class="fragment">
Hello = "this is a long string value" ; comment
Hello = this is a long string value ; comment
</pre></div><p>The semicolon and comment at the end of the line are optional. If there is a comment, it starts from the first character after the semicolon up to the end of the line.</p>
<p>Multi-line values can be provided by ending the line with a backslash (\).</p>
<div class="fragment"><pre class="fragment">
Multiple = Line 1 \
Line 2 \
Line 3 \
Line 4 ; comment
</pre></div><p>This would yield: "multiple" &lt;- "Line1 Line2 Line3 Line4"</p>
<p>Comments in an ini file are:</p>
<ul>
<li>Lines starting with a hash sign</li>
<li>Blank lines (only blanks or tabs)</li>
<li>Comments given on value lines after the semicolon (if present)</li>
</ul>
<h2><a class="anchor" id="install">
Compiling/installing the library</a></h2>
<p>Edit the Makefile to indicate the C compiler you want to use, the options to provide to compile ANSI C, and possibly the options to pass to the ar program on your machine to build a library (.a) from a set of object (.o) files.</p>
<p>Defaults are set for the gcc compiler and the standard ar library builder.</p>
<p>Type 'make', that should do it.</p>
<p>To use the library in your programs, add the following line on top of your module:</p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> #include &quot;<a class="code" href="iniparser_8h.html" title="Parser for ini files.">iniparser.h</a>&quot;</span>
</pre></div><p>And link your program with the iniparser library by adding <code>-liniparser.a</code> to the compile line.</p>
<p>See the file test/initest.c for an example.</p>
<p>iniparser is an ANSI C library. If you want to compile it with a C++ compiler you will likely run into compatibility issues. Headers probably have to include the extern "C" hack and function prototypes will want to add some const here and there to keep the compiler happy. This job is left to the reader as there are too many C++ compilers around, each with its own requirements as to what represents acceptable C code in a C++ environment. You have been warned.</p>
<h2><a class="anchor" id="reference">
Library reference</a></h2>
<p>The library is completely documented in its header file. On-line documentation has been generated and can be consulted here:</p>
<ul>
<li><a class="el" href="iniparser_8h.html" title="Parser for ini files.">iniparser.h</a></li>
</ul>
<h2><a class="anchor" id="usage">
Using the parser</a></h2>
<p>Comments are discarded by the parser. Then sections are identified, and in each section a new entry is created for every keyword found. The keywords are stored with the following syntax:</p>
<div class="fragment"><pre class="fragment">
[Section]
Keyword = value ; comment
</pre></div><p>is converted to the following key pair:</p>
<div class="fragment"><pre class="fragment">
("section:keyword", "value")
</pre></div><p>This means that if you want to retrieve the value that was stored in the section called <code>Pizza</code>, in the keyword <code>Cheese</code>, you would make a request to the dictionary for <code>"pizza:cheese"</code>. All section and keyword names are converted to lowercase before storage in the structure. The value side is conserved as it has been parsed, though.</p>
<p>Section names are also stored in the structure. They are stored using as key the section name, and a NULL associated value. They can be queried through <a class="el" href="iniparser_8h.html#a3d67c98bbc0cb5239f024ad54bdc63f1" title="Finds out if a given entry exists in a dictionary.">iniparser_find_entry()</a>.</p>
<p>To launch the parser, use the function called <a class="el" href="iniparser_8h.html#a45d87791d4d2593781bfdfe2991c3a2d" title="Parse an ini file and return an allocated dictionary object.">iniparser_load()</a>, which takes an input file name and returns a newly allocated <em>dictionary</em> structure. This latter object should remain opaque to the user and only accessed through the following accessor functions:</p>
<ul>
<li><a class="el" href="iniparser_8h.html#aec2e5539bc2be063d1323cdf65f162a3" title="Get the string associated to a key.">iniparser_getstring()</a></li>
<li><a class="el" href="iniparser_8h.html#ab813340fa9c9a7fcfe6775d6e5e458c2" title="Get the string associated to a key, convert to an int.">iniparser_getint()</a></li>
<li><a class="el" href="iniparser_8h.html#a480d35322f1252344cf2246ac21ee559" title="Get the string associated to a key, convert to a double.">iniparser_getdouble()</a></li>
<li><a class="el" href="iniparser_8h.html#aa2ea2b34f6f4b3cf93c9d4f8f992811f" title="Get the string associated to a key, convert to a boolean.">iniparser_getboolean()</a></li>
</ul>
<p>Finally, discard this structure using <a class="el" href="iniparser_8h.html#a90549ee518523921886b74454ff872eb" title="Free all memory associated to an ini dictionary.">iniparser_freedict()</a>.</p>
<p>All values parsed from the ini file are stored as strings. The accessors are just converting these strings to the requested type on the fly, but you could basically perform this conversion by yourself after having called the string accessor.</p>
<p>Notice that <a class="el" href="iniparser_8h.html#aa2ea2b34f6f4b3cf93c9d4f8f992811f" title="Get the string associated to a key, convert to a boolean.">iniparser_getboolean()</a> will return an integer (0 or 1), trying to make sense of what was found in the file. Strings starting with "y", "Y", "t", "T" or "1" are considered true values (return 1), strings starting with "n", "N", "f", "F", "0" are considered false (return 0). This allows some flexibility in handling of boolean answers.</p>
<p>If you want to add extra information into the structure that was not present in the ini file, you can use <a class="el" href="iniparser_8h.html#aa5d5787f96d6982a937edb2fd499ba60" title="Set an entry in a dictionary.">iniparser_set()</a> to insert a string.</p>
<p>If you want to add a section to the structure, add a key with a NULL value. Example: </p>
<div class="fragment"><pre class="fragment">
iniparser_set(ini, "section", NULL);
iniparser_set(ini, "section:key1", NULL);
iniparser_set(ini, "section:key2", NULL);
</pre></div><h2><a class="anchor" id="implementation">
A word about the implementation</a></h2>
<p>The dictionary structure is a pretty simple dictionary implementation which might find some uses in other applications. If you are curious, look into the source.</p>
<h2><a class="anchor" id="defects">
Known defects</a></h2>
<p>The dictionary structure is extremely unefficient for searching as keys are sorted in the same order as they are read from the ini file, which is convenient when dumping back to a file. The simplistic first-approach linear search implemented there can become a bottleneck if you have a very large number of keys.</p>
<p>People who need to load large amounts of data from an ini file should definitely turn to more appropriate solutions: sqlite3 or similar. There are otherwise many other dictionary implementations available on the net to replace this one.</p>
<h2><a class="anchor" id="authors">
Authors</a></h2>
<p>Nicolas Devillard (ndevilla AT free DOT fr). </p>
</div>
<hr class="footer"/><address style="text-align: right;"><small>Generated on Wed Mar 2 22:04:58 2011 for iniparser by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.3 </small></address>
</body>
</html>

View file

@ -0,0 +1,583 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>iniparser: iniparser.h File Reference</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<!-- Generated by Doxygen 1.6.3 -->
<div class="contents">
<h1>iniparser.h File Reference</h1>
<p>Parser for ini files.
<a href="#_details">More...</a></p>
<table border="0" cellpadding="0" cellspacing="0">
<tr><td colspan="2"><h2>Functions</h2></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a0b5d6cdc7587e2d27a30f5cdc4a91931">iniparser_getnsec</a> (dictionary *d)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get number of sections in a dictionary. <a href="#a0b5d6cdc7587e2d27a30f5cdc4a91931"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">char *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a393212be805f395bbfdeb1bafa8bb72a">iniparser_getsecname</a> (dictionary *d, int n)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get name for section n in a dictionary. <a href="#a393212be805f395bbfdeb1bafa8bb72a"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#aece0e32de371c9e9592d8333f816dfac">iniparser_dump_ini</a> (dictionary *d, FILE *f)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Save a dictionary to a loadable ini file. <a href="#aece0e32de371c9e9592d8333f816dfac"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a046436b3489cd8854ba8e29109250324">iniparser_dump</a> (dictionary *d, FILE *f)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Dump a dictionary to an opened file pointer. <a href="#a046436b3489cd8854ba8e29109250324"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">char *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#aec2e5539bc2be063d1323cdf65f162a3">iniparser_getstring</a> (dictionary *d, char *key, char *def)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key. <a href="#aec2e5539bc2be063d1323cdf65f162a3"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#ab813340fa9c9a7fcfe6775d6e5e458c2">iniparser_getint</a> (dictionary *d, char *key, int notfound)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key, convert to an int. <a href="#ab813340fa9c9a7fcfe6775d6e5e458c2"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">double&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a480d35322f1252344cf2246ac21ee559">iniparser_getdouble</a> (dictionary *d, char *key, double notfound)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key, convert to a double. <a href="#a480d35322f1252344cf2246ac21ee559"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#aa2ea2b34f6f4b3cf93c9d4f8f992811f">iniparser_getboolean</a> (dictionary *d, char *key, int notfound)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key, convert to a boolean. <a href="#aa2ea2b34f6f4b3cf93c9d4f8f992811f"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#aa5d5787f96d6982a937edb2fd499ba60">iniparser_set</a> (dictionary *ini, char *entry, char *val)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Set an entry in a dictionary. <a href="#aa5d5787f96d6982a937edb2fd499ba60"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a7b1a7f2492a35043867fa801b8f21e52">iniparser_unset</a> (dictionary *ini, char *entry)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Delete an entry in a dictionary. <a href="#a7b1a7f2492a35043867fa801b8f21e52"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a3d67c98bbc0cb5239f024ad54bdc63f1">iniparser_find_entry</a> (dictionary *ini, char *entry)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Finds out if a given entry exists in a dictionary. <a href="#a3d67c98bbc0cb5239f024ad54bdc63f1"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">dictionary *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a45d87791d4d2593781bfdfe2991c3a2d">iniparser_load</a> (char *ininame)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Parse an ini file and return an allocated dictionary object. <a href="#a45d87791d4d2593781bfdfe2991c3a2d"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#a90549ee518523921886b74454ff872eb">iniparser_freedict</a> (dictionary *d)</td></tr>
<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Free all memory associated to an ini dictionary. <a href="#a90549ee518523921886b74454ff872eb"></a><br/></td></tr>
</table>
<hr/><a name="_details"></a><h2>Detailed Description</h2>
<p>Parser for ini files. </p>
<dl class="author"><dt><b>Author:</b></dt><dd>N. Devillard </dd></dl>
<dl class="date"><dt><b>Date:</b></dt><dd>Sep 2007 </dd></dl>
<dl class="version"><dt><b>Version:</b></dt><dd>3.0 </dd></dl>
<hr/><h2>Function Documentation</h2>
<a class="anchor" id="a046436b3489cd8854ba8e29109250324"></a><!-- doxytag: member="iniparser.h::iniparser_dump" ref="a046436b3489cd8854ba8e29109250324" args="(dictionary *d, FILE *f)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">void iniparser_dump </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">FILE *&nbsp;</td>
<td class="paramname"> <em>f</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Dump a dictionary to an opened file pointer. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to dump. </td></tr>
<tr><td valign="top"></td><td valign="top"><em>f</em>&nbsp;</td><td>Opened file pointer to dump to. </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>void</dd></dl>
<p>This function prints out the contents of a dictionary, one element by line, onto the provided file pointer. It is OK to specify <code>stderr</code> or <code>stdout</code> as output files. This function is meant for debugging purposes mostly. </p>
</div>
</div>
<a class="anchor" id="aece0e32de371c9e9592d8333f816dfac"></a><!-- doxytag: member="iniparser.h::iniparser_dump_ini" ref="aece0e32de371c9e9592d8333f816dfac" args="(dictionary *d, FILE *f)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">void iniparser_dump_ini </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">FILE *&nbsp;</td>
<td class="paramname"> <em>f</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Save a dictionary to a loadable ini file. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to dump </td></tr>
<tr><td valign="top"></td><td valign="top"><em>f</em>&nbsp;</td><td>Opened file pointer to dump to </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>void</dd></dl>
<p>This function dumps a given dictionary into a loadable ini file. It is Ok to specify <code>stderr</code> or <code>stdout</code> as output files. </p>
</div>
</div>
<a class="anchor" id="a3d67c98bbc0cb5239f024ad54bdc63f1"></a><!-- doxytag: member="iniparser.h::iniparser_find_entry" ref="a3d67c98bbc0cb5239f024ad54bdc63f1" args="(dictionary *ini, char *entry)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">int iniparser_find_entry </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>ini</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>entry</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Finds out if a given entry exists in a dictionary. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>ini</em>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</td><td>Name of the entry to look for </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>integer 1 if entry exists, 0 otherwise</dd></dl>
<p>Finds out if a given entry exists in the dictionary. Since sections are stored as keys with NULL associated values, this is the only way of querying for the presence of sections in a dictionary. </p>
</div>
</div>
<a class="anchor" id="a90549ee518523921886b74454ff872eb"></a><!-- doxytag: member="iniparser.h::iniparser_freedict" ref="a90549ee518523921886b74454ff872eb" args="(dictionary *d)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">void iniparser_freedict </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em></td>
<td>&nbsp;)&nbsp;</td>
<td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Free all memory associated to an ini dictionary. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to free </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>void</dd></dl>
<p>Free all memory associated to an ini dictionary. It is mandatory to call this function before the dictionary object gets out of the current context. </p>
</div>
</div>
<a class="anchor" id="aa2ea2b34f6f4b3cf93c9d4f8f992811f"></a><!-- doxytag: member="iniparser.h::iniparser_getboolean" ref="aa2ea2b34f6f4b3cf93c9d4f8f992811f" args="(dictionary *d, char *key, int notfound)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">int iniparser_getboolean </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>key</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&nbsp;</td>
<td class="paramname"> <em>notfound</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Get the string associated to a key, convert to a boolean. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</td><td>Value to return in case of error </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>integer</dd></dl>
<p>This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned.</p>
<p>A true boolean is found if one of the following is matched:</p>
<ul>
<li>A string starting with 'y'</li>
<li>A string starting with 'Y'</li>
<li>A string starting with 't'</li>
<li>A string starting with 'T'</li>
<li>A string starting with '1'</li>
</ul>
<p>A false boolean is found if one of the following is matched:</p>
<ul>
<li>A string starting with 'n'</li>
<li>A string starting with 'N'</li>
<li>A string starting with 'f'</li>
<li>A string starting with 'F'</li>
<li>A string starting with '0'</li>
</ul>
<p>The notfound value returned if no boolean is identified, does not necessarily have to be 0 or 1. </p>
</div>
</div>
<a class="anchor" id="a480d35322f1252344cf2246ac21ee559"></a><!-- doxytag: member="iniparser.h::iniparser_getdouble" ref="a480d35322f1252344cf2246ac21ee559" args="(dictionary *d, char *key, double notfound)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">double iniparser_getdouble </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>key</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">double&nbsp;</td>
<td class="paramname"> <em>notfound</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Get the string associated to a key, convert to a double. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</td><td>Value to return in case of error </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>double</dd></dl>
<p>This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. </p>
</div>
</div>
<a class="anchor" id="ab813340fa9c9a7fcfe6775d6e5e458c2"></a><!-- doxytag: member="iniparser.h::iniparser_getint" ref="ab813340fa9c9a7fcfe6775d6e5e458c2" args="(dictionary *d, char *key, int notfound)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">int iniparser_getint </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>key</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&nbsp;</td>
<td class="paramname"> <em>notfound</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Get the string associated to a key, convert to an int. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</td><td>Value to return in case of error </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>integer</dd></dl>
<p>This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned.</p>
<p>Supported values for integers include the usual C notation so decimal, octal (starting with 0) and hexadecimal (starting with 0x) are supported. Examples:</p>
<ul>
<li>"42" -&gt; 42</li>
<li>"042" -&gt; 34 (octal -&gt; decimal)</li>
<li>"0x42" -&gt; 66 (hexa -&gt; decimal)</li>
</ul>
<p>Warning: the conversion may overflow in various ways. Conversion is totally outsourced to strtol(), see the associated man page for overflow handling.</p>
<p>Credits: Thanks to A. Becker for suggesting strtol() </p>
</div>
</div>
<a class="anchor" id="a0b5d6cdc7587e2d27a30f5cdc4a91931"></a><!-- doxytag: member="iniparser.h::iniparser_getnsec" ref="a0b5d6cdc7587e2d27a30f5cdc4a91931" args="(dictionary *d)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">int iniparser_getnsec </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em></td>
<td>&nbsp;)&nbsp;</td>
<td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Get number of sections in a dictionary. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to examine </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>int Number of sections found in dictionary</dd></dl>
<p>This function returns the number of sections found in a dictionary. The test to recognize sections is done on the string stored in the dictionary: a section name is given as "section" whereas a key is stored as "section:key", thus the test looks for entries that do not contain a colon.</p>
<p>This clearly fails in the case a section name contains a colon, but this should simply be avoided.</p>
<p>This function returns -1 in case of error. </p>
</div>
</div>
<a class="anchor" id="a393212be805f395bbfdeb1bafa8bb72a"></a><!-- doxytag: member="iniparser.h::iniparser_getsecname" ref="a393212be805f395bbfdeb1bafa8bb72a" args="(dictionary *d, int n)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">char* iniparser_getsecname </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&nbsp;</td>
<td class="paramname"> <em>n</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Get name for section n in a dictionary. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to examine </td></tr>
<tr><td valign="top"></td><td valign="top"><em>n</em>&nbsp;</td><td>Section number (from 0 to nsec-1). </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>Pointer to char string</dd></dl>
<p>This function locates the n-th section in a dictionary and returns its name as a pointer to a string statically allocated inside the dictionary. Do not free or modify the returned string!</p>
<p>This function returns NULL in case of error. </p>
</div>
</div>
<a class="anchor" id="aec2e5539bc2be063d1323cdf65f162a3"></a><!-- doxytag: member="iniparser.h::iniparser_getstring" ref="aec2e5539bc2be063d1323cdf65f162a3" args="(dictionary *d, char *key, char *def)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">char* iniparser_getstring </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>d</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>key</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>def</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Get the string associated to a key. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>def</em>&nbsp;</td><td>Default value to return if key not found. </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>pointer to statically allocated character string</dd></dl>
<p>This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the pointer passed as 'def' is returned. The returned char pointer is pointing to a string allocated in the dictionary, do not free or modify it. </p>
</div>
</div>
<a class="anchor" id="a45d87791d4d2593781bfdfe2991c3a2d"></a><!-- doxytag: member="iniparser.h::iniparser_load" ref="a45d87791d4d2593781bfdfe2991c3a2d" args="(char *ininame)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">dictionary* iniparser_load </td>
<td>(</td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>ininame</em></td>
<td>&nbsp;)&nbsp;</td>
<td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Parse an ini file and return an allocated dictionary object. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>ininame</em>&nbsp;</td><td>Name of the ini file to read. </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>Pointer to newly allocated dictionary</dd></dl>
<p>This is the parser for ini files. This function is called, providing the name of the file to be read. It returns a dictionary object that should not be accessed directly, but through accessor functions instead.</p>
<p>The returned dictionary must be freed using <a class="el" href="iniparser_8h.html#a90549ee518523921886b74454ff872eb" title="Free all memory associated to an ini dictionary.">iniparser_freedict()</a>. </p>
</div>
</div>
<a class="anchor" id="aa5d5787f96d6982a937edb2fd499ba60"></a><!-- doxytag: member="iniparser.h::iniparser_set" ref="aa5d5787f96d6982a937edb2fd499ba60" args="(dictionary *ini, char *entry, char *val)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">int iniparser_set </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>ini</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>entry</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>val</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Set an entry in a dictionary. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>ini</em>&nbsp;</td><td>Dictionary to modify. </td></tr>
<tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</td><td>Entry to modify (entry name) </td></tr>
<tr><td valign="top"></td><td valign="top"><em>val</em>&nbsp;</td><td>New value to associate to the entry. </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>int 0 if Ok, -1 otherwise.</dd></dl>
<p>If the given entry can be found in the dictionary, it is modified to contain the provided value. If it cannot be found, -1 is returned. It is Ok to set val to NULL. </p>
</div>
</div>
<a class="anchor" id="a7b1a7f2492a35043867fa801b8f21e52"></a><!-- doxytag: member="iniparser.h::iniparser_unset" ref="a7b1a7f2492a35043867fa801b8f21e52" args="(dictionary *ini, char *entry)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">void iniparser_unset </td>
<td>(</td>
<td class="paramtype">dictionary *&nbsp;</td>
<td class="paramname"> <em>ini</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">char *&nbsp;</td>
<td class="paramname"> <em>entry</em></td><td>&nbsp;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td><td></td>
</tr>
</table>
</div>
<div class="memdoc">
<p>Delete an entry in a dictionary. </p>
<dl><dt><b>Parameters:</b></dt><dd>
<table border="0" cellspacing="2" cellpadding="0">
<tr><td valign="top"></td><td valign="top"><em>ini</em>&nbsp;</td><td>Dictionary to modify </td></tr>
<tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</td><td>Entry to delete (entry name) </td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>void</dd></dl>
<p>If the given entry can be found, it is deleted from the dictionary. </p>
</div>
</div>
</div>
<hr class="footer"/><address style="text-align: right;"><small>Generated on Wed Mar 2 22:04:59 2011 for iniparser by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.3 </small></address>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>iniparser: iniparser.main File Reference</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<!-- Generated by Doxygen 1.6.3 -->
<div class="contents">
<h1>iniparser.main File Reference</h1><table border="0" cellpadding="0" cellspacing="0">
</table>
</div>
<hr class="footer"/><address style="text-align: right;"><small>Generated on Wed Mar 2 22:04:59 2011 for iniparser by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.3 </small></address>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,105 @@
/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */
DIV.tabs
{
float : left;
width : 100%;
background : url("tab_b.gif") repeat-x bottom;
margin-bottom : 4px;
}
DIV.tabs UL
{
margin : 0px;
padding-left : 10px;
list-style : none;
}
DIV.tabs LI, DIV.tabs FORM
{
display : inline;
margin : 0px;
padding : 0px;
}
DIV.tabs FORM
{
float : right;
}
DIV.tabs A
{
float : left;
background : url("tab_r.gif") no-repeat right top;
border-bottom : 1px solid #84B0C7;
font-size : 80%;
font-weight : bold;
text-decoration : none;
}
DIV.tabs A:hover
{
background-position: 100% -150px;
}
DIV.tabs A:link, DIV.tabs A:visited,
DIV.tabs A:active, DIV.tabs A:hover
{
color: #1A419D;
}
DIV.tabs SPAN
{
float : left;
display : block;
background : url("tab_l.gif") no-repeat left top;
padding : 5px 9px;
white-space : nowrap;
}
DIV.tabs #MSearchBox
{
float : right;
display : inline;
font-size : 1em;
}
DIV.tabs TD
{
font-size : 80%;
font-weight : bold;
text-decoration : none;
}
/* Commented Backslash Hack hides rule from IE5-Mac \*/
DIV.tabs SPAN {float : none;}
/* End IE5-Mac hack */
DIV.tabs A:hover SPAN
{
background-position: 0% -150px;
}
DIV.tabs LI.current A
{
background-position: 100% -150px;
border-width : 0px;
}
DIV.tabs LI.current SPAN
{
background-position: 0% -150px;
padding-bottom : 6px;
}
DIV.navpath
{
background : none;
border : none;
border-bottom : 1px solid #84B0C7;
text-align : center;
margin : 2px;
padding : 2px;
}

View file

@ -0,0 +1,402 @@
/*-------------------------------------------------------------------------*/
/**
@file dictionary.c
@author N. Devillard
@brief Implements a dictionary for string variables.
This module implements a simple dictionary object, i.e. a list
of string/string associations. This object is useful to store e.g.
informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include "dictionary.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/** Maximum value size for integers and doubles. */
#define MAXVALSZ 1024
/** Minimal allocated number of entries in a dictionary */
#define DICTMINSZ 128
/** Invalid key token */
#define DICT_INVALID_KEY ((char*)-1)
/*---------------------------------------------------------------------------
Private functions
---------------------------------------------------------------------------*/
/* Doubles the allocated size associated to a pointer */
/* 'size' is the current allocated size. */
static void * mem_double(void * ptr, size_t size)
{
void * newptr ;
newptr = calloc(2*size, 1);
if (newptr==NULL) {
return NULL ;
}
memcpy(newptr, ptr, size);
free(ptr);
return newptr ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Duplicate a string
@param s String to duplicate
@return Pointer to a newly allocated string, to be freed with free()
This is a replacement for strdup(). This implementation is provided
for systems that do not have it.
*/
/*--------------------------------------------------------------------------*/
char * xstrdup(const char * s)
{
char * t ;
size_t len ;
if (!s)
return NULL ;
len = strlen(s) + 1 ;
t = malloc(len) ;
if (t) {
memcpy(t, s, len) ;
}
return t ;
}
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Compute the hash key for a string.
@param key Character string to use for key.
@return 1 unsigned int on at least 32 bits.
This hash function has been taken from an Article in Dr Dobbs Journal.
This is normally a collision-free function, distributing keys evenly.
The key is stored anyway in the struct so that collision can be avoided
by comparing the key itself in last resort.
*/
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(const char * key)
{
size_t len ;
unsigned hash ;
size_t i ;
len = strlen(key);
for (hash=0, i=0 ; i<len ; i++) {
hash += (unsigned)key[i] ;
hash += (hash<<10);
hash ^= (hash>>6) ;
}
hash += (hash <<3);
hash ^= (hash >>11);
hash += (hash <<15);
return hash ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Create a new dictionary object.
@param size Optional initial size of the dictionary.
@return 1 newly allocated dictionary objet.
This function allocates a new dictionary object of given size and returns
it. If you do not know in advance (roughly) the number of entries in the
dictionary, give size=0.
*/
/*--------------------------------------------------------------------------*/
dictionary * dictionary_new(size_t size)
{
dictionary * d ;
/* If no size was specified, allocate space for DICTMINSZ */
if (size<DICTMINSZ) size=DICTMINSZ ;
d = calloc(1, sizeof *d) ;
if (d) {
d->size = size ;
d->val = calloc(size, sizeof *d->val);
d->key = calloc(size, sizeof *d->key);
d->hash = calloc(size, sizeof *d->hash);
}
return d ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete a dictionary object
@param d dictionary object to deallocate.
@return void
Deallocate a dictionary object and all memory associated to it.
*/
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * d)
{
size_t i ;
if (d==NULL) return ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]!=NULL)
free(d->key[i]);
if (d->val[i]!=NULL)
free(d->val[i]);
}
free(d->val);
free(d->key);
free(d->hash);
free(d);
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get a value from a dictionary.
@param d dictionary object to search.
@param key Key to look for in the dictionary.
@param def Default value to return if key not found.
@return 1 pointer to internally allocated character string.
This function locates a key in a dictionary and returns a pointer to its
value, or the passed 'def' pointer if no such key can be found in
dictionary. The returned character pointer points to data internal to the
dictionary object, you should not try to free it or modify it.
*/
/*--------------------------------------------------------------------------*/
char * dictionary_get(dictionary * d, const char * key, char * def)
{
unsigned hash ;
size_t i ;
hash = dictionary_hash(key);
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
/* Compare hash */
if (hash==d->hash[i]) {
/* Compare string, to avoid hash collisions */
if (!strcmp(key, d->key[i])) {
return d->val[i] ;
}
}
}
return def ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Set a value in a dictionary.
@param d dictionary object to modify.
@param key Key to modify or add.
@param val Value to add.
@return int 0 if Ok, anything else otherwise
If the given key is found in the dictionary, the associated value is
replaced by the provided one. If the key cannot be found in the
dictionary, it is added to it.
It is Ok to provide a NULL value for val, but NULL values for the dictionary
or the key are considered as errors: the function will return immediately
in such a case.
Notice that if you dictionary_set a variable to NULL, a call to
dictionary_get will return a NULL value: the variable will be found, and
its value (NULL) is returned. In other words, setting the variable
content to NULL is equivalent to deleting the variable from the
dictionary. It is not possible (in this implementation) to have a key in
the dictionary without value.
This function returns non-zero in case of failure.
*/
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * d, const char * key, const char * val)
{
size_t i ;
unsigned hash ;
if (d==NULL || key==NULL) return -1 ;
/* Compute hash for this key */
hash = dictionary_hash(key) ;
/* Find if value is already in dictionary */
if (d->n>0) {
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (hash==d->hash[i]) { /* Same hash value */
if (!strcmp(key, d->key[i])) { /* Same key */
/* Found a value: modify and return */
if (d->val[i]!=NULL)
free(d->val[i]);
d->val[i] = val ? xstrdup(val) : NULL ;
/* Value has been modified: return */
return 0 ;
}
}
}
}
/* Add a new value */
/* See if dictionary needs to grow */
if (d->n==d->size) {
/* Reached maximum size: reallocate dictionary */
d->val = mem_double(d->val, d->size * sizeof *d->val) ;
d->key = mem_double(d->key, d->size * sizeof *d->key) ;
d->hash = mem_double(d->hash, d->size * sizeof *d->hash) ;
if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
/* Cannot grow dictionary */
return -1 ;
}
/* Double size */
d->size *= 2 ;
}
/* Insert key in the first empty slot. Start at d->n and wrap at
d->size. Because d->n < d->size this will necessarily
terminate. */
for (i=d->n ; d->key[i] ; ) {
if(++i == d->size) i = 0;
}
/* Copy key */
d->key[i] = xstrdup(key);
d->val[i] = val ? xstrdup(val) : NULL ;
d->hash[i] = hash;
d->n ++ ;
return 0 ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete a key in a dictionary
@param d dictionary object to modify.
@param key Key to remove.
@return void
This function deletes a key in a dictionary. Nothing is done if the
key cannot be found.
*/
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, const char * key)
{
unsigned hash ;
size_t i ;
if (key == NULL) {
return;
}
hash = dictionary_hash(key);
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
/* Compare hash */
if (hash==d->hash[i]) {
/* Compare string, to avoid hash collisions */
if (!strcmp(key, d->key[i])) {
/* Found key */
break ;
}
}
}
if (i>=d->size)
/* Key not found */
return ;
free(d->key[i]);
d->key[i] = NULL ;
if (d->val[i]!=NULL) {
free(d->val[i]);
d->val[i] = NULL ;
}
d->hash[i] = 0 ;
d->n -- ;
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump
@param f Opened file pointer.
@return void
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
output file pointers.
*/
/*--------------------------------------------------------------------------*/
void dictionary_dump(dictionary * d, FILE * out)
{
size_t i ;
if (d==NULL || out==NULL) return ;
if (d->n<1) {
fprintf(out, "empty dictionary\n");
return ;
}
for (i=0 ; i<d->size ; i++) {
if (d->key[i]) {
fprintf(out, "%20s\t[%s]\n",
d->key[i],
d->val[i] ? d->val[i] : "UNDEF");
}
}
return ;
}
/* Test code */
#ifdef TESTDIC
#define NVALS 20000
int main(int argc, char *argv[])
{
dictionary * d ;
char * val ;
int i ;
char cval[90] ;
/* Allocate dictionary */
printf("allocating...\n");
d = dictionary_new(0);
/* Set values in dictionary */
printf("setting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
dictionary_set(d, cval, "salut");
}
printf("getting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
val = dictionary_get(d, cval, DICT_INVALID_KEY);
if (val==DICT_INVALID_KEY) {
printf("cannot get value for key [%s]\n", cval);
}
}
printf("unsetting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
dictionary_unset(d, cval);
}
if (d->n != 0) {
printf("error deleting values\n");
}
printf("deallocating...\n");
dictionary_del(d);
return 0 ;
}
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View file

@ -0,0 +1,185 @@
/*-------------------------------------------------------------------------*/
/**
@file dictionary.h
@author N. Devillard
@brief Implements a dictionary for string variables.
This module implements a simple dictionary object, i.e. a list
of string/string associations. This object is useful to store e.g.
informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
#ifndef _DICTIONARY_H_
#define _DICTIONARY_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Dictionary object
This object contains a list of string/string associations. Each
association is identified by a unique string key. Looking up values
in the dictionary is speeded up by the use of a (hopefully collision-free)
hash function.
*/
/*-------------------------------------------------------------------------*/
typedef struct _dictionary_ {
int n ; /** Number of entries in dictionary */
int size ; /** Storage size */
char ** val ; /** List of string values */
char ** key ; /** List of string keys */
unsigned * hash ; /** List of hash values for keys */
} dictionary ;
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Compute the hash key for a string.
@param key Character string to use for key.
@return 1 unsigned int on at least 32 bits.
This hash function has been taken from an Article in Dr Dobbs Journal.
This is normally a collision-free function, distributing keys evenly.
The key is stored anyway in the struct so that collision can be avoided
by comparing the key itself in last resort.
*/
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(const char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Create a new dictionary object.
@param size Optional initial size of the dictionary.
@return 1 newly allocated dictionary objet.
This function allocates a new dictionary object of given size and returns
it. If you do not know in advance (roughly) the number of entries in the
dictionary, give size=0.
*/
/*--------------------------------------------------------------------------*/
dictionary * dictionary_new(size_t size);
/*-------------------------------------------------------------------------*/
/**
@brief Delete a dictionary object
@param d dictionary object to deallocate.
@return void
Deallocate a dictionary object and all memory associated to it.
*/
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * vd);
/*-------------------------------------------------------------------------*/
/**
@brief Get a value from a dictionary.
@param d dictionary object to search.
@param key Key to look for in the dictionary.
@param def Default value to return if key not found.
@return 1 pointer to internally allocated character string.
This function locates a key in a dictionary and returns a pointer to its
value, or the passed 'def' pointer if no such key can be found in
dictionary. The returned character pointer points to data internal to the
dictionary object, you should not try to free it or modify it.
*/
/*--------------------------------------------------------------------------*/
char * dictionary_get(dictionary * d, const char * key, char * def);
/*-------------------------------------------------------------------------*/
/**
@brief Set a value in a dictionary.
@param d dictionary object to modify.
@param key Key to modify or add.
@param val Value to add.
@return int 0 if Ok, anything else otherwise
If the given key is found in the dictionary, the associated value is
replaced by the provided one. If the key cannot be found in the
dictionary, it is added to it.
It is Ok to provide a NULL value for val, but NULL values for the dictionary
or the key are considered as errors: the function will return immediately
in such a case.
Notice that if you dictionary_set a variable to NULL, a call to
dictionary_get will return a NULL value: the variable will be found, and
its value (NULL) is returned. In other words, setting the variable
content to NULL is equivalent to deleting the variable from the
dictionary. It is not possible (in this implementation) to have a key in
the dictionary without value.
This function returns non-zero in case of failure.
*/
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * vd, const char * key, const char * val);
/*-------------------------------------------------------------------------*/
/**
@brief Delete a key in a dictionary
@param d dictionary object to modify.
@param key Key to remove.
@return void
This function deletes a key in a dictionary. Nothing is done if the
key cannot be found.
*/
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, const char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump
@param f Opened file pointer.
@return void
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
output file pointers.
*/
/*--------------------------------------------------------------------------*/
void dictionary_dump(dictionary * d, FILE * out);
/*-------------------------------------------------------------------------*/
/**
@brief Duplicate a string
@param s String to duplicate
@return Pointer to a newly allocated string, to be freed with free()
This is a replacement for strdup(). This implementation is provided
for systems that do not have it.
*/
/*--------------------------------------------------------------------------*/
char * xstrdup(const char * s);
#ifdef __cplusplus
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show more