У цій статті пояснено, що таке Argon2id, як Blocknet перетворює його на доказ роботи, чому він винагороджує великий обсяг швидкої пам’яті і як seine отримує максимум хешів із кожного CPU, на якому працює.
Що таке Argon2id?
Argon2id — це вимоглива до пам’яті хеш-функція, описана в RFC 9106 для хешування паролів і доказу роботи. Вона заповнює велику область пам’яті блоками по 1 KiB, будуючи кожен блок із попереднього та ще одного, раніше записаного блоку з іншого місця пам’яті, тож обчислення хешу потребує справжньої пам’яті, а не лише процесорного часу.
RFC 9106, опублікований 2021 року дослідницькою групою Crypto Forum Research Group організації IRTF, описує «вимогливу до пам’яті функцію Argon2 для хешування паролів і застосувань доказу роботи». Argon2 має три варіанти:
- Argon2d вибирає, який попередній блок прочитати, на основі вже обчислених даних. RFC називає його «придатним для криптовалют і застосувань доказу роботи».
- Argon2i вибирає блоки в порядку, що не залежить від даних, і це підходить для хешування паролів.
- Argon2id «працює як Argon2i у першій половині першого проходу по пам’яті і як Argon2d в решті». Це основний варіант: за RFC, кожна реалізація мусить його підтримувати.
Усередині Argon2 розглядає пам’ять як довгу послідовність блоків по 1 024 байти. Кожен новий блок є результатом функції стиснення G, застосованої до двох входів: блоку безпосередньо перед ним і опорного блоку з попередньої частини пам’яті. G побудована на раундах перемішування хеш-функції BLAKE2b, які працюють із 64-бітовими словами за допомогою додавань, XOR і циклічних зсувів.
Як Blocknet використовує Argon2id як доказ роботи?
Blocknet фіксує всі параметри Argon2id у своєму коді консенсусу, тож кожен майнер і кожна нода обчислюють ту саму функцію:
| Параметр | Значення в Blocknet | Що це означає |
|---|---|---|
| Варіант | Argon2id, версія 1.3 | Основний варіант за RFC 9106 |
| Пам’ять | 2 GiB (2 097 152 KiB) | 2 097 152 блоки по 1 KiB, заповнені на кожен хеш |
| Ітерації | 1 | Один прохід по пам’яті |
| Паралельність | 1 | Одна смуга, тож один хеш виконується в одному потоці |
| Вихід | 32 байти | Значення, яке порівнюють із ціллю |
| Пароль | 8-байтовий nonce, little-endian | Число, яке майнер змінює з кожною спробою |
| Сіль | Заголовок блоку без nonce | Прив’язує хеш до одного шаблону блоку |
Майнінг — це пошук. Майнер бере заголовок блоку, який хоче опублікувати, вибирає nonce і обчислює хеш Argon2id. Якщо 32-байтовий результат, прочитаний як число, не перевищує ціль мережі, блок дійсний. Якщо ні, майнер пробує наступний nonce.
Ціль виводиться безпосередньо зі складності: це (2^256 − 1), поділене на складність. Тому складність приблизно дорівнює кількості хешів, яку вся мережа має обчислити, щоб знайти один блок. Blocknet розрахований на один блок кожні п’ять хвилин, тож хешрейт мережі приблизно дорівнює складності, поділеній на 300 секунд. Сама складність стежить за часом останніх блоків через зважене ковзне середнє за 60 блоків.
Пули працюють так само, але з легшою ціллю. На bntpool.com seine надсилає шари, що відповідають нижчій складності для кожного з’єднання, і будь-яка шара, яка також відповідає цілі мережі, є знайденим блоком.
Чому вимогливий до пам’яті доказ роботи підходить звичайним комп’ютерам?
Наведені вище параметри роблять пам’ять центром кожного хешу. За одного проходу й однієї смуги друга половина проходу залежить від даних: позиція опорного блоку для кожного нового блоку береться з першого 64-бітового слова блоку, обчисленого безпосередньо перед ним. Майнер не може знати, який попередній блок йому знадобиться, аж до моменту, коли він знадобиться, тож він тримає в пам’яті всю область розміром 2 GiB.
Майнер міг би спробувати зберігати менше блоків і перераховувати відсутні за потреби. RFC 9106 називає це компромісами між часом і пам’яттю: вони заощаджують пам’ять «ціною більшої кількості викликів внутрішньої функції стиснення». За кожен блок, викинутий з області, доводиться платити знову додатковими обчисленнями.
Саме це робить конструкцію дружньою до звичайного обладнання. Настільні комп’ютери, ноутбуки й сервери вже мають гігабайти ОЗП і контролери пам’яті, створені для того, щоб її живити. Чипу, розробленому лише для хешування, все одно знадобилися б гігабайти швидкої пам’яті поруч із ядрами хешування. Перший рекомендований у RFC 9106 параметр — Argon2id з одним проходом по 2 GiB пам’яті, тобто та сама кількість проходів і той самий обсяг пам’яті, що й у Blocknet, і RFC зазначає, що цей параметр «максимізує витрати супротивника на спеціалізоване обладнання для повного перебору». Код демона Blocknet описує цей вибір як вимогливий до пам’яті доказ роботи, щоб «протистояти ASIC і забезпечити чесний майнінг». Argon2id розроблено так, щоб протистояти ASIC, а параметр 2 GiB втілює цю конструкцію на практиці, тож майнінг залишається відкритим для комп’ютерів, які люди вже мають. Як це порівнюється зі стейкінгом, пояснено в статті Proof of Work проти Proof of Stake.
Чому ОЗП і пропускна здатність пам’яті визначають хешрейт?
Кожен потік майнінгу тримає власну область розміром 2 GiB, тож ваша ОЗП визначає, скільки потоків можна запустити. Кожен хеш також записує 2 GiB і зчитує приблизно стільки ж із розкиданих місць, тож швидкість і затримка пам’яті визначають, як швидко ці потоки завершують роботу. Пам’ять важить стільки ж, скільки кількість ядер.
ОЗП визначає кількість потоків. Паралельність 1 означає, що один хеш виконується в одному потоці, і кожному потоку потрібна власна повна область розміром 2 GiB. Комп’ютер із 16 GB може запустити приблизно шість-сім потоків, залишивши місце для системи. seine вимірює вашу пам’ять, тримає 5% у резерві й сам вибирає кількість потоків.
Пропускна здатність і затримка визначають швидкість кожного потоку. Хеш створює 2 097 152 нові блоки, і кожен із них зчитує опорний блок розміром 1 KiB з якогось місця області. Це приблизно 2 GiB запису й 2 GiB читання на кожен хеш. За 10 H/s комп’ютер щосекунди пропускає через пам’ять близько 40 GiB даних. У половині, що залежить від даних, кожна адреса читання стає відомою лише після завершення попереднього блоку, тож час відповіді пам’яті важить стільки ж, скільки її пропускна здатність.
Саме тому на сторінці продуктивності seine сказано, що хешрейт «залежить від пропускної здатності й затримки пам’яті так само, як від кількості ядер». Посібник з обладнання для майнінгу Blocknet показує найкращий результат для кожного покоління обладнання.
Huge pages допомагають із тієї самої причини. Область розміром 2 GiB охоплює 524 288 звичайних сторінок по 4 KiB або 1 024 сторінки по 2 MiB. Менше, але більших сторінок означає менше промахів трансляції адрес під час цих розкиданих читань, що додало близько 4–6% на тестовому комп’ютері seine. Налаштування описано в посібнику з huge pages.
Як обчислювальні ядра seine для CPU отримують максимум з Argon2id?
Обчислювальне ядро — це внутрішній цикл, який обчислює блоки. Збірки seine для x86 містять скалярне ядро, ядра AVX2 і AVX-512, а також потоковий (streaming) варіант, а збірки для Arm містять NEON зі швидким шляхом SHA3. Кожне з них по-своєму справляється з роботою, обмеженою пам’яттю:
- AVX2 і AVX-512 виконують раунди G у стилі BLAKE2b одразу над багатьма 64-бітовими словами в широких векторних регістрах. AVX-512 також має вбудовані інструкції циклічного зсуву, які ці раунди використовують постійно.
- Попередня вибірка (prefetching) запитує опорні блоки з пам’яті ще до того, як вони знадобляться. У першій половині проходу адреси відомі заздалегідь, тож seine запитує блоки на кілька кроків наперед. У другій половині seine запитує наступний опорний блок, щойно перше слово поточного блоку стає остаточним, і решта стиснення виконується, поки дані надходять.
- Streaming тримає 64 останні блоки в невеликому кешованому кільці й записує кожен готовий блок в область розміром 2 GiB потоковими записами, які йдуть безпосередньо в пам’ять і залишають кеш вільним для блоків, які ще потрібні хешу. seine автоматично порівнює його на процесорах AMD EPYC Zen 5.
- NEON із SHA3 використовує інструкцію XAR з розширення Arm SHA3, яка виконує XOR і циклічний зсув за один крок, разом із ширшим охопленням попередньої вибірки.
На протестованому нами обладнанні правильне обчислювальне ядро давало велику різницю. Це парні запуски на тому самому комп’ютері з тією самою кількістю потоків, зі сторінки продуктивності seine:
| Комп’ютер | Зміна ядра | Приріст |
|---|---|---|
| AWS Graviton4 (Neoverse V2), 16 потоків | NEON → SHA3 з попередньою вибіркою | +56% (з 13,80 до 21,50 H/s) |
| AWS Graviton3 (Neoverse V1), 16 потоків | NEON → SHA3 з попередньою вибіркою | +45% (з 12,52 до 18,17 H/s) |
| AMD EPYC 9R45 (Zen 5), 24 потоки | AVX2 → streaming | +30% (з 34,47 до 44,74 H/s) |
| Intel Xeon 8375C (Ice Lake), 1–4 потоки | AVX2 → AVX-512 | +21–29% |
Нічого з цього вам не потрібно вибирати самостійно. seine порівнює обчислювальні ядра, які підтримує ваш CPU, на реальній роботі з майнінгу, перемикається лише після двох підтверджених приростів і зберігає переможця для наступного запуску. Найкраще ядро залежить від кількості потоків, розміру сторінок і розміщення на CPU, тому seine вимірює на вашому комп’ютері, а не жорстко прописує вибір у коді.
Щоб задіяти власну пам’ять, завантажте seine, запустіть його й вставте свою адресу. Решту описано в посібнику з майнінгу.
Поширені запитання
Які параметри Argon2id використовує Blocknet для доказу роботи?
Blocknet використовує Argon2id версії 1.3 з 2 GiB пам'яті, однією ітерацією, паралельністю 1 і 32-байтовим виходом. Паролем слугує 8-байтовий nonce, а сіллю є заголовок блоку без nonce. Хеш знаходить блок, коли він не перевищує ціль, встановлену складністю мережі.
Чому кожному потоку майнінгу Blocknet потрібно 2 GB ОЗП?
Кожен хеш Argon2id заповнює область пам'яті розміром 2 GiB із блоків по 1 KiB, і в другій половині проходу кожен новий блок читає один із попередніх, вибраний за даними, які майнер не може передбачити. Потік мусить тримати всю свою область у пам'яті, тому кожному запущеному потоку потрібно близько 2 GB ОЗП.
Чому Argon2id розроблено так, щоб протистояти ASIC?
Argon2id робить пам'ять найдорожчою частиною кожного хешу. Кожен хеш Blocknet потребує 2 GiB швидкої пам'яті й пропускає через неї гігабайти даних, тож чипу, створеному лише для хешування, все одно знадобився б великий обсяг ОЗП на кожне ядро. У коді демона цей вибір описано як вимогливий до пам'яті доказ роботи, що протистоїть ASIC і забезпечує чесний майнінг.
Чи можна майнити Argon2id від Blocknet на відеокарті?
Так. У Windows і Linux seine майнить на всіх відеокартах NVIDIA в комп'ютері одночасно з CPU, і хешрейт підсумовується. Обчислювальні ядра компілюються під час запуску, а перший запуск налаштовує кожну карту й зберігає результат, тож перед початком нічого налаштовувати не потрібно.