ブロックチェーンアプリケーションを最初から開発する(11)--Ethereumアドレスの生成

1.イーサリアムアドレスの秘密鍵を生成します

1.1イーサリアムアドレス秘密鍵機能コードを生成する

  • 定数を作成する
const (
	BitcoinSeed = "Bitcoin seed"
	Mnemonic    = "search crime session tag file joke leaf express interest slender file hawk"
)
  • アドレス生成関数を作成する
func NewAccount(password string) string {
	seed := pbkdf2.Key([]byte(Mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
	hmac := hmac.New(sha512.New, []byte(BitcoinSeed))
	_, err := hmac.Write([]byte(seed))
	if err != nil {
		return ""
	}
	intermediary := hmac.Sum(nil)
	keyBytes := intermediary[:32] // 私钥
	_, pub := ecdsa.PrivKeyFromBytes(ecdsa.S256(), keyBytes)
	return pub.ToAddress().String()
}

1.2 pbkdf2.Key()キー生成関数

PBKDF2(パスワードベースの鍵導出関数)

キーを導出するために使用される関数であり、暗号化されたパスワードを生成するためによく使用されます。

その基本的な原則は、疑似ランダム関数(HMAC関数、sha512など)を渡し、入力パラメーターとして平文(パスワード)とソルト値(ソルト)を取り、操作を繰り返して、最後に生成することです。秘密鍵。

繰り返し回数が多ければ、クラッキングのコストは非常に高くなります。ソルト値を追加すると、「レインボーテーブル」攻撃の難易度も上がります。

ユーザーパスワードは、比較的安全なPBKDF2アルゴリズムを使用して保存されます。

PBKDF2関数の構文定義

DK = PBKDF2(PRF, Password, Salt, c, dkLen ,Hash algorithm)
  • PRFは、HASH_HMAC関数などの疑似ランダム関数であり、長さhLenの結果を出力します。
  • パスワードは、キーの生成に使用される元のパスワードです。
  • ソルトは暗号化に使用されるソルトです。
  • cは、計算を繰り返す回数です。
  • dkLenは、キーの予想される長さです。
  • DKは最後に生成されたキーです。

以下は、ニーモニックを使用して秘密鍵を生成するためのコードです

package pbkdf2

import (
	"crypto/rand"
	"crypto/sha512"
	"golang.org/x/crypto/pbkdf2"
)

const (
    Mnemonic =  "search crime conversation tag directory joke leaf express interest password = ""
)
func encryptPwdWithSalt(password string) (*ecdsa.PrivateKey, *ecdsa.PublicKey) {
		seed := pbkdf2.Key([]byte(Mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
}

// []byte(Mnemonic):助记词
// []byte("mnemonic"+password) :salt盐值
// 2048:重复计算的次数
// 64:返回的秘钥长度
// sha512.New:哈希算法

1.3HMAC生成ダイジェストアルゴリズム

HMACアルゴリズムの中国語名はハッシュメッセージ認証コードであり、完全な英語名はハッシュベースのメッセージ認証コードです。そのアルゴリズムは、特定のハッシュ関数(主にSHAシリーズとMDシリーズ)に基づいており、入力としてキーとメッセージを受け取り、出力としてメッセージダイジェストを生成しますHMACアルゴリズムと他のハッシュアルゴリズムの最大の違いは、キーが必要なことです。そのアルゴリズム関数は、ブロック暗号を使用して確立された一方向ハッシュ関数です。
次の表は、特定のアルゴリズムに対応する出力ダイジェストの長さを示しています。

アルゴリズム ダイジェスト長(ビット) 述べる
HmacMD5 128 BouncyCastleの実装
HmacSHA1 160 (20バイト)BouncyCastleの実装
HmacSHA256 256 BouncyCastleの実装
HmacSHA384 384 BouncyCastleの実装
HmacSHA512 512 JAVA6の実装
HmacMD2 128 BouncyCastleの実装
HmacMD4 128 BouncyCastleの実装
HmacSHA224 224 BouncyCastleの実装

HMACのキーは任意の長さにすることができます。キーの長さがダイジェストアルゴリズム情報パケットの長さを超える場合、キーのダイジェストは最初にダイジェストアルゴリズムを新しいキーとして使用して計算されます。キーの長さはセキュリティの強度に関係しているため、通常、短すぎるキーを使用することはお勧めしません。通常、キーの長さは、選択したダイジェストアルゴリズムによって出力される情報ダイジェストの長さ以上です。

HMACアルゴリズムのgolangにカプセル化されたコードの詳細な分析

//创建运算对象,HMAC需要两个参数:hash函数和key
hmac := hmac.New(sha512.New, []byte(BitcoinSeed))
//将明文写入到hmac中
	_, err := hmac.Write([]byte(seed))
	if err != nil {
		return nil, nil
	}
//hmac对象对写入数据的运算,生成的参数为字节	
intermediary := hmac.Sum(nil)

golangでHMACアルゴリズムを使用した距離の例

package main

import (
    "crypto/hmac"
    "crypto/md5"
    "crypto/sha1"
    "encoding/hex"
    "fmt"
)

func Md5(data string) string {
    md5 := md5.New()
    md5.Write([]byte(data))
    md5Data := md5.Sum([]byte(""))
    return hex.EncodeToString(md5Data)
}

func Hmac(key, data string) string {
    hmac := hmac.New(md5.New, []byte(key))
    hmac.Write([]byte(data))
    return hex.EncodeToString(hmac.Sum(nil)
}

func Sha1(data string) string {
    sha1 := sha1.New()
    sha1.Write([]byte(data))
    return hex.EncodeToString(sha1.Sum(nil))
}

func main() {
    fmt.Println(Md5("hello"))
    fmt.Println(Hmac("key2", "hello"))
    fmt.Println(Sha1("hello"))
}

2.秘密鍵に基づいて公開鍵と秘密鍵を作成します

2.1秘密鍵に基づいて公開鍵と秘密鍵の機能コードを作成する

  • 秘密鍵の構造を定義し、秘密鍵に従って公開鍵に対応する構造を返します
// ToPubKey 返回与此私钥对应的公钥
func (p *PrivateKey) ToPubKey() *PublicKey {
	return (*PublicKey)(&p.PublicKey)
}
  • 秘密鍵から公開鍵を作成するための関数コード
// PrivKeyFromBytes 根据私钥随机数D返回公私钥
func PrivKeyFromBytes(curve elliptic.Curve, pk []byte) (*PrivateKey, *PublicKey) {
	// 根据字节pk,返回x,y
	x, y := curve.ScalarBaseMult(pk)
	// 定义一个私钥结构体,结构体中包含:公钥结构体
	priv := &PrivateKey{
		PublicKey: e.PublicKey{
			Curve: curve,
			X:     x,
			Y:     y,
		},
		D: new(big.Int).SetBytes(pk),
	}
	return priv, (*PublicKey)(&priv.PublicKey)
}

受信パラメータ:

  • 曲線楕円曲線:楕円曲線暗号化アルゴリズム
  • pk [] byte:秘密鍵バイト

戻りパラメーター:

  • PrivateKey:ECDSA秘密鍵
  • PublicKey:ECDSA公開鍵

2.2 PrivKeyFromBytesは、秘密鍵と公開鍵のペアを作成します

引数としてバイトスライスとして渡された秘密鍵に基づいて、「曲線」の秘密鍵と公開鍵を返します。

公開鍵は秘密鍵から生成できることを知っておく必要があります。したがって、秘密鍵を所有することは、鍵ペア全体を所有することと同じです。

* ecdsa.PrivateKeyは、PublicKeyとPrivateKeyの構造です。これは、生のバイトPrivateKeyからキーペアを取得する関数でもあります。

3.公開鍵に基づいてアドレスを転送します

3.1主な機能コード

  • 構造を定義する
// Address 表示20字节地址
type Address [AddressLength]byte
  • 主な関数PubkeyToAddress()
// PubkeyToAddress 公钥转地址方法
func (p *PublicKey) ToAddress() Address {
	pubBytes := p.FromECDSAPub()
	i := sha3.Keccak256(pubBytes[1:])[12:]
	return BytesToAddress(i)
}

3.2サブファンクションコード

  • サブ関数FromECDSAPub()
// FromECDSAPub 椭圆加密公钥转坐标
func (p *PublicKey) FromECDSAPub() []byte {
	if p == nil || p.X == nil || p.Y == nil {
		return nil
	}
	return elliptic.Marshal(S256(), p.X, p.Y)
}

// S256()是特定的椭圆曲线,在程序启动的时候进行初始化,后来调用只是获取其引用而已。

// elliptic.Marshal(...)为标准库函数,按照非压缩形式得到相应的[]byte
func Marshal(curve Curve, x, y *big.Int) []byte {
	byteLen := (curve.Params().BitSize + 7) / 8

	ret := make([]byte, 1+2*byteLen)
	ret[0] = 4 // uncompressed point

	x.FillBytes(ret[1 : 1+byteLen])
	y.FillBytes(ret[1+byteLen : 1+2*byteLen])

	return ret
}
  • サブ関数Keccak256()
// Keccak256 使用sha3 256加密内容
func Keccak256(data ...[]byte) []byte {
	d := NewKeccak256()
	for _, b := range data {
		d.Write(b)
	}
	return d.Sum(nil)
}

符号ビット(最初のバイト)を除く他のバイト配列でsha3処理を実行します。//sha3
の結果は合計32バイトになります。
// sha3結果の最後の20バイトを取得し、アドレスを生成します。イーサリアムでは、アドレスは次のとおりです。type Address [AddressLength] byte

  • サブ関数BytesToAddress()
 // BytesToAddress其实就是字节拷贝
// BytesToAddress byte转address
func BytesToAddress(b []byte) Address {
	var a Address
	a.SetBytes(b)
	return a
}


// SetBytes 将地址设置为b的值。如果b大于len(a),会宕机
// SetBytes()考虑到了字节数量不匹配的情况
func (a *Address) SetBytes(b []byte) {
	if len(b) > len(a) {
		b = b[len(b)-AddressLength:]
	}
	copy(a[AddressLength-len(b):], b)
}

おすすめ

転載: blog.csdn.net/cljdsc/article/details/122692601