Pull to refresh

Сеть-шифровальщик или как я от нейросети странного хотел

Идея использовать нейросети для шифрования информации витала в голове у меня давно (с конца 2000х). Но, как это водится, то времени не хватало, то желания. Так что пишу это только сейчас (хотя может материал уже и устарел).

Вводная


Суть идеи заключается в том что-б передавать не само зашифрованное сообщение а настроенные веса сети которая сможет данное сообщение воспроизвести будучи активированной кужным ключем.

Описание работы


Предположим у нас есть сообщение «Hello i'm EncryptNN and i'm here». Преобразуем его в пару массивов tc, letters; где tc = массив «таймкодов последовательности» а letters соответсвующие байты сообщения. Дальше учим сеть сопоставлять таймкоды определенным байтам сообщения.

Процесс обмена сообщениями выглядит так:

  1. Отправитель передает тело сообщения
  2. Отправитель передает сообщения (подсказка для генератора последовательностей таймкодов)
  3. Получатель загружает в сеть веса переданные в п.1
  4. Получатель загружает в сеть секрет и получает дешифрованное сообщение

Прототип


Сначала нам понядобятся утилитарные ф-ции преобразования из/в строку:

def toChars(s):
    return np.array([ord(c) for c in s])

def toArr(c):
    r = np.zeros(256);
    r[c] = 1
    return r

def toCharArr(s):
    return np.array([toArr(c) for c in toChars(s)])

def fromChars(arr):
    return ''.join(chr(i) for i in arr)

def fromArr(arr):
    return np.argmax(arr)
    
def fromCharArr(arr):
    return fromChars([fromArr(a) for a in arr])
    
def toTimeCode(i, l = 8):
    val = [int(x) for x in bin(i)[2:]]
    result = [0] * (l - len(val))
    result.extend(val)
    return result
    
def stringToSequence(s):
    tc = []
    letters = []
    for t,c in enumerate(toCharArr(s)):
        tc+=[toTimeCode(t)]
        letters+=[c]
    
    return np.array(tc),np.array(letters)

В текущем примере «секрет» — начало последовательности = 0, шаг = 1.

Далее опишем саму сеточку (я буду использовать Keras для краткости). В текущей реализации работает простейший персептрон. Сесть состоит из 2х слоев: входной слой принимающий таймкод и выходной — отдающий байт исходного сообщения закодированный как «one-hot».

inSize = 8 #выбрано просто под полную ASCII таблицу

model = Sequential()
model.add(Dense(inSize, input_shape = (inSize,),activation="relu"))
model.add(Dense(256))
model.add(Activation("softmax"))

model.compile(loss=keras.losses.categorical_crossentropy, optimizer='sgd')

Теперь нам остались только тренировка и экспорт данных для получателя:

#тренировка
tc,l = stringToSequence(testString)

res = 10
cnt = 0 
epochs = 100

while( res > 0.1):
    cnt+=1
    model.fit(tc,l, epochs=epochs, verbose=False)
    res = model.evaluate(tc,l, verbose=False)
    
    print("Loss: ", res)
    v = model.predict(tc)  
    print(fromCharArr(v))
    
print("epochs = ", cnt*epochs)

#экспорт
model.save_weights("/tmp/test1.data.w")

Для примера — обучение фразе «Hello i'm EncryptNN and i'm here» на моем ноутбуке заняло 22800 эпох.

Выводы


  • Такое кодирование в принципе возможно
  • Для кодирования требуются огромные ресурсы, для раскодирования — нет
  • ИМХО (и тут я очень прошу помощи математиков) невозможно восстановить сообщения при налиции только 1 половины данных
  • Все сообщения которым я смог научить сеть весили одинаково
  • Можно щифровать в одну сеть несколько сообщений с разными секретами (немного не очевидно, но очень просто)

Вопросы и доработки


  • Очевидо что секрет выбран простейшим и его надо переделать
  • Какой предел памяти у такой сети (какой макс объем данных так можно зашифровать)?
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.