-/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
- *
- * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
- * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
- * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
- * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
- * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
- * EXPOSE YOU TO LIABILITY.
- ***************************************************************************
-
- CONFIDENTIAL CONFIDENTIAL CONFIDENTIAL
- engineNSA.c
-
- Security Engine code, to be compiled prior to software
- distribution. The code performs the
- elliptic curve algebra fundamental to the patented FEE
- system.
-
- This Engine is designed to be virtually nonmalleable
- with respect to key size. This is achieved herein
- via hard-coding of numerical algorithms with respect to
- the DEPTH = 4 security level (127 bit Mersenne prime).
-
- In meetings between the NSA and NeXT Software, Inc. in
- 1995-1996, the notion of Security Engine emerged as a
- means by which one could discourage disassembly of
- FEE compilations, especially when such disassembly
- has the sinister goal of modifying encryption depth.
-
- DO NOT EVEN THINK ABOUT READING THE SOURCE CODE
- BELOW UNLESS YOU ARE EXPLICITLY AUTHORIZED TO DO SO
- BY NeXT OR ITS DESIGNEE.
-
- c. 1996, NeXT Software, Inc.
- All Rights Reserved.
-*/
-
-/* This engine requires no initialization. There is one
- function to becalled externally, namely elliptic().
- */
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/*
- * Revision History
- * ----------------
- * 10/06/98 ap
- * Changed to compile with C++.
- * 6 Aug 06 at NeXT
- * 'a' argument to elliptic() and ell_even() is now a giant.
- * 25 Jul 96 at NeXT
- * Wrapped ENGINEmul() with gmersennemod(127,.) to guarantee no
- * overflow in the hard-coded mul.
- * Fixed sign calculation bug in ENGINEmul().
- * 24 Jul 96 at NeXT
- * Made conditional on ENGINE_127_BITS.
- * Made all functions except for elliptic() static.
- * Renamed some giants function calls via #define.
- * Deleted use of array of static pseudo-giants.
- * Cosmetic changes for debuggability.
- * 19 Jun 96 at NeXT
- * Created.
- */
-
-#include "ckconfig.h"
-
-#if ENGINE_127_BITS
-/*
- * This file is obsolete as of 8 January 1997.
- */
-#error Hey! New curveParam-dependent 127-bit elliptic() needed!
-#warning Using NSA-approved 127-bit security engine...
-
-#include "NSGiantIntegers.h"
-
-#define D 65536
-#define DM 65535
-
-/*
- * Size of 127-bit giantstruct n[] array, in shorts.
- */
-#define SHORTCOUNT (8 * 2)
-#define BORROW_SIZE 0
-
-
-static void
-ENGINEmul(giant a, giant b) {
- int a0,a1,a2,a3,a4,a5,a6,a7,
- b0,b1,b2,b3,b4,b5,b6,b7;
- int asign, bsign;
- int i, j, car;
- unsigned int prod;
- unsigned short mult;
-
- gmersennemod(127, a);
- gmersennemod(127, b);
- asign = a->sign;
- bsign = b->sign;
-
- for(j = abs(asign); j < SHORTCOUNT; j++) a->n[j] = 0;
- for(j = abs(bsign); j < SHORTCOUNT; j++) b->n[j] = 0;
- a0 = a->n[0];
- a1 = a->n[1];
- a2 = a->n[2];
- a3 = a->n[3];
- a4 = a->n[4];
- a5 = a->n[5];
- a6 = a->n[6];
- a7 = a->n[7];
- b0 = b->n[0];
- b1 = b->n[1];
- b2 = b->n[2];
- b3 = b->n[3];
- b4 = b->n[4];
- b5 = b->n[5];
- b6 = b->n[6];
- b7 = b->n[7];
- for(j = 0; j < SHORTCOUNT; j++) b->n[j] = 0;
-
- i = 0;
- mult = b0;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
-
- i = 1;
- mult = b1;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
-
- i = 2;
- mult = b2;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
-
- i = 3;
- mult = b3;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
-
- i = 4;
- mult = b4;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
-
- i = 5;
- mult = b5;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
-
- i = 6;
- mult = b6;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
-
- i = 7;
- mult = b7;
- car = 0;
-
- prod = a0 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a1 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a2 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a3 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a4 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a5 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a6 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- prod = a7 * mult + b->n[i] + car;
- b->n[i++] = prod & DM;
- car = prod/D;
-
- b->n[i] = car;
- b->sign = abs(b->sign) + abs(a->sign);
- for(j = (b->sign)-1; j >= 0; j--) {
- if(b->n[j] != 0) {
- break;
- }
- }
- b->sign = j+1;
- gmersennemod(127,b);
-}
-
-static void
-ell_even(giant x1, giant z1, giant x2, giant z2, giant a, int q)
-{
- giant t1, t2, t3;
-
- t1 = borrowGiant(BORROW_SIZE);
- t2 = borrowGiant(BORROW_SIZE);
- t3 = borrowGiant(BORROW_SIZE);
-
- gtog(x1, t1); gsquare(t1); gmersennemod(q, t1);
- gtog(z1, t2); gsquare(t2); gmersennemod(q, t2);
- gtog(x1, t3); ENGINEmul(z1, t3);
- gtog(t1, x2); subg(t2, x2); gsquare(x2); gmersennemod(q, x2);
- gtog(a, z2);
- ENGINEmul(t3, z2);
- addg(t1, z2); addg(t2, z2); ENGINEmul(t3, z2);
- gshiftleft(2, z2);
- gmersennemod(q, z2);
-
- returnGiant(t1);
- returnGiant(t2);
- returnGiant(t3);
-}
-
-static void
-ell_odd(giant x1, giant z1, giant x2, giant z2, giant xor, giant zor, int q)
-{
- giant t1, t2, t3;
-
- t1 = borrowGiant(BORROW_SIZE);
- t2 = borrowGiant(BORROW_SIZE);
- t3 = borrowGiant(BORROW_SIZE);
-
- gtog(x1, t1); subg(z1, t1);
- gtog(x2, t2); addg(z2, t2);
- ENGINEmul(t1, t2);
- gtog(x1, t1); addg(z1, t1);
- gtog(x2, t3); subg(z2, t3);
- ENGINEmul(t3, t1);
- gtog(t2, x2); addg(t1, x2);
- gsquare(x2); gmersennemod(q, x2); //?
- gtog(t2, z2); subg(t1, z2);
- gsquare(z2); gmersennemod(q, z2); //?
- ENGINEmul(zor, x2);
- ENGINEmul(xor, z2);
-
- returnGiant(t1);
- returnGiant(t2);
- returnGiant(t3);
-}
-
-/* Elliptic multiply.
- For given curve parameter a and given prime p = 2^q-1,
- the point (xx,zz) becomes k * (xx,zz), in place.
- */
-void
-elliptic(giant xx, giant zz, giant k, giant a, int q)
-{
- int len = bitlen(k), pos = len-2;
- giant xs;
- giant zs;
- giant xorg;
- giant zorg;
-
- if(scompg(1,k)) return;
- if(scompg(2,k)) {
- ell_even(xx, zz, xx, zz, a, q);
- return;
- }
-
- zs = borrowGiant(BORROW_SIZE);
- xs = borrowGiant(BORROW_SIZE);
- zorg = borrowGiant(BORROW_SIZE);
- xorg = borrowGiant(BORROW_SIZE);
-
- gtog(xx, xorg); gtog(zz, zorg);
- ell_even(xx, zz, xs, zs, a, q);
- do{
- if(bitval(k, pos--)) {
- ell_odd(xs, zs, xx, zz, xorg, zorg, q);
- ell_even(xs, zs, xs, zs, a, q);
- } else {
- ell_odd(xx, zz, xs, zs, xorg, zorg, q);
- ell_even(xx, zz, xx, zz, a, q);
- }
- } while(pos >=0);
-
- returnGiant(xs);
- returnGiant(zs);
- returnGiant(xorg);
- returnGiant(zorg);
-}
-
-#endif /* ENGINE_127_BITS */