/*############################################################################
# Copyright 2016-2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
############################################################################*/
/*!
* \file
* \brief Epid11NrVerify implementation.
*/
#include "epid/common/math/hash.h"
#include "epid/common/src/endian_convert.h"
#include "epid/common/src/memory.h"
#include "epid/verifier/1.1/api.h"
#include "epid/verifier/1.1/src/context.h"
#include "ext/ipp/include/ippcp.h"
/// Handle SDK Error with Break
#define BREAK_ON_EPID_ERROR(ret) \
if (kEpidNoErr != (ret)) { \
break; \
}
/// Count of elements in array
#define COUNT_OF(A) (sizeof(A) / sizeof((A)[0]))
#pragma pack(1)
/// Storage for values to create commitment in NrVerify algorithm
typedef struct Epid11NrVerifyCommitValues {
BigNumStr p_tick; //!< A large prime (256-bit)
Epid11G3ElemStr g3; //!< Generator of G3 (512-bit)
Epid11G3ElemStr B; //!< (element of G3): part of basic signature Sigma0
Epid11G3ElemStr K; //!< (element of G3): part of basic signature Sigma0
Epid11G3ElemStr B_tick; //!< (element of G3): one entry in SigRL
Epid11G3ElemStr K_tick; //!< (element of G3): one entry in SigRL
Epid11G3ElemStr T; //!< element of G3
Epid11G3ElemStr R1; //!< element of G3
Epid11G3ElemStr R2; //!< element of G3
uint32_t msg_len; //!< length of the message
uint8_t msg[1]; //!< message
} Epid11NrVerifyCommitValues;
#pragma pack()
EpidStatus Epid11NrVerify(Epid11VerifierCtx const* ctx,
Epid11BasicSignature const* sig, void const* msg,
size_t msg_len, Epid11SigRlEntry const* sigrl_entry,
Epid11NrProof const* proof) {
size_t const cv_header_len =
sizeof(Epid11NrVerifyCommitValues) - sizeof(uint8_t);
Epid11NrVerifyCommitValues* commit_values = NULL;
size_t const commit_len = sizeof(Epid11NrVerifyCommitValues) + msg_len - 1;
EpidStatus res = kEpidErr;
// Epid11 G3 elements
EcPoint* T = NULL;
EcPoint* R1 = NULL;
EcPoint* R2 = NULL;
EcPoint* K = NULL;
EcPoint* B = NULL;
EcPoint* K_tick = NULL;
EcPoint* B_tick = NULL;
// Big integers
BigNum* smu = NULL;
BigNum* snu = NULL;
BigNum* nc_tick_bn = NULL;
Sha256Digest commit_hash;
if (!ctx || !sig || !proof || !sigrl_entry) {
return kEpidBadArgErr;
}
if (!msg && (0 != msg_len)) {
return kEpidBadArgErr;
}
if (msg_len > (UINT_MAX - cv_header_len)) {
return kEpidBadArgErr;
}
if (!ctx->epid11_params) {
return kEpidBadArgErr;
}
do {
bool cmp_result = false;
// handy shorthands:
EcGroup* G3 = ctx->epid11_params->G3;
BigNum* p_tick_bn = ctx->epid11_params->p_tick;
if (!G3 || !p_tick_bn) {
res = kEpidBadArgErr;
BREAK_ON_EPID_ERROR(res);
}
commit_values = SAFE_ALLOC(commit_len);
if (commit_values == NULL) {
res = kEpidMemAllocErr;
break;
}
// 1. We use the following variables T, R1, R2 (elements of G3), and c, smu,
// snu, nc (big integers).
res = NewEcPoint(G3, &T);
BREAK_ON_EPID_ERROR(res);
res = NewEcPoint(G3, &R1);
BREAK_ON_EPID_ERROR(res);
res = NewEcPoint(G3, &R2);
BREAK_ON_EPID_ERROR(res);
res = NewEcPoint(G3, &K);
BREAK_ON_EPID_ERROR(res);
res = NewEcPoint(G3, &B);
BREAK_ON_EPID_ERROR(res);
res = NewEcPoint(G3, &K_tick);
BREAK_ON_EPID_ERROR(res);
res = NewEcPoint(G3, &B_tick);
BREAK_ON_EPID_ERROR(res);
res = NewBigNum(sizeof(proof->smu), &smu);
BREAK_ON_EPID_ERROR(res);
res = NewBigNum(sizeof(proof->smu), &snu);
BREAK_ON_EPID_ERROR(res);
res = NewBigNum(sizeof(FpElemStr), &nc_tick_bn);
BREAK_ON_EPID_ERROR(res);
// 2. The verifier verifies that G3.inGroup(T) = true.
res = ReadEcPoint(G3, &(proof->T), sizeof(proof->T), T);
if (kEpidNoErr != res) {
res = kEpidBadArgErr;
break;
}
// 3. The verifier verifies that G3.isIdentity(T) = false.
res = EcIsIdentity(G3, T, &(cmp_result));
BREAK_ON_EPID_ERROR(res);
if (cmp_result) {
res = kEpidBadArgErr;
break;
}
// 4. The verifier verifies that smu, snu in [0, p'-1].
res = WriteBigNum(ctx->epid11_params->p_tick, sizeof(commit_values->p_tick),
&commit_values->p_tick);
BREAK_ON_EPID_ERROR(res);
if (memcmp(&proof->smu, &commit_values->p_tick, sizeof(FpElemStr)) >= 0 ||
memcmp(&proof->snu, &commit_values->p_tick, sizeof(FpElemStr)) >= 0) {
res = kEpidBadArgErr;
break;
}
// 5. The verifier computes nc = (- c) mod p'.
res = ReadBigNum(&(proof->c), sizeof(proof->c), nc_tick_bn);
BREAK_ON_EPID_ERROR(res);
res = BigNumMod(nc_tick_bn, p_tick_bn, nc_tick_bn);
BREAK_ON_EPID_ERROR(res);
// (-c) mod p' == p' - (c mod p')
res = BigNumSub(p_tick_bn, nc_tick_bn, nc_tick_bn);
BREAK_ON_EPID_ERROR(res);
// 6. The verifier computes R1 = G3.multiExp(K, smu, B, snu).
res = ReadEcPoint(G3, &(sig->K), sizeof(sig->K), K);
if (kEpidNoErr != res) {
res = kEpidBadArgErr;
break;
}
res = ReadEcPoint(G3, &(sig->B), sizeof(sig->B), B);
if (kEpidNoErr != res) {
res = kEpidBadArgErr;
break;
}
res = ReadBigNum(&(proof->smu), sizeof(proof->smu), smu);
BREAK_ON_EPID_ERROR(res);
res = ReadBigNum(&(proof->snu), sizeof(proof->snu), snu);
BREAK_ON_EPID_ERROR(res);
{
EcPoint const* points[2];
BigNum const* exponents[2];
points[0] = K;
points[1] = B;
exponents[0] = smu;
exponents[1] = snu;
res = EcMultiExpBn(G3, points, exponents, COUNT_OF(points), R1);
BREAK_ON_EPID_ERROR(res);
}
// 7. The verifier computes R2 = G3.multiExp(K', smu, B', snu, T, nc).
res = ReadEcPoint(G3, &(sigrl_entry->k), sizeof(sigrl_entry->k), K_tick);
if (kEpidNoErr != res) {
res = kEpidBadArgErr;
break;
}
res = ReadEcPoint(G3, &(sigrl_entry->b), sizeof(sigrl_entry->b), B_tick);
if (kEpidNoErr != res) {
res = kEpidBadArgErr;
break;
}
{
EcPoint const* points[3];
BigNum const* exponents[3];
points[0] = K_tick;
points[1] = B_tick;
points[2] = T;
exponents[0] = smu;
exponents[1] = snu;
exponents[2] = nc_tick_bn;
res = EcMultiExpBn(G3, points, exponents, COUNT_OF(points), R2);
BREAK_ON_EPID_ERROR(res);
}
// 8. The verifier verifies c = Hash(p' || g3 || B || K || B' || K' || T ||
// R1 || R2 || mSize || m).
if (msg) {
// Memory copy is used to copy a message of variable length
if (0 != memcpy_S(&commit_values->msg[0], msg_len, msg, msg_len)) {
res = kEpidBadArgErr;
break;
}
}
commit_values->g3 = ctx->commit_values.g3;
commit_values->B = sig->B;
commit_values->K = sig->K;
commit_values->B_tick = sigrl_entry->b;
commit_values->K_tick = sigrl_entry->k;
commit_values->T = proof->T;
commit_values->msg_len = ntohl(msg_len);
res = WriteEcPoint(G3, R1, &commit_values->R1, sizeof(commit_values->R1));
BREAK_ON_EPID_ERROR(res);
res = WriteEcPoint(G3, R2, &commit_values->R2, sizeof(commit_values->R2));
BREAK_ON_EPID_ERROR(res);
res = Sha256MessageDigest(commit_values, commit_len, &commit_hash);
if (0 != memcmp(&proof->c, &commit_hash, sizeof(proof->c))) {
res = kEpidBadArgErr;
break;
}
} while (0);
SAFE_FREE(commit_values);
DeleteEcPoint(&T);
DeleteEcPoint(&R1);
DeleteEcPoint(&R2);
DeleteEcPoint(&K);
DeleteEcPoint(&B);
DeleteEcPoint(&K_tick);
DeleteEcPoint(&B_tick);
DeleteBigNum(&smu);
DeleteBigNum(&snu);
DeleteBigNum(&nc_tick_bn);
return res;
}