2019-01-07 18:02:22 +00:00
|
|
|
// Copyright (c) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package identity
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-02-07 20:39:20 +00:00
|
|
|
"crypto"
|
2019-01-07 18:02:22 +00:00
|
|
|
|
2019-02-07 09:04:29 +00:00
|
|
|
"storj.io/storj/pkg/pkcrypto"
|
2019-01-07 18:02:22 +00:00
|
|
|
"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) (
|
2019-02-07 20:39:20 +00:00
|
|
|
k crypto.PrivateKey, id storj.NodeID, err error) {
|
2019-01-07 18:02:22 +00:00
|
|
|
var d uint16
|
|
|
|
for {
|
|
|
|
err = ctx.Err()
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2019-02-07 09:04:29 +00:00
|
|
|
k, err = pkcrypto.GeneratePrivateKey()
|
2019-01-07 18:02:22 +00:00
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2019-02-07 20:39:20 +00:00
|
|
|
id, err = NodeIDFromKey(pkcrypto.PublicKeyFromPrivate(k))
|
2019-01-07 18:02:22 +00:00
|
|
|
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
|
2019-02-07 20:39:20 +00:00
|
|
|
type GenerateCallback func(crypto.PrivateKey, storj.NodeID) (done bool, err error)
|
2019-01-07 18:02:22 +00:00
|
|
|
|
|
|
|
// GenerateKeys continues to generate keys until found returns done == false,
|
|
|
|
// or the ctx is canceled.
|
|
|
|
func GenerateKeys(ctx context.Context, minDifficulty uint16, concurrency int, found GenerateCallback) error {
|
|
|
|
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)
|
|
|
|
if err != nil {
|
|
|
|
errchan <- err
|
|
|
|
return
|
|
|
|
}
|
2019-02-06 08:04:12 +00:00
|
|
|
|
2019-01-07 18:02:22 +00:00
|
|
|
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
|
|
|
|
}
|