You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
962 lines
37 KiB
962 lines
37 KiB
/******************************************************************************
|
|
* Copyright © 2014-2016 The SuperNET Developers. *
|
|
* *
|
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
|
* the top-level directory of this distribution for the individual copyright *
|
|
* holder information and the developer policies on copyright and licensing. *
|
|
* *
|
|
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
|
* SuperNET software, including this file may be copied, modified, propagated *
|
|
* or distributed except according to the terms contained in the LICENSE file *
|
|
* *
|
|
* Removal or modification of this copyright notice is prohibited. *
|
|
* *
|
|
******************************************************************************/
|
|
|
|
// based on SaM code by Come-from-Beyond
|
|
|
|
#ifdef DEFINES_ONLY
|
|
#ifndef crypto777_SaM_h
|
|
#define crypto777_SaM_h
|
|
#include <stdio.h>
|
|
#include <memory.h>
|
|
#include <time.h>
|
|
|
|
#define TRIT signed char
|
|
|
|
#define TRIT_FALSE 1
|
|
#define TRIT_UNKNOWN 0
|
|
#define TRIT_TRUE -1
|
|
|
|
#define SAM_HASH_SIZE 243
|
|
#define SAM_STATE_SIZE (SAM_HASH_SIZE * 3)
|
|
#define SAM_NUMBER_OF_ROUNDS 9
|
|
#define SAM_DELTA 254
|
|
|
|
#define SAMHIT_LIMIT ((uint64_t)1594323 * 4782969) //7625597484987LL // 3 ** 27
|
|
#define MAX_CRYPTO777_HIT (((uint64_t)1 << 62) / 1000)
|
|
|
|
//#include "bits777.c"
|
|
//#include "utils777.c"
|
|
#include <stdlib.h>
|
|
#include "../includes/curve25519.h"
|
|
#define MAX_INPUT_SIZE ((int32_t)(65536 - sizeof(bits256) - 2*sizeof(uint32_t)))
|
|
|
|
struct SaM_info { bits384 bits; TRIT trits[SAM_STATE_SIZE],hash[SAM_HASH_SIZE]; };
|
|
struct SaMhdr { bits384 sig; uint32_t timestamp,nonce; uint8_t numrounds,leverage; };
|
|
|
|
void SaM_Initialize(struct SaM_info *state);
|
|
int32_t SaM_Absorb(struct SaM_info *state,const uint8_t *input,const uint32_t inputSize,const uint8_t *input2,const uint32_t inputSize2);
|
|
bits384 SaM_emit(struct SaM_info *state);
|
|
bits384 SaM_encrypt(uint8_t *dest,uint8_t *src,int32_t len,bits384 password,uint32_t timestamp);
|
|
uint64_t SaM_threshold(int32_t leverage);
|
|
uint64_t SaM(bits384 *sigp,uint8_t *input,int32_t inputSize,uint8_t *input2,int32_t inputSize2);
|
|
uint32_t SaM_nonce(void *data,int32_t datalen,int32_t leverage,int32_t maxmillis,uint32_t nonce);
|
|
//uint64_t SaMnonce(bits384 *sigp,uint32_t *noncep,uint8_t *buf,int32_t len,uint64_t threshold,uint32_t rseed,int32_t maxmillis);
|
|
#endif
|
|
#else
|
|
#ifndef crypto777_SaM_c
|
|
#define crypto777_SaM_c
|
|
|
|
#ifndef crypto777_SaM_h
|
|
#define DEFINES_ONLY
|
|
#include "SaM.c"
|
|
#undef DEFINES_ONLY
|
|
#endif
|
|
|
|
static int32_t SAM_INDICES[SAM_STATE_SIZE];
|
|
|
|
void SaM_PrepareIndices()
|
|
{
|
|
int32_t i,nextIndex,currentIndex = 0;
|
|
for (i=0; i<SAM_STATE_SIZE; i++)
|
|
{
|
|
nextIndex = (currentIndex + SAM_DELTA) % SAM_STATE_SIZE;
|
|
SAM_INDICES[i] = nextIndex;
|
|
currentIndex = nextIndex;
|
|
}
|
|
}
|
|
|
|
TRIT SaM_Bias(const TRIT a, const TRIT b) { return a == 0 ? 0 : (a == -b ? a : -a); }
|
|
TRIT SaM_Sum(const TRIT a, const TRIT b) { return a == b ? -a : (a + b); }
|
|
|
|
void SaM_SplitAndMerge(struct SaM_info *state)
|
|
{
|
|
static const TRIT SAMSUM[3][3] = { { 1, -1, 0, }, { -1, 0, 1, }, { 0, 1, -1, } };
|
|
static const TRIT SAMBIAS[3][3] = { { 1, 1, -1, }, { 0, 0, 0, }, { 1, -1, -1, } };
|
|
struct SaM_info leftPart,rightPart;
|
|
int32_t i,nextIndex,round,currentIndex = 0;
|
|
for (round=0; round<SAM_NUMBER_OF_ROUNDS; round++)
|
|
{
|
|
for (i=0; i<SAM_STATE_SIZE; i++)
|
|
{
|
|
nextIndex = SAM_INDICES[i];
|
|
//leftPart.trits[i] = SaM_Bias(state->trits[currentIndex],state->trits[nextIndex]);
|
|
//rightPart.trits[i] = SaM_Bias(state->trits[nextIndex],state->trits[currentIndex]);
|
|
leftPart.trits[i] = SAMBIAS[state->trits[currentIndex]+1][1+state->trits[nextIndex]];
|
|
rightPart.trits[i] = SAMBIAS[state->trits[nextIndex]+1][1+state->trits[currentIndex]];
|
|
currentIndex = nextIndex;
|
|
}
|
|
for (i=0; i<SAM_STATE_SIZE; i++)
|
|
{
|
|
nextIndex = SAM_INDICES[i];
|
|
//state->trits[i] = SaM_Sum(leftPart.trits[currentIndex],rightPart.trits[nextIndex]);
|
|
state->trits[i] = SAMSUM[leftPart.trits[currentIndex]+1][1+rightPart.trits[nextIndex]];
|
|
currentIndex = nextIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SaM_Initialize(struct SaM_info *state)
|
|
{
|
|
int32_t i;
|
|
for (i=SAM_HASH_SIZE; i<SAM_STATE_SIZE; i++)
|
|
state->trits[i] = (i & 1) ? TRIT_FALSE : TRIT_TRUE;
|
|
}
|
|
|
|
void SaM_Squeeze(struct SaM_info *state,TRIT *output)
|
|
{
|
|
memcpy(output,state->trits,SAM_HASH_SIZE * sizeof(TRIT));
|
|
SaM_SplitAndMerge(state);
|
|
}
|
|
|
|
void _SaM_Absorb(struct SaM_info *state,const TRIT *input,const int32_t inputSize)
|
|
{
|
|
int32_t size,i,remainder = inputSize;
|
|
do
|
|
{
|
|
size = remainder >= SAM_HASH_SIZE ? SAM_HASH_SIZE : remainder;
|
|
memcpy(state->trits,&input[inputSize - remainder],size);
|
|
remainder -= SAM_HASH_SIZE;
|
|
if ( size < SAM_HASH_SIZE )
|
|
for (i=size; i<SAM_HASH_SIZE; i++)
|
|
state->trits[i] = (i & 1) ? TRIT_FALSE : TRIT_TRUE;
|
|
SaM_SplitAndMerge(state);
|
|
} while ( remainder > 0 );
|
|
}
|
|
|
|
int32_t SaM_Absorb(struct SaM_info *state,const uint8_t *input,uint32_t inputSize,const uint8_t *input2,uint32_t inputSize2)
|
|
{
|
|
//TRIT output[(MAX_INPUT_SIZE + sizeof(struct SaMhdr)) << 3];
|
|
TRIT *trits,tritbuf[4096];
|
|
int32_t i,size,n = 0;
|
|
/*if ( inputSize + inputSize2 > sizeof(output) )
|
|
{
|
|
printf("SaM overflow (%d + %d) > %ld\n",inputSize,inputSize2,sizeof(output));
|
|
if ( inputSize > MAX_INPUT_SIZE )
|
|
inputSize = MAX_INPUT_SIZE;
|
|
inputSize2 = 0;
|
|
}*/
|
|
size = (inputSize + inputSize2) << 3;
|
|
trits = (size < sizeof(tritbuf)) ? tritbuf : malloc(size);
|
|
if ( input != 0 && inputSize != 0 )
|
|
{
|
|
for (i=0; i<(inputSize << 3); i++)
|
|
trits[n++] = ((input[i >> 3] & (1 << (i & 7))) != 0);
|
|
}
|
|
if ( input2 != 0 && inputSize2 != 0 )
|
|
{
|
|
for (i=0; i<(inputSize2 << 3); i++)
|
|
trits[n++] = ((input2[i >> 3] & (1 << (i & 7))) != 0);
|
|
}
|
|
_SaM_Absorb(state,trits,n);
|
|
if ( trits != tritbuf )
|
|
free(trits);
|
|
return(n);
|
|
}
|
|
|
|
static TRIT InputA[] = { 0 }; // zero len
|
|
static TRIT OutputA[] = { 1, -1, 1, 1, -1, -1, 0, -1, 0, 0, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0, 0, 0, 1, 1, -1, -1, 0, 0, 1, -1, -1, 0, 0, -1, 1, -1, 0, 0, -1, -1, -1, -1, 0, 0, 0, -1, 1, 0, 1, 0, -1, -1, -1, -1, 0, 1, -1, 1, -1, 0, 1, 1, 0, 0, -1, 0, 1, 1, -1, 1, 0, 0, 0, 1, 0, -1, 1, 1, 0, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 0, 1, -1, 1, -1, 0, 0, 1, 1, 1, 1, -1, 1, 1, -1, 0, 0, 1, 1, 0, 0, -1, 1, 1, -1, 0, 0, -1, 0, 0, 1, 0, 0, 0, -1, 1, -1, 0, 1, -1, 0, -1, 1, 1, 1, -1, 0, 1, 1, -1, -1, 0, 0, 1, -1, -1, -1, 0, -1, -1, 1, 1, 0, 1, 0, 1, -1, 1, -1, -1, 0, 0, -1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, -1, 1, -1, 0, 0, 1, 0, -1, -1, -1, 1, -1, 1, -1, -1, 1, 0, 1, -1, 1, -1, 1, -1, 1, 0, 1, 0, 1, -1, -1, -1, -1, 1, 0, 0, -1, -1, 1, 0, 1, 1, -1, 1, -1, -1, -1, 0, 0, -1, 0, 1, 1, 1, 0, 1, 1, -1, 1, 1, 0, 1, 1, 1, 0, -1, 0, 0, -1, -1, -1 };
|
|
|
|
static TRIT InputB[] = { 0 };
|
|
static TRIT OutputB[] = { -1, -1, -1, 1, 0, 0, 1, 1, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 1, 0, -1, 1, 0, 1, 0, 1, -1, 0, -1, 0, 0, -1, 1, -1, -1, 0, 0, 1, -1, -1, 0, 0, -1, 1, 1, 0, 1, 0, 0, 1, -1, 1, 0, -1, -1, 1, -1, 0, -1, 1, -1, 0, 0, 0, 1, -1, 0, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 0, 1, -1, -1, -1, 0, 1, 0, 0, -1, 1, 1, 0, 0, -1, 1, 1, 0, -1, -1, 0, 0, 0, -1, 1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 1, 0, -1, 1, 1, -1, 1, 0, 1, -1, -1, 1, 1, 0, -1, 0, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 0, 0, 0, 0, -1, -1, 1, 1, 1, -1, 1, 0, -1, 1, 0, 1, 0, 0, -1, -1, 1, 1, 0, 0, 1, 0, 0, 0, 0, -1, 1, 0, 0, 1, 1, 0, -1, 1, -1, 1, 0, -1, 0, 0, 1, -1, -1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, -1, 1, 1, 1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 0, -1, 1, 1, -1, 0, -1, 1, 1, 0, -1, -1, -1, -1, 1, 0, 0, -1, -1, -1, 0, 1 };
|
|
|
|
static TRIT InputC[] = { 1 };
|
|
static TRIT OutputC[] = { 1, -1, 1, 1, -1, -1, 0, -1, 0, 0, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0, 0, 0, 1, 1, -1, -1, 0, 0, 1, -1, -1, 0, 0, -1, 1, -1, 0, 0, -1, -1, -1, -1, 0, 0, 0, -1, 1, 0, 1, 0, -1, -1, -1, -1, 0, 1, -1, 1, -1, 0, 1, 1, 0, 0, -1, 0, 1, 1, -1, 1, 0, 0, 0, 1, 0, -1, 1, 1, 0, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 0, 1, -1, 1, -1, 0, 0, 1, 1, 1, 1, -1, 1, 1, -1, 0, 0, 1, 1, 0, 0, -1, 1, 1, -1, 0, 0, -1, 0, 0, 1, 0, 0, 0, -1, 1, -1, 0, 1, -1, 0, -1, 1, 1, 1, -1, 0, 1, 1, -1, -1, 0, 0, 1, -1, -1, -1, 0, -1, -1, 1, 1, 0, 1, 0, 1, -1, 1, -1, -1, 0, 0, -1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, -1, 1, -1, 0, 0, 1, 0, -1, -1, -1, 1, -1, 1, -1, -1, 1, 0, 1, -1, 1, -1, 1, -1, 1, 0, 1, 0, 1, -1, -1, -1, -1, 1, 0, 0, -1, -1, 1, 0, 1, 1, -1, 1, -1, -1, -1, 0, 0, -1, 0, 1, 1, 1, 0, 1, 1, -1, 1, 1, 0, 1, 1, 1, 0, -1, 0, 0, -1, -1, -1 };
|
|
|
|
static TRIT InputD[] = { -1 };
|
|
static TRIT OutputD[] = { -1, 0, 0, 1, 1, 0, -1, 1, 1, 0, 1, 0, -1, 1, -1, 0, 0, 1, 0, -1, 0, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 0, 0, 0, -1, -1, 1, 1, -1, 1, -1, 0, -1, 1, -1, 0, 0, -1, 0, 0, 0, -1, -1, 0, -1, 1, -1, 1, 1, 0, -1, 1, -1, 0, 0, 1, -1, 1, -1, 0, 0, 1, 1, -1, -1, -1, -1, 1, 0, 0, -1, 0, 0, -1, 0, 0, 1, -1, -1, -1, -1, 1, 1, 0, 0, -1, 1, -1, 1, 0, 0, -1, 1, -1, 0, 1, 1, -1, 1, -1, 0, -1, -1, 0, 0, 0, -1, 0, 0, -1, 1, -1, 0, -1, 1, -1, 1, 1, -1, -1, 0, 0, 0, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 0, -1, 0, 1, 0, 0, -1, 1, -1, 0, 1, 0, 1, 1, -1, 0, 1, 1, 0, 0, -1, -1, -1, -1, 0, 1, 0, -1, -1, 0, 0, 1, 1, 1, 0, 0, -1, 1, -1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, -1, -1, 0, -1, -1, 0, -1, -1, 1, 0, 0, -1, -1, 1, 0, 0, 0, 1, 1, 0, -1, 1, -1, -1, 1, -1, -1, 1, 1, 0, 1, 0, 0, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 0, 0, -1, -1, 1, 1 };
|
|
|
|
static TRIT InputE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
static TRIT OutputE[] = { 0, 1, 0, 1, -1, -1, 1, -1, -1, 0, 0, 1, 1, -1, -1, -1, 0, 1, 0, 0, -1, -1, 1, 1, 1, -1, 0, -1, -1, -1, -1, -1, 1, -1, -1, -1, 0, 0, 1, 1, 0, 1, -1, -1, 0, -1, -1, 1, 1, 1, -1, 1, 1, 0, -1, 0, 1, -1, 1, -1, 1, 1, -1, 1, 0, -1, -1, -1, 0, 0, 1, 1, 0, -1, 0, 0, -1, 0, 0, 1, 1, -1, 0, 1, -1, -1, 1, -1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, -1, 0, 1, -1, 0, 1, -1, 1, 0, -1, 1, -1, 1, 0, -1, -1, 1, 0, 1, 0, 0, 1, 1, 1, -1, 1, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 1, 0, 0, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 1, 0, 0, 1, 0, -1, -1, 0, 0, -1, -1, 1, -1, 0, -1, 1, -1, 0, 1, -1, 0, 1, 1, -1, 1, -1, 1, -1, 0, 0, 0, -1, 0, -1, 1, -1, 1, 1, 1, 1, 1, 0, -1, 0, -1, -1, 0, 0, -1, -1, 1, -1, -1, -1, 1, 0, 0, 0, 1, 0, 1, 0, 1, -1, 0, -1, -1, 1, -1, -1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, -1, -1, -1, -1, 1, 0, -1, 0, 0 };
|
|
|
|
bits384 SaM_emit(struct SaM_info *state)
|
|
{
|
|
// i.12 531441 81bf1 0.68% numbits.19 mask.7ffff -> bias -0.0005870312
|
|
TRIT *ptr;
|
|
uint64_t bits64;
|
|
uint32_t i,j,rawbits,bits19[20],mask = 0x7ffff;
|
|
SaM_Squeeze(state,state->hash);
|
|
ptr = state->hash;
|
|
for (i=0; i<SAM_HASH_SIZE/12; i++)
|
|
{
|
|
for (j=rawbits=0; j<12; j++)
|
|
rawbits = (rawbits * 3 + *ptr++ + 1);
|
|
bits19[i] = ((((uint64_t)rawbits<<19)/531441) & mask); // 3^12 == 531441 //bits19[i] = (rawbits & mask);
|
|
//printf("%05x ",bits19[i]);
|
|
}
|
|
for (i*=12,rawbits=0; i<SAM_HASH_SIZE; i++) // 3 trits -> 27
|
|
rawbits = (rawbits * 3 + *ptr++ + 1);
|
|
rawbits = (((rawbits<<4)/27) & 0xf);
|
|
//printf("%x -> Sam_emit\n",rawbits);
|
|
for (bits64=i=0; i<20; i++)
|
|
{
|
|
memcpy(&state->bits.bytes[i*sizeof(uint16_t)],&bits19[i],sizeof(uint16_t));
|
|
bits64 = (bits64 << 3) | ((bits19[i] >> 16) & 7);
|
|
}
|
|
bits64 = (bits64 << 4) | (rawbits & 0xf);
|
|
memcpy(&state->bits.bytes[40],&bits64,sizeof(uint64_t));
|
|
return(state->bits);
|
|
}
|
|
|
|
int32_t _SaM_test(char *msg,TRIT *testvector,int32_t n,TRIT *checkvals)
|
|
{
|
|
struct SaM_info state; int32_t i,errs;
|
|
SaM_Initialize(&state);
|
|
_SaM_Absorb(&state,testvector,n);
|
|
SaM_emit(&state);
|
|
for (i=errs=0; i<243; i++)
|
|
{
|
|
if ( state.hash[i] != checkvals[i] )
|
|
errs++;
|
|
}
|
|
if ( errs != 0 )
|
|
{
|
|
for (i=0; i<243; i++)
|
|
printf("%2d, ",state.hash[i]);
|
|
printf("\nSaM_test.%s errs.%d vs output\n",msg,errs);
|
|
}
|
|
return(errs);
|
|
}
|
|
|
|
/*int32_t bitweight(uint64_t x)
|
|
{
|
|
int i,wt = 0;
|
|
for (i=0; i<64; i++)
|
|
if ( (1LL << i) & x )
|
|
wt++;
|
|
return(wt);
|
|
}*/
|
|
int32_t bitweight(uint64_t x);
|
|
#define SETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] |= (1 << ((bitoffset) & 7)))
|
|
#define GETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] & (1 << ((bitoffset) & 7)))
|
|
#define CLEARBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] &= ~(1 << ((bitoffset) & 7)))
|
|
|
|
double OS_milliseconds();
|
|
|
|
int32_t SaM_test()
|
|
{
|
|
int32_t i,j,wt,iter,totalset,totalclr,setcount[48*8],clrcount[48*8],histo[16]; bits256 seed;
|
|
struct SaM_info state;
|
|
uint8_t buf[4096*2],bits[2][10][48]; char trits[243];
|
|
double startmilli = OS_milliseconds();
|
|
for (i=0; i<sizeof(trits); i++)
|
|
trits[i] = (rand() % 3) - 1;
|
|
SaM_Initialize(&state);
|
|
for (i=0; i<100000; i++)
|
|
{
|
|
_SaM_Absorb(&state,(void *)trits,sizeof(trits));
|
|
}
|
|
SaM_emit(&state);
|
|
printf("per SaM %.3f\n",(OS_milliseconds() - startmilli) / i);
|
|
getchar();
|
|
|
|
for (i=0; i<1000; i++)
|
|
{
|
|
_SaM_test("A",InputA,0,OutputA);
|
|
_SaM_test("B",InputB,sizeof(InputB),OutputB);
|
|
_SaM_test("C",InputC,sizeof(InputC),OutputC);
|
|
_SaM_test("D",InputD,sizeof(InputD),OutputD);
|
|
_SaM_test("E",InputE,sizeof(InputE),OutputE);
|
|
}
|
|
printf("per SaM %.3f\n",((time(NULL) * 1000) - startmilli) / (5 * i));
|
|
memset(seed.bytes,0,sizeof(seed));
|
|
memcpy(seed.bytes,(uint8_t *)"12345678901",11);
|
|
for (i=0; i<243*2; i++)
|
|
buf[i] = 0;
|
|
OS_randombytes(buf,sizeof(buf));
|
|
for (iter=0; iter<2; iter++)
|
|
{
|
|
memset(&state,0,sizeof(state));
|
|
SaM_Initialize(&state);
|
|
SaM_Absorb(&state,buf,243*2,0,0);
|
|
memset(setcount,0,sizeof(setcount));
|
|
memset(clrcount,0,sizeof(clrcount));
|
|
memset(histo,0,sizeof(histo));
|
|
for (i=0; i<5; i++)
|
|
{
|
|
if ( 0 && (i % 100) == 99 )
|
|
{
|
|
for (j=0; j<32; j++)
|
|
seed.bytes[j] = rand() >> 8;
|
|
SaM_Absorb(&state,seed.bytes,sizeof(seed),0,0);
|
|
}
|
|
memset(bits[iter][i],0,sizeof(bits[iter][i]));
|
|
SaM_emit(&state);
|
|
memcpy(bits[iter][i],state.bits.bytes,sizeof(bits[iter][i]));
|
|
for (j=0; j<48; j++)
|
|
{
|
|
histo[bits[iter][i][j] & 0xf]++;
|
|
histo[(bits[iter][i][j]>>4) & 0xf]++;
|
|
printf("%02x ",bits[iter][i][j]);
|
|
}
|
|
printf("\n");
|
|
for (j=0; j<48*8; j++)
|
|
{
|
|
if ( GETBIT(bits[iter][i],j) != 0 )
|
|
setcount[j]++;
|
|
else clrcount[j]++;
|
|
}
|
|
}
|
|
for (i=0; i<16; i++)
|
|
printf("%8d ",histo[i]);
|
|
printf("hex histogram\n");
|
|
seed.bytes[0] ^= 1;
|
|
buf[0] ^= 1;
|
|
}
|
|
for (i=0; i<5; i++)
|
|
{
|
|
for (j=wt=0; j<48; j++)
|
|
{
|
|
wt += bitweight(bits[0][i][j] ^ bits[1][i][j]);
|
|
printf("%02x",bits[0][i][j] ^ bits[1][i][j]);
|
|
}
|
|
printf(" i.%d diff.%d\n",i,wt);
|
|
}
|
|
//set.19090245 clr.19309755 -0.0057
|
|
//total set.19200072 clr.19199928 0.0000037500
|
|
// total set.19191713 clr.19208287 -0.0004316146
|
|
for (totalset=totalclr=j=0; j<48*8; j++)
|
|
{
|
|
totalset += setcount[j];
|
|
totalclr += clrcount[j];
|
|
printf("%.2f ",(double)(setcount[j]-clrcount[j])/i);
|
|
}
|
|
printf("total set.%d clr.%d %.10f\n",totalset,totalclr,(double)(totalset-totalclr)/(totalset+totalclr));
|
|
return(0);
|
|
}
|
|
|
|
bits384 SaM_encrypt(uint8_t *dest,uint8_t *src,int32_t len,bits384 password,uint32_t timestamp)
|
|
{
|
|
bits384 xorpad; int32_t i; struct SaM_info XORpad;
|
|
SaM_Initialize(&XORpad), SaM_Absorb(&XORpad,password.bytes,sizeof(password),(void *)×tamp,sizeof(timestamp));
|
|
while ( len >= 0 )
|
|
{
|
|
SaM_emit(&XORpad);
|
|
for (i=0; i<sizeof(xorpad) && len>=0; i++,len--)
|
|
{
|
|
xorpad.bytes[i] = (XORpad.bits.bytes[i] ^ *src++);
|
|
if ( dest != 0 )
|
|
*dest++ = xorpad.bytes[i];
|
|
}
|
|
}
|
|
return(xorpad);
|
|
}
|
|
|
|
uint64_t SaM_hit(struct SaM_info *state)
|
|
{
|
|
int32_t i; uint64_t hit = 0;
|
|
for (i=0; i<27; i++)
|
|
hit = (hit * 3 + state->hash[i] + 1);
|
|
return(hit);
|
|
}
|
|
|
|
uint64_t SaM(bits384 *sigp,uint8_t *input,int32_t inputSize,uint8_t *input2,int32_t inputSize2)
|
|
{
|
|
int32_t verify_SaM(TRIT *newhash,uint8_t *buf,const int n);
|
|
struct SaM_info state;
|
|
SaM_Initialize(&state);
|
|
SaM_Absorb(&state,input,inputSize,input2,inputSize2);
|
|
//printf("len.%d: ",inputSize+inputSize2);
|
|
*sigp = SaM_emit(&state);
|
|
//if ( 0 && input2 == 0 && numrounds == SAM_MAGIC_NUMBER )
|
|
// verify_SaM(state.hash,(uint8_t *)input,inputSize);
|
|
return(SaM_hit(&state));
|
|
}
|
|
|
|
uint64_t SaM_threshold(int32_t leverage)
|
|
{
|
|
int32_t i;
|
|
uint64_t threshold,divisor = 1;
|
|
if ( leverage > 26 )
|
|
leverage = 26;
|
|
for (i=0; i<leverage; i++)
|
|
divisor *= 3;
|
|
threshold = (SAMHIT_LIMIT / divisor);
|
|
return(threshold);
|
|
}
|
|
|
|
#include <stdlib.h>
|
|
|
|
uint32_t SaM_nonce(void *data,int32_t datalen,int32_t leverage,int32_t maxmillis,uint32_t nonce)
|
|
{
|
|
uint64_t hit,threshold; bits384 sig; double endmilli;
|
|
if ( leverage != 0 )
|
|
{
|
|
threshold = SaM_threshold(leverage);
|
|
if ( maxmillis == 0 )
|
|
{
|
|
if ( (hit= SaM(&sig,data,datalen,(void *)&nonce,sizeof(nonce))) >= threshold )
|
|
{
|
|
printf("nonce failure hit.%llu >= threshold.%llu | leverage.%d nonce.%u\n",(long long)hit,(long long)threshold,leverage,nonce);
|
|
if ( (threshold - hit) > ((uint64_t)1L << 32) )
|
|
return(0xffffffff);
|
|
else return((uint32_t)(threshold - hit));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
endmilli = (OS_milliseconds() + maxmillis);
|
|
while ( OS_milliseconds() < endmilli )
|
|
{
|
|
OS_randombytes((void *)&nonce,sizeof(nonce));
|
|
if ( (hit= SaM(&sig,data,datalen,(void *)&nonce,sizeof(nonce))) < threshold )
|
|
{
|
|
printf("-> nonce.%u leverage.%d | hit.%llu < threshold.%llu\n",nonce,leverage,(long long)hit,(long long)threshold);
|
|
SaM_nonce(data,datalen,leverage,0,nonce);
|
|
return(nonce);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*uint64_t SaMnonce(bits384 *sigp,uint32_t *noncep,uint8_t *buf,int32_t len,uint64_t threshold,uint32_t rseed,int32_t maxmillis)
|
|
{
|
|
uint64_t hit = SAMHIT_LIMIT;
|
|
double startmilli = 0;
|
|
if ( maxmillis == 0 )
|
|
{
|
|
hit = calc_SaM(sigp,buf,len,0,0);
|
|
if ( hit >= threshold )
|
|
{
|
|
printf("nonce failure hit.%llu >= threshold.%llu\n",(long long)hit,(long long)threshold);
|
|
return(threshold - hit);
|
|
}
|
|
else return(0);
|
|
}
|
|
else startmilli = milliseconds();
|
|
while ( hit >= threshold )
|
|
{
|
|
if ( rseed == 0 )
|
|
randombytes((uint8_t *)noncep,sizeof(*noncep));
|
|
else _randombytes((uint8_t *)noncep,sizeof(*noncep),rseed);
|
|
hit = calc_SaM(sigp,buf,len,0,0);
|
|
//printf("%llu %.2f%% (%s) len.%d numrounds.%lld threshold.%llu seed.%u\n",(long long)hit,100.*(double)hit/threshold,(char *)buf,len,(long long)numrounds,(long long)threshold,rseed);
|
|
if ( maxmillis != 0 && milliseconds() > (startmilli + maxmillis) )
|
|
return(0);
|
|
if ( rseed != 0 )
|
|
rseed = (uint32_t)(sigp->txid ^ hit);
|
|
}
|
|
//printf("%5.1f %14llu %7.2f%% numrounds.%lld threshold.%llu seed.%u\n",milliseconds()-startmilli,(long long)hit,100.*(double)hit/threshold,(long long)numrounds,(long long)threshold,rseed);
|
|
return(hit);
|
|
}*/
|
|
|
|
#ifdef include_vps
|
|
// from Come-from-Beyond
|
|
#define HASH_SIZE 32
|
|
|
|
#define DAILY 0
|
|
#define WEEKLY 1
|
|
#define MONTHLY 2
|
|
#define YEARLY 3
|
|
|
|
#define MAX_NUMBER_OF_POOLS 1000
|
|
#define MAX_NUMBER_OF_TOKENS 1000
|
|
#define MAX_NUMBER_OF_UNITS 1000000
|
|
#define MAX_NUMBER_OF_SUPERVISORS 1000000
|
|
|
|
#define MAX_TOKEN_LIFESPAN 36500
|
|
|
|
unsigned int numberOfPools = 0;
|
|
struct Pool {
|
|
|
|
signed long reserve;
|
|
unsigned long quorum, decisionThreshold;
|
|
|
|
} pools[MAX_NUMBER_OF_POOLS];
|
|
|
|
unsigned int numberOfTokens = 0;
|
|
struct Token {
|
|
|
|
BOOL enabled;
|
|
unsigned int pool;
|
|
unsigned long curSupply, maxSupply; // Defines max %% of total coin supply that can be locked
|
|
signed int fadeRate; // Per day in 1/1000th (zero - to keep value const; negative - for deflation; positive - for inflation)
|
|
unsigned int decreaseLimits[YEARLY + 1], increaseLimits[YEARLY + 1]; // In 1/1000th
|
|
unsigned long unitSize; // Locked amount
|
|
unsigned short minLockPeriod, maxLockPeriod; // In days
|
|
unsigned char minExtraLockPeriod, maxExtraLockPeriod; // In days
|
|
unsigned char redemptionGap; // In days
|
|
unsigned long day0Offset; // UNIX time
|
|
unsigned long prices[MAX_TOKEN_LIFESPAN]; // In main currency units
|
|
|
|
} tokens[MAX_NUMBER_OF_TOKENS];
|
|
|
|
unsigned int numberOfUnits = 0;
|
|
struct Unit {
|
|
|
|
unsigned long id;
|
|
unsigned int token;
|
|
unsigned long account;
|
|
signed int fadeRate;
|
|
unsigned long size;
|
|
unsigned long timestamp;
|
|
unsigned char lockPeriodHash[HASH_SIZE];
|
|
unsigned short minLockPeriod, maxLockPeriod;
|
|
unsigned char extraLockPeriod;
|
|
unsigned char redemptionGap;
|
|
|
|
} units[MAX_NUMBER_OF_UNITS];
|
|
|
|
unsigned int numberOfSupervisors = 0;
|
|
struct Supervisor {
|
|
|
|
unsigned long id;
|
|
signed long rating;
|
|
unsigned int activity;
|
|
|
|
} supervisors[MAX_NUMBER_OF_SUPERVISORS];
|
|
|
|
struct Vote {
|
|
|
|
unsigned long supervisorId;
|
|
unsigned long price;
|
|
unsigned long tolerance;
|
|
unsigned long weight;
|
|
unsigned long bet;
|
|
};
|
|
|
|
unsigned char random() {
|
|
|
|
return 42; // TODO: Replace with a better RNG
|
|
}
|
|
|
|
void hash(unsigned char* data, unsigned int dataSize, unsigned char* hash) {
|
|
|
|
// TODO: Invoke SHA-256
|
|
}
|
|
|
|
unsigned int addPool(unsigned long quorum, unsigned long decisionThreshold) {
|
|
// Returns the index of the new pool
|
|
|
|
if (numberOfPools >= MAX_NUMBER_OF_POOLS) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
pools[numberOfPools].reserve = 0;
|
|
pools[numberOfPools].quorum = quorum;
|
|
pools[numberOfPools].decisionThreshold = decisionThreshold;
|
|
|
|
return numberOfPools++;
|
|
}
|
|
|
|
unsigned int addToken(unsigned int pool,
|
|
unsigned long maxSupply,
|
|
signed int fadeRate,
|
|
unsigned int* decreaseLimits, unsigned int* increaseLimits,
|
|
unsigned long unitSize,
|
|
unsigned short minLockPeriod, unsigned short maxLockPeriod,
|
|
unsigned char minExtraLockPeriod, unsigned char maxExtraLockPeriod,
|
|
unsigned char redemptionGap,
|
|
unsigned long day0Offset,
|
|
unsigned long initialPrice) {
|
|
// Returns the index of the new token
|
|
|
|
if (numberOfTokens >= MAX_NUMBER_OF_TOKENS) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
if (pool >= numberOfPools) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
if (minLockPeriod > maxLockPeriod || minExtraLockPeriod > maxExtraLockPeriod) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
tokens[numberOfTokens].enabled = TRUE;
|
|
tokens[numberOfTokens].pool = pool;
|
|
tokens[numberOfTokens].curSupply = 0;
|
|
tokens[numberOfTokens].maxSupply = maxSupply;
|
|
tokens[numberOfTokens].fadeRate = fadeRate;
|
|
memcpy(tokens[numberOfTokens].decreaseLimits, decreaseLimits, sizeof(tokens[numberOfTokens].decreaseLimits));
|
|
memcpy(tokens[numberOfTokens].increaseLimits, increaseLimits, sizeof(tokens[numberOfTokens].increaseLimits));
|
|
tokens[numberOfTokens].unitSize = unitSize;
|
|
tokens[numberOfTokens].minLockPeriod = minLockPeriod;
|
|
tokens[numberOfTokens].maxLockPeriod = maxLockPeriod;
|
|
tokens[numberOfTokens].minExtraLockPeriod = minExtraLockPeriod;
|
|
tokens[numberOfTokens].maxExtraLockPeriod = maxExtraLockPeriod;
|
|
tokens[numberOfTokens].redemptionGap = redemptionGap;
|
|
tokens[numberOfTokens].day0Offset = day0Offset;
|
|
|
|
memset(tokens[numberOfTokens].prices, 0, sizeof(tokens[numberOfTokens].prices));
|
|
tokens[numberOfTokens].prices[0] = initialPrice;
|
|
|
|
return numberOfTokens++;
|
|
}
|
|
|
|
void enableToken(unsigned int token) {
|
|
|
|
tokens[token].enabled = TRUE;
|
|
}
|
|
|
|
void disableToken(unsigned int token) {
|
|
|
|
tokens[token].enabled = FALSE;
|
|
}
|
|
|
|
void changeFadeRate(unsigned int token, signed int newFadeRate) {
|
|
|
|
tokens[token].fadeRate = newFadeRate;
|
|
}
|
|
|
|
void changeUnitSize(unsigned int token, unsigned long newUnitSize) {
|
|
|
|
tokens[token].unitSize = newUnitSize;
|
|
}
|
|
|
|
void changeLockPeriods(unsigned int token, unsigned short newMinLockPeriod, unsigned short newMaxLockPeriod) {
|
|
|
|
tokens[token].minLockPeriod = newMinLockPeriod;
|
|
tokens[token].maxLockPeriod = newMaxLockPeriod;
|
|
}
|
|
|
|
void changeExtraLockPeriods(unsigned int token, unsigned char newMinExtraLockPeriod, unsigned char newMaxExtraLockPeriod) {
|
|
|
|
tokens[token].minExtraLockPeriod = newMinExtraLockPeriod;
|
|
tokens[token].maxExtraLockPeriod = newMaxExtraLockPeriod;
|
|
}
|
|
|
|
void changeRedemptionGap(unsigned int token, unsigned char newRedemptionGap) {
|
|
|
|
tokens[token].redemptionGap = newRedemptionGap;
|
|
}
|
|
|
|
void getLockPeriodHashAndPrefix(unsigned short lockPeriod, unsigned char* lockPeriodHash, unsigned char* lockPeriodPrefix) {
|
|
|
|
unsigned char buffer[HASH_SIZE];
|
|
int i;
|
|
for (i = 0; i < HASH_SIZE - sizeof(lockPeriod); i++) {
|
|
|
|
buffer[i] = random();
|
|
}
|
|
*((unsigned short*)&buffer[i]) = lockPeriod; // WARNING: Depends on endianness!
|
|
hash(buffer, sizeof(buffer), lockPeriodHash);
|
|
memcpy(lockPeriodPrefix, buffer, i);
|
|
}
|
|
|
|
unsigned long getLastPrice(unsigned int token, unsigned long time) {
|
|
|
|
for (int i = (time - tokens[token].day0Offset) / (24 * 60 * 60 * 1000) + 1; i-- > 0;) {
|
|
|
|
if (tokens[token].prices[i] > 0) {
|
|
|
|
return tokens[token].prices[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int addUnit(unsigned long id,
|
|
unsigned int token,
|
|
unsigned long account,
|
|
unsigned long time,
|
|
unsigned char* lockPeriodHash,
|
|
unsigned short minLockPeriod, unsigned short maxLockPeriod,
|
|
unsigned long seed,
|
|
unsigned long mainCurrencyUnitSize) {
|
|
// Returns the index of the new unit
|
|
|
|
if (numberOfUnits >= MAX_NUMBER_OF_UNITS) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
if (token >= numberOfTokens) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
if (tokens[token].enabled == FALSE) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
units[numberOfUnits].id = id;
|
|
units[numberOfUnits].token = token;
|
|
units[numberOfUnits].account = account;
|
|
units[numberOfUnits].fadeRate = tokens[token].fadeRate;
|
|
units[numberOfUnits].size = tokens[token].unitSize;
|
|
units[numberOfUnits].timestamp = time;
|
|
memcpy(units[numberOfUnits].lockPeriodHash, lockPeriodHash, HASH_SIZE);
|
|
units[numberOfUnits].minLockPeriod = minLockPeriod;
|
|
units[numberOfUnits].maxLockPeriod = maxLockPeriod;
|
|
units[numberOfUnits].extraLockPeriod = seed % (tokens[token].maxExtraLockPeriod - tokens[token].minExtraLockPeriod + 1) + tokens[token].minExtraLockPeriod;
|
|
units[numberOfUnits].redemptionGap = tokens[token].redemptionGap;
|
|
|
|
pools[tokens[token].pool].reserve += units[numberOfUnits].size * getLastPrice(token, time) / mainCurrencyUnitSize; // WARNING: May overflow!
|
|
|
|
return numberOfUnits++;
|
|
}
|
|
|
|
unsigned long redeemUnit(unsigned long id, unsigned long account, unsigned short lockPeriod, unsigned char* lockPeriodPrefix, unsigned long time, unsigned long mainCurrencyUnitSize) {
|
|
// Returns amount to add to the account balance
|
|
|
|
for (int i = 0; i < numberOfUnits; i++) {
|
|
|
|
if (units[i].id == id) {
|
|
|
|
if (units[i].account == account) {
|
|
|
|
unsigned char buffer[HASH_SIZE];
|
|
memcpy(buffer, lockPeriodPrefix, HASH_SIZE - sizeof(lockPeriod));
|
|
*((unsigned short*)&buffer[HASH_SIZE - sizeof(lockPeriod)]) = lockPeriod; // WARNING: Depends on endianness!
|
|
unsigned char lockPeriodHash[HASH_SIZE];
|
|
hash(buffer, sizeof(buffer), lockPeriodHash);
|
|
for (int j = 0; j < HASH_SIZE; j++) {
|
|
|
|
if (lockPeriodHash[j] != units[i].lockPeriodHash[j]) {
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (lockPeriod < units[i].minLockPeriod || lockPeriod > units[i].maxLockPeriod) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned int delta = (time - units[i].timestamp) / (24 * 60 * 60 * 1000);
|
|
if (delta < lockPeriod + units[i].extraLockPeriod || delta > lockPeriod + units[i].extraLockPeriod + units[i].redemptionGap) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned long amount = units[i].size * getLastPrice(units[i].token, units[i].timestamp + (lockPeriod + units[i].extraLockPeriod) * 24 * 60 * 60 * 1000) / mainCurrencyUnitSize; // WARNING: May overflow!
|
|
for (int j = lockPeriod + units[i].extraLockPeriod; j-- > 0; ) {
|
|
|
|
amount = amount * (1000 - units[i].fadeRate) / 1000; // WARNING: Do not use floating-point math!
|
|
}
|
|
if (pools[tokens[units[i].token].pool].reserve < amount) {
|
|
|
|
amount = pools[tokens[units[i].token].pool].reserve;
|
|
}
|
|
pools[tokens[units[i].token].pool].reserve -= amount;
|
|
|
|
memcpy(&units[i], &units[--numberOfUnits], sizeof(Unit));
|
|
|
|
return amount;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void salvageExpiredUnits(unsigned long time) {
|
|
|
|
for (int i = numberOfUnits; i-- > 0; ) {
|
|
|
|
if ((time - units[i].timestamp) / (24 * 60 * 60 * 1000) > units[i].maxLockPeriod + units[i].extraLockPeriod + units[i].redemptionGap) {
|
|
|
|
memcpy(&units[i], &units[--numberOfUnits], sizeof(Unit));
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int addSupervisor(unsigned long id) {
|
|
// Returns the index of the new supervisor
|
|
|
|
if (numberOfSupervisors >= MAX_NUMBER_OF_SUPERVISORS) {
|
|
|
|
// TODO: Throw exception
|
|
}
|
|
|
|
supervisors[numberOfSupervisors].id = id;
|
|
supervisors[numberOfSupervisors].rating = 0;
|
|
supervisors[numberOfSupervisors].activity = 0;
|
|
|
|
return numberOfSupervisors++;
|
|
}
|
|
|
|
Supervisor* getSupervisor(unsigned long id) {
|
|
|
|
for (int i = 0; i < numberOfSupervisors; i++) {
|
|
|
|
if (supervisors[i].id == id) {
|
|
|
|
return &supervisors[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL castSupervisorVotes(unsigned int token, unsigned long time, Vote* votes, unsigned int numberOfVotes, unsigned long* prizes) {
|
|
// Returns if a new price has been set
|
|
|
|
unsigned long totalWeight = 0;
|
|
unsigned long totalBet = 0;
|
|
for (int i = 0; i < numberOfVotes; i++) {
|
|
|
|
totalWeight += votes[i].weight;
|
|
getSupervisor(votes[i].supervisorId)->activity++;
|
|
totalBet += votes[i].bet;
|
|
}
|
|
|
|
if (totalWeight < pools[tokens[token].pool].quorum) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
unsigned long prices[MAX_NUMBER_OF_SUPERVISORS];
|
|
unsigned long weights[MAX_NUMBER_OF_SUPERVISORS];
|
|
for (int i = 0; i < numberOfVotes; i++) {
|
|
|
|
int j;
|
|
for (j = 0; j < i; j++) {
|
|
|
|
if (prices[j] > votes[i].price) {
|
|
|
|
break;
|
|
}
|
|
memmove(&prices[j + 1], &prices[j], (i - j) * sizeof(Vote));
|
|
memmove(&weights[j + 1], &weights[j], (i - j) * sizeof(Vote));
|
|
prices[j] = votes[i].price;
|
|
weights[j] = votes[i].weight;
|
|
}
|
|
}
|
|
|
|
unsigned long newPrice = 0;
|
|
for (int i = 0; i < numberOfVotes; i++) {
|
|
|
|
unsigned long weight = 0;
|
|
unsigned long bet = 0;
|
|
for (int j = 0; j < numberOfVotes; j++) {
|
|
|
|
signed long delta = votes[i].price - votes[j].price;
|
|
if (delta < 0) {
|
|
|
|
delta = -delta;
|
|
}
|
|
|
|
if (delta <= votes[j].tolerance) {
|
|
|
|
weight += votes[j].weight;
|
|
bet += votes[j].bet;
|
|
}
|
|
}
|
|
if (weight > totalWeight / 2) {
|
|
|
|
newPrice = votes[i].price;
|
|
|
|
unsigned long totalPrize = 0;
|
|
for (int j = 0; j < numberOfVotes; j++) {
|
|
|
|
signed long delta = votes[i].price - votes[j].price;
|
|
if (delta < 0) {
|
|
|
|
delta = -delta;
|
|
}
|
|
|
|
if (delta <= votes[j].tolerance) {
|
|
|
|
getSupervisor(votes[j].supervisorId)->rating++;
|
|
if (prizes != NULL) {
|
|
|
|
prizes[j] = votes[j].bet + (votes[j].bet * (totalBet - bet) / bet);
|
|
totalPrize += prizes[j];
|
|
}
|
|
|
|
} else {
|
|
|
|
if (prizes != NULL) {
|
|
|
|
prizes[j] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prizes != NULL) {
|
|
|
|
pools[tokens[token].pool].reserve += totalBet - totalPrize;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (newPrice == 0) {
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
unsigned long lastPrice = getLastPrice(token, time);
|
|
if (newPrice < lastPrice) {
|
|
|
|
if ((lastPrice - newPrice) * 1000 / lastPrice > tokens[token].decreaseLimits[DAILY]) {
|
|
|
|
newPrice = lastPrice - tokens[token].decreaseLimits[DAILY] * lastPrice / 1000;
|
|
}
|
|
|
|
lastPrice = getLastPrice(token, time - 7L * 24 * 60 * 60 * 1000);
|
|
if ((lastPrice - newPrice) * 1000 / lastPrice > tokens[token].decreaseLimits[WEEKLY]) {
|
|
|
|
newPrice = lastPrice - tokens[token].decreaseLimits[WEEKLY] * lastPrice / 1000;
|
|
}
|
|
|
|
lastPrice = getLastPrice(token, time - 30L * 24 * 60 * 60 * 1000);
|
|
if ((lastPrice - newPrice) * 1000 / lastPrice > tokens[token].decreaseLimits[MONTHLY]) {
|
|
|
|
newPrice = lastPrice - tokens[token].decreaseLimits[MONTHLY] * lastPrice / 1000;
|
|
}
|
|
|
|
lastPrice = getLastPrice(token, time - 365L * 24 * 60 * 60 * 1000);
|
|
if ((lastPrice - newPrice) * 1000 / lastPrice > tokens[token].decreaseLimits[YEARLY]) {
|
|
|
|
newPrice = lastPrice - tokens[token].decreaseLimits[YEARLY] * lastPrice / 1000;
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((newPrice - lastPrice) * 1000 / lastPrice > tokens[token].increaseLimits[DAILY]) {
|
|
|
|
newPrice = lastPrice + tokens[token].increaseLimits[DAILY] * lastPrice / 1000;
|
|
}
|
|
|
|
lastPrice = getLastPrice(token, time - 7L * 24 * 60 * 60 * 1000);
|
|
if ((newPrice - lastPrice) * 1000 / lastPrice > tokens[token].increaseLimits[WEEKLY]) {
|
|
|
|
newPrice = lastPrice + tokens[token].increaseLimits[WEEKLY] * lastPrice / 1000;
|
|
}
|
|
|
|
lastPrice = getLastPrice(token, time - 30L * 24 * 60 * 60 * 1000);
|
|
if ((newPrice - lastPrice) * 1000 / lastPrice > tokens[token].increaseLimits[MONTHLY]) {
|
|
|
|
newPrice = lastPrice + tokens[token].increaseLimits[MONTHLY] * lastPrice / 1000;
|
|
}
|
|
|
|
lastPrice = getLastPrice(token, time - 365L * 24 * 60 * 60 * 1000);
|
|
if ((newPrice - lastPrice) * 1000 / lastPrice > tokens[token].increaseLimits[YEARLY]) {
|
|
|
|
newPrice = lastPrice + tokens[token].increaseLimits[YEARLY] * lastPrice / 1000;
|
|
}
|
|
}
|
|
|
|
tokens[token].prices[(time - tokens[token].day0Offset) / (24 * 60 * 60 * 1000)] = newPrice;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
#endif
|
|
|