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:
Jonas Nick 2023-02-27 17:36:16 +00:00
commit 8ec6d111c8
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
33 changed files with 2429 additions and 520 deletions

View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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

View File

@ -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
View 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;
}

View File

@ -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);

View 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

View 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

View 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

View 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
View 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

View 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

View 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;

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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) {

View File

@ -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();
}

View File

@ -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);

View File

@ -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];

View File

@ -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];

View File

@ -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;

View File

@ -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

View File

@ -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();