Vitalik Buterin: Bagaimana Teknologi zk-SNARKs Melindungi Privasi?

MenengahDec 03, 2023
Artikel ini mendalami cara kerja teknologi zk-SNARK, penerapannya dalam aplikasi saat ini, dan menguraikan tantangan serta potensi kemampuan teknologi ini dalam skenario dunia nyata.
Vitalik Buterin: Bagaimana Teknologi zk-SNARKs Melindungi Privasi?

zk-SNARKs adalah alat kriptografi canggih yang telah menjadi bagian yang semakin penting dari aplikasi berbasis blockchain dan non-blockchain. Kompleksitasnya terlihat jelas dalam memahami cara kerjanya dan bagaimana cara memanfaatkannya secara efektif. Artikel ini menyelidiki bagaimana zk-SNARKs beradaptasi dengan aplikasi saat ini, memberikan contoh apa yang bisa dan tidak bisa mereka capai, dan menawarkan pedoman umum tentang kapan zk-SNARKs cocok untuk aplikasi tertentu. Penekanan khusus akan diberikan pada peran mereka dalam menjamin privasi.

Apa itu zk-SNARK?

Bayangkan memiliki masukan publik x, masukan pribadi w, dan fungsi (publik) f(x,w) → {True,False}, yang memvalidasi masukan. Dengan zk-SNARKs, seseorang dapat membuktikan bahwa mereka mengetahui aw, sehingga untuk f dan x tertentu, f(x,w) = Benar, semuanya tanpa mengungkapkan apa sebenarnya w itu. Selain itu, verifikator dapat mengautentikasi bukti jauh lebih cepat dibandingkan menghitung f(x,w) meskipun mereka mengetahui w.

Ini memberi zk-SNARK dua atribut: privasi dan skalabilitas. Seperti disebutkan, contoh kami di artikel ini terutama akan berfokus pada aspek privasi.

Bukti Keanggotaan

Misalkan Anda memiliki dompet Ethereum dan ingin membuktikan bahwa dompet ini terdaftar berdasarkan sistem bukti kemanusiaan, tanpa mengungkapkan siapa sebenarnya individu yang terdaftar. Fungsi ini secara matematis dapat digambarkan sebagai:

Input pribadi (w): Alamat Anda A, kunci pribadi alamat Anda k

Masukan publik (x): Kumpulan alamat semua profil bukti kemanusiaan yang terverifikasi {H1…Hn}

Fungsi verifikasi f(x,w):

Tafsirkan w sebagai pasangan (A, σ) dan x sebagai daftar profil yang valid {H1…Hn}

Verifikasi A adalah salah satu alamat di {H1…Hn}

Konfirmasikan privtoaddr(k) = A

Jika kedua verifikasi lolos, kembalikan True. Jika salah satu dari mereka gagal, kembalikan False.

Pepatah menghasilkan alamatnya A dan kunci terkait k, menyediakan w=(A,k) sebagai masukan pribadi untuk f. Mereka memperoleh masukan publik, yang merupakan kumpulan profil bukti kemanusiaan terverifikasi saat ini {H1…Hn}, dari rantai tersebut. Mereka kemudian menjalankan algoritma bukti zk-SNARK, yang (dengan asumsi inputnya benar) menghasilkan bukti. Bukti ini dikirim ke pemverifikasi, bersama dengan tinggi blok tempat mereka mengambil daftar profil terverifikasi.

Verifikator juga membaca rantai tersebut, memperoleh daftar {H1…Hn} dari ketinggian yang ditentukan oleh peribahasa, dan memeriksa buktinya. Jika verifikasi berhasil, verifikator yakin bahwa pembukti tersebut memiliki profil bukti kemanusiaan yang terverifikasi.

Sebelum mempelajari contoh yang lebih rumit, saya sangat menyarankan untuk memahami sepenuhnya contoh di atas.

Membuat Bukti Keanggotaan Lebih Efisien

Salah satu kelemahan dari sistem pembuktian yang disebutkan di atas adalah bahwa pemverifikasi perlu mengetahui seluruh kumpulan profil {H1…Hn}, yang memerlukan waktu O(n) untuk “memasukkan” kumpulan ini ke dalam mekanisme zk-SNARK. Masalah ini dapat diatasi dengan menggunakan root Merkle on-chain, yang mencakup semua profil, sebagai masukan publik (mungkin hanya root negara). Kami menambahkan masukan pribadi lainnya, bukti Merkle M, yang mengonfirmasi bahwa akun pembuktian A ada di bagian pohon yang bersangkutan.

Alternatif terbaru dan lebih efisien terhadap bukti Merkle untuk bukti keanggotaan ZK adalah Caulk. Di masa depan, beberapa kasus penggunaan ini mungkin akan beralih ke solusi serupa dengan Caulk.

ZK-SNARK dan Koin

Proyek seperti Zcash dan Tornado.cash memungkinkan kami memiliki mata uang yang melindungi privasi. Sekarang, orang mungkin berpikir mereka dapat menggunakan “bukti manusia ZK” yang disebutkan di atas, namun ini bukan tentang membuktikan akses terhadap bukti profil manusia; ini tentang membuktikan akses terhadap koin. Di sinilah letak masalahnya: kita harus mengatasi privasi dan pembelanjaan ganda secara bersamaan. Artinya, kita tidak boleh mengeluarkan koin yang sama dua kali.

Begini cara kami menyelesaikannya: Siapa pun yang memiliki koin memiliki rahasia pribadi “s”. Mereka menghitung “leaf” L=hash(s,1) secara lokal, yang dipublikasikan pada rantai, menjadi bagian dari negara, N=hash(s,2), yang kita sebut nullifier. Negara disimpan di pohon Merkle.

Untuk membelanjakan koin, pengirim harus menunjukkan ZK-SNARK dimana:

  • Masukan publik mencakup nullifier N, akar Merkle R saat ini atau baru-baru ini, dan daun baru L' (dimaksudkan untuk penerima yang memiliki rahasia s' yang diteruskan ke pengirim sebagai L'=hash(s',1)).

  • Input privat terdiri dari secret s, leaf L, dan cabang Merkle M.

Fungsi verifikasi memeriksa:

  • M adalah cabang Merkle yang valid, membuktikan L adalah daun dari pohon yang berakar di R, dimana R adalah akar Merkle dari keadaan saat ini.

  • hash(s,1)=L dan hash(s,2)=N.

Transaksi tersebut berisi nullifier N dan daun baru L'. Kami sebenarnya tidak membuktikan apa pun tentang L', namun “dicampur” menjadi bukti untuk mencegah modifikasi oleh pihak ketiga selama transaksi. Untuk memvalidasi transaksi, rantai memverifikasi ZK-SNARK dan memeriksa apakah N telah digunakan dalam transaksi sebelumnya. Jika berhasil, N ditambahkan ke kumpulan nullifier yang dihabiskan, menjadikannya tidak dapat digunakan lagi. L' ditambahkan ke pohon Merkle.

Dengan menggunakan ZK-SNARK, kami menghubungkan dua nilai: L (muncul di rantai saat koin dicetak) dan N (muncul saat dibelanjakan), tanpa mengungkapkan L mana yang terhubung ke N mana. Hubungan antara L dan N hanya terlihat saat Anda mengetahui rahasia yang menghasilkannya. Setiap koin yang dicetak dapat digunakan satu kali (karena hanya ada satu N yang valid untuk setiap L), namun koin spesifik yang digunakan kapan saja tetap dirahasiakan.

Ini adalah hal primitif yang penting untuk dipahami. Banyak mekanisme yang kami uraikan di bawah ini didasarkan pada hal ini, meskipun dengan tujuan yang berbeda-beda.

Koin dengan Saldo Sewenang-wenang

Hal di atas dapat dengan mudah diperluas ke koin dengan saldo sewenang-wenang. Kami mempertahankan konsep “koin”, namun setiap koin membawa saldo (pribadi). Cara mudah untuk mencapai hal ini adalah dengan setiap koin memiliki penyimpanan berantai, tidak hanya dengan daun L, tetapi juga dengan saldo terenkripsi. Setiap transaksi akan menggunakan dua koin dan membuat dua koin baru, menambahkan dua pasang (daun, saldo terenkripsi) ke negara bagian. ZK-SNARK juga memverifikasi bahwa jumlah saldo masukan sama dengan jumlah saldo keluaran, dan kedua saldo keluaran tidak negatif.

ZK Anti-Penolakan Layanan

Alat anti-DOS yang menarik: Bayangkan Anda memiliki identitas on-chain yang tidak mudah dibuat; bisa berupa profil tahan manusia atau 32 validator ETH, atau hanya akun dengan saldo ETH bukan nol. Kita dapat menciptakan jaringan peer-to-peer yang lebih tahan DOS dengan hanya menerima pesan yang membuktikan bahwa pengirim memiliki profil. Setiap profil akan diizinkan hingga 1000 pesan per jam. Jika pengirim curang, profilnya akan dihapus dari daftar. Namun bagaimana kita memastikan privasi?

Pertama, pengaturannya: misalkan k adalah kunci pribadi pengguna, dan A=privtoaddr(k) adalah alamat yang sesuai. Daftar alamat yang valid bersifat publik (misalnya, registri on-chain). Sejauh ini, hal ini mencerminkan contoh yang dapat dibuktikan oleh manusia: Anda harus membuktikan bahwa Anda memegang kunci pribadi suatu alamat tanpa mengungkapkan alamat mana. Namun kami tidak hanya ingin bukti bahwa Anda ada dalam daftar. Kami membutuhkan protokol yang memungkinkan Anda membuktikan bahwa Anda ada dalam daftar tetapi membatasi pembuktian Anda.

Kami akan membagi waktu menjadi beberapa periode: masing-masing berlangsung selama 3,6 detik (menjadikan 1000 periode per jam). Tujuan kami adalah membiarkan setiap pengguna hanya mengirim satu pesan per periode; jika mereka mengirim dua dalam periode yang sama, mereka tertangkap. Untuk memungkinkan terjadinya ledakan sesekali, mereka dapat menggunakan periode terkini. Jadi, jika pengguna memiliki 500 periode yang belum terpakai, mereka dapat mengirim 500 pesan sekaligus.

Protokol

Mari kita mulai dengan versi dasar menggunakan nullifier. Seorang pengguna membuat nullifier dengan (N = \text{hash}(k, e)) di mana (k) adalah kuncinya, dan (e) adalah nomor zaman, lalu menerbitkannya dengan pesan (m). ZK-SNARK kemudian mengaburkan (\text{hash}(m)). Tidak ada apa pun tentang (m) yang diverifikasi dalam proses ini, sehingga mengikat bukti pada satu pesan. Jika pengguna mengikat dua bukti ke dua pesan berbeda menggunakan nullifier yang sama, mereka berisiko ketahuan.

Sekarang, kita beralih ke versi yang lebih rumit. Dalam skenario ini, protokol berikutnya mengungkapkan kunci pribadi mereka dan bukan sekadar mengonfirmasi apakah seseorang telah menggunakan periode yang sama dua kali. Teknik penting kami bergantung pada prinsip bahwa “dua titik menentukan sebuah garis.” Mengungkapkan satu titik pada suatu garis tidak akan mengungkapkan banyak hal, tetapi memperlihatkan dua titik akan menyingkapkan keseluruhan garis.

Untuk setiap epoch (e), kita memilih sebuah garis (L_e(x) = \text{hash}(k, e) \times x + k). Kemiringan garis adalah (\text{hash}(k, e)), dan titik potong y adalah (k), keduanya tidak diketahui publik. Untuk menghasilkan sertifikat pesan (m), pengirim menyediakan (y = L_e(\text{hash}(m)) = \text{hash}(k, e) \times \text{hash}(m) + k ), disertai bukti ZK-SNARK bahwa penghitungan (y) akurat.

Ringkasnya, ZK-SNARK adalah sebagai berikut:

Masukan Publik:

  • ({A_1…A_n}): Daftar akun yang valid

  • (M): Pesan sedang divalidasi oleh sertifikat

  • (E): Nomor zaman untuk sertifikat

  • (Y): Evaluasi fungsi garis

Masukan Pribadi:

  • (K): Kunci pribadi Anda

Fungsi Verifikasi:

  • Periksa apakah (\text{privtoaddr}(k)) ada di ({A_1…A_n})

  • Konfirmasi (y = \text{hash}(k, e) \times \text{hash}(m) + k)

Namun bagaimana jika seseorang menggunakan suatu epoch dua kali? Mereka akan mengungkapkan dua nilai (m_1) dan (m_2) beserta nilai sertifikatnya (y_1 = \text{hash}(k, e) \times \text{hash}(m_1) + k) dan (y_2 = \text{hash}(k, e) \kali \teks{hash}(m_2) + k). Kita kemudian dapat menggunakan dua titik ini untuk memulihkan garis dan selanjutnya perpotongan y, yang merupakan kunci privat.

Jadi, jika seseorang menggunakan kembali suatu zaman, mereka secara tidak sengaja mengungkapkan kunci pribadinya kepada semua orang. Tergantung pada konteksnya, hal ini dapat menyebabkan pencurian dana atau hanya menyebarkan kunci pribadi dan mengintegrasikannya ke dalam kontrak cerdas, yang mengakibatkan penghapusan alamat terkait.

Sistem anti-penolakan layanan anonim off-chain yang layak, cocok untuk jaringan peer-to-peer blockchain, aplikasi obrolan, dan sistem serupa, tidak memerlukan bukti kerja. Proyek RLN pada dasarnya berfokus pada konsep ini, meskipun dengan sedikit perubahan (yaitu, mereka menggunakan nullifier dan teknik garis dua titik, membuatnya lebih mudah untuk mendeteksi kejadian di mana suatu epoch digunakan kembali).

Reputasi Negatif ZK

Bayangkan mendirikan 0chan, forum online seperti 4chan yang menawarkan anonimitas lengkap (Anda bahkan tidak memiliki nama permanen), namun dengan sistem reputasi untuk mempromosikan konten berkualitas lebih tinggi. Sistem seperti itu dapat memiliki DAO tata kelola untuk menandai postingan yang melanggar aturan sistem, dan memperkenalkan mekanisme tiga teguran.

Sistem reputasi dapat melayani reputasi positif atau negatif; namun, untuk mengakomodasi reputasi negatif memerlukan infrastruktur tambahan. Hal ini mengharuskan pengguna untuk memasukkan semua data reputasi ke dalam bukti mereka, meskipun itu negatif. Kami terutama akan fokus pada kasus penggunaan yang menantang ini, serupa dengan apa yang ingin diterapkan oleh Unirep Social.

Posting Tertaut: Pengetahuan Dasar

Siapa pun dapat memposting dengan mengirimkan pesan pada rantai yang berisi postingan tersebut, disertai dengan ZK-SNARK. ZK-SNARK ini berfungsi sebagai bukti bahwa (i) Anda memiliki identitas eksternal unik yang memberi Anda izin untuk membuat akun, atau (ii) Anda sebelumnya telah memublikasikan postingan tertentu. Secara khusus, ZK-SNARK berfungsi sebagai berikut:

Masukan Publik:

  • Pembatal, N

  • Akar status blockchain terbaru, R

  • Konten postingan ('dicampur' ke dalam bukti untuk mengikatnya ke postingan, tanpa perhitungan apa pun)

Masukan Pribadi:

  • Kunci pribadi Anda, k

  • Identitas eksternal (alamat A) atau nullifier, Nprev, yang digunakan pada postingan sebelumnya

  • Bukti Merkle, M, bahwa rantai tersebut mengandung A atau Nprev

  • Postingan ke-i yang Anda publikasikan menggunakan akun ini

Fungsi Verifikasi:

  1. Konfirmasikan bahwa M adalah cabang Merkle yang valid, buktikan bahwa (A atau Nprev, mana saja yang disediakan) adalah daun dari pohon dengan akar R.

  2. Verifikasikan N = enc(i, k) di mana enc adalah fungsi enkripsi (misalnya, AES).

  3. Jika i=0, verifikasi A=privtoaddr(k), jika tidak, verifikasi Nprev=enc(i−1,k).

Selain validasi bukti, rantai juga memeriksa (i) apakah R benar-benar merupakan akar status terbaru, dan (ii) bahwa nullifier N belum pernah digunakan sebelumnya. Hingga saat ini, ini mirip dengan koin yang menjaga privasi seperti dijelaskan sebelumnya, namun kami telah menambahkan proses untuk 'mencetak' akun baru dan menghapus kemampuan untuk 'mengirim' akun Anda ke kunci yang berbeda. Sebaliknya, semua nullifier dihasilkan menggunakan kunci asli. Kami menggunakan enc di sini untuk membuat nullifier dapat dibalik. Jika Anda memiliki kunci k, Anda dapat mendekripsi nullifier tertentu secara on-chain; jika hasilnya adalah indeks yang valid dan bukan omong kosong acak (misalnya, kita cukup memeriksa dec(N) < 2^64), Anda akan tahu bahwa nullifier dihasilkan menggunakan kunci k.

Menambah Reputasi:

Dalam skema ini, reputasi bersifat on-chain dan eksplisit. Beberapa kontrak pintar memiliki metode yang disebut addReputation, yang mengambil nullifier yang dirilis bersama sebuah postingan dan jumlah unit reputasi yang akan ditambahkan atau dikurangi sebagai input.

Kami telah memperluas data yang disimpan secara on-chain untuk setiap postingan. Daripada hanya menyimpan nullifier N, kita menyimpan {N, h¯, u¯} di mana:

  • h¯ = hash(h, r) di mana h mewakili tinggi blok dari akar keadaan yang direferensikan dalam pembuktian.

  • u¯ = hash(u, r) dengan u adalah skor reputasi akun (dimulai dari 0 untuk akun baru).

R di sini adalah nilai tambah acak untuk mencegah h dan u ditemukan melalui pencarian brute force. Dalam istilah kriptografi, menambahkan R menjadikan hash sebagai komitmen tersembunyi.

Asumsikan sebuah postingan menggunakan root R dan menyimpan {N, h¯, u¯}. Sebagai buktinya, ini tertaut ke postingan sebelumnya yang menyimpan data {Nprev, h¯prev, u¯prev}. Bukti postingan juga harus melewati semua entri reputasi yang diposting antara hprev dan h. Untuk setiap nullifier N, fungsi verifikasi mendekripsi N menggunakan kunci pengguna k. Jika dekripsi menghasilkan indeks yang valid, pembaruan reputasi akan diterapkan. Jika total seluruh pembaruan reputasi sama dengan δ, maka ini membuktikan u = uprev + δ.

Jika kami ingin menerapkan aturan “tiga pukulan dan Anda keluar”, ZK-SNARK juga akan memastikan u > -3. Jika kita menginginkan aturan di mana postingan dengan rep ≥ 100 menerima tag khusus “postingan bereputasi tinggi”, itu juga bisa dilakukan.

Untuk meningkatkan skalabilitas sistem ini, kita dapat membaginya menjadi dua jenis pesan: Posting dan RCA. Sebuah postingan akan bersifat off-chain, meskipun memerlukan penunjukan ke RCA yang dibuat dalam seminggu terakhir. RCA akan bersifat on-chain, menelusuri semua pembaruan reputasi sejak RCA penerbit sebelumnya. Dengan cara ini, beban on-chain dikurangi menjadi satu transaksi per postingan per minggu, ditambah satu transaksi untuk setiap pesan reputasi.

Meminta Akuntabilitas Pihak-pihak yang Terpusat

Terkadang, ada kebutuhan untuk merancang sistem dengan “operator” terpusat. Alasannya mungkin berbeda-beda: terkadang demi skalabilitas, dan terkadang demi privasi, terutama privasi data yang disimpan oleh operator. Misalnya, sistem pemungutan suara yang tahan terhadap koersif MACI mengharuskan pemilih untuk menyerahkan suara mereka secara on-chain, dienkripsi dengan kunci yang dipegang oleh operator terpusat. Operator ini mendekripsi semua suara on-chain, menghitungnya, dan menampilkan hasil akhirnya. Mereka menggunakan ZK-SNARK untuk membuktikan bahwa semua yang mereka lakukan akurat. Kompleksitas tambahan ini sangat penting untuk memastikan privasi yang kuat (disebut resistensi koersif): pengguna tidak dapat membuktikan kepada siapa pun bagaimana mereka memilih, bahkan jika mereka menginginkannya. Berkat blockchain dan ZK-SNARK, tingkat kepercayaan kami terhadap operator tetap minimal. Operator jahat dapat melanggar perlawanan koersif, namun karena suara diposting di blockchain, mereka tidak dapat berbuat curang dengan menyensor suara. Dan karena mereka harus memberikan ZK-SNARK, mereka tidak bisa berbuat curang dengan salah menghitung hasil.

Menggabungkan ZK-SNARK dengan MPC

Penggunaan ZK-SNARK yang lebih maju adalah dalam komputasi yang memerlukan pembuktian, dengan masukan didistribusikan ke dua pihak atau lebih, dan kami tidak ingin ada pihak yang mengetahui masukan pihak lain. Dalam skenario dua pihak, sirkuit yang kacau dapat memenuhi persyaratan privasi; untuk N pihak, protokol komputasi multi-pihak yang lebih rumit dapat digunakan. ZK-SNARK dapat diintegrasikan dengan protokol ini untuk komputasi multipihak yang dapat diverifikasi. Hal ini memungkinkan sistem reputasi yang canggih, memungkinkan banyak peserta untuk melakukan perhitungan bersama atas masukan pribadi mereka. Perhitungan untuk mencapai hal ini secara efektif masih dalam tahap awal.

Apa yang tidak bisa kita jadikan pribadi?

ZK-SNARKs sangat efektif dalam menciptakan sistem di mana pengguna memiliki negara bagian. Namun, mereka tidak bisa mempertahankan suatu negara sebagai negara yang privat dan tidak diketahui siapa pun. Agar informasi dapat dibuktikan, pembukti harus mengetahuinya dalam teks biasa. Uniswap adalah contoh yang sulit untuk diprivatisasi. Di Uniswap, terdapat “entitas” logis pusat – akun penyedia likuiditas, yang bukan milik siapa pun, dan semua transaksi Uniswap terjadi dengan akun ini. Anda tidak dapat menyembunyikan status akun ini karena seseorang perlu menyimpan status ini dalam teks biasa untuk membuktikannya, dan setiap transaksi memerlukan keterlibatan aktif mereka. Anda dapat menggunakan sirkuit ZK-SNARK yang kacau untuk membuat Uniswap versi pribadi yang terpusat, aman, tetapi tidak jelas apakah manfaatnya lebih besar daripada biayanya. Bahkan mungkin tidak memberikan manfaat nyata: kontrak perlu memberi tahu pengguna tentang harga aset, dan perubahan harga per blok dapat mengungkap aktivitas transaksi. Blockchain dapat mengglobalisasikan informasi negara, dan ZK-SNARK dapat memprivatisasinya, namun tidak ada metode yang solid untuk mengglobalisasi dan memprivatisasi informasi negara secara bersamaan.

Menyatukan yang primitif

Pada bagian di atas, kita melihat contoh alat yang kuat namun juga dapat berfungsi sebagai landasan untuk aplikasi lain. Nullifier, yang penting untuk mata uang, kini muncul kembali dalam kasus penggunaan lainnya. Teknik “tautan koersif” yang digunakan pada bagian reputasi negatif mempunyai penerapan yang luas. Ini sangat efektif untuk banyak aplikasi yang “profil” penggunanya berubah seiring waktu dengan cara yang rumit, dan Anda ingin memaksa pengguna untuk mengikuti aturan sistem sambil menjaga privasi. Pengguna bahkan dapat ditugaskan untuk mewakili “keadaan” internal mereka menggunakan pohon Merkle pribadi yang lengkap. Alat “kumpulan komitmen” yang disebutkan dapat dibangun dengan ZK-SNARK. Jika aplikasi tertentu tidak dapat berfungsi sepenuhnya secara on-chain dan memerlukan operator terpusat, teknik yang sama dapat membuat operator tetap jujur. ZK-SNARK adalah alat yang ampuh, memadukan akuntabilitas dan manfaat privasi. Meskipun mereka mempunyai keterbatasan, dalam beberapa kasus, desain aplikasi yang cerdas dapat mengatasi kendala ini. Saya berharap dapat melihat lebih banyak aplikasi yang mengadopsi ZK-SNARK dan pada akhirnya membangun aplikasi yang menggabungkan ZK-SNARK dengan bentuk enkripsi lainnya di tahun-tahun mendatang.

Penafian:

  1. Artikel ini dicetak ulang dari [Foresightnews]. Semua hak cipta milik penulis asli [Jacob Ko]. Jika ada keberatan terhadap cetak ulang ini, silakan menghubungi tim Gate Learn, dan mereka akan segera menanganinya.
  2. Penafian Tanggung Jawab: Pandangan dan pendapat yang diungkapkan dalam artikel ini adalah sepenuhnya milik penulis dan bukan merupakan nasihat investasi apa pun.
  3. Terjemahan artikel ke bahasa lain dilakukan oleh tim Gate Learn. Kecuali disebutkan, dilarang menyalin, mendistribusikan, atau menjiplak artikel terjemahan.
Начните торговать сейчас
Зарегистрируйтесь сейчас и получите ваучер на
$100
!
Создайте аккаунт