From 9670519a211f81474dd3a1b42a0d210e0aab54e4 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 13 Jan 2018 15:38:40 -0500 Subject: [PATCH] remove PoW from ID --- node/node.go | 8 ++----- p2p/key.go | 64 ++++++++++++++++++++----------------------------- p2p/key_test.go | 31 ++++++++++++------------ 3 files changed, 44 insertions(+), 59 deletions(-) diff --git a/node/node.go b/node/node.go index 7fecf710c..bd3bd1ca8 100644 --- a/node/node.go +++ b/node/node.go @@ -368,11 +368,8 @@ func (n *Node) OnStart() error { n.sw.AddListener(l) // Generate node PrivKey - // TODO: both the loading function and the target - // will need to be configurable - difficulty := uint8(16) // number of leading 0s in bitstring - target := p2p.MakePoWTarget(difficulty) - nodeKey, err := p2p.LoadOrGenNodeKey(n.config.NodeKeyFile(), target) + // TODO: the loading function will need to be configurable + nodeKey, err := p2p.LoadOrGenNodeKey(n.config.NodeKeyFile()) if err != nil { return err } @@ -381,7 +378,6 @@ func (n *Node) OnStart() error { // Start the switch n.sw.SetNodeInfo(n.makeNodeInfo(nodeKey.PubKey())) n.sw.SetNodeKey(nodeKey) - n.sw.SetPeerIDTarget(target) err = n.sw.Start() if err != nil { return err diff --git a/p2p/key.go b/p2p/key.go index d0031458d..6883c86e2 100644 --- a/p2p/key.go +++ b/p2p/key.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "math/big" crypto "github.com/tendermint/go-crypto" cmn "github.com/tendermint/tmlibs/common" @@ -42,37 +41,20 @@ func (nodeKey *NodeKey) SatisfiesTarget(target []byte) bool { return bytes.Compare(nodeKey.id(), target) < 0 } -// LoadOrGenNodeKey attempts to load the NodeKey from the given filePath, -// and checks that the corresponding ID is less than the target. -// If the file does not exist, it generates and saves a new NodeKey -// with ID less than target. -func LoadOrGenNodeKey(filePath string, target []byte) (*NodeKey, error) { +// LoadOrGenNodeKey attempts to load the NodeKey from the given filePath. +// If the file does not exist, it generates and saves a new NodeKey. +func LoadOrGenNodeKey(filePath string) (*NodeKey, error) { if cmn.FileExists(filePath) { nodeKey, err := loadNodeKey(filePath) if err != nil { return nil, err } - if !nodeKey.SatisfiesTarget(target) { - return nil, fmt.Errorf("Loaded ID (%s) does not satisfy target (%X)", nodeKey.ID(), target) - } return nodeKey, nil } else { - return genNodeKey(filePath, target) + return genNodeKey(filePath) } } -// MakePoWTarget returns a 20 byte target byte array. -func MakePoWTarget(difficulty uint8) []byte { - zeroPrefixLen := (int(difficulty) / 8) - prefix := bytes.Repeat([]byte{0}, zeroPrefixLen) - mod := (difficulty % 8) - if mod > 0 { - nonZeroPrefix := byte(1 << (8 - mod)) - prefix = append(prefix, nonZeroPrefix) - } - return append(prefix, bytes.Repeat([]byte{255}, 20-len(prefix))...) -} - func loadNodeKey(filePath string) (*NodeKey, error) { jsonBytes, err := ioutil.ReadFile(filePath) if err != nil { @@ -86,8 +68,8 @@ func loadNodeKey(filePath string) (*NodeKey, error) { return nodeKey, nil } -func genNodeKey(filePath string, target []byte) (*NodeKey, error) { - privKey := genPrivKeyEd25519PoW(target).Wrap() +func genNodeKey(filePath string) (*NodeKey, error) { + privKey := crypto.GenPrivKeyEd25519().Wrap() nodeKey := &NodeKey{ PrivKey: privKey, } @@ -103,20 +85,26 @@ func genNodeKey(filePath string, target []byte) (*NodeKey, error) { return nodeKey, nil } -// generate key with address satisfying the difficult target -func genPrivKeyEd25519PoW(target []byte) crypto.PrivKeyEd25519 { - secret := crypto.CRandBytes(32) - var privKey crypto.PrivKeyEd25519 - for i := 0; ; i++ { - privKey = crypto.GenPrivKeyEd25519FromSecret(secret) - if bytes.Compare(privKey.PubKey().Address(), target) < 0 { - break - } - z := new(big.Int) - z.SetBytes(secret) - z = z.Add(z, big.NewInt(1)) - secret = z.Bytes() +//------------------------------------------------------------------------------ +// MakePoWTarget returns the big-endian encoding of 2^(targetBits - difficulty) - 1. +// It can be used as a Proof of Work target. +// NOTE: targetBits must be a multiple of 8 and difficulty must be less than targetBits. +func MakePoWTarget(difficulty, targetBits uint) []byte { + if targetBits%8 != 0 { + panic(fmt.Sprintf("targetBits (%d) not a multiple of 8", targetBits)) } - return privKey + if difficulty >= targetBits { + panic(fmt.Sprintf("difficulty (%d) >= targetBits (%d)", difficulty, targetBits)) + } + targetBytes := targetBits / 8 + zeroPrefixLen := (int(difficulty) / 8) + prefix := bytes.Repeat([]byte{0}, zeroPrefixLen) + mod := (difficulty % 8) + if mod > 0 { + nonZeroPrefix := byte(1<<(8-mod) - 1) + prefix = append(prefix, nonZeroPrefix) + } + tailLen := int(targetBytes) - len(prefix) + return append(prefix, bytes.Repeat([]byte{0xFF}, tailLen)...) } diff --git a/p2p/key_test.go b/p2p/key_test.go index ef885e55d..c2e1f3e0e 100644 --- a/p2p/key_test.go +++ b/p2p/key_test.go @@ -13,37 +13,38 @@ import ( func TestLoadOrGenNodeKey(t *testing.T) { filePath := filepath.Join(os.TempDir(), cmn.RandStr(12)+"_peer_id.json") - target := MakePoWTarget(2) - nodeKey, err := LoadOrGenNodeKey(filePath, target) + nodeKey, err := LoadOrGenNodeKey(filePath) assert.Nil(t, err) - nodeKey2, err := LoadOrGenNodeKey(filePath, target) + nodeKey2, err := LoadOrGenNodeKey(filePath) assert.Nil(t, err) assert.Equal(t, nodeKey, nodeKey2) } -func repeatBytes(val byte, n int) []byte { - return bytes.Repeat([]byte{val}, n) +//---------------------------------------------------------- + +func padBytes(bz []byte, targetBytes int) []byte { + return append(bz, bytes.Repeat([]byte{0xFF}, targetBytes-len(bz))...) } func TestPoWTarget(t *testing.T) { + targetBytes := 20 cases := []struct { - difficulty uint8 + difficulty uint target []byte }{ - {0, bytes.Repeat([]byte{255}, 20)}, - {1, append([]byte{128}, repeatBytes(255, 19)...)}, - {8, append([]byte{0}, repeatBytes(255, 19)...)}, - {9, append([]byte{0, 128}, repeatBytes(255, 18)...)}, - {10, append([]byte{0, 64}, repeatBytes(255, 18)...)}, - {16, append([]byte{0, 0}, repeatBytes(255, 18)...)}, - {17, append([]byte{0, 0, 128}, repeatBytes(255, 17)...)}, + {0, padBytes([]byte{}, targetBytes)}, + {1, padBytes([]byte{127}, targetBytes)}, + {8, padBytes([]byte{0}, targetBytes)}, + {9, padBytes([]byte{0, 127}, targetBytes)}, + {10, padBytes([]byte{0, 63}, targetBytes)}, + {16, padBytes([]byte{0, 0}, targetBytes)}, + {17, padBytes([]byte{0, 0, 127}, targetBytes)}, } for _, c := range cases { - assert.Equal(t, MakePoWTarget(c.difficulty), c.target) + assert.Equal(t, MakePoWTarget(c.difficulty, 20*8), c.target) } - }