å
容
- Goã®ãããã¯ãã§ãŒã³ã ããŒã1ïŒãããã¿ã€ã
- Goã®ãããã¯ãã§ãŒã³ã ããŒã2ïŒäœæ¥èšŒæ
- Goã®ãããã¯ãã§ãŒã³ã ããŒã3ïŒèªã¿åãå°çšã¡ã¢ãªãšã³ãã³ãã©ã€ã³ã€ã³ã¿ãŒãã§ã€ã¹
- Goã®ãããã¯ãã§ãŒã³ã ããŒã4ïŒãã©ã³ã¶ã¯ã·ã§ã³ãããŒã1
- Goã®ãããã¯ãã§ãŒã³ã ããŒã5ïŒã¢ãã¬ã¹
- Goã®ãããã¯ãã§ãŒã³ã ããŒã6ïŒãã©ã³ã¶ã¯ã·ã§ã³ãããŒã2
- Goã®ãããã¯ãã§ãŒã³ã ããŒã7ïŒãããã¯ãŒã¯
ãšã³ããªãŒ
åã®èšäºã§ããã©ã³ã¶ã¯ã·ã§ã³ã®å®è£
ãéå§ãããã®æäœã®åçã«ã粟éããŸããïŒã¢ã«ãŠã³ãããªããå人ããŒã¿ïŒååãã·ãªãŒãºããã¹ããŒãçªå·ãªã©ïŒã¯äžèŠã§ããããã³ã€ã³ã®ã©ãã«ãä¿åãããŸããã ããããããã§ãããã©ã³ã¶ã¯ã·ã§ã³ã®åºåã®ææè
ïŒã€ãŸããåºåã§ãããã¯ãããã³ã€ã³ã®ææè
ïŒãšããŠããªããèå¥ãããã®ããªããã°ãªããŸããã ãããŠãããããããã³ã€ã³ã¢ãã¬ã¹ã®ç®çã§ãã ãããŸã§ãä»»æã®æååãã¢ãã¬ã¹ãšããŠäœ¿çšããŠããŸããããä»åºŠã¯ãããã³ã€ã³ã§ã®å®è£
æ¹æ³ã§å®éã®ã¢ãã¬ã¹ãå®è£
ããŸãã
ãã®ããŒãã§ã¯ãå€ãã®ã³ãŒããå€æŽããããããã¹ãŠã詳现ã«èª¬æããçç±ã¯ãããŸããã
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããŠã以åã®èšäºãšæ¯èŒãããã¹ãŠã®å€æŽã確èªããŠãã ããã
ãããã³ã€ã³ã¢ãã¬ã¹
ãããã³ã€ã³ã¢ãã¬ã¹ã®äŸã次ã«ç€ºããŸãïŒ
1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa ã ããã¯ãããããäžæ¬Sã«å±ãããããã³ã€ã³ã®æåã®ã¢ãã¬ã¹ã§ãã ãããã³ã€ã³ã®ã¢ãã¬ã¹ã¯å
¬éãããŠããŸãã 誰ãã«ã³ã€ã³ãéãããå Žåã¯ãåå人ã®äœæãç¥ãå¿
èŠããããŸãã ããããã¢ãã¬ã¹ã¯ïŒäžææ§ã«ããããããïŒããŠã©ã¬ãããã®ææè
ãšããŠã®ããªãã®èå¥åã§ã¯ãããŸããã å®éããã®ãããªã¢ãã¬ã¹ã¯å
¬ééµã§ãã ãããã³ã€ã³ã§ã¯ãããªãã®èº«å
ã¯ãã³ã³ãã¥ãŒã¿ãŒïŒãŸãã¯ã¢ã¯ã»ã¹ã§ããä»ã®å ŽæïŒã«ä¿åãããŠããç§å¯ããŒãšå
¬éããŒã®ãã¢ã§ãã ãã®ãããªããŒãäœæããã«ã¯ãæå·åã¢ã«ãŽãªãºã ã䜿çšããŠãããŒã«ç©ççã«ã¢ã¯ã»ã¹ããªãéãã誰ãã³ã€ã³ã«ã¢ã¯ã»ã¹ã§ããªãããã«ããŸãã ãããã®ã¢ã«ãŽãªãºã ãäœã§ããããèŠãŠã¿ãŸãããã
å
¬ééµæå·ã·ã¹ãã
å
¬ééµæå·ã·ã¹ãã ã¯ãå
¬ééµãšç§å¯éµã®ãã¢ã䜿çšããŸãã å
¬ééµã¯èª°ãšã§ãå
±æã§ããŸãã å察ã«ãç§å¯éµã¯èª°ã«ãé瀺ãããã¹ãã§ã¯ãããŸãããææè
以å€ã®èª°ãã¢ã¯ã»ã¹ããã¹ãã§ã¯ãããŸããããããã¯ææè
ã®èå¥åãšããŠæ©èœããç§å¯éµã ããã§ãã ããªãã®é¡ã¯ããªãã®ç§å¯éµã§ãïŒãã¡ãããæå·é貚ã®äžçã§ã¯ïŒã
æ¬è³ªçã«ããããã³ã€ã³ãŠã©ã¬ããã¯ãã®ãããªããŒã®ãã¢ã§ãã ãŠã©ã¬ããã¢ããªã±ãŒã·ã§ã³ãã€ã³ã¹ããŒã«ããããBitcoinã¯ã©ã€ã¢ã³ãã䜿çšããŠæ°ããã¢ãã¬ã¹ãäœæãããšãããŒãã¢ãçæãããŸãã ç§å¯éµãå¶åŸ¡ããè
ã¯ãéä¿¡ããããã¹ãŠã®ã³ã€ã³ãå¶åŸ¡ããŸãã
ç§å¯éµãšå
¬ééµã¯åçŽã«ã©ã³ãã ãªãã€ãã·ãŒã±ã³ã¹ã§ãããããç»é¢ã«å°å·ããŠäººãèªãããšã¯ã§ããŸããã ããããBitcoinãã¢ã«ãŽãªãºã ã䜿çšããŠå
¬éããŒã人éãèªã¿åããæååã«å€æããçç±ã§ãã
BitcoinãŠã©ã¬ãããã¢ããªã±ãŒã·ã§ã³ãšããŠäœ¿çšããããšãããå Žåã¯ãããããããŒã¢ããã¯ãã¬ãŒãºãäœæãããŠããŸãã ãã®ãããªãã¬ãŒãºã¯ãç§å¯éµã®ä»£ããã«äœ¿çšãããããããçæããããã«äœ¿çšã§ããŸãã ãã®ã¡ã«ããºã ã¯BIP-039ã§å®è£
ãããŠããŸãã
ããã§ããããã³ã€ã³ã§ãŠãŒã¶ãŒãèå¥ãããã®ãããããŸããã ããããBitcoinã¯ãã©ã³ã¶ã¯ã·ã§ã³åºå£ïŒããã³ããã«ä¿åãããŠããã³ã€ã³ïŒã®ææè
ãã©ã®ããã«ç¢ºèªããŸããïŒ
é»åããžã¿ã«çœ²å
æ°åŠãšæå·åã«ã¯ãé»åããžã¿ã«çœ²åã®æŠå¿µããããŸã-ä¿èšŒããã¢ã«ãŽãªãºã ïŒ
- éä¿¡è
ããåä¿¡è
ãžã®éä¿¡äžã«ããŒã¿ãå€æŽãããŠããªãããšã
- ããŒã¿ãç¹å®ã®éä¿¡è
ã«ãã£ãŠäœæãããããšã
- éä¿¡è
ãããŒã¿ãéä¿¡ããããšãåŠå®ã§ããªãããšã
é»åããžã¿ã«çœ²åã¢ã«ãŽãªãºã ãããŒã¿ã«é©çšïŒã€ãŸããããŒã¿ã«çœ²åïŒãããšãåŸã§æ€èšŒã§ãã眲åãååŸãããŸãã ããŒã¿ã¯ç§å¯éµã䜿çšããŠçœ²åãããæ€èšŒã«ã¯å
¬ééµãå¿
èŠã§ãã
ããŒã¿ã«çœ²åããã«ã¯ã次ã®ãã®ãå¿
èŠã§ãã
- 眲åçšã®ããŒã¿ã
- ç§å¯éµã
ã¢ã«ãŽãªãºã ã¯ããã©ã³ã¶ã¯ã·ã§ã³å
¥åã«ä¿åããã眲åãäœæããŸãã 眲åã確èªããã«ã¯ã次ã®ãã®ãå¿
èŠã§ãã
- 眲åãããããŒã¿ã
- 眲å
- å
¬ééµã
ç°¡åã«èšãã°ãæ€èšŒããã»ã¹ã¯æ¬¡ã®ããã«èª¬æã§ããŸããå
¬éããŒã®çæã«äœ¿çšãããç§å¯ããŒã䜿çšããŠããã®ããŒã¿ãã眲åãååŸãããããšã確èªããå¿
èŠããããŸãã
ããžã¿ã«çœ²åã¯æå·åãããŠããããããŒã¿ãååŸã§ããŸããã ããã¯ããã·ã¥ã®ãããªãã®ã§ããã¢ã«ãŽãªãºã ã䜿çšããŠããŒã¿ãå€æãããã®äžæã®è¡šçŸãååŸããŸãã ããã·ã¥ãšçœ²åã®éãã¯ãåŸè
ãæ€èšŒã§ããããŒãã¢ã§ãã
ãã ãããã®ãããªããŒãã¢ã¯ããŒã¿ã®æå·åã«ã䜿çšã§ããŸããç§å¯ããŒã¯æå·åã«äœ¿çšãããå
¬éããŒã¯åŸ©å·åã«äœ¿çšãããŸãã ãã ãããããã³ã€ã³ã¯æå·åã¢ã«ãŽãªãºã ã䜿çšããŸããã
ãããã³ã€ã³ã®åãã©ã³ã¶ã¯ã·ã§ã³ãšã³ããªã¯ããã®ãã©ã³ã¶ã¯ã·ã§ã³ãäœæãã人ã«ãã£ãŠçœ²åãããŸãã ãããã³ã€ã³ã®ãã¹ãŠã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ããããã¯ã«é
眮ããåã«æ€èšŒããå¿
èŠããããŸãã æ€èšŒæ段ïŒä»ã®æé ã®äžã§ïŒïŒ
- å
¥åã«ã以åã®ãã©ã³ã¶ã¯ã·ã§ã³ããã®åºåã䜿çšããããã®ååãªæš©éãããããšã確èªããŸãã
- ãã©ã³ã¶ã¯ã·ã§ã³ã®çœ²åã®æ€èšŒã
æŠç¥çã«ãããŒã¿ã®çœ²åãšæ€èšŒã®ããã»ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
å®å
šãªãã©ã³ã¶ã¯ã·ã§ã³ã©ã€ããµã€ã¯ã«ãèŠãŠã¿ãŸãããã
- åœåã¯ãã³ã€ã³ããŒã¹ãã©ã³ã¶ã¯ã·ã§ã³ã䌎ããžã§ãã·ã¹ãããã¯ããããŸãã coinbaseãã©ã³ã¶ã¯ã·ã§ã³ã«ã¯å®éã®å
¥åããªãããã眲åã¯äžèŠã§ãã ãã©ã³ã¶ã¯ã·ã§ã³åºåã«ã¯ãããã·ã¥ãããå
¬éããŒãå«ãŸããŸãïŒ
RIPEMD16(SHA256(PubKey))
ã¢ã«ãŽãªãºã ã䜿çšãããŸãRIPEMD16(SHA256(PubKey))
ïŒã - 誰ããã³ã€ã³ãéä¿¡ãããšããã©ã³ã¶ã¯ã·ã§ã³ãäœæãããŸãã ãã©ã³ã¶ã¯ã·ã§ã³å
¥åã¯ã以åã®ãã©ã³ã¶ã¯ã·ã§ã³ã®çµäºãåç
§ããŸãã åãšã³ããªã«ã¯ãå
¬éããŒïŒããã·ã¥ãããŠããªãïŒãšãã©ã³ã¶ã¯ã·ã§ã³å
šäœã®çœ²åãæ ŒçŽãããŸãã
- ãã©ã³ã¶ã¯ã·ã§ã³ãåä¿¡ãããããã³ã€ã³ãããã¯ãŒã¯å
ã®ä»ã®ããŒããæ€èšŒããŸãã ãšããããããã¯ããã©ã³ã¶ã¯ã·ã§ã³ã®å
¥åã§ã®å
¬éããŒã®ããã·ã¥ã察å¿ããåºåã®ããã·ã¥ãšæ¯èŒããŸãïŒããã«ãããéä¿¡è
ã¯èªåã«å±ããã³ã€ã³ã®ã¿ã䜿ãããšãä¿èšŒãããŸãïŒã 眲åãæ£ããïŒããã«ãããã³ã€ã³ã®å®éã®ææè
ã«ãã£ãŠãã©ã³ã¶ã¯ã·ã§ã³ãäœæãããŸãïŒã
- ããŒããæ°ãããããã¯ããã€ãã³ã°ããæºåãã§ãããšããããã¯ã«ãã©ã³ã¶ã¯ã·ã§ã³ãé
眮ãããã€ãã³ã°ãéå§ããŸãã
- ãããã¯ããã€ãã³ã°ããããšããããã¯ãŒã¯å
ã®ä»ã®åããŒãã¯ããããã¯ããã€ãã³ã°ããããšããã¡ãã»ãŒãžãåä¿¡ãããããåç·ã«è¿œå ããŸãã
- ãããã¯ããã§ãŒã³ã«è¿œå ããããšããã©ã³ã¶ã¯ã·ã§ã³ãå®äºãããã®åºåãæ°ãããã©ã³ã¶ã¯ã·ã§ã³ã§åç
§ã§ããããã«ãªããŸãã
æ¥åæå·
ãã§ã«è¿°ã¹ãããã«ãå
¬éããŒãšç§å¯ããŒã¯ã©ã³ãã ãã€ãã®ã·ãŒã±ã³ã¹ã§ãã ä»ã®èª°ãã«å±ããç§å¯éµãçæããããªããããã·ãŒã±ã³ã¹ãçæããããã®ç¹å¥ãªã¢ã«ãŽãªãºã ãå¿
èŠã§ãã
ãããã³ã€ã³ã¯æ¥åæ²ç·ã䜿çšããŠç§å¯éµãçæããŸãã æ¥åæ²ç·ã¯è€éãªæ°åŠçæŠå¿µã§ãããããã§ã¯è©³çŽ°ã«èª¬æããŸããïŒèå³ãããå Žåã¯ã
ããã§ããã«ã€ããŠèªãããšãã§ã
ãŸãã èŠå ïŒå€ãã®æ°åŠïŒïŒã Bitcoinã䜿çšããæ²ç·ã¯ã0ã2²randomlyã®æ°åãã©ã³ãã ã«éžæã§ããŸãïŒããã¯ãçŽ10 isã§ãã泚æããŠãã ãããç®ã«èŠããå®å®ã®ååã¯10â·âžã10âžÂ²ã®éã§ãïŒã ãã®ãããªå¶éã¯ãåãç§å¯éµã2åçæããããšã¯
ã»ãšãã©äžå¯èœã§ããããšãæå³ããŸãã
ããã«ããããã³ã€ã³ã¯ãã©ã³ã¶ã¯ã·ã§ã³ã«çœ²åããããã«
ECDSAã¢ã«ãŽãªãºã ã䜿çšããŸãã
ããŒã¹58
ããã§ã¯ãäžèšã®ã¢ãã¬ã¹1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNaã«æ»ããŸãããã ããã¯ããããäžè¬ã«åãå
¥ããããŠããå人ã®å
¬éããŒã®è¡šçŸã§ããããšãç¥ã£ãŠããŸãã ãããŠããã³ãŒããããšã次ã®ããã«ãªããŸãïŒ16é²æ°ã·ã¹ãã ã§æžã蟌ãŸãããã€ãã·ãŒã±ã³ã¹ã®ããã«ïŒã
0062E907B15CBF27D5425399EBF6F0FB50EBB88F18C29B7D93
ãããã³ã€ã³ã¯Base58ã¢ã«ãŽãªãºã ã䜿çšããŠãå
¬éããŒã人éãèªã¿åãã圢åŒã«å€æããŸãã ãã®ã¢ã«ãŽãªãºã ã¯ãããç¥ãããŠããBase64ãšéåžžã«ãã䌌ãŠããŸãããçãã¢ã«ãã¡ãããã䜿çšããŠããŸãã
ãã¢ã°ã©ãã£æ»æãé¿ããããã«ãã¢ã«ãã¡ãããããäžéšã®æåãåé€ãããŠããŸãã ãã®ç¹ã«é¢ããŠããã®ã¢ã«ãã¡ãããã«ã¯æ¬¡ã®æåãå«ãŸããŠããŸããïŒ0ïŒãŒãïŒãOïŒå€§æåã® "o"ïŒãIïŒå€§æåã® "i"ïŒãlïŒå°æåã® "L"ïŒãããã³èšå· "+"ããã³ "/ ã
å
¬ééµããã¢ãã¬ã¹ãååŸããããã»ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
ãã®ã¹ããŒã ã«åŸã£ãŠãäžèšã§æ瀺ããããŒã¯3ã€ã®éšåã«åå²ãããŸãã
Version 00 Public key hash 62E907B15CBF27D5425399EBF6F0FB50EBB88F18 Checksum C29B7D93
ããŠããã¹ãŠããŸãšããã®ã§ã次ã¯ã³ãŒããäœæããŸãã ç解ã§ããªãã£ãããšããã¹ãŠæããã«ãªãããšãé¡ã£ãŠããŸãã
ã¢ãã¬ã¹å®è£
ãŠã©ã¬ããã®ãŠã©ã¬ããæ§é ããå§ããŸãããã
type Wallet struct { PrivateKey ecdsa.PrivateKey PublicKey []byte } type Wallets struct { Wallets map[string]*Wallet } func NewWallet() *Wallet { private, public := newKeyPair() wallet := Wallet{private, public} return &wallet } func newKeyPair() (ecdsa.PrivateKey, []byte) { curve := elliptic.P256() private, err := ecdsa.GenerateKey(curve, rand.Reader) pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) return *private, pubKey }
ãŠã©ã¬ããã¯ãããŒã®ãã¢ã«ãããŸããã ãŠã©ã¬ããã®ã³ã¬ã¯ã·ã§ã³ãä¿åãããã¡ã€ã«ã«ä¿åããããããã¢ã³ããŒãããã«ã¯ã
Wallets
ã¿ã€ããå¿
èŠã§ãã
Wallet
ã³ã³ã¹ãã©ã¯ã¿ãŒã§æ°ããããŒãã¢ãäœæãã
Wallet
ã
newKeyPair
é¢æ°
newKeyPair
ç°¡åã§ããããã§ã¯ECDSAã䜿çšããŸãã 次ã«ãæ²ç·ã䜿çšããŠç§å¯éµãäœæãããç§å¯éµã䜿çšããŠå
¬ééµãçæãããŸãã 泚ïŒæ¥åæ²ç·ã¢ã«ãŽãªãºã ã§ã¯ãå
¬éããŒã¯æ²ç·äžã®ç¹ã§ãã ãããã£ãŠãå
¬éããŒã¯XãY座æšã®çµã¿åããã§ããããããã³ã€ã³ã§ã¯ããããã®åº§æšãçµã¿åããããŠå
¬éããŒã圢æãããŸãã
次ã«ãã¢ãã¬ã¹çæé¢æ°ãäœæããŸãã
func (w Wallet) GetAddress() []byte { pubKeyHash := HashPubKey(w.PublicKey) versionedPayload := append([]byte{version}, pubKeyHash...) checksum := checksum(versionedPayload) fullPayload := append(versionedPayload, checksum...) address := Base58Encode(fullPayload) return address } func HashPubKey(pubKey []byte) []byte { publicSHA256 := sha256.Sum256(pubKey) RIPEMD160Hasher := ripemd160.New() _, err := RIPEMD160Hasher.Write(publicSHA256[:]) publicRIPEMD160 := RIPEMD160Hasher.Sum(nil) return publicRIPEMD160 } func checksum(payload []byte) []byte { firstSHA := sha256.Sum256(payload) secondSHA := sha256.Sum256(firstSHA[:]) return secondSHA[:addressChecksumLen] }
å
¬ééµãBase58ã¢ãã¬ã¹ã«å€æããæé ãèŠãŠã¿ãŸãããã
- å
¬ééµã
RIPEMD160 (SHA256 (PubKey))
ããããã·ã¥ã¢ã«ãŽãªãºã RIPEMD160 (SHA256 (PubKey))
ã䜿çšããŠ2åRIPEMD160 (SHA256 (PubKey))
ãŸãã - ããŒãžã§ã³ãæºåããŸãã
- ã¹ããã2ã®çµæãš
SHA256 (SHA256 (payload))
ããã·ã¥ããããšã«ããããã§ãã¯ãµã ãèšç®ããŸãã ãã§ãã¯ãµã ã¯ãåä¿¡ããããã·ã¥ã®æåã®4ãã€ãã§ãã - ãã§ãã¯ãµã ã
version+PubKeyHash
ã®çµã¿åããã«è¿œå ããŸãã - çµã¿åãã
version+PubKeyHash+checksum
ãBase58ã§æå·åããŸãã
ãã®çµæã
å®éã®ãããã³ã€ã³ã¢ãã¬ã¹ãååŸãã
blockchain.infoã§æ®é«ã確èªããããšãã§ããŸãã ããããç§ã¯ãã®ã¢ãã¬ã¹ã®ã¢ã«ãŠã³ãã«ã¯äœããªãããšã確信ããŠããŸãã ãã®ãããé©åãªå
¬ééµæå·åã¢ã«ãŽãªãºã ãéžæããããšãéåžžã«éèŠã§ããç§å¯éµã¯ä¹±æ°ã§ãããããåãçªå·ãçæãããå¯èœæ§ã¯ã§ããã ãäœãããå¿
èŠããããŸãã çæ³çã«ã¯ããŸã£ããç¹°ãè¿ããªãã§ãã ããã
ã¢ãã¬ã¹ãåä¿¡ããããã«ãããã³ã€ã³ããŒãã«æ¥ç¶ããå¿
èŠããªãããšã«æ³šæããŠãã ããã ã¢ãã¬ã¹çæã¢ã«ãŽãªãºã ã¯ãäžè¬çãªããã°ã©ãã³ã°èšèªã®å€ãã®æšæºã©ã€ãã©ãªã«æ¢ã«å®è£
ãããŠããã¢ã«ãŽãªãºã ã®çµã¿åããã䜿çšããŸãã
次ã«ãã¢ãã¬ã¹ã䜿çšããããã«å
¥åãšåºåãå€æŽããå¿
èŠããããŸãã
type TXInput struct { Txid []byte Vout int Signature []byte PubKey []byte } func (in *TXInput) UsesKey(pubKeyHash []byte) bool { lockingHash := HashPubKey(in.PubKey) return bytes.Compare(lockingHash, pubKeyHash) == 0 } type TXOutput struct { Value int PubKeyHash []byte } func (out *TXOutput) Lock(address []byte) { pubKeyHash := Base58Decode(address) pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-4] out.PubKeyHash = pubKeyHash } func (out *TXOutput) IsLockedWithKey(pubKeyHash []byte) bool { return bytes.Compare(out.PubKeyHash, pubKeyHash) == 0 }
ScriptSig
ãš
ScriptSig
ã¯äœ¿çšã
ScriptPubKey
ã代ããã«
ScriptSig
ã
Signature
PubKey
ãš
PubKey
åå²ãã
ScriptPubKey
ååã
PubKeyHash
å€æŽã
PubKeyHash
ã Bitcoinãšåãããã«ãåºåã®ãããã¯/ãããã¯è§£é€ã®æ©èœãšå
¥åã®çœ²åã®ããžãã¯ãå®è£
ããŸãããã¡ãœããã䜿çšããŠãããå®è£
ããŸãã
UsesKey
ã¡ãœããã¯ãå
¥åãç¹å®ã®ããŒã䜿çšããŠåºåã®ããã¯ã解é€ããããšã確èªããŸãã å
¥åã¯ããã·ã¥ãããŠããªãå
¬ééµãä¿åããé¢æ°ã¯ããã·ã¥ããããã®ãåãå
¥ããããšã«æ³šæããŠãã ããã
IsLockedWithKey
ã¯ãåºå£ããããã¯ããããã«å
¬éããŒããã·ã¥ããŒã䜿çšãããŠãããã©ããã確èªããŸãã ããã¯
UsesKey
ãªãã·ã§ã³æ©èœã§
UsesKey
ãã©ã¡ãã
FindUnspentTransactions
䜿çšãããŠãã©ã³ã¶ã¯ã·ã§ã³éã®æ¥ç¶ãæ§ç¯ããŸãã
Lock
åã«åºå£ããããã¯ããŸãã ã³ã€ã³ã誰ãã«éããšããã¢ãã¬ã¹ããç¥ããªãã®ã§ãé¢æ°ã¯ã¢ãã¬ã¹ãå¯äžã®åŒæ°ãšããŠåãåããŸãã 次ã«ãã¢ãã¬ã¹ããã³ãŒããããå
¬éããŒããã·ã¥ããŒãããããæœåºãããŠã
PubKeyHash
ãã£ãŒã«ãã«æ ŒçŽãããŸãã
ããã§ã¯ããã¹ãŠãæ£ããæ©èœããããšã確èªããŸãããã
$ blockchain_go createwallet Your new address: 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt $ blockchain_go createwallet Your new address: 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h $ blockchain_go createwallet Your new address: 1Lhqun1E9zZZhodiTqxfPQBcwr1CVDV2sy $ blockchain_go createblockchain -address 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt 0000005420fbfdafa00c093f56e033903ba43599fa7cd9df40458e373eee724d Done! $ blockchain_go getbalance -address 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt Balance of '13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt': 10 $ blockchain_go send -from 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h -to 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt -amount 5 2017/09/12 13:08:56 ERROR: Not enough funds $ blockchain_go send -from 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt -to 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h -amount 6 00000019afa909094193f64ca06e9039849709f5948fbac56cae7b1b8f0ff162 Success! $ blockchain_go getbalance -address 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt Balance of '13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt': 4 $ blockchain_go getbalance -address 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h Balance of '15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h': 6 $ blockchain_go getbalance -address 1Lhqun1E9zZZhodiTqxfPQBcwr1CVDV2sy Balance of '1Lhqun1E9zZZhodiTqxfPQBcwr1CVDV2sy': 0
ãããïŒ ãã©ã³ã¶ã¯ã·ã§ã³çœ²åãå®è£
ãããšããæ¥ãŸããã
眲åã®å®è£
ããã¯ãããã³ã€ã³ã§ãã©ã³ã¶ã¯ã·ã§ã³ã®ä¿¡é Œæ§ãä¿èšŒããå¯äžã®æ¹æ³ã§ããããããã©ã³ã¶ã¯ã·ã§ã³ã«çœ²åããå¿
èŠããããŸãã 眲åãç¡å¹ãªå Žåããã©ã³ã¶ã¯ã·ã§ã³ã¯ç¡å¹ãšèŠãªããããããã£ãŠããã§ãŒã³ã«è¿œå ã§ããŸããã
1ã€ãé€ããŠããã©ã³ã¶ã¯ã·ã§ã³çœ²åã®å®è£
çšã®ãã¹ãŠããããŸãã眲åçšã®ããŒã¿ã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ã®ã©ã®éšåã«çœ²åããå¿
èŠããããŸããïŒ ãŸãã¯ãååŒå
šäœã«çœ²åããå¿
èŠããããŸããïŒ çœ²åããããŒã¿ã®éžæã¯éåžžã«éèŠã§ãã å®éã眲åãå¿
èŠãªããŒã¿ã«ã¯ãããŒã¿ãäžæã«èå¥ããæ
å ±ãå«ãŸããŠããå¿
èŠããããŸãã ããšãã°ãåºåå€ã®ã¿ã«çœ²åããããšã¯æå³ããããŸããããã®ãããªçœ²åã§ã¯éä¿¡è
ãšåä¿¡è
ãèæ
®ãããªãããã§ãã
ãã©ã³ã¶ã¯ã·ã§ã³ã以åã®åºåã®ãããã¯ã解é€ãããããã®å€ãåé
åžããæ°ããåºåããããã¯ããå Žåã次ã®ããŒã¿ã«çœ²åããå¿
èŠããããŸãã
- ããã¯ãããŠããªãåºåã«ä¿åãããŠããå
¬éããŒããã·ã¥ã ããã«ããããã©ã³ã¶ã¯ã·ã§ã³ã®ãéä¿¡è
ããèå¥ãããŸãã
- æ°ããããã¯ãããã³ã³ã»ã³ãã«ä¿åãããŠããå
¬éããŒããã·ã¥ã ããã«ããããã©ã³ã¶ã¯ã·ã§ã³ã®ãåä¿¡è
ããèå¥ãããŸãã
- æ°ããåºåã®æå³ã
Bitcoinã§ã¯ãããã¯/ããã¯è§£é€ããžãã¯ã¯ãããããScriptSig
ãšScriptPubKey
å
¥åãã£ãŒã«ããšåºåãã£ãŒã«ãã«ä¿åãããã¹ã¯ãªããã«ä¿åãããŸãã Bitcoinã¯ããŸããŸãªã¿ã€ãã®ãã®ãããªã¹ã¯ãªãããèš±å¯ããããã ScriptPubKey
ã³ã³ãã³ãå
šäœã«ScriptPubKey
ãŸãã
ããã«é¢ããŠããã©ã³ã¶ã¯ã·ã§ã³ã¯ãããã³ã€ã³ã§ã¯çœ²åãããŸãã
ScriptPubKey
æå®ãããåºåã®
ScriptPubKey
å«ãå
¥åãå«ãåŠçæžã¿ã³ããŒ
ããã§ã¯ããã©ã³ã¶ã¯ã·ã§ã³ã®ã³ããŒãåŠçããããã®è©³çŽ°ãªããã»ã¹ã«ã€ããŠèª¬æããŸã ã ããããå€ããªã£ãŠããŸãããããä¿¡é Œã§ããæ
å ±æºãèŠã€ããããšãã§ããŸããã§ããã
ããã¯ãã¹ãŠååã«è€éãªããã§ããã³ãŒããæžãå§ããŸãããã ãããŠã
Sign
ã¡ãœããããå§ããŸãã
func (tx *Transaction) Sign(privKey ecdsa.PrivateKey, prevTXs map[string]Transaction) { if tx.IsCoinbase() { return } txCopy := tx.TrimmedCopy() for inID, vin := range txCopy.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil r, s, err := ecdsa.Sign(rand.Reader, &privKey, txCopy.ID) signature := append(r.Bytes(), s.Bytes()...) tx.Vin[inID].Signature = signature } }
ãã®ã¡ãœããã¯ãç§å¯ããŒãšä»¥åã®ãã©ã³ã¶ã¯ã·ã§ã³ã®é£æ³é
åãåãå
¥ããŸãã åè¿°ã®ããã«ããã©ã³ã¶ã¯ã·ã§ã³ã«çœ²åããã«ã¯ããã©ã³ã¶ã¯ã·ã§ã³å
¥åã§æå®ãããåºåã«ã¢ã¯ã»ã¹ããå¿
èŠãããããããããã®åºåãä¿åãããã©ã³ã¶ã¯ã·ã§ã³ãå¿
èŠã§ãã
ãã®ã¡ãœããã詳ããèŠãŠã¿ãŸãããã
if tx.IsCoinbase() { return }
Coinbaseãã©ã³ã¶ã¯ã·ã§ã³ã«ã¯å®éã®åºåããªãããã眲åãããŠããŸãã
txCopy := tx.TrimmedCopy()
ãã©ã³ã¶ã¯ã·ã§ã³å
šäœã§ã¯ãªããåŠçæžã¿ã®ã³ããŒã«çœ²åããŸãã
func (tx *Transaction) TrimmedCopy() Transaction { var inputs []TXInput var outputs []TXOutput for _, vin := range tx.Vin { inputs = append(inputs, TXInput{vin.Txid, vin.Vout, nil, nil}) } for _, vout := range tx.Vout { outputs = append(outputs, TXOutput{vout.Value, vout.PubKeyHash}) } txCopy := Transaction{tx.ID, inputs, outputs} return txCopy }
ã³ããŒã«ã¯ãã¹ãŠã®å
¥åãšåºåãå«ãŸãã
TXInput.Signature
ãš
TXInput.PubKey
ã¯nilã«ãªããŸãã
次ã«ãã³ããŒã®åãšã³ããªã確èªããŸãã
for inID, vin := range txCopy.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash
åå
¥åã§ã
Signature
nilïŒåãªãããã«ãã§ãã¯ïŒã«èšå®ããã
PubKey
ã®åºåãžã®ãªã³ã¯
PubKey
å²ãåœãŠãããŸãã çŸæç¹ã§ã¯ãçŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ãé€ããã¹ãŠã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ã空ãã§ãã
PubKey
ã眲å
PubKey
ãš
PubKey
ã¯ãŒãã§ãã ãããã£ãŠã
å
¥åã¯åå¥ã«
眲åãããŸãã ãããã¯ã¢ããªã±ãŒã·ã§ã³ã«ã¯å¿
èŠãããŸãããããããã³ã€ã³ã§ã¯ãç°ãªãã¢ãã¬ã¹ãåç
§ãããšã³ããªããã©ã³ã¶ã¯ã·ã§ã³ã«å«ããããšãã§ããŸãã
txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil
Hash
ã¡ãœããã¯ããã©ã³ã¶ã¯ã·ã§ã³ãã·ãªã¢ã«åããSHA-256ã¢ã«ãŽãªãºã ã䜿çšããŠããã·ã¥ããŸãã çµæã¯ã眲åã®æºåãã§ããããŒã¿ã§ãã ããã·ã¥ãåãåã£ãåŸã
PubKey
ãã£ãŒã«ãããªã»ããããŠã以éã®å埩ã«åœ±é¿ãäžããªã
PubKey
ããå¿
èŠããããŸãã
r, s, err := ecdsa.Sign(rand.Reader, &privKey, txCopy.ID) signature := append(r.Bytes(), s.Bytes()...) tx.Vin[inID].Signature = signature
txCopy.ID
ã§
privKey
眲åã
privKey
ã ECDSA眲åã¯ãçµã¿åãããŠ
Signature
å
¥åãã£ãŒã«ãã«ä¿åããæ°å€ã®ãã¢ã§ãã
æ€èšŒæ©èœãæ€èšããŠãã ããã
func (tx *Transaction) Verify(prevTXs map[string]Transaction) bool { txCopy := tx.TrimmedCopy() curve := elliptic.P256() for inID, vin := range tx.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil r := big.Int{} s := big.Int{} sigLen := len(vin.Signature) r.SetBytes(vin.Signature[:(sigLen / 2)]) s.SetBytes(vin.Signature[(sigLen / 2):]) x := big.Int{} y := big.Int{} keyLen := len(vin.PubKey) x.SetBytes(vin.PubKey[:(keyLen / 2)]) y.SetBytes(vin.PubKey[(keyLen / 2):]) rawPubKey := ecdsa.PublicKey{curve, &x, &y} if ecdsa.Verify(&rawPubKey, txCopy.ID, &r, &s) == false { return false } } return true }
ãã®æ¹æ³ã¯éåžžã«ç°¡åã§ãã æåã«ãåã®æ¹æ³ã®ããã«ããã©ã³ã¶ã¯ã·ã§ã³ã®ã³ããŒãååŸããŸãã
txCopy := tx.TrimmedCopy()
次ã«ãããŒãã¢ã®çæã«äœ¿çšãããæ²ç·ãå¿
èŠã§ãã
curve := elliptic.P256()
次ã«ããã¹ãŠã®å
¥åã調ã¹ãŠããããã眲åãããŠããããšã確èªããŸãã
for inID, vin := range tx.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil
æ€èšŒäžã«çœ²åããããŒã¿ãšåãããŒã¿ãå¿
èŠã«ãªãããããã®éšåã¯Signã¡ãœããã§äœ¿çšãããéšåãšåãã§ãã
r := big.Int{} s := big.Int{} sigLen := len(vin.Signature) r.SetBytes(vin.Signature[:(sigLen / 2)]) s.SetBytes(vin.Signature[(sigLen / 2):]) x := big.Int{} y := big.Int{} keyLen := len(vin.PubKey) x.SetBytes(vin.PubKey[:(keyLen / 2)]) y.SetBytes(vin.PubKey[(keyLen / 2):])
ããã§ã¯ã眲åãæ°å€ã®ãã¢ã§ãããå
¬éããŒã座æšã®ãã¢ã§ããããã
TXInput.Signature
ããã³
TXInput.PubKey
æ ŒçŽãããŠããå€ã解åããŸãã 以åã¯ã¹ãã¬ãŒãžçšã«ããããé£çµããŠããŸãããã
crypto/ecdsa
ã§äœ¿çšããããã«ãããã解åããå¿
èŠããã
crypto/ecdsa
ã
rawPubKey := ecdsa.PublicKey{curve, &x, &y} if ecdsa.Verify(&rawPubKey, txCopy.ID, &r, &s) == false { return false } } return true
次ã«ãå
¥åãã
ecdsa.PublicKey
ããå
¬éããŒã䜿çšããŠ
ecdsa.PublicKey
ãäœæããå
¥åãã眲åãæž¡ããŠ
ecdsa.Verify
ãå®è¡ããŸãã ãã¹ãŠã®å
¥åããã§ãã¯ããããšãtrueãè¿ããŸãã å°ãªããšã1ã€ã®å
¥åããã¹ãã«å€±æããå Žåãfalseãè¿ããŸãã
ããã§ã以åã®ãã©ã³ã¶ã¯ã·ã§ã³ãååŸããé¢æ°ãå¿
èŠã§ãã ããã«ã¯ãã§ãŒã³å
šäœãšã®çžäºäœçšãå¿
èŠãªããã
Blockchain
ã¡ãœããã«ããŸãã
func (bc *Blockchain) FindTransaction(ID []byte) (Transaction, error) { bci := bc.Iterator() for { block := bci.Next() for _, tx := range block.Transactions { if bytes.Compare(tx.ID, ID) == 0 { return *tx, nil } } if len(block.PrevBlockHash) == 0 { break } } return Transaction{}, errors.New("Transaction is not found") } func (bc *Blockchain) SignTransaction(tx *Transaction, privKey ecdsa.PrivateKey) { prevTXs := make(map[string]Transaction) for _, vin := range tx.Vin { prevTX, err := bc.FindTransaction(vin.Txid) prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX } tx.Sign(privKey, prevTXs) } func (bc *Blockchain) VerifyTransaction(tx *Transaction) bool { prevTXs := make(map[string]Transaction) for _, vin := range tx.Vin { prevTX, err := bc.FindTransaction(vin.Txid) prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX } return tx.Verify(prevTXs) }
FindTransaction
ã¯ãèå¥åã«ãã£ãŠãã©ã³ã¶ã¯ã·ã§ã³ãæ€çŽ¢ããŸãïŒããã«ã¯ããã§ãŒã³å
ã®ãã¹ãŠã®ãããã¯ã«å¯Ÿããå埩ãå¿
èŠã§ãïŒã
SignTransaction
ã¯1ã€ã®ãã©ã³ã¶ã¯ã·ã§ã³ã
SignTransaction
ããããåç
§ãããã©ã³ã¶ã¯ã·ã§ã³ãèŠã€ããŠçœ²åããŸãã
VerifyTransaction
ã¯ããã©ã³ã¶ã¯ã·ã§ã³ãæ€èšŒããã ãã§ãã
次ã«ããã©ã³ã¶ã¯ã·ã§ã³ã«çœ²åããŠæ€èšŒããå¿
èŠããããŸãã
NewUTXOTransaction
ã¡ãœããã«ãµã€ã³ã€ã³ã
NewUTXOTransaction
ã
func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transaction { ... tx := Transaction{nil, inputs, outputs} tx.ID = tx.Hash() bc.SignTransaction(&tx, wallet.PrivateKey) return &tx }
ãã©ã³ã¶ã¯ã·ã§ã³ã®æ€èšŒã¯ããããã¯ã«è¿œå ãããåã«çºçããŸãã
func (bc *Blockchain) MineBlock(transactions []*Transaction) { var lastHash []byte for _, tx := range transactions { if bc.VerifyTransaction(tx) != true { log.Panic("ERROR: Invalid transaction") } } ... }
以äžã§ãïŒ ããäžåºŠç¢ºèªããŸãããã
$ blockchain_go createwallet Your new address: 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR $ blockchain_go createwallet Your new address: 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab $ blockchain_go createblockchain -address 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR 000000122348da06c19e5c513710340f4c307d884385da948a205655c6a9d008 Done! $ blockchain_go send -from 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR -to 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab -amount 6 0000000f3dbb0ab6d56c4e4b9f7479afe8d5a5dad4d2a8823345a1a16cf3347b Success! $ blockchain_go getbalance -address 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR Balance of '1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR': 4 $ blockchain_go getbalance -address 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab Balance of '1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab': 6
äœãå£ããŠããŸããããããïŒ
bc.SignTransaction (& tx, wallet.PrivateKey)
ãžã®åŒã³åºããã³ã¡ã³ãã¢ãŠãããŠãæªçœ²åã®ãã©ã³ã¶ã¯ã·ã§ã³ããã€ãã³ã°ã§ããªãããã«ããŸãã
func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transaction { ... tx := Transaction{nil, inputs, outputs} tx.ID = tx.Hash()
$ go install $ blockchain_go send -from 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR -to 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab -amount 1 2017/09/12 16:28:15 ERROR: Invalid transaction
ãããã«
ãããã³ã€ã³ã®ã»ãŒãã¹ãŠã®äž»èŠæ©èœãå®è£
ããŸããããããã¯é©ãã¹ãããšã§ãã 次ã®ããŒãã§ã¯ãæçµçã«ãã©ã³ã¶ã¯ã·ã§ã³ã®å®è£
ãå®äºããŸãã
åç
§è³æ
- å®å
šãªãœãŒã¹ã³ãŒã
- å
¬ééµæå·
- ããžã¿ã«çœ²å
- æ¥åæ²ç·
- æ¥åæ²ç·æå·
- ECDSA
- ãããã³ã€ã³ã¢ãã¬ã¹ã®æè¡çèæ¯
- äœæ
- ããŒã¹58
- æ¥åæ²ç·æå·ã®ç°¡åãªçŽ¹ä»