Update BLS to the latest scheme. (#80)

* Attempt to switch to nim-blscurve.

* "Fix" BLS test for new tests

* Missing domain param in validator keygen
This commit is contained in:
Mamy Ratsimbazafy 2019-02-05 17:13:29 +01:00 committed by GitHub
parent bbd94185a4
commit e5d152c6d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 65 additions and 54 deletions

View File

@ -16,7 +16,7 @@ requires "nim >= 0.18.0",
"eth_common",
"eth_keys",
"nimcrypto",
"https://github.com/status-im/nim-milagro-crypto#master",
"https://github.com/status-im/nim-blscurve#master",
"eth_p2p",
"ranges",
"chronicles",

View File

@ -1,7 +1,7 @@
import
os, options,
confutils/defs, chronicles/options as chroniclesOptions,
milagro_crypto, json_serialization,
json_serialization,
spec/[crypto, datatypes], randao, time
export
@ -79,7 +79,7 @@ proc readFileBytes(path: string): seq[byte] =
cast[seq[byte]](readFile(path))
proc loadPrivKey*(p: ValidatorKeyPath): ValidatorPrivKey =
initSigKey(readFileBytes(string(p) & ".privkey"))
ValidatorPrivKey.init(readFileBytes(string(p) & ".privkey"))
proc loadRandao*(p: ValidatorKeyPath): Randao =
initRandao(readFileBytes(string(p) & ".randao"))

View File

@ -1,6 +1,5 @@
import
deques, options, tables,
milagro_crypto,
./spec/[datatypes, crypto, digest, helpers, validator], extras,
./beacon_chain_db

View File

@ -383,7 +383,7 @@ proc checkAttestation*(
if not bls_verify(
group_public_key, @(msg.data) & @[0'u8], attestation.aggregate_signature,
get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION)
0, # TODO: get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION)
):
warn("Invalid attestation group signature")
return

View File

@ -46,20 +46,23 @@
import
hashes,
milagro_crypto, json_serialization
blscurve, json_serialization
export
json_serialization, milagro_crypto.`$`
json_serialization
export blscurve.init, blscurve.getBytes, blscurve.combine
type
ValidatorPubKey* = milagro_crypto.VerKey
ValidatorPrivKey* = milagro_crypto.SigKey
ValidatorSig* = milagro_crypto.Signature
ValidatorPubKey* = blscurve.VerKey
ValidatorPrivKey* = blscurve.SigKey
ValidatorSig* = blscurve.Signature
ValidatorPKI* = ValidatorPrivKey|ValidatorPubKey|ValidatorSig
template hash*(k: ValidatorPubKey|ValidatorPrivKey): Hash =
hash(k.getRaw)
hash(k.getBytes())
func pubKey*(pk: ValidatorPrivKey): ValidatorPubKey = fromSigKey(pk)
func pubKey*(pk: ValidatorPrivKey): ValidatorPubKey = pk.getKey()
func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
var empty = true
@ -74,24 +77,28 @@ func bls_verify*(
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
domain: uint64): bool =
# name from spec!
# TODO domain!
sig.verifyMessage(msg, pubkey)
sig.verify(msg, domain, pubkey)
func bls_sign*(key: ValidatorPrivKey,
msg: openarray[byte], domain: uint64): ValidatorSig =
# name from spec!
key.sign(domain, msg)
proc writeValue*(writer: var JsonWriter, value: ValidatorPubKey) {.inline.} =
writer.writeValue $value
writer.writeValue($value)
proc readValue*(reader: var JsonReader, value: var ValidatorPubKey) {.inline.} =
value = initVerKey reader.readValue(string)
value = VerKey.init(reader.readValue(string))
proc writeValue*(writer: var JsonWriter, value: ValidatorSig) {.inline.} =
writer.writeValue $value
writer.writeValue($value)
proc readValue*(reader: var JsonReader, value: var ValidatorSig) {.inline.} =
value = initSignature reader.readValue(string)
value = Signature.init(reader.readValue(string))
proc writeValue*(writer: var JsonWriter, value: ValidatorPrivKey) {.inline.} =
writer.writeValue $value
writer.writeValue($value)
proc readValue*(reader: var JsonReader, value: var ValidatorPrivKey) {.inline.} =
value = initSigKey reader.readValue(string)
value = SigKey.init(reader.readValue(string))

View File

@ -13,8 +13,6 @@ import
eth_common, nimcrypto/blake2,
./spec/[crypto, datatypes, digest]
from milagro_crypto import getRaw, fromRaw
# ################### Helper functions ###################################
# toBytesSSZ convert simple fixed-length types to their SSZ wire representation
@ -43,7 +41,7 @@ func toBytesSSZ(x: Eth2Digest): array[32, byte] = x.data
# TODO these two are still being debated:
# https://github.com/ethereum/eth2.0-specs/issues/308#issuecomment-447026815
func toBytesSSZ(x: ValidatorPubKey|ValidatorSig): auto = x.getRaw()
func toBytesSSZ(x: ValidatorPubKey|ValidatorSig): auto = x.getBytes()
type
TrivialTypes =
@ -116,7 +114,7 @@ proc deserialize[T: TrivialTypes](
false
else:
when T is (ValidatorPubKey|ValidatorSig):
if T.fromRaw(data[offset..data.len-1], dest):
if dest.init(data[offset..data.len-1]):
offset += sszLen(dest)
true
else:
@ -307,13 +305,13 @@ func hash_tree_root*(x: ValidatorPubKey): array[32, byte] =
## TODO - Warning ⚠️: not part of the spec
## as of https://github.com/ethereum/beacon_chain/pull/133/files
## This is a "stub" needed for BeaconBlock hashing
x.getRaw().hash()
x.getBytes().hash()
func hash_tree_root*(x: ValidatorSig): array[32, byte] =
## TODO - Warning ⚠️: not part of the spec
## as of https://github.com/ethereum/beacon_chain/pull/133/files
## This is a "stub" needed for BeaconBlock hashing
x.getRaw().hash()
x.getBytes().hash()
func hash_tree_root_final*(x: object|tuple): Eth2Digest =
# TODO suggested for spec:

View File

@ -33,8 +33,7 @@
import
chronicles, math, options, sequtils,
./extras, ./ssz,
./spec/[beaconstate, crypto, datatypes, digest, helpers, validator],
milagro_crypto
./spec/[beaconstate, crypto, datatypes, digest, helpers, validator]
func flatten[T](v: openArray[seq[T]]): seq[T] =
# TODO not in nim - doh.

View File

@ -1,6 +1,6 @@
import
os, ospaths, strutils, strformat,
asyncdispatch2, milagro_crypto, nimcrypto, json_serialization, confutils,
asyncdispatch2, nimcrypto, json_serialization, confutils,
spec/[datatypes, digest, crypto], conf, randao, time, ssz,
../tests/testutil
@ -12,7 +12,7 @@ proc genSingleValidator(path: string): (ValidatorPubKey,
ValidatorPrivKey,
Eth2Digest) =
var v: PrivateValidatorData
v.privKey = newSigKey()
# v.privKey = newSigKey()
if randomBytes(v.randao.seed.data) != sizeof(v.randao.seed.data):
raise newException(Exception, "Could not generate randao seed")
@ -51,8 +51,10 @@ cli do (validators: int,
withdrawal_credentials: withdrawalCredentials,
randao_commitment: randaoCommitment)
proofOfPossession = signMessage(
privkey, hash_tree_root_final(proofOfPossessionData).data)
proofOfPossession = bls_sign(
privkey, hash_tree_root_final(proofOfPossessionData).data,
0 # TODO - domain
)
startupData.validatorDeposits.add Deposit(
deposit_data: DepositData(

View File

@ -1,6 +1,6 @@
import
tables, random,
asyncdispatch2, milagro_crypto,
asyncdispatch2,
spec/[datatypes, crypto, digest], randao, ssz
type
@ -50,7 +50,9 @@ proc signBlockProposal*(v: AttachedValidator,
let proposalRoot = hash_tree_root_final(proposal)
# TODO: Should we use proposalRoot as data, or digest in regards to signature?
result = signMessage(v.privKey, proposalRoot.data)
# TODO: Use `domain` here
let domain = 0'u64
result = bls_sign(v.privKey, proposalRoot.data, domain)
else:
# TODO:
# send RPC
@ -65,7 +67,9 @@ proc signAttestation*(v: AttachedValidator,
let attestationRoot = hash_tree_root_final(attestation)
# TODO: Avoid the allocations belows
var dataToSign = @(attestationRoot.data) & @[0'u8]
result = signMessage(v.privKey, dataToSign)
# TODO: Use `domain` here
let domain = 0'u64
result = bls_sign(v.privKey, dataToSign, domain)
else:
# TODO:
# send RPC

View File

@ -1,6 +1,5 @@
import
sequtils, tables,
milagro_crypto,
spec/[datatypes, crypto, digest], ssz
type

View File

@ -1,6 +1,6 @@
import
./bench_common,
milagro_crypto,
blscurve,
nimcrypto, endians, sequtils, times, strformat,
random
@ -82,7 +82,7 @@ proc main(nb_samples: Natural) =
echo '\n'
var start = cpuTime()
let secret_public_keypairs = newSeqWith(num_validators, newKeyPair())
let secret_public_keypairs = newSeqWith(num_validators, KeyPair.random())
var stop = cpuTime()
echo "#### Message crypto keys, signatures and proofs of possession"
echo '\n'
@ -111,10 +111,11 @@ proc main(nb_samples: Natural) =
echo '\n'
var pubkeys: seq[VerKey]
var signatures: seq[Signature]
let domain = 0'u64
start = cpuTime()
for kp in secret_public_keypairs:
pubkeys.add kp.verkey
signatures.add kp.sigkey.signMessage(msg.data) # toOpenArray?
signatures.add kp.sigkey.sign(domain, msg.data) # toOpenArray?
stop = cpuTime()
echo &"{num_validators} public key and message signature pairs generated in {stop - start :>4.3f} s"
echo &"Throughput: {num_validators.float / (stop - start) :>4.3f} kps/s (keysig pairs/second)"
@ -147,7 +148,8 @@ proc main(nb_samples: Natural) =
var msg_verif: bool
bench "Benchmarking message verification", msg_verif:
msg_verif = agg_sig.verifyMessage(msg.data, agg_pubkey)
let domain = 0'u64
msg_verif = agg_sig.verify(msg.data, domain, agg_pubkey)
#####################
#

View File

@ -24,8 +24,7 @@
import
tables, hashes,
milagro_crypto,
../../beacon_chain/spec/[datatypes, helpers, digest],
../../beacon_chain/spec/[datatypes, helpers, digest, crypto],
../../beacon_chain/ssz
type

View File

@ -2,7 +2,6 @@ import
confutils,
json, strformat,
options, sequtils, random,
milagro_crypto,
../tests/[testutil],
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest, helpers, validator],
../beacon_chain/[extras, ssz, state_transition, fork_choice]

View File

@ -6,7 +6,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
unittest, nimcrypto, eth_common, sequtils, options, milagro_crypto,
unittest, nimcrypto, eth_common, sequtils, options, blscurve,
../beacon_chain/ssz, ../beacon_chain/spec/datatypes
func filled[N: static[int], T](typ: type array[N, T], value: T): array[N, T] =
@ -83,7 +83,7 @@ suite "Simple serialization":
deserialize(ser, type(v)).get() == v
test "Key roundtrip":
let v = newSigKey().fromSigKey()
let v = SigKey.random().getKey()
let ser = v.serialize()
check:
@ -94,7 +94,7 @@ suite "Simple serialization":
let
bb = BeaconBlock(
slot: 42,
signature: signMessage(newSigKey(), "")
signature: sign(SigKey.random(), 0'u64, "")
)
bs = BeaconState(slot: 42)

View File

@ -6,7 +6,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
options, milagro_crypto, sequtils,
options, sequtils,
../beacon_chain/[extras, ssz, state_transition],
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest, helpers, validator]
@ -43,7 +43,7 @@ func makeDeposit(i: int, flags: UpdateFlags): Deposit =
## for testing :)
let
privkey = makeValidatorPrivKey(i)
pubkey = privkey.fromSigKey()
pubkey = privkey.pubKey()
withdrawal_credentials = makeFakeHash(i)
randao_commitment = repeat_hash(withdrawal_credentials, randaoRounds)
@ -56,8 +56,8 @@ func makeDeposit(i: int, flags: UpdateFlags): Deposit =
withdrawal_credentials: withdrawal_credentials,
randao_commitment: randao_commitment
)
signMessage(
privkey, hash_tree_root_final(proof_of_possession_data).data)
let domain = 0'u64
bls_sign(privkey, hash_tree_root_final(proof_of_possession_data).data, domain)
Deposit(
deposit_data: DepositData(
@ -140,14 +140,15 @@ proc addBlock*(
)
proposal_hash = hash_tree_root(signed_data)
assert proposerPrivkey.fromSigKey() == proposer.pubkey,
assert proposerPrivkey.pubKey() == proposer.pubkey,
"signature key should be derived from private key! - wrong privkey?"
if skipValidation notin flags:
# We have a signature - put it in the block and we should be done!
# TODO domain present do something!
new_block.signature =
# TODO domain missing!
signMessage(proposerPrivkey, proposal_hash)
bls_sign(proposerPrivkey, proposal_hash,
get_domain(state.fork, state.slot, DOMAIN_PROPOSAL))
assert bls_verify(
proposer.pubkey,
@ -201,9 +202,11 @@ proc makeAttestation*(
let
msg = hash_tree_root_final(data)
# TODO: domain
domain = 0'u64
sig =
if skipValidation notin flags:
signMessage(hackPrivKey(validator), @(msg.data) & @[0'u8])
bls_sign(hackPrivKey(validator), @(msg.data) & @[0'u8], domain)
else:
ValidatorSig()