Skip to content

Commit

Permalink
Functions to inverse and negate private key, commit with 2 blinding f…
Browse files Browse the repository at this point in the history
…actors (#39)

* Private key inverse function

* Private key negate function, more tests

* Add another test

* Add commit with 2 blinding factors

* Add new method to header

* Add tests for pedersen_blind_commit
  • Loading branch information
jaspervdm authored and garyyu committed Feb 27, 2019
1 parent 1760fb2 commit f081a53
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 0 deletions.
20 changes: 20 additions & 0 deletions include/secp256k1.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,26 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
size_t n
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Tweak a private key by inverting it.
* Returns: 0 if the input was out of range. 1 otherwise.
* Args: ctx: pointer to a context object (cannot be NULL).
* In/Out: seckey: pointer to a 32-byte private key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_inv(
const secp256k1_context* ctx,
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);

/** Tweak a private key by negating it.
* Returns: 0 if the input was out of range. 1 otherwise.
* Args: ctx: pointer to a context object (cannot be NULL).
* In/Out: seckey: pointer to a 32-byte private key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_neg(
const secp256k1_context* ctx,
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);

#ifdef __cplusplus
}
#endif
Expand Down
23 changes: 23 additions & 0 deletions include/secp256k1_commitment.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,29 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
const secp256k1_generator *blind_gen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);

/** Generate a Pedersen commitment from two blinding factors.
* 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 (cannot be NULL)
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
* value: pointer to a 32-byte blinding factor (cannot be NULL)
* value_gen: value generator 'h'
* blind_gen: blinding factor generator 'g'
* 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_blind_commit(
const secp256k1_context* ctx,
secp256k1_pedersen_commitment *commit,
const unsigned char *blind,
const unsigned char *value,
const secp256k1_generator *value_gen,
const secp256k1_generator *blind_gen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);

/** 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
Expand Down
35 changes: 35 additions & 0 deletions src/modules/commitment/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,41 @@ int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_c
return ret;
}

/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
int secp256k1_pedersen_blind_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *value, const secp256k1_generator* value_gen, const secp256k1_generator* blind_gen) {
secp256k1_ge value_genp;
secp256k1_ge blind_genp;
secp256k1_gej rj;
secp256k1_ge r;
secp256k1_scalar sec;
secp256k1_scalar sec2;
int overflow;
int overflow2;
int ret = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(commit != NULL);
ARG_CHECK(blind != NULL);
ARG_CHECK(value != NULL);
ARG_CHECK(value_gen != NULL);
ARG_CHECK(blind_gen != NULL);
secp256k1_generator_load(&value_genp, value_gen);
secp256k1_generator_load(&blind_genp, blind_gen);
secp256k1_scalar_set_b32(&sec, blind, &overflow);
secp256k1_scalar_set_b32(&sec2, value, &overflow2);
if (!overflow && !overflow2) {
secp256k1_pedersen_blind_ecmult(&rj, &sec, &sec2, &value_genp, &blind_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;
}

int secp256k1_pedersen_commitment_to_pubkey(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const secp256k1_pedersen_commitment* commit) {
secp256k1_ge Q;
secp256k1_fe fe;
Expand Down
18 changes: 18 additions & 0 deletions src/modules/commitment/pedersen_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,22 @@ SECP256K1_INLINE static void secp256k1_pedersen_ecmult(secp256k1_gej *rj, const
secp256k1_scalar_clear(&vs);
}

SECP256K1_INLINE static void secp256k1_pedersen_blind_ecmult(secp256k1_gej *rj, const secp256k1_scalar *sec, const secp256k1_scalar *value, const secp256k1_ge* value_gen, const secp256k1_ge* blind_gen) {
secp256k1_gej bj;
secp256k1_ge bp;

secp256k1_ecmult_const(rj, value_gen, value, 256);
secp256k1_ecmult_const(&bj, blind_gen, sec, 256);

/* zero blinding factor indicates that we are not trying to be zero-knowledge,
* so not being constant-time in this case is OK. */
if (!secp256k1_gej_is_infinity(&bj)) {
secp256k1_ge_set_gej(&bp, &bj);
secp256k1_gej_add_ge(rj, rj, &bp);
}

secp256k1_gej_clear(&bj);
secp256k1_ge_clear(&bp);
}

#endif
40 changes: 40 additions & 0 deletions src/modules/commitment/tests_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

static void test_commitment_api(void) {
secp256k1_pedersen_commitment commit;
secp256k1_pedersen_commitment commit2;
const secp256k1_pedersen_commitment *commit_ptr = &commit;
unsigned char blind[32];
unsigned char blind_out[32];
Expand Down Expand Up @@ -94,6 +95,45 @@ static void test_commitment_api(void) {
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
CHECK(ecount == 16);

/* Test commit with integer and blinding factor */
/* Value: 1*/
secp256k1_scalar tmp_s;
unsigned char out[33];
unsigned char out2[33];
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(blind, &tmp_s);
memset(blind_out, 0, 32);
blind_out[31] = 1;
val = 1;
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 1);
CHECK(secp256k1_pedersen_commitment_serialize(sign, out, &commit) == 1);
CHECK(secp256k1_pedersen_blind_commit(sign, &commit2, blind, blind_out, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 1);
CHECK(secp256k1_pedersen_commitment_serialize(sign, out2, &commit2) == 1);
CHECK(memcmp(out, out2, 33) == 0);
/* Value: 1 and 2*/
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(blind, &tmp_s);
memset(blind_out, 0, 32);
blind_out[31] = 1;
val = 2;
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 1);
CHECK(secp256k1_pedersen_commitment_serialize(sign, out, &commit) == 1);
CHECK(secp256k1_pedersen_blind_commit(sign, &commit2, blind, blind_out, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 1);
CHECK(secp256k1_pedersen_commitment_serialize(sign, out2, &commit2) == 1);
CHECK(memcmp(out, out2, 33) != 0);
/* Value: random*/
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(blind, &tmp_s);
memset(blind_out, 0, 32);
blind_out[30] = secp256k1_rand32()%256;
blind_out[31] = secp256k1_rand32()%256;
val = blind_out[30]*256 + blind_out[31];
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 1);
CHECK(secp256k1_pedersen_commitment_serialize(sign, out, &commit) == 1);
CHECK(secp256k1_pedersen_blind_commit(sign, &commit2, blind, blind_out, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 1);
CHECK(secp256k1_pedersen_commitment_serialize(sign, out2, &commit2) == 1);
CHECK(memcmp(out, out2, 33) == 0);

secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
Expand Down
40 changes: 40 additions & 0 deletions src/secp256k1.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,46 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
return 1;
}

int secp256k1_ec_privkey_tweak_inv(const secp256k1_context* ctx, unsigned char *seckey) {
secp256k1_scalar sec;
secp256k1_scalar inv;
int ret = 0;
int overflow = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);

secp256k1_scalar_set_b32(&sec, seckey, &overflow);
ret = !overflow;
memset(seckey, 0, 32);
if (ret) {
secp256k1_scalar_inverse(&inv, &sec);
secp256k1_scalar_get_b32(seckey, &inv);
secp256k1_scalar_clear(&inv);
}
secp256k1_scalar_clear(&sec);
return ret;
}

int secp256k1_ec_privkey_tweak_neg(const secp256k1_context* ctx, unsigned char *seckey) {
secp256k1_scalar sec;
secp256k1_scalar neg;
int ret = 0;
int overflow = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);

secp256k1_scalar_set_b32(&sec, seckey, &overflow);
ret = !overflow;
memset(seckey, 0, 32);
if (ret) {
secp256k1_scalar_negate(&neg, &sec);
secp256k1_scalar_get_b32(seckey, &neg);
secp256k1_scalar_clear(&neg);
}
secp256k1_scalar_clear(&sec);
return ret;
}

#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/main_impl.h"
#endif
Expand Down
67 changes: 67 additions & 0 deletions src/tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -3988,6 +3988,73 @@ void run_eckey_edge_case_test(void) {
CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
CHECK(ecount == 3);
secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
/* Secret key inversion and negation tests */
/* Inverse of 1 is 1 */
memset(ctmp, 0, 32);
ctmp[31] = 0x01;
memset(ctmp2, 0, 32);
ctmp2[31] = 0x01;
CHECK(secp256k1_ec_privkey_tweak_inv(ctx, ctmp2) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) == 0);
/* Inverse of inverse */
secp256k1_scalar tmp_s;
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(ctmp, &tmp_s);
memcpy(ctmp2, ctmp, 32);
CHECK(secp256k1_ec_privkey_tweak_inv(ctx, ctmp2) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) != 0);
CHECK(secp256k1_ec_privkey_tweak_inv(ctx, ctmp2) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) == 0);
/* Self times inverse is 1 */
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(ctmp, &tmp_s);
memcpy(ctmp2, ctmp, 32);
CHECK(secp256k1_ec_privkey_tweak_inv(ctx, ctmp2) == 1);
CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 1);
memset(ctmp2, 0, 32);
ctmp2[31] = 0x01;
CHECK(memcmp(ctmp, ctmp2, 32) == 0);
/* Negated added to self is 0 */
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(ctmp, &tmp_s);
memcpy(ctmp2, ctmp, 32);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp2) == 1);
CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 0);
/* Negation of negation */
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(ctmp, &tmp_s);
memcpy(ctmp2, ctmp, 32);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp2) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) != 0);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp2) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) == 0);
/* 2*(-1)*x == (-1)*2*x */
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(ctmp, &tmp_s);
memcpy(ctmp2, ctmp, 32);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp) == 1);
CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp) == 1);
CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp2) == 1);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp2) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) == 0);
/* -x == (-1)*x */
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(ctmp, &tmp_s);
memset(ctmp2, 0, 32);
ctmp2[31] = 0x01;
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp2) == 1);
CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp2, ctmp) == 1);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) == 0);
/* -1/x == 1/(-x) */
random_scalar_order_test(&tmp_s);
secp256k1_scalar_get_b32(ctmp, &tmp_s);
memcpy(ctmp2, ctmp, 32);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp) == 1);
CHECK(secp256k1_ec_privkey_tweak_inv(ctx, ctmp) == 1);
CHECK(secp256k1_ec_privkey_tweak_inv(ctx, ctmp2) == 1);
CHECK(secp256k1_ec_privkey_tweak_neg(ctx, ctmp2) == 1);
CHECK(memcmp(ctmp, ctmp2, 32) == 0);
}

void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
Expand Down

0 comments on commit f081a53

Please sign in to comment.