Use 0.11 style domains

This commit is contained in:
Jim McDonald
2020-04-09 21:03:10 +01:00
parent afcbd177a3
commit be3fd8edd2
7 changed files with 82 additions and 47 deletions

View File

@@ -27,9 +27,10 @@ import (
homedir "github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-ssz"
"github.com/spf13/cobra"
"github.com/spf13/viper"
types "github.com/wealdtech/go-eth2-types/v2"
e2types "github.com/wealdtech/go-eth2-types/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
@@ -335,14 +336,42 @@ func accountsFromPath(path string) ([]wtypes.Account, error) {
return accounts, nil
}
// sign signs data in a domain.
func sign(account wtypes.Account, data []byte, domain []byte) (types.Signature, error) {
// signStruct signs an arbitrary structure.
func signStruct(account wtypes.Account, data interface{}, domain []byte) (e2types.Signature, error) {
objRoot, err := ssz.HashTreeRoot(data)
if err != nil {
return nil, err
}
return signRoot(account, objRoot, domain)
}
// SigningContainer is the container for signing roots with a domain.
// Contains SSZ sizes to allow for correct calculation of root.
type SigningContainer struct {
Root []byte `ssz-size:"32"`
Domain []byte `ssz-size:"32"`
}
// signRoot signs a root.
func signRoot(account wtypes.Account, root [32]byte, domain []byte) (e2types.Signature, error) {
container := &SigningContainer{
Root: root[:],
Domain: domain,
}
signingRoot, err := ssz.HashTreeRoot(container)
if err != nil {
return nil, err
}
return sign(account, signingRoot[:])
}
// sign signs arbitrary data.
func sign(account wtypes.Account, data []byte) (e2types.Signature, error) {
if !account.IsUnlocked() {
return nil, errors.New("account must be unlocked to sign")
}
// TODO combine data and domain for signing.
return account.Sign(data)
}

View File

@@ -22,40 +22,40 @@ import (
"github.com/spf13/viper"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
"github.com/wealdtech/go-bytesutil"
types "github.com/wealdtech/go-eth2-types/v2"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
// signatureSignCmd represents the signature sign command
var signatureSignCmd = &cobra.Command{
Use: "sign",
Short: "Sign data",
Short: "Sign a 32-byte piece of data",
Long: `Sign presented data. For example:
ethereal signature sign --data="0x5FfC014343cd971B7eb70732021E26C35B744cc4" --account="Personal wallet/Operations" --passphrase="my account passphrase"
ethereal signature sign --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --account="Personal wallet/Operations" --passphrase="my account passphrase"
In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(signatureData != "", "--data is required")
data, err := bytesutil.FromHexString(signatureData)
errCheck(err, "Failed to parse data")
assert(len(data) == 32, "data to sign must be 32 bytes")
domain := types.Domain([]byte{0, 0, 0, 0}, []byte{0, 0, 0, 0})
domain := e2types.Domain(e2types.DomainType([4]byte{0, 0, 0, 0}), e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot)
if signatureDomain != "" {
domainBytes, err := bytesutil.FromHexString(signatureDomain)
errCheck(err, "Failed to parse domain")
assert(len(domainBytes) == 8, "Domain data invalid")
assert(len(domainBytes) == 32, "Domain data invalid")
}
assert(rootAccount != "", "--account is required")
var signature types.Signature
var signature e2types.Signature
if remote {
signClient := pb.NewSignerClient(remoteGRPCConn)
domainBytes := bytesutil.Bytes64(domain)
signReq := &pb.SignRequest{
Id: &pb.SignRequest_Account{Account: rootAccount},
Data: data,
Domain: domainBytes,
Domain: domain,
}
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
@@ -67,7 +67,7 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
case pb.ResponseState_FAILED:
die("Signing request failed")
case pb.ResponseState_SUCCEEDED:
signature, err = types.BLSSignatureFromBytes(resp.Signature)
signature, err = e2types.BLSSignatureFromBytes(resp.Signature)
errCheck(err, "Invalid signature")
}
} else {
@@ -75,9 +75,10 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
errCheck(err, "Failed to access account for signing")
err = account.Unlock([]byte(rootAccountPassphrase))
errCheck(err, "Failed to unlock account for signing")
var fixedSizeData [32]byte
copy(fixedSizeData[:], data)
defer account.Lock()
// TODO fix domain.
signature, err = sign(account, data, []byte{})
signature, err = signRoot(account, fixedSizeData, domain)
errCheck(err, "Failed to sign data")
}

View File

@@ -17,10 +17,11 @@ import (
"context"
"os"
"github.com/prysmaticlabs/go-ssz"
"github.com/spf13/cobra"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
"github.com/wealdtech/go-bytesutil"
types "github.com/wealdtech/go-eth2-types/v2"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
var signatureVerifySignature string
@@ -32,28 +33,29 @@ var signatureVerifyCmd = &cobra.Command{
Short: "Verify signed data",
Long: `Verify signed data. For example:
ethereal signature verify --data="0x5FfC014343cd971B7eb70732021E26C35B744cc4" --signature="0x8888..." --account="Personal wallet/Operations"
ethereal signature verify --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --signature=0x8888... --account="Personal wallet/Operations"
In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(signatureData != "", "--data is required")
data, err := bytesutil.FromHexString(signatureData)
errCheck(err, "Failed to parse data")
assert(len(data) == 32, "data to verify must be 32 bytes")
assert(signatureVerifySignature != "", "--signature is required")
signatureBytes, err := bytesutil.FromHexString(signatureVerifySignature)
errCheck(err, "Failed to parse signature")
signature, err := types.BLSSignatureFromBytes(signatureBytes)
signature, err := e2types.BLSSignatureFromBytes(signatureBytes)
errCheck(err, "Invalid signature")
// domain := types.Domain([]byte{0, 0, 0, 0}, []byte{0, 0, 0, 0})
domain := e2types.Domain(e2types.DomainType([4]byte{0, 0, 0, 0}), e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot)
if signatureDomain != "" {
domainBytes, err := bytesutil.FromHexString(signatureDomain)
errCheck(err, "Failed to parse domain")
assert(len(domainBytes) == 8, "Domain data invalid")
assert(len(domainBytes) == 32, "Domain data invalid")
}
var pubKey types.PublicKey
var pubKey e2types.PublicKey
assert(signatureVerifyPubKey == "" || rootAccount == "", "Either --pubkey or --account should be supplied")
if rootAccount != "" {
if remote {
@@ -67,7 +69,7 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
errCheck(err, "Failed to access account")
assert(resp.State == pb.ResponseState_SUCCEEDED, "Failed to obtain account")
assert(len(resp.Accounts) == 1, "No such account")
pubKey, err = types.BLSPublicKeyFromBytes(resp.Accounts[0].PublicKey)
pubKey, err = e2types.BLSPublicKeyFromBytes(resp.Accounts[0].PublicKey)
errCheck(err, "Invalid public key provided for account")
} else {
account, err := accountFromPath(rootAccount)
@@ -77,11 +79,17 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
} else {
pubKeyBytes, err := bytesutil.FromHexString(signatureVerifyPubKey)
errCheck(err, "Invalid public key")
pubKey, err = types.BLSPublicKeyFromBytes(pubKeyBytes)
pubKey, err = e2types.BLSPublicKeyFromBytes(pubKeyBytes)
errCheck(err, "Invalid public key")
}
// TODO data + domain -> root
verified := signature.Verify(data, pubKey)
container := &SigningContainer{
Root: data,
Domain: domain,
}
root, err := ssz.HashTreeRoot(container)
errCheck(err, "Failed to create signing root")
verified := signature.Verify(root[:], pubKey)
if !verified {
outputIf(!quiet, "Not verified")
os.Exit(_exitFailure)

View File

@@ -1,4 +1,4 @@
// Copyright © 2019 Weald Technology Trading
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -20,6 +20,7 @@ import (
"github.com/prysmaticlabs/go-ssz"
"github.com/spf13/cobra"
e2types "github.com/wealdtech/go-eth2-types/v2"
util "github.com/wealdtech/go-eth2-util"
string2eth "github.com/wealdtech/go-string2eth"
)
@@ -84,16 +85,12 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
WithdrawalCredentials: withdrawalCredentials,
Value: val,
}
signingRoot, err := ssz.HashTreeRoot(depositData)
errCheck(err, "Failed to generate deposit data signing root")
outputIf(debug, fmt.Sprintf("Signing root is %x", signingRoot))
// domain := types.Domain(types.DomainDeposit, []byte{0, 0, 0, 0})
domain := e2types.Domain(e2types.DomainDeposit, e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot)
err = validatorAccount.Unlock([]byte(rootAccountPassphrase))
errCheck(err, "Failed to unlock validator account")
// TODO data + domain -> root
signature, err := validatorAccount.Sign(signingRoot[:])
signature, err := signStruct(validatorAccount, depositData, domain)
validatorAccount.Lock()
errCheck(err, "Failed to sign deposit data signing root")
errCheck(err, "Failed to generate deposit data signature")
signedDepositData := struct {
PubKey []byte `ssz-size:"48"`

View File

@@ -20,10 +20,10 @@ import (
"time"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
ssz "github.com/prysmaticlabs/go-ssz"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/grpc"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
var validatorExitEpoch int64
@@ -78,16 +78,15 @@ In quiet mode this will return 0 if the transaction has been sent, otherwise 1.`
Epoch: currentEpoch,
ValidatorIndex: index,
}
root, err := ssz.HashTreeRoot(exit)
errCheck(err, "Failed to generate exit proposal root")
// TODO fetch current fork version from config (currently using genesis fork version)
// currentForkVersion := config["GenesisForkVersion"].([]byte)
// domain := types.Domain(types.DomainVoluntaryExit, currentForkVersion)
currentForkVersion := config["GenesisForkVersion"].([]byte)
// TODO fetch genesis validators root from somewhere.
//domain := e2types.Domain(e2types.DomainVoluntaryExit, currentForkVersion, genesisValidatorsRoot)
domain := e2types.Domain(e2types.DomainVoluntaryExit, currentForkVersion, e2types.ZeroGenesisValidatorsRoot)
err = account.Unlock([]byte(rootAccountPassphrase))
errCheck(err, "Failed to unlock account; please confirm passphrase is correct")
// TODO supply domain
signature, err := sign(account, root[:], []byte{})
signature, err := signStruct(account, exit, domain)
errCheck(err, "Failed to sign exit proposal")
proposal := &ethpb.SignedVoluntaryExit{

7
go.mod
View File

@@ -29,13 +29,12 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.6.2
github.com/wealdtech/eth2-signer-api v1.2.0
github.com/wealdtech/eth2-signer-api v1.3.0
github.com/wealdtech/go-bytesutil v1.1.1
github.com/wealdtech/go-eth2-types v1.0.0
github.com/wealdtech/go-eth2-types/v2 v2.0.2
github.com/wealdtech/go-eth2-types/v2 v2.1.0
github.com/wealdtech/go-eth2-util v1.1.2
github.com/wealdtech/go-eth2-wallet v1.9.2
github.com/wealdtech/go-eth2-wallet-types v1.10.0
github.com/wealdtech/go-eth2-wallet-types v1.10.0 // indirect
github.com/wealdtech/go-eth2-wallet-types/v2 v2.0.0
github.com/wealdtech/go-string2eth v1.1.0
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 // indirect

6
go.sum
View File

@@ -215,8 +215,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/wealdtech/eth2-signer-api v1.2.0 h1:AL4bRJDW6lyRc0ROPruVTEHt7Xs+EV2lRBPen2plOr8=
github.com/wealdtech/eth2-signer-api v1.2.0/go.mod h1:H8OpAoTBl6CaBvZEnhxWDjjWXNc3kwVFKWMAZd6sHlk=
github.com/wealdtech/eth2-signer-api v1.3.0 h1:Fs0GfrdhboBKW7zaMvIvUHJaOB1ibpAmRG3lkB53in4=
github.com/wealdtech/eth2-signer-api v1.3.0/go.mod h1:H8OpAoTBl6CaBvZEnhxWDjjWXNc3kwVFKWMAZd6sHlk=
github.com/wealdtech/go-bytesutil v1.0.0/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
github.com/wealdtech/go-bytesutil v1.0.1 h1:6xzMM+VEHf5WNh1PsIFcRwScgcno+CP8Rw1rGvT6Cew=
github.com/wealdtech/go-bytesutil v1.0.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
@@ -230,6 +230,8 @@ github.com/wealdtech/go-eth2-types v1.0.0 h1:ggrbQ5HeFcxVm20zxVWr8Sc3uCditaetzWB
github.com/wealdtech/go-eth2-types v1.0.0/go.mod h1:fWUgtKQ7hiNVl6263bGeyjlydYuaxkxcUIPIopgz2CM=
github.com/wealdtech/go-eth2-types/v2 v2.0.2 h1:L1Eg55aArRpUR2H8dnpSevHlSGRDuRQbQwA4IyYh0Js=
github.com/wealdtech/go-eth2-types/v2 v2.0.2/go.mod h1:CXyZc4kcDaJ+s2SglGofkbHbSjXC6zFwKLJpEVYm5tw=
github.com/wealdtech/go-eth2-types/v2 v2.1.0 h1:nGtVjYm4zb/YerzzsKOG48BWLayqJPpZwR1tRkb+PfI=
github.com/wealdtech/go-eth2-types/v2 v2.1.0/go.mod h1:CXyZc4kcDaJ+s2SglGofkbHbSjXC6zFwKLJpEVYm5tw=
github.com/wealdtech/go-eth2-util v1.1.2 h1:m56HKJgWSuNy53Gt5GN7HcoFaGRCl1uE3OGWhIhWh1M=
github.com/wealdtech/go-eth2-util v1.1.2/go.mod h1:6Enc18JSH8FDy0sv/4ydEBbfoh3EOF++3HqLd66sO3M=
github.com/wealdtech/go-eth2-wallet v1.9.2 h1:H/T1n0SNd0jTsbf4rA4YxigsBPFWRUWgobsTOjzW4Hw=