Merge elementsproject/secp256k1-zkp#205: Bulletproofs++: Norm argument
d7fb25c8ca5bda0e969ce94ccabedfd7b8432769 Make sure that bppp_log2 isn't called with value 0 (Jonas Nick) e5a01d12c63b30d3627cd0114a042a9853b0d233 Rename buletproof_pp* to bppp* (sanket1729) c9831868723b06cca72141651f9e27f37c6ca3eb transcript: add tests (Jonas Nick) 73edc75528a9a4d4cf69b77d38f108023a132994 norm arg: add verification vectors (Jonas Nick) 13ad32e814ece805a5bd2ef7c4b46fa37cedf136 norm arg: add tests for zero length and zero vectors (Jonas Nick) 34c4847a6a72e340dac2c078bbea4d65441e5971 ci: add bulletproofs (Jonas Nick) 25745164835669d71e86863d1de747f26480ec08 Add testcases for bulletproofs++ norm arugment (sanket1729) 46c7391154a7325133f97f9ec816ccf98ba76ede Add norm argument verify API (sanket1729) d9145455bb741c9f363c2a085abd0109e63c961f Add bulletproofs++ norm argument prove API (sanket1729) 8638f0e0cecad113e11b826a41bed1fe7a8d3b85 Add internal BP++ commit API (sanket1729) 412f8f66a08ef0e60644c7b5b22ee2a3d19ae3e8 Add utility functions required in norm argument (sanket1729) 420353d7da7793513621da3a5ad7479feaf76713 Add utilities for log2 (sanket1729) 17417d44f307a44e42468200458c3eb2c407b6b8 Add utilities from uncompressed Bulletproofs PR (sanket1729) 48563c8c791d2d5ed50dabde9de8c0839f43c8f3 bulletproofs: add API functionality to generate a large set of generators (Andrew Poelstra) 048f9f8642297578a4e7975fa1e9837a58fc1c66 bulletproofs: add new empty module (Andrew Poelstra) 6162d577fec175c620f759675eb09ffa10368de1 generator: cleanups in Pedersen/generator code (Andrew Poelstra) 0a6006989f6215a45e982cd696339c503ddfc325 Revert "Remove unused scalar_sqr" (Andrew Poelstra) 87373f51451bed948340d6885111d04051cbfc02 MOVE ONLY: move Pedersen commitment stuff to generator module from rangeproof module (Andrew Poelstra) Pull request description: ACKs for top commit: Liam-Eagen: ACK d7fb25c jonasnick: ACK d7fb25c8ca5bda0e969ce94ccabedfd7b8432769 Tree-SHA512: 0a51e2b404ab594e4ce6c4a65a35f6bbf870d718e0a3cdf7ddd085ed37a0e0c0db55dabca8fe9d8b8beb3f7e60280aa46a2951408c18942dd6ad1c9a71bab5cd
This commit is contained in:
commit
8ec6d111c8
10
.cirrus.yml
10
.cirrus.yml
@ -23,6 +23,7 @@ env:
|
||||
WHITELIST: no
|
||||
MUSIG: no
|
||||
ECDSAADAPTOR: no
|
||||
BPPP: no
|
||||
### test options
|
||||
SECP256K1_TEST_ITERS:
|
||||
BENCH: yes
|
||||
@ -72,12 +73,12 @@ task:
|
||||
<< : *LINUX_CONTAINER
|
||||
matrix: &ENV_MATRIX
|
||||
- env: {WIDEMUL: int64, RECOVERY: yes}
|
||||
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
|
||||
- env: {WIDEMUL: int128}
|
||||
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
|
||||
- env: {WIDEMUL: int128, ASM: x86_64}
|
||||
- env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||
- env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
|
||||
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
|
||||
- env: {CPPFLAGS: -DDETERMINISTIC}
|
||||
- env: {CFLAGS: -O0, CTIMETEST: no}
|
||||
@ -108,6 +109,7 @@ task:
|
||||
GENERATOR: yes
|
||||
MUSIG: yes
|
||||
ECDSAADAPTOR: yes
|
||||
BPPP: yes
|
||||
matrix:
|
||||
- env:
|
||||
CC: i686-linux-gnu-gcc
|
||||
@ -165,6 +167,7 @@ task:
|
||||
GENERATOR: yes
|
||||
MUSIG: yes
|
||||
ECDSAADAPTOR: yes
|
||||
BPPP: yes
|
||||
CTIMETEST: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
@ -259,6 +262,7 @@ task:
|
||||
GENERATOR: yes
|
||||
MUSIG: yes
|
||||
ECDSAADAPTOR: yes
|
||||
BPPP: yes
|
||||
CTIMETEST: no
|
||||
matrix:
|
||||
- name: "Valgrind (memcheck)"
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,9 +1,12 @@
|
||||
bench
|
||||
bench_bppp
|
||||
bench_ecmult
|
||||
bench_generator
|
||||
bench_rangeproof
|
||||
bench_internal
|
||||
bench_whitelist
|
||||
tests
|
||||
example_musig
|
||||
exhaustive_tests
|
||||
precompute_ecmult_gen
|
||||
precompute_ecmult
|
||||
@ -66,4 +69,4 @@ src/stamp-h1
|
||||
libsecp256k1.pc
|
||||
contrib/gh-pr-create.sh
|
||||
|
||||
musig_example
|
||||
musig_example
|
||||
|
@ -226,6 +226,10 @@ clean-precomp:
|
||||
|
||||
EXTRA_DIST = autogen.sh SECURITY.md
|
||||
|
||||
if ENABLE_MODULE_BPPP
|
||||
include src/modules/bppp/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_ECDH
|
||||
include src/modules/ecdh/Makefile.am.include
|
||||
endif
|
||||
|
@ -19,6 +19,7 @@ valgrind --version || true
|
||||
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
|
||||
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
|
||||
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
|
||||
--enable-module-bppp="$BPPP" \
|
||||
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" \
|
||||
@ -51,6 +52,10 @@ then
|
||||
$EXEC ./bench_ecmult
|
||||
$EXEC ./bench_internal
|
||||
$EXEC ./bench
|
||||
if [ "$BPPP" = "yes" ]
|
||||
then
|
||||
$EXEC ./bench_bppp
|
||||
fi
|
||||
} >> bench.log 2>&1
|
||||
fi
|
||||
|
||||
|
15
configure.ac
15
configure.ac
@ -140,6 +140,11 @@ AC_ARG_ENABLE(examples,
|
||||
AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_bppp,
|
||||
AS_HELP_STRING([--enable-module-bppp],[enable Bulletproofs++ module (experimental)]),
|
||||
[],
|
||||
[SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_ecdh,
|
||||
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
|
||||
@ -417,6 +422,11 @@ if test x"$enable_module_rangeproof" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_bppp" = x"yes"; then
|
||||
enable_module_generator=yes
|
||||
AC_DEFINE(ENABLE_MODULE_BPPP, 1, [Define this symbol to enable the Bulletproofs++ module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_generator" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module])
|
||||
fi
|
||||
@ -460,6 +470,9 @@ else
|
||||
# module (which automatically enables the module dependencies) we want to
|
||||
# print an error for the dependent module, not the module dependency. Hence,
|
||||
# we first test dependent modules.
|
||||
if test x"$enable_module_bppp" = x"yes"; then
|
||||
AC_MSG_ERROR([Bulletproofs++ module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_whitelist" = x"yes"; then
|
||||
AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
@ -502,6 +515,7 @@ AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
|
||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||
@ -541,6 +555,7 @@ echo " module whitelist = $enable_module_whitelist"
|
||||
echo " module musig = $enable_module_musig"
|
||||
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
|
||||
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
|
||||
echo " module bppp = $enable_module_bppp"
|
||||
echo
|
||||
echo " asm = $set_asm"
|
||||
echo " ecmult window size = $set_ecmult_window"
|
||||
|
73
include/secp256k1_bppp.h
Normal file
73
include/secp256k1_bppp.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef _SECP256K1_BPPP_
|
||||
# define _SECP256K1_BPPP_
|
||||
|
||||
# include "secp256k1.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Opaque structure representing a large number of NUMS generators */
|
||||
typedef struct secp256k1_bppp_generators secp256k1_bppp_generators;
|
||||
|
||||
/** Allocates and initializes a list of NUMS generators.
|
||||
* Returns a list of generators, or calls the error callback if the allocation fails.
|
||||
* Args: ctx: pointer to a context object
|
||||
* n: number of NUMS generators to produce.
|
||||
*
|
||||
* TODO: In a followup range-proof PR, this is would still require 16 + 8 = 24 NUMS
|
||||
* points. We will later use G = H0(required for compatibility with pedersen_commitment DS)
|
||||
* in a separate commit to make review easier.
|
||||
*/
|
||||
SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_create(
|
||||
const secp256k1_context* ctx,
|
||||
size_t n
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Allocates a list of generators from a static array
|
||||
* Returns a list of generators or NULL in case of failure.
|
||||
* Args: ctx: pointer to a context object
|
||||
* In: data: data that came from `secp256k1_bppp_generators_serialize`
|
||||
* data_len: the length of the `data` buffer
|
||||
*/
|
||||
SECP256K1_API secp256k1_bppp_generators* secp256k1_bppp_generators_parse(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char* data,
|
||||
size_t data_len
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Serializes a list of generators to an array
|
||||
* Returns 1 on success, 0 if the provided array was not large enough
|
||||
* Args: ctx: pointer to a context object
|
||||
* gen: pointer to the generator set to be serialized
|
||||
* Out: data: pointer to buffer into which the generators will be serialized
|
||||
* In/Out: data_len: the length of the `data` buffer. Should be at least
|
||||
* k = 33 * num_gens. Will be set to k on successful return
|
||||
*
|
||||
* TODO: For ease of review, this setting G = H0 is not included in this commit. We will
|
||||
* add it in the follow-up rangeproof PR.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_bppp_generators_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_bppp_generators* gen,
|
||||
unsigned char* data,
|
||||
size_t *data_len
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Destroys a list of NUMS generators, freeing allocated memory
|
||||
* Args: ctx: pointer to a context object
|
||||
* gen: pointer to the generator set to be destroyed
|
||||
* (can be NULL, in which case this function is a no-op)
|
||||
*/
|
||||
SECP256K1_API void secp256k1_bppp_generators_destroy(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_bppp_generators* gen
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
@ -21,6 +21,11 @@ typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_generator;
|
||||
|
||||
/**
|
||||
* Static constant generator 'h' maintained for historical reasons.
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
|
||||
|
||||
/** Parse a 33-byte generator byte sequence into a generator object.
|
||||
*
|
||||
* Returns: 1 if input contains a valid generator.
|
||||
@ -86,6 +91,149 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blin
|
||||
const unsigned char *blind32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Opaque data structure that stores a Pedersen commitment
|
||||
*
|
||||
* 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 secp256k1_pedersen_commitment_serialize and
|
||||
* secp256k1_pedersen_commitment_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_pedersen_commitment;
|
||||
|
||||
/** Parse a 33-byte commitment into a commitment object.
|
||||
*
|
||||
* Returns: 1 if input contains a valid commitment.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: commit: pointer to the output commitment object
|
||||
* In: input: pointer to a 33-byte serialized commitment key
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pedersen_commitment* commit,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a commitment object into a serialized byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output: a pointer to a 33-byte byte array
|
||||
* In: commit: a pointer to a secp256k1_pedersen_commitment containing an
|
||||
* initialized commitment
|
||||
*/
|
||||
SECP256K1_API int secp256k1_pedersen_commitment_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_pedersen_commitment* commit
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a pedersen commitment.
|
||||
* Returns 1: Commitment successfully created.
|
||||
* 0: Error. The blinding factor is larger than the group order
|
||||
* (probability for random 32 byte number < 2^-127) or results in the
|
||||
* point at infinity. Retry with a different factor.
|
||||
* In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
|
||||
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
|
||||
* value: unsigned 64-bit integer value to commit to.
|
||||
* gen: additional generator 'h'
|
||||
* Out: commit: pointer to the commitment (cannot be NULL)
|
||||
*
|
||||
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pedersen_commitment *commit,
|
||||
const unsigned char *blind,
|
||||
uint64_t value,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Computes the sum of multiple positive and negative blinding factors.
|
||||
* Returns 1: Sum successfully computed.
|
||||
* 0: Error. A blinding factor is larger than the group order
|
||||
* (probability for random 32 byte number < 2^-127). Retry with
|
||||
* different factors.
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
|
||||
* n: number of factors pointed to by blinds.
|
||||
* npositive: how many of the initial factors should be treated with a positive sign.
|
||||
* Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
const unsigned char * const *blinds,
|
||||
size_t n,
|
||||
size_t npositive
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Verify a tally of pedersen commitments
|
||||
* Returns 1: commitments successfully sum to zero.
|
||||
* 0: Commitments do not sum to zero or other error.
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero)
|
||||
* pcnt: number of commitments pointed to by commits.
|
||||
* ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero)
|
||||
* ncnt: number of commitments pointed to by ncommits.
|
||||
*
|
||||
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0.
|
||||
*
|
||||
* A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor,
|
||||
* while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator
|
||||
* A all blinding factors and all values must sum to zero.
|
||||
*
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_pedersen_commitment * const* commits,
|
||||
size_t pcnt,
|
||||
const secp256k1_pedersen_commitment * const* ncommits,
|
||||
size_t ncnt
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Sets the final Pedersen blinding factor correctly when the generators themselves
|
||||
* have blinding factors.
|
||||
*
|
||||
* Consider a generator of the form A' = A + rG, where A is the "real" generator
|
||||
* but A' is the generator provided to verifiers. Then a Pedersen commitment
|
||||
* P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
|
||||
* to sum to zero for multiple commitments, we take three arrays consisting of
|
||||
* the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
|
||||
* and `blinding_factor`s, and sum them.
|
||||
*
|
||||
* The function then subtracts the sum of all (vr + r') from the last element
|
||||
* of the `blinding_factor` array, setting the total sum to zero.
|
||||
*
|
||||
* Returns 1: Blinding factor successfully computed.
|
||||
* 0: Error. A blinding_factor or generator_blind are larger than the group
|
||||
* order (probability for random 32 byte number < 2^-127). Retry with
|
||||
* different values.
|
||||
*
|
||||
* In: ctx: pointer to a context object
|
||||
* value: array of asset values, `v` in the above paragraph.
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* generator_blind: array of asset blinding factors, `r` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* n_total: Total size of the above arrays
|
||||
* n_inputs: How many of the initial array elements represent commitments that
|
||||
* will be negated in the final sum
|
||||
* In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* the last value will be modified to get the total sum to zero.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
const uint64_t *value,
|
||||
const unsigned char* const* generator_blind,
|
||||
unsigned char* const* blinding_factor,
|
||||
size_t n_total,
|
||||
size_t n_inputs
|
||||
);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
@ -19,154 +19,6 @@ extern "C" {
|
||||
*/
|
||||
#define SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN 3968
|
||||
|
||||
/** Opaque data structure that stores a Pedersen commitment
|
||||
*
|
||||
* 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 secp256k1_pedersen_commitment_serialize and
|
||||
* secp256k1_pedersen_commitment_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_pedersen_commitment;
|
||||
|
||||
/**
|
||||
* Static constant generator 'h' maintained for historical reasons.
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
|
||||
|
||||
/** Parse a 33-byte commitment into a commitment object.
|
||||
*
|
||||
* Returns: 1 if input contains a valid commitment.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: commit: pointer to the output commitment object
|
||||
* In: input: pointer to a 33-byte serialized commitment key
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pedersen_commitment* commit,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a commitment object into a serialized byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output: a pointer to a 33-byte byte array
|
||||
* In: commit: a pointer to a secp256k1_pedersen_commitment containing an
|
||||
* initialized commitment
|
||||
*/
|
||||
SECP256K1_API int secp256k1_pedersen_commitment_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_pedersen_commitment* commit
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a pedersen commitment.
|
||||
* Returns 1: Commitment successfully created.
|
||||
* 0: Error. The blinding factor is larger than the group order
|
||||
* (probability for random 32 byte number < 2^-127) or results in the
|
||||
* point at infinity. Retry with a different factor.
|
||||
* In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
|
||||
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
|
||||
* value: unsigned 64-bit integer value to commit to.
|
||||
* gen: additional generator 'h'
|
||||
* Out: commit: pointer to the commitment (cannot be NULL)
|
||||
*
|
||||
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pedersen_commitment *commit,
|
||||
const unsigned char *blind,
|
||||
uint64_t value,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Computes the sum of multiple positive and negative blinding factors.
|
||||
* Returns 1: Sum successfully computed.
|
||||
* 0: Error. A blinding factor is larger than the group order
|
||||
* (probability for random 32 byte number < 2^-127). Retry with
|
||||
* different factors.
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
|
||||
* n: number of factors pointed to by blinds.
|
||||
* npositive: how many of the initial factors should be treated with a positive sign.
|
||||
* Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
const unsigned char * const *blinds,
|
||||
size_t n,
|
||||
size_t npositive
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Verify a tally of pedersen commitments
|
||||
* Returns 1: commitments successfully sum to zero.
|
||||
* 0: Commitments do not sum to zero or other error.
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero)
|
||||
* pcnt: number of commitments pointed to by commits.
|
||||
* ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero)
|
||||
* ncnt: number of commitments pointed to by ncommits.
|
||||
*
|
||||
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0.
|
||||
*
|
||||
* A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor,
|
||||
* while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator
|
||||
* A all blinding factors and all values must sum to zero.
|
||||
*
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_pedersen_commitment * const* commits,
|
||||
size_t pcnt,
|
||||
const secp256k1_pedersen_commitment * const* ncommits,
|
||||
size_t ncnt
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Sets the final Pedersen blinding factor correctly when the generators themselves
|
||||
* have blinding factors.
|
||||
*
|
||||
* Consider a generator of the form A' = A + rG, where A is the "real" generator
|
||||
* but A' is the generator provided to verifiers. Then a Pedersen commitment
|
||||
* P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
|
||||
* to sum to zero for multiple commitments, we take three arrays consisting of
|
||||
* the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
|
||||
* and `blinding_factor`s, and sum them.
|
||||
*
|
||||
* The function then subtracts the sum of all (vr + r') from the last element
|
||||
* of the `blinding_factor` array, setting the total sum to zero.
|
||||
*
|
||||
* Returns 1: Blinding factor successfully computed.
|
||||
* 0: Error. A blinding_factor or generator_blind are larger than the group
|
||||
* order (probability for random 32 byte number < 2^-127). Retry with
|
||||
* different values.
|
||||
*
|
||||
* In: ctx: pointer to a context object
|
||||
* value: array of asset values, `v` in the above paragraph.
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* generator_blind: array of asset blinding factors, `r` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* n_total: Total size of the above arrays
|
||||
* n_inputs: How many of the initial array elements represent commitments that
|
||||
* will be negated in the final sum
|
||||
* In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* the last value will be modified to get the total sum to zero.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
const uint64_t *value,
|
||||
const unsigned char* const* generator_blind,
|
||||
unsigned char* const* blinding_factor,
|
||||
size_t n_total,
|
||||
size_t n_inputs
|
||||
);
|
||||
|
||||
/** Verify a proof that a committed value is within a range.
|
||||
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs.
|
||||
* 0: Proof failed or other error.
|
||||
|
38
src/bench_bppp.c
Normal file
38
src/bench_bppp.c
Normal file
@ -0,0 +1,38 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "include/secp256k1_bppp.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
} bench_bppp_data;
|
||||
|
||||
static void bench_bppp_setup(void* arg) {
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
static void bench_bppp(void* arg, int iters) {
|
||||
bench_bppp_data *data = (bench_bppp_data*)arg;
|
||||
|
||||
(void) data;
|
||||
(void) iters;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
bench_bppp_data data;
|
||||
int iters = get_iters(32);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
run_benchmark("bppp_verify_bit", bench_bppp, bench_bppp_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
}
|
@ -98,6 +98,15 @@ void bench_scalar_negate(void* arg, int iters) {
|
||||
}
|
||||
}
|
||||
|
||||
void bench_scalar_sqr(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_sqr(&data->scalar[0], &data->scalar[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_scalar_mul(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
@ -376,6 +385,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters);
|
||||
|
13
src/modules/bppp/Makefile.am.include
Normal file
13
src/modules/bppp/Makefile.am.include
Normal file
@ -0,0 +1,13 @@
|
||||
include_HEADERS += include/secp256k1_bppp.h
|
||||
noinst_HEADERS += src/modules/bppp/bppp_util.h
|
||||
noinst_HEADERS += src/modules/bppp/main_impl.h
|
||||
noinst_HEADERS += src/modules/bppp/bppp_transcript_impl.h
|
||||
noinst_HEADERS += src/modules/bppp/bppp_norm_product_impl.h
|
||||
noinst_HEADERS += src/modules/bppp/tests_impl.h
|
||||
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_bppp
|
||||
bench_bppp_SOURCES = src/bench_bppp.c
|
||||
bench_bppp_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_bppp_LDFLAGS = -static
|
||||
endif
|
559
src/modules/bppp/bppp_norm_product_impl.h
Normal file
559
src/modules/bppp/bppp_norm_product_impl.h
Normal file
@ -0,0 +1,559 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 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_BPPP_PP_NORM_PRODUCT_
|
||||
#define _SECP256K1_MODULE_BPPP_PP_NORM_PRODUCT_
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "modules/bppp/main.h"
|
||||
#include "modules/bppp/bppp_util.h"
|
||||
#include "modules/bppp/bppp_transcript_impl.h"
|
||||
|
||||
/* Computes the inner product of two vectors of scalars
|
||||
* with elements starting from offset a and offset b
|
||||
* skipping elements according to specified step.
|
||||
* Returns: Sum_{i=0..len-1}(a[offset_a + i*step] * b[offset_b + i*step]) */
|
||||
static int secp256k1_scalar_inner_product(
|
||||
secp256k1_scalar* res,
|
||||
const secp256k1_scalar* a_vec,
|
||||
const size_t a_offset,
|
||||
const secp256k1_scalar* b_vec,
|
||||
const size_t b_offset,
|
||||
const size_t step,
|
||||
const size_t len
|
||||
) {
|
||||
size_t i;
|
||||
secp256k1_scalar_set_int(res, 0);
|
||||
for (i = 0; i < len; i++) {
|
||||
secp256k1_scalar term;
|
||||
secp256k1_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]);
|
||||
secp256k1_scalar_add(res, res, &term);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Computes the q-weighted inner product of two vectors of scalars
|
||||
* for elements starting from offset a and offset b respectively with the
|
||||
* given step.
|
||||
* Returns: Sum_{i=0..len-1}(a[offset_a + step*i] * b[offset_b2 + step*i]*q^(i+1)) */
|
||||
static int secp256k1_weighted_scalar_inner_product(
|
||||
secp256k1_scalar* res,
|
||||
const secp256k1_scalar* a_vec,
|
||||
const size_t a_offset,
|
||||
const secp256k1_scalar* b_vec,
|
||||
const size_t b_offset,
|
||||
const size_t step,
|
||||
const size_t len,
|
||||
const secp256k1_scalar* q
|
||||
) {
|
||||
secp256k1_scalar q_pow;
|
||||
size_t i;
|
||||
secp256k1_scalar_set_int(res, 0);
|
||||
q_pow = *q;
|
||||
for (i = 0; i < len; i++) {
|
||||
secp256k1_scalar term;
|
||||
secp256k1_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]);
|
||||
secp256k1_scalar_mul(&term, &term, &q_pow);
|
||||
secp256k1_scalar_mul(&q_pow, &q_pow, q);
|
||||
secp256k1_scalar_add(res, res, &term);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the powers of r as r, r^2, r^4 ... r^(2^(n-1)) */
|
||||
static void secp256k1_bppp_powers_of_r(secp256k1_scalar *powers, const secp256k1_scalar *r, size_t n) {
|
||||
size_t i;
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
powers[0] = *r;
|
||||
for (i = 1; i < n; i++) {
|
||||
secp256k1_scalar_sqr(&powers[i], &powers[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct ecmult_bp_commit_cb_data {
|
||||
const secp256k1_scalar *n;
|
||||
const secp256k1_ge *g;
|
||||
const secp256k1_scalar *l;
|
||||
size_t g_len;
|
||||
} ecmult_bp_commit_cb_data;
|
||||
|
||||
static int ecmult_bp_commit_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
|
||||
ecmult_bp_commit_cb_data *data = (ecmult_bp_commit_cb_data*) cbdata;
|
||||
*pt = data->g[idx];
|
||||
if (idx < data->g_len) {
|
||||
*sc = data->n[idx];
|
||||
} else {
|
||||
*sc = data->l[idx - data->g_len];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create a commitment `commit` = vG + n_vec*G_vec + l_vec*H_vec where
|
||||
v = |n_vec*n_vec|_q + <l_vec, c_vec>. |w|_q denotes q-weighted norm of w and
|
||||
<l, r> denotes inner product of l and r.
|
||||
*/
|
||||
static int secp256k1_bppp_commit(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space* scratch,
|
||||
secp256k1_ge* commit,
|
||||
const secp256k1_bppp_generators* g_vec,
|
||||
const secp256k1_scalar* n_vec,
|
||||
size_t n_vec_len,
|
||||
const secp256k1_scalar* l_vec,
|
||||
size_t l_vec_len,
|
||||
const secp256k1_scalar* c_vec,
|
||||
size_t c_vec_len,
|
||||
const secp256k1_scalar* q
|
||||
) {
|
||||
secp256k1_scalar v, l_c;
|
||||
/* First n_vec_len generators are Gs, rest are Hs*/
|
||||
VERIFY_CHECK(g_vec->n == (n_vec_len + l_vec_len));
|
||||
VERIFY_CHECK(l_vec_len == c_vec_len);
|
||||
|
||||
/* It is possible to extend to support n_vec and c_vec to not be power of
|
||||
two. For the initial iterations of the code, we stick to powers of two for simplicity.*/
|
||||
VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len));
|
||||
VERIFY_CHECK(secp256k1_is_power_of_two(c_vec_len));
|
||||
|
||||
/* Compute v = n_vec*n_vec*q + l_vec*c_vec */
|
||||
secp256k1_weighted_scalar_inner_product(&v, n_vec, 0 /*a offset */, n_vec, 0 /*b offset*/, 1 /*step*/, n_vec_len, q);
|
||||
secp256k1_scalar_inner_product(&l_c, l_vec, 0 /*a offset */, c_vec, 0 /*b offset*/, 1 /*step*/, l_vec_len);
|
||||
secp256k1_scalar_add(&v, &v, &l_c);
|
||||
|
||||
{
|
||||
ecmult_bp_commit_cb_data data;
|
||||
secp256k1_gej commitj;
|
||||
data.g = g_vec->gens;
|
||||
data.n = n_vec;
|
||||
data.l = l_vec;
|
||||
data.g_len = n_vec_len;
|
||||
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &commitj, &v, ecmult_bp_commit_cb, (void*) &data, n_vec_len + l_vec_len)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej_var(commit, &commitj);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct ecmult_x_cb_data {
|
||||
const secp256k1_scalar *n;
|
||||
const secp256k1_ge *g;
|
||||
const secp256k1_scalar *l;
|
||||
const secp256k1_scalar *r;
|
||||
const secp256k1_scalar *r_inv;
|
||||
size_t G_GENS_LEN; /* Figure out initialization syntax so that this can also be const */
|
||||
size_t n_len;
|
||||
} ecmult_x_cb_data;
|
||||
|
||||
static int ecmult_x_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
|
||||
ecmult_x_cb_data *data = (ecmult_x_cb_data*) cbdata;
|
||||
if (idx < data->n_len) {
|
||||
if (idx % 2 == 0) {
|
||||
secp256k1_scalar_mul(sc, &data->n[idx + 1], data->r);
|
||||
*pt = data->g[idx];
|
||||
} else {
|
||||
secp256k1_scalar_mul(sc, &data->n[idx - 1], data->r_inv);
|
||||
*pt = data->g[idx];
|
||||
}
|
||||
} else {
|
||||
idx -= data->n_len;
|
||||
if (idx % 2 == 0) {
|
||||
*sc = data->l[idx + 1];
|
||||
*pt = data->g[data->G_GENS_LEN + idx];
|
||||
} else {
|
||||
*sc = data->l[idx - 1];
|
||||
*pt = data->g[data->G_GENS_LEN + idx];
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct ecmult_r_cb_data {
|
||||
const secp256k1_scalar *n1;
|
||||
const secp256k1_ge *g1;
|
||||
const secp256k1_scalar *l1;
|
||||
size_t G_GENS_LEN;
|
||||
size_t n_len;
|
||||
} ecmult_r_cb_data;
|
||||
|
||||
static int ecmult_r_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
|
||||
ecmult_r_cb_data *data = (ecmult_r_cb_data*) cbdata;
|
||||
if (idx < data->n_len) {
|
||||
*sc = data->n1[2*idx + 1];
|
||||
*pt = data->g1[2*idx + 1];
|
||||
} else {
|
||||
idx -= data->n_len;
|
||||
*sc = data->l1[2*idx + 1];
|
||||
*pt = data->g1[data->G_GENS_LEN + 2*idx + 1];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Recursively compute the norm argument proof satisfying the relation
|
||||
* <n_vec, n_vec>_q + <c_vec, l_vec> = v for some commitment
|
||||
* C = v*G + <n_vec, G_vec> + <l_vec, H_vec>. <x, x>_q is the weighted inner
|
||||
* product of x with itself, where the weights are the first n powers of q.
|
||||
* <x, x>_q = q*x_1^2 + q^2*x_2^2 + q^3*x_3^2 + ... + q^n*x_n^2.
|
||||
* The API computes q as square of the r challenge (`r^2`).
|
||||
*
|
||||
* The norm argument is not zero knowledge and does not operate on any secret data.
|
||||
* Thus the following code uses variable time operations while computing the proof.
|
||||
* This function also modifies the values of n_vec, l_vec, c_vec and g_vec. The caller
|
||||
* is expected to copy these values if they need to be preserved.
|
||||
*
|
||||
* Assumptions: This function is intended to be used in conjunction with the
|
||||
* some parent protocol. To use this norm protocol in a standalone manner, the user
|
||||
* should add the commitment, generators and initial public data to the transcript hash.
|
||||
*/
|
||||
static int secp256k1_bppp_rangeproof_norm_product_prove(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space* scratch,
|
||||
unsigned char* proof,
|
||||
size_t *proof_len,
|
||||
secp256k1_sha256* transcript, /* Transcript hash of the parent protocol */
|
||||
const secp256k1_scalar* r,
|
||||
secp256k1_ge* g_vec,
|
||||
size_t g_vec_len,
|
||||
secp256k1_scalar* n_vec,
|
||||
size_t n_vec_len,
|
||||
secp256k1_scalar* l_vec,
|
||||
size_t l_vec_len,
|
||||
secp256k1_scalar* c_vec,
|
||||
size_t c_vec_len
|
||||
) {
|
||||
secp256k1_scalar q_f, r_f = *r;
|
||||
size_t proof_idx = 0;
|
||||
ecmult_x_cb_data x_cb_data;
|
||||
ecmult_r_cb_data r_cb_data;
|
||||
size_t g_len = n_vec_len, h_len = l_vec_len;
|
||||
const size_t G_GENS_LEN = g_len;
|
||||
size_t log_g_len, log_h_len;
|
||||
size_t num_rounds;
|
||||
|
||||
VERIFY_CHECK(g_len > 0 && h_len > 0);
|
||||
log_g_len = secp256k1_bppp_log2(g_len);
|
||||
log_h_len = secp256k1_bppp_log2(h_len);
|
||||
num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len;
|
||||
/* Check proof sizes.*/
|
||||
VERIFY_CHECK(*proof_len >= 65 * num_rounds + 64);
|
||||
VERIFY_CHECK(g_vec_len == (n_vec_len + l_vec_len) && l_vec_len == c_vec_len);
|
||||
VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len) && secp256k1_is_power_of_two(c_vec_len));
|
||||
|
||||
x_cb_data.n = n_vec;
|
||||
x_cb_data.g = g_vec;
|
||||
x_cb_data.l = l_vec;
|
||||
x_cb_data.G_GENS_LEN = G_GENS_LEN;
|
||||
|
||||
r_cb_data.n1 = n_vec;
|
||||
r_cb_data.g1 = g_vec;
|
||||
r_cb_data.l1 = l_vec;
|
||||
r_cb_data.G_GENS_LEN = G_GENS_LEN;
|
||||
secp256k1_scalar_sqr(&q_f, &r_f);
|
||||
|
||||
|
||||
while (g_len > 1 || h_len > 1) {
|
||||
size_t i, num_points;
|
||||
secp256k1_scalar q_sq, r_inv, c0_l1, c1_l0, x_v, c1_l1, r_v;
|
||||
secp256k1_gej rj, xj;
|
||||
secp256k1_ge r_ge, x_ge;
|
||||
secp256k1_scalar e;
|
||||
|
||||
secp256k1_scalar_inverse_var(&r_inv, &r_f);
|
||||
secp256k1_scalar_sqr(&q_sq, &q_f);
|
||||
|
||||
/* Compute the X commitment X = WIP(r_inv*n0,n1)_q2 * g + r<n1,G> + <r_inv*x0, G1> */
|
||||
secp256k1_scalar_inner_product(&c0_l1, c_vec, 0, l_vec, 1, 2, h_len/2);
|
||||
secp256k1_scalar_inner_product(&c1_l0, c_vec, 1, l_vec, 0, 2, h_len/2);
|
||||
secp256k1_weighted_scalar_inner_product(&x_v, n_vec, 0, n_vec, 1, 2, g_len/2, &q_sq);
|
||||
secp256k1_scalar_mul(&x_v, &x_v, &r_inv);
|
||||
secp256k1_scalar_add(&x_v, &x_v, &x_v);
|
||||
secp256k1_scalar_add(&x_v, &x_v, &c0_l1);
|
||||
secp256k1_scalar_add(&x_v, &x_v, &c1_l0);
|
||||
|
||||
x_cb_data.r = &r_f;
|
||||
x_cb_data.r_inv = &r_inv;
|
||||
x_cb_data.n_len = g_len >= 2 ? g_len : 0;
|
||||
num_points = x_cb_data.n_len + (h_len >= 2 ? h_len : 0);
|
||||
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &xj, &x_v, ecmult_x_cb, (void*)&x_cb_data, num_points)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_weighted_scalar_inner_product(&r_v, n_vec, 1, n_vec, 1, 2, g_len/2, &q_sq);
|
||||
secp256k1_scalar_inner_product(&c1_l1, c_vec, 1, l_vec, 1, 2, h_len/2);
|
||||
secp256k1_scalar_add(&r_v, &r_v, &c1_l1);
|
||||
|
||||
r_cb_data.n_len = g_len/2;
|
||||
num_points = r_cb_data.n_len + h_len/2;
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &rj, &r_v, ecmult_r_cb, (void*)&r_cb_data, num_points)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We only fail here because we cannot serialize points at infinity. */
|
||||
if (secp256k1_gej_is_infinity(&xj) || secp256k1_gej_is_infinity(&rj)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_ge_set_gej_var(&x_ge, &xj);
|
||||
secp256k1_fe_normalize_var(&x_ge.x);
|
||||
secp256k1_fe_normalize_var(&x_ge.y);
|
||||
secp256k1_ge_set_gej_var(&r_ge, &rj);
|
||||
secp256k1_fe_normalize_var(&r_ge.x);
|
||||
secp256k1_fe_normalize_var(&r_ge.y);
|
||||
secp256k1_bppp_serialize_points(&proof[proof_idx], &x_ge, &r_ge);
|
||||
proof_idx += 65;
|
||||
|
||||
/* Obtain challenge e for the the next round */
|
||||
secp256k1_sha256_write(transcript, &proof[proof_idx - 65], 65);
|
||||
secp256k1_bppp_challenge_scalar(&e, transcript, 0);
|
||||
|
||||
if (g_len > 1) {
|
||||
for (i = 0; i < g_len; i = i + 2) {
|
||||
secp256k1_scalar nl, nr;
|
||||
secp256k1_gej gl, gr;
|
||||
secp256k1_scalar_mul(&nl, &n_vec[i], &r_inv);
|
||||
secp256k1_scalar_mul(&nr, &n_vec[i + 1], &e);
|
||||
secp256k1_scalar_add(&n_vec[i/2], &nl, &nr);
|
||||
|
||||
secp256k1_gej_set_ge(&gl, &g_vec[i]);
|
||||
secp256k1_ecmult(&gl, &gl, &r_f, NULL);
|
||||
secp256k1_gej_set_ge(&gr, &g_vec[i + 1]);
|
||||
secp256k1_ecmult(&gr, &gr, &e, NULL);
|
||||
secp256k1_gej_add_var(&gl, &gl, &gr, NULL);
|
||||
secp256k1_ge_set_gej_var(&g_vec[i/2], &gl);
|
||||
}
|
||||
}
|
||||
|
||||
if (h_len > 1) {
|
||||
for (i = 0; i < h_len; i = i + 2) {
|
||||
secp256k1_scalar temp1;
|
||||
secp256k1_gej grj;
|
||||
secp256k1_scalar_mul(&temp1, &c_vec[i + 1], &e);
|
||||
secp256k1_scalar_add(&c_vec[i/2], &c_vec[i], &temp1);
|
||||
|
||||
secp256k1_scalar_mul(&temp1, &l_vec[i + 1], &e);
|
||||
secp256k1_scalar_add(&l_vec[i/2], &l_vec[i], &temp1);
|
||||
|
||||
secp256k1_gej_set_ge(&grj, &g_vec[G_GENS_LEN + i + 1]);
|
||||
secp256k1_ecmult(&grj, &grj, &e, NULL);
|
||||
secp256k1_gej_add_ge_var(&grj, &grj, &g_vec[G_GENS_LEN + i], NULL);
|
||||
secp256k1_ge_set_gej_var(&g_vec[G_GENS_LEN + i/2], &grj);
|
||||
}
|
||||
}
|
||||
g_len = g_len / 2;
|
||||
h_len = h_len / 2;
|
||||
r_f = q_f;
|
||||
q_f = q_sq;
|
||||
}
|
||||
|
||||
secp256k1_scalar_get_b32(&proof[proof_idx], &n_vec[0]);
|
||||
secp256k1_scalar_get_b32(&proof[proof_idx + 32], &l_vec[0]);
|
||||
proof_idx += 64;
|
||||
*proof_len = proof_idx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct ec_mult_verify_cb_data1 {
|
||||
const unsigned char *proof;
|
||||
const secp256k1_ge *commit;
|
||||
const secp256k1_scalar *challenges;
|
||||
} ec_mult_verify_cb_data1;
|
||||
|
||||
static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
|
||||
ec_mult_verify_cb_data1 *data = (ec_mult_verify_cb_data1*) cbdata;
|
||||
if (idx == 0) {
|
||||
*pt = *data->commit;
|
||||
secp256k1_scalar_set_int(sc, 1);
|
||||
return 1;
|
||||
}
|
||||
idx -= 1;
|
||||
if (idx % 2 == 0) {
|
||||
unsigned char pk_buf[33];
|
||||
idx /= 2;
|
||||
*sc = data->challenges[idx];
|
||||
pk_buf[0] = 2 | (data->proof[65*idx] >> 1);
|
||||
memcpy(&pk_buf[1], &data->proof[65*idx + 1], 32);
|
||||
if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
unsigned char pk_buf[33];
|
||||
secp256k1_scalar neg_one;
|
||||
idx /= 2;
|
||||
secp256k1_scalar_set_int(&neg_one, 1);
|
||||
secp256k1_scalar_negate(&neg_one, &neg_one);
|
||||
*sc = data->challenges[idx];
|
||||
secp256k1_scalar_sqr(sc, sc);
|
||||
secp256k1_scalar_add(sc, sc, &neg_one);
|
||||
pk_buf[0] = 2 | data->proof[65*idx];
|
||||
memcpy(&pk_buf[1], &data->proof[65*idx + 33], 32);
|
||||
if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct ec_mult_verify_cb_data2 {
|
||||
const secp256k1_scalar *s_g;
|
||||
const secp256k1_scalar *s_h;
|
||||
const secp256k1_ge *g_vec;
|
||||
size_t g_vec_len;
|
||||
} ec_mult_verify_cb_data2;
|
||||
|
||||
static int ec_mult_verify_cb2(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
|
||||
ec_mult_verify_cb_data2 *data = (ec_mult_verify_cb_data2*) cbdata;
|
||||
if (idx < data->g_vec_len) {
|
||||
*sc = data->s_g[idx];
|
||||
} else {
|
||||
*sc = data->s_h[idx - data->g_vec_len];
|
||||
}
|
||||
*pt = data->g_vec[idx];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Verify the proof. This function modifies the generators, c_vec and the challenge r. The
|
||||
caller should make sure to back them up if they need to be reused.
|
||||
*/
|
||||
static int secp256k1_bppp_rangeproof_norm_product_verify(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space* scratch,
|
||||
const unsigned char* proof,
|
||||
size_t proof_len,
|
||||
secp256k1_sha256* transcript,
|
||||
const secp256k1_scalar* r,
|
||||
const secp256k1_bppp_generators* g_vec,
|
||||
size_t g_len,
|
||||
const secp256k1_scalar* c_vec,
|
||||
size_t c_vec_len,
|
||||
const secp256k1_ge* commit
|
||||
) {
|
||||
secp256k1_scalar r_f, q_f, v, n, l, r_inv, h_c;
|
||||
secp256k1_scalar *es, *s_g, *s_h, *r_inv_pows;
|
||||
secp256k1_gej res1, res2;
|
||||
size_t i = 0, scratch_checkpoint;
|
||||
int overflow;
|
||||
size_t log_g_len, log_h_len;
|
||||
size_t n_rounds;
|
||||
size_t h_len = c_vec_len;
|
||||
|
||||
if (g_len == 0 || c_vec_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
log_g_len = secp256k1_bppp_log2(g_len);
|
||||
log_h_len = secp256k1_bppp_log2(c_vec_len);
|
||||
n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len;
|
||||
|
||||
if (g_vec->n != (h_len + g_len) || (proof_len != 65 * n_rounds + 64)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!secp256k1_is_power_of_two(g_len) || !secp256k1_is_power_of_two(h_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&n, &proof[n_rounds*65], &overflow); /* n */
|
||||
if (overflow) return 0;
|
||||
secp256k1_scalar_set_b32(&l, &proof[n_rounds*65 + 32], &overflow); /* l */
|
||||
if (overflow) return 0;
|
||||
if (secp256k1_scalar_is_zero(r)) return 0;
|
||||
|
||||
/* Collect the challenges in a new vector */
|
||||
scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
|
||||
es = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, n_rounds * sizeof(secp256k1_scalar));
|
||||
s_g = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar));
|
||||
s_h = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
|
||||
r_inv_pows = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, log_g_len * sizeof(secp256k1_scalar));
|
||||
if (es == NULL || s_g == NULL || s_h == NULL || r_inv_pows == NULL) {
|
||||
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute powers of r_inv. Later used in g_factor computations*/
|
||||
secp256k1_scalar_inverse_var(&r_inv, r);
|
||||
secp256k1_bppp_powers_of_r(r_inv_pows, &r_inv, log_g_len);
|
||||
|
||||
/* Compute r_f = r^(2^log_g_len) */
|
||||
r_f = *r;
|
||||
for (i = 0; i < log_g_len; i++) {
|
||||
secp256k1_scalar_sqr(&r_f, &r_f);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_rounds; i++) {
|
||||
secp256k1_scalar e;
|
||||
secp256k1_sha256_write(transcript, &proof[i * 65], 65);
|
||||
secp256k1_bppp_challenge_scalar(&e, transcript, 0);
|
||||
es[i] = e;
|
||||
}
|
||||
/* s_g[0] = n * \prod_{j=0}^{log_g_len - 1} r^(2^j)
|
||||
* = n * r^(2^log_g_len - 1)
|
||||
* = n * r_f * r_inv */
|
||||
secp256k1_scalar_mul(&s_g[0], &n, &r_f);
|
||||
secp256k1_scalar_mul(&s_g[0], &s_g[0], &r_inv);
|
||||
for (i = 1; i < g_len; i++) {
|
||||
size_t log_i = secp256k1_bppp_log2(i);
|
||||
size_t nearest_pow_of_two = (size_t)1 << log_i;
|
||||
/* This combines the two multiplications of challenges and r_invs in a
|
||||
* single loop.
|
||||
* s_g[i] = s_g[i - nearest_pow_of_two]
|
||||
* * e[log_i] * r_inv^(2^log_i) */
|
||||
secp256k1_scalar_mul(&s_g[i], &s_g[i - nearest_pow_of_two], &es[log_i]);
|
||||
secp256k1_scalar_mul(&s_g[i], &s_g[i], &r_inv_pows[log_i]);
|
||||
}
|
||||
s_h[0] = l;
|
||||
secp256k1_scalar_set_int(&h_c, 0);
|
||||
for (i = 1; i < h_len; i++) {
|
||||
size_t log_i = secp256k1_bppp_log2(i);
|
||||
size_t nearest_pow_of_two = (size_t)1 << log_i;
|
||||
secp256k1_scalar_mul(&s_h[i], &s_h[i - nearest_pow_of_two], &es[log_i]);
|
||||
}
|
||||
secp256k1_scalar_inner_product(&h_c, c_vec, 0 /* a_offset */ , s_h, 0 /* b_offset */, 1 /* step */, h_len);
|
||||
/* Compute v = n*n*q_f + l*h_c where q_f = r_f^2 */
|
||||
secp256k1_scalar_sqr(&q_f, &r_f);
|
||||
secp256k1_scalar_mul(&v, &n, &n);
|
||||
secp256k1_scalar_mul(&v, &v, &q_f);
|
||||
secp256k1_scalar_add(&v, &v, &h_c);
|
||||
|
||||
{
|
||||
ec_mult_verify_cb_data1 data;
|
||||
data.proof = proof;
|
||||
data.commit = commit;
|
||||
data.challenges = es;
|
||||
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res1, NULL, ec_mult_verify_cb1, &data, 2*n_rounds + 1)) {
|
||||
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
ec_mult_verify_cb_data2 data;
|
||||
data.g_vec = g_vec->gens;
|
||||
data.g_vec_len = g_len;
|
||||
data.s_g = s_g;
|
||||
data.s_h = s_h;
|
||||
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res2, &v, ec_mult_verify_cb2, &data, g_len + h_len)) {
|
||||
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
|
||||
|
||||
/* res1 and res2 should be equal. Could not find a simpler way to compare them */
|
||||
secp256k1_gej_neg(&res1, &res1);
|
||||
secp256k1_gej_add_var(&res1, &res1, &res2, NULL);
|
||||
return secp256k1_gej_is_infinity(&res1);
|
||||
}
|
||||
#endif
|
40
src/modules/bppp/bppp_transcript_impl.h
Normal file
40
src/modules/bppp/bppp_transcript_impl.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2022 Sanket Kanjalkar *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
#ifndef _SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_
|
||||
#define _SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "bppp_util.h"
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("Bulletproofs_pp/v0/commitment")||SHA256("Bulletproofs_pp/v0/commitment").
|
||||
*/
|
||||
static void secp256k1_bppp_sha256_tagged_commitment_init(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x52fc8185ul;
|
||||
sha->s[1] = 0x0e7debf0ul;
|
||||
sha->s[2] = 0xb0967270ul;
|
||||
sha->s[3] = 0x6f5abfe1ul;
|
||||
sha->s[4] = 0x822bdec0ul;
|
||||
sha->s[5] = 0x36db8beful;
|
||||
sha->s[6] = 0x03d9e1f1ul;
|
||||
sha->s[7] = 0x8a5cef6ful;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Obtain a challenge scalar from the current transcript.*/
|
||||
static void secp256k1_bppp_challenge_scalar(secp256k1_scalar* ch, const secp256k1_sha256 *transcript, uint64_t idx) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256 sha = *transcript;
|
||||
secp256k1_bppp_le64(buf, idx);
|
||||
secp256k1_sha256_write(&sha, buf, 8);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_scalar_set_b32(ch, buf, NULL);
|
||||
}
|
||||
|
||||
#endif
|
57
src/modules/bppp/bppp_util.h
Normal file
57
src/modules/bppp/bppp_util.h
Normal file
@ -0,0 +1,57 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 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_BPPP_UTIL_
|
||||
#define _SECP256K1_MODULE_BPPP_UTIL_
|
||||
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "hash.h"
|
||||
#include "eckey.h"
|
||||
|
||||
/* Outputs a pair of points, amortizing the parity byte between them
|
||||
* Assumes both points' coordinates have been normalized.
|
||||
*/
|
||||
static void secp256k1_bppp_serialize_points(unsigned char *output, const secp256k1_ge *lpt, const secp256k1_ge *rpt) {
|
||||
output[0] = (secp256k1_fe_is_odd(&lpt->y) << 1) + secp256k1_fe_is_odd(&rpt->y);
|
||||
secp256k1_fe_get_b32(&output[1], &lpt->x);
|
||||
secp256k1_fe_get_b32(&output[33], &rpt->x);
|
||||
}
|
||||
|
||||
/* Outputs a serialized point in compressed form. Returns 0 at point at infinity.
|
||||
*/
|
||||
static int secp256k1_bppp_serialize_pt(unsigned char *output, secp256k1_ge *lpt) {
|
||||
size_t size;
|
||||
return secp256k1_eckey_pubkey_serialize(lpt, output, &size, 1 /*compressed*/);
|
||||
}
|
||||
|
||||
/* little-endian encodes a uint64 */
|
||||
static void secp256k1_bppp_le64(unsigned char *output, const uint64_t n) {
|
||||
output[0] = n;
|
||||
output[1] = n >> 8;
|
||||
output[2] = n >> 16;
|
||||
output[3] = n >> 24;
|
||||
output[4] = n >> 32;
|
||||
output[5] = n >> 40;
|
||||
output[6] = n >> 48;
|
||||
output[7] = n >> 56;
|
||||
}
|
||||
|
||||
/* Check if n is power of two*/
|
||||
static int secp256k1_is_power_of_two(size_t n) {
|
||||
return n > 0 && (n & (n - 1)) == 0;
|
||||
}
|
||||
|
||||
/* Compute the log2 of n. n must NOT be 0. If n is not a power of two, it
|
||||
* returns the largest `k` such that 2^k <= n. Assumes 0 < n < 2^64. In
|
||||
* Bulletproofs, this is bounded by len of input vectors which can be safely
|
||||
* assumed to be less than 2^64.
|
||||
*/
|
||||
static size_t secp256k1_bppp_log2(size_t n) {
|
||||
return 64 - 1 - secp256k1_clz64_var((uint64_t)n);
|
||||
}
|
||||
|
||||
#endif
|
13
src/modules/bppp/main.h
Normal file
13
src/modules/bppp/main.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef SECP256K1_MODULE_BPPP_MAIN_H
|
||||
#define SECP256K1_MODULE_BPPP_MAIN_H
|
||||
|
||||
/* this type must be completed before any of the modules/bppp includes */
|
||||
struct secp256k1_bppp_generators {
|
||||
size_t n;
|
||||
/* n total generators; includes both G_i and H_i */
|
||||
/* For BP++, the generators are G_i from [0..(n - 8)] and the last 8 values
|
||||
are generators are for H_i */
|
||||
secp256k1_ge* gens;
|
||||
};
|
||||
|
||||
#endif
|
115
src/modules/bppp/main_impl.h
Normal file
115
src/modules/bppp/main_impl.h
Normal file
@ -0,0 +1,115 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 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_BPPP_MAIN_
|
||||
#define _SECP256K1_MODULE_BPPP_MAIN_
|
||||
|
||||
#include "include/secp256k1_bppp.h"
|
||||
#include "include/secp256k1_generator.h"
|
||||
#include "modules/generator/main_impl.h" /* for generator_{load, save} */
|
||||
#include "hash.h"
|
||||
#include "util.h"
|
||||
#include "modules/bppp/main.h"
|
||||
#include "modules/bppp/bppp_norm_product_impl.h"
|
||||
|
||||
secp256k1_bppp_generators *secp256k1_bppp_generators_create(const secp256k1_context *ctx, size_t n) {
|
||||
secp256k1_bppp_generators *ret;
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
unsigned char seed[64];
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
||||
ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
|
||||
if (ret->gens == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->n = n;
|
||||
|
||||
secp256k1_fe_get_b32(&seed[0], &secp256k1_ge_const_g.x);
|
||||
secp256k1_fe_get_b32(&seed[32], &secp256k1_ge_const_g.y);
|
||||
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed, 64);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_generator gen;
|
||||
unsigned char tmp[32] = { 0 };
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
CHECK(secp256k1_generator_generate(ctx, &gen, tmp));
|
||||
secp256k1_generator_load(&ret->gens[i], &gen);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
secp256k1_bppp_generators* secp256k1_bppp_generators_parse(const secp256k1_context* ctx, const unsigned char* data, size_t data_len) {
|
||||
size_t n = data_len / 33;
|
||||
secp256k1_bppp_generators* ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(data != NULL);
|
||||
|
||||
if (data_len % 33 != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret->n = n;
|
||||
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
|
||||
if (ret->gens == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
secp256k1_generator gen;
|
||||
if (!secp256k1_generator_parse(ctx, &gen, &data[33 * n])) {
|
||||
free(ret->gens);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
secp256k1_generator_load(&ret->gens[n], &gen);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_bppp_generators_serialize(const secp256k1_context* ctx, const secp256k1_bppp_generators* gens, unsigned char* data, size_t *data_len) {
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gens != NULL);
|
||||
ARG_CHECK(data != NULL);
|
||||
ARG_CHECK(data_len != NULL);
|
||||
ARG_CHECK(*data_len >= 33 * gens->n);
|
||||
|
||||
memset(data, 0, *data_len);
|
||||
for (i = 0; i < gens->n; i++) {
|
||||
secp256k1_generator gen;
|
||||
secp256k1_generator_save(&gen, &gens->gens[i]);
|
||||
secp256k1_generator_serialize(ctx, &data[33 * i], &gen);
|
||||
}
|
||||
|
||||
*data_len = 33 * gens->n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void secp256k1_bppp_generators_destroy(const secp256k1_context* ctx, secp256k1_bppp_generators *gens) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
(void) ctx;
|
||||
if (gens != NULL) {
|
||||
free(gens->gens);
|
||||
free(gens);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
65
src/modules/bppp/test_vectors/verify.h
Normal file
65
src/modules/bppp/test_vectors/verify.h
Normal file
@ -0,0 +1,65 @@
|
||||
static const unsigned char verify_vector_gens[264] = { 0x03, 0xAF, 0x2C, 0x40, 0xAD, 0x03, 0xCD, 0xC5, 0x76, 0x8C, 0x07, 0x1E, 0x58, 0xD6, 0x8C, 0x73, 0x45, 0xBA, 0xEB, 0xB5, 0x3F, 0x40, 0xFA, 0x8B, 0xBF, 0x73, 0x6E, 0x7B, 0x4A, 0x54, 0x06, 0xED, 0x32, 0x03, 0xCC, 0x11, 0x19, 0x22, 0x2C, 0xA1, 0x0A, 0x45, 0x23, 0xAF, 0x9B, 0x40, 0x0D, 0xA4, 0x5E, 0x06, 0x24, 0xF4, 0x5F, 0x07, 0x89, 0x88, 0xCD, 0x71, 0xAE, 0x77, 0xC1, 0xF5, 0x87, 0x4E, 0xFC, 0xA5, 0x03, 0xDE, 0x61, 0xB1, 0x8F, 0x2C, 0xAC, 0x18, 0xF5, 0xE4, 0x06, 0x8F, 0x65, 0x55, 0xA1, 0x30, 0x5E, 0xF5, 0xF4, 0x84, 0xED, 0x6B, 0xDD, 0xC2, 0xCC, 0xE8, 0x51, 0x38, 0xB8, 0xA5, 0x4C, 0x43, 0xBD, 0x02, 0xA5, 0xF9, 0x8C, 0x1F, 0x82, 0x2D, 0xC6, 0xF3, 0x0F, 0x53, 0xDB, 0x74, 0x77, 0xC7, 0x91, 0x04, 0xB0, 0xB1, 0xA6, 0x17, 0xB2, 0x91, 0xF4, 0x8B, 0x93, 0x3E, 0xBB, 0x73, 0x15, 0x3E, 0x5A, 0xD1, 0x02, 0x44, 0xF5, 0xC6, 0x4E, 0x77, 0x60, 0x81, 0x83, 0xFF, 0xC2, 0x8E, 0x06, 0xFE, 0x67, 0x0C, 0x9A, 0x4B, 0xF2, 0x34, 0xB9, 0xEA, 0xE9, 0x37, 0xDA, 0x30, 0xE2, 0x32, 0x27, 0xF3, 0x88, 0x5F, 0x2A, 0x02, 0x1D, 0x49, 0x5D, 0x04, 0xED, 0x61, 0x95, 0x37, 0xDD, 0x95, 0xB1, 0x4F, 0x64, 0x0E, 0x1E, 0xFB, 0x47, 0x9F, 0xA7, 0xD7, 0xE0, 0x7A, 0xB1, 0x02, 0x81, 0x95, 0xD1, 0xA5, 0x7E, 0xB2, 0x74, 0x8F, 0x03, 0x26, 0xA5, 0xEC, 0xE9, 0x71, 0x46, 0x37, 0xAC, 0x3D, 0x74, 0x84, 0x26, 0xCB, 0x7C, 0xE8, 0xFE, 0x4E, 0xB0, 0x6D, 0x70, 0x3D, 0x00, 0x10, 0x1A, 0x3A, 0x5B, 0xB8, 0xAA, 0x29, 0x59, 0x93, 0x15, 0x03, 0xE1, 0xA5, 0x39, 0x44, 0x75, 0x16, 0x28, 0x5F, 0xBA, 0x69, 0xA2, 0x4A, 0x2A, 0xC3, 0x5B, 0x63, 0x1F, 0x40, 0x10, 0x36, 0xF9, 0x4C, 0xD2, 0x76, 0x0F, 0xCF, 0x7F, 0x50, 0x30, 0x6E, 0x2B, 0x1D };
|
||||
static const unsigned char verify_vector_0_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
|
||||
static const size_t verify_vector_0_n_vec_len = 1;
|
||||
static const unsigned char verify_vector_0_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_0_c_vec[1];
|
||||
static const unsigned char verify_vector_0_r32[32] = { 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, 0x3A };
|
||||
static const unsigned char verify_vector_0_proof[] = { 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, 0x3F, 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, 0x3E };
|
||||
static const int verify_vector_0_result = 1;
|
||||
static const unsigned char verify_vector_1_commit33[33] = { 0x02, 0x6C, 0x09, 0xD7, 0x06, 0x2D, 0x1C, 0x07, 0x0A, 0x64, 0x34, 0x82, 0xF6, 0x46, 0x03, 0xEB, 0x24, 0x3E, 0x54, 0x0F, 0xDA, 0xAF, 0x3A, 0x69, 0x5F, 0x86, 0xB6, 0xD2, 0xC2, 0x06, 0xE9, 0x49, 0xC7 };
|
||||
static const size_t verify_vector_1_n_vec_len = 1;
|
||||
static const unsigned char verify_vector_1_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_1_c_vec[1];
|
||||
static const unsigned char verify_vector_1_r32[32] = { 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, 0x3A };
|
||||
static const unsigned char verify_vector_1_proof[] = { 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, 0x3F, 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, 0x3E };
|
||||
static const int verify_vector_1_result = 0;
|
||||
static const unsigned char verify_vector_2_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
|
||||
static const size_t verify_vector_2_n_vec_len = 1;
|
||||
static const unsigned char verify_vector_2_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_2_c_vec[1];
|
||||
static const unsigned char verify_vector_2_r32[32] = { 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, 0x3A };
|
||||
static const unsigned char verify_vector_2_proof[] = { 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, 0x3F, 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 };
|
||||
static const int verify_vector_2_result = 0;
|
||||
static const unsigned char verify_vector_3_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
|
||||
static const size_t verify_vector_3_n_vec_len = 1;
|
||||
static const unsigned char verify_vector_3_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_3_c_vec[1];
|
||||
static const unsigned char verify_vector_3_r32[32] = { 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, 0x3A };
|
||||
static const unsigned char verify_vector_3_proof[] = { 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, 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 };
|
||||
static const int verify_vector_3_result = 0;
|
||||
static const unsigned char verify_vector_4_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
|
||||
static const size_t verify_vector_4_n_vec_len = 1;
|
||||
static const unsigned char verify_vector_4_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_4_c_vec[1];
|
||||
static const unsigned char verify_vector_4_r32[32] = { 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, 0x3A };
|
||||
static const unsigned char verify_vector_4_proof[] = { 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, 0x3F, 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 };
|
||||
static const int verify_vector_4_result = 0;
|
||||
static const unsigned char verify_vector_5_commit33[33] = { 0x03, 0x83, 0x6A, 0xD4, 0x2D, 0xD2, 0x02, 0x49, 0xC8, 0x6E, 0x53, 0x22, 0x53, 0x24, 0xDA, 0x52, 0x08, 0xC0, 0x62, 0x4C, 0xCB, 0xB3, 0x13, 0xD7, 0x14, 0x59, 0x68, 0x47, 0x56, 0x00, 0xC0, 0x8D, 0xBA };
|
||||
static const size_t verify_vector_5_n_vec_len = 2;
|
||||
static const unsigned char verify_vector_5_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_5_c_vec[1];
|
||||
static const unsigned char verify_vector_5_r32[32] = { 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, 0x36 };
|
||||
static const unsigned char verify_vector_5_proof[] = { 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, 0x05, 0x4C, 0xB9, 0xD4, 0x34, 0xA2, 0xD6, 0xD5, 0x4C, 0x0F, 0x2E, 0x2C, 0xE3, 0x82, 0x17, 0x48, 0x63, 0xE0, 0xAE, 0x6B, 0xD7, 0x64, 0x9D, 0x43, 0x2B, 0x6E, 0x6E, 0x1C, 0x62, 0x55, 0x4B, 0xC5, 0x73, 0x3D, 0x74, 0x7B, 0x78, 0x43, 0xF4, 0x8B, 0x7C, 0x84, 0x10, 0x00, 0x8B, 0x12, 0xAF, 0xA4, 0xF1, 0xF4, 0x01, 0x96, 0x21, 0x8B, 0xE9, 0x05, 0x01, 0xF8, 0x23, 0x7A, 0x8F, 0x66, 0xC9, 0xDE, 0xE1, 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, 0x3E };
|
||||
static const int verify_vector_5_result = 0;
|
||||
static const unsigned char verify_vector_6_commit33[33] = { 0x03, 0xCF, 0x7F, 0x08, 0xF5, 0x8A, 0x06, 0x74, 0x5C, 0xDB, 0xCE, 0xC6, 0x51, 0xF3, 0xE5, 0xE4, 0xDC, 0xAD, 0xF4, 0x40, 0x3C, 0xFA, 0xE6, 0x78, 0xBE, 0x49, 0x2D, 0x90, 0xC8, 0xD0, 0x16, 0x3D, 0x78 };
|
||||
static const size_t verify_vector_6_n_vec_len = 2;
|
||||
static const unsigned char verify_vector_6_c_vec32[4][32] = { { 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, 0x3C }, { 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, 0x03 }, { 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, 0x30 }, { 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, 0x0D } };
|
||||
static secp256k1_scalar verify_vector_6_c_vec[4];
|
||||
static const unsigned char verify_vector_6_r32[32] = { 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, 0x3A };
|
||||
static const unsigned char verify_vector_6_proof[] = { 0x00, 0xD2, 0xEC, 0xE2, 0x53, 0x97, 0x28, 0x68, 0x22, 0x59, 0x34, 0xEF, 0xE4, 0x7B, 0x87, 0x4D, 0xE9, 0x57, 0xD5, 0xB7, 0xC7, 0x72, 0xF4, 0xC9, 0xEA, 0x66, 0x14, 0x59, 0xE1, 0xA9, 0xD5, 0xB2, 0x10, 0xDF, 0xE2, 0xFF, 0xF5, 0xA4, 0x38, 0x6B, 0xFE, 0x36, 0x89, 0xE4, 0x9D, 0x90, 0x9F, 0x71, 0x19, 0xE6, 0xA3, 0x1E, 0xAA, 0xAA, 0x4E, 0xFE, 0xC2, 0xD3, 0x37, 0xBB, 0xDE, 0xDB, 0x46, 0x43, 0xC2, 0x01, 0x42, 0x5F, 0xFC, 0xC6, 0x25, 0xA0, 0xB4, 0xF0, 0x76, 0x99, 0xF4, 0x7C, 0xE9, 0x83, 0x82, 0xED, 0x7C, 0x95, 0xBA, 0xD0, 0xE6, 0x5B, 0x88, 0xFD, 0x38, 0xEA, 0x23, 0x54, 0xD4, 0xBD, 0xD4, 0x37, 0xB8, 0x2B, 0x49, 0xAF, 0x81, 0xFD, 0xBE, 0x88, 0xB2, 0xE5, 0x3F, 0xF4, 0x30, 0x52, 0x00, 0x63, 0x9D, 0xAE, 0x82, 0x44, 0xE9, 0x62, 0x87, 0x2A, 0x23, 0x89, 0x10, 0xE4, 0x9A, 0x64, 0x9F, 0x71, 0xD9, 0x32, 0x57, 0x3B, 0xCB, 0xAC, 0x30, 0xAE, 0x71, 0x61, 0xE9, 0x50, 0x1F, 0xCB, 0x49, 0x9C, 0x52, 0xBA, 0x0C, 0xC4, 0x00, 0x58, 0x73, 0x63, 0xD3, 0x42, 0xDE, 0x42, 0x5E, 0xC5, 0x97, 0xE5, 0xDA, 0x88, 0x76, 0x49, 0x6C, 0x8B, 0x92, 0x99, 0xEE, 0xD0, 0xA9, 0xEB, 0x6E, 0xCA, 0xE1, 0x93, 0x81, 0x56, 0x2E, 0xCA, 0xF3, 0x8E, 0xF0, 0x04, 0xD2, 0x96, 0xD8, 0xDB, 0xEE, 0xEE, 0x1C, 0x44 };
|
||||
static const int verify_vector_6_result = 1;
|
||||
static const unsigned char verify_vector_7_commit33[33] = { 0x02, 0x7A, 0xAA, 0xB2, 0x7E, 0xA5, 0x5B, 0x77, 0x08, 0xE5, 0x43, 0xB6, 0x22, 0x7F, 0xC9, 0xAC, 0x53, 0x10, 0x32, 0x61, 0x7B, 0x7D, 0xAC, 0xB1, 0xB6, 0xF6, 0xAC, 0xDE, 0x63, 0x79, 0x82, 0x9C, 0x24 };
|
||||
static const size_t verify_vector_7_n_vec_len = 4;
|
||||
static const unsigned char verify_vector_7_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_7_c_vec[1];
|
||||
static const unsigned char verify_vector_7_r32[32] = { 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, 0x34 };
|
||||
static const unsigned char verify_vector_7_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 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, 0x3E };
|
||||
static const int verify_vector_7_result = 1;
|
||||
static const unsigned char verify_vector_8_commit33[33] = { 0x02, 0x2D, 0x4F, 0xF9, 0xB7, 0x15, 0x22, 0xBC, 0xB0, 0x8B, 0xF8, 0xBA, 0x31, 0x0A, 0x80, 0x76, 0x7A, 0xE9, 0xA9, 0x83, 0x00, 0xBC, 0x5A, 0x01, 0xCC, 0xE9, 0x00, 0x83, 0x56, 0xEA, 0x77, 0xEB, 0x75 };
|
||||
static const size_t verify_vector_8_n_vec_len = 4;
|
||||
static const unsigned char verify_vector_8_c_vec32[1][32] = { { 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, 0x3C } };
|
||||
static secp256k1_scalar verify_vector_8_c_vec[1];
|
||||
static const unsigned char verify_vector_8_r32[32] = { 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, 0x34 };
|
||||
static const unsigned char verify_vector_8_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 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, 0x3E };
|
||||
static const int verify_vector_8_result = 0;
|
||||
|
584
src/modules/bppp/tests_impl.h
Normal file
584
src/modules/bppp/tests_impl.h
Normal file
@ -0,0 +1,584 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 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_BPPP_TEST_
|
||||
#define _SECP256K1_MODULE_BPPP_TEST_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "include/secp256k1_bppp.h"
|
||||
#include "bppp_norm_product_impl.h"
|
||||
#include "bppp_util.h"
|
||||
#include "bppp_transcript_impl.h"
|
||||
#include "test_vectors/verify.h"
|
||||
|
||||
static void test_bppp_generators_api(void) {
|
||||
/* The BP generator API requires no precomp */
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
secp256k1_bppp_generators *gens;
|
||||
secp256k1_bppp_generators *gens_orig;
|
||||
unsigned char gens_ser[330];
|
||||
size_t len = sizeof(gens_ser);
|
||||
|
||||
int32_t ecount = 0;
|
||||
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
/* Create */
|
||||
gens = secp256k1_bppp_generators_create(none, 10);
|
||||
CHECK(gens != NULL && ecount == 0);
|
||||
gens_orig = gens; /* Preserve for round-trip test */
|
||||
|
||||
/* Serialize */
|
||||
ecount = 0;
|
||||
CHECK(!secp256k1_bppp_generators_serialize(none, NULL, gens_ser, &len));
|
||||
CHECK(ecount == 1);
|
||||
CHECK(!secp256k1_bppp_generators_serialize(none, gens, NULL, &len));
|
||||
CHECK(ecount == 2);
|
||||
CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, NULL));
|
||||
CHECK(ecount == 3);
|
||||
len = 0;
|
||||
CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
|
||||
CHECK(ecount == 4);
|
||||
len = sizeof(gens_ser) - 1;
|
||||
CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
|
||||
CHECK(ecount == 5);
|
||||
len = sizeof(gens_ser);
|
||||
{
|
||||
/* Output buffer can be greater than minimum needed */
|
||||
unsigned char gens_ser_tmp[331];
|
||||
size_t len_tmp = sizeof(gens_ser_tmp);
|
||||
CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser_tmp, &len_tmp));
|
||||
CHECK(len_tmp == sizeof(gens_ser_tmp) - 1);
|
||||
CHECK(ecount == 5);
|
||||
}
|
||||
|
||||
/* Parse */
|
||||
CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
|
||||
ecount = 0;
|
||||
gens = secp256k1_bppp_generators_parse(none, NULL, sizeof(gens_ser));
|
||||
CHECK(gens == NULL && ecount == 1);
|
||||
/* Not a multiple of 33 */
|
||||
gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser) - 1);
|
||||
CHECK(gens == NULL && ecount == 1);
|
||||
gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser));
|
||||
CHECK(gens != NULL && ecount == 1);
|
||||
/* Not valid generators */
|
||||
memset(gens_ser, 1, sizeof(gens_ser));
|
||||
CHECK(secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser)) == NULL);
|
||||
CHECK(ecount == 1);
|
||||
|
||||
/* Check that round-trip succeeded */
|
||||
CHECK(gens->n == gens_orig->n);
|
||||
for (len = 0; len < gens->n; len++) {
|
||||
ge_equals_ge(&gens->gens[len], &gens_orig->gens[len]);
|
||||
}
|
||||
|
||||
/* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */
|
||||
ecount = 0;
|
||||
secp256k1_bppp_generators_destroy(none, NULL);
|
||||
secp256k1_bppp_generators_destroy(none, gens);
|
||||
secp256k1_bppp_generators_destroy(none, gens_orig);
|
||||
CHECK(ecount == 0);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
}
|
||||
|
||||
static void test_bppp_generators_fixed(void) {
|
||||
secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(ctx, 3);
|
||||
unsigned char gens_ser[330];
|
||||
const unsigned char fixed_first_3[99] = {
|
||||
0x0b,
|
||||
0xb3, 0x4d, 0x5f, 0xa6, 0xb8, 0xf3, 0xd1, 0x38,
|
||||
0x49, 0xce, 0x51, 0x91, 0xb7, 0xf6, 0x76, 0x18,
|
||||
0xfe, 0x5b, 0xd1, 0x2a, 0x88, 0xb2, 0x0e, 0xac,
|
||||
0x33, 0x89, 0x45, 0x66, 0x7f, 0xb3, 0x30, 0x56,
|
||||
0x0a,
|
||||
0x62, 0x86, 0x15, 0x16, 0x92, 0x42, 0x10, 0x9e,
|
||||
0x9e, 0x64, 0xd4, 0xcb, 0x28, 0x81, 0x60, 0x9c,
|
||||
0x24, 0xb9, 0x89, 0x51, 0x2a, 0xd9, 0x01, 0xae,
|
||||
0xff, 0x75, 0x64, 0x9c, 0x37, 0x5d, 0xbd, 0x79,
|
||||
0x0a,
|
||||
0xed, 0xe0, 0x6e, 0x07, 0x5e, 0x79, 0xd0, 0xf7,
|
||||
0x7b, 0x03, 0x3e, 0xb9, 0xa9, 0x21, 0xa4, 0x5b,
|
||||
0x99, 0xf3, 0x9b, 0xee, 0xfe, 0xa0, 0x37, 0xa2,
|
||||
0x1f, 0xe9, 0xd7, 0x4f, 0x95, 0x8b, 0x10, 0xe2,
|
||||
};
|
||||
size_t len;
|
||||
|
||||
len = 99;
|
||||
CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len));
|
||||
CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
|
||||
|
||||
len = sizeof(gens_ser);
|
||||
CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len));
|
||||
CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
|
||||
|
||||
secp256k1_bppp_generators_destroy(ctx, gens);
|
||||
}
|
||||
|
||||
static void test_bppp_tagged_hash(void) {
|
||||
unsigned char tag_data[29] = "Bulletproofs_pp/v0/commitment";
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256 sha_cached;
|
||||
unsigned char output[32];
|
||||
unsigned char output_cached[32];
|
||||
secp256k1_scalar s;
|
||||
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data));
|
||||
secp256k1_bppp_sha256_tagged_commitment_init(&sha_cached);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_finalize(&sha_cached, output_cached);
|
||||
CHECK(secp256k1_memcmp_var(output, output_cached, 32) == 0);
|
||||
|
||||
{
|
||||
unsigned char expected[32] = { 0x21, 0x2F, 0xB6, 0x4F, 0x9D, 0x8C, 0x3B, 0xC5,
|
||||
0xF6, 0x91, 0x15, 0xEE, 0x74, 0xF5, 0x12, 0x67,
|
||||
0x8A, 0x41, 0xC6, 0x85, 0x1A, 0x79, 0x14, 0xFC,
|
||||
0x48, 0x15, 0xC7, 0x2D, 0xF8, 0x63, 0x8F, 0x1B };
|
||||
secp256k1_bppp_sha256_tagged_commitment_init(&sha);
|
||||
secp256k1_bppp_challenge_scalar(&s, &sha, 0);
|
||||
secp256k1_scalar_get_b32(output, &s);
|
||||
CHECK(memcmp(output, expected, sizeof(output)) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char tmp[3] = {0, 1, 2};
|
||||
unsigned char expected[32] = { 0x8D, 0xAA, 0xB7, 0x7E, 0x3C, 0x6A, 0x9E, 0xEC,
|
||||
0x72, 0x7E, 0x3E, 0xB7, 0x10, 0x03, 0xF0, 0xE9,
|
||||
0x69, 0x4D, 0xAA, 0x96, 0xCE, 0x98, 0xBB, 0x39,
|
||||
0x1C, 0x2F, 0x7C, 0x2E, 0x1C, 0x17, 0x78, 0x6D };
|
||||
secp256k1_sha256_write(&sha, tmp, sizeof(tmp));
|
||||
secp256k1_bppp_challenge_scalar(&s, &sha, 0);
|
||||
secp256k1_scalar_get_b32(output, &s);
|
||||
CHECK(memcmp(output, expected, sizeof(output)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void test_log_exp(void) {
|
||||
CHECK(secp256k1_is_power_of_two(0) == 0);
|
||||
CHECK(secp256k1_is_power_of_two(1) == 1);
|
||||
CHECK(secp256k1_is_power_of_two(2) == 1);
|
||||
CHECK(secp256k1_is_power_of_two(64) == 1);
|
||||
CHECK(secp256k1_is_power_of_two(63) == 0);
|
||||
CHECK(secp256k1_is_power_of_two(256) == 1);
|
||||
|
||||
CHECK(secp256k1_bppp_log2(1) == 0);
|
||||
CHECK(secp256k1_bppp_log2(2) == 1);
|
||||
CHECK(secp256k1_bppp_log2(255) == 7);
|
||||
CHECK(secp256k1_bppp_log2(256) == 8);
|
||||
CHECK(secp256k1_bppp_log2(257) == 8);
|
||||
}
|
||||
|
||||
void test_norm_util_helpers(void) {
|
||||
secp256k1_scalar a_vec[4], b_vec[4], r_pows[4], res, res2, q, r;
|
||||
int i;
|
||||
/* a = {1, 2, 3, 4} b = {5, 6, 7, 8}, q = 4, r = 2 */
|
||||
for (i = 0; i < 4; i++) {
|
||||
secp256k1_scalar_set_int(&a_vec[i], i + 1);
|
||||
secp256k1_scalar_set_int(&b_vec[i], i + 5);
|
||||
}
|
||||
secp256k1_scalar_set_int(&q, 4);
|
||||
secp256k1_scalar_set_int(&r, 2);
|
||||
secp256k1_scalar_inner_product(&res, a_vec, 0, b_vec, 0, 1, 4);
|
||||
secp256k1_scalar_set_int(&res2, 70);
|
||||
CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
|
||||
|
||||
secp256k1_scalar_inner_product(&res, a_vec, 0, b_vec, 1, 2, 2);
|
||||
secp256k1_scalar_set_int(&res2, 30);
|
||||
CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
|
||||
|
||||
secp256k1_scalar_inner_product(&res, a_vec, 1, b_vec, 0, 2, 2);
|
||||
secp256k1_scalar_set_int(&res2, 38);
|
||||
CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
|
||||
|
||||
secp256k1_scalar_inner_product(&res, a_vec, 1, b_vec, 1, 2, 2);
|
||||
secp256k1_scalar_set_int(&res2, 44);
|
||||
CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
|
||||
|
||||
secp256k1_weighted_scalar_inner_product(&res, a_vec, 0, a_vec, 0, 1, 4, &q);
|
||||
secp256k1_scalar_set_int(&res2, 4740); /*i*i*4^(i+1) */
|
||||
CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
|
||||
|
||||
secp256k1_bppp_powers_of_r(r_pows, &r, 4);
|
||||
secp256k1_scalar_set_int(&res, 2); CHECK(secp256k1_scalar_eq(&res, &r_pows[0]));
|
||||
secp256k1_scalar_set_int(&res, 4); CHECK(secp256k1_scalar_eq(&res, &r_pows[1]));
|
||||
secp256k1_scalar_set_int(&res, 16); CHECK(secp256k1_scalar_eq(&res, &r_pows[2]));
|
||||
secp256k1_scalar_set_int(&res, 256); CHECK(secp256k1_scalar_eq(&res, &r_pows[3]));
|
||||
}
|
||||
|
||||
static void secp256k1_norm_arg_commit_initial_data(
|
||||
secp256k1_sha256* transcript,
|
||||
const secp256k1_scalar* r,
|
||||
const secp256k1_bppp_generators* gens_vec,
|
||||
size_t g_len, /* Same as n_vec_len, g_len + c_vec_len = gens->n */
|
||||
const secp256k1_scalar* c_vec,
|
||||
size_t c_vec_len,
|
||||
const secp256k1_ge* commit
|
||||
) {
|
||||
/* Commit to the initial public values */
|
||||
unsigned char ser_commit[33], ser_scalar[32], ser_le64[8];
|
||||
size_t i;
|
||||
secp256k1_ge comm = *commit;
|
||||
secp256k1_bppp_sha256_tagged_commitment_init(transcript);
|
||||
secp256k1_fe_normalize(&comm.x);
|
||||
secp256k1_fe_normalize(&comm.y);
|
||||
CHECK(secp256k1_ge_is_infinity(&comm) == 0);
|
||||
CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &comm));
|
||||
secp256k1_sha256_write(transcript, ser_commit, 33);
|
||||
secp256k1_scalar_get_b32(ser_scalar, r);
|
||||
secp256k1_sha256_write(transcript, ser_scalar, 32);
|
||||
secp256k1_bppp_le64(ser_le64, g_len);
|
||||
secp256k1_sha256_write(transcript, ser_le64, 8);
|
||||
secp256k1_bppp_le64(ser_le64, gens_vec->n);
|
||||
secp256k1_sha256_write(transcript, ser_le64, 8);
|
||||
for (i = 0; i < gens_vec->n; i++) {
|
||||
secp256k1_fe_normalize(&gens_vec->gens[i].x);
|
||||
secp256k1_fe_normalize(&gens_vec->gens[i].y);
|
||||
CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &gens_vec->gens[i]));
|
||||
secp256k1_sha256_write(transcript, ser_commit, 33);
|
||||
}
|
||||
secp256k1_bppp_le64(ser_le64, c_vec_len);
|
||||
secp256k1_sha256_write(transcript, ser_le64, 8);
|
||||
for (i = 0; i < c_vec_len; i++) {
|
||||
secp256k1_scalar_get_b32(ser_scalar, &c_vec[i]);
|
||||
secp256k1_sha256_write(transcript, ser_scalar, 32);
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_vectors_into_scratch(secp256k1_scratch_space* scratch,
|
||||
secp256k1_scalar **ns,
|
||||
secp256k1_scalar **ls,
|
||||
secp256k1_scalar **cs,
|
||||
secp256k1_ge **gs,
|
||||
const secp256k1_scalar *n_vec,
|
||||
const secp256k1_scalar *l_vec,
|
||||
const secp256k1_scalar *c_vec,
|
||||
const secp256k1_ge *gens_vec,
|
||||
size_t g_len,
|
||||
size_t h_len) {
|
||||
*ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar));
|
||||
*ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
|
||||
*cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
|
||||
*gs = (secp256k1_ge*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, (g_len + h_len) * sizeof(secp256k1_ge));
|
||||
CHECK(ns != NULL && ls != NULL && cs != NULL && gs != NULL);
|
||||
memcpy(*ns, n_vec, g_len * sizeof(secp256k1_scalar));
|
||||
memcpy(*ls, l_vec, h_len * sizeof(secp256k1_scalar));
|
||||
memcpy(*cs, c_vec, h_len * sizeof(secp256k1_scalar));
|
||||
memcpy(*gs, gens_vec, (g_len + h_len) * sizeof(secp256k1_ge));
|
||||
}
|
||||
|
||||
/* A complete norm argument. In contrast to secp256k1_bppp_rangeproof_norm_product_prove, this is meant
|
||||
to be used as a standalone norm argument.
|
||||
This is a simple wrapper around secp256k1_bppp_rangeproof_norm_product_prove
|
||||
that also commits to the initial public values used in the protocol. In this case, these public
|
||||
values are commitment.
|
||||
*/
|
||||
static int secp256k1_norm_arg_prove(
|
||||
secp256k1_scratch_space* scratch,
|
||||
unsigned char* proof,
|
||||
size_t *proof_len,
|
||||
const secp256k1_scalar* r,
|
||||
const secp256k1_bppp_generators* gens_vec,
|
||||
const secp256k1_scalar* n_vec,
|
||||
size_t n_vec_len,
|
||||
const secp256k1_scalar* l_vec,
|
||||
size_t l_vec_len,
|
||||
const secp256k1_scalar* c_vec,
|
||||
size_t c_vec_len,
|
||||
const secp256k1_ge* commit
|
||||
) {
|
||||
secp256k1_scalar *ns, *ls, *cs;
|
||||
secp256k1_ge *gs, comm = *commit;
|
||||
size_t scratch_checkpoint;
|
||||
size_t g_len = n_vec_len, h_len = l_vec_len;
|
||||
int res;
|
||||
secp256k1_sha256 transcript;
|
||||
|
||||
scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
|
||||
|
||||
copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens_vec->gens, g_len, h_len);
|
||||
|
||||
/* Commit to the initial public values */
|
||||
secp256k1_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm);
|
||||
|
||||
res = secp256k1_bppp_rangeproof_norm_product_prove(
|
||||
ctx,
|
||||
scratch,
|
||||
proof,
|
||||
proof_len,
|
||||
&transcript, /* Transcript hash of the parent protocol */
|
||||
r,
|
||||
gs,
|
||||
gens_vec->n,
|
||||
ns,
|
||||
n_vec_len,
|
||||
ls,
|
||||
l_vec_len,
|
||||
cs,
|
||||
c_vec_len
|
||||
);
|
||||
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Verify the proof */
|
||||
static int secp256k1_norm_arg_verify(
|
||||
secp256k1_scratch_space* scratch,
|
||||
const unsigned char* proof,
|
||||
size_t proof_len,
|
||||
const secp256k1_scalar* r,
|
||||
const secp256k1_bppp_generators* gens_vec,
|
||||
size_t g_len,
|
||||
const secp256k1_scalar* c_vec,
|
||||
size_t c_vec_len,
|
||||
const secp256k1_ge* commit
|
||||
) {
|
||||
secp256k1_ge comm = *commit;
|
||||
int res;
|
||||
secp256k1_sha256 transcript;
|
||||
|
||||
/* Commit to the initial public values */
|
||||
secp256k1_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm);
|
||||
|
||||
res = secp256k1_bppp_rangeproof_norm_product_verify(
|
||||
ctx,
|
||||
scratch,
|
||||
proof,
|
||||
proof_len,
|
||||
&transcript,
|
||||
r,
|
||||
gens_vec,
|
||||
g_len,
|
||||
c_vec,
|
||||
c_vec_len,
|
||||
commit
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
void norm_arg_zero(void) {
|
||||
secp256k1_scalar n_vec[64], l_vec[64], c_vec[64];
|
||||
secp256k1_scalar r, q;
|
||||
secp256k1_ge commit;
|
||||
size_t i;
|
||||
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*10); /* shouldn't need much */
|
||||
unsigned char proof[1000];
|
||||
secp256k1_sha256 transcript;
|
||||
|
||||
random_scalar_order(&r);
|
||||
secp256k1_scalar_sqr(&q, &r);
|
||||
|
||||
/* l is zero vector and n is zero vectors of length 1 each. */
|
||||
{
|
||||
size_t plen = sizeof(proof);
|
||||
unsigned int n_vec_len = 1;
|
||||
unsigned int c_vec_len = 1;
|
||||
secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
|
||||
|
||||
secp256k1_scalar_set_int(&n_vec[0], 0);
|
||||
secp256k1_scalar_set_int(&l_vec[0], 0);
|
||||
random_scalar_order(&c_vec[0]);
|
||||
|
||||
secp256k1_sha256_initialize(&transcript); /* No challenges used in n = 1, l = 1, but we set transcript as a good practice*/
|
||||
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q));
|
||||
{
|
||||
secp256k1_scalar *ns, *ls, *cs;
|
||||
secp256k1_ge *gs;
|
||||
size_t scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
|
||||
copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens->gens, n_vec_len, c_vec_len);
|
||||
CHECK(secp256k1_bppp_rangeproof_norm_product_prove(ctx, scratch, proof, &plen, &transcript, &r, gs, gens->n, ns, n_vec_len, ls, c_vec_len, cs, c_vec_len));
|
||||
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
|
||||
}
|
||||
secp256k1_sha256_initialize(&transcript);
|
||||
CHECK(secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gens, c_vec_len, c_vec, c_vec_len, &commit));
|
||||
|
||||
secp256k1_bppp_generators_destroy(ctx, gens);
|
||||
}
|
||||
|
||||
/* l is the zero vector and longer than n. This results in one of the
|
||||
* internal commitments X or R to be the point at infinity. */
|
||||
{
|
||||
unsigned int n_vec_len = 1;
|
||||
unsigned int c_vec_len = 2;
|
||||
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
|
||||
size_t plen = sizeof(proof);
|
||||
for (i = 0; i < n_vec_len; i++) {
|
||||
random_scalar_order(&n_vec[i]);
|
||||
}
|
||||
for (i = 0; i < c_vec_len; i++) {
|
||||
secp256k1_scalar_set_int(&l_vec[i], 0);
|
||||
random_scalar_order(&c_vec[i]);
|
||||
}
|
||||
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q));
|
||||
CHECK(!secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
|
||||
secp256k1_bppp_generators_destroy(ctx, gs);
|
||||
}
|
||||
|
||||
/* Verify vectors of length 0 */
|
||||
{
|
||||
unsigned int n_vec_len = 1;
|
||||
unsigned int c_vec_len = 1;
|
||||
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
|
||||
size_t plen = sizeof(proof);
|
||||
random_scalar_order(&n_vec[0]);
|
||||
random_scalar_order(&c_vec[0]);
|
||||
random_scalar_order(&l_vec[0]);
|
||||
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q));
|
||||
CHECK(secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
|
||||
CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n_vec_len, c_vec, c_vec_len, &commit));
|
||||
CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, 0, c_vec, c_vec_len, &commit));
|
||||
CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n_vec_len, c_vec, 0, &commit));
|
||||
|
||||
secp256k1_bppp_generators_destroy(ctx, gs);
|
||||
}
|
||||
|
||||
secp256k1_scratch_space_destroy(ctx, scratch);
|
||||
}
|
||||
|
||||
void norm_arg_test(unsigned int n, unsigned int m) {
|
||||
secp256k1_scalar n_vec[64], l_vec[64], c_vec[64];
|
||||
secp256k1_scalar r, q;
|
||||
secp256k1_ge commit;
|
||||
size_t i, plen;
|
||||
int res;
|
||||
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n + m);
|
||||
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
|
||||
unsigned char proof[1000];
|
||||
plen = 1000;
|
||||
random_scalar_order(&r);
|
||||
secp256k1_scalar_sqr(&q, &r);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
random_scalar_order(&n_vec[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < m; i++) {
|
||||
random_scalar_order(&l_vec[i]);
|
||||
random_scalar_order(&c_vec[i]);
|
||||
}
|
||||
|
||||
res = secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &q);
|
||||
CHECK(res == 1);
|
||||
res = secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n, l_vec, m, c_vec, m, &commit);
|
||||
CHECK(res == 1);
|
||||
|
||||
res = secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit);
|
||||
CHECK(res == 1);
|
||||
|
||||
/* Changing any of last two scalars should break the proof */
|
||||
proof[plen - 1] ^= 1;
|
||||
res = secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit);
|
||||
CHECK(res == 0);
|
||||
proof[plen - 1 - 32] ^= 1;
|
||||
res = secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit);
|
||||
CHECK(res == 0);
|
||||
|
||||
secp256k1_scratch_space_destroy(ctx, scratch);
|
||||
secp256k1_bppp_generators_destroy(ctx, gs);
|
||||
}
|
||||
|
||||
/* Parses generators from points compressed as pubkeys */
|
||||
secp256k1_bppp_generators* bppp_generators_parse_regular(const unsigned char* data, size_t data_len) {
|
||||
size_t n = data_len / 33;
|
||||
secp256k1_bppp_generators* ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(data != NULL);
|
||||
|
||||
if (data_len % 33 != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret->n = n;
|
||||
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
|
||||
if (ret->gens == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
if (!secp256k1_eckey_pubkey_parse(&ret->gens[n], &data[33 * n], 33)) {
|
||||
free(ret->gens);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, size_t n_vec_len, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, const unsigned char *commit33) {
|
||||
secp256k1_sha256 transcript;
|
||||
secp256k1_bppp_generators *gs = bppp_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len));
|
||||
secp256k1_scalar r;
|
||||
secp256k1_ge commit;
|
||||
int overflow;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
CHECK(gs != NULL);
|
||||
secp256k1_sha256_initialize(&transcript);
|
||||
|
||||
secp256k1_scalar_set_b32(&r, r32, &overflow);
|
||||
CHECK(!overflow);
|
||||
|
||||
for (i = 0; i < (int)c_vec_len; i++) {
|
||||
secp256k1_scalar_set_b32(&c_vec[i], c_vec32[i], &overflow);
|
||||
CHECK(!overflow);
|
||||
}
|
||||
CHECK(secp256k1_eckey_pubkey_parse(&commit, commit33, 33));
|
||||
ret = secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gs, n_vec_len, c_vec, c_vec_len, &commit);
|
||||
|
||||
secp256k1_bppp_generators_destroy(ctx, gs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define IDX_TO_TEST(i) (norm_arg_verify_vectors_helper(scratch, verify_vector_gens, verify_vector_##i##_proof, sizeof(verify_vector_##i##_proof), verify_vector_##i##_r32, verify_vector_##i##_n_vec_len, verify_vector_##i##_c_vec32, verify_vector_##i##_c_vec, sizeof(verify_vector_##i##_c_vec)/sizeof(secp256k1_scalar), verify_vector_##i##_commit33) == verify_vector_##i##_result)
|
||||
|
||||
void norm_arg_verify_vectors(void) {
|
||||
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
|
||||
size_t alloc = scratch->alloc_size;
|
||||
|
||||
CHECK(IDX_TO_TEST(0));
|
||||
CHECK(IDX_TO_TEST(1));
|
||||
CHECK(IDX_TO_TEST(2));
|
||||
CHECK(IDX_TO_TEST(3));
|
||||
CHECK(IDX_TO_TEST(4));
|
||||
CHECK(IDX_TO_TEST(5));
|
||||
CHECK(IDX_TO_TEST(6));
|
||||
CHECK(IDX_TO_TEST(7));
|
||||
CHECK(IDX_TO_TEST(8));
|
||||
|
||||
CHECK(alloc == scratch->alloc_size);
|
||||
secp256k1_scratch_space_destroy(ctx, scratch);
|
||||
}
|
||||
#undef IDX_TO_TEST
|
||||
|
||||
void run_bppp_tests(void) {
|
||||
test_log_exp();
|
||||
test_norm_util_helpers();
|
||||
test_bppp_generators_api();
|
||||
test_bppp_generators_fixed();
|
||||
test_bppp_tagged_hash();
|
||||
|
||||
norm_arg_zero();
|
||||
norm_arg_test(1, 1);
|
||||
norm_arg_test(1, 64);
|
||||
norm_arg_test(64, 1);
|
||||
norm_arg_test(32, 32);
|
||||
norm_arg_test(32, 64);
|
||||
norm_arg_test(64, 32);
|
||||
norm_arg_test(64, 64);
|
||||
norm_arg_verify_vectors();
|
||||
}
|
||||
|
||||
#endif
|
@ -1,4 +1,6 @@
|
||||
include_HEADERS += include/secp256k1_generator.h
|
||||
noinst_HEADERS += src/modules/generator/pedersen.h
|
||||
noinst_HEADERS += src/modules/generator/pedersen_impl.h
|
||||
noinst_HEADERS += src/modules/generator/main_impl.h
|
||||
noinst_HEADERS += src/modules/generator/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
|
@ -14,6 +14,29 @@
|
||||
#include "../../hash.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
#include "modules/generator/pedersen_impl.h"
|
||||
|
||||
/** Alternative generator for secp256k1.
|
||||
* This is the sha256 of 'g' after standard encoding (without compression),
|
||||
* which happens to be a point on the curve. More precisely, the generator is
|
||||
* derived by running the following script with the sage mathematics software.
|
||||
|
||||
import hashlib
|
||||
F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
|
||||
G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
|
||||
H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16)))
|
||||
print('%x %x' % H.xy())
|
||||
*/
|
||||
static const secp256k1_generator secp256k1_generator_h_internal = {{
|
||||
0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e,
|
||||
0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0,
|
||||
0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a,
|
||||
0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04
|
||||
}};
|
||||
|
||||
const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal;
|
||||
|
||||
|
||||
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
|
||||
int succeed;
|
||||
succeed = secp256k1_fe_set_b32(&ge->x, &gen->data[0]);
|
||||
@ -219,4 +242,201 @@ int secp256k1_generator_generate_blinded(const secp256k1_context* ctx, secp256k1
|
||||
return secp256k1_generator_generate_internal(ctx, gen, key32, blind32);
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &commit->data[1]);
|
||||
secp256k1_ge_set_xquad(ge, &fe);
|
||||
if (commit->data[0] & 1) {
|
||||
secp256k1_ge_neg(ge, ge);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) {
|
||||
secp256k1_fe_normalize(&ge->x);
|
||||
secp256k1_fe_get_b32(&commit->data[1], &ge->x);
|
||||
commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y);
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) {
|
||||
secp256k1_fe x;
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
(void) ctx;
|
||||
|
||||
if ((input[0] & 0xFE) != 8 ||
|
||||
!secp256k1_fe_set_b32(&x, &input[1]) ||
|
||||
!secp256k1_ge_set_xquad(&ge, &x)) {
|
||||
return 0;
|
||||
}
|
||||
if (input[0] & 1) {
|
||||
secp256k1_ge_neg(&ge, &ge);
|
||||
}
|
||||
secp256k1_pedersen_commitment_save(commit, &ge);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) {
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
|
||||
secp256k1_pedersen_commitment_load(&ge, commit);
|
||||
|
||||
output[0] = 9 ^ secp256k1_fe_is_quad_var(&ge.y);
|
||||
secp256k1_fe_normalize_var(&ge.x);
|
||||
secp256k1_fe_get_b32(&output[1], &ge.x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
|
||||
int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) {
|
||||
secp256k1_ge genp;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar sec;
|
||||
int overflow;
|
||||
int ret = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(blind != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
secp256k1_scalar_set_b32(&sec, blind, &overflow);
|
||||
if (!overflow) {
|
||||
secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp);
|
||||
if (!secp256k1_gej_is_infinity(&rj)) {
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
secp256k1_pedersen_commitment_save(commit, &r);
|
||||
ret = 1;
|
||||
}
|
||||
secp256k1_gej_clear(&rj);
|
||||
secp256k1_ge_clear(&r);
|
||||
}
|
||||
secp256k1_scalar_clear(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest
|
||||
* negative, then calculates an additional blinding value that adds to zero.
|
||||
*/
|
||||
int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) {
|
||||
secp256k1_scalar acc;
|
||||
secp256k1_scalar x;
|
||||
size_t i;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(blind_out != NULL);
|
||||
ARG_CHECK(blinds != NULL);
|
||||
ARG_CHECK(npositive <= n);
|
||||
(void) ctx;
|
||||
secp256k1_scalar_set_int(&acc, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_set_b32(&x, blinds[i], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (i >= npositive) {
|
||||
secp256k1_scalar_negate(&x, &x);
|
||||
}
|
||||
secp256k1_scalar_add(&acc, &acc, &x);
|
||||
}
|
||||
secp256k1_scalar_get_b32(blind_out, &acc);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
secp256k1_scalar_clear(&x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */
|
||||
int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) {
|
||||
secp256k1_gej accj;
|
||||
secp256k1_ge add;
|
||||
size_t i;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(!pcnt || (commits != NULL));
|
||||
ARG_CHECK(!ncnt || (ncommits != NULL));
|
||||
(void) ctx;
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
for (i = 0; i < ncnt; i++) {
|
||||
secp256k1_pedersen_commitment_load(&add, ncommits[i]);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
for (i = 0; i < pcnt; i++) {
|
||||
secp256k1_pedersen_commitment_load(&add, commits[i]);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&accj);
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
|
||||
secp256k1_scalar sum;
|
||||
secp256k1_scalar tmp;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(n_total == 0 || value != NULL);
|
||||
ARG_CHECK(n_total == 0 || generator_blind != NULL);
|
||||
ARG_CHECK(n_total == 0 || blinding_factor != NULL);
|
||||
ARG_CHECK(n_total > n_inputs);
|
||||
(void) ctx;
|
||||
|
||||
if (n_total == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_int(&sum, 0);
|
||||
secp256k1_scalar_set_int(&tmp, 0);
|
||||
|
||||
/* Here, n_total > 0. Thus the loop runs at least once.
|
||||
Thus we may use a do-while loop, which checks the loop
|
||||
condition only at the end.
|
||||
|
||||
The do-while loop helps GCC prove that the loop runs at least
|
||||
once and suppresses a -Wmaybe-uninitialized warning. */
|
||||
i = 0;
|
||||
do {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar addend;
|
||||
secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */
|
||||
secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
|
||||
secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
|
||||
secp256k1_scalar_clear(&addend);
|
||||
|
||||
i++;
|
||||
} while (i < n_total);
|
||||
|
||||
/* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
|
||||
secp256k1_scalar_negate(&sum, &sum);
|
||||
secp256k1_scalar_add(&tmp, &tmp, &sum);
|
||||
secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp);
|
||||
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -223,11 +223,174 @@ void test_generator_fixed_vector(void) {
|
||||
CHECK(!secp256k1_generator_parse(ctx, &parse, result));
|
||||
}
|
||||
|
||||
static void test_pedersen_api(void) {
|
||||
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 *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
|
||||
secp256k1_pedersen_commitment commit;
|
||||
const secp256k1_pedersen_commitment *commit_ptr = &commit;
|
||||
unsigned char blind[32];
|
||||
unsigned char blind_out[32];
|
||||
const unsigned char *blind_ptr = blind;
|
||||
unsigned char *blind_out_ptr = blind_out;
|
||||
uint64_t val = secp256k1_testrand32();
|
||||
int32_t ecount = 0;
|
||||
|
||||
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(sttc, 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(sttc, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
secp256k1_testrand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_pedersen_commit(sttc, &commit, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(ecount == 1);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0);
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
|
||||
CHECK(ecount == 8);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
|
||||
CHECK(ecount == 9);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0);
|
||||
CHECK(ecount == 9);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
|
||||
CHECK(ecount == 10);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
|
||||
CHECK(ecount == 11);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(ecount == 12);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(ecount == 13);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
|
||||
CHECK(ecount == 14);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
secp256k1_context_destroy(sttc);
|
||||
}
|
||||
|
||||
static void test_pedersen(void) {
|
||||
secp256k1_pedersen_commitment commits[19];
|
||||
const secp256k1_pedersen_commitment *cptr[19];
|
||||
unsigned char blinds[32*19];
|
||||
const unsigned char *bptr[19];
|
||||
secp256k1_scalar s;
|
||||
uint64_t values[19];
|
||||
int64_t totalv;
|
||||
int i;
|
||||
int inputs;
|
||||
int outputs;
|
||||
int total;
|
||||
inputs = (secp256k1_testrand32() & 7) + 1;
|
||||
outputs = (secp256k1_testrand32() & 7) + 2;
|
||||
total = inputs + outputs;
|
||||
for (i = 0; i < 19; i++) {
|
||||
cptr[i] = &commits[i];
|
||||
bptr[i] = &blinds[i * 32];
|
||||
}
|
||||
totalv = 0;
|
||||
for (i = 0; i < inputs; i++) {
|
||||
values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
|
||||
totalv += values[i];
|
||||
}
|
||||
for (i = 0; i < outputs - 1; i++) {
|
||||
values[i + inputs] = secp256k1_testrandi64(0, totalv);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
values[total - 1] = totalv;
|
||||
|
||||
for (i = 0; i < total - 1; i++) {
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
|
||||
for (i = 0; i < total; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
|
||||
if (inputs > 0 && values[0] > 0) {
|
||||
CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs));
|
||||
}
|
||||
random_scalar_order(&s);
|
||||
for (i = 0; i < 4; i++) {
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
values[0] = INT64_MAX;
|
||||
values[1] = 0;
|
||||
values[2] = 1;
|
||||
for (i = 0; i < 3; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
|
||||
}
|
||||
|
||||
void test_pedersen_commitment_fixed_vector(void) {
|
||||
const unsigned char two_g[33] = {
|
||||
0x09,
|
||||
0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8,
|
||||
0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5
|
||||
};
|
||||
unsigned char result[33];
|
||||
secp256k1_pedersen_commitment parse;
|
||||
|
||||
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g));
|
||||
CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse));
|
||||
CHECK(secp256k1_memcmp_var(two_g, result, 33) == 0);
|
||||
|
||||
result[0] = 0x08;
|
||||
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result));
|
||||
result[0] = 0x0c;
|
||||
CHECK(!secp256k1_pedersen_commitment_parse(ctx, &parse, result));
|
||||
}
|
||||
|
||||
|
||||
void run_generator_tests(void) {
|
||||
int i;
|
||||
|
||||
test_shallue_van_de_woestijne();
|
||||
test_generator_fixed_vector();
|
||||
test_generator_api();
|
||||
test_generator_generate();
|
||||
test_pedersen_api();
|
||||
test_pedersen_commitment_fixed_vector();
|
||||
for (i = 0; i < count / 2 + 1; i++) {
|
||||
test_pedersen();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,5 @@
|
||||
include_HEADERS += include/secp256k1_rangeproof.h
|
||||
noinst_HEADERS += src/modules/rangeproof/main_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/pedersen.h
|
||||
noinst_HEADERS += src/modules/rangeproof/pedersen_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/borromean.h
|
||||
noinst_HEADERS += src/modules/rangeproof/borromean_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/rangeproof.h
|
||||
|
@ -9,225 +9,9 @@
|
||||
|
||||
#include "../../group.h"
|
||||
|
||||
#include "pedersen_impl.h"
|
||||
#include "borromean_impl.h"
|
||||
#include "rangeproof_impl.h"
|
||||
|
||||
/** Alternative generator for secp256k1.
|
||||
* This is the sha256 of 'g' after standard encoding (without compression),
|
||||
* which happens to be a point on the curve. More precisely, the generator is
|
||||
* derived by running the following script with the sage mathematics software.
|
||||
|
||||
import hashlib
|
||||
F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
|
||||
G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
|
||||
H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16)))
|
||||
print('%x %x' % H.xy())
|
||||
*/
|
||||
static const secp256k1_generator secp256k1_generator_h_internal = {{
|
||||
0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e,
|
||||
0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0,
|
||||
0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a,
|
||||
0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04
|
||||
}};
|
||||
|
||||
const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal;
|
||||
|
||||
static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &commit->data[1]);
|
||||
secp256k1_ge_set_xquad(ge, &fe);
|
||||
if (commit->data[0] & 1) {
|
||||
secp256k1_ge_neg(ge, ge);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) {
|
||||
secp256k1_fe_normalize(&ge->x);
|
||||
secp256k1_fe_get_b32(&commit->data[1], &ge->x);
|
||||
commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y);
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) {
|
||||
secp256k1_fe x;
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
(void) ctx;
|
||||
|
||||
if ((input[0] & 0xFE) != 8 ||
|
||||
!secp256k1_fe_set_b32(&x, &input[1]) ||
|
||||
!secp256k1_ge_set_xquad(&ge, &x)) {
|
||||
return 0;
|
||||
}
|
||||
if (input[0] & 1) {
|
||||
secp256k1_ge_neg(&ge, &ge);
|
||||
}
|
||||
secp256k1_pedersen_commitment_save(commit, &ge);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) {
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
|
||||
secp256k1_pedersen_commitment_load(&ge, commit);
|
||||
|
||||
output[0] = 9 ^ secp256k1_fe_is_quad_var(&ge.y);
|
||||
secp256k1_fe_normalize_var(&ge.x);
|
||||
secp256k1_fe_get_b32(&output[1], &ge.x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
|
||||
int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) {
|
||||
secp256k1_ge genp;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar sec;
|
||||
int overflow;
|
||||
int ret = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(blind != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
secp256k1_scalar_set_b32(&sec, blind, &overflow);
|
||||
if (!overflow) {
|
||||
secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp);
|
||||
if (!secp256k1_gej_is_infinity(&rj)) {
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
secp256k1_pedersen_commitment_save(commit, &r);
|
||||
ret = 1;
|
||||
}
|
||||
secp256k1_gej_clear(&rj);
|
||||
secp256k1_ge_clear(&r);
|
||||
}
|
||||
secp256k1_scalar_clear(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest
|
||||
* negative, then calculates an additional blinding value that adds to zero.
|
||||
*/
|
||||
int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) {
|
||||
secp256k1_scalar acc;
|
||||
secp256k1_scalar x;
|
||||
size_t i;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(blind_out != NULL);
|
||||
ARG_CHECK(blinds != NULL);
|
||||
ARG_CHECK(npositive <= n);
|
||||
(void) ctx;
|
||||
secp256k1_scalar_set_int(&acc, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_set_b32(&x, blinds[i], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (i >= npositive) {
|
||||
secp256k1_scalar_negate(&x, &x);
|
||||
}
|
||||
secp256k1_scalar_add(&acc, &acc, &x);
|
||||
}
|
||||
secp256k1_scalar_get_b32(blind_out, &acc);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
secp256k1_scalar_clear(&x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */
|
||||
int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) {
|
||||
secp256k1_gej accj;
|
||||
secp256k1_ge add;
|
||||
size_t i;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(!pcnt || (commits != NULL));
|
||||
ARG_CHECK(!ncnt || (ncommits != NULL));
|
||||
(void) ctx;
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
for (i = 0; i < ncnt; i++) {
|
||||
secp256k1_pedersen_commitment_load(&add, ncommits[i]);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
for (i = 0; i < pcnt; i++) {
|
||||
secp256k1_pedersen_commitment_load(&add, commits[i]);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&accj);
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
|
||||
secp256k1_scalar sum;
|
||||
secp256k1_scalar tmp;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(n_total == 0 || value != NULL);
|
||||
ARG_CHECK(n_total == 0 || generator_blind != NULL);
|
||||
ARG_CHECK(n_total == 0 || blinding_factor != NULL);
|
||||
ARG_CHECK(n_total > n_inputs);
|
||||
(void) ctx;
|
||||
|
||||
if (n_total == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_int(&sum, 0);
|
||||
|
||||
/* Here, n_total > 0. Thus the loop runs at least once.
|
||||
Thus we may use a do-while loop, which checks the loop
|
||||
condition only at the end.
|
||||
|
||||
The do-while loop helps GCC prove that the loop runs at least
|
||||
once and suppresses a -Wmaybe-uninitialized warning. */
|
||||
i = 0;
|
||||
do {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar addend;
|
||||
secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */
|
||||
secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
|
||||
secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
|
||||
secp256k1_scalar_clear(&addend);
|
||||
|
||||
i++;
|
||||
} while (i < n_total);
|
||||
|
||||
/* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
|
||||
secp256k1_scalar_negate(&sum, &sum);
|
||||
secp256k1_scalar_add(&tmp, &tmp, &sum);
|
||||
secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp);
|
||||
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 1;
|
||||
}
|
||||
#include "modules/generator/main_impl.h"
|
||||
#include "modules/rangeproof/borromean_impl.h"
|
||||
#include "modules/rangeproof/rangeproof_impl.h"
|
||||
|
||||
int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *mantissa,
|
||||
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
|
||||
|
@ -13,9 +13,9 @@
|
||||
#include "../../hash_impl.h"
|
||||
#include "../../util.h"
|
||||
|
||||
#include "pedersen.h"
|
||||
#include "rangeproof.h"
|
||||
#include "borromean.h"
|
||||
#include "modules/generator/pedersen.h"
|
||||
#include "modules/rangeproof/borromean.h"
|
||||
#include "modules/rangeproof/rangeproof.h"
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(secp256k1_gej *pubs,
|
||||
int exp, size_t *rsizes, size_t rings, const secp256k1_ge* genp) {
|
||||
|
@ -16,66 +16,6 @@
|
||||
|
||||
#include "../../../include/secp256k1_rangeproof.h"
|
||||
|
||||
static void test_pedersen_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *sttc, const int32_t *ecount) {
|
||||
secp256k1_pedersen_commitment commit;
|
||||
const secp256k1_pedersen_commitment *commit_ptr = &commit;
|
||||
unsigned char blind[32];
|
||||
unsigned char blind_out[32];
|
||||
const unsigned char *blind_ptr = blind;
|
||||
unsigned char *blind_out_ptr = blind_out;
|
||||
uint64_t val = secp256k1_testrand32();
|
||||
|
||||
secp256k1_testrand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 0);
|
||||
CHECK(secp256k1_pedersen_commit(sttc, &commit, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 1);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 2);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 3);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0);
|
||||
CHECK(*ecount == 4);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0);
|
||||
CHECK(*ecount == 4);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
|
||||
CHECK(*ecount == 5);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
|
||||
CHECK(*ecount == 6);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
|
||||
CHECK(*ecount == 7);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0);
|
||||
CHECK(*ecount == 7);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0);
|
||||
CHECK(*ecount == 7);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
|
||||
CHECK(*ecount == 9);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0);
|
||||
CHECK(*ecount == 9);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
|
||||
CHECK(*ecount == 10);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
|
||||
CHECK(*ecount == 11);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(*ecount == 12);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(*ecount == 13);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
|
||||
CHECK(*ecount == 14);
|
||||
}
|
||||
|
||||
static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *both, const secp256k1_context *sttc, const int32_t *ecount) {
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
@ -253,8 +193,6 @@ static void test_api(void) {
|
||||
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ecount = 0;
|
||||
test_pedersen_api(none, sign, vrfy, sttc, &ecount);
|
||||
ecount = 0;
|
||||
test_rangeproof_api(none, sign, vrfy, both, sttc, &ecount);
|
||||
}
|
||||
@ -266,63 +204,6 @@ static void test_api(void) {
|
||||
secp256k1_context_destroy(sttc);
|
||||
}
|
||||
|
||||
static void test_pedersen(void) {
|
||||
secp256k1_pedersen_commitment commits[19];
|
||||
const secp256k1_pedersen_commitment *cptr[19];
|
||||
unsigned char blinds[32*19];
|
||||
const unsigned char *bptr[19];
|
||||
secp256k1_scalar s;
|
||||
uint64_t values[19];
|
||||
int64_t totalv;
|
||||
int i;
|
||||
int inputs;
|
||||
int outputs;
|
||||
int total;
|
||||
inputs = (secp256k1_testrand32() & 7) + 1;
|
||||
outputs = (secp256k1_testrand32() & 7) + 2;
|
||||
total = inputs + outputs;
|
||||
for (i = 0; i < 19; i++) {
|
||||
cptr[i] = &commits[i];
|
||||
bptr[i] = &blinds[i * 32];
|
||||
}
|
||||
totalv = 0;
|
||||
for (i = 0; i < inputs; i++) {
|
||||
values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
|
||||
totalv += values[i];
|
||||
}
|
||||
for (i = 0; i < outputs - 1; i++) {
|
||||
values[i + inputs] = secp256k1_testrandi64(0, totalv);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
values[total - 1] = totalv;
|
||||
|
||||
for (i = 0; i < total - 1; i++) {
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
|
||||
for (i = 0; i < total; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
|
||||
if (inputs > 0 && values[0] > 0) {
|
||||
CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs));
|
||||
}
|
||||
random_scalar_order(&s);
|
||||
for (i = 0; i < 4; i++) {
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
values[0] = INT64_MAX;
|
||||
values[1] = 0;
|
||||
values[2] = 1;
|
||||
for (i = 0; i < 3; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
|
||||
}
|
||||
|
||||
static void test_borromean(void) {
|
||||
unsigned char e0[32];
|
||||
secp256k1_scalar s[64];
|
||||
@ -1523,25 +1404,6 @@ void test_rangeproof_fixed_vectors_reproducible(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void test_pedersen_commitment_fixed_vector(void) {
|
||||
const unsigned char two_g[33] = {
|
||||
0x09,
|
||||
0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8,
|
||||
0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5
|
||||
};
|
||||
unsigned char result[33];
|
||||
secp256k1_pedersen_commitment parse;
|
||||
|
||||
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g));
|
||||
CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse));
|
||||
CHECK(secp256k1_memcmp_var(two_g, result, 33) == 0);
|
||||
|
||||
result[0] = 0x08;
|
||||
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result));
|
||||
result[0] = 0x0c;
|
||||
CHECK(!secp256k1_pedersen_commitment_parse(ctx, &parse, result));
|
||||
}
|
||||
|
||||
void run_rangeproof_tests(void) {
|
||||
int i;
|
||||
test_api();
|
||||
@ -1552,10 +1414,6 @@ void run_rangeproof_tests(void) {
|
||||
|
||||
test_rangeproof_fixed_vectors();
|
||||
test_rangeproof_fixed_vectors_reproducible();
|
||||
test_pedersen_commitment_fixed_vector();
|
||||
for (i = 0; i < count / 2 + 1; i++) {
|
||||
test_pedersen();
|
||||
}
|
||||
for (i = 0; i < count / 2 + 1; i++) {
|
||||
test_borromean();
|
||||
}
|
||||
|
@ -65,6 +65,9 @@ static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a,
|
||||
* the low bits that were shifted off */
|
||||
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n);
|
||||
|
||||
/** Compute the square of a scalar (modulo the group order). */
|
||||
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a);
|
||||
|
||||
/** Compute the inverse of a scalar (modulo the group order). */
|
||||
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a);
|
||||
|
||||
|
@ -224,6 +224,28 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
VERIFY_CHECK(c1 >= th); \
|
||||
}
|
||||
|
||||
/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
|
||||
#define muladd2(a,b) { \
|
||||
uint64_t tl, th, th2, tl2; \
|
||||
{ \
|
||||
uint128_t t = (uint128_t)a * b; \
|
||||
th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
|
||||
tl = t; \
|
||||
} \
|
||||
th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \
|
||||
c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
|
||||
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
|
||||
tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \
|
||||
th2 += (tl2 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
|
||||
c0 += tl2; /* overflow is handled on the next line */ \
|
||||
th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
|
||||
c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
|
||||
VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
|
||||
c1 += th2; /* overflow is handled on the next line */ \
|
||||
c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
|
||||
VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
|
||||
}
|
||||
|
||||
/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
|
||||
#define sumadd(a) { \
|
||||
unsigned int over; \
|
||||
@ -733,10 +755,148 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) {
|
||||
#ifdef USE_ASM_X86_64
|
||||
__asm__ __volatile__(
|
||||
/* Preload */
|
||||
"movq 0(%%rdi), %%r11\n"
|
||||
"movq 8(%%rdi), %%r12\n"
|
||||
"movq 16(%%rdi), %%r13\n"
|
||||
"movq 24(%%rdi), %%r14\n"
|
||||
/* (rax,rdx) = a0 * a0 */
|
||||
"movq %%r11, %%rax\n"
|
||||
"mulq %%r11\n"
|
||||
/* Extract l0 */
|
||||
"movq %%rax, 0(%%rsi)\n"
|
||||
/* (r8,r9,r10) = (rdx,0) */
|
||||
"movq %%rdx, %%r8\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
"xorq %%r10, %%r10\n"
|
||||
/* (r8,r9,r10) += 2 * a0 * a1 */
|
||||
"movq %%r11, %%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax, %%r8\n"
|
||||
"adcq %%rdx, %%r9\n"
|
||||
"adcq $0, %%r10\n"
|
||||
"addq %%rax, %%r8\n"
|
||||
"adcq %%rdx, %%r9\n"
|
||||
"adcq $0, %%r10\n"
|
||||
/* Extract l1 */
|
||||
"movq %%r8, 8(%%rsi)\n"
|
||||
"xorq %%r8, %%r8\n"
|
||||
/* (r9,r10,r8) += 2 * a0 * a2 */
|
||||
"movq %%r11, %%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax, %%r9\n"
|
||||
"adcq %%rdx, %%r10\n"
|
||||
"adcq $0, %%r8\n"
|
||||
"addq %%rax, %%r9\n"
|
||||
"adcq %%rdx, %%r10\n"
|
||||
"adcq $0, %%r8\n"
|
||||
/* (r9,r10,r8) += a1 * a1 */
|
||||
"movq %%r12, %%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax, %%r9\n"
|
||||
"adcq %%rdx, %%r10\n"
|
||||
"adcq $0, %%r8\n"
|
||||
/* Extract l2 */
|
||||
"movq %%r9, 16(%%rsi)\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
/* (r10,r8,r9) += 2 * a0 * a3 */
|
||||
"movq %%r11, %%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax, %%r10\n"
|
||||
"adcq %%rdx, %%r8\n"
|
||||
"adcq $0, %%r9\n"
|
||||
"addq %%rax, %%r10\n"
|
||||
"adcq %%rdx, %%r8\n"
|
||||
"adcq $0, %%r9\n"
|
||||
/* (r10,r8,r9) += 2 * a1 * a2 */
|
||||
"movq %%r12, %%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax, %%r10\n"
|
||||
"adcq %%rdx, %%r8\n"
|
||||
"adcq $0, %%r9\n"
|
||||
"addq %%rax, %%r10\n"
|
||||
"adcq %%rdx, %%r8\n"
|
||||
"adcq $0, %%r9\n"
|
||||
/* Extract l3 */
|
||||
"movq %%r10, 24(%%rsi)\n"
|
||||
"xorq %%r10, %%r10\n"
|
||||
/* (r8,r9,r10) += 2 * a1 * a3 */
|
||||
"movq %%r12, %%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax, %%r8\n"
|
||||
"adcq %%rdx, %%r9\n"
|
||||
"adcq $0, %%r10\n"
|
||||
"addq %%rax, %%r8\n"
|
||||
"adcq %%rdx, %%r9\n"
|
||||
"adcq $0, %%r10\n"
|
||||
/* (r8,r9,r10) += a2 * a2 */
|
||||
"movq %%r13, %%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax, %%r8\n"
|
||||
"adcq %%rdx, %%r9\n"
|
||||
"adcq $0, %%r10\n"
|
||||
/* Extract l4 */
|
||||
"movq %%r8, 32(%%rsi)\n"
|
||||
"xorq %%r8, %%r8\n"
|
||||
/* (r9,r10,r8) += 2 * a2 * a3 */
|
||||
"movq %%r13, %%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax, %%r9\n"
|
||||
"adcq %%rdx, %%r10\n"
|
||||
"adcq $0, %%r8\n"
|
||||
"addq %%rax, %%r9\n"
|
||||
"adcq %%rdx, %%r10\n"
|
||||
"adcq $0, %%r8\n"
|
||||
/* Extract l5 */
|
||||
"movq %%r9, 40(%%rsi)\n"
|
||||
/* (r10,r8) += a3 * a3 */
|
||||
"movq %%r14, %%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax, %%r10\n"
|
||||
"adcq %%rdx, %%r8\n"
|
||||
/* Extract l6 */
|
||||
"movq %%r10, 48(%%rsi)\n"
|
||||
/* Extract l7 */
|
||||
"movq %%r8, 56(%%rsi)\n"
|
||||
:
|
||||
: "S"(l), "D"(a->d)
|
||||
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory");
|
||||
#else
|
||||
/* 160 bit accumulator. */
|
||||
uint64_t c0 = 0, c1 = 0;
|
||||
uint32_t c2 = 0;
|
||||
|
||||
/* l[0..7] = a[0..3] * b[0..3]. */
|
||||
muladd_fast(a->d[0], a->d[0]);
|
||||
extract_fast(l[0]);
|
||||
muladd2(a->d[0], a->d[1]);
|
||||
extract(l[1]);
|
||||
muladd2(a->d[0], a->d[2]);
|
||||
muladd(a->d[1], a->d[1]);
|
||||
extract(l[2]);
|
||||
muladd2(a->d[0], a->d[3]);
|
||||
muladd2(a->d[1], a->d[2]);
|
||||
extract(l[3]);
|
||||
muladd2(a->d[1], a->d[3]);
|
||||
muladd(a->d[2], a->d[2]);
|
||||
extract(l[4]);
|
||||
muladd2(a->d[2], a->d[3]);
|
||||
extract(l[5]);
|
||||
muladd_fast(a->d[3], a->d[3]);
|
||||
extract_fast(l[6]);
|
||||
VERIFY_CHECK(c1 == 0);
|
||||
l[7] = c0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef sumadd
|
||||
#undef sumadd_fast
|
||||
#undef muladd
|
||||
#undef muladd_fast
|
||||
#undef muladd2
|
||||
#undef extract
|
||||
#undef extract_fast
|
||||
|
||||
@ -758,6 +918,12 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
uint64_t l[8];
|
||||
secp256k1_scalar_sqr_512(l, a);
|
||||
secp256k1_scalar_reduce_512(r, l);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
|
||||
r1->d[0] = k->d[0];
|
||||
r1->d[1] = k->d[1];
|
||||
|
@ -306,6 +306,28 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
VERIFY_CHECK(c1 >= th); \
|
||||
}
|
||||
|
||||
/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
|
||||
#define muladd2(a,b) { \
|
||||
uint32_t tl, th, th2, tl2; \
|
||||
{ \
|
||||
uint64_t t = (uint64_t)a * b; \
|
||||
th = t >> 32; /* at most 0xFFFFFFFE */ \
|
||||
tl = t; \
|
||||
} \
|
||||
th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
|
||||
c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
|
||||
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
|
||||
tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
|
||||
th2 += (tl2 < tl); /* at most 0xFFFFFFFF */ \
|
||||
c0 += tl2; /* overflow is handled on the next line */ \
|
||||
th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
|
||||
c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
|
||||
VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
|
||||
c1 += th2; /* overflow is handled on the next line */ \
|
||||
c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
|
||||
VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
|
||||
}
|
||||
|
||||
/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
|
||||
#define sumadd(a) { \
|
||||
unsigned int over; \
|
||||
@ -569,10 +591,71 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, con
|
||||
l[15] = c0;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) {
|
||||
/* 96 bit accumulator. */
|
||||
uint32_t c0 = 0, c1 = 0, c2 = 0;
|
||||
|
||||
/* l[0..15] = a[0..7]^2. */
|
||||
muladd_fast(a->d[0], a->d[0]);
|
||||
extract_fast(l[0]);
|
||||
muladd2(a->d[0], a->d[1]);
|
||||
extract(l[1]);
|
||||
muladd2(a->d[0], a->d[2]);
|
||||
muladd(a->d[1], a->d[1]);
|
||||
extract(l[2]);
|
||||
muladd2(a->d[0], a->d[3]);
|
||||
muladd2(a->d[1], a->d[2]);
|
||||
extract(l[3]);
|
||||
muladd2(a->d[0], a->d[4]);
|
||||
muladd2(a->d[1], a->d[3]);
|
||||
muladd(a->d[2], a->d[2]);
|
||||
extract(l[4]);
|
||||
muladd2(a->d[0], a->d[5]);
|
||||
muladd2(a->d[1], a->d[4]);
|
||||
muladd2(a->d[2], a->d[3]);
|
||||
extract(l[5]);
|
||||
muladd2(a->d[0], a->d[6]);
|
||||
muladd2(a->d[1], a->d[5]);
|
||||
muladd2(a->d[2], a->d[4]);
|
||||
muladd(a->d[3], a->d[3]);
|
||||
extract(l[6]);
|
||||
muladd2(a->d[0], a->d[7]);
|
||||
muladd2(a->d[1], a->d[6]);
|
||||
muladd2(a->d[2], a->d[5]);
|
||||
muladd2(a->d[3], a->d[4]);
|
||||
extract(l[7]);
|
||||
muladd2(a->d[1], a->d[7]);
|
||||
muladd2(a->d[2], a->d[6]);
|
||||
muladd2(a->d[3], a->d[5]);
|
||||
muladd(a->d[4], a->d[4]);
|
||||
extract(l[8]);
|
||||
muladd2(a->d[2], a->d[7]);
|
||||
muladd2(a->d[3], a->d[6]);
|
||||
muladd2(a->d[4], a->d[5]);
|
||||
extract(l[9]);
|
||||
muladd2(a->d[3], a->d[7]);
|
||||
muladd2(a->d[4], a->d[6]);
|
||||
muladd(a->d[5], a->d[5]);
|
||||
extract(l[10]);
|
||||
muladd2(a->d[4], a->d[7]);
|
||||
muladd2(a->d[5], a->d[6]);
|
||||
extract(l[11]);
|
||||
muladd2(a->d[5], a->d[7]);
|
||||
muladd(a->d[6], a->d[6]);
|
||||
extract(l[12]);
|
||||
muladd2(a->d[6], a->d[7]);
|
||||
extract(l[13]);
|
||||
muladd_fast(a->d[7], a->d[7]);
|
||||
extract_fast(l[14]);
|
||||
VERIFY_CHECK(c1 == 0);
|
||||
l[15] = c0;
|
||||
}
|
||||
|
||||
#undef sumadd
|
||||
#undef sumadd_fast
|
||||
#undef muladd
|
||||
#undef muladd_fast
|
||||
#undef muladd2
|
||||
#undef extract
|
||||
#undef extract_fast
|
||||
|
||||
@ -598,6 +681,12 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
uint32_t l[16];
|
||||
secp256k1_scalar_sqr_512(l, a);
|
||||
secp256k1_scalar_reduce_512(r, l);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
|
||||
r1->d[0] = k->d[0];
|
||||
r1->d[1] = k->d[1];
|
||||
|
@ -105,6 +105,10 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
*r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
|
||||
*r1 = *a;
|
||||
*r2 = 0;
|
||||
|
@ -38,8 +38,6 @@
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
# include "include/secp256k1_rangeproof.h"
|
||||
# include "modules/rangeproof/pedersen.h"
|
||||
# include "modules/rangeproof/rangeproof.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDSA_S2C
|
||||
@ -802,6 +800,10 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MODULE_BPPP
|
||||
# include "modules/bppp/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDH
|
||||
# include "modules/ecdh/main_impl.h"
|
||||
#endif
|
||||
|
22
src/tests.c
22
src/tests.c
@ -1898,6 +1898,14 @@ void scalar_test(void) {
|
||||
CHECK(secp256k1_scalar_eq(&r1, &r2));
|
||||
}
|
||||
|
||||
{
|
||||
/* Test square. */
|
||||
secp256k1_scalar r1, r2;
|
||||
secp256k1_scalar_sqr(&r1, &s1);
|
||||
secp256k1_scalar_mul(&r2, &s1, &s1);
|
||||
CHECK(secp256k1_scalar_eq(&r1, &r2));
|
||||
}
|
||||
|
||||
{
|
||||
/* Test multiplicative identity. */
|
||||
secp256k1_scalar r1, v1;
|
||||
@ -2653,6 +2661,12 @@ void run_scalar_tests(void) {
|
||||
CHECK(!secp256k1_scalar_check_overflow(&zz));
|
||||
CHECK(secp256k1_scalar_eq(&one, &zz));
|
||||
}
|
||||
secp256k1_scalar_mul(&z, &x, &x);
|
||||
CHECK(!secp256k1_scalar_check_overflow(&z));
|
||||
secp256k1_scalar_sqr(&zz, &x);
|
||||
CHECK(!secp256k1_scalar_check_overflow(&zz));
|
||||
CHECK(secp256k1_scalar_eq(&zz, &z));
|
||||
CHECK(secp256k1_scalar_eq(&r2, &zz));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7118,6 +7132,10 @@ void run_ecdsa_edge_cases(void) {
|
||||
test_ecdsa_edge_cases();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MODULE_BPPP
|
||||
# include "modules/bppp/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDH
|
||||
# include "modules/ecdh/tests_impl.h"
|
||||
#endif
|
||||
@ -7438,6 +7456,10 @@ int main(int argc, char **argv) {
|
||||
/* EC key arithmetic test */
|
||||
run_eckey_negate_test();
|
||||
|
||||
#ifdef ENABLE_MODULE_BPPP
|
||||
run_bppp_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDH
|
||||
/* ecdh tests */
|
||||
run_ecdh_tests();
|
||||
|
Loading…
x
Reference in New Issue
Block a user