def solve(self, target): assert type(self.base) == type( target), 'Element and base are not the same type.' curr = target conn = self.get_conn() cursor = conn.cursor() cursor.execute( f'prepare sel as select log from {self.table} where hash=$1') for i in range(0, self.step): h = hash(curr) cursor.execute(f'execute sel ({h})') line = cursor.fetchone() if not line: curr *= self.base continue [first] = line if exp(self.base, first) == curr: return first - i rest = cursor.fetchall() for c in rest: if exp(self.base, c) == curr: return c - i return None curr *= self.base print('Aborting discrete logarithm.') return None
def decrypt(self, ciphertext): """RSA Decryption Args: ciphertext: Ciphertext object to decrypt REFERENCES ========== https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Decryption """ d, n = self.__private_key if ciphertext.is_str: return self.recover_string(exp(ciphertext.text, d, n)) return exp(ciphertext.text, d, n)
def verify(self, signature, key): """RSA signature verification Args: signature: signature we want to verify key: public key of the person who's signature we want to verify REFERENCES ========== https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Signing_messages """ e, n = key if signature.is_str: return self.recover_string(exp(signature.text, e, n)) return exp(signature.text, e, n)
def sign(self, message): """RSA signing Similar to RSA encryption but we use private key to sign. Note that this is merely for proof of concept and should not be used in production Args: message: message to sign REFERENCES ========== https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Signing_messages """ # If input is string, convert it to long first self.is_str = 0 if type(message) is str: self.is_str = 1 if len(message) > 32: raise ValueError("Please enter a smaller string") message = self.process_string(message) assert message.bit_length() <= self.n.bit_length() d, n = self.__private_key return Ciphertext(exp(message, d, n), self.is_str)
def check_if_composite_using(a): x = exp(a, d, n) if x == 1 or x == n - 1: return False # probably prime for _ in range(s): x = (x * x) % n # check for each a^((2^i)*d) if x == n - 1: return False # probably prime return True # definitely composite
def fermats_test(n, k=10): """Fermat's Primality test Returns True(probably prime) if n is prime, Flase if n is composite. Args: n: integer to be tested for primality k: number of iterations of the Fermat's Primality Test NOTES ===== Not very efficient for large integers as exp is costly Carmichael numbers can bypass this test https://en.wikipedia.org/wiki/Fermat_primality_test#Flaw REFERENCES ========== https://en.wikipedia.org/wiki/Primality_test#Fermat_primality_test EXAMPLES ======== >>> fermats_test(5) True >>> fermats_test(4) False >>> fermats_test(341) False The test may fail for n = 561 = 3.11.17, the smallest Carmichael number if we add the condition that the chosen 'a' values have to be co-prime to n. >>> fermats_test(561) False """ if n == 2: return True if not n % 2: return False # Check if a^(n-1) = 1 mod n for k different a values for _ in range(k): a = random.randint(2, n - 1) if exp(a, n - 1, n) != 1: return False return True
def solovay_strassen(n, k=10): """Solovay Strassen Primality Test Returns False is n is composite, True(probably prime) otherwise. Args: n: integer to be tested for primality k: number of iterations to run the test NOTES ===== It is possible for the algorithm to return an incorrect answer. If the input n is indeed prime, then the output will always correctly be probably prime. However, if the input n is composite then it is possible for the output to be incorrectly probably prime. The number n is then called a Euler-Jacobi pseudoprime. The probability of failure is at most 2^(-k) REFERENCES ========== https://en.wikipedia.org/wiki/Solovay%E2%80%93Strassen_primality_test EXAMPLES >>> solovay_strassen(561) False >>> solovay_strassen(29) True >>> solovay_strassen(221) False """ if n == 2: return True if n == 1 or n % 2 == 0: return False for _ in range(k): a = random.randint(2, n - 1) x = (jacobi(a, n) + n) % n # map -1 to n - 1 if x == 0 or exp(a, (n - 1) // 2, n) != x: return False return True
def encrypt(self, message, key): """RSA Encryption Args: message: message to encrypt key: public key to use for encryption REFERENCES ========== https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Encryption """ # If input is string, convert it to long first self.is_str = 0 if type(message) is str: self.is_str = 1 if len(message) > 32: raise ValueError("Please enter a smaller string") message = self.process_string(message) assert message.bit_length() <= self.n.bit_length() e, n = key return Ciphertext(exp(message, e, n), self.is_str)
def precomp(self): conn = self.get_conn() cursor = conn.cursor() cursor.itersize = 10000 batch_size = 500 conn.set_session(autocommit=False) # Check if table has elements try: cursor.execute( f'insert into {self.table}(hash, log) values (1, 1)') conn.commit() except psycopg2.IntegrityError as e: if e.pgcode == '23505': print( 'Database seems to have already been filled (at least', 'partially). We do not currently support filling', 'databases in multiple sessions. If you believe the', 'database is incomplete, please drop the table and run', 'precomputation again.', ) return else: raise e i = 1 mult = exp(self.base, self.step) total = (self.maximum - self.minimum) // self.step + 1 preparation = ( f'prepare ins as insert into {self.table}(hash, log) values ' + ','.join([ '(${}, ${})'.format(2 * i + 1, 2 * (i + 1)) for i in range(batch_size) ]) + ';') cursor.execute(preparation) z = self.group.random() one = z / z curr = self.base**(self.minimum * one) for i in range(total // batch_size): L = [] for j in range(batch_size): if (i * batch_size + j) % 100000 == 0: print( f'Precomputation step {i * batch_size + j} out of {total}.' ) ratio = (i * batch_size + j) / int(total) print('|' + '=' * (round(40 * ratio)) + ' ' * (40 - round(40 * ratio)) + f'| {round(ratio * 100)}%') h = hash(curr) L.append(h) L.append(self.minimum + self.step * (i * batch_size + j)) curr *= mult ins = 'execute ins (' + ','.join([str(x) for x in L]) + ');' cursor.execute(ins) if (i * batch_size) % 1000000 == 0: conn.commit() conn.commit() k = (total // batch_size) * batch_size while k < total + 1: curr *= mult h = hash(curr) cursor.execute('insert into {}(hash, log) values ({}, {})'.format( self.table, h, self.minimum + self.step * k)) k += 1 conn.commit()
#!/usr/bin/env python # coding: utf-8 from utils import multiplication_entiere, produit, affiche_table_multiplicative, exp, inverse, subgroup, generateurs if __name__ == '__main__': print "Hello world!" print "multiplication_entiere(2, 5) =", multiplication_entiere(2, 5) n = 8 poly = (0b1 << 8) ^ (0b1 << 4) ^ (0b1 << 3) ^ (0b1 << 1) ^ 0b1 print produit(n, poly, 45, 72) affiche_table_multiplicative(3, poly & 0b1111) alpha = 0b10 for i in xrange(1, 2**3): print "alpha **", i, ":", exp(3, poly & 0b1111, alpha, i) print inverse(3, poly & 0b1111, 1) print inverse(3, poly & 0b1111, 0b10) print inverse(3, poly & 0b1111, 0b11) print inverse(3, poly & 0b1111, 0b100) print subgroup(3, poly & 0b1111, 0b10) print generateurs(3, poly & 0b1111) print generateurs(8, poly)