From c691d37f0b20b5172413adb3abca1c00a821dc0b Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Wed, 18 Dec 2019 17:48:38 +0300 Subject: [PATCH] consensus: implement BLS signatures prototype --- config/config.go | 4 + config/protocol.privnet.docker.four.yml | 7 ++ config/protocol.privnet.docker.one.yml | 12 ++ config/protocol.privnet.docker.three.yml | 12 ++ config/protocol.privnet.docker.two.yml | 12 ++ go.mod | 3 +- go.sum | 15 ++- pkg/consensus/block.go | 6 +- pkg/consensus/consensus.go | 136 +++++++++++++++++++++-- pkg/consensus/crypto_test.go | 15 +++ pkg/core/blockchain.go | 1 + pkg/smartcontract/contract.go | 23 ++++ pkg/vm/opcode/opcode.go | 1 + pkg/vm/vm.go | 37 ++++++ 14 files changed, 271 insertions(+), 13 deletions(-) diff --git a/config/config.go b/config/config.go index f962ec41c..f364be6e6 100644 --- a/config/config.go +++ b/config/config.go @@ -84,8 +84,12 @@ type ( // WalletConfig is a wallet info. WalletConfig struct { + BLS string `yaml:"BLS"` + BLSPub string `yaml:"BLSPub"` Path string `yaml:"Path"` Password string `yaml:"Password"` + + BLSValidators []string `yaml:"BLSValidators"` } // RPCConfig is an RPC service configuration information (to be moved to the rpc package, see #423). diff --git a/config/protocol.privnet.docker.four.yml b/config/protocol.privnet.docker.four.yml index 05fdd6fa4..38bec0f43 100644 --- a/config/protocol.privnet.docker.four.yml +++ b/config/protocol.privnet.docker.four.yml @@ -55,5 +55,12 @@ ApplicationConfiguration: Enabled: false Port: 20014 UnlockWallet: + BLSValidators: + - 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d + - 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e + - 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 + - 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 + BLS: 4261a32d175a79a7aeac3c5d584d1135dd72acf8bf3897556dbf4e3d9331bcc3 + BLSPub: 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 Path: "6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc" Password: "four" diff --git a/config/protocol.privnet.docker.one.yml b/config/protocol.privnet.docker.one.yml index f44bc8df5..ee8932578 100644 --- a/config/protocol.privnet.docker.one.yml +++ b/config/protocol.privnet.docker.one.yml @@ -8,6 +8,11 @@ ProtocolConfiguration: - 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e - 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699 - 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62 + BLSValidators: + - 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d + - 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e + - 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 + - 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 SeedList: - 172.200.0.1:20333 - 172.200.0.2:20334 @@ -55,5 +60,12 @@ ApplicationConfiguration: Enabled: false Port: 20011 UnlockWallet: + BLSValidators: + - 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d + - 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e + - 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 + - 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 + BLS: 380aa8806e10350b114b0ef2b0f7dcc3f45b4db0622ed83ef4e75f8d4a92e81b + BLSPub: 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d Path: "6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y" Password: "one" diff --git a/config/protocol.privnet.docker.three.yml b/config/protocol.privnet.docker.three.yml index ad746a52d..a31c2510c 100644 --- a/config/protocol.privnet.docker.three.yml +++ b/config/protocol.privnet.docker.three.yml @@ -8,6 +8,11 @@ ProtocolConfiguration: - 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e - 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699 - 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62 + BLSValidators: + - 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d + - 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e + - 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 + - 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 SeedList: - 172.200.0.1:20333 - 172.200.0.2:20334 @@ -55,5 +60,12 @@ ApplicationConfiguration: Enabled: false Port: 20013 UnlockWallet: + BLSValidators: + - 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d + - 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e + - 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 + - 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 + BLS: 2d2c13c5018040977388792913d74f45aed99c260ec4b4fc36d2774fd56cf383 + BLSPub: 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 Path: "6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh" Password: "three" diff --git a/config/protocol.privnet.docker.two.yml b/config/protocol.privnet.docker.two.yml index b250aab10..7aa256fa6 100644 --- a/config/protocol.privnet.docker.two.yml +++ b/config/protocol.privnet.docker.two.yml @@ -8,6 +8,11 @@ ProtocolConfiguration: - 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e - 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699 - 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62 + BLSValidators: + - 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d + - 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e + - 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 + - 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 SeedList: - 172.200.0.1:20333 - 172.200.0.2:20334 @@ -55,5 +60,12 @@ ApplicationConfiguration: Enabled: false Port: 20012 UnlockWallet: + BLSValidators: + - 51856b9fe924fe1f5f91713e2ff056dab5602a88c1a72505fb8c2b749143a6788dcced6b86c1c4c25913aa7c993c0bb80dc1a21f40ca0a0c2893252bbe6bcf2b624af8f9dd97f53b4d15ed324cb01b61bf82bb7a3eb3d23f3ebfd76a6ed14bd7718d5740b4ec71486c99b234884352e73332c19ea8b11396d54cb28f3a326e3d + - 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e + - 69906710b7bdabfd224a94b932ae0942f81f302d39bc01fc3e069bc35e298f312c9e2c0160eb6a51f1fe65c4362502b2c6572f3a49ad96b3f07de56b5b8877cf53dd2a77d747983373301a37a731208ff44da1c8a2572c0b10feaa551dabde432ebebb1c6fd7119f8f0da21ef682ba0787619bd3f091f50158543be741938bc7 + - 10cf58258ee1966cfe506a1e8ba22dd5fddd5d3af2e67bcd5b835e05688ec4613a01ee8cf552715c12397f7e4b79e1fa12547d98e5df818e2f5472c54e91e8a6306dad6ee9a883d5df06e0c85e441968eff1ffcdf954b777d5312729b9049746650c416498878cd7724bfe8345f6a51b8f459d4a92630888de73b15520c011c2 + BLS: 7044746c1d9c9e043a61384a2f46fd0ada2a14b5ff377ba7474b31423c45da3c + BLSPub: 7f20fbb5a509059360aabd9e1c497b613abaa92b750d63d5c4503846e5fed3fd3d013f519ec984b110bff541b8144f7df460e4a0685fb1e6715ce1b1b68eb45a29724d614b3b46866a1e0bd5a489afa7763c2cfd598dfd476beee64a4e8554657da72d9495d7b1c982e01b40b10026b78f3d203335bc6d6be790945045b2901e Path: "6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L" Password: "two" diff --git a/go.mod b/go.mod index 6121dd82e..b4d5a9ca2 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-redis/redis v6.10.2+incompatible github.com/go-yaml/yaml v2.1.0+incompatible github.com/mr-tron/base58 v1.1.2 - github.com/nspcc-dev/dbft v0.0.0-20191213082456-c81c7a796775 + github.com/nspcc-dev/dbft v0.0.0-20191218095856-a0151004c0e6 github.com/nspcc-dev/rfc6979 v0.1.0 github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v1.2.1 @@ -15,6 +15,7 @@ require ( github.com/stretchr/testify v1.4.0 github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73 github.com/urfave/cli v1.20.0 + go.dedis.ch/kyber/v4 v4.0.0-pre2 go.uber.org/atomic v1.4.0 go.uber.org/zap v1.10.0 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 diff --git a/go.sum b/go.sum index 95c56f302..4dda23145 100644 --- a/go.sum +++ b/go.sum @@ -94,8 +94,8 @@ github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254 h1:A4OkQDQOSPsJF8qU github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw= github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae h1:T5V1QANlNMKun0EPB3eqg2PTXG4rmLhzDyEiV63kdB0= github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY= -github.com/nspcc-dev/dbft v0.0.0-20191213082456-c81c7a796775 h1:iqRxuEBrT2QbSdgmvGCwgn+lnOKmx1L5EiVTcOXUYt8= -github.com/nspcc-dev/dbft v0.0.0-20191213082456-c81c7a796775/go.mod h1:IyIyVYKfi41kAlGWqicz9G8Iyni71Resuhtd9Y5ujJM= +github.com/nspcc-dev/dbft v0.0.0-20191218095856-a0151004c0e6 h1:x6dNWn3ifNesdN5bW7dQadeZWFNLAaEsQ5L5phCy5Ek= +github.com/nspcc-dev/dbft v0.0.0-20191218095856-a0151004c0e6/go.mod h1:yEPpS/iA3ZN6yJwq9EbRLVVMK36YR3TuevCjOht+34U= github.com/nspcc-dev/neofs-crypto v0.2.0 h1:ftN+59WqxSWz/RCgXYOfhmltOOqU+udsNQSvN6wkFck= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= github.com/nspcc-dev/rfc6979 v0.1.0 h1:Lwg7esRRoyK1Up/IN1vAef1EmvrBeMHeeEkek2fAJ6c= @@ -149,6 +149,15 @@ github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036 h1:1b6PAtenNyhsmo/ github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7 h1:Y17pEjKgx2X0A69WQPGa8hx/Myzu+4NdUxlkZpbAYio= github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/kyber/v3 v3.0.4 h1:FDuC/S3STkvwxZ0ooo3gcp56QkUKsN7Jy7cpzBxL+vQ= +go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= +go.dedis.ch/kyber/v4 v4.0.0-pre2 h1:+KMfT7P/+KOfeYge3tY3JrnJXka8NwQacaL+BFkRts8= +go.dedis.ch/kyber/v4 v4.0.0-pre2/go.mod h1:+e66qaKOPauwNsLgvFyoU4n2vj6BMxdvNc/suD72H9g= +go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= +go.dedis.ch/protobuf v1.0.7 h1:wRUEiq3u0/vBhLjcw9CmAVrol+BnDyq2M0XLukdphyI= +go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= @@ -158,6 +167,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= @@ -176,6 +186,7 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/pkg/consensus/block.go b/pkg/consensus/block.go index 6d9c6dc27..c023d097d 100644 --- a/pkg/consensus/block.go +++ b/pkg/consensus/block.go @@ -20,7 +20,7 @@ var _ block.Block = (*neoBlock)(nil) // Sign implements block.Block interface. func (n *neoBlock) Sign(key crypto.PrivateKey) error { - data := n.BlockBase.GetHashableData() + data := n.BlockBase.VerificationHash() sig, err := key.Sign(data[:]) if err != nil { return err @@ -33,8 +33,8 @@ func (n *neoBlock) Sign(key crypto.PrivateKey) error { // Verify implements block.Block interface. func (n *neoBlock) Verify(key crypto.PublicKey, sign []byte) error { - data := n.BlockBase.GetHashableData() - return key.Verify(data, sign) + data := n.BlockBase.VerificationHash() + return key.Verify(data[:], sign) } // Transactions implements block.Block interface. diff --git a/pkg/consensus/consensus.go b/pkg/consensus/consensus.go index 39c7de9e2..d13ae4524 100644 --- a/pkg/consensus/consensus.go +++ b/pkg/consensus/consensus.go @@ -1,7 +1,10 @@ package consensus import ( + "bytes" + "encoding/hex" "errors" + "math/big" "math/rand" "sort" "time" @@ -19,6 +22,8 @@ import ( "github.com/nspcc-dev/dbft/block" "github.com/nspcc-dev/dbft/crypto" "github.com/nspcc-dev/dbft/payload" + "go.dedis.ch/kyber/v4" + "go.dedis.ch/kyber/v4/pairing" "go.uber.org/zap" ) @@ -56,6 +61,7 @@ type service struct { // everything in single thread. messages chan Payload transactions chan *transaction.Transaction + validators []crypto.PublicKey } // Config is a configuration for consensus services. @@ -103,7 +109,17 @@ func NewService(cfg Config) (Service, error) { return srv, nil } - priv, pub := getKeyPair(cfg.Wallet) + priv, pub := getBLSKeyPair(cfg.Wallet) + + for _, s := range cfg.Wallet.BLSValidators { + srv.validators = append(srv.validators, crypto.NewBLSPublicKey(getBLSPub(s))) + } + + sort.Slice(srv.validators, func(i, j int) bool { + pi, _ := srv.validators[i].MarshalBinary() + pj, _ := srv.validators[j].MarshalBinary() + return bytes.Compare(pi, pj) == -1 + }) srv.dbft = dbft.New( dbft.WithLogger(srv.log.Desugar()), @@ -177,6 +193,45 @@ func (s *service) validatePayload(p *Payload) bool { return p.Verify(h) } +var blsSuite = pairing.NewSuiteBn256() + +func getBLSPub(s string) kyber.Point { + data, err := hex.DecodeString(s) + if err != nil { + return nil + } + + pub := blsSuite.Point() + err = pub.UnmarshalBinary(data) + if err != nil { + return nil + } + + return pub +} + +func getBLSPriv(s string) kyber.Scalar { + data, err := hex.DecodeString(s) + if err != nil { + return nil + } + + priv := blsSuite.Scalar() + err = priv.UnmarshalBinary(data) + if err != nil { + return nil + } + + return priv +} + +func getBLSKeyPair(cfg *config.WalletConfig) (crypto.PrivateKey, crypto.PublicKey) { + priv := getBLSPriv(cfg.BLS) + pub := getBLSPub(cfg.BLSPub) + + return crypto.NewBLSPrivateKey(priv), crypto.NewBLSPublicKey(pub) +} + func getKeyPair(cfg *config.WalletConfig) (crypto.PrivateKey, crypto.PublicKey) { acc, err := wallet.DecryptAccount(cfg.Path, cfg.Password) if err != nil { @@ -238,9 +293,9 @@ func (s *service) broadcast(p payload.ConsensusPayload) { pr.minerTx = *s.txx.Get(pr.transactionHashes[0]).(*transaction.Transaction) } - if err := p.(*Payload).Sign(s.dbft.Priv.(*privateKey)); err != nil { - s.log.Warnf("can't sign consensus payload: %v", err) - } + // if err := p.(*Payload).Sign(s.dbft.Priv.(*privateKey)); err != nil { + // s.log.Warnf("can't sign consensus payload: %v", err) + // } s.cache.Add(p) s.Config.Broadcast(p.(*Payload)) @@ -269,7 +324,7 @@ func (s *service) verifyBlock(b block.Block) bool { func (s *service) processBlock(b block.Block) { bb := &b.(*neoBlock).Block - bb.Script = *(s.getBlockWitness(bb)) + bb.Script = *(s.getBlockWitnessBLS(bb)) if err := s.Chain.AddBlock(bb); err != nil { s.log.Warnf("error on add block: %v", err) @@ -278,6 +333,68 @@ func (s *service) processBlock(b block.Block) { } } +func (s *service) getBlockWitnessBLS(b *core.Block) *transaction.Witness { + dctx := s.dbft.Context + pubs := dctx.Validators + sigs := make(map[crypto.PublicKey][]byte) + + for i := range dctx.Validators { + if p := dctx.CommitPayloads[i]; p != nil && p.ViewNumber() == dctx.ViewNumber { + sigs[pubs[i]] = p.GetCommit().Signature() + } + } + + pubKeys := make([][]byte, len(pubs)) + for i := range pubs { + pubKeys[i], _ = pubs[i].MarshalBinary() + } + + m := s.dbft.Context.M() + verif, err := smartcontract.CreateBLSMultisigScript(m, pubKeys) + if err != nil { + s.log.Warnf("can't create multisig redeem script: %v", err) + return nil + } + + var indices []int + var sigSlice [][]byte + for i := range pubs { + if s := sigs[pubs[i]]; s != nil { + indices = append(indices, i) + sigSlice = append(sigSlice, s) + } + } + + sig, err := crypto.AggregateBLSSignatures(sigSlice...) + if err != nil { + return nil + } + + pk := make([]crypto.PublicKey, len(sigSlice)) + mask := big.NewInt(0) + + for i, j := range indices { + pk[i] = pubs[j] + + // keys will be pushed in reverse order + t := new(big.Int).Lsh(big.NewInt(1), uint(len(pubs)-j-1)) + mask.Or(mask, t) + } + + var invoc []byte + invoc = append(invoc, byte(opcode.PUSHBYTES64)) + invoc = append(invoc, sig...) + + buf := mask.Bytes() + invoc = append(invoc, byte(opcode.PUSHBYTES1)+byte(len(buf)-1)) + invoc = append(invoc, buf...) + + return &transaction.Witness{ + InvocationScript: invoc, + VerificationScript: verif, + } +} + func (s *service) getBlockWitness(b *core.Block) *transaction.Witness { dctx := s.dbft.Context pubs := convertKeys(dctx.Validators) @@ -355,6 +472,8 @@ func (s *service) getVerifiedTx(count int) []block.Transaction { } func (s *service) getValidators(txx ...block.Transaction) []crypto.PublicKey { + return s.validators + var pKeys []*keys.PublicKey if len(txx) == 0 { pKeys, _ = s.Chain.GetValidators() @@ -376,9 +495,12 @@ func (s *service) getValidators(txx ...block.Transaction) []crypto.PublicKey { } func (s *service) getConsensusAddress(validators ...crypto.PublicKey) (h util.Uint160) { - pubs := convertKeys(validators) + pubKeys := make([][]byte, len(validators)) + for i := range validators { + pubKeys[i], _ = validators[i].MarshalBinary() + } - script, err := smartcontract.CreateMultiSigRedeemScript(s.dbft.M(), pubs) + script, err := smartcontract.CreateBLSMultisigScript(s.dbft.M(), pubKeys) if err != nil { return } diff --git a/pkg/consensus/crypto_test.go b/pkg/consensus/crypto_test.go index 9c7405343..fb6bc836e 100644 --- a/pkg/consensus/crypto_test.go +++ b/pkg/consensus/crypto_test.go @@ -1,6 +1,10 @@ package consensus import ( + "crypto/rand" + "encoding/hex" + "fmt" + "github.com/nspcc-dev/dbft/crypto" "testing" "github.com/CityOfZion/neo-go/pkg/crypto/keys" @@ -41,3 +45,14 @@ func TestCrypt(t *testing.T) { sign[0] = ^sign[0] require.Error(t, pub.Verify(data, sign)) } + +func Test1(t *testing.T) { + for i := 0; i < 4; i++ { + priv, pub := crypto.GenerateWith(crypto.SuiteBLS, rand.Reader) + data, _ := priv.MarshalBinary() + fmt.Printf("pri %d: %s\n", i, hex.EncodeToString(data)) + + data, _ = pub.MarshalBinary() + fmt.Printf("pub %d: %s\n", i, hex.EncodeToString(data)) + } +} \ No newline at end of file diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index a44a03386..cb10d92f4 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1467,6 +1467,7 @@ func (bc *Blockchain) verifyBlockWitnesses(block *Block, prevHeader *Header) err hash = prevHeader.NextConsensus } interopCtx := newInteropContext(trigger.Verification, bc, bc.dao.store, nil, nil) + return bc.verifyHashAgainstScript(block.Script.ScriptHash(), &block.Script, block.VerificationHash(), interopCtx, true) return bc.verifyHashAgainstScript(hash, &block.Script, block.VerificationHash(), interopCtx, true) } diff --git a/pkg/smartcontract/contract.go b/pkg/smartcontract/contract.go index 4766659ea..c684367d1 100644 --- a/pkg/smartcontract/contract.go +++ b/pkg/smartcontract/contract.go @@ -41,3 +41,26 @@ func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, erro return buf.Bytes(), nil } + +func CreateBLSMultisigScript(m int, pubs [][]byte) ([]byte, error) { + sort.Slice(pubs, func(i, j int) bool { return bytes.Compare(pubs[i], pubs[j]) == -1 }) + + buf := new(bytes.Buffer) + if err := vm.EmitInt(buf, int64(m)); err != nil { + return nil, err + } + for i := range pubs { + if err := vm.EmitBytes(buf, pubs[i]); err != nil { + return nil, err + } + } + + if err := vm.EmitInt(buf, int64(len(pubs))); err != nil { + return nil, err + } + if err := vm.EmitOpcode(buf, opcode.CHECKBLS); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} \ No newline at end of file diff --git a/pkg/vm/opcode/opcode.go b/pkg/vm/opcode/opcode.go index f3e09a5a8..bc1b630a9 100644 --- a/pkg/vm/opcode/opcode.go +++ b/pkg/vm/opcode/opcode.go @@ -185,6 +185,7 @@ const ( CHECKSIG Opcode = 0xAC VERIFY Opcode = 0xAD CHECKMULTISIG Opcode = 0xAE + CHECKBLS Opcode = 0xAF // Advanced data structures (arrays, structures, maps) ARRAYSIZE Opcode = 0xC0 diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index eae4aaab5..76735a8d3 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -16,6 +16,9 @@ import ( "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm/opcode" "github.com/pkg/errors" + "go.dedis.ch/kyber/v4" + "go.dedis.ch/kyber/v4/pairing" + "go.dedis.ch/kyber/v4/sign/bls" ) type errorAtInstruct struct { @@ -1174,6 +1177,40 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro res := pkey.Verify(signature, hashToCheck) v.estack.PushVal(res) + case opcode.CHECKBLS: + pkeys, err := v.estack.popSigElements() + if err != nil { + panic(fmt.Sprintf("wrong parameters: %s", err.Error())) + } + + m := v.estack.Pop().BigInt().Int64() + mask := v.estack.Pop().BigInt() + sig := v.estack.Pop().Bytes() + + s := pairing.NewSuiteBn256() + var pubs []kyber.Point + for i := range pkeys { + if mask.Bit(i) == 1 { + m-- + pub := s.Point() + err := pub.UnmarshalBinary(pkeys[i]) + if err != nil { + panic(err) + } + + pubs = append(pubs, pub) + } + } + + if m != 0 { + panic("wrong number of signatures") + } + + pub := bls.AggregatePublicKeys(s, pubs...) + err = bls.Verify(s, pub, v.checkhash, sig) + + v.estack.PushVal(err == nil) + case opcode.CHECKMULTISIG: pkeys, err := v.estack.popSigElements() if err != nil {