/*############################################################################
# Copyright 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.
############################################################################*/
/// Implementation of EFq math
/*! \file */
#include "epid/member/tiny/math/efq.h"
#include "epid/member/tiny/math/fq.h"
#include "epid/member/tiny/math/hashwrap.h"
#include "epid/member/tiny/math/mathtypes.h"
#include "epid/member/tiny/math/serialize.h"
#include "epid/member/tiny/math/vli.h"
#include "epid/member/tiny/stdlib/tiny_stdlib.h"
static int EFqMakePoint(EccPointFq* output, FqElem* in) {
FqElem fq_sqrt = {0};
FqElem fq_tmp = {0};
FqSet(&fq_tmp, 3);
FqSquare(&fq_sqrt, in);
FqMul(&fq_sqrt, &fq_sqrt, in);
FqAdd(&fq_sqrt, &fq_sqrt, &fq_tmp);
if (!FqSqrt(&output->y, &fq_sqrt)) {
return 0;
}
FqCp(&output->x, in);
return 1;
}
void EFqMulSSCM(EccPointJacobiFq* result, EccPointJacobiFq const* base,
FpElem const* exp) {
EccPointJacobiFq efqj_1;
EccPointJacobiFq efqj_2;
uint32_t position;
EFqInf(&efqj_1);
EFqJCp(&efqj_2, base);
for (position = 32 * NUM_ECC_DIGITS; position > 0; --position) {
EFqDbl(&efqj_1, &efqj_1);
EFqAdd(&efqj_2, base, &efqj_1);
EFqCondSet(&efqj_1, &efqj_2, &efqj_1,
VliTestBit(&(exp->limbs), position - 1));
}
EFqJCp(result, &efqj_1);
}
int EFqAffineExp(EccPointFq* result, EccPointFq const* base,
FpElem const* exp) {
EccPointJacobiFq efqj;
EFqFromAffine(&efqj, base);
EFqMulSSCM(&efqj, &efqj, exp);
return EFqToAffine(result, &efqj);
}
int EFqAffineMultiExp(EccPointFq* result, EccPointFq const* base0,
FpElem const* exp0, EccPointFq const* base1,
FpElem const* exp1) {
EccPointJacobiFq efqj_base0;
EccPointJacobiFq efqj_base1;
EFqFromAffine(&efqj_base0, base0);
EFqFromAffine(&efqj_base1, base1);
EFqMultiExp(&efqj_base0, &efqj_base0, exp0, &efqj_base1, exp1);
return EFqToAffine(result, &efqj_base0);
}
void EFqMultiExp(EccPointJacobiFq* result, EccPointJacobiFq const* base0,
FpElem const* exp0, EccPointJacobiFq const* base1,
FpElem const* exp1) {
EccPointJacobiFq efqj_base0;
EccPointJacobiFq efqj_a;
EccPointJacobiFq efqj_b;
int i, j;
EFqAdd(&efqj_base0, base0, base1);
EFqInf(&efqj_a);
for (i = NUM_ECC_DIGITS - 1; i >= 0; i--) {
for (j = 31; j >= 0; j--) {
EFqAdd(&efqj_a, &efqj_a, &efqj_a);
EFqInf(&efqj_b);
EFqJCp(&efqj_b, base0);
EFqCondSet(&efqj_b, base1, &efqj_b,
(int)((exp1->limbs.word[i] >> j) & (0x1)));
EFqCondSet(&efqj_b, &efqj_base0, &efqj_b,
(int)((exp0->limbs.word[i] >> j) & (exp1->limbs.word[i] >> j) &
(0x1)));
EFqAdd(&efqj_b, &efqj_a, &efqj_b);
EFqCondSet(&efqj_a, &efqj_b, &efqj_a, (int)(((exp0->limbs.word[i] >> j) |
(exp1->limbs.word[i] >> j)) &
(0x1)));
}
}
EFqJCp(result, &efqj_a);
}
int EFqAffineAdd(EccPointFq* result, EccPointFq const* left,
EccPointFq const* right) {
EccPointJacobiFq efqj_a;
EccPointJacobiFq efqj_b;
if (EFqEqAffine(left, right)) return EFqAffineDbl(result, left);
EFqFromAffine(&efqj_a, left);
EFqFromAffine(&efqj_b, right);
EFqAdd(&efqj_a, &efqj_a, &efqj_b);
return EFqToAffine(result, &efqj_a);
}
int EFqAffineDbl(EccPointFq* result, EccPointFq const* in) {
EccPointJacobiFq efqj_a;
EFqFromAffine(&efqj_a, in);
EFqAdd(&efqj_a, &efqj_a, &efqj_a);
return EFqToAffine(result, &efqj_a);
}
void EFqDbl(EccPointJacobiFq* result, EccPointJacobiFq const* in) {
FqElem fq_a;
FqElem fq_b;
FqAdd(&(result->Z), &(in->Z), &(in->Z));
FqMul(&(result->Z), &(result->Z), &(in->Y));
FqSquare(&fq_a, &(in->X));
FqAdd(&fq_b, &fq_a, &fq_a);
FqAdd(&fq_b, &fq_b, &fq_a);
FqSquare(&fq_a, &(in->Y));
FqAdd(&fq_a, &fq_a, &fq_a);
FqSquare(&(result->Y), &fq_a);
FqAdd(&(result->Y), &(result->Y), &(result->Y));
FqAdd(&fq_a, &fq_a, &fq_a);
FqMul(&fq_a, &fq_a, &(in->X));
FqSquare(&(result->X), &fq_b);
FqSub(&(result->X), &(result->X), &fq_a);
FqSub(&(result->X), &(result->X), &fq_a);
FqSub(&fq_a, &fq_a, &(result->X));
FqMul(&fq_a, &fq_a, &fq_b);
FqSub(&(result->Y), &fq_a, &(result->Y));
}
void EFqAdd(EccPointJacobiFq* result, EccPointJacobiFq const* left,
EccPointJacobiFq const* right) {
FqElem fq0;
FqElem fq1;
FqElem fq2;
FqElem fq3;
FqElem fq4;
FqElem fq5;
if (FqIsZero(&(left->Z))) {
EFqJCp(result, right);
return;
}
if (FqIsZero(&(right->Z))) {
EFqJCp(result, left);
return;
}
FqSquare(&fq2, &(right->Z));
FqSquare(&fq3, &(left->Z));
// P.X * Q.Z^2
FqMul(&fq0, &(left->X), &fq2);
// Q.X * P.Z^2
FqMul(&fq1, &(right->X), &fq3);
// Q.X*P.Z^2 - P*X+Q*Z^2
FqSub(&fq5, &fq1, &fq0);
FqMul(&fq3, &(right->Y), &fq3);
// P.Y * Q.Z^3
FqMul(&fq3, &(left->Z), &fq3);
FqMul(&fq2, &(left->Y), &fq2);
// Q.Y * P.Z^3
FqMul(&fq2, &(right->Z), &fq2);
FqSub(&fq4, &fq3, &fq2);
if (FqIsZero(&fq5)) {
if (FqIsZero(&fq4)) {
EFqDbl(result, left);
return;
} else {
EFqInf(result);
return;
}
}
FqMul(&(result->Z), &(left->Z), &(right->Z));
FqMul(&(result->Z), &(result->Z), &fq5);
// Q.X*P.Z^2 + P*X+Q*Z^2
FqAdd(&fq1, &fq0, &fq1);
FqMul(&fq2, &fq2, &fq5);
FqSquare(&fq5, &fq5);
FqMul(&fq1, &fq1, &fq5);
FqSquare(&(result->X), &fq4);
FqSub(&(result->X), &(result->X), &fq1);
FqMul(&fq2, &fq2, &fq5);
FqMul(&fq0, &fq0, &fq5);
FqSub(&fq0, &fq0, &(result->X));
FqMul(&(result->Y), &fq4, &fq0);
FqSub(&(result->Y), &(result->Y), &fq2);
}
int EFqRand(EccPointFq* result, BitSupplier rnd_func, void* rnd_param) {
FqElem fq;
do {
if (!FqRand(&fq, rnd_func, rnd_param)) {
return 0;
}
} while (!EFqMakePoint(result, &fq));
return 1;
}
void EFqSet(EccPointJacobiFq* result, FqElem const* x, FqElem const* y) {
FqCp(&result->X, x);
FqCp(&result->Y, y);
FqSet(&result->Z, 1);
}
int EFqIsInf(EccPointJacobiFq const* in) {
return FqIsZero(&in->X) && FqIsZero(&in->Z) && (!FqIsZero(&in->Y));
}
void EFqFromAffine(EccPointJacobiFq* result, EccPointFq const* in) {
FqCp(&result->X, &in->x);
FqCp(&result->Y, &in->y);
FqSet(&result->Z, 1);
}
int EFqToAffine(EccPointFq* result, EccPointJacobiFq const* in) {
FqElem fq_inv;
if (EFqIsInf(in)) {
return 0;
}
FqInv(&fq_inv, &in->Z);
FqMul(&result->x, &in->X, &fq_inv);
FqMul(&result->x, &result->x, &fq_inv);
FqMul(&result->y, &in->Y, &fq_inv);
FqMul(&result->y, &result->y, &fq_inv);
FqMul(&result->y, &result->y, &fq_inv);
return 1;
}
void EFqNeg(EccPointJacobiFq* result, EccPointJacobiFq const* in) {
FqCp(&result->X, &in->X);
FqNeg(&result->Y, &in->Y);
FqCp(&result->Z, &in->Z);
}
int EFqEq(EccPointJacobiFq const* left, EccPointJacobiFq const* right) {
FqElem fq1;
FqElem fq2;
FqElem fq3;
FqElem fq4;
if (EFqIsInf(left) && EFqIsInf(right)) {
return 1;
}
if (EFqIsInf(left) || EFqIsInf(right)) {
return 0;
}
// Z1^2
FqSquare(&fq1, &left->Z);
// Z2^2
FqSquare(&fq2, &right->Z);
// (Z1^2)*X2
FqMul(&fq3, &fq1, &right->X);
// (Z2^2)*X1
FqMul(&fq4, &fq2, &left->X);
// Z1^3
FqMul(&fq1, &fq1, &left->Z);
// Z2^3
FqMul(&fq2, &fq2, &right->Z);
// (Z1^3)*Y2
FqMul(&fq1, &fq1, &right->Y);
// (Z2^3)*Y1
FqMul(&fq2, &fq2, &left->Y);
// (Z1^2)*X2 == (Z2^2)*X1 && (Z1^3)*Y2 == (Z2^3)*Y1
return FqEq(&fq1, &fq2) && FqEq(&fq3, &fq4);
}
int EFqHash(EccPointFq* result, unsigned char const* msg, size_t len,
HashAlg hashalg) {
tiny_sha hash_context;
FqElem three;
FqElem tmp;
uint32_t hash_salt = 0;
uint32_t buf = 0;
sha_digest hash_buf;
// 1/q in Fq
FqElem montgomery_r = {
0x512ccfed, 0x2cd6d224, 0xed67f57d, 0xf3239a04,
0x118e5b60, 0xb91a0da1, 0x00030f32, 0,
};
if ((kSha512 != hashalg) && (kSha256 != hashalg)) {
return 0;
}
FqSet(&three, 3);
for (hash_salt = 0; hash_salt < 0xFFFFFFFF; ++hash_salt) {
tinysha_init(hashalg, &hash_context);
Uint32Serialize((OctStr32*)&buf, hash_salt);
tinysha_update(&hash_context, &buf, sizeof(buf));
tinysha_update(&hash_context, msg, len);
tinysha_final(hash_buf.digest, &hash_context);
FqFromHash(&result->x, hash_buf.digest, tinysha_digest_size(&hash_context));
FqSquare(&tmp, &result->x);
FqMul(&tmp, &tmp, &result->x);
FqAdd(&tmp, &tmp, &three);
if (FqSqrt(&result->y, &tmp)) {
FqNeg(&tmp, &result->y);
// Verify and Non-tiny member use montgomery representation to determine
// if negation is needed: this is to be compatible with them
FqMul(&montgomery_r, &result->y, &montgomery_r);
FqCondSet(&result->y, &tmp, &result->y, montgomery_r.limbs.word[0] & 1);
return 1;
}
}
return 0;
}
void EFqCp(EccPointFq* result, EccPointFq const* in) {
FqCp(&result->x, &in->x);
FqCp(&result->y, &in->y);
}
int EFqEqAffine(EccPointFq const* left, EccPointFq const* right) {
return FqEq(&left->x, &right->x) && FqEq(&left->y, &right->y);
}
void EFqCondSet(EccPointJacobiFq* result, EccPointJacobiFq const* true_val,
EccPointJacobiFq const* false_val, int truth_val) {
FqCondSet(&result->X, &true_val->X, &false_val->X, truth_val);
FqCondSet(&result->Y, &true_val->Y, &false_val->Y, truth_val);
FqCondSet(&result->Z, &true_val->Z, &false_val->Z, truth_val);
}
void EFqJCp(EccPointJacobiFq* result, EccPointJacobiFq const* in) {
FqCp(&result->X, &in->X);
FqCp(&result->Y, &in->Y);
FqCp(&result->Z, &in->Z);
}
void EFqInf(EccPointJacobiFq* result) {
FqSet(&result->X, 0);
FqSet(&result->Y, 1);
FqSet(&result->Z, 0);
}
int EFqOnCurve(EccPointFq const* in) {
// test that Y^2 mod q == (X^3 + a*Z^4*X + b*Z^6) mod q
// This simplifies to: Y^2 mod q == (X^3 + 3) mod q
// since: Z = 1
// a = 0
// b = 3
FqElem t1;
FqElem t2;
FqSquare(&t1, &in->x);
FqMul(&t2, &in->x, &t1);
FqSquare(&t1, &in->y);
FqSub(&t1, &t1, &t2);
t1.limbs.word[0] -= 3; // check equal to curve b
// this operation will not always
// result in the same value as T1 - 3
// however it will always result in a correct
// value for the zero check below
return FqIsZero(&t1);
}
int EFqJOnCurve(EccPointJacobiFq const* in) {
FqElem fq1;
FqElem fq2;
FqSquare(&fq1, &in->Z);
FqSquare(&fq2, &fq1);
FqMul(&fq2, &fq2, &fq1); // T2 = Z^6
FqAdd(&fq1, &fq2, &fq2);
FqAdd(&fq1, &fq1, &fq2); // T1 = 3 * Z^6
FqSquare(&fq2, &in->X);
FqMul(&fq2, &fq2, &in->X); // T2 = X^3
FqAdd(&fq1, &fq1, &fq2); // T1 = X^3 + 3 Z^6
FqSquare(&fq2, &in->Y);
FqMul(&fq1, &fq1, &in->Z);
FqMul(&fq2, &fq2, &in->Z);
return FqEq(&fq1, &fq2); // check Y^2 = X^3 + 3 Z^6
}
int EFqJRand(EccPointJacobiFq* result, BitSupplier rnd_func, void* rnd_param) {
FqElem fq;
do {
if (!FqRand(&fq, rnd_func, rnd_param)) {
return 0;
}
} while (!EFqMakePoint((EccPointFq*)result, &fq));
FqSet(&result->Z, 1);
return 1;
}