storj/pkg/identity/generate.go

83 lines
1.9 KiB
Go

// Copyright (c) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package identity
import (
"context"
"crypto"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj"
)
// GenerateKey generates a private key with a node id with difficulty at least
// minDifficulty. No parallelism is used.
func GenerateKey(ctx context.Context, minDifficulty uint16, version storj.IDVersion) (
k crypto.PrivateKey, id storj.NodeID, err error) {
defer mon.Task()(&ctx)(&err)
var d uint16
for {
err = ctx.Err()
if err != nil {
break
}
k, err = version.NewPrivateKey()
if err != nil {
break
}
id, err = NodeIDFromKey(pkcrypto.PublicKeyFromPrivate(k), version)
if err != nil {
break
}
d, err = id.Difficulty()
if err != nil {
break
}
if d >= minDifficulty {
return k, id, nil
}
}
return k, id, storj.ErrNodeID.Wrap(err)
}
// GenerateCallback indicates that key generation is done when done is true.
// if err != nil key generation will stop with that error
type GenerateCallback func(crypto.PrivateKey, storj.NodeID) (done bool, err error)
// GenerateKeys continues to generate keys until found returns done == false,
// or the ctx is canceled.
func GenerateKeys(ctx context.Context, minDifficulty uint16, concurrency int, version storj.IDVersion, found GenerateCallback) (err error) {
defer mon.Task()(&ctx)(&err)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
errchan := make(chan error, concurrency)
for i := 0; i < concurrency; i++ {
go func() {
for {
k, id, err := GenerateKey(ctx, minDifficulty, version)
if err != nil {
errchan <- err
return
}
done, err := found(k, id)
if err != nil {
errchan <- err
return
}
if done {
errchan <- nil
return
}
}
}()
}
// we only care about the first error. the rest of the errors will be
// context cancellation errors
return <-errchan
}