-
Notifications
You must be signed in to change notification settings - Fork 107
/
ec_recover.nim
104 lines (81 loc) · 3.49 KB
/
ec_recover.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http:https://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
##
## Address Cache for Clique PoA Consensus Protocol
## ===============================================
##
## For details see
## `EIP-225 <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-225.md>`_
## and
## `go-ethereum <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-225.md>`_
##
import
../../../utils,
../../../utils/lru_cache,
../clique_defs,
../clique_helpers,
eth/[common, keys, rlp],
stint
type
# simplify Hash256 for rlp serialisation
EcKey32 = array[32, byte]
EcRecover* = LruCache[BlockHeader,EcKey32,EthAddress,CliqueError]
{.push raises: [Defect].}
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc initEcRecover*(cache: var EcRecover) =
var toKey: LruKey[BlockHeader,EcKey32] =
# Use the seal hash for cache lookup
proc(header:BlockHeader): EcKey32 =
## If the signature's already cached, return that
# clique/clique.go(148): hash := header.Hash()
header.hash.data
var toValue: LruValue[BlockHeader,EthAddress,CliqueError] =
# Retrieve signature from the header's extra data fields
proc(header: BlockHeader): Result[EthAddress,CliqueError] =
# Extract signature from extra data field (last 65 bytes)
let msg = header.extraData
# clique/clique.go(153): if len(header.Extra) < extraSeal {
if msg.len < EXTRA_SEAL:
return err((errMissingSignature,""))
let sig = Signature.fromRaw(
msg.toOpenArray(msg.len - EXTRA_SEAL, msg.high))
if sig.isErr:
return err((errSkSigResult,$sig.error))
# Recover the public key from signature and seal hash
# clique/clique.go(159): pubkey, err := crypto.Ecrecover( [..]
let pubKey = recover(sig.value, SKMessage(header.hashSealHeader.data))
if pubKey.isErr:
return err((errSkPubKeyResult,$pubKey.error))
# Convert public key to address.
return ok(pubKey.value.toCanonicalAddress)
cache.initCache(toKey, toValue, INMEMORY_SIGNATURES)
proc initEcRecover*: EcRecover {.gcsafe, raises: [Defect].} =
result.initEcRecover
# clique/clique.go(145): func ecrecover(header [..]
proc getEcRecover*(addrCache: var EcRecover; header: BlockHeader): auto {.
gcsafe, raises: [Defect,CatchableError].} =
## extract Ethereum account address from a signed header block, the relevant
## signature used is appended to the re-purposed extra data field
addrCache.getItem(header)
proc append*(rw: var RlpWriter; ecRec: EcRecover) {.
inline, raises: [Defect,KeyError].} =
## Generic support for `rlp.encode(ecRec)`
rw.append(ecRec.data)
proc read*(rlp: var Rlp; Q: type EcRecover): Q {.
inline, raises: [Defect,KeyError].} =
## Generic support for `rlp.decode(bytes)` for loading the cache from a
## serialised data stream.
result.initEcRecover
result.data = rlp.read(type result.data)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------