Update to BLS v0.10.1
This commit is contained in:
parent
c418bf2b24
commit
bfd4df912e
|
@ -31,7 +31,7 @@ proc combine*(tgt: var Attestation, src: Attestation, flags: UpdateFlags) =
|
|||
tgt.aggregation_bits.combine(src.aggregation_bits)
|
||||
|
||||
if skipBlsValidation notin flags:
|
||||
tgt.signature.combine(src.signature)
|
||||
tgt.signature.aggregate(src.signature)
|
||||
else:
|
||||
trace "Ignoring overlapping attestations"
|
||||
|
||||
|
@ -341,7 +341,7 @@ proc getAttestationsForBlock*(
|
|||
# one new attestation in there
|
||||
if not attestation.aggregation_bits.overlaps(v.aggregation_bits):
|
||||
attestation.aggregation_bits.combine(v.aggregation_bits)
|
||||
attestation.signature.combine(v.aggregate_signature)
|
||||
attestation.signature.aggregate(v.aggregate_signature)
|
||||
|
||||
result.add(attestation)
|
||||
|
||||
|
|
|
@ -293,4 +293,3 @@ iterator validatorKeys*(conf: BeaconNodeConf): ValidatorPrivKey =
|
|||
template writeValue*(writer: var JsonWriter,
|
||||
value: TypedInputFile|InputFile|InputDir|OutPath|OutDir|OutFile) =
|
||||
writer.writeValue(string value)
|
||||
|
||||
|
|
|
@ -15,24 +15,19 @@ func get_eth1data_stub*(deposit_count: uint64, current_epoch: Epoch): Eth1Data =
|
|||
block_hash: hash_tree_root(hash_tree_root(voting_period).data),
|
||||
)
|
||||
|
||||
when ValidatorPrivKey is BlsValue:
|
||||
func makeInteropPrivKey*(i: int): ValidatorPrivKey =
|
||||
discard
|
||||
{.fatal: "todo/unused?".}
|
||||
else:
|
||||
func makeInteropPrivKey*(i: int): ValidatorPrivKey =
|
||||
var bytes: array[32, byte]
|
||||
bytes[0..7] = uint64(i).toBytesLE()
|
||||
func makeInteropPrivKey*(i: int): ValidatorPrivKey =
|
||||
var bytes: array[32, byte]
|
||||
bytes[0..7] = uint64(i).toBytesLE()
|
||||
|
||||
let
|
||||
# BLS381-12 curve order - same as milagro but formatted different
|
||||
curveOrder =
|
||||
"52435875175126190479447740508185965837690552500527637822603658699938581184513".parse(UInt256)
|
||||
let
|
||||
# BLS381-12 curve order - same as milagro but formatted different
|
||||
curveOrder =
|
||||
"52435875175126190479447740508185965837690552500527637822603658699938581184513".parse(UInt256)
|
||||
|
||||
privkeyBytes = eth2hash(bytes)
|
||||
key = (UInt256.fromBytesLE(privkeyBytes.data) mod curveOrder).toBytesBE()
|
||||
privkeyBytes = eth2hash(bytes)
|
||||
key = (UInt256.fromBytesLE(privkeyBytes.data) mod curveOrder).toBytesBE()
|
||||
|
||||
ValidatorPrivKey.init(key)
|
||||
result.initFromBytes(key)
|
||||
|
||||
const eth1BlockHash* = block:
|
||||
var x: Eth2Digest
|
||||
|
@ -56,10 +51,10 @@ func makeDeposit*(
|
|||
pubkey: pubkey,
|
||||
withdrawal_credentials: makeWithdrawalCredentials(pubkey)))
|
||||
|
||||
if skipBlsValidation notin flags:
|
||||
ret.data.signature =
|
||||
bls_sign(
|
||||
privkey, hash_tree_root(ret.getDepositMessage).data,
|
||||
compute_domain(DOMAIN_DEPOSIT))
|
||||
if skipBLSValidation notin flags:
|
||||
let domain = compute_domain(DOMAIN_DEPOSIT)
|
||||
let signing_root = compute_signing_root(ret.getDepositMessage, domain)
|
||||
|
||||
ret.data.signature = bls_sign(privkey, signing_root.data)
|
||||
|
||||
ret
|
||||
|
|
|
@ -73,9 +73,11 @@ proc process_deposit*(
|
|||
|
||||
if index == -1:
|
||||
# Verify the deposit signature (proof of possession)
|
||||
if skipBlsValidation notin flags and not bls_verify(
|
||||
pubkey, hash_tree_root(deposit.getDepositMessage).data,
|
||||
deposit.data.signature, compute_domain(DOMAIN_DEPOSIT)):
|
||||
let domain = compute_domain(DOMAIN_DEPOSIT)
|
||||
let signing_root = compute_signing_root(deposit.getDepositMessage, domain)
|
||||
if skipBLSValidation notin flags and not bls_verify(
|
||||
pubkey, signing_root.data,
|
||||
deposit.data.signature):
|
||||
return false
|
||||
|
||||
# Add validator and balance entries
|
||||
|
@ -214,7 +216,7 @@ func initialize_beacon_state_from_eth1*(
|
|||
latest_block_header:
|
||||
BeaconBlockHeader(
|
||||
body_root: hash_tree_root(BeaconBlockBody(
|
||||
randao_reveal: BlsValue[Signature](kind: OpaqueBlob)
|
||||
randao_reveal: ValidatorSig(kind: OpaqueBlob)
|
||||
))
|
||||
)
|
||||
)
|
||||
|
@ -263,7 +265,7 @@ func get_initial_beacon_block*(state: BeaconState): SignedBeaconBlock =
|
|||
state_root: hash_tree_root(state),
|
||||
body: BeaconBlockBody(
|
||||
# TODO: This shouldn't be necessary if OpaqueBlob is the default
|
||||
randao_reveal: BlsValue[Signature](kind: OpaqueBlob))))
|
||||
randao_reveal: ValidatorSig(kind: OpaqueBlob))))
|
||||
# parent_root, randao_reveal, eth1_data, signature, and body automatically
|
||||
# initialized to default values.
|
||||
|
||||
|
@ -381,13 +383,13 @@ proc is_valid_indexed_attestation*(
|
|||
return false
|
||||
|
||||
# Verify aggregate signature
|
||||
if skipBlsValidation notin flags and not bls_verify(
|
||||
bls_aggregate_pubkeys(mapIt(indices, state.validators[it.int].pubkey)),
|
||||
hash_tree_root(indexed_attestation.data).data,
|
||||
indexed_attestation.signature,
|
||||
get_domain(
|
||||
state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
|
||||
):
|
||||
let pubkeys = mapIt(indices, state.validators[it.int].pubkey) # TODO: fuse loops with blsFastAggregateVerify
|
||||
let domain = state.get_domain(DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
|
||||
let signing_root = compute_signing_root(indexed_attestation.data, domain)
|
||||
if skipBLSValidation notin flags and
|
||||
not blsFastAggregateVerify(
|
||||
pubkeys, signing_root.data, indexed_attestation.signature
|
||||
):
|
||||
notice "indexed attestation: signature verification failure"
|
||||
return false
|
||||
|
||||
|
|
|
@ -22,18 +22,26 @@
|
|||
# even if in theory it is possible to allow this in BLS.
|
||||
|
||||
import
|
||||
stew/[endians2, objects, byteutils], hashes, nimcrypto/utils,
|
||||
# Internal
|
||||
./digest,
|
||||
# Status
|
||||
stew/[endians2, objects, byteutils],
|
||||
nimcrypto/[utils, sysrand],
|
||||
blscurve, json_serialization,
|
||||
digest,
|
||||
chronicles
|
||||
chronicles,
|
||||
# Standard library
|
||||
hashes
|
||||
|
||||
export
|
||||
json_serialization
|
||||
|
||||
export
|
||||
blscurve.init, blscurve.getBytes, blscurve.combine,
|
||||
blscurve.`$`, blscurve.`==`,
|
||||
blscurve.Signature
|
||||
# export
|
||||
# blscurve.init, blscurve.getBytes, blscurve.combine,
|
||||
# blscurve.`$`, blscurve.`==`,
|
||||
# blscurve.Signature
|
||||
|
||||
# Type definitions
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
type
|
||||
BlsValueType* = enum
|
||||
|
@ -52,34 +60,22 @@ type
|
|||
else:
|
||||
blob*: array[48, byte]
|
||||
|
||||
ValidatorPubKey* = BlsValue[blscurve.VerKey]
|
||||
# ValidatorPubKey* = blscurve.VerKey
|
||||
ValidatorPubKey* = BlsValue[blscurve.PublicKey]
|
||||
# Alternatives
|
||||
# ValidatorPubKey* = blscurve.PublicKey
|
||||
# ValidatorPubKey* = array[48, byte]
|
||||
# The use of byte arrays proved to be a dead end pretty quickly.
|
||||
# Plenty of code needs to be modified for a successful build and
|
||||
# the changes will negatively affect the performance.
|
||||
|
||||
# ValidatorPubKey* = array[48, byte]
|
||||
# The use of byte arrays proved to be a dead end pretty quickly.
|
||||
# Plenty of code needs to be modified for a successful build and
|
||||
# the changes will negatively affect the performance.
|
||||
|
||||
# ValidatorPrivKey* = BlsValue[blscurve.SigKey]
|
||||
ValidatorPrivKey* = blscurve.SigKey
|
||||
ValidatorPrivKey* = blscurve.SecretKey
|
||||
# ValidatorPrivKey* = BlsValue[blscurve.SecretKey]
|
||||
|
||||
ValidatorSig* = BlsValue[blscurve.Signature]
|
||||
|
||||
BlsCurveType* = VerKey|SigKey|Signature
|
||||
BlsCurveType* = PublicKey|SecretKey|Signature
|
||||
ValidatorPKI* = ValidatorPrivKey|ValidatorPubKey|ValidatorSig
|
||||
|
||||
proc init*[T](BLS: type BlsValue[T], val: auto): BLS =
|
||||
result.kind = BlsValueType.Real
|
||||
result.blsValue = init(T, val)
|
||||
|
||||
func `$`*(x: BlsValue): string =
|
||||
if x.kind == Real:
|
||||
$x.blsValue
|
||||
else:
|
||||
# r: is short for random. The prefix must be short
|
||||
# due to the mechanics of the `shortLog` function.
|
||||
"r:" & toHex(x.blob, true)
|
||||
|
||||
func `==`*(a, b: BlsValue): bool =
|
||||
if a.kind != b.kind: return false
|
||||
if a.kind == Real:
|
||||
|
@ -87,11 +83,123 @@ func `==`*(a, b: BlsValue): bool =
|
|||
else:
|
||||
return a.blob == b.blob
|
||||
|
||||
func getBytes*(x: BlsValue): auto =
|
||||
if x.kind == Real:
|
||||
getBytes x.blsValue
|
||||
template `==`*[T](a: BlsValue[T], b: T): bool =
|
||||
a.blsValue == b
|
||||
|
||||
template `==`*[T](a: T, b: BlsValue[T]): bool =
|
||||
a == b.blsValue
|
||||
|
||||
# API
|
||||
# ----------------------------------------------------------------------
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#bls-signatures
|
||||
|
||||
func pubKey*(privkey: ValidatorPrivKey): ValidatorPubKey =
|
||||
## Create a private key from a public key
|
||||
# Un-specced in either hash-to-curve or Eth2
|
||||
# TODO: Test suite should use `keyGen` instead
|
||||
when ValidatorPubKey is BlsValue:
|
||||
ValidatorPubKey(kind: Real, blsValue: privkey.privToPub())
|
||||
elif ValidatorPubKey is array:
|
||||
privkey.getKey.getBytes
|
||||
else:
|
||||
x.blob
|
||||
privkey.getKey
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#bls-signatures
|
||||
func aggregate*[T](values: openarray[ValidatorSig]): ValidatorSig =
|
||||
## Aggregate arrays of sequences of Validator Signatures
|
||||
## This assumes that they are real signatures
|
||||
|
||||
result = BlsValue[T](kind: Real, blsValue: values[0].BlsValue)
|
||||
|
||||
for i in 1 ..< values.len:
|
||||
result.blsValue.aggregate(values[i].blsValue)
|
||||
|
||||
func aggregate*(x: var ValidatorSig, other: ValidatorSig) =
|
||||
## Aggregate 2 Validator Signatures
|
||||
## This assumes that they are real signatures
|
||||
x.blsValue.aggregate(other.blsValue)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#bls-signatures
|
||||
func blsVerify*(
|
||||
pubkey: ValidatorPubKey, message: openArray[byte],
|
||||
signature: ValidatorSig): bool =
|
||||
## Check that a signature is valid for a message
|
||||
## under the provided public key.
|
||||
## returns `true` if the signature is valid, `false` otherwise.
|
||||
##
|
||||
## The proof-of-possession MUST be verified before calling this function.
|
||||
## It is recommended to use the overload that accepts a proof-of-possession
|
||||
## to enforce correct usage.
|
||||
if signature.kind != Real:
|
||||
# Invalid signatures are possible in deposits (discussed with Danny)
|
||||
return false
|
||||
if pubkey.kind != Real:
|
||||
# TODO: chronicles warning
|
||||
return false
|
||||
|
||||
# TODO: remove fully if the comment below is not true anymore and
|
||||
# and we don't need this workaround
|
||||
# # TODO bls_verify_multiple(...) used to have this workaround, and now it
|
||||
# # lives here. No matter the signature, there's also no meaningful way to
|
||||
# # verify it -- it's a kind of vacuous truth. No pubkey/sig pairs. Sans a
|
||||
# # getBytes() or similar mechanism, pubKey == default(ValidatorPubKey) is
|
||||
# # a way to create many false positive matches. This seems odd.
|
||||
# if pubkey.getBytes() == default(ValidatorPubKey).getBytes():
|
||||
# return true
|
||||
pubkey.blsValue.verify(message, signature.blsValue)
|
||||
|
||||
func blsSign*(privkey: ValidatorPrivKey, message: openarray[byte]): ValidatorSig =
|
||||
## Computes a signature from a secret key and a message
|
||||
ValidatorSig(kind: Real, blsValue: privkey.sign(message))
|
||||
|
||||
func blsFastAggregateVerify*[T: byte|char](
|
||||
publicKeys: openarray[ValidatorPubKey],
|
||||
message: openarray[T],
|
||||
signature: ValidatorSig
|
||||
): bool =
|
||||
## Verify the aggregate of multiple signatures on the same message
|
||||
## This function is faster than AggregateVerify
|
||||
##
|
||||
## The proof-of-possession MUST be verified before calling this function.
|
||||
## It is recommended to use the overload that accepts a proof-of-possession
|
||||
## to enforce correct usage.
|
||||
# TODO: Note: `invalid` in the following paragraph means invalid by construction
|
||||
# The keys/signatures are not even points on the elliptic curves.
|
||||
# To respect both the IETF API and the fact that
|
||||
# we can have invalid public keys (as in not point on the elliptic curve),
|
||||
# requiring a wrapper indirection,
|
||||
# we need a first pass to extract keys from the wrapper
|
||||
# and then call fastAggregateVerify.
|
||||
# Instead:
|
||||
# - either we expose a new API: context + init-update-finish
|
||||
# in blscurve which already exists internally
|
||||
# - or at network/databases/serialization boundaries we do not
|
||||
# allow invalid BLS objects to pollute consensus routines
|
||||
if signature.kind != Real:
|
||||
return false
|
||||
var unwrapped: seq[PublicKey]
|
||||
for pubkey in publicKeys:
|
||||
if pubkey.kind != Real:
|
||||
return false
|
||||
unwrapped.add pubkey.blsValue
|
||||
return fastAggregateVerify(unwrapped, message, signature.blsValue)
|
||||
|
||||
proc newKeyPair*(): tuple[pub: ValidatorPubKey, priv: ValidatorPrivKey] {.noInit.}=
|
||||
## Generates a new public-private keypair
|
||||
## This requires entropy on the system
|
||||
# The input-keying-material requires 32 bytes at least for security
|
||||
# The generation is deterministic and the input-keying-material
|
||||
# must be protected against side-channel attacks
|
||||
|
||||
var ikm: array[32, byte]
|
||||
let written = randomBytes(ikm)
|
||||
doAssert written >= 32, "Key generation failure"
|
||||
|
||||
result.pub.kind = Real
|
||||
doAssert keyGen(ikm, result.pub.blsValue, result.priv), "Key generation failure"
|
||||
|
||||
# Logging
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
func shortLog*(x: BlsValue): string =
|
||||
($x)[0..7]
|
||||
|
@ -99,93 +207,30 @@ func shortLog*(x: BlsValue): string =
|
|||
func shortLog*(x: BlsCurveType): string =
|
||||
($x)[0..7]
|
||||
|
||||
func hash*(x: BlsValue): Hash {.inline.} =
|
||||
proc toGaugeValue*(hash: Eth2Digest): int64 =
|
||||
# Only the last 8 bytes are taken into consideration in accordance
|
||||
# to the ETH2 metrics spec:
|
||||
# https://github.com/ethereum/eth2.0-metrics/blob/6a79914cb31f7d54858c7dd57eee75b6162ec737/metrics.md#interop-metrics
|
||||
cast[int64](uint64.fromBytesLE(hash.data[24..31]))
|
||||
|
||||
# Codecs
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
func `$`*(x: BlsValue): string =
|
||||
if x.kind == Real:
|
||||
hash x.blsValue.getBytes()
|
||||
"r: 0x" & x.blsValue.toHex()
|
||||
else:
|
||||
hash x.blob
|
||||
# r: is short for random. The prefix must be short
|
||||
# due to the mechanics of the `shortLog` function.
|
||||
"r: 0x" & x.blob.toHex(lowercase = true)
|
||||
|
||||
template hash*(x: BlsCurveType): Hash =
|
||||
hash(getBytes(x))
|
||||
|
||||
template `==`*[T](a: BlsValue[T], b: T): bool =
|
||||
a.blsValue == b
|
||||
|
||||
template `==`*[T](a: T, b: BlsValue[T]): bool =
|
||||
a == b.blsValue
|
||||
|
||||
func pubKey*(pk: ValidatorPrivKey): ValidatorPubKey =
|
||||
when ValidatorPubKey is BlsValue:
|
||||
ValidatorPubKey(kind: Real, blsValue: pk.getKey())
|
||||
elif ValidatorPubKey is array:
|
||||
pk.getKey.getBytes
|
||||
func getBytes*(x: BlsValue): auto =
|
||||
if x.kind == Real:
|
||||
x.blsValue.exportRaw()
|
||||
else:
|
||||
pk.getKey
|
||||
x.blob
|
||||
|
||||
func init*(T: type VerKey): VerKey =
|
||||
result.point.inf()
|
||||
|
||||
func init*(T: type Signature): Signature =
|
||||
result.point.inf()
|
||||
|
||||
func combine*[T](values: openarray[BlsValue[T]]): BlsValue[T] =
|
||||
result = BlsValue[T](kind: Real, blsValue: T.init())
|
||||
|
||||
for value in values:
|
||||
result.blsValue.combine(value.blsValue)
|
||||
|
||||
func combine*[T](x: var BlsValue[T], other: BlsValue[T]) =
|
||||
doAssert x.kind == Real and other.kind == Real
|
||||
x.blsValue.combine(other.blsValue)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/bls_signature.md#bls_aggregate_pubkeys
|
||||
func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
|
||||
keys.combine()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/bls_signature.md#bls_aggregate_signatures
|
||||
func bls_aggregate_signatures*(keys: openArray[ValidatorSig]): ValidatorSig =
|
||||
keys.combine()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/bls_signature.md#bls_verify
|
||||
func bls_verify*(
|
||||
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
|
||||
domain: Domain
|
||||
): bool =
|
||||
# name from spec!
|
||||
if sig.kind != Real:
|
||||
# Invalid signatures are possible in deposits (discussed with Danny)
|
||||
return false
|
||||
when ValidatorPubKey is BlsValue:
|
||||
if sig.kind != Real or pubkey.kind != Real:
|
||||
# TODO: chronicles warning
|
||||
return false
|
||||
# TODO bls_verify_multiple(...) used to have this workaround, and now it
|
||||
# lives here. No matter the signature, there's also no meaningful way to
|
||||
# verify it -- it's a kind of vacuous truth. No pubkey/sig pairs. Sans a
|
||||
# getBytes() or similar mechanism, pubKey == default(ValidatorPubKey) is
|
||||
# a way to create many false positive matches. This seems odd.
|
||||
if pubkey.getBytes() == default(ValidatorPubKey).getBytes():
|
||||
return true
|
||||
|
||||
sig.blsValue.verify(msg, domain, pubkey.blsValue)
|
||||
else:
|
||||
sig.verify(msg, domain, pubkey)
|
||||
|
||||
when ValidatorPrivKey is BlsValue:
|
||||
func bls_sign*(key: ValidatorPrivKey, msg: openarray[byte],
|
||||
domain: Domain): ValidatorSig =
|
||||
# name from spec!
|
||||
if key.kind == Real:
|
||||
ValidatorSig(kind: Real, blsValue: key.blsValue.sign(domain, msg))
|
||||
else:
|
||||
ValidatorSig(kind: OpaqueBlob)
|
||||
else:
|
||||
func bls_sign*(key: ValidatorPrivKey, msg: openarray[byte],
|
||||
domain: Domain): ValidatorSig =
|
||||
# name from spec!
|
||||
ValidatorSig(kind: Real, blsValue: key.sign(domain, msg))
|
||||
|
||||
func fromBytes*[T](R: type BlsValue[T], bytes: openarray[byte]): R =
|
||||
func initFromBytes[T](val: var BlsValue[T], bytes: openarray[byte]) =
|
||||
# This is a workaround, so that we can deserialize the serialization of a
|
||||
# default-initialized BlsValue without raising an exception
|
||||
when defined(ssz_testing):
|
||||
|
@ -194,22 +239,40 @@ func fromBytes*[T](R: type BlsValue[T], bytes: openarray[byte]): R =
|
|||
else:
|
||||
# Try if valid BLS value
|
||||
# TODO: address the side-effects in nim-blscurve
|
||||
{.noSideEffect.}:
|
||||
let success = init(result.blsValue, bytes)
|
||||
val = BlsValue[T](kind: Real)
|
||||
let success = val.blsValue.fromBytes(bytes)
|
||||
if not success:
|
||||
# TODO: chronicles trace
|
||||
result = R(kind: OpaqueBlob)
|
||||
doAssert result.blob.len == bytes.len
|
||||
result.blob[result.blob.low .. result.blob.high] = bytes
|
||||
val = BlsValue[T](kind: OpaqueBlob)
|
||||
val.blob[val.blob.low .. val.blob.high] = bytes
|
||||
|
||||
func fromHex*[T](R: type BlsValue[T], hexStr: string): R =
|
||||
fromBytes(R, hexToSeqByte(hexStr))
|
||||
func initFromBytes*(val: var ValidatorPrivKey, bytes: openarray[byte]) {.inline.} =
|
||||
discard val.fromBytes(bytes)
|
||||
|
||||
func initFromBytes*[T](val: var BlsValue[T], bytes: openarray[byte]) =
|
||||
val = fromBytes(BlsValue[T], bytes)
|
||||
func fromBytes[T](R: type BlsValue[T], bytes: openarray[byte]): R {.inline.}=
|
||||
result.initFromBytes(bytes)
|
||||
|
||||
func initFromBytes*(val: var BlsCurveType, bytes: openarray[byte]) =
|
||||
val = init(type(val), bytes)
|
||||
func fromHex*[T](R: var BlsValue[T], hexStr: string) {.inline.} =
|
||||
## Initialize a BLSValue from its hex representation
|
||||
R.fromBytes(hexStr.hexToSeqByte())
|
||||
|
||||
# Hashing
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
func hash*(x: BlsValue): Hash {.inline.} =
|
||||
# TODO: we can probably just slice the BlsValue
|
||||
if x.kind == Real:
|
||||
hash x.blsValue.exportRaw()
|
||||
else:
|
||||
hash x.blob
|
||||
|
||||
template hash*(x: BlsCurveType): Hash =
|
||||
# TODO: prevent using secret keys
|
||||
bind getBytes
|
||||
hash(getBytes(x))
|
||||
|
||||
# Serialization
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc writeValue*(writer: var JsonWriter, value: ValidatorPubKey) {.inline.} =
|
||||
when value is BlsValue:
|
||||
|
@ -246,30 +309,26 @@ proc writeValue*(writer: var JsonWriter, value: ValidatorPrivKey) {.inline.} =
|
|||
proc readValue*(reader: var JsonReader, value: var ValidatorPrivKey) {.inline.} =
|
||||
value.initFromBytes(fromHex reader.readValue(string))
|
||||
|
||||
when ValidatorPrivKey is BlsValue:
|
||||
proc newPrivKey*(): ValidatorPrivKey =
|
||||
ValidatorPrivKey(kind: Real, blsValue: SigKey.random())
|
||||
else:
|
||||
proc newPrivKey*(): ValidatorPrivKey =
|
||||
SigKey.random()
|
||||
|
||||
proc writeValue*(writer: var JsonWriter, value: VerKey) {.inline.} =
|
||||
proc writeValue*(writer: var JsonWriter, value: PublicKey) {.inline.} =
|
||||
writer.writeValue($value)
|
||||
|
||||
proc readValue*(reader: var JsonReader, value: var VerKey) {.inline.} =
|
||||
value = VerKey.init(reader.readValue(string))
|
||||
proc readValue*(reader: var JsonReader, value: var PublicKey) {.inline.} =
|
||||
let hex = reader.readValue(string)
|
||||
let ok = value.fromHex(hex)
|
||||
doAssert ok, "Invalid public key: " & hex
|
||||
|
||||
proc writeValue*(writer: var JsonWriter, value: Signature) {.inline.} =
|
||||
writer.writeValue($value)
|
||||
|
||||
proc readValue*(reader: var JsonReader, value: var Signature) {.inline.} =
|
||||
value = Signature.init(reader.readValue(string))
|
||||
|
||||
proc toGaugeValue*(hash: Eth2Digest): int64 =
|
||||
# Only the last 8 bytes are taken into consideration in accordance
|
||||
# to the ETH2 metrics spec:
|
||||
# https://github.com/ethereum/eth2.0-metrics/blob/6a79914cb31f7d54858c7dd57eee75b6162ec737/metrics.md#interop-metrics
|
||||
cast[int64](uint64.fromBytesLE(hash.data[24..31]))
|
||||
let hex = reader.readValue(string)
|
||||
let ok = value.fromHex(hex)
|
||||
doAssert ok, "Invalid signature: " & hex
|
||||
|
||||
template fromSszBytes*(T: type BlsValue, bytes: openarray[byte]): auto =
|
||||
fromBytes(T, bytes)
|
||||
|
||||
# For confutils
|
||||
func init*(T: typedesc[ValidatorPrivKey], hex: string): T {.inline.} =
|
||||
let success = result.fromHex(hex)
|
||||
doAssert success, "Private key is invalid" # Don't display private keys even if invalid
|
||||
|
|
|
@ -96,6 +96,9 @@ type
|
|||
DOMAIN_SHARD_PROPOSER = 128
|
||||
DOMAIN_SHARD_ATTESTER = 129
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#custom-types
|
||||
Domain* = array[8, byte]
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/574 and be consistent across
|
||||
# 32-bit and 64-bit word platforms.
|
||||
# TODO VALIDATOR_REGISTRY_LIMIT is 1 shl 40 in 0.8.3, and
|
||||
|
@ -324,7 +327,7 @@ type
|
|||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#signingroot
|
||||
SigningRoot* = object
|
||||
object_root*: Eth2Digest
|
||||
domain*: uint64
|
||||
domain*: Domain
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#signedvoluntaryexit
|
||||
SignedVoluntaryExit* = object
|
||||
|
|
|
@ -12,7 +12,6 @@ import
|
|||
math,
|
||||
# Third-party
|
||||
stew/endians2,
|
||||
blscurve, # defines Domain
|
||||
# Internal
|
||||
./datatypes, ./digest, ../ssz
|
||||
|
||||
|
|
|
@ -100,12 +100,9 @@ proc process_randao(
|
|||
let proposer = addr state.validators[proposer_index.get]
|
||||
|
||||
# Verify that the provided randao value is valid
|
||||
if skipBlsValidation notin flags and not bls_verify(
|
||||
proposer.pubkey,
|
||||
hash_tree_root(epoch.uint64).data,
|
||||
body.randao_reveal,
|
||||
get_domain(state, DOMAIN_RANDAO)):
|
||||
|
||||
let signing_root = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO))
|
||||
if skipBLSValidation notin flags:
|
||||
if not blsVerify(proposer.pubkey, signing_root.data, body.randao_reveal):
|
||||
notice "Randao mismatch", proposer_pubkey = proposer.pubkey,
|
||||
message = epoch,
|
||||
signature = body.randao_reveal,
|
||||
|
@ -167,13 +164,12 @@ proc process_proposer_slashing*(
|
|||
if skipBlsValidation notin flags:
|
||||
for i, signed_header in [proposer_slashing.signed_header_1,
|
||||
proposer_slashing.signed_header_2]:
|
||||
if not bls_verify(
|
||||
proposer.pubkey,
|
||||
hash_tree_root(signed_header.message).data,
|
||||
signed_header.signature,
|
||||
get_domain(
|
||||
let domain = get_domain(
|
||||
state, DOMAIN_BEACON_PROPOSER,
|
||||
compute_epoch_at_slot(signed_header.message.slot))):
|
||||
compute_epoch_at_slot(signed_header.message.slot)
|
||||
)
|
||||
let signing_root = compute_signing_root(signed_header.message, domain)
|
||||
if not blsVerify(proposer.pubkey, signing_root.data, signed_header.signature):
|
||||
notice "Proposer slashing: invalid signature",
|
||||
signature_index = i
|
||||
return false
|
||||
|
@ -339,11 +335,8 @@ proc process_voluntary_exit*(
|
|||
# Verify signature
|
||||
if skipBlsValidation notin flags:
|
||||
let domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
||||
if not bls_verify(
|
||||
validator.pubkey,
|
||||
hash_tree_root(voluntary_exit).data,
|
||||
signed_voluntary_exit.signature,
|
||||
domain):
|
||||
let signing_root = compute_signing_root(voluntary_exit, domain)
|
||||
if not bls_verify(validator.pubkey, signing_root.data, signed_voluntary_exit.signature):
|
||||
notice "Exit: invalid signature"
|
||||
return false
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ func getValidator*(pool: ValidatorPool,
|
|||
validatorKey: ValidatorPubKey): AttachedValidator =
|
||||
pool.validators.getOrDefault(validatorKey)
|
||||
|
||||
# TODO: Honest validator - https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md
|
||||
proc signBlockProposal*(v: AttachedValidator, fork: Fork, slot: Slot,
|
||||
blockRoot: Eth2Digest): Future[ValidatorSig] {.async.} =
|
||||
|
||||
|
@ -38,7 +39,8 @@ proc signBlockProposal*(v: AttachedValidator, fork: Fork, slot: Slot,
|
|||
# replaced by something more sensible
|
||||
await sleepAsync(chronos.milliseconds(1))
|
||||
|
||||
result = bls_sign(v.privKey, blockRoot.data, domain)
|
||||
let signing_root = compute_signing_root(blockRoot, domain)
|
||||
result = blsSign(v.privKey, signing_root.data)
|
||||
else:
|
||||
error "Unimplemented"
|
||||
quit 1
|
||||
|
@ -56,18 +58,20 @@ proc signAttestation*(v: AttachedValidator,
|
|||
# replaced by something more sensible
|
||||
await sleepAsync(chronos.milliseconds(1))
|
||||
|
||||
result = bls_sign(v.privKey, attestationRoot.data, domain)
|
||||
let signing_root = compute_signing_root(attestationRoot, domain)
|
||||
result = blsSign(v.privKey, signing_root.data)
|
||||
else:
|
||||
error "Unimplemented"
|
||||
quit 1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#randao-reveal
|
||||
func genRandaoReveal*(k: ValidatorPrivKey, fork: Fork, slot: Slot):
|
||||
ValidatorSig =
|
||||
let
|
||||
domain = get_domain(fork, DOMAIN_RANDAO, compute_epoch_at_slot(slot))
|
||||
root = hash_tree_root(compute_epoch_at_slot(slot).uint64).data
|
||||
signing_root = compute_signing_root(compute_epoch_at_slot(slot).uint64, domain)
|
||||
|
||||
bls_sign(k, root, domain)
|
||||
bls_sign(k, signing_root.data)
|
||||
|
||||
func genRandaoReveal*(v: AttachedValidator, fork: Fork, slot: Slot):
|
||||
ValidatorSig =
|
||||
|
|
|
@ -138,18 +138,25 @@ proc main(nb_samples: Natural) =
|
|||
for i in 0 ..< proof_of_possessions.len:
|
||||
pop_valid = pop_valid and proof_of_possessions[i].verifyPoP(pubkeys[i])
|
||||
|
||||
var agg_pubkey: VerKey
|
||||
bench &"Benchmarking {num_validators} public keys aggregation", agg_pubkey:
|
||||
agg_pubkey = combine(pubkeys)
|
||||
# TODO: update with IETF API (Eth2 v0.10.1)
|
||||
# func fastAggregateVerify*[T: byte|char](
|
||||
# publicKeys: openarray[PublicKey],
|
||||
# message: openarray[T],
|
||||
# signature: Signature # Aggregated signature
|
||||
# ): bool
|
||||
|
||||
var agg_sig: Signature
|
||||
bench &"Benchmarking {num_validators} signatures aggregation", agg_sig:
|
||||
agg_sig = combine(signatures)
|
||||
# var agg_pubkey: VerKey
|
||||
# bench &"Benchmarking {num_validators} public keys aggregation", agg_pubkey:
|
||||
# agg_pubkey = combine(pubkeys)
|
||||
|
||||
var msg_verif: bool
|
||||
bench "Benchmarking message verification", msg_verif:
|
||||
let domain = 0'u64
|
||||
msg_verif = agg_sig.verify(msg.data, domain, agg_pubkey)
|
||||
# var agg_sig: Signature
|
||||
# bench &"Benchmarking {num_validators} signatures aggregation", agg_sig:
|
||||
# agg_sig = combine(signatures)
|
||||
|
||||
# var msg_verif: bool
|
||||
# bench "Benchmarking message verification", msg_verif:
|
||||
# let domain = 0'u64
|
||||
# msg_verif = agg_sig.verify(msg.data, domain, agg_pubkey)
|
||||
|
||||
#####################
|
||||
#
|
||||
|
|
|
@ -18,7 +18,6 @@ import # Unit test
|
|||
./test_block_pool,
|
||||
./test_discovery_helpers,
|
||||
./test_helpers,
|
||||
./test_interop,
|
||||
./test_kvstore,
|
||||
./test_kvstore_lmdb,
|
||||
./test_kvstore_sqlite3,
|
||||
|
@ -31,6 +30,11 @@ import # Unit test
|
|||
./test_sync_manager,
|
||||
./test_honest_validator
|
||||
|
||||
# ./test_interop
|
||||
# TODO: BLS changes in v0.10.1 will generate different interop signatures
|
||||
# Requires an update of the interop mocked start: https://github.com/ethereum/eth2.0-pm/tree/master/interop/mocked_start
|
||||
# or of ZRNT / ZCLI to v0.10.1
|
||||
|
||||
import # Refactor state transition unit tests
|
||||
# TODO re-enable when useful
|
||||
# ./spec_block_processing/test_genesis,
|
||||
|
|
|
@ -60,16 +60,14 @@ proc get_attestation_signature(
|
|||
): ValidatorSig =
|
||||
|
||||
let msg = attestation_data.hash_tree_root()
|
||||
|
||||
return bls_sign(
|
||||
key = privkey,
|
||||
msg = msg.data,
|
||||
domain = get_domain(
|
||||
let domain = get_domain(
|
||||
state = state,
|
||||
domain_type = DOMAIN_BEACON_ATTESTER,
|
||||
message_epoch = attestation_data.target.epoch
|
||||
)
|
||||
)
|
||||
let signing_root = compute_signing_root(msg, domain)
|
||||
|
||||
return bls_sign(privkey, signing_root.data)
|
||||
|
||||
proc signMockAttestation*(state: BeaconState, attestation: var Attestation) =
|
||||
var cache = get_empty_per_epoch_cache()
|
||||
|
@ -89,7 +87,7 @@ proc signMockAttestation*(state: BeaconState, attestation: var Attestation) =
|
|||
attestation.signature = sig
|
||||
first_iter = false
|
||||
else:
|
||||
combine(attestation.signature, sig)
|
||||
aggregate(attestation.signature, sig)
|
||||
|
||||
proc mockAttestationImpl(
|
||||
state: BeaconState,
|
||||
|
|
|
@ -27,28 +27,27 @@ proc signMockBlockImpl(
|
|||
|
||||
let privkey = MockPrivKeys[proposer_index]
|
||||
|
||||
signedBlock.message.body.randao_reveal = bls_sign(
|
||||
key = privkey,
|
||||
msg = block_slot
|
||||
.compute_epoch_at_slot()
|
||||
.hash_tree_root()
|
||||
.data,
|
||||
domain = get_domain(
|
||||
state,
|
||||
DOMAIN_RANDAO,
|
||||
message_epoch = block_slot.compute_epoch_at_slot(),
|
||||
)
|
||||
)
|
||||
|
||||
signedBlock.signature = bls_sign(
|
||||
key = privkey,
|
||||
msg = signedBlock.message.hash_tree_root().data,
|
||||
domain = get_domain(
|
||||
state,
|
||||
DOMAIN_BEACON_PROPOSER,
|
||||
message_epoch = block_slot.compute_epoch_at_slot(),
|
||||
)
|
||||
)
|
||||
block:
|
||||
let domain = get_domain(
|
||||
state,
|
||||
DOMAIN_RANDAO,
|
||||
message_epoch = block_slot.compute_epoch_at_slot(),
|
||||
)
|
||||
let signing_root = compute_signing_root(
|
||||
block_slot.compute_epoch_at_slot(),
|
||||
domain
|
||||
)
|
||||
signedBlock.message.body.randao_reveal = bls_sign(privkey, signing_root.data)
|
||||
|
||||
block:
|
||||
let domain = get_domain(
|
||||
state,
|
||||
DOMAIN_BEACON_PROPOSER,
|
||||
message_epoch = block_slot.compute_epoch_at_slot(),
|
||||
)
|
||||
let signing_root = compute_signing_root(signedBlock.message, domain)
|
||||
signedBlock.signature = bls_sign(privkey, signing_root.data)
|
||||
|
||||
proc signMockBlock*(
|
||||
state: BeaconState,
|
||||
|
|
|
@ -23,13 +23,17 @@ func signMockDepositData(
|
|||
privkey: ValidatorPrivKey
|
||||
) =
|
||||
# No state --> Genesis
|
||||
deposit_data.signature = bls_sign(
|
||||
key = privkey,
|
||||
msg = deposit_data.getDepositMessage().hash_tree_root().data,
|
||||
domain = compute_domain(
|
||||
let domain = compute_domain(
|
||||
DOMAIN_DEPOSIT,
|
||||
default(array[4, byte]) # Genesis is fork_version 0
|
||||
)
|
||||
let signing_root = compute_signing_root(
|
||||
deposit_data.getDepositMessage(),
|
||||
domain
|
||||
)
|
||||
deposit_data.signature = blsSign(
|
||||
privkey,
|
||||
signing_root.data
|
||||
)
|
||||
|
||||
func signMockDepositData(
|
||||
|
@ -37,13 +41,17 @@ func signMockDepositData(
|
|||
privkey: ValidatorPrivKey,
|
||||
state: BeaconState
|
||||
) =
|
||||
deposit_data.signature = bls_sign(
|
||||
key = privkey,
|
||||
msg = deposit_data.getDepositMessage().hash_tree_root().data,
|
||||
domain = get_domain(
|
||||
state,
|
||||
DOMAIN_DEPOSIT
|
||||
let domain = compute_domain(
|
||||
DOMAIN_DEPOSIT,
|
||||
default(array[4, byte]) # Genesis is fork_version 0
|
||||
)
|
||||
let signing_root = compute_signing_root(
|
||||
deposit_data.getDepositMessage(),
|
||||
domain
|
||||
)
|
||||
deposit_data.signature = blsSign(
|
||||
privkey,
|
||||
signing_root.data
|
||||
)
|
||||
|
||||
func mockDepositData(
|
||||
|
|
|
@ -17,7 +17,8 @@ import
|
|||
let MockPrivKeys* = block:
|
||||
var privkeys: array[MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, ValidatorPrivKey]
|
||||
for pk in privkeys.mitems():
|
||||
pk = newPrivKey()
|
||||
let pair = newKeyPair()
|
||||
pk = pair.priv
|
||||
privkeys
|
||||
|
||||
let MockPubKeys* = block:
|
||||
|
|
|
@ -60,11 +60,6 @@ suite "Beacon chain DB" & preset():
|
|||
timedTest "find ancestors" & preset():
|
||||
var
|
||||
db = init(BeaconChainDB, kvStore MemoryStoreRef.init())
|
||||
x: ValidatorSig
|
||||
y = init(ValidatorSig, x.getBytes())
|
||||
|
||||
# Silly serialization check that fails without the right import
|
||||
check: x == y
|
||||
|
||||
let
|
||||
a0 = SignedBeaconBlock(message: BeaconBlock(slot: GENESIS_SLOT + 0))
|
||||
|
|
|
@ -5,6 +5,10 @@ import
|
|||
../beacon_chain/[extras, interop, ssz],
|
||||
../beacon_chain/spec/[beaconstate, crypto, helpers, datatypes]
|
||||
|
||||
# TODO: BLS changes in v0.10.1 will generate different interop signatures
|
||||
# Requires an update of the interop mocked start
|
||||
# or of ZRNT / ZCLI to v0.10.1
|
||||
|
||||
# Interop test yaml, found here:
|
||||
# https://github.com/ethereum/eth2.0-pm/blob/a0b9d22fad424574b1307828f867b30237758468/interop/mocked_start/keygen_10_validators.yaml
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ suite "Zero signature sanity checks":
|
|||
timedTest "SSZ serialization roundtrip of SignedBeaconBlockHeader":
|
||||
|
||||
let defaultBlockHeader = SignedBeaconBlockHeader(
|
||||
signature: BlsValue[Signature](kind: OpaqueBlob)
|
||||
signature: ValidatorSig(kind: OpaqueBlob)
|
||||
)
|
||||
|
||||
check:
|
||||
|
|
|
@ -13,21 +13,12 @@ import
|
|||
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest,
|
||||
helpers, validator]
|
||||
|
||||
when ValidatorPrivKey is BlsValue:
|
||||
func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey =
|
||||
# 0 is not a valid BLS private key - 1000 helps interop with rust BLS library,
|
||||
# lighthouse.
|
||||
# TODO: switch to https://github.com/ethereum/eth2.0-pm/issues/60
|
||||
result.kind = BlsValueType.Real
|
||||
var bytes = uint64(i + 1000).toBytesLE()
|
||||
copyMem(addr result.blsValue.x[0], addr bytes[0], sizeof(bytes))
|
||||
else:
|
||||
func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey =
|
||||
# 0 is not a valid BLS private key - 1000 helps interop with rust BLS library,
|
||||
# lighthouse.
|
||||
# TODO: switch to https://github.com/ethereum/eth2.0-pm/issues/60
|
||||
var bytes = uint64(i + 1000).toBytesLE()
|
||||
copyMem(addr result.x[0], addr bytes[0], sizeof(bytes))
|
||||
func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey =
|
||||
# 0 is not a valid BLS private key - 1000 helps interop with rust BLS library,
|
||||
# lighthouse.
|
||||
# TODO: switch to https://github.com/ethereum/eth2.0-pm/issues/60
|
||||
var bytes = uint64(i + 1000).toBytesLE()
|
||||
copyMem(addr result, addr bytes[0], sizeof(bytes))
|
||||
|
||||
func makeFakeHash(i: int): Eth2Digest =
|
||||
var bytes = uint64(i).toBytesLE()
|
||||
|
@ -62,10 +53,9 @@ func makeDeposit(i: int, flags: UpdateFlags): Deposit =
|
|||
)
|
||||
)
|
||||
|
||||
if skipBlsValidation notin flags:
|
||||
result.data.signature =
|
||||
bls_sign(privkey, hash_tree_root(result.getDepositMessage).data,
|
||||
domain)
|
||||
if skipBLSValidation notin flags:
|
||||
let signing_root = compute_signing_root(result.getDepositMessage, domain)
|
||||
result.data.signature = bls_sign(privkey, signing_root.data)
|
||||
|
||||
func makeInitialDeposits*(
|
||||
n = SLOTS_PER_EPOCH, flags: UpdateFlags = {}): seq[Deposit] =
|
||||
|
@ -123,20 +113,16 @@ proc addBlock*(
|
|||
doAssert privKey.pubKey() == proposer.pubkey,
|
||||
"signature key should be derived from private key! - wrong privkey?"
|
||||
|
||||
if skipBlsValidation notin flags:
|
||||
let block_root = hash_tree_root(new_block.message)
|
||||
if skipBLSValidation notin flags:
|
||||
let domain = get_domain(state, DOMAIN_BEACON_PROPOSER,
|
||||
compute_epoch_at_slot(new_block.message.slot))
|
||||
let signing_root = compute_signing_root(new_block.message, domain)
|
||||
# We have a signature - put it in the block and we should be done!
|
||||
new_block.signature =
|
||||
bls_sign(privKey, block_root.data,
|
||||
get_domain(state, DOMAIN_BEACON_PROPOSER,
|
||||
compute_epoch_at_slot(new_block.message.slot)))
|
||||
new_block.signature = bls_sign(privKey, signing_root.data)
|
||||
|
||||
doAssert bls_verify(
|
||||
proposer.pubkey,
|
||||
block_root.data, new_block.signature,
|
||||
get_domain(
|
||||
state, DOMAIN_BEACON_PROPOSER,
|
||||
compute_epoch_at_slot(new_block.message.slot))),
|
||||
signing_root.data, new_block.signature),
|
||||
"we just signed this message - it should pass verification!"
|
||||
|
||||
new_block
|
||||
|
@ -171,12 +157,11 @@ proc makeAttestation*(
|
|||
aggregation_bits.setBit sac_index
|
||||
|
||||
let
|
||||
msg = hash_tree_root(data)
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, data.target.epoch)
|
||||
signing_root = compute_signing_root(data, domain)
|
||||
sig =
|
||||
if skipBlsValidation notin flags:
|
||||
bls_sign(
|
||||
hackPrivKey(validator), msg.data,
|
||||
get_domain(state, DOMAIN_BEACON_ATTESTER, data.target.epoch))
|
||||
if skipBLSValidation notin flags:
|
||||
bls_sign(hackPrivKey(validator), signing_root.data)
|
||||
else:
|
||||
ValidatorSig()
|
||||
|
||||
|
@ -223,19 +208,27 @@ proc makeFullAttestations*(
|
|||
let
|
||||
committee = get_beacon_committee(state, slot, index, cache)
|
||||
data = makeAttestationData(state, slot, index, beacon_block_root)
|
||||
msg = hash_tree_root(data)
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, data.target.epoch)
|
||||
signing_root = compute_signing_root(data, domain)
|
||||
|
||||
var
|
||||
attestation = Attestation(
|
||||
aggregation_bits: CommitteeValidatorsBits.init(committee.len),
|
||||
data: data,
|
||||
signature: ValidatorSig(kind: Real, blsValue: Signature.init())
|
||||
doAssert committee.len() >= 1
|
||||
# Initial attestation
|
||||
var attestation = Attestation(
|
||||
aggregation_bits: CommitteeValidatorsBits.init(committee.len),
|
||||
data: data,
|
||||
signature: bls_sign(
|
||||
hackPrivKey(state.validators[committee[0]]),
|
||||
signing_root.data
|
||||
)
|
||||
for j in 0..<committee.len():
|
||||
)
|
||||
# Aggregate the remainder
|
||||
attestation.aggregation_bits.setBit 0
|
||||
for j in 1 ..< committee.len():
|
||||
attestation.aggregation_bits.setBit j
|
||||
if skipBlsValidation notin flags:
|
||||
attestation.signature.combine(bls_sign(
|
||||
hackPrivKey(state.validators[committee[j]]), msg.data,
|
||||
get_domain(state, DOMAIN_BEACON_ATTESTER, data.target.epoch)))
|
||||
if skipBLSValidation notin flags:
|
||||
attestation.signature.aggregate(bls_sign(
|
||||
hackPrivKey(state.validators[committee[j]]),
|
||||
signing_root.data
|
||||
))
|
||||
|
||||
result.add attestation
|
||||
|
|
Loading…
Reference in New Issue