Rot13 для чисел

РЕДАКТИРОВАТЬ: теперь сообщение основного сообщения о движении в http://messymatters.com/sealedbids

Идея rot13 заключается в том, чтобы скрывать текст, например, для предотвращения спойлеров. Это не должно быть криптографически безопасным, но просто убедитесь, что только люди, которые уверены, что они хотят его прочитать, прочтут его.

Я хотел бы сделать что-то подобное для чисел, для приложения с закрытыми ставками. Примерно я хочу отправить кого-то своему номеру и доверять им, чтобы выбрать свой номер, не затронутый моим, но тогда они должны быть способны выявить мою (чисто клиентскую), когда они будут готовы. Они не должны требовать от меня или третьих лиц дополнительного ввода.

(Добавлено: обратите внимание на предположение, что получателю доверяют не обманывать.)

Это не так просто, как rot13, потому что некоторые числа, такие как 1 и 2, будут повторяться достаточно часто, чтобы вы могли вспомнить, что, скажем, 34.2 действительно 1.

Вот что я ищу специально:

Функция seal(), которая отображает действительное число в действительное число (или строку). Он не должен быть детерминированным - печать (7) не должна отображаться на одно и то же каждый раз. Но соответствующая функция unseal() должна быть детерминированной - unseal (seal (x)) должно равняться x для всех x. Я не хочу, чтобы печать или вскрытие вызывали любые веб-сервисы или даже получали системное время (потому что я не хочу принимать синхронизированные часы). (Добавлено: Хорошо, чтобы предположить, что все ставки будут меньше некоторого максимума, известного всем, скажем, миллион.)

Проверка работоспособности:

> seal(7)
482.2382   # some random-seeming number or string.
> seal(7)
71.9217    # a completely different random-seeming number or string.
> unseal(seal(7))
7          # we always recover the original number by unsealing.

Ответ 1

Вот решение, на которое отвечает Сванте.

M = 9999  # Upper bound on bid.
seal(x) = M * randInt(9,99) + x
unseal(x) = x % M

Проверка работоспособности:

> seal(7)
716017
> seal(7)
518497
> unseal(seal(7))
7

Для этого нужно настроить, чтобы разрешить отрицательные ставки:

M = 9999  # Numbers between -M/2 and M/2 can be sealed.
seal(x) = M * randInt(9,99) + x
unseal(x) = 
  m = x % M; 
  if m > M/2 return m - M else return m

Хорошая вещь об этом решении заключается в том, насколько тривиальным для получателя является декодирование - просто мода на 9999 (и если это 5000 или более, то это была отрицательная ставка, чтобы вычесть еще 9999). Также приятно, что неясное предложение будет длиться не более 6 цифр. (Это большая безопасность для того, что я имею в виду - если ставки могут превышать $5k, тогда я бы использовал более безопасный метод. Хотя, конечно, максимальная ставка в этом методе может быть установлена ​​так высоко, как вы хотите.)

Инструкции для Lay Folk

Выберите число от 9 до 99 и умножьте его на 9999, затем добавьте ставку. Это даст 5 или 6-значное число, которое кодирует вашу ставку. Чтобы вскрыть его, разделите его на 9999, вычтите часть слева от десятичной точки, затем умножьте ее на 9999. (Это известно детям и математикам как "нахождение остатка при делении на 9999" или "изменение на 9999" соответственно.)

Это работает для неотрицательных ставок менее 9999 (если этого недостаточно, используйте 99999 или столько цифр, сколько захотите). Если вы хотите разрешить отрицательные ставки, тогда волшебный номер 9999 должен быть в два раза больше возможной ставки. И когда декодирование, если результат больше половины из 9999, т.е. 5000 или более, затем вычитает 9999 для получения фактической (отрицательной) ставки.

Опять же, обратите внимание, что это в системе чести: ничего технически не мешает вам вскрыть другой номер человека, как только вы его увидите.

Ответ 2

Вы можете упаковать свой номер в виде 4 байтового поплавка вместе с другим случайным поплавком в double и отправить его. Затем клиенту просто нужно забрать первые четыре байта. В python:

import struct, random
def seal(f):
   return struct.unpack("d",struct.pack("ff", f, random.random() ))[0]
def unseal(f):
   return struct.unpack("ff",struct.pack("d", f))[0]

>>> unseal( seal( 3))
3.0
>>> seal(3)
4.4533985422978706e-009
>>> seal(3)
9.0767582382536571e-010

Ответ 3

Что вы хотите сделать (Схема обязательств) невозможно выполнить только на стороне клиента. Лучшее, что вы можете сделать, это шифрование с помощью общего ключа.

Если клиенту не требуется ваше сотрудничество, чтобы выявить номер, они могут просто изменить программу, чтобы показать номер. Вы могли бы просто отправить его и не отобразить.

Чтобы сделать это правильно, вы можете отправить безопасный хэш своей ставки + случайную соль. Это обязывает вас к вашей заявке. Другой клиент может передать свою ставку таким же образом. Затем вы делитесь своей ценой и солью.

[edit] Поскольку вы доверяете другому клиенту:

Sender:
Let M be your message
K = random 4-byte key
C1 = M xor hash(K) //hash optional: hides patterns in M xor K
//(you can repeat or truncate hash(K) as necessary to cover the message)
//(could also xor with output of a PRNG instead)
C2 = K append M //they need to know K to reveal the message
send C2 //(convert bytes to hex representation if needed)

Receiver:
receive C2
K = C2[:4]
C1 = C2[4:]
M = C1 xor hash(K)

Ответ 4

Если вы полагаетесь на честность пользователя и имеете дело только с целыми ставками, простая операция XOR со случайным числом должна быть все, что вам нужно, пример в С#:

static Random rng = new Random();

static string EncodeBid(int bid)
{
    int i = rng.Next();
    return String.Format("{0}:{1}", i, bid ^ i);
}

static int DecodeBid(string encodedBid)
{
    string[] d = encodedBid.Split(":".ToCharArray());
    return Convert.ToInt32(d[0]) ^ Convert.ToInt32(d[1]);
}

Использование:

int bid = 500;
string encodedBid = EncodeBid(bid); // encodedBid is something like 54017514:4017054 and will be different each time
int decodedBid = DecodeBid(encodedBid); // decodedBid is 500

Преобразование процесса декодирования в конструкцию клиентской стороны должно быть достаточно простым.

Ответ 5

Есть ли максимальная ставка? Если это так, вы можете сделать это:

Пусть max-bid - максимальная ставка и a-bid ставка, которую вы хотите кодировать. Умножьте max-bid на довольно большое случайное число (если вы хотите использовать кодировку base64 на последнем шаге, max-rand должен быть (2^24/max-bid)-1, а min-rand возможно, половина из них), затем добавьте a-bid. Кодируйте это, например. через base64.

Затем получатель должен просто декодировать и найти остаток по модулю max-bid.

Ответ 6

Знаете ли вы, что вам нужен больший "запечатанный" набор чисел, чем ваш оригинал, если вы хотите, чтобы это работало?

Итак, вам нужно каким-то образом ограничить свои реальные цифры или сохранить дополнительную информацию, которую вы не показываете.

Ответ 7

Один простой способ - написать сообщение вроде:

"моя ставка: $14.23: aduigfurjwjnfdjfugfojdjkdskdfdhfddfuiodrnfnghfifyis"

Все эти нежелательные файлы генерируются случайным образом и различаются каждый раз.

Отправить другому лицу сообщение SHA256 сообщения. Попросите их отправить вам хеш их заявки. Затем, как только у вас есть хеши, отправьте полное сообщение и подтвердите, что их ставка соответствует хешу, которую они вам дали.

Это дает более сильные гарантии, чем вам нужно - от них не получается выработать свою ставку, прежде чем отправлять свое полное сообщение. Однако, как вы описали, нет функции unseal().

Эта простая схема имеет различные недостатки, которые не имеют полной схемы нулевого знания. Например, если они подделывают вас, отправив вам случайное число вместо хеша, то они могут разработать вашу ставку, не раскрывая свои собственные. Но вы не просили пуленепробиваемого. Это предотвращает как случайный, так и (я думаю) необнаруживаемый обман, и использует только общедоступную утилиту командной строки, а также генератор случайных чисел (кости будут делать).

Если, как вы говорите, вы хотите, чтобы они смогли восстановить вашу ставку без каких-либо дополнительных данных от вас, и вы готовы доверять им только для того, чтобы сделать это после публикации своей заявки, а затем просто зашифровать с использованием любого старого симметричного шифра (gpg --symmetric, возможно) и ключ "rot13". Это предотвратит случайное обманывание, но допускает необнаруживаемый обман.

Ответ 8

Так как кажется, что вы предполагаете, что другой человек не хочет знать вашу ставку до тех пор, пока они не поместили свои собственные, и им можно доверять не обманывать, вы можете попробовать схему с переменным вращением:

from random import randint

def seal(input):
    r = randint(0, 50)
    obfuscate = [str(r)] + [ str(ord(c) + r) for c in '%s' % input ]
    return ':'.join(obfuscate)

def unseal(input):
    tmp = input.split(':')
    r = int(tmp.pop(0))
    deobfuscate = [ chr(int(c) - r) for c in tmp ]
    return ''.join(deobfuscate)

# I suppose you would put your bid in here, for 100 dollars
tmp = seal('$100.00') # --> '1:37:50:49:49:47:49:49' (output varies)
print unseal(tmp) # --> '$100.00'

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

Ответ 9

Одна идея, которая появилась в моем сознании, заключалась в том, чтобы, возможно, основывать свой алгоритм на математике используется для безопасного обмена ключами.

Если вы хотите дать двум людям, Бобу и Алисе, по пол ключа каждый так что только при их объединении они смогут открыть все блокировки ключей, как вы это делаете? Решение этого исходит из математики. Скажем, у вас есть две точки A (-2,2) и B (2,0) в системе координат x/y.

               |
       A       +
               |
               C
               |
---+---+---+---|---+---B---+---+---+---
               |
               +
               |
               +

Если вы нарисуете прямую линию между ними, она пересечет ось y точно в одной единственной точке, C (0,1). Если вы знаете только одну из точек A или B, невозможно сказать, где она пересечет. Таким образом, вы можете позволить точкам A и B быть разделяемыми ключами, которые при объединении покажут значение y точки пересечения (то есть 1 в этом примере), и это значение обычно используется как реальный ключ для чего-то.

В заявке на участие в торгах вы можете позволить seal() и unseal() поменять значение y между точками C и B (детерминированным), но время от времени имеет точку А.

Таким образом, уплотнение (y-значение точки B) даст совершенно разные результаты в зависимости от точки A, но unseal (печать (y-значение точки B)) должна вернуть y-значение B, которое вы просите.

PS Не требуется иметь A и B по разные стороны оси y, но гораздо проще концептуально думать об этом таким образом (и я рекомендую также реализовать его таким образом).

С помощью этой прямой вы можете делиться ключами между несколькими людьми, чтобы только два из они необходимы для разблокировки. Можно использовать типы кривых, кроме прямых, для создания других свойства обмена ключами (т.е. требуется 3 из 3 ключей и т.д.).

Ответ 10

Псевдокод:

закодировать:

value = 2000
key = random(0..255); // our key is only 2 bytes

// 'sealing it'
value = value XOR 2000;

// add key
sealed = (value << 16) | key

расшифровывает:

key = sealed & 0xFF
unsealed = key XOR (sealed >> 16)

Будет ли это работать?

Ответ 11

Если ставки довольно большие, как насчет поразрядного XOR с некоторым заданным числом случайных чисел? Затем XORing снова получит исходное значение.
Вы можете изменить число так часто, как вам нравится, если это знают как клиент, так и сервер.

Ответ 12

Вы можете установить другую базу (например, 16, 17, 18 и т.д.) и отслеживать, какая база вы "запечатали" ставку с помощью...

Конечно, это предполагает большие числа ( > база, которую вы используете, по крайней мере). Если бы они были десятичными, вы могли бы отказаться от этой точки (например, 27.04 становится 2704, которую вы затем переводите на базу 29...)

Вероятно, вы захотите использовать базу с 17 по 36 (только потому, что некоторые люди могут распознать гекс и иметь возможность перевести его в голову...)

Таким образом, у вас будут такие номера, как G4 или Z3 или KW (в зависимости от номеров, которые вы запечатываете)...

Ответ 13

Здесь дешевый способ контрейлеризации с rot13:

Предположим, что у нас есть функция gibberish(), которая генерирует нечто вроде "fdjk alqef lwwqisvz" и слова функции (x), которое преобразует число x в слова, например, слова (42) возвращают "сорок два" (без дефис).

Затем определите

seal(x) = rot13(gibberish() + words(x) + gibberish())

и

unseal(x) = rot13(x)

Конечно, вывод unseal не является фактическим числом и полезен только человеку, но это может быть хорошо. Вы могли бы сделать его немного более изощренным с функцией слова-к-номеру, которая также просто выбросила бы все слова тарабарщины (определяемые как все, что не является одним из числовых слов, - я думаю, их насчитывается менее сотни).

Проверка работоспособности:

> seal(7)
fhrlls hqufw huqfha frira afsb ht ahuqw ajaijzji
> seal(7)
qbua adfshua hqgya ubiwi ahp wqwia qhu frira wge
> unseal(seal(7))
sueyyf udhsj seven ahkua snsfo ug nuhdj nwnvwmwv

Я знаю, что это глупо, но это способ сделать это "вручную", если все, что у вас есть, доступно rot13.