diff --git a/core/vdf/engine.go b/core/vdf/engine.go new file mode 100644 index 000000000000..67d0746165e5 --- /dev/null +++ b/core/vdf/engine.go @@ -0,0 +1,133 @@ +// Copyright 2019 The gonex Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vdf + +import ( + "fmt" + "os/exec" + "strconv" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum/go-ethereum/log" + "github.com/harmony-one/vdf/src/vdf_go" +) + +var ( + engine *Engine + engineOnce sync.Once +) + +// Engine defines the structure of the engine +type Engine struct { + cli string +} + +// Instance returns the singleton instance of the VDF Engine +func Instance() *Engine { + engineOnce.Do(func() { + engine = newEngine() + }) + return engine +} + +func newEngine() *Engine { + cli, err := exec.LookPath("vdf-cli") + if err != nil { + log.Warn("vdf.newEngine", "vdf-cli", "not found") + } + return &Engine{cli} +} + +// Verify verifies the generated output against the seed +func (e *Engine) Verify(seed, output []byte, iteration uint64, bitSize uint64) (valid bool) { + defer func() { + if x := recover(); x != nil { + log.Error("vdf.Verify: verification process panic", "reason", x) + valid = false + } + }() + return vdf_go.VerifyVDF(seed, output, int(iteration), int(bitSize)) +} + +// Generate generates the vdf output = (y, proof) +func (e *Engine) Generate(seed []byte, iteration uint64, bitSize uint64, stop <-chan struct{}) (output []byte, err error) { + if len(e.cli) == 0 { + defer func() { + if x := recover(); x != nil { + log.Error("vdf.Generate: generation process panic", "reason", x) + err = fmt.Errorf("%v", x) + } + }() + y, proof := vdf_go.GenerateVDFWithStopChan(seed, int(iteration), int(bitSize), stop) + if y == nil || proof == nil { + return nil, nil + } + return append(y, proof...), nil + } + + cmd := exec.Command(e.cli, + "-l"+strconv.Itoa(int(bitSize)), + common.Bytes2Hex(seed), + strconv.Itoa(int(iteration))) + + log.Trace(e.cli + " -l" + strconv.Itoa(int(bitSize)) + " " + common.Bytes2Hex(seed) + " " + strconv.Itoa(int(iteration))) + + var done chan struct{} + if stop != nil { + go func() { + select { + case <-stop: + if cmd == nil || cmd.Process == nil { + return + } + log.Trace("vdf.Generate: vdf-cli interrupted") + if err := cmd.Process.Kill(); err != nil { + log.Error("vdf.Generate: failed to kill vdf-cli process", "err", err) + } + return + case <-done: + return + } + }() + } + + log.Trace("vdf.Generate", "seed", common.Bytes2Hex(seed), "iteration", iteration, "output", common.Bytes2Hex(output)) + output, err = cmd.Output() + if err, ok := err.(*exec.ExitError); ok { + // verification failed + log.Trace("vdf.Generate", "error code", err.Error()) + return nil, err + } + if err != nil { + // sum ting wong + log.Error("vdf.Generate", "error", err) + return nil, err + } + + if stop != nil && done != nil { + // prevent goroutine leakage + done <- struct{}{} + } + + strOutput := strings.TrimSpace(string(output)) + + log.Trace("vdf.Generate", "output", strOutput) + return common.Hex2Bytes(strOutput), nil +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 20b741f8f144..7610b6652a35 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -23,8 +23,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/vdf" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/bn256" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "golang.org/x/crypto/ripemd160" ) @@ -59,6 +61,20 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{8}): &bn256Pairing{}, } +// PrecompiledContractsCoLoa contains the default set of pre-compiled Ethereum +// contracts used in the CoLoa release. +var PrecompiledContractsCoLoa = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{0x01}): &ecrecover{}, + common.BytesToAddress([]byte{0x02}): &sha256hash{}, + common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x04}): &dataCopy{}, + common.BytesToAddress([]byte{0x05}): &bigModExp{}, + common.BytesToAddress([]byte{0x06}): &bn256Add{}, + common.BytesToAddress([]byte{0x07}): &bn256ScalarMul{}, + common.BytesToAddress([]byte{0x08}): &bn256Pairing{}, + common.BytesToAddress([]byte{0xFF}): &vdfVerify{}, +} + // RunPrecompiledContract runs and evaluates the output of a precompiled contract. func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { gas := p.RequiredGas(input) @@ -320,6 +336,15 @@ var ( // errBadPairingInput is returned if the bn256 pairing input is invalid. errBadPairingInput = errors.New("bad elliptic curve pairing size") + + // errBadVDFInputLen is returned if the vdf verification input length is invalid. + errBadVDFInputLen = errors.New("bad VDF verification input length") + + // errBadVDFInput is returned if the vdf verification input is invalid. + errBadVDFInput = errors.New("bad VDF verification input") + + // errVDFVerificationFailed is returned if there is something wrong with vdf verification process. + errVDFVerificationFailed = errors.New("VDF verification internal error") ) // bn256Pairing implements a pairing pre-compile for the bn256 curve @@ -358,3 +383,41 @@ func (c *bn256Pairing) Run(input []byte) ([]byte, error) { } return false32Byte, nil } + +// vdfVerify implements a VDF verification using either wesolowski or pietrzak construction +type vdfVerify struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *vdfVerify) RequiredGas(input []byte) uint64 { + return params.VDFVerifyBaseGas // TODO +++ +} + +func (c *vdfVerify) Run(input []byte) (valid []byte, err error) { + log.Trace("VDFVerify", "input", common.ToHex(input)) + + // Convert the input into a vdf params + bitSize := new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() + outputLen := (bitSize + 16) >> 2 + // Handle some corner cases cheaply + if uint64(len(input)) != 32*3+outputLen { + log.Error("VDFVerify", "error", errBadVDFInputLen, "input len", len(input), "expected", 32*3+outputLen) + return nil, errBadVDFInputLen + } + + iteration := new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() + seed := getData(input, 64, 32) + output := getData(input, 96, outputLen) + + log.Trace("VDFVerify", + "bitSize", bitSize, + "iteration", iteration, + "seed", common.ToHex(seed), + "output", common.ToHex(output)) + + ok := vdf.Instance().Verify(seed, output, iteration, bitSize) + log.Trace("VDFVerify", "valid", ok) + if ok { + return true32Byte, nil + } + return false32Byte, nil +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 188a39f9fd5e..bafe4b2fe52f 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -44,7 +44,9 @@ type ( func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { precompiles := PrecompiledContractsHomestead - if evm.ChainConfig().IsByzantium(evm.BlockNumber) { + if evm.ChainConfig().IsCoLoa(evm.BlockNumber) { + precompiles = PrecompiledContractsCoLoa + } else if evm.ChainConfig().IsByzantium(evm.BlockNumber) { precompiles = PrecompiledContractsByzantium } if p := precompiles[*contract.CodeAddr]; p != nil { @@ -203,7 +205,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas ) if !evm.StateDB.Exist(addr) { precompiles := PrecompiledContractsHomestead - if evm.ChainConfig().IsByzantium(evm.BlockNumber) { + if evm.ChainConfig().IsCoLoa(evm.BlockNumber) { + precompiles = PrecompiledContractsCoLoa + } else if evm.ChainConfig().IsByzantium(evm.BlockNumber) { precompiles = PrecompiledContractsByzantium } if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { diff --git a/eth/tracers/tracer.go b/eth/tracers/tracer.go index 9d6701868c72..cb341ea17233 100644 --- a/eth/tracers/tracer.go +++ b/eth/tracers/tracer.go @@ -390,7 +390,7 @@ func New(code string) (*Tracer, error) { return 1 }) tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { - _, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))] + _, ok := vm.PrecompiledContractsCoLoa[common.BytesToAddress(popSlice(ctx))] ctx.PushBoolean(ok) return 1 }) diff --git a/params/protocol_params.go b/params/protocol_params.go index f4d6a6815f98..0cb987c34cac 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -87,6 +87,8 @@ const ( Bn256ScalarMulGas uint64 = 40000 // Gas needed for an elliptic curve scalar multiplication Bn256PairingBaseGas uint64 = 100000 // Base price for an elliptic curve pairing check Bn256PairingPerPointGas uint64 = 80000 // Per-point price for an elliptic curve pairing check + VDFVerifyBaseGas uint64 = 130000 // Base price for a VDF verification + VDFVerifyPerBitGas uint64 = 15000 // Per-bit integer size for a VDF verification ) var ( diff --git a/vendor/github.com/harmony-one/vdf/.gitignore b/vendor/github.com/harmony-one/vdf/.gitignore new file mode 100644 index 000000000000..b8916a4b7acf --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/.gitignore @@ -0,0 +1,16 @@ +.idea +*.exe +*.exe~ +*.dll +*.so +*.dylib + +*.test + +*.out + +bin/ + +# Dependency directories (remove the comment below to include it) +github.com/ +golang.org/ diff --git a/vendor/github.com/harmony-one/vdf/LICENSE b/vendor/github.com/harmony-one/vdf/LICENSE new file mode 100644 index 000000000000..39bc137aefed --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 harmony-one + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/harmony-one/vdf/README.md b/vendor/github.com/harmony-one/vdf/README.md new file mode 100644 index 000000000000..1a6bd937f507 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/README.md @@ -0,0 +1,8 @@ +### VDF (verified delay function) implementation in Golang + +This is the VDF used in Harmony Project. It is based on Benjanmin Wesolowski's paper "Efficient verifiable delay functions"(https://eprint.iacr.org/2018/623.pdf). +In this implementation, the VDF function takes 32 bytes as seed and an integer as difficulty. + +Please note that only 2048 integer size for class group variables are supported now. + +The interface of VDF is in src/vdf_go/vdf.go and examples are in src/test/vdf_module_test.go diff --git a/vendor/github.com/harmony-one/vdf/go.mod b/vendor/github.com/harmony-one/vdf/go.mod new file mode 100644 index 000000000000..0f7790a78946 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/go.mod @@ -0,0 +1,5 @@ +module github.com/harmony-one/vdf + +go 1.12 + +require github.com/stretchr/testify v1.3.0 diff --git a/vendor/github.com/harmony-one/vdf/go.sum b/vendor/github.com/harmony-one/vdf/go.sum new file mode 100644 index 000000000000..4347755afe82 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/go.sum @@ -0,0 +1,7 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/classgroup.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/classgroup.go new file mode 100644 index 000000000000..6e5ac2c1efe9 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/classgroup.go @@ -0,0 +1,381 @@ +package vdf_go + +import ( + "math/big" +) + +type ClassGroup struct { + a *big.Int + b *big.Int + c *big.Int + d *big.Int +} + +func CloneClassGroup(cg *ClassGroup) *ClassGroup { + return &ClassGroup{a: cg.a, b: cg.b, c: cg.c} +} + +func NewClassGroup(a, b, c *big.Int) *ClassGroup { + return &ClassGroup{a: a, b: b, c: c} +} + +func NewClassGroupFromAbDiscriminant(a, b, discriminant *big.Int) *ClassGroup { + //z = b*b-discriminant + z := new(big.Int).Sub(new(big.Int).Mul(b, b), discriminant) + + //z = z // 4a + c := floorDivision(z, new(big.Int).Mul(a, big.NewInt(4))) + + return NewClassGroup(a, b, c) +} + +func NewClassGroupFromBytesDiscriminant(buf []byte, discriminant *big.Int) (*ClassGroup, bool) { + int_size_bits := discriminant.BitLen() + + //add additional one byte for sign + int_size := (int_size_bits + 16) >> 4 + + //make sure the input byte buffer size matches with discriminant's + if len(buf) != int_size*2 { + return nil, false + } + + a := decodeTwosComplement(buf[:int_size]) + b := decodeTwosComplement(buf[int_size:]) + + return NewClassGroupFromAbDiscriminant(a, b, discriminant), true +} + +func IdentityForDiscriminant(d *big.Int) *ClassGroup { + return NewClassGroupFromAbDiscriminant(big.NewInt(1), big.NewInt(1), d) +} + +func (group *ClassGroup) Normalized() *ClassGroup { + a := new(big.Int).Set(group.a) + b := new(big.Int).Set(group.b) + c := new(big.Int).Set(group.c) + + //if b > -a && b <= a: + if (b.Cmp(new(big.Int).Neg(a)) == 1) && (b.Cmp(a) < 1) { + return group + } + + //r = (a - b) // (2 * a) + r := new(big.Int).Sub(a, b) + r = floorDivision(r, new(big.Int).Mul(a, big.NewInt(2))) + + //b, c = b + 2 * r * a, a * r * r + b * r + c + t := new(big.Int).Mul(big.NewInt(2), r) + t.Mul(t, a) + oldB := new(big.Int).Set(b) + b.Add(b, t) + + x := new(big.Int).Mul(a, r) + x.Mul(x, r) + y := new(big.Int).Mul(oldB, r) + c.Add(c, x) + c.Add(c, y) + + return NewClassGroup(a, b, c) +} + +func (group *ClassGroup) Reduced() *ClassGroup { + g := group.Normalized() + a := new(big.Int).Set(g.a) + b := new(big.Int).Set(g.b) + c := new(big.Int).Set(g.c) + + //while a > c or (a == c and b < 0): + for (a.Cmp(c) == 1) || ((a.Cmp(c) == 0) && (b.Sign() == -1)) { + //s = (c + b) // (c + c) + s := new(big.Int).Add(c, b) + s = floorDivision(s, new(big.Int).Add(c, c)) + + //a, b, c = c, -b + 2 * s * c, c * s * s - b * s + a + oldA := new(big.Int).Set(a) + oldB := new(big.Int).Set(b) + a = new(big.Int).Set(c) + + b.Neg(b) + x := new(big.Int).Mul(big.NewInt(2), s) + x.Mul(x, c) + b.Add(b, x) + + c.Mul(c, s) + c.Mul(c, s) + oldB.Mul(oldB, s) + c.Sub(c, oldB) + c.Add(c, oldA) + } + + return NewClassGroup(a, b, c).Normalized() +} + +func (group *ClassGroup) identity() *ClassGroup { + return NewClassGroupFromAbDiscriminant(big.NewInt(1), big.NewInt(1), group.Discriminant()) +} + +func (group *ClassGroup) Discriminant() *big.Int { + if group.d == nil { + d := new(big.Int).Set(group.b) + d.Mul(d, d) + a := new(big.Int).Set(group.a) + a.Mul(a, group.c) + a.Mul(a, big.NewInt(4)) + d.Sub(d, a) + + group.d = d + } + return group.d +} + +func (group *ClassGroup) Multiply(other *ClassGroup) *ClassGroup { + //a1, b1, c1 = self.reduced() + x := group.Reduced() + + //a2, b2, c2 = other.reduced() + y := other.Reduced() + + //g = (b2 + b1) // 2 + g := new(big.Int).Add(x.b, y.b) + g = floorDivision(g, big.NewInt(2)) + + //h = (b2 - b1) // 2 + h := new(big.Int).Sub(y.b, x.b) + h = floorDivision(h, big.NewInt(2)) + + //w = mod.gcd(a1, a2, g) + w1 := allInputValueGCD(y.a, g) + w := allInputValueGCD(x.a, w1) + + //j = w + j := new(big.Int).Set(w) + //r = 0 + r := big.NewInt(0) + //s = a1 // w + s := floorDivision(x.a, w) + //t = a2 // w + t := floorDivision(y.a, w) + //u = g // w + u := floorDivision(g, w) + + //k_temp, constant_factor = mod.solve_mod(t * u, h * u + s * c1, s * t) + b := new(big.Int).Mul(h, u) + sc := new(big.Int).Mul(s, x.c) + b.Add(b, sc) + k_temp, constant_factor, solvable := SolveMod(new(big.Int).Mul(t, u), b, new(big.Int).Mul(s, t)) + if !solvable { + return nil + } + + //n, constant_factor_2 = mod.solve_mod(t * constant_factor, h - t * k_temp, s) + n, _, solvable := SolveMod(new(big.Int).Mul(t, constant_factor), new(big.Int).Sub(h, new(big.Int).Mul(t, k_temp)), s) + if !solvable { + return nil + } + + //k = k_temp + constant_factor * n + k := new(big.Int).Add(k_temp, new(big.Int).Mul(constant_factor, n)) + + //l = (t * k - h) // s + l := floorDivision(new(big.Int).Sub(new(big.Int).Mul(t, k), h), s) + + //m = (t * u * k - h * u - s * c1) // (s * t) + tuk := new(big.Int).Mul(t, u) + tuk.Mul(tuk, k) + + hu := new(big.Int).Mul(h, u) + + tuk.Sub(tuk, hu) + tuk.Sub(tuk, sc) + + st := new(big.Int).Mul(s, t) + m := floorDivision(tuk, st) + + //a3 = s * t - r * u + ru := new(big.Int).Mul(r, u) + a3 := st.Sub(st, ru) + + //b3 = (j * u + m * r) - (k * t + l * s) + ju := new(big.Int).Mul(j, u) + mr := new(big.Int).Mul(m, r) + ju = ju.Add(ju, mr) + + kt := new(big.Int).Mul(k, t) + ls := new(big.Int).Mul(l, s) + kt = kt.Add(kt, ls) + + b3 := ju.Sub(ju, kt) + + //c3 = k * l - j * m + kl := new(big.Int).Mul(k, l) + jm := new(big.Int).Mul(j, m) + + c3 := kl.Sub(kl, jm) + return NewClassGroup(a3, b3, c3).Reduced() +} + +func (group *ClassGroup) Pow(n int64) *ClassGroup { + x := CloneClassGroup(group) + items_prod := group.identity() + + for n > 0 { + if n&1 == 1 { + items_prod = items_prod.Multiply(x) + if items_prod == nil { + return nil + } + } + x = x.Square() + if x == nil { + return nil + } + n >>= 1 + } + return items_prod +} + +func (group *ClassGroup) BigPow(n *big.Int) *ClassGroup { + x := CloneClassGroup(group) + items_prod := group.identity() + + p := new(big.Int).Set(n) + for p.Sign() > 0 { + if p.Bit(0) == 1 { + items_prod = items_prod.Multiply(x) + if items_prod == nil { + return nil + } + } + x = x.Square() + if x == nil { + return nil + } + p.Rsh(p, 1) + } + return items_prod +} + +func (group *ClassGroup) Square() *ClassGroup { + u, _, solvable := SolveMod(group.b, group.c, group.a) + if !solvable { + return nil + } + + //A = a + A := new(big.Int).Mul(group.a, group.a) + + //B = b − 2aµ, + au := new(big.Int).Mul(group.a, u) + B := new(big.Int).Sub(group.b, new(big.Int).Mul(au, big.NewInt(2))) + + //C = µ ^ 2 - (bµ−c)//a + C := new(big.Int).Mul(u, u) + m := new(big.Int).Mul(group.b, u) + m = new(big.Int).Sub(m, group.c) + m = floorDivision(m, group.a) + C = new(big.Int).Sub(C, m) + + return NewClassGroup(A, B, C).Reduced() +} + +func (group *ClassGroup) SquareUsingMultiply() *ClassGroup { + //a1, b1, c1 = self.reduced() + x := group.Reduced() + + //g = b1 + g := x.b + //h = 0 + h := big.NewInt(0) + + //w = mod.gcd(a1, g) + w := allInputValueGCD(x.a, g) + + //j = w + j := new(big.Int).Set(w) + //r = 0 + r := big.NewInt(0) + //s = a1 // w + s := floorDivision(x.a, w) + //t = s + t := s + //u = g // w + u := floorDivision(g, w) + + //k_temp, constant_factor = mod.solve_mod(t * u, h * u + s * c1, s * t) + b := new(big.Int).Mul(h, u) + sc := new(big.Int).Mul(s, x.c) + b.Add(b, sc) + k_temp, constant_factor, solvable := SolveMod(new(big.Int).Mul(t, u), b, new(big.Int).Mul(s, t)) + if !solvable { + return nil + } + + //n, constant_factor_2 = mod.solve_mod(t * constant_factor, h - t * k_temp, s) + n, _, solvable := SolveMod(new(big.Int).Mul(t, constant_factor), new(big.Int).Sub(h, new(big.Int).Mul(t, k_temp)), s) + if !solvable { + return nil + } + + //k = k_temp + constant_factor * n + k := new(big.Int).Add(k_temp, new(big.Int).Mul(constant_factor, n)) + + //l = (t * k - h) // s + l := floorDivision(new(big.Int).Sub(new(big.Int).Mul(t, k), h), s) + + //m = (t * u * k - h * u - s * c1) // (s * t) + tuk := new(big.Int).Mul(t, u) + tuk.Mul(tuk, k) + + hu := new(big.Int).Mul(h, u) + + tuk.Sub(tuk, hu) + tuk.Sub(tuk, sc) + + st := new(big.Int).Mul(s, t) + m := floorDivision(tuk, st) + + //a3 = s * t - r * u + ru := new(big.Int).Mul(r, u) + a3 := st.Sub(st, ru) + + //b3 = (j * u + m * r) - (k * t + l * s) + ju := new(big.Int).Mul(j, u) + mr := new(big.Int).Mul(m, r) + ju = ju.Add(ju, mr) + + kt := new(big.Int).Mul(k, t) + ls := new(big.Int).Mul(l, s) + kt = kt.Add(kt, ls) + + b3 := ju.Sub(ju, kt) + + //c3 = k * l - j * m + kl := new(big.Int).Mul(k, l) + jm := new(big.Int).Mul(j, m) + + c3 := kl.Sub(kl, jm) + + return NewClassGroup(a3, b3, c3).Reduced() +} + +// Serialize encodes a, b based on discriminant's size +// using one more byte for sign if nessesary +func (group *ClassGroup) Serialize() []byte { + r := group.Reduced() + int_size_bits := group.Discriminant().BitLen() + int_size := (int_size_bits + 16) >> 4 + + buf := make([]byte, int_size*2) + copy(buf[:int_size], signBitFill(encodeTwosComplement(r.a), int_size)) + copy(buf[int_size:], signBitFill(encodeTwosComplement(r.b), int_size)) + + return buf +} + +func (group *ClassGroup) Equal(other *ClassGroup) bool { + g := group.Reduced() + o := other.Reduced() + + return (g.a.Cmp(o.a) == 0 && g.b.Cmp(o.b) == 0 && g.c.Cmp(o.c) == 0) +} diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/discriminant.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/discriminant.go new file mode 100644 index 000000000000..11decddf58e3 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/discriminant.go @@ -0,0 +1,110 @@ +package vdf_go + +import ( + "bytes" + "crypto/sha256" + "encoding/binary" + "math/big" +) + +type Pair struct { + p int64 + q int64 +} + +var odd_primes = primeLessThanN(1 << 16) +var m = 8 * 3 * 5 * 7 * 11 * 13 +var residues = make([]int, 0, m) +var sieve_info = make([]Pair, 0, len(odd_primes)) + +func init() { + for x := 7; x < m; x += 8 { + if (x%3 != 0) && (x%5 != 0) && (x%7 != 0) && (x%11 != 0) && (x%13 != 0) { + residues = append(residues, x) + } + } + + var odd_primes_above_13 = odd_primes[5:] + + for i := 0; i < len(odd_primes_above_13); i++ { + prime := int64(odd_primes_above_13[i]) + sieve_info = append(sieve_info, Pair{p: int64(prime), q: modExp(int64(m)%prime, prime-2, prime)}) + } +} + +func modExp(base, exponent, modulus int64) int64 { + if modulus == 1 { + return 0 + } + base = base % modulus + result := int64(1) + for i := int64(0); i < exponent; i++ { + result = (result * base) % modulus + } + return result +} + +func EntropyFromSeed(seed []byte, byte_count int) []byte { + buffer := bytes.Buffer{} + bufferSize := 0 + + extra := uint16(0) + bytes := make([]byte, len(seed)+2) + copy(bytes, seed) + for bufferSize <= byte_count { + binary.BigEndian.PutUint16(bytes[len(seed):], extra) + more_entropy := sha256.Sum256(bytes) + buffer.Write(more_entropy[:]) + bufferSize += sha256.Size + extra += 1 + } + + return buffer.Bytes()[:byte_count] +} + +//Return a discriminant of the given length using the given seed +//It is a random prime p between 13 - 2^2K +//return -p, where p % 8 == 7 +func CreateDiscriminant(seed []byte, length int) *big.Int { + extra := uint8(length) & 7 + byte_count := ((length + 7) >> 3) + 2 + entropy := EntropyFromSeed(seed, byte_count) + + n := new(big.Int) + n.SetBytes(entropy[:len(entropy)-2]) + n = new(big.Int).Rsh(n, uint(((8 - extra) & 7))) + n = new(big.Int).SetBit(n, length-1, 1) + n = new(big.Int).Sub(n, new(big.Int).Mod(n, big.NewInt(int64(m)))) + n = new(big.Int).Add(n, big.NewInt(int64(residues[int(binary.BigEndian.Uint16(entropy[len(entropy)-2:len(entropy)]))%len(residues)]))) + + negN := new(big.Int).Neg(n) + + // Find the smallest prime >= n of the form n + m*x + for { + sieve := make([]bool, (1 << 16)) + + for _, v := range sieve_info { + // q = m^-1 (mod p) + // i = -n / m, so that m*i is -n (mod p) + //i := ((-n % v.p) * v.q) % v.p + i := (new(big.Int).Mod(negN, big.NewInt(v.p)).Int64() * v.q) % v.p + + for i < int64(len(sieve)) { + sieve[i] = true + i += v.p + } + } + + for i, v := range sieve { + t := new(big.Int).Add(n, big.NewInt(int64(m)*int64(i))) + if !v && t.ProbablyPrime(1) { + return new(big.Int).Neg(t) + } + } + + //n += m * (1 << 16) + bigM := big.NewInt(int64(m)) + n = new(big.Int).Add(n, bigM.Mul(bigM, big.NewInt(int64(1<<16)))) + + } +} diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/division.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/division.go new file mode 100644 index 000000000000..628b4019bcba --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/division.go @@ -0,0 +1,18 @@ +package vdf_go + +import "math/big" + +//Floor Division for big.Int +//Reference : Division and Modulus for Computer Scientists +//https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote.pdf +//Golang only has Euclid division and T-division +func floorDivision(x, y *big.Int) *big.Int { + var r big.Int + q, _ := new(big.Int).QuoRem(x, y, &r) + + if (r.Sign() == 1 && y.Sign() == -1) || (r.Sign() == -1 && y.Sign() == 1) { + q.Sub(q, big.NewInt(1)) + } + + return q +} diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/encode.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/encode.go new file mode 100644 index 000000000000..db81f6ce0428 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/encode.go @@ -0,0 +1,78 @@ +package vdf_go + +import "math/big" + +var bigOne = big.NewInt(1) + +func decodeTwosComplement(bytes []byte) *big.Int { + if bytes[0]&0x80 == 0 { + // non-negative + return new(big.Int).SetBytes(bytes) + } + setyb := make([]byte, len(bytes)) + for i := range bytes { + setyb[i] = bytes[i] ^ 0xff + } + n := new(big.Int).SetBytes(setyb) + return n.Sub(n.Neg(n), bigOne) +} + +func encodeTwosComplement(n *big.Int) []byte { + if n.Sign() > 0 { + bytes := n.Bytes() + if bytes[0]&0x80 == 0 { + return bytes + } + // add one more byte for positive sign + buf := make([]byte, len(bytes)+1) + copy(buf[1:], bytes) + return buf + } + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement form. So we + // invert and subtract 1. If the most-significant-bit isn't set then + // we'll need to pad the beginning with 0xff in order to keep the number + // negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + if len(bytes) == 0 { + // sneaky -1 value + return []byte{0xff} + } + for i := range bytes { + bytes[i] ^= 0xff + } + if bytes[0]&0x80 != 0 { + return bytes + } + // add one more byte for negative sign + buf := make([]byte, len(bytes)+1) + buf[0] = 0xff + copy(buf[1:], bytes) + return buf + } + return []byte{} +} + +func signBitFill(bytes []byte, targetLen int) []byte { + if len(bytes) >= targetLen { + return bytes + } + buf := make([]byte, targetLen) + offset := targetLen - len(bytes) + if bytes[0]&0x80 != 0 { + for i := 0; i < offset; i++ { + buf[i] = 0xff + } + } + copy(buf[offset:], bytes) + return buf +} + +func EncodeBigIntBigEndian(a *big.Int) []byte { + int_size_bits := a.BitLen() + int_size := (int_size_bits + 16) >> 3 + + return signBitFill(encodeTwosComplement(a), int_size) +} diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/gcd.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/gcd.go new file mode 100644 index 000000000000..c2207bfcd455 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/gcd.go @@ -0,0 +1,100 @@ +package vdf_go + +import ( + "math/big" +) + +//Return r, s, t such that gcd(a, b) = r = a * s + b * t +func extendedGCD(a, b *big.Int) (r, s, t *big.Int) { + //r0, r1 = a, b + r0 := new(big.Int).Set(a) + r1 := new(big.Int).Set(b) + + //s0, s1, t0, t1 = 1, 0, 0, 1 + s0 := big.NewInt(1) + s1 := big.NewInt(0) + t0 := big.NewInt(0) + t1 := big.NewInt(1) + + //if r0 > r1: + //r0, r1, s0, s1, t0, t1 = r1, r0, t0, t1, s0, s1 + if r0.Cmp(r1) == 1 { + oldR0 := new(big.Int).Set(r0) + r0 = r1 + r1 = oldR0 + oldS0 := new(big.Int).Set(s0) + s0 = t0 + oldS1 := new(big.Int).Set(s1) + s1 = t1 + t0 = oldS0 + t1 = oldS1 + } + + //while r1 > 0: + for r1.Sign() == 1 { + //q, r = divmod(r0, r1) + r := big.NewInt(1) + bb := new(big.Int).Set(b) + q, r := bb.DivMod(r0, r1, r) + + //r0, r1, s0, s1, t0, t1 = r1, r, s1, s0 - q * s1, t1, t0 - q * t1 + r0 = r1 + r1 = r + oldS0 := new(big.Int).Set(s0) + s0 = s1 + s1 = new(big.Int).Sub(oldS0, new(big.Int).Mul(q, s1)) + oldT0 := new(big.Int).Set(t0) + t0 = t1 + t1 = new(big.Int).Sub(oldT0, new(big.Int).Mul(q, t1)) + + } + return r0, s0, t0 +} + +//wrapper around big.Int GCD to allow all input values for GCD +//as Golang big.Int GCD requires both a, b > 0 +//If a == b == 0, GCD sets r = 0. +//If a == 0 and b != 0, GCD sets r = |b| +//If a != 0 and b == 0, GCD sets r = |a| +//Otherwise r = GCD(|a|, |b|) +func allInputValueGCD(a, b *big.Int) (r *big.Int) { + if a.Sign() == 0 { + return new(big.Int).Abs(b) + } + + if b.Sign() == 0 { + return new(big.Int).Abs(a) + } + + return new(big.Int).GCD(nil, nil, new(big.Int).Abs(a), new(big.Int).Abs(b)) +} + +//Solve ax == b mod m for x. +//Return s, t where x = s + k * t for integer k yields all solutions. +func SolveMod(a, b, m *big.Int) (s, t *big.Int, solvable bool) { + //g, d, e = extended_gcd(a, m) + //TODO: golang 1.x big.int GCD requires both a > 0 and m > 0, so we can't use it :( + //d := big.NewInt(0) + //e := big.NewInt(0) + //g := new(big.Int).GCD(d, e, a, m) + g, d, _ := extendedGCD(a, m) + + //q, r = divmod(b, g) + r := big.NewInt(1) + bb := new(big.Int).Set(b) + q, r := bb.DivMod(b, g, r) + + //TODO: replace with utils.GetLogInstance().Error(...) + //if r != 0: + if r.Cmp(big.NewInt(0)) != 0 { + //panic(fmt.Sprintf("no solution to %s x = %s mod %s", a.String(), b.String(), m.String())) + return nil, nil, false + } + + //assert b == q * g + //return (q * d) % m, m // g + q.Mul(q, d) + s = q.Mod(q, m) + t = floorDivision(m, g) + return s, t, true +} diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/prime.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/prime.go new file mode 100644 index 000000000000..727718355600 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/prime.go @@ -0,0 +1,64 @@ +package vdf_go + +import ( + "log" + "math" + "math/big" +) + +func primeLessThanN(num int) []int { + //initialized to false + sieve := make([]bool, num+1) + + for i := 3; i <= int(math.Floor(math.Sqrt(float64(num)))); i += 2 { + if sieve[i] == false { + for j := i * 2; j <= num; j += i { + sieve[j] = true // cross + } + } + } + + primes := make([]int, 0, num) + for i := 3; i <= num; i += 2 { + if sieve[i] == false { + primes = append(primes, i) + } + } + + return primes +} + +//testing +func checkArrayEqual(a []int, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +func testIntLessThan(num int) { + var refPrimes = make([]int, 0, num) + for i := 3; i < num; i += 2 { + if big.NewInt(int64(i)).ProbablyPrime(1) { + refPrimes = append(refPrimes, i) + } + } + + var primes = primeLessThanN(num) + log.Printf("%v ", primes) + + if checkArrayEqual(refPrimes, primes) { + log.Printf("OK") + } else { + log.Printf("ERROR") + } +} + +func main() { + testIntLessThan(1 << 16) +} diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/proof_wesolowski.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/proof_wesolowski.go new file mode 100644 index 000000000000..2620cd890602 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/proof_wesolowski.go @@ -0,0 +1,304 @@ +package vdf_go + +import ( + "crypto/sha256" + "encoding/binary" + "fmt" + "log" + "math" + "math/big" + "regexp" + "runtime" + "sort" + "time" +) + +//Creates L and k parameters from papers, based on how many iterations need to be +//performed, and how much memory should be used. +func approximateParameters(T int) (int, int, int) { + //log_memory = math.log(10000000, 2) + log_memory := math.Log(10000000) / math.Log(2) + log_T := math.Log(float64(T)) / math.Log(2) + L := 1 + + if log_T-log_memory > 0 { + L = int(math.Ceil(math.Pow(2, log_memory-20))) + } + + // Total time for proof: T/k + L * 2^(k+1) + // To optimize, set left equal to right, and solve for k + // k = W(T * log(2) / (2 * L)) / log(2), where W is the product log function + // W can be approximated by log(x) - log(log(x)) + 0.25 + intermediate := float64(T) * math.Log(2) / float64(2*L) + k := int(math.Max(math.Round(math.Log(intermediate)-math.Log(math.Log(intermediate))+0.25), 1)) + + // 1/w is the approximate proportion of time spent on the proof + w := int(math.Floor(float64(T)/(float64(T)/float64(k)+float64(L)*math.Pow(2, float64(k+1)))) - 2) + + return L, k, w +} + +func iterateSquarings(x *ClassGroup, powers_to_calculate []int, stop <-chan struct{}) map[int]*ClassGroup { + powers_calculated := make(map[int]*ClassGroup) + + previous_power := 0 + currX := CloneClassGroup(x) + sort.Ints(powers_to_calculate) + for _, current_power := range powers_to_calculate { + + for i := 0; i < current_power-previous_power; i++ { + currX = currX.Pow(2) + if currX == nil { + return nil + } + } + + previous_power = current_power + powers_calculated[current_power] = currX + + select { + case <-stop: + return nil + default: + } + } + + return powers_calculated +} + +func GenerateVDF(seed []byte, iterations, int_size_bits int) ([]byte, []byte) { + return GenerateVDFWithStopChan(seed, iterations, int_size_bits, nil) +} + +func GenerateVDFWithStopChan(seed []byte, iterations, int_size_bits int, stop <-chan struct{}) ([]byte, []byte) { + defer timeTrack(time.Now()) + + D := CreateDiscriminant(seed, int_size_bits) + x := NewClassGroupFromAbDiscriminant(big.NewInt(2), big.NewInt(1), D) + + y, proof := calculateVDF(D, x, iterations, int_size_bits, stop) + + if (y == nil) || (proof == nil) { + return nil, nil + } else { + return y.Serialize(), proof.Serialize() + } +} + +func VerifyVDF(seed, proof_blob []byte, iterations, int_size_bits int) bool { + defer timeTrack(time.Now()) + + int_size := (int_size_bits + 16) >> 4 + + D := CreateDiscriminant(seed, int_size_bits) + x := NewClassGroupFromAbDiscriminant(big.NewInt(2), big.NewInt(1), D) + y, _ := NewClassGroupFromBytesDiscriminant(proof_blob[:(2*int_size)], D) + proof, _ := NewClassGroupFromBytesDiscriminant(proof_blob[2*int_size:], D) + + return verifyProof(x, y, proof, iterations) +} + +// Creates a random prime based on input x, y +func hashPrime(x, y []byte) *big.Int { + var j uint64 = 0 + + jBuf := make([]byte, 8) + z := new(big.Int) + for { + binary.BigEndian.PutUint64(jBuf, j) + s := append([]byte("prime"), jBuf...) + s = append(s, x...) + s = append(s, y...) + + checkSum := sha256.Sum256(s[:]) + z.SetBytes(checkSum[:16]) + + if z.ProbablyPrime(1) { + return z + } + j++ + + } +} + +// Get's the ith block of 2^T // B +// such that sum(get_block(i) * 2^ki) = t^T // B +func getBlock(i, k, T int, B *big.Int) *big.Int { + //(pow(2, k) * pow(2, T - k * (i + 1), B)) // B + p1 := big.NewInt(int64(math.Pow(2, float64(k)))) + p2 := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(T-k*(i+1))), B) + return floorDivision(new(big.Int).Mul(p1, p2), B) +} + +//Optimized evalutation of h ^ (2^T // B) +func evalOptimized(identity, h *ClassGroup, B *big.Int, T, k, l int, C map[int]*ClassGroup) *ClassGroup { + //k1 = k//2 + var k1 int = k / 2 + k0 := k - k1 + + //x = identity + x := CloneClassGroup(identity) + + for j := l - 1; j > -1; j-- { + //x = pow(x, pow(2, k)) + b_limit := int64(math.Pow(2, float64(k))) + x = x.Pow(b_limit) + if x == nil { + return nil + } + + //ys = {} + ys := make([]*ClassGroup, b_limit) + for b := int64(0); b < b_limit; b++ { + ys[b] = identity + } + + //for i in range(0, math.ceil((T)/(k*l))): + for i := 0; i < int(math.Ceil(float64(T)/float64(k*l))); i++ { + if T-k*(i*l+j+1) < 0 { + continue + } + + ///TODO: carefully check big.Int to int64 value conversion...might cause serious issues later + b := getBlock(i*l+j, k, T, B).Int64() + ys[b] = ys[b].Multiply(C[i*k*l]) + if ys[b] == nil { + return nil + } + } + + //for b1 in range(0, pow(2, k1)): + for b1 := 0; b1 < int(math.Pow(float64(2), float64(k1))); b1++ { + z := identity + //for b0 in range(0, pow(2, k0)): + for b0 := 0; b0 < int(math.Pow(float64(2), float64((k0)))); b0++ { + //z *= ys[b1 * pow(2, k0) + b0] + z = z.Multiply(ys[int64(b1)*int64(math.Pow(float64(2), float64(k0)))+int64(b0)]) + if z == nil { + return nil + } + } + + //x *= pow(z, b1 * pow(2, k0)) + c := z.Pow(int64(b1) * int64(math.Pow(float64(2), float64(k0)))) + if c == nil { + return nil + } + x = x.Multiply(c) + if x == nil { + return nil + } + } + + //for b0 in range(0, pow(2, k0)): + for b0 := 0; b0 < int(math.Pow(float64(2), float64(k0))); b0++ { + z := identity + //for b1 in range(0, pow(2, k1)): + for b1 := 0; b1 < int(math.Pow(float64(2), float64(k1))); b1++ { + //z *= ys[b1 * pow(2, k0) + b0] + z = z.Multiply(ys[int64(b1)*int64(math.Pow(float64(2), float64(k0)))+int64(b0)]) + if z == nil { + return nil + } + } + //x *= pow(z, b0) + d := z.Pow(int64(b0)) + if d == nil { + return nil + } + x = x.Multiply(d) + if x == nil { + return nil + } + } + } + + return x +} + +//generate y = x ^ (2 ^T) and pi +func generateProof(identity, x, y *ClassGroup, T, k, l int, powers map[int]*ClassGroup) *ClassGroup { + //x_s = x.serialize() + x_s := x.Serialize() + + //y_s = y.serialize() + y_s := y.Serialize() + + B := hashPrime(x_s, y_s) + + proof := evalOptimized(identity, x, B, T, k, l, powers) + + return proof +} + +func calculateVDF(discriminant *big.Int, x *ClassGroup, iterations, int_size_bits int, stop <-chan struct{}) (y, proof *ClassGroup) { + L, k, _ := approximateParameters(iterations) + + loopCount := int(math.Ceil(float64(iterations) / float64(k*L))) + powers_to_calculate := make([]int, loopCount+2) + + for i := 0; i < loopCount+1; i++ { + powers_to_calculate[i] = i * k * L + } + + powers_to_calculate[loopCount+1] = iterations + + powers := iterateSquarings(x, powers_to_calculate, stop) + + if powers == nil { + return nil, nil + } + + y = powers[iterations] + + identity := IdentityForDiscriminant(discriminant) + + proof = generateProof(identity, x, y, iterations, k, L, powers) + + return y, proof +} + +func verifyProof(x, y, proof *ClassGroup, T int) bool { + //x_s = x.serialize() + x_s := x.Serialize() + + //y_s = y.serialize() + y_s := y.Serialize() + + B := hashPrime(x_s, y_s) + + r := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(T)), B) + + piB := proof.BigPow(B) + if piB == nil { + return false + } + + xR := x.BigPow(r) + if xR == nil { + return false + } + + z := piB.Multiply(xR) + if (z != nil) && (z.Equal(y)) { + return true + } else { + return false + } +} + +func timeTrack(start time.Time) { + elapsed := time.Since(start) + + // Skip this function, and fetch the PC and file for its parent. + pc, _, _, _ := runtime.Caller(1) + + // Retrieve a function object this functions parent. + funcObj := runtime.FuncForPC(pc) + + // Regex to extract just the function name (and not the module path). + runtimeFunc := regexp.MustCompile(`^.*\.(.*)$`) + name := runtimeFunc.ReplaceAllString(funcObj.Name(), "$1") + + log.Println(fmt.Sprintf("%s took %s", name, elapsed)) +} diff --git a/vendor/github.com/harmony-one/vdf/src/vdf_go/vdf.go b/vendor/github.com/harmony-one/vdf/src/vdf_go/vdf.go new file mode 100644 index 000000000000..9e646f313c91 --- /dev/null +++ b/vendor/github.com/harmony-one/vdf/src/vdf_go/vdf.go @@ -0,0 +1,61 @@ +package vdf_go + +// VDF is the struct holding necessary state for a hash chain delay function. +type VDF struct { + difficulty int + input [32]byte + output [516]byte + outputChan chan [516]byte + finished bool +} + +//size of long integers in quadratic function group +const sizeInBits = 2048 + +// New create a new instance of VDF. +func New(difficulty int, input [32]byte) *VDF { + return &VDF{ + difficulty: difficulty, + input: input, + outputChan: make(chan [516]byte), + } +} + +// GetOutputChannel returns the vdf output channel. +// VDF output consists of 258 bytes of serialized Y and 258 bytes of serialized Proof +func (vdf *VDF) GetOutputChannel() chan [516]byte { + return vdf.outputChan +} + +// Execute runs the VDF until it's finished and put the result into output channel. +// currently on i7-6700K, it takes about 14 seconds when iteration is set to 10000 +func (vdf *VDF) Execute() { + vdf.finished = false + + yBuf, proofBuf := GenerateVDF(vdf.input[:], vdf.difficulty, sizeInBits) + + copy(vdf.output[:], yBuf) + copy(vdf.output[258:], proofBuf) + + go func() { + vdf.outputChan <- vdf.output + }() + + vdf.finished = true +} + +// Verify runs the verification of generated proof +// currently on i7-6700K, verification takes about 350 ms +func (vdf *VDF) Verify(proof [516]byte) bool { + return VerifyVDF(vdf.input[:], proof[:], vdf.difficulty, sizeInBits) +} + +// IsFinished returns whether the vdf execution is finished or not. +func (vdf *VDF) IsFinished() bool { + return vdf.finished +} + +// GetOutput returns the vdf output, which can be bytes of 0s is the vdf is not finished. +func (vdf *VDF) GetOutput() [516]byte { + return vdf.output +}