/* Copyright (c) (2010,2011,2012,2013,2014,2015,2016,2017,2018,2019) Apple Inc. All rights reserved. * * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which * is contained in the License.txt file distributed with corecrypto) and only to * people who accept that license. IMPORTANT: Any license rights granted to you by * Apple Inc. (if any) are limited to internal use within your organization only on * devices and computers you own or control, for the sole purpose of verifying the * security characteristics and correct functioning of the Apple Software. You may * not, directly or indirectly, redistribute the Apple Software or any portions thereof. */ #import "CCNValidation.h" #import "ccn_unit.h" #define GI_MODG_ENABLE 1 #include #include #include "cczp_internal.h" #include "ccn_internal.h" #include #include #include #include #define LOOPS_DEF 3 #define MAX_SIZE_DEF 3 * 4096 / 8 #define LOOP_NOTIFY 100 /* tweak these to focus on a specific test */ #define DVT_BASIC_ENABLE 1 /* comp, mulg, addg, subg */ #define DVT_SHIFT_ENABLE 0 /* shift l/r */ #define DVT_MOD_ENABLE 1 /* mod */ #define DVT_GCD_ENABLE 0 /* gcd */ #define DVT_PRIME_ENABLE 0 /* prime test */ #define DVT_INVMOD_ENABLE 0 /* ginverseMod */ #define DVT_DIVMOD_ENABLE 0 /* divmodg_via_recip */ @implementation CCNValidation /* * ...min <= return <= max */ static uint32_t genRand(uint32_t min, uint32_t max) { uint32_t r; uint8_t c[4]; if (max == min) { /* avoid % 1 ! */ return max; } ccrng_generate(ccrng(NULL), 4, c); r = (((uint32_t)c[0] << 24) | ((uint32_t)c[1] << 16) | ((uint32_t)c[2] << 8) | c[3]); return min + (r % (max - min + 1)); } /* * Fill buffer with random data, random size from 1 to maxByteSize. * Returns size of random data generated. */ #define MIN_SIZE 1 static cc_size fillData(cc_size maxByteSize, uint8_t *data) { cc_size size; size = maxByteSize; //genRand(MIN_SIZE, maxByteSize); ccrng_generate(ccrng(NULL), size, data); return size; } /* * create a giant with random size and data. *Buf is mallocd and * uninitialized and will change here. * Giants with values of zero or one will never be returned - too * many corner cases involving those numbers. */ static cc_size genGiant(cc_size count, cc_unit *r, size_t maxBytes, uint8_t *buf) { assert(maxBytes <= ccn_sizeof_n(count)); for(;;) { cc_size size = fillData(maxBytes, buf); if (ccn_read_uint(count, r, size, buf)) { /* should never happen */ printf("***genGiant overflow\n"); exit(1); } cc_unit one[count]; ccn_seti(count, one, 1); /* If r is less or equal to 1 we don't return it. */ if (ccn_cmp(count, r, one) <= 0) continue; return count; } } /* * Individual tests. API is identical for all tests. * * g1, g2 : giants with random data, size, and sign. Tests do not modify * these. * scr1, scr2 : scratch giants, big enough for all conceivable ops. Can * be modified at will. * Return : 0 for sucess, 1 on error. */ #if DVT_BASIC_ENABLE -(void) compTst:(cc_size) count : (const cc_unit *) g1 : (cc_unit *) scr1 : (cc_unit *) scr2 { ccn_set(count, scr1, g1); ccn_set(count, scr2, scr1); XCAssertCCNEquals(count, g1, scr2, @"scr1 = g1; scr2 = scr1; g1 == scr2"); } -(void) addSubTst:(cc_size) count : (const cc_unit *) g1 : (const cc_unit *) g2 : (cc_unit *) scr1 { ccn_add(count, scr1, g1, g2); // scr1 := g1 + g2 ccn_sub(count, scr1, scr1, g1); // scr1 := g1 + g2 - g1 =? g2 XCAssertCCNEquals(count, g2, scr1, @"g2 == g1+g2-g1\ng1 = %@", ccn_string(count, g1)); } /* Largest random uint32_t integer to use a multiplier */ #define LARGEST_MUL 0xffff -(void) mulTst:(cc_size) count : (const cc_unit *) g1 : (cc_unit *) scr1 : (cc_unit *) scr2 { uint32_t randInt = genRand(1, LARGEST_MUL); uint32_t i; ccn_seti(2 * count, scr1, randInt); // scr1 := randInt ccn_mul(count, scr2, g1, scr1); // scr2 := g1 * randInt /* now do the same thing with multiple adds */ ccn_seti(2 * count, scr1, 0); // scr1 := 0 cc_unit carry = 0; for(i = 0; i> CCN_LOG2_BITS_PER_UNIT; giantDigit bitMask = 1 << (bitPos & (GIANT_BITS_PER_DIGIT - 1)); if(nDex > (g->sign - 1)) { printf("***clearBit screwup, nDex %u sign %u\n", nDex, g->sign); return; } g->n[nDex] &= ~bitMask; } -(void) rshiftTst:(cc_size) count : (const cc_unit *) g1 : (const cc_unit *) g2 : (cc_unit *) scr1 : (cc_unit *) scr2 { unsigned maxShift = bitlen(g1) - 1; unsigned shiftCnt; lgiant scr3; int rtn = 0; unsigned dex; localGiantAlloc(&scr3); /* special case, can't have g1 = 1 */ if(maxShift == 0) { #if GIANTS_DEBUG printf("...rshiftTst: tweaking g1 = 1\n"); #endif g1->n[0] = 2; shiftCnt = 1; } else { shiftCnt = genRand(1, maxShift); } /* first do the shift right */ gtog(g1, scr1); // scr1 := g1 gshiftright(shiftCnt, scr1); // scr1 := (g1 >> shiftCnt) /* now shift left the result by the same amount */ gtog(scr1, scr2); // scr2 := (g1 >> shiftCnt) gshiftleft(shiftCnt, scr2); // scr2 := ((g1 >> shiftCnt) << shiftCnt /* get a copy of original giant a mask off the bits which should be full of * zeroes now */ gtog(g1, &scr3.g); for(dex=0; dexsign; unsigned shiftCntWords; unsigned shiftCntBits; int rtn = 0; shiftCntWords = genRand(1, maxShiftWords); shiftCntBits = shiftCntWords * GIANT_BITS_PER_DIGIT; /* shift right by words --> scr1 */ gtog(g1, scr1); gshifltwordsright(shiftCntWords, scr1); /* shift right by bits --> scr2 */ gtog(g1, scr2); gshiftright(shiftCntBits, scr2); /* * this assumes of course that we have a reliable gshiftright(), which * was in fact tested in rshiftTest(). */ if(gcompg(scr1, scr2)) { printf("shiftCntWords %u 0x%x\n", shiftCntWords, shiftCntWords); printf("g1 : "); printGiantHex(g1); printf("scr1 : "); printGiantHex(scr1); printf("scr2 : "); printGiantHex(scr2); printf("gshifltwordsright error\n"); rtn = testError(); } return rtn; } #endif /* DVT_SHIFT_ENABLE */ #if GI_MODG_ENABLE && DVT_MOD_ENABLE #define ccn_modulo(count, n, a, d) ([self ccn_mod: count : n : a : d]) -(void) ccn_mod:(cc_size) count : (cc_unit *) n : (const cc_unit *) a : (const cc_unit *) d { struct cczp *zp = alloca(cczp_size(ccn_sizeof_n(count))); CCZP_N(zp) = count; ccn_set(count, CCZP_PRIME(zp), d); cczp_init(zp); CC_DECL_WORKSPACE_STACK(ws,CCZP_MOD_WORKSPACE_N(count)); cczp_mod_ws(ws, zp, n, a); CC_FREE_WORKSPACE_STACK(ws); } #define ccn_modn(count, n, count_a, a, d) ([self ccn_modn: count : n : count_a : a : d]) -(void) ccn_modn:(cc_size) count : (cc_unit *) n : (cc_size) count_a :(const cc_unit *) a : (const cc_unit *) d { struct cczp *zp = alloca(cczp_size(ccn_sizeof_n(count))); CCZP_N(zp) = count; ccn_set(count, CCZP_PRIME(zp), d); cczp_init(zp); cczp_modn(zp, n, count_a,a); } #define LARGEST_MOD_MUL 0x40 -(void) modTst:(cc_size) count : (const cc_unit *) g1 : (const cc_unit *) g2 : (cc_unit *) scr1 : (cc_unit *) scr2 { cc_unit *scr3 = alloca(ccn_sizeof_n(2 * count)), *scr4 = alloca(ccn_sizeof_n(2 * count)); const cc_unit *modulus; const cc_unit *factor; //int randInt = genRand(1, LARGEST_MOD_MUL); //ccn_seti(count, scr1, randInt); // scr1 = rand uint8_t buf[ccn_sizeof_n(count)]; genGiant(2*count, scr1, ccn_sizeof_n(count) - genRand(0, CCN_UNIT_SIZE - 1), buf); if (ccn_cmp(count,g2,g1)>=0) { modulus=g2; factor=g1; } else { modulus=g1; factor=g2; } /* current ccn_mod can't deal with g mod 1 */ if (ccn_bitlen(count, modulus) == 1) { printf("..modTst: tweaking g1 = 1\n"); scr2[0] = 0x54; } /* end ccn_mod workaround */ /* this will only work if randInt < g1 */ if (ccn_cmp(count, scr1, modulus) >= 0) { ccn_modn(count, scr1, 2*count,scr1, modulus); // scr1 = rand mod g1 XCTAssertTrue(ccn_cmp(count, scr1, modulus) < 0, @"\nscr1 = %@\nmod = %@", ccn_string(count, scr1), ccn_string(count, modulus)); } else { ccn_modulo(count, scr2, scr1, modulus); // scr1 = rand mod g1 XCTAssertTrue(ccn_cmp(count, scr1, scr2) == 0, @"\nscr1 = %@\nmod = %@", ccn_string(count, scr1), ccn_string(count, modulus)); ccn_modn(count, scr2, 2*count,scr1, modulus); // scr1 = rand mod g1 XCTAssertTrue(ccn_cmp(count, scr1, scr2) == 0, @"\nscr1 = %@\nmod = %@", ccn_string(count, scr1), ccn_string(count, modulus)); } ccn_mul(count, scr3, factor, modulus); // scr3 = g2 * g1 if (ccn_add(count, scr3, scr3, scr1)) // scr3 = g2 * g1 + rand ccn_add1(count, scr3 + count, scr3 + count, 1); // propagate carry in scr3 ccn_modulo(count, scr4, scr3, modulus); // scr4 := scr3 mod g1 =? rand XCAssertCCNEquals(count, scr1, scr4, @"rand != (g2 * g1 + rand) mod g1\ng1: %@\ng2: %@\nscr3: %@\nscr4:%@", ccn_string(count, g1), ccn_string(count, g2), ccn_string(2 * count, scr3), ccn_string(2 * count, scr4)); ccn_modn(count, scr4, 2*count,scr3, modulus); // scr3 := scr3 mod g1 =? rand XCAssertCCNEquals(count, scr1, scr4, @"rand != (g2 * g1 + rand) mod g1\ng1: %@\ng2: %@\nscr3: %@\nscr4:%@", ccn_string(count, g1), ccn_string(count, g2), ccn_string(2 * count, scr3), ccn_string(2 * count, scr4)); } #endif /* GI_MODG_ENABLE && DVT_MOD_ENABLE */ #if GI_MODG_ENABLE && DVT_GCD_ENABLE #define SHOW_GCDTEST 0 -(void) gcdTst:(cc_size) count : (giant) g1 : (giant) g2 : (giant) scr1 : (giant) scr2 { /* * This test's algorithm results in a gcd op on (g1*randInt, g2*randInt). * This can overflow an lgiant, so we have to truncate g1 and g2 to ensure * we're within bounds. */ #define MAX_GCD_TRUNC_SIZE (MAX_PRIME_SIZE_DIGITS - 3) lgiant g1Trunc; lgiant g2Trunc; bgiant existGcd; uint32_t randInt = genRand(2, 0x100000); bgiant expectGcd; bgiant g1Mul; bgiant g2Mul; bgiant gotGcd; int ourRtn = 0; localGiantAlloc(&g1Trunc); localGiantAlloc(&g2Trunc); gtog(g1, &g1Trunc.g); gtog(g2, &g2Trunc.g); if(g1Trunc.g.sign > MAX_GCD_TRUNC_SIZE) { g1Trunc.g.sign = MAX_GCD_TRUNC_SIZE; gtrimSign(&g1Trunc.g); } if(g2Trunc.g.sign > MAX_GCD_TRUNC_SIZE) { g2Trunc.g.sign = MAX_GCD_TRUNC_SIZE; gtrimSign(&g2Trunc.g); } localBigGiantAlloc(&existGcd); localBigGiantAlloc(&g1Mul); localBigGiantAlloc(&g2Mul); localBigGiantAlloc(&expectGcd); localBigGiantAlloc(&gotGcd); /* first see if g1 and g2 already have a gcd other than 1 */ gtog(&g1Trunc.g, &existGcd.g); nbgcdg(&g2Trunc.g, &existGcd.g); if(isone(&existGcd.g)) { /* * g1Trunc, g2Trunc are apparently relatively prime. * Quick check: are they both even? */ if( ((g1Trunc.g.n[0] & 1) == 0) && ((g2Trunc.g.n[0] & 1) == 0) ) { printf("***HEY! WE've got two even numbers whose gcd is 1!\n"); printf("g1 : "); printGiant(&g1Trunc.g); printf("g2 : "); printGiant(&g2Trunc.g); return testError(); } } /* random multiplier */ int_to_giant(randInt, scr1); /* * Expected gcd after we multiply g1Trunc and g2Trunc by randInt is * existGcd * randInt */ mulg_common(scr1, &existGcd.g, &expectGcd.g); /* multiply both reference giants by randInt */ mulg_common(&g1Trunc.g, scr1, &g1Mul.g); mulg_common(&g2Trunc.g, scr1, &g2Mul.g); /* gcd of resulting giants should be expectedGcd */ gtog(&g2Mul.g, &gotGcd.g); nbgcdg(&g1Mul.g, &gotGcd.g); if(gcompg(&gotGcd.g, &expectGcd.g)) { ourRtn = 1; printf("****gcompg failure\n"); } if(ourRtn || SHOW_GCDTEST) { printf("----------- \n"); printf("g1 : "); printGiant(&g1Trunc.g); printf("g2 : "); printGiant(&g2Trunc.g); printf("existGcd : "); printGiant(&existGcd.g); printf("randInt : "); printGiant(scr1); printf("g1Mul : "); printGiant(&g1Mul.g); printf("g2Mul : "); printGiant(&g2Mul.g); printf("expectGcd : "); printGiant(&expectGcd.g); printf("gotGcd : "); printGiant(&gotGcd.g); printf("----------- \n"); } if(ourRtn) { return testError(); } return 0; } #endif /* GI_MODG_ENABLE && DVT_GCD_ENABLE */ #if GI_PRIME_TEST_ENABLE && DVT_PRIME_ENABLE /* * isGiantPrime() test - easy - just multiply g1 * g2 and make sure it's * not reported as prime. However we have to cut the sizes of g1 and * g2 in half - can't do isGiantPrime on a number bigger than * GIANT_LITTLE_DIGITS. */ #define PRIME_DEPTH_DEF 8 -(void) primeTst:(cc_size) count : (giant) g1 : (giant) g2 : (giant) scr1 : (giant) scr2 { lgiant t1; lgiant t2; localGiantAlloc(&t1); localGiantAlloc(&t2); gtog(g1, &t1.g); gtog(g2, &t2.g); if(t1.g.sign > (GIANT_LITTLE_DIGITS / 2)) { t1.g.sign /= 2; } if(t2.g.sign > (GIANT_LITTLE_DIGITS / 2)) { t2.g.sign /= 2; } mulg_common(&t1.g, &t2.g, scr1); if(isGiantPrime(scr1, PRIME_DEPTH_DEF)) { printf("***isGiantPrime error: composite number reported as prime for " "depth %u\n", PRIME_DEPTH_DEF); printf("t1 : "); printGiant(&t1.g); printf("t2 : "); printGiant(&t2.g); printf("scr1 : "); printGiant(scr2); return testError(); } return 0; } /* * Highest known prime in giantPrime.c - we have to keep this in sync if * SIZEOF_PRIME_TABLE changes. */ #define SIEVE_MAX 1619 -(void) primeSieveTst:(cc_size) count : (giant) g1 : (giant) g2 : (giant) scr1 : (giant) scr2 { /* * multiply g1 by a random r, 2<=r<=SIEVE_MAX. Ensure that * checkPrimeCandidate reports the result as SIEVE_COMPOSITE or * SIEVE_CANDIDATE. */ unsigned r = genRand(2, SIEVE_MAX); int rtn; int_to_giant(r, scr1); mulg_common(g1, scr1, scr2); rtn = checkPrimeCandidate(scr2); switch(rtn) { case SIEVE_COMPOSITE: case SIEVE_CANDIDATE: return 0; default: break; } printf("***checkPrimeCandidate returned %d for known composite\n", rtn); printf("r : %u\n", r); printf("g1 : "); printGiant(g1); printf("r * g1 : "); printGiant(scr2); return testError(); } #endif /* GI_PRIME_TEST_ENABLE && DVT_PRIME_ENABLE */ #if DVT_INVMOD_ENABLE && GI_MODG_ENABLE && GI_INVERSE_MOD_ENABLE /* cook up a global prime modulus for ginverseMod(), just once then it's const */ lgiant primeModulus; lgiant primeModulusRecip; static GIReturn genPrimeModulus(cc_size count, unsigned giantBytes, int quiet) { localGiantAlloc(&primeModulus); localGiantAlloc(&primeModulusRecip); GIReturn grtn; if(!quiet) { printf("...generating %u bit prime for ginverseModTest...\n", giantBytes * 8); } grtn = genPrimeGiant(&primeModulus.g, giantBytes * 8, PRIME_DEPTH_DEFAULT); if(grtn) { printf("***Error (%d) generating primeModulus for ginverseMod() test\n", (int)grtn); return grtn; } make_recip(&primeModulus.g, &primeModulusRecip.g); return GR_Success; } -(void) ginverseModTst:(cc_size) count : (giant) g1 : (giant) g2 : (giant) scr1 : (giant) scr2 { lgiant workG1; /* working, possibly modified g1 */ localGiantAlloc(&workG1); gtog(g1, &workG1.g); /* first ensure g1 < primeModulus */ modg_via_recip(&primeModulus.g, &primeModulusRecip.g, &workG1.g); /* scr1 := g1^(-1) mod primeModulus */ gtog(&workG1.g, scr1); ginverseMod(&primeModulus.g, &primeModulusRecip.g, scr1); /* scr2 := g1 * scr1 mod primeModulus, should equal 1 (one) */ gtog(&workG1.g, scr2); rmulg(scr1, scr2, &primeModulus.g, &primeModulusRecip.g); if(!isone(scr2)) { printf("***ginverseMod failure, g1 * (g1^(-1) mod m) mod m != 1 ***\n"); printf("----------- \n"); printf("g1 : "); printGiant(&workG1.g); printf("modulus : "); printGiant(&primeModulus.g); printf("modulusRecip : "); printGiant(&primeModulusRecip.g); printf("g1^(-1) mod m : "); printGiant(scr1); printf("g1 * (g1^(-1)) mod m : "); printGiant(scr2); printf("----------- \n"); return testError(); } return 0; } #endif /* DVT_INVMOD_ENABLE && GI_MODG_ENABLE && GI_INVERSE_MOD_ENABLE */ #if DVT_DIVMOD_ENABLE && GI_MODG_ENABLE /* * Test divmodg_via_recip(). * * Cook up third random giant g3 such that g3 < g2; * giant product = (g1 * g2) + g3; * use divmodg_via_recip to get * giant gmod = product mod g2; * giant gdiv = product div g2; * Ensure that gmod==g3 and gdiv==g1; */ -(void) divModTst:(cc_size) count : (giant) g1 : (giant) g2 : (giant) scr1 : (giant) scr2 { lgiant g3; uint8_t buf[MAX_PRIME_SIZE_BYTES]; tgiant product; giant gmod = scr1; giant gdiv = scr2; lgiant recip; int gotErr = 0; if(isone(g2)) { /* well shoot. This ain't gonna work. */ printf("divModTst: g2==1; skipping this test.\n"); return 0; } /* generate random g3 < g2 */ localGiantAlloc(&g3); genGiant(count, &g3.g, g2->sign * GIANT_BYTES_PER_DIGIT, buf); if(gcompg(g2, &g3.g) <= 0) { lgiant oneG; /* g3 := g2 - 1 */ localGiantAlloc(&oneG); int_to_giant(1, &oneG.g); gtog(g2, &g3.g); normal_subg(&oneG.g, &g3.g); } /* product := (g1 * g2) + g3 */ localTriGiantAlloc(&product); mulg_common(g1, g2, &product.g); addg(&g3.g, &product.g); /* * gmod = product mod g2; * gdiv = product div g2; */ localGiantAlloc(&recip); make_recip(g2, &recip.g); gtog(&product.g, gmod); divmodg_via_recip(g2, &recip.g, gmod, gdiv); /* Ensure that gmod==g3 and gdiv==g1 */ if(gcompg(&g3.g, gmod) != 0) { printf("***Error in mod portion of divmodg_via_recip\n"); gotErr = 1; } if(gcompg(g1, gdiv) != 0) { printf("***Error in div portion of divmodg_via_recip\n"); gotErr = 1; } if(gotErr) { printf("----------- \n"); printf("g1 : "); printGiant(g1); printf("g2 : "); printGiant(g2); printf("g3 : "); printGiant(&g3.g); printf("(g1 * g2) + g3 : "); printGiant(&product.g); printf("product mod g2 : "); printGiant(gmod); printf("product div g2 : "); printGiant(gdiv); printf("----------- \n"); return testError(); } return 0; } #endif /* DVT_DIVMOD_ENABLE && GI_MODG_ENABLE */ static void testStartBanner( char *testName, int argc, char **argv) { int i; printf("Starting %s; args: ", testName); for(i=1; i 1) testStartBanner("MPNValidation", argc, argv); #if DVT_INVMOD_ENABLE && GI_MODG_ENABLE && GI_INVERSE_MOD_ENABLE if (doPrimeMod) { /* one-time only init for this guy... */ if (genPrimeModulus(maxCount, maxByteSize, quiet)) { free(buf); exit(1); } } #endif for (loop=0; loop