forked from ledgerwatch/erigon
/
keygen.go
77 lines (63 loc) · 1.47 KB
/
keygen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package observer
import (
"context"
"crypto/ecdsa"
"time"
"github.com/nebojsa94/erigon/crypto"
"github.com/nebojsa94/erigon/p2p/enode"
"github.com/ledgerwatch/log/v3"
)
func keygen(
parentContext context.Context,
targetKey *ecdsa.PublicKey,
timeout time.Duration,
concurrencyLimit uint,
logger log.Logger,
) []*ecdsa.PublicKey {
ctx, cancel := context.WithTimeout(parentContext, timeout)
defer cancel()
targetID := enode.PubkeyToIDV4(targetKey)
cpus := concurrencyLimit
type result struct {
key *ecdsa.PublicKey
distance int
}
generatedKeys := make(chan result, cpus)
for i := uint(0); i < cpus; i++ {
go func() {
for ctx.Err() == nil {
keyPair, err := crypto.GenerateKey()
if err != nil {
logger.Error("keygen has failed to generate a key", "err", err)
break
}
key := &keyPair.PublicKey
id := enode.PubkeyToIDV4(key)
distance := enode.LogDist(targetID, id)
select {
case generatedKeys <- result{key, distance}:
case <-ctx.Done():
break
}
}
}()
}
keysAtDist := make(map[int]*ecdsa.PublicKey)
for ctx.Err() == nil {
select {
case res := <-generatedKeys:
keysAtDist[res.distance] = res.key
case <-ctx.Done():
break
}
}
keys := valuesOfIntToPubkeyMap(keysAtDist)
return keys
}
func valuesOfIntToPubkeyMap(m map[int]*ecdsa.PublicKey) []*ecdsa.PublicKey {
values := make([]*ecdsa.PublicKey, 0, len(m))
for _, value := range m {
values = append(values, value)
}
return values
}