Skip to content

Instantly share code, notes, and snippets.

@matburt
Forked from anonymous/ACYNOS (Tomillo)
Created February 10, 2010 23:04

Revisions

  1. @invalid-email-address Anonymous created this gist Feb 10, 2010.
    435 changes: 435 additions & 0 deletions ACYNOS (Tomillo)
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,435 @@
    #!/usr/bin/python
    """
    Criptosistema ACYMOS2 por Agustin, Kriptopolis
    Notas:
    "~" representa la "enye"
    Los comentarios estan sin acentos y caracteres especiales
    by xiscu [en] email [punto] de
    """

    import re
    from decimal import *
    from math import *

    ###############################################################################
    # CONFIGURACION Y CONSTANTES

    ## El alfabeto basico
    ALFABETO_BASE = list('ABCDEFGHIJKLMN~OPQRSTUVWXYZ_')
    ALFA_N = len(ALFABETO_BASE)


    ## Traducciones
    espacio = re.compile(' ') # 1
    enye = re.compile('\xc3\x91') # 2
    retorno = re.compile('\n') # 3


    ## Numero de Cifras decimales
    ND = 10
    DIEZ_DECIMALES = Decimal(10) ** -ND


    ## Fichero con numeros primeros
    FICHERO_PRIMOS = '100000_primos.txt'
    PRIMOS=[]


    ###############################################################################
    # FUNCIONES INTERNAS

    def lee_primos():
    f=None
    try:
    f=open(FICHERO_PRIMOS)
    for linea in f:
    primos_texto=linea.split()
    for p in primos_texto:
    PRIMOS.append(int(p))
    except:
    raise

    finally:
    if f:
    f.close()

    ## Lee los primos
    lee_primos()

    ## Constante PI_DECIMAL
    PI_DEC = Decimal('3.1415926536')


    ###############################################################################
    # FUNCIONES EXPORTADAS

    def texto_a_ascii(texto):
    """Traduce un texto a ascii
    """
    tt = espacio.sub('_', texto) # 1
    tt = enye.sub('~', tt) # 2
    tt = retorno.sub('', tt) # 3

    return tt


    def lan(alfabeto, letras):
    """Traduce una o una lista de letras a numeros segun el orden del alfabeto
    """
    index_mas1 = lambda letra: alfabeto.index(letra) + 1
    if len(letras)==1:
    return index_mas1(letras)
    else:
    return map(index_mas1, letras)


    def primo_n(n):
    """Retorna el primo numero n, empezando a contar por 0
    """
    return PRIMOS[n]


    def s_alfa(clave):
    """Calcula la semilla para contruir el alfabeto derivado con la clave dada
    """
    s=Decimal(0)
    pn=0
    for c in clave:
    n=lan(ALFABETO_BASE, c)
    s+=n * Decimal(primo_n(pn)).log10()
    pn+=1

    # Desplazamiento
    d=s.adjusted()+1
    s=s/Decimal(10**d)

    return s.quantize(DIEZ_DECIMALES)


    def s_cifra(clave):
    """Calcula la semilla para contruir el cifrado (Ai) con la clave dada
    """
    s=Decimal(0)
    alfa_derivado=alfa_k(clave)
    pn=0
    for c in clave:
    n=lan(alfa_derivado, c)
    s+=n * Decimal(primo_n(pn)).log10()
    pn+=1

    # Desplazamiento
    d=s.adjusted()+1
    s=s/Decimal(10**d)

    return s.quantize(DIEZ_DECIMALES)


    def pseudo(s):
    """Calcula el siguiente numero pseudo aleatorio
    """
    resto = divmod((PI_DEC + s)**2, Decimal(1))[1]

    return resto.quantize(DIEZ_DECIMALES)


    def fn_a(l, s):
    """Funcion A para el calculo de la siguiente letra en el alfabeto
    derivado
    """
    n = s * (l-1)+1

    # Solo la parte entera
    return int(n.quantize(1))


    def alfa_k(clave):
    """Calcula el alfabeto derivado para la clave dada
    """
    s = s_alfa(clave)
    alfa_act = list(ALFABETO_BASE)
    alfa_derivado = []
    for n in range(ALFA_N):
    # Numero pseudoaleatorio
    s = pseudo(s)

    # L (Longitud restante)
    l = ALFA_N - n

    # Funcion A (el "-1" es para el siguiente indexado)
    p = fn_a(l, s) - 1

    # Nueva letra
    alfa_derivado.append(alfa_act[p])

    # Resto alfabeto
    alfa_act = alfa_act[0:p] + alfa_act[p+1::]

    return alfa_derivado



    def ldist(letra, pos):
    """Toma una letra a distancia "x" del alfabeto base
    """
    nueva_letra = (ALFABETO_BASE.index(letra) + pos) % NUM_LETRAS

    return ALFABETO_BASE[nueva_letra]


    def codifica(clave, texto, formato_s='t'):
    """Codifica un texto con la clave
    Uso: codifica(clave, texto, formato)
    Donde los parametros son:
    - clave: clave usada para cifrar (en mayusculas)
    - texto: texto a cifrar (en mayusculas y ya traducido)
    - formato_s: formato de salida. 't' texto (por defecto) y 'n' numerico
    """

    # Alfabeto derivado
    alfa_d = alfa_k(clave)

    # Tamano de la clave
    clave_n = len(clave)

    # Posiciones de las letras de la clave en el alfabeto derivado
    clave_ki = lan(alfa_d, clave)

    # Semilla aleatoria para la el calculo del cifrado
    s0 = s_cifra(clave)

    # Cifrado
    cifra = []
    sa = s0
    for n, ca in enumerate(texto):
    sa = pseudo(sa)
    a = fn_a(ALFA_N, sa)
    k = clave_ki[n % clave_n]
    p = lan(alfa_d, ca)
    c = (a + p + k) % ALFA_N
    if c == 0:
    c = ALFA_N

    cifra.append(c)

    # Formato de salida en texto ?
    if formato_s == 't':
    pos_menos1 = lambda pos: alfa_d.__getitem__(pos-1)
    return ''.join(map(pos_menos1, cifra))

    return cifra


    def decodifica(clave, texto, formato_s='t'):
    """ Decodifica un texto con la clave
    Uso: decodifica(clave, texto, formato)
    Donde los parametros son:
    - clave: clave para descifrar (en mayusculas)
    - texto: texto a descifrar (en mayusculas)
    - formato_s: formato de salida. 't' texto (por defecto) y 'n' numerico
    """

    # Alfabeto derivado
    alfa_d = alfa_k(clave)

    # Tamano de la clave
    clave_n = len(clave)

    # Posiciones de las letras de la clave en el alfabeto derivado
    clave_ki = lan(alfa_d, clave)

    # Semilla aleatoria para la el calculo del cifrado
    s0 = s_cifra(clave)

    # Cifrado
    claro = ''
    sa = s0
    for n, ca in enumerate(texto):
    sa = pseudo(sa)
    a = fn_a(ALFA_N, sa)
    k = clave_ki[n % clave_n]
    c = lan(alfa_d, ca)
    p = (c - a - k) % ALFA_N
    p = p % ALFA_N
    if p == 0:
    p = ALFA_N

    claro += alfa_d[p-1]

    # Formato de salida numerico ?
    if formato_s == 'n':
    index_mas1 = lambda pos: ALFABETO_BASE.index(pos) + 1
    claro = map(index_mas1, claro)

    return claro


    ###############################################################################
    # Ejecucion directa del modulo: Ejecuta los tests
    #
    if __name__ == '__main__' :

    import unittest

    ###########################################################################
    # Definicion de los tests
    class TestACYNOS2(unittest.TestCase):

    def test_letra_a_numero(self):
    self.assertEqual(lan('ABC', 'A'), 1)
    self.assertEqual(lan('ABC', 'C'), 3)
    self.assertRaises(ValueError, lan, 'ABC', 'D')


    def test_traduccion(self):
    self.assertEqual(texto_a_ascii('ABCDE'), 'ABCDE')
    self.assertEqual(texto_a_ascii(''), '')
    self.assertEqual(texto_a_ascii('\xc3\x91'), '~')
    self.assertEqual(texto_a_ascii(' '), '_')
    self.assertEqual(texto_a_ascii('\n'), '')


    def test_lee_primos(self):
    self.assertEqual(primo_n(0), 2)
    self.assertEqual(primo_n(1), 3)
    self.assertEqual(primo_n(100007), 1299827)


    def test_semilla_alfabeto(self):
    self.assertEqual(s_alfa(''), Decimal(0))
    self.assertEqual(s_alfa('VALE'), Decimal("0.2001394141"))


    def test_pi_decimal(self):
    self.assertEqual(PI_DEC, Decimal("3.1415926536"))


    def test_pseudo(self):
    self.assertEqual(
    pseudo(Decimal("0.2001394141")),
    Decimal("0.1671732123"))

    self.assertEqual(
    pseudo(Decimal("0.1671732123")),
    Decimal("0.9479315553"))

    sa=Decimal("0.2001394141")
    for s in range(28):
    sa=pseudo(sa)

    self.assertEqual(sa, Decimal("0.3376494172"))


    def test_fn_a(self):
    s = Decimal("0.1671732123")
    self.assertEqual(fn_a(28, s), 6)

    s = Decimal("0.9479315553")
    self.assertEqual(fn_a(27, s), 26)

    s = Decimal("0.7242082552")
    self.assertEqual(fn_a(26, s), 19)

    s = Decimal("0.9444166665")
    self.assertEqual(fn_a(25, s), 24)


    def test_alfa_derivado(self):
    alfa_derivado = alfa_k('VALE')
    self.assertEqual(ALFA_N, len(alfa_derivado))
    self.assertEqual(
    alfa_derivado,
    list('FZSYQRXNDAVGBWLUKHEPOMIJT~_C'))


    def test_semilla_cifrado(self):
    self.assertEqual(s_cifra(''), Decimal(0))

    s0_cifrado=Decimal("0.3462395532")
    self.assertEqual(s_cifra('VALE'), s0_cifrado)

    s115 = Decimal("0.4232082654")
    si = s0_cifrado
    for i in range(115):
    si=pseudo(si)

    self.assertEqual(si, s115)


    def test_de_claro_a_pi(self):
    clave = 'VALE'
    claro = "LA_HEROICA_CIUDAD_DORMIA"
    pi = [15,10,27,18,19,06,21,23,28,10,\
    27,28,23,16, 9,10, 9,27, 9,21,\
    06,22,23,10]

    r = lan(alfa_k(clave), claro)
    for n, (c, p) in enumerate(zip(r, pi)):
    self.assertEqual(c, p, "C: %d, P: %d, N: %d"% (c, p, n))


    def test_cifrado(self):
    # cifrado vacio
    self.assertEqual('', codifica('', ''))
    self.assertEqual([], codifica('', '', 'n'))

    clave = 'VALE'
    claro = 'LA_HEROICA_CIUDAD_DORMIA'
    cin = [ 3,18, 3,11, 6, 7,20, 1,22, 2,\
    13,16,11,18,19,18,23,16, 8, 4,\
    14,10,13,13]

    cit = 'SHSVRXPFMZBUVHEHIUNYWABB'

    r = codifica(clave, claro, 'n')

    self.assertEqual(len(r), len(claro))

    for n, (c, p) in enumerate(zip(r, cin)):
    self.assertEqual(c, p, "C: %d, P: %d, N: %d"% (c, p, n))

    r = codifica(clave, claro)
    for n, (c, p) in enumerate(zip(r, cit)):
    self.assertEqual(c, p, "C: %s, P: %s, N: %d"% (c, p, n))


    def test_descifrado(self):
    # cifrado vacio
    self.assertEqual('', decodifica('', ''))
    self.assertEqual([], decodifica('', [], 'n'))

    clave = 'VALE'
    claro = 'LA_HEROICA_CIUDAD_DORMIA'

    lan_alfabase = lambda letra: lan(ALFABETO_BASE, letra)
    claro_num = map(lan_alfabase, claro)

    cit = 'SHSVRXPFMZBUVHEHIUNYWABB'

    # Formato de salida numerico
    r = decodifica(clave, cit, 'n')
    self.assertEqual(len(r), len(claro))

    for n, (c_desc, c_claro) in enumerate(zip(r, claro_num)):
    self.assertEqual(c_desc, c_claro,
    "Caracter descifrado: %s, Caracter claro: %s, N: %d" %
    (c_desc, c_claro, n))

    # Formato de salida texto
    r = decodifica(clave, cit)
    self.assertEqual(len(r), len(claro))
    for n, (c_desc, c_claro) in enumerate(zip(r, claro)):
    self.assertEqual(c_desc, c_claro,
    "Caracter descifrado: %s, Caracter claro: %s, N: %d" %
    (c_desc, c_claro, n))


    ###########################################################################
    # Ejecucion de los tests
    unittest.main()