vector-crypt 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vector_crypt-0.1.0/LICENSE +21 -0
- vector_crypt-0.1.0/PKG-INFO +116 -0
- vector_crypt-0.1.0/README.md +101 -0
- vector_crypt-0.1.0/pyproject.toml +27 -0
- vector_crypt-0.1.0/setup.cfg +4 -0
- vector_crypt-0.1.0/tests/test_basic.py +27 -0
- vector_crypt-0.1.0/vector_crypt/__init__.py +85 -0
- vector_crypt-0.1.0/vector_crypt/classes.py +154 -0
- vector_crypt-0.1.0/vector_crypt/endecode.py +95 -0
- vector_crypt-0.1.0/vector_crypt/keygen.py +94 -0
- vector_crypt-0.1.0/vector_crypt/vector_codec.py +130 -0
- vector_crypt-0.1.0/vector_crypt.egg-info/PKG-INFO +116 -0
- vector_crypt-0.1.0/vector_crypt.egg-info/SOURCES.txt +13 -0
- vector_crypt-0.1.0/vector_crypt.egg-info/dependency_links.txt +1 -0
- vector_crypt-0.1.0/vector_crypt.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sagu4ka
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vector_crypt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A toy cryptographic library encoding data as applied vector sets.
|
|
5
|
+
Author-email: Sagu4ka <sagu4ka@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: cryptography,vector,encoding,one-time-pad
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# Applied-Vector Crypto (`vector_crypt`)
|
|
17
|
+
|
|
18
|
+
A lightweight Python library demonstrating a **novel cryptographic
|
|
19
|
+
principle**: represent both plaintext and keys as _sets of applied vectors_
|
|
20
|
+
and perform encryption simply by vector addition. The package is intended as
|
|
21
|
+
an educational toy, a research starting point, or a playful experiment rather
|
|
22
|
+
than a drop-in replacement for real-world ciphers.
|
|
23
|
+
|
|
24
|
+
## 🚀 Основная идея
|
|
25
|
+
|
|
26
|
+
Каждый байт (или символ, блок) сообщения кодируется как
|
|
27
|
+
**`AppliedVector`** — отрезок с фиксированным началом и направлением. Ключ
|
|
28
|
+
тоже является набором таких векторов. Шифрование сводится к поэлементному
|
|
29
|
+
сложению двух наборов (похожим на операцию `XOR` для чисел), а расшифровка –
|
|
30
|
+
к вычитанию.
|
|
31
|
+
|
|
32
|
+
*В отличие от большинства алгоритмов, здесь информация представлена геометрически,
|
|
33
|
+
что даёт визуализацию, естественное расширение на многомерность и простой
|
|
34
|
+
потоковый интерфейс.*
|
|
35
|
+
|
|
36
|
+
### Почему это уникально?
|
|
37
|
+
|
|
38
|
+
- **Геометрическое представление.** Традиционные симметричные схемы оперируют
|
|
39
|
+
на битах и байтах. Мы работаем с векторами, что позволяет легко вводить
|
|
40
|
+
масштабирование, вращения, линейные преобразования и работать в произвольных
|
|
41
|
+
пространствах (включая конечные поля).
|
|
42
|
+
|
|
43
|
+
- **Простота.** Всего пара строк кода даёт шифрование/дешифровку. Нет S‑боксов,
|
|
44
|
+
нет ключевого расписания, только алгебра над векторами.
|
|
45
|
+
|
|
46
|
+
- **Потоковая обработка.** Код поддерживает генераторы, чтение/запись файлов
|
|
47
|
+
по кускам и пакетные операции, что пригодится для больших данных.
|
|
48
|
+
|
|
49
|
+
- **Проверяемость.** Отображение вектор‑множества на экран, графы, SVG…
|
|
50
|
+
Приятно для обучения и визуальных демо.
|
|
51
|
+
|
|
52
|
+
## 🔍 Схожие идеи в криптографии
|
|
53
|
+
|
|
54
|
+
- **One‑time pad / Vernam cipher.** Байт сообщения прибавляется к байту ключа
|
|
55
|
+
по модулю 2⁸; наша операция аналогична, но мы «вырастаем» в векторное
|
|
56
|
+
пространство и сохраняем абсолютную информацию в промежуточном виде (можно
|
|
57
|
+
наложить дополнительные операции).
|
|
58
|
+
|
|
59
|
+
- **Кодировка векторов в стойкие каналы.** В теории информации часто
|
|
60
|
+
рассматривают передаваемые сигналы как точки в \\Rⁿ; в этом смысле наше
|
|
61
|
+
шифрование — частный случай линейного кодирования.
|
|
62
|
+
|
|
63
|
+
- **Графовые шифры.** В гомоморфных системах используются линейные операции;
|
|
64
|
+
наш механизм легко расширяется до гомоморфизма над векторным пространством.
|
|
65
|
+
|
|
66
|
+
Однако: мы не претендуем на криптостойкость, а скорее демонстрируем новый
|
|
67
|
+
формальный подход. Внедрить в реальную систему потребует серьёзного
|
|
68
|
+
криптоанализа и, вероятно, модификаций (например, работа в конечных полях,
|
|
69
|
+
нелинейные слои и т. д.).
|
|
70
|
+
|
|
71
|
+
## 🧩 Структура проекта
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
vector_crypt/ # репозиторий
|
|
75
|
+
├── vector_crypt/ # собственно пакет Python
|
|
76
|
+
│ ├── __init__.py
|
|
77
|
+
│ ├── classes.py
|
|
78
|
+
│ ├── endecode.py
|
|
79
|
+
│ ├── keygen.py
|
|
80
|
+
│ └── vector_codec.py
|
|
81
|
+
├── tests/ # простые тесты (пока минимум)
|
|
82
|
+
├── README.md # вы читаете
|
|
83
|
+
├── LICENSE # MIT
|
|
84
|
+
└── pyproject.toml # сборка/метаданные
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## ⚙️ Установка и использование
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pip install vector_crypt
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from vector_crypt import encrypt_text, decrypt_text, key_for_data
|
|
95
|
+
|
|
96
|
+
key = key_for_data(b"secret message")
|
|
97
|
+
cipher = encrypt_text("hello", key)
|
|
98
|
+
print(decrypt_text(cipher, key)) # hello
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Для потокового шифрования используйте `encrypt_bytes_stream` вместе с
|
|
102
|
+
`generate_random_key_stream`.
|
|
103
|
+
|
|
104
|
+
## 📝 Где использовать
|
|
105
|
+
|
|
106
|
+
Библиотека подходит для:
|
|
107
|
+
|
|
108
|
+
* учебных примеров и лекций по основам криптографии;
|
|
109
|
+
* прототипирования альтернативных представлений данных (векторов вместо
|
|
110
|
+
скаляров);
|
|
111
|
+
* демонстраций визуализации шифрования в 2D/3D;
|
|
112
|
+
* утилит, где требуется совместное хранение геометрической информации и
|
|
113
|
+
шифрования (например, защитить набор координат).
|
|
114
|
+
|
|
115
|
+
Не рекомендуется применять `vector_crypt` для защиты реальных данных без
|
|
116
|
+
дополнительного анализа.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Applied-Vector Crypto (`vector_crypt`)
|
|
2
|
+
|
|
3
|
+
A lightweight Python library demonstrating a **novel cryptographic
|
|
4
|
+
principle**: represent both plaintext and keys as _sets of applied vectors_
|
|
5
|
+
and perform encryption simply by vector addition. The package is intended as
|
|
6
|
+
an educational toy, a research starting point, or a playful experiment rather
|
|
7
|
+
than a drop-in replacement for real-world ciphers.
|
|
8
|
+
|
|
9
|
+
## 🚀 Основная идея
|
|
10
|
+
|
|
11
|
+
Каждый байт (или символ, блок) сообщения кодируется как
|
|
12
|
+
**`AppliedVector`** — отрезок с фиксированным началом и направлением. Ключ
|
|
13
|
+
тоже является набором таких векторов. Шифрование сводится к поэлементному
|
|
14
|
+
сложению двух наборов (похожим на операцию `XOR` для чисел), а расшифровка –
|
|
15
|
+
к вычитанию.
|
|
16
|
+
|
|
17
|
+
*В отличие от большинства алгоритмов, здесь информация представлена геометрически,
|
|
18
|
+
что даёт визуализацию, естественное расширение на многомерность и простой
|
|
19
|
+
потоковый интерфейс.*
|
|
20
|
+
|
|
21
|
+
### Почему это уникально?
|
|
22
|
+
|
|
23
|
+
- **Геометрическое представление.** Традиционные симметричные схемы оперируют
|
|
24
|
+
на битах и байтах. Мы работаем с векторами, что позволяет легко вводить
|
|
25
|
+
масштабирование, вращения, линейные преобразования и работать в произвольных
|
|
26
|
+
пространствах (включая конечные поля).
|
|
27
|
+
|
|
28
|
+
- **Простота.** Всего пара строк кода даёт шифрование/дешифровку. Нет S‑боксов,
|
|
29
|
+
нет ключевого расписания, только алгебра над векторами.
|
|
30
|
+
|
|
31
|
+
- **Потоковая обработка.** Код поддерживает генераторы, чтение/запись файлов
|
|
32
|
+
по кускам и пакетные операции, что пригодится для больших данных.
|
|
33
|
+
|
|
34
|
+
- **Проверяемость.** Отображение вектор‑множества на экран, графы, SVG…
|
|
35
|
+
Приятно для обучения и визуальных демо.
|
|
36
|
+
|
|
37
|
+
## 🔍 Схожие идеи в криптографии
|
|
38
|
+
|
|
39
|
+
- **One‑time pad / Vernam cipher.** Байт сообщения прибавляется к байту ключа
|
|
40
|
+
по модулю 2⁸; наша операция аналогична, но мы «вырастаем» в векторное
|
|
41
|
+
пространство и сохраняем абсолютную информацию в промежуточном виде (можно
|
|
42
|
+
наложить дополнительные операции).
|
|
43
|
+
|
|
44
|
+
- **Кодировка векторов в стойкие каналы.** В теории информации часто
|
|
45
|
+
рассматривают передаваемые сигналы как точки в \\Rⁿ; в этом смысле наше
|
|
46
|
+
шифрование — частный случай линейного кодирования.
|
|
47
|
+
|
|
48
|
+
- **Графовые шифры.** В гомоморфных системах используются линейные операции;
|
|
49
|
+
наш механизм легко расширяется до гомоморфизма над векторным пространством.
|
|
50
|
+
|
|
51
|
+
Однако: мы не претендуем на криптостойкость, а скорее демонстрируем новый
|
|
52
|
+
формальный подход. Внедрить в реальную систему потребует серьёзного
|
|
53
|
+
криптоанализа и, вероятно, модификаций (например, работа в конечных полях,
|
|
54
|
+
нелинейные слои и т. д.).
|
|
55
|
+
|
|
56
|
+
## 🧩 Структура проекта
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
vector_crypt/ # репозиторий
|
|
60
|
+
├── vector_crypt/ # собственно пакет Python
|
|
61
|
+
│ ├── __init__.py
|
|
62
|
+
│ ├── classes.py
|
|
63
|
+
│ ├── endecode.py
|
|
64
|
+
│ ├── keygen.py
|
|
65
|
+
│ └── vector_codec.py
|
|
66
|
+
├── tests/ # простые тесты (пока минимум)
|
|
67
|
+
├── README.md # вы читаете
|
|
68
|
+
├── LICENSE # MIT
|
|
69
|
+
└── pyproject.toml # сборка/метаданные
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## ⚙️ Установка и использование
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install vector_crypt
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from vector_crypt import encrypt_text, decrypt_text, key_for_data
|
|
80
|
+
|
|
81
|
+
key = key_for_data(b"secret message")
|
|
82
|
+
cipher = encrypt_text("hello", key)
|
|
83
|
+
print(decrypt_text(cipher, key)) # hello
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Для потокового шифрования используйте `encrypt_bytes_stream` вместе с
|
|
87
|
+
`generate_random_key_stream`.
|
|
88
|
+
|
|
89
|
+
## 📝 Где использовать
|
|
90
|
+
|
|
91
|
+
Библиотека подходит для:
|
|
92
|
+
|
|
93
|
+
* учебных примеров и лекций по основам криптографии;
|
|
94
|
+
* прототипирования альтернативных представлений данных (векторов вместо
|
|
95
|
+
скаляров);
|
|
96
|
+
* демонстраций визуализации шифрования в 2D/3D;
|
|
97
|
+
* утилит, где требуется совместное хранение геометрической информации и
|
|
98
|
+
шифрования (например, защитить набор координат).
|
|
99
|
+
|
|
100
|
+
Не рекомендуется применять `vector_crypt` для защиты реальных данных без
|
|
101
|
+
дополнительного анализа.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vector_crypt"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A toy cryptographic library encoding data as applied vector sets."
|
|
9
|
+
authors = [
|
|
10
|
+
{name = "Sagu4ka", email = "sagu4ka@gmail.com"},
|
|
11
|
+
]
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = {text = "MIT"}
|
|
14
|
+
requires-python = ">=3.8"
|
|
15
|
+
keywords = ["cryptography", "vector", "encoding", "one-time-pad"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
# no external dependencies for now
|
|
23
|
+
dependencies = []
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["."]
|
|
27
|
+
include = ["vector_crypt*"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from vector_crypt import (
|
|
4
|
+
Point,
|
|
5
|
+
encrypt,
|
|
6
|
+
decrypt,
|
|
7
|
+
bytes_to_vectors,
|
|
8
|
+
vectors_to_bytes,
|
|
9
|
+
generate_random_key,
|
|
10
|
+
encrypt_bytes_stream,
|
|
11
|
+
generate_random_key_stream,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_roundtrip_bytes():
|
|
16
|
+
data = b"hello"
|
|
17
|
+
key = generate_random_key(len(data))
|
|
18
|
+
vec = bytes_to_vectors(data)
|
|
19
|
+
cipher = encrypt(vec, key)
|
|
20
|
+
assert decrypt(cipher, key) == vec
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_stream_bytes():
|
|
24
|
+
data = b"streamy"
|
|
25
|
+
key_stream = generate_random_key_stream(len(data))
|
|
26
|
+
enc = list(encrypt_bytes_stream(data, key_stream))
|
|
27
|
+
assert len(enc) == len(data)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Top-level package for the applied-vector cryptography library.
|
|
2
|
+
|
|
3
|
+
The package is intentionally small and re-exports most of the user-facing
|
|
4
|
+
symbols from its submodules. Importing :mod:`vector_crypt` gives you access to
|
|
5
|
+
all the functionality described in the README.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
# re-export core data classes
|
|
11
|
+
from .classes import (
|
|
12
|
+
Point,
|
|
13
|
+
Vector,
|
|
14
|
+
AppliedVector,
|
|
15
|
+
AppliedVectorSet,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# encryption / decryption helpers
|
|
19
|
+
from .endecode import (
|
|
20
|
+
encrypt,
|
|
21
|
+
decrypt,
|
|
22
|
+
encrypt_bytes,
|
|
23
|
+
decrypt_bytes,
|
|
24
|
+
encrypt_text,
|
|
25
|
+
decrypt_text,
|
|
26
|
+
encrypt_sequence,
|
|
27
|
+
decrypt_sequence,
|
|
28
|
+
encrypt_bytes_stream,
|
|
29
|
+
decrypt_bytes_stream,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# codec utilities
|
|
33
|
+
from .vector_codec import (
|
|
34
|
+
bytes_to_vectors,
|
|
35
|
+
vectors_to_bytes,
|
|
36
|
+
text_to_vectors,
|
|
37
|
+
vectors_to_text,
|
|
38
|
+
bytes_to_vectors_stream,
|
|
39
|
+
vectors_to_bytes_stream,
|
|
40
|
+
file_to_vectors,
|
|
41
|
+
vectors_to_file,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# key generation helpers
|
|
45
|
+
from .keygen import (
|
|
46
|
+
generate_random_key,
|
|
47
|
+
key_for_data,
|
|
48
|
+
generate_random_key_stream,
|
|
49
|
+
generate_batch_keys,
|
|
50
|
+
key_stream_for_data,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
# core
|
|
55
|
+
"Point",
|
|
56
|
+
"Vector",
|
|
57
|
+
"AppliedVector",
|
|
58
|
+
"AppliedVectorSet",
|
|
59
|
+
# encryption
|
|
60
|
+
"encrypt",
|
|
61
|
+
"decrypt",
|
|
62
|
+
"encrypt_bytes",
|
|
63
|
+
"decrypt_bytes",
|
|
64
|
+
"encrypt_text",
|
|
65
|
+
"decrypt_text",
|
|
66
|
+
"encrypt_sequence",
|
|
67
|
+
"decrypt_sequence",
|
|
68
|
+
"encrypt_bytes_stream",
|
|
69
|
+
"decrypt_bytes_stream",
|
|
70
|
+
# codecs
|
|
71
|
+
"bytes_to_vectors",
|
|
72
|
+
"vectors_to_bytes",
|
|
73
|
+
"text_to_vectors",
|
|
74
|
+
"vectors_to_text",
|
|
75
|
+
"bytes_to_vectors_stream",
|
|
76
|
+
"vectors_to_bytes_stream",
|
|
77
|
+
"file_to_vectors",
|
|
78
|
+
"vectors_to_file",
|
|
79
|
+
# keygen
|
|
80
|
+
"generate_random_key",
|
|
81
|
+
"key_for_data",
|
|
82
|
+
"generate_random_key_stream",
|
|
83
|
+
"generate_batch_keys",
|
|
84
|
+
"key_stream_for_data",
|
|
85
|
+
]
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from math import sqrt
|
|
2
|
+
from typing import Iterable
|
|
3
|
+
|
|
4
|
+
class Point:
|
|
5
|
+
"""Class of a point in space"""
|
|
6
|
+
def __init__(self, x: float, y: float):
|
|
7
|
+
self.x = x
|
|
8
|
+
self.y = y
|
|
9
|
+
|
|
10
|
+
def __repr__(self):
|
|
11
|
+
return f"Point({self.x}, {self.y})"
|
|
12
|
+
|
|
13
|
+
def __eq__(self, other):
|
|
14
|
+
if not isinstance(other, Point):
|
|
15
|
+
return NotImplemented
|
|
16
|
+
return self.x == other.x and self.y == other.y
|
|
17
|
+
|
|
18
|
+
class Vector:
|
|
19
|
+
"""A vector class with no fixed location. It has only an endpoint, as if it were located at coordinates 0, 0.
|
|
20
|
+
More accurately, it represents the components (dx, dy) of the vector."""
|
|
21
|
+
def __init__(self, dx: float, dy: float):
|
|
22
|
+
self.dx = dx
|
|
23
|
+
self.dy = dy
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def from_points(cls, start_point: Point, end_point: Point):
|
|
27
|
+
"""Creates a Vector from two points."""
|
|
28
|
+
dx = end_point.x - start_point.x
|
|
29
|
+
dy = end_point.y - start_point.y
|
|
30
|
+
return cls(dx, dy)
|
|
31
|
+
|
|
32
|
+
def get_length(self) -> float:
|
|
33
|
+
return sqrt(self.dx**2 + self.dy**2)
|
|
34
|
+
|
|
35
|
+
def __repr__(self):
|
|
36
|
+
return f"Vector(dx={self.dx}, dy={self.dy})"
|
|
37
|
+
|
|
38
|
+
def __add__(self, other):
|
|
39
|
+
if not isinstance(other, Vector):
|
|
40
|
+
return NotImplemented
|
|
41
|
+
return Vector(self.dx + other.dx, self.dy + other.dy)
|
|
42
|
+
|
|
43
|
+
def __sub__(self, other):
|
|
44
|
+
if not isinstance(other, Vector):
|
|
45
|
+
return NotImplemented
|
|
46
|
+
return Vector(self.dx - other.dx, self.dy - other.dy)
|
|
47
|
+
|
|
48
|
+
def __mul__(self, scalar: float):
|
|
49
|
+
return Vector(self.dx * scalar, self.dy * scalar)
|
|
50
|
+
|
|
51
|
+
def __rmul__(self, scalar: float):
|
|
52
|
+
return self.__mul__(scalar)
|
|
53
|
+
|
|
54
|
+
def dot_product(self, other) -> float:
|
|
55
|
+
if not isinstance(other, Vector):
|
|
56
|
+
raise TypeError("Can only perform dot product with another Vector.")
|
|
57
|
+
return self.dx * other.dx + self.dy * other.dy
|
|
58
|
+
|
|
59
|
+
class AppliedVector:
|
|
60
|
+
"""
|
|
61
|
+
Represents a vector applied to a specific starting point.
|
|
62
|
+
It has:
|
|
63
|
+
- Direction (like a Vector)
|
|
64
|
+
- Length (like a line segment)
|
|
65
|
+
- Fixed coordinates (like a Point, specifically its start_point)
|
|
66
|
+
"""
|
|
67
|
+
def __init__(self, start_point: Point, end_point: Point):
|
|
68
|
+
self.start_point = start_point
|
|
69
|
+
self.end_point = end_point
|
|
70
|
+
self._free_vector = Vector.from_points(start_point, end_point)
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def direction_vector(self) -> Vector:
|
|
74
|
+
return self._free_vector
|
|
75
|
+
|
|
76
|
+
def get_length(self) -> float:
|
|
77
|
+
return self._free_vector.get_length()
|
|
78
|
+
|
|
79
|
+
def __repr__(self):
|
|
80
|
+
return f"AppliedVector(start={self.start_point}, end={self.end_point})"
|
|
81
|
+
|
|
82
|
+
def __eq__(self, other):
|
|
83
|
+
if not isinstance(other, AppliedVector):
|
|
84
|
+
return NotImplemented
|
|
85
|
+
return self.start_point == other.start_point and self.end_point == other.end_point
|
|
86
|
+
|
|
87
|
+
def __add__(self, other):
|
|
88
|
+
if not isinstance(other, AppliedVector):
|
|
89
|
+
return NotImplemented
|
|
90
|
+
|
|
91
|
+
result_free_vector = self.direction_vector + other.direction_vector
|
|
92
|
+
|
|
93
|
+
new_end_x = self.start_point.x + result_free_vector.dx
|
|
94
|
+
new_end_y = self.start_point.y + result_free_vector.dy
|
|
95
|
+
return AppliedVector(self.start_point, Point(new_end_x, new_end_y))
|
|
96
|
+
|
|
97
|
+
def __sub__(self, other):
|
|
98
|
+
if not isinstance(other, AppliedVector):
|
|
99
|
+
return NotImplemented
|
|
100
|
+
|
|
101
|
+
result_free_vector = self.direction_vector - other.direction_vector
|
|
102
|
+
|
|
103
|
+
new_end_x = self.start_point.x + result_free_vector.dx
|
|
104
|
+
new_end_y = self.start_point.y + result_free_vector.dy
|
|
105
|
+
return AppliedVector(self.start_point, Point(new_end_x, new_end_y))
|
|
106
|
+
|
|
107
|
+
def __mul__(self, scalar: float):
|
|
108
|
+
scaled_free_vector = self.direction_vector * scalar
|
|
109
|
+
new_end_x = self.start_point.x + scaled_free_vector.dx
|
|
110
|
+
new_end_y = self.start_point.y + scaled_free_vector.dy
|
|
111
|
+
return AppliedVector(self.start_point, Point(new_end_x, new_end_y))
|
|
112
|
+
|
|
113
|
+
def __rmul__(self, scalar: float):
|
|
114
|
+
return self.__mul__(scalar)
|
|
115
|
+
|
|
116
|
+
class AppliedVectorSet:
|
|
117
|
+
"""A set of applied vectors that support element-wise operations."""
|
|
118
|
+
def __init__(self, vectors: Iterable[AppliedVector] = (), origin: Point | None = None):
|
|
119
|
+
self.vectors = list(vectors)
|
|
120
|
+
self.origin = origin
|
|
121
|
+
|
|
122
|
+
def __len__(self):
|
|
123
|
+
return len(self.vectors)
|
|
124
|
+
|
|
125
|
+
def __iter__(self):
|
|
126
|
+
return iter(self.vectors)
|
|
127
|
+
|
|
128
|
+
def __repr__(self):
|
|
129
|
+
return f"<AppliedVectorSet {self.vectors!r}>"
|
|
130
|
+
|
|
131
|
+
def __eq__(self, other: "AppliedVectorSet"):
|
|
132
|
+
if not isinstance(other, AppliedVectorSet):
|
|
133
|
+
return NotImplemented
|
|
134
|
+
return self.origin == other.origin and self.vectors == other.vectors
|
|
135
|
+
|
|
136
|
+
def __add__(self, other: "AppliedVectorSet"):
|
|
137
|
+
if len(self) != len(other):
|
|
138
|
+
raise ValueError("The sizes of the sets must match!")
|
|
139
|
+
return AppliedVectorSet(
|
|
140
|
+
(a + b for a, b in zip(self.vectors, other.vectors)),
|
|
141
|
+
origin=self.origin or other.origin,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def __sub__(self, other: "AppliedVectorSet"):
|
|
145
|
+
if len(self) != len(other):
|
|
146
|
+
raise ValueError("The sizes of the sets must match!")
|
|
147
|
+
return AppliedVectorSet(
|
|
148
|
+
(a - b for a, b in zip(self.vectors, other.vectors)),
|
|
149
|
+
origin=self.origin or other.origin,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def scalar_mul(self, scalar: float):
|
|
153
|
+
return AppliedVectorSet((v * scalar for v in self.vectors),
|
|
154
|
+
origin=self.origin)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Iterable, Iterator
|
|
4
|
+
|
|
5
|
+
from .classes import AppliedVectorSet, AppliedVector, Point
|
|
6
|
+
from .vector_codec import (
|
|
7
|
+
bytes_to_vectors,
|
|
8
|
+
vectors_to_bytes,
|
|
9
|
+
text_to_vectors,
|
|
10
|
+
vectors_to_text,
|
|
11
|
+
)
|
|
12
|
+
from .keygen import key_for_data
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def encrypt(plaintext: AppliedVectorSet,
|
|
16
|
+
key: AppliedVectorSet) -> AppliedVectorSet:
|
|
17
|
+
return plaintext + key
|
|
18
|
+
|
|
19
|
+
def decrypt(ciphertext: AppliedVectorSet,
|
|
20
|
+
key: AppliedVectorSet) -> AppliedVectorSet:
|
|
21
|
+
return ciphertext - key
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# high-level helpers ----------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
def encrypt_bytes(data: bytes, key: AppliedVectorSet) -> AppliedVectorSet:
|
|
27
|
+
"""Encrypt raw data. ``key`` must be at least as long as ``data``."""
|
|
28
|
+
pt = bytes_to_vectors(data)
|
|
29
|
+
return encrypt(pt, key)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def decrypt_bytes(cipher: AppliedVectorSet, key: AppliedVectorSet) -> bytes:
|
|
33
|
+
"""Decrypt to raw bytes. ``cipher`` and ``key`` should have equal length."""
|
|
34
|
+
pt = decrypt(cipher, key)
|
|
35
|
+
return vectors_to_bytes(pt)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def encrypt_text(text: str, key: AppliedVectorSet, encoding: str = "utf-8") -> AppliedVectorSet:
|
|
39
|
+
"""Convenience: encode and encrypt a string."""
|
|
40
|
+
return encrypt(text_to_vectors(text, encoding=encoding), key)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def decrypt_text(cipher: AppliedVectorSet, key: AppliedVectorSet, encoding: str = "utf-8") -> str:
|
|
44
|
+
"""Decrypt and decode to text."""
|
|
45
|
+
return vectors_to_text(decrypt(cipher, key), encoding=encoding)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# batch / streaming helpers ---------------------------------------------------
|
|
49
|
+
|
|
50
|
+
def encrypt_sequence(
|
|
51
|
+
plaintexts: Iterable[AppliedVectorSet],
|
|
52
|
+
keys: Iterable[AppliedVectorSet],
|
|
53
|
+
) -> list[AppliedVectorSet]:
|
|
54
|
+
"""Encrypt many plaintext vector sets with corresponding keys.
|
|
55
|
+
|
|
56
|
+
Both iterables are consumed in lockstep; lengths must match.
|
|
57
|
+
"""
|
|
58
|
+
return [encrypt(p, k) for p, k in zip(plaintexts, keys)]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def decrypt_sequence(
|
|
62
|
+
ciphertexts: Iterable[AppliedVectorSet],
|
|
63
|
+
keys: Iterable[AppliedVectorSet],
|
|
64
|
+
) -> list[AppliedVectorSet]:
|
|
65
|
+
"""Decrypt many ciphertexts with the provided keys."""
|
|
66
|
+
return [decrypt(c, k) for c, k in zip(ciphertexts, keys)]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def encrypt_bytes_stream(
|
|
70
|
+
data: Iterable[int],
|
|
71
|
+
key_stream: Iterable[AppliedVector],
|
|
72
|
+
origin: Point | None = None,
|
|
73
|
+
) -> Iterator[AppliedVector]:
|
|
74
|
+
"""Stream-encrypt a byte sequence against a stream of key vectors.
|
|
75
|
+
|
|
76
|
+
``data`` yields byte values; ``key_stream`` yields pre-generated random
|
|
77
|
+
``AppliedVector`` objects. The resulting stream produces encrypted vectors
|
|
78
|
+
that can be consumed without buffering the whole message.
|
|
79
|
+
"""
|
|
80
|
+
if origin is None:
|
|
81
|
+
origin = Point(0.0, 0.0)
|
|
82
|
+
for byte, key_vec in zip(data, key_stream):
|
|
83
|
+
pt_vec = AppliedVector(origin, Point(origin.x + float(byte), origin.y))
|
|
84
|
+
# addition uses AppliedVector.__add__, which keeps start == origin
|
|
85
|
+
yield pt_vec + key_vec
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def decrypt_bytes_stream(
|
|
89
|
+
cipher_stream: Iterable[AppliedVector],
|
|
90
|
+
key_stream: Iterable[AppliedVector],
|
|
91
|
+
) -> Iterator[int]:
|
|
92
|
+
"""Inverse of :func:`encrypt_bytes_stream`, yields raw byte values."""
|
|
93
|
+
for cipher_vec, key_vec in zip(cipher_stream, key_stream):
|
|
94
|
+
pt = cipher_vec - key_vec
|
|
95
|
+
yield int(pt.direction_vector.dx)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
from typing import Iterable, Iterator, List, Optional
|
|
5
|
+
|
|
6
|
+
from .classes import AppliedVector, AppliedVectorSet, Point
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# --- key generation ------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
def generate_random_key(
|
|
12
|
+
num_vectors: int,
|
|
13
|
+
max_coord: float = 255.0,
|
|
14
|
+
origin: Optional[Point] = None,
|
|
15
|
+
) -> AppliedVectorSet:
|
|
16
|
+
"""Produce a random ``AppliedVectorSet`` containing ``num_vectors`` vectors.
|
|
17
|
+
|
|
18
|
+
Each vector starts at ``origin`` (default ``Point(0,0)``) and has an end
|
|
19
|
+
point whose coordinates are chosen uniformly from ``[-max_coord, max_coord]``.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
num_vectors
|
|
24
|
+
Number of vectors in the key; typically equal to the length of the
|
|
25
|
+
plaintext when encoding byte-wise.
|
|
26
|
+
max_coord
|
|
27
|
+
Maximum absolute value for each coordinate of the end point. Smaller
|
|
28
|
+
values yield shorter vectors.
|
|
29
|
+
origin
|
|
30
|
+
Optional common starting point for all vectors.
|
|
31
|
+
"""
|
|
32
|
+
if origin is None:
|
|
33
|
+
origin = Point(0.0, 0.0)
|
|
34
|
+
|
|
35
|
+
vecs: list[AppliedVector] = []
|
|
36
|
+
for _ in range(num_vectors):
|
|
37
|
+
dx = random.uniform(-max_coord, max_coord)
|
|
38
|
+
dy = random.uniform(-max_coord, max_coord)
|
|
39
|
+
end = Point(origin.x + dx, origin.y + dy)
|
|
40
|
+
vecs.append(AppliedVector(origin, end))
|
|
41
|
+
return AppliedVectorSet(vecs, origin=origin)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def key_for_data(data: bytes, **kwargs) -> AppliedVectorSet:
|
|
45
|
+
"""Convenience helper that generates a key matching the length of ``data``.
|
|
46
|
+
|
|
47
|
+
All keyword arguments are forwarded to :func:`generate_random_key`.
|
|
48
|
+
"""
|
|
49
|
+
return generate_random_key(len(data), **kwargs)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def generate_random_key_stream(
|
|
53
|
+
num_vectors: int,
|
|
54
|
+
max_coord: float = 255.0,
|
|
55
|
+
origin: Optional[Point] = None,
|
|
56
|
+
) -> Iterator[AppliedVector]:
|
|
57
|
+
"""Yield ``num_vectors`` random ``AppliedVector`` objects one by one.
|
|
58
|
+
|
|
59
|
+
This is useful for encrypting large blobs without materializing the entire
|
|
60
|
+
``AppliedVectorSet`` in memory. The caller can consume the stream in
|
|
61
|
+
chunks and assemble sets as needed.
|
|
62
|
+
"""
|
|
63
|
+
if origin is None:
|
|
64
|
+
origin = Point(0.0, 0.0)
|
|
65
|
+
|
|
66
|
+
for _ in range(num_vectors):
|
|
67
|
+
dx = random.uniform(-max_coord, max_coord)
|
|
68
|
+
dy = random.uniform(-max_coord, max_coord)
|
|
69
|
+
end = Point(origin.x + dx, origin.y + dy)
|
|
70
|
+
yield AppliedVector(origin, end)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def generate_batch_keys(
|
|
74
|
+
lengths: Iterable[int],
|
|
75
|
+
**kwargs,
|
|
76
|
+
) -> List[AppliedVectorSet]:
|
|
77
|
+
"""Return a list of random keys for each length in ``lengths``.
|
|
78
|
+
|
|
79
|
+
This helper is convenient when encrypting or decrypting a collection of
|
|
80
|
+
messages with independent keys.
|
|
81
|
+
"""
|
|
82
|
+
return [generate_random_key(n, **kwargs) for n in lengths]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def key_stream_for_data(
|
|
86
|
+
data: bytes,
|
|
87
|
+
**kwargs,
|
|
88
|
+
) -> Iterator[AppliedVector]:
|
|
89
|
+
"""Generate a stream of random vectors matching ``len(data)``.
|
|
90
|
+
|
|
91
|
+
Equivalent to ``generate_random_key_stream(len(data), **kwargs)`` but
|
|
92
|
+
named to echo :func:`key_for_data`.
|
|
93
|
+
"""
|
|
94
|
+
yield from generate_random_key_stream(len(data), **kwargs)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Iterable, Iterator
|
|
4
|
+
|
|
5
|
+
from .classes import AppliedVector, AppliedVectorSet, Point
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# --- data <-> vectors conversion ------------------------------------------------
|
|
9
|
+
|
|
10
|
+
def bytes_to_vectors(data: bytes, origin: Point | None = None) -> AppliedVectorSet:
|
|
11
|
+
"""Encode raw bytes into an AppliedVectorSet.
|
|
12
|
+
|
|
13
|
+
Each byte value is turned into a vector with dx equal to the byte and dy=0.
|
|
14
|
+
All vectors share a common ``origin`` (defaults to ``Point(0, 0)``).
|
|
15
|
+
|
|
16
|
+
This is a toy encoding; you can easily swap in a different mapping (e.g. two
|
|
17
|
+
bytes per vector, use dy for a second channel, etc.).
|
|
18
|
+
"""
|
|
19
|
+
if origin is None:
|
|
20
|
+
origin = Point(0.0, 0.0)
|
|
21
|
+
|
|
22
|
+
vectors: list[AppliedVector] = []
|
|
23
|
+
for b in data:
|
|
24
|
+
end = Point(origin.x + float(b), origin.y)
|
|
25
|
+
vectors.append(AppliedVector(origin, end))
|
|
26
|
+
return AppliedVectorSet(vectors, origin=origin)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def vectors_to_bytes(vectors: AppliedVectorSet) -> bytes:
|
|
30
|
+
"""Decode a previously-encoded ``AppliedVectorSet`` back to bytes.
|
|
31
|
+
|
|
32
|
+
This function reverses :func:`bytes_to_vectors` and therefore will raise an
|
|
33
|
+
exception if the encoding scheme has changed or the set contains vectors
|
|
34
|
+
that do not have ``dy == 0`` or start at a consistent origin.
|
|
35
|
+
"""
|
|
36
|
+
result = bytearray()
|
|
37
|
+
if len(vectors) == 0:
|
|
38
|
+
return bytes(result)
|
|
39
|
+
|
|
40
|
+
orig = vectors.origin or vectors.vectors[0].start_point
|
|
41
|
+
for av in vectors:
|
|
42
|
+
if av.start_point != orig:
|
|
43
|
+
raise ValueError("Inconsistent origin in AppliedVectorSet")
|
|
44
|
+
dx = av.direction_vector.dx
|
|
45
|
+
if av.direction_vector.dy != 0:
|
|
46
|
+
raise ValueError("Unexpected non-zero dy component")
|
|
47
|
+
if not (0 <= dx <= 255):
|
|
48
|
+
raise ValueError("dx value out of byte range: %r" % dx)
|
|
49
|
+
result.append(int(dx))
|
|
50
|
+
|
|
51
|
+
return bytes(result)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def text_to_vectors(text: str, encoding: str = "utf-8", **kwargs) -> AppliedVectorSet:
|
|
55
|
+
"""Convenience wrapper that encodes ``text`` using ``bytes_to_vectors``."""
|
|
56
|
+
return bytes_to_vectors(text.encode(encoding), **kwargs)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def vectors_to_text(vectors: AppliedVectorSet, encoding: str = "utf-8") -> str:
|
|
60
|
+
"""Convenience wrapper that decodes vectors back to a string."""
|
|
61
|
+
return vectors_to_bytes(vectors).decode(encoding)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# streaming helpers -----------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
def bytes_to_vectors_stream(
|
|
67
|
+
data: Iterable[int], origin: Point | None = None
|
|
68
|
+
) -> Iterator[AppliedVector]:
|
|
69
|
+
"""Yield vectors corresponding to each byte in ``data``.
|
|
70
|
+
|
|
71
|
+
``data`` may be any iterable of integer values in ``0..255``; typical use
|
|
72
|
+
is to pass a ``bytes`` or ``bytearray`` object. The caller can wrap the
|
|
73
|
+
output in an :class:`AppliedVectorSet` if desired.
|
|
74
|
+
"""
|
|
75
|
+
if origin is None:
|
|
76
|
+
origin = Point(0.0, 0.0)
|
|
77
|
+
for b in data:
|
|
78
|
+
end = Point(origin.x + float(b), origin.y)
|
|
79
|
+
yield AppliedVector(origin, end)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def vectors_to_bytes_stream(
|
|
83
|
+
vectors: Iterable[AppliedVector],
|
|
84
|
+
origin: Point | None = None,
|
|
85
|
+
) -> Iterator[int]:
|
|
86
|
+
"""Yield integer byte values from an iterable of vectors.
|
|
87
|
+
|
|
88
|
+
This is the streaming counterpart to :func:`vectors_to_bytes` and is
|
|
89
|
+
useful when processing large sequences without collecting them all first.
|
|
90
|
+
``origin`` may be specified to validate start points.
|
|
91
|
+
"""
|
|
92
|
+
first = True
|
|
93
|
+
for av in vectors:
|
|
94
|
+
if first:
|
|
95
|
+
first = False
|
|
96
|
+
if origin is None:
|
|
97
|
+
origin = av.start_point
|
|
98
|
+
if av.start_point != origin:
|
|
99
|
+
raise ValueError("Inconsistent origin in stream")
|
|
100
|
+
if av.direction_vector.dy != 0:
|
|
101
|
+
raise ValueError("Unexpected non-zero dy component")
|
|
102
|
+
dx = av.direction_vector.dx
|
|
103
|
+
if not (0 <= dx <= 255):
|
|
104
|
+
raise ValueError("dx value out of byte range: %r" % dx)
|
|
105
|
+
yield int(dx)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# file helpers ---------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
def file_to_vectors(path: str, chunk_size: int = 4096) -> Iterator[AppliedVector]:
|
|
111
|
+
"""Read a file and yield vectors for its bytes in chunks.
|
|
112
|
+
|
|
113
|
+
The file is opened in binary mode and read incrementally to avoid large
|
|
114
|
+
memory consumption. ``chunk_size`` controls how many bytes are read at a
|
|
115
|
+
time.
|
|
116
|
+
"""
|
|
117
|
+
origin = Point(0.0, 0.0)
|
|
118
|
+
with open(path, "rb") as f:
|
|
119
|
+
while True:
|
|
120
|
+
chunk = f.read(chunk_size)
|
|
121
|
+
if not chunk:
|
|
122
|
+
break
|
|
123
|
+
yield from bytes_to_vectors_stream(chunk, origin=origin)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def vectors_to_file(vectors: Iterable[AppliedVector], path: str):
|
|
127
|
+
"""Write vector data back to a file as raw bytes."""
|
|
128
|
+
with open(path, "wb") as f:
|
|
129
|
+
for byte in vectors_to_bytes_stream(vectors):
|
|
130
|
+
f.write(bytes((byte,)))
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vector_crypt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A toy cryptographic library encoding data as applied vector sets.
|
|
5
|
+
Author-email: Sagu4ka <sagu4ka@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: cryptography,vector,encoding,one-time-pad
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# Applied-Vector Crypto (`vector_crypt`)
|
|
17
|
+
|
|
18
|
+
A lightweight Python library demonstrating a **novel cryptographic
|
|
19
|
+
principle**: represent both plaintext and keys as _sets of applied vectors_
|
|
20
|
+
and perform encryption simply by vector addition. The package is intended as
|
|
21
|
+
an educational toy, a research starting point, or a playful experiment rather
|
|
22
|
+
than a drop-in replacement for real-world ciphers.
|
|
23
|
+
|
|
24
|
+
## 🚀 Основная идея
|
|
25
|
+
|
|
26
|
+
Каждый байт (или символ, блок) сообщения кодируется как
|
|
27
|
+
**`AppliedVector`** — отрезок с фиксированным началом и направлением. Ключ
|
|
28
|
+
тоже является набором таких векторов. Шифрование сводится к поэлементному
|
|
29
|
+
сложению двух наборов (похожим на операцию `XOR` для чисел), а расшифровка –
|
|
30
|
+
к вычитанию.
|
|
31
|
+
|
|
32
|
+
*В отличие от большинства алгоритмов, здесь информация представлена геометрически,
|
|
33
|
+
что даёт визуализацию, естественное расширение на многомерность и простой
|
|
34
|
+
потоковый интерфейс.*
|
|
35
|
+
|
|
36
|
+
### Почему это уникально?
|
|
37
|
+
|
|
38
|
+
- **Геометрическое представление.** Традиционные симметричные схемы оперируют
|
|
39
|
+
на битах и байтах. Мы работаем с векторами, что позволяет легко вводить
|
|
40
|
+
масштабирование, вращения, линейные преобразования и работать в произвольных
|
|
41
|
+
пространствах (включая конечные поля).
|
|
42
|
+
|
|
43
|
+
- **Простота.** Всего пара строк кода даёт шифрование/дешифровку. Нет S‑боксов,
|
|
44
|
+
нет ключевого расписания, только алгебра над векторами.
|
|
45
|
+
|
|
46
|
+
- **Потоковая обработка.** Код поддерживает генераторы, чтение/запись файлов
|
|
47
|
+
по кускам и пакетные операции, что пригодится для больших данных.
|
|
48
|
+
|
|
49
|
+
- **Проверяемость.** Отображение вектор‑множества на экран, графы, SVG…
|
|
50
|
+
Приятно для обучения и визуальных демо.
|
|
51
|
+
|
|
52
|
+
## 🔍 Схожие идеи в криптографии
|
|
53
|
+
|
|
54
|
+
- **One‑time pad / Vernam cipher.** Байт сообщения прибавляется к байту ключа
|
|
55
|
+
по модулю 2⁸; наша операция аналогична, но мы «вырастаем» в векторное
|
|
56
|
+
пространство и сохраняем абсолютную информацию в промежуточном виде (можно
|
|
57
|
+
наложить дополнительные операции).
|
|
58
|
+
|
|
59
|
+
- **Кодировка векторов в стойкие каналы.** В теории информации часто
|
|
60
|
+
рассматривают передаваемые сигналы как точки в \\Rⁿ; в этом смысле наше
|
|
61
|
+
шифрование — частный случай линейного кодирования.
|
|
62
|
+
|
|
63
|
+
- **Графовые шифры.** В гомоморфных системах используются линейные операции;
|
|
64
|
+
наш механизм легко расширяется до гомоморфизма над векторным пространством.
|
|
65
|
+
|
|
66
|
+
Однако: мы не претендуем на криптостойкость, а скорее демонстрируем новый
|
|
67
|
+
формальный подход. Внедрить в реальную систему потребует серьёзного
|
|
68
|
+
криптоанализа и, вероятно, модификаций (например, работа в конечных полях,
|
|
69
|
+
нелинейные слои и т. д.).
|
|
70
|
+
|
|
71
|
+
## 🧩 Структура проекта
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
vector_crypt/ # репозиторий
|
|
75
|
+
├── vector_crypt/ # собственно пакет Python
|
|
76
|
+
│ ├── __init__.py
|
|
77
|
+
│ ├── classes.py
|
|
78
|
+
│ ├── endecode.py
|
|
79
|
+
│ ├── keygen.py
|
|
80
|
+
│ └── vector_codec.py
|
|
81
|
+
├── tests/ # простые тесты (пока минимум)
|
|
82
|
+
├── README.md # вы читаете
|
|
83
|
+
├── LICENSE # MIT
|
|
84
|
+
└── pyproject.toml # сборка/метаданные
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## ⚙️ Установка и использование
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pip install vector_crypt
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from vector_crypt import encrypt_text, decrypt_text, key_for_data
|
|
95
|
+
|
|
96
|
+
key = key_for_data(b"secret message")
|
|
97
|
+
cipher = encrypt_text("hello", key)
|
|
98
|
+
print(decrypt_text(cipher, key)) # hello
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Для потокового шифрования используйте `encrypt_bytes_stream` вместе с
|
|
102
|
+
`generate_random_key_stream`.
|
|
103
|
+
|
|
104
|
+
## 📝 Где использовать
|
|
105
|
+
|
|
106
|
+
Библиотека подходит для:
|
|
107
|
+
|
|
108
|
+
* учебных примеров и лекций по основам криптографии;
|
|
109
|
+
* прототипирования альтернативных представлений данных (векторов вместо
|
|
110
|
+
скаляров);
|
|
111
|
+
* демонстраций визуализации шифрования в 2D/3D;
|
|
112
|
+
* утилит, где требуется совместное хранение геометрической информации и
|
|
113
|
+
шифрования (например, защитить набор координат).
|
|
114
|
+
|
|
115
|
+
Не рекомендуется применять `vector_crypt` для защиты реальных данных без
|
|
116
|
+
дополнительного анализа.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
tests/test_basic.py
|
|
5
|
+
vector_crypt/__init__.py
|
|
6
|
+
vector_crypt/classes.py
|
|
7
|
+
vector_crypt/endecode.py
|
|
8
|
+
vector_crypt/keygen.py
|
|
9
|
+
vector_crypt/vector_codec.py
|
|
10
|
+
vector_crypt.egg-info/PKG-INFO
|
|
11
|
+
vector_crypt.egg-info/SOURCES.txt
|
|
12
|
+
vector_crypt.egg-info/dependency_links.txt
|
|
13
|
+
vector_crypt.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vector_crypt
|