remove PoW from ID

This commit is contained in:
Ethan Buchman
2018-01-13 15:38:40 -05:00
parent b1485b181a
commit 9670519a21
3 changed files with 44 additions and 59 deletions

View File

@ -368,11 +368,8 @@ func (n *Node) OnStart() error {
n.sw.AddListener(l) n.sw.AddListener(l)
// Generate node PrivKey // Generate node PrivKey
// TODO: both the loading function and the target // TODO: the loading function will need to be configurable
// will need to be configurable nodeKey, err := p2p.LoadOrGenNodeKey(n.config.NodeKeyFile())
difficulty := uint8(16) // number of leading 0s in bitstring
target := p2p.MakePoWTarget(difficulty)
nodeKey, err := p2p.LoadOrGenNodeKey(n.config.NodeKeyFile(), target)
if err != nil { if err != nil {
return err return err
} }
@ -381,7 +378,6 @@ func (n *Node) OnStart() error {
// Start the switch // Start the switch
n.sw.SetNodeInfo(n.makeNodeInfo(nodeKey.PubKey())) n.sw.SetNodeInfo(n.makeNodeInfo(nodeKey.PubKey()))
n.sw.SetNodeKey(nodeKey) n.sw.SetNodeKey(nodeKey)
n.sw.SetPeerIDTarget(target)
err = n.sw.Start() err = n.sw.Start()
if err != nil { if err != nil {
return err return err

View File

@ -6,7 +6,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
@ -42,37 +41,20 @@ func (nodeKey *NodeKey) SatisfiesTarget(target []byte) bool {
return bytes.Compare(nodeKey.id(), target) < 0 return bytes.Compare(nodeKey.id(), target) < 0
} }
// LoadOrGenNodeKey attempts to load the NodeKey from the given filePath, // 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.
// If the file does not exist, it generates and saves a new NodeKey func LoadOrGenNodeKey(filePath string) (*NodeKey, error) {
// with ID less than target.
func LoadOrGenNodeKey(filePath string, target []byte) (*NodeKey, error) {
if cmn.FileExists(filePath) { if cmn.FileExists(filePath) {
nodeKey, err := loadNodeKey(filePath) nodeKey, err := loadNodeKey(filePath)
if err != nil { if err != nil {
return nil, err 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 return nodeKey, nil
} else { } 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) { func loadNodeKey(filePath string) (*NodeKey, error) {
jsonBytes, err := ioutil.ReadFile(filePath) jsonBytes, err := ioutil.ReadFile(filePath)
if err != nil { if err != nil {
@ -86,8 +68,8 @@ func loadNodeKey(filePath string) (*NodeKey, error) {
return nodeKey, nil return nodeKey, nil
} }
func genNodeKey(filePath string, target []byte) (*NodeKey, error) { func genNodeKey(filePath string) (*NodeKey, error) {
privKey := genPrivKeyEd25519PoW(target).Wrap() privKey := crypto.GenPrivKeyEd25519().Wrap()
nodeKey := &NodeKey{ nodeKey := &NodeKey{
PrivKey: privKey, PrivKey: privKey,
} }
@ -103,20 +85,26 @@ func genNodeKey(filePath string, target []byte) (*NodeKey, error) {
return nodeKey, nil 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)...)
} }

View File

@ -13,37 +13,38 @@ import (
func TestLoadOrGenNodeKey(t *testing.T) { func TestLoadOrGenNodeKey(t *testing.T) {
filePath := filepath.Join(os.TempDir(), cmn.RandStr(12)+"_peer_id.json") filePath := filepath.Join(os.TempDir(), cmn.RandStr(12)+"_peer_id.json")
target := MakePoWTarget(2) nodeKey, err := LoadOrGenNodeKey(filePath)
nodeKey, err := LoadOrGenNodeKey(filePath, target)
assert.Nil(t, err) assert.Nil(t, err)
nodeKey2, err := LoadOrGenNodeKey(filePath, target) nodeKey2, err := LoadOrGenNodeKey(filePath)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, nodeKey, nodeKey2) 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) { func TestPoWTarget(t *testing.T) {
targetBytes := 20
cases := []struct { cases := []struct {
difficulty uint8 difficulty uint
target []byte target []byte
}{ }{
{0, bytes.Repeat([]byte{255}, 20)}, {0, padBytes([]byte{}, targetBytes)},
{1, append([]byte{128}, repeatBytes(255, 19)...)}, {1, padBytes([]byte{127}, targetBytes)},
{8, append([]byte{0}, repeatBytes(255, 19)...)}, {8, padBytes([]byte{0}, targetBytes)},
{9, append([]byte{0, 128}, repeatBytes(255, 18)...)}, {9, padBytes([]byte{0, 127}, targetBytes)},
{10, append([]byte{0, 64}, repeatBytes(255, 18)...)}, {10, padBytes([]byte{0, 63}, targetBytes)},
{16, append([]byte{0, 0}, repeatBytes(255, 18)...)}, {16, padBytes([]byte{0, 0}, targetBytes)},
{17, append([]byte{0, 0, 128}, repeatBytes(255, 17)...)}, {17, padBytes([]byte{0, 0, 127}, targetBytes)},
} }
for _, c := range cases { for _, c := range cases {
assert.Equal(t, MakePoWTarget(c.difficulty), c.target) assert.Equal(t, MakePoWTarget(c.difficulty, 20*8), c.target)
} }
} }