Bls official tests (#268)
* Update fixtures with BLS and SSZ generic * Stash changes following https://github.com/status-im/nim-serialization/issues/4 * Add Private to Public key conversion * Add message signing tests * Add aggregate signatures and public keys * Add BLS to test suite
This commit is contained in:
parent
8da71715eb
commit
2a4c4df7c3
|
@ -21,4 +21,5 @@ import # Unit test
|
||||||
import # Official fixtures
|
import # Official fixtures
|
||||||
# TODO - re-enable
|
# TODO - re-enable
|
||||||
#./official/test_fixture_state
|
#./official/test_fixture_state
|
||||||
./official/test_fixture_shuffling
|
./official/test_fixture_shuffling,
|
||||||
|
./official/test_fixture_bls
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 80c3652796488e62c37087a9bffae60c6b1cefa5
|
Subproject commit 76fd020646fef404c55837fbc40833b0d0b2ac72
|
|
@ -5,7 +5,9 @@ import
|
||||||
# Beacon chain internals
|
# Beacon chain internals
|
||||||
# submodule in nim-beacon-chain/tests/official/fixtures/
|
# submodule in nim-beacon-chain/tests/official/fixtures/
|
||||||
../../beacon_chain/spec/[datatypes, crypto, digest],
|
../../beacon_chain/spec/[datatypes, crypto, digest],
|
||||||
../../beacon_chain/ssz
|
../../beacon_chain/ssz,
|
||||||
|
# Workarounds
|
||||||
|
endians # parseHex into uint64
|
||||||
|
|
||||||
export nimcrypto.toHex
|
export nimcrypto.toHex
|
||||||
|
|
||||||
|
@ -75,7 +77,7 @@ type
|
||||||
blocks*: seq[BeaconBlock]
|
blocks*: seq[BeaconBlock]
|
||||||
expected_state*: BeaconState
|
expected_state*: BeaconState
|
||||||
|
|
||||||
ShufflingTests* = object
|
Tests*[T] = object
|
||||||
title*: string
|
title*: string
|
||||||
summary*: string
|
summary*: string
|
||||||
forks_timeline*: string
|
forks_timeline*: string
|
||||||
|
@ -83,14 +85,52 @@ type
|
||||||
config*: string
|
config*: string
|
||||||
runner*: string
|
runner*: string
|
||||||
handler*: string
|
handler*: string
|
||||||
test_cases*: seq[ShufflingTestCase]
|
test_cases*: seq[T]
|
||||||
|
|
||||||
ShufflingTestCase* = object
|
Shuffling* = object
|
||||||
seed*: Eth2Digest
|
seed*: Eth2Digest
|
||||||
count*: uint64
|
count*: uint64
|
||||||
shuffled*: seq[ValidatorIndex]
|
shuffled*: seq[ValidatorIndex]
|
||||||
|
|
||||||
Tests* = StateTests or ShufflingTests
|
# # TODO - but already tested in nim-blscurve
|
||||||
|
# BLSUncompressedG2 = object
|
||||||
|
# input*: tuple[
|
||||||
|
# message: seq[byte],
|
||||||
|
# domain: array[1, byte]
|
||||||
|
# ]
|
||||||
|
# output*: ECP2_BLS381
|
||||||
|
|
||||||
|
# # TODO - but already tested in nim-blscurve
|
||||||
|
# BLSCompressedG2 = object
|
||||||
|
# input*: tuple[
|
||||||
|
# message: seq[byte],
|
||||||
|
# domain: array[1, byte]
|
||||||
|
# ]
|
||||||
|
# output*: ECP2_BLS381
|
||||||
|
|
||||||
|
Domain = distinct uint64
|
||||||
|
## Domains have custom hex serialization
|
||||||
|
|
||||||
|
BLSPrivToPub* = object
|
||||||
|
input*: ValidatorPrivKey
|
||||||
|
output*: ValidatorPubKey
|
||||||
|
|
||||||
|
BLSSignMsgInput = object
|
||||||
|
privkey*: ValidatorPrivKey
|
||||||
|
message*: seq[byte]
|
||||||
|
domain*: Domain
|
||||||
|
|
||||||
|
BLSSignMsg* = object
|
||||||
|
input*: BLSSignMsgInput
|
||||||
|
output*: Signature
|
||||||
|
|
||||||
|
BLSAggSig* = object
|
||||||
|
input*: seq[Signature]
|
||||||
|
output*: Signature
|
||||||
|
|
||||||
|
BLSAggPubKey* = object
|
||||||
|
input*: seq[ValidatorPubKey]
|
||||||
|
output*: ValidatorPubKey
|
||||||
|
|
||||||
# #######################
|
# #######################
|
||||||
# Default init
|
# Default init
|
||||||
|
@ -110,30 +150,47 @@ proc readValue*[N: static int](r: var JsonReader, a: var array[N, byte]) {.inlin
|
||||||
proc readValue*(r: var JsonReader, a: var ValidatorIndex) {.inline.} =
|
proc readValue*(r: var JsonReader, a: var ValidatorIndex) {.inline.} =
|
||||||
a = r.readValue(uint32)
|
a = r.readValue(uint32)
|
||||||
|
|
||||||
# TODO: cannot pass a typedesc
|
proc readValue*(r: var JsonReader, a: var Domain) {.inline.} =
|
||||||
# proc parseTests*(jsonPath: string, T: typedesc[Tests]): T =
|
## Custom deserializer for Domain
|
||||||
# # TODO: due to generic early symbol resolution
|
## They are uint64 stored in hex values
|
||||||
# # we cannot use a generic proc
|
# Furthermore Nim parseHex doesn't support uint
|
||||||
# # Otherwise we get:
|
# until https://github.com/nim-lang/Nim/pull/11067
|
||||||
# # "Error: undeclared identifier: 'ReaderType'"
|
# (0.20)
|
||||||
# # Templates, even untyped don't work
|
let be_uint = hexToPaddedByteArray[8](r.readValue(string))
|
||||||
# try:
|
bigEndian64(a.addr, be_uint.unsafeAddr)
|
||||||
# result = Json.loadFile(jsonPath, T)
|
|
||||||
# except SerializationError as err:
|
|
||||||
# writeStackTrace()
|
|
||||||
# stderr.write "Json load issue for file \"", jsonPath, "\"\n"
|
|
||||||
# stderr.write err.formatMsg(jsonPath), "\n"
|
|
||||||
# quit 1
|
|
||||||
|
|
||||||
proc parseTests*(jsonPath: string): ShufflingTests =
|
proc readValue*(r: var JsonReader, a: var seq[byte]) {.inline.} =
|
||||||
|
## Custom deserializer for seq[byte]
|
||||||
|
a = hexToSeqByte(r.readValue(string))
|
||||||
|
|
||||||
|
template parseTestsImpl(T: untyped) {.dirty.} =
|
||||||
|
# TODO: workaround typedesc/generics
|
||||||
|
# being broken with nim-serialization
|
||||||
|
# - https://github.com/status-im/nim-serialization/issues/4
|
||||||
|
# - https://github.com/status-im/nim-serialization/issues/5
|
||||||
try:
|
try:
|
||||||
result = Json.loadFile(jsonPath, ShufflingTests)
|
result = Json.loadFile(jsonPath, T)
|
||||||
except SerializationError as err:
|
except SerializationError as err:
|
||||||
writeStackTrace()
|
writeStackTrace()
|
||||||
stderr.write "Json load issue for file \"", jsonPath, "\"\n"
|
stderr.write "Json load issue for file \"", jsonPath, "\"\n"
|
||||||
stderr.write err.formatMsg(jsonPath), "\n"
|
stderr.write err.formatMsg(jsonPath), "\n"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
|
proc parseTestsShuffling*(jsonPath: string): Tests[Shuffling] =
|
||||||
|
parseTestsImpl(Tests[Shuffling])
|
||||||
|
|
||||||
|
proc parseTestsBLSPrivToPub*(jsonPath: string): Tests[BLSPrivToPub] =
|
||||||
|
parseTestsImpl(Tests[BLSPrivToPub])
|
||||||
|
|
||||||
|
proc parseTestsBLSSignMsg*(jsonPath: string): Tests[BLSSignMsg] =
|
||||||
|
parseTestsImpl(Tests[BLSSignMsg])
|
||||||
|
|
||||||
|
proc parseTestsBLSAggSig*(jsonPath: string): Tests[BLSAggSig] =
|
||||||
|
parseTestsImpl(Tests[BLSAggSig])
|
||||||
|
|
||||||
|
proc parseTestsBLSAggPubKey*(jsonPath: string): Tests[BLSAggPubKey] =
|
||||||
|
parseTestsImpl(Tests[BLSAggPubKey])
|
||||||
|
|
||||||
# #######################
|
# #######################
|
||||||
# Mocking helpers
|
# Mocking helpers
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/75f0af45bb0613bb406fc72d10266cee4cfb402a/tests/phase0/helpers.py#L107
|
# https://github.com/ethereum/eth2.0-specs/blob/75f0af45bb0613bb406fc72d10266cee4cfb402a/tests/phase0/helpers.py#L107
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# beacon_chain
|
||||||
|
# Copyright (c) 2018 Status Research & Development GmbH
|
||||||
|
# Licensed and distributed under either of
|
||||||
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||||
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
import
|
||||||
|
# Standard libs
|
||||||
|
ospaths, strutils, json, unittest,
|
||||||
|
# Third parties
|
||||||
|
|
||||||
|
# Beacon chain internals
|
||||||
|
../../beacon_chain/spec/crypto,
|
||||||
|
# Test utilities
|
||||||
|
./fixtures_utils
|
||||||
|
|
||||||
|
const TestFolder = currentSourcePath.rsplit(DirSep, 1)[0]
|
||||||
|
const TestsPath = "fixtures" / "json_tests" / "bls"
|
||||||
|
var
|
||||||
|
blsPrivToPubTests: Tests[BLSPrivToPub]
|
||||||
|
blsSignMsgTests: Tests[BLSSignMsg]
|
||||||
|
blsAggSigTests: Tests[BLSAggSig]
|
||||||
|
blsAggPubKeyTests: Tests[BLSAggPubKey]
|
||||||
|
|
||||||
|
suite "Official - BLS tests":
|
||||||
|
test "Parsing the official BLS tests":
|
||||||
|
blsPrivToPubTests = parseTestsBLSPrivToPub(TestFolder / TestsPath / "priv_to_pub" / "priv_to_pub.json")
|
||||||
|
blsSignMsgTests = parseTestsBLSSignMsg(TestFolder / TestsPath / "sign_msg" / "sign_msg.json")
|
||||||
|
blsAggSigTests = parseTestsBLSAggSig(TestFolder / TestsPath / "aggregate_sigs" / "aggregate_sigs.json")
|
||||||
|
blsAggPubKeyTests = parseTestsBLSAggPubKey(TestFolder / TestsPath / "aggregate_pubkeys" / "aggregate_pubkeys.json")
|
||||||
|
|
||||||
|
test "Private to public key conversion":
|
||||||
|
for t in blsPrivToPubTests.test_cases:
|
||||||
|
let implResult = t.input.pubkey()
|
||||||
|
check: implResult == t.output
|
||||||
|
|
||||||
|
test "Message signing":
|
||||||
|
for t in blsSignMsgTests.test_cases:
|
||||||
|
let implResult = t.input.privkey.bls_sign(
|
||||||
|
t.input.message,
|
||||||
|
uint64(t.input.domain)
|
||||||
|
)
|
||||||
|
check: implResult == t.output
|
||||||
|
|
||||||
|
test "Aggregating signatures":
|
||||||
|
for t in blsAggSigTests.test_cases:
|
||||||
|
let implResult = t.input.combine()
|
||||||
|
check: implResult == t.output
|
||||||
|
|
||||||
|
test "Aggregating public keys":
|
||||||
|
for t in blsAggPubKeyTests.test_cases:
|
||||||
|
let implResult = t.input.combine()
|
||||||
|
check: implResult == t.output
|
|
@ -18,11 +18,11 @@ import
|
||||||
const TestFolder = currentSourcePath.rsplit(DirSep, 1)[0]
|
const TestFolder = currentSourcePath.rsplit(DirSep, 1)[0]
|
||||||
const TestsPath = "fixtures" / "json_tests" / "shuffling" / "core" / "shuffling_full.json"
|
const TestsPath = "fixtures" / "json_tests" / "shuffling" / "core" / "shuffling_full.json"
|
||||||
|
|
||||||
var shufflingTests: ShufflingTests
|
var shufflingTests: Tests[Shuffling]
|
||||||
|
|
||||||
suite "Official - Shuffling tests":
|
suite "Official - Shuffling tests":
|
||||||
test "Parsing the official shuffling tests":
|
test "Parsing the official shuffling tests":
|
||||||
shufflingTests = parseTests(TestFolder / TestsPath)
|
shufflingTests = parseTestsShuffling(TestFolder / TestsPath)
|
||||||
|
|
||||||
test "Shuffling a sequence of N validators":
|
test "Shuffling a sequence of N validators":
|
||||||
for t in shufflingTests.test_cases:
|
for t in shufflingTests.test_cases:
|
||||||
|
|
|
@ -24,7 +24,7 @@ var stateTests: StateTests
|
||||||
suite "Official - State tests": # Initializing a beacon state from the deposits
|
suite "Official - State tests": # Initializing a beacon state from the deposits
|
||||||
# Source: https://github.com/ethereum/eth2.0-specs/blob/2baa242ac004b0475604c4c4ef4315e14f56c5c7/tests/phase0/test_sanity.py#L55-L460
|
# Source: https://github.com/ethereum/eth2.0-specs/blob/2baa242ac004b0475604c4c4ef4315e14f56c5c7/tests/phase0/test_sanity.py#L55-L460
|
||||||
test "Parsing the official state tests into Nimbus beacon types":
|
test "Parsing the official state tests into Nimbus beacon types":
|
||||||
stateTests = parseTests(TestFolder / TestsPath, StateTests) # TODO pending typedesc fix in fixture_utils.nim
|
stateTests = parseTests(TestFolder / TestsPath, StateTests)
|
||||||
doAssert $stateTests.test_cases[0].name == "test_empty_block_transition"
|
doAssert $stateTests.test_cases[0].name == "test_empty_block_transition"
|
||||||
|
|
||||||
test "[For information - Non-blocking] Block root signing":
|
test "[For information - Non-blocking] Block root signing":
|
||||||
|
|
Loading…
Reference in New Issue