Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support creation and signing of Eth keys #5593

Merged
merged 1 commit into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions pkg/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,16 @@ func NewBLSKeyFromSeed(seed io.Reader) (KeyInfo, error) {
copy(k, make([]byte, len(k))) // wipe with zero bytes
return *ki, nil
}

func NewDelegatedKeyFromSeed(seed io.Reader) (KeyInfo, error) {
k, err := sigs[crypto.SigTypeDelegated].GenPrivateFromSeed(seed)
if err != nil {
return KeyInfo{}, err
}
ki := &KeyInfo{
SigType: SigTypeDelegated,
}
ki.SetPrivateKey(k)
copy(k, make([]byte, len(k))) // wipe with zero bytes
return *ki, nil
}
32 changes: 32 additions & 0 deletions pkg/crypto/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/filecoin-project/venus/pkg/crypto"
_ "github.com/filecoin-project/venus/pkg/crypto/bls"
_ "github.com/filecoin-project/venus/pkg/crypto/delegated"
_ "github.com/filecoin-project/venus/pkg/crypto/secp"
tf "github.com/filecoin-project/venus/pkg/testhelpers/testflags"
)
Expand Down Expand Up @@ -108,6 +109,37 @@ func TestBLSSigning(t *testing.T) {
require.Error(t, err)
}

func TestDelegatedSigning(t *testing.T) {
token := bytes.Repeat([]byte{42}, 512)
ki, err := crypto.NewDelegatedKeyFromSeed(bytes.NewReader(token))
assert.NoError(t, err)

data := []byte("data to be signed")
privateKey := ki.Key()
publicKey, err := ki.PublicKey()
assert.NoError(t, err)
t.Logf("%x", privateKey)
t.Logf("%x", publicKey)

signature, err := crypto.Sign(data, privateKey[:], crypto.SigTypeDelegated)
require.NoError(t, err)

addr, err := ki.Address()
require.NoError(t, err)
t.Logf("%v", addr.String())

err = crypto.Verify(signature, addr, data)
require.NoError(t, err)

// invalid signature fails
err = crypto.Verify(&crypto.Signature{Type: crypto.SigTypeDelegated, Data: signature.Data[3:]}, addr, data)
require.Error(t, err)

// invalid digest fails
err = crypto.Verify(signature, addr, data[3:])
require.Error(t, err)
}

func aggregateSignatures(sigs []*crypto.Signature) (*crypto.Signature, error) {
sigsS := make([]ffi.Signature, len(sigs))
for i := 0; i < len(sigs); i++ {
Expand Down
10 changes: 9 additions & 1 deletion pkg/crypto/delegated/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ func (delegatedSigner) ToPublic(pk []byte) ([]byte, error) {
}

func (delegatedSigner) Sign(pk []byte, msg []byte) ([]byte, error) {
return nil, fmt.Errorf("not implemented")
hasher := sha3.NewLegacyKeccak256()
hasher.Write(msg)
hashSum := hasher.Sum(nil)
sig, err := gocrypto.Sign(pk, hashSum)
if err != nil {
return nil, err
}

return sig, nil
}

func (delegatedSigner) Verify(sig []byte, a address.Address, msg []byte) error {
Expand Down
18 changes: 17 additions & 1 deletion pkg/crypto/keyinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (

"github.com/awnumar/memguard"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/crypto"
logging "github.com/ipfs/go-log/v2"
"github.com/pkg/errors"
"golang.org/x/crypto/sha3"
)

const (
Expand Down Expand Up @@ -150,9 +152,23 @@ func (ki *KeyInfo) Address() (address.Address, error) {
if ki.SigType == SigTypeBLS {
return address.NewBLSAddress(pubKey)
}
if ki.SigType == SigTypeSecp256k1 || ki.SigType == SigTypeDelegated {
if ki.SigType == SigTypeSecp256k1 {
return address.NewSecp256k1Address(pubKey)
}
if ki.SigType == SigTypeDelegated {
// Assume eth for now
hasher := sha3.NewLegacyKeccak256()
// if we get an uncompressed public key (that's what we get from the library,
// but putting this check here for defensiveness), strip the prefix
if pubKey[0] == 0x04 {
pubKey = pubKey[1:]
}

hasher.Write(pubKey)

return address.NewDelegatedAddress(builtin.EthereumAddressManagerActorID, hasher.Sum(nil)[12:])
}

return address.Undef, errors.Errorf("can not generate address for unknown crypto system: %d", ki.SigType)
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/gen/genesis/fevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func SetupFEVM(ctx context.Context, cs *chain.Store, sroot cid.Cid, nv network.V
return fvm.NewVM(ctx, vmopt)
}

genesisVm, err := newVM(sroot)
genesisVM, err := newVM(sroot)
if err != nil {
return cid.Undef, fmt.Errorf("creating vm: %w", err)
}
Expand Down Expand Up @@ -111,11 +111,11 @@ func SetupFEVM(ctx context.Context, cs *chain.Store, sroot cid.Cid, nv network.V

// TODO method 3 is Exec4; we have to name the methods in go-state-types and avoid using the number
// directly.
if _, err := doExecValue(ctx, genesisVm, builtintypes.InitActorAddr, builtintypes.EthereumAddressManagerActorAddr, big.Zero(), 3, mustEnc(params)); err != nil {
if _, err := doExecValue(ctx, genesisVM, builtintypes.InitActorAddr, builtintypes.EthereumAddressManagerActorAddr, big.Zero(), 3, mustEnc(params)); err != nil {
return cid.Undef, fmt.Errorf("creating ETH0 actor: %w", err)
}

newroot, err := genesisVm.Flush(ctx)
newroot, err := genesisVM.Flush(ctx)
if err != nil {
return cid.Undef, fmt.Errorf("flushing vm: %w", err)
}
Expand Down
16 changes: 15 additions & 1 deletion pkg/wallet/dsbackend.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,27 @@ func (backend *DSBackend) NewAddress(ctx context.Context, protocol address.Proto
switch protocol {
case address.BLS:
return backend.newBLSAddress(ctx)
case address.SECP256K1, address.Delegated:
case address.SECP256K1:
return backend.newSecpAddress(ctx)
case address.Delegated:
return backend.newDelegatedAddress(ctx)
default:
return address.Undef, errors.Errorf("Unknown address protocol %d", protocol)
}
}

func (backend *DSBackend) newDelegatedAddress(ctx context.Context) (address.Address, error) {
ki, err := crypto.NewDelegatedKeyFromSeed(rand.Reader)
if err != nil {
return address.Undef, err
}

if err := backend.putKeyInfo(ctx, &ki); err != nil {
return address.Undef, err
}
return ki.Address()
}

func (backend *DSBackend) newSecpAddress(ctx context.Context) (address.Address, error) {
ki, err := crypto.NewSecpKeyFromSeed(rand.Reader)
if err != nil {
Expand Down
45 changes: 45 additions & 0 deletions pkg/wallet/wallet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
bls "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/venus/pkg/config"
"github.com/filecoin-project/venus/pkg/crypto"
_ "github.com/filecoin-project/venus/pkg/crypto/delegated" // enable delegated signatures
tf "github.com/filecoin-project/venus/pkg/testhelpers/testflags"
)

Expand Down Expand Up @@ -132,6 +133,50 @@ func TestWalletBLSKeys(t *testing.T) {
})
}

func TestWalletDelegatedKeys(t *testing.T) {
tf.UnitTest(t)

w, wb := newWalletAndDSBackend(t)

ctx := context.Background()
addr, err := w.NewAddress(ctx, address.Delegated)
require.NoError(t, err)

data := []byte("data to be signed")
// stm: @WALLET_WALLET_SIGN_BYTES_001
sig, err := w.SignBytes(ctx, data, addr)
require.NoError(t, err)

t.Run("address is delegated protocol", func(t *testing.T) {
assert.Equal(t, address.Delegated, addr.Protocol())
})

t.Run("key uses delegated cryptography", func(t *testing.T) {
ki, err := wb.GetKeyInfo(context.Background(), addr)
require.NoError(t, err)
assert.Equal(t, crypto.SigTypeDelegated, ki.SigType)
})

t.Run("valid signatures verify", func(t *testing.T) {
err := crypto.Verify(sig, addr, data)
assert.NoError(t, err)
})

t.Run("invalid signatures do not verify", func(t *testing.T) {
notTheData := []byte("not the data")
err := crypto.Verify(sig, addr, notTheData)
assert.Error(t, err)

notTheSig := &crypto.Signature{
Type: crypto.SigTypeDelegated,
Data: make([]byte, bls.SignatureBytes),
}
copy(notTheSig.Data[:], "not the sig")
err = crypto.Verify(notTheSig, addr, data)
assert.Error(t, err)
})
}

func TestSimpleSignAndVerify(t *testing.T) {
tf.UnitTest(t)

Expand Down
2 changes: 1 addition & 1 deletion venus-shared/types/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func EthAddressFromHex(s string) (EthAddress, error) {
func EthAddressFromBytes(b []byte) (EthAddress, error) {
var a EthAddress
if len(b) != EthAddressLength {
return EthAddress{}, xerrors.Errorf("cannot parse bytes into anœ EthAddress: incorrect input length")
return EthAddress{}, xerrors.Errorf("cannot parse bytes into an EthAddress: incorrect input length")
}
copy(a[:], b[:])
return a, nil
Expand Down
2 changes: 1 addition & 1 deletion venus-shared/utils/method_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func loadMethodsMap() {
methodMeta.Params = et.In(0)
}

methods[abi.MethodNum(number)] = methodMeta
methods[number] = methodMeta
}

MethodsMap[actor.Code()] = methods
Expand Down