in crypto/trust_token/pmbtoken.c [927:1071]
static STACK_OF(TRUST_TOKEN) *pmbtoken_unblind(
const PMBTOKEN_METHOD *method, const TRUST_TOKEN_CLIENT_KEY *key,
const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
uint32_t key_id) {
const EC_GROUP *group = method->group;
if (count > sk_TRUST_TOKEN_PRETOKEN_num(pretokens)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
return NULL;
}
int ok = 0;
STACK_OF(TRUST_TOKEN) *ret = sk_TRUST_TOKEN_new_null();
EC_JACOBIAN *Tps = OPENSSL_calloc(count, sizeof(EC_JACOBIAN));
EC_JACOBIAN *Sps = OPENSSL_calloc(count, sizeof(EC_JACOBIAN));
EC_JACOBIAN *Wps = OPENSSL_calloc(count, sizeof(EC_JACOBIAN));
EC_JACOBIAN *Wsps = OPENSSL_calloc(count, sizeof(EC_JACOBIAN));
EC_SCALAR *es = OPENSSL_calloc(count, sizeof(EC_SCALAR));
CBB batch_cbb;
CBB_zero(&batch_cbb);
if (ret == NULL ||
Tps == NULL ||
Sps == NULL ||
Wps == NULL ||
Wsps == NULL ||
es == NULL ||
!CBB_init(&batch_cbb, 0) ||
!point_to_cbb(&batch_cbb, method->group, &key->pubs) ||
!point_to_cbb(&batch_cbb, method->group, &key->pub0) ||
!point_to_cbb(&batch_cbb, method->group, &key->pub1)) {
goto err;
}
for (size_t i = 0; i < count; i++) {
const TRUST_TOKEN_PRETOKEN *pretoken =
sk_TRUST_TOKEN_PRETOKEN_value(pretokens, i);
uint8_t s[TRUST_TOKEN_NONCE_SIZE];
EC_AFFINE Wp_affine, Wsp_affine;
if (!CBS_copy_bytes(cbs, s, TRUST_TOKEN_NONCE_SIZE) ||
!cbs_get_prefixed_point(cbs, group, &Wp_affine, method->prefix_point) ||
!cbs_get_prefixed_point(cbs, group, &Wsp_affine,
method->prefix_point)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
goto err;
}
ec_affine_to_jacobian(group, &Tps[i], &pretoken->Tp);
ec_affine_to_jacobian(group, &Wps[i], &Wp_affine);
ec_affine_to_jacobian(group, &Wsps[i], &Wsp_affine);
if (!method->hash_s(group, &Sps[i], &pretoken->Tp, s)) {
goto err;
}
EC_AFFINE Sp_affine;
if (!point_to_cbb(&batch_cbb, group, &pretoken->Tp) ||
!ec_jacobian_to_affine(group, &Sp_affine, &Sps[i]) ||
!point_to_cbb(&batch_cbb, group, &Sp_affine) ||
!point_to_cbb(&batch_cbb, group, &Wp_affine) ||
!point_to_cbb(&batch_cbb, group, &Wsp_affine)) {
goto err;
}
// Unblind the token.
EC_JACOBIAN jacobians[3];
EC_AFFINE affines[3];
if (!ec_point_mul_scalar(group, &jacobians[0], &Sps[i], &pretoken->r) ||
!ec_point_mul_scalar(group, &jacobians[1], &Wps[i], &pretoken->r) ||
!ec_point_mul_scalar(group, &jacobians[2], &Wsps[i], &pretoken->r) ||
!ec_jacobian_to_affine_batch(group, affines, jacobians, 3)) {
goto err;
}
// Serialize the token. Include |key_id| to avoid an extra copy in the layer
// above.
CBB token_cbb;
size_t point_len = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBB_init(&token_cbb,
4 + TRUST_TOKEN_NONCE_SIZE + 3 * (2 + point_len)) ||
!CBB_add_u32(&token_cbb, key_id) ||
!CBB_add_bytes(&token_cbb, pretoken->salt, TRUST_TOKEN_NONCE_SIZE) ||
!cbb_add_prefixed_point(&token_cbb, group, &affines[0],
method->prefix_point) ||
!cbb_add_prefixed_point(&token_cbb, group, &affines[1],
method->prefix_point) ||
!cbb_add_prefixed_point(&token_cbb, group, &affines[2],
method->prefix_point) ||
!CBB_flush(&token_cbb)) {
CBB_cleanup(&token_cbb);
goto err;
}
TRUST_TOKEN *token =
TRUST_TOKEN_new(CBB_data(&token_cbb), CBB_len(&token_cbb));
CBB_cleanup(&token_cbb);
if (token == NULL ||
!sk_TRUST_TOKEN_push(ret, token)) {
TRUST_TOKEN_free(token);
goto err;
}
}
// The DLEQ batching construction is described in appendix B of
// https://eprint.iacr.org/2020/072/20200324:214215. Note the additional
// computations all act on public inputs.
for (size_t i = 0; i < count; i++) {
if (!hash_c_batch(method, &es[i], &batch_cbb, i)) {
goto err;
}
}
EC_JACOBIAN Tp_batch, Sp_batch, Wp_batch, Wsp_batch;
if (!ec_point_mul_scalar_public_batch(group, &Tp_batch,
/*g_scalar=*/NULL, Tps, es, count) ||
!ec_point_mul_scalar_public_batch(group, &Sp_batch,
/*g_scalar=*/NULL, Sps, es, count) ||
!ec_point_mul_scalar_public_batch(group, &Wp_batch,
/*g_scalar=*/NULL, Wps, es, count) ||
!ec_point_mul_scalar_public_batch(group, &Wsp_batch,
/*g_scalar=*/NULL, Wsps, es, count)) {
goto err;
}
CBS proof;
if (!CBS_get_u16_length_prefixed(cbs, &proof) ||
!dleq_verify(method, &proof, key, &Tp_batch, &Sp_batch, &Wp_batch,
&Wsp_batch) ||
CBS_len(&proof) != 0) {
goto err;
}
ok = 1;
err:
OPENSSL_free(Tps);
OPENSSL_free(Sps);
OPENSSL_free(Wps);
OPENSSL_free(Wsps);
OPENSSL_free(es);
CBB_cleanup(&batch_cbb);
if (!ok) {
sk_TRUST_TOKEN_pop_free(ret, TRUST_TOKEN_free);
ret = NULL;
}
return ret;
}