فهرست منبع

Add VAA serialization logic

Hendrik Hofstadt 5 سال پیش
والد
کامیت
7993a72dea

+ 1 - 1
.gitignore

@@ -3,5 +3,5 @@ node_modules
 .idea
 .arcconfig
 *.iml
-target
 bin
+target

+ 1218 - 0
bridge/go.sum

@@ -0,0 +1,1218 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
+cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
+dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
+dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
+git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
+github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
+github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
+github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
+github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
+github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
+github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
+github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
+github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
+github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
+github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DATA-DOG/go-txdb v0.1.3/go.mod h1:DhAhxMXZpUJVGnT+p9IbzJoRKvlArO2pkHjnGX7o0n0=
+github.com/Depado/ginprom v1.2.1-0.20200115153638-53bbba851bd8/go.mod h1:VHRucFf/9saDXsYg6uzQ8Oo8gUwngtWec9ZJ00H+ZCc=
+github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
+github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
+github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
+github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
+github.com/aristanetworks/goarista v0.0.0-20190204200901-2166578f3448/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
+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 v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
+github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
+github.com/boj/redistore v0.0.0-20160128113310-fc113767cd6b/go.mod h1:5r9chGCb4uUhBCGMDDCYfyHU/awSRoBeG53Zaj1crhU=
+github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
+github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
+github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
+github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
+github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
+github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
+github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
+github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
+github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
+github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
+github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
+github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
+github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
+github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs=
+github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
+github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
+github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
+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-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+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/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e/go.mod h1:IJgIiGUARc4aOr4bOQ85klmjsShkEEfiRc6q/yBSfo8=
+github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
+github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f h1:BOaYiTvg8p9vBUXpklC22XSK/mifLF7lG9jtmYYi3Tc=
+github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
+github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
+github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
+github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
+github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
+github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
+github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
+github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
+github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=
+github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+github.com/ethereum/go-ethereum v1.9.15/go.mod h1:slT8bPPRhXsyNTwHQxrOnjuTZ1sDXRajW11EkJ84QJ0=
+github.com/ethereum/go-ethereum v1.9.18 h1:+vzvufVD7+OfQa07IJP20Z7AGZsJaw0M6JIA/WQcqy8=
+github.com/ethereum/go-ethereum v1.9.18/go.mod h1:JSSTypSMTkGZtAdAChH2wP5dZEvPGh3nUTuDpH+hNrg=
+github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
+github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
+github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
+github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
+github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
+github.com/gin-contrib/expvar v0.0.0-20181230111036-f23b556cc79f/go.mod h1:lKdjvm96uBFqhKVjrNmDm66m199oRiOxJAThyr6rdW8=
+github.com/gin-contrib/size v0.0.0-20190528085907-355431950c57/go.mod h1:tnsW+BI6lwWXXNN+IJNJGRPjs10RYHJFCnbUOO1EPWc=
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/contrib v0.0.0-20190526021735-7fb7810ed2a0/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
+github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
+github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
+github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
+github.com/gin-gonic/gin v1.6.0/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
+github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
+github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+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/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/protobuf v0.0.0-20170307001533-c9c7427a2a70/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
+github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY=
+github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
+github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
+github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
+github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/guregu/null v3.5.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM=
+github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
+github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
+github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
+github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
+github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
+github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
+github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
+github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=
+github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
+github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
+github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY=
+github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
+github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
+github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
+github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
+github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
+github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
+github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8=
+github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
+github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
+github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
+github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
+github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=
+github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
+github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=
+github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
+github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=
+github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=
+github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
+github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
+github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
+github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
+github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=
+github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
+github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs=
+github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=
+github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
+github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=
+github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
+github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY=
+github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=
+github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
+github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
+github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
+github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0=
+github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
+github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
+github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
+github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
+github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=
+github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
+github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=
+github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
+github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
+github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
+github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
+github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
+github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
+github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
+github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
+github.com/jinzhu/gorm v1.9.11-0.20190912141731-0c98e7d712e2/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw=
+github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v0.0.0-20181116074157-8ec929ed50c3/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc=
+github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+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/jpillora/backoff v0.0.0-20170918002102-8eab2debe79d/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
+github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
+github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/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/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+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/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=
+github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
+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=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
+github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=
+github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E=
+github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
+github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
+github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
+github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=
+github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M=
+github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU=
+github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=
+github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc=
+github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8=
+github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
+github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
+github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
+github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
+github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=
+github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=
+github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=
+github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM=
+github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8=
+github.com/libp2p/go-libp2p v0.10.2 h1:VQOo/Pbj9Ijco9jiMYN5ImAg236IjTXfnUPJ2OvbpLM=
+github.com/libp2p/go-libp2p v0.10.2/go.mod h1:BYckt6lmS/oA1SlRETSPWSUulCQKiZuTVsymVMc//HQ=
+github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
+github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=
+github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI=
+github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A=
+github.com/libp2p/go-libp2p-autonat v0.2.3/go.mod h1:2U6bNWCNsAG9LEbwccBDQbjzQ8Krdjge1jLTE9rdoMM=
+github.com/libp2p/go-libp2p-autonat v0.3.1 h1:60sc3NuQz+RxEb4ZVCRp/7uPtD7gnlLcOIKYNulzSIo=
+github.com/libp2p/go-libp2p-autonat v0.3.1/go.mod h1:0OzOi1/cVc7UcxfOddemYD5vzEqi4fwRbnZcJGLi68U=
+github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=
+github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=
+github.com/libp2p/go-libp2p-blankhost v0.1.6/go.mod h1:jONCAJqEP+Z8T6EQviGL4JsQcLx1LgTGtVqFNY8EMfQ=
+github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk=
+github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ=
+github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=
+github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo=
+github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4=
+github.com/libp2p/go-libp2p-circuit v0.2.3/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4=
+github.com/libp2p/go-libp2p-circuit v0.3.1 h1:69ENDoGnNN45BNDnBd+8SXSetDuw0eJFcGmOvvtOgBw=
+github.com/libp2p/go-libp2p-circuit v0.3.1/go.mod h1:8RMIlivu1+RxhebipJwFDA45DasLx+kkrp4IlJj53F4=
+github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w=
+github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0=
+github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=
+github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I=
+github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=
+github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=
+github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
+github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=
+github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
+github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=
+github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
+github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
+github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
+github.com/libp2p/go-libp2p-core v0.5.2/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
+github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
+github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
+github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM=
+github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
+github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
+github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
+github.com/libp2p/go-libp2p-core v0.6.1 h1:XS+Goh+QegCDojUZp00CaPMfiEADCrLjNZskWE7pvqs=
+github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
+github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
+github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=
+github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=
+github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4=
+github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ=
+github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
+github.com/libp2p/go-libp2p-kad-dht v0.8.3 h1:ceK5ML6s/I8UAcw6veoNsuEHdHvfo88leU/5uWOIFWs=
+github.com/libp2p/go-libp2p-kad-dht v0.8.3/go.mod h1:HnYYy8taJWESkqiESd1ngb9XX/XGGsMA5G0Vj2HoSh4=
+github.com/libp2p/go-libp2p-kbucket v0.4.2 h1:wg+VPpCtY61bCasGRexCuXOmEmdKjN+k1w+JtTwu9gA=
+github.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY=
+github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=
+github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
+github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=
+github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=
+github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=
+github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
+github.com/libp2p/go-libp2p-mplex v0.2.4 h1:XFFXaN4jhqnIuJVjYOR3k6bnRj0mFfJOlIuDVww+4Zo=
+github.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE=
+github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
+github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=
+github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=
+github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=
+github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
+github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
+github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=
+github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=
+github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=
+github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=
+github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
+github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
+github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw=
+github.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
+github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U=
+github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
+github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
+github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
+github.com/libp2p/go-libp2p-pubsub v0.3.3 h1:/AzOAmjDc+IJWybEzhYj1UaV1HErqmo4v3pQVepbgi8=
+github.com/libp2p/go-libp2p-pubsub v0.3.3/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI=
+github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M=
+github.com/libp2p/go-libp2p-quic-transport v0.7.1 h1:X6Ond9GANspXpgwJlSR9yxcMMD6SLBnGKRtwjBG5awc=
+github.com/libp2p/go-libp2p-quic-transport v0.7.1/go.mod h1:TD31to4E5exogR/GWHClXCfkktigjAl5rXSt7HoxNvY=
+github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=
+github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0=
+github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4=
+github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
+github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
+github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
+github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=
+github.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg=
+github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=
+github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=
+github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=
+github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=
+github.com/libp2p/go-libp2p-swarm v0.2.7/go.mod h1:ZSJ0Q+oq/B1JgfPHJAT2HTall+xYRNYp1xs4S2FBWKA=
+github.com/libp2p/go-libp2p-swarm v0.2.8 h1:cIUUvytBzNQmGSjnXFlI6UpoBGsaud82mJPIJVfkDlg=
+github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=
+github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
+github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
+github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
+github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
+github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
+github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8 h1:v4dvk7YEW8buwCdIVWnhpv0Hp/AAJKRWIxBhmLRZrsk=
+github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
+github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
+github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
+github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
+github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
+github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4=
+github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=
+github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
+github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=
+github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=
+github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=
+github.com/libp2p/go-libp2p-yamux v0.2.8 h1:0s3ELSLu2O7hWKfX1YjzudBKCP0kZ+m9e2+0veXzkn4=
+github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=
+github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
+github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=
+github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
+github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=
+github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
+github.com/libp2p/go-mplex v0.1.2 h1:qOg1s+WdGLlpkrczDqmhYzyk3vCfsQ8+RxRTQjOZWwI=
+github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
+github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
+github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
+github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA=
+github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
+github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=
+github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q=
+github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=
+github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
+github.com/libp2p/go-netroute v0.1.3 h1:1ngWRx61us/EpaKkdqkMjKk/ufr/JlIFYQAxV2XX8Ig=
+github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
+github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0=
+github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
+github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
+github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
+github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw=
+github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
+github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=
+github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
+github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
+github.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M=
+github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=
+github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
+github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0=
+github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
+github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
+github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=
+github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=
+github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=
+github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=
+github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=
+github.com/libp2p/go-tcp-transport v0.2.0 h1:YoThc549fzmNJIh7XjHVtMIFaEDRtIrtWciG5LyYAPo=
+github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0=
+github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=
+github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
+github.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw=
+github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
+github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
+github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
+github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
+github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
+github.com/libp2p/go-yamux v1.3.7 h1:v40A1eSPJDIZwz2AvrV3cxpTZEGDP11QJbukmEhYyQI=
+github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
+github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE=
+github.com/lucas-clemente/quic-go v0.17.3 h1:jMX/MmDNCljfisgMmPGUcBJ+zUh9w3d3ia4YJjYS3TM=
+github.com/lucas-clemente/quic-go v0.17.3/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE=
+github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
+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-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f/go.mod h1:Z60vy0EZVSu0bOugCHdcN5ZxFMKSpjRgsnh0XKPFqqk=
+github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
+github.com/marten-seemann/qtls v0.9.1 h1:O0YKQxNVPaiFgMng0suWEOY2Sb4LT2sRn9Qimq3Z1IQ=
+github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
+github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
+github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
+github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
+github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
+github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
+github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
+github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
+github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
+github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
+github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
+github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
+github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
+github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
+github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
+github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
+github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
+github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
+github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
+github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
+github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
+github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
+github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
+github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
+github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
+github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=
+github.com/multiformats/go-multiaddr v0.2.2 h1:XZLDTszBIJe6m0zF6ITBrEcZR73OPUhCBBS9rYAuUzI=
+github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
+github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
+github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
+github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA=
+github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=
+github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=
+github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
+github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
+github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=
+github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
+github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
+github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=
+github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
+github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
+github.com/multiformats/go-multiaddr-net v0.1.5 h1:QoRKvu0xHN1FCFJcMQLbG/yQE2z441L5urvG3+qyz7g=
+github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
+github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
+github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
+github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
+github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
+github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
+github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
+github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
+github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
+github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
+github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I=
+github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
+github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
+github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=
+github.com/multiformats/go-multistream v0.1.2 h1:knyamLYMPFPngQjGQ0lhnlys3jtVR/3xV6TREUJr+fE=
+github.com/multiformats/go-multistream v0.1.2/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=
+github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
+github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
+github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
+github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
+github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
+github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
+github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
+github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
+github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181120120127-aeab699e26f4/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
+github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+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 v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
+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/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shirou/gopsutil v2.20.5-0.20200531151128-663af789c085+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
+github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
+github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
+github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
+github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
+github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
+github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
+github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
+github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
+github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
+github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
+github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
+github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
+github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
+github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
+github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
+github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
+github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
+github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
+github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
+github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/smartcontractkit/chainlink v0.8.11 h1:i3R5vxvyfxpyAfcGi476PiBIaYuQxnWfj9NgtxApLWk=
+github.com/smartcontractkit/chainlink v0.8.11/go.mod h1:MSQX0UpcGbMswJnihA9NtZjOW3QrLo5sJlfseqd1wKc=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
+github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
+github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
+github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
+github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+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/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
+github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
+github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
+github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
+github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
+github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0=
+github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
+github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/sjson v1.1.1/go.mod h1:yvVuSnpEQv5cYIrO+AT6kw4QVfd5SDZoGIS7/5+fZFs=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
+github.com/ulule/limiter v0.0.0-20190417201358-7873d115fc4e/go.mod h1:VJx/ZNGmClQDS5F6EmsGqK8j3jz1qJYZ6D9+MdAD+kw=
+github.com/unrolled/secure v0.0.0-20190624173513-716474489ad3/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
+github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
+github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
+github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
+github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
+github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
+github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE=
+github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=
+github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
+github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
+github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
+github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=
+github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
+github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
+github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs=
+go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw=
+go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ=
+go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg=
+go.dedis.ch/kyber/v3 v3.0.12 h1:15d61EyBcBoFIS97kS2c/Vz4o3FR8ALnZ2ck9J/ebYM=
+go.dedis.ch/kyber/v3 v3.0.12/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U=
+go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo=
+go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=
+go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo=
+go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
+go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
+go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
+golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
+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-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/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-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20170324220409-6c2325251549/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20170325170518-afadfcc7779c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/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-20181122145206-62eef0e2fa9b/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-20190124100055-b90733256f2e/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-20190219092855-153ac476189d/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-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+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-20190526052359-791d8a0f4d09/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-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+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=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200414032229-332987a829c3 h1:Z68UA+HA9shnGhQbAFXKqL1Rk/tfiTHJ57bNm/MUL/A=
+golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
+google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
+gopkg.in/go-playground/validator.v8 v8.18.1/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
+gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
+gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw=
+gopkg.in/guregu/null.v2 v2.1.2/go.mod h1:XORrx8tyS5ZDcyUboCIxQtta/Aujk/6pfWrn9Xe33mU=
+gopkg.in/guregu/null.v3 v3.5.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
+gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200603215123-a4a8cb9d2cbc/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=
+gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
+gopkg.in/yaml.v2 v2.0.0-20170208141851-a3f3340b5840/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
+sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

+ 33 - 0
bridge/pkg/signatures/cryptotest/cryptotest.go

@@ -0,0 +1,33 @@
+// package cryptotest provides convenience functions for kyber-based APIs.
+//
+// It is separate from cltest to prevent an import cycle.
+package cryptotest
+
+import (
+	"math/rand"
+	"testing"
+)
+
+// randomStream implements cipher.Stream, but with a deterministic output.
+type randomStream rand.Rand
+
+// NewStream returns a randomStream seeded from seed, for deterministic
+// randomness in tests of random outputs, and for small property-based tests.
+//
+// This API is deliberately awkward to prevent it from being used outside of
+// tests.
+//
+// The testing framework runs the tests in a file in series, unless you
+// explicitly request otherwise with testing.T.Parallel(). So one such stream
+// per file is enough, most of the time.
+func NewStream(t *testing.T, seed int64) *randomStream {
+	return (*randomStream)(rand.New(rand.NewSource(seed)))
+}
+
+// XORKeyStream dumps the output from a math/rand PRNG on dst.
+//
+// It gives no consideration for the contents of src, and is named so
+// misleadingly purely to satisfy the cipher.Stream interface.
+func (s *randomStream) XORKeyStream(dst, src []byte) {
+	(*rand.Rand)(s).Read(dst)
+}

+ 304 - 0
bridge/pkg/signatures/ethdss/ethdss.go

@@ -0,0 +1,304 @@
+// Package ethdss implements the Distributed Schnorr Signature protocol from the
+////////////////////////////////////////////////////////////////////////////////
+//       XXX: Do not use in production until this code has been audited.
+////////////////////////////////////////////////////////////////////////////////
+// paper "Provably Secure Distributed Schnorr Signatures and a (t, n)
+// Threshold Scheme for Implicit Certificates".
+// https://dl.acm.org/citation.cfm?id=678297
+// To generate a distributed signature from a group of participants, the group
+// must first generate one longterm distributed secret with the share/dkg
+// package, and then one random secret to be used only once.
+// Each participant then creates a DSS struct, that can issue partial signatures
+// with `dss.PartialSignature()`. These partial signatures can be broadcasted to
+// the whole group or to a trusted combiner. Once one has collected enough
+// partial signatures, it is possible to compute the distributed signature with
+// the `Signature` method.
+//
+// This is mostly copied from the sign/dss package, with minor adjustments for
+// use with ethschnorr.
+package ethdss
+
+import (
+	"bytes"
+	"errors"
+	"math/big"
+
+	"github.com/certusone/wormhole/bridge/pkg/signatures/ethschnorr"
+	"github.com/certusone/wormhole/bridge/pkg/signatures/secp256k1"
+
+	"go.dedis.ch/kyber/v3"
+	"go.dedis.ch/kyber/v3/share"
+)
+
+// Suite represents the functionalities needed by the dss package
+type Suite interface {
+	kyber.Group
+	kyber.HashFactory
+	kyber.Random
+}
+
+var secp256k1Suite = secp256k1.NewBlakeKeccackSecp256k1()
+var secp256k1Group kyber.Group = secp256k1Suite
+
+// DistKeyShare is an abstraction to allow one to use distributed key share
+// from different schemes easily into this distributed threshold Schnorr
+// signature framework.
+type DistKeyShare interface {
+	PriShare() *share.PriShare
+	Commitments() []kyber.Point
+}
+
+// DSS holds the information used to issue partial signatures as well as to
+// compute the distributed schnorr signature.
+type DSS struct {
+	// Keypair for this participant in the signing process (i.e., the one where
+	// this struct is stored.) This is not the keypair for full signing key; that
+	// would defeat the point.
+	secret kyber.Scalar
+	public kyber.Point
+	// Index value of this participant in the signing process. The index is shared
+	// across participants.
+	index int
+	// Public keys of potential participants in the signing process
+	participants []kyber.Point
+	// Number of participants needed to construct a signature
+	T int
+	// Shares of the distributed long-term signing keypair
+	long DistKeyShare
+	// Shares of the distributed ephemeral nonce keypair
+	random DistKeyShare
+	// Pedersen commitments to the coefficients of the polynomial implicitly used
+	// to share the long-term signing public/private keypair.
+	longPoly *share.PubPoly
+	// Pedersen commitments to the coefficients of the polynomial implicitly used
+	// to share the ephemeral nonce keypair.
+	randomPoly *share.PubPoly
+	// Message to be signed
+	msg *big.Int
+	// The partial signatures collected so far.
+	partials []*share.PriShare
+	// Indices for the participants who have provided their partial signatures to
+	// this participant.
+	partialsIdx map[int]bool
+	// True iff the partial signature for this dss has been signed by its owner.
+	signed bool
+	// String which uniquely identifies this signature, shared by all
+	// participants.
+	sessionID []byte
+}
+
+// DSSArgs is the arguments to NewDSS, as a struct. See NewDSS for details.
+type DSSArgs = struct {
+	secret       kyber.Scalar
+	participants []kyber.Point
+	long         DistKeyShare
+	random       DistKeyShare
+	msg          *big.Int
+	T            int
+}
+
+// PartialSig is partial representation of the final distributed signature. It
+// must be sent to each of the other participants.
+type PartialSig struct {
+	Partial   *share.PriShare
+	SessionID []byte
+	Signature ethschnorr.Signature
+}
+
+// NewDSS returns a DSS struct out of the suite, the longterm secret of this
+// node, the list of participants, the longterm and random distributed key
+// (generated by the dkg package), the message to sign and finally the T
+// threshold. It returns an error if the public key of the secret can't be found
+// in the list of participants.
+func NewDSS(args DSSArgs) (*DSS, error) {
+	public := secp256k1Group.Point().Mul(args.secret, nil)
+	var i int
+	var found bool
+	for j, p := range args.participants {
+		if p.Equal(public) {
+			found = true
+			i = j
+			break
+		}
+	}
+	if !found {
+		return nil, errors.New("dss: public key not found in list of participants")
+	}
+	return &DSS{
+		secret:       args.secret,
+		public:       public,
+		index:        i,
+		participants: args.participants,
+		long:         args.long,
+		longPoly: share.NewPubPoly(secp256k1Suite,
+			secp256k1Group.Point().Base(), args.long.Commitments()),
+		random: args.random,
+		randomPoly: share.NewPubPoly(secp256k1Suite,
+			secp256k1Group.Point().Base(), args.random.Commitments()),
+		msg:         args.msg,
+		T:           args.T,
+		partialsIdx: make(map[int]bool),
+		sessionID:   sessionID(secp256k1Suite, args.long, args.random),
+	}, nil
+}
+
+// PartialSig generates the partial signature related to this DSS. This
+// PartialSig can be broadcasted to every other participant or only to a
+// trusted combiner as described in the paper.
+// The signature format is compatible with EdDSA verification implementations.
+//
+// Corresponds to section 4.2, step 2 the Stinson 2001 paper.
+func (d *DSS) PartialSig() (*PartialSig, error) {
+	secretPartialLongTermKey := d.long.PriShare().V     // ɑᵢ, in the paper
+	secretPartialCommitmentKey := d.random.PriShare().V // βᵢ, in the paper
+	fullChallenge := d.hashSig()                        // h(m‖V), in the paper
+	secretChallengeMultiple := secp256k1Suite.Scalar().Mul(
+		fullChallenge, secretPartialLongTermKey) // ɑᵢh(m‖V)G, in the paper
+	// Corresponds to ɣᵢG=βᵢG+ɑᵢh(m‖V)G in the paper, but NB, in its notation, we
+	// use ɣᵢG=βᵢG-ɑᵢh(m‖V)G. (Subtract instead of add.)
+	partialSignature := secp256k1Group.Scalar().Sub(
+		secretPartialCommitmentKey, secretChallengeMultiple)
+	ps := &PartialSig{
+		Partial:   &share.PriShare{V: partialSignature, I: d.index},
+		SessionID: d.sessionID,
+	}
+	var err error
+	ps.Signature, err = ethschnorr.Sign(d.secret, ps.Hash()) // sign share
+	if !d.signed {
+		d.partialsIdx[d.index] = true
+		d.partials = append(d.partials, ps.Partial)
+		d.signed = true
+	}
+	return ps, err
+}
+
+// ProcessPartialSig takes a PartialSig from another participant and stores it
+// for generating the distributed signature. It returns an error if the index is
+// wrong, or the signature is invalid or if a partial signature has already been
+// received by the same peer. To know whether the distributed signature can be
+// computed after this call, one can use the `EnoughPartialSigs` method.
+//
+// Corresponds to section 4.3, step 3 of the paper
+func (d *DSS) ProcessPartialSig(ps *PartialSig) error {
+	var err error
+	public, ok := findPub(d.participants, ps.Partial.I)
+	if !ok {
+		err = errors.New("dss: partial signature with invalid index")
+	}
+	// nothing secret here
+	if err == nil && !bytes.Equal(ps.SessionID, d.sessionID) {
+		err = errors.New("dss: session id do not match")
+	}
+	if err == nil {
+		if vrr := ethschnorr.Verify(public, ps.Hash(), ps.Signature); vrr != nil {
+			err = vrr
+		}
+	}
+	if err == nil {
+		if _, ok := d.partialsIdx[ps.Partial.I]; ok {
+			err = errors.New("dss: partial signature already received from peer")
+		}
+	}
+	if err != nil {
+		return err
+	}
+	hash := d.hashSig() // h(m‖V), in the paper's notation
+	idx := ps.Partial.I
+	// βᵢG=sum(cₖi^kG), in the paper, defined as sᵢ in step 2 of section 2.4
+	randShare := d.randomPoly.Eval(idx)
+	// ɑᵢG=sum(bₖi^kG), defined as sᵢ in step 2 of section 2.4
+	longShare := d.longPoly.Eval(idx)
+	// h(m‖V)(Y+...) term from equation (3) of the paper. AKA h(m‖V)ɑᵢG
+	challengeSummand := secp256k1Group.Point().Mul(hash, longShare.V)
+	// RHS of equation (3), except we subtract the second term instead of adding.
+	// AKA (βᵢ-ɑᵢh(m‖V))G, which should equal ɣᵢG, according to equation (3)
+	maybePartialSigCommitment := secp256k1Group.Point().Sub(randShare.V,
+		challengeSummand)
+	// Check that equation (3) holds (ɣᵢ is represented as ps.Partial.V, here.)
+	partialSigCommitment := secp256k1Group.Point().Mul(ps.Partial.V, nil)
+	if !partialSigCommitment.Equal(maybePartialSigCommitment) {
+		return errors.New("dss: partial signature not valid")
+	}
+	d.partialsIdx[ps.Partial.I] = true
+	d.partials = append(d.partials, ps.Partial)
+	return nil
+}
+
+// EnoughPartialSig returns true if there are enough partial signature to compute
+// the distributed signature. It returns false otherwise. If there are enough
+// partial signatures, one can issue the signature with `Signature()`.
+func (d *DSS) EnoughPartialSig() bool {
+	return len(d.partials) >= d.T
+}
+
+// Signature computes the distributed signature from the list of partial
+// signatures received. It returns an error if there are not enough partial
+// signatures.
+//
+// Corresponds to section 4.2, step 4 of Stinson, 2001 paper
+func (d *DSS) Signature() (ethschnorr.Signature, error) {
+	if !d.EnoughPartialSig() {
+		return nil, errors.New("dkg: not enough partial signatures to sign")
+	}
+	// signature corresponds to σ in step 4 of section 4.2
+	signature, err := share.RecoverSecret(secp256k1Suite, d.partials, d.T,
+		len(d.participants))
+	if err != nil {
+		return nil, err
+	}
+	rv := ethschnorr.NewSignature()
+	rv.Signature = secp256k1.ToInt(signature)
+	// commitmentPublicKey corresponds to V in step 4 of section 4.2
+	commitmentPublicKey := d.random.Commitments()[0]
+	rv.CommitmentPublicAddress = secp256k1.EthereumAddress(commitmentPublicKey)
+	return rv, nil
+}
+
+// hashSig returns, in the paper's notation, h(m‖V). It is the challenge hash
+// for the signature. (Actually, the hash also includes the public key, but that
+// has no effect on the correctness or robustness arguments from the paper.)
+func (d *DSS) hashSig() kyber.Scalar {
+	v := d.random.Commitments()[0] // Public-key commitment, in signature from d
+	vAddress := secp256k1.EthereumAddress(v)
+	publicKey := d.long.Commitments()[0]
+	rv, err := ethschnorr.ChallengeHash(publicKey, vAddress, d.msg)
+	if err != nil {
+		panic(err)
+	}
+	return rv
+}
+
+// Verify takes a public key, a message and a signature and returns an error if
+// the signature is invalid.
+func Verify(public kyber.Point, msg *big.Int, sig ethschnorr.Signature) error {
+	return ethschnorr.Verify(public, msg, sig)
+}
+
+// Hash returns the hash representation of this PartialSig to be used in a
+// signature.
+func (ps *PartialSig) Hash() *big.Int {
+	h := secp256k1Suite.Hash()
+	_, _ = h.Write(ps.Partial.Hash(secp256k1Suite))
+	_, _ = h.Write(ps.SessionID)
+	return (&big.Int{}).SetBytes(h.Sum(nil))
+}
+
+func findPub(list []kyber.Point, i int) (kyber.Point, bool) {
+	if i >= len(list) {
+		return nil, false
+	}
+	return list[i], true
+}
+
+func sessionID(s Suite, a, b DistKeyShare) []byte {
+	h := s.Hash()
+	for _, p := range a.Commitments() {
+		_, _ = p.MarshalTo(h)
+	}
+
+	for _, p := range b.Commitments() {
+		_, _ = p.MarshalTo(h)
+	}
+
+	return h.Sum(nil)
+}

+ 290 - 0
bridge/pkg/signatures/ethdss/ethdss_test.go

@@ -0,0 +1,290 @@
+package ethdss
+
+import (
+	"crypto/rand"
+	"fmt"
+	"math/big"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/certusone/wormhole/bridge/pkg/signatures/cryptotest"
+	"github.com/certusone/wormhole/bridge/pkg/signatures/ethschnorr"
+	"github.com/certusone/wormhole/bridge/pkg/signatures/secp256k1"
+
+	"go.dedis.ch/kyber/v3"
+	dkg "go.dedis.ch/kyber/v3/share/dkg/rabin"
+)
+
+var suite = secp256k1.NewBlakeKeccackSecp256k1()
+
+var nbParticipants = 7
+var t = nbParticipants/2 + 1
+
+var partPubs []kyber.Point
+var partSec []kyber.Scalar
+
+var longterms []*dkg.DistKeyShare
+var randoms []*dkg.DistKeyShare
+
+var msg *big.Int
+
+var randomStream = cryptotest.NewStream(&testing.T{}, 0)
+
+func init() {
+	partPubs = make([]kyber.Point, nbParticipants)
+	partSec = make([]kyber.Scalar, nbParticipants)
+	for i := 0; i < nbParticipants; i++ {
+		kp := secp256k1.Generate(randomStream)
+		partPubs[i] = kp.Public
+		partSec[i] = kp.Private
+	}
+	// Corresponds to section 4.2, step 1 of Stinson, 2001 paper
+	longterms = genDistSecret(true) // Keep trying until valid public key
+	randoms = genDistSecret(false)
+
+	var err error
+	msg, err = rand.Int(rand.Reader, big.NewInt(0).Lsh(big.NewInt(1), 256))
+	if err != nil {
+		panic(err)
+	}
+}
+
+func TestDSSNew(t *testing.T) {
+	dssArgs := DSSArgs{secret: partSec[0], participants: partPubs,
+		long: longterms[0], random: randoms[0], msg: msg, T: 4}
+	dss, err := NewDSS(dssArgs)
+	assert.NotNil(t, dss)
+	assert.Nil(t, err)
+	dssArgs.secret = suite.Scalar().Zero()
+	dss, err = NewDSS(dssArgs)
+	assert.Nil(t, dss)
+	assert.Error(t, err)
+}
+
+func TestDSSPartialSigs(t *testing.T) {
+	dss0 := getDSS(0)
+	dss1 := getDSS(1)
+	ps0, err := dss0.PartialSig()
+	assert.Nil(t, err)
+	assert.NotNil(t, ps0)
+	assert.Len(t, dss0.partials, 1)
+	// second time should not affect list
+	ps0, err = dss0.PartialSig()
+	assert.Nil(t, err)
+	assert.NotNil(t, ps0)
+	assert.Len(t, dss0.partials, 1)
+
+	// wrong index
+	goodI := ps0.Partial.I
+	ps0.Partial.I = 100
+	err = dss1.ProcessPartialSig(ps0)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "invalid index")
+	ps0.Partial.I = goodI
+
+	// wrong sessionID
+	goodSessionID := ps0.SessionID
+	ps0.SessionID = []byte("ahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")
+	err = dss1.ProcessPartialSig(ps0)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "dss: session id")
+	ps0.SessionID = goodSessionID
+
+	// wrong Signature
+	goodSig := ps0.Signature
+	ps0.Signature = ethschnorr.NewSignature()
+	copy(ps0.Signature.CommitmentPublicAddress[:], randomBytes(20))
+	badSig := secp256k1.ToInt(suite.Scalar().Pick(randomStream))
+	ps0.Signature.Signature.Set(badSig)
+	assert.Error(t, dss1.ProcessPartialSig(ps0))
+	ps0.Signature = goodSig
+
+	// invalid partial sig
+	goodV := ps0.Partial.V
+	ps0.Partial.V = suite.Scalar().Zero()
+	ps0.Signature, err = ethschnorr.Sign(dss0.secret, ps0.Hash())
+	require.Nil(t, err)
+	err = dss1.ProcessPartialSig(ps0)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "not valid")
+	ps0.Partial.V = goodV
+	ps0.Signature = goodSig
+
+	// fine
+	err = dss1.ProcessPartialSig(ps0)
+	assert.Nil(t, err)
+
+	// already received
+	assert.Error(t, dss1.ProcessPartialSig(ps0))
+
+	// if not enough partial signatures, can't generate signature
+	sig, err := dss1.Signature()
+	assert.Nil(t, sig) // XXX: Should also check err is nil?
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "not enough")
+
+	// enough partial sigs ?
+	for i := 2; i < nbParticipants; i++ {
+		dss := getDSS(i)
+		ps, e := dss.PartialSig()
+		require.Nil(t, e)
+		require.Nil(t, dss1.ProcessPartialSig(ps))
+	}
+	assert.True(t, dss1.EnoughPartialSig())
+	sig, err = dss1.Signature()
+	assert.NoError(t, err)
+	assert.NoError(t, Verify(dss1.long.Commitments()[0], msg, sig))
+}
+
+var printTests = false
+
+func printTest(t *testing.T, msg *big.Int, public kyber.Point,
+	signature ethschnorr.Signature) {
+	pX, pY := secp256k1.Coordinates(public)
+	fmt.Printf("  ['%064x',\n   '%064x',\n   '%064x',\n   '%064x',\n   '%040x'],\n",
+		msg, pX, pY, signature.Signature,
+		signature.CommitmentPublicAddress)
+}
+
+func TestDSSSignature(t *testing.T) {
+	dsss := make([]*DSS, nbParticipants)
+	pss := make([]*PartialSig, nbParticipants)
+	for i := 0; i < nbParticipants; i++ {
+		dsss[i] = getDSS(i)
+		ps, err := dsss[i].PartialSig()
+		require.Nil(t, err)
+		require.NotNil(t, ps)
+		pss[i] = ps
+	}
+	for i, dss := range dsss {
+		for j, ps := range pss {
+			if i == j {
+				continue
+			}
+			require.Nil(t, dss.ProcessPartialSig(ps))
+		}
+	}
+	// issue and verify signature
+	dss0 := dsss[0]
+	sig, err := dss0.Signature()
+	assert.NotNil(t, sig)
+	assert.Nil(t, err)
+	assert.NoError(t, ethschnorr.Verify(longterms[0].Public(), dss0.msg, sig))
+	// Original contains this second check. Unclear why.
+	assert.NoError(t, ethschnorr.Verify(longterms[0].Public(), dss0.msg, sig))
+	if printTests {
+		printTest(t, dss0.msg, dss0.long.Commitments()[0], sig)
+	}
+}
+
+func TestPartialSig_Hash(t *testing.T) {
+	observedHashes := make(map[*big.Int]bool)
+	for i := 0; i < nbParticipants; i++ {
+		psig, err := getDSS(i).PartialSig()
+		require.NoError(t, err)
+		hash := psig.Hash()
+		require.False(t, observedHashes[hash])
+		observedHashes[hash] = true
+	}
+}
+
+func getDSS(i int) *DSS {
+	dss, err := NewDSS(DSSArgs{secret: partSec[i], participants: partPubs,
+		long: longterms[i], random: randoms[i], msg: msg, T: t})
+	if dss == nil || err != nil {
+		panic("nil dss")
+	}
+	return dss
+}
+
+func _genDistSecret() []*dkg.DistKeyShare {
+	dkgs := make([]*dkg.DistKeyGenerator, nbParticipants)
+	for i := 0; i < nbParticipants; i++ {
+		dkg, err := dkg.NewDistKeyGenerator(suite, partSec[i], partPubs, nbParticipants/2+1)
+		if err != nil {
+			panic(err)
+		}
+		dkgs[i] = dkg
+	}
+	// full secret sharing exchange
+	// 1. broadcast deals
+	resps := make([]*dkg.Response, 0, nbParticipants*nbParticipants)
+	for _, dkg := range dkgs {
+		deals, err := dkg.Deals()
+		if err != nil {
+			panic(err)
+		}
+		for i, d := range deals {
+			resp, err := dkgs[i].ProcessDeal(d)
+			if err != nil {
+				panic(err)
+			}
+			if !resp.Response.Approved {
+				panic("wrong approval")
+			}
+			resps = append(resps, resp)
+		}
+	}
+	// 2. Broadcast responses
+	for _, resp := range resps {
+		for h, dkg := range dkgs {
+			// ignore all messages from ourself
+			if resp.Response.Index == uint32(h) {
+				continue
+			}
+			j, err := dkg.ProcessResponse(resp)
+			if err != nil || j != nil {
+				panic("wrongProcessResponse")
+			}
+		}
+	}
+	// 4. Broadcast secret commitment
+	for i, dkg := range dkgs {
+		scs, err := dkg.SecretCommits()
+		if err != nil {
+			panic("wrong SecretCommits")
+		}
+		for j, dkg2 := range dkgs {
+			if i == j {
+				continue
+			}
+			cc, err := dkg2.ProcessSecretCommits(scs)
+			if err != nil || cc != nil {
+				panic("wrong ProcessSecretCommits")
+			}
+		}
+	}
+
+	// 5. reveal shares
+	dkss := make([]*dkg.DistKeyShare, len(dkgs))
+	for i, dkg := range dkgs {
+		dks, err := dkg.DistKeyShare()
+		if err != nil {
+			panic(err)
+		}
+		dkss[i] = dks
+	}
+	return dkss
+
+}
+
+func genDistSecret(checkValidPublicKey bool) []*dkg.DistKeyShare {
+	rv := _genDistSecret()
+	if checkValidPublicKey {
+		// Because of the trick we're using to verify the signatures on-chain, we
+		// need to make sure that the  ordinate of this distributed public key is
+		// in the lower half of {0,...,}
+		for !secp256k1.ValidPublicKey(rv[0].Public()) {
+			rv = _genDistSecret() // Keep trying until valid distributed public key.
+		}
+	}
+	return rv
+}
+
+func randomBytes(n int) []byte {
+	var buff = make([]byte, n)
+	_, _ = rand.Read(buff[:])
+	return buff
+}

+ 154 - 0
bridge/pkg/signatures/ethschnorr/ethschnorr.go

@@ -0,0 +1,154 @@
+// Package ethschnorr implements a version of the Schnorr signature which is
+////////////////////////////////////////////////////////////////////////////////
+//       XXX: Do not use in production until this code has been audited.
+////////////////////////////////////////////////////////////////////////////////
+// cheap to verify on-chain.
+//
+// See https://en.wikipedia.org/wiki/Schnorr_signature For vanilla Schnorr.
+//
+// Since we are targeting ethereum specifically, there is no need to abstract
+// away the group operations, as original kyber Schnorr code does. Thus, these
+// functions only work with secp256k1 objects, even though they are expressed in
+// terms of the abstract kyber Group interfaces.
+//
+// This code is largely based on EPFL-DEDIS's go.dedis.ch/kyber/sign/schnorr
+package ethschnorr
+
+import (
+	"bytes"
+	"fmt"
+	"go.dedis.ch/kyber/v3"
+	"math/big"
+
+	"github.com/certusone/wormhole/bridge/pkg/signatures/secp256k1"
+)
+
+var secp256k1Suite = secp256k1.NewBlakeKeccackSecp256k1()
+var secp256k1Group kyber.Group = secp256k1Suite
+
+type signature = struct {
+	CommitmentPublicAddress [20]byte
+	R                       string
+	Signature               *big.Int
+}
+
+// Signature is a representation of the Schnorr signature generated and verified
+// by this library.
+type Signature = *signature
+
+func i() *big.Int { return big.NewInt(0) }
+
+var one = big.NewInt(1)
+var u256Cardinality = i().Lsh(one, 256)
+var maxUint256 = i().Sub(u256Cardinality, one)
+
+// NewSignature allocates space for a Signature, and returns it
+func NewSignature() Signature { return &signature{Signature: i()} }
+
+var zero = i()
+
+// ValidSignature(s) is true iff s.Signature represents an element of secp256k1
+func ValidSignature(s Signature) bool {
+	return s.Signature.Cmp(secp256k1.GroupOrder) == -1 &&
+		s.Signature.Cmp(zero) != -1
+}
+
+// ChallengeHash returns the value the signer must use to demonstrate knowledge
+// of the secret key
+//
+// NB: for parity with the on-chain hash, it's important that public and r
+// marshall to the big-endian x ordinate, followed by a byte which is 0 if the y
+// ordinate is even, 1 if it's odd. See evm/contracts/SchnorrSECP256K1.sol and
+// evm/test/schnorr_test.js
+func ChallengeHash(public kyber.Point, rAddress [20]byte, msg *big.Int) (
+	kyber.Scalar, error) {
+	var err error
+	h := secp256k1Suite.Hash()
+	if _, herr := public.MarshalTo(h); herr != nil {
+		err = fmt.Errorf("failed to hash public key for signature: %s", herr)
+	}
+	if err != nil && (msg.BitLen() > 256 || msg.Cmp(zero) == -1) {
+		err = fmt.Errorf("msg must be a uint256")
+	}
+	if err == nil {
+		if _, herr := h.Write(msg.Bytes()); herr != nil {
+			err = fmt.Errorf("failed to hash message for signature: %s", herr)
+		}
+	}
+	if err == nil {
+		if _, herr := h.Write(rAddress[:]); herr != nil {
+			err = fmt.Errorf("failed to hash r for signature: %s", herr)
+		}
+	}
+	if err != nil {
+		return nil, err
+	}
+	return secp256k1Suite.Scalar().SetBytes(h.Sum(nil)), nil
+}
+
+// Sign creates a signature from a msg and a private key. Verify with the
+// function Verify, or on-chain with SchnorrSECP256K1.sol.
+func Sign(private kyber.Scalar, msg *big.Int) (Signature, error) {
+	if !secp256k1.IsSecp256k1Scalar(private) {
+		return nil, fmt.Errorf("private key is not a secp256k1 scalar")
+	}
+	// create random secret and public commitment to it
+	commitmentSecretKey := secp256k1Group.Scalar().Pick(
+		secp256k1Suite.RandomStream())
+	commitmentPublicKey := secp256k1Group.Point().Mul(commitmentSecretKey, nil)
+	commitmentPublicAddress := secp256k1.EthereumAddress(commitmentPublicKey)
+
+	public := secp256k1Group.Point().Mul(private, nil)
+	challenge, err := ChallengeHash(public, commitmentPublicAddress, msg)
+	if err != nil {
+		return nil, err
+	}
+	// commitmentSecretKey-private*challenge
+	s := secp256k1Group.Scalar().Sub(commitmentSecretKey,
+		secp256k1Group.Scalar().Mul(private, challenge))
+	rv := signature{commitmentPublicAddress, commitmentPublicKey.String(), secp256k1.ToInt(s)}
+	return &rv, nil
+}
+
+// Verify verifies the given Schnorr signature. It returns true iff the
+// signature is valid.
+func Verify(public kyber.Point, msg *big.Int, s Signature) error {
+	var err error
+	if !ValidSignature(s) {
+		err = fmt.Errorf("s is not a valid signature")
+	}
+	if err == nil && !secp256k1.IsSecp256k1Point(public) {
+		err = fmt.Errorf("public key is not a secp256k1 point")
+	}
+	if err == nil && !secp256k1.ValidPublicKey(public) {
+		err = fmt.Errorf("`public` is not a valid public key")
+	}
+	if err == nil && (msg.Cmp(zero) == -1 || msg.Cmp(maxUint256) == 1) {
+		err = fmt.Errorf("msg is not a uint256")
+	}
+	var challenge kyber.Scalar
+	var herr error
+	if err == nil {
+		challenge, herr = ChallengeHash(public, s.CommitmentPublicAddress, msg)
+		if herr != nil {
+			err = herr
+		}
+		println("hash", challenge.String())
+	}
+	if err != nil {
+		return err
+	}
+	sigScalar := secp256k1.IntToScalar(s.Signature)
+	// s*g + challenge*public = s*g + challenge*(secretKey*g) =
+	// commitmentSecretKey*g = commitmentPublicKey
+	maybeCommitmentPublicKey := secp256k1Group.Point().Add(
+		secp256k1Group.Point().Mul(sigScalar, nil),
+		secp256k1Group.Point().Mul(challenge, public))
+	println("commpoint", maybeCommitmentPublicKey.String())
+	maybeCommitmentPublicAddress := secp256k1.EthereumAddress(maybeCommitmentPublicKey)
+	if !bytes.Equal(s.CommitmentPublicAddress[:],
+		maybeCommitmentPublicAddress[:]) {
+		return fmt.Errorf("signature mismatch")
+	}
+	return nil
+}

+ 119 - 0
bridge/pkg/signatures/ethschnorr/ethschnorr_test.go

@@ -0,0 +1,119 @@
+package ethschnorr
+
+// This code is largely based on go.dedis.ch/kyber/sign/schnorr_test from
+// EPFL's DEDIS
+
+import (
+	crand "crypto/rand"
+	"encoding/hex"
+	"fmt"
+	"math/big"
+	mrand "math/rand"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"go.dedis.ch/kyber/v3"
+	"go.dedis.ch/kyber/v3/group/curve25519"
+
+	"github.com/certusone/wormhole/bridge/pkg/signatures/cryptotest"
+	"github.com/certusone/wormhole/bridge/pkg/signatures/secp256k1"
+)
+
+var numSignatures = 5
+
+var randomStream = cryptotest.NewStream(&testing.T{}, 0)
+
+var printTests = false
+
+func printTest(t *testing.T, msg *big.Int, private kyber.Scalar,
+	public kyber.Point, signature Signature) {
+	privateBytes, err := private.MarshalBinary()
+	require.Nil(t, err)
+	pX, pY := secp256k1.Coordinates(public)
+	fmt.Printf("  ['%064x',\n   '%064x',\n   '%064x',\n   '%064x',\n   "+
+		"'%064x',\n   '%040x'],\n",
+		msg, privateBytes, pX, pY, signature.Signature,
+		signature.CommitmentPublicAddress)
+}
+
+func TestShortSchnorr_SignAndVerify(t *testing.T) {
+	if printTests {
+		fmt.Printf("tests = [\n")
+	}
+	for i := 0; i < numSignatures; i++ {
+		rand := mrand.New(mrand.NewSource(2))
+		msg, err := crand.Int(rand, maxUint256)
+		require.NoError(t, err)
+		kp := secp256k1.Generate(randomStream)
+		sig, err := Sign(kp.Private, msg)
+		require.NoError(t, err, "failed to sign message")
+		println("msg", hex.EncodeToString(msg.Bytes()))
+		println("sig", hex.EncodeToString(sig.Signature.Bytes()))
+		println("addr", hex.EncodeToString(sig.CommitmentPublicAddress[:]))
+		println("pub", kp.Public.String())
+		require.NoError(t, Verify(kp.Public, msg, sig),
+			"failed to validate own signature")
+		require.Error(t, Verify(kp.Public, u256Cardinality, sig),
+			"failed to abort on too large a message")
+		require.Error(t, Verify(kp.Public, big.NewInt(0).Neg(big.NewInt(1)), sig),
+			"failed to abort on negative message")
+		if printTests {
+			printTest(t, msg, kp.Private, kp.Public, sig)
+		}
+		wrongMsg := big.NewInt(0).Add(msg, big.NewInt(1))
+		require.Error(t, Verify(kp.Public, wrongMsg, sig),
+			"failed to reject signature with bad message")
+		wrongPublic := secp256k1Group.Point().Add(kp.Public, kp.Public)
+		require.Error(t, Verify(wrongPublic, msg, sig),
+			"failed to reject signature with bad public key")
+		wrongSignature := &signature{
+			CommitmentPublicAddress: sig.CommitmentPublicAddress,
+			Signature:               big.NewInt(0).Add(sig.Signature, one),
+		}
+		require.Error(t, Verify(kp.Public, msg, wrongSignature),
+			"failed to reject bad signature")
+		badPublicCommitmentAddress := &signature{Signature: sig.Signature}
+		copy(badPublicCommitmentAddress.CommitmentPublicAddress[:],
+			sig.CommitmentPublicAddress[:])
+		badPublicCommitmentAddress.CommitmentPublicAddress[0] ^= 1 // Corrupt it
+		require.Error(t, Verify(kp.Public, msg, badPublicCommitmentAddress),
+			"failed to reject signature with bad public commitment")
+	}
+	if printTests {
+		fmt.Println("]")
+	}
+	// Check other validations
+	edSuite := curve25519.NewBlakeSHA256Curve25519(false)
+	badScalar := edSuite.Scalar()
+	_, err := Sign(badScalar, i())
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "not a secp256k1 scalar")
+	err = Verify(edSuite.Point(), i(), NewSignature())
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "not a secp256k1 point")
+	err = Verify(secp256k1Suite.Point(), i(), &signature{Signature: big.NewInt(-1)})
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "not a valid signature")
+	err = Verify(secp256k1Suite.Point(), i(), &signature{Signature: u256Cardinality})
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "not a valid signature")
+}
+
+func TestShortSchnorr_NewSignature(t *testing.T) {
+	s := NewSignature()
+	require.Equal(t, s.Signature, big.NewInt(0))
+}
+
+func TestShortSchnorr_ChallengeHash(t *testing.T) {
+	point := secp256k1Group.Point()
+	var hash [20]byte
+	h, err := ChallengeHash(point, hash, big.NewInt(-1))
+	require.Nil(t, h)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "msg must be a uint256")
+	h, err = ChallengeHash(point, hash, u256Cardinality)
+	require.Nil(t, h)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "msg must be a uint256")
+}

+ 44 - 0
bridge/pkg/signatures/secp256k1/curve.go

@@ -0,0 +1,44 @@
+// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar}
+////////////////////////////////////////////////////////////////////////////////
+//       XXX: Do not use in production until this code has been audited.
+////////////////////////////////////////////////////////////////////////////////
+// interfaces, based on btcd/btcec and kyber/group/mod
+//
+// XXX: NOT CONSTANT TIME!
+package secp256k1
+
+import (
+	"math/big"
+
+	secp256k1BTCD "github.com/btcsuite/btcd/btcec"
+
+	"go.dedis.ch/kyber/v3"
+)
+
+// Secp256k1 represents the secp256k1 group.
+// There are no parameters and no initialization is required
+// because it supports only this one specific curve.
+type Secp256k1 struct{}
+
+// s256 is the btcec representation of secp256k1.
+var s256 *secp256k1BTCD.KoblitzCurve = secp256k1BTCD.S256()
+
+// String returns the name of the curve
+func (*Secp256k1) String() string { return "Secp256k1" }
+
+var egScalar kyber.Scalar = newScalar(big.NewInt(0))
+var egPoint kyber.Point = &Secp256k1Point{newFieldZero(), newFieldZero()}
+
+// ScalarLen returns the length of a marshalled Scalar
+func (*Secp256k1) ScalarLen() int { return egScalar.MarshalSize() }
+
+// Scalar creates a new Scalar for the prime-order group on the secp256k1 curve
+func (*Secp256k1) Scalar() kyber.Scalar { return newScalar(big.NewInt(0)) }
+
+// PointLen returns the length of a marshalled Point
+func (*Secp256k1) PointLen() int { return egPoint.MarshalSize() }
+
+// Point returns a new secp256k1 point
+func (*Secp256k1) Point() kyber.Point {
+	return &Secp256k1Point{newFieldZero(), newFieldZero()}
+}

+ 20 - 0
bridge/pkg/signatures/secp256k1/curve_test.go

@@ -0,0 +1,20 @@
+package secp256k1
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+var group = &Secp256k1{}
+
+func TestSecp256k1_String(t *testing.T) {
+	require.Equal(t, group.String(), "Secp256k1")
+}
+
+func TestSecp256k1_Constructors(t *testing.T) {
+	require.Equal(t, group.ScalarLen(), 32)
+	require.Equal(t, ToInt(group.Scalar()), bigZero)
+	require.Equal(t, group.PointLen(), 33)
+	require.Equal(t, group.Point(), &Secp256k1Point{fieldZero, fieldZero})
+}

+ 169 - 0
bridge/pkg/signatures/secp256k1/field.go

@@ -0,0 +1,169 @@
+// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar}
+////////////////////////////////////////////////////////////////////////////////
+//       XXX: Do not use in production until this code has been audited.
+////////////////////////////////////////////////////////////////////////////////
+// interfaces, based on btcd/btcec and kyber/group/mod
+//
+// XXX: NOT CONSTANT TIME!
+package secp256k1
+
+// Arithmetic operations in the base field of secp256k1, i.e. ℤ/qℤ, where q is
+// the base field characteristic.
+
+import (
+	"crypto/cipher"
+	"fmt"
+	"math/big"
+
+	"go.dedis.ch/kyber/v3/util/random"
+)
+
+// q is the field characteristic (cardinality) of the secp256k1 base field. All
+// arithmetic operations on the field are modulo this.
+var q = s256.P
+
+type fieldElt big.Int
+
+// newFieldZero returns a newly allocated field element.
+func newFieldZero() *fieldElt { return (*fieldElt)(big.NewInt(0)) }
+
+// Int returns f as a big.Int
+func (f *fieldElt) int() *big.Int { return (*big.Int)(f) }
+
+// modQ reduces f's underlying big.Int modulo q, and returns it
+func (f *fieldElt) modQ() *fieldElt {
+	if f.int().Cmp(q) != -1 || f.int().Cmp(bigZero) == -1 {
+		// f ∉ {0, ..., q-1}. Find the representative of f+qℤ in that set.
+		//
+		// Per Mod docstring, "Mod implements Euclidean modulus", meaning that after
+		// this, f will be the smallest non-negative representative of its
+		// equivalence class in ℤ/qℤ. TODO(alx): Make this faster
+		f.int().Mod(f.int(), q)
+	}
+	return f
+}
+
+// This differs from SetInt below, in that it does not take a copy of v.
+func fieldEltFromBigInt(v *big.Int) *fieldElt { return (*fieldElt)(v).modQ() }
+
+func fieldEltFromInt(v int64) *fieldElt {
+	return fieldEltFromBigInt(big.NewInt(int64(v))).modQ()
+}
+
+var fieldZero = fieldEltFromInt(0)
+var bigZero = big.NewInt(0)
+
+// String returns the string representation of f
+func (f *fieldElt) String() string {
+	return fmt.Sprintf("fieldElt{%x}", f.int())
+}
+
+// Equal returns true iff f=g, i.e. the backing big.Ints satisfy f ≡ g mod q
+func (f *fieldElt) Equal(g *fieldElt) bool {
+	if f == (*fieldElt)(nil) && g == (*fieldElt)(nil) {
+		return true
+	}
+	if f == (*fieldElt)(nil) { // f is nil, g is not
+		return false
+	}
+	if g == (*fieldElt)(nil) { // g is nil, f is not
+		return false
+	}
+	return bigZero.Cmp(newFieldZero().Sub(f, g).modQ().int()) == 0
+}
+
+// Add sets f to the sum of a and b modulo q, and returns it.
+func (f *fieldElt) Add(a, b *fieldElt) *fieldElt {
+	f.int().Add(a.int(), b.int())
+	return f.modQ()
+}
+
+// Sub sets f to a-b mod q, and returns it.
+func (f *fieldElt) Sub(a, b *fieldElt) *fieldElt {
+	f.int().Sub(a.int(), b.int())
+	return f.modQ()
+}
+
+// Set sets f's value to v, and returns f.
+func (f *fieldElt) Set(v *fieldElt) *fieldElt {
+	f.int().Set(v.int())
+	return f.modQ()
+}
+
+// SetInt sets f's value to v mod q, and returns f.
+func (f *fieldElt) SetInt(v *big.Int) *fieldElt {
+	f.int().Set(v)
+	return f.modQ()
+}
+
+// Pick samples uniformly from {0, ..., q-1}, assigns sample to f, and returns f
+func (f *fieldElt) Pick(rand cipher.Stream) *fieldElt {
+	return f.SetInt(random.Int(q, rand)) // random.Int safe because q≅2²⁵⁶, q<2²⁵⁶
+}
+
+// Neg sets f to the negation of g modulo q, and returns it
+func (f *fieldElt) Neg(g *fieldElt) *fieldElt {
+	f.int().Neg(g.int())
+	return f.modQ()
+}
+
+// Clone returns a new fieldElt, backed by a clone of f
+func (f *fieldElt) Clone() *fieldElt { return newFieldZero().Set(f.modQ()) }
+
+// SetBytes sets f to the 32-byte big-endian value represented by buf, reduces
+// it, and returns it.
+func (f *fieldElt) SetBytes(buf [32]byte) *fieldElt {
+	f.int().SetBytes(buf[:])
+	return f.modQ()
+}
+
+// Bytes returns the 32-byte big-endian representation of f
+func (f *fieldElt) Bytes() [32]byte {
+	bytes := f.modQ().int().Bytes()
+	if len(bytes) > 32 {
+		panic("field element longer than 256 bits")
+	}
+	var rv [32]byte
+	copy(rv[32-len(bytes):], bytes) // leftpad w zeros
+	return rv
+}
+
+var two = big.NewInt(2)
+
+// square returns y² mod q
+func fieldSquare(y *fieldElt) *fieldElt {
+	return fieldEltFromBigInt(newFieldZero().int().Exp(y.int(), two, q))
+}
+
+// sqrtPower is s.t. n^sqrtPower≡sqrt(n) mod q, if n has a root at all. See
+// https://math.stackexchange.com/a/1816280, for instance
+//
+// What I'm calling sqrtPower is called q on the s256 struct. (See
+// btcec.initS256), which is confusing because the "Q" in "QPlus1Div4" refers to
+// the field characteristic
+var sqrtPower = s256.QPlus1Div4()
+
+// maybeSqrtInField returns a square root of v, if it has any, else nil
+func maybeSqrtInField(v *fieldElt) *fieldElt {
+	s := newFieldZero()
+	s.int().Exp(v.int(), sqrtPower, q)
+	if !fieldSquare(s).Equal(v) {
+		return nil
+	}
+	return s
+}
+
+var three = big.NewInt(3)
+var seven = fieldEltFromInt(7)
+
+// rightHandSide returns the RHS of the secp256k1 equation, x³+7 mod q, given x
+func rightHandSide(x *fieldElt) *fieldElt {
+	xCubed := newFieldZero()
+	xCubed.int().Exp(x.int(), three, q)
+	return xCubed.Add(xCubed, seven)
+}
+
+// isEven returns true if f is even, false otherwise
+func (f *fieldElt) isEven() bool {
+	return big.NewInt(0).Mod(f.int(), two).Cmp(big.NewInt(0)) == 0
+}

+ 159 - 0
bridge/pkg/signatures/secp256k1/field_test.go

@@ -0,0 +1,159 @@
+package secp256k1
+
+import (
+	"encoding/hex"
+	"math/big"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/certusone/wormhole/bridge/pkg/signatures/cryptotest"
+)
+
+var numFieldSamples = 10
+
+var observedFieldElts map[string]bool
+
+func init() {
+	observedFieldElts = make(map[string]bool)
+}
+
+// observedFieldElt ensures that novel scalars are being picked.
+func observedFieldElt(t *testing.T, s *fieldElt) {
+	elt := s.Bytes()
+	data := hex.Dump(elt[:])
+	require.False(t, observedFieldElts[data])
+	observedFieldElts[data] = true
+}
+
+var randomStream = cryptotest.NewStream(&testing.T{}, 0)
+
+func TestField_SetIntAndEqual(t *testing.T) {
+	tests := []int64{5, 67108864, 67108865, 4294967295}
+	g := newFieldZero()
+	for _, test := range tests {
+		f := fieldEltFromInt(test)
+		i := big.NewInt(test)
+		g.SetInt(i)
+		assert.Equal(t, f, g,
+			"different values obtained for same input, using "+
+				"SetInt vs fieldEltFromInt")
+		i.Add(i, big.NewInt(1))
+		assert.Equal(t, f, g,
+			"SetInt should take a copy of the backing big.Int")
+	}
+}
+
+func TestField_String(t *testing.T) {
+	require.Equal(t, fieldZero.String(), "fieldElt{0}")
+}
+
+func TestField_Equal(t *testing.T) {
+	require.True(t, (*fieldElt)(nil).Equal((*fieldElt)(nil)))
+	require.False(t, (*fieldElt)(nil).Equal(fieldZero))
+	require.False(t, fieldZero.Equal((*fieldElt)(nil)))
+}
+
+func TestField_Set(t *testing.T) {
+	f := fieldEltFromInt(1)
+	g := newFieldZero()
+	g.Set(f)
+	g.Add(g, fieldEltFromInt(1))
+	assert.Equal(t, f, fieldEltFromInt(1),
+		"Set takes a copy of the backing big.Int")
+}
+
+func TestFieldEltFromInt(t *testing.T) {
+	assert.Equal(t, fieldEltFromInt(1), // Also tests fieldElt.modQ
+		fieldEltFromBigInt(new(big.Int).Add(q, big.NewInt(1))),
+		"only one representation of a ℤ/qℤ element should be used")
+}
+
+func TestField_SmokeTestPick(t *testing.T) {
+	f := newFieldZero()
+	f.Pick(randomStream)
+	observedFieldElt(t, f)
+	assert.True(t, f.int().Cmp(big.NewInt(1000000000)) == 1,
+		"should be greater than 1000000000, with very high probability")
+}
+
+func TestField_Neg(t *testing.T) {
+	f := newFieldZero()
+	for i := 0; i < numFieldSamples; i++ {
+		f.Pick(randomStream)
+		observedFieldElt(t, f)
+		g := f.Clone()
+		g.Neg(g)
+		require.True(t, g.Add(f, g).Equal(fieldZero),
+			"adding something to its negative should give zero: "+
+				"failed with %s", f)
+	}
+}
+
+func TestField_Sub(t *testing.T) {
+	f := newFieldZero()
+	for i := 0; i < numFieldSamples; i++ {
+		f.Pick(randomStream)
+		observedFieldElt(t, f)
+		require.True(t, f.Sub(f, f).Equal(fieldZero),
+			"subtracting something from itself should give zero: "+
+				"failed with %s", f)
+	}
+}
+
+func TestField_Clone(t *testing.T) {
+	f := fieldEltFromInt(1)
+	g := f.Clone()
+	h := f.Clone()
+	assert.Equal(t, f, g, "clone output does not equal original")
+	g.Add(f, f)
+	assert.Equal(t, f, h, "clone does not make a copy")
+
+}
+
+func TestField_SetBytesAndBytes(t *testing.T) {
+	f := newFieldZero()
+	g := newFieldZero()
+	for i := 0; i < numFieldSamples; i++ {
+		f.Pick(randomStream)
+		observedFieldElt(t, f)
+		g.SetBytes(f.Bytes())
+		require.True(t, g.Equal(f),
+			"roundtrip through serialization should give same "+
+				"result back: failed with %s", f)
+	}
+}
+
+func TestField_MaybeSquareRootInField(t *testing.T) {
+	f := newFieldZero()
+	minusOne := fieldEltFromInt(-1)
+	assert.Nil(t, maybeSqrtInField(minusOne), "-1 is not a square, in this field")
+	for i := 0; i < numFieldSamples; i++ {
+		f.Pick(randomStream)
+		observedFieldElt(t, f)
+		require.True(t, f.int().Cmp(q) == -1, "picked larger value than q: %s", f)
+		require.True(t, f.int().Cmp(big.NewInt(-1)) != -1,
+			"backing int must be non-negative")
+		s := fieldSquare(f)
+		g := maybeSqrtInField(s)
+		require.NotEqual(t, g, (*fieldElt)(nil))
+		ng := newFieldZero().Neg(g)
+		require.True(t, f.Equal(g) || f.Equal(ng), "squaring something and "+
+			"taking the square root should give ± the original: failed with %s", f)
+		bigIntSqrt := newFieldZero() // Cross-check against big.ModSqrt
+		rv := bigIntSqrt.int().ModSqrt(s.int(), q)
+		require.NotNil(t, rv)
+		require.True(t, bigIntSqrt.Equal(g) || bigIntSqrt.Equal(ng))
+		nonSquare := newFieldZero().Neg(s)
+		rv = bigIntSqrt.int().ModSqrt(nonSquare.int(), q)
+		require.Nil(t, rv, "ModSqrt indicates nonSquare is square")
+		require.Nil(t, maybeSqrtInField(nonSquare), "the negative of square "+
+			"should not be a square")
+	}
+}
+
+func TestField_RightHandSide(t *testing.T) {
+	assert.Equal(t, rightHandSide(fieldEltFromInt(1)), fieldEltFromInt(8))
+	assert.Equal(t, rightHandSide(fieldEltFromInt(2)), fieldEltFromInt(15))
+}

+ 379 - 0
bridge/pkg/signatures/secp256k1/point.go

@@ -0,0 +1,379 @@
+// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar}
+////////////////////////////////////////////////////////////////////////////////
+//       XXX: Do not use in production until this code has been audited.
+////////////////////////////////////////////////////////////////////////////////
+// interfaces, based on btcd/btcec and kyber/group/mod
+//
+// XXX: NOT CONSTANT TIME!
+package secp256k1
+
+// Implementation of kyber.Point interface for elliptic-curve arithmetic
+// operations on secpk256k1.
+//
+// This is mostly a wrapper of the functionality provided by btcec
+
+import (
+	"crypto/cipher"
+	"fmt"
+	"io"
+	"math/big"
+
+	"go.dedis.ch/kyber/v3"
+	"go.dedis.ch/kyber/v3/util/key"
+	"golang.org/x/crypto/sha3"
+)
+
+// btcec's public interface uses this affine representation for points on the
+// curve. This does not naturally accommodate the point at infinity. btcec
+// represents it as (0, 0), which is not a point on {y²=x³+7}.
+type Secp256k1Point struct {
+	X *fieldElt
+	Y *fieldElt
+}
+
+func NewPoint() *Secp256k1Point {
+	return &Secp256k1Point{newFieldZero(), newFieldZero()}
+}
+
+// String returns a string representation of P
+func (P *Secp256k1Point) String() string {
+	return fmt.Sprintf("Secp256k1{X: %s, Y: %s}", P.X, P.Y)
+}
+
+// Equal returns true if p and pPrime represent the same point, false otherwise.
+func (P *Secp256k1Point) Equal(pPrime kyber.Point) bool {
+	return P.X.Equal(pPrime.(*Secp256k1Point).X) &&
+		P.Y.Equal(pPrime.(*Secp256k1Point).Y)
+}
+
+// Null sets p to the group-identity value, and returns it.
+func (P *Secp256k1Point) Null() kyber.Point {
+	P.X = fieldEltFromInt(0) // btcec representation of null point is (0,0)
+	P.Y = fieldEltFromInt(0)
+	return P
+}
+
+// Base sets p to a copy of the standard group generator, and returns it.
+func (P *Secp256k1Point) Base() kyber.Point {
+	P.X.SetInt(s256.Gx)
+	P.Y.SetInt(s256.Gy)
+	return P
+}
+
+// Pick sets P to a random point sampled from rand, and returns it.
+func (P *Secp256k1Point) Pick(rand cipher.Stream) kyber.Point {
+	for { // Keep trying X's until one fits the curve (~50% probability of
+		// success each iteration
+		P.X.Set(newFieldZero().Pick(rand))
+		maybeRHS := rightHandSide(P.X)
+		if maybeY := maybeSqrtInField(maybeRHS); maybeY != (*fieldElt)(nil) {
+			P.Y.Set(maybeY)
+			// Take the negative with 50% probability
+			b := make([]byte, 1)
+			rand.XORKeyStream(b[:], b[:])
+			if b[0]&1 == 0 {
+				P.Y.Neg(P.Y)
+			}
+			return P
+		}
+	}
+}
+
+// Set sets P to copies of pPrime's values, and returns it.
+func (P *Secp256k1Point) Set(pPrime kyber.Point) kyber.Point {
+	P.X.Set(pPrime.(*Secp256k1Point).X)
+	P.Y.Set(pPrime.(*Secp256k1Point).Y)
+	return P
+}
+
+// Clone returns a copy of P.
+func (P *Secp256k1Point) Clone() kyber.Point {
+	return &Secp256k1Point{X: P.X.Clone(), Y: P.Y.Clone()}
+}
+
+// EmbedLen returns the number of bytes of data which can be embedded in a point.
+func (*Secp256k1Point) EmbedLen() int {
+	// Reserve the most-significant 8 bits for pseudo-randomness.
+	// Reserve the least-significant 8 bits for embedded data length.
+	return (255 - 8 - 8) / 8
+}
+
+// Embed encodes a limited amount of specified data in the Point, using r as a
+// source of cryptographically secure random data. Implementations only embed
+// the first EmbedLen bytes of the given data.
+func (P *Secp256k1Point) Embed(data []byte, r cipher.Stream) kyber.Point {
+	numEmbedBytes := P.EmbedLen()
+	if len(data) > numEmbedBytes {
+		panic("too much data to embed in a point")
+	}
+	numEmbedBytes = len(data)
+	var x [32]byte
+	randStart := 1 // First byte to fill with random data
+	if data != nil {
+		x[0] = byte(numEmbedBytes)       // Encode length in low 8 bits
+		copy(x[1:1+numEmbedBytes], data) // Copy in data to embed
+		randStart = 1 + numEmbedBytes
+	}
+	maxAttempts := 10000
+	// Try random x ordinates satisfying the constraints, until one provides
+	// a point on secp256k1
+	for numAttempts := 0; numAttempts < maxAttempts; numAttempts++ {
+		// Fill the rest of the x ordinate with random data
+		r.XORKeyStream(x[randStart:], x[randStart:])
+		xOrdinate := newFieldZero().SetBytes(x)
+		// RHS of secp256k1 equation is x³+7 mod p. Success if square.
+		// We optimistically don't use btcec.IsOnCurve, here, because we
+		// hope to assign the intermediate result maybeY to P.Y
+		secp256k1RHS := rightHandSide(xOrdinate)
+		if maybeY := maybeSqrtInField(secp256k1RHS); maybeY != (*fieldElt)(nil) {
+			P.X = xOrdinate // success: found (x,y) s.t. y²=x³+7
+			P.Y = maybeY
+			return P
+		}
+	}
+	// Probability 2^{-maxAttempts}, under correct operation.
+	panic("failed to find point satisfying all constraints")
+}
+
+// Data returns data embedded in P, or an error if inconsistent with encoding
+func (P *Secp256k1Point) Data() ([]byte, error) {
+	b := P.X.Bytes()
+	dataLength := int(b[0])
+	if dataLength > P.EmbedLen() {
+		return nil, fmt.Errorf("point specifies too much data")
+	}
+	return b[1 : dataLength+1], nil
+}
+
+// Add sets P to a+b (secp256k1 group operation) and returns it.
+func (P *Secp256k1Point) Add(a, b kyber.Point) kyber.Point {
+	X, Y := s256.Add(
+		a.(*Secp256k1Point).X.int(), a.(*Secp256k1Point).Y.int(),
+		b.(*Secp256k1Point).X.int(), b.(*Secp256k1Point).Y.int())
+	P.X.SetInt(X)
+	P.Y.SetInt(Y)
+	return P
+}
+
+// Add sets P to a-b (secp256k1 group operation), and returns it.
+func (P *Secp256k1Point) Sub(a, b kyber.Point) kyber.Point {
+	X, Y := s256.Add(
+		a.(*Secp256k1Point).X.int(), a.(*Secp256k1Point).Y.int(),
+		b.(*Secp256k1Point).X.int(),
+		newFieldZero().Neg(b.(*Secp256k1Point).Y).int()) // -b_y
+	P.X.SetInt(X)
+	P.Y.SetInt(Y)
+	return P
+}
+
+// Neg sets P to -a (in the secp256k1 group), and returns it.
+func (P *Secp256k1Point) Neg(a kyber.Point) kyber.Point {
+	P.X = a.(*Secp256k1Point).X.Clone()
+	P.Y = newFieldZero().Neg(a.(*Secp256k1Point).Y)
+	return P
+}
+
+// Mul sets P to s*a (in the secp256k1 group, i.e. adding a to itself s times),
+// and returns it. If a is nil, it is replaced by the secp256k1 generator.
+func (P *Secp256k1Point) Mul(s kyber.Scalar, a kyber.Point) kyber.Point {
+	sBytes, err := s.(*secp256k1Scalar).MarshalBinary()
+	if err != nil {
+		panic(fmt.Errorf("failure while marshaling multiplier: %s",
+			err))
+	}
+	var X, Y *big.Int
+	if a == (*Secp256k1Point)(nil) || a == nil {
+		X, Y = s256.ScalarBaseMult(sBytes)
+	} else {
+		X, Y = s256.ScalarMult(a.(*Secp256k1Point).X.int(),
+			a.(*Secp256k1Point).Y.int(), sBytes)
+	}
+	P.X.SetInt(X)
+	P.Y.SetInt(Y)
+	return P
+}
+
+// MarshalBinary returns the concatenated big-endian representation of the X
+// ordinate and a byte which is 0 if Y is even, 1 if it's odd. Or it returns an
+// error on failure.
+func (P *Secp256k1Point) MarshalBinary() ([]byte, error) {
+	maybeSqrt := maybeSqrtInField(rightHandSide(P.X))
+	if maybeSqrt == (*fieldElt)(nil) {
+		return nil, fmt.Errorf("x³+7 not a square")
+	}
+	minusMaybeSqrt := newFieldZero().Neg(maybeSqrt)
+	if !P.Y.Equal(maybeSqrt) && !P.Y.Equal(minusMaybeSqrt) {
+		return nil, fmt.Errorf(
+			"y ≠ ±maybeSqrt(x³+7), so not a point on the curve")
+	}
+	rv := make([]byte, P.MarshalSize())
+	signByte := P.MarshalSize() - 1 // Last byte contains sign of Y.
+	xordinate := P.X.Bytes()
+	copyLen := copy(rv[:signByte], xordinate[:])
+	if copyLen != P.MarshalSize()-1 {
+		return []byte{}, fmt.Errorf("marshal of x ordinate too short")
+	}
+	if P.Y.isEven() {
+		rv[signByte] = 0
+	} else {
+		rv[signByte] = 1
+	}
+	return rv, nil
+}
+
+// MarshalSize returns the length of the byte representation of P
+func (P *Secp256k1Point) MarshalSize() int { return 33 }
+
+// MarshalID returns the ID for a secp256k1 point
+func (P *Secp256k1Point) MarshalID() [8]byte {
+	return [8]byte{'s', 'p', '2', '5', '6', '.', 'p', 'o'}
+}
+
+// UnmarshalBinary sets P to the point represented by contents of buf, or
+// returns an non-nil error
+func (P *Secp256k1Point) UnmarshalBinary(buf []byte) error {
+	var err error
+	if len(buf) != P.MarshalSize() {
+		err = fmt.Errorf("wrong length for marshaled point")
+	}
+	if err == nil && !(buf[32] == 0 || buf[32] == 1) {
+		err = fmt.Errorf("bad sign byte (the last one)")
+	}
+	if err != nil {
+		return err
+	}
+	var xordinate [32]byte
+	copy(xordinate[:], buf[:32])
+	P.X = newFieldZero().SetBytes(xordinate)
+	secp256k1RHS := rightHandSide(P.X)
+	maybeY := maybeSqrtInField(secp256k1RHS)
+	if maybeY == (*fieldElt)(nil) {
+		return fmt.Errorf("x ordinate does not correspond to a curve point")
+	}
+	isEven := maybeY.isEven()
+	P.Y.Set(maybeY)
+	if (buf[32] == 0 && !isEven) || (buf[32] == 1 && isEven) {
+		P.Y.Neg(P.Y)
+	} else {
+		if buf[32] != 0 && buf[32] != 1 {
+			return fmt.Errorf("parity byte must be 0 or 1")
+		}
+	}
+	return nil
+}
+
+// MarshalTo writes the serialized P to w, and returns the number of bytes
+// written, or an error on failure.
+func (P *Secp256k1Point) MarshalTo(w io.Writer) (int, error) {
+	buf, err := P.MarshalBinary()
+	if err != nil {
+		return 0, err
+	}
+	return w.Write(buf)
+}
+
+// UnmarshalFrom sets P to the secp256k1 point represented by bytes read from r,
+// and returns the number of bytes read, or an error on failure.
+func (P *Secp256k1Point) UnmarshalFrom(r io.Reader) (int, error) {
+	buf := make([]byte, P.MarshalSize())
+	n, err := io.ReadFull(r, buf)
+	if err != nil {
+		return 0, err
+	}
+	return n, P.UnmarshalBinary(buf)
+}
+
+// EthereumAddress returns the 160-bit address corresponding to p as public key.
+func EthereumAddress(p kyber.Point) (rv [20]byte) {
+	// The Ethereum address of P is the bottom 160 bits of keccak256(P.X‖P.Y),
+	// where P.X and P.Y are represented in 32 bytes as big-endian. See equations
+	// (277, 284) of Ethereum Yellow Paper version 3e36772, or go-ethereum's
+	// crypto.PubkeyToAddress.
+	h := sha3.NewLegacyKeccak256()
+	if _, err := h.Write(LongMarshal(p)); err != nil {
+		panic(err)
+	}
+	copy(rv[:], h.Sum(nil)[12:])
+	return rv
+}
+
+// IsSecp256k1Point returns true if p is a Secp256k1Point
+func IsSecp256k1Point(p kyber.Point) bool {
+	switch p.(type) {
+	case *Secp256k1Point:
+		return true
+	default:
+		return false
+	}
+}
+
+// Coordinates returns the coordinates of p
+func Coordinates(p kyber.Point) (*big.Int, *big.Int) {
+	return p.(*Secp256k1Point).X.int(), p.(*Secp256k1Point).Y.int()
+}
+
+// ValidPublicKey returns true iff p can be used in the optimized on-chain
+// Schnorr-signature verification. See SchnorrSECP256K1.sol for details.
+func ValidPublicKey(p kyber.Point) bool {
+	if p == (*Secp256k1Point)(nil) || p == nil {
+		return false
+	}
+	P, ok := p.(*Secp256k1Point)
+	if !ok {
+		return false
+	}
+	maybeY := maybeSqrtInField(rightHandSide(P.X))
+	return maybeY != nil && (P.Y.Equal(maybeY) || P.Y.Equal(maybeY.Neg(maybeY)))
+}
+
+// Generate generates a public/private key pair, which can be verified cheaply
+// on-chain
+func Generate(random cipher.Stream) *key.Pair {
+	p := key.Pair{}
+	for !ValidPublicKey(p.Public) {
+		p.Private = (&Secp256k1{}).Scalar().Pick(random)
+		p.Public = (&Secp256k1{}).Point().Mul(p.Private, nil)
+	}
+	return &p
+}
+
+// LongMarshal returns the concatenated coordinates serialized as uint256's
+func LongMarshal(p kyber.Point) []byte {
+	xMarshal := p.(*Secp256k1Point).X.Bytes()
+	yMarshal := p.(*Secp256k1Point).Y.Bytes()
+	return append(xMarshal[:], yMarshal[:]...)
+}
+
+// LongUnmarshal returns the secp256k1 point represented by m, as a concatenated
+// pair of uint256's
+func LongUnmarshal(m []byte) (kyber.Point, error) {
+	if len(m) != 64 {
+		return nil, fmt.Errorf(
+			"0x%x does not represent an uncompressed Secp256k1Point. Should be length 64, but is length %d",
+			m, len(m))
+	}
+	p := NewPoint()
+	p.X.SetInt(big.NewInt(0).SetBytes(m[:32]))
+	p.Y.SetInt(big.NewInt(0).SetBytes(m[32:]))
+	if !ValidPublicKey(p) {
+		return nil, fmt.Errorf("%s is not a valid secp256k1 point", p)
+	}
+	return p, nil
+}
+
+// ScalarToPublicPoint returns the public secp256k1 point associated to s
+func ScalarToPublicPoint(s kyber.Scalar) kyber.Point {
+	publicPoint := (&Secp256k1{}).Point()
+	return publicPoint.Mul(s, nil)
+}
+
+// SetCoordinates returns the point (x,y), or panics if an invalid Secp256k1Point
+func SetCoordinates(x, y *big.Int) kyber.Point {
+	rv := NewPoint()
+	rv.X.SetInt(x)
+	rv.Y.SetInt(y)
+	if !ValidPublicKey(rv) {
+		panic("point requested from invalid coordinates")
+	}
+	return rv
+}

+ 232 - 0
bridge/pkg/signatures/secp256k1/point_test.go

@@ -0,0 +1,232 @@
+package secp256k1
+
+import (
+	"bytes"
+	"crypto/rand"
+	"fmt"
+	"math/big"
+	"testing"
+
+	"go.dedis.ch/kyber/v3/group/curve25519"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/certusone/wormhole/bridge/pkg/signatures/cryptotest"
+)
+
+var numPointSamples = 10
+
+var randomStreamPoint = cryptotest.NewStream(&testing.T{}, 0)
+
+func TestPoint_String(t *testing.T) {
+	require.Equal(t, NewPoint().String(),
+		"Secp256k1{X: fieldElt{0}, Y: fieldElt{0}}")
+}
+
+func TestPoint_CloneAndEqual(t *testing.T) {
+	f := NewPoint()
+	for i := 0; i < numPointSamples; i++ {
+		g := f.Clone()
+		f.Pick(randomStreamPoint)
+		assert.NotEqual(t, f, g,
+			"modifying original shouldn't change clone")
+		g, h := f.Clone(), f.Clone()
+		assert.Equal(t, f, g, "clones should be equal")
+		g.Add(g, f)
+		assert.Equal(t, h, f,
+			"modifying a clone shouldn't change originial")
+	}
+}
+
+func TestPoint_NullAndAdd(t *testing.T) {
+	f, g := NewPoint(), NewPoint()
+	for i := 0; i < numPointSamples; i++ {
+		g.Null()
+		f.Pick(randomStreamPoint)
+		g.Add(f, g)
+		assert.Equal(t, f, g, "adding zero should have no effect")
+	}
+}
+
+func TestPoint_Set(t *testing.T) {
+	p := NewPoint()
+	base := NewPoint().Base()
+	assert.NotEqual(t, p, base, "generator should not be zero")
+	p.Set(base)
+	assert.Equal(t, p, base, "setting to generator should yield generator")
+}
+
+func TestPoint_Embed(t *testing.T) {
+	p := NewPoint()
+	for i := 0; i < numPointSamples; i++ {
+		data := make([]byte, p.EmbedLen())
+		_, err := rand.Read(data)
+		require.Nil(t, err)
+		p.Embed(data, randomStreamPoint)
+		require.True(t, s256.IsOnCurve(p.X.int(), p.Y.int()),
+			"should embed to a secp256k1 point")
+		output, err := p.Data()
+		require.NoError(t, err)
+		require.True(t, bytes.Equal(data, output),
+			"should get same value back after round-trip "+
+				"embedding, got %v, then %v", data, output)
+	}
+	var uint256Bytes [32]byte
+	uint256Bytes[0] = 30
+	p.X.SetBytes(uint256Bytes)
+	_, err := p.Data()
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "specifies too much data")
+	var b bytes.Buffer
+	p.Pick(randomStreamPoint)
+	_, err = p.MarshalTo(&b)
+	require.NoError(t, err)
+	_, err = p.UnmarshalFrom(&b)
+	require.NoError(t, err)
+	data := make([]byte, p.EmbedLen()+1) // Check length validation. This test
+	defer func() {                       // comes last, because it triggers panic
+		r := recover()
+		require.NotNil(t, r, "calling embed with too much data should panic")
+		require.Contains(t, r, "too much data to embed in a point")
+	}()
+	p.Embed(data, randomStreamPoint)
+}
+
+func TestPoint_AddSubAndNeg(t *testing.T) {
+	zero := NewPoint().Null()
+	p := NewPoint()
+	for i := 0; i < numPointSamples; i++ {
+		p.Pick(randomStreamPoint)
+		q := p.Clone()
+		p.Sub(p, q)
+		require.True(t, p.Equal(zero),
+			"subtracting a point from itself should give zero, "+
+				"got %v - %v = %v ≠ %v", q, q, p, zero)
+		p.Neg(q)
+		r := NewPoint().Add(p, q)
+		require.True(t, r.Equal(zero),
+			"adding a point to its negative should give zero"+
+				" got %v+%v=%v≠%v", q, p, r, zero)
+		r.Neg(q)
+		p.Sub(q, r)
+		s := NewPoint().Add(q, q)
+		require.True(t, p.Equal(s), "q-(-q)=q+q?"+
+			" got %v-%v=%v≠%v", q, r, p, s)
+	}
+}
+
+func TestPoint_Mul(t *testing.T) {
+	zero := NewPoint().Null()
+	multiplier := newScalar(bigZero)
+	one := newScalar(big.NewInt(int64(1)))
+	var p *Secp256k1Point
+	for i := 0; i < numPointSamples/5; i++ {
+		if i%20 == 0 {
+			p = nil // Test default to generator point
+		} else {
+			p = NewPoint()
+			p.Pick(randomStreamPoint)
+		}
+		multiplier.Pick(randomStreamPoint)
+		q := NewPoint().Mul(one, p)
+		comparee := NewPoint()
+		if p == (*Secp256k1Point)(nil) {
+			comparee.Base()
+		} else {
+			comparee = p.Clone().(*Secp256k1Point)
+		}
+		require.True(t, comparee.Equal(q), "1*p=p? %v * %v ≠ %v", one,
+			comparee, q)
+		q.Mul(multiplier, p)
+		negMultiplier := newScalar(bigZero).Neg(multiplier)
+		r := NewPoint().Mul(negMultiplier, p)
+		s := NewPoint().Add(q, r)
+		require.True(t, s.Equal(zero), "s*p+(-s)*p=0? got "+
+			"%v*%v + %v*%v = %v + %v = %v ≠ %v", multiplier, p,
+		)
+	}
+}
+
+func TestPoint_Marshal(t *testing.T) {
+	p := NewPoint()
+	for i := 0; i < numPointSamples; i++ {
+		p.Pick(randomStreamPoint)
+		serialized, err := p.MarshalBinary()
+		require.Nil(t, err)
+		q := NewPoint()
+		err = q.UnmarshalBinary(serialized)
+		require.Nil(t, err)
+		require.True(t, p.Equal(q), "%v marshalled to %x, which "+
+			"unmarshalled to %v", p, serialized, q)
+	}
+	p.X.SetInt(big.NewInt(0)) // 0³+7 is not a square in the base field.
+	_, err := p.MarshalBinary()
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "not a square")
+	p.X.SetInt(big.NewInt(1))
+	_, err = p.MarshalBinary()
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "not a point on the curve")
+	id := p.MarshalID()
+	require.Equal(t, string(id[:]), "sp256.po")
+	data := make([]byte, 34)
+	err = p.UnmarshalBinary(data)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "wrong length for marshaled point")
+	require.Contains(t, p.UnmarshalBinary(data[:32]).Error(),
+		"wrong length for marshaled point")
+	data[32] = 2
+	require.Contains(t, p.UnmarshalBinary(data[:33]).Error(),
+		"bad sign byte")
+	data[32] = 0
+	data[31] = 5 // I.e., x-ordinate is now 5
+	require.Contains(t, p.UnmarshalBinary(data[:33]).Error(),
+		"does not correspond to a curve point")
+}
+
+func TestPoint_BaseTakesCopy(t *testing.T) {
+	p := NewPoint().Base()
+	p.Add(p, p)
+	q := NewPoint().Base()
+	assert.False(t, p.Equal(q),
+		"modifying output from Base changes S256.G{x,y}")
+}
+
+func TestPoint_EthereumAddress(t *testing.T) {
+	// Example taken from
+	// https://theethereum.wiki/w/index.php/Accounts,_Addresses,_Public_And_Private_Keys,_And_Tokens
+	pString := "3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"
+	pInt, ok := big.NewInt(0).SetString(pString, 16)
+	require.True(t, ok, "failed to parse private key")
+	private := newScalar(pInt)
+	public := NewPoint().Mul(private, nil)
+	address := EthereumAddress(public)
+	assert.Equal(t, fmt.Sprintf("%x", address),
+		"c2d7cf95645d33006175b78989035c7c9061d3f9")
+}
+
+func TestIsSecp256k1Point(t *testing.T) {
+	p := curve25519.NewBlakeSHA256Curve25519(false).Point()
+	require.False(t, IsSecp256k1Point(p))
+	require.True(t, IsSecp256k1Point(NewPoint()))
+}
+
+func TestCoordinates(t *testing.T) {
+	x, y := Coordinates(NewPoint())
+	require.Equal(t, x, bigZero)
+	require.Equal(t, y, bigZero)
+}
+
+func TestValidPublicKey(t *testing.T) {
+	require.False(t, ValidPublicKey(NewPoint()), "zero is not a valid key")
+	require.True(t, ValidPublicKey(NewPoint().Base()))
+}
+
+func TestGenerate(t *testing.T) {
+	for {
+		if ValidPublicKey(Generate(randomStreamPoint).Public) {
+			break
+		}
+	}
+}

+ 228 - 0
bridge/pkg/signatures/secp256k1/scalar.go

@@ -0,0 +1,228 @@
+// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalcar}
+////////////////////////////////////////////////////////////////////////////////
+//       XXX: Do not use in production until this code has been audited.
+////////////////////////////////////////////////////////////////////////////////
+// interfaces, based on btcd/btcec and kyber/group/mod
+//
+// XXX: NOT CONSTANT TIME!
+package secp256k1
+
+// Implementation of kyber.Scalar interface for arithmetic operations mod the
+// order of the secpk256k1 group (i.e. hex value
+// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141.)
+
+import (
+	"crypto/cipher"
+	"fmt"
+	"io"
+	"math/big"
+
+	secp256k1BTCD "github.com/btcsuite/btcd/btcec"
+	"github.com/ethereum/go-ethereum/common"
+
+	"go.dedis.ch/kyber/v3"
+	"go.dedis.ch/kyber/v3/util/random"
+)
+
+var GroupOrder = secp256k1BTCD.S256().N
+
+type secp256k1Scalar big.Int
+
+// AllowVarTime, if passed true indicates that variable-time operations may be
+// used on s.
+func (s *secp256k1Scalar) AllowVarTime(varTimeAllowed bool) {
+	// Since constant-time operations are unimplemented for secp256k1, a
+	// value of false panics.
+	if !varTimeAllowed {
+		panic("implementation is not constant-time!")
+	}
+}
+
+// newScalar returns a secpk256k1 scalar, with value v modulo GroupOrder.
+func newScalar(v *big.Int) kyber.Scalar {
+	return (*secp256k1Scalar)(zero().Mod(v, GroupOrder))
+}
+
+func zero() *big.Int { return big.NewInt(0) }
+
+func ToInt(s kyber.Scalar) *big.Int { return (*big.Int)(s.(*secp256k1Scalar)) }
+
+func (s *secp256k1Scalar) int() *big.Int { return (*big.Int)(s) }
+
+func (s *secp256k1Scalar) modG() kyber.Scalar {
+	// TODO(alx): Make this faster
+	s.int().Mod(s.int(), GroupOrder)
+	return s
+}
+
+func (s *secp256k1Scalar) String() string {
+	return fmt.Sprintf("scalar{%x}", (*big.Int)(s))
+}
+
+var scalarZero = zero()
+
+// Equal returns true if s and sPrime represent the same value modulo the group
+// order, false otherwise
+func (s *secp256k1Scalar) Equal(sPrime kyber.Scalar) bool {
+	difference := zero().Sub(s.int(), ToInt(sPrime))
+	return scalarZero.Cmp(difference.Mod(difference, GroupOrder)) == 0
+}
+
+// Set copies sPrime's value (modulo GroupOrder) to s, and returns it
+func (s *secp256k1Scalar) Set(sPrime kyber.Scalar) kyber.Scalar {
+	return (*secp256k1Scalar)(s.int().Mod(ToInt(sPrime), GroupOrder))
+}
+
+// Clone returns a copy of s mod GroupOrder
+func (s *secp256k1Scalar) Clone() kyber.Scalar {
+	return (*secp256k1Scalar)(zero().Mod(s.int(), GroupOrder))
+}
+
+// SetInt64 returns s with value set to v modulo GroupOrder
+func (s *secp256k1Scalar) SetInt64(v int64) kyber.Scalar {
+	return (*secp256k1Scalar)(s.int().SetInt64(v)).modG()
+}
+
+// Zero sets s to 0 mod GroupOrder, and returns it
+func (s *secp256k1Scalar) Zero() kyber.Scalar {
+	return s.SetInt64(0)
+}
+
+// Add sets s to a+b mod GroupOrder, and returns it
+func (s *secp256k1Scalar) Add(a, b kyber.Scalar) kyber.Scalar {
+	s.int().Add(ToInt(a), ToInt(b))
+	return s.modG()
+}
+
+// Sub sets s to a-b mod GroupOrder, and returns it
+func (s *secp256k1Scalar) Sub(a, b kyber.Scalar) kyber.Scalar {
+	s.int().Sub(ToInt(a), ToInt(b))
+	return s.modG()
+}
+
+// Neg sets s to -a mod GroupOrder, and returns it
+func (s *secp256k1Scalar) Neg(a kyber.Scalar) kyber.Scalar {
+	s.int().Neg(ToInt(a))
+	return s.modG()
+}
+
+// One sets s to 1 mod GroupOrder, and returns it
+func (s *secp256k1Scalar) One() kyber.Scalar {
+	return s.SetInt64(1)
+}
+
+// Mul sets s to a*b mod GroupOrder, and returns it
+func (s *secp256k1Scalar) Mul(a, b kyber.Scalar) kyber.Scalar {
+	// TODO(alx): Make this faster
+	s.int().Mul(ToInt(a), ToInt(b))
+	return s.modG()
+}
+
+// Div sets s to a*b⁻¹ mod GroupOrder, and returns it
+func (s *secp256k1Scalar) Div(a, b kyber.Scalar) kyber.Scalar {
+	if ToInt(b).Cmp(scalarZero) == 0 {
+		panic("attempt to divide by zero")
+	}
+	// TODO(alx): Make this faster
+	s.int().Mul(ToInt(a), zero().ModInverse(ToInt(b), GroupOrder))
+	return s.modG()
+}
+
+// Inv sets s to s⁻¹ mod GroupOrder, and returns it
+func (s *secp256k1Scalar) Inv(a kyber.Scalar) kyber.Scalar {
+	if ToInt(a).Cmp(scalarZero) == 0 {
+		panic("attempt to divide by zero")
+	}
+	s.int().ModInverse(ToInt(a), GroupOrder)
+	return s
+}
+
+// Pick sets s to a random value mod GroupOrder sampled from rand, and returns
+// it
+func (s *secp256k1Scalar) Pick(rand cipher.Stream) kyber.Scalar {
+	return s.Set((*secp256k1Scalar)(random.Int(GroupOrder, rand)))
+}
+
+// MarshalBinary returns the big-endian byte representation of s, or an error on
+// failure
+func (s *secp256k1Scalar) MarshalBinary() ([]byte, error) {
+	b := ToInt(s.modG()).Bytes()
+	// leftpad with zeros
+	rv := append(make([]byte, s.MarshalSize()-len(b)), b...)
+	if len(rv) != s.MarshalSize() {
+		return nil, fmt.Errorf("marshalled scalar to wrong length")
+	}
+	return rv, nil
+}
+
+// MarshalSize returns the length of the byte representation of s
+func (s *secp256k1Scalar) MarshalSize() int { return 32 }
+
+// MarshalID returns the ID for a secp256k1 scalar
+func (s *secp256k1Scalar) MarshalID() [8]byte {
+	return [8]byte{'s', 'p', '2', '5', '6', '.', 's', 'c'}
+}
+
+// UnmarshalBinary sets s to the scalar represented by the contents of buf,
+// returning error on failure.
+func (s *secp256k1Scalar) UnmarshalBinary(buf []byte) error {
+	if len(buf) != s.MarshalSize() {
+		return fmt.Errorf("cannot unmarshal to scalar: wrong length")
+	}
+	s.int().Mod(s.int().SetBytes(buf), GroupOrder)
+	return nil
+}
+
+// MarshalTo writes the serialized s to w, and returns the number of bytes
+// written, or an error on failure.
+func (s *secp256k1Scalar) MarshalTo(w io.Writer) (int, error) {
+	buf, err := s.MarshalBinary()
+	if err != nil {
+		return 0, fmt.Errorf("cannot marshal binary: %s", err)
+	}
+	return w.Write(buf)
+}
+
+// UnmarshalFrom sets s to the scalar represented by bytes read from r, and
+// returns the number of bytes read, or an error on failure.
+func (s *secp256k1Scalar) UnmarshalFrom(r io.Reader) (int, error) {
+	buf := make([]byte, s.MarshalSize())
+	n, err := io.ReadFull(r, buf)
+	if err != nil {
+		return n, err
+	}
+	return n, s.UnmarshalBinary(buf)
+}
+
+// SetBytes sets s to the number with big-endian representation a mod
+// GroupOrder, and returns it
+func (s *secp256k1Scalar) SetBytes(a []byte) kyber.Scalar {
+	return ((*secp256k1Scalar)(s.int().SetBytes(a))).modG()
+}
+
+// IsSecp256k1Scalar returns true if p is a secp256k1Scalar
+func IsSecp256k1Scalar(s kyber.Scalar) bool {
+	switch s := s.(type) {
+	case *secp256k1Scalar:
+		s.modG()
+		return true
+	default:
+		return false
+	}
+}
+
+// IntToScalar returns i wrapped as a big.Int.
+//
+// May modify i to reduce mod GroupOrder
+func IntToScalar(i *big.Int) kyber.Scalar {
+	return ((*secp256k1Scalar)(i)).modG()
+}
+
+func ScalarToHash(s kyber.Scalar) common.Hash {
+	return common.BigToHash(ToInt(s.(*secp256k1Scalar)))
+}
+
+// RepresentsScalar returns true iff i is in the right range to be a scalar
+func RepresentsScalar(i *big.Int) bool {
+	return i.Cmp(GroupOrder) == -1
+}

+ 189 - 0
bridge/pkg/signatures/secp256k1/scalar_test.go

@@ -0,0 +1,189 @@
+package secp256k1
+
+import (
+	"bytes"
+	"encoding/hex"
+	"math/big"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"go.dedis.ch/kyber/v3"
+	"go.dedis.ch/kyber/v3/group/curve25519"
+
+	"github.com/certusone/wormhole/bridge/pkg/signatures/cryptotest"
+)
+
+var numScalarSamples = 10
+
+var observedScalars map[string]bool
+
+func init() {
+	observedScalars = make(map[string]bool)
+}
+
+// observedScalar ensures that novel scalars are being picked.
+func observedScalar(t *testing.T, s kyber.Scalar) {
+	data, err := s.(*secp256k1Scalar).modG().MarshalBinary()
+	require.NoError(t, err)
+	scalar := hex.Dump(data)
+	require.False(t, observedScalars[scalar])
+	observedScalars[scalar] = true
+}
+
+var randomStreamScalar = cryptotest.NewStream(&testing.T{}, 0)
+
+func TestScalar_SetAndEqual(t *testing.T) {
+	tests := []int64{5, 67108864, 67108865, 4294967295}
+	g := newScalar(scalarZero)
+	for _, test := range tests {
+		f := newScalar(big.NewInt(test))
+		g.Set(f)
+		assert.Equal(t, f, g,
+			"the method Set should give the same value to receiver")
+		f.Add(f, newScalar(big.NewInt(1)))
+		assert.NotEqual(t, f, g,
+			"SetInt should take a copy of the backing big.Int")
+	}
+}
+
+func TestNewScalar(t *testing.T) {
+	one := newScalar(big.NewInt(1))
+	assert.Equal(t, ToInt(one),
+		ToInt(newScalar(big.NewInt(0).Add(ToInt(one), GroupOrder))),
+		"equivalence classes mod GroupOrder not equal")
+}
+
+func TestScalar_SmokeTestPick(t *testing.T) {
+	f := newScalar(scalarZero).Clone()
+	for i := 0; i < numScalarSamples; i++ {
+		f.Pick(randomStreamScalar)
+		observedScalar(t, f)
+		require.True(t, ToInt(f).Cmp(big.NewInt(1000000000)) == 1,
+			"implausibly low value returned from Pick: %v", f)
+	}
+}
+
+func TestScalar_Neg(t *testing.T) {
+	f := newScalar(scalarZero).Clone()
+	for i := 0; i < numScalarSamples; i++ {
+		f.Pick(randomStreamScalar)
+		observedScalar(t, f)
+		g := f.Clone()
+		g.Neg(g)
+		require.True(t, g.Add(f, g).Equal(newScalar(scalarZero)))
+	}
+}
+
+func TestScalar_Sub(t *testing.T) {
+	f := newScalar(scalarZero).Clone()
+	for i := 0; i < numScalarSamples; i++ {
+		f.Pick(randomStreamScalar)
+		observedScalar(t, f)
+		require.True(t, f.Sub(f, f).Equal(newScalar(scalarZero)),
+			"subtracting something from itself should give zero")
+	}
+}
+
+func TestScalar_Clone(t *testing.T) {
+	f := newScalar(big.NewInt(1))
+	g := f.Clone()
+	h := f.Clone()
+	assert.Equal(t, f, g, "clone output does not equal input")
+	g.Add(f, f)
+	assert.Equal(t, f, h, "clone does not make a copy")
+}
+
+func TestScalar_Marshal(t *testing.T) {
+	f := newScalar(scalarZero)
+	g := newScalar(scalarZero)
+	for i := 0; i < numFieldSamples; i++ {
+		f.Pick(randomStreamScalar)
+		observedScalar(t, f)
+		data, err := f.MarshalBinary()
+		require.Nil(t, err)
+		err = g.UnmarshalBinary(data)
+		require.Nil(t, err)
+		require.True(t, g.Equal(f),
+			"roundtrip through serialization should give same "+
+				"result back: failed with %s", f)
+	}
+	marshalID := f.(*secp256k1Scalar).MarshalID()
+	require.Equal(t, string(marshalID[:]), "sp256.sc")
+	data := make([]byte, 33)
+	require.Contains(t, f.UnmarshalBinary(data).Error(), "wrong length")
+	var buf bytes.Buffer
+	_, err := f.MarshalTo(&buf)
+	require.NoError(t, err)
+	_, err = f.UnmarshalFrom(&buf)
+	require.NoError(t, err)
+}
+
+func TestScalar_MulDivInv(t *testing.T) {
+	f := newScalar(scalarZero)
+	g := newScalar(scalarZero)
+	h := newScalar(scalarZero)
+	j := newScalar(scalarZero)
+	k := newScalar(scalarZero)
+	for i := 0; i < numFieldSamples; i++ {
+		f.Pick(randomStreamScalar)
+		observedScalar(t, f)
+		g.Inv(f)
+		h.Mul(f, g)
+		require.True(t, h.Equal(newScalar(big.NewInt(1))))
+		h.Div(f, f)
+		require.True(t, h.Equal(newScalar(big.NewInt(1))))
+		h.Div(newScalar(big.NewInt(1)), f)
+		require.True(t, h.Equal(g))
+		h.Pick(randomStreamScalar)
+		observedScalar(t, h)
+		j.Neg(j.Mul(h, f))
+		k.Mul(h, k.Neg(f))
+		require.True(t, j.Equal(k), "-(h*f) != h*(-f)")
+	}
+}
+
+func TestScalar_AllowVarTime(t *testing.T) {
+	defer func() { require.Contains(t, recover(), "not constant-time!") }()
+	newScalar(bigZero).(*secp256k1Scalar).AllowVarTime(false)
+}
+
+func TestScalar_String(t *testing.T) {
+	require.Equal(t, newScalar(bigZero).String(), "scalar{0}")
+}
+
+func TestScalar_SetInt64(t *testing.T) {
+	require.Equal(t, newScalar(bigZero).SetInt64(1), newScalar(big.NewInt(1)))
+	require.True(t, newScalar(big.NewInt(1)).Zero().Equal(newScalar(bigZero)))
+	require.Equal(t, newScalar(bigZero).One(), newScalar(big.NewInt(1)))
+}
+
+func TestScalar_DivPanicsOnZeroDivisor(t *testing.T) {
+	defer func() { require.Contains(t, recover(), "divide by zero") }()
+	newScalar(bigZero).Div(newScalar(bigZero).One(), newScalar(bigZero))
+}
+
+func TestScalar_InvPanicsOnZero(t *testing.T) {
+	defer func() { require.Contains(t, recover(), "divide by zero") }()
+	newScalar(bigZero).Inv(newScalar(bigZero))
+}
+
+func TestScalar_SetBytes(t *testing.T) {
+	u256Cardinality := zero().Lsh(big.NewInt(1), 256)
+	newScalar(bigZero).(*secp256k1Scalar).int().Cmp(
+		zero().Sub(u256Cardinality, GroupOrder))
+}
+
+func TestScalar_IsSecp256k1Scalar(t *testing.T) {
+	c := curve25519.NewBlakeSHA256Curve25519(true)
+	require.False(t, IsSecp256k1Scalar(c.Scalar()))
+	require.True(t, IsSecp256k1Scalar(newScalar(bigZero)))
+}
+
+func TestScalar_IntToScalar(t *testing.T) {
+	u256Cardinality := zero().Lsh(big.NewInt(1), 256)
+	IntToScalar(u256Cardinality)
+	require.Equal(t, u256Cardinality, zero().Sub(zero().Lsh(big.NewInt(1), 256),
+		GroupOrder))
+}

+ 89 - 0
bridge/pkg/signatures/secp256k1/suite.go

@@ -0,0 +1,89 @@
+// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar}
+////////////////////////////////////////////////////////////////////////////////
+//       XXX: Do not use in production until this code has been audited.
+////////////////////////////////////////////////////////////////////////////////
+// interfaces, based on btcd/btcec and kyber/group/mod
+//
+// XXX: NOT CONSTANT TIME!
+package secp256k1
+
+import (
+	"crypto/cipher"
+	"hash"
+	"io"
+	"reflect"
+
+	"golang.org/x/crypto/sha3"
+
+	"go.dedis.ch/fixbuf"
+	"go.dedis.ch/kyber/v3"
+	"go.dedis.ch/kyber/v3/util/random"
+	"go.dedis.ch/kyber/v3/xof/blake2xb"
+)
+
+// SuiteSecp256k1 implements some basic functionalities such as Group, HashFactory,
+// and XOFFactory.
+type SuiteSecp256k1 struct {
+	Secp256k1
+	r cipher.Stream
+}
+
+// Hash returns a newly instantiated keccak hash function.
+func (s *SuiteSecp256k1) Hash() hash.Hash {
+	return sha3.NewLegacyKeccak256()
+}
+
+// XOF returns an XOR function, implemented via the Blake2b hash.
+//
+// This should only be used for generating secrets, so there is no need to make
+// it cheap to compute on-chain.
+func (s *SuiteSecp256k1) XOF(key []byte) kyber.XOF {
+	return blake2xb.New(key)
+}
+
+// Read implements the Encoding interface function, and reads a series of objs from r
+// The objs must all be pointers
+func (s *SuiteSecp256k1) Read(r io.Reader, objs ...interface{}) error {
+	return fixbuf.Read(r, s, objs...)
+}
+
+// Write implements the Encoding interface, and writes the objs to r using their
+// built-in binary serializations. Supports Points, Scalars, fixed-length data
+// types supported by encoding/binary/Write(), and structs, arrays, and slices
+// containing these types.
+func (s *SuiteSecp256k1) Write(w io.Writer, objs ...interface{}) error {
+	return fixbuf.Write(w, objs)
+}
+
+var aScalar kyber.Scalar
+var tScalar = reflect.TypeOf(aScalar)
+var aPoint kyber.Point
+var tPoint = reflect.TypeOf(aPoint)
+
+// New implements the kyber.Encoding interface, and returns a new element of
+// type t, which can be a Point or a Scalar
+func (s *SuiteSecp256k1) New(t reflect.Type) interface{} {
+	switch t {
+	case tScalar:
+		return s.Scalar()
+	case tPoint:
+		return s.Point()
+	}
+	return nil
+}
+
+// RandomStream returns a cipher.Stream that returns a key stream
+// from crypto/rand.
+func (s *SuiteSecp256k1) RandomStream() cipher.Stream {
+	if s.r != nil {
+		return s.r
+	}
+	return random.New()
+}
+
+// NewBlakeKeccackSecp256k1 returns a cipher suite based on package
+// go.dedis.ch/kyber/xof/blake2xb, SHA-256, and the secp256k1 curve. It
+// produces cryptographically secure random numbers via package crypto/rand.
+func NewBlakeKeccackSecp256k1() *SuiteSecp256k1 {
+	return new(SuiteSecp256k1)
+}

+ 16 - 0
bridge/pkg/signatures/secp256k1/suite_test.go

@@ -0,0 +1,16 @@
+package secp256k1
+
+import (
+	"encoding/hex"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestSuite(t *testing.T) {
+	s := NewBlakeKeccackSecp256k1()
+	emptyHashAsHex := hex.EncodeToString(s.Hash().Sum(nil))
+	require.Equal(t, emptyHashAsHex,
+		"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
+	_ = s.RandomStream()
+}

+ 298 - 0
bridge/pkg/vaa/structs.go

@@ -0,0 +1,298 @@
+package vaa
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"github.com/certusone/wormhole/bridge/pkg/signatures/secp256k1"
+	"github.com/ethereum/go-ethereum/common"
+	"go.dedis.ch/kyber/v3"
+	"io"
+	"math"
+	"math/big"
+	"time"
+)
+
+type (
+	// VAA is a verifiable action approval of the Wormhole protocol
+	VAA struct {
+		// Version of the VAA schema
+		Version uint8
+		// GuardianSetIndex is the index of the guardian set that signed this VAA
+		GuardianSetIndex uint32
+		// Signature is the signature of the guardian set
+		Signature *Signature
+
+		// Timestamp when the VAA was created
+		Timestamp time.Time
+		// Payload of the VAA. This describes the action to be performed
+		Payload vaaBody
+	}
+
+	// ChainID of a Wormhole chain
+	ChainID uint8
+	// Action of a VAA
+	Action uint8
+
+	// Address is a Wormhole protocol address, it contains the native chain's address. If the address data type of a
+	// chain is < 32bytes the value is zero-padded on the left.
+	Address [32]byte
+
+	// Signature of a VAA
+	Signature struct {
+		// Sig is the signature field of a Schnorr signature
+		Sig [32]byte
+		// Address is the R equivalent in our Schnorr signature schema
+		Address common.Address
+	}
+
+	// AssetMeta describes an asset within the Wormhole protocol
+	AssetMeta struct {
+		// Chain is the ID of the chain the original version of the asset exists on
+		Chain ChainID
+		// Address is the address of the token contract/mint/equivalent.
+		Address Address
+	}
+
+	vaaBody interface {
+		getActionID() Action
+		serialize() ([]byte, error)
+	}
+
+	BodyTransfer struct {
+		// SourceChain is the id of the chain the transfer was initiated from
+		SourceChain ChainID
+		// TargetChain is the id of the chain the transfer is directed to
+		TargetChain ChainID
+		// TargetAddress is the address of the recipient on TargetChain
+		TargetAddress Address
+		// Asset is the asset to be transferred
+		Asset *AssetMeta
+		// Amount is the amount of tokens to be transferred
+		Amount *big.Int
+	}
+
+	BodyGuardianSetUpdate struct {
+		// Key is the new guardian set key
+		Key kyber.Point
+		// NewIndex is the index of the new guardian set
+		NewIndex uint32
+	}
+)
+
+const (
+	ActionGuardianSetUpdate Action = 0x01
+	ActionTransfer          Action = 0x10
+
+	// ChainIDSolana is the ChainID of Solana
+	ChainIDSolana = 1
+	// ChainIDEthereum is the ChainID of Ethereum
+	ChainIDEthereum = 2
+
+	minVAALength        = 1 + 4 + 52 + 4 + 1 + 1
+	supportedVAAVersion = 0x01
+)
+
+// ParseVAA deserializes the binary representation of a VAA
+func ParseVAA(data []byte) (*VAA, error) {
+	if len(data) < minVAALength {
+		return nil, fmt.Errorf("VAA is too short")
+	}
+	v := &VAA{
+		Signature: &Signature{},
+	}
+
+	v.Version = data[0]
+	if v.Version < supportedVAAVersion {
+		return nil, fmt.Errorf("unsupported VAA version: %d", v.Version)
+	}
+
+	reader := bytes.NewReader(data[1:])
+
+	if err := binary.Read(reader, binary.BigEndian, &v.GuardianSetIndex); err != nil {
+		return nil, fmt.Errorf("failed to read guardian set index: %w", err)
+	}
+
+	if n, err := reader.Read(v.Signature.Sig[:]); err != nil || n != 32 {
+		return nil, fmt.Errorf("failed to read signature sig field: %w", err)
+	}
+	if n, err := reader.Read(v.Signature.Address[:]); err != nil || n != 20 {
+		return nil, fmt.Errorf("failed to read signature addr field: %w", err)
+	}
+
+	unixSeconds := uint32(0)
+	if err := binary.Read(reader, binary.BigEndian, &unixSeconds); err != nil {
+		return nil, fmt.Errorf("failed to read timestamp: %w", err)
+	}
+	v.Timestamp = time.Unix(int64(unixSeconds), 0)
+
+	action := data[61]
+	payloadLength := data[62]
+
+	if len(data[63:]) != int(payloadLength) {
+		return nil, fmt.Errorf("payload length does not match given payload data size")
+	}
+
+	payloadReader := bytes.NewReader(data[63:])
+	var err error
+	switch Action(action) {
+	case ActionGuardianSetUpdate:
+		v.Payload, err = parseBodyGuardianSetUpdate(payloadReader)
+	case ActionTransfer:
+		v.Payload, err = parseBodyTransfer(payloadReader)
+	default:
+		return nil, fmt.Errorf("unknown action: %d", action)
+	}
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse payload: %w", err)
+	}
+
+	return v, nil
+}
+
+// SigningBody returns the binary representation of the data that is relevant for signing and verifying the VAA
+func (v *VAA) SigningBody() ([]byte, error) {
+	return v.serializeBody()
+}
+
+// Serialize returns the binary representation of the VAA
+func (v *VAA) Serialize() ([]byte, error) {
+	buf := new(bytes.Buffer)
+	MustWrite(buf, binary.BigEndian, v.Version)
+	MustWrite(buf, binary.BigEndian, v.GuardianSetIndex)
+
+	if v.Signature == nil {
+		return nil, fmt.Errorf("empty signature")
+	}
+
+	// Write signature
+	buf.Write(v.Signature.Sig[:])
+	buf.Write(v.Signature.Address[:])
+
+	// Write Body
+	body, err := v.serializeBody()
+	if err != nil {
+		return nil, fmt.Errorf("failed to serialize body: %w", err)
+	}
+	buf.Write(body)
+
+	return buf.Bytes(), nil
+}
+
+func (v *VAA) serializeBody() ([]byte, error) {
+	buf := new(bytes.Buffer)
+	MustWrite(buf, binary.BigEndian, uint32(v.Timestamp.Unix()))
+	MustWrite(buf, binary.BigEndian, v.Payload.getActionID())
+
+	payloadData, err := v.Payload.serialize()
+	if err != nil {
+		return nil, fmt.Errorf("failed to serialize payload: %w", err)
+	}
+
+	if len(payloadData) > math.MaxUint8 {
+		return nil, fmt.Errorf("payload size exceeds maximum")
+	}
+	MustWrite(buf, binary.BigEndian, uint8(len(payloadData)))
+	buf.Write(payloadData)
+
+	return buf.Bytes(), nil
+}
+
+func parseBodyTransfer(r io.Reader) (*BodyTransfer, error) {
+	b := &BodyTransfer{}
+
+	if err := binary.Read(r, binary.BigEndian, &b.SourceChain); err != nil {
+		return nil, fmt.Errorf("failed to read source chain: %w", err)
+	}
+
+	if err := binary.Read(r, binary.BigEndian, &b.TargetChain); err != nil {
+		return nil, fmt.Errorf("failed to read target chain: %w", err)
+	}
+
+	if n, err := r.Read(b.TargetAddress[:]); err != nil || n != 32 {
+		return nil, fmt.Errorf("failed to read target address: %w", err)
+	}
+
+	b.Asset = &AssetMeta{}
+	if err := binary.Read(r, binary.BigEndian, &b.Asset.Chain); err != nil {
+		return nil, fmt.Errorf("failed to read asset chain: %w", err)
+	}
+	if n, err := r.Read(b.Asset.Address[:]); err != nil || n != 32 {
+		return nil, fmt.Errorf("failed to read asset address: %w", err)
+	}
+
+	var amountBytes [32]byte
+	if n, err := r.Read(amountBytes[:]); err != nil || n != 32 {
+		return nil, fmt.Errorf("failed to read amount: %w", err)
+	}
+	b.Amount = new(big.Int).SetBytes(amountBytes[:])
+
+	return b, nil
+}
+
+func (v *BodyTransfer) getActionID() Action {
+	return ActionTransfer
+}
+
+func (v *BodyTransfer) serialize() ([]byte, error) {
+	buf := new(bytes.Buffer)
+	MustWrite(buf, binary.BigEndian, v.SourceChain)
+	MustWrite(buf, binary.BigEndian, v.TargetChain)
+	buf.Write(v.TargetAddress[:])
+
+	if v.Asset == nil {
+		return nil, fmt.Errorf("asset is empty")
+	}
+	MustWrite(buf, binary.BigEndian, v.Asset.Chain)
+	buf.Write(v.Asset.Address[:])
+
+	if v.Amount == nil {
+		return nil, fmt.Errorf("amount is empty")
+	}
+	buf.Write(common.LeftPadBytes(v.Amount.Bytes(), 32))
+
+	return buf.Bytes(), nil
+}
+
+func parseBodyGuardianSetUpdate(r io.Reader) (*BodyGuardianSetUpdate, error) {
+	b := &BodyGuardianSetUpdate{}
+
+	b.Key = secp256k1.NewPoint()
+	_, err := b.Key.UnmarshalFrom(r)
+	if err != nil {
+		return nil, fmt.Errorf("failed to unmarshal new key: %w", err)
+	}
+
+	if err := binary.Read(r, binary.BigEndian, &b.NewIndex); err != nil {
+		return nil, fmt.Errorf("failed to read new index: %w", err)
+	}
+
+	return b, nil
+}
+
+func (v *BodyGuardianSetUpdate) getActionID() Action {
+	return ActionGuardianSetUpdate
+}
+
+func (v *BodyGuardianSetUpdate) serialize() ([]byte, error) {
+	buf := new(bytes.Buffer)
+
+	if v.Key == nil {
+		return nil, fmt.Errorf("key is empty")
+	}
+	_, err := v.Key.MarshalTo(buf)
+	if err != nil {
+		return nil, fmt.Errorf("failed to marshal key: %w", err)
+	}
+
+	MustWrite(buf, binary.BigEndian, v.NewIndex)
+
+	return buf.Bytes(), nil
+}
+
+// MustWrite calls binary.Write and panics on errors
+func MustWrite(w io.Writer, order binary.ByteOrder, data interface{}) {
+	if err := binary.Write(w, order, data); err != nil {
+		panic(fmt.Errorf("failed to write binary data: %v", data).Error())
+	}
+}

+ 71 - 0
bridge/pkg/vaa/types_test.go

@@ -0,0 +1,71 @@
+package vaa
+
+import (
+	"github.com/certusone/wormhole/bridge/pkg/signatures/cryptotest"
+	"github.com/certusone/wormhole/bridge/pkg/signatures/secp256k1"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/stretchr/testify/require"
+	"math/big"
+	"testing"
+	"time"
+)
+
+var randomStream = cryptotest.NewStream(&testing.T{}, 0)
+
+func TestSerializeDeserialize(t *testing.T) {
+	tests := []struct {
+		name string
+		vaa  *VAA
+	}{
+		{
+			name: "BodyTransfer",
+			vaa: &VAA{
+				Version:          8,
+				GuardianSetIndex: 9,
+				Signature: &Signature{
+					Sig:     [32]byte{2, 8},
+					Address: common.Address{1, 2, 3, 4},
+				},
+				Timestamp: time.Unix(2837, 0),
+				Payload: &BodyTransfer{
+					SourceChain:   2,
+					TargetChain:   1,
+					TargetAddress: Address{2, 1, 3},
+					Asset: &AssetMeta{
+						Chain:   9,
+						Address: Address{9, 2, 4},
+					},
+					Amount: big.NewInt(29),
+				},
+			},
+		},
+		{
+			name: "GuardianSetUpdate",
+			vaa: &VAA{
+				Version:          8,
+				GuardianSetIndex: 9,
+				Signature: &Signature{
+					Sig:     [32]byte{2, 8},
+					Address: common.Address{1, 2, 3, 4},
+				},
+				Timestamp: time.Unix(2837, 0),
+				Payload: &BodyGuardianSetUpdate{
+					Key:      secp256k1.Generate(randomStream).Public,
+					NewIndex: 2,
+				},
+			},
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+
+			vaaData, err := test.vaa.Serialize()
+			require.NoError(t, err)
+
+			vaaParsed, err := ParseVAA(vaaData)
+			require.NoError(t, err)
+
+			require.EqualValues(t, test.vaa, vaaParsed)
+		})
+	}
+}

+ 1 - 1
docs/protocol.md

@@ -136,7 +136,7 @@ They are structured as follows:
 Header:
 uint8               version (0x01)
 uint32              guardian set index
-[72]uint8           signature(body)
+[52]uint8           signature(body)
 
 body:
 uint32              unix seconds