Схеми за подпис

SLH-DSA, обяснен математически

Как SLH-DSA-SHA2-256f (FIPS 205) подписва, без да разчита на каквато и да е трудна задача освен хеш функциите — от хеш веригите през дърветата на Меркъл до гората от FORS дървета.

Актуално към: 2026-11-09

1. За какво става дума

В McGesund клиентите с тарифите Оценки Premium и Сигнали Premium могат да изберат нивото на подпис PQ-Dual-Diversified. Тогава всеки QR код носи освен класическия подпис Ed25519 и два квантово устойчиви подписа: ML-DSA-87 и SLH-DSA-SHA2-256f.

Тази статия обяснява втория. Той е устроен различно от всичко друго, което използваме.

SLH-DSA не е криптиране. Съдържанието остава публично четимо. SLH-DSA доказва произход и цялост — както всеки цифров подпис.

SLH-DSA означава Stateless Hash-Based Digital Signature Algorithm. Разработен е от SPHINCS+ и през 2024 г. е стандартизиран като FIPS 205. Името вече издава особеното: схемата използва само хеш функции. Никакви решетки, никакви елиптични криви, никакви големи прости числа.


2. Какво точно се подписва?

В McGesund SLH-DSA подписва същия набор от данни, който покрива и подписът Ed25519 в QR кода: полезния товар на QR кода. Той съдържа, наред с другото, към коя фирма принадлежи кодът (fid), от какъв вид е (typ), кога е издаден (iat) и до кога е валиден (exp) — като компактно кодирана последователност от байтове (CBOR).

Тази последователност от байтове е нашето съобщение MM. Ако някой впоследствие промени дори един-единствен бит, нито един от подписите вече не пасва.

Подписът SLH-DSA не се намира в самия QR код. С около 49 KB той е твърде голям за това. Съхранява се като отделен „печат“ към записа на QR кода в бекенда на McGesund и се зарежда в браузъра при щракване върху „Проверка на автентичността“.


3. Защо схема, изградена само от хеш функции?

Всяка схема за подпис почива на задача, която без тайния ключ е практически нерешима:

СхемаСигурността почива на
Ed25519дискретен логаритъм върху елиптична крива
FALCONкъси вектори в NTRU решетки
ML-DSAModule-LWE и Module-SIS (решетки)
SLH-DSAсамо на свойствата на хеш функцията

Ed25519 би бил разбит от голям квантов компютър. FALCON и ML-DSA се смятат за квантово устойчиви — но и двата се опират на решетъчни задачи. Ако един ден бъде открита фундаментална атака срещу решетките, и двата биха били засегнати едновременно.

SLH-DSA, напротив, има нужда само хеш функцията да прави онова, за което е създадена:

От H(x) не може да се изчисли обратно x, и никой не намира второ x′ с H(x′)=H(x).\text{От } H(x) \text{ не може да се изчисли обратно } x \text{, и никой не намира второ } x' \text{ с } H(x') = H(x) \text{.}

Това е най-дълго и най-задълбочено изследваното допускане в цялата криптография. Дори квантов компютър помага тук само ограничено: алгоритъмът на Гроувър намалява наполовина битовете на сигурност. Затова вариантът 256 използва хеш стойности с n=32n = 32 байта =256= 256 бита — след Гроувър остават все още 128 бита.

Точно затова нивото се нарича Diversified: ML-DSA (решетки) и SLH-DSA (хеш) произхождат от различни математически семейства. Ако едното падне, другото продължава да носи.


4. Градивен елемент 1: подписване с хеш вериги (WOTS+)

Основната идея е изненадващо проста. Започваме с една-единствена цифра.

Вземете тайна случайна стойност ss и я хеширайте отново и отново:

s  →  H(s)  →  H2(s)  →  …  →  H15(s)=ps \;\to\; H(s) \;\to\; H^2(s) \;\to\; \dots \;\to\; H^{15}(s) = p

Краят на веригата, pp, се публикува. Това е публичният ключ за тази една цифра.

За да се подпише цифра dd между 0 и 15, се разкрива стойността на веригата на позиция dd:

σ=Hd(s)\sigma = H^{d}(s)

Който иска да провери, хешира σ\sigma още 15−d15 - d пъти. Ако се получи точно pp, подписът е истински:

H15−d(σ)=?pH^{15-d}(\sigma) \stackrel{?}{=} p

Мини пример

Подписваме цифрата d=6d = 6:

  • Подписващият публикува σ=H6(s)\sigma = H^6(s).
  • Проверяващият изчислява H9(σ)=H15(s)H^{9}(\sigma) = H^{15}(s) и сравнява с pp. Съвпада.

Фалшификатор, който е видял σ\sigma, може без усилие да изчисли от нея H7(s)H^7(s), H8(s)H^8(s) и т.н. — т.е. да подпише по-големи цифри. По-малки не може — за целта би трябвало да хешира назад.

Контролната сума срещу „броене нагоре“

За да не може никой просто да увеличава цифри, допълнително се подписва контролна сума:

C=∑i(15−di)C = \sum_{i} (15 - d_i)

Ако фалшификаторът увеличи цифра от съобщението, CC става по-малка — а за това той би трябвало да смята назад във веригата на контролната сума. Така и двете посоки са блокирани.

Пренесено върху цяла хеш стойност

Хеш стойност от 32 байта има 64 цифри в основа 16. Към тях се добавят 3 цифри контролна сума:

len=64+3=67 вериги\text{len} = 64 + 3 = 67 \text{ вериги}

Такъв подпис се нарича WOTS+ (Winternitz One-Time Signature). Голямата му уловка е в името: One-Time — еднократен. Който подпише две различни съобщения с един и същ ключ, разкрива толкова много стойности от веригите, че фалшификациите стават възможни.


5. Градивен елемент 2: много еднократни ключове под един покрив (дърво на Меркъл)

Ако всеки ключ може да се използва само веднъж, нужни са ни много от тях — но искаме да публикуваме само един публичен ключ.

Решението е дърво на Меркъл: публичните ключове на 2h′2^{h'} двойки WOTS+ образуват листата. Всеки два съседа се хешират заедно, резултатите — отново по двойки, докато най-горе остане един-единствен корен.

възел=H(ляв ∥ десен)\text{възел} = H(\text{ляв} \,\|\, \text{десен})

При SLH-DSA-SHA2-256f всяко дърво има височина h′=4h' = 4, т.е. 24=162^4 = 16 листа.

За да се покаже, че определено листо принадлежи на дървото, се предоставя пътят за автентикация: 4-те съседни възела по пътя нагоре. С тях проверяващият хешира от листото до корена. Ако се получи познатият корен, листото принадлежи на дървото.


6. Градивен елемент 3: дървета върху дървета (хипердърво)

16 еднократни ключа, разбира се, не стигат. Затова SLH-DSA подрежда дърветата едно върху друго: коренът на едно дърво се подписва с ключ WOTS+ на дървото над него. Тази кула се нарича хипердърво.

При SLH-DSA-SHA2-256f има d=17d = 17 слоя с височина 4 всеки:

h=d⋅h′=17⋅4=68h = d \cdot h' = 17 \cdot 4 = 68

Най-отдолу така са на разположение

268≈2,95⋅10202^{68} \approx 2{,}95 \cdot 10^{20}

листа. Коренът на най-горното дърво се нарича PK.root\text{PK.root} — той е същинският публичен ключ.

Важно: никой не изчислява тези дървета предварително. Всички тайни стойности се извеждат при нужда от тайна начална стойност SK.seed\text{SK.seed}. Съхраняват се само четири стойности по 32 байта:

ЧастСъдържаниеРазмер
SK.seedначална стойност за всички тайни стойности на веригите32 B
SK.prfначална стойност за случайния компонент RR32 B
PK.seedпублична начална стойност, разграничава двойките ключове една от друга32 B
PK.rootкорен на най-горното дърво32 B

Частният ключ се състои от всичките четири (128 байта), публичният — само от PK.seed и PK.root (64 байта).


7. Градивен елемент 4: гора срещу случайни попадения (FORS)

Сега истинският проблем: откъде подписващият знае кое от 2682^{68}-те листа е още неизползвано?

По-старите схеми, основани на хеш (XMSS, LMS), водят за целта брояч. Той никога не бива да бъде нулиран — нито от резервно копие, нито от втори сървър. Ако това все пак се случи, един еднократен ключ се използва два пъти и схемата е разбита. Такива схеми се наричат със състояние.

SLH-DSA е без състояние: листото се избира псевдослучайно от самото съобщение. Тогава може да се случи две съобщения да попаднат на едно и също листо. Затова най-отдолу виси не еднократен подпис, а подпис за малко на брой употреби: FORS (Forest of Random Subsets).

FORS се състои от k=35k = 35 малки дървета на Меркъл с по 2a=29=5122^a = 2^9 = 512 листа. Листата са тайни случайни стойности.

За подписване хешът на съобщението се разделя на 35 числа по 9 бита. Всяко число избира в „своето“ дърво точно едно листо. Подписът съдържа за всяко дърво:

  • тайната стойност на това листо
  • неговия път за автентикация (9 възела)

За друго съобщение фалшификаторът би трябвало във всичките 35 дървета да уцели листа, чиито тайни вече са разкрити. Дори ако една и съща инстанция на FORS е използвана няколко пъти, това е безнадеждно.


8. Целият процес на подписване

  1. Случаен компонент. От SK.prf\text{SK.prf}, свежо случайно число и съобщението се получава 32-байтова стойност RR.
  2. Хеш на съобщението.
    digest=Hmsg(R, PK.seed, PK.root, M)\text{digest} = H_{\text{msg}}(R,\ \text{PK.seed},\ \text{PK.root},\ M)
    49-те байта на дайджеста се разпределят: 40 байта избират 35-те листа на FORS, а останалото определя кое дърво (idx_tree) и кое листо (idx_leaf) най-отдолу в хипердървото се използват.
  3. Подпис FORS върху съобщението. От него се получава публичен ключ на FORS.
  4. Подпис на хипердървото върху този ключ на FORS: 17 подписа WOTS+, всеки с път за автентикация, слой по слой чак до PK.root\text{PK.root}.

Готовият подпис е просто последователното им свързване:

σ=R ∥ σFORS ∥ σHT\sigma = R \,\|\, \sigma_{\text{FORS}} \,\|\, \sigma_{\text{HT}}

9. Защо подписът е голям 49 856 байта

С параметрите на SLH-DSA-SHA2-256f размерът може да се пресметне точно (n=32n = 32 байта на хеш стойност):

ЧастИзчислениеБайта
RRnn32
FORSk⋅(1+a)⋅n=35⋅10⋅32k \cdot (1 + a) \cdot n = 35 \cdot 10 \cdot 3211 200
Хипердърво(h+d⋅len)⋅n=(68+17⋅67)⋅32(h + d \cdot \text{len}) \cdot n = (68 + 17 \cdot 67) \cdot 3238 624
Общо49 856

За сравнение: подписът Ed25519 е 64 байта, ML-DSA-87 — 4627 байта. Размерът е цената за това, че SLH-DSA се справя единствено с хеш функции.


10. Как проверява браузърът

При SLH-DSA проверката означава: повторно хеширане.

  1. Дайджестът се изчислява наново от RR, публичния ключ и съобщението.
  2. От 35-те разкрити листа на FORS и техните пътища се изчисляват 35-те корена на дърветата, а от тях — публичният ключ на FORS.
  3. С всеки от 17-те подписа WOTS+ веригите се дохешират до края, образува се публичният ключ WOTS+ и по пътя се хешира нагоре до корена на дървото.
  4. Накрая трябва да се получи точно PK.root\text{PK.root}.

Това са няколко хиляди извиквания на хеш функцията — дреболия за един компютър. В браузъра проверката при нас отнема около 6 до 12 милисекунди.


11. Какво става, ако някой промени набора от данни?

Ако се промени дори един бит от съобщението MM, дайджестът се променя изцяло. Така 35-те числа сочат към други листа на FORS, а схемата — към друго място в хипердървото.

Разкритите тайни вече не пасват: преизчислените корени се различават и накрая не се получава PK.root\text{PK.root}. Проверката е неуспешна.

За да състави въпреки това валиден подпис, нападателят би трябвало да знае тайни, които никога не са били публикувани — т.е. да изчисли хеш функция назад.


12. Защо точно 256f?

FIPS 205 определя дванадесет набора от параметри: две хеш семейства (SHA-2 и SHAKE), три нива на сигурност (128, 192, 256) и за всяко по един бърз („f“) и един малък („s“) вариант.

ВариантПодписПодписване (при нас)Проверка
SHA2-256s29 792 Bок. 2,6 sок. 3 ms
SHA2-256f49 856 Bок. 0,26 sок. 6 ms

256 означава категория 5 за сигурност на NIST — същото ниво като FALCON-1024 и ML-DSA-87.

„f“ избрахме, защото фирмите могат да издават до 500 QR кода наведнъж. С „s“ подписването би отнело над 20 минути, с „f“ — под минута. За сметка на това подписът е по-голям — но понеже не е в QR кода, това е поносимо.

SHA-2 вместо SHAKE, защото SHA-256 и SHA-512 са хардуерно ускорени на практически всяко устройство.


13. Случайност при подписването

FIPS 205 допуска два начина за генериране на RR:

  • детерминистично: едно и също съобщение, един и същ подпис
  • рандомизирано („hedged“): включва се и свежо случайно число

Ние използваме рандомизирания вариант. Затова два подписа върху едно и също съобщение изглеждат различно — и двата са валидни. Това затруднява атаки, които съчетават измервания на устройството (консумация на ток, време) с повторни подписвания.


14. Какво прави McGesund конкретно с това

Нивото. PQ-Dual-Diversified се предлага в Оценки Premium и Сигнали Premium. Тогава един QR код носи три подписа:

ПодписСемействоМясто
Ed25519елиптична кривав QR кода
ML-DSA-87решеткипечат в бекенда
SLH-DSA-SHA2-256fхеш функциипечат в бекенда

Подписването. Един подпис SLH-DSA струва около четвърт секунда изчислително време. За да остане сървърът междувременно достъпен за всички останали, изчисленията се извършват в отделни фонови нишки.

Проверката. Браузърът на читателя зарежда двата печата и ги проверява със същия модул WASM като всички останали PQ подписи. Ние доставяме данните; пресмятането става на устройството на посетителя.

Сверката с NIST. Нашият модул преминава официалните тестови вектори на NIST за SLH-DSA-SHA2-256f: от началните стойности на NIST се получават байт по байт същите ключове, а всички умишлено манипулирани подписи биват отхвърлени. Можете сами да проверите това в браузъра на тестовата страница на NIST.

Времевата котва. Както при всички ключове, отпечатъкът на ключа SLH-DSA се закотвя чрез OpenTimestamps в блок на Bitcoin.


15. SLH-DSA, ML-DSA и FALCON едно до друго

СвойствоFALCON (FN-DSA)ML-DSA-87SLH-DSA-SHA2-256f
ОсноваNTRU решеткимодулни решеткисамо хеш функции
СтандартFIPS 206 (в процес на разработка)FIPS 204, окончателенFIPS 205, окончателен
Публичен ключ1793 B2592 B64 B
Подпис1280 B4627 B49 856 B
Подписванемилисекундимилисекундиок. 0,26 s
Проверкамилисекундимилисекундимилисекунди
Допусканерешетъчна задачарешетъчна задачахеш функция

Накратко: SLH-DSA е най-бавната и най-обемната от трите схеми — и най-консервативната. Тя не разчита на нищо, което всеки друг подпис и без това не предполага: сигурна хеш функция.


16. Едно изречение за накрая

SLH-DSA подписва с хеш вериги, обединява ги в дървета на Меркъли избира листото от самото съобщение — сигурен, докатохеш функцията е сигурна.\boxed{ \begin{array}{c} \text{SLH-DSA подписва с хеш вериги, обединява ги в дървета на Меркъл}\\ \text{и избира листото от самото съобщение — сигурен, докато}\\ \text{хеш функцията е сигурна.} \end{array}}

Който притежава тайната начална стойност, подписва за четвърт секунда. Който не я притежава, би трябвало да изчисли SHA-256 или SHA-512 назад — дори с квантов компютър.

За читателя на един отзив това означава: дори ако един ден всички решетъчни схеми паднат, този подпис остава проверим. Той не трябва да ни вярва. Може да провери сам.