Перейти к содержанию

Идентификаторы

Любую сущность можно выразить точкой на кривой secp256k1.
Чат, пользователь, группа, конкретное сообщение — всё может стать публичной точкой, если нам это удобно.

В контексте использования точки как идентификатора мы получаем несколько ценных возможностей:

  • Любая группа, канал или пользователь может быть представлен как уникальная точка на кривой, что позволяет нам агрегировать сообщения вокруг сущности, которой они принадлежат.
  • Любой, кто создал сущность, может доказать свое авторство, что на уровне криптографии создает примитивную систему управления. Например, создатель канала может публиковать свои сообщения, добавляя к ним подпись с помощью имеющегося у него скаляра. Тем самым любой участник канала может убедиться, что то что он читает было написано истинным владельцем, а не злоумышленником.

Подпись и проверка

Так как каждый Identifier может служить x-only публичным ключом Schnorr-подписи, то Kaspeak SDK по умолчанию поддерживает возможность подписывать сообщения и проверять подписи прямо в обьекте Identifier

1
2
3
const sid = SecretIdentifier.random()
const sig = await sid.sign("Hello, Kaspa")
const ok  = await sid.verify(sig, "Hello, Kaspa") // true
  • SecretIdentifier хранит приватный скаляр и умеет sign.
  • Обычный Identifier хранит только точку и умеет verify.

Вы можете использовать Identifier и SecretIdentifier как обычный повторяющийся идентификатор, не прибегая к сложной криптографии, описанной далее. Однако, если Вы хотите охватить все возможности Kaspeak SDK, то рекомендую внимательно ознакомиться со следующим разделом, который способен добавить в прозрачный blockdag элемент конфиденциальности.

Суть

Пусть у нас есть произвольная «начальная точка» BasePoint.
Любой следующий объект той же природы — это просто BasePoint · t, где t — известный обоим сторонам скаляр-множитель.

  • Так мы получаем дерево или цепочку сущностей, не храня лишних данных.
  • Внешний наблюдатель видит только случайные точки, не понимая их семантики.

Формула идентификатора

Идентификатор (Identifier) — это 33-байтовая сжатая точка secp256k1, вычисляемая по формуле

ID(i) = PK_A · (chainKey^i mod n), i ≥ 1

  • PK_A — открытый ключ автора (может быть и любой другой фиксированной точкой).
  • chainKey — 32-байтовый скаляр, общий для обоих участников;
  • i — порядковый номер сообщения внутри диалога.
  • n— порядок кривой secp256k1.

Формирование chainKey

const { secret, chainKey } = sdk.deriveConversationKeys(peerPublicKey)

secret — результат ECDH.
chainKey = SHA-256(secret) > bigint ( mod n ).

Вывод идентификатора

Операция Формула
следующий (+1) ID_(i+1) = ID_i · chainKey
предыдущий (-1) ID_(i-1) = ID_i · chainKey⁻¹
произвольный +k ID_(i+k) = ID_i · chainKey^k

Все вычисления — обычная скалярная мультипликация точек.

1
2
3
const id2 = Identifier.fromChainKey(chainKey, 2, sdk.publicKey) // первый ID
const id3 = id1.next(chainKey)  // второй (ID₁·k)
const id1 = id1.prev(chainKey)  // предыдущий (ID₁·k⁻¹)

Внутри next/prev используется быстрое возведение в степень.

Свойства безопасности

  1. Конфиденциальность цепочки. Без chainKey нельзя отличить ID_1 от ID_999; все точки выглядят случайно.
  2. Одна пара - одна точка. chainKey тождественно вычисляется только для пары А и Б. Третья сторона не сможет «склеить» цепочки разных участников.
  3. Неотслеживаемость. Алгоритм «следующий / предыдущий» работает лишь с секретным множителем, следовательно нельзя проследить историю сообщений, даже имея их полный архив.

Благодаря этому нехитрому приему и мощному шифрованию из раздела Шифрование сообщений, мы можем вести по настоящему безопасное и конфиденциальное общение внутри сети Kaspa. Теперь злоумышленник не только не может расшифровать наши сообщения, но даже быть уверенным в том, с кем именно Вы общаетесь.