Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncompressed Bulletproof Rangeproofs #108

Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
bulletproofs: implement the iterative step of the uncompressed prover
apoelstra committed Aug 27, 2022
commit 2e651b9cd0982e90b2c267f2247e4c8a0da17a5a
22 changes: 22 additions & 0 deletions src/modules/bulletproofs/bulletproofs_util.h
Original file line number Diff line number Diff line change
@@ -80,6 +80,28 @@ static void secp256k1_bulletproofs_lrgen_init(secp256k1_bulletproofs_bulletproof
generator->count = 0;
}

/* Serializes yn and z22n as a 64-byte char array */
static void secp256k1_bulletproofs_lrgen_serialize(unsigned char* output, const secp256k1_bulletproofs_bulletproofs_lrgen *generator) {
secp256k1_scalar_get_b32(&output[0], &generator->yn);
secp256k1_scalar_get_b32(&output[32], &generator->z22n);
}

/* Deserializes yn and z22n from a 64-byte char array, otherwise the same as `secp256k1_bulletproofs_lrgen_init` */
static int secp256k1_bulletproofs_lrgen_deserialize(secp256k1_bulletproofs_bulletproofs_lrgen *generator, const unsigned char *saved_state, size_t idx, const unsigned char *nonce, const secp256k1_scalar *y, const secp256k1_scalar *z, const uint64_t val_less_min) {
int overflow;
secp256k1_bulletproofs_lrgen_init(generator, nonce, y, z, val_less_min);
secp256k1_scalar_set_b32(&generator->yn, &saved_state[0], &overflow);
if (overflow || secp256k1_scalar_is_zero(&generator->yn)) {
return 0;
}
secp256k1_scalar_set_b32(&generator->z22n, &saved_state[32], &overflow);
if (overflow || secp256k1_scalar_is_zero(&generator->z22n)) {
return 0;
}
generator->count = idx;
return 1;
}

static void secp256k1_lr_generate(secp256k1_bulletproofs_bulletproofs_lrgen *generator, secp256k1_scalar *lout, secp256k1_scalar *rout, const secp256k1_scalar *x) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation for treating x separately from y and z, given that each call to lr_generate seems to create a fresh lrgen struct anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

y and z are constants. x is a variable. By treating x separately we retain the ability to make copies of the lrgen generator rather than re-initializing it. (Indeed, we do this in Step 3 on line 380.)

const int al = (generator->val_less_min >> generator->count) & 1;
secp256k1_scalar sl, sr;
57 changes: 57 additions & 0 deletions src/modules/bulletproofs/rangeproof_uncompressed_impl.h
Original file line number Diff line number Diff line change
@@ -344,4 +344,61 @@ static int secp256k1_bulletproofs_rangeproof_uncompressed_prove_step2_impl(
return 1;
}

/* Step 3 of the proof. Should be called n_bits many times.
* Outputs the scalars l(i) and r(i), encoded in 64 bytes (l first then r).
* Does not update the state when idx > 0.
*/
static int secp256k1_bulletproofs_rangeproof_uncompressed_prove_step3_impl(
secp256k1_bulletproofs_prover_context* prover_ctx,
unsigned char* output,
size_t idx,
const uint64_t value,
const uint64_t min_value,
const unsigned char* nonce
) {
secp256k1_bulletproofs_bulletproofs_lrgen lr_gen;
secp256k1_scalar x, y, z, l, r;
int overflow;

/* Extract challenges */
secp256k1_scalar_set_b32(&x, &prover_ctx->data[0], &overflow);
if (overflow || secp256k1_scalar_is_zero(&x)) {
memset(prover_ctx->data, 0, sizeof(prover_ctx->data));
memset(output, 0, 64);
return 0;
}
secp256k1_scalar_set_b32(&y, &prover_ctx->data[32], &overflow);
if (overflow || secp256k1_scalar_is_zero(&y)) {
memset(prover_ctx->data, 0, sizeof(prover_ctx->data));
memset(output, 0, 64);
return 0;
}
secp256k1_scalar_set_b32(&z, &prover_ctx->data[64], &overflow);
if (overflow || secp256k1_scalar_is_zero(&z)) {
memset(prover_ctx->data, 0, sizeof(prover_ctx->data));
memset(output, 0, 64);
return 0;
}

/* Restore lrgen state */
if (idx == 0) {
secp256k1_bulletproofs_lrgen_init(&lr_gen, nonce, &y, &z, value - min_value);
} else {
if (!secp256k1_bulletproofs_lrgen_deserialize(&lr_gen, &prover_ctx->data[96], idx, nonce, &y, &z, value - min_value)) {
memset(prover_ctx->data, 0, sizeof(prover_ctx->data));
memset(output, 0, 64);
return 0;
}
}

/* Generate l(x) and r(x) */
secp256k1_lr_generate(&lr_gen, &l, &r, &x);

/* Success */
secp256k1_bulletproofs_lrgen_serialize(&prover_ctx->data[96], &lr_gen);
secp256k1_scalar_get_b32(&output[0], &l);
secp256k1_scalar_get_b32(&output[32], &r);
return 1;
}

#endif