Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Allow deterministic key generation from seed
Browse files Browse the repository at this point in the history
  • Loading branch information
thattommyhall committed Jul 24, 2021
1 parent caa90ea commit f79ca70
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 3 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ Usage of hydra-booster:
Specify the DHT protocol prefix (default "/ipfs") (default "/ipfs")
-pstore string
Peerstore directory for LevelDB store (defaults to in-memory store)
-random-seed string
Seed to use to generate IDs (useful if you want to have persistent IDs). Should be Base64 encoded and 256bits
-stagger duration
Duration to stagger nodes starts by
-ui-theme string
Expand Down Expand Up @@ -135,6 +137,8 @@ Alternatively, some flags can be set via environment variables. Note that flags
Specify the number of Hydra heads to create. (default -1)
HYDRA_PORT_BEGIN int
If set, begin port allocation here (default -1)
HYDRA_RANDOM_SEED string
Seed to use to generate IDs (useful if you want to have persistent IDs). Should be Base64 encoded and 256bits
```

### Best Practices
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ require (
github.com/prometheus/client_golang v1.7.1
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee
go.opencensus.io v0.22.5
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
)

go 1.14
23 changes: 20 additions & 3 deletions idgen/idgen.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package idgen

import (
"crypto/rand"
"crypto/sha256"
"fmt"
"io"
"math/bits"
"sync"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
kbucket "github.com/libp2p/go-libp2p-kbucket"
"golang.org/x/crypto/hkdf"
)

// HydraIdentityGenerator is a shared balanced ID generator.
Expand All @@ -34,12 +38,25 @@ type BalancedIdentityGenerator struct {
sync.Mutex
xorTrie *XorTrie
count int
reader io.Reader
}

// NewBalancedIdentityGenerator creates a new balanced identity generator.
func NewBalancedIdentityGenerator() *BalancedIdentityGenerator {
return &BalancedIdentityGenerator{
xorTrie: NewXorTrie(),
reader: rand.Reader,
}
}

func NewBalancedIdentityGeneratorFromSeed(seed []byte) *BalancedIdentityGenerator {
hash := sha256.New
info := []byte("hydra keys")
hkdf := hkdf.New(hash, seed, nil, info)

return &BalancedIdentityGenerator{
xorTrie: NewXorTrie(),
reader: hkdf,
}
}

Expand Down Expand Up @@ -85,7 +102,7 @@ func (bg *BalancedIdentityGenerator) AddBalanced() (crypto.PrivKey, error) {

func (bg *BalancedIdentityGenerator) genUniqueID() (privKey crypto.PrivKey, trieKey TrieKey, depth int, err error) {
for {
if privKey, trieKey, err = genID(); err != nil {
if privKey, trieKey, err = bg.genID(); err != nil {
return nil, nil, 0, err
}
if depth, ok := bg.xorTrie.Insert(trieKey); ok {
Expand Down Expand Up @@ -121,8 +138,8 @@ func (bg *BalancedIdentityGenerator) Depth() int {
return bg.xorTrie.Depth()
}

func genID() (crypto.PrivKey, TrieKey, error) {
privKey, _, err := crypto.GenerateKeyPair(crypto.Ed25519, 0)
func (bg *BalancedIdentityGenerator) genID() (crypto.PrivKey, TrieKey, error) {
privKey, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 0, bg.reader)
if err != nil {
return nil, nil, fmt.Errorf("generating private key for trie, %w", err)
}
Expand Down
18 changes: 18 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"encoding/base64"
"flag"
"fmt"
"log"
Expand Down Expand Up @@ -35,6 +36,7 @@ const (
func main() {
start := time.Now()
nheads := flag.Int("nheads", -1, "Specify the number of Hydra heads to create.")
randomSeed := flag.String("random-seed", "", "Seed to use to generate IDs (useful if you want to have persistent IDs). Should be Base64 encoded and 256bits")
dbpath := flag.String("db", "", "Datastore directory (for LevelDB store) or postgresql:// connection URI (for PostgreSQL store)")
pstorePath := flag.String("pstore", "", "Peerstore directory for LevelDB store (defaults to in-memory store)")
httpAPIAddr := flag.String("httpapi-addr", defaultHTTPAPIAddr, "Specify an IP and port to run the HTTP API server on")
Expand Down Expand Up @@ -71,6 +73,9 @@ func main() {
if *nheads == -1 {
*nheads = mustGetEnvInt("HYDRA_NHEADS", 1)
}
if *randomSeed == "" {
*randomSeed = os.Getenv("HYDRA_RANDOM_SEED")
}
if *portBegin == -1 {
*portBegin = mustGetEnvInt("HYDRA_PORT_BEGIN", 0)
}
Expand Down Expand Up @@ -110,6 +115,19 @@ func main() {
defer cancel()

var idGenerator idgen.IdentityGenerator
if *randomSeed != "" && *idgenAddr != "" {
log.Fatalln("error: Should not set both idgen-addr and random-seed")
}
if *randomSeed != "" {
seed, err := base64.StdEncoding.DecodeString(*randomSeed)
if err != nil {
log.Fatalln("error: Could not base64 decode seed")
}
if len(seed) != 32 {
log.Fatalln("error: Seed should be 256bit in base64")
}
idGenerator = idgen.NewBalancedIdentityGeneratorFromSeed(seed)
}
if *idgenAddr != "" {
dg := idgen.NewCleaningIDGenerator(idgen.NewDelegatedIDGenerator(*idgenAddr))
defer func() {
Expand Down

0 comments on commit f79ca70

Please sign in to comment.