Ewolucja architektury prywatności: od mikserów do protokołów programowalnych
Klasyczne miksery, takie jak Tornado Cash czy Sinbad, odchodzą w przeszłość pod presją regulatorów, sankcji amerykańskiego Biura ds. Kontroli Aktywów Zagranicznych (OFAC) oraz analizy grafów transakcji metodą heurystycznego śledzenia klastrowego. Natywna anonimizacja na poziomie pul płynności jest blokowana w warstwie smart kontraktów poprzez listy adresów podwyższonego ryzyka (Chainalysis, Elliptic) zintegrowane z węzłami RPC wiodących dostawców (Infura, Alchemy).
Branża przechodzi w stronę koncepcji programowalnej prywatności (Programmable Privacy). Zamiast ukrywać sam fakt transakcji poprzez rozmycie depozytów w puli, nowe rozwiązania protokołowe pozwalają na wykonywanie dowolnej logiki biznesowej i smart kontraktów na zaszyfrowanych danych. Liderami tej transformacji stają się sieci oparte na architekturze zk-rollup ze wsparciem dla Programmable Privacy, takie jak Aztec (Noir), oraz wyspecjalizowanymi poufnymi sieciami L1, jak COTI 2.0, wykorzystującymi prymitywy sprzętowe i kryptograficzne nowej generacji.
Zaburzone obwody (Garbled Circuits) w blockchainie
W centrum platform takich jak COTI 2.0 leży klasyczny prymityw kryptograficzny – protokół Yao (Yao's Garbled Circuits), zaadaptowany do zdecentralizowanego środowiska blockchaina. W przeciwieństwie do dowodów zk-SNARK, które dowodzą poprawności twierdzenia bez ujawniania danych, Garbled Circuits pozwalają dwóm lub więcej sobie nieufającym stronom obliczyć dowolną funkcję boolowską na poufnych wejściach w taki sposób, że żadna ze stron nie widzi danych drugiej.
Mechanika zaburzonego obwodu
- 1. Reprezentacja logiki w postaci obwodu boolowskiego: Każde obliczenie (przelew tokenów, sprawdzenie salda, scoring kredytowy) jest kompilowane do skierowanego grafu acyklicznego złożonego z bramek logicznych (AND, XOR, NOT).
- 2. Zaburzanie (Garbling): Twórca obwodu (Garbler) generuje losowe 128-bitowe klucze dla każdego wejścia i wyjścia każdej bramki. Tablice prawdy bramek są szyfrowane tymi kluczami w losowej kolejności.
- 3. Transfer nieświadomy (Oblivious Transfer, OT): Ewaluator obwodu (Evaluator) otrzymuje swoje klucze wejściowe od Garblera za pomocą protokołu kryptograficznego OT. Ewaluator poznaje klucze tylko dla swojego rzeczywistego inputu, nie ujawniając go Garblerowi i nie zyskując dostępu do pozostałych kluczy.
- 4. Obliczenia element po elemencie: Ewaluator odszyfrowuje zaszyfrowane tablice prawdy od dołu do góry obwodu, wyliczając wynik bez możliwości poznania pośrednich wartości zmiennych.
Optymalizacje inżynieryjne dla blockchaina
Surowe Garbled Circuits wymagają ogromnej ilości komunikacji sieciowej. Aby wdrożyć je w środowisku blockchaina, programiści stosują dwie kluczowe optymalizacje:
- Technika Free-XOR: Pozwala na wykonywanie bramek XOR bez szyfrowania i przesyłania danych, wielokrotnie zmniejszając obciążenie pamięci oraz przepustowość szyny.
- Point-and-permute: Metoda maskowania bitów, która pozwala Ewaluatorowi na natychmiastowe odnalezienie właściwego wiersza w zaszyfrowanej tablicy prawdy bez konieczności przeszukiwania wszystkich wariantów deszyfrowania.
Porównanie stosów kryptograficznych zapewniających poufność
Do wyboru odpowiedniego stosu technologicznego przy projektowaniu zdecentralizowanych aplikacji z ochroną danych wykorzystuje się zestawienie kluczowych metryk współczesnych protokołów.
| Protokół / Technologia | Baza kryptograficzna | Wsparcie dla smart kontraktów | Narzut obliczeniowy | Model compliance |
|---|---|---|---|---|
| Tornado Cash (Historyczny mikser) | zk-SNARK (Groth16) | Brak (stałe nominały) | Niski (tylko weryfikacja dowodu) | Brak (pełna odporność na cenzurę) |
| Aztec Network | zk-SNARKs + Język Noir | Turing-zupełność (prywatne smart kontrakty) | Umiarkowany (generowanie dowodu po stronie klienta) | View Keys, programowalne noty audytowe |
| COTI 2.0 | Garbled Circuits + MPC | Natywne wsparcie dla kontraktów zgodnych z EVM | Wysoki (wymaga zoptymalizowanych obwodów) | Selektywne ujawnianie (Selective Disclosure) |
| Zcash (Shielded Pool) | zk-SNARKs (Halo 2 / Sapling) | Ograniczone (pule przejrzyste vs. ukryte) | Średni | Klucze podglądu (Viewing keys) |
Praktyka: Selektywne ujawnianie (Selective Disclosure) i stablecoiny
Nowoczesny compliance wymaga odejścia od koncepcji „całkowitego cienia” na rzecz zasady selektywnego ujawniania (Selective Disclosure). Użytkownik zachowuje pełną kontrolę nad historią swojego kapitału, ale w razie potrzeby może udowodnić kontrahentowi, regulatorowi lub urzędowi skarbowemu legalność środków bez ujawniania pełnego salda portfela i całej matrycy powiązań z innymi adresami.
W architekturze Aztec jest to realizowane poprzez system oddzielnych kluczy oraz wykonywanie operacji po stronie klienta w Private Execution Environment (PXE).
Architektura kluczy w Aztec
Każdy użytkownik zarządza deterministycznym zestawem kluczy powiązanych ze smart kontraktem konta:
- Nullifier Keys ($nhk$): Służą do generowania dowodów wydatku środków (nullifier) bez wycieku informacji o tym, jakie konkretnie saldo lub nota (note) są wydatkowane.
- Incoming Viewing Keys ($ivsk$): Pozwalają na przyznanie dostępu audytowego do konkretnych transakcji przychodzących. Możesz przekazać zaszyfrowany klucz podglądu kontrahentowi lub regulatorowi, udostępniając im widoczność wyłącznie docelowej transakcji stablecoina (np. USDT/USDC w otoczce L2), pozostawiając pozostałe aktywa ukryte.
Przykład wdrożenia: Prywatny przelew stablecoinów w Noir
Poniżej znajduje się fragment kodu gotowego do produkcji (production-ready) w języku Noir (bazowy DSL do pisania obwodów w Aztec), realizujący prywatną weryfikację salda i generowanie zobowiązania przelewu tokenów bez publikowania kwot w publicznym rejestrze.
Fragment kodu
// Zależność w Nargo.toml: poseidon = { tag = "...", git = "https://github.com/noir-lang/poseidon" }
use poseidon::poseidon::bn254::{hash_2, hash_3};
global TREE_DEPTH: u32 = 32;
struct Note {
owner: Field,
amount: u64,
randomness: Field,
}
fn commit(note: Note) -> Field {
hash_3([note.owner, note.amount as Field, note.randomness])
}
fn merkle_root(leaf: Field, index: u32, path: [Field; TREE_DEPTH]) -> Field {
let bits: [u1; TREE_DEPTH] = (index as Field).to_le_bits();
let mut node = leaf;
for i in 0..TREE_DEPTH {
node = if bits[i] == 0 {
hash_2([node, path[i]])
} else {
hash_2([path[i], node])
};
}
node
}
fn main(
// Wejścia publiczne: nic o kwotach i adresach
merkle_root_pub: pub Field,
nullifier: pub Field,
recipient_commitment: pub Field,
change_commitment: pub Field,
// Wejścia prywatne
sender_sk: Field,
sender_note: Note,
path: [Field; TREE_DEPTH],
leaf_index: u32,
transfer_amount: u64,
recipient_owner: Field,
recipient_randomness: Field,
change_randomness: Field,
) {
// 1. Własność noty (z tagiem domenowym)
assert(hash_2([sender_sk, 1]) == sender_note.owner);
// 2. Przynależność do drzewa względem publicznego korzenia
let sender_commitment = commit(sender_note);
assert(merkle_root(sender_commitment, leaf_index, path) == merkle_root_pub);
// 3. Wystarczalność środków (przy braku środków odejmowanie u64 również spowoduje błąd)
assert(sender_note.amount >= transfer_amount);
let change_amount = sender_note.amount - transfer_amount;
// 4. Nullifier
assert(hash_3([sender_commitment, sender_sk, 2]) == nullifier);
// 5. Obie nowe noty są powiązane z publicznymi commitments
assert(commit(Note {
owner: recipient_owner,
amount: transfer_amount,
randomness: recipient_randomness,
}) == recipient_commitment);
assert(commit(Note {
owner: sender_note.owner,
amount: change_amount,
randomness: change_randomness,
}) == change_commitment);
}Poza obwodem pozostają: szyfrowanie not dla odbiorcy, przechowywanie i aktualizacja drzewa w kontrakcie, weryfikacja unikalności nullifier oraz sprawdzenie zgodności merkle_root_pub ze znanym korzeniem.
Rekomendacje dotyczące integracji dla deweloperów
- 1. Rezygnacja z generowania dowodów po stronie serwera: Nigdy nie powierzaj generowania dowodów ZK zewnętrznym zdalnym serwerom API. Cały cykl obliczeniowy (PXE w Aztec lub skrypty klienta) musi być wykonywany lokalnie na urządzeniu użytkownika lub w odizolowanym węźle.
- 2. Zarządzanie kluczami izolowanymi dla aplikacji (App-Siloed Keys): Używaj odizolowanych kluczy pochodnych dla każdej zdecentralizowanej aplikacji. Gwarantuje to, że kompromitacja klucza w jednym protokole nie doprowadzi do deanonymizacji historii transakcji użytkownika w innych smart kontraktach.
- 3. Audyt kanałów View Keys: Projektując bramki korporacyjne lub bramki płatnicze oparte na programowalnej prywatności, uwzględnij logikę generowania tymczasowych kluczy podglądu z ograniczonym czasem życia. Pozwala to przechodzić compliance bankowy i regulacyjny (AML/KYT) bez publikowania permanentnych kluczy głównych (master keys) portfela.