還記得我們創(chuàng)建比特幣錢包時的場景嗎?其中有一步操作,要求我們拿出紙筆,把屏幕上出現(xiàn)的一系列單詞(有時稱助記符,有的軟件叫Seed Words)按順序抄在紙張上,并提示我們保管好,因為這些單詞是恢復(fù)錢包的唯一手段。
如果你對比特幣有一定的了解,當(dāng)你在看到這些助記符時肯定會產(chǎn)生疑惑,因為通常人們理解的是:只有私鑰才需要保管,且只有私鑰才能恢復(fù)錢包,但創(chuàng)建錢包時并沒有要求你保存私鑰,而是記錄一些助記符,那么我們很容易的做出推斷——私鑰和助記符之間一定有著某種聯(lián)系。
我和助記符的故事
那為了驗證這種聯(lián)系,在沒有搞清楚助記符背后的邏輯之前,通常的做法是驗證這些助記符是否能像私鑰一樣恢復(fù)錢包
很多人一開始應(yīng)該和我一樣,很少考慮錢包的事情,然后把代幣都托管在交易所的錢包上,但9月4日之后,我開始陸續(xù)把資產(chǎn)轉(zhuǎn)移到自己的錢包,記得第一次使用比特幣錢包,我先轉(zhuǎn)了一筆價值不到100元的比特幣到錢包上,然后在錢包上把這個賬號刪掉,接著使用助記符恢復(fù)這個錢包,在確認(rèn)能夠恢復(fù)后,才放心的把剩余代幣轉(zhuǎn)移過去。
我還記得當(dāng)初花了2個小時來折騰這個事兒,因為我使用的是trezor錢包,trezor在恢復(fù)時會故意打亂助記符的順序,由于忽視了這一點,導(dǎo)致多浪費了不少時間。實際上,如果你理解了助記符的原理,你完全不需要再花時間來反復(fù)驗證了。
種子
那么助記符到底是怎么回事呢,在介紹助記符之前,我們要先說一個概念——種子(Seed),實際上比特幣錢包往往不會直接保存私鑰,而是保存一個“種子”(Seed)數(shù)據(jù),步驟大致如下:
- 產(chǎn)生種子數(shù)據(jù)
- 用種子算出一個賬號數(shù)據(jù)
- 通過這個賬號,可以產(chǎn)生無數(shù)個私鑰
其中從第1步到第2步,只要種子不變,通過種子算出的賬號也是不變的。
而第3步中,你可以給每個產(chǎn)生的私鑰分配一個序號,例如0、1、2等,只要序號確定,那么私鑰的數(shù)值就是一定的。這也是為什么我們可以在錢包里創(chuàng)建多個賬號的原因,這么多賬號雖然都各自擁有一對公、私鑰,但我們只需要一個種子,就可以把它們?nèi)炕謴?fù),你說是不是很神奇,保存種子比直接保存私鑰效率要高很多。
下面我們通過一個程序(bitcoin explorer是一個比特幣命令行工具)來觀察一下整個過程(符號 '#' 右邊的文字是我的解釋):
- 產(chǎn)生種子數(shù)據(jù)
$ bx seed
00654f0bbd1721b75bbe54e29fdbf755523ab435708336ad
- 產(chǎn)生account數(shù)據(jù),你可以把這一步重復(fù)多次,然后會觀察到產(chǎn)生的結(jié)果是一樣的
# 產(chǎn)生master數(shù)據(jù)
$ bx hd-new 00654f0bbd1721b75bbe54e29fdbf755523ab435708336ad
xprv9s21ZrQH143K4VHVZmdpHhfRKmZ4fnySJBpNaSpkC7UfA3wNiMzN714ga5BSqXhdGDJCaMvW5Ww176mnuTsB4pFurk2fNrnsNhYS4igVrkS
# 產(chǎn)生account數(shù)據(jù)
$ bx hd-private --hard xprv9s21ZrQH143K4VHVZmdpHhfRKmZ4fnySJBpNaSpkC7UfA3wNiMzN714ga5BSqXhdGDJCaMvW5Ww176mnuTsB4pFurk2fNrnsNhYS4igVrkS
xprv9uUeTjMk9f3C2u7sEUzBqtWWJ9AekeHAy1pfjq5X19nKW5qqyiUr5LBHp87bHSyNSMRT9ehaBP4H5A21AVSzFhjiqvxbDMfTQfhYD6Hh3xV
- 通過account數(shù)據(jù),你就可以按照序號來產(chǎn)生私鑰了,同樣你也可以多試幾次,并觀察同樣的序號,產(chǎn)生的私鑰是否是一致的
# 序號0
$ bx hd-private --index 0 xprv9uUeTjMk9f3C2u7sEUzBqtWWJ9AekeHAy1pfjq5X19nKW5qqyiUr5LBHp87bHSyNSMRT9ehaBP4H5A21AVSzFhjiqvxbDMfTQfhYD6Hh3xV
xprv9xcBDpHwSSEXHBCMqTcMSGooQjLgYKXxkMN9cdVWV9HJKVBzgMhk1kXy1WdsfG9FT1SzATjAPguZjGj6LoBhLBd7tyKz2EA2xixX6uxAuVN
# 序號1
$ bx hd-private --index 1 xprv9uUeTjMk9f3C2u7sEUzBqtWWJ9AekeHAy1pfjq5X19nKW5qqyiUr5LBHp87bHSyNSMRT9ehaBP4H5A21AVSzFhjiqvxbDMfTQfhYD6Hh3xV
xprv9xcBDpHwSSEXLjzaSkjq8khKHKR1BsXHWVZhz14VNZsM5eWyjYVwhwsjnLHJaHXD4EXrTSM1N3JzWJU8jqNrmF4sdpFiTEGsh1MkNUR6TUy
助記符
現(xiàn)在你再知道錢包是如何保存私鑰了的吧,但這還沒完,設(shè)想一個場景,在助記符出現(xiàn)之前,我們要備份賬號就一定要記下種子,而你也看到了,種子是一串長長的字符串,它沒有任何意義,人們在記錄它的時候會很容易出錯,助記符就是為了解決這個問題而生的。
從整個產(chǎn)生私鑰的過程來說,要引入了更容易記錄的助記符,只需調(diào)整一下種子的生成過程:
讓種子的生成算法僅依賴于助記符
通過示意圖,可以看到所做的調(diào)整是:用算法生成助記符,再通過助記符產(chǎn)生種子,后面的步驟保持不變。
下面我們再用命令來演示下如何產(chǎn)生助記符,及它是如何產(chǎn)生種子的
# 創(chuàng)建一個用來生成助記符的種子
$ bx seed
b03e3cf733130570068147160b80a117078ed3c9459dc2d2
# 創(chuàng)建助記符
$ bx mnemonic-new b03e3cf733130570068147160b80a117078ed3c9459dc2d2
rabbit vehicle differ great core retreat borrow cigar bid foster choose come jump hazard celery recipe security motion
# 通過助記符創(chuàng)建一個用來生成私鑰的種子
$ bx mnemonic-to-seed rabbit vehicle differ great core retreat borrow cigar bid foster choose come jump hazard celery recipe security motion
488e65727e3bf0440cee45863961828a2de2963c14e2124740c6e18d5c0c61a7c661760aa8fc82141af5c023e69a997d88ef1f1204eeef9e90e323dc76cfcdc6
同樣的,對于相同的助記符,你可以多執(zhí)行幾次bx mnemonic-to-seed
命令,看看產(chǎn)生的種子是否都是一致的,可以推斷,恢復(fù)錢包的過程就是從這條命令開始的。
最后,如果你有一定的編程基礎(chǔ),建議你去閱讀一下Bitcoin Explorer的源碼(這套代碼的組織結(jié)構(gòu)非常清晰),可以更深入的理解背后的密碼學(xué)原理。