6#include "irmaverifier_p.h"
7#include "irmapublickey_p.h"
9#include "openssl/bignum_p.h"
11#include <QCryptographicHash>
16IrmaProof::IrmaProof() =
default;
18bool IrmaProof::isNull()
const
20 return !C || !A || !EResponse || !VResponse
21 || std::any_of(AResponses.begin(), AResponses.end(), [](
const auto &n) ->
bool { return !n; })
22 || std::any_of(ADisclosed.begin(), ADisclosed.end(), [](
const auto &n) ->
bool { return !n; });
26static bool checkResponseSize(
const IrmaProof &proof,
const IrmaPublicKey &pubKey)
28 if (std::any_of(proof.AResponses.begin(), proof.AResponses.end(), [&pubKey](
const auto &ares) {
29 return BN_num_bits(ares.get()) > pubKey.LmCommit();
31 qDebug() <<
"AResponse entry too large";
35 if (BN_num_bits(proof.EResponse.get()) > pubKey.LeCommit()) {
36 qDebug() <<
"EResponse too large";
45static openssl::bn_ptr calculateTimeBasedChallenge(int64_t timestamp)
49 return Bignum::fromByteArray(h);
53static openssl::bn_ptr bignum_sha256(
const openssl::bn_ptr &in)
56 return Bignum::fromByteArray(h);
60static openssl::bn_ptr reconstructZ(
const IrmaProof &proof,
const IrmaPublicKey &pubKey)
62 openssl::bn_ctx_ptr bnCtx(BN_CTX_new());
64 openssl::bn_ptr numerator(BN_new()), tmp(BN_new());
65 BN_one(numerator.get());
66 BN_lshift(tmp.get(), numerator.get(), pubKey.Le() - 1);
67 std::swap(tmp, numerator);
69 BN_mod_exp(tmp.get(), proof.A.get(), numerator.get(), pubKey.N.get(), bnCtx.get());
70 std::swap(tmp, numerator);
72 for (std::size_t i = 0; i < proof.ADisclosed.size(); ++i) {
74 if (BN_num_bits(proof.ADisclosed[i].get()) > pubKey.Lm()) {
75 exp = bignum_sha256(proof.ADisclosed[i]);
78 BN_mod_exp(tmp.get(), pubKey.R[i+1].get(), exp ? exp.get() : proof.ADisclosed[i].get(), pubKey.N.get(), bnCtx.get());
79 openssl::bn_ptr tmp2(BN_new());
80 BN_mul(tmp2.get(), numerator.get(), tmp.get(), bnCtx.get());
81 std::swap(tmp2, numerator);
84 openssl::bn_ptr known(BN_new());
85 BN_mod_inverse(known.get(), numerator.get(), pubKey.N.get(), bnCtx.get());
86 BN_mul(tmp.get(), pubKey.Z.get(), known.get(), bnCtx.get());
87 std::swap(tmp, known);
89 openssl::bn_ptr knownC(BN_new());
90 BN_mod_inverse(tmp.get(), known.get(), pubKey.N.get(), bnCtx.get());
91 BN_mod_exp(knownC.get(), tmp.get(), proof.C.get(), pubKey.N.get(), bnCtx.get());
93 openssl::bn_ptr Ae(BN_new());
94 BN_mod_exp(Ae.get(), proof.A.get(), proof.EResponse.get(), pubKey.N.get(), bnCtx.get());
95 openssl::bn_ptr Sv(BN_new());
96 BN_mod_exp(Sv.get(), pubKey.S.get(), proof.VResponse.get(), pubKey.N.get(), bnCtx.get());
98 openssl::bn_ptr Rs(BN_new());
100 for (std::size_t i = 0; i < proof.AResponses.size(); ++i) {
101 openssl::bn_ptr tmp2(BN_new());
102 BN_mod_exp(tmp2.get(), pubKey.R[i].get(), proof.AResponses[i].get(), pubKey.N.get(), bnCtx.get());
103 BN_mul(tmp.get(), Rs.get(), tmp2.get(), bnCtx.get());
107 openssl::bn_ptr Z(BN_new());
108 BN_mul(Z.get(), knownC.get(), Ae.get(), bnCtx.get());
110 BN_mul(tmp.get(), Z.get(), Rs.get(), bnCtx.get());
112 BN_mod_mul(tmp.get(), Z.get(), Sv.get(), pubKey.N.get(), bnCtx.get());
118static QByteArray asn1EncodeSequence(
const std::vector<const BIGNUM*> &numbers)
121 for (
auto number : numbers) {
122 openssl::asn1_integer_ptr num(BN_to_ASN1_INTEGER(number,
nullptr));
123 openssl::asn1_type_ptr obj(ASN1_TYPE_new());
124 ASN1_TYPE_set(obj.get(), V_ASN1_INTEGER, num.release());
126 uint8_t *buffer =
nullptr;
127 const auto size = i2d_ASN1_TYPE(obj.get(), &buffer);
128 payloadBuffer.
append(
reinterpret_cast<const char*
>(buffer), size);
133 result.
resize(ASN1_object_size(1, payloadBuffer.
size(), V_ASN1_SEQUENCE));
134 auto resultIt =
reinterpret_cast<uint8_t*
>(result.
data());
135 ASN1_put_object(&resultIt, 1, payloadBuffer.
size(), V_ASN1_SEQUENCE, 0);
136 std::memcpy(resultIt, payloadBuffer.
constData(), payloadBuffer.
size());
141bool IrmaVerifier::verify(
const IrmaProof &proof,
const IrmaPublicKey &pubKey)
143 if (!checkResponseSize(proof, pubKey)) {
147 openssl::bn_ptr context(BN_new());
148 BN_one(context.get());
150 const auto timeBasedChallenge = calculateTimeBasedChallenge(proof.disclosureTime);
151 const auto Z = reconstructZ(proof, pubKey);
154 openssl::bn_ptr numElements(BN_new());
155 BN_set_word(numElements.get(), 4);
157 const auto encoded = asn1EncodeSequence({numElements.get(), context.get(), proof.A.get(), Z.get(), timeBasedChallenge.get()});
160 const auto proofC = Bignum::toByteArray(proof.C);
161 return proofC == challenge;
QByteArray & append(QByteArrayView data)
const char * constData() const const
QByteArray number(double n, char format, int precision)
void resize(qsizetype newSize, char c)
qsizetype size() const const
QByteArray hash(QByteArrayView data, Algorithm method)