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.
 
 
 
 
 
 

801 lines
29 KiB

/*
* This file is Copyright Daniel Silverstone <dsilvers@digital-scurf.org> 2006,2015
*
* 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.
*
*/
#include "iguana777.h"
#include "secp256k1/include/secp256k1.h"
#include "secp256k1/include/secp256k1_schnorr.h"
#include "secp256k1/include/secp256k1_rangeproof.h"
// ------------------------------------------------------[ Preparation ]----
static gfshare_ctx *_gfshare_ctx_init_core(uint8_t *sharenrs,uint32_t sharecount,uint8_t threshold,uint32_t size,void *space,int32_t spacesize)
{
gfshare_ctx *ctx; int32_t allocsize;
allocsize = (int32_t)(sizeof(struct _gfshare_ctx) + threshold * size);
if ( allocsize > spacesize )
{
printf("malloc allocsize %d vs spacesize.%d\n",allocsize,spacesize);
ctx = malloc(allocsize);
if( ctx == NULL )
return NULL; // errno should still be set from XMALLOC()
ctx->allocsize = allocsize;
} else ctx = space;
memset(ctx,0,allocsize);
ctx->sharecount = sharecount;
ctx->threshold = threshold;
ctx->size = size;
memcpy(ctx->sharenrs,sharenrs,sharecount);
ctx->buffersize = threshold * size;
return(ctx);
}
// Initialise a gfshare context for producing shares
gfshare_ctx *gfshare_ctx_initenc(uint8_t *sharenrs,uint32_t sharecount,uint8_t threshold,uint32_t size,void *space,int32_t spacesize)
{
uint32_t i;
for (i=0; i<sharecount; i++)
{
if ( sharenrs[i] == 0 )
{
// can't have x[i] = 0 - that would just be a copy of the secret, in
// theory (in fact, due to the way we use exp/log for multiplication and
// treat log(0) as 0, it ends up as a copy of x[i] = 1)
errno = EINVAL;
return NULL;
}
}
return(_gfshare_ctx_init_core(sharenrs,sharecount,threshold,size,space,spacesize));
}
// Initialise a gfshare context for recombining shares
gfshare_ctx *gfshare_ctx_initdec(uint8_t *sharenrs,uint32_t sharecount,uint32_t size,void *space,int32_t spacesize)
{
gfshare_ctx *ctx = _gfshare_ctx_init_core(sharenrs,sharecount,sharecount,size,space,spacesize);
if ( ctx != NULL )
ctx->threshold = 0;
return(ctx);
}
// Free a share context's memory
void gfshare_ctx_free(gfshare_ctx *ctx)
{
OS_randombytes(ctx->buffer,ctx->buffersize);
OS_randombytes(ctx->sharenrs,ctx->sharecount);
if ( ctx->allocsize != 0 )
{
OS_randombytes((uint8_t *)ctx,sizeof(struct _gfshare_ctx));
free(ctx);
}
OS_randombytes((uint8_t *)ctx,sizeof(struct _gfshare_ctx));
}
// --------------------------------------------------------[ Splitting ]----
// Provide a secret to the encoder. (this re-scrambles the coefficients)
void gfshare_ctx_enc_setsecret(gfshare_ctx *ctx,uint8_t *secret)
{
memcpy(ctx->buffer + ((ctx->threshold-1) * ctx->size),secret,ctx->size);
OS_randombytes(ctx->buffer,(ctx->threshold-1) * ctx->size);
}
// Extract a share from the context. 'share' must be preallocated and at least 'size' bytes long. 'sharenr' is the index into the 'sharenrs' array of the share you want.
void gfshare_ctx_encgetshare(uint8_t *_logs,uint8_t *_exps,gfshare_ctx *ctx,uint8_t sharenr,uint8_t *share)
{
uint32_t pos,coefficient,ilog = _logs[ctx->sharenrs[sharenr]];
uint8_t *share_ptr,*coefficient_ptr = ctx->buffer;
for (pos=0; pos<ctx->size; pos++)
share[pos] = *(coefficient_ptr++);
for (coefficient=1; coefficient<ctx->threshold; coefficient++)
{
share_ptr = share;
for (pos=0; pos<ctx->size; pos++)
{
uint8_t share_byte = *share_ptr;
if ( share_byte != 0 )
share_byte = _exps[ilog + _logs[share_byte]];
*share_ptr++ = share_byte ^ *coefficient_ptr++;
}
}
}
// ----------------------------------------------------[ Recombination ]----
// Inform a recombination context of a change in share indexes
void gfshare_ctx_dec_newshares(gfshare_ctx *ctx,uint8_t *sharenrs)
{
memcpy(ctx->sharenrs,sharenrs,ctx->sharecount);
}
// Provide a share context with one of the shares. The 'sharenr' is the index into the 'sharenrs' array
void gfshare_ctx_dec_giveshare(gfshare_ctx *ctx,uint8_t sharenr,uint8_t *share)
{
memcpy(ctx->buffer + (sharenr * ctx->size),share,ctx->size);
}
// Extract the secret by interpolating the shares. secretbuf must be allocated and at least 'size' bytes
void gfshare_ctx_decextract(uint8_t *_logs,uint8_t *_exps,gfshare_ctx *ctx,uint8_t *secretbuf)
{
uint32_t i,j; uint8_t *secret_ptr,*share_ptr,sharei,sharej;
for (i=0; i<ctx->size; i++)
secretbuf[i] = 0;
for (i=0; i<ctx->sharecount; i++)
{
// Compute L(i) as per Lagrange Interpolation
unsigned Li_top = 0, Li_bottom = 0;
if ( (sharei= ctx->sharenrs[i]) != 0 )
{
for (j=0; j<ctx->sharecount; j++)
{
if ( i != j && sharei != (sharej= ctx->sharenrs[j]) )
{
if ( sharej == 0 )
continue; // skip empty share
Li_top += _logs[sharej];
if ( Li_top >= 0xff )
Li_top -= 0xff;
Li_bottom += _logs[sharei ^ sharej];
if ( Li_bottom >= 0xff )
Li_bottom -= 0xff;
}
}
if ( Li_bottom > Li_top )
Li_top += 0xff;
Li_top -= Li_bottom; // Li_top is now log(L(i))
secret_ptr = secretbuf, share_ptr = ctx->buffer + (ctx->size * i);
for (j=0; j<ctx->size; j++)
{
if ( *share_ptr != 0 )
*secret_ptr ^= _exps[Li_top + _logs[*share_ptr]];
share_ptr++, secret_ptr++;
}
}
}
}
int32_t gfshare_test(struct supernet_info *myinfo,int32_t M,int32_t N,int32_t datasize)
{
int ok = 1, i,k;
uint8_t * secret = malloc(datasize);
uint8_t *shares[255];
uint8_t *recomb = malloc(datasize);
uint8_t space[8192],sharenrs[255],newsharenrs[255];// = (uint8_t *)strdup("0124z89abehtr");
gfshare_ctx *G;
for (i=0; i<N; i++)
{
sharenrs[i] = i+1;
shares[i] = malloc(datasize);
}
init_sharenrs(sharenrs,0,N,N);
/* Stage 1, make a secret */
for( i = 0; i < datasize; ++i )
secret[i] = (rand() & 0xff00) >> 8;
/* Stage 2, split it N ways with a threshold of M */
G = gfshare_ctx_initenc( sharenrs, N, M, datasize,space,sizeof(space) );
gfshare_ctx_enc_setsecret( G, secret );
for (i=0; i<N; i++)
gfshare_ctx_encgetshare(myinfo->logs,myinfo->exps, G, i, shares[i] );
gfshare_ctx_free( G );
/* Prep the decode shape */
uint8_t save[255];
memcpy(save,sharenrs,sizeof(sharenrs));
G = gfshare_ctx_initdec( sharenrs, N, datasize,space,sizeof(space) );
for (k=0; k<10; k++)
{
memcpy(sharenrs,save,sizeof(sharenrs));
memset(newsharenrs,0,N);
int32_t j,r,m;
m = M + (rand() % (N-M+1));
for (i=0; i<m && i<N; i++)
{
r = rand() % N;
while ( (j= sharenrs[r]) == 0 || newsharenrs[r] != 0 )
r = rand() % N;
newsharenrs[r] = j;
sharenrs[r] = 0;
}
for (i=0; i<N; i++)
{
if ( newsharenrs[i] != 0 )
{
fprintf(stderr,"%d ",newsharenrs[i]);
gfshare_ctx_dec_giveshare( G, i, shares[i] );
}
//newsharenrs[i] = sharenrs[i];
}
gfshare_ctx_dec_newshares( G, newsharenrs );
gfshare_ctx_decextract(myinfo->logs,myinfo->exps, G, recomb );
for (i=0; i<datasize; i++)
if ( secret[i] != recomb[i] )
ok = 0;
printf("m.%d M.%-3d N.%-3d ok.%d datalen.%d\n",m,M,N,ok,datasize);
}
free(recomb), free(secret);
for (i=0; i<N; i++)
free(shares[i]);
return ok!=1;
}
void iguana_fixsecp(struct supernet_info *myinfo)
{
myinfo->ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_pedersen_context_initialize(myinfo->ctx);
secp256k1_rangeproof_context_initialize(myinfo->ctx);
}
void libgfshare_init(struct supernet_info *myinfo,uint8_t _logs[256],uint8_t _exps[510])
{
uint32_t i,x = 1;
myinfo->ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_pedersen_context_initialize(myinfo->ctx);
secp256k1_rangeproof_context_initialize(myinfo->ctx);
for (i=0; i<255; i++)
{
_exps[i] = x;
_logs[x] = i;
x <<= 1;
if ( x & 0x100 )
x ^= 0x11d; // Unset the 8th bit and mix in 0x1d
}
for (i=255; i<510; i++)
_exps[i] = _exps[i % 255];
_logs[0] = 0; // can't log(0) so just set it neatly to 0
if ( 0 )
{
void test_mofn(struct supernet_info *myinfo);
gfshare_test(myinfo,6,11,32);
test_mofn(myinfo);
getchar();
}
}
// Construct and write out the tables for the gfshare code
int maingen(int argc,char **argv)
{
uint8_t logs[256],exps[255]; uint32_t i;
libgfshare_init(0,logs,exps);
// The above generation algorithm clearly demonstrates that
// logs[exps[i]] == i for 0 <= i <= 254
// exps[logs[i]] == i for 1 <= i <= 255
// Spew out the tables
fprintf(stdout, "\
/*\n\
* This file is autogenerated by gfshare_maketable.\n\
*/\n\
\n\
static uint8_t logs[256] = {\n ");
for ( i = 0; i < 256; ++i )
{
fprintf(stdout, "0x%02x", logs[i]);
if( i == 255 )
fprintf(stdout, " };\n");
else if( (i % 8) == 7 )
fprintf(stdout, ",\n ");
else
fprintf(stdout, ", ");
}
// The exp table we output from 0 to 509 because that way when we
// do the lagrange interpolation we don't have to be quite so strict
// with staying inside the field which makes it quicker
fprintf(stdout, "\
\n\
static uint8_t exps[510] = {\n ");
for ( i = 0; i < 510; ++i )
{
fprintf(stdout, "0x%02x", exps[i % 255]); /* exps[255]==exps[0] */
if ( i == 509 )
fprintf(stdout, " };\n");
else if( (i % 8) == 7)
fprintf(stdout, ",\n ");
else
fprintf(stdout, ", ");
}
return 0;
}
/******************************************************************************
* Copyright © 2014-2017 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. *
* *
******************************************************************************/
int32_t init_sharenrs(uint8_t sharenrs[255],uint8_t *orig,int32_t m,int32_t n)
{
uint8_t *randvals,valid[255];
int32_t i,j,r,remains,orign;
if ( m > n || n >= 0xff ) // reserve 255 for illegal sharei
{
printf("illegal M.%d of N.%d\n",m,n);
return(-1);
}
randvals = calloc(1,65536);
OS_randombytes(randvals,65536);
if ( orig == 0 && n == m )
{
memset(sharenrs,0,n);
for (i=0; i<255; i++)
valid[i] = (i + 1);
remains = orign = 255;
for (i=0; i<n; i++)
{
r = (randvals[i] % remains);
sharenrs[i] = valid[r];
printf("%d ",sharenrs[i]);
valid[r] = valid[--remains];
}
printf("FULL SET\n");
}
else
{
memcpy(valid,orig,n);
memset(sharenrs,0,n);
for (i=0; i<n; i++)
printf("%d ",valid[i]);
printf("valid\n");
for (i=0; i<m; i++)
{
r = rand() % n;
while ( (j= valid[r]) == 0 )
{
//printf("i.%d j.%d m.%d n.%d r.%d\n",i,j,m,n,r);
r = rand() % n;
}
sharenrs[i] = j;
valid[r] = 0;
}
for (i=0; i<n; i++)
printf("%d ",valid[i]);
printf("valid\n");
for (i=0; i<m; i++)
printf("%d ",sharenrs[i]);
printf("sharenrs vals m.%d of n.%d\n",m,n);
//getchar();
}
free(randvals);
for (i=0; i<m; i++)
{
for (j=0; j<m; j++)
{
if ( i == j )
continue;
if ( sharenrs[i] != 0 && sharenrs[i] == sharenrs[j] )
{
printf("FATAL: duplicate entry sharenrs[%d] %d vs %d sharenrs[%d]\n",i,sharenrs[i],sharenrs[j],j);
return(-1);
}
}
}
return(0);
}
uint8_t *recoverdata(struct supernet_info *myinfo,uint8_t *shares[],uint8_t *sharenrs,int32_t M,uint8_t *recover,int32_t datasize,int32_t N)
{
void *G; int32_t i,m=0; uint8_t recovernrs[255],space[8192];
memset(recovernrs,0,sizeof(recovernrs));
for (i=0; i<N; i++)
if ( shares[i] != 0 )
recovernrs[i] = sharenrs[i], m++;
if ( m >= M )
{
G = gfshare_ctx_initdec(recovernrs,N,datasize,space,sizeof(space));
for (i=0; i<N; i++)
if ( shares[i] != 0 )
gfshare_ctx_dec_giveshare(G,i,shares[i]);
gfshare_ctx_dec_newshares(G,recovernrs);
gfshare_ctx_decextract(myinfo->logs,myinfo->exps,G,recover);
gfshare_ctx_free(G);
return(recover);
} else return(0);
}
void calc_share(struct supernet_info *myinfo,uint8_t *buffer,int32_t size,int32_t M,uint32_t ilog,uint8_t *share)
{
uint32_t pos,coefficient; uint8_t *share_ptr,share_byte;
for (pos=0; pos<size; pos++)
share[pos] = *(buffer++);
for (coefficient=1; coefficient<M; coefficient++)
{
share_ptr = share;
for (pos=0; pos<size; pos++)
{
share_byte = *share_ptr;
if ( share_byte != 0 )
share_byte = myinfo->exps[ilog + myinfo->logs[share_byte]];
*share_ptr++ = (share_byte ^ *buffer++);
}
}
}
void calc_shares(struct supernet_info *myinfo,uint8_t *shares,uint8_t *secret,int32_t size,int32_t width,int32_t M,int32_t N,uint8_t *sharenrs,uint8_t *space,int32_t spacesize)
{
int32_t i; uint8_t *buffer;
if ( M*width > spacesize )
{
buffer = calloc(M,width);
printf("calloc M.%d width.%d\n",M,width);
} else buffer = space;
memset(shares,0,N * width);
memcpy(buffer + ((M - 1) * size),secret,size);
OS_randombytes(buffer,(M - 1) * size);
for (i=0; i<N; i++)
{
calc_share(myinfo,buffer,size,M,myinfo->logs[sharenrs[i]],&shares[i * width]);
//printf("(%03d %08x) ",sharenrs[i],calc_crc32(0,&shares[i * width],size));
}
if ( buffer != space )
free(buffer);
}
int32_t calc_sharenrs(uint8_t *sharenrs,int32_t N,uint8_t *data,int32_t datasize)
{
bits256 hash,hash2; uint8_t r; int32_t i,j,n = sizeof(hash);
vcalc_sha256(0,hash.bytes,data,datasize);
vcalc_sha256(0,hash2.bytes,hash.bytes,sizeof(hash));
for (i=0; i<N; i++)
{
while ( 1 )
{
if ( n >= sizeof(hash) )
{
vcalc_sha256(0,hash.bytes,hash2.bytes,sizeof(hash2));
vcalc_sha256(0,hash2.bytes,hash.bytes,sizeof(hash));
n = 0;
}
r = hash2.bytes[n++];
if ( (sharenrs[i]= r) == 0 || sharenrs[i] == 0xff )
continue;
for (j=0; j<i; j++)
if ( sharenrs[j] == sharenrs[i] )
break;
if ( j == i )
break;
}
//printf("%3d ",sharenrs[i]);
}
return(N);
}
int32_t calcmofn(struct supernet_info *myinfo,uint8_t *allshares,uint8_t *sharenrs,int32_t M,uint8_t *data,int32_t datasize,int32_t N)
{
uint8_t space[8192];
calc_sharenrs(sharenrs,N,data,datasize);
calc_shares(myinfo,allshares,(void *)data,datasize,datasize,M,N,sharenrs,space,sizeof(space));
return(datasize);
}
struct mofn256_info
{
bits256 secret;
uint8_t *sharenrs;
int32_t M,N,allocsize;
bits256 allshares[];
};
int32_t mofn256_size(uint8_t M,uint8_t N)
{
int32_t allocsize;
allocsize = ((int32_t)(sizeof(struct mofn256_info) + sizeof(bits256) * N + N));
if ( (allocsize & 0xf) != 0 )
allocsize += 0x10 - (allocsize & 0xf);
return(allocsize);
}
struct mofn256_info *mofn256_init(struct supernet_info *myinfo,bits256 secret,uint8_t M,uint8_t N,int32_t calcflag,uint8_t *space,int32_t spacesize)
{
int32_t allocsize; struct mofn256_info *mofn = 0;
if ( M > N || N == 0 || N == 0xff )
return(0);
allocsize = mofn256_size(M,N);
if ( allocsize > spacesize )
{
mofn = calloc(1,allocsize);
mofn->allocsize = allocsize;
}
else
{
mofn = (void *)space;
memset(mofn,0,allocsize);
}
mofn->M = M;
mofn->N = N;
mofn->sharenrs = (void *)&mofn->allshares[N];
if ( calcflag != 0 )
{
mofn->secret = secret;
calcmofn(myinfo,mofn->allshares[0].bytes,mofn->sharenrs,M,secret.bytes,sizeof(secret),N);
}
return(mofn);
}
bits256 mofn256_recover(struct supernet_info *myinfo,struct mofn256_info *mofn)
{
uint8_t *shares[255]; bits256 recover; int32_t i;
for (i=0; i<mofn->N; i++)
{
if ( bits256_nonz(mofn->allshares[i]) != 0 )
shares[i] = mofn->allshares[i].bytes;
else shares[i] = 0;
}
if ( recoverdata(myinfo,shares,mofn->sharenrs,mofn->M,recover.bytes,sizeof(recover),mofn->N) == 0 )
memset(recover.bytes,0,sizeof(recover));
return(recover);
}
int32_t test_mofn256(struct supernet_info *myinfo,int32_t M,int32_t N)
{
uint8_t space[8192]; char str[65],str2[65]; struct mofn256_info *mofn,*cmp; bits256 secret,recover; int32_t i,allocsize,retval,m = 0;
allocsize = mofn256_size(M,N);
cmp = mofn256_init(myinfo,GENESIS_PUBKEY,M,N,0,space,sizeof(space));
secret = rand256(0);
mofn = mofn256_init(myinfo,secret,M,N,1,&space[allocsize],sizeof(space) - allocsize);
memcpy(cmp->sharenrs,mofn->sharenrs,mofn->N);
for (i=0; i<N; i++)
if ( (rand() % 100) < 50 )
cmp->allshares[i] = mofn->allshares[i], m++;
recover = mofn256_recover(myinfo,cmp);
retval = -1 * (bits256_cmp(recover,mofn->secret) != 0);
if ( bits256_cmp(recover,mofn->secret) != 0 )
{
if ( m >= M )
printf("%s %s error m.%d vs M.%d N.%d\n",bits256_str(str,secret),bits256_str(str2,recover),m,mofn->M,mofn->N);
}
#if defined(_M_X64)
if (((uint64_t)mofn - (uint64_t)space) >= sizeof(space) || ((uint64_t)mofn - (uint64_t)space) < 0)
free(mofn);
if (((uint64_t)cmp - (uint64_t)space) >= sizeof(space) || ((uint64_t)cmp - (uint64_t)space) < 0)
free(cmp);
#else
if ( ((long)mofn - (long)space) >= sizeof(space) || ((long)mofn - (long)space) < 0 )
free(mofn);
if ( ((long)cmp - (long)space) >= sizeof(space) || ((long)cmp - (long)space) < 0 )
free(cmp);
#endif
return(retval);
}
#define N 11
#define M 6
void test_mofn(struct supernet_info *myinfo)
{
bits256 allshares[N],secret,recover; uint8_t *shares[N],sharenrs[N]; int32_t i,j,m;
secret = rand256(0);
srand(secret.uints[0]);
calcmofn(myinfo,allshares[0].bytes,sharenrs,M,secret.bytes,sizeof(secret),N);
for (i=0; i<10000; i++)
{
memset(shares,0,sizeof(shares));
for (j=m=0; j<N; j++)
if ( (rand() % 100) < 55 )
shares[j] = allshares[j].bytes, m++;
if ( recoverdata(myinfo,shares,sharenrs,M,recover.bytes,sizeof(secret),N) != 0 )
{
if ( memcmp(secret.bytes,recover.bytes,sizeof(secret)) != 0 )
printf("FAILED m.%d M.%d N.%d\n",m,M,N);
else if ( 0 )
{
char str[65];
printf("%s PASSED m.%d M.%d N.%d\n",bits256_str(str,recover),m,M,N);
}
} //else printf("not enough shares m.%d M.%d N.%d\n",m,M,N);
}
printf("finished %d tests\n",i);
for (i=0; i<10000; i++)
test_mofn256(myinfo,M,N);
printf("finished %d tests256\n",i);
}
#undef M
#undef N
#define SECP_ENSURE_CTX int32_t flag = 0; if ( ctx == 0 ) { ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); secp256k1_pedersen_context_initialize(ctx); secp256k1_rangeproof_context_initialize(ctx); flag++; } else flag = 0; if ( ctx != 0 )
#define ENDSECP_ENSURE_CTX if ( flag != 0 ) secp256k1_context_destroy(ctx);
int32_t iguana_schnorr_peersign(void *ctx,uint8_t *allpub33,uint8_t *partialsig64,int32_t peeri,bits256 mypriv,bits256 privnonce,bits256 *nonces,int32_t n,bits256 msg256)
{
secp256k1_pubkey Rall,ALL,PUBS[256],*PUBptrs[256]; int32_t i,num,retval = -1; size_t plen; uint8_t pubkey[33];
pubkey[0] = 2;
SECP_ENSURE_CTX
{
for (i=num=0; i<n; i++)
{
plen = 33;
memcpy(pubkey+1,nonces[i].bytes,32);
if ( secp256k1_ec_pubkey_parse(ctx,&PUBS[i],pubkey,plen) == 0 )
printf("error extracting pubkey.%d of %d\n",i,n);
if ( i != peeri )
PUBptrs[num++] = &PUBS[i];
}
PUBptrs[num] = &PUBS[peeri];
if ( secp256k1_ec_pubkey_combine(ctx,&ALL,(void *)PUBptrs,num+1) != 0 )
{
plen = 33;
secp256k1_ec_pubkey_serialize(ctx,allpub33,&plen,&ALL,SECP256K1_EC_COMPRESSED);
//for (i=0; i<33; i++)
// printf("%02x",allpub33[i]);
//printf("\n");
} else printf("error combining ALL\n");
if ( secp256k1_ec_pubkey_combine(ctx,&Rall,(void *)PUBptrs,num) != 0 )
{
if ( secp256k1_schnorr_partial_sign(ctx,partialsig64,msg256.bytes,mypriv.bytes,&Rall,privnonce.bytes) == 0 )
printf("iguana_schnorr_peersign: err %d of num.%d\n",peeri,n);
else retval = 0;
} else printf("error parsing pubkey.%d\n",peeri);
ENDSECP_ENSURE_CTX
}
return(retval);
}
bits256 iguana_schnorr_noncepair(void *ctx,bits256 *pubkey,uint8_t odd_even,bits256 msg256,bits256 privkey,int32_t maxj)
{
bits256 privnonce; int32_t j; uint8_t pubkey33[33];
for (j=0; j<maxj; j++)
{
privnonce = bitcoin_schnorr_noncepair(ctx,pubkey33,msg256,privkey);
if ( pubkey33[0] == (odd_even + 2) )
{
memcpy(pubkey->bytes,pubkey33+1,32);
break;
}
}
if ( j == maxj )
{
printf("couldnt generate even noncepair\n");
iguana_exit(0,0);
}
return(privnonce);
}
struct schnorr_info
{
bits256 msg256,privkey,pubkey,privnonce,pubnonce,serhash2;
int32_t M,N; uint32_t msgid;
uint8_t sig64[64],combinedsig64[64],allpub[33],combined_allpub[33];
uint16_t ind,nonz;
bits256 *pubkeys,*pubnonces;
uint8_t serialized[65 + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(bits256)*4];
uint8_t sigs[];
};
int32_t schnorr_rwinitdata(int32_t rwflag,uint8_t *serialized,uint16_t *indp,uint32_t *msgidp,bits256 hashes[4])
{
int32_t i,j,len = 0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(*indp),indp);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(*msgidp),msgidp);
for (j=0; j<4; j++)
for (i=0; i<32; i++)
iguana_rwnum(rwflag,&serialized[len++],1,&hashes[j].bytes[i]);
return(len);
}
struct schnorr_info *schnorr_init(struct supernet_info *myinfo,uint32_t msgid,uint16_t ind,int32_t M,int32_t N,void *space,int32_t spacesize,bits256 msg256)
{
uint8_t *serialized; bits256 hashes[4]; int32_t len,odd_even = 0; struct schnorr_info *si = space;
si->pubnonces = (void *)&si->sigs[N * 64];
si->pubkeys = &si->pubnonces[N];
si->M = M;
si->N = N;
si->ind = ind;
si->msgid = msgid;
si->msg256 = msg256;
si->pubkey = bitcoin_pub256(myinfo->ctx,&si->privkey,odd_even);
si->privnonce = iguana_schnorr_noncepair(myinfo->ctx,&si->pubnonce,odd_even,msg256,si->privkey,100);
len = 0;
serialized = &si->serialized[65];
hashes[0] = myinfo->myaddr.persistent;
hashes[1] = si->pubkey;
hashes[2] = si->pubnonce;
hashes[3] = msg256;
len = schnorr_rwinitdata(1,serialized,&ind,&msgid,hashes);
blockhash_sha256(si->serhash2.bytes,serialized,len);
if ( bitcoin_sign(myinfo->ctx,"SCHNORR",si->serialized,si->serhash2,myinfo->persistent_priv,1) != 65 )
printf("error signing schnorr initdata\n");
return(si);
}
int32_t schnorr_update(struct supernet_info *myinfo,struct schnorr_info *si,uint8_t *serialized,int32_t recvlen)
{
int32_t len; uint16_t ind; uint32_t msgid; bits256 hashes[4];
// verify compact sig
len = schnorr_rwinitdata(0,&serialized[65],&ind,&msgid,hashes);
// verify persistent pubkey matches ind
if ( bits256_cmp(hashes[3],si->msg256) == 0 && msgid == si->msgid && bits256_nonz(si->pubkeys[ind]) == 0 && bits256_nonz(si->pubnonces[ind]) == 0 )
{
si->pubkeys[ind] = hashes[1];
si->pubnonces[ind] = hashes[2];
if ( ++si->nonz >= si->M )
{
iguana_schnorr_peersign(myinfo->ctx,si->allpub,si->sig64,si->ind,si->privkey,si->privnonce,si->pubnonces,si->M,si->msg256);
// broadcast si->sig64 + ind + msgid
}
}
return(si->M);
}
/*{
if ( bitcoin_schnorr_combine(myinfo->ctx,si->combinedsig64,si->combined_allpub,si->sigs,si->M,si->msg256) < 0 )
printf("error combining k.%d sig64 iter.%d\n",k,iter);
if ( bitcoin_schnorr_verify(myinfo->ctx,si->combinedsig64,si->msg256,si->combined_allpub,33) < 0 )
printf("allpub2 error verifying combined sig k.%d\n",k);
}*/
void iguana_schnorr(struct supernet_info *myinfo)
{
uint8_t allpubs[256][33],allpub[33],allpub2[33],sig64s[256][64],sig64[64],*sigs[256]; bits256 msg256,privnonces[256],signers,privkeys[256],pubkeys[256],pubkeysB[256],nonces[256]; int32_t i,iter,n,k,maxj = 100;
OS_randombytes((void *)&n,sizeof(n));
srand(n);
n = 1 + (rand() % 255);
// generate onetime keypairs
for (i=0; i<n; i++)
pubkeys[i] = bitcoin_pub256(myinfo->ctx,&privkeys[i],0);
msg256 = rand256(0);
for (i=0; i<n; i++)
privnonces[i] = iguana_schnorr_noncepair(myinfo->ctx,&nonces[i],0,msg256,privkeys[i],maxj);
for (i=0; i<n; i++)
iguana_schnorr_peersign(myinfo->ctx,allpubs[i],sig64s[i],i,privkeys[i],privnonces[i],nonces,n,msg256);
for (iter=0; iter<1; iter++)
{
memset(signers.bytes,0,sizeof(signers));
for (i=k=0; i<n; i++)
{
if ( (rand() % 100) < 50 )
{
printf("%2d ",i);
sigs[k] = sig64s[i];
pubkeysB[k] = pubkeys[i];
k++;
SETBIT(signers.bytes,i);
}
}
if ( bitcoin_schnorr_combine(myinfo->ctx,sig64,allpub2,sigs,k,msg256) < 0 )
printf("error combining k.%d sig64 iter.%d\n",k,iter);
else if ( bitcoin_schnorr_verify(myinfo->ctx,sig64,msg256,allpub2,33) < 0 )
printf("allpub2 error verifying combined sig k.%d\n",k);
else if ( 0 ) // doesnt replicate with subsets
{
if ( bitcoin_pubkey_combine(myinfo->ctx,allpub,0,pubkeys,n,0,0) == 0 )
{
if ( memcmp(allpub,allpubs[0],33) != 0 )
{
printf("\n");
for (k=0; k<33; k++)
printf("%02x",allpubs[0][k]);
printf(" combined\n");
for (k=0; k<33; k++)
printf("%02x",allpub[k]);
printf(" allpub, ");
printf("allpub mismatch iter.%d i.%d n.%d\n",iter,i,n);
} else printf("validated iter.%d k.%d %llx\n",iter,k,(long long)signers.txid);
} //else printf("error combining\n");
} else printf("passed n.%d\n",n);
}
}