2021-09-07 12:30:12 +00:00
|
|
|
# Nimbus
|
2024-05-30 12:54:03 +00:00
|
|
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
2021-09-07 12:30:12 +00:00
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
|
|
# at your option.
|
|
|
|
# This file may not be copied, modified, or distributed except according to
|
|
|
|
# those terms.
|
|
|
|
|
|
|
|
import
|
2022-07-27 16:07:54 +00:00
|
|
|
std/[strutils, os],
|
2022-12-02 04:39:12 +00:00
|
|
|
manager,
|
2024-05-30 12:54:03 +00:00
|
|
|
stew/[io2, byteutils],
|
|
|
|
results,
|
2024-10-16 01:34:12 +00:00
|
|
|
eth/common/keys
|
2021-09-07 12:30:12 +00:00
|
|
|
|
|
|
|
export manager
|
|
|
|
|
2023-01-31 01:32:17 +00:00
|
|
|
{.push raises: [].}
|
|
|
|
|
2021-09-07 12:30:12 +00:00
|
|
|
type
|
|
|
|
EthContext* = ref object
|
|
|
|
am*: AccountsManager
|
2021-09-07 13:45:01 +00:00
|
|
|
# You should only create one instance of the RNG per application / library
|
|
|
|
# Ref is used so that it can be shared between components
|
2022-07-04 07:38:02 +00:00
|
|
|
rng*: ref HmacDrbgContext
|
2021-09-07 12:30:12 +00:00
|
|
|
|
|
|
|
proc newEthContext*(): EthContext =
|
|
|
|
result = new(EthContext)
|
|
|
|
result.am = AccountsManager.init()
|
2021-09-07 13:45:01 +00:00
|
|
|
result.rng = newRng()
|
|
|
|
|
|
|
|
proc randomPrivateKey*(ctx: EthContext): PrivateKey =
|
|
|
|
random(PrivateKey, ctx.rng[])
|
|
|
|
|
|
|
|
proc randomKeyPair*(ctx: EthContext): KeyPair =
|
|
|
|
random(KeyPair, ctx.rng[])
|
|
|
|
|
2022-07-27 16:07:54 +00:00
|
|
|
proc containsOnlyHexDigits(hex: string): bool =
|
|
|
|
const HexDigitsX = HexDigits + {'x'}
|
|
|
|
for c in hex:
|
|
|
|
if c notin HexDigitsX:
|
|
|
|
return false
|
|
|
|
true
|
|
|
|
|
2023-01-31 01:32:17 +00:00
|
|
|
proc getNetKeys*(ctx: EthContext, netKey, dataDir: string): Result[KeyPair, string]
|
|
|
|
{.gcsafe, raises: [OSError]} =
|
2022-07-27 16:07:54 +00:00
|
|
|
if netKey.len == 0 or netKey == "random":
|
2021-09-07 13:45:01 +00:00
|
|
|
let privateKey = ctx.randomPrivateKey()
|
2022-07-27 16:07:54 +00:00
|
|
|
return ok(privateKey.toKeyPair())
|
|
|
|
elif netKey.len in {64, 66} and netKey.containsOnlyHexDigits:
|
|
|
|
let res = PrivateKey.fromHex(netKey)
|
2021-09-07 13:45:01 +00:00
|
|
|
if res.isErr:
|
|
|
|
return err($res.error)
|
2022-07-27 16:07:54 +00:00
|
|
|
return ok(res.get().toKeyPair())
|
|
|
|
else:
|
|
|
|
# TODO: should we secure the private key with
|
|
|
|
# keystore encryption?
|
|
|
|
if fileAccessible(netKey, {AccessFlags.Find}):
|
|
|
|
try:
|
|
|
|
let lines = netKey.readLines(1)
|
|
|
|
if lines.len == 0:
|
|
|
|
return err("empty network key file")
|
|
|
|
let rc = PrivateKey.fromHex(lines[0])
|
|
|
|
if rc.isErr:
|
|
|
|
return err($rc.error)
|
|
|
|
return ok(rc.get().toKeyPair())
|
|
|
|
except IOError as e:
|
|
|
|
return err("cannot open network key file: " & e.msg)
|
|
|
|
except ValueError as ex:
|
|
|
|
return err("invalid hex string in network key file: " & ex.msg)
|
|
|
|
else:
|
|
|
|
let privateKey = ctx.randomPrivateKey()
|
|
|
|
|
|
|
|
try:
|
|
|
|
createDir(netKey.splitFile.dir)
|
|
|
|
netKey.writeFile(privateKey.toRaw.to0xHex)
|
|
|
|
except IOError as e:
|
|
|
|
return err("could not write network key file: " & e.msg)
|
|
|
|
|
|
|
|
return ok(privateKey.toKeyPair())
|