#include "bee2/core/blob.h"
#include "bee2/core/err.h"
#include "bee2/core/mem.h"
#include "bee2/core/oid.h"
#include "bee2/core/str.h"
#include "bee2/core/util.h"
#include "bee2/crypto/bign.h"
#include "bee2/math/ecp.h"
#include "bee2/math/ww.h"
#include "bee2/math/zz.h"
#include "bign_lcl.h"
err_t bignOidToDER(octet der[], size_t* count, const char* oid)
{
size_t len;
if (!strIsValid(oid) ||
!memIsValid(count, O_PER_S) ||
!memIsNullOrValid(der, *count))
return ERR_BAD_INPUT;
len = oidToDER(0, oid);
if (len == SIZE_MAX)
return ERR_BAD_OID;
if (der)
{
if (*count < len)
return ERR_OUTOFMEMORY;
len = oidToDER(der, oid);
ASSERT(len != SIZE_MAX);
}
*count = len;
return ERR_OK;
}
static size_t bignKeypairGen_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(n + 2 * n) +
ecMulA_deep(n, ec_d, ec_deep, n);
}
err_t bignKeypairGen(octet privkey[], octet pubkey[],
const bign_params* params, gen_i rng, void* rng_state)
{
err_t code;
size_t no, n;
void* state;
ec_o* ec;
word* d;
word* Q;
void* stack;
if (!memIsValid(params, sizeof(bign_params)))
return ERR_BAD_INPUT;
if (!bignIsOperable(params))
return ERR_BAD_PARAMS;
if (rng == 0)
return ERR_BAD_RNG;
state = blobCreate(bignStart_keep(params->l, bignKeypairGen_deep));
if (state == 0)
return ERR_OUTOFMEMORY;
code = bignStart(state, params);
ERR_CALL_HANDLE(code, blobClose(state));
ec = (ec_o*)state;
no = ec->f->no;
n = ec->f->n;
if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no))
{
blobClose(state);
return ERR_BAD_INPUT;
}
d = objEnd(ec, word);
Q = d + n;
stack = Q + 2 * n;
if (!zzRandNZMod(d, ec->f->mod, n, rng, rng_state))
{
blobClose(state);
return ERR_BAD_RNG;
}
if (ecMulA(Q, ec->base, ec, d, n, stack))
{
wwTo(privkey, no, d);
qrTo(pubkey, ecX(Q), ec->f, stack);
qrTo(pubkey + no, ecY(Q, n), ec->f, stack);
}
else
code = ERR_BAD_PARAMS;
blobClose(state);
return code;
}
static size_t bignKeypairVal_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(n + 2 * n) +
ecMulA_deep(n, ec_d, ec_deep, n);
}
err_t bignKeypairVal(const bign_params* params, const octet privkey[],
const octet pubkey[])
{
err_t code;
size_t no, n;
void* state;
ec_o* ec;
word* d;
word* Q;
void* stack;
if (!memIsValid(params, sizeof(bign_params)))
return ERR_BAD_INPUT;
if (!bignIsOperable(params))
return ERR_BAD_PARAMS;
state = blobCreate(bignStart_keep(params->l, bignKeypairVal_deep));
if (state == 0)
return ERR_OUTOFMEMORY;
code = bignStart(state, params);
ERR_CALL_HANDLE(code, blobClose(state));
ec = (ec_o*)state;
no = ec->f->no;
n = ec->f->n;
if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no))
{
blobClose(state);
return ERR_BAD_INPUT;
}
d = objEnd(ec, word);
Q = d + n;
stack = Q + 2 * n;
wwFrom(d, privkey, no);
wwFrom(Q, params->q, no);
if (wwIsZero(d, n) || wwCmp(d, Q, n) >= 0)
{
blobClose(state);
return ERR_BAD_PRIVKEY;
}
if (ecMulA(Q, ec->base, ec, d, n, stack))
{
wwTo(Q, 2 * no, Q);
if (!memEq(Q, pubkey, 2 * no))
code = ERR_BAD_PUBKEY;
}
else
code = ERR_BAD_PARAMS;
blobClose(state);
return code;
}
static size_t bignPubkeyVal_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(2 * n) +
ecpIsOnA_deep(n, f_deep);
}
err_t bignPubkeyVal(const bign_params* params, const octet pubkey[])
{
err_t code;
size_t no, n;
void* state;
ec_o* ec;
word* Q;
void* stack;
if (!memIsValid(params, sizeof(bign_params)))
return ERR_BAD_INPUT;
if (!bignIsOperable(params))
return ERR_BAD_PARAMS;
state = blobCreate(bignStart_keep(params->l, bignPubkeyVal_deep));
if (state == 0)
return ERR_OUTOFMEMORY;
code = bignStart(state, params);
ERR_CALL_HANDLE(code, blobClose(state));
ec = (ec_o*)state;
no = ec->f->no;
n = ec->f->n;
if (!memIsValid(pubkey, 2 * no))
{
blobClose(state);
return ERR_BAD_INPUT;
}
Q = objEnd(ec, word);
stack = Q + 2 * n;
if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
!qrFrom(ecY(Q, n), pubkey + no, ec->f, stack))
{
blobClose(state);
return ERR_BAD_PUBKEY;
}
code = ecpIsOnA(Q, ec, stack) ? ERR_OK : ERR_BAD_PUBKEY;
blobClose(state);
return code;
}
static size_t bignPubkeyCalc_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(n + 2 * n) +
ecMulA_deep(n, ec_d, ec_deep, n);
}
err_t bignPubkeyCalc(octet pubkey[], const bign_params* params,
const octet privkey[])
{
err_t code;
size_t no, n;
void* state;
ec_o* ec;
word* d;
word* Q;
void* stack;
if (!memIsValid(params, sizeof(bign_params)))
return ERR_BAD_INPUT;
if (!bignIsOperable(params))
return ERR_BAD_PARAMS;
state = blobCreate(bignStart_keep(params->l, bignPubkeyCalc_deep));
if (state == 0)
return ERR_OUTOFMEMORY;
code = bignStart(state, params);
ERR_CALL_HANDLE(code, blobClose(state));
ec = (ec_o*)state;
no = ec->f->no;
n = ec->f->n;
if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no))
{
blobClose(state);
return ERR_BAD_INPUT;
}
d = objEnd(ec, word);
Q = d + n;
stack = Q + 2 * n;
wwFrom(d, privkey, no);
if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0)
{
blobClose(state);
return ERR_BAD_PRIVKEY;
}
if (ecMulA(Q, ec->base, ec, d, n, stack))
{
qrTo(pubkey, ecX(Q), ec->f, stack);
qrTo(pubkey + no, ecY(Q, n), ec->f, stack);
}
else
code = ERR_BAD_PARAMS;
blobClose(state);
return code;
}
static size_t bignDH_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(n + 2 * n) +
utilMax(2,
ecpIsOnA_deep(n, f_deep),
ecMulA_deep(n, ec_d, ec_deep, n));
}
err_t bignDH(octet key[], const bign_params* params, const octet privkey[],
const octet pubkey[], size_t key_len)
{
err_t code;
size_t no, n;
void* state;
ec_o* ec;
word* d;
word* Q;
void* stack;
if (!memIsValid(params, sizeof(bign_params)))
return ERR_BAD_INPUT;
if (!bignIsOperable(params))
return ERR_BAD_PARAMS;
state = blobCreate(bignStart_keep(params->l, bignDH_deep));
if (state == 0)
return ERR_OUTOFMEMORY;
code = bignStart(state, params);
ERR_CALL_HANDLE(code, blobClose(state));
ec = (ec_o*)state;
no = ec->f->no;
n = ec->f->n;
if (key_len > 2 * no)
{
blobClose(state);
return ERR_BAD_SHAREDKEY;
}
if (!memIsValid(privkey, no) ||
!memIsValid(pubkey, 2 * no) ||
!memIsValid(key, key_len))
{
blobClose(state);
return ERR_BAD_INPUT;
}
d = objEnd(ec, word);
Q = d + n;
stack = Q + 2 * n;
wwFrom(d, privkey, no);
if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0)
{
blobClose(state);
return ERR_BAD_PRIVKEY;
}
if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
!qrFrom(ecY(Q, n), pubkey + no, ec->f, stack) ||
!ecpIsOnA(Q, ec, stack))
{
blobClose(state);
return ERR_BAD_PUBKEY;
}
if (ecMulA(Q, Q, ec, d, n, stack))
{
qrTo((octet*)Q, ecX(Q), ec->f, stack);
if (key_len > no)
qrTo((octet*)Q + no, ecY(Q, n), ec->f, stack);
memCopy(key, Q, key_len);
}
else
code = ERR_BAD_PARAMS;
blobClose(state);
return code;
}