2023-06-19 22:43:50 +00:00
|
|
|
# beacon_chain
|
|
|
|
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
2022-05-17 13:50:49 +00:00
|
|
|
import
|
|
|
|
std/os,
|
2023-06-19 22:43:50 +00:00
|
|
|
confutils,
|
2022-05-17 13:50:49 +00:00
|
|
|
../beacon_chain/validators/keystore_management,
|
|
|
|
../beacon_chain/spec/[keystore, crypto],
|
|
|
|
../beacon_chain/conf
|
|
|
|
|
|
|
|
type
|
|
|
|
Config = object
|
|
|
|
threshold {.
|
|
|
|
desc: "Used to generate distributed keys"
|
|
|
|
name: "threshold" }: uint32
|
|
|
|
|
|
|
|
remoteSignersUrls {.
|
|
|
|
desc: "URLs of the remote signers"
|
|
|
|
name: "remote-signer" }: seq[string]
|
|
|
|
|
|
|
|
dataDir {.
|
|
|
|
defaultValue: config.defaultDataDir()
|
|
|
|
defaultValueDesc: ""
|
|
|
|
desc: "A Nimbus data directory"
|
|
|
|
name: "data-dir" }: InputDir
|
|
|
|
|
|
|
|
validatorsDirFlag* {.
|
|
|
|
desc: "A directory containing validator keystores"
|
|
|
|
name: "validators-dir" }: Option[InputDir]
|
|
|
|
|
|
|
|
secretsDirFlag* {.
|
|
|
|
desc: "A directory containing validator keystore passwords"
|
|
|
|
name: "secrets-dir" }: Option[InputDir]
|
|
|
|
|
|
|
|
key {.
|
|
|
|
desc: "A public key of the keystore"
|
|
|
|
name: "key" }: string
|
|
|
|
|
|
|
|
outDir {.
|
|
|
|
desc: "A directory to store the generated validator keystores"
|
|
|
|
name: "out-dir" }: OutDir
|
|
|
|
|
|
|
|
template valueOr(x: Option, elseBlock: untyped): untyped =
|
|
|
|
let val = x
|
|
|
|
if val.isSome:
|
|
|
|
val.get
|
|
|
|
else:
|
|
|
|
elseBlock
|
|
|
|
|
|
|
|
proc main =
|
|
|
|
let conf = load Config
|
|
|
|
if conf.threshold == 0:
|
|
|
|
error "The specified treshold must be greater than zero"
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
if conf.remoteSignersUrls.len == 0:
|
|
|
|
error "Please specify at least one remote signer URL"
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
if conf.threshold > conf.remoteSignersUrls.len.uint32:
|
|
|
|
error "The specified treshold must be lower or equal to the number of signers"
|
|
|
|
quit 1
|
|
|
|
|
2023-06-19 22:43:50 +00:00
|
|
|
let rng = HmacDrbgContext.new()
|
|
|
|
template rngCtx: untyped = rng[]
|
2022-05-17 13:50:49 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
validatorsDir = conf.validatorsDir
|
|
|
|
secretsDir = conf.secretsDir
|
|
|
|
keystore = loadKeystore(validatorsDir,
|
|
|
|
secretsDir,
|
2023-02-16 17:25:48 +00:00
|
|
|
conf.key, true, nil).valueOr:
|
2022-05-17 13:50:49 +00:00
|
|
|
error "Can't load keystore", validatorsDir, secretsDir, pubkey = conf.key
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
signingPubKey = keystore.pubkey
|
|
|
|
sharesCount = uint32 conf.remoteSignersUrls.len
|
|
|
|
shares = generateSecretShares(keystore.privateKey,
|
|
|
|
rngCtx,
|
|
|
|
conf.threshold,
|
|
|
|
sharesCount).valueOr:
|
|
|
|
error "Failed to generate distributed key: ",
|
|
|
|
threshold = conf.threshold, sharesCount
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
if not signingPubKey.confirmShares(shares, rngCtx):
|
|
|
|
error "Secret shares can't reconstruct original signature. " &
|
|
|
|
"Distributed key will not be generated."
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
let
|
|
|
|
outSharesDir = conf.outDir / "shares"
|
2023-02-16 17:25:48 +00:00
|
|
|
status = generateDistributedStore(
|
2022-05-17 13:50:49 +00:00
|
|
|
rngCtx,
|
|
|
|
shares,
|
|
|
|
signingPubKey,
|
|
|
|
0,
|
|
|
|
outSharesDir / "secrets",
|
|
|
|
outSharesDir / "validators",
|
|
|
|
string conf.outDir,
|
|
|
|
conf.remoteSignersUrls,
|
|
|
|
conf.threshold)
|
|
|
|
|
|
|
|
if status.isErr:
|
|
|
|
error "Failed to generate distributed keystore", err = status.error
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
main()
|