Testo originale: "Vanity Addresses" di foobar
Compilazione: porridge notturno, la via della DeFi
Sono scomparsi 160 milioni di dollari USA e Wintermute ha perso i fondi. Wintermute è uno dei fondi di market-making più astuti del settore. Una mattina di settembre, quando il responsabile di Wintermute si è svegliato, ha scoperto che uno dei loro importanti portafogli aveva perso 9 cifre.fondi. Quindi cosa ha portato al furto di Wintermute? Ciò è causato dalla scarsa casualità in un generatore di indirizzi vanity. Gli hacker black hat forzano da zero la coppia di chiave privata e indirizzo pubblico, quindi una grande quantità di risorse crittografiche vengono trasferite.
C'è anche una storia su Indexed Finance che è stata hackerata, dove sono stati rubati 16 milioni di dollari nell'ottobre 2021, e i fondi rubati sono stati poi spostati a indirizzi che iniziano con 0xba5ed…. Ciò che non sapevano era che anche l’indirizzo vanity era influenzato dalla grave vulnerabilità della casualità che affliggeva Wintermute e, nel settembre 2022, tutto il denaro è stato nuovamente rubato, andando a un altro indirizzo di portafoglio compromesso. I ladri sono spietati.
Quali problemi hanno incontrato questi talentuosi sviluppatori e cosa possiamo imparare da loro?
A sinistra c'è l'indirizzo normale utilizzato per il contratto WETH. Sulla destra c'è un bell'indirizzo con 14 zeri iniziali per l'ottimizzazione del robot MEV. Il tipo più comune di indirizzo vanity è quello con molti zeri iniziali.
Innanzitutto, cos’è un vanity address (noto anche come vanity address)? Un indirizzo vanity si riferisce a un indirizzo pubblico che un utente crea deliberatamente per associarlo al proprio portafoglio o contratto intelligente. Forse inizia con 0x0000000, forse inizia con 0xdeadbeef, forse è qualche altro indirizzo normale. Ci sono diverse ragioni per la loro popolarità:
1. Ottimizzazione del gas: Wintermute ha risparmiato $ 15.000 utilizzando un indirizzo EOA con più zeri iniziali. Sembra sciocco? Molte persone sono d'accordo, ma è così che funziona l'EVM Se hai molti zeri nel tuo indirizzo, la tariffa per la transazione del gas può diminuire! Quindi, se utilizzi un indirizzo di contratto intelligente con molti zeri iniziali, gli utenti saranno felici quando interagiranno con esso perché fa risparmiare loro denaro.
L'Ethereum Yellow Paper descrive come gli indirizzi zero iniziali possono consentire gas più economico
2. Marchio contrattuale. Sai che il contratto Token da 1 pollice inizia con 0x111111111...?
Contratto token da 1 pollice
3. Ripetibilità multi-filo. A mio parere, questa è una priorità assoluta ed è il motivo per cui ogni protocollo dovrebbe utilizzare un indirizzo vanity per la propria implementazione. La tua applicazione può vivere su 15 diverse catene EVM e avere lo stesso indirizzo ovunque! Non sarebbe più facile per sviluppatori e utenti?
Allora quando un bell'indirizzo è sicuro?
Esistono due tipi di indirizzi Ethereum: account di proprietà esterna (EOA) e account smart contract. Se hai utilizzato un portafoglio come MetaMask, ogni indirizzo in esso contenuto è un EOA, che viene utilizzato per firmare messaggi ed elaborare transazioni. Confrontalo con un account di contratto intelligente come il contratto Uniswap, con cui le persone possono interagire ma non può intraprendere le proprie azioni senza essere attivato. Per riassumere, è molto semplice. Gli indirizzi con numeri buoni non sono sicuri per gli account EOA, ma lo sono per gli account con contratto intelligente.
Allora perché è così? Lo spiegheremo più dettagliatamente di seguito, ma dipende da come viene generato l'indirizzo vanity. Per gli account EOA, scorri milioni di chiavi private finché non ne trovi una che corrisponde a un indirizzo pubblico dall'aspetto gradevole. Tuttavia, la chiave privata controlla i fondi all'interno di un conto EOA, quindi se la casualità che utilizzi per attraversare la chiave privata è compromessa, l'intero account sarà rovinato. D’altra parte, la creazione di indirizzi vanity per i contratti intelligenti richiede solo l’attraversamento di seed pubblici, che non garantiscono alcun diritto amministrativo al contratto intelligente.
Questo è il motivo per cui Wintermute fallisce e OpenSea ha successo: generare chiavi private in una memoria non sicura con software non sicuro è un male. Ma generare semi pubblici in questo modo è davvero carino! Pertanto, un buon indirizzo EOA è una strada verso il fallimento, mentre un buon indirizzo di contratto intelligente è una strada verso il successo.
Perché il protocollo richiede un indirizzo carino?
Documentazione più semplice! Puoi puntare a un indirizzo contrattuale su tutte le catene;
Verificabile dall'utente! Lo stesso indirizzo del contratto apparirà solo se e solo se il bytecode viene abbinato byte per byte;
Gli sviluppatori possono verificare! Poiché gli indirizzi contrattuali identici si verificano solo in caso di corrispondenza esatta, è possibile individuare piccole modifiche complicate nello script di distribuzione;
Integrazione più semplice! Altri protocolli possono codificare l'indirizzo del tuo contratto nel loro multi-chaincode senza dover utilizzare istruzioni if basate su chainId.
NOTA: Stiamo per approfondire un manuale di istruzioni dettagliato. Mettendo insieme tutti i pezzi per la prima volta, ci stiamo immergendo in profondità nello spazio tecnico e prendendo di mira gli sviluppatori di contratti intelligenti con esperienza nell’implementazione di contratti intelligenti on-chain. Se sei interessato, continua a leggere, ma se non fa per te, non preoccuparti di tenere il passo. Alla fine è prevista un'ulteriore sfida tecnica (con ricompense).
Bellissimo indirizzo del contratto intelligente
Esiste un modo per generare indirizzi vanity di contratti intelligenti sicuri al 100%, indipendentemente dal software utilizzato e non importa se la tecnologia iterativa viene divulgata pubblicamente. Si chiama "metodo CREATE2 factory" e non solo fornisce un indirizzo carino, ma è anche un modo infallibile per garantire di avere lo stesso indirizzo di distribuzione del contratto su più catene. Consente inoltre ad altri di distribuire codice in modo sicuro per tuo conto senza alcuna condivisione di chiave privata o presupposti nonce.
Innanzitutto, una rapida panoramica su come scegliere un indirizzo per contratto intelligente. Sono disponibili due opzioni di distribuzione, CREATE e CREATE2. Quando distribuisci uno smart contract direttamente da EOA, il processo predefinito è CREATE. L'indirizzo viene determinato eseguendo l'hashing dell'indirizzo del creatore del contratto con il nonce del creatore del contratto. Questo nonce si riferisce al numero di transazioni inviate da un indirizzo, quindi un nuovo portafoglio inizia da 0 e viene incrementato di 1 ogni volta che viene inviata una nuova transazione. Ecco la formula magica per l'indirizzo del contratto intelligente implementato da CREATE:
nuovo_indirizzo = hash(mittente, nonce)
Meno comune, ma più interessante, è l'indirizzo del contratto intelligente distribuito utilizzando CREATE2, ed ecco la sua formula:
nuovo_indirizzo = hash(0xFF, mittente, salt, bytecode)
Il primo sembra più semplice, vero? Tuttavia, diamo un esempio di dove questa semplicità può essere dannosa rispetto al più robusto processo CREATE2.
Airy Alice: C'è un problema con la multicatena
Immagina che uno sviluppatore di criptovaluta di nome Alice crei due contratti intelligenti: un fork Uniswap chiamato GriddleSwap e un progetto NFT chiamato ph00ts. Sono tutte primitive indipendenti e immutabili, il che significa che non esistono dipendenze esterne o rischi di ponti a catena incrociata. Alice distribuisce GriddleSwap su Ethereum utilizzando nonce 0, quindi distribuisce ph00ts su Ethereum utilizzando nonce 1. Sfortunatamente, Alice ha una capacità di attenzione ridotta ed è stata distratta per alcuni minuti sul crypto Twitter prima di distribuire il suo lavoro su Binance Smart Chain (BSC), la seconda più grande piattaforma di contratti intelligenti.
Ops, ho incasinato l'ordine di schieramento!
Ma aspetta! Ha incasinato l'ordine di distribuzione e ha distribuito ph00ts prima di GriddleSwap. Poiché l'indirizzo del contratto intelligente si basa solo sull'indirizzo del creatore e nella blockchain distribuita, Ethereum gridleswap ha esattamente lo stesso indirizzo di BSC ph00ts. A peggiorare le cose, l'indirizzo di Ethereum ph00ts è lo stesso dell'indirizzo di BSC GriddleSwap. Pensare che gli utenti finali saranno confusi è un eufemismo. In effetti, può essere abusato da distributori malintenzionati per indurre le persone a pensare che il comportamento del contratto sulla catena sia lo stesso, il che è un presupposto corretto, dato lo stesso indirizzo!
Attenta Alice: Ci saranno ancora problemi
Anche se Alice sta attenta durante il deploy e non confonde mai l'ordine dei suoi nonce, ci sono altri problemi. Se Alice si distribuisce correttamente su Ethereum e BSC, ma poi effettua una transazione non correlata su Polygon, il nonce 0 è stato utilizzato. Non potrà mai distribuire GriddleSwap lì perché il suo nonce è stato incrementato. Pertanto, le chiavi private del distributore devono essere protette a tutti i costi. Se Alice lo fa trapelare, un sabotatore malintenzionato può effettuare transazioni non correlate. Se Alice lo perde, perderà anche la capacità di schierarsi nuovamente a quell'indirizzo su una nuova catena. Questa è una vulnerabilità permanente che fa affidamento su un individuo onesto per proteggere la chiave privata. Se nemmeno gli sviluppatori principali di Bitcoin possono farlo, come possono farlo gli altri?
Soluzione: CREARE2
Per fortuna, esiste un modo migliore per ottenere indirizzi coerenti attraverso le catene: uno che non si basa su chiavi private segrete, non si basa su un singolo distributore ed è resistente agli errori del distributore lungo il percorso. Ricorda la formula per trovare l'indirizzo di uno smart contract distribuito utilizzando CREATE2:
nuovo_indirizzo = hash(0xFF, mittente, salt, bytecode)
Il primo parametro 0xFF è un valore costante che può essere ignorato. Il secondo parametro (indirizzo mittente) può essere reso coerente selezionando la distribuzione CREATE2Factory di z0age 0x0000000000FFe8B47B3e2130213B802212439497 nella maggior parte delle catene EVM. Il terzo parametro è un sale selezionato dall'utente, che possiamo usare per trovare un buon indirizzo e poi mantenerlo invariato sulla catena. Il quarto è il bytecode del contratto, che funge da utile controllo di integrità per garantire che stiamo implementando esattamente la stessa funzionalità sulla catena. Tutti e quattro i parametri possono rimanere gli stessi, indipendentemente da ciò che fa ogni singolo distributore.
Perché è meglio? A differenza della chiave privata, il salt selezionato dal distributore può essere reso pubblico. Conoscere il salt ti consente di distribuire il contratto, ma non hai alcun controllo sulle risorse o sulle funzionalità del contratto. Poiché non vincola alcuna informazione segreta, chiunque può implementare il contratto nella nuova catena senza rivelare o condividere la chiave privata. Il parametro bytecode garantisce inoltre che queste nuove distribuzioni senza autorizzazione avranno lo stesso indirizzo se e solo se il bytecode è lo stesso. Pertanto, gli utenti finali ottengono garanzie più forti senza dover apportare differenze di codice dettagliate.
Per una panoramica più approfondita, vedere il popolare articolo scientifico di OpenZeppelin.
Crea il tuo bellissimo indirizzo
Pensi che il Proof of Work (PoW) sarà inutile dopo la fusione di Ethereum? Pensa di nuovo! Le stesse funzionalità della GPU che aiutano a trovare preimmagini hash con un gran numero di zeri iniziali per i blocchi Bitcoin sono eccellenti anche per trovare preimmagini hash con un gran numero di zeri iniziali per contratti intelligenti EVM. z0age di OpenSea (grazie alla sua spiegazione per questo post) ha trovato una semplice configurazione per creare il proprio indirizzo personale.
1. Utilizza vast.ai per avviare un'istanza di esempio GPU, che tenta circa 2 miliardi di volte al secondo e costa circa 25 centesimi/ora:
Immagine:nvidia / opencl
GPU: 1xRTX 3090
Spazio su disco richiesto da allocare: 1,83 GB
2. SSH e installa Rust + create2crunch
sudo apt install build-essential -y; curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; fonte "$HOME/.cargo/env"; git clone https://github.com/0age/create2crunch && cd create2crunch; sed -i 's/0x4/0x40/g' src/lib.rs
3. Esegui una ricerca seed. Per le variabili di ambiente, INIT_CODE_HASH è il keccak256 del codice di creazione del contratto. Una stampa di un test di fonderia di esempio può essere trovata qui : assicurati di verificarlo prima di consumare grandi quantità di risorse di calcolo! LEADING dovrebbe essere il numero di byte zero iniziali desiderati e TOTAL dovrebbe essere il numero totale di byte zero desiderati nell'indirizzo del contratto.
esporta FABBRICA="0x0000000000ffe8b47b3e2130213b802212439497"; esporta CALLER="0x0000000000000000000000000000000000000000"; esporta INIT_CODE_HASH="0xabc...def"; esporta LEADER=5; TOTALE esportazione=7; cargo run --release $FACTORY $CALLER $INIT_CODE_HASH 0 $LEADING $TOTAL
Quando z0age ha rilasciato per la prima volta il suo repository, era in grado di eseguire 1,9 miliardi di tentativi al secondo sul vasto hardware AI sopra menzionato. Da allora, la vettorizzazione è impazzita su alcuni core OpenGL e ho osservato 2,15 miliardi di tentativi al secondo. Ciò significa che per trovare un indirizzo con 5 byte zero iniziali occorrerebbero 256^5/(21500000000 * 60) ~= 8 minuti e per trovare un indirizzo con 6 byte zero iniziali occorrerebbero 256^6/(21500000000 * 3600) ~ = 36 ore . Un indirizzo di 7 byte zero iniziali richiede 256^7/(2150000000 * 86400) ~= 387 giorni. Tieni presente che un byte equivale a due caratteri esadecimali, quindi un indirizzo di 5 byte iniziali avrà 10 zeri. Naturalmente, questa ricerca può essere completamente parallelizzata e l’effettiva probabilità di successo nel tempo seguirà una distribuzione di Poisson.
Distribuire la factory CREATE2
I lettori più attenti potrebbero aver notato che CREATE2 Factory esiste già a 0x0000000000FFe8B47B3e2130213B802212439497 su tutte le catene. È un po' un problema dell'uovo e della gallina: in che modo la distribuzione coerente degli indirizzi dipende dalla distribuzione coerente degli indirizzi?
Quando ho appreso per la prima volta di questo approccio, ho pensato che fosse solo una chiave privata detenuta da qualcuno più intelligente di me (lo scenario "Alice osservante" sopra). Ma in realtà è molto più robusto di così! L'approccio "transazioni senza chiave" del fondatore di ENS Nick Johnson sfrutta il fatto che è possibile recuperare l'indirizzo pubblico da qualsiasi firma di transazione senza conoscere la chiave privata corrispondente che l'ha firmata. Pertanto, è possibile creare una transazione ("deploy a create2 factory") e quindi inventare per essa una firma contraffatta, ad esempio composta da soli 2. La chiave privata per questa firma contraffatta esiste, ma nessuno sa cosa sia. Ma possiamo recuperare l'indirizzo pubblico corrispondente alla "firma senza chiave", inviargli un po' di ETH e quindi inviare la transazione firmata al mempool. Nonostante l'oscurità di questo metodo, si tratta di una transazione valida, e di fatto l'unica transazione valida che può essere inviata da questo indirizzo pubblico.
Il risultato? Chiunque può implementare una fabbrica in una nuova catena senza alcuna informazione proprietaria, impedendo al tempo stesso ad attori malintenzionati di causare danni. Creare un EOA con un unico scopo che possa implementare una sola transazione è una tecnica molto intelligente.
Indirizzi e contratti specifici creati durante le transazioni senza chiave
Ciò può essere ottenuto con tre semplici comandi "forge cast". Il bytecode è troppo lungo per essere copiato qui, ma puoi seguire le istruzioni su https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md senza autorizzazione su qualsiasi catena di tua scelta Distribuisci facilmente CREATE2 Factory!
Naturalmente, se è già stato distribuito, non è necessario distribuirlo nuovamente.
Nota a margine: i requisiti EIP-155 sono terribili
Un breve tentativo di supportare le mie avventure di governance in L1, sentitevi liberi di saltare avanti. EIP-155 è una proposta avanzata da Vitalik nel 2016, che introduce il concetto di "chain ID" per prevenire attacchi di replay. Ogni catena ha il proprio identificatore univoco - 1 per Ethereum, 56 per BSC e 137 per Polygon - che sarà incluso nelle transazioni firmate per prevenire attacchi di replay, che è stato rapidamente adottato da Ethereum e tutte le altre catene EVM hanno seguito questa proposta. Questo è fantastico, ma il problema sorge quando vengono selezionate alcune catene, come Evmos che recentemente ha deciso di vietare esplicitamente le transazioni prima dell'EIP-155 , che, per strani motivi, impedisce un errore operativo in cui Optimism ha inviato 20 milioni di token OP a un indirizzo multisig (sì, ancora loro) che Wintermute non esiste, afferma di possedere ma non è mai stato inizializzato. Tuttavia, la disabilitazione delle transazioni precedenti alla 155 interromperebbe in modo significativo tutta una serie di implementazioni cross-chain, come la factory CREATE2 e progetti leader come Seaport. Queste proposte di governance dovrebbero essere ritirate immediatamente e i dettagli di protezione come questo dovrebbero provenire dal portafoglio piuttosto che dal livello di consenso. Se la multicatena è il futuro, allora queste restrizioni inutili costituiranno un enorme ostacolo per i migliori progetti da implementare sulla tua blockchain.
Cose divertenti: distribuire taglie
Oggi https://delegate.cash è distribuito su 7 diverse catene EVM (Ethereum, Polygon, Optimism, Celo, Avalanche, Fantom e Arbitrum) e 7 testnet corrispondenti a queste catene. L'indirizzo del contratto per tutti questi è lo stesso: 0x00000000000076A84feF008CDAbe6409d2FE638B.
Quindi è sufficiente? No, abbiamo bisogno di più catene. Poiché delegatecash è una primitiva indipendente con zero dipendenze, ciò significa che il rischio di catene multiple è effettivamente pari a zero. Questo è puro vantaggio! Pertanto, per le prime 5 persone che distribuiranno e verificheranno il contratto intelligente delegatecash alla nuova catena e al testnet corrispondente, assegnerò un bonus di 100 USDC!
È necessario utilizzare lo script di distribuzione dal repository open source qui. Ciò potrebbe richiedere la distribuzione di CREATE2 Factory se non esiste e non dimenticare la verifica Etherscan! Buona distribuzione e goditi l'apprendimento esperienziale!
