| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | package discover | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/ecdsa" | 
					
						
							|  |  |  | 	"crypto/elliptic" | 
					
						
							|  |  |  | 	"encoding/hex" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-03-02 15:26:24 +01:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	"math/rand" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-03-02 15:26:24 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto/secp256k1" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-12 11:59:52 +01:00
										 |  |  | const nodeIDBits = 512 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | // Node represents a host on the network. | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | // The fields of Node may not be modified. | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | type Node struct { | 
					
						
							| 
									
										
										
										
											2015-04-18 01:50:31 +02:00
										 |  |  | 	IP       net.IP // len 4 for IPv4 or 16 for IPv6 | 
					
						
							|  |  |  | 	UDP, TCP uint16 // port numbers | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	ID       NodeID // the node's public key | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// This is a cached copy of sha3(ID) which is used for node | 
					
						
							|  |  |  | 	// distance calculations. This is part of Node in order to make it | 
					
						
							|  |  |  | 	// possible to write tests that need a node at a certain distance. | 
					
						
							|  |  |  | 	// In those tests, the content of sha will not actually correspond | 
					
						
							|  |  |  | 	// with ID. | 
					
						
							|  |  |  | 	sha common.Hash | 
					
						
							| 
									
										
										
										
											2015-08-17 11:27:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// whether this node is currently being pinged in order to replace | 
					
						
							|  |  |  | 	// it in a bucket | 
					
						
							|  |  |  | 	contested bool | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | // NewNode creates a new node. It is mostly meant to be used for | 
					
						
							|  |  |  | // testing purposes. | 
					
						
							|  |  |  | func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node { | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	if ipv4 := ip.To4(); ipv4 != nil { | 
					
						
							|  |  |  | 		ip = ipv4 | 
					
						
							| 
									
										
										
										
											2015-04-18 01:50:31 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	return &Node{ | 
					
						
							| 
									
										
										
										
											2015-04-18 01:50:31 +02:00
										 |  |  | 		IP:  ip, | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 		UDP: udpPort, | 
					
						
							|  |  |  | 		TCP: tcpPort, | 
					
						
							| 
									
										
										
										
											2015-04-18 01:50:31 +02:00
										 |  |  | 		ID:  id, | 
					
						
							| 
									
										
										
										
											2016-02-21 18:40:27 +00:00
										 |  |  | 		sha: crypto.Keccak256Hash(id[:]), | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-25 16:45:53 +01:00
										 |  |  | func (n *Node) addr() *net.UDPAddr { | 
					
						
							| 
									
										
										
										
											2015-04-18 01:50:31 +02:00
										 |  |  | 	return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)} | 
					
						
							| 
									
										
										
										
											2015-03-25 16:45:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | // Incomplete returns true for nodes with no IP address. | 
					
						
							|  |  |  | func (n *Node) Incomplete() bool { | 
					
						
							|  |  |  | 	return n.IP == nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 12:06:49 +01:00
										 |  |  | // checks whether n is a valid complete node. | 
					
						
							|  |  |  | func (n *Node) validateComplete() error { | 
					
						
							|  |  |  | 	if n.Incomplete() { | 
					
						
							|  |  |  | 		return errors.New("incomplete node") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.UDP == 0 { | 
					
						
							|  |  |  | 		return errors.New("missing UDP port") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.TCP == 0 { | 
					
						
							|  |  |  | 		return errors.New("missing TCP port") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.IP.IsMulticast() || n.IP.IsUnspecified() { | 
					
						
							|  |  |  | 		return errors.New("invalid IP (multicast/unspecified)") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, err := n.ID.Pubkey() // validate the key (on curve, etc.) | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | // The string representation of a Node is a URL. | 
					
						
							|  |  |  | // Please see ParseNode for a description of the format. | 
					
						
							|  |  |  | func (n *Node) String() string { | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | 	u := url.URL{Scheme: "enode"} | 
					
						
							|  |  |  | 	if n.Incomplete() { | 
					
						
							|  |  |  | 		u.Host = fmt.Sprintf("%x", n.ID[:]) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)} | 
					
						
							|  |  |  | 		u.User = url.User(fmt.Sprintf("%x", n.ID[:])) | 
					
						
							|  |  |  | 		u.Host = addr.String() | 
					
						
							|  |  |  | 		if n.UDP != n.TCP { | 
					
						
							|  |  |  | 			u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP)) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return u.String() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ParseNode parses a node designator. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // There are two basic forms of node designators | 
					
						
							|  |  |  | //   - incomplete nodes, which only have the public key (node ID) | 
					
						
							|  |  |  | //   - complete nodes, which contain the public key and IP/Port information | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // For incomplete nodes, the designator must look like one of these | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | //    enode://<hex node id> | 
					
						
							|  |  |  | //    <hex node id> | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | // For complete nodes, the node ID is encoded in the username portion | 
					
						
							|  |  |  | // of the URL, separated from the host by an @ sign. The hostname can | 
					
						
							|  |  |  | // only be given as an IP address, DNS domain names are not allowed. | 
					
						
							|  |  |  | // The port in the host name section is the TCP listening port. If the | 
					
						
							|  |  |  | // TCP and UDP (discovery) ports differ, the UDP port is specified as | 
					
						
							|  |  |  | // query parameter "discport". | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | // | 
					
						
							|  |  |  | // In the following example, the node URL describes | 
					
						
							|  |  |  | // a node with IP address 10.3.58.6, TCP listening port 30303 | 
					
						
							|  |  |  | // and UDP discovery port 30301. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //    enode://<hex node id>@10.3.58.6:30303?discport=30301 | 
					
						
							|  |  |  | func ParseNode(rawurl string) (*Node, error) { | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | 	if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { | 
					
						
							|  |  |  | 		id, err := HexID(m[1]) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("invalid node ID (%v)", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return NewNode(id, nil, 0, 0), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return parseComplete(rawurl) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parseComplete(rawurl string) (*Node, error) { | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		id               NodeID | 
					
						
							|  |  |  | 		ip               net.IP | 
					
						
							|  |  |  | 		tcpPort, udpPort uint64 | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	u, err := url.Parse(rawurl) | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	if u.Scheme != "enode" { | 
					
						
							|  |  |  | 		return nil, errors.New("invalid URL scheme, want \"enode\"") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	// Parse the Node ID from the user portion. | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	if u.User == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("does not contain node ID") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	if id, err = HexID(u.User.String()); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 		return nil, fmt.Errorf("invalid node ID (%v)", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	// Parse the IP address. | 
					
						
							|  |  |  | 	host, port, err := net.SplitHostPort(u.Host) | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("invalid host: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	if ip = net.ParseIP(host); ip == nil { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 		return nil, errors.New("invalid IP address") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	// Ensure the IP is 4 bytes long for IPv4 addresses. | 
					
						
							|  |  |  | 	if ipv4 := ip.To4(); ipv4 != nil { | 
					
						
							|  |  |  | 		ip = ipv4 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Parse the port numbers. | 
					
						
							|  |  |  | 	if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 		return nil, errors.New("invalid port") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	udpPort = tcpPort | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	qv := u.Query() | 
					
						
							| 
									
										
										
										
											2015-04-23 12:11:21 +02:00
										 |  |  | 	if qv.Get("discport") != "" { | 
					
						
							|  |  |  | 		udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16) | 
					
						
							| 
									
										
										
										
											2015-04-18 01:50:31 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 			return nil, errors.New("invalid discport in query") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | 	return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MustParseNode parses a node URL. It panics if the URL is not valid. | 
					
						
							|  |  |  | func MustParseNode(rawurl string) *Node { | 
					
						
							|  |  |  | 	n, err := ParseNode(rawurl) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic("invalid node URL: " + err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return n | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NodeID is a unique identifier for each node. | 
					
						
							|  |  |  | // The node identifier is a marshaled elliptic curve public key. | 
					
						
							| 
									
										
										
										
											2015-02-12 11:59:52 +01:00
										 |  |  | type NodeID [nodeIDBits / 8]byte | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // NodeID prints as a long hexadecimal number. | 
					
						
							|  |  |  | func (n NodeID) String() string { | 
					
						
							| 
									
										
										
										
											2015-03-20 12:52:03 +01:00
										 |  |  | 	return fmt.Sprintf("%x", n[:]) | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The Go syntax representation of a NodeID is a call to HexID. | 
					
						
							|  |  |  | func (n NodeID) GoString() string { | 
					
						
							| 
									
										
										
										
											2015-03-20 12:52:03 +01:00
										 |  |  | 	return fmt.Sprintf("discover.HexID(\"%x\")", n[:]) | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // HexID converts a hex string to a NodeID. | 
					
						
							|  |  |  | // The string may be prefixed with 0x. | 
					
						
							|  |  |  | func HexID(in string) (NodeID, error) { | 
					
						
							|  |  |  | 	if strings.HasPrefix(in, "0x") { | 
					
						
							|  |  |  | 		in = in[2:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var id NodeID | 
					
						
							|  |  |  | 	b, err := hex.DecodeString(in) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return id, err | 
					
						
							|  |  |  | 	} else if len(b) != len(id) { | 
					
						
							| 
									
										
										
										
											2015-10-22 23:46:01 +02:00
										 |  |  | 		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	copy(id[:], b) | 
					
						
							|  |  |  | 	return id, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MustHexID converts a hex string to a NodeID. | 
					
						
							|  |  |  | // It panics if the string is not a valid NodeID. | 
					
						
							|  |  |  | func MustHexID(in string) NodeID { | 
					
						
							|  |  |  | 	id, err := HexID(in) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return id | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // PubkeyID returns a marshaled representation of the given public key. | 
					
						
							|  |  |  | func PubkeyID(pub *ecdsa.PublicKey) NodeID { | 
					
						
							|  |  |  | 	var id NodeID | 
					
						
							|  |  |  | 	pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) | 
					
						
							|  |  |  | 	if len(pbytes)-1 != len(id) { | 
					
						
							|  |  |  | 		panic(fmt.Errorf("need %d bit pubkey, got %d bits", (len(id)+1)*8, len(pbytes))) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	copy(id[:], pbytes[1:]) | 
					
						
							|  |  |  | 	return id | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-02 15:26:24 +01:00
										 |  |  | // Pubkey returns the public key represented by the node ID. | 
					
						
							|  |  |  | // It returns an error if the ID is not a point on the curve. | 
					
						
							|  |  |  | func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { | 
					
						
							| 
									
										
										
										
											2015-09-29 19:37:44 +02:00
										 |  |  | 	p := &ecdsa.PublicKey{Curve: secp256k1.S256(), X: new(big.Int), Y: new(big.Int)} | 
					
						
							| 
									
										
										
										
											2015-03-02 15:26:24 +01:00
										 |  |  | 	half := len(id) / 2 | 
					
						
							|  |  |  | 	p.X.SetBytes(id[:half]) | 
					
						
							|  |  |  | 	p.Y.SetBytes(id[half:]) | 
					
						
							|  |  |  | 	if !p.Curve.IsOnCurve(p.X, p.Y) { | 
					
						
							| 
									
										
										
										
											2015-12-07 12:06:49 +01:00
										 |  |  | 		return nil, errors.New("id is invalid secp256k1 curve point") | 
					
						
							| 
									
										
										
										
											2015-03-02 15:26:24 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return p, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | // recoverNodeID computes the public key used to sign the | 
					
						
							|  |  |  | // given hash from the signature. | 
					
						
							|  |  |  | func recoverNodeID(hash, sig []byte) (id NodeID, err error) { | 
					
						
							|  |  |  | 	pubkey, err := secp256k1.RecoverPubkey(hash, sig) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return id, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(pubkey)-1 != len(id) { | 
					
						
							|  |  |  | 		return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id)+1)*8) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := range id { | 
					
						
							|  |  |  | 		id[i] = pubkey[i+1] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return id, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // distcmp compares the distances a->target and b->target. | 
					
						
							|  |  |  | // Returns -1 if a is closer to target, 1 if b is closer to target | 
					
						
							|  |  |  | // and 0 if they are equal. | 
					
						
							| 
									
										
										
										
											2015-04-27 00:50:18 +02:00
										 |  |  | func distcmp(target, a, b common.Hash) int { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	for i := range target { | 
					
						
							|  |  |  | 		da := a[i] ^ target[i] | 
					
						
							|  |  |  | 		db := b[i] ^ target[i] | 
					
						
							|  |  |  | 		if da > db { | 
					
						
							|  |  |  | 			return 1 | 
					
						
							|  |  |  | 		} else if da < db { | 
					
						
							|  |  |  | 			return -1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // table of leading zero counts for bytes [0..255] | 
					
						
							|  |  |  | var lzcount = [256]int{ | 
					
						
							|  |  |  | 	8, 7, 6, 6, 5, 5, 5, 5, | 
					
						
							|  |  |  | 	4, 4, 4, 4, 4, 4, 4, 4, | 
					
						
							|  |  |  | 	3, 3, 3, 3, 3, 3, 3, 3, | 
					
						
							|  |  |  | 	3, 3, 3, 3, 3, 3, 3, 3, | 
					
						
							|  |  |  | 	2, 2, 2, 2, 2, 2, 2, 2, | 
					
						
							|  |  |  | 	2, 2, 2, 2, 2, 2, 2, 2, | 
					
						
							|  |  |  | 	2, 2, 2, 2, 2, 2, 2, 2, | 
					
						
							|  |  |  | 	2, 2, 2, 2, 2, 2, 2, 2, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // logdist returns the logarithmic distance between a and b, log2(a ^ b). | 
					
						
							| 
									
										
										
										
											2015-04-27 00:50:18 +02:00
										 |  |  | func logdist(a, b common.Hash) int { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	lz := 0 | 
					
						
							|  |  |  | 	for i := range a { | 
					
						
							|  |  |  | 		x := a[i] ^ b[i] | 
					
						
							|  |  |  | 		if x == 0 { | 
					
						
							|  |  |  | 			lz += 8 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			lz += lzcount[x] | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return len(a)*8 - lz | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-27 00:50:18 +02:00
										 |  |  | // hashAtDistance returns a random hash such that logdist(a, b) == n | 
					
						
							|  |  |  | func hashAtDistance(a common.Hash, n int) (b common.Hash) { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	if n == 0 { | 
					
						
							|  |  |  | 		return a | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// flip bit at position n, fill the rest with random bits | 
					
						
							|  |  |  | 	b = a | 
					
						
							|  |  |  | 	pos := len(a) - n/8 - 1 | 
					
						
							|  |  |  | 	bit := byte(0x01) << (byte(n%8) - 1) | 
					
						
							|  |  |  | 	if bit == 0 { | 
					
						
							|  |  |  | 		pos++ | 
					
						
							|  |  |  | 		bit = 0x80 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits | 
					
						
							|  |  |  | 	for i := pos + 1; i < len(a); i++ { | 
					
						
							|  |  |  | 		b[i] = byte(rand.Intn(255)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return b | 
					
						
							|  |  |  | } |