Skip to content

Commit

Permalink
Batch inversions in Trust Tokens.
Browse files Browse the repository at this point in the history
The DLEQ and DLEQOR proofs require converting many Jacobian points to
affine, some multiple times. The inversions involved can be batched.

This buys us a +5-8% improvement in token issuance speed. issue and
finish_issue should each only perform two inversions per token now. We
could save an inversion per token by changing the dleq_generate and
dleq_verify function signatures, but that would complicate the likely
more valuable batched DLEQ(OR) optimization, so I've left those alone.

Before:
Did 300 TrustToken-Exp0-Batch1 generate_key operations in 2031798us (147.7 ops/sec)
Did 1449 TrustToken-Exp0-Batch1 begin_issuance operations in 2093639us (692.1 ops/sec)
Did 96 TrustToken-Exp0-Batch1 issue operations in 2044310us (47.0 ops/sec)
Did 84 TrustToken-Exp0-Batch1 finish_issuance operations in 2072137us (40.5 ops/sec)
Did 12170000 TrustToken-Exp0-Batch1 begin_redemption operations in 2000098us (6084701.8 ops/sec)
Did 315 TrustToken-Exp0-Batch1 redeem operations in 2091938us (150.6 ops/sec)
Did 35000 TrustToken-Exp0-Batch1 finish_redemption operations in 2004900us (17457.2 ops/sec)
Did 308 TrustToken-Exp0-Batch10 generate_key operations in 2067860us (148.9 ops/sec)
Did 138 TrustToken-Exp0-Batch10 begin_issuance operations in 2005706us (68.8 ops/sec)
Did 9 TrustToken-Exp0-Batch10 issue operations in 2107753us (4.3 ops/sec)
Did 8 TrustToken-Exp0-Batch10 finish_issuance operations in 2193489us (3.6 ops/sec)
Did 12046750 TrustToken-Exp0-Batch10 begin_redemption operations in 2000025us (6023299.7 ops/sec)
Did 315 TrustToken-Exp0-Batch10 redeem operations in 2091940us (150.6 ops/sec)
Did 35000 TrustToken-Exp0-Batch10 finish_redemption operations in 2008851us (17422.9 ops/sec)

Did 756 TrustToken-Exp1-Batch1 generate_key operations in 2051005us (368.6 ops/sec)
Did 3633 TrustToken-Exp1-Batch1 begin_issuance operations in 2072577us (1752.9 ops/sec)
Did 242 TrustToken-Exp1-Batch1 issue operations in 2052091us (117.9 ops/sec)
Did 210 TrustToken-Exp1-Batch1 finish_issuance operations in 2058740us (102.0 ops/sec)
Did 12477000 TrustToken-Exp1-Batch1 begin_redemption operations in 2000004us (6238487.5 ops/sec)
Did 777 TrustToken-Exp1-Batch1 redeem operations in 2084953us (372.7 ops/sec)
Did 35000 TrustToken-Exp1-Batch1 finish_redemption operations in 2028286us (17255.9 ops/sec)
Did 756 TrustToken-Exp1-Batch10 generate_key operations in 2051178us (368.6 ops/sec)
Did 357 TrustToken-Exp1-Batch10 begin_issuance operations in 2041875us (174.8 ops/sec)
Did 23 TrustToken-Exp1-Batch10 issue operations in 2026494us (11.3 ops/sec)
Did 20 TrustToken-Exp1-Batch10 finish_issuance operations in 2048478us (9.8 ops/sec)
Did 12492000 TrustToken-Exp1-Batch10 begin_redemption operations in 2000053us (6245834.5 ops/sec)
Did 777 TrustToken-Exp1-Batch10 redeem operations in 2084956us (372.7 ops/sec)
Did 36000 TrustToken-Exp1-Batch10 finish_redemption operations in 2021991us (17804.2 ops/sec)

After:
Did 315 TrustToken-Exp0-Batch1 generate_key operations in 2046638us (153.9 ops/sec) [+4.2%]
Did 1449 TrustToken-Exp0-Batch1 begin_issuance operations in 2087930us (694.0 ops/sec) [+0.3%]
Did 105 TrustToken-Exp0-Batch1 issue operations in 2071104us (50.7 ops/sec) [+8.0%]
Did 88 TrustToken-Exp0-Batch1 finish_issuance operations in 2023502us (43.5 ops/sec) [+7.3%]
Did 11847000 TrustToken-Exp0-Batch1 begin_redemption operations in 2000041us (5923378.6 ops/sec) [-2.7%]
Did 315 TrustToken-Exp0-Batch1 redeem operations in 2084116us (151.1 ops/sec) [+0.4%]
Did 35000 TrustToken-Exp0-Batch1 finish_redemption operations in 2003732us (17467.4 ops/sec) [+0.1%]
Did 315 TrustToken-Exp0-Batch10 generate_key operations in 2046863us (153.9 ops/sec) [+3.3%]
Did 138 TrustToken-Exp0-Batch10 begin_issuance operations in 2000108us (69.0 ops/sec) [+0.3%]
Did 10 TrustToken-Exp0-Batch10 issue operations in 2149283us (4.7 ops/sec) [+9.0%]
Did 8 TrustToken-Exp0-Batch10 finish_issuance operations in 2046416us (3.9 ops/sec) [+7.2%]
Did 12112000 TrustToken-Exp0-Batch10 begin_redemption operations in 2000077us (6055766.9 ops/sec) [+0.5%]
Did 315 TrustToken-Exp0-Batch10 redeem operations in 2084427us (151.1 ops/sec) [+0.4%]
Did 35000 TrustToken-Exp0-Batch10 finish_redemption operations in 2015111us (17368.8 ops/sec) [-0.3%]

Did 777 TrustToken-Exp1-Batch1 generate_key operations in 2029777us (382.8 ops/sec) [+3.9%]
Did 3654 TrustToken-Exp1-Batch1 begin_issuance operations in 2093484us (1745.4 ops/sec) [-0.4%]
Did 252 TrustToken-Exp1-Batch1 issue operations in 2024557us (124.5 ops/sec) [+5.5%]
Did 220 TrustToken-Exp1-Batch1 finish_issuance operations in 2034633us (108.1 ops/sec) [+6.0%]
Did 12659000 TrustToken-Exp1-Batch1 begin_redemption operations in 2000112us (6329145.6 ops/sec) [+1.5%]
Did 777 TrustToken-Exp1-Batch1 redeem operations in 2073783us (374.7 ops/sec) [+0.5%]
Did 35000 TrustToken-Exp1-Batch1 finish_redemption operations in 2050371us (17070.1 ops/sec) [-1.1%]
Did 768 TrustToken-Exp1-Batch10 generate_key operations in 2025482us (379.2 ops/sec) [+2.9%]
Did 357 TrustToken-Exp1-Batch10 begin_issuance operations in 2034429us (175.5 ops/sec) [+0.4%]
Did 25 TrustToken-Exp1-Batch10 issue operations in 2049293us (12.2 ops/sec) [+7.5%]
Did 21 TrustToken-Exp1-Batch10 finish_issuance operations in 2022256us (10.4 ops/sec) [+6.4%]
Did 12702000 TrustToken-Exp1-Batch10 begin_redemption operations in 2000015us (6350952.4 ops/sec) [+1.7%]
Did 777 TrustToken-Exp1-Batch10 redeem operations in 2072048us (375.0 ops/sec) [+0.6%]
Did 35000 TrustToken-Exp1-Batch10 finish_redemption operations in 2024580us (17287.5 ops/sec) [-2.9%]

Change-Id: Ia1b09cd14aa8ce0935d18033fb4bd75666a258e9
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/41086
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
  • Loading branch information
davidben authored and CQ bot account: commit-bot@chromium.org committed May 7, 2020
1 parent 54a59c6 commit ce1665b
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 98 deletions.
15 changes: 15 additions & 0 deletions crypto/fipsmodule/ec/ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,15 @@ int ec_jacobian_to_affine(const EC_GROUP *group, EC_AFFINE *out,
return group->meth->point_get_affine_coordinates(group, p, &out->X, &out->Y);
}

int ec_jacobian_to_affine_batch(const EC_GROUP *group, EC_AFFINE *out,
const EC_RAW_POINT *in, size_t num) {
if (group->meth->jacobian_to_affine_batch == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
return group->meth->jacobian_to_affine_batch(group, out, in, num);
}

int ec_point_set_affine_coordinates(const EC_GROUP *group, EC_AFFINE *out,
const EC_FELEM *x, const EC_FELEM *y) {
void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
Expand Down Expand Up @@ -1046,6 +1055,12 @@ void ec_point_select(const EC_GROUP *group, EC_RAW_POINT *out, BN_ULONG mask,
ec_felem_select(group, &out->Z, mask, &a->Z, &b->Z);
}

void ec_affine_select(const EC_GROUP *group, EC_AFFINE *out, BN_ULONG mask,
const EC_AFFINE *a, const EC_AFFINE *b) {
ec_felem_select(group, &out->X, mask, &a->X, &b->X);
ec_felem_select(group, &out->Y, mask, &a->Y, &b->Y);
}

int ec_cmp_x_coordinate(const EC_GROUP *group, const EC_RAW_POINT *p,
const EC_SCALAR *r) {
return group->meth->cmp_x_coordinate(group, p, r);
Expand Down
47 changes: 47 additions & 0 deletions crypto/fipsmodule/ec/ec_montgomery.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,52 @@ static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group,
return 1;
}

static int ec_GFp_mont_jacobian_to_affine_batch(const EC_GROUP *group,
EC_AFFINE *out,
const EC_RAW_POINT *in,
size_t num) {
if (num == 0) {
return 1;
}

// Compute prefix products of all Zs. Use |out[i].X| as scratch space
// to store these values.
out[0].X = in[0].Z;
for (size_t i = 1; i < num; i++) {
ec_GFp_mont_felem_mul(group, &out[i].X, &out[i - 1].X, &in[i].Z);
}

// Some input was infinity iff the product of all Zs is zero.
if (ec_felem_non_zero_mask(group, &out[num - 1].X) == 0) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
return 0;
}

// Invert the product of all Zs.
EC_FELEM zinvprod;
ec_GFp_mont_felem_inv0(group, &zinvprod, &out[num - 1].X);
for (size_t i = num - 1; i < num; i--) {
// Our loop invariant is that |zinvprod| is Z0^-1 * Z1^-1 * ... * Zi^-1.
// Recover Zi^-1 by multiplying by the previous product.
EC_FELEM zinv, zinv2;
if (i == 0) {
zinv = zinvprod;
} else {
ec_GFp_mont_felem_mul(group, &zinv, &zinvprod, &out[i - 1].X);
// Maintain the loop invariant for the next iteration.
ec_GFp_mont_felem_mul(group, &zinvprod, &zinvprod, &in[i].Z);
}

// Compute affine coordinates: x = X * Z^-2 and y = Y * Z^-3.
ec_GFp_mont_felem_sqr(group, &zinv2, &zinv);
ec_GFp_mont_felem_mul(group, &out[i].X, &in[i].X, &zinv2);
ec_GFp_mont_felem_mul(group, &out[i].Y, &in[i].Y, &zinv2);
ec_GFp_mont_felem_mul(group, &out[i].Y, &out[i].Y, &zinv);
}

return 1;
}

void ec_GFp_mont_add(const EC_GROUP *group, EC_RAW_POINT *out,
const EC_RAW_POINT *a, const EC_RAW_POINT *b) {
if (a == b) {
Expand Down Expand Up @@ -456,6 +502,7 @@ DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_mont_method) {
out->group_finish = ec_GFp_mont_group_finish;
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ec_GFp_mont_point_get_affine_coordinates;
out->jacobian_to_affine_batch = ec_GFp_mont_jacobian_to_affine_batch;
out->add = ec_GFp_mont_add;
out->dbl = ec_GFp_mont_dbl;
out->mul = ec_GFp_mont_mul;
Expand Down
22 changes: 22 additions & 0 deletions crypto/fipsmodule/ec/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,15 @@ void ec_affine_to_jacobian(const EC_GROUP *group, EC_RAW_POINT *out,
int ec_jacobian_to_affine(const EC_GROUP *group, EC_AFFINE *out,
const EC_RAW_POINT *p);

// ec_jacobian_to_affine_batch converts |num| points in |in| from Jacobian
// coordinates to affine coordinates and writes the results to |out|. It returns
// one on success and zero if any of the input points were infinity.
//
// This function is not implemented for all curves. Add implementations as
// needed.
int ec_jacobian_to_affine_batch(const EC_GROUP *group, EC_AFFINE *out,
const EC_RAW_POINT *in, size_t num);

// ec_point_set_affine_coordinates sets |out|'s to a point with affine
// coordinates |x| and |y|. It returns one if the point is on the curve and
// zero otherwise. If the point is not on the curve, the value of |out| is
Expand Down Expand Up @@ -313,6 +322,10 @@ OPENSSL_EXPORT int ec_point_mul_scalar_public(const EC_GROUP *group,
void ec_point_select(const EC_GROUP *group, EC_RAW_POINT *out, BN_ULONG mask,
const EC_RAW_POINT *a, const EC_RAW_POINT *b);

// ec_affine_select behaves like |ec_point_select| but acts on affine points.
void ec_affine_select(const EC_GROUP *group, EC_AFFINE *out, BN_ULONG mask,
const EC_AFFINE *a, const EC_AFFINE *b);

// ec_cmp_x_coordinate compares the x (affine) coordinate of |p|, mod the group
// order, with |r|. It returns one if the values match and zero if |p| is the
// point at infinity of the values do not match.
Expand Down Expand Up @@ -350,6 +363,11 @@ int ec_point_from_uncompressed(const EC_GROUP *group, EC_AFFINE *out,
// external APIs not checking the return value.
void ec_set_to_safe_point(const EC_GROUP *group, EC_RAW_POINT *out);

// ec_affine_jacobian_equal returns one if |a| and |b| represent the same point
// and zero otherwise. It treats both inputs as secret.
int ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
const EC_RAW_POINT *b);


// Implementation details.

Expand All @@ -365,6 +383,10 @@ struct ec_method_st {
int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_RAW_POINT *p,
EC_FELEM *x, EC_FELEM *y);

// jacobian_to_affine_batch implements |ec_jacobian_to_affine_batch|.
int (*jacobian_to_affine_batch)(const EC_GROUP *group, EC_AFFINE *out,
const EC_RAW_POINT *in, size_t num);

// add sets |r| to |a| + |b|.
void (*add)(const EC_GROUP *group, EC_RAW_POINT *r, const EC_RAW_POINT *a,
const EC_RAW_POINT *b);
Expand Down
30 changes: 30 additions & 0 deletions crypto/fipsmodule/ec/simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,36 @@ int ec_GFp_simple_points_equal(const EC_GROUP *group, const EC_RAW_POINT *a,
return equal & 1;
}

int ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
const EC_RAW_POINT *b) {
// If |b| is not infinity, we have to decide whether
// (X_a, Y_a) = (X_b/Z_b^2, Y_b/Z_b^3),
// or equivalently, whether
// (X_a*Z_b^2, Y_a*Z_b^3) = (X_b, Y_b).

void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
const EC_FELEM *b) = group->meth->felem_mul;
void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
group->meth->felem_sqr;

EC_FELEM tmp, Zb2;
felem_sqr(group, &Zb2, &b->Z); // Zb2 = Z_b^2
felem_mul(group, &tmp, &a->X, &Zb2); // tmp = X_a * Z_b^2
ec_felem_sub(group, &tmp, &tmp, &b->X);
const BN_ULONG x_not_equal = ec_felem_non_zero_mask(group, &tmp);

felem_mul(group, &tmp, &a->Y, &Zb2); // tmp = Y_a * Z_b^2
felem_mul(group, &tmp, &tmp, &b->Z); // tmp = Y_a * Z_b^3
ec_felem_sub(group, &tmp, &tmp, &b->Y);
const BN_ULONG y_not_equal = ec_felem_non_zero_mask(group, &tmp);
const BN_ULONG x_and_y_equal = ~(x_not_equal | y_not_equal);

const BN_ULONG b_not_infinity = ec_felem_non_zero_mask(group, &b->Z);

const BN_ULONG equal = b_not_infinity & x_and_y_equal;
return equal & 1;
}

int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_RAW_POINT *p,
const EC_SCALAR *r) {
if (ec_GFp_simple_is_at_infinity(group, p)) {
Expand Down
14 changes: 7 additions & 7 deletions crypto/trust_token/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ extern "C" {
#define PMBTOKEN_NONCE_SIZE 64

typedef struct {
EC_RAW_POINT pub0;
EC_RAW_POINT pub1;
EC_RAW_POINT pubs;
EC_AFFINE pub0;
EC_AFFINE pub1;
EC_AFFINE pubs;
} PMBTOKEN_CLIENT_KEY;

typedef struct {
Expand All @@ -54,17 +54,17 @@ typedef struct {
EC_SCALAR y1;
EC_SCALAR xs;
EC_SCALAR ys;
EC_RAW_POINT pub0;
EC_RAW_POINT pub1;
EC_RAW_POINT pubs;
EC_AFFINE pub0;
EC_AFFINE pub1;
EC_AFFINE pubs;
} PMBTOKEN_ISSUER_KEY;

// PMBTOKEN_PRETOKEN represents the intermediate state a client keeps during a
// PMBToken issuance operation.
typedef struct pmb_pretoken_st {
uint8_t t[PMBTOKEN_NONCE_SIZE];
EC_SCALAR r;
EC_RAW_POINT Tp;
EC_AFFINE Tp;
} PMBTOKEN_PRETOKEN;

// PMBTOKEN_PRETOKEN_free releases the memory associated with |token|.
Expand Down
Loading

0 comments on commit ce1665b

Please sign in to comment.