//we don't have to bother with making sure that gcd(R,M) == 1 since M is odd. uberzahl modexp_mm(mm_t & mm, uberzahl base, uberzahl exp, uberzahl M){ if(!mm.initialized){ mm.R = next_power(M); mm.Rbits = mm.R.bitLength(); mm.Mprime = (mm.R-M.inverse(mm.R)); uberzahl z("1"); uberzahl t("2"); mm.Rsq = modexp(mm.R,t,M); //mm.z_init = mm.R % M; mm.z_init = montgomery_reduction(mm.Rsq, M, mm.Mprime, mm.Rbits, mm.R); mm.initialized = true; } //convert into Montgomery space uberzahl z = mm.z_init; //According to Piazza post we don't even need to calculate the residues with mod if(base * mm.Rsq < mm.R*M) base = montgomery_reduction(base * mm.Rsq, M, mm.Mprime, mm.Rbits, mm.R); else base = base * mm.R % M; mediumType i = exp.bitLength() - 1; while(i >= 0) { z = montgomery_reduction(z * z, M, mm.Mprime, mm.Rbits, mm.R); if(exp.bit(i) == 1){ z = montgomery_reduction(z * base , M, mm.Mprime, mm.Rbits, mm.R); } if(i == 0) break; i -= 1; } return montgomery_reduction(z, M, mm.Mprime, mm.Rbits, mm.R); }
uberzahl originalModExp(uberzahl c, uberzahl a, uberzahl p, uberzahl q){ //a^c mod pq auto start = chrono::steady_clock::now(); uberzahl z = 1; uberzahl n = p*q; unsigned int numBits = c.bitLength(); unsigned int currentBit = 1; for (unsigned int i = 0; i < numBits; i++){ z = (z*z) % n; currentBit = c.bit(numBits-i-1); if (currentBit == 1) z = (z*a) % n; } if(q > 1){ auto current = chrono::steady_clock::now(); auto elapsed = chrono::duration_cast<chrono::duration<double>>(current-start); double chrono_time = elapsed.count(); cerr << "\tSqMultOrig time: " << chrono_time << "\n"; } return z; }
uberzahl modexp_mm_crt(mm_t & mm1, mm_t & mm2, crt_t & crt, uberzahl base, uberzahl exp, uberzahl p, uberzahl q){ if(!crt.initialized){ crt.p_inverse = p.inverse(q); crt.q_inverse = q.inverse(p); crt.initialized = true; } return ( crt_helper(MONTGOMERY,mm1,base,exp,p,q, crt.q_inverse) + crt_helper(MONTGOMERY, mm2, base, exp, q, p, crt.p_inverse) ) % (p * q); }
uberzahl modexp_crt(crt_t & crt, uberzahl base, uberzahl exp, uberzahl p, uberzahl q){ mm_t mm; if(!crt.initialized){ crt.p_inverse = p.inverse(q); crt.q_inverse = q.inverse(p); crt.initialized = true; } return ( crt_helper(CLASSIC,mm, base,exp,p,q,crt.q_inverse) + crt_helper(CLASSIC, mm, base, exp, q, p, crt.p_inverse) ) % (p * q); }
inline void ReduceZ(){ // m = (z*NPrime) % R; m = (z*NPrime) & (( (uberzahl)1 << (R.bitLength()-1) )-(uberzahl)1); t = (z + m*N) >> (R.bitLength()-1); if(t >= N) z = (t-N); else z = (t); }
void encrypt(const uberzahl &m, uberzahl &r, uberzahl &s) { //Encrypts m, //Modifies r, s to the outputs of the encryption uberzahl low = 2; uberzahl high = prime - 2; uberzahl k = random(low, high); r = generator.expm(k, prime); s = m * y.expm(k,prime) % prime; }
uberzahl modexp(uberzahl base, uberzahl exp, uberzahl n){ mediumType i = exp.bitLength() - 1; uberzahl z((largeType)1); while(i >= 0){ z = (z * z ) % n; if(exp.bit(i) == 1) z = (z * base) % n; if(i == 0) break; i -= 1; } return z; }
uberzahl increment (uberzahl x) { // Extract and "increment" least significant 32 bits from x uberzahl leastSigBits = betterExtract(x, 0, 31) + 1; uberzahl modulo = 4294967296; leastSigBits = leastSigBits % modulo; // Set least significant bits in x for (int i = 0; i < 32; ++i) { if(leastSigBits.bit(i) == 0) { x.clearBit(i); } else { x.setBit(i); } } return x; }
uberzahl decrypt(const uberzahl &r, const uberzahl &s, uberzahl &m) { //Takes in r, s and decrypts them //modifies m to the decrypted ciphertext value uberzahl rx = r.expm(x, prime); m = s * rx.inverse(prime) % prime; return m; }
uberzahl chineseModExp2(uberzahl c, uberzahl a, uberzahl p, uberzahl q){ //a^c mod pq auto start = chrono::steady_clock::now(); uberzahl dp = c % (p-1); uberzahl dq = c % (q-1); uberzahl T = q.inverse(p); uberzahl S = p.inverse(q); uberzahl m1 = originalModExp(dp,a,p,1); uberzahl m2 = originalModExp(dq,a,q,1); uberzahl m = (m1*q*T + m2*p*S) % (p*q); auto current = chrono::steady_clock::now(); auto elapsed = chrono::duration_cast<chrono::duration<double>>(current-start); double chrono_time = elapsed.count(); cerr << "\tSqMult_CRT time: " << chrono_time << "\n"; return m; }
vector<uberzahl> Speck::generateKeys(){ vector<uberzahl> keySeed; uberzahl lowerBound = two.exp(n - 1) - one; uberzahl upperBound = two.exp(n + 1) - one; for(int i = 0; i < m; i++){ keySeed.push_back(random(lowerBound, upperBound) & modulus); } keyExpansion(keySeed); return keySeed; }
uberzahl multiply (uberzahl x, uberzahl y) { uberzahl z, v = y, r = "299076299051606071403356588563077529600"; for (int i = 127; i >= 0; --i) { // Set z block if (x.bit(i) == 0) { z = z; } else { z = z ^ v; } // Set v block if (v.bit(0) == 0) { v = v >> 1; } else {
elGamal() { //Initializes all of the required values using a 128-bit prime srand(time(NULL)); uberzahl temp = 2; minPrime = temp.exp(126); temp = 2; maxPrime = temp.exp(127); prime = getPrime(minPrime, maxPrime); uberzahl low = 2; uberzahl high = prime - 2; x = random(low, high); generator = gen(prime); y = generator.expm(x, prime); }
int main(int argc, char **argv){ srand(time(0)); //uberzahl new_key = generate(); vector<uberzahl> k; vector<uberzahl> plaintext_vector; vector<uberzahl> ciphertext_vector; uberzahl ciphertext; uberzahl plaintext; uberzahl zero = "0"; if(strcmp(argv[1],"encrypt") == 0) { key = argv[2]; if(key.bitLength() > 256) { cout << "key bit length is more than 256 bit, please see README file." << endl; return 0; } plaintext = argv[3]; //For test the result // k.push_back(0x1f1e1d1c1b1a1918); // k.push_back(0x1716151413121110); // k.push_back(0x0f0e0d0c0b0a0908); // k.push_back(0x0706050403020100); // key = (k[0] << (3*n)) | (k[1] << (2*n)) | (k[2] << (n)) | k[3]; // plaintext = 0x74206e69206d6f6f; // plaintext = (plaintext << n) | 0x6d69732061207369; int num_block = 0; uberzahl result; uberzahl temp; while(plaintext != zero) { temp = plaintext & take_128_bit; plaintext = plaintext >> (2*n); result = encrypt(temp, key); ciphertext = ciphertext | (result << num_block*(2*n)); num_block++; } cout << "The ciphertext is: " << endl; cout << ciphertext << endl; }
//x is a random number 0 < x < q - private key void pqgGen(uberzahl & p, uberzahl & q, uberzahl & g) { //find a L-bit long p prime /* uberzahl rand; p = 2; rand.random(L); string p_string = rand.convert_to_string(); mpz_class p_mpz(p_string, 10); while(p.bitLength() != L) { mpz_nextprime(p_mpz.get_mpz_t(), p_mpz.get_mpz_t()); p_string = p_mpz.get_str(10); p = p_string.c_str(); } cout<<p<<endl; */ //find an N bit q such that p-1 divides q //method 1 /* rand.random(N); string q_string = rand.convert_to_string(); mpz_class q_mpz(q_string, 10); while(q.bitLength() != N || (((p-1)%q) != zero)) { mpz_nextprime(q_mpz.get_mpz_t(), q_mpz.get_mpz_t()); q_string = q_mpz.get_str(10); q = q_string.c_str(); cout<<1<<endl; } cout<<q<<endl; */ //method2 /* uberzahl two = 2; uberzahl lower_bound = two.exp(N-1); q = lower_bound; mpz_class q_mpz(q.convert_to_string(), 10); string q_string; while(((p-1) % q) != zero) { mpz_nextprime(q_mpz.get_mpz_t(), q_mpz.get_mpz_t()); q_string = q_mpz.get_str(10); q = q_string.c_str(); if (q.bitLength() != N) { cout<<"no such q exists"<<endl; exit(1); } cout<<1<<endl; } cout<<q<<endl; cout<<2<<endl; */ string p_string, q_string; mpz_class p_mpz; uberzahl rand; bool none = 0; while(1) { //find random N bit prime q do { rand.random(N); q = nextprime(rand, 10); q_string = q.convert_to_string(); q = q_string.c_str(); } while (q.bitLength() != N); mpz_class q_mpz(q_string, 10); mpz_class mult_mpz = 3; while (1) { mpz_class product_mpz = mult_mpz * q_mpz; //if product is odd -> no way product+1 is prime if ((product_mpz % 2) == one) { mult_mpz = mult_mpz + 1; continue; } //this number should be p-1 mpz_class product_1_mpz = product_mpz + 1; //check if p is a prime uberzahl product = (product_mpz.get_str(10)).c_str(); uberzahl product_1 = (product_1_mpz.get_str(10)).c_str(); //missing 1 bit if (product.bitLength() == L-1) { mult_mpz = mult_mpz * 2; } //increment mult if mult not big enough if (product.bitLength() < L) { double diff = L - product.bitLength(); mult_mpz = mult_mpz * diff; } //increment multi if mult is not big enough //mult too high? find other q if (product.bitLength() > L) { none = 1; break; } //if it is of bitlength N --> check product if it is a prime if (mpz_probab_prime_p(product_1_mpz.get_mpz_t(), 10) > 0) { //found a right p p_string = product_1_mpz.get_str(10); p = p_string.c_str(); break; } else { mult_mpz = mult_mpz + 1; } } if (none) { none = 0; continue; } else break; } // while (q.bitLength() != N || ((p-1) % q) != zero ) { // rand.random(N); // uberzahl rand = random(lower_bound, upper_bound); // q = nextprime(rand, 20); // this is gonna EVEN slower // } //find g with multiplicative order modulo p = q uberzahl h = 20; g = 1; while (g == 1) { uberzahl c = ((p-1)/q); g = h.expm(c, p); h = h + 1; if (h == (p-1)) { cout<<"no such generator g"<<endl; exit(1); } } }