montana/Русский/Гиппокамп/Архив/cognitive_signature.py

381 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
cognitive_signature.py — Когнитивные подписи Montana
Montana Protocol
Подписание мыслей и сообщений с domain separation
"""
import hashlib
import hmac
import secrets
from typing import Optional, Dict, Tuple
from datetime import datetime, timezone
from enum import Enum
# ═══════════════════════════════════════════════════════════════════════════
# DOMAIN SEPARATION
# ═══════════════════════════════════════════════════════════════════════════
class DomainType(Enum):
"""
Типы доменов для domain separation
Domain separation гарантирует что подпись для одного контекста
не может быть переиспользована в другом
"""
THOUGHT = "montana.thought" # Сырая мысль
MESSAGE = "montana.message" # Обычное сообщение
TRANSACTION = "montana.transaction" # Транзакция
PRESENCE = "montana.presence" # Proof of Presence
NODE_AUTH = "montana.node.auth" # Аутентификация узла
SYNC = "montana.sync" # Синхронизация данных
def get_domain_prefix(domain: DomainType) -> bytes:
"""
Получить префикс домена для domain separation
Args:
domain: Тип домена
Returns:
Префикс в байтах
Example:
>>> get_domain_prefix(DomainType.THOUGHT)
b'montana.thought'
"""
return domain.value.encode('utf-8')
# ═══════════════════════════════════════════════════════════════════════════
# COGNITIVE SIGNATURE
# ═══════════════════════════════════════════════════════════════════════════
class CognitiveSignature:
"""
Когнитивная подпись Montana
Использует HMAC-SHA256 с domain separation для подписания
мыслей, сообщений и других данных
"""
def __init__(self, secret_key: Optional[bytes] = None):
"""
Args:
secret_key: Секретный ключ (32 байта).
Если не указан, генерируется случайно.
"""
if secret_key is None:
self.secret_key = secrets.token_bytes(32)
else:
if len(secret_key) != 32:
raise ValueError("Secret key must be exactly 32 bytes")
self.secret_key = secret_key
def sign(
self,
message: str,
domain: DomainType,
timestamp: Optional[str] = None,
metadata: Optional[Dict] = None
) -> Dict:
"""
Подписать сообщение
Args:
message: Текст сообщения
domain: Домен для domain separation
timestamp: Timestamp в ISO format (UTC)
metadata: Дополнительные метаданные
Returns:
{
"message": "текст",
"domain": "montana.thought",
"timestamp": "2026-01-20T12:00:00+00:00",
"signature": "hex...",
"metadata": {}
}
"""
if timestamp is None:
timestamp = datetime.now(timezone.utc).isoformat()
# Собираем данные для подписи
domain_prefix = get_domain_prefix(domain)
message_bytes = message.encode('utf-8')
timestamp_bytes = timestamp.encode('utf-8')
# Формат: domain || timestamp || message
data_to_sign = domain_prefix + b'||' + timestamp_bytes + b'||' + message_bytes
# Подписываем с HMAC-SHA256
signature = hmac.new(
self.secret_key,
data_to_sign,
hashlib.sha256
).hexdigest()
return {
"message": message,
"domain": domain.value,
"timestamp": timestamp,
"signature": signature,
"metadata": metadata or {}
}
def verify(
self,
signed_data: Dict,
domain: Optional[DomainType] = None
) -> bool:
"""
Верифицировать подпись
Args:
signed_data: Подписанные данные (результат sign())
domain: Ожидаемый домен (опционально)
Returns:
True если подпись валидна
"""
try:
message = signed_data["message"]
domain_str = signed_data["domain"]
timestamp = signed_data["timestamp"]
signature = signed_data["signature"]
# Проверяем домен если указан
if domain:
if domain_str != domain.value:
return False
# Восстанавливаем domain enum
domain_enum = DomainType(domain_str)
# Пересобираем данные
domain_prefix = get_domain_prefix(domain_enum)
message_bytes = message.encode('utf-8')
timestamp_bytes = timestamp.encode('utf-8')
data_to_sign = domain_prefix + b'||' + timestamp_bytes + b'||' + message_bytes
# Вычисляем ожидаемую подпись
expected_signature = hmac.new(
self.secret_key,
data_to_sign,
hashlib.sha256
).hexdigest()
# Сравниваем
return hmac.compare_digest(signature, expected_signature)
except (KeyError, ValueError):
return False
def sign_thought(self, thought: str, user_id: Optional[int] = None) -> Dict:
"""
Подписать сырую мысль
Args:
thought: Текст мысли
user_id: ID пользователя
Returns:
Подписанная мысль
"""
metadata = {}
if user_id:
metadata["user_id"] = user_id
return self.sign(
message=thought,
domain=DomainType.THOUGHT,
metadata=metadata
)
def sign_message(self, message: str, sender_id: Optional[int] = None) -> Dict:
"""
Подписать обычное сообщение
Args:
message: Текст сообщения
sender_id: ID отправителя
Returns:
Подписанное сообщение
"""
metadata = {}
if sender_id:
metadata["sender_id"] = sender_id
return self.sign(
message=message,
domain=DomainType.MESSAGE,
metadata=metadata
)
def sign_transaction(
self,
transaction_data: str,
from_address: Optional[str] = None,
to_address: Optional[str] = None,
amount: Optional[float] = None
) -> Dict:
"""
Подписать транзакцию
Args:
transaction_data: Данные транзакции
from_address: Адрес отправителя
to_address: Адрес получателя
amount: Сумма
Returns:
Подписанная транзакция
"""
metadata = {}
if from_address:
metadata["from"] = from_address
if to_address:
metadata["to"] = to_address
if amount:
metadata["amount"] = amount
return self.sign(
message=transaction_data,
domain=DomainType.TRANSACTION,
metadata=metadata
)
def sign_presence(self, presence_data: str, user_id: Optional[int] = None) -> Dict:
"""
Подписать proof of presence
Args:
presence_data: Данные присутствия
user_id: ID пользователя
Returns:
Подписанное proof of presence
"""
metadata = {}
if user_id:
metadata["user_id"] = user_id
return self.sign(
message=presence_data,
domain=DomainType.PRESENCE,
metadata=metadata
)
# ═══════════════════════════════════════════════════════════════════════════
# KEY MANAGEMENT
# ═══════════════════════════════════════════════════════════════════════════
def generate_keypair() -> Tuple[bytes, bytes]:
"""
Сгенерировать пару ключей (secret, public)
В текущей реализации используется симметричный ключ (HMAC),
поэтому "публичный" ключ — это хеш секретного ключа
Returns:
(secret_key, public_key_hash)
"""
secret_key = secrets.token_bytes(32)
# "Публичный" ключ — хеш секретного
public_key_hash = hashlib.sha256(secret_key).digest()
return (secret_key, public_key_hash)
def derive_key_from_passphrase(passphrase: str, salt: Optional[bytes] = None) -> bytes:
"""
Получить ключ из парольной фразы
Args:
passphrase: Парольная фраза
salt: Соль (16 байт, если не указана — генерируется)
Returns:
32-байтовый ключ
"""
if salt is None:
salt = secrets.token_bytes(16)
# PBKDF2 с SHA256
key = hashlib.pbkdf2_hmac(
'sha256',
passphrase.encode('utf-8'),
salt,
100_000 # итераций
)
return key
# ═══════════════════════════════════════════════════════════════════════════
# EXPORTS
# ═══════════════════════════════════════════════════════════════════════════
__all__ = [
'DomainType',
'get_domain_prefix',
'CognitiveSignature',
'generate_keypair',
'derive_key_from_passphrase'
]
# ═══════════════════════════════════════════════════════════════════════════
# CLI
# ═══════════════════════════════════════════════════════════════════════════
if __name__ == "__main__":
print("🧠 Montana Cognitive Signature")
print("=" * 60)
# Генерируем ключ
print("\n🔑 Генерация ключей:")
secret_key, public_key_hash = generate_keypair()
print(f" Secret key (hex): {secret_key.hex()[:32]}...")
print(f" Public key hash (hex): {public_key_hash.hex()[:32]}...")
# Создаём signer
signer = CognitiveSignature(secret_key)
# Подписываем мысль
print("\n💭 Подписание мысли:")
thought = "Маска тяжелее лица"
signed_thought = signer.sign_thought(thought, user_id=123)
print(f" Мысль: {signed_thought['message']}")
print(f" Домен: {signed_thought['domain']}")
print(f" Timestamp: {signed_thought['timestamp']}")
print(f" Подпись: {signed_thought['signature'][:32]}...")
# Верификация
print("\n✅ Верификация:")
is_valid = signer.verify(signed_thought, domain=DomainType.THOUGHT)
print(f" Подпись валидна: {is_valid}")
# Подделка подписи
print("\n❌ Попытка подделки:")
forged = signed_thought.copy()
forged["message"] = "Поддельная мысль"
is_valid_forged = signer.verify(forged, domain=DomainType.THOUGHT)
print(f" Поддельная подпись валидна: {is_valid_forged}")
# Domain separation
print("\n🔒 Domain separation:")
print(" Пытаемся верифицировать мысль как сообщение...")
is_valid_wrong_domain = signer.verify(signed_thought, domain=DomainType.MESSAGE)
print(f" Подпись валидна в другом домене: {is_valid_wrong_domain}")
print("\n🎯 Когнитивные подписи готовы!")