- Регистрация
- 31.12.2019
- Сообщения
- 7,535
- Реакции
- 36
Только ленивый не задумывался о том, как бы сбрутить приватный ключ к жирным кошелькам вроде этого https://www.blockchain.com/btc/address/35hK24tcLEWcgNA4JxpvbkNkoAcDGqQPsP
Существует проект с названием Large Bitcoin Collider https://lbc.cryptoguru.org/ Суть их идеи проста: все кошельки с положительным балансом известны, нужно найти коллизии приватных ключей.
(c) Википедия
Количество всех возможных ключей 2^160 или 115792089237316195423570985008687907852837564279074904382605163141518161494400 Много, правда?
Но смотреть можно по-другому, каждый биткойн-адрес имеет примерно 2^96 закрытых ключей, соответствующих ему. Стакан наполовину полон!
По причине отсутствия личного дата-центра, разворачиваться буду на домашнем пк. Из вложений - был докуплен SHDD на 500 гигабайт за 3500 рублей чтобы хранить на нём >300 гигабайт блоков.
Ставим
Поискав в сети, был найден сайт https://getbitcoinblockchain.com, но на нем раздача шла ещё медленнее. Снова фейл.
Вбиваем на удачу на рутрекере и, о чудо, добрый русский человек на раздаче почти круглосуточно https://rutracker.org/forum/viewtopic.php?t=5520053. За ночь раздача скачалась, отлично!
Запускаем rpc-сервер
Изначально, в аккаунт добавлялись просто адреса для мониторинга, это было ошибочное решение, т.к. в один момент сторадж был удалён, а через некоторое время прошли 4 транзакции по этим адресам. Мелкие, но всё же. Теперь приватные ключи нужно импортировать в наш wallet.
И rpc-клиент
Скорость оставляла желать лучшего, а импортировав примерно ~300k ключей скорость упала до 8-12 ключей в секунду на импорте.
Поскольку 24/7 наблюдать нереально, нужно мониторить и делать автослив.
Проверка и автослив положительного баланса
Прошло время, количество импортированных ключей перевалило за 3 миллиона, rpc-сервер еле ворочался, а денег на личный дата-центр по-прежнему как не было, так и нет.
Меняем концепцию, больше никаких импортов в wallet. Сторим приватный ключ и соответствующий сжатый адрес в kv-хранилище. Я выбрал библиотеку boltdb (https://github.com/etcd-io/bbolt) потому что давно с ней работаю и она себя отлично зарекомендовала. Хранилище
Воркер будет таким
Теперь нужно находить приватный ключ по адресу, если, конечно же, он имеется в нашей базе.
Ну а теперь, пока `genWorker` работает в отдельной goroutine, будем мониторить транзакции. Как только будет проведена новая, проверим нет ли в нашем хранилище приватного ключа, которому соответствует txOut. И если соответствует, сделаем перевод заветных биточков на нужный кош.
Собственно, осталось только добавить параметры коммандной строки для удобства, мне достаточно трёх:
- только генерировать новые пары
- генерировать, проверять баланс, отправлять на мой кош
- слить две базы в одну
1 и 3 нужно для того, чтобы в дороге, например, можно было нагружать ноут чем-нибудь полезным,а дома уже объединять с основной. Хотя полезность, конечно, сомнительна.
Ну и всё, собственно. Запускаем демон bitcoind с ресканом и построением индексов по транзам, запускаем нашу лотерею и, желательно, забываем о ней. Возможно, через какое-то время будет очень приятный сюрприз. В любом случае, затрат никаких, кроме электроэнергии, да и чем чёрт не шутит.
P.S. Предугадывая главный вопрос, отвечаю сразу - нет, больше коллизий не найдено. Пока не найдено
Но количество приватный ключей уже измеряется не миллионами, а гигабайтами, так что всё может случится.
Автор: corax
Существует проект с названием Large Bitcoin Collider https://lbc.cryptoguru.org/ Суть их идеи проста: все кошельки с положительным балансом известны, нужно найти коллизии приватных ключей.
(c) Википедия
Количество всех возможных ключей 2^160 или 115792089237316195423570985008687907852837564279074904382605163141518161494400 Много, правда?
Но смотреть можно по-другому, каждый биткойн-адрес имеет примерно 2^96 закрытых ключей, соответствующих ему. Стакан наполовину полон!
По причине отсутствия личного дата-центра, разворачиваться буду на домашнем пк. Из вложений - был докуплен SHDD на 500 гигабайт за 3500 рублей чтобы хранить на нём >300 гигабайт блоков.
Ставим
bitcoind
, запускаем синхронизацию full node. Четыре дня и 25%. Долго, однако.Поискав в сети, был найден сайт https://getbitcoinblockchain.com, но на нем раздача шла ещё медленнее. Снова фейл.
Вбиваем на удачу на рутрекере и, о чудо, добрый русский человек на раздаче почти круглосуточно https://rutracker.org/forum/viewtopic.php?t=5520053. За ночь раздача скачалась, отлично!
Запускаем rpc-сервер
bitcoind -rpcpassword=pass -rpcuser=user -server -datadir=/path/to/blockchain
, долго ждём рескана блоков. Пока приступаем к написанию нашего "коллайдера"
Код:
// 1BTC
func genLegacy() (string, string) {
priv, err := btcec.NewPrivateKey(btcec.S256())
if err != nil {
log.Fatal(err)
}
byteHash := btcutil.Hash160(priv.PubKey().SerializeCompressed())
addr, err := btcutil.NewAddressPubKeyHash(byteHash, &chaincfg.MainNetParams)
if err != nil {
log.Fatal(err)
}
wif, _ := btcutil.NewWIF(priv, &chaincfg.MainNetParams, false)
return wif.String(), addr.String()
}
Изначально, в аккаунт добавлялись просто адреса для мониторинга, это было ошибочное решение, т.к. в один момент сторадж был удалён, а через некоторое время прошли 4 транзакции по этим адресам. Мелкие, но всё же. Теперь приватные ключи нужно импортировать в наш wallet.
Код:
func importPriv(privKey string) {
wif, _ := btcutil.DecodeWIF(privKey)
if err := client.ImportPrivKeyRescan(wif, "", true); err != nil {
log.Fatal(err)
}
}
И rpc-клиент
Код:
func newClient() *rpcclient.Client {
connCfg := &rpcclient.ConnConfig{
Host: "localhost:8332",
User: "user",
Pass: "pass",
HTTPPostMode: true,
DisableTLS: true,
}
client, err := rpcclient.New(connCfg, nil)
if err != nil {
log.Fatal(err)
}
return client
}
Скорость оставляла желать лучшего, а импортировав примерно ~300k ключей скорость упала до 8-12 ключей в секунду на импорте.
Код:
$ stat wallet.dat
Файл: wallet.dat
Размер: 339472384 Блоков: 663040 Блок В/В: 4096 обычный файл
Поскольку 24/7 наблюдать нереально, нужно мониторить и делать автослив.
Проверка и автослив положительного баланса
Код:
func autoSendBalance() {
for {
balance, err := client.GetBalance("*")
if err != nil {
log.Println(err)
continue
}
if balance.ToBTC() > 0 {
myAddress, err := btcutil.DecodeAddress(TO, &chaincfg.MainNetParams)
//SendFrom requires to the wallet to be unlocked
if err := client.WalletPassphrase(secret, 60); err != nil {
panic(err)
}
_, err = client.SendFrom("*", myAddress, balance)
if err != nil {
log.Println(err)
continue
}
}
time.Sleep(time.Second * 1)
}
}
Прошло время, количество импортированных ключей перевалило за 3 миллиона, rpc-сервер еле ворочался, а денег на личный дата-центр по-прежнему как не было, так и нет.
Меняем концепцию, больше никаких импортов в wallet. Сторим приватный ключ и соответствующий сжатый адрес в kv-хранилище. Я выбрал библиотеку boltdb (https://github.com/etcd-io/bbolt) потому что давно с ней работаю и она себя отлично зарекомендовала. Хранилище
Код:
func saveToStorage(addr, priv string, db *bolt.DB) error {
db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte("Bitcoin"))
if err != nil {
return err
}
return nil
})
db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("Bitcoin"))
err := b.Put([]byte(addr), []byte(priv))
return err
})
}
Воркер будет таким
Код:
func genWorker() {
var priv, addr string
for {
switch format {
case "legacy":
priv, addr = genLegacy()
/*
case "p2sh":
priv, addr = genP2SH()
case "segwit":
priv, addr = genSegWit()
*/
default:
panic("format not defined")
}
saveToStorage(addr, priv)
}
}
Теперь нужно находить приватный ключ по адресу, если, конечно же, он имеется в нашей базе.
Код:
func getPrivKey(addr string, db *bolt.DB) []byte {
var priv []byte
db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("Bitcoin"))
priv = b.Get([]byte(addr))
})
return priv
}
Ну а теперь, пока `genWorker` работает в отдельной goroutine, будем мониторить транзакции. Как только будет проведена новая, проверим нет ли в нашем хранилище приватного ключа, которому соответствует txOut. И если соответствует, сделаем перевод заветных биточков на нужный кош.
Код:
func txTrack() error {
bc, err := client.GetBlockCount()
if err != nil {
return err
}
chHash, err := client.GetBlockHash(bc)
if err != nil {
return err
}
block, err := client.GetBlock(chHash)
if err != nil {
return err
}
hashes, err := block.TxHashes()
if err != nil {
return err
}
for _, hash := range hashes {
parseRawTx(hash.String())
}
return nil
}
Собственно, осталось только добавить параметры коммандной строки для удобства, мне достаточно трёх:
- только генерировать новые пары
- генерировать, проверять баланс, отправлять на мой кош
- слить две базы в одну
1 и 3 нужно для того, чтобы в дороге, например, можно было нагружать ноут чем-нибудь полезным,а дома уже объединять с основной. Хотя полезность, конечно, сомнительна.
Код:
func joinDB(src, dst string) error {
srcDb, err := bolt.Open(src, 0600, nil)
if err != nil {
return err
}
defer srcDb.Close()
dstDb, err := bolt.Open(dst, 0600, nil)
if err != nil {
return err
}
defer dstDb.Close()
srcDb.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("Bitcoin"))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
dstDb.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("Bitcoin"))
err := b.Put(k, v)
return err
})
}
return nil
})
return nil
}
Ну и всё, собственно. Запускаем демон bitcoind с ресканом и построением индексов по транзам, запускаем нашу лотерею и, желательно, забываем о ней. Возможно, через какое-то время будет очень приятный сюрприз. В любом случае, затрат никаких, кроме электроэнергии, да и чем чёрт не шутит.
P.S. Предугадывая главный вопрос, отвечаю сразу - нет, больше коллизий не найдено. Пока не найдено
Автор: corax