void fp2sqr_mont(const f2elm_t *a, f2elm_t *c) { // GF(p^2) squaring using Montgomery arithmetic, c = a^2 in GF(p^2). // Inputs: a = a0+a1*i, where a0, a1 are in [0, 2*p-1] // Output: c = c0+c1*i, where c0, c1 are in [0, 2*p-1] felm_t t1, t2, t3; mp_addfast(a->e[0], a->e[1], t1); // t1 = a0+a1 fpsub(a->e[0], a->e[1], t2); // t2 = a0-a1 mp_addfast(a->e[0], a->e[0], t3); // t3 = 2a0 fpmul_mont(t1, t2, c->e[0]); // c0 = (a0+a1)(a0-a1) fpmul_mont(t3, a->e[1], c->e[1]); // c1 = 2a0*a1 }
enum RPNError rpn_run(byte *rpnExpr, word rpnLen, Float *yValue, Float *xValue) { rpnStackIndex = 0; word reader = 0; while (reader < rpnLen) { byte op = rpnExpr[reader++]; switch (op) { case RPN_VAR: // put a copy of the independent variable's value on rpnStack if (rpnStackIndex == RPN_STACK_SIZE) return RPN_ERR_OVERFLOW; rpn_push(xValue); break; case RPN_FUNC: { if (rpnStackIndex < 1) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 1)); byte funcIndex = rpnExpr[reader++]; if (funcIndex == UNKNOWN_FUNCTION_INDEX) { --reader; return RPN_ERR_INVALID_FUNC; } // Check the argument (FP0). void *check = knownFunctions[funcIndex].checkArgFuncPtr; if (check) { enum RPNError e = (*check)(); // check FP0 if (e != RPN_ERR_NONE) return e; } // Argument (FP0) is valid. Apply the function to it. (*knownFunctions[funcIndex].evalFuncPtr)(); --rpnStackIndex; rpn_push(FP0ADDR); // push the result break; } case RPN_NUM: // put FP that follows on rpnStack if (rpnStackIndex == RPN_STACK_SIZE) return RPN_ERR_OVERFLOW; rpn_push((Float *) (rpnExpr + reader)); // push 6-byte accumulator reader += sizeof(Float); break; case RPN_ADD: case RPN_SUB: case RPN_MUL: if (rpnStackIndex < 2) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 2)); fp1load(rpn_get(rpnStackIndex - 1)); switch (op) { case RPN_ADD: fpadd(); break; case RPN_SUB: fpsub(); break; case RPN_MUL: fpmul(); break; } rpnStackIndex -= 2; rpn_push(FP0ADDR); // push the result break; case RPN_DIV: { if (rpnStackIndex < 2) return RPN_ERR_UNDERFLOW; // Check if the divisor is too close to zero Float *divisor = rpn_get(rpnStackIndex - 1); fp0load(divisor); fpabs(); if (fpcmp(&verySmall) < 0) // if abs(divisor) too small return RPN_ERR_DIV_BY_ZERO; // avoid enormous (and unusable) quotient fp0load(divisor); fp1load(rpn_get(rpnStackIndex - 2)); // dividend fpdiv(); rpnStackIndex -= 2; rpn_push(FP0ADDR); // push the result break; } case RPN_NEG: if (rpnStackIndex < 1) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 1)); fpneg(); --rpnStackIndex; rpn_push(FP0ADDR); // push the result break; case RPN_POW: if (rpnStackIndex < 2) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 1)); // power fp1load(rpn_get(rpnStackIndex - 2)); // base if (fp1sgn() < 0 && ! fpisint()) // if negative base and non-int power return RPN_ERR_POW_OF_NEG; fppow(); rpnStackIndex -= 2; rpn_push(FP0ADDR); // push the result break; default: --reader; return RPN_ERR_UNEXPECTED; } } if (rpnStackIndex != 1) return RPN_ERR_INVALID_EXPR; #if 0 fp0load(rpn_get(0)); char buf[FPSTRBUFSIZ]; char *decimalResult = fpstr(buf); printf("Result: [%s]\n", decimalResult); #endif fpcpy(yValue, rpn_get(0)); return RPN_ERR_NONE; }
__inline void fp2sub(const f2elm_t *a, const f2elm_t *b, f2elm_t *c) { // GF(p^2) subtraction, c = a-b in GF(p^2). fpsub(a->e[0], b->e[0], c->e[0]); fpsub(a->e[1], b->e[1], c->e[1]); }