Кодирование и шифрование

advertisement
Кодирование по Фано
a
b
c
d
e
f
g
h
i
j
k
20
18
17
11
10
7
5
4
4
3
1
0
a
b
c
1
d
e
f
g
h
i
j
k
55
20
18
17
45
11
10
7
5
4
4
3
1
00
a
01
b
c
10
d
e
11
f
g
h
i
j
k
20
35
18
17
21
11
10
24
7
5
4
4
3
1
a
b
c
d
e
f
g
h
i
j
k
00
010
011
100
101
1100
1101
11100
11101
11110
11111
Программа на языке Java
public class Code {
public long code;
public byte len;
// Собственно код символа
// Длина кода
// Символы (в порядке убывания вероятностей появления)
public static char[] chars =
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'};
// Вероятности появления символов
public static int[] probs =
{ 20, 18, 17, 11, 10,
7,
5,
4,
4,
3,
1 };
// Формируемый массив кодов
public static Code[] codes = new Code[chars.length];
}
public class Fano {
private static int mediana(int low, int high) {
int sLow = 0;
// Сумма первых элементов
int sHigh = Code.probs[high]; // Сумма последних элементов
for (int i = low; i < high; i++) {
sLow += Code.probs[i];
}
int m = high;
// Перед поиском границы sLow = sum[low:(high-1)], sHigh = sum[high]
int diff;
do {
m--;
diff = Math.abs(sLow - sHigh);
// Вычисляем предыдущую разность
// Изменяем верхнюю и нижнюю суммы
sLow -= Code.probs[m];
sHigh += Code.probs[m];
} while (Math.abs(sLow - sHigh) < diff);
// Цикл заканчивается, когда разности перестанут уменьшаться
return m;
}
public static void fano(int low, int high) {
if (low < high) {
// Определяем границу равных сумм вероятностей
int m = mediana(low, high);
for (int i = low; i <= high; i++) {
// Сдвигаем коды и дописываем нули в первую половину и единицы во вторую
Code.codes[i].code <<= 1;
if (i > m) Code.codes[i].code++;
Code.codes[i].len++;
}
// Рекурсивный вызов алгоритма для двух отдельных половин таблицы
fano(low, m);
fano(m+1, high);
}
}
}
Кодирование по Хаффмену
a
b
c
d
e
f
g
h
i
j
k
bcdfijk aegh
20
18
17
11
10
7
5
4
4
3
1
a
b
c
d
e
f
g
h
i
jk
aegh
bc
dfijk
20
18
17
11
10
7
5
4
4
4
39
35
26
a
b
c
d
e
ijk
f
g
h
bc
dfijk
a
egh
20
18
17
11
10
8
7
5
4
35
26
20
19
a
b
c
d
e
gh
ijk
f
dfijk
a
egh
b
c
20
18
17
11
10
9
8
7
26
20
19
18
17
a
b
c
fijk
d
e
gh
a
egh
b
c
fijk
d
20
18
17
15
11
10
9
20
19
18
17
15
11
61
39
a
aegh
10
1
e
egh
11
gh
bc
bcdfijk
110
g
1110
h
1111
111
b
000
c
001
00
0
i
ijk
fijk
dfijk
01
d
0100
jk
010
f
011
01000
0101
j
010000
k
010001
01000
public class Huffman {
// Рабочая копия массива вероятностей
static int[] prs = new int[Code.probs.length];
private static int up(int n, int p) {
int j = n-1;
// Поиск начинаем с конца таблицы
while (j >= 1) {
if (prs[j-1] < p) {
// Сдвиг по таблице
prs[j] = prs[j-1];
j--;
} else {
// Место в таблице найдено
break;
}
}
// Вставка значения в таблицу и возврат
prs[j] = p;
return j;
}
public static void huffman(int n) {
if (n == 2) {
// Предельный случай - два символа в таблице
Code.codes[0] = new Code((long)0, (byte)1);
Code.codes[1] = new Code((long)1, (byte)1);
} else {
// Просуммируем две наименьшие вероятности и вставим в табицу на свое место
int j = up(n, prs[n-2] + prs[n-1]);
// Рекурсивный вызов алгоритма для уменьшенной таблицы
huffman(n-1);
// Приписывание кодов согласно сохраненному значению j
down(n, j);
}
}
private static void down(int n, int j) {
Code c = new Code(Code.codes[j]); // Запомнили код
for (int i = j; i < n-2; i++) {
// Сдвигаем коды вниз по таблице
Code.codes[i].assign(Code.codes[i+1]);
}
// Восстанавливаем два последних кода
c.len++;
c.code <<= 1;
Code.codes[n-2] = new Code(c);
c.code++;
Code.codes[n-1] = new Code(c);
}
}
Некоторые сведения из модульной
арифметики
 a  b (mod n)  a mod n = b mod n
 Операции «по модулю n»:
a +n b  (a + b) mod n
a *n b  (a * b) mod n
 Малая теорема Ферма:
0 < a < p  ap-1  1 (mod p)
 Следствие из «китайской теоремы об остатках»:
n = p*q и x  y (mod n)  x  y (mod p) и x  y (mod q)
Шифрование с открытым ключом
Выбираем два простых числа p и q;
Вычисляем n = p*q;
Выбираем нечетное e, взаимно простое с (p-1)(q-1);
Вычисляем d = e–1 mod (p-1)(q-1);
Открытый ключ – пара <n, e>;
Закрытый ключ – пара <n, d>.
 Исходное сообщение: S = S0S1…Sk,
Шифрованное сообщение: C = C0C1…Ck.
 Шифрование: Ci = (Si)e mod n;
Расшифровка: Pi = (Ci)d mod n.
 Утверждение: Pi = Si.





Доказательство корректности
 Pi = (Si)ed mod n.
Покажем, что при M < n Med  M mod n
 Это очевидно верно при M = 0
 При M > 0 по малой теореме Ферма:
k(q-1)
Med = M (Mp-1)
, поскольку ed = 1 + k(p-1)(q-1);
Med  M  1k(q-1)  M (mod p)
 Аналогично, Med  M (mod q),
следовательно, Med  M (mod n)
Пример кода
Выберем p = 3, q = 11.
Тогда n = 33, (p-1)(q-1) = 20,
Выберем e = 7, тогда d = 3 (ed = 21; 21  1 mod 20)
Фрагменты сообщения могут быть не длиннее 5 бит.
Пусть S0 = 21, S1 = 13, S2 = 17
Тогда C0 = 217 mod 33 = 21,
C1 = 137 mod 33 = 7,
C2 = 177 mod 33 = 8,
 Проверка (расшифровка):
P0 = 213 mod 33 = 21 = S0,
P1 = 73 mod 33 = 13 = S1,
P2 = 83 mod 33 = 17 = S2,





Download