From 1c49a26783bad8977fdb059ee3a67368872463f8 Mon Sep 17 00:00:00 2001 From: lukepark327 Date: Fri, 6 Jan 2023 10:09:14 +0900 Subject: [PATCH 1/8] feat: vrf && chore: documents for vrf && test: for vrf --- accounts/accounts.go | 12 + accounts/external/backend.go | 16 ++ accounts/keystore/keystore.go | 83 +++++++ accounts/keystore/wallet.go | 36 +++ accounts/scwallet/wallet.go | 16 ++ accounts/usbwallet/ledger.go | 16 ++ accounts/usbwallet/trezor.go | 16 ++ accounts/usbwallet/wallet.go | 24 ++ common/types.go | 2 + contracts/vrf/contract/vrf.sol | 44 ++++ core/vm/contracts.go | 37 +++ core/vm/contracts_test.go | 5 + core/vm/testdata/precompiles/vrf.json | 30 +++ crypto/vrf/vrf.go | 337 ++++++++++++++++++++++++++ crypto/vrf/vrf_test.go | 290 ++++++++++++++++++++++ docs/vrf.md | 69 ++++++ go.mod | 1 + go.sum | 29 +++ internal/ethapi/api.go | 52 ++++ internal/web3ext/web3ext.go | 17 +- mobile/accounts.go | 16 ++ params/protocol_params.go | 2 + signer/core/api.go | 16 ++ 23 files changed, 1165 insertions(+), 1 deletion(-) create mode 100644 contracts/vrf/contract/vrf.sol create mode 100644 core/vm/testdata/precompiles/vrf.json create mode 100644 crypto/vrf/vrf.go create mode 100644 crypto/vrf/vrf_test.go create mode 100644 docs/vrf.md diff --git a/accounts/accounts.go b/accounts/accounts.go index 6c351a9649ea..e7cf714e5999 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -151,6 +151,18 @@ type Wallet interface { // SignTxWithPassphrase is identical to SignTx, but also takes a password SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) + + // Get pk from sk based on ed25519 + EdPubKey(account Account) ([]byte, error) + + // Get pk from sk based on ed25519 with account password + EdPubKeyWithPassphrase(account Account, passphrase string) ([]byte, error) + + // Get prove + Prove(account Account, message []byte) ([]byte, error) + + // Get prove with account password + ProveWithPassphrase(account Account, passphrase string, message []byte) ([]byte, error) } // Backend is a "wallet provider" that may contain a batch of accounts they can diff --git a/accounts/external/backend.go b/accounts/external/backend.go index e3f754eafcc4..d806484250b3 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -256,6 +256,22 @@ func (api *ExternalSigner) SignDataWithPassphrase(account accounts.Account, pass return nil, fmt.Errorf("password-operations not supported on external signers") } +func (api *ExternalSigner) EdPubKey(account accounts.Account) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on external signers yet") // TODO (lukepark327) +} + +func (api *ExternalSigner) EdPubKeyWithPassphrase(account accounts.Account, passphrase string) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on external signers yet") // TODO (lukepark327) +} + +func (api *ExternalSigner) Prove(account accounts.Account, message []byte) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on external signers yet") // TODO (lukepark327) +} + +func (api *ExternalSigner) ProveWithPassphrase(account accounts.Account, passphrase string, message []byte) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on external signers yet") // TODO (lukepark327) +} + func (api *ExternalSigner) listAccounts() ([]common.Address, error) { var res []common.Address if err := api.client.Call(&res, "account_list"); err != nil { diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 88dcfbeb69e0..43f5981a6b2c 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -22,6 +22,7 @@ package keystore import ( "crypto/ecdsa" + "crypto/ed25519" crand "crypto/rand" "errors" "math/big" @@ -36,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/vrf" "github.com/ethereum/go-ethereum/event" ) @@ -43,6 +45,7 @@ var ( ErrLocked = accounts.NewAuthNeededError("password or unlock") ErrNoMatch = errors.New("no key for given address or file") ErrDecrypt = errors.New("could not decrypt key with given password") + ErrVrf = errors.New("errors on VRF functions") // TODO (lukepark327): more details // ErrAccountAlreadyExists is returned if an account attempted to import is // already present in the keystore. @@ -505,3 +508,83 @@ func zeroKey(k *ecdsa.PrivateKey) { b[i] = 0 } } + +func (ks *KeyStore) EdPubKey(a accounts.Account) ([]byte, error) { + // Look up the key to sign with and abort if it cannot be found + ks.mu.RLock() + defer ks.mu.RUnlock() + + unlockedKey, found := ks.unlocked[a.Address] + if !found { + return nil, ErrLocked + } + + return edPubKeyFromPrivateKey(unlockedKey.PrivateKey) +} + +func (ks *KeyStore) EdPubKeyWithPassphrase(a accounts.Account, passphrase string) ([]byte, error) { + _, key, err := ks.getDecryptedKey(a, passphrase) + if err != nil { + return nil, err + } + defer zeroKey(key.PrivateKey) + + return edPubKeyFromPrivateKey(key.PrivateKey) +} + +func edPubKeyFromPrivateKey(k *ecdsa.PrivateKey) ([]byte, error) { + // get private key + seed := k.D.Bytes() + sk := ed25519.NewKeyFromSeed(seed) + pk := sk.Public() + + xx, ok := pk.(ed25519.PublicKey) + if !ok { + return nil, ErrVrf + } + return xx, nil +} + +func (ks *KeyStore) Prove(a accounts.Account, m []byte) ([]byte, error) { + // Look up the key to sign with and abort if it cannot be found + ks.mu.RLock() + defer ks.mu.RUnlock() + + unlockedKey, found := ks.unlocked[a.Address] + if !found { + return nil, ErrLocked + } + + pi, _, err := prove(unlockedKey.PrivateKey, m) + if err != nil { + return nil, err + } + return pi, err +} + +func (ks *KeyStore) ProveWithPassphrase(a accounts.Account, passphrase string, m []byte) ([]byte, error) { + _, key, err := ks.getDecryptedKey(a, passphrase) + if err != nil { + return nil, err + } + defer zeroKey(key.PrivateKey) + + pi, _, err := prove(key.PrivateKey, m) + if err != nil { + return nil, err + } + return pi, err +} + +func prove(k *ecdsa.PrivateKey, msg []byte) ([]byte, []byte, error) { + // get private key + seed := k.D.Bytes() + sk := ed25519.NewKeyFromSeed(seed) + pk := sk.Public() + + xx, ok := pk.(ed25519.PublicKey) + if !ok { + return nil, nil, ErrVrf + } + return vrf.Prove(xx, sk, msg[:]) +} diff --git a/accounts/keystore/wallet.go b/accounts/keystore/wallet.go index 1066095f6d07..b31348ed7b8a 100644 --- a/accounts/keystore/wallet.go +++ b/accounts/keystore/wallet.go @@ -148,3 +148,39 @@ func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphra // Account seems valid, request the keystore to sign return w.keystore.SignTxWithPassphrase(account, passphrase, tx, chainID) } + +func (w *keystoreWallet) EdPubKey(account accounts.Account) ([]byte, error) { + // Make sure the requested account is contained within + if !w.Contains(account) { + return nil, accounts.ErrUnknownAccount + } + // Account seems valid, request the keystore to get EdPubKey + return w.keystore.EdPubKey(account) +} + +func (w *keystoreWallet) EdPubKeyWithPassphrase(account accounts.Account, passphrase string) ([]byte, error) { + // Make sure the requested account is contained within + if !w.Contains(account) { + return nil, accounts.ErrUnknownAccount + } + // Account seems valid, request the keystore to get EdPubKey + return w.keystore.EdPubKeyWithPassphrase(account, passphrase) +} + +func (w *keystoreWallet) Prove(account accounts.Account, message []byte) ([]byte, error) { + // Make sure the requested account is contained within + if !w.Contains(account) { + return nil, accounts.ErrUnknownAccount + } + // Account seems valid, request the keystore to prove + return w.keystore.Prove(account, message) +} + +func (w *keystoreWallet) ProveWithPassphrase(account accounts.Account, passphrase string, message []byte) ([]byte, error) { + // Make sure the requested account is contained within + if !w.Contains(account) { + return nil, accounts.ErrUnknownAccount + } + // Account seems valid, request the keystore to prove + return w.keystore.ProveWithPassphrase(account, passphrase, message) +} diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 5e74e606e13f..e003f4e08566 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -788,6 +788,22 @@ func (w *Wallet) findAccountPath(account accounts.Account) (accounts.DerivationP return accounts.ParseDerivationPath(parts[1]) } +func (w *Wallet) EdPubKey(account accounts.Account) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *Wallet) EdPubKeyWithPassphrase(account accounts.Account, passphrase string) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *Wallet) Prove(account accounts.Account, message []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *Wallet) ProveWithPassphrase(account accounts.Account, passphrase string, message []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + // Session represents a secured communication session with the wallet. type Session struct { Wallet *Wallet // A handle to the wallet that opened the session diff --git a/accounts/usbwallet/ledger.go b/accounts/usbwallet/ledger.go index cda94280fdd2..c8eb915800d5 100644 --- a/accounts/usbwallet/ledger.go +++ b/accounts/usbwallet/ledger.go @@ -190,6 +190,22 @@ func (w *ledgerDriver) SignTypedMessage(path accounts.DerivationPath, domainHash return w.ledgerSignTypedMessage(path, domainHash, messageHash) } +func (w *ledgerDriver) EdPubKey(a accounts.Account) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *ledgerDriver) EdPubKeyWithPassphrase(a accounts.Account, passphrase string) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *ledgerDriver) Prove(a accounts.Account, m []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *ledgerDriver) ProveWithPassphrase(a accounts.Account, passphrase string, m []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + // ledgerVersion retrieves the current version of the Ethereum wallet app running // on the Ledger wallet. // diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 190b97f90094..cf0a7cb15b97 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -189,6 +189,22 @@ func (w *trezorDriver) SignTypedMessage(path accounts.DerivationPath, domainHash return nil, accounts.ErrNotSupported } +func (w *trezorDriver) EdPubKey(a accounts.Account) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *trezorDriver) EdPubKeyWithPassphrase(a accounts.Account, passphrase string) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *trezorDriver) Prove(a accounts.Account, m []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *trezorDriver) ProveWithPassphrase(a accounts.Account, passphrase string, m []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + // trezorDerive sends a derivation request to the Trezor device and returns the // Ethereum address located on that path. func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, error) { diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 382f3ddaee21..3351f13db0fc 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -69,6 +69,14 @@ type driver interface { SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) SignTypedMessage(path accounts.DerivationPath, messageHash []byte, domainHash []byte) ([]byte, error) + + EdPubKey(account accounts.Account) ([]byte, error) + + EdPubKeyWithPassphrase(account accounts.Account, passphrase string) ([]byte, error) + + Prove(account accounts.Account, message []byte) ([]byte, error) + + ProveWithPassphrase(account accounts.Account, passphrase string, message []byte) ([]byte, error) } // wallet represents the common functionality shared by all USB hardware @@ -638,3 +646,19 @@ func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase str func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { return w.SignTx(account, tx, chainID) } + +func (w *wallet) EdPubKey(account accounts.Account) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *wallet) EdPubKeyWithPassphrase(account accounts.Account, passphrase string) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *wallet) Prove(account accounts.Account, message []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (w *wallet) ProveWithPassphrase(account accounts.Account, passphrase string, message []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} diff --git a/common/types.go b/common/types.go index 2205835cb5d0..4768a559e0dd 100644 --- a/common/types.go +++ b/common/types.go @@ -38,6 +38,8 @@ const ( HashLength = 32 // AddressLength is the expected length of the address AddressLength = 20 + + EdPubKeyLength = 32 ) var ( diff --git a/contracts/vrf/contract/vrf.sol b/contracts/vrf/contract/vrf.sol new file mode 100644 index 000000000000..0423f0d7392f --- /dev/null +++ b/contracts/vrf/contract/vrf.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.17; + +/** + * @author @lukepark327 + * @title VRF + */ +abstract contract VRF { + function _callVrfVerify( + bytes32 publicKey, + bytes memory pi, + bytes memory message + ) internal view returns (bool result) { + return _vrf(abi.encodePacked(publicKey, pi, message)); + } + + function _callVrfVerifyRaw( + bytes memory input + ) internal view returns (bool result) { + return _vrf(input); + } + + function _vrf(bytes memory input) internal view returns (bool result) { + assembly { + let memPtr := mload(0x40) + let success := staticcall( + gas(), + 0x14, + add(input, 0x20), + mload(input), + memPtr, + 0x20 + ) + switch success + case 0 { + revert(0, 0) + } + default { + result := mload(memPtr) + } + } + } +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index e34817aabfe9..1cf0e61af6ef 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/blake2b" "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" + "github.com/ethereum/go-ethereum/crypto/vrf" "github.com/ethereum/go-ethereum/params" //lint:ignore SA1019 Needed for precompile @@ -104,6 +105,7 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{16}): &bls12381Pairing{}, common.BytesToAddress([]byte{17}): &bls12381MapG1{}, common.BytesToAddress([]byte{18}): &bls12381MapG2{}, + common.BytesToAddress([]byte{19}): &vrfVerify{}, // TODO (lukepark327): hardfork } var ( @@ -1044,3 +1046,38 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { // Encode the G2 point to 256 bytes return g.EncodePoint(r), nil } + +// vrf implemented as a native contract. +type vrfVerify struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *vrfVerify) RequiredGas(input []byte) uint64 { + return params.VrfVerifyGas +} + +func (c *vrfVerify) Run(input []byte) ([]byte, error) { + length := uint64(len(input)) + + var ( + pk = getData(input, 0, 32) + pi = getData(input, 32, 81) + msg = getData(input, 113, length-113) + ) + + // fmt.Println(hex.EncodeToString(pk)) + // fmt.Println(hex.EncodeToString(pi)) + // fmt.Println(hex.EncodeToString(msg)) + + res, err := vrf.Verify(pk, pi, msg) + if err != nil { + return nil, err + } + + // fmt.Println(hex.EncodeToString(bytesTrue)) + // fmt.Println(hex.EncodeToString(bytesFalse)) + + if res { + return true32Byte, nil + } + return false32Byte, nil +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index aa8d2f1eb38b..22ec04035444 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -65,6 +65,7 @@ var allPrecompiles = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{16}): &bls12381Pairing{}, common.BytesToAddress([]byte{17}): &bls12381MapG1{}, common.BytesToAddress([]byte{18}): &bls12381MapG2{}, + common.BytesToAddress([]byte{19}): &vrfVerify{}, } // EIP-152 test vectors @@ -391,3 +392,7 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) { } benchmarkPrecompiled("0f", testcase, b) } + +func TestPrecompiledVRF(t *testing.T) { testJson("vrf", "13", t) } + +func BenchmarkPrecompiledVRF(b *testing.B) { benchJson("vrf", "13", b) } diff --git a/core/vm/testdata/precompiles/vrf.json b/core/vm/testdata/precompiles/vrf.json new file mode 100644 index 000000000000..f8de45678073 --- /dev/null +++ b/core/vm/testdata/precompiles/vrf.json @@ -0,0 +1,30 @@ +[ + { + "Input": "ca3b325e7ea0942ecb7658dce007374b53e0096d1c0d3d7d114264eac8d355e6026251907f16127c3db7d765de0d0b1bca44b737bdbcdbb57c4728e90aba425c6e0bd5e3c0f9969b55f580c7f46ff0a15707a618829ff44ee099ae346f991e1b5df4819a6666f136956c14699c9789cf7c48656c6c6f2c20576f726c6421", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "vrf-1", + "Gas": 3000, + "NoBenchmark": false + }, + { + "Input": "ffc0b13383ffb12e08bee1e4fce1d7782a334870f6fafea7437e23a4e525f2a8036bf3524542b262497da4d3c4d08b6a9e0a6d3094d5abbf3f11d38014c941a6c02c5063f8b7b111dabf70669400c12dce0f64ad90edfb6981b5b275a280aec804be61cdc55b5087a6625153408846504f48692074686572652e204d79206e616d652069732053616e676879656f6e205061726b2e205768617420697320796f7572206e616d653f", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "vrf-2", + "Gas": 3000, + "NoBenchmark": false + }, + { + "Input": "a6b4b002288784e52bb72d1b9247ad37b11a9cce9c152c24578c7da6f3c133e202ea8ec59e030acdb3bef69e048c3cfca0297c3ad45e4a99ec4136be9cd9644844e742bc0ec4e2a3b1b14077f742ae988105d125f55f55110079e954d946405b43f2ad8166da8d5c979344a7aad9b792535768617420697320746865206d65616e696e67206f66207468697320616262726576696174696f6e2c2022564d4f223f", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "vrf-3", + "Gas": 3000, + "NoBenchmark": false + }, + { + "Input": "16357cf6de199737298f93b9fc2ae3f508baa666f0d545e3af629ff73ae528e60288345a9bdf6b43162ae639c27be4e8332b8d497657574514306ba462c2f2fc20e74c269a94adeb3358c106342f2120570910c9aa58ad7e19e9e141d5c8b1783a73d142e5856d82d9ea43a9c7c92e2018486f772069732074686520776865617468657220746f64617920696e2053656f756c3f", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "vrf-4", + "Gas": 3000, + "NoBenchmark": false + } +] \ No newline at end of file diff --git a/crypto/vrf/vrf.go b/crypto/vrf/vrf.go new file mode 100644 index 000000000000..4cd917cacb76 --- /dev/null +++ b/crypto/vrf/vrf.go @@ -0,0 +1,337 @@ +/** + * @license + * Copyright 2017 Yahoo Inc. All rights reserved. + * Modifications Copyright 2020 Yosep Lee. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package vrf + +import ( + "bytes" + "crypto/ed25519" + "crypto/sha256" + "crypto/sha512" + "errors" + "math/big" + + "github.com/yoseplee/vrf/edwards25519" +) + +const ( + limit = 100 + N2 = 32 // ceil(log2(q) / 8) + N = N2 / 2 + qs = "1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed" // 2^252 + 27742317777372353535851937790883648493 + cofactor = 8 + NOSIGN = 3 +) + +var ( + ErrMalformedInput = errors.New("ECVRF: malformed input") + ErrDecodeError = errors.New("ECVRF: decode error") + ErrInternalError = errors.New("ECVRF: internal error") + q, _ = new(big.Int).SetString(qs, 16) + g = ge() +) + +const ( + // PublicKeySize is the size, in bytes, of public keys as used in this package. + PublicKeySize = 32 + // PrivateKeySize is the size, in bytes, of private keys as used in this package. + PrivateKeySize = 64 + // SignatureSize is the size, in bytes, of signatures generated and verified by this package. + SignatureSize = 64 +) + +// assume were generated by ed25519.GenerateKey() +// Prove generates vrf output and corresponding proof(pi) with secret key +func Prove(pk []byte, sk []byte, m []byte) (pi, hash []byte, err error) { + x := expandSecret(sk) + h := hashToCurve(m, pk) + r := ecp2OS(geScalarMult(h, x)) + + kp, ks, err := ed25519.GenerateKey(nil) // use GenerateKey to generate a random + if err != nil { + return nil, nil, err + } + k := expandSecret(ks) + + // hashPoints(g, h, g^x, h^x, g^k, h^k) + c := hashPoints(ecp2OS(g), ecp2OS(h), s2OS(pk), r, s2OS(kp), ecp2OS(geScalarMult(h, k))) + + // s = k - c*x mod q + var z big.Int + s := z.Mod(z.Sub(f2IP(k), z.Mul(c, f2IP(x))), q) + + // pi = gamma || i2OSP(c, N) || i2OSP(s, 2N) + var buf bytes.Buffer + buf.Write(r) // 2N + buf.Write(i2OSP(c, N)) + buf.Write(i2OSP(s, N2)) + pi = buf.Bytes() + return pi, Hash(pi), nil +} + +// Hash converts proof(pi) into vrf output(hash) without verifying it +func Hash(pi []byte) []byte { + return pi[1 : N2+1] +} + +// Verify checks if the proof is correct or not +func Verify(pk []byte, pi []byte, m []byte) (bool, error) { + r, c, s, err := decodeProof(pi) + if err != nil { + return false, err + } + + // u = (g^x)^c * g^s = P^c * g^s + var u edwards25519.ProjectiveGroupElement + P := os2ECP(pk, pk[31]>>7) + if P == nil { + return false, ErrMalformedInput + } + edwards25519.GeDoubleScalarMultVartime(&u, c, P, s) + + h := hashToCurve(m, pk) + + // v = gamma^c * h^s + // fmt.Printf("c, r, s, h\n%s%s%s%s\n", hex.Dump(c[:]), hex.Dump(ecp2OS(r)), hex.Dump(s[:]), hex.Dump(ecp2OS(h))) + v := geAdd(geScalarMult(r, c), geScalarMult(h, s)) + + // c' = hashPoints(g, h, g^x, gamma, u, v) + c2 := hashPoints(ecp2OS(g), ecp2OS(h), s2OS(pk), ecp2OS(r), ecp2OSProj(&u), ecp2OS(v)) + + return c2.Cmp(f2IP(c)) == 0, nil +} + +func decodeProof(pi []byte) (r *edwards25519.ExtendedGroupElement, c *[N2]byte, s *[N2]byte, err error) { + i := 0 + sign := pi[i] + i++ + if sign != 2 && sign != 3 { + return nil, nil, nil, ErrDecodeError + } + r = os2ECP(pi[i:i+N2], sign-2) + i += N2 + if r == nil { + return nil, nil, nil, ErrDecodeError + } + + // swap and expand to make it a field + c = new([N2]byte) + for j := N - 1; j >= 0; j-- { + c[j] = pi[i] + i++ + } + + // swap to make it a field + s = new([N2]byte) + for j := N2 - 1; j >= 0; j-- { + s[j] = pi[i] + i++ + } + return +} + +func hashPoints(ps ...[]byte) *big.Int { + h := sha256.New() + // fmt.Printf("hash_points:\n") + for _, p := range ps { + h.Write(p) + // fmt.Printf("%s\n", hex.Dump(p)) + } + v := h.Sum(nil) + return os2IP(v[:N]) +} + +func hashToCurve(m []byte, pk []byte) *edwards25519.ExtendedGroupElement { + hash := sha256.New() + for i := int64(0); i < limit; i++ { + ctr := i2OSP(big.NewInt(i), 4) + hash.Write(m) + hash.Write(pk) + hash.Write(ctr) + h := hash.Sum(nil) + hash.Reset() + if P := os2ECP(h, NOSIGN); P != nil { + // assume cofactor is 2^n + for j := 1; j < cofactor; j *= 2 { + P = geDouble(P) + } + return P + } + } + panic("hashToCurve: couldn't make a point on curve") +} + +func os2ECP(os []byte, sign byte) *edwards25519.ExtendedGroupElement { + P := new(edwards25519.ExtendedGroupElement) + var buf [32]byte + copy(buf[:], os) + if sign == 0 || sign == 1 { + buf[31] = (sign << 7) | (buf[31] & 0x7f) + } + if !P.FromBytes(&buf) { + return nil + } + return P +} + +// just prepend the sign octet +func s2OS(s []byte) []byte { + sign := s[31] >> 7 // @@ we should clear the sign bit?? + os := []byte{sign + 2} // Y = 0x02 if positive or 0x03 if negative + os = append([]byte(os), s...) + return os +} + +func ecp2OS(P *edwards25519.ExtendedGroupElement) []byte { + var s [32]byte + P.ToBytes(&s) + return s2OS(s[:]) +} + +func ecp2OSProj(P *edwards25519.ProjectiveGroupElement) []byte { + var s [32]byte + P.ToBytes(&s) + return s2OS(s[:]) +} + +func i2OSP(b *big.Int, n int) []byte { + os := b.Bytes() + if n > len(os) { + var buf bytes.Buffer + buf.Write(make([]byte, n-len(os))) // prepend 0s + buf.Write(os) + return buf.Bytes() + } else { + return os[:n] + } +} + +func os2IP(os []byte) *big.Int { + return new(big.Int).SetBytes(os) +} + +// convert a field number (in LittleEndian) to a big int +func f2IP(f *[32]byte) *big.Int { + var t [32]byte + for i := 0; i < 32; i++ { + t[32-i-1] = f[i] + } + return os2IP(t[:]) +} + +func ip2F(b *big.Int) *[32]byte { + os := b.Bytes() + r := new([32]byte) + j := len(os) - 1 + for i := 0; i < 32 && j >= 0; i++ { + r[i] = os[j] + j-- + } + return r +} + +func ge() *edwards25519.ExtendedGroupElement { + g := new(edwards25519.ExtendedGroupElement) + var f edwards25519.FieldElement + edwards25519.FeOne(&f) + var s [32]byte + edwards25519.FeToBytes(&s, &f) + edwards25519.GeScalarMultBase(g, &s) // g = g^1 + return g +} + +func expandSecret(sk []byte) *[32]byte { + // copied from golang.org/x/crypto/ed25519/ed25519.go -- has to be the same + digest := sha512.Sum512(sk[:32]) + digest[0] &= 248 + digest[31] &= 127 + digest[31] |= 64 + h := new([32]byte) + copy(h[:], digest[:]) + return h +} + +// copied from edwards25519.go and const.go in golang.org/x/crypto/ed25519/internal/edwards25519 +type CachedGroupElement struct { + yPlusX, yMinusX, Z, T2d edwards25519.FieldElement +} + +// d2 is 2*d. +var d2 = edwards25519.FieldElement{ + -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199, +} + +func toCached(r *CachedGroupElement, p *edwards25519.ExtendedGroupElement) { + edwards25519.FeAdd(&r.yPlusX, &p.Y, &p.X) + edwards25519.FeSub(&r.yMinusX, &p.Y, &p.X) + edwards25519.FeCopy(&r.Z, &p.Z) + edwards25519.FeMul(&r.T2d, &p.T, &d2) +} + +func geAdd(p, qe *edwards25519.ExtendedGroupElement) *edwards25519.ExtendedGroupElement { + var q CachedGroupElement + var r edwards25519.CompletedGroupElement + var t0 edwards25519.FieldElement + + toCached(&q, qe) + + edwards25519.FeAdd(&r.X, &p.Y, &p.X) + edwards25519.FeSub(&r.Y, &p.Y, &p.X) + edwards25519.FeMul(&r.Z, &r.X, &q.yPlusX) + edwards25519.FeMul(&r.Y, &r.Y, &q.yMinusX) + edwards25519.FeMul(&r.T, &q.T2d, &p.T) + edwards25519.FeMul(&r.X, &p.Z, &q.Z) + edwards25519.FeAdd(&t0, &r.X, &r.X) + edwards25519.FeSub(&r.X, &r.Z, &r.Y) + edwards25519.FeAdd(&r.Y, &r.Z, &r.Y) + edwards25519.FeAdd(&r.Z, &t0, &r.T) + edwards25519.FeSub(&r.T, &t0, &r.T) + + re := new(edwards25519.ExtendedGroupElement) + r.ToExtended(re) + return re +} + +func geDouble(p *edwards25519.ExtendedGroupElement) *edwards25519.ExtendedGroupElement { + var q edwards25519.ProjectiveGroupElement + p.ToProjective(&q) + var rc edwards25519.CompletedGroupElement + q.Double(&rc) + r := new(edwards25519.ExtendedGroupElement) + rc.ToExtended(r) + return r +} + +func extendedGroupElementCMove(t, u *edwards25519.ExtendedGroupElement, b int32) { + edwards25519.FeCMove(&t.X, &u.X, b) + edwards25519.FeCMove(&t.Y, &u.Y, b) + edwards25519.FeCMove(&t.Z, &u.Z, b) + edwards25519.FeCMove(&t.T, &u.T, b) +} + +func geScalarMult(h *edwards25519.ExtendedGroupElement, a *[32]byte) *edwards25519.ExtendedGroupElement { + q := new(edwards25519.ExtendedGroupElement) + q.Zero() + p := h + for i := uint(0); i < 256; i++ { + bit := int32(a[i>>3]>>(i&7)) & 1 + t := geAdd(q, p) + extendedGroupElementCMove(q, t, bit) + p = geDouble(p) + } + return q +} diff --git a/crypto/vrf/vrf_test.go b/crypto/vrf/vrf_test.go new file mode 100644 index 000000000000..a7b435b7d5ab --- /dev/null +++ b/crypto/vrf/vrf_test.go @@ -0,0 +1,290 @@ +/** + * @license + * Copyright 2017 Yahoo Inc. All rights reserved. + * Modifications Copyright 2020 Yosep Lee. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package vrf + +import ( + "bytes" + "crypto/ed25519" + "crypto/rand" + "encoding/hex" + "fmt" + "io" + "math/big" + "testing" + + ed2 "github.com/yahoo/coname/ed25519/edwards25519" + ed1 "github.com/yoseplee/vrf/edwards25519" +) + +const message = "message" + +func TestGeScalarMult(t *testing.T) { + var res1, res2 [32]byte + + pk, sk, err := ed25519.GenerateKey(nil) + if err != nil { + t.Fatal(err) + } + c := hashToCurve([]byte(message), pk) + x := expandSecret(sk) + h1 := geScalarMult(c, x) + h1.ToBytes(&res1) + // copy c to h2 + var h2, h3 ed2.ExtendedGroupElement + var ts [32]byte + c.ToBytes(&ts) + h2.FromBytes(&ts) + ed2.GeScalarMult(&h3, x, &h2) + h3.ToBytes(&res2) + + if !bytes.Equal(res1[:], res2[:]) { + t.Errorf("geScalarMult mismatch:\n%s\n%s\nx=\n%s\n", hex.Dump(res1[:]), hex.Dump(res2[:]), hex.Dump(x[:])) + } +} + +func TestGeAdd(t *testing.T) { + var p1, p2 ed2.ProjectiveGroupElement + var h1, h2, c2 ed2.ExtendedGroupElement + var res1, res2, tmp [32]byte + + io.ReadFull(rand.Reader, tmp[:]) + c1 := hashToCurve([]byte(message), tmp[:]) + + io.ReadFull(rand.Reader, tmp[:]) + a1 := expandSecret(tmp[:]) + io.ReadFull(rand.Reader, tmp[:]) + a2 := expandSecret(tmp[:]) + + c1.ToBytes(&tmp) + c2.FromBytes(&tmp) + ed2.GeDoubleScalarMultVartime(&p1, a1, &c2, &[32]byte{}) + ed2.GeDoubleScalarMultVartime(&p2, a2, &c2, &[32]byte{}) + p1.ToExtended(&h1) + p2.ToExtended(&h2) + ed2.GeAdd(&h1, &h1, &h2) + h1.ToBytes(&res1) + + h3 := geAdd(geScalarMult(c1, a1), geScalarMult(c1, a2)) + h3.ToBytes(&res2) + if !bytes.Equal(res1[:], res2[:]) { + t.Errorf("geAdd mismatch: %x, %x", a1[:], a2[:]) + } +} + +var extendedBaseEl = ed1.ExtendedGroupElement{ + ed1.FieldElement{25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708}, + ed1.FieldElement{-758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719}, + ed1.FieldElement{-947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649}, + ed1.FieldElement{6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166}, +} + +func TestG(t *testing.T) { + var res1, res2 [32]byte + g := ge() + g.ToBytes(&res1) + extendedBaseEl.ToBytes(&res2) + + if !bytes.Equal(res1[:], res2[:]) { + t.Errorf("ge mismatch") + } +} + +func toLittle(x []byte) *[32]byte { + r := new([32]byte) + for i := 0; i < 32; i++ { + r[32-i-1] = x[i] + } + return r +} + +func TestArith(t *testing.T) { + q, _ := new(big.Int).SetString(qs, 16) + + var c [32]byte + /* + // generate c randmly + var cc [64]byte + io.ReadFull(rand.Reader, cc[:]) + ed2.ScReduce(&c, &cc) + */ + for { + io.ReadFull(rand.Reader, c[:]) + if c[0] < 0x10 { + // c < q + break + } + } + + x := i2OSP(big.NewInt(1), N2) + k := i2OSP(big.NewInt(4), N2) + var z big.Int + s := z.Mod(z.Sub(os2IP(k), z.Mul(os2IP(c[:]), os2IP(x))), q) + ss := i2OSP(s, N2) + s1 := toLittle(ss) + + var s2, minusC2 [32]byte + ed2.ScNeg(&minusC2, toLittle(c[:])) + x2 := toLittle(x) + k2 := toLittle(k) + ed2.ScMulAdd(&s2, x2, &minusC2, k2) + + if !bytes.Equal(s1[:], s2[:]) { + t.Errorf("Arith mismatch\n%s\n%s", hex.Dump(ss), hex.Dump(s2[:])) + } +} + +func DoTestECVRF(t *testing.T, pk, sk []byte, msg []byte, verbose bool) { + pi, _, err := Prove(pk, sk, msg[:]) + if err != nil { + t.Fatal(err) + } + res, err := Verify(pk, pi, msg[:]) + if err != nil { + t.Fatal(err) + } + if !res { + t.Errorf("VRF failed") + } + + // when everything get through + if verbose { + fmt.Printf("alpha: %s\n", hex.EncodeToString(msg)) + fmt.Printf("x: %s\n", hex.EncodeToString(sk)) + fmt.Printf("P: %s\n", hex.EncodeToString(pk)) + fmt.Printf("pi: %s\n", hex.EncodeToString(pi)) + fmt.Printf("vrf: %s\n", hex.EncodeToString(Hash(pi))) + + r, c, s, err := decodeProof(pi) + if err != nil { + t.Fatal(err) + } + // u = (g^x)^c * g^s = P^c * g^s + var u ed1.ProjectiveGroupElement + P := os2ECP(pk, pk[31]>>7) + ed1.GeDoubleScalarMultVartime(&u, c, P, s) + fmt.Printf("r: %s\n", hex.EncodeToString(ecp2OS(r))) + fmt.Printf("c: %s\n", hex.EncodeToString(c[:])) + fmt.Printf("s: %s\n", hex.EncodeToString(s[:])) + fmt.Printf("u: %s\n", hex.EncodeToString(ecp2OSProj(&u))) + } +} + +const howMany = 1000 + +func TestECVRF(t *testing.T) { + for i := howMany; i > 0; i-- { + pk, sk, err := ed25519.GenerateKey(nil) + if err != nil { + t.Fatal(err) + } + var msg [32]byte + io.ReadFull(rand.Reader, msg[:]) + DoTestECVRF(t, pk, sk, msg[:], false) + } +} + +const pks = "885f642c8390293eb74d08cf38d3333771e9e319cfd12a21429eeff2eddeebd2" +const sks = "1fcce948db9fc312902d49745249cfd287de1a764fd48afb3cd0bdd0a8d74674885f642c8390293eb74d08cf38d3333771e9e319cfd12a21429eeff2eddeebd2" + +// old keys -- must fail +//const sks = "c4d50101fc48c65ea496105e5f0a43a67636972d0186edfb9445a2d3377e8b9c8e6fb0fd096402527e7c2375255093975324751f99ef0b7db014eb7e311befb5" +//const pks = "8e6fb0fd096402527e7c2375255093975324751f99ef0b7db014eb7e311befb5" + +func TestECVRFOnce(t *testing.T) { + pk, _ := hex.DecodeString(pks) + sk, _ := hex.DecodeString(sks) + m := []byte(message) + DoTestECVRF(t, pk, sk, m, true) + + h := hashToCurve(m, pk) + fmt.Printf("h: %s\n", hex.EncodeToString(ecp2OS(h))) +} + +func TestHashToCurve(t *testing.T) { + var m [32]byte + pk, _ := hex.DecodeString(pks) + for i := 0; i < 1000; i++ { + io.ReadFull(rand.Reader, m[:]) + P := hashToCurve(m[:], pk) + // test P on curve by P^order = infinity + var infs [32]byte + inf := geScalarMult(P, ip2F(q)) + inf.ToBytes(&infs) + if infs != [32]byte{1} { + t.Fatalf("os2ECP: not valid curve") + } + } +} + +/** + * Generally, VRF implementation has the 3 functions below: + * 1. Keygen (VRF_GEN): generates a key pair (secret key, public key) + * 2. Evaluate (VRF_EVAL): generates a pseudorandom number and its proof + * 3. Verify (VRF_VER): verifies the random number with proof + */ +func TestVrfBasicFunctions(t *testing.T) { + // msg: Hello, World! + msg, err := hex.DecodeString("48656c6c6f2c20576f726c6421") + if err != nil { + t.Fatal(err) + } + // fmt.Println(">>> msg:", len(msg), msg) + + // // 1-1. Keygen + // pk, sk, err := ed25519.GenerateKey(nil) + // if err != nil { + // t.Fatal(err) + // } + + // 1-2. Use custom keys + skRaw, err := hex.DecodeString("6e3fa40baabcafff2cb1f0eaacd4382077c3e5ce2306d4482826ab5a210fd719dbc86475e18027b20fbb846f4d6bdcd6fcc7297c845f72799eb64d3d7b152136") + if err != nil { + t.Fatal(err) + } + sk := ed25519.PrivateKey(skRaw) + pkRaw, err := hex.DecodeString("dbc86475e18027b20fbb846f4d6bdcd6fcc7297c845f72799eb64d3d7b152136") + if err != nil { + t.Fatal(err) + } + pk := ed25519.PublicKey(pkRaw) + + fmt.Println(">>> match:", pk.Equal(sk.Public())) // TODO: Require + fmt.Println(">>> pk:", len(pk), hex.EncodeToString(pk)) // 32 + fmt.Println(">>> sk:", len(sk), hex.EncodeToString(sk)) // 64 + + // 2. Evaluate + // Prove generates vrf output and corresponding proof(pi) with secret key + pi, hash, err := Prove(pk, sk, msg[:]) // `hash`` is same as `Hash(pi)` + if err != nil { + t.Fatal(err) + } + fmt.Println(">>> pi:", len(pi), hex.EncodeToString(pi)) // pi = gamma || i2OSP(c, N) || i2OSP(s, 2N) // 33 + 16 + 32 = 81 + fmt.Println(">>> hash:", len(hash), hex.EncodeToString(hash)) // 32 + + // 3. Verify + res, err := Verify(pk, pi, msg[:]) + if err != nil { + t.Fatal(err) + } + if !res { + t.Errorf("VRF failed") + } + + fmt.Printf(">>> pk||pi||msg: %s%s%s", hex.EncodeToString(pk), hex.EncodeToString(pi), hex.EncodeToString(msg)) + fmt.Println() +} diff --git a/docs/vrf.md b/docs/vrf.md new file mode 100644 index 000000000000..5ca4d5a7b4bd --- /dev/null +++ b/docs/vrf.md @@ -0,0 +1,69 @@ +# VRF + +## Install Dependencies + +```bash +$ go get github.com/ethereum/go-ethereum/crypto/vrf +``` + +# Get Results of `Prove()` + +## curl + +```bash +$ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0", "method":"personal_edPubKey","params":["0x14e98077090336e914b8c76ef1a7c999c9e4d76e", ], "id":11}' : + +{"jsonrpc":"2.0","id":11,"result":"0xf1b59f7bcb2ff6f33e8cbb01fcab71e98d80ac4d94a3b1197d2f433c3c5ced9b"} +``` + +```bash +$ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0", "method":"personal_prove","params":["0x14e98077090336e914b8c76ef1a7c999c9e4d76e", "", "0x48656c6c6f2c20576f726c6421"], "id":11}' : + +{"jsonrpc":"2.0","id":11,"result":"0x035d91cb46308d31126f4308b3f69872a4f835cfa162e06a8588d1bb3a50ee608101bba5caec2da6f1c2733a60fb055c470a4e00d50ae07fa57f6d4e637fb71f45359ad6bb514bdb5e37a10fe44e99a93b"} +``` + +```bash +$ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0", "method":"personal_verify","params":["0xf1b59f7bcb2ff6f33e8cbb01fcab71e98d80ac4d94a3b1197d2f433c3c5ced9b", "0x035d91cb46308d31126f4308b3f69872a4f835cfa162e06a8588d1bb3a50ee608101bba5caec2da6f1c2733a60fb055c470a4e00d50ae07fa57f6d4e637fb71f45359ad6bb514bdb5e37a10fe44e99a93b", "0x48656c6c6f2c20576f726c6421"], "id":11}' : + +{"jsonrpc":"2.0","id":11,"result":true} +``` + +## In geth console: + +```bash +> accounts = personal.listAccounts + +["0x14e98077090336e914b8c76ef1a7c999c9e4d76e", "0x5257cee5ce8381c89b1535939fc37b357e33fe48", "0x86a1551f03fa47e85afa1360637766adcf274449"] +``` + +```bash +> personal.edPubKey(accounts[0], ) + +"0xf1b59f7bcb2ff6f33e8cbb01fcab71e98d80ac4d94a3b1197d2f433c3c5ced9b" +``` + +```bash +> personal.prove(accounts[0], , "0x48656c6c6f2c20576f726c6421") + +"0x035d91cb46308d31126f4308b3f69872a4f835cfa162e06a8588d1bb3a50ee60819dbd1abfb575f8dc792ddc78c718769f0508287cb0852497518731773a2c66bd9efb27b73338aff59e00a04aabdbb791" +``` + +```bash +> personal.verify("0xf1b59f7bcb2ff6f33e8cbb01fcab71e98d80ac4d94a3b1197d2f433c3c5ced9b", "0x035d91cb46308d31126f4308b3f69872a4f835cfa162e06a8588d1bb3a50ee60819dbd1abfb575f8dc792ddc78c718769f0508287cb0852497518731773a2c66bd9efb27b73338aff59e00a04aabdbb791", "0x48656c6c6f2c20576f726c6421") + +true +``` + +# Test + +## Test `Verify()` + +```bash +$ /usr/local/go/bin/go test -timeout 30s -run ^TestPrecompiledVRF$ github.com/ethereum/go-ethereum/core/vm -v +``` + +## Benchmark + +```bash +$ /usr/local/go/bin/go test -benchmem -run=^$ -bench ^BenchmarkPrecompiledVRF$ github.com/ethereum/go-ethereum/core/vm +``` diff --git a/go.mod b/go.mod index 8d9fa00c92f8..958390ad20ee 100644 --- a/go.mod +++ b/go.mod @@ -66,6 +66,7 @@ require ( gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 + github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b ) require ( diff --git a/go.sum b/go.sum index 61d9b4676c52..b398722e527b 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,7 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go-v2 v1.2.0 h1:BS+UYpbsElC82gB+2E2jiCBg36i8HlubTB/dO/moQ9c= @@ -131,13 +132,17 @@ github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -197,6 +202,7 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-echarts/go-echarts v0.0.0-20190915064101-cbb3b43ade5d/go.mod h1:v4lFmU586g/A0xaH1RMDS86YlYrwpj8eHtR+xBReKE8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -216,6 +222,11 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -351,6 +362,7 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1C github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= @@ -371,6 +383,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -381,6 +394,7 @@ github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM52 github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -397,6 +411,7 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -515,9 +530,11 @@ github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeC github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -541,11 +558,13 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= @@ -571,6 +590,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -579,6 +599,10 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673/go.mod h1:Wq2sZrP++Us4tAw1h58MHS8BGIpC4NmKHfvw2QWBe9U= +github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b h1:P+RO/IfYtPQHAm+8V8mwVsj6x0nwKR7/6nsWmyN3nYI= +github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b/go.mod h1:KselA/fRyGFKpcu7sUBHPOz6Ji+7J9GzCKF/c6/ssbI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -640,9 +664,11 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -737,6 +763,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-20181205085412-a5c9d58dba9a/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= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -744,6 +771,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -810,6 +838,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 20a7c6e313ad..1e50f67525a0 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -41,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/vrf" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" @@ -602,6 +603,57 @@ func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (s } } +// Get ED25519 Public Key from address (same private key) +func (s *PrivateAccountAPI) EdPubKey(ctx context.Context, addr common.Address, passwd string) (hexutil.Bytes, error) { + // Look up the wallet containing the requested signer + account := accounts.Account{Address: addr} + + wallet, err := s.b.AccountManager().Find(account) + if err != nil { + return nil, err + } + + // Get + pubkey, err := wallet.EdPubKeyWithPassphrase(account, passwd) + if err != nil { + log.Warn("Failed Get ED25519 Public Key", "address", addr, "err", err) + return nil, err + } + return pubkey, nil +} + +// VRF Prove +func (s *PrivateAccountAPI) Prove(ctx context.Context, addr common.Address, passwd string, msg hexutil.Bytes) (hexutil.Bytes, error) { + // Look up the wallet containing the requested signer + account := accounts.Account{Address: addr} + + wallet, err := s.b.AccountManager().Find(account) + if err != nil { + return nil, err + } + + // Get + prove, err := wallet.ProveWithPassphrase(account, passwd, msg) + if err != nil { + log.Warn("Failed to VRF Prove", "address", addr, "msg", msg, "err", err) + return nil, err + } + return prove, nil +} + +// VRF Verify +func (s *PrivateAccountAPI) Verify(ctx context.Context, pk, pi, msg hexutil.Bytes) (bool, error) { + // Look up the wallet containing the requested signer + + // Get + res, err := vrf.Verify(pk, pi, msg[:]) + if err != nil { + log.Warn("Failed to VRF Verify", "pubkey", pk, "pi", pi, "msg", msg, "err", err) + return false, err + } + return res, nil +} + // Unpair deletes a pairing between wallet and geth. func (s *PrivateAccountAPI) Unpair(ctx context.Context, url string, pin string) error { wallet, err := s.am.Wallet(url) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index df590c3c4030..5c9bf14ada77 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -823,7 +823,22 @@ web3._extend({ name: 'initializeWallet', call: 'personal_initializeWallet', params: 1 - }) + }), + new web3._extend.Method({ + name: 'edPubKey', + call: 'personal_edPubKey', + params: 2 + }), + new web3._extend.Method({ + name: 'prove', + call: 'personal_prove', + params: 3 + }), + new web3._extend.Method({ + name: 'verify', + call: 'personal_verify', + params: 3 + }), ], properties: [ new web3._extend.Property({ diff --git a/mobile/accounts.go b/mobile/accounts.go index 4d979bffff5d..76c811efd5a4 100644 --- a/mobile/accounts.go +++ b/mobile/accounts.go @@ -219,3 +219,19 @@ func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (ccount } return &Account{account}, nil } + +func (ks *KeyStore) EdPubKey(a accounts.Account) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (ks *KeyStore) EdPubKeyWithPassphrase(a accounts.Account, passphrase string) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (ks *KeyStore) Prove(a accounts.Account, m []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} + +func (ks *KeyStore) ProveWithPassphrase(a accounts.Account, passphrase string, m []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported // TODO +} diff --git a/params/protocol_params.go b/params/protocol_params.go index 45c19273a558..c83ae14365c4 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -154,6 +154,8 @@ const ( Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation Bls12381MapG2Gas uint64 = 110000 // Gas price for BLS12-381 mapping field element to G2 operation + VrfVerifyGas uint64 = 3000 // TODO (lukepark327): VRF Verify gas price + // The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529, // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 RefundQuotient uint64 = 2 diff --git a/signer/core/api.go b/signer/core/api.go index f06fbeb76dd1..867965327c30 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -647,3 +647,19 @@ func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common func (api *SignerAPI) Version(ctx context.Context) (string, error) { return ExternalAPIVersion, nil } + +func (api *SignerAPI) EdPubKey(account accounts.Account) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on signers yet") // TODO +} + +func (api *SignerAPI) EdPubKeyWithPassphrase(account accounts.Account, passphrase string) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on signers yet") // TODO +} + +func (api *SignerAPI) Prove(account accounts.Account, message []byte) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on signers yet") // TODO +} + +func (api *SignerAPI) ProveWithPassphrase(account accounts.Account, passphrase string, message []byte) ([]byte, error) { + return nil, fmt.Errorf("vrf-operations not supported on signers yet") // TODO +} From 80ba68e4d0ccf1b2631042c389af109b89ad48f1 Mon Sep 17 00:00:00 2001 From: lukepark327 Date: Mon, 9 Jan 2023 10:35:11 +0900 Subject: [PATCH 2/8] build: update go.mod and go.sum && chore: update vrf.md build: update go.mod && chore: update vrf.md build: update go.mod build: update go.mod & go.sum --- docs/vrf.md | 14 +++++++++++++- go.mod | 1 + go.sum | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/vrf.md b/docs/vrf.md index 5ca4d5a7b4bd..694038ac77fb 100644 --- a/docs/vrf.md +++ b/docs/vrf.md @@ -1,6 +1,6 @@ # VRF -## Install Dependencies +# Install Dependencies ```bash $ go get github.com/ethereum/go-ethereum/crypto/vrf @@ -67,3 +67,15 @@ $ /usr/local/go/bin/go test -timeout 30s -run ^TestPrecompiledVRF$ github.com/et ```bash $ /usr/local/go/bin/go test -benchmem -run=^$ -bench ^BenchmarkPrecompiledVRF$ github.com/ethereum/go-ethereum/core/vm ``` + +# Node + +```bash +$ ./build/bin/geth --datadir data account new + +$ ./build/bin/geth --datadir data --networkid 327 --allow-insecure-unlock --http --http.api 'web3,eth,net,debug,personal' --http.corsdomain '*' --http.addr 0.0.0.0 --http.port 8545 --port 30301 +``` + +```bash +$ ./build/bin/geth attach http://localhost:8545 +``` diff --git a/go.mod b/go.mod index 958390ad20ee..fcb61a8afc63 100644 --- a/go.mod +++ b/go.mod @@ -67,6 +67,7 @@ require ( gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b + github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673 ) require ( diff --git a/go.sum b/go.sum index b398722e527b..06a61b8aaf8a 100644 --- a/go.sum +++ b/go.sum @@ -600,6 +600,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673 h1:PSg2cEFd+9Ae/r5x5iO8cJ3VmTbZNQp6X8tHDmVJAbA= github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673/go.mod h1:Wq2sZrP++Us4tAw1h58MHS8BGIpC4NmKHfvw2QWBe9U= github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b h1:P+RO/IfYtPQHAm+8V8mwVsj6x0nwKR7/6nsWmyN3nYI= github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b/go.mod h1:KselA/fRyGFKpcu7sUBHPOz6Ji+7J9GzCKF/c6/ssbI= From cb24b8bca363da4a7756aae9ecc492709188d82d Mon Sep 17 00:00:00 2001 From: lukepark327 Date: Mon, 9 Jan 2023 11:28:26 +0900 Subject: [PATCH 3/8] chore: to pass env GO111MODULE=on go run build/ci.go lint build/cache/golangci-lint-1.49.0-darwin-arm64.tar.gz is up-to-date >>> build/cache/golangci-lint-1.49.0-darwin-arm64/golangci-lint run --config .golangci.yml ./... You have achieved perfection. --- crypto/vrf/vrf.go | 2 +- crypto/vrf/vrf_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crypto/vrf/vrf.go b/crypto/vrf/vrf.go index 4cd917cacb76..c5621a9af4b8 100644 --- a/crypto/vrf/vrf.go +++ b/crypto/vrf/vrf.go @@ -192,7 +192,7 @@ func os2ECP(os []byte, sign byte) *edwards25519.ExtendedGroupElement { func s2OS(s []byte) []byte { sign := s[31] >> 7 // @@ we should clear the sign bit?? os := []byte{sign + 2} // Y = 0x02 if positive or 0x03 if negative - os = append([]byte(os), s...) + os = append(os, s...) return os } diff --git a/crypto/vrf/vrf_test.go b/crypto/vrf/vrf_test.go index a7b435b7d5ab..2c6a43e536a6 100644 --- a/crypto/vrf/vrf_test.go +++ b/crypto/vrf/vrf_test.go @@ -87,10 +87,10 @@ func TestGeAdd(t *testing.T) { } var extendedBaseEl = ed1.ExtendedGroupElement{ - ed1.FieldElement{25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708}, - ed1.FieldElement{-758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719}, - ed1.FieldElement{-947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649}, - ed1.FieldElement{6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166}, + X: ed1.FieldElement{25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708}, + Y: ed1.FieldElement{-758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719}, + Z: ed1.FieldElement{-947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649}, + T: ed1.FieldElement{6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166}, } func TestG(t *testing.T) { From 38cd544a2d5d829e0cde589123e01f1012bdf4da Mon Sep 17 00:00:00 2001 From: lukepark327 Date: Fri, 13 Jan 2023 09:55:35 +0900 Subject: [PATCH 4/8] fix: precompiled address --- contracts/vrf/contract/vrf.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/vrf/contract/vrf.sol b/contracts/vrf/contract/vrf.sol index 0423f0d7392f..993a610e378f 100644 --- a/contracts/vrf/contract/vrf.sol +++ b/contracts/vrf/contract/vrf.sol @@ -26,7 +26,7 @@ abstract contract VRF { let memPtr := mload(0x40) let success := staticcall( gas(), - 0x14, + 0x13, add(input, 0x20), mload(input), memPtr, From 5d143ed31ed4083b26ef58e1bc01007fe7ec6dce Mon Sep 17 00:00:00 2001 From: lukepark327 Date: Mon, 8 May 2023 17:57:20 +0900 Subject: [PATCH 5/8] feat: change gas cost & testfile --- core/vm/testdata/precompiles/vrf.json | 8 ++++---- params/protocol_params.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/vm/testdata/precompiles/vrf.json b/core/vm/testdata/precompiles/vrf.json index f8de45678073..f752976429a5 100644 --- a/core/vm/testdata/precompiles/vrf.json +++ b/core/vm/testdata/precompiles/vrf.json @@ -3,28 +3,28 @@ "Input": "ca3b325e7ea0942ecb7658dce007374b53e0096d1c0d3d7d114264eac8d355e6026251907f16127c3db7d765de0d0b1bca44b737bdbcdbb57c4728e90aba425c6e0bd5e3c0f9969b55f580c7f46ff0a15707a618829ff44ee099ae346f991e1b5df4819a6666f136956c14699c9789cf7c48656c6c6f2c20576f726c6421", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "vrf-1", - "Gas": 3000, + "Gas": 50000, "NoBenchmark": false }, { "Input": "ffc0b13383ffb12e08bee1e4fce1d7782a334870f6fafea7437e23a4e525f2a8036bf3524542b262497da4d3c4d08b6a9e0a6d3094d5abbf3f11d38014c941a6c02c5063f8b7b111dabf70669400c12dce0f64ad90edfb6981b5b275a280aec804be61cdc55b5087a6625153408846504f48692074686572652e204d79206e616d652069732053616e676879656f6e205061726b2e205768617420697320796f7572206e616d653f", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "vrf-2", - "Gas": 3000, + "Gas": 50000, "NoBenchmark": false }, { "Input": "a6b4b002288784e52bb72d1b9247ad37b11a9cce9c152c24578c7da6f3c133e202ea8ec59e030acdb3bef69e048c3cfca0297c3ad45e4a99ec4136be9cd9644844e742bc0ec4e2a3b1b14077f742ae988105d125f55f55110079e954d946405b43f2ad8166da8d5c979344a7aad9b792535768617420697320746865206d65616e696e67206f66207468697320616262726576696174696f6e2c2022564d4f223f", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "vrf-3", - "Gas": 3000, + "Gas": 50000, "NoBenchmark": false }, { "Input": "16357cf6de199737298f93b9fc2ae3f508baa666f0d545e3af629ff73ae528e60288345a9bdf6b43162ae639c27be4e8332b8d497657574514306ba462c2f2fc20e74c269a94adeb3358c106342f2120570910c9aa58ad7e19e9e141d5c8b1783a73d142e5856d82d9ea43a9c7c92e2018486f772069732074686520776865617468657220746f64617920696e2053656f756c3f", "Expected": "0000000000000000000000000000000000000000000000000000000000000001", "Name": "vrf-4", - "Gas": 3000, + "Gas": 50000, "NoBenchmark": false } ] \ No newline at end of file diff --git a/params/protocol_params.go b/params/protocol_params.go index c83ae14365c4..b64e82ba54d8 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -154,7 +154,7 @@ const ( Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation Bls12381MapG2Gas uint64 = 110000 // Gas price for BLS12-381 mapping field element to G2 operation - VrfVerifyGas uint64 = 3000 // TODO (lukepark327): VRF Verify gas price + VrfVerifyGas uint64 = 50000 // @lukepark327: VRF Verify gas price // The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529, // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 From 3513dab4cf31618eae569796a090ba257b1c8768 Mon Sep 17 00:00:00 2001 From: lukepark327 Date: Tue, 9 May 2023 09:11:42 +0900 Subject: [PATCH 6/8] fix: fix web3ext.go error from auto merge --- internal/web3ext/web3ext.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index f9746a033aa9..ce98b71359ae 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -858,8 +858,9 @@ web3._extend({ name: 'verify', call: 'personal_verify', params: 3 - // fee delegation - new web3._extend.Method({ + }), + // fee delegation + new web3._extend.Method({ name: 'signRawFeeDelegateTransaction', call: 'personal_signRawFeeDelegateTransaction', params: 3, From cc799437ecad58270f4e48eb8ff3b5b2bd4c0287 Mon Sep 17 00:00:00 2001 From: Luke Park Date: Tue, 9 May 2023 09:42:33 +0900 Subject: [PATCH 7/8] Update web3ext.go fix indent --- internal/web3ext/web3ext.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index ce98b71359ae..a50eb615ead0 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -859,8 +859,8 @@ web3._extend({ call: 'personal_verify', params: 3 }), - // fee delegation - new web3._extend.Method({ + // fee delegation + new web3._extend.Method({ name: 'signRawFeeDelegateTransaction', call: 'personal_signRawFeeDelegateTransaction', params: 3, From 6bcac0a50b3e2d9906150aea5e6fe198db682cb7 Mon Sep 17 00:00:00 2001 From: Luke Park Date: Tue, 9 May 2023 10:17:00 +0900 Subject: [PATCH 8/8] Create ci.yml --- .github/workflows/ci.yml | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000000..9c7375cc86e5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: feat-vrf-ci + +on: + workflow_dispatch: + +jobs: + build_test: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.ref }} + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + + - name: Build Go-WEMIX + run: make gwemix.tar.gz + - name: Check Build + run: ls -al build/gwemix.tar.gz + + lint_test: + strategy: + fail-fast: false + matrix: + version: [1.17, 1.18, 1.19] + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.ref }} + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.version }} + + - name: Check Lint + run: make lint + + unit_test: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.ref }} + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + + - name: Check golang Test Cases + run: | + unset ANDROID_HOME + make test-short