EpidStatus EpidCheckPrivRlEntry(VerifierCtx const* ctx, BasicSignature const* sig, FpElemStr const* f) { EpidStatus result = kEpidErr; EcPoint* b = NULL; EcPoint* k = NULL; EcPoint* t4 = NULL; EcGroup* G1 = NULL; FfElement* ff_elem = NULL; if (!ctx || !sig || !f) { return kEpidBadArgErr; } if (!ctx->epid2_params || !ctx->epid2_params->G1) { return kEpidBadArgErr; } do { // Section 4.1.2 Step 4.b For i = 0, ... , n1-1, the verifier computes t4 // =G1.exp(B, f[i]) and verifies that G1.isEqual(t4, K) = false. bool compare_result = false; FiniteField* Fp = ctx->epid2_params->Fp; G1 = ctx->epid2_params->G1; result = NewFfElement(Fp, &ff_elem); if (kEpidNoErr != result) { break; } result = NewEcPoint(G1, &b); if (kEpidNoErr != result) { break; } result = NewEcPoint(G1, &k); if (kEpidNoErr != result) { break; } result = NewEcPoint(G1, &t4); if (kEpidNoErr != result) { break; } // ReadFfElement checks that the value f is in the field result = ReadFfElement(Fp, (BigNumStr const*)f, sizeof(BigNumStr), ff_elem); if (kEpidNoErr != result) { break; } result = ReadEcPoint(G1, &sig->B, sizeof(sig->B), b); if (kEpidNoErr != result) { break; } result = ReadEcPoint(G1, &sig->K, sizeof(sig->K), k); if (kEpidNoErr != result) { break; } result = EcExp(G1, b, (BigNumStr const*)f, t4); if (kEpidNoErr != result) { break; } result = EcIsEqual(G1, t4, k, &compare_result); if (kEpidNoErr != result) { break; } // if t4 == k, sig revoked in PrivRl if (compare_result) { result = kEpidSigRevokedInPrivRl; } else { result = kEpidNoErr; } } while (0); DeleteFfElement(&ff_elem); DeleteEcPoint(&t4); DeleteEcPoint(&k); DeleteEcPoint(&b); return result; }
EpidStatus EpidRequestJoin(GroupPubKey const* pub_key, IssuerNonce const* ni, FpElemStr const* f, BitSupplier rnd_func, void* rnd_param, HashAlg hash_alg, JoinRequest* join_request) { EpidStatus sts; static const BigNumStr one = { {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}}; BigNumStr r_str; JoinPCommitValues commit_values; Epid2Params_* params = NULL; FfElement* r_el = NULL; FfElement* f_el = NULL; FfElement* c_el = NULL; FfElement* cf_el = NULL; FfElement* s_el = NULL; EcPoint* f_pt = NULL; EcPoint* r_pt = NULL; EcPoint* h1_pt = NULL; if (!pub_key || !ni || !f || !rnd_func || !join_request) { return kEpidBadArgErr; } if (kSha256 != hash_alg && kSha384 != hash_alg && kSha512 != hash_alg) { return kEpidBadArgErr; } do { sts = CreateEpid2Params(¶ms); BREAK_ON_EPID_ERROR(sts); if (!params->Fp || !params->G1) { sts = kEpidBadArgErr; break; } sts = NewFfElement(params->Fp, &r_el); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(params->Fp, &f_el); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(params->Fp, &c_el); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(params->Fp, &cf_el); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(params->Fp, &s_el); BREAK_ON_EPID_ERROR(sts); sts = NewEcPoint(params->G1, &f_pt); BREAK_ON_EPID_ERROR(sts); sts = NewEcPoint(params->G1, &h1_pt); BREAK_ON_EPID_ERROR(sts); sts = NewEcPoint(params->G1, &r_pt); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(params->Fp, (uint8_t const*)f, sizeof(*f), f_el); BREAK_ON_EPID_ERROR(sts); sts = ReadEcPoint(params->G1, (uint8_t*)&pub_key->h1, sizeof(pub_key->h1), h1_pt); BREAK_ON_EPID_ERROR(sts); // Step 1. The member chooses a random integer r from [1, p-1]. sts = FfGetRandom(params->Fp, &one, rnd_func, rnd_param, r_el); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(params->Fp, r_el, (uint8_t*)&r_str, sizeof(r_str)); // Step 2. The member computes F = G1.sscmExp(h1, f). sts = EcExp(params->G1, h1_pt, (BigNumStr const*)f, f_pt); BREAK_ON_EPID_ERROR(sts); // Step 3. The member computes R = G1.sscmExp(h1, r). sts = EcExp(params->G1, h1_pt, (BigNumStr const*)&r_str, r_pt); BREAK_ON_EPID_ERROR(sts); // Step 4. The member computes c = Fp.hash(p || g1 || g2 || h1 || h2 || w || // F || R || NI). Refer to Section 7.1 for hash operation over a prime // field. sts = WriteBigNum(params->p, sizeof(commit_values.p), (uint8_t*)&commit_values.p); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(params->G1, params->g1, (uint8_t*)&commit_values.g1, sizeof(commit_values.g1)); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(params->G2, params->g2, (uint8_t*)&commit_values.g2, sizeof(commit_values.g2)); BREAK_ON_EPID_ERROR(sts); commit_values.h1 = pub_key->h1; commit_values.h2 = pub_key->h2; commit_values.w = pub_key->w; sts = WriteEcPoint(params->G1, f_pt, (uint8_t*)&commit_values.F, sizeof(commit_values.F)); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(params->G1, r_pt, (uint8_t*)&commit_values.R, sizeof(commit_values.R)); BREAK_ON_EPID_ERROR(sts); commit_values.NI = *ni; sts = FfHash(params->Fp, (uint8_t*)&commit_values, sizeof(commit_values), hash_alg, c_el); BREAK_ON_EPID_ERROR(sts); // Step 5. The member computes s = (r + c * f) mod p. sts = FfMul(params->Fp, c_el, f_el, cf_el); BREAK_ON_EPID_ERROR(sts); sts = FfAdd(params->Fp, r_el, cf_el, s_el); BREAK_ON_EPID_ERROR(sts); // Step 6. The output join request is (F, c, s). sts = WriteFfElement(params->Fp, c_el, (uint8_t*)&join_request->c, sizeof(join_request->c)); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(params->Fp, s_el, (uint8_t*)&join_request->s, sizeof(join_request->s)); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(params->G1, f_pt, (uint8_t*)&join_request->F, sizeof(join_request->F)); BREAK_ON_EPID_ERROR(sts); sts = kEpidNoErr; } while (0); DeleteEcPoint(&h1_pt); DeleteEcPoint(&r_pt); DeleteEcPoint(&f_pt); DeleteFfElement(&s_el); DeleteFfElement(&cf_el); DeleteFfElement(&c_el); DeleteFfElement(&f_el); DeleteFfElement(&r_el); DeleteEpid2Params(¶ms); return sts; }
EpidStatus EpidComputePreSig(MemberCtx const* ctx, PreComputedSignature* precompsig) { EpidStatus res = kEpidNotImpl; EcPoint* B = NULL; EcPoint* K = NULL; EcPoint* T = NULL; EcPoint* R1 = NULL; FfElement* R2 = NULL; FfElement* a = NULL; FfElement* b = NULL; FfElement* rx = NULL; FfElement* rf = NULL; FfElement* ra = NULL; FfElement* rb = NULL; FfElement* t1 = NULL; FfElement* t2 = NULL; FfElement* f = NULL; if (!ctx || !precompsig) return kEpidBadArgErr; if (!ctx->epid2_params || !ctx->pub_key || !ctx->priv_key) return kEpidBadArgErr; do { // handy shorthands: EcGroup* G1 = ctx->epid2_params->G1; FiniteField* GT = ctx->epid2_params->GT; FiniteField* Fp = ctx->epid2_params->Fp; EcPoint* h2 = ctx->pub_key->h2; EcPoint* A = ctx->priv_key->A; FfElement* x = ctx->priv_key->x; BigNumStr f_str = {0}; BigNumStr a_str = {0}; BigNumStr t1_str = {0}; BigNumStr rf_str = {0}; BigNumStr t2_str = {0}; BigNumStr ra_str = {0}; static const BigNumStr one = { {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}}; if (!G1 || !GT || !Fp || !h2 || !A || !x || !ctx->priv_key->f || !ctx->e12 || !ctx->e22 || !ctx->e2w || !ctx->ea2) { res = kEpidBadArgErr; BREAK_ON_EPID_ERROR(res); } f = ctx->priv_key->f; // The following variables B, K, T, R1 (elements of G1), R2 // (elements of GT), a, b, rx, rf, ra, rb, t1, t2 (256-bit // integers) are used. res = NewEcPoint(G1, &B); BREAK_ON_EPID_ERROR(res); res = NewEcPoint(G1, &K); BREAK_ON_EPID_ERROR(res); res = NewEcPoint(G1, &T); BREAK_ON_EPID_ERROR(res); res = NewEcPoint(G1, &R1); BREAK_ON_EPID_ERROR(res); res = NewFfElement(GT, &R2); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &a); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &b); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &rx); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &rf); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &ra); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &rb); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &t1); BREAK_ON_EPID_ERROR(res); res = NewFfElement(Fp, &t2); BREAK_ON_EPID_ERROR(res); // 1. The member expects the pre-computation is done (e12, e22, e2w, // ea2). Refer to Section 3.5 for the computation of these // values. // 2. The member verifies gid in public key matches gid in private // key. // 3. The member computes B = G1.getRandom(). res = EcGetRandom(G1, ctx->rnd_func, ctx->rnd_param, B); BREAK_ON_EPID_ERROR(res); // 4. The member computes K = G1.sscmExp(B, f). res = WriteFfElement(Fp, f, &f_str, sizeof(f_str)); BREAK_ON_EPID_ERROR(res); res = EcExp(G1, B, &f_str, K); BREAK_ON_EPID_ERROR(res); // 5. The member chooses randomly an integers a from [1, p-1]. res = FfGetRandom(Fp, &one, ctx->rnd_func, ctx->rnd_param, a); BREAK_ON_EPID_ERROR(res); // 6. The member computes T = G1.sscmExp(h2, a). res = WriteFfElement(Fp, a, &a_str, sizeof(a_str)); BREAK_ON_EPID_ERROR(res); res = EcExp(G1, h2, &a_str, T); BREAK_ON_EPID_ERROR(res); // 7. The member computes T = G1.mul(T, A). res = EcMul(G1, T, A, T); BREAK_ON_EPID_ERROR(res); // 8. The member computes b = (a * x) mod p. res = FfMul(Fp, a, x, b); BREAK_ON_EPID_ERROR(res); // 9. The member chooses rx, rf, ra, rb randomly from [1, p-1]. res = FfGetRandom(Fp, &one, ctx->rnd_func, ctx->rnd_param, rx); BREAK_ON_EPID_ERROR(res); res = FfGetRandom(Fp, &one, ctx->rnd_func, ctx->rnd_param, rf); BREAK_ON_EPID_ERROR(res); res = FfGetRandom(Fp, &one, ctx->rnd_func, ctx->rnd_param, ra); BREAK_ON_EPID_ERROR(res); res = FfGetRandom(Fp, &one, ctx->rnd_func, ctx->rnd_param, rb); BREAK_ON_EPID_ERROR(res); // 10. The member computes t1 = (- rx) mod p. res = FfNeg(Fp, rx, t1); BREAK_ON_EPID_ERROR(res); // 11. The member computes t2 = (rb - a * rx) mod p. res = FfMul(Fp, a, rx, t2); BREAK_ON_EPID_ERROR(res); res = FfNeg(Fp, t2, t2); BREAK_ON_EPID_ERROR(res); res = FfAdd(Fp, rb, t2, t2); BREAK_ON_EPID_ERROR(res); // 12. The member computes R1 = G1.sscmExp(B, rf). res = WriteFfElement(Fp, rf, &rf_str, sizeof(rf_str)); BREAK_ON_EPID_ERROR(res); res = EcExp(G1, B, &rf_str, R1); BREAK_ON_EPID_ERROR(res); // 13. The member computes R2 = GT.sscmMultiExp(ea2, t1, e12, rf, // e22, t2, e2w, ra). res = WriteFfElement(Fp, t1, &t1_str, sizeof(t1_str)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, t2, &t2_str, sizeof(t2_str)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, ra, &ra_str, sizeof(ra_str)); BREAK_ON_EPID_ERROR(res); { FfElement const* points[4]; BigNumStr const* exponents[4]; points[0] = ctx->ea2; points[1] = ctx->e12; points[2] = ctx->e22; points[3] = ctx->e2w; exponents[0] = &t1_str; exponents[1] = &rf_str; exponents[2] = &t2_str; exponents[3] = &ra_str; res = FfMultiExp(GT, points, exponents, COUNT_OF(points), R2); BREAK_ON_EPID_ERROR(res); } // 14. The member sets and outputs pre-sigma = (B, K, T, a, b, rx, // rf, ra, rb, R1, R2). res = WriteEcPoint(G1, B, &precompsig->B, sizeof(precompsig->B)); BREAK_ON_EPID_ERROR(res); res = WriteEcPoint(G1, K, &precompsig->K, sizeof(precompsig->K)); BREAK_ON_EPID_ERROR(res); res = WriteEcPoint(G1, T, &precompsig->T, sizeof(precompsig->T)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, a, &precompsig->a, sizeof(precompsig->a)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, b, &precompsig->b, sizeof(precompsig->b)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, rx, &precompsig->rx, sizeof(precompsig->rx)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, rf, &precompsig->rf, sizeof(precompsig->rf)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, ra, &precompsig->ra, sizeof(precompsig->ra)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(Fp, rb, &precompsig->rb, sizeof(precompsig->rb)); BREAK_ON_EPID_ERROR(res); res = WriteEcPoint(G1, R1, &precompsig->R1, sizeof(precompsig->R1)); BREAK_ON_EPID_ERROR(res); res = WriteFfElement(GT, R2, &precompsig->R2, sizeof(precompsig->R2)); BREAK_ON_EPID_ERROR(res); // 15. The member stores pre-sigma in the secure storage of the // member. res = kEpidNoErr; } while (0); f = NULL; DeleteEcPoint(&B); DeleteEcPoint(&K); DeleteEcPoint(&T); DeleteEcPoint(&R1); DeleteFfElement(&R2); DeleteFfElement(&a); DeleteFfElement(&b); DeleteFfElement(&rx); DeleteFfElement(&rf); DeleteFfElement(&ra); DeleteFfElement(&rb); DeleteFfElement(&t1); DeleteFfElement(&t2); return (res); }
EpidStatus Tpm2LoadExternal(Tpm2Ctx* ctx, FpElemStr const* f_str) { EpidStatus sts = kEpidErr; TPM_RC rc = TPM_RC_SUCCESS; EcPoint* pub = NULL; FfElement* f = NULL; TPMI_ALG_HASH tpm_hash_alg = TPM_ALG_NULL; if (!ctx || !ctx->epid2_params || !f_str) { return kEpidBadArgErr; } do { LoadExternal_In in = {0}; LoadExternal_Out out; G1ElemStr pub_str = {0}; TPMS_ECC_PARMS* ecc_details = &in.inPublic.publicArea.parameters.eccDetail; EcGroup* G1 = ctx->epid2_params->G1; EcPoint* g1 = ctx->epid2_params->g1; sts = NewFfElement(ctx->epid2_params->Fp, &f); BREAK_ON_EPID_ERROR(sts); // verify that f is valid sts = ReadFfElement(ctx->epid2_params->Fp, f_str, sizeof(*f_str), f); BREAK_ON_EPID_ERROR(sts); if (ctx->key_handle) { FlushContext_In in_fc; in_fc.flushHandle = ctx->key_handle; TSS_Execute(ctx->tss, NULL, (COMMAND_PARAMETERS*)&in_fc, NULL, TPM_CC_FlushContext, TPM_RH_NULL, NULL, 0); if (rc != TPM_RC_SUCCESS) { print_tpm2_response_code("TPM2_FlushContext", rc); } ctx->key_handle = 0; } sts = NewEcPoint(G1, &pub); BREAK_ON_EPID_ERROR(sts); sts = EcExp(G1, g1, (BigNumStr const*)f_str, pub); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(G1, pub, &pub_str, sizeof(pub_str)); BREAK_ON_EPID_ERROR(sts); tpm_hash_alg = EpidtoTpm2HashAlg(ctx->hash_alg); if (tpm_hash_alg == TPM_ALG_NULL) { sts = kEpidHashAlgorithmNotSupported; break; } in.hierarchy = TPM_RH_NULL; in.inPublic.size = sizeof(TPM2B_PUBLIC); in.inPublic.publicArea.type = TPM_ALG_ECC; in.inPublic.publicArea.nameAlg = tpm_hash_alg; in.inPublic.publicArea.objectAttributes.val = TPMA_OBJECT_NODA | TPMA_OBJECT_USERWITHAUTH | TPMA_OBJECT_SIGN; in.inPublic.publicArea.authPolicy.t.size = 0; ecc_details->symmetric.algorithm = TPM_ALG_NULL; ecc_details->scheme.scheme = TPM_ALG_ECDAA; ecc_details->scheme.details.ecdaa.hashAlg = tpm_hash_alg; ecc_details->scheme.details.ecdaa.count = 0; ecc_details->curveID = TPM_ECC_BN_P256; ecc_details->kdf.scheme = TPM_ALG_NULL; sts = ReadTpm2FfElement(&pub_str.x.data, &in.inPublic.publicArea.unique.ecc.x); BREAK_ON_EPID_ERROR(sts); sts = ReadTpm2FfElement(&pub_str.y.data, &in.inPublic.publicArea.unique.ecc.y); BREAK_ON_EPID_ERROR(sts); in.inPrivate.t.size = sizeof(in.inPrivate.t.sensitiveArea); in.inPrivate.t.sensitiveArea.sensitiveType = TPM_ALG_ECC; sts = ReadTpm2FfElement(&f_str->data, &in.inPrivate.t.sensitiveArea.sensitive.ecc); BREAK_ON_EPID_ERROR(sts); rc = TSS_Execute(ctx->tss, (RESPONSE_PARAMETERS*)&out, (COMMAND_PARAMETERS*)&in, NULL, TPM_CC_LoadExternal, TPM_RH_NULL, NULL, 0); if (rc != TPM_RC_SUCCESS) { print_tpm2_response_code("TPM2_LoadExternal", rc); if (TPM_RC_BINDING == rc || TPM_RC_ECC_POINT == rc || TPM_RC_KEY_SIZE == rc) sts = kEpidBadArgErr; else sts = kEpidErr; break; } ctx->key_handle = out.objectHandle; } while (0); DeleteEcPoint(&pub); DeleteFfElement(&f); return sts; }