![blackjok3r@gmail.com](/assets/img/avatar_default.png)
79 changed files with 13958 additions and 651 deletions
@ -0,0 +1,38 @@ |
|||
SHELL = /bin/sh |
|||
CC = gcc |
|||
CC_DARWIN = g++-6 |
|||
CC_WIN = x86_64-w64-mingw32-gcc-posix |
|||
CFLAGS_DARWIN = -DBUILD_ROGUE -std=c++11 -arch x86_64 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib |
|||
CFLAGS = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared |
|||
CFLAGS_WIN = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/x86_64-w64-mingw32/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared |
|||
DEBUGFLAGS = -O0 -D _DEBUG |
|||
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program |
|||
$(info $(OS)) |
|||
OS := $(shell uname -s) |
|||
$(info $(OS)) |
|||
TARGET = librogue.so |
|||
TARGET_DARWIN = librogue.dylib |
|||
TARGET_WIN = librogue.dll |
|||
SOURCES = cclib.cpp |
|||
#HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ |
|||
|
|||
all: $(TARGET) |
|||
|
|||
$(TARGET): $(SOURCES) |
|||
$(info Building cclib to src/) |
|||
ifeq ($(OS),Darwin) |
|||
$(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) -c $(SOURCES) |
|||
cp $(TARGET_DARWIN) ../libcc.dylib |
|||
else ifeq ($(HOST),x86_64-w64-mingw32) |
|||
$(info WINDOWS) |
|||
$(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) -c $(SOURCES) |
|||
cp $(TARGET_WIN) ../libcc.dll |
|||
#else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host |
|||
else |
|||
$(info LINUX) |
|||
$(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES) |
|||
cp $(TARGET) ../libcc.so |
|||
endif |
|||
|
|||
clean: |
|||
rm -rf $(TARGET) |
File diff suppressed because one or more lines are too long
@ -0,0 +1,475 @@ |
|||
#include <stdint.h> |
|||
|
|||
/*
|
|||
#ifndef CPUCYCLES_H |
|||
#define CPUCYCLES_H |
|||
|
|||
#ifdef DBENCH |
|||
#define DBENCH_START() uint64_t time = cpucycles_start() |
|||
#define DBENCH_STOP(t) t += cpucycles_stop() - time - timing_overhead |
|||
#else |
|||
#define DBENCH_START() |
|||
#define DBENCH_STOP(t) |
|||
#endif |
|||
|
|||
#ifdef USE_RDPMC // Needs echo 2 > /sys/devices/cpu/rdpmc
|
|||
#ifdef SERIALIZE_RDC |
|||
|
|||
static inline uint64_t cpucycles_start(void) { |
|||
const uint32_t ecx = (1U << 30) + 1; |
|||
uint64_t result; |
|||
|
|||
asm volatile("cpuid; movl %1,%%ecx; rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax" |
|||
: "=&a" (result) : "r" (ecx) : "rbx", "rcx", "rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
static inline uint64_t cpucycles_stop(void) { |
|||
const uint32_t ecx = (1U << 30) + 1; |
|||
uint64_t result, dummy; |
|||
|
|||
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax; movq %%rax,%0; cpuid" |
|||
: "=&r" (result), "=c" (dummy) : "c" (ecx) : "rax", "rbx", "rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
#else |
|||
|
|||
static inline uint64_t cpucycles_start(void) { |
|||
const uint32_t ecx = (1U << 30) + 1; |
|||
uint64_t result; |
|||
|
|||
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax" |
|||
: "=a" (result) : "c" (ecx) : "rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
static inline uint64_t cpucycles_stop(void) { |
|||
const uint32_t ecx = (1U << 30) + 1; |
|||
uint64_t result; |
|||
|
|||
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax" |
|||
: "=a" (result) : "c" (ecx) : "rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
#endif |
|||
#else |
|||
#ifdef SERIALIZE_RDC |
|||
|
|||
static inline uint64_t cpucycles_start(void) { |
|||
uint64_t result; |
|||
|
|||
asm volatile("cpuid; rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax" |
|||
: "=a" (result) : : "%rbx", "%rcx", "%rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
static inline uint64_t cpucycles_stop(void) { |
|||
uint64_t result; |
|||
|
|||
asm volatile("rdtscp; shlq $32,%%rdx; orq %%rdx,%%rax; mov %%rax,%0; cpuid" |
|||
: "=r" (result) : : "%rax", "%rbx", "%rcx", "%rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
#else |
|||
|
|||
static inline uint64_t cpucycles_start(void) { |
|||
uint64_t result; |
|||
|
|||
asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax" |
|||
: "=a" (result) : : "%rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
static inline uint64_t cpucycles_stop(void) { |
|||
uint64_t result; |
|||
|
|||
asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax" |
|||
: "=a" (result) : : "%rdx"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
#endif |
|||
#endif |
|||
|
|||
int64_t cpucycles_overhead(void); |
|||
|
|||
#endif*/ |
|||
|
|||
#ifndef FIPS202_H |
|||
#define FIPS202_H |
|||
|
|||
|
|||
#define SHAKE128_RATE 168 |
|||
#define SHAKE256_RATE 136 |
|||
|
|||
void shake128_absorb(uint64_t *s, |
|||
const uint8_t *input, |
|||
int32_t inlen); |
|||
|
|||
void shake128_squeezeblocks(uint8_t *output, |
|||
int32_t nblocks, |
|||
uint64_t *s); |
|||
|
|||
void shake256_absorb(uint64_t *s, |
|||
const uint8_t *input, |
|||
int32_t inlen); |
|||
|
|||
void shake256_squeezeblocks(uint8_t *output, |
|||
int32_t nblocks, |
|||
uint64_t *s); |
|||
|
|||
void shake128(uint8_t *output, |
|||
int32_t outlen, |
|||
const uint8_t *input, |
|||
int32_t inlen); |
|||
|
|||
void shake256(uint8_t *output, |
|||
int32_t outlen, |
|||
const uint8_t *input, |
|||
int32_t inlen); |
|||
|
|||
#endif |
|||
|
|||
#ifndef PARAMS_H |
|||
#define PARAMS_H |
|||
|
|||
#ifndef MODE |
|||
#define MODE 3 |
|||
#endif |
|||
|
|||
#define SEEDBYTES 32U |
|||
#define CRHBYTES 48U |
|||
#define N 256U |
|||
#define Q 8380417U |
|||
#define QBITS 23U |
|||
#define ROOT_OF_UNITY 1753U |
|||
#define D 14U |
|||
#define GAMMA1 ((Q - 1U)/16U) |
|||
#define GAMMA2 (GAMMA1/2U) |
|||
#define ALPHA (2U*GAMMA2) |
|||
|
|||
#if MODE == 0 |
|||
#define K 3U |
|||
#define L 2U |
|||
#define ETA 7U |
|||
#define SETABITS 4U |
|||
#define BETA 375U |
|||
#define OMEGA 64U |
|||
|
|||
#elif MODE == 1 |
|||
#define K 4U |
|||
#define L 3U |
|||
#define ETA 6U |
|||
#define SETABITS 4U |
|||
#define BETA 325U |
|||
#define OMEGA 80U |
|||
|
|||
#elif MODE == 2 |
|||
#define K 5U |
|||
#define L 4U |
|||
#define ETA 5U |
|||
#define SETABITS 4U |
|||
#define BETA 275U |
|||
#define OMEGA 96U |
|||
|
|||
#elif MODE == 3 |
|||
#define K 6U |
|||
#define L 5U |
|||
#define ETA 3U |
|||
#define SETABITS 3U |
|||
#define BETA 175U |
|||
#define OMEGA 120U |
|||
|
|||
#endif |
|||
|
|||
#define POL_SIZE_PACKED ((N*QBITS)/8) |
|||
#define POLT1_SIZE_PACKED ((N*(QBITS - D))/8) |
|||
#define POLT0_SIZE_PACKED ((N*D)/8) |
|||
#define POLETA_SIZE_PACKED ((N*SETABITS)/8) |
|||
#define POLZ_SIZE_PACKED ((N*(QBITS - 3))/8) |
|||
#define POLW1_SIZE_PACKED ((N*4)/8) |
|||
#define POLVECK_SIZE_PACKED (K*POL_SIZE_PACKED) |
|||
#define POLVECL_SIZE_PACKED (L*POL_SIZE_PACKED) |
|||
|
|||
#define CRYPTO_PUBLICKEYBYTES (SEEDBYTES + K*POLT1_SIZE_PACKED) |
|||
#define CRYPTO_SECRETKEYBYTES (2*SEEDBYTES + (L + K)*POLETA_SIZE_PACKED + CRHBYTES + K*POLT0_SIZE_PACKED) |
|||
#define CRYPTO_BYTES (L*POLZ_SIZE_PACKED + (OMEGA + K) + (N/8 + 8)) |
|||
|
|||
#endif |
|||
#ifndef POLY_H |
|||
#define POLY_H |
|||
|
|||
//#include <stdint.h>
|
|||
//#include "params.h"
|
|||
//#include "fips202.h"
|
|||
|
|||
typedef struct { |
|||
uint32_t coeffs[N]; |
|||
} poly __attribute__((aligned(32))); |
|||
|
|||
void poly_reduce(poly *a); |
|||
void poly_csubq(poly *a); |
|||
void poly_freeze(poly *a); |
|||
|
|||
void poly_add(poly *c, const poly *a, const poly *b); |
|||
void poly_sub(poly *c, const poly *a, const poly *b); |
|||
void poly_neg(poly *a); |
|||
void poly_shiftl(poly *a, uint32_t k); |
|||
|
|||
void poly_ntt(poly *a); |
|||
void poly_invntt_montgomery(poly *a); |
|||
void poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b); |
|||
|
|||
void poly_power2round(poly *a1, poly *a0, const poly *a); |
|||
void poly_decompose(poly *a1, poly *a0, const poly *a); |
|||
uint32_t poly_make_hint(poly *h, const poly *a, const poly *b); |
|||
void poly_use_hint(poly *a, const poly *b, const poly *h); |
|||
|
|||
int poly_chknorm(const poly *a, uint32_t B); |
|||
void poly_uniform(poly *a, const uint8_t *buf); |
|||
void poly_uniform_eta(poly *a, |
|||
const uint8_t seed[SEEDBYTES], |
|||
uint8_t nonce); |
|||
void poly_uniform_gamma1m1(poly *a, |
|||
const uint8_t seed[SEEDBYTES + CRHBYTES], |
|||
uint16_t nonce); |
|||
|
|||
void polyeta_pack(uint8_t *r, const poly *a); |
|||
void polyeta_unpack(poly *r, const uint8_t *a); |
|||
|
|||
void polyt1_pack(uint8_t *r, const poly *a); |
|||
void polyt1_unpack(poly *r, const uint8_t *a); |
|||
|
|||
void polyt0_pack(uint8_t *r, const poly *a); |
|||
void polyt0_unpack(poly *r, const uint8_t *a); |
|||
|
|||
void polyz_pack(uint8_t *r, const poly *a); |
|||
void polyz_unpack(poly *r, const uint8_t *a); |
|||
|
|||
void polyw1_pack(uint8_t *r, const poly *a); |
|||
#endif |
|||
#ifndef POLYVEC_H |
|||
#define POLYVEC_H |
|||
|
|||
//#include <stdint.h>
|
|||
//#include "params.h"
|
|||
//#include "poly.h"
|
|||
|
|||
/* Vectors of polynomials of length L */ |
|||
typedef struct { |
|||
poly vec[L]; |
|||
} polyvecl; |
|||
|
|||
void polyvecl_freeze(polyvecl *v); |
|||
|
|||
void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v); |
|||
|
|||
void polyvecl_ntt(polyvecl *v); |
|||
void polyvecl_pointwise_acc_invmontgomery(poly *w, |
|||
const polyvecl *u, |
|||
const polyvecl *v); |
|||
|
|||
int polyvecl_chknorm(const polyvecl *v, uint32_t B); |
|||
|
|||
|
|||
|
|||
/* Vectors of polynomials of length K */ |
|||
typedef struct { |
|||
poly vec[K]; |
|||
} polyveck; |
|||
|
|||
void polyveck_reduce(polyveck *v); |
|||
void polyveck_csubq(polyveck *v); |
|||
void polyveck_freeze(polyveck *v); |
|||
|
|||
void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v); |
|||
void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v); |
|||
void polyveck_shiftl(polyveck *v, uint32_t k); |
|||
|
|||
void polyveck_ntt(polyveck *v); |
|||
void polyveck_invntt_montgomery(polyveck *v); |
|||
|
|||
int polyveck_chknorm(const polyveck *v, uint32_t B); |
|||
|
|||
void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v); |
|||
void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v); |
|||
uint32_t polyveck_make_hint(polyveck *h, |
|||
const polyveck *u, |
|||
const polyveck *v); |
|||
void polyveck_use_hint(polyveck *w, const polyveck *v, const polyveck *h); |
|||
|
|||
#endif |
|||
|
|||
#ifndef NTT_H |
|||
#define NTT_H |
|||
|
|||
//#include <stdint.h>
|
|||
//#include "params.h"
|
|||
|
|||
void ntt(uint32_t p[N]); |
|||
void invntt_frominvmont(uint32_t p[N]); |
|||
|
|||
#endif |
|||
#ifndef PACKING_H |
|||
#define PACKING_H |
|||
|
|||
//#include "params.h"
|
|||
//#include "polyvec.h"
|
|||
|
|||
void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES], |
|||
const uint8_t rho[SEEDBYTES], const polyveck *t1); |
|||
void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], |
|||
const uint8_t rho[SEEDBYTES], |
|||
const uint8_t key[SEEDBYTES], |
|||
const uint8_t tr[CRHBYTES], |
|||
const polyvecl *s1, |
|||
const polyveck *s2, |
|||
const polyveck *t0); |
|||
void pack_sig(uint8_t sig[CRYPTO_BYTES], |
|||
const polyvecl *z, const polyveck *h, const poly *c); |
|||
|
|||
void unpack_pk(uint8_t rho[SEEDBYTES], polyveck *t1, |
|||
const uint8_t pk[CRYPTO_PUBLICKEYBYTES]); |
|||
void unpack_sk(uint8_t rho[SEEDBYTES], |
|||
uint8_t key[SEEDBYTES], |
|||
uint8_t tr[CRHBYTES], |
|||
polyvecl *s1, |
|||
polyveck *s2, |
|||
polyveck *t0, |
|||
const uint8_t sk[CRYPTO_SECRETKEYBYTES]); |
|||
int unpack_sig(polyvecl *z, polyveck *h, poly *c, |
|||
const uint8_t sig[CRYPTO_BYTES]); |
|||
|
|||
#endif |
|||
#ifndef REDUCE_H |
|||
#define REDUCE_H |
|||
|
|||
//#include <stdint.h>
|
|||
|
|||
#define MONT 4193792U // 2^32 % Q
|
|||
#define QINV 4236238847U // -q^(-1) mod 2^32
|
|||
|
|||
/* a <= Q*2^32 => r < 2*Q */ |
|||
uint32_t montgomery_reduce(uint64_t a); |
|||
|
|||
/* r < 2*Q */ |
|||
uint32_t reduce32(uint32_t a); |
|||
|
|||
/* a < 2*Q => r < Q */ |
|||
uint32_t csubq(uint32_t a); |
|||
|
|||
/* r < Q */ |
|||
uint32_t freeze(uint32_t a); |
|||
|
|||
#endif |
|||
#ifndef ROUNDING_H |
|||
#define ROUNDING_H |
|||
|
|||
//#include <stdint.h>
|
|||
|
|||
uint32_t power2round(const uint32_t a, uint32_t *a0); |
|||
uint32_t decompose(uint32_t a, uint32_t *a0); |
|||
uint32_t make_hint(const uint32_t a, const uint32_t b); |
|||
uint32_t use_hint(const uint32_t a, const uint32_t hint); |
|||
|
|||
#endif |
|||
#ifndef SIGN_H |
|||
#define SIGN_H |
|||
|
|||
//#include "params.h"
|
|||
//#include "poly.h"
|
|||
//#include "polyvec.h"
|
|||
|
|||
void expand_mat(polyvecl mat[K], const uint8_t rho[SEEDBYTES]); |
|||
void challenge(poly *c, const uint8_t mu[CRHBYTES], |
|||
const polyveck *w1); |
|||
|
|||
int crypto_sign_keypair(uint8_t *pk, uint8_t *sk); |
|||
|
|||
int crypto_sign(uint8_t *sm, int32_t *smlen, |
|||
const uint8_t *msg, int32_t len, |
|||
const uint8_t *sk); |
|||
|
|||
int crypto_sign_open(uint8_t *m, int32_t *mlen, |
|||
const uint8_t *sm, int32_t smlen, |
|||
const uint8_t *pk); |
|||
|
|||
#endif |
|||
|
|||
#ifndef API_H |
|||
#define API_H |
|||
|
|||
#ifndef MODE |
|||
#define MODE 3 |
|||
#endif |
|||
|
|||
#if MODE == 0 |
|||
#if CRYPTO_PUBLICKEYBYTES -896U |
|||
CRYPTO_PUBLICKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_SECRETKEYBYTES -2096U |
|||
CRYPTO_SECRETKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_BYTES -1387U |
|||
CRYPTO_BYTES size error |
|||
#endif |
|||
|
|||
#elif MODE == 1 |
|||
#if CRYPTO_PUBLICKEYBYTES -1184U |
|||
CRYPTO_PUBLICKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_SECRETKEYBYTES -2800U |
|||
CRYPTO_SECRETKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_BYTES -2044U |
|||
CRYPTO_BYTES size error |
|||
#endif |
|||
|
|||
#elif MODE == 2 |
|||
#if CRYPTO_PUBLICKEYBYTES -1472U |
|||
CRYPTO_PUBLICKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_SECRETKEYBYTES -3504U |
|||
CRYPTO_SECRETKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_BYTES -2701U |
|||
CRYPTO_BYTES size error |
|||
#endif |
|||
|
|||
#elif MODE == 3 |
|||
#if CRYPTO_PUBLICKEYBYTES -1760U |
|||
CRYPTO_PUBLICKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_SECRETKEYBYTES -3856U |
|||
CRYPTO_SECRETKEYBYTES size error |
|||
#endif |
|||
#if CRYPTO_BYTES -3366U |
|||
CRYPTO_BYTES size error |
|||
#endif |
|||
|
|||
#endif |
|||
|
|||
#define CRYPTO_ALGNAME "Dilithium" |
|||
|
|||
int crypto_sign_keypair(uint8_t *pk, uint8_t *sk); |
|||
|
|||
int crypto_sign(uint8_t *sm, int32_t *smlen, |
|||
const uint8_t *msg, int32_t len, |
|||
const uint8_t *sk); |
|||
|
|||
int crypto_sign_open(uint8_t *m, int32_t *mlen, |
|||
const uint8_t *sm, int32_t smlen, |
|||
const uint8_t *pk); |
|||
|
|||
#endif |
@ -1,2 +1,2 @@ |
|||
#!/bin/sh |
|||
gcc -std=c++11 -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp |
|||
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp |
|||
|
@ -1,8 +1,38 @@ |
|||
#!/bin/sh |
|||
cd rogue; |
|||
./configure # only need this first time |
|||
make; cd .. |
|||
gcc -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -o librogue.so -c cclib.cpp |
|||
#gcc -std=c++11 -fPIC -shared -o librogue.so cclib.o rogue/rogue.so |
|||
cp librogue.so ../libcc.so |
|||
|
|||
if [ "$HOST" = "x86_64-w64-mingw32" ]; then |
|||
echo building rogue.exe... |
|||
./configure --host=x86_64-w64-mingw32 |
|||
mkdir ncurses && cd ncurses |
|||
echo $PWD |
|||
wget https://invisible-island.net/datafiles/release/mingw32.zip |
|||
unzip mingw32.zip && rm mingw32.zip |
|||
echo lib archive cleaned |
|||
cd .. |
|||
echo $PWD |
|||
if make -f Makefile_win "$@"; then |
|||
echo rogue.exe build SUCCESSFUL |
|||
cd .. |
|||
else |
|||
echo rogue.exe build FAILED |
|||
exit 1 |
|||
fi |
|||
else |
|||
echo building rogue... |
|||
./configure |
|||
if make "$@"; then |
|||
echo rogue build SUCCESSFUL |
|||
cd .. |
|||
else |
|||
echo rogue build FAILED |
|||
exit 1 |
|||
fi |
|||
fi |
|||
|
|||
if make -f Makefile_rogue "$@"; then |
|||
echo ROGUE BUILD SUCCESSFUL |
|||
else |
|||
echo ROGUE BUILD FAILED |
|||
exit 1 |
|||
fi |
|||
|
@ -0,0 +1,868 @@ |
|||
/******************************************************************************
|
|||
* Copyright © 2014-2019 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. * |
|||
* * |
|||
******************************************************************************/ |
|||
|
|||
/* first make a combined pk:
|
|||
|
|||
./komodo-cli -ac_name=MUSIG cclib combine 18 '["02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28","0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4"]' |
|||
{ |
|||
"pkhash": "5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b", |
|||
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b", |
|||
"result": "success" |
|||
} |
|||
|
|||
the combined_pk and pkhash will be needed for various other rpc calls |
|||
|
|||
second, send 1 coin to the combined_pk |
|||
./komodo-cli -ac_name=MUSIG cclib send 18 '["03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",1]' |
|||
{ |
|||
"hex": "0400008085202f8901a980664dffc810725a79ffb89ac48be4c7b6bade9b789732fcf871acf8e81a2e010000006a47304402207e52763661ecd2c34a65d6623950be11794825db71576dc11894c606ddc317800220028fef46dc20630d0fdf22647b5d4ff0f1c47cf75f48702d0a91d5589eff99d001210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ffffffff031008f60500000000302ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cce09aa4350000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000266a2412782103f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b00000000920500000000000000000000000000", |
|||
"txid": "5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c", |
|||
"result": "success" |
|||
} |
|||
|
|||
sendrawtransaction of the above hex. |
|||
./komodo-cli -ac_name=MUSIG getrawtransaction 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c 1 |
|||
"vout": [ |
|||
{ |
|||
"value": 1.00010000, |
|||
"valueSat": 100010000, |
|||
"n": 0, |
|||
"scriptPubKey": { |
|||
"asm": "a22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401 OP_CHECKCRYPTOCONDITION", |
|||
"hex": "2ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cc", |
|||
"reqSigs": 1, |
|||
"type": "cryptocondition", |
|||
"addresses": [ |
|||
"RKWS7jxyjPX9iaJttk8iMKf1AumanKypez" |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
"value": 8.99980000, |
|||
"valueSat": 899980000, |
|||
"n": 1, |
|||
"scriptPubKey": { |
|||
"asm": "0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4 OP_CHECKSIG", |
|||
"hex": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac", |
|||
"reqSigs": 1, |
|||
"type": "pubkey", |
|||
"addresses": [ |
|||
"RVQjvGdRbYLJ49bfH4SAFseipvwE3UdoDw" |
|||
] |
|||
} |
|||
|
|||
script: 210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac |
|||
|
|||
sendtxid: 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c |
|||
|
|||
get the msg we need to sign: |
|||
|
|||
./komodo-cli -ac_name=MUSIG cclib calcmsg 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac"]' |
|||
|
|||
{ |
|||
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75", |
|||
"result": "success" |
|||
} |
|||
|
|||
the "msg" is what needs to be signed to create a valid spend |
|||
|
|||
now on each signing node, a session needs to be created: |
|||
5 args: ind, numsigners, combined_pk, pkhash, message to be signed |
|||
|
|||
on node with pubkey: 02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28 |
|||
./komodo-cli -ac_name=MUSIG cclib session 18 '[0,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]' |
|||
{ |
|||
"myind": 0, |
|||
"numsigners": 2, |
|||
"commitment": "bbea1f2562eca01b9a1393c5dc188bdd44551aebf684f4459930f59dde01f7ae", |
|||
"result": "success" |
|||
} |
|||
|
|||
on node with pubkey: 0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4 |
|||
./komodo-cli -ac_name=MUSIG cclib session 18 '[1,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]' |
|||
{ |
|||
"myind": 1, |
|||
"numsigners": 2, |
|||
"commitment": "c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851", |
|||
"result": "success" |
|||
} |
|||
|
|||
now we need to get the commitment from each node to the other one. the session already put the commitment for each node into the global struct. Keep in mind there is a single global struct with session unique to each cclib session call. that means no restarting any deamon in the middle of the process on any of the nodes and only call cclib session a single time. this is an artificial restriction just to simplify the initial implementation of musig |
|||
./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851"]' |
|||
{ |
|||
"added_index": 1, |
|||
"myind": 0, |
|||
"nonce": "02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b", |
|||
"result": "success" |
|||
} |
|||
|
|||
./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"d242cff13fa8c9b83248e4219fda459ada146b885f2171481f1b0f66c66d94ad"]' |
|||
{ |
|||
"added_index": 0, |
|||
"myind": 1, |
|||
"nonce": "039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c", |
|||
"result": "success" |
|||
} |
|||
|
|||
Now exchange the revealed nonces to each node: |
|||
./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c"]' |
|||
{ |
|||
"added_index": 1, |
|||
"myind": 0, |
|||
"partialsig": "1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b", |
|||
"result": "success" |
|||
} |
|||
|
|||
./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b"]' |
|||
{ |
|||
"added_index": 0, |
|||
"myind": 1, |
|||
"partialsig": "4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e", |
|||
"result": "success" |
|||
} |
|||
|
|||
Almost there! final step is to exchange the partial sigs between signers |
|||
./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e"]' |
|||
{ |
|||
"added_index": 1, |
|||
"result": "success", |
|||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9" |
|||
} |
|||
|
|||
./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b"]' |
|||
{ |
|||
"added_index": 0, |
|||
"result": "success", |
|||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9" |
|||
} |
|||
|
|||
Notice both nodes generated the same combined signature! |
|||
|
|||
Now for a sanity test, we can use the verify call to make sure this sig will work with the msg needed for the spend: |
|||
|
|||
./komodo-cli -ac_name=MUSIG cclib verify 18 '["f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75","03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]' |
|||
{ |
|||
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75", |
|||
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b", |
|||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9", |
|||
"result": "success" |
|||
} |
|||
|
|||
and finally the spend: sendtxid, scriptPubKey, musig |
|||
|
|||
./komodo-cli -ac_name=MUSIG cclib spend 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]' |
|||
{ |
|||
"scriptpubkey": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac", |
|||
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75", |
|||
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b", |
|||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9", |
|||
"hex": "0400008085202f89014c821930f9eb360daaf1a1e12d5a82998b63884e8db4130421ee53a13740e75c000000007b4c79a276a072a26ba067a5658021032d29d6545a2aafad795d9cf50912ecade549137 |
|||
163934dfb2895ebc0e211ce8a81409671a60db89b3bc58966f3acc80194479b1a43d868e95a11ebc5609646d18710341a8ff92a7817571980307f5d660cc00a2735ac6333e0a7191243f1263f1959a100af03800112 |
|||
a10001ffffffff0200e1f5050000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000686a4c6512792103f016c348437c7422eed92d865aa9789614f |
|||
75327cada463eefc566126b54785b40a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f900000000a805 |
|||
00000000000000000000000000", |
|||
"txid": "910635bf69a047fc90567a83ff12e47b753f470658b6d0855ec96e07e7349a8a", |
|||
"result": "success" |
|||
} |
|||
*/ |
|||
|
|||
|
|||
#define USE_BASIC_CONFIG |
|||
#define ENABLE_MODULE_MUSIG |
|||
#include "../secp256k1/src/basic-config.h" |
|||
#include "../secp256k1/include/secp256k1.h" |
|||
#include "../secp256k1/src/ecmult.h" |
|||
#include "../secp256k1/src/ecmult_gen.h" |
|||
|
|||
typedef struct { unsigned char data[64]; } secp256k1_schnorrsig; |
|||
struct secp256k1_context_struct { |
|||
secp256k1_ecmult_context ecmult_ctx; |
|||
secp256k1_ecmult_gen_context ecmult_gen_ctx; |
|||
secp256k1_callback illegal_callback; |
|||
secp256k1_callback error_callback; |
|||
}; |
|||
|
|||
|
|||
//#include "../secp256k1/include/secp256k1.h"
|
|||
//#include "../secp256k1/include/secp256k1_schnorrsig.h"
|
|||
#include "../secp256k1/include/secp256k1_musig.h" |
|||
|
|||
|
|||
extern "C" int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); |
|||
extern "C" int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk); |
|||
extern "C" int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64); |
|||
extern "C" int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys); |
|||
extern "C" int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey); |
|||
extern "C" int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig); |
|||
|
|||
#define MUSIG_PREVN 0 // for now, just use vout0 for the musig output
|
|||
#define MUSIG_TXFEE 10000 |
|||
|
|||
struct musig_info |
|||
{ |
|||
secp256k1_musig_session session; |
|||
secp256k1_pubkey combined_pk; |
|||
uint8_t *nonce_commitments,**commitment_ptrs; // 32*N_SIGNERS
|
|||
secp256k1_musig_session_signer_data *signer_data; //[N_SIGNERS];
|
|||
secp256k1_pubkey *nonces; //[N_SIGNERS];
|
|||
secp256k1_musig_partial_signature *partial_sig; //[N_SIGNERS];
|
|||
int32_t myind,num,numcommits,numnonces,numpartials; |
|||
uint8_t msg[32],pkhash[32],combpk[33]; |
|||
}; |
|||
|
|||
std::vector <struct musig_info *> MUSIG; |
|||
|
|||
struct musig_info *musig_infocreate(int32_t myind,int32_t num) |
|||
{ |
|||
int32_t i; struct musig_info *mp = (struct musig_info *)calloc(1,sizeof(*mp)); |
|||
mp->myind = myind, mp->num = num; |
|||
mp->nonce_commitments = (uint8_t *)calloc(num,32); |
|||
mp->commitment_ptrs = (uint8_t **)calloc(num,sizeof(*mp->commitment_ptrs)); |
|||
for (i=0; i<num; i++) |
|||
mp->commitment_ptrs[i] = &mp->nonce_commitments[i*32]; |
|||
mp->signer_data = (secp256k1_musig_session_signer_data *)calloc(num,sizeof(*mp->signer_data)); |
|||
mp->nonces = (secp256k1_pubkey *)calloc(num,sizeof(*mp->nonces)); |
|||
mp->partial_sig = (secp256k1_musig_partial_signature *)calloc(num,sizeof(*mp->partial_sig)); |
|||
return(mp); |
|||
} |
|||
|
|||
void musig_infofree(struct musig_info *mp) |
|||
{ |
|||
if ( mp->partial_sig != 0 ) |
|||
{ |
|||
GetRandBytes((uint8_t *)mp->partial_sig,mp->num*sizeof(*mp->partial_sig)); |
|||
free(mp->partial_sig); |
|||
} |
|||
if ( mp->nonces != 0 ) |
|||
{ |
|||
GetRandBytes((uint8_t *)mp->nonces,mp->num*sizeof(*mp->nonces)); |
|||
free(mp->nonces); |
|||
} |
|||
if ( mp->signer_data != 0 ) |
|||
{ |
|||
GetRandBytes((uint8_t *)mp->signer_data,mp->num*sizeof(*mp->signer_data)); |
|||
free(mp->signer_data); |
|||
} |
|||
if ( mp->nonce_commitments != 0 ) |
|||
{ |
|||
GetRandBytes((uint8_t *)mp->nonce_commitments,mp->num*32); |
|||
free(mp->nonce_commitments); |
|||
} |
|||
if ( mp->commitment_ptrs != 0 ) |
|||
{ |
|||
GetRandBytes((uint8_t *)mp->commitment_ptrs,mp->num*sizeof(*mp->commitment_ptrs)); |
|||
free(mp->commitment_ptrs); |
|||
} |
|||
GetRandBytes((uint8_t *)mp,sizeof(*mp)); |
|||
free(mp); |
|||
} |
|||
|
|||
CScript musig_sendopret(uint8_t funcid,CPubKey pk) |
|||
{ |
|||
CScript opret; uint8_t evalcode = EVAL_MUSIG; |
|||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk); |
|||
return(opret); |
|||
} |
|||
|
|||
uint8_t musig_sendopretdecode(CPubKey &pk,CScript scriptPubKey) |
|||
{ |
|||
std::vector<uint8_t> vopret; uint8_t e,f; |
|||
GetOpReturnData(scriptPubKey,vopret); |
|||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_MUSIG && f == 'x' ) |
|||
{ |
|||
return(f); |
|||
} |
|||
return(0); |
|||
} |
|||
|
|||
CScript musig_spendopret(uint8_t funcid,CPubKey pk,std::vector<uint8_t> musig64) |
|||
{ |
|||
CScript opret; uint8_t evalcode = EVAL_MUSIG; |
|||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk << musig64); |
|||
return(opret); |
|||
} |
|||
|
|||
uint8_t musig_spendopretdecode(CPubKey &pk,std::vector<uint8_t> &musig64,CScript scriptPubKey) |
|||
{ |
|||
std::vector<uint8_t> vopret; uint8_t e,f; |
|||
GetOpReturnData(scriptPubKey,vopret); |
|||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk; ss >> musig64) != 0 && e == EVAL_MUSIG && f == 'y' ) |
|||
{ |
|||
return(f); |
|||
} |
|||
return(0); |
|||
} |
|||
|
|||
int32_t musig_parsepubkey(secp256k1_context *ctx,secp256k1_pubkey &spk,cJSON *item) |
|||
{ |
|||
char *hexstr; |
|||
if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == 66 ) |
|||
{ |
|||
CPubKey pk(ParseHex(hexstr)); |
|||
if ( secp256k1_ec_pubkey_parse(ctx,&spk,pk.begin(),33) > 0 ) |
|||
return(1); |
|||
} else return(-1); |
|||
} |
|||
|
|||
int32_t musig_msghash(uint8_t *msg,uint256 prevhash,int32_t prevn,CTxOut vout,CPubKey pk) |
|||
{ |
|||
CScript data; uint256 hash; int32_t len = 0; |
|||
data << E_MARSHAL(ss << prevhash << prevn << vout << pk); |
|||
hash = Hash(data.begin(),data.end()); |
|||
memcpy(msg,&hash,sizeof(hash)); |
|||
return(0); |
|||
} |
|||
|
|||
int32_t musig_prevoutmsg(uint8_t *msg,uint256 sendtxid,CScript scriptPubKey) |
|||
{ |
|||
CTransaction vintx; uint256 hashBlock; int32_t numvouts; CTxOut vout; CPubKey pk; |
|||
memset(msg,0,32); |
|||
if ( myGetTransaction(sendtxid,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 ) |
|||
{ |
|||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' ) |
|||
{ |
|||
vout.nValue = vintx.vout[MUSIG_PREVN].nValue - MUSIG_TXFEE; |
|||
vout.scriptPubKey = scriptPubKey; |
|||
return(musig_msghash(msg,sendtxid,MUSIG_PREVN,vout,pk)); |
|||
} |
|||
} |
|||
return(-1); |
|||
} |
|||
|
|||
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
UniValue result(UniValue::VOBJ); uint256 sendtxid; int32_t i,zeros=0; uint8_t msg[32]; char *scriptstr,str[65]; int32_t n; |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) |
|||
{ |
|||
if ( n == 2 ) |
|||
{ |
|||
sendtxid = juint256(jitem(params,0)); |
|||
scriptstr = jstr(jitem(params,1),0); |
|||
if ( is_hexstr(scriptstr,0) != 0 ) |
|||
{ |
|||
CScript scriptPubKey; |
|||
scriptPubKey.resize(strlen(scriptstr)/2); |
|||
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr); |
|||
musig_prevoutmsg(msg,sendtxid,scriptPubKey); |
|||
for (i=0; i<32; i++) |
|||
{ |
|||
sprintf(&str[i<<1],"%02x",msg[i]); |
|||
if ( msg[i] == 0 ) |
|||
zeros++; |
|||
} |
|||
str[64] = 0; |
|||
if ( zeros != 32 ) |
|||
{ |
|||
result.push_back(Pair("msg",str)); |
|||
result.push_back(Pair("result","success")); |
|||
return(result); |
|||
} else return(cclib_error(result,"null result, make sure params are sendtxid, scriptPubKey")); |
|||
} else return(cclib_error(result,"script is not hex")); |
|||
} else return(cclib_error(result,"need exactly 2 parameters: sendtxid, scriptPubKey")); |
|||
} else return(cclib_error(result,"couldnt parse params")); |
|||
} |
|||
|
|||
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
size_t clen = CPubKey::PUBLIC_KEY_SIZE; |
|||
UniValue result(UniValue::VOBJ); CPubKey pk; int32_t i,n; uint8_t pkhash[32]; char *hexstr,str[67]; secp256k1_pubkey combined_pk,spk; std::vector<secp256k1_pubkey> pubkeys; |
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) |
|||
{ |
|||
//fprintf(stderr,"n.%d args.(%s)\n",n,jprint(params,0));
|
|||
for (i=0; i<n; i++) |
|||
{ |
|||
if ( musig_parsepubkey(ctx,spk,jitem(params,i)) < 0 ) |
|||
return(cclib_error(result,"error parsing pk")); |
|||
pubkeys.push_back(spk); |
|||
} |
|||
if ( secp256k1_musig_pubkey_combine(ctx,NULL,&combined_pk,pkhash,&pubkeys[0],n) > 0 ) |
|||
{ |
|||
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&combined_pk,SECP256K1_EC_COMPRESSED) > 0 && clen == 33 ) |
|||
{ |
|||
for (i=0; i<32; i++) |
|||
sprintf(&str[i<<1],"%02x",pkhash[i]); |
|||
str[64] = 0; |
|||
result.push_back(Pair("pkhash",str)); |
|||
|
|||
for (i=0; i<33; i++) |
|||
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]); |
|||
str[66] = 0; |
|||
result.push_back(Pair("combined_pk",str)); |
|||
result.push_back(Pair("result","success")); |
|||
return(result); |
|||
} else return(cclib_error(result,"error serializeing combined_pk")); |
|||
} else return(cclib_error(result,"error combining pukbeys")); |
|||
} else return(cclib_error(result,"need pubkeys params")); |
|||
} |
|||
|
|||
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
UniValue result(UniValue::VOBJ); int32_t i,n,myind,num,musiglocation; char *pkstr,*pkhashstr,*msgstr; uint8_t session[32],msg[32],pkhash[32],privkey[32],pub33[33]; CPubKey pk; char str[67]; |
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 5 ) |
|||
{ |
|||
myind = juint(jitem(params,0),0); |
|||
num = juint(jitem(params,1),0); |
|||
if ( myind < 0 || myind >= num || num <= 0 ) |
|||
return(cclib_error(result,"illegal myindex and numsigners")); |
|||
if ( n > 5 ) |
|||
musiglocation = juint(jitem(params,5),0); |
|||
else if ( n == 5 ) |
|||
musiglocation = 0; |
|||
//printf("number of params.%i musiglocation.%i\n",n,musiglocation);
|
|||
if ( MUSIG.size() > musiglocation ) |
|||
{ |
|||
for (int i = 0; i < MUSIG.size()-1; i++) |
|||
musig_infofree(MUSIG[i]); |
|||
MUSIG.clear(); |
|||
} |
|||
struct musig_info *temp_musig = musig_infocreate(myind,num); |
|||
MUSIG.push_back(temp_musig); |
|||
if ( musig_parsepubkey(ctx,MUSIG[musiglocation]->combined_pk,jitem(params,2)) < 0 ) |
|||
return(cclib_error(result,"error parsing combined_pubkey")); |
|||
else if ( cclib_parsehash(MUSIG[musiglocation]->pkhash,jitem(params,3),32) < 0 ) |
|||
return(cclib_error(result,"error parsing pkhash")); |
|||
else if ( cclib_parsehash(MUSIG[musiglocation]->msg,jitem(params,4),32) < 0 ) |
|||
return(cclib_error(result,"error parsing msg")); |
|||
Myprivkey(privkey); |
|||
GetRandBytes(session,32); |
|||
/** Initializes a signing session for a signer
|
|||
* |
|||
* Returns: 1: session is successfully initialized |
|||
* 0: session could not be initialized: secret key or secret nonce overflow |
|||
* Args: ctx: pointer to a context object, initialized for signing (cannot |
|||
* be NULL) |
|||
* Out: session: the session structure to initialize (cannot be NULL) |
|||
* signers: an array of signers' data to be initialized. Array length must |
|||
* equal to `n_signers` (cannot be NULL) |
|||
* nonce_commitment32: filled with a 32-byte commitment to the generated nonce |
|||
* (cannot be NULL) |
|||
* In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be |
|||
* NULL). If a non-unique session_id32 was given then a partial |
|||
* signature will LEAK THE SECRET KEY. |
|||
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you |
|||
* require sharing public nonces before the message is known |
|||
* because it reduces nonce misuse resistance. If NULL, must be |
|||
* set with `musig_session_set_msg` before signing and verifying. |
|||
* combined_pk: the combined public key of all signers (cannot be NULL) |
|||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be |
|||
* NULL) |
|||
* n_signers: length of signers array. Number of signers participating in |
|||
* the MuSig. Must be greater than 0 and at most 2^32 - 1. |
|||
* my_index: index of this signer in the signers array |
|||
* seckey: the signer's 32-byte secret key (cannot be NULL) |
|||
*/ |
|||
//fprintf(stderr, "SESSION: struct_size.%li using struct %i\n",MUSIG.size(), musiglocation);
|
|||
if ( secp256k1_musig_session_initialize(ctx,&MUSIG[musiglocation]->session,MUSIG[musiglocation]->signer_data, &MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind * 32],session,MUSIG[musiglocation]->msg,&MUSIG[musiglocation]->combined_pk,MUSIG[musiglocation]->pkhash,MUSIG[musiglocation]->num,MUSIG[musiglocation]->myind,privkey) > 0 ) |
|||
{ |
|||
memset(session,0,sizeof(session)); |
|||
result.push_back(Pair("myind",(int64_t)myind)); |
|||
result.push_back(Pair("numsigners",(int64_t)num)); |
|||
for (i=0; i<32; i++) |
|||
sprintf(&str[i<<1],"%02x",MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind*32 + i]); |
|||
str[64] = 0; |
|||
if ( n == 5 ) |
|||
MUSIG[musiglocation]->numcommits = 1; |
|||
result.push_back(Pair("commitment",str)); |
|||
result.push_back(Pair("result","success")); |
|||
return(result); |
|||
} |
|||
else |
|||
{ |
|||
memset(session,0,sizeof(session)); |
|||
return(cclib_error(result,"couldnt initialize session")); |
|||
} |
|||
} else return(cclib_error(result,"wrong number of params, need 5: myindex, numsigners, combined_pk, pkhash, msg32")); |
|||
} |
|||
|
|||
UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
size_t clen = CPubKey::PUBLIC_KEY_SIZE; |
|||
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32]; CPubKey pk; char str[67]; |
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 ) |
|||
{ |
|||
if ( n > 3 ) |
|||
myind = juint(jitem(params,3),0); |
|||
else if ( n == 3 ) |
|||
myind = 0; |
|||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 ) |
|||
return(cclib_error(result,"error parsing pkhash")); |
|||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 ) |
|||
return(cclib_error(result,"pkhash doesnt match session pkhash")); |
|||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num ) |
|||
return(cclib_error(result,"illegal ind for session")); |
|||
else if ( cclib_parsehash(&MUSIG[myind]->nonce_commitments[ind*32],jitem(params,2),32) < 0 ) |
|||
return(cclib_error(result,"error parsing commitment")); |
|||
/** Gets the signer's public nonce given a list of all signers' data with commitments
|
|||
* |
|||
* Returns: 1: public nonce is written in nonce |
|||
* 0: signer data is missing commitments or session isn't initialized |
|||
* for signing |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: the signing session to get the nonce from (cannot be NULL) |
|||
* signers: an array of signers' data initialized with |
|||
* `musig_session_initialize`. Array length must equal to |
|||
* `n_commitments` (cannot be NULL) |
|||
* Out: nonce: the nonce (cannot be NULL) |
|||
* In: commitments: array of 32-byte nonce commitments (cannot be NULL) |
|||
* n_commitments: the length of commitments and signers array. Must be the total |
|||
* number of signers participating in the MuSig. |
|||
*/ |
|||
result.push_back(Pair("added_index",ind)); |
|||
//fprintf(stderr, "COMMIT: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
|
|||
MUSIG[myind]->numcommits++; |
|||
if ( MUSIG[myind]->numcommits >= MUSIG[myind]->num && secp256k1_musig_session_get_public_nonce(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,&MUSIG[myind]->nonces[MUSIG[myind]->myind],MUSIG[myind]->commitment_ptrs,MUSIG[myind]->num) > 0 ) |
|||
{ |
|||
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&MUSIG[myind]->nonces[MUSIG[myind]->myind],SECP256K1_EC_COMPRESSED) > 0 && clen == 33 ) |
|||
{ |
|||
for (i=0; i<33; i++) |
|||
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]); |
|||
str[66] = 0; |
|||
if ( n == 5 ) |
|||
MUSIG[myind]->numnonces = 1; |
|||
result.push_back(Pair("myind",MUSIG[myind]->myind)); |
|||
result.push_back(Pair("nonce",str)); |
|||
result.push_back(Pair("result","success")); |
|||
} else return(cclib_error(result,"error serializing nonce (pubkey)")); |
|||
} |
|||
else |
|||
{ |
|||
result.push_back(Pair("status","not enough commitments")); |
|||
result.push_back(Pair("result","success")); |
|||
} |
|||
return(result); |
|||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, commitment")); |
|||
} |
|||
|
|||
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32],psig[32]; CPubKey pk; char str[67]; |
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 ) |
|||
{ |
|||
if ( n > 3 ) |
|||
myind = juint(jitem(params,3),0); |
|||
else if ( n == 3 ) |
|||
myind = 0; |
|||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 ) |
|||
return(cclib_error(result,"error parsing pkhash")); |
|||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 ) |
|||
return(cclib_error(result,"pkhash doesnt match session pkhash")); |
|||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num ) |
|||
return(cclib_error(result,"illegal ind for session")); |
|||
else if ( musig_parsepubkey(ctx,MUSIG[myind]->nonces[ind],jitem(params,2)) < 0 ) |
|||
return(cclib_error(result,"error parsing nonce")); |
|||
result.push_back(Pair("added_index",ind)); |
|||
/** Checks a signer's public nonce against a commitment to said nonce, and update
|
|||
* data structure if they match |
|||
* |
|||
* Returns: 1: commitment was valid, data structure updated |
|||
* 0: commitment was invalid, nothing happened |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* signer: pointer to the signer data to update (cannot be NULL). Must have |
|||
* been used with `musig_session_get_public_nonce` or initialized |
|||
* with `musig_session_initialize_verifier`. |
|||
* In: nonce: signer's alleged public nonce (cannot be NULL) |
|||
*/ |
|||
MUSIG[myind]->numnonces++; |
|||
//fprintf(stderr, "NONCE: struct_size.%li using_struct.%i added_index.%i numnounces.%i num.%i\n",MUSIG.size(), myind, ind, MUSIG[myind]->numnonces, MUSIG[myind]->num);
|
|||
if ( MUSIG[myind]->numnonces < MUSIG[myind]->num ) |
|||
{ |
|||
result.push_back(Pair("status","not enough nonces")); |
|||
result.push_back(Pair("result","success")); |
|||
return(result); |
|||
} |
|||
for (i=0; i<MUSIG[myind]->num; i++) |
|||
{ |
|||
if ( secp256k1_musig_set_nonce(ctx,&MUSIG[myind]->signer_data[i],&MUSIG[myind]->nonces[i]) == 0 ) |
|||
return(cclib_error(result,"error setting nonce")); |
|||
} |
|||
/** Updates a session with the combined public nonce of all signers. The combined
|
|||
* public nonce is the sum of every signer's public nonce. |
|||
* |
|||
* Returns: 1: nonces are successfully combined |
|||
* 0: a signer's nonce is missing |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: session to update with the combined public nonce (cannot be |
|||
* NULL) |
|||
* signers: an array of signers' data, which must have had public nonces |
|||
* set with `musig_set_nonce`. Array length must equal to `n_signers` |
|||
* (cannot be NULL) |
|||
* n_signers: the length of the signers array. Must be the total number of |
|||
* signers participating in the MuSig. |
|||
* Out: nonce_is_negated: a pointer to an integer that indicates if the combined |
|||
* public nonce had to be negated. |
|||
* adaptor: point to add to the combined public nonce. If NULL, nothing is |
|||
* added to the combined nonce. |
|||
*/ |
|||
if ( secp256k1_musig_session_combine_nonces(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,MUSIG[myind]->num,NULL,NULL) > 0 ) |
|||
{ |
|||
if ( secp256k1_musig_partial_sign(ctx,&MUSIG[myind]->session,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 ) |
|||
{ |
|||
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 ) |
|||
{ |
|||
for (i=0; i<32; i++) |
|||
sprintf(&str[i<<1],"%02x",psig[i]); |
|||
str[64] = 0; |
|||
result.push_back(Pair("myind",MUSIG[myind]->myind)); |
|||
result.push_back(Pair("partialsig",str)); |
|||
result.push_back(Pair("result","success")); |
|||
if ( n == 5 ) |
|||
MUSIG[myind]->numpartials = 1; |
|||
return(result); |
|||
} else return(cclib_error(result,"error serializing partial sig")); |
|||
} else return(cclib_error(result,"error making partial sig")); |
|||
} else return(cclib_error(result,"error combining nonces")); |
|||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, nonce")); |
|||
} |
|||
|
|||
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
UniValue result(UniValue::VOBJ); int32_t i,ind,n,myind; uint8_t pkhash[32],psig[32],out64[64]; char str[129]; secp256k1_schnorrsig sig; |
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 ) |
|||
{ |
|||
if ( n > 3 ) |
|||
myind = juint(jitem(params,3),0); |
|||
else if ( n == 3 ) |
|||
myind = 0; |
|||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 ) |
|||
return(cclib_error(result,"error parsing pkhash")); |
|||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 ) |
|||
return(cclib_error(result,"pkhash doesnt match session pkhash")); |
|||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num ) |
|||
return(cclib_error(result,"illegal ind for session")); |
|||
else if ( cclib_parsehash(psig,jitem(params,2),32) < 0 ) |
|||
return(cclib_error(result,"error parsing psig")); |
|||
else if ( secp256k1_musig_partial_signature_parse(ctx,&MUSIG[myind]->partial_sig[ind],psig) == 0 ) |
|||
return(cclib_error(result,"error parsing partialsig")); |
|||
result.push_back(Pair("added_index",ind)); |
|||
//fprintf(stderr, "SIG: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
|
|||
MUSIG[myind]->numpartials++; |
|||
if ( MUSIG[myind]->numpartials >= MUSIG[myind]->num && secp256k1_musig_partial_sig_combine(ctx,&MUSIG[myind]->session,&sig,MUSIG[myind]->partial_sig,MUSIG[myind]->num) > 0 ) |
|||
{ |
|||
if ( secp256k1_schnorrsig_serialize(ctx,out64,&sig) > 0 ) |
|||
{ |
|||
result.push_back(Pair("result","success")); |
|||
for (i=0; i<64; i++) |
|||
sprintf(&str[i<<1],"%02x",out64[i]); |
|||
str[128] = 0; |
|||
result.push_back(Pair("combinedsig",str)); |
|||
} else return(cclib_error(result,"error serializing combinedsig")); |
|||
} |
|||
else |
|||
{ |
|||
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 ) |
|||
{ |
|||
result.push_back(Pair("myind",ind)); |
|||
for (i=0; i<32; i++) |
|||
sprintf(&str[i<<1],"%02x",psig[i]); |
|||
str[64] = 0; |
|||
result.push_back(Pair("partialsig",str)); |
|||
result.push_back(Pair("result","success")); |
|||
result.push_back(Pair("status","need more partialsigs")); |
|||
} else return(cclib_error(result,"error generating my partialsig")); |
|||
} |
|||
return(result); |
|||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, partialsig")); |
|||
} |
|||
|
|||
//int testmain(void);
|
|||
UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
UniValue result(UniValue::VOBJ); int32_t i,n; uint8_t msg[32],musig64[64]; secp256k1_pubkey combined_pk; secp256k1_schnorrsig musig; char str[129]; |
|||
//testmain();
|
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 ) |
|||
{ |
|||
if ( cclib_parsehash(msg,jitem(params,0),32) < 0 ) |
|||
return(cclib_error(result,"error parsing pkhash")); |
|||
else if ( musig_parsepubkey(ctx,combined_pk,jitem(params,1)) < 0 ) |
|||
return(cclib_error(result,"error parsing combined_pk")); |
|||
else if ( cclib_parsehash(musig64,jitem(params,2),64) < 0 ) |
|||
return(cclib_error(result,"error parsing musig64")); |
|||
for (i=0; i<32; i++) |
|||
sprintf(&str[i*2],"%02x",msg[i]); |
|||
str[64] = 0; |
|||
result.push_back(Pair("msg",str)); |
|||
result.push_back(Pair("combined_pk",jstr(jitem(params,1),0))); |
|||
for (i=0; i<64; i++) |
|||
sprintf(&str[i*2],"%02x",musig64[i]); |
|||
str[128] = 0; |
|||
result.push_back(Pair("combinedsig",str)); |
|||
if ( secp256k1_schnorrsig_parse(ctx,&musig,&musig64[0]) > 0 ) |
|||
{ |
|||
if ( secp256k1_schnorrsig_verify(ctx,&musig,msg,&combined_pk) > 0 ) |
|||
{ |
|||
result.push_back(Pair("result","success")); |
|||
return(result); |
|||
} else return(cclib_error(result,"musig didnt verify")); |
|||
} else return(cclib_error(result,"couldnt parse musig64")); |
|||
} else return(cclib_error(result,"wrong number of params, need 3: msg, combined_pk, combinedsig")); |
|||
} |
|||
|
|||
// helpers for rpc calls that generate/validate onchain tx
|
|||
|
|||
UniValue musig_rawtxresult(UniValue &result,std::string rawtx) |
|||
{ |
|||
CTransaction tx; |
|||
if ( rawtx.size() > 0 ) |
|||
{ |
|||
result.push_back(Pair("hex",rawtx)); |
|||
if ( DecodeHexTx(tx,rawtx) != 0 ) |
|||
{ |
|||
//if ( broadcastflag != 0 && myAddtomempool(tx) != 0 )
|
|||
// RelayTransaction(tx);
|
|||
result.push_back(Pair("txid",tx.GetHash().ToString())); |
|||
result.push_back(Pair("result","success")); |
|||
} else result.push_back(Pair("error","decode hex")); |
|||
} else result.push_back(Pair("error","couldnt finalize CCtx")); |
|||
return(result); |
|||
} |
|||
|
|||
UniValue musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); |
|||
UniValue result(UniValue::VOBJ); int32_t n; char *hexstr; std::string rawtx; int64_t amount; CPubKey musigpk,mypk; |
|||
if ( txfee == 0 ) |
|||
txfee = MUSIG_TXFEE; |
|||
mypk = pubkey2pk(Mypubkey()); |
|||
musigpk = GetUnspendable(cp,0); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) |
|||
{ |
|||
if ( n == 2 && (hexstr= jstr(jitem(params,0),0)) != 0 && is_hexstr(hexstr,0) == 66 ) |
|||
{ |
|||
CPubKey pk(ParseHex(hexstr)); |
|||
amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049; |
|||
if ( amount >= 3*txfee && AddNormalinputs(mtx,mypk,amount+2*txfee,64) >= amount+2*txfee ) |
|||
{ |
|||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount+txfee,musigpk)); |
|||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_sendopret('x',pk)); |
|||
return(musig_rawtxresult(result,rawtx)); |
|||
} else return(cclib_error(result,"couldnt find funds or less than 0.0003")); |
|||
} else return(cclib_error(result,"must have 2 params: pk, amount")); |
|||
} else return(cclib_error(result,"not enough parameters")); |
|||
} |
|||
|
|||
UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); |
|||
UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,pk; secp256k1_pubkey combined_pk; char *scriptstr,*musigstr; uint8_t msg[32]; CTransaction vintx; uint256 prevhash,hashBlock; int32_t i,n,numvouts; char str[129]; CTxOut vout; secp256k1_schnorrsig musig; |
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) |
|||
{ |
|||
if ( n == 3 ) |
|||
{ |
|||
prevhash = juint256(jitem(params,0)); |
|||
scriptstr = jstr(jitem(params,1),0); |
|||
musigstr = jstr(jitem(params,2),0); |
|||
if ( is_hexstr(scriptstr,0) != 0 && is_hexstr(musigstr,0) == 128 ) |
|||
{ |
|||
if ( txfee == 0 ) |
|||
txfee = MUSIG_TXFEE; |
|||
mypk = pubkey2pk(Mypubkey()); |
|||
std::vector<uint8_t> musig64(ParseHex(musigstr)); |
|||
CScript scriptPubKey; |
|||
scriptPubKey.resize(strlen(scriptstr)/2); |
|||
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr); |
|||
if ( myGetTransaction(prevhash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 ) |
|||
{ |
|||
vout.nValue = vintx.vout[0].nValue - txfee; |
|||
vout.scriptPubKey = scriptPubKey; |
|||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' ) |
|||
{ |
|||
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 && |
|||
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 ) |
|||
{ |
|||
musig_prevoutmsg(msg,prevhash,vout.scriptPubKey); |
|||
{ |
|||
for (i=0; i<32; i++) |
|||
sprintf(&str[i*2],"%02x",msg[i]); |
|||
str[64] = 0; |
|||
result.push_back(Pair("msg",str)); |
|||
for (i=0; i<33; i++) |
|||
sprintf(&str[i*2],"%02x",((uint8_t *)pk.begin())[i]); |
|||
str[66] = 0; |
|||
result.push_back(Pair("combined_pk",str)); |
|||
for (i=0; i<64; i++) |
|||
sprintf(&str[i*2],"%02x",musig64[i]); |
|||
str[128] = 0; |
|||
result.push_back(Pair("combinedsig",str)); |
|||
} |
|||
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) ) |
|||
{ |
|||
return(cclib_error(result,"musig didnt validate")); |
|||
} |
|||
mtx.vin.push_back(CTxIn(prevhash,MUSIG_PREVN)); |
|||
mtx.vout.push_back(vout); |
|||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_spendopret('y',pk,musig64)); |
|||
return(musig_rawtxresult(result,rawtx)); |
|||
} else return(cclib_error(result,"couldnt parse pk or musig")); |
|||
} else return(cclib_error(result,"couldnt decode send opret")); |
|||
} else return(cclib_error(result,"couldnt find vin0")); |
|||
} else return(cclib_error(result,"script or musig is not hex")); |
|||
} else return(cclib_error(result,"need to have exactly 3 params sendtxid, scriptPubKey, musig")); |
|||
} else return(cclib_error(result,"params parse error")); |
|||
} |
|||
|
|||
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) |
|||
{ |
|||
static secp256k1_context *ctx; |
|||
secp256k1_pubkey combined_pk; CPubKey pk,checkpk; secp256k1_schnorrsig musig; uint256 hashBlock; CTransaction vintx; int32_t numvouts; std::vector<uint8_t> musig64; uint8_t msg[32]; |
|||
if ( ctx == 0 ) |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
if ( tx.vout.size() != 2 ) |
|||
return eval->Invalid("numvouts != 2"); |
|||
else if ( tx.vin.size() != 1 ) |
|||
return eval->Invalid("numvins != 1"); |
|||
else if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) |
|||
return eval->Invalid("illegal normal vin0"); |
|||
else if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 ) |
|||
{ |
|||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' ) |
|||
{ |
|||
if ( musig_spendopretdecode(checkpk,musig64,tx.vout[tx.vout.size()-1].scriptPubKey) == 'y' ) |
|||
{ |
|||
if ( pk == checkpk ) |
|||
{ |
|||
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 && |
|||
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 ) |
|||
{ |
|||
musig_prevoutmsg(msg,tx.vin[0].prevout.hash,tx.vout[0].scriptPubKey); |
|||
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) ) |
|||
return eval->Invalid("failed schnorrsig_verify"); |
|||
else return(true); |
|||
} else return eval->Invalid("couldnt parse pk or musig"); |
|||
} else return eval->Invalid("combined_pk didnt match send opret"); |
|||
} else return eval->Invalid("failed decode musig spendopret"); |
|||
} else return eval->Invalid("couldnt decode send opret"); |
|||
} else return eval->Invalid("couldnt find vin0 tx"); |
|||
} |
@ -0,0 +1,222 @@ |
|||
############################################################################### |
|||
# |
|||
# Makefile for rogue |
|||
# |
|||
# Rogue: Exploring the Dungeons of Doom |
|||
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman |
|||
# All rights reserved. |
|||
# |
|||
# See the file LICENSE.TXT for full copyright and licensing information. |
|||
# |
|||
############################################################################### |
|||
|
|||
############################################################################### |
|||
# Site configuration occurs beneath this comment |
|||
# Typically ./configure (autoconf tools) configures this section |
|||
# This section could be manually configured if autoconf/configure fails |
|||
############################################################################### |
|||
|
|||
DISTNAME=rogue5.4.4 |
|||
PACKAGE_TARNAME = rogue-5.4.4 |
|||
PROGRAM=rogue |
|||
|
|||
O=o |
|||
|
|||
#CC=gcc |
|||
CC = x86_64-w64-mingw32-gcc |
|||
|
|||
#CFLAGS=-O2 |
|||
CFLAGS= -g -O2 -I./ncurses/include -I./ncurses/include/ncursesw -I../../../depends/x86_64-w64-mingw32/include |
|||
|
|||
#LIBS=-lcurses |
|||
LIBS = -L./ncurses/lib -lncursesw -lcurl |
|||
|
|||
#RM=rm -f |
|||
RM = rm -f |
|||
|
|||
#GROFF=groff |
|||
GROFF = groff |
|||
|
|||
#NROFF=nroff |
|||
NROFF = nroff |
|||
|
|||
#TBL=tbl |
|||
TBL = tbl |
|||
|
|||
#COLCRT=colcrt |
|||
COLCRT = colcrt |
|||
|
|||
#SED=sed |
|||
SED = sed |
|||
|
|||
#SCOREFILE=rogue54.scr |
|||
SCOREFILE = rogue.scr |
|||
|
|||
#LOCKFILE=rogue54.lck |
|||
LOCKFILE = rogue.lck |
|||
|
|||
#GROUPOWNER=games |
|||
GROUPOWNER = |
|||
|
|||
#CPPFLAGS=-DHAVE_CONFIG_H |
|||
CPPFLAGS =-DHAVE_CONFIG_H |
|||
|
|||
#DISTFILE = $(PROGRAM) |
|||
DISTFILE = $(DISTNAME)-x86_64-w64-mingw32 |
|||
|
|||
INSTALL=./install-sh |
|||
|
|||
#INSTGROUP=-g games |
|||
INSTGROUP= |
|||
#INSTOWNER=-u root |
|||
INSTOWNER= |
|||
|
|||
CHGRP=chgrp |
|||
|
|||
MKDIR=mkdir |
|||
|
|||
TOUCH=touch |
|||
|
|||
RMDIR=rmdir |
|||
|
|||
CHMOD=chmod |
|||
|
|||
DESTDIR= |
|||
|
|||
prefix=/usr/local |
|||
exec_prefix=${prefix} |
|||
datarootdir=${prefix}/share |
|||
datadir=${datarootdir} |
|||
bindir=${exec_prefix}/bin |
|||
mandir=${datarootdir}/man |
|||
docdir=${datarootdir}/doc/${PACKAGE_TARNAME} |
|||
man6dir = $(mandir)/man6 |
|||
|
|||
############################################################################### |
|||
# Site configuration occurs above this comment |
|||
# It should not be necessary to change anything below this comment |
|||
############################################################################### |
|||
|
|||
HDRS = rogue.h extern.h score.h |
|||
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \ |
|||
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \ |
|||
mach_dep.$(O) rogue.$(O) mdport.$(O) misc.$(O) monsters.$(O) \ |
|||
move.$(O) new_level.$(O) |
|||
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \ |
|||
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \ |
|||
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O) |
|||
OBJS = main.$(O) $(OBJS1) $(OBJS2) |
|||
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \ |
|||
daemons.c fight.c init.c io.c list.c mach_dep.c \ |
|||
main.c mdport.c misc.c monsters.c move.c new_level.c \ |
|||
options.c pack.c passages.c potions.c rings.c rip.c \ |
|||
rooms.c save.c scrolls.c state.c sticks.c things.c \ |
|||
weapons.c wizard.c xcrypt.c |
|||
MISC_C = findpw.c scedit.c scmisc.c |
|||
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in |
|||
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \ |
|||
$(PROGRAM).6 |
|||
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \ |
|||
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in |
|||
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \ |
|||
rogue.png rogue.desktop |
|||
|
|||
.SUFFIXES: .obj |
|||
|
|||
.c.obj: |
|||
$(CC) $(CFLAGS) $(CPPFLAGS) /c $*.c |
|||
|
|||
.c.o: |
|||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c |
|||
|
|||
#$(RM) rogue.so ; $(CC) -shared -o rogue.so cursesd.c $(OBJS1) $(OBJS2); $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ |
|||
|
|||
$(PROGRAM): $(HDRS) $(OBJS) |
|||
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@.exe |
|||
|
|||
clean: |
|||
$(RM) $(OBJS1); $(RM) main.$(O) ; $(RM) rogue.so |
|||
$(RM) $(OBJS2) |
|||
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe |
|||
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip |
|||
$(RM) $(DISTNAME)/* |
|||
-rmdir $(DISTNAME) |
|||
|
|||
maintainer-clean: |
|||
$(RM) config.h |
|||
$(RM) Makefile |
|||
$(RM) config.status |
|||
$(RM) -r autom4te.cache |
|||
$(RM) config.log |
|||
$(RM) $(PROGRAM).scr $(PROGRAM).lck |
|||
|
|||
stddocs: |
|||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.6.in > rogue.6 |
|||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.me.in > rogue.me |
|||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.html.in > rogue,html |
|||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.doc.in > rogue.doc |
|||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.cat.in > rogue.cat |
|||
|
|||
dist.src: |
|||
$(MAKE) $(MAKEFILE) clean |
|||
mkdir $(DISTNAME) |
|||
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME) |
|||
tar cf $(DISTNAME)-src.tar $(DISTNAME) |
|||
gzip -f $(DISTNAME)-src.tar |
|||
rm -fr $(DISTNAME) |
|||
|
|||
findpw: findpw.c xcrypt.o mdport.o xcrypt.o |
|||
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses |
|||
|
|||
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o |
|||
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses |
|||
|
|||
scmisc.o scedit.o: |
|||
$(CC) -O -c $(SF) $*.c |
|||
|
|||
$(PROGRAM).doc: rogue.me |
|||
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \ |
|||
$(GROFF) -P-c -t -me -Tascii rogue.me | $(SED) -e 's/.\x08//g' > $(PROGRAM).doc ;\ |
|||
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \ |
|||
tbl rogue.me | $(NROFF) -me | colcrt - > $(PROGRAM).doc ;\ |
|||
fi |
|||
|
|||
$(PROGRAM).cat: rogue.6 |
|||
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \ |
|||
$(GROFF) -Tascii -man rogue.6 | $(SED) -e 's/.\x08//g' > $(PROGRAM).cat ;\ |
|||
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \ |
|||
$(NROFF) -man rogue.6 | $(COLCRT) - > $(PROGRAM).cat ;\ |
|||
fi |
|||
|
|||
dist: clean $(PROGRAM) |
|||
tar cf $(DISTFILE).tar $(PROGRAM) LICENSE.TXT $(DOCS) |
|||
gzip -f $(DISTFILE).tar |
|||
|
|||
install: $(PROGRAM) |
|||
-$(TOUCH) test |
|||
-if test ! -f $(DESTDIR)$(SCOREFILE) ; then $(INSTALL) -m 0664 test $(DESTDIR)$(SCOREFILE) ; fi |
|||
-$(INSTALL) -m 0755 $(PROGRAM) $(DESTDIR)$(bindir)/$(PROGRAM) |
|||
-if test "x$(GROUPOWNER)" != "x" ; then \ |
|||
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(SCOREFILE) ; \ |
|||
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(bindir)/$(PROGRAM) ; \ |
|||
$(CHMOD) 02755 $(DESTDIR)$(bindir)/$(PROGRAM) ; \ |
|||
$(CHMOD) 0464 $(DESTDIR)$(SCOREFILE) ; \ |
|||
fi |
|||
-if test -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(man6dir)/$(PROGRAM).6 ; fi |
|||
-if test ! -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(mandir)/$(PROGRAM).6 ; fi |
|||
-$(INSTALL) -m 0644 rogue.doc $(DESTDIR)$(docdir)/$(PROGRAM).doc |
|||
-$(INSTALL) -m 0644 rogue.html $(DESTDIR)$(docdir)/$(PROGRAM).html |
|||
-$(INSTALL) -m 0644 rogue.cat $(DESTDIR)$(docdir)/$(PROGRAM).cat |
|||
-$(INSTALL) -m 0644 LICENSE.TXT $(DESTDIR)$(docdir)/LICENSE.TXT |
|||
-$(INSTALL) -m 0644 rogue.me $(DESTDIR)$(docdir)/$(PROGRAM).me |
|||
-if test ! -f $(DESTDIR)$(LOCKFILE) ; then $(INSTALL) -m 0666 test $(DESTDIR)$(LOCKFILE) ; $(RM) $(DESTDIR)$(LOCKFILE) ; fi |
|||
-$(RM) test |
|||
|
|||
uninstall: |
|||
-$(RM) $(DESTDIR)$(bindir)/$(PROGRAM) |
|||
-$(RM) $(DESTDIR)$(man6dir)/$(PROGRAM).6 |
|||
-$(RM) $(DESTDIR)$(docdir)$(PROGRAM)/$(PROGRAM).doc |
|||
-$(RM) $(DESTDIR)$(LOCKFILE) |
|||
-$(RMDIR) $(DESTDIR)$(docdir)$(PROGRAM) |
|||
|
|||
reinstall: uninstall install |
@ -1,270 +0,0 @@ |
|||
/* config.h. Generated from config.h.in by configure. */ |
|||
/* config.h.in. Generated from configure.ac by autoheader. */ |
|||
|
|||
/* Define if scorefile is top scores, not top players */ |
|||
#define ALLSCORES 1 |
|||
|
|||
/* Define if checktime feature should be enabled */ |
|||
/* #undef CHECKTIME */ |
|||
|
|||
/* Define to group owner of setgid executable */ |
|||
/* #undef GROUPOWNER */ |
|||
|
|||
/* Define to 1 if you have the `alarm' function. */ |
|||
#define HAVE_ALARM 1 |
|||
|
|||
/* Define to 1 if you have the <arpa/inet.h> header file. */ |
|||
#define HAVE_ARPA_INET_H 1 |
|||
|
|||
/* Define to 1 if libcurses is requested */ |
|||
#define HAVE_CURSES_H 1 |
|||
|
|||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ |
|||
/* #undef HAVE_DOPRNT */ |
|||
|
|||
/* Define to 1 if you have the `erasechar' function. */ |
|||
#define HAVE_ERASECHAR 1 |
|||
|
|||
/* Define if ncurses has ESCDELAY variable */ |
|||
#define HAVE_ESCDELAY 1 |
|||
|
|||
/* Define to 1 if you have the <fcntl.h> header file. */ |
|||
#define HAVE_FCNTL_H 1 |
|||
|
|||
/* Define to 1 if you have the `fork' function. */ |
|||
#define HAVE_FORK 1 |
|||
|
|||
/* Define to 1 if you have the `getgid' function. */ |
|||
#define HAVE_GETGID 1 |
|||
|
|||
/* Define to 1 if you have the `getloadavg' function. */ |
|||
#define HAVE_GETLOADAVG 1 |
|||
|
|||
/* Define to 1 if you have the `getpass' function. */ |
|||
#define HAVE_GETPASS 1 |
|||
|
|||
/* Define to 1 if you have the `getpwuid' function. */ |
|||
#define HAVE_GETPWUID 1 |
|||
|
|||
/* Define to 1 if you have the `getuid' function. */ |
|||
#define HAVE_GETUID 1 |
|||
|
|||
/* Define to 1 if you have the <inttypes.h> header file. */ |
|||
#define HAVE_INTTYPES_H 1 |
|||
|
|||
/* Define to 1 if you have the `killchar' function. */ |
|||
#define HAVE_KILLCHAR 1 |
|||
|
|||
/* Define to 1 if you have the <limits.h> header file. */ |
|||
#define HAVE_LIMITS_H 1 |
|||
|
|||
/* Define to 1 if you have the `loadav' function. */ |
|||
/* #undef HAVE_LOADAV */ |
|||
|
|||
/* Define to 1 if `lstat' has the bug that it succeeds when given the
|
|||
zero-length file name argument. */ |
|||
/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ |
|||
|
|||
/* Define to 1 if you have the <memory.h> header file. */ |
|||
#define HAVE_MEMORY_H 1 |
|||
|
|||
/* Define to 1 if you have the `memset' function. */ |
|||
#define HAVE_MEMSET 1 |
|||
|
|||
/* Define to 1 if libncurses is requested */ |
|||
/* #undef HAVE_NCURSES_H */ |
|||
|
|||
/* Define to 1 if you have the <ncurses/term.h> header file. */ |
|||
/* #undef HAVE_NCURSES_TERM_H */ |
|||
|
|||
/* Define to 1 if you have the `nlist' function. */ |
|||
/* #undef HAVE_NLIST */ |
|||
|
|||
/* Define to 1 if you have the <nlist.h> header file. */ |
|||
#define HAVE_NLIST_H 1 |
|||
|
|||
/* Define to 1 if you have the <process.h> header file. */ |
|||
/* #undef HAVE_PROCESS_H */ |
|||
|
|||
/* Define to 1 if you have the <pwd.h> header file. */ |
|||
#define HAVE_PWD_H 1 |
|||
|
|||
/* Define to 1 if you have the `setenv' function. */ |
|||
#define HAVE_SETENV 1 |
|||
|
|||
/* Define to 1 if you have the `setgid' function. */ |
|||
#define HAVE_SETGID 1 |
|||
|
|||
/* Define to 1 if you have the `setregid' function. */ |
|||
#define HAVE_SETREGID 1 |
|||
|
|||
/* Define to 1 if you have the `setresgid' function. */ |
|||
/* #undef HAVE_SETRESGID */ |
|||
|
|||
/* Define to 1 if you have the `setresuid' function. */ |
|||
/* #undef HAVE_SETRESUID */ |
|||
|
|||
/* Define to 1 if you have the `setreuid' function. */ |
|||
#define HAVE_SETREUID 1 |
|||
|
|||
/* Define to 1 if you have the `setuid' function. */ |
|||
#define HAVE_SETUID 1 |
|||
|
|||
/* Define to 1 if you have the `spawnl' function. */ |
|||
/* #undef HAVE_SPAWNL */ |
|||
|
|||
/* Define to 1 if `stat' has the bug that it succeeds when given the
|
|||
zero-length file name argument. */ |
|||
/* #undef HAVE_STAT_EMPTY_STRING_BUG */ |
|||
|
|||
/* Define to 1 if stdbool.h conforms to C99. */ |
|||
#define HAVE_STDBOOL_H 1 |
|||
|
|||
/* Define to 1 if you have the <stdint.h> header file. */ |
|||
#define HAVE_STDINT_H 1 |
|||
|
|||
/* Define to 1 if you have the <stdlib.h> header file. */ |
|||
#define HAVE_STDLIB_H 1 |
|||
|
|||
/* Define to 1 if you have the `strchr' function. */ |
|||
#define HAVE_STRCHR 1 |
|||
|
|||
/* Define to 1 if you have the `strerror' function. */ |
|||
#define HAVE_STRERROR 1 |
|||
|
|||
/* Define to 1 if you have the <strings.h> header file. */ |
|||
#define HAVE_STRINGS_H 1 |
|||
|
|||
/* Define to 1 if you have the <string.h> header file. */ |
|||
#define HAVE_STRING_H 1 |
|||
|
|||
/* Define to 1 if you have the <sys/ioctl.h> header file. */ |
|||
#define HAVE_SYS_IOCTL_H 1 |
|||
|
|||
/* Define to 1 if you have the <sys/stat.h> header file. */ |
|||
#define HAVE_SYS_STAT_H 1 |
|||
|
|||
/* Define to 1 if you have the <sys/types.h> header file. */ |
|||
#define HAVE_SYS_TYPES_H 1 |
|||
|
|||
/* Define to 1 if you have the <sys/utsname.h> header file. */ |
|||
#define HAVE_SYS_UTSNAME_H 1 |
|||
|
|||
/* Define to 1 if you have the <termios.h> header file. */ |
|||
#define HAVE_TERMIOS_H 1 |
|||
|
|||
/* Define to 1 if you have the <term.h> header file. */ |
|||
#define HAVE_TERM_H 1 |
|||
|
|||
/* Define to 1 if you have the <unistd.h> header file. */ |
|||
#define HAVE_UNISTD_H 1 |
|||
|
|||
/* Define to 1 if you have the <utmp.h> header file. */ |
|||
#define HAVE_UTMP_H 1 |
|||
|
|||
/* Define to 1 if you have the `vfork' function. */ |
|||
#define HAVE_VFORK 1 |
|||
|
|||
/* Define to 1 if you have the <vfork.h> header file. */ |
|||
/* #undef HAVE_VFORK_H */ |
|||
|
|||
/* Define to 1 if you have the `vprintf' function. */ |
|||
#define HAVE_VPRINTF 1 |
|||
|
|||
/* Define to 1 if `fork' works. */ |
|||
#define HAVE_WORKING_FORK 1 |
|||
|
|||
/* Define to 1 if `vfork' works. */ |
|||
#define HAVE_WORKING_VFORK 1 |
|||
|
|||
/* Define to 1 if the system has the type `_Bool'. */ |
|||
#define HAVE__BOOL 1 |
|||
|
|||
/* Define to 1 if you have the `_spawnl' function. */ |
|||
/* #undef HAVE__SPAWNL */ |
|||
|
|||
/* define if we should use program's load average function instead of system
|
|||
*/ |
|||
/* #undef LOADAV */ |
|||
|
|||
/* Define to file to use for scoreboard lockfile */ |
|||
#define LOCKFILE "rogue.lck" |
|||
|
|||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
|||
slash. */ |
|||
/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ |
|||
|
|||
/* Define to include wizard mode */ |
|||
/* #undef MASTER */ |
|||
|
|||
/* Define if maxusers feature should be enabled */ |
|||
/* #undef MAXLOAD */ |
|||
|
|||
/* Define if maxusers feature should be enabled */ |
|||
/* #undef MAXUSERS */ |
|||
|
|||
/* kernel file to pass to nlist() when reading load average (unlikely to work)
|
|||
*/ |
|||
/* #undef NAMELIST */ |
|||
|
|||
/* word for the number of scores to store in scoreboard */ |
|||
#define NUMNAME "Ten" |
|||
|
|||
/* number of scores to store in scoreboard */ |
|||
#define NUMSCORES 10 |
|||
|
|||
/* Define to the address where bug reports for this package should be sent. */ |
|||
#define PACKAGE_BUGREPORT "yendor@rogueforge.net" |
|||
|
|||
/* Define to the full name of this package. */ |
|||
#define PACKAGE_NAME "Rogue" |
|||
|
|||
/* Define to the full name and version of this package. */ |
|||
#define PACKAGE_STRING "Rogue 5.4.4" |
|||
|
|||
/* Define to the one symbol short name of this package. */ |
|||
#define PACKAGE_TARNAME "rogue" |
|||
|
|||
/* Define to the version of this package. */ |
|||
#define PACKAGE_VERSION "5.4.4" |
|||
|
|||
/* Define crypt(3) wizard mode password */ |
|||
/* #undef PASSWD */ |
|||
|
|||
/* Define as the return type of signal handlers (`int' or `void'). */ |
|||
#define RETSIGTYPE void |
|||
|
|||
/* Define to file to use for scoreboard */ |
|||
#define SCOREFILE "rogue.scr" |
|||
|
|||
/* Define to 1 if you have the ANSI C header files. */ |
|||
#define STDC_HEADERS 1 |
|||
|
|||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */ |
|||
/* #undef TM_IN_SYS_TIME */ |
|||
|
|||
/* define if we should use program's user counting function instead of
|
|||
system's */ |
|||
/* #undef UCOUNT */ |
|||
|
|||
/* utmp like file to pass to ucount() when counting online users (unlikely to
|
|||
work) */ |
|||
/* #undef UTMP */ |
|||
|
|||
/* Define to empty if `const' does not conform to ANSI C. */ |
|||
/* #undef const */ |
|||
|
|||
/* Define to `int' if <sys/types.h> doesn't define. */ |
|||
/* #undef gid_t */ |
|||
|
|||
/* Define to `int' if <sys/types.h> does not define. */ |
|||
/* #undef pid_t */ |
|||
|
|||
/* Define to `unsigned int' if <sys/types.h> does not define. */ |
|||
/* #undef size_t */ |
|||
|
|||
/* Define to `int' if <sys/types.h> doesn't define. */ |
|||
/* #undef uid_t */ |
|||
|
|||
/* Define as `fork' if `vfork' does not work. */ |
|||
/* #undef vfork */ |
@ -0,0 +1,200 @@ |
|||
#!/usr/bin/env python3 |
|||
import platform |
|||
import os |
|||
import re |
|||
import json |
|||
import random |
|||
import base58 |
|||
import binascii |
|||
import hashlib |
|||
import sys |
|||
import time |
|||
from slickrpc import Proxy |
|||
|
|||
# fucntion to define rpc_connection |
|||
def def_credentials(chain): |
|||
rpcport = ''; |
|||
operating_system = platform.system() |
|||
if operating_system == 'Darwin': |
|||
ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo' |
|||
elif operating_system == 'Linux': |
|||
ac_dir = os.environ['HOME'] + '/.komodo' |
|||
elif operating_system == 'Windows': |
|||
ac_dir = '%s/komodo/' % os.environ['APPDATA'] |
|||
if chain == 'KMD': |
|||
coin_config_file = str(ac_dir + '/komodo.conf') |
|||
else: |
|||
coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf') |
|||
with open(coin_config_file, 'r') as f: |
|||
for line in f: |
|||
l = line.rstrip() |
|||
if re.search('rpcuser', l): |
|||
rpcuser = l.replace('rpcuser=', '') |
|||
elif re.search('rpcpassword', l): |
|||
rpcpassword = l.replace('rpcpassword=', '') |
|||
elif re.search('rpcport', l): |
|||
rpcport = l.replace('rpcport=', '') |
|||
if len(rpcport) == 0: |
|||
if chain == 'KMD': |
|||
rpcport = 7771 |
|||
else: |
|||
print("rpcport not in conf file, exiting") |
|||
print("check " + coin_config_file) |
|||
exit(1) |
|||
return (Proxy("http://%s:%s@127.0.0.1:%d" % (rpcuser, rpcpassword, int(rpcport)))) |
|||
|
|||
|
|||
# generate address, validate address, dump private key |
|||
def genvaldump(rpc_connection): |
|||
# get new address |
|||
address = rpc_connection.getnewaddress() |
|||
# validate address |
|||
validateaddress_result = rpc_connection.validateaddress(address) |
|||
pubkey = validateaddress_result['pubkey'] |
|||
address = validateaddress_result['address'] |
|||
# dump private key for the address |
|||
privkey = rpc_connection.dumpprivkey(address) |
|||
# function output |
|||
output = [pubkey, privkey, address] |
|||
return(output) |
|||
|
|||
CHAIN = 'MUSIG' #sys.argv[1] |
|||
|
|||
rpc = def_credentials(CHAIN) |
|||
|
|||
pubkeys = [] |
|||
address_info = [] |
|||
ret = input('Do you want to generate new pubkeys? ').lower() |
|||
|
|||
if ret.startswith('y'): |
|||
numpks = int(input('Enter number of pubkeys to combine: ')) |
|||
if os.path.isfile("list.json"): |
|||
print('Already have list.json, move it if you would like to generate a new set.') |
|||
sys.exit(0) |
|||
while len(address_info) < numpks: |
|||
addressinfo = genvaldump(rpc) |
|||
address_info.append(addressinfo) |
|||
f = open("list.json", "w+") |
|||
f.write(json.dumps(address_info)) |
|||
else: |
|||
if os.path.isfile("list.json"): |
|||
with open('list.json') as list: |
|||
address_info = json.load(list) |
|||
else: |
|||
sys.exit('No list.json you need to create new pubkeys!') |
|||
|
|||
for addressinfo in address_info: |
|||
pubkeys.append(addressinfo[0]) |
|||
|
|||
ret = rpc.setpubkey(pubkeys[0]) |
|||
ret = rpc.cclib("combine", "18", str(pubkeys)) |
|||
pkhash = str(ret['pkhash']) |
|||
combinedpk = str(ret['combined_pk']) |
|||
print('Your combined pubkey is: ' + combinedpk) |
|||
print('Your pkhash is: ' + pkhash) |
|||
amount = float(input('Enter amount to send: ')) |
|||
if amount == 0: |
|||
sys.exit('Cannot send 0 coins. Exiting.') |
|||
tmp = str([combinedpk, amount]) |
|||
hex = rpc.cclib("send", "18", tmp)['hex'] |
|||
senttxid = rpc.sendrawtransaction(hex) |
|||
print('Your senttxid is: ' + senttxid) |
|||
|
|||
print("Waiting for tx to be confirmed") |
|||
while True: |
|||
confirmed = int(rpc.gettransaction(senttxid)["confirmations"]) |
|||
if not confirmed: |
|||
time.sleep(10) |
|||
else: |
|||
print('SentTX confirmed') |
|||
break |
|||
|
|||
scriptPubKey = rpc.getrawtransaction(senttxid,1)['vout'][1]['scriptPubKey']['hex'] |
|||
print('Your scriptPubKey is: ' + scriptPubKey) |
|||
tmp = str([senttxid, scriptPubKey]) |
|||
msg = rpc.cclib("calcmsg", "18", tmp)['msg'] |
|||
print('Your msg is: ' + msg) |
|||
|
|||
i = 0; |
|||
commitments = [] |
|||
for pubkey in pubkeys: |
|||
ret = rpc.setpubkey(pubkey) |
|||
tmp = str([i, len(pubkeys), combinedpk, pkhash, msg, i]) |
|||
commitments.append(rpc.cclib("session", "18", tmp)['commitment']) |
|||
i = i + 1 |
|||
|
|||
print("Created commitments sucessfully... Sending to all signers.") |
|||
|
|||
i = 0 |
|||
nonces = [] |
|||
for pubkey in pubkeys: |
|||
ret = rpc.setpubkey(pubkey) |
|||
n = 0 |
|||
for commitment in commitments: |
|||
tmp = str([pkhash, n, commitment, i]) |
|||
ret = rpc.cclib("commit", "18", tmp) |
|||
try: |
|||
nonces.append(ret['nonce']) |
|||
except: |
|||
x = 1 |
|||
n = n + 1 |
|||
i = i + 1 |
|||
|
|||
print("Created nounce's sucessfully... Sending to all signers.") |
|||
|
|||
i = 0 |
|||
partialsigs = [] |
|||
for pubkey in pubkeys: |
|||
ret = rpc.setpubkey(pubkey) |
|||
n = 0 |
|||
for nonce in nonces: |
|||
tmp = str([pkhash, n, nonce, i]) |
|||
ret = rpc.cclib("nonce", "18", tmp) |
|||
try: |
|||
partialsigs.append(ret['partialsig']) |
|||
except: |
|||
x = 1 |
|||
n = n + 1 |
|||
i = i + 1 |
|||
|
|||
print("Created partial sigs sucessfully... Sending to all signers.") |
|||
|
|||
i = 0 |
|||
combinedsigs = [] |
|||
for pubkey in pubkeys: |
|||
ret = rpc.setpubkey(pubkey) |
|||
n = 0 |
|||
for partialsig in partialsigs: |
|||
tmp = str([pkhash, n, partialsig, i]) |
|||
ret = rpc.cclib("partialsig", "18", tmp) |
|||
try: |
|||
combinedsigs.append(ret['combinedsig']) |
|||
except: |
|||
x = 1 |
|||
n = n + 1 |
|||
i = i + 1 |
|||
|
|||
print("Created combined sigs sucessfully... Verifying.") |
|||
|
|||
tmp = str([msg, combinedpk, combinedsigs[0]]) |
|||
ret = rpc.cclib("verify", "18", tmp) |
|||
|
|||
if ret['result'] != "success": |
|||
print(ret) |
|||
sys.exit('Could not verify signature.') |
|||
|
|||
print('Verified... Attempting to send.') |
|||
|
|||
tmp = str([senttxid, scriptPubKey, combinedsigs[0]]) |
|||
ret = rpc.cclib("spend", "18", tmp) |
|||
|
|||
if ret['result'] != "success": |
|||
print(ret) |
|||
sys.exit('Could not create spend transaction.') |
|||
|
|||
try: |
|||
ret = rpc.sendrawtransaction(ret['hex']) |
|||
except: |
|||
sys.exit('Could not send transaction.') |
|||
|
|||
print('Spent txid: ' + ret) |
@ -0,0 +1,502 @@ |
|||
#ifndef SECP256K1_MUSIG_H |
|||
#define SECP256K1_MUSIG_H |
|||
|
|||
#include <stdint.h> |
|||
|
|||
/** This module implements a Schnorr-based multi-signature scheme called MuSig
|
|||
* (https://eprint.iacr.org/2018/068.pdf). There's an example C source file in the
|
|||
* module's directory (src/modules/musig/example.c) that demonstrates how it can be |
|||
* used. |
|||
*/ |
|||
|
|||
/** Data structure containing data related to a signing session resulting in a single
|
|||
* signature. |
|||
* |
|||
* This structure is not opaque, but it MUST NOT be copied or read or written to it |
|||
* directly. A signer who is online throughout the whole process and can keep this |
|||
* structure in memory can use the provided API functions for a safe standard |
|||
* workflow. |
|||
* |
|||
* A signer who goes offline and needs to import/export or save/load this structure |
|||
* **must** take measures prevent replay attacks wherein an old state is loaded and |
|||
* the signing protocol forked from that point. One straightforward way to accomplish |
|||
* this is to attach the output of a monotonic non-resettable counter (hardware |
|||
* support is needed for this). Increment the counter before each output and |
|||
* encrypt+sign the entire package. If a package is deserialized with an old counter |
|||
* state or bad signature it should be rejected. |
|||
* |
|||
* Observe that an independent counter is needed for each concurrent signing session |
|||
* such a device is involved in. To avoid fragility, it is therefore recommended that |
|||
* any offline signer be usable for only a single session at once. |
|||
* |
|||
* Given access to such a counter, its output should be used as (or mixed into) the |
|||
* session ID to ensure uniqueness. |
|||
* |
|||
* Fields: |
|||
* combined_pk: MuSig-computed combined public key |
|||
* n_signers: Number of signers |
|||
* pk_hash: The 32-byte hash of the original public keys |
|||
* combined_nonce: Summed combined public nonce (undefined if `nonce_is_set` is false) |
|||
* nonce_is_set: Whether the above nonce has been set |
|||
* nonce_is_negated: If `nonce_is_set`, whether the above nonce was negated after |
|||
* summing the participants' nonces. Needed to ensure the nonce's y |
|||
* coordinate has a quadratic-residue y coordinate |
|||
* msg: The 32-byte message (hash) to be signed |
|||
* msg_is_set: Whether the above message has been set |
|||
* has_secret_data: Whether this session object has a signers' secret data; if this |
|||
* is `false`, it may still be used for verification purposes. |
|||
* seckey: If `has_secret_data`, the signer's secret key |
|||
* secnonce: If `has_secret_data`, the signer's secret nonce |
|||
* nonce: If `has_secret_data`, the signer's public nonce |
|||
* nonce_commitments_hash: If `has_secret_data` and `nonce_commitments_hash_is_set`, |
|||
* the hash of all signers' commitments |
|||
* nonce_commitments_hash_is_set: If `has_secret_data`, whether the |
|||
* nonce_commitments_hash has been set |
|||
*/ |
|||
typedef struct { |
|||
secp256k1_pubkey combined_pk; |
|||
uint32_t n_signers; |
|||
unsigned char pk_hash[32]; |
|||
secp256k1_pubkey combined_nonce; |
|||
int nonce_is_set; |
|||
int nonce_is_negated; |
|||
unsigned char msg[32]; |
|||
int msg_is_set; |
|||
int has_secret_data; |
|||
unsigned char seckey[32]; |
|||
unsigned char secnonce[32]; |
|||
secp256k1_pubkey nonce; |
|||
unsigned char nonce_commitments_hash[32]; |
|||
int nonce_commitments_hash_is_set; |
|||
} secp256k1_musig_session; |
|||
|
|||
/** Data structure containing data on all signers in a single session.
|
|||
* |
|||
* The workflow for this structure is as follows: |
|||
* |
|||
* 1. This structure is initialized with `musig_session_initialize` or |
|||
* `musig_session_initialize_verifier`, which set the `index` field, and zero out |
|||
* all other fields. The public session is initialized with the signers' |
|||
* nonce_commitments. |
|||
* |
|||
* 2. In a non-public session the nonce_commitments are set with the function |
|||
* `musig_get_public_nonce`, which also returns the signer's public nonce. This |
|||
* ensures that the public nonce is not exposed until all commitments have been |
|||
* received. |
|||
* |
|||
* 3. Each individual data struct should be updated with `musig_set_nonce` once a |
|||
* nonce is available. This function takes a single signer data struct rather than |
|||
* an array because it may fail in the case that the provided nonce does not match |
|||
* the commitment. In this case, it is desirable to identify the exact party whose |
|||
* nonce was inconsistent. |
|||
* |
|||
* Fields: |
|||
* present: indicates whether the signer's nonce is set |
|||
* index: index of the signer in the MuSig key aggregation |
|||
* nonce: public nonce, must be a valid curvepoint if the signer is `present` |
|||
* nonce_commitment: commitment to the nonce, or all-bits zero if a commitment |
|||
* has not yet been set |
|||
*/ |
|||
typedef struct { |
|||
int present; |
|||
uint32_t index; |
|||
secp256k1_pubkey nonce; |
|||
unsigned char nonce_commitment[32]; |
|||
} secp256k1_musig_session_signer_data; |
|||
|
|||
/** Opaque data structure that holds a MuSig partial signature.
|
|||
* |
|||
* The exact representation of data inside is implementation defined and not |
|||
* guaranteed to be portable between different platforms or versions. It is however |
|||
* guaranteed to be 32 bytes in size, and can be safely copied/moved. If you need |
|||
* to convert to a format suitable for storage, transmission, or comparison, use the |
|||
* `musig_partial_signature_serialize` and `musig_partial_signature_parse` |
|||
* functions. |
|||
*/ |
|||
typedef struct { |
|||
unsigned char data[32]; |
|||
} secp256k1_musig_partial_signature; |
|||
|
|||
/** Computes a combined public key and the hash of the given public keys
|
|||
* |
|||
* Returns: 1 if the public keys were successfully combined, 0 otherwise |
|||
* Args: ctx: pointer to a context object initialized for verification |
|||
* (cannot be NULL) |
|||
* scratch: scratch space used to compute the combined pubkey by |
|||
* multiexponentiation. If NULL, an inefficient algorithm is used. |
|||
* Out: combined_pk: the MuSig-combined public key (cannot be NULL) |
|||
* pk_hash32: if non-NULL, filled with the 32-byte hash of all input public |
|||
* keys in order to be used in `musig_session_initialize`. |
|||
* In: pubkeys: input array of public keys to combine. The order is important; |
|||
* a different order will result in a different combined public |
|||
* key (cannot be NULL) |
|||
* n_pubkeys: length of pubkeys array |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_pubkey_combine( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_scratch_space *scratch, |
|||
secp256k1_pubkey *combined_pk, |
|||
unsigned char *pk_hash32, |
|||
const secp256k1_pubkey *pubkeys, |
|||
size_t n_pubkeys |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); |
|||
|
|||
/** Initializes a signing session for a signer
|
|||
* |
|||
* Returns: 1: session is successfully initialized |
|||
* 0: session could not be initialized: secret key or secret nonce overflow |
|||
* Args: ctx: pointer to a context object, initialized for signing (cannot |
|||
* be NULL) |
|||
* Out: session: the session structure to initialize (cannot be NULL) |
|||
* signers: an array of signers' data to be initialized. Array length must |
|||
* equal to `n_signers` (cannot be NULL) |
|||
* nonce_commitment32: filled with a 32-byte commitment to the generated nonce |
|||
* (cannot be NULL) |
|||
* In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be |
|||
* NULL). If a non-unique session_id32 was given then a partial |
|||
* signature will LEAK THE SECRET KEY. |
|||
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you |
|||
* require sharing public nonces before the message is known |
|||
* because it reduces nonce misuse resistance. If NULL, must be |
|||
* set with `musig_session_set_msg` before signing and verifying. |
|||
* combined_pk: the combined public key of all signers (cannot be NULL) |
|||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be |
|||
* NULL) |
|||
* n_signers: length of signers array. Number of signers participating in |
|||
* the MuSig. Must be greater than 0 and at most 2^32 - 1. |
|||
* my_index: index of this signer in the signers array |
|||
* seckey: the signer's 32-byte secret key (cannot be NULL) |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_session_initialize( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_session *session, |
|||
secp256k1_musig_session_signer_data *signers, |
|||
unsigned char *nonce_commitment32, |
|||
const unsigned char *session_id32, |
|||
const unsigned char *msg32, |
|||
const secp256k1_pubkey *combined_pk, |
|||
const unsigned char *pk_hash32, |
|||
size_t n_signers, |
|||
size_t my_index, |
|||
const unsigned char *seckey |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11); |
|||
|
|||
/** Gets the signer's public nonce given a list of all signers' data with commitments
|
|||
* |
|||
* Returns: 1: public nonce is written in nonce |
|||
* 0: signer data is missing commitments or session isn't initialized |
|||
* for signing |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: the signing session to get the nonce from (cannot be NULL) |
|||
* signers: an array of signers' data initialized with |
|||
* `musig_session_initialize`. Array length must equal to |
|||
* `n_commitments` (cannot be NULL) |
|||
* Out: nonce: the nonce (cannot be NULL) |
|||
* In: commitments: array of 32-byte nonce commitments (cannot be NULL) |
|||
* n_commitments: the length of commitments and signers array. Must be the total |
|||
* number of signers participating in the MuSig. |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_session *session, |
|||
secp256k1_musig_session_signer_data *signers, |
|||
secp256k1_pubkey *nonce, |
|||
const unsigned char *const *commitments, |
|||
size_t n_commitments |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); |
|||
|
|||
/** Initializes a verifier session that can be used for verifying nonce commitments
|
|||
* and partial signatures. It does not have secret key material and therefore can not |
|||
* be used to create signatures. |
|||
* |
|||
* Returns: 1 when session is successfully initialized, 0 otherwise |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* Out: session: the session structure to initialize (cannot be NULL) |
|||
* signers: an array of signers' data to be initialized. Array length must |
|||
* equal to `n_signers`(cannot be NULL) |
|||
* In: msg32: the 32-byte message to be signed If NULL, must be set with |
|||
* `musig_session_set_msg` before using the session for verifying |
|||
* partial signatures. |
|||
* combined_pk: the combined public key of all signers (cannot be NULL) |
|||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL) |
|||
* commitments: array of 32-byte nonce commitments. Array length must equal to |
|||
* `n_signers` (cannot be NULL) |
|||
* n_signers: length of signers and commitments array. Number of signers |
|||
* participating in the MuSig. Must be greater than 0 and at most |
|||
* 2^32 - 1. |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_session_initialize_verifier( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_session *session, |
|||
secp256k1_musig_session_signer_data *signers, |
|||
const unsigned char *msg32, |
|||
const secp256k1_pubkey *combined_pk, |
|||
const unsigned char *pk_hash32, |
|||
const unsigned char *const *commitments, |
|||
size_t n_signers |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7); |
|||
|
|||
/** Checks a signer's public nonce against a commitment to said nonce, and update
|
|||
* data structure if they match |
|||
* |
|||
* Returns: 1: commitment was valid, data structure updated |
|||
* 0: commitment was invalid, nothing happened |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* signer: pointer to the signer data to update (cannot be NULL). Must have |
|||
* been used with `musig_session_get_public_nonce` or initialized |
|||
* with `musig_session_initialize_verifier`. |
|||
* In: nonce: signer's alleged public nonce (cannot be NULL) |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_session_signer_data *signer, |
|||
const secp256k1_pubkey *nonce |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Updates a session with the combined public nonce of all signers. The combined
|
|||
* public nonce is the sum of every signer's public nonce. |
|||
* |
|||
* Returns: 1: nonces are successfully combined |
|||
* 0: a signer's nonce is missing |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: session to update with the combined public nonce (cannot be |
|||
* NULL) |
|||
* signers: an array of signers' data, which must have had public nonces |
|||
* set with `musig_set_nonce`. Array length must equal to `n_signers` |
|||
* (cannot be NULL) |
|||
* n_signers: the length of the signers array. Must be the total number of |
|||
* signers participating in the MuSig. |
|||
* Out: nonce_is_negated: a pointer to an integer that indicates if the combined |
|||
* public nonce had to be negated. |
|||
* adaptor: point to add to the combined public nonce. If NULL, nothing is |
|||
* added to the combined nonce. |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_session_combine_nonces( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_session *session, |
|||
const secp256k1_musig_session_signer_data *signers, |
|||
size_t n_signers, |
|||
int *nonce_is_negated, |
|||
const secp256k1_pubkey *adaptor |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Sets the message of a session if previously unset
|
|||
* |
|||
* Returns 1 if the message was not set yet and is now successfully set |
|||
* 0 otherwise |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: the session structure to update with the message (cannot be NULL) |
|||
* In: msg32: the 32-byte message to be signed (cannot be NULL) |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_set_msg( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_session *session, |
|||
const unsigned char *msg32 |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Serialize a MuSig partial signature or adaptor signature
|
|||
* |
|||
* Returns: 1 when the signature could be serialized, 0 otherwise |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: out32: pointer to a 32-byte array to store the serialized signature |
|||
* In: sig: pointer to the signature |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_partial_signature_serialize( |
|||
const secp256k1_context* ctx, |
|||
unsigned char *out32, |
|||
const secp256k1_musig_partial_signature* sig |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Parse and verify a MuSig partial signature.
|
|||
* |
|||
* Returns: 1 when the signature could be parsed, 0 otherwise. |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: sig: pointer to a signature object |
|||
* In: in32: pointer to the 32-byte signature to be parsed |
|||
* |
|||
* After the call, sig will always be initialized. If parsing failed or the |
|||
* encoded numbers are out of range, signature verification with it is |
|||
* guaranteed to fail for every message and public key. |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_partial_signature_parse( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_partial_signature* sig, |
|||
const unsigned char *in32 |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Produces a partial signature
|
|||
* |
|||
* Returns: 1: partial signature constructed |
|||
* 0: session in incorrect or inconsistent state |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: active signing session for which the combined nonce has been |
|||
* computed (cannot be NULL) |
|||
* Out: partial_sig: partial signature (cannot be NULL) |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_partial_sign( |
|||
const secp256k1_context* ctx, |
|||
const secp256k1_musig_session *session, |
|||
secp256k1_musig_partial_signature *partial_sig |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Checks that an individual partial signature verifies
|
|||
* |
|||
* This function is essential when using protocols with adaptor signatures. |
|||
* However, it is not essential for regular MuSig's, in the sense that if any |
|||
* partial signatures does not verify, the full signature will also not verify, so the |
|||
* problem will be caught. But this function allows determining the specific party |
|||
* who produced an invalid signature, so that signing can be restarted without them. |
|||
* |
|||
* Returns: 1: partial signature verifies |
|||
* 0: invalid signature or bad data |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: active session for which the combined nonce has been computed |
|||
* (cannot be NULL) |
|||
* signer: data for the signer who produced this signature (cannot be NULL) |
|||
* In: partial_sig: signature to verify (cannot be NULL) |
|||
* pubkey: public key of the signer who produced the signature (cannot be NULL) |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify( |
|||
const secp256k1_context* ctx, |
|||
const secp256k1_musig_session *session, |
|||
const secp256k1_musig_session_signer_data *signer, |
|||
const secp256k1_musig_partial_signature *partial_sig, |
|||
const secp256k1_pubkey *pubkey |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); |
|||
|
|||
/** Combines partial signatures
|
|||
* |
|||
* Returns: 1: all partial signatures have values in range. Does NOT mean the |
|||
* resulting signature verifies. |
|||
* 0: some partial signature had s/r out of range |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* session: initialized session for which the combined nonce has been |
|||
* computed (cannot be NULL) |
|||
* Out: sig: complete signature (cannot be NULL) |
|||
* In: partial_sigs: array of partial signatures to combine (cannot be NULL) |
|||
* n_sigs: number of signatures in the partial_sigs array |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine( |
|||
const secp256k1_context* ctx, |
|||
const secp256k1_musig_session *session, |
|||
secp256k1_schnorrsig *sig, |
|||
const secp256k1_musig_partial_signature *partial_sigs, |
|||
size_t n_sigs |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
/** Converts a partial signature to an adaptor signature by adding a given secret
|
|||
* adaptor. |
|||
* |
|||
* Returns: 1: signature and secret adaptor contained valid values |
|||
* 0: otherwise |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* Out: adaptor_sig: adaptor signature to produce (cannot be NULL) |
|||
* In: partial_sig: partial signature to tweak with secret adaptor (cannot be NULL) |
|||
* sec_adaptor32: 32-byte secret adaptor to add to the partial signature (cannot |
|||
* be NULL) |
|||
* nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_musig_partial_sig_adapt( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_musig_partial_signature *adaptor_sig, |
|||
const secp256k1_musig_partial_signature *partial_sig, |
|||
const unsigned char *sec_adaptor32, |
|||
int nonce_is_negated |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
/** Extracts a secret adaptor from a MuSig, given all parties' partial
|
|||
* signatures. This function will not fail unless given grossly invalid data; if it |
|||
* is merely given signatures that do not verify, the returned value will be |
|||
* nonsense. It is therefore important that all data be verified at earlier steps of |
|||
* any protocol that uses this function. |
|||
* |
|||
* Returns: 1: signatures contained valid data such that an adaptor could be extracted |
|||
* 0: otherwise |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL) |
|||
* In: sig: complete 2-of-2 signature (cannot be NULL) |
|||
* partial_sigs: array of partial signatures (cannot be NULL) |
|||
* n_partial_sigs: number of elements in partial_sigs array |
|||
* nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor( |
|||
const secp256k1_context* ctx, |
|||
unsigned char *sec_adaptor32, |
|||
const secp256k1_schnorrsig *sig, |
|||
const secp256k1_musig_partial_signature *partial_sigs, |
|||
size_t n_partial_sigs, |
|||
int nonce_is_negated |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,129 @@ |
|||
#ifndef SECP256K1_SCHNORRSIG_H |
|||
#define SECP256K1_SCHNORRSIG_H |
|||
|
|||
/** This module implements a variant of Schnorr signatures compliant with
|
|||
* BIP-schnorr |
|||
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki).
|
|||
*/ |
|||
|
|||
/** Opaque data structure that holds a parsed Schnorr signature.
|
|||
* |
|||
* The exact representation of data inside is implementation defined and not |
|||
* guaranteed to be portable between different platforms or versions. It is |
|||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved. |
|||
* If you need to convert to a format suitable for storage, transmission, or |
|||
* comparison, use the `secp256k1_schnorrsig_serialize` and |
|||
* `secp256k1_schnorrsig_parse` functions. |
|||
*/ |
|||
typedef struct { |
|||
unsigned char data[64]; |
|||
} secp256k1_schnorrsig; |
|||
|
|||
/** Serialize a Schnorr signature.
|
|||
* |
|||
* Returns: 1 |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: out64: pointer to a 64-byte array to store the serialized signature |
|||
* In: sig: pointer to the signature |
|||
* |
|||
* See secp256k1_schnorrsig_parse for details about the encoding. |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_schnorrsig_serialize( |
|||
const secp256k1_context* ctx, |
|||
unsigned char *out64, |
|||
const secp256k1_schnorrsig* sig |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Parse a Schnorr signature.
|
|||
* |
|||
* Returns: 1 when the signature could be parsed, 0 otherwise. |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: sig: pointer to a signature object |
|||
* In: in64: pointer to the 64-byte signature to be parsed |
|||
* |
|||
* The signature is serialized in the form R||s, where R is a 32-byte public |
|||
* key (x-coordinate only; the y-coordinate is considered to be the unique |
|||
* y-coordinate satisfying the curve equation that is a quadratic residue) |
|||
* and s is a 32-byte big-endian scalar. |
|||
* |
|||
* After the call, sig will always be initialized. If parsing failed or the |
|||
* encoded numbers are out of range, signature validation with it is |
|||
* guaranteed to fail for every message and public key. |
|||
*/ |
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
#else |
|||
SECP256K1_API |
|||
#endif |
|||
int secp256k1_schnorrsig_parse( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_schnorrsig* sig, |
|||
const unsigned char *in64 |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Create a Schnorr signature.
|
|||
* |
|||
* Returns 1 on success, 0 on failure. |
|||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) |
|||
* Out: sig: pointer to the returned signature (cannot be NULL) |
|||
* nonce_is_negated: a pointer to an integer indicates if signing algorithm negated the |
|||
* nonce (can be NULL) |
|||
* In: msg32: the 32-byte message hash being signed (cannot be NULL) |
|||
* seckey: pointer to a 32-byte secret key (cannot be NULL) |
|||
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bipschnorr is used |
|||
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) |
|||
*/ |
|||
SECP256K1_API int secp256k1_schnorrsig_sign( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_schnorrsig *sig, |
|||
int *nonce_is_negated, |
|||
const unsigned char *msg32, |
|||
const unsigned char *seckey, |
|||
secp256k1_nonce_function noncefp, |
|||
void *ndata |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); |
|||
|
|||
/** Verify a Schnorr signature.
|
|||
* |
|||
* Returns: 1: correct signature |
|||
* 0: incorrect or unparseable signature |
|||
* Args: ctx: a secp256k1 context object, initialized for verification. |
|||
* In: sig: the signature being verified (cannot be NULL) |
|||
* msg32: the 32-byte message hash being verified (cannot be NULL) |
|||
* pubkey: pointer to a public key to verify with (cannot be NULL) |
|||
*/ |
|||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( |
|||
const secp256k1_context* ctx, |
|||
const secp256k1_schnorrsig *sig, |
|||
const unsigned char *msg32, |
|||
const secp256k1_pubkey *pubkey |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
/** Verifies a set of Schnorr signatures.
|
|||
* |
|||
* Returns 1 if all succeeded, 0 otherwise. In particular, returns 1 if n_sigs is 0. |
|||
* |
|||
* Args: ctx: a secp256k1 context object, initialized for verification. |
|||
* scratch: scratch space used for the multiexponentiation |
|||
* In: sig: array of signatures, or NULL if there are no signatures |
|||
* msg32: array of messages, or NULL if there are no signatures |
|||
* pk: array of public keys, or NULL if there are no signatures |
|||
* n_sigs: number of signatures in above arrays. Must be smaller than |
|||
* 2^31 and smaller than half the maximum size_t value. Must be 0 |
|||
* if above arrays are NULL. |
|||
*/ |
|||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_scratch_space *scratch, |
|||
const secp256k1_schnorrsig *const *sig, |
|||
const unsigned char *const *msg32, |
|||
const secp256k1_pubkey *const *pk, |
|||
size_t n_sigs |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); |
|||
#endif |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,17 @@ |
|||
include_HEADERS += include/secp256k1_musig.h |
|||
noinst_HEADERS += src/modules/musig/main_impl.h |
|||
noinst_HEADERS += src/modules/musig/tests_impl.h |
|||
|
|||
noinst_PROGRAMS += example_musig |
|||
example_musig_SOURCES = src/modules/musig/example.c |
|||
example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES) |
|||
if !ENABLE_COVERAGE |
|||
example_musig_CPPFLAGS += -DVERIFY |
|||
endif |
|||
example_musig_LDADD = libsecp256k1.la $(SECP_LIBS) |
|||
example_musig_LDFLAGS = -static |
|||
|
|||
if USE_TESTS |
|||
TESTS += example_musig |
|||
endif |
|||
|
@ -0,0 +1,166 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2018 Jonas Nick * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
/**
|
|||
* This file demonstrates how to use the MuSig module to create a multisignature. |
|||
* Additionally, see the documentation in include/secp256k1_musig.h. |
|||
*/ |
|||
|
|||
/*#include <stdio.h>
|
|||
#include <assert.h> |
|||
#include <secp256k1.h> |
|||
#include <secp256k1_schnorrsig.h> |
|||
#include <secp256k1_musig.h>*/ |
|||
|
|||
/* Number of public keys involved in creating the aggregate signature */ |
|||
#define N_SIGNERS 3 |
|||
/* Create a key pair and store it in seckey and pubkey */ |
|||
int create_key(const secp256k1_context* ctx, unsigned char* seckey, secp256k1_pubkey* pubkey) { |
|||
int ret; |
|||
FILE *frand = fopen("/dev/urandom", "r"); |
|||
if (frand == NULL) { |
|||
return 0; |
|||
} |
|||
do { |
|||
if(!fread(seckey, 32, 1, frand)) { |
|||
fclose(frand); |
|||
return 0; |
|||
} |
|||
/* The probability that this not a valid secret key is approximately 2^-128 */ |
|||
} while (!secp256k1_ec_seckey_verify(ctx, seckey)); |
|||
fclose(frand); |
|||
ret = secp256k1_ec_pubkey_create(ctx, pubkey, seckey); |
|||
return ret; |
|||
} |
|||
|
|||
/* Sign a message hash with the given key pairs and store the result in sig */ |
|||
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_pubkey* pubkeys, const unsigned char* msg32, secp256k1_schnorrsig *sig) { |
|||
secp256k1_musig_session musig_session[N_SIGNERS]; |
|||
unsigned char nonce_commitment[N_SIGNERS][32]; |
|||
const unsigned char *nonce_commitment_ptr[N_SIGNERS]; |
|||
secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS]; |
|||
secp256k1_pubkey nonce[N_SIGNERS]; |
|||
int i, j; |
|||
secp256k1_musig_partial_signature partial_sig[N_SIGNERS]; |
|||
|
|||
for (i = 0; i < N_SIGNERS; i++) { |
|||
FILE *frand; |
|||
unsigned char session_id32[32]; |
|||
unsigned char pk_hash[32]; |
|||
secp256k1_pubkey combined_pk; |
|||
|
|||
/* Create combined pubkey and initialize signer data */ |
|||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, pk_hash, pubkeys, N_SIGNERS)) { |
|||
return 0; |
|||
} |
|||
/* Create random session ID. It is absolutely necessary that the session ID
|
|||
* is unique for every call of secp256k1_musig_session_initialize. Otherwise |
|||
* it's trivial for an attacker to extract the secret key! */ |
|||
frand = fopen("/dev/urandom", "r"); |
|||
if(frand == NULL) { |
|||
return 0; |
|||
} |
|||
if (!fread(session_id32, 32, 1, frand)) { |
|||
fclose(frand); |
|||
return 0; |
|||
} |
|||
fclose(frand); |
|||
/* Initialize session */ |
|||
if (!secp256k1_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, pk_hash, N_SIGNERS, i, seckeys[i])) { |
|||
return 0; |
|||
} |
|||
nonce_commitment_ptr[i] = &nonce_commitment[i][0]; |
|||
} |
|||
/* Communication round 1: Exchange nonce commitments */ |
|||
for (i = 0; i < N_SIGNERS; i++) { |
|||
/* Set nonce commitments in the signer data and get the own public nonce */ |
|||
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS)) { |
|||
return 0; |
|||
} |
|||
} |
|||
/* Communication round 2: Exchange nonces */ |
|||
for (i = 0; i < N_SIGNERS; i++) { |
|||
for (j = 0; j < N_SIGNERS; j++) { |
|||
if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], &nonce[j])) { |
|||
/* Signer j's nonce does not match the nonce commitment. In this case
|
|||
* abort the protocol. If you make another attempt at finishing the |
|||
* protocol, create a new session (with a fresh session ID!). */ |
|||
return 0; |
|||
} |
|||
} |
|||
if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) { |
|||
return 0; |
|||
} |
|||
} |
|||
for (i = 0; i < N_SIGNERS; i++) { |
|||
if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) { |
|||
return 0; |
|||
} |
|||
} |
|||
/* Communication round 3: Exchange partial signatures */ |
|||
for (i = 0; i < N_SIGNERS; i++) { |
|||
for (j = 0; j < N_SIGNERS; j++) { |
|||
/* To check whether signing was successful, it suffices to either verify
|
|||
* the the combined signature with the combined public key using |
|||
* secp256k1_schnorrsig_verify, or verify all partial signatures of all |
|||
* signers individually. Verifying the combined signature is cheaper but |
|||
* verifying the individual partial signatures has the advantage that it |
|||
* can be used to determine which of the partial signatures are invalid |
|||
* (if any), i.e., which of the partial signatures cause the combined |
|||
* signature to be invalid and thus the protocol run to fail. It's also |
|||
* fine to first verify the combined sig, and only verify the individual |
|||
* sigs if it does not work. |
|||
*/ |
|||
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], &pubkeys[j])) { |
|||
return 0; |
|||
} |
|||
} |
|||
} |
|||
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS); |
|||
} |
|||
|
|||
int testmain(void) { |
|||
secp256k1_context* ctx; |
|||
int i; |
|||
unsigned char seckeys[N_SIGNERS][32]; |
|||
secp256k1_pubkey pubkeys[N_SIGNERS]; |
|||
secp256k1_pubkey combined_pk; |
|||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg"; |
|||
secp256k1_schnorrsig sig; |
|||
|
|||
/* Create a context for signing and verification */ |
|||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
fprintf(stderr,"Creating key pairs......"); |
|||
for (i = 0; i < N_SIGNERS; i++) { |
|||
if (!create_key(ctx, seckeys[i], &pubkeys[i])) { |
|||
fprintf(stderr,"FAILED\n"); |
|||
return 1; |
|||
} |
|||
} |
|||
fprintf(stderr,"ok\n"); |
|||
fprintf(stderr,"Combining public keys..."); |
|||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) { |
|||
fprintf(stderr,"FAILED\n"); |
|||
return 1; |
|||
} |
|||
fprintf(stderr,"ok\n"); |
|||
fprintf(stderr,"Signing message........."); |
|||
if (!sign(ctx, seckeys, pubkeys, msg, &sig)) { |
|||
fprintf(stderr,"FAILED\n"); |
|||
return 1; |
|||
} |
|||
fprintf(stderr,"ok\n"); |
|||
fprintf(stderr,"Verifying signature....."); |
|||
if (!secp256k1_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) { |
|||
fprintf(stderr,"FAILED\n"); |
|||
return 1; |
|||
} |
|||
fprintf(stderr,"ok\n"); |
|||
secp256k1_context_destroy(ctx); |
|||
return 0; |
|||
} |
|||
|
|||
|
@ -0,0 +1,631 @@ |
|||
|
|||
/**********************************************************************
|
|||
* Copyright (c) 2018 Andrew Poelstra, Jonas Nick * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_MODULE_MUSIG_MAIN_ |
|||
#define _SECP256K1_MODULE_MUSIG_MAIN_ |
|||
|
|||
#include "../../../include/secp256k1.h" |
|||
#include "../../../include/secp256k1_musig.h" |
|||
#include "hash.h" |
|||
|
|||
/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */ |
|||
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_pubkey *pk, size_t np) { |
|||
secp256k1_sha256 sha; |
|||
size_t i; |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
for (i = 0; i < np; i++) { |
|||
unsigned char ser[33]; |
|||
size_t serlen = sizeof(ser); |
|||
if (!secp256k1_ec_pubkey_serialize(ctx, ser, &serlen, &pk[i], SECP256K1_EC_COMPRESSED)) { |
|||
return 0; |
|||
} |
|||
secp256k1_sha256_write(&sha, ser, serlen); |
|||
} |
|||
secp256k1_sha256_finalize(&sha, ell); |
|||
return 1; |
|||
} |
|||
|
|||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
|||
* SHA256 to SHA256("MuSig coefficient")||SHA256("MuSig coefficient"). */ |
|||
static void secp256k1_musig_sha256_init_tagged(secp256k1_sha256 *sha) { |
|||
secp256k1_sha256_initialize(sha); |
|||
|
|||
sha->s[0] = 0x0fd0690cul; |
|||
sha->s[1] = 0xfefeae97ul; |
|||
sha->s[2] = 0x996eac7ful; |
|||
sha->s[3] = 0x5c30d864ul; |
|||
sha->s[4] = 0x8c4a0573ul; |
|||
sha->s[5] = 0xaca1a22ful; |
|||
sha->s[6] = 0x6f43b801ul; |
|||
sha->s[7] = 0x85ce27cdul; |
|||
sha->bytes = 64; |
|||
} |
|||
|
|||
/* Compute r = SHA256(ell, idx). The four bytes of idx are serialized least significant byte first. */ |
|||
static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char *ell, uint32_t idx) { |
|||
secp256k1_sha256 sha; |
|||
unsigned char buf[32]; |
|||
size_t i; |
|||
|
|||
secp256k1_musig_sha256_init_tagged(&sha); |
|||
secp256k1_sha256_write(&sha, ell, 32); |
|||
/* We're hashing the index of the signer instead of its public key as specified
|
|||
* in the MuSig paper. This reduces the total amount of data that needs to be |
|||
* hashed. |
|||
* Additionally, it prevents creating identical musig_coefficients for identical |
|||
* public keys. A participant Bob could choose his public key to be the same as |
|||
* Alice's, then replay Alice's messages (nonce and partial signature) to create |
|||
* a valid partial signature. This is not a problem for MuSig per se, but could |
|||
* result in subtle issues with protocols building on threshold signatures. |
|||
* With the assumption that public keys are unique, hashing the index is |
|||
* equivalent to hashing the public key. Because the public key can be |
|||
* identified by the index given the ordered list of public keys (included in |
|||
* ell), the index is just a different encoding of the public key.*/ |
|||
for (i = 0; i < sizeof(uint32_t); i++) { |
|||
unsigned char c = idx; |
|||
secp256k1_sha256_write(&sha, &c, 1); |
|||
idx >>= 8; |
|||
} |
|||
secp256k1_sha256_finalize(&sha, buf); |
|||
secp256k1_scalar_set_b32(r, buf, NULL); |
|||
} |
|||
|
|||
typedef struct { |
|||
const secp256k1_context *ctx; |
|||
unsigned char ell[32]; |
|||
const secp256k1_pubkey *pks; |
|||
} secp256k1_musig_pubkey_combine_ecmult_data; |
|||
|
|||
/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */ |
|||
static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { |
|||
secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data; |
|||
secp256k1_musig_coefficient(sc, ctx->ell, idx); |
|||
return secp256k1_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]); |
|||
} |
|||
|
|||
|
|||
static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *signers, uint32_t n_signers) { |
|||
uint32_t i; |
|||
for (i = 0; i < n_signers; i++) { |
|||
memset(&signers[i], 0, sizeof(signers[i])); |
|||
signers[i].index = i; |
|||
signers[i].present = 0; |
|||
} |
|||
} |
|||
|
|||
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys) { |
|||
secp256k1_musig_pubkey_combine_ecmult_data ecmult_data; |
|||
secp256k1_gej pkj; |
|||
secp256k1_ge pkp; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(combined_pk != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); |
|||
ARG_CHECK(pubkeys != NULL); |
|||
ARG_CHECK(n_pubkeys > 0); |
|||
|
|||
ecmult_data.ctx = ctx; |
|||
ecmult_data.pks = pubkeys; |
|||
if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) { |
|||
return 0; |
|||
} |
|||
if (!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) { |
|||
return 0; |
|||
} |
|||
secp256k1_ge_set_gej(&pkp, &pkj); |
|||
secp256k1_pubkey_save(combined_pk, &pkp); |
|||
|
|||
if (pk_hash32 != NULL) { |
|||
memcpy(pk_hash32, ecmult_data.ell, 32); |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey) { |
|||
unsigned char combined_ser[33]; |
|||
size_t combined_ser_size = sizeof(combined_ser); |
|||
int overflow; |
|||
secp256k1_scalar secret; |
|||
secp256k1_scalar mu; |
|||
secp256k1_sha256 sha; |
|||
secp256k1_gej rj; |
|||
secp256k1_ge rp; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); |
|||
ARG_CHECK(session != NULL); |
|||
ARG_CHECK(signers != NULL); |
|||
ARG_CHECK(nonce_commitment32 != NULL); |
|||
ARG_CHECK(session_id32 != NULL); |
|||
ARG_CHECK(combined_pk != NULL); |
|||
ARG_CHECK(pk_hash32 != NULL); |
|||
ARG_CHECK(seckey != NULL); |
|||
|
|||
memset(session, 0, sizeof(*session)); |
|||
|
|||
if (msg32 != NULL) { |
|||
memcpy(session->msg, msg32, 32); |
|||
session->msg_is_set = 1; |
|||
} else { |
|||
session->msg_is_set = 0; |
|||
} |
|||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); |
|||
memcpy(session->pk_hash, pk_hash32, 32); |
|||
session->nonce_is_set = 0; |
|||
session->has_secret_data = 1; |
|||
if (n_signers == 0 || my_index >= n_signers) { |
|||
return 0; |
|||
} |
|||
if (n_signers > UINT32_MAX) { |
|||
return 0; |
|||
} |
|||
session->n_signers = (uint32_t) n_signers; |
|||
secp256k1_musig_signers_init(signers, session->n_signers); |
|||
session->nonce_commitments_hash_is_set = 0; |
|||
|
|||
/* Compute secret key */ |
|||
secp256k1_scalar_set_b32(&secret, seckey, &overflow); |
|||
if (overflow) { |
|||
secp256k1_scalar_clear(&secret); |
|||
return 0; |
|||
} |
|||
secp256k1_musig_coefficient(&mu, pk_hash32, (uint32_t) my_index); |
|||
secp256k1_scalar_mul(&secret, &secret, &mu); |
|||
secp256k1_scalar_get_b32(session->seckey, &secret); |
|||
|
|||
/* Compute secret nonce */ |
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, session_id32, 32); |
|||
if (session->msg_is_set) { |
|||
secp256k1_sha256_write(&sha, msg32, 32); |
|||
} |
|||
secp256k1_ec_pubkey_serialize(ctx, combined_ser, &combined_ser_size, combined_pk, SECP256K1_EC_COMPRESSED); |
|||
secp256k1_sha256_write(&sha, combined_ser, combined_ser_size); |
|||
secp256k1_sha256_write(&sha, seckey, 32); |
|||
secp256k1_sha256_finalize(&sha, session->secnonce); |
|||
secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow); |
|||
if (overflow) { |
|||
secp256k1_scalar_clear(&secret); |
|||
return 0; |
|||
} |
|||
|
|||
/* Compute public nonce and commitment */ |
|||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &secret); |
|||
secp256k1_ge_set_gej(&rp, &rj); |
|||
secp256k1_pubkey_save(&session->nonce, &rp); |
|||
|
|||
if (nonce_commitment32 != NULL) { |
|||
unsigned char commit[33]; |
|||
size_t commit_size = sizeof(commit); |
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, &session->nonce, SECP256K1_EC_COMPRESSED); |
|||
secp256k1_sha256_write(&sha, commit, commit_size); |
|||
secp256k1_sha256_finalize(&sha, nonce_commitment32); |
|||
} |
|||
|
|||
secp256k1_scalar_clear(&secret); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, secp256k1_pubkey *nonce, const unsigned char *const *commitments, size_t n_commitments) { |
|||
secp256k1_sha256 sha; |
|||
unsigned char nonce_commitments_hash[32]; |
|||
size_t i; |
|||
(void) ctx; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(session != NULL); |
|||
ARG_CHECK(signers != NULL); |
|||
ARG_CHECK(nonce != NULL); |
|||
ARG_CHECK(commitments != NULL); |
|||
|
|||
if (!session->has_secret_data || n_commitments != session->n_signers) { |
|||
return 0; |
|||
} |
|||
for (i = 0; i < n_commitments; i++) { |
|||
ARG_CHECK(commitments[i] != NULL); |
|||
} |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
for (i = 0; i < n_commitments; i++) { |
|||
memcpy(signers[i].nonce_commitment, commitments[i], 32); |
|||
secp256k1_sha256_write(&sha, commitments[i], 32); |
|||
} |
|||
secp256k1_sha256_finalize(&sha, nonce_commitments_hash); |
|||
if (session->nonce_commitments_hash_is_set |
|||
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) { |
|||
/* Abort if get_public_nonce has been called before with a different array of
|
|||
* commitments. */ |
|||
return 0; |
|||
} |
|||
memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32); |
|||
session->nonce_commitments_hash_is_set = 1; |
|||
memcpy(nonce, &session->nonce, sizeof(*nonce)); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, const unsigned char *const *commitments, size_t n_signers) { |
|||
size_t i; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(session != NULL); |
|||
ARG_CHECK(signers != NULL); |
|||
ARG_CHECK(combined_pk != NULL); |
|||
ARG_CHECK(pk_hash32 != NULL); |
|||
ARG_CHECK(commitments != NULL); |
|||
/* Check n_signers before checking commitments to allow testing the case where
|
|||
* n_signers is big without allocating the space. */ |
|||
if (n_signers > UINT32_MAX) { |
|||
return 0; |
|||
} |
|||
for (i = 0; i < n_signers; i++) { |
|||
ARG_CHECK(commitments[i] != NULL); |
|||
} |
|||
(void) ctx; |
|||
|
|||
memset(session, 0, sizeof(*session)); |
|||
|
|||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); |
|||
if (n_signers == 0) { |
|||
return 0; |
|||
} |
|||
session->n_signers = (uint32_t) n_signers; |
|||
secp256k1_musig_signers_init(signers, session->n_signers); |
|||
|
|||
memcpy(session->pk_hash, pk_hash32, 32); |
|||
session->nonce_is_set = 0; |
|||
session->msg_is_set = 0; |
|||
if (msg32 != NULL) { |
|||
memcpy(session->msg, msg32, 32); |
|||
session->msg_is_set = 1; |
|||
} |
|||
session->has_secret_data = 0; |
|||
session->nonce_commitments_hash_is_set = 0; |
|||
|
|||
for (i = 0; i < n_signers; i++) { |
|||
memcpy(signers[i].nonce_commitment, commitments[i], 32); |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const secp256k1_pubkey *nonce) { |
|||
unsigned char commit[33]; |
|||
size_t commit_size = sizeof(commit); |
|||
secp256k1_sha256 sha; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(signer != NULL); |
|||
ARG_CHECK(nonce != NULL); |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, nonce, SECP256K1_EC_COMPRESSED); |
|||
secp256k1_sha256_write(&sha, commit, commit_size); |
|||
secp256k1_sha256_finalize(&sha, commit); |
|||
|
|||
if (memcmp(commit, signer->nonce_commitment, 32) != 0) { |
|||
return 0; |
|||
} |
|||
memcpy(&signer->nonce, nonce, sizeof(*nonce)); |
|||
signer->present = 1; |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, int *nonce_is_negated, const secp256k1_pubkey *adaptor) { |
|||
secp256k1_gej combined_noncej; |
|||
secp256k1_ge combined_noncep; |
|||
secp256k1_ge noncep; |
|||
secp256k1_sha256 sha; |
|||
unsigned char nonce_commitments_hash[32]; |
|||
size_t i; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(session != NULL); |
|||
ARG_CHECK(signers != NULL); |
|||
|
|||
if (n_signers != session->n_signers) { |
|||
return 0; |
|||
} |
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_gej_set_infinity(&combined_noncej); |
|||
for (i = 0; i < n_signers; i++) { |
|||
if (!signers[i].present) { |
|||
return 0; |
|||
} |
|||
secp256k1_sha256_write(&sha, signers[i].nonce_commitment, 32); |
|||
secp256k1_pubkey_load(ctx, &noncep, &signers[i].nonce); |
|||
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL); |
|||
} |
|||
secp256k1_sha256_finalize(&sha, nonce_commitments_hash); |
|||
/* Either the session is a verifier session or or the nonce_commitments_hash has
|
|||
* been set in `musig_session_get_public_nonce`. */ |
|||
VERIFY_CHECK(!session->has_secret_data || session->nonce_commitments_hash_is_set); |
|||
if (session->has_secret_data |
|||
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) { |
|||
/* If the signers' commitments changed between get_public_nonce and now we
|
|||
* have to abort because in that case they may have seen our nonce before |
|||
* creating their commitment. That can happen if the signer_data given to |
|||
* this function is different to the signer_data given to get_public_nonce. |
|||
* */ |
|||
return 0; |
|||
} |
|||
|
|||
/* Add public adaptor to nonce */ |
|||
if (adaptor != NULL) { |
|||
secp256k1_pubkey_load(ctx, &noncep, adaptor); |
|||
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL); |
|||
} |
|||
secp256k1_ge_set_gej(&combined_noncep, &combined_noncej); |
|||
if (secp256k1_fe_is_quad_var(&combined_noncep.y)) { |
|||
session->nonce_is_negated = 0; |
|||
} else { |
|||
session->nonce_is_negated = 1; |
|||
secp256k1_ge_neg(&combined_noncep, &combined_noncep); |
|||
} |
|||
if (nonce_is_negated != NULL) { |
|||
*nonce_is_negated = session->nonce_is_negated; |
|||
} |
|||
secp256k1_pubkey_save(&session->combined_nonce, &combined_noncep); |
|||
session->nonce_is_set = 1; |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_session_set_msg(const secp256k1_context* ctx, secp256k1_musig_session *session, const unsigned char *msg32) { |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(session != NULL); |
|||
ARG_CHECK(msg32 != NULL); |
|||
|
|||
if (session->msg_is_set) { |
|||
return 0; |
|||
} |
|||
memcpy(session->msg, msg32, 32); |
|||
session->msg_is_set = 1; |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_partial_signature_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig) { |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(out32 != NULL); |
|||
ARG_CHECK(sig != NULL); |
|||
memcpy(out32, sig->data, 32); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp256k1_musig_partial_signature* sig, const unsigned char *in32) { |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(in32 != NULL); |
|||
memcpy(sig->data, in32, 32); |
|||
return 1; |
|||
} |
|||
|
|||
/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */ |
|||
static int secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) { |
|||
unsigned char buf[33]; |
|||
size_t bufsize = 33; |
|||
secp256k1_ge rp; |
|||
secp256k1_sha256 sha; |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
if (!session->nonce_is_set) { |
|||
return 0; |
|||
} |
|||
secp256k1_pubkey_load(ctx, &rp, &session->combined_nonce); |
|||
secp256k1_fe_get_b32(buf, &rp.x); |
|||
secp256k1_sha256_write(&sha, buf, 32); |
|||
secp256k1_ec_pubkey_serialize(ctx, buf, &bufsize, &session->combined_pk, SECP256K1_EC_COMPRESSED); |
|||
VERIFY_CHECK(bufsize == 33); |
|||
secp256k1_sha256_write(&sha, buf, bufsize); |
|||
if (!session->msg_is_set) { |
|||
return 0; |
|||
} |
|||
secp256k1_sha256_write(&sha, session->msg, 32); |
|||
secp256k1_sha256_finalize(&sha, msghash); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig) { |
|||
unsigned char msghash[32]; |
|||
int overflow; |
|||
secp256k1_scalar sk; |
|||
secp256k1_scalar e, k; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(partial_sig != NULL); |
|||
ARG_CHECK(session != NULL); |
|||
|
|||
if (!session->nonce_is_set || !session->has_secret_data) { |
|||
return 0; |
|||
} |
|||
|
|||
/* build message hash */ |
|||
if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_set_b32(&e, msghash, NULL); |
|||
|
|||
secp256k1_scalar_set_b32(&sk, session->seckey, &overflow); |
|||
if (overflow) { |
|||
secp256k1_scalar_clear(&sk); |
|||
return 0; |
|||
} |
|||
|
|||
secp256k1_scalar_set_b32(&k, session->secnonce, &overflow); |
|||
if (overflow || secp256k1_scalar_is_zero(&k)) { |
|||
secp256k1_scalar_clear(&sk); |
|||
secp256k1_scalar_clear(&k); |
|||
return 0; |
|||
} |
|||
if (session->nonce_is_negated) { |
|||
secp256k1_scalar_negate(&k, &k); |
|||
} |
|||
|
|||
/* Sign */ |
|||
secp256k1_scalar_mul(&e, &e, &sk); |
|||
secp256k1_scalar_add(&e, &e, &k); |
|||
secp256k1_scalar_get_b32(&partial_sig->data[0], &e); |
|||
secp256k1_scalar_clear(&sk); |
|||
secp256k1_scalar_clear(&k); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) { |
|||
size_t i; |
|||
secp256k1_scalar s; |
|||
secp256k1_ge noncep; |
|||
(void) ctx; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(partial_sigs != NULL); |
|||
ARG_CHECK(session != NULL); |
|||
|
|||
if (!session->nonce_is_set) { |
|||
return 0; |
|||
} |
|||
if (n_sigs != session->n_signers) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_clear(&s); |
|||
for (i = 0; i < n_sigs; i++) { |
|||
int overflow; |
|||
secp256k1_scalar term; |
|||
|
|||
secp256k1_scalar_set_b32(&term, partial_sigs[i].data, &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_add(&s, &s, &term); |
|||
} |
|||
|
|||
secp256k1_pubkey_load(ctx, &noncep, &session->combined_nonce); |
|||
VERIFY_CHECK(secp256k1_fe_is_quad_var(&noncep.y)); |
|||
secp256k1_fe_normalize(&noncep.x); |
|||
secp256k1_fe_get_b32(&sig->data[0], &noncep.x); |
|||
secp256k1_scalar_get_b32(&sig->data[32], &s); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_pubkey *pubkey) { |
|||
unsigned char msghash[32]; |
|||
secp256k1_scalar s; |
|||
secp256k1_scalar e; |
|||
secp256k1_scalar mu; |
|||
secp256k1_gej rj; |
|||
secp256k1_ge rp; |
|||
int overflow; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); |
|||
ARG_CHECK(session != NULL); |
|||
ARG_CHECK(signer != NULL); |
|||
ARG_CHECK(partial_sig != NULL); |
|||
ARG_CHECK(pubkey != NULL); |
|||
|
|||
if (!session->nonce_is_set || !signer->present) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_set_b32(&e, msghash, NULL); |
|||
|
|||
/* Multiplying the messagehash by the musig coefficient is equivalent
|
|||
* to multiplying the signer's public key by the coefficient, except |
|||
* much easier to do. */ |
|||
secp256k1_musig_coefficient(&mu, session->pk_hash, signer->index); |
|||
secp256k1_scalar_mul(&e, &e, &mu); |
|||
|
|||
if (!secp256k1_pubkey_load(ctx, &rp, &signer->nonce)) { |
|||
return 0; |
|||
} |
|||
|
|||
if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pubkey)) { |
|||
return 0; |
|||
} |
|||
if (!session->nonce_is_negated) { |
|||
secp256k1_ge_neg(&rp, &rp); |
|||
} |
|||
secp256k1_gej_add_ge_var(&rj, &rj, &rp, NULL); |
|||
|
|||
return secp256k1_gej_is_infinity(&rj); |
|||
} |
|||
|
|||
int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_is_negated) { |
|||
secp256k1_scalar s; |
|||
secp256k1_scalar t; |
|||
int overflow; |
|||
|
|||
(void) ctx; |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(adaptor_sig != NULL); |
|||
ARG_CHECK(partial_sig != NULL); |
|||
ARG_CHECK(sec_adaptor32 != NULL); |
|||
|
|||
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow); |
|||
if (overflow) { |
|||
secp256k1_scalar_clear(&t); |
|||
return 0; |
|||
} |
|||
|
|||
if (nonce_is_negated) { |
|||
secp256k1_scalar_negate(&t, &t); |
|||
} |
|||
|
|||
secp256k1_scalar_add(&s, &s, &t); |
|||
secp256k1_scalar_get_b32(adaptor_sig->data, &s); |
|||
secp256k1_scalar_clear(&t); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) { |
|||
secp256k1_scalar t; |
|||
secp256k1_scalar s; |
|||
int overflow; |
|||
size_t i; |
|||
|
|||
(void) ctx; |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(sec_adaptor32 != NULL); |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(partial_sigs != NULL); |
|||
|
|||
secp256k1_scalar_set_b32(&t, &sig->data[32], &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_negate(&t, &t); |
|||
|
|||
for (i = 0; i < n_partial_sigs; i++) { |
|||
secp256k1_scalar_set_b32(&s, partial_sigs[i].data, &overflow); |
|||
if (overflow) { |
|||
secp256k1_scalar_clear(&t); |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_add(&t, &t, &s); |
|||
} |
|||
|
|||
if (!nonce_is_negated) { |
|||
secp256k1_scalar_negate(&t, &t); |
|||
} |
|||
secp256k1_scalar_get_b32(sec_adaptor32, &t); |
|||
secp256k1_scalar_clear(&t); |
|||
return 1; |
|||
} |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,758 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2018 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_MODULE_MUSIG_TESTS_ |
|||
#define _SECP256K1_MODULE_MUSIG_TESTS_ |
|||
|
|||
#include "secp256k1_musig.h" |
|||
|
|||
void musig_api_tests(secp256k1_scratch_space *scratch) { |
|||
secp256k1_scratch_space *scratch_small; |
|||
secp256k1_musig_session session[2]; |
|||
secp256k1_musig_session verifier_session; |
|||
secp256k1_musig_session_signer_data signer0[2]; |
|||
secp256k1_musig_session_signer_data signer1[2]; |
|||
secp256k1_musig_session_signer_data verifier_signer_data[2]; |
|||
secp256k1_musig_partial_signature partial_sig[2]; |
|||
secp256k1_musig_partial_signature partial_sig_adapted[2]; |
|||
secp256k1_musig_partial_signature partial_sig_overflow; |
|||
secp256k1_schnorrsig final_sig; |
|||
secp256k1_schnorrsig final_sig_cmp; |
|||
|
|||
unsigned char buf[32]; |
|||
unsigned char sk[2][32]; |
|||
unsigned char ones[32]; |
|||
unsigned char session_id[2][32]; |
|||
unsigned char nonce_commitment[2][32]; |
|||
int nonce_is_negated; |
|||
const unsigned char *ncs[2]; |
|||
unsigned char msg[32]; |
|||
unsigned char msghash[32]; |
|||
secp256k1_pubkey combined_pk; |
|||
unsigned char pk_hash[32]; |
|||
secp256k1_pubkey pk[2]; |
|||
|
|||
unsigned char sec_adaptor[32]; |
|||
unsigned char sec_adaptor1[32]; |
|||
secp256k1_pubkey adaptor; |
|||
|
|||
/** setup **/ |
|||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); |
|||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); |
|||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); |
|||
int ecount; |
|||
|
|||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); |
|||
|
|||
memset(ones, 0xff, 32); |
|||
|
|||
secp256k1_rand256(session_id[0]); |
|||
secp256k1_rand256(session_id[1]); |
|||
secp256k1_rand256(sk[0]); |
|||
secp256k1_rand256(sk[1]); |
|||
secp256k1_rand256(msg); |
|||
secp256k1_rand256(sec_adaptor); |
|||
|
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1); |
|||
|
|||
/** main test body **/ |
|||
|
|||
/* Key combination */ |
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, pk_hash, pk, 2) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, pk_hash, pk, 2) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); |
|||
CHECK(ecount == 2); |
|||
/* pubkey_combine does not require a scratch space */ |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, pk_hash, pk, 2) == 1); |
|||
CHECK(ecount == 2); |
|||
/* If a scratch space is given it shouldn't be too small */ |
|||
scratch_small = secp256k1_scratch_space_create(ctx, 1); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, pk_hash, pk, 2) == 0); |
|||
secp256k1_scratch_space_destroy(scratch_small); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, pk_hash, pk, 2) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 2) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 0) == 0); |
|||
CHECK(ecount == 5); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 0) == 0); |
|||
CHECK(ecount == 6); |
|||
|
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); |
|||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); |
|||
|
|||
/** Session creation **/ |
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_session_initialize(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_session_initialize(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_session_initialize(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 5); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 6); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); |
|||
CHECK(ecount == 6); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, pk_hash, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 7); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0); |
|||
CHECK(ecount == 8); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 0, 0, sk[0]) == 0); |
|||
CHECK(ecount == 8); |
|||
/* If more than UINT32_MAX fits in a size_t, test that session_initialize
|
|||
* rejects n_signers that high. */ |
|||
if (SIZE_MAX > UINT32_MAX) { |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0); |
|||
} |
|||
CHECK(ecount == 8); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, NULL) == 0); |
|||
CHECK(ecount == 9); |
|||
/* secret key overflows */ |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, ones) == 0); |
|||
CHECK(ecount == 9); |
|||
|
|||
|
|||
{ |
|||
secp256k1_musig_session session_without_msg; |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session_without_msg, signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); |
|||
CHECK(secp256k1_musig_session_set_msg(none, &session_without_msg, msg) == 1); |
|||
CHECK(secp256k1_musig_session_set_msg(none, &session_without_msg, msg) == 0); |
|||
} |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); |
|||
CHECK(secp256k1_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1); |
|||
ncs[0] = nonce_commitment[0]; |
|||
ncs[1] = nonce_commitment[1]; |
|||
|
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1); |
|||
CHECK(ecount == 0); |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, pk_hash, ncs, 2) == 1); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, pk_hash, ncs, 2) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, NULL, 2) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 0) == 0); |
|||
CHECK(ecount == 4); |
|||
if (SIZE_MAX > UINT32_MAX) { |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, ((size_t) UINT32_MAX) + 2) == 0); |
|||
} |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1); |
|||
|
|||
CHECK(secp256k1_musig_compute_messagehash(none, msghash, &verifier_session) == 0); |
|||
CHECK(secp256k1_musig_compute_messagehash(none, msghash, &session[0]) == 0); |
|||
|
|||
/** Signing step 0 -- exchange nonce commitments */ |
|||
ecount = 0; |
|||
{ |
|||
secp256k1_pubkey nonce; |
|||
|
|||
/* Can obtain public nonce after commitments have been exchanged; still can't sign */ |
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &nonce, ncs, 2) == 1); |
|||
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 0); |
|||
CHECK(ecount == 0); |
|||
} |
|||
|
|||
/** Signing step 1 -- exchange nonces */ |
|||
ecount = 0; |
|||
{ |
|||
secp256k1_pubkey public_nonce[3]; |
|||
|
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1); |
|||
CHECK(ecount == 0); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, &public_nonce[0], ncs, 2) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], NULL, &public_nonce[0], ncs, 2) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, NULL, ncs, 2) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], NULL, 2) == 0); |
|||
CHECK(ecount == 4); |
|||
/* Number of commitments and number of signers are different */ |
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 1) == 0); |
|||
CHECK(ecount == 4); |
|||
|
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, &public_nonce[1], ncs, 2) == 1); |
|||
|
|||
CHECK(secp256k1_musig_set_nonce(none, &signer0[0], &public_nonce[0]) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[0]) == 0); |
|||
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1); |
|||
CHECK(ecount == 4); |
|||
|
|||
CHECK(secp256k1_musig_set_nonce(none, NULL, &public_nonce[0]) == 0); |
|||
CHECK(ecount == 5); |
|||
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], NULL) == 0); |
|||
CHECK(ecount == 6); |
|||
|
|||
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], &public_nonce[0]) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(none, &signer1[1], &public_nonce[1]) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[0], &public_nonce[0]) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[1], &public_nonce[1]) == 1); |
|||
|
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1); |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, NULL, signer0, 2, &nonce_is_negated, &adaptor) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], NULL, 2, &nonce_is_negated, &adaptor) == 0); |
|||
CHECK(ecount == 2); |
|||
/* Number of signers differs from number during intialization */ |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 1, &nonce_is_negated, &adaptor) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, NULL, &adaptor) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, NULL) == 1); |
|||
|
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1); |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[1], signer0, 2, &nonce_is_negated, &adaptor) == 1); |
|||
CHECK(secp256k1_musig_session_combine_nonces(none, &verifier_session, verifier_signer_data, 2, &nonce_is_negated, &adaptor) == 1); |
|||
} |
|||
|
|||
/** Signing step 2 -- partial signatures */ |
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1); |
|||
CHECK(ecount == 0); |
|||
CHECK(secp256k1_musig_partial_sign(none, NULL, &partial_sig[0]) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_partial_sign(none, &session[0], NULL) == 0); |
|||
CHECK(ecount == 2); |
|||
|
|||
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1); |
|||
CHECK(secp256k1_musig_partial_sign(none, &session[1], &partial_sig[1]) == 1); |
|||
/* observer can't sign */ |
|||
CHECK(secp256k1_musig_partial_sign(none, &verifier_session, &partial_sig[2]) == 0); |
|||
CHECK(ecount == 2); |
|||
|
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, &partial_sig[0]) == 1); |
|||
CHECK(secp256k1_musig_partial_signature_serialize(none, NULL, &partial_sig[0]) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, NULL) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], buf) == 1); |
|||
CHECK(secp256k1_musig_partial_signature_parse(none, NULL, buf) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], NULL) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig_overflow, ones) == 1); |
|||
|
|||
/** Partial signature verification */ |
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_partial_sig_verify(none, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(sign, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[1], &pk[0]) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, NULL, &signer0[0], &partial_sig[0], &pk[0]) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], NULL, &pk[0]) == 0); |
|||
CHECK(ecount == 5); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0); |
|||
CHECK(ecount == 5); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0); |
|||
CHECK(ecount == 6); |
|||
|
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[0], &partial_sig[0], &pk[0]) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[0], &partial_sig[0], &pk[0]) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[1], &partial_sig[1], &pk[1]) == 1); |
|||
CHECK(ecount == 6); |
|||
|
|||
/** Adaptor signature verification */ |
|||
memcpy(&partial_sig_adapted[1], &partial_sig[1], sizeof(partial_sig_adapted[1])); |
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], sec_adaptor, nonce_is_negated) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_adapt(none, NULL, &partial_sig[0], sec_adaptor, 0) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], NULL, sec_adaptor, 0) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig_overflow, sec_adaptor, nonce_is_negated) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], NULL, 0) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], ones, nonce_is_negated) == 0); |
|||
CHECK(ecount == 3); |
|||
|
|||
/** Signing combining and verification */ |
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1); |
|||
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0); |
|||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1); |
|||
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0); |
|||
|
|||
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, &final_sig, partial_sig_adapted, 2) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, NULL, 2) == 0); |
|||
CHECK(ecount == 3); |
|||
{ |
|||
secp256k1_musig_partial_signature partial_sig_tmp[2]; |
|||
partial_sig_tmp[0] = partial_sig_adapted[0]; |
|||
partial_sig_tmp[1] = partial_sig_overflow; |
|||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_tmp, 2) == 0); |
|||
} |
|||
CHECK(ecount == 3); |
|||
/* Wrong number of partial sigs */ |
|||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 1) == 0); |
|||
CHECK(ecount == 3); |
|||
|
|||
CHECK(secp256k1_schnorrsig_verify(vrfy, &final_sig, msg, &combined_pk) == 1); |
|||
|
|||
/** Secret adaptor can be extracted from signature */ |
|||
ecount = 0; |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, nonce_is_negated) == 1); |
|||
CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0); |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, &final_sig, partial_sig, 2, 0) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0); |
|||
CHECK(ecount == 2); |
|||
{ |
|||
secp256k1_schnorrsig final_sig_tmp = final_sig; |
|||
memcpy(&final_sig_tmp.data[32], ones, 32); |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig_tmp, partial_sig, 2, nonce_is_negated) == 0); |
|||
} |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, NULL, 2, 0) == 0); |
|||
CHECK(ecount == 3); |
|||
{ |
|||
secp256k1_musig_partial_signature partial_sig_tmp[2]; |
|||
partial_sig_tmp[0] = partial_sig[0]; |
|||
partial_sig_tmp[1] = partial_sig_overflow; |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig_tmp, 2, nonce_is_negated) == 0); |
|||
} |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 0, 0) == 1); |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, 1) == 1); |
|||
|
|||
/** cleanup **/ |
|||
memset(&session, 0, sizeof(session)); |
|||
secp256k1_context_destroy(none); |
|||
secp256k1_context_destroy(sign); |
|||
secp256k1_context_destroy(vrfy); |
|||
} |
|||
|
|||
/* Initializes two sessions, one use the given parameters (session_id,
|
|||
* nonce_commitments, etc.) except that `session_tmp` uses new signers with different |
|||
* public keys. The point of this test is to call `musig_session_get_public_nonce` |
|||
* with signers from `session_tmp` who have different public keys than the correct |
|||
* ones and return the resulting messagehash. This should not result in a different |
|||
* messagehash because the public keys of the signers are only used during session |
|||
* initialization. */ |
|||
int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, const unsigned char * const *nonce_commitments, unsigned char *msg, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id) { |
|||
secp256k1_musig_session session; |
|||
secp256k1_musig_session session_tmp; |
|||
unsigned char nonce_commitment[32]; |
|||
secp256k1_musig_session_signer_data signers[2]; |
|||
secp256k1_musig_session_signer_data signers_tmp[2]; |
|||
unsigned char sk_dummy[32]; |
|||
secp256k1_pubkey pks_tmp[2]; |
|||
secp256k1_pubkey combined_pk_tmp; |
|||
unsigned char pk_hash_tmp[32]; |
|||
secp256k1_pubkey nonce; |
|||
|
|||
/* Set up signers with different public keys */ |
|||
secp256k1_rand256(sk_dummy); |
|||
pks_tmp[0] = pks[0]; |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pks_tmp[1], sk_dummy) == 1); |
|||
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, pk_hash_tmp, pks_tmp, 2) == 1); |
|||
CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, pk_hash_tmp, 2, 0, sk_dummy) == 1); |
|||
|
|||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1); |
|||
CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0); |
|||
/* Call get_public_nonce with different signers than the signers the session was
|
|||
* initialized with. */ |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, &nonce, nonce_commitments, 2) == 1); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, &nonce, nonce_commitments, 2) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); |
|||
|
|||
return secp256k1_musig_compute_messagehash(ctx, msghash, &session); |
|||
} |
|||
|
|||
/* Creates a new session (with a different session id) and tries to use that session
|
|||
* to combine nonces with given signers_other. This should fail, because the nonce |
|||
* commitments of signers_other do not match the nonce commitments the new session |
|||
* was initialized with. If do_test is 0, the correct signers are being used and |
|||
* therefore the function should return 1. */ |
|||
int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) { |
|||
secp256k1_musig_session session; |
|||
secp256k1_musig_session_signer_data signers[2]; |
|||
secp256k1_musig_session_signer_data *signers_to_use; |
|||
unsigned char nonce_commitment[32]; |
|||
unsigned char session_id[32]; |
|||
secp256k1_pubkey nonce; |
|||
const unsigned char *ncs[2]; |
|||
|
|||
/* Initialize new signers */ |
|||
secp256k1_rand256(session_id); |
|||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1); |
|||
ncs[0] = nonce_commitment_other; |
|||
ncs[1] = nonce_commitment; |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); |
|||
secp256k1_musig_session_combine_nonces(ctx, &session, signers_other, 2, NULL, NULL); |
|||
if (do_test) { |
|||
signers_to_use = signers_other; |
|||
} else { |
|||
signers_to_use = signers; |
|||
} |
|||
return secp256k1_musig_session_combine_nonces(ctx, &session, signers_to_use, 2, NULL, NULL); |
|||
} |
|||
|
|||
/* Recreates a session with the given session_id, signers, pk, msg etc. parameters
|
|||
* and tries to sign and verify the other signers partial signature. Both should fail |
|||
* if msg is NULL. */ |
|||
int musig_state_machine_missing_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) { |
|||
secp256k1_musig_session session; |
|||
secp256k1_musig_session_signer_data signers[2]; |
|||
unsigned char nonce_commitment[32]; |
|||
const unsigned char *ncs[2]; |
|||
secp256k1_pubkey nonce; |
|||
secp256k1_musig_partial_signature partial_sig; |
|||
int partial_sign, partial_verify; |
|||
|
|||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1); |
|||
ncs[0] = nonce_commitment_other; |
|||
ncs[1] = nonce_commitment; |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); |
|||
|
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); |
|||
partial_sign = secp256k1_musig_partial_sign(ctx, &session, &partial_sig); |
|||
partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, &signers[0], partial_sig_other, &pks[0]); |
|||
if (msg != NULL) { |
|||
/* Return 1 if both succeeded */ |
|||
return partial_sign && partial_verify; |
|||
} |
|||
/* Return 0 if both failed */ |
|||
return partial_sign || partial_verify; |
|||
} |
|||
|
|||
/* Recreates a session with the given session_id, signers, pk, msg etc. parameters
|
|||
* and tries to verify and combine partial sigs. If do_combine is 0, the |
|||
* combine_nonces step is left out. In that case verify and combine should fail and |
|||
* this function should return 0. */ |
|||
int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *msg, unsigned char *sk, unsigned char *session_id, secp256k1_musig_partial_signature *partial_sig, int do_combine) { |
|||
secp256k1_musig_session session; |
|||
secp256k1_musig_session_signer_data signers[2]; |
|||
unsigned char nonce_commitment[32]; |
|||
const unsigned char *ncs[2]; |
|||
secp256k1_pubkey nonce; |
|||
secp256k1_musig_partial_signature partial_sigs[2]; |
|||
secp256k1_schnorrsig sig; |
|||
int partial_verify, sig_combine; |
|||
|
|||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1); |
|||
ncs[0] = nonce_commitment_other; |
|||
ncs[1] = nonce_commitment; |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); |
|||
|
|||
partial_sigs[0] = *partial_sig_other; |
|||
partial_sigs[1] = *partial_sig; |
|||
if (do_combine != 0) { |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); |
|||
} |
|||
partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, signers, partial_sig_other, &pks[0]); |
|||
sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, &sig, partial_sigs, 2); |
|||
if (do_combine != 0) { |
|||
/* Return 1 if both succeeded */ |
|||
return partial_verify && sig_combine; |
|||
} |
|||
/* Return 0 if both failed */ |
|||
return partial_verify || sig_combine; |
|||
} |
|||
|
|||
void musig_state_machine_tests(secp256k1_scratch_space *scratch) { |
|||
size_t i; |
|||
secp256k1_musig_session session[2]; |
|||
secp256k1_musig_session_signer_data signers0[2]; |
|||
secp256k1_musig_session_signer_data signers1[2]; |
|||
unsigned char nonce_commitment[2][32]; |
|||
unsigned char session_id[2][32]; |
|||
unsigned char msg[32]; |
|||
unsigned char sk[2][32]; |
|||
secp256k1_pubkey pk[2]; |
|||
secp256k1_pubkey combined_pk; |
|||
unsigned char pk_hash[32]; |
|||
secp256k1_pubkey nonce[2]; |
|||
const unsigned char *ncs[2]; |
|||
secp256k1_musig_partial_signature partial_sig[2]; |
|||
unsigned char msghash1[32]; |
|||
unsigned char msghash2[32]; |
|||
|
|||
/* Run state machine with the same objects twice to test that it's allowed to
|
|||
* reinitialize session and session_signer_data. */ |
|||
for (i = 0; i < 2; i++) { |
|||
/* Setup */ |
|||
secp256k1_rand256(session_id[0]); |
|||
secp256k1_rand256(session_id[1]); |
|||
secp256k1_rand256(sk[0]); |
|||
secp256k1_rand256(sk[1]); |
|||
secp256k1_rand256(msg); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1); |
|||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, pk_hash, pk, 2) == 1); |
|||
CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); |
|||
CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1); |
|||
|
|||
/* Set nonce commitments */ |
|||
ncs[0] = nonce_commitment[0]; |
|||
ncs[1] = nonce_commitment[1]; |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1); |
|||
/* Changing a nonce commitment is not okay */ |
|||
ncs[1] = (unsigned char*) "this isn't a nonce commitment..."; |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 0); |
|||
/* Repeating with the same nonce commitments is okay */ |
|||
ncs[1] = nonce_commitment[1]; |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1); |
|||
|
|||
/* Get nonce for signer 1 */ |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2) == 1); |
|||
|
|||
/* Set nonces */ |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], &nonce[0]) == 1); |
|||
/* Can't set nonce that doesn't match nonce commitment */ |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[0]) == 0); |
|||
/* Set correct nonce */ |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[1]) == 1); |
|||
|
|||
/* Combine nonces */ |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1); |
|||
/* Not everyone is present from signer 1's view */ |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 0); |
|||
/* Make everyone present */ |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], &nonce[0]) == 1); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1); |
|||
|
|||
/* Can't combine nonces from signers of a different session */ |
|||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 1) == 0); |
|||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 0) == 1); |
|||
|
|||
/* Partially sign */ |
|||
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1); |
|||
/* Can't verify or sign until nonce is combined */ |
|||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 0); |
|||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 0); |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1); |
|||
/* messagehash should be the same as a session whose get_public_nonce was called
|
|||
* with different signers (i.e. they diff in public keys). This is because the |
|||
* public keys of the signers is set in stone when initializing the session. */ |
|||
CHECK(secp256k1_musig_compute_messagehash(ctx, msghash1, &session[1]) == 1); |
|||
CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, pk_hash, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1); |
|||
CHECK(memcmp(msghash1, msghash2, 32) == 0); |
|||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[1], &pk[1]) == 1); |
|||
/* Wrong signature */ |
|||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0); |
|||
/* Can't sign or verify until msg is set */ |
|||
CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], NULL) == 0); |
|||
CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], msg) == 1); |
|||
|
|||
/* Can't verify and combine partial sigs until nonces are combined */ |
|||
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0); |
|||
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 1) == 1); |
|||
} |
|||
} |
|||
|
|||
void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { |
|||
/* Throughout this test "a" and "b" refer to two hypothetical blockchains,
|
|||
* while the indices 0 and 1 refer to the two signers. Here signer 0 is |
|||
* sending a-coins to signer 1, while signer 1 is sending b-coins to signer |
|||
* 0. Signer 0 produces the adaptor signatures. */ |
|||
secp256k1_schnorrsig final_sig_a; |
|||
secp256k1_schnorrsig final_sig_b; |
|||
secp256k1_musig_partial_signature partial_sig_a[2]; |
|||
secp256k1_musig_partial_signature partial_sig_b_adapted[2]; |
|||
secp256k1_musig_partial_signature partial_sig_b[2]; |
|||
unsigned char sec_adaptor[32]; |
|||
unsigned char sec_adaptor_extracted[32]; |
|||
secp256k1_pubkey pub_adaptor; |
|||
|
|||
unsigned char seckey_a[2][32]; |
|||
unsigned char seckey_b[2][32]; |
|||
secp256k1_pubkey pk_a[2]; |
|||
secp256k1_pubkey pk_b[2]; |
|||
unsigned char pk_hash_a[32]; |
|||
unsigned char pk_hash_b[32]; |
|||
secp256k1_pubkey combined_pk_a; |
|||
secp256k1_pubkey combined_pk_b; |
|||
secp256k1_musig_session musig_session_a[2]; |
|||
secp256k1_musig_session musig_session_b[2]; |
|||
unsigned char noncommit_a[2][32]; |
|||
unsigned char noncommit_b[2][32]; |
|||
const unsigned char *noncommit_a_ptr[2]; |
|||
const unsigned char *noncommit_b_ptr[2]; |
|||
secp256k1_pubkey pubnon_a[2]; |
|||
secp256k1_pubkey pubnon_b[2]; |
|||
int nonce_is_negated_a; |
|||
int nonce_is_negated_b; |
|||
secp256k1_musig_session_signer_data data_a[2]; |
|||
secp256k1_musig_session_signer_data data_b[2]; |
|||
|
|||
const unsigned char seed[32] = "still tired of choosing seeds..."; |
|||
const unsigned char msg32_a[32] = "this is the message blockchain a"; |
|||
const unsigned char msg32_b[32] = "this is the message blockchain b"; |
|||
|
|||
/* Step 1: key setup */ |
|||
secp256k1_rand256(seckey_a[0]); |
|||
secp256k1_rand256(seckey_a[1]); |
|||
secp256k1_rand256(seckey_b[0]); |
|||
secp256k1_rand256(seckey_b[1]); |
|||
secp256k1_rand256(sec_adaptor); |
|||
|
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[0], seckey_a[0])); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[1], seckey_a[1])); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[0], seckey_b[0])); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[1], seckey_b[1])); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor)); |
|||
|
|||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, pk_hash_a, pk_a, 2)); |
|||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, pk_hash_b, pk_b, 2)); |
|||
|
|||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 0, seckey_a[0])); |
|||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 1, seckey_a[1])); |
|||
noncommit_a_ptr[0] = noncommit_a[0]; |
|||
noncommit_a_ptr[1] = noncommit_a[1]; |
|||
|
|||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 0, seckey_b[0])); |
|||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 1, seckey_b[1])); |
|||
noncommit_b_ptr[0] = noncommit_b[0]; |
|||
noncommit_b_ptr[1] = noncommit_b[1]; |
|||
|
|||
/* Step 2: Exchange nonces */ |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, &pubnon_a[0], noncommit_a_ptr, 2)); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, &pubnon_a[1], noncommit_a_ptr, 2)); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, &pubnon_b[0], noncommit_b_ptr, 2)); |
|||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, &pubnon_b[1], noncommit_b_ptr, 2)); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[0], &pubnon_a[0])); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[1], &pubnon_a[1])); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[0], &pubnon_b[0])); |
|||
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[1], &pubnon_b[1])); |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[0], data_a, 2, &nonce_is_negated_a, &pub_adaptor)); |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[1], data_a, 2, NULL, &pub_adaptor)); |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[0], data_b, 2, &nonce_is_negated_b, &pub_adaptor)); |
|||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[1], data_b, 2, NULL, &pub_adaptor)); |
|||
|
|||
/* Step 3: Signer 0 produces partial signatures for both chains. */ |
|||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[0], &partial_sig_a[0])); |
|||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[0], &partial_sig_b[0])); |
|||
|
|||
/* Step 4: Signer 1 receives partial signatures, verifies them and creates a
|
|||
* partial signature to send B-coins to signer 0. */ |
|||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_a[1], data_a, &partial_sig_a[0], &pk_a[0]) == 1); |
|||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_b[1], data_b, &partial_sig_b[0], &pk_b[0]) == 1); |
|||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[1], &partial_sig_b[1])); |
|||
|
|||
/* Step 5: Signer 0 adapts its own partial signature and combines it with the
|
|||
* partial signature from signer 1. This results in a complete signature which |
|||
* is broadcasted by signer 0 to take B-coins. */ |
|||
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, nonce_is_negated_b)); |
|||
memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1])); |
|||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], &final_sig_b, partial_sig_b_adapted, 2) == 1); |
|||
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_b, msg32_b, &combined_pk_b) == 1); |
|||
|
|||
/* Step 6: Signer 1 extracts adaptor from the published signature, applies it to
|
|||
* other partial signature, and takes A-coins. */ |
|||
CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, &final_sig_b, partial_sig_b, 2, nonce_is_negated_b) == 1); |
|||
CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */ |
|||
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, nonce_is_negated_a)); |
|||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1])); |
|||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], &final_sig_a, partial_sig_a, 2) == 1); |
|||
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_a, msg32_a, &combined_pk_a) == 1); |
|||
} |
|||
|
|||
/* Checks that hash initialized by secp256k1_musig_sha256_init_tagged has the
|
|||
* expected state. */ |
|||
void sha256_tag_test(void) { |
|||
char tag[17] = "MuSig coefficient"; |
|||
secp256k1_sha256 sha; |
|||
secp256k1_sha256 sha_tagged; |
|||
unsigned char buf[32]; |
|||
unsigned char buf2[32]; |
|||
size_t i; |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, (unsigned char *) tag, 17); |
|||
secp256k1_sha256_finalize(&sha, buf); |
|||
/* buf = SHA256("MuSig coefficient") */ |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, buf, 32); |
|||
secp256k1_sha256_write(&sha, buf, 32); |
|||
/* Is buffer fully consumed? */ |
|||
CHECK((sha.bytes & 0x3F) == 0); |
|||
|
|||
/* Compare with tagged SHA */ |
|||
secp256k1_musig_sha256_init_tagged(&sha_tagged); |
|||
for (i = 0; i < 8; i++) { |
|||
CHECK(sha_tagged.s[i] == sha.s[i]); |
|||
} |
|||
secp256k1_sha256_write(&sha, buf, 32); |
|||
secp256k1_sha256_write(&sha_tagged, buf, 32); |
|||
secp256k1_sha256_finalize(&sha, buf); |
|||
secp256k1_sha256_finalize(&sha_tagged, buf2); |
|||
CHECK(memcmp(buf, buf2, 32) == 0); |
|||
} |
|||
|
|||
void run_musig_tests(void) { |
|||
int i; |
|||
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024); |
|||
|
|||
musig_api_tests(scratch); |
|||
musig_state_machine_tests(scratch); |
|||
for (i = 0; i < count; i++) { |
|||
/* Run multiple times to ensure that the nonce is negated in some tests */ |
|||
scriptless_atomic_swap(scratch); |
|||
} |
|||
sha256_tag_test(); |
|||
|
|||
secp256k1_scratch_space_destroy(scratch); |
|||
} |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,9 @@ |
|||
include_HEADERS += include/secp256k1_schnorrsig.h |
|||
noinst_HEADERS += src/modules/schnorrsig/main_impl.h |
|||
noinst_HEADERS += src/modules/schnorrsig/tests_impl.h |
|||
if USE_BENCHMARK |
|||
noinst_PROGRAMS += bench_schnorrsig |
|||
bench_schnorrsig_SOURCES = src/bench_schnorrsig.c |
|||
bench_schnorrsig_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) |
|||
endif |
|||
|
@ -0,0 +1,339 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2018 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_ |
|||
#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_ |
|||
|
|||
#include "../../../include/secp256k1.h" |
|||
#include "../../../include/secp256k1_schnorrsig.h" |
|||
#include "hash.h" |
|||
|
|||
int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig) { |
|||
(void) ctx; |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(out64 != NULL); |
|||
ARG_CHECK(sig != NULL); |
|||
memcpy(out64, sig->data, 64); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64) { |
|||
(void) ctx; |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(in64 != NULL); |
|||
memcpy(sig->data, in64, 64); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, int *nonce_is_negated, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) { |
|||
secp256k1_scalar x; |
|||
secp256k1_scalar e; |
|||
secp256k1_scalar k; |
|||
secp256k1_gej pkj; |
|||
secp256k1_gej rj; |
|||
secp256k1_ge pk; |
|||
secp256k1_ge r; |
|||
secp256k1_sha256 sha; |
|||
int overflow; |
|||
unsigned char buf[33]; |
|||
size_t buflen = sizeof(buf); |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(msg32 != NULL); |
|||
ARG_CHECK(seckey != NULL); |
|||
|
|||
if (noncefp == NULL) { |
|||
noncefp = secp256k1_nonce_function_bipschnorr; |
|||
} |
|||
secp256k1_scalar_set_b32(&x, seckey, &overflow); |
|||
/* Fail if the secret key is invalid. */ |
|||
if (overflow || secp256k1_scalar_is_zero(&x)) { |
|||
memset(sig, 0, sizeof(*sig)); |
|||
return 0; |
|||
} |
|||
|
|||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x); |
|||
secp256k1_ge_set_gej(&pk, &pkj); |
|||
|
|||
if (!noncefp(buf, msg32, seckey, NULL, (void*)ndata, 0)) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_set_b32(&k, buf, NULL); |
|||
if (secp256k1_scalar_is_zero(&k)) { |
|||
return 0; |
|||
} |
|||
|
|||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); |
|||
secp256k1_ge_set_gej(&r, &rj); |
|||
|
|||
if (nonce_is_negated != NULL) { |
|||
*nonce_is_negated = 0; |
|||
} |
|||
if (!secp256k1_fe_is_quad_var(&r.y)) { |
|||
secp256k1_scalar_negate(&k, &k); |
|||
if (nonce_is_negated != NULL) { |
|||
*nonce_is_negated = 1; |
|||
} |
|||
} |
|||
secp256k1_fe_normalize(&r.x); |
|||
secp256k1_fe_get_b32(&sig->data[0], &r.x); |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, &sig->data[0], 32); |
|||
secp256k1_eckey_pubkey_serialize(&pk, buf, &buflen, 1); |
|||
secp256k1_sha256_write(&sha, buf, buflen); |
|||
secp256k1_sha256_write(&sha, msg32, 32); |
|||
secp256k1_sha256_finalize(&sha, buf); |
|||
|
|||
secp256k1_scalar_set_b32(&e, buf, NULL); |
|||
secp256k1_scalar_mul(&e, &e, &x); |
|||
secp256k1_scalar_add(&e, &e, &k); |
|||
|
|||
secp256k1_scalar_get_b32(&sig->data[32], &e); |
|||
secp256k1_scalar_clear(&k); |
|||
secp256k1_scalar_clear(&x); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
/* Helper function for verification and batch verification.
|
|||
* Computes R = sG - eP. */ |
|||
static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp256k1_gej *rj, const secp256k1_scalar *s, const secp256k1_scalar *e, const secp256k1_pubkey *pk) { |
|||
secp256k1_scalar nege; |
|||
secp256k1_ge pkp; |
|||
secp256k1_gej pkj; |
|||
|
|||
secp256k1_scalar_negate(&nege, e); |
|||
|
|||
if (!secp256k1_pubkey_load(ctx, &pkp, pk)) { |
|||
return 0; |
|||
} |
|||
secp256k1_gej_set_ge(&pkj, &pkp); |
|||
|
|||
/* rj = s*G + (-e)*pkj */ |
|||
secp256k1_ecmult(&ctx->ecmult_ctx, rj, &pkj, &nege, s); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk) { |
|||
secp256k1_scalar s; |
|||
secp256k1_scalar e; |
|||
secp256k1_gej rj; |
|||
secp256k1_fe rx; |
|||
secp256k1_sha256 sha; |
|||
unsigned char buf[33]; |
|||
size_t buflen = sizeof(buf); |
|||
int overflow; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(msg32 != NULL); |
|||
ARG_CHECK(pk != NULL); |
|||
|
|||
if (!secp256k1_fe_set_b32(&rx, &sig->data[0])) { |
|||
return 0; |
|||
} |
|||
|
|||
secp256k1_scalar_set_b32(&s, &sig->data[32], &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, &sig->data[0], 32); |
|||
secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED); |
|||
secp256k1_sha256_write(&sha, buf, buflen); |
|||
secp256k1_sha256_write(&sha, msg32, 32); |
|||
secp256k1_sha256_finalize(&sha, buf); |
|||
secp256k1_scalar_set_b32(&e, buf, NULL); |
|||
|
|||
if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pk) |
|||
|| !secp256k1_gej_has_quad_y_var(&rj) /* fails if rj is infinity */ |
|||
|| !secp256k1_gej_eq_x_var(&rx, &rj)) { |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
/* Data that is used by the batch verification ecmult callback */ |
|||
typedef struct { |
|||
const secp256k1_context *ctx; |
|||
/* Seed for the random number generator */ |
|||
unsigned char chacha_seed[32]; |
|||
/* Caches randomizers generated by the PRNG which returns two randomizers per call. Caching
|
|||
* avoids having to call the PRNG twice as often. The very first randomizer will be set to 1 and |
|||
* the PRNG is called at every odd indexed schnorrsig to fill the cache. */ |
|||
secp256k1_scalar randomizer_cache[2]; |
|||
/* Signature, message, public key tuples to verify */ |
|||
const secp256k1_schnorrsig *const *sig; |
|||
const unsigned char *const *msg32; |
|||
const secp256k1_pubkey *const *pk; |
|||
size_t n_sigs; |
|||
} secp256k1_schnorrsig_verify_ecmult_context; |
|||
|
|||
/* Callback function which is called by ecmult_multi in order to convert the ecmult_context
|
|||
* consisting of signature, message and public key tuples into scalars and points. */ |
|||
static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { |
|||
secp256k1_schnorrsig_verify_ecmult_context *ecmult_context = (secp256k1_schnorrsig_verify_ecmult_context *) data; |
|||
|
|||
if (idx % 4 == 2) { |
|||
/* Every idx corresponds to a (scalar,point)-tuple. So this callback is called with 4
|
|||
* consecutive tuples before we need to call the RNG for new randomizers: |
|||
* (-randomizer_cache[0], R1) |
|||
* (-randomizer_cache[0]*e1, P1) |
|||
* (-randomizer_cache[1], R2) |
|||
* (-randomizer_cache[1]*e2, P2) */ |
|||
secp256k1_scalar_chacha20(&ecmult_context->randomizer_cache[0], &ecmult_context->randomizer_cache[1], ecmult_context->chacha_seed, idx / 4); |
|||
} |
|||
|
|||
/* R */ |
|||
if (idx % 2 == 0) { |
|||
secp256k1_fe rx; |
|||
*sc = ecmult_context->randomizer_cache[(idx / 2) % 2]; |
|||
if (!secp256k1_fe_set_b32(&rx, &ecmult_context->sig[idx / 2]->data[0])) { |
|||
return 0; |
|||
} |
|||
if (!secp256k1_ge_set_xquad(pt, &rx)) { |
|||
return 0; |
|||
} |
|||
/* eP */ |
|||
} else { |
|||
unsigned char buf[33]; |
|||
size_t buflen = sizeof(buf); |
|||
secp256k1_sha256 sha; |
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32); |
|||
secp256k1_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED); |
|||
secp256k1_sha256_write(&sha, buf, buflen); |
|||
secp256k1_sha256_write(&sha, ecmult_context->msg32[idx / 2], 32); |
|||
secp256k1_sha256_finalize(&sha, buf); |
|||
|
|||
secp256k1_scalar_set_b32(sc, buf, NULL); |
|||
secp256k1_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]); |
|||
|
|||
if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, ecmult_context->pk[idx / 2])) { |
|||
return 0; |
|||
} |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
/** Helper function for batch verification. Hashes signature verification data into the
|
|||
* randomization seed and initializes ecmult_context. |
|||
* |
|||
* Returns 1 if the randomizer was successfully initialized. |
|||
* |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: ecmult_context: context for batch_ecmult_callback |
|||
* In/Out sha: an initialized sha256 object which hashes the schnorrsig input in order to get a |
|||
* seed for the randomizer PRNG |
|||
* In: sig: array of signatures, or NULL if there are no signatures |
|||
* msg32: array of messages, or NULL if there are no signatures |
|||
* pk: array of public keys, or NULL if there are no signatures |
|||
* n_sigs: number of signatures in above arrays (must be 0 if they are NULL) |
|||
*/ |
|||
int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { |
|||
size_t i; |
|||
|
|||
if (n_sigs > 0) { |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(msg32 != NULL); |
|||
ARG_CHECK(pk != NULL); |
|||
} |
|||
|
|||
for (i = 0; i < n_sigs; i++) { |
|||
unsigned char buf[33]; |
|||
size_t buflen = sizeof(buf); |
|||
secp256k1_sha256_write(sha, sig[i]->data, 64); |
|||
secp256k1_sha256_write(sha, msg32[i], 32); |
|||
secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED); |
|||
secp256k1_sha256_write(sha, buf, 32); |
|||
} |
|||
ecmult_context->ctx = ctx; |
|||
ecmult_context->sig = sig; |
|||
ecmult_context->msg32 = msg32; |
|||
ecmult_context->pk = pk; |
|||
ecmult_context->n_sigs = n_sigs; |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
/** Helper function for batch verification. Sums the s part of all signatures multiplied by their
|
|||
* randomizer. |
|||
* |
|||
* Returns 1 if s is successfully summed. |
|||
* |
|||
* In/Out: s: the s part of the input sigs is added to this s argument |
|||
* In: chacha_seed: PRNG seed for computing randomizers |
|||
* sig: array of signatures, or NULL if there are no signatures |
|||
* n_sigs: number of signatures in above array (must be 0 if they are NULL) |
|||
*/ |
|||
int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned char *chacha_seed, const secp256k1_schnorrsig *const *sig, size_t n_sigs) { |
|||
secp256k1_scalar randomizer_cache[2]; |
|||
size_t i; |
|||
|
|||
secp256k1_scalar_set_int(&randomizer_cache[0], 1); |
|||
for (i = 0; i < n_sigs; i++) { |
|||
int overflow; |
|||
secp256k1_scalar term; |
|||
if (i % 2 == 1) { |
|||
secp256k1_scalar_chacha20(&randomizer_cache[0], &randomizer_cache[1], chacha_seed, i / 2); |
|||
} |
|||
|
|||
secp256k1_scalar_set_b32(&term, &sig[i]->data[32], &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_mul(&term, &term, &randomizer_cache[i % 2]); |
|||
secp256k1_scalar_add(s, s, &term); |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
/* schnorrsig batch verification.
|
|||
* Seeds a random number generator with the inputs and derives a random number ai for every |
|||
* signature i. Fails if y-coordinate of any R is not a quadratic residue or if |
|||
* 0 != -(s1 + a2*s2 + ... + au*su)G + R1 + a2*R2 + ... + au*Ru + e1*P1 + (a2*e2)P2 + ... + (au*eu)Pu. */ |
|||
int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_scratch *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { |
|||
secp256k1_schnorrsig_verify_ecmult_context ecmult_context; |
|||
secp256k1_sha256 sha; |
|||
secp256k1_scalar s; |
|||
secp256k1_gej rj; |
|||
|
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); |
|||
ARG_CHECK(scratch != NULL); |
|||
/* Check that n_sigs is less than half of the maximum size_t value. This is necessary because
|
|||
* the number of points given to ecmult_multi is 2*n_sigs. */ |
|||
ARG_CHECK(n_sigs <= SIZE_MAX / 2); |
|||
/* Check that n_sigs is less than 2^31 to ensure the same behavior of this function on 32-bit
|
|||
* and 64-bit platforms. */ |
|||
ARG_CHECK(n_sigs < (size_t)(1 << 31)); |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
if (!secp256k1_schnorrsig_verify_batch_init_randomizer(ctx, &ecmult_context, &sha, sig, msg32, pk, n_sigs)) { |
|||
return 0; |
|||
} |
|||
secp256k1_sha256_finalize(&sha, ecmult_context.chacha_seed); |
|||
secp256k1_scalar_set_int(&ecmult_context.randomizer_cache[0], 1); |
|||
|
|||
secp256k1_scalar_clear(&s); |
|||
if (!secp256k1_schnorrsig_verify_batch_sum_s(&s, ecmult_context.chacha_seed, sig, n_sigs)) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_negate(&s, &s); |
|||
|
|||
return secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs) |
|||
&& secp256k1_gej_is_infinity(&rj); |
|||
} |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,727 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2018 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_ |
|||
#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_ |
|||
|
|||
#include "secp256k1_schnorrsig.h" |
|||
|
|||
void test_schnorrsig_serialize(void) { |
|||
secp256k1_schnorrsig sig; |
|||
unsigned char in[64]; |
|||
unsigned char out[64]; |
|||
|
|||
memset(in, 0x12, 64); |
|||
CHECK(secp256k1_schnorrsig_parse(ctx, &sig, in)); |
|||
CHECK(secp256k1_schnorrsig_serialize(ctx, out, &sig)); |
|||
CHECK(memcmp(in, out, 64) == 0); |
|||
} |
|||
|
|||
void test_schnorrsig_api(secp256k1_scratch_space *scratch) { |
|||
unsigned char sk1[32]; |
|||
unsigned char sk2[32]; |
|||
unsigned char sk3[32]; |
|||
unsigned char msg[32]; |
|||
unsigned char sig64[64]; |
|||
secp256k1_pubkey pk[3]; |
|||
secp256k1_schnorrsig sig; |
|||
const secp256k1_schnorrsig *sigptr = &sig; |
|||
const unsigned char *msgptr = msg; |
|||
const secp256k1_pubkey *pkptr = &pk[0]; |
|||
int nonce_is_negated; |
|||
|
|||
/** setup **/ |
|||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); |
|||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); |
|||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); |
|||
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
int ecount; |
|||
|
|||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); |
|||
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); |
|||
|
|||
secp256k1_rand256(sk1); |
|||
secp256k1_rand256(sk2); |
|||
secp256k1_rand256(sk3); |
|||
secp256k1_rand256(msg); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk1) == 1); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk2) == 1); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[2], sk3) == 1); |
|||
|
|||
/** main test body **/ |
|||
ecount = 0; |
|||
CHECK(secp256k1_schnorrsig_sign(none, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_schnorrsig_sign(vrfy, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_sign(sign, NULL, &nonce_is_negated, msg, sk1, NULL, NULL) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_schnorrsig_sign(sign, &sig, NULL, msg, sk1, NULL, NULL) == 1); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, NULL, sk1, NULL, NULL) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, NULL, NULL, NULL) == 0); |
|||
CHECK(ecount == 5); |
|||
|
|||
ecount = 0; |
|||
CHECK(secp256k1_schnorrsig_serialize(none, sig64, &sig) == 1); |
|||
CHECK(ecount == 0); |
|||
CHECK(secp256k1_schnorrsig_serialize(none, NULL, &sig) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_schnorrsig_serialize(none, sig64, NULL) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_parse(none, &sig, sig64) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_parse(none, NULL, sig64) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_schnorrsig_parse(none, &sig, NULL) == 0); |
|||
CHECK(ecount == 4); |
|||
|
|||
ecount = 0; |
|||
CHECK(secp256k1_schnorrsig_verify(none, &sig, msg, &pk[0]) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_schnorrsig_verify(sign, &sig, msg, &pk[0]) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, &pk[0]) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, NULL, &pk[0]) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, NULL) == 0); |
|||
CHECK(ecount == 5); |
|||
|
|||
ecount = 0; |
|||
CHECK(secp256k1_schnorrsig_verify_batch(none, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); |
|||
CHECK(ecount == 1); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(sign, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, NULL, NULL, 0) == 1); |
|||
CHECK(ecount == 2); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, &msgptr, &pkptr, 1) == 0); |
|||
CHECK(ecount == 3); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, NULL, &pkptr, 1) == 0); |
|||
CHECK(ecount == 4); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, NULL, 1) == 0); |
|||
CHECK(ecount == 5); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (size_t)1 << (sizeof(size_t)*8-1)) == 0); |
|||
CHECK(ecount == 6); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1 << 31) == 0); |
|||
CHECK(ecount == 7); |
|||
|
|||
secp256k1_context_destroy(none); |
|||
secp256k1_context_destroy(sign); |
|||
secp256k1_context_destroy(vrfy); |
|||
secp256k1_context_destroy(both); |
|||
} |
|||
|
|||
/* Helper function for schnorrsig_bip_vectors
|
|||
* Signs the message and checks that it's the same as expected_sig. */ |
|||
void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *msg, const unsigned char *expected_sig, const int expected_nonce_is_negated) { |
|||
secp256k1_schnorrsig sig; |
|||
unsigned char serialized_sig[64]; |
|||
secp256k1_pubkey pk; |
|||
int nonce_is_negated; |
|||
|
|||
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, &nonce_is_negated, msg, sk, NULL, NULL)); |
|||
CHECK(nonce_is_negated == expected_nonce_is_negated); |
|||
CHECK(secp256k1_schnorrsig_serialize(ctx, serialized_sig, &sig)); |
|||
CHECK(memcmp(serialized_sig, expected_sig, 64) == 0); |
|||
|
|||
CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); |
|||
CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &pk)); |
|||
} |
|||
|
|||
/* Helper function for schnorrsig_bip_vectors
|
|||
* Checks that both verify and verify_batch return the same value as expected. */ |
|||
void test_schnorrsig_bip_vectors_check_verify(secp256k1_scratch_space *scratch, const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig_serialized, int expected) { |
|||
const unsigned char *msg_arr[1]; |
|||
const secp256k1_schnorrsig *sig_arr[1]; |
|||
const secp256k1_pubkey *pk_arr[1]; |
|||
secp256k1_pubkey pk; |
|||
secp256k1_schnorrsig sig; |
|||
|
|||
CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); |
|||
CHECK(secp256k1_schnorrsig_parse(ctx, &sig, sig_serialized)); |
|||
|
|||
sig_arr[0] = &sig; |
|||
msg_arr[0] = msg32; |
|||
pk_arr[0] = &pk; |
|||
|
|||
CHECK(expected == secp256k1_schnorrsig_verify(ctx, &sig, msg32, &pk)); |
|||
CHECK(expected == secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); |
|||
} |
|||
|
|||
/* Test vectors according to BIP-schnorr
|
|||
* (https://github.com/sipa/bips/blob/7f6a73e53c8bbcf2d008ea0546f76433e22094a8/bip-schnorr/test-vectors.csv).
|
|||
*/ |
|||
void test_schnorrsig_bip_vectors(secp256k1_scratch_space *scratch) { |
|||
{ |
|||
/* Test vector 1 */ |
|||
const unsigned char sk1[32] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 |
|||
}; |
|||
const unsigned char pk1[33] = { |
|||
0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, |
|||
0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, |
|||
0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, |
|||
0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, |
|||
0x98 |
|||
}; |
|||
const unsigned char msg1[32] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
|||
}; |
|||
const unsigned char sig1[64] = { |
|||
0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, |
|||
0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, |
|||
0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, |
|||
0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, |
|||
0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3, |
|||
0x4D, 0xFF, 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84, |
|||
0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1, |
|||
0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05 |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_signing(sk1, pk1, msg1, sig1, 1); |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk1, msg1, sig1, 1); |
|||
} |
|||
{ |
|||
/* Test vector 2 */ |
|||
const unsigned char sk2[32] = { |
|||
0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, |
|||
0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, |
|||
0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, |
|||
0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF |
|||
}; |
|||
const unsigned char pk2[33] = { |
|||
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg2[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig2[64] = { |
|||
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, |
|||
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, |
|||
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, |
|||
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, |
|||
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, |
|||
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, |
|||
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, |
|||
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_signing(sk2, pk2, msg2, sig2, 0); |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk2, msg2, sig2, 1); |
|||
} |
|||
{ |
|||
/* Test vector 3 */ |
|||
const unsigned char sk3[32] = { |
|||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, |
|||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, |
|||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, |
|||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC7 |
|||
}; |
|||
const unsigned char pk3[33] = { |
|||
0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, |
|||
0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, |
|||
0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, |
|||
0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, |
|||
0x4B |
|||
}; |
|||
const unsigned char msg3[32] = { |
|||
0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, |
|||
0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, |
|||
0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, |
|||
0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C |
|||
}; |
|||
const unsigned char sig3[64] = { |
|||
0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, |
|||
0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, |
|||
0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, |
|||
0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, |
|||
0x00, 0x88, 0x03, 0x71, 0xD0, 0x17, 0x66, 0x93, |
|||
0x5B, 0x92, 0xD2, 0xAB, 0x4C, 0xD5, 0xC8, 0xA2, |
|||
0xA5, 0x83, 0x7E, 0xC5, 0x7F, 0xED, 0x76, 0x60, |
|||
0x77, 0x3A, 0x05, 0xF0, 0xDE, 0x14, 0x23, 0x80 |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_signing(sk3, pk3, msg3, sig3, 0); |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk3, msg3, sig3, 1); |
|||
} |
|||
{ |
|||
/* Test vector 4 */ |
|||
const unsigned char pk4[33] = { |
|||
0x03, 0xDE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, |
|||
0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, |
|||
0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, |
|||
0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, |
|||
0x34 |
|||
}; |
|||
const unsigned char msg4[32] = { |
|||
0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, |
|||
0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, |
|||
0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, |
|||
0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 |
|||
}; |
|||
const unsigned char sig4[64] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, |
|||
0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, |
|||
0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, |
|||
0x02, 0xA8, 0xDC, 0x32, 0xE6, 0x4E, 0x86, 0xA3, |
|||
0x33, 0xF2, 0x0E, 0xF5, 0x6E, 0xAC, 0x9B, 0xA3, |
|||
0x0B, 0x72, 0x46, 0xD6, 0xD2, 0x5E, 0x22, 0xAD, |
|||
0xB8, 0xC6, 0xBE, 0x1A, 0xEB, 0x08, 0xD4, 0x9D |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk4, msg4, sig4, 1); |
|||
} |
|||
{ |
|||
/* Test vector 5 */ |
|||
const unsigned char pk5[33] = { |
|||
0x03, 0x1B, 0x84, 0xC5, 0x56, 0x7B, 0x12, 0x64, |
|||
0x40, 0x99, 0x5D, 0x3E, 0xD5, 0xAA, 0xBA, 0x05, |
|||
0x65, 0xD7, 0x1E, 0x18, 0x34, 0x60, 0x48, 0x19, |
|||
0xFF, 0x9C, 0x17, 0xF5, 0xE9, 0xD5, 0xDD, 0x07, |
|||
0x8F |
|||
}; |
|||
const unsigned char msg5[32] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
|||
}; |
|||
const unsigned char sig5[64] = { |
|||
0x52, 0x81, 0x85, 0x79, 0xAC, 0xA5, 0x97, 0x67, |
|||
0xE3, 0x29, 0x1D, 0x91, 0xB7, 0x6B, 0x63, 0x7B, |
|||
0xEF, 0x06, 0x20, 0x83, 0x28, 0x49, 0x92, 0xF2, |
|||
0xD9, 0x5F, 0x56, 0x4C, 0xA6, 0xCB, 0x4E, 0x35, |
|||
0x30, 0xB1, 0xDA, 0x84, 0x9C, 0x8E, 0x83, 0x04, |
|||
0xAD, 0xC0, 0xCF, 0xE8, 0x70, 0x66, 0x03, 0x34, |
|||
0xB3, 0xCF, 0xC1, 0x8E, 0x82, 0x5E, 0xF1, 0xDB, |
|||
0x34, 0xCF, 0xAE, 0x3D, 0xFC, 0x5D, 0x81, 0x87 |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk5, msg5, sig5, 1); |
|||
} |
|||
{ |
|||
/* Test vector 6 */ |
|||
const unsigned char pk6[33] = { |
|||
0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, |
|||
0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, |
|||
0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, |
|||
0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, |
|||
0x4B |
|||
}; |
|||
const unsigned char msg6[32] = { |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF |
|||
}; |
|||
const unsigned char sig6[64] = { |
|||
0x57, 0x0D, 0xD4, 0xCA, 0x83, 0xD4, 0xE6, 0x31, |
|||
0x7B, 0x8E, 0xE6, 0xBA, 0xE8, 0x34, 0x67, 0xA1, |
|||
0xBF, 0x41, 0x9D, 0x07, 0x67, 0x12, 0x2D, 0xE4, |
|||
0x09, 0x39, 0x44, 0x14, 0xB0, 0x50, 0x80, 0xDC, |
|||
0xE9, 0xEE, 0x5F, 0x23, 0x7C, 0xBD, 0x10, 0x8E, |
|||
0xAB, 0xAE, 0x1E, 0x37, 0x75, 0x9A, 0xE4, 0x7F, |
|||
0x8E, 0x42, 0x03, 0xDA, 0x35, 0x32, 0xEB, 0x28, |
|||
0xDB, 0x86, 0x0F, 0x33, 0xD6, 0x2D, 0x49, 0xBD |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk6, msg6, sig6, 1); |
|||
} |
|||
{ |
|||
/* Test vector 7 */ |
|||
const unsigned char pk7[33] = { |
|||
0x03, 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, |
|||
0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, |
|||
0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, |
|||
0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, |
|||
0x34 |
|||
}; |
|||
secp256k1_pubkey pk7_parsed; |
|||
/* No need to check the signature of the test vector as parsing the pubkey already fails */ |
|||
CHECK(!secp256k1_ec_pubkey_parse(ctx, &pk7_parsed, pk7, 33)); |
|||
} |
|||
{ |
|||
/* Test vector 8 */ |
|||
const unsigned char pk8[33] = { |
|||
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg8[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig8[64] = { |
|||
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, |
|||
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, |
|||
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, |
|||
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, |
|||
0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A, |
|||
0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46, |
|||
0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14, |
|||
0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7 |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk8, msg8, sig8, 0); |
|||
} |
|||
{ |
|||
/* Test vector 9 */ |
|||
const unsigned char pk9[33] = { |
|||
0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, |
|||
0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, |
|||
0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, |
|||
0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, |
|||
0x4B |
|||
}; |
|||
const unsigned char msg9[32] = { |
|||
0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, |
|||
0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, |
|||
0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, |
|||
0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C |
|||
}; |
|||
const unsigned char sig9[64] = { |
|||
0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, |
|||
0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, |
|||
0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, |
|||
0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, |
|||
0xD0, 0x92, 0xF9, 0xD8, 0x60, 0xF1, 0x77, 0x6A, |
|||
0x1F, 0x74, 0x12, 0xAD, 0x8A, 0x1E, 0xB5, 0x0D, |
|||
0xAC, 0xCC, 0x22, 0x2B, 0xC8, 0xC0, 0xE2, 0x6B, |
|||
0x20, 0x56, 0xDF, 0x2F, 0x27, 0x3E, 0xFD, 0xEC |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk9, msg9, sig9, 0); |
|||
} |
|||
{ |
|||
/* Test vector 10 */ |
|||
const unsigned char pk10[33] = { |
|||
0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, |
|||
0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, |
|||
0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, |
|||
0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, |
|||
0x98 |
|||
}; |
|||
const unsigned char msg10[32] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
|||
}; |
|||
const unsigned char sig10[64] = { |
|||
0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, |
|||
0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, |
|||
0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, |
|||
0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, |
|||
0x8F, 0xCE, 0x56, 0x77, 0xCE, 0x7A, 0x62, 0x3C, |
|||
0xB2, 0x00, 0x11, 0x22, 0x57, 0x97, 0xCE, 0x7A, |
|||
0x8D, 0xE1, 0xDC, 0x6C, 0xCD, 0x4F, 0x75, 0x4A, |
|||
0x47, 0xDA, 0x6C, 0x60, 0x0E, 0x59, 0x54, 0x3C |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk10, msg10, sig10, 0); |
|||
} |
|||
{ |
|||
/* Test vector 11 */ |
|||
const unsigned char pk11[33] = { |
|||
0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg11[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig11[64] = { |
|||
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, |
|||
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, |
|||
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, |
|||
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, |
|||
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, |
|||
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, |
|||
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, |
|||
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk11, msg11, sig11, 0); |
|||
} |
|||
{ |
|||
/* Test vector 12 */ |
|||
const unsigned char pk12[33] = { |
|||
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg12[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig12[64] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x9E, 0x9D, 0x01, 0xAF, 0x98, 0x8B, 0x5C, 0xED, |
|||
0xCE, 0x47, 0x22, 0x1B, 0xFA, 0x9B, 0x22, 0x27, |
|||
0x21, 0xF3, 0xFA, 0x40, 0x89, 0x15, 0x44, 0x4A, |
|||
0x4B, 0x48, 0x90, 0x21, 0xDB, 0x55, 0x77, 0x5F |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk12, msg12, sig12, 0); |
|||
} |
|||
{ |
|||
/* Test vector 13 */ |
|||
const unsigned char pk13[33] = { |
|||
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg13[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig13[64] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, |
|||
0xD3, 0x7D, 0xDF, 0x02, 0x54, 0x35, 0x18, 0x36, |
|||
0xD8, 0x4B, 0x1B, 0xD6, 0xA7, 0x95, 0xFD, 0x5D, |
|||
0x52, 0x30, 0x48, 0xF2, 0x98, 0xC4, 0x21, 0x4D, |
|||
0x18, 0x7F, 0xE4, 0x89, 0x29, 0x47, 0xF7, 0x28 |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk13, msg13, sig13, 0); |
|||
} |
|||
{ |
|||
/* Test vector 14 */ |
|||
const unsigned char pk14[33] = { |
|||
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg14[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x14, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig14[64] = { |
|||
0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, |
|||
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, |
|||
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, |
|||
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, |
|||
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, |
|||
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, |
|||
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, |
|||
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk14, msg14, sig14, 0); |
|||
} |
|||
{ |
|||
/* Test vector 15 */ |
|||
const unsigned char pk15[33] = { |
|||
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg15[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig15[64] = { |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, |
|||
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, |
|||
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, |
|||
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, |
|||
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk15, msg15, sig15, 0); |
|||
} |
|||
{ |
|||
/* Test vector 16 */ |
|||
const unsigned char pk16[33] = { |
|||
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, |
|||
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, |
|||
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, |
|||
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, |
|||
0x59 |
|||
}; |
|||
const unsigned char msg16[32] = { |
|||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, |
|||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, |
|||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, |
|||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 |
|||
}; |
|||
const unsigned char sig16[64] = { |
|||
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, |
|||
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, |
|||
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, |
|||
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, |
|||
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, |
|||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 |
|||
}; |
|||
test_schnorrsig_bip_vectors_check_verify(scratch, pk16, msg16, sig16, 0); |
|||
} |
|||
} |
|||
|
|||
/* Nonce function that returns constant 0 */ |
|||
static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { |
|||
(void) msg32; |
|||
(void) key32; |
|||
(void) algo16; |
|||
(void) data; |
|||
(void) counter; |
|||
(void) nonce32; |
|||
return 0; |
|||
} |
|||
|
|||
/* Nonce function that sets nonce to 0 */ |
|||
static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { |
|||
(void) msg32; |
|||
(void) key32; |
|||
(void) algo16; |
|||
(void) data; |
|||
(void) counter; |
|||
|
|||
memset(nonce32, 0, 32); |
|||
return 1; |
|||
} |
|||
|
|||
void test_schnorrsig_sign(void) { |
|||
unsigned char sk[32]; |
|||
const unsigned char msg[32] = "this is a msg for a schnorrsig.."; |
|||
secp256k1_schnorrsig sig; |
|||
|
|||
memset(sk, 23, sizeof(sk)); |
|||
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, NULL, NULL) == 1); |
|||
|
|||
/* Overflowing secret key */ |
|||
memset(sk, 0xFF, sizeof(sk)); |
|||
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, NULL, NULL) == 0); |
|||
memset(sk, 23, sizeof(sk)); |
|||
|
|||
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, nonce_function_failing, NULL) == 0); |
|||
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, nonce_function_0, NULL) == 0); |
|||
} |
|||
|
|||
#define N_SIGS 200 |
|||
/* Creates N_SIGS valid signatures and verifies them with verify and verify_batch. Then flips some
|
|||
* bits and checks that verification now fails. */ |
|||
void test_schnorrsig_sign_verify(secp256k1_scratch_space *scratch) { |
|||
const unsigned char sk[32] = "shhhhhhhh! this key is a secret."; |
|||
unsigned char msg[N_SIGS][32]; |
|||
secp256k1_schnorrsig sig[N_SIGS]; |
|||
size_t i; |
|||
const secp256k1_schnorrsig *sig_arr[N_SIGS]; |
|||
const unsigned char *msg_arr[N_SIGS]; |
|||
const secp256k1_pubkey *pk_arr[N_SIGS]; |
|||
secp256k1_pubkey pk; |
|||
|
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk)); |
|||
|
|||
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, NULL, NULL, NULL, 0)); |
|||
|
|||
for (i = 0; i < N_SIGS; i++) { |
|||
secp256k1_rand256(msg[i]); |
|||
CHECK(secp256k1_schnorrsig_sign(ctx, &sig[i], NULL, msg[i], sk, NULL, NULL)); |
|||
CHECK(secp256k1_schnorrsig_verify(ctx, &sig[i], msg[i], &pk)); |
|||
sig_arr[i] = &sig[i]; |
|||
msg_arr[i] = msg[i]; |
|||
pk_arr[i] = &pk; |
|||
} |
|||
|
|||
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 2)); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, N_SIGS)); |
|||
|
|||
{ |
|||
/* Flip a few bits in the signature and in the message and check that
|
|||
* verify and verify_batch fail */ |
|||
size_t sig_idx = secp256k1_rand_int(4); |
|||
size_t byte_idx = secp256k1_rand_int(32); |
|||
unsigned char xorbyte = secp256k1_rand_int(254)+1; |
|||
sig[sig_idx].data[byte_idx] ^= xorbyte; |
|||
CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); |
|||
CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); |
|||
sig[sig_idx].data[byte_idx] ^= xorbyte; |
|||
|
|||
byte_idx = secp256k1_rand_int(32); |
|||
sig[sig_idx].data[32+byte_idx] ^= xorbyte; |
|||
CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); |
|||
CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); |
|||
sig[sig_idx].data[32+byte_idx] ^= xorbyte; |
|||
|
|||
byte_idx = secp256k1_rand_int(32); |
|||
msg[sig_idx][byte_idx] ^= xorbyte; |
|||
CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); |
|||
CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); |
|||
msg[sig_idx][byte_idx] ^= xorbyte; |
|||
|
|||
/* Check that above bitflips have been reversed correctly */ |
|||
CHECK(secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); |
|||
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); |
|||
} |
|||
} |
|||
#undef N_SIGS |
|||
|
|||
void run_schnorrsig_tests(void) { |
|||
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024); |
|||
|
|||
test_schnorrsig_serialize(); |
|||
test_schnorrsig_api(scratch); |
|||
test_schnorrsig_bip_vectors(scratch); |
|||
test_schnorrsig_sign(); |
|||
test_schnorrsig_sign_verify(scratch); |
|||
|
|||
secp256k1_scratch_space_destroy(scratch); |
|||
} |
|||
|
|||
#endif |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,40 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2017 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_SCRATCH_ |
|||
#define _SECP256K1_SCRATCH_ |
|||
|
|||
#define SECP256K1_SCRATCH_MAX_FRAMES 5 |
|||
|
|||
/* The typedef is used internally; the struct name is used in the public API
|
|||
* (where it is exposed as a different typedef) */ |
|||
typedef struct secp256k1_scratch_space_struct { |
|||
void *data[SECP256K1_SCRATCH_MAX_FRAMES]; |
|||
size_t offset[SECP256K1_SCRATCH_MAX_FRAMES]; |
|||
size_t frame_size[SECP256K1_SCRATCH_MAX_FRAMES]; |
|||
size_t frame; |
|||
size_t max_size; |
|||
const secp256k1_callback* error_callback; |
|||
} secp256k1_scratch; |
|||
|
|||
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); |
|||
|
|||
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch); |
|||
|
|||
/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */ |
|||
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects); |
|||
|
|||
/** Deallocates a stack frame */ |
|||
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch); |
|||
|
|||
/** Returns the maximum allocation the scratch space will allow */ |
|||
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t n_objects); |
|||
|
|||
/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ |
|||
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t n); |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,87 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2017 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_SCRATCH_IMPL_H_ |
|||
#define _SECP256K1_SCRATCH_IMPL_H_ |
|||
|
|||
#include "scratch.h" |
|||
|
|||
/* Using 16 bytes alignment because common architectures never have alignment
|
|||
* requirements above 8 for any of the types we care about. In addition we |
|||
* leave some room because currently we don't care about a few bytes. |
|||
* TODO: Determine this at configure time. */ |
|||
#define ALIGNMENT 16 |
|||
|
|||
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size) { |
|||
secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret)); |
|||
if (ret != NULL) { |
|||
memset(ret, 0, sizeof(*ret)); |
|||
ret->max_size = max_size; |
|||
ret->error_callback = error_callback; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) { |
|||
if (scratch != NULL) { |
|||
VERIFY_CHECK(scratch->frame == 0); |
|||
free(scratch); |
|||
} |
|||
} |
|||
|
|||
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) { |
|||
size_t i = 0; |
|||
size_t allocated = 0; |
|||
for (i = 0; i < scratch->frame; i++) { |
|||
allocated += scratch->frame_size[i]; |
|||
} |
|||
if (scratch->max_size - allocated <= objects * ALIGNMENT) { |
|||
return 0; |
|||
} |
|||
return scratch->max_size - allocated - objects * ALIGNMENT; |
|||
} |
|||
|
|||
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects) { |
|||
VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES); |
|||
|
|||
if (n <= secp256k1_scratch_max_allocation(scratch, objects)) { |
|||
n += objects * ALIGNMENT; |
|||
scratch->data[scratch->frame] = checked_malloc(scratch->error_callback, n); |
|||
if (scratch->data[scratch->frame] == NULL) { |
|||
return 0; |
|||
} |
|||
scratch->frame_size[scratch->frame] = n; |
|||
scratch->offset[scratch->frame] = 0; |
|||
scratch->frame++; |
|||
return 1; |
|||
} else { |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) { |
|||
VERIFY_CHECK(scratch->frame > 0); |
|||
scratch->frame -= 1; |
|||
free(scratch->data[scratch->frame]); |
|||
} |
|||
|
|||
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) { |
|||
void *ret; |
|||
size_t frame = scratch->frame - 1; |
|||
size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; |
|||
|
|||
if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) { |
|||
return NULL; |
|||
} |
|||
ret = (void *) ((unsigned char *) scratch->data[frame] + scratch->offset[frame]); |
|||
memset(ret, 0, size); |
|||
scratch->offset[frame] += size; |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
#endif |
|||
|
Loading…
Reference in new issue