如何從私鑰中獲取比特幣公鑰
極其具體地,我如何將給定的私人比特幣密鑰轉換為公共比特幣密鑰(像我 5 歲一樣跟我說話,我必須一步一步地做這個,否則邪惡的女巫會在她的烤箱裡把我活活煮熟)。不是我在哪裡可以找到一個可以做到這一點的程序,但如果我自己做,我會怎麼做?
私鑰:
18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725
據說會導致公鑰:
0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
其他人問如何私有化,我還沒有看到一個真正具體的答案,只是更一般的方向,但沒有答案解釋所有變數。我知道這是相當複雜的,如果某個特定的人認為它的工作量太大而無法回答,我完全尊重這一點。注意:我不關心比特幣地址,只對 Privatekey to Publickey 和具體方法感興趣。
ECDSA 曲線算法中的“a”和“b”等變數已經由比特幣指定(根據<https://en.bitcoin.it/wiki/Secp256k1>)。該頁面上還指定了“基點”又名“G”。“私人指數”或“k”,我還沒有找到。其中一些變數被認為是“隨機的”,這似乎是錯誤的,因為您可以將私鑰放入的每個生成器似乎總是吐出相同的公鑰……所以……所有變數要麼已經預設,要麼是從私鑰派生的。
感謝您對此的任何幫助。幾天來我一直在嘗試研究和理解這一點,但有時我似乎不理解這些術語和或符號,但我認為我已經超越了這一點,現在只是缺少了等式的一部分。
編輯添加:
這是先前在十進制中聲明的私鑰:
11253563012059685825953619222107823549092147699031672238385790369351542642469
這是先前聲明的十進制公鑰(x 和 y 值):
36422191471907241029883925342251831624200921388586025344128047678873736520530 20277110887056303803699431755396003735040374760118964734768299847012543114150
我只想知道如何從該私鑰轉到公鑰。假設它是一個簡單的方程,不涉及位移或異或等。它可能包括“點乘法”(我不知道如何將定義為同時具有 x 和 ay 的點相乘)。似乎沒有人理解其中的複雜性。你們是否建議我實際上向任何解釋清楚的人提供比特幣的一部分?
我將嘗試以不同的方式再次回答這個問題,使用小數字來保持可讀性。
- 將私鑰轉換為二進製表示,因此十進制數 105,即十六進制的 0x69,變為 01101001。
- 通過將生成器點 G 重複加倍來計算此點列表:
1*G 2*G = G+G 4*G = 2*G + 2*G 8*G = 4*G + 4*G 16*G = 8*G + 8*G 32*G = 16*G + 16*G 64*G = 32*G + 32*G
- 在這個列表旁邊寫下私鑰的位,如下所示:
privkey pointlist 1 1*G 0 2*G 0 4*G 1 8*G 0 16*G 1 32*G 1 64*G
- 現在開始只添加那些
1
旁邊寫著的點。9*G = 1*G + 8*G 41*G = (9+32)*G = 9*G + 32*G 105*G = (41+64)*G = 41*G + 64*G
- 現在您已經計算了私鑰 105 的公鑰,只使用了點加倍和點加操作。
實際值將是:
(0xf219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63, 0x4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1)
公鑰將採用以下兩種格式之一:
- full,這是一個 65 字節的數字,以一個字節開頭
0x04
- 壓縮,這是一個較短的格式,33 個字節,從 0x02 或 0x03 開始。
完整的公鑰是 0x04,後跟 32 個字節的 x 座標,然後是 32 個字節的 y 座標。
壓縮後的公鑰是 0x02 還是 0x03,具體取決於 y 座標是偶數還是奇數,後跟 32 個字節的 x 座標。
然後對您的問題進行更多說明:
這是一個執行轉換的獨立 Python 腳本。您可以通過比較在Brainwallet輸入您的私鑰作為“秘密指數”來檢查它的工作。我從這個 Bitcointalk 執行緒中提取了腳本並刪除了不必要的東西(例如使用公鑰簽署消息並驗證該簽名的程式碼)。
將 Python 轉換為人類指令作為練習留給讀者(儘管我認為在這種 Python 程式碼的場景中,具有適當的文件,作為人類指令就可以了)。請注意,完全可以用筆和紙來計算,但這可能需要一段時間,而且由於必須處理如此龐大的數字,您可能會犯錯誤。
另請注意,這裡沒有比您在小學/小學學到的複雜得多的單個操作。有基本的比較
< > ==
、算術+ - *
、除法,您關心的是商/
、餘數%
或兩者divmod
,還有按位 AND (&
,如果您使用十六進制工作,這很容易;或者可以用算術複製)。我不認為一個(非天才)5 歲的孩子真的能做到(對不起,邪惡的女巫贏了這一輪),但我認為一個有足夠耐心的普通成年人幾乎可以很快學會所需的數學(用Python 腳本作為..well.. 腳本,後面跟著)。然而,實際上即使在沒有電子計算設備的幫助下計算一個公鑰也可能需要很長時間(猜測:數年)。
#! /usr/bin/env python # python 2.x class CurveFp( object ): def __init__( self, p, a, b ): self.__p = p self.__a = a self.__b = b def p( self ): return self.__p def a( self ): return self.__a def b( self ): return self.__b def contains_point( self, x, y ): return ( y * y - ( x * x * x + self.__a * x + self.__b ) ) % self.__p == 0 class Point( object ): def __init__( self, curve, x, y, order = None ): self.__curve = curve self.__x = x self.__y = y self.__order = order if self.__curve: assert self.__curve.contains_point( x, y ) if order: assert self * order == INFINITY def __add__( self, other ): if other == INFINITY: return self if self == INFINITY: return other assert self.__curve == other.__curve if self.__x == other.__x: if ( self.__y + other.__y ) % self.__curve.p() == 0: return INFINITY else: return self.double() p = self.__curve.p() l = ( ( other.__y - self.__y ) * \ inverse_mod( other.__x - self.__x, p ) ) % p x3 = ( l * l - self.__x - other.__x ) % p y3 = ( l * ( self.__x - x3 ) - self.__y ) % p return Point( self.__curve, x3, y3 ) def __mul__( self, other ): def leftmost_bit( x ): assert x > 0 result = 1L while result <= x: result = 2 * result return result / 2 e = other if self.__order: e = e % self.__order if e == 0: return INFINITY if self == INFINITY: return INFINITY assert e > 0 e3 = 3 * e negative_self = Point( self.__curve, self.__x, -self.__y, self.__order ) i = leftmost_bit( e3 ) / 2 result = self while i > 1: result = result.double() if ( e3 & i ) != 0 and ( e & i ) == 0: result = result + self if ( e3 & i ) == 0 and ( e & i ) != 0: result = result + negative_self i = i / 2 return result def __rmul__( self, other ): return self * other def __str__( self ): if self == INFINITY: return "infinity" return "(%d,%d)" % ( self.__x, self.__y ) def double( self ): if self == INFINITY: return INFINITY p = self.__curve.p() a = self.__curve.a() l = ( ( 3 * self.__x * self.__x + a ) * \ inverse_mod( 2 * self.__y, p ) ) % p x3 = ( l * l - 2 * self.__x ) % p y3 = ( l * ( self.__x - x3 ) - self.__y ) % p return Point( self.__curve, x3, y3 ) def x( self ): return self.__x def y( self ): return self.__y def curve( self ): return self.__curve def order( self ): return self.__order INFINITY = Point( None, None, None ) def inverse_mod( a, m ): if a < 0 or m <= a: a = a % m c, d = a, m uc, vc, ud, vd = 1, 0, 0, 1 while c != 0: q, c, d = divmod( d, c ) + ( c, ) uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc assert d == 1 if ud > 0: return ud else: return ud + m # secp256k1 _p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL _r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L _b = 0x0000000000000000000000000000000000000000000000000000000000000007L _a = 0x0000000000000000000000000000000000000000000000000000000000000000L _Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L _Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L class Public_key( object ): def __init__( self, generator, point ): self.curve = generator.curve() self.generator = generator self.point = point n = generator.order() if not n: raise RuntimeError, "Generator point must have order." if not n * point == INFINITY: raise RuntimeError, "Generator point order is bad." if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y(): raise RuntimeError, "Generator point has x or y out of range." curve_256 = CurveFp( _p, _a, _b ) generator_256 = Point( curve_256, _Gx, _Gy, _r ) g = generator_256 if __name__ == "__main__": print '=======================================================================' ### set privkey # wiki #secret = 0xE9873D79C6D87DC0FB6A5778633389F4453213303DA61F20BD67FC233AA33262L # question secret = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725L ### print privkey print 'secret', hex(secret) ### generate pubkey pubkey = Public_key( g, g * secret ) ### print pubkey print 'pubkey', hex(pubkey.point.x()), hex(pubkey.point.y()) print '======================================================================='
另請參閱用 C# 編寫的更加精簡的版本。
class CalcPub { public static void Main() { var p = BigInteger.Parse("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", NumberStyles.HexNumber); var b = (BigInteger)7; var a = BigInteger.Zero; var Gx = BigInteger.Parse("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", NumberStyles.HexNumber); var Gy = BigInteger.Parse("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", NumberStyles.HexNumber); CurveFp curve256 = new CurveFp(p, a, b); Point generator256 = new Point(curve256, Gx, Gy); var secret = BigInteger.Parse("18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725", NumberStyles.HexNumber); Console.WriteLine("secret {0}", secret.ToString("X")); var pubkeyPoint = generator256 * secret; Console.WriteLine("pubkey {0}{1}", pubkeyPoint.X.ToString("X"), pubkeyPoint.Y.ToString("X")); } } class Point { public static readonly Point INFINITY = new Point(null, default(BigInteger), default(BigInteger)); public CurveFp Curve { get; private set; } public BigInteger X { get; private set; } public BigInteger Y { get; private set; } public Point(CurveFp curve, BigInteger x, BigInteger y) { this.Curve = curve; this.X = x; this.Y = y; } public Point Double() { if (this == INFINITY) return INFINITY; BigInteger p = this.Curve.p; BigInteger a = this.Curve.a; BigInteger l = ((3 * this.X * this.X + a) * InverseMod(2 * this.Y, p)) % p; BigInteger x3 = (l * l - 2 * this.X) % p; BigInteger y3 = (l * (this.X - x3) - this.Y) % p; return new Point(this.Curve, x3, y3); } public override string ToString() { if (this == INFINITY) return "infinity"; return string.Format("({0},{1})", this.X, this.Y); } public static Point operator +(Point left, Point right) { if (right == INFINITY) return left; if (left == INFINITY) return right; if (left.X == right.X) { if ((left.Y + right.Y) % left.Curve.p == 0) return INFINITY; else return left.Double(); } var p = left.Curve.p; var l = ((right.Y - left.Y) * InverseMod(right.X - left.X, p)) % p; var x3 = (l * l - left.X - right.X) % p; var y3 = (l * (left.X - x3) - left.Y) % p; return new Point(left.Curve, x3, y3); } public static Point operator *(Point left, BigInteger right) { var e = right; if (e == 0 || left == INFINITY) return INFINITY; var e3 = 3 * e; var negativeLeft = new Point(left.Curve, left.X, -left.Y); var i = LeftmostBit(e3) / 2; var result = left; while (i > 1) { result = result.Double(); if ((e3 & i) != 0 && (e & i) == 0) result += left; if ((e3 & i) == 0 && (e & i) != 0) result += negativeLeft; i /= 2; } return result; } private static BigInteger LeftmostBit(BigInteger x) { BigInteger result = 1; while (result <= x) result = 2 * result; return result / 2; } private static BigInteger InverseMod(BigInteger a, BigInteger m) { while (a < 0) a += m; if (a < 0 || m <= a) a = a % m; BigInteger c = a; BigInteger d = m; BigInteger uc = 1; BigInteger vc = 0; BigInteger ud = 0; BigInteger vd = 1; while (c != 0) { BigInteger r; //q, c, d = divmod( d, c ) + ( c, ); var q = BigInteger.DivRem(d, c, out r); d = c; c = r; //uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc; var uct = uc; var vct = vc; var udt = ud; var vdt = vd; uc = udt - q * uct; vc = vdt - q * vct; ud = uct; vd = vct; } if (ud > 0) return ud; else return ud + m; } } class CurveFp { public BigInteger p { get; private set; } public BigInteger a { get; private set; } public BigInteger b { get; private set; } public CurveFp(BigInteger p, BigInteger a, BigInteger b) { this.p = p; this.a = a; this.b = b; } }