Merge pull request #296 from filecoin-project/feat/verify-block-msg-signatures

Feat/verify block msg signatures
This commit is contained in:
Łukasz Magiera 2019-10-09 09:25:21 +02:00 committed by GitHub
commit b8bc54fd5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 22 deletions

View File

@ -336,12 +336,7 @@ func (cg *ChainGen) getRandomMessages() ([]*types.SignedMessage, error) {
GasPrice: types.NewInt(0), GasPrice: types.NewInt(0),
} }
unsigned, err := msg.Serialize() sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())
if err != nil {
return nil, err
}
sig, err := cg.w.Sign(context.TODO(), cg.banker, unsigned)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,7 +1,6 @@
package chain package chain
import ( import (
"encoding/base64"
"sync" "sync"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
@ -82,14 +81,9 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
} }
func (mp *MessagePool) addLocked(m *types.SignedMessage) error { func (mp *MessagePool) addLocked(m *types.SignedMessage) error {
data, err := m.Message.Serialize() log.Debugf("mpooladd: %s %s", m.Message.From, m.Message.Nonce)
if err != nil {
return err
}
log.Debugf("mpooladd: %d %s", m.Message.Nonce, base64.StdEncoding.EncodeToString(data)) if err := m.Signature.Verify(m.Message.From, m.Message.Cid().Bytes()); err != nil {
if err := m.Signature.Verify(m.Message.From, data); err != nil {
log.Warnf("mpooladd signature verification failed: %s", err) log.Warnf("mpooladd signature verification failed: %s", err)
return err return err
} }

View File

@ -14,6 +14,7 @@ import (
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
bls "github.com/filecoin-project/go-bls-sigs"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld" hamt "github.com/ipfs/go-hamt-ipld"
logging "github.com/ipfs/go-log" logging "github.com/ipfs/go-log"
@ -233,3 +234,43 @@ func (sm *StateManager) LoadActorState(ctx context.Context, a address.Address, o
return act, nil return act, nil
} }
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
switch addr.Protocol() {
case address.BLS, address.SECP256K1:
return addr, nil
case address.Actor:
return address.Undef, xerrors.New("cannot resolve actor address to key address")
default:
}
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
}
st, _, err := sm.TipSetState(ts)
if err != nil {
return address.Undef, xerrors.Errorf("resolve address failed to get tipset state: %w", err)
}
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
tree, err := state.LoadStateTree(cst, st)
if err != nil {
return address.Undef, xerrors.Errorf("failed to load state tree")
}
return vm.ResolveToKeyAddr(tree, cst, addr)
}
func (sm *StateManager) GetBlsPublicKey(ctx context.Context, addr address.Address, ts *types.TipSet) (pubk bls.PublicKey, err error) {
kaddr, err := sm.ResolveToKeyAddress(ctx, addr, ts)
if err != nil {
return pubk, xerrors.Errorf("failed to resolve address to key address: %w", err)
}
if kaddr.Protocol() != address.BLS {
return pubk, xerrors.Errorf("address must be BLS address to load bls public key")
}
copy(pubk[:], kaddr.Payload())
return pubk, nil
}

View File

@ -6,6 +6,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/filecoin-project/go-bls-sigs"
"github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/build" "github.com/filecoin-project/go-lotus/build"
"github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/actors"
@ -520,16 +521,28 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
bs := amt.WrapBlockstore(syncer.store.Blockstore()) bs := amt.WrapBlockstore(syncer.store.Blockstore())
var blsCids []cbg.CBORMarshaler var blsCids []cbg.CBORMarshaler
var sigCids []cid.Cid // this is what we get for people not wanting the marshalcbor method on the cid type
var pubks []bls.PublicKey
for i, m := range b.BlsMessages { for i, m := range b.BlsMessages {
if err := checkMsg(m); err != nil { if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err) return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
} }
sigCids = append(sigCids, m.Cid())
c := cbg.CborCid(m.Cid()) c := cbg.CborCid(m.Cid())
blsCids = append(blsCids, &c) blsCids = append(blsCids, &c)
pubk, err := syncer.sm.GetBlsPublicKey(ctx, m.From, baseTs)
if err != nil {
return xerrors.Errorf("failed to load bls public to validate block: %w", err)
}
pubks = append(pubks, pubk)
} }
bmroot, err := amt.FromArray(bs, blsCids)
if err != nil { if err := syncer.verifyBlsAggregate(h.BLSAggregate, sigCids, pubks); err != nil {
return xerrors.Errorf("failed to build amt from bls msg cids: %w", err) return xerrors.Errorf("bls aggregate signature was invalid: %w", err)
} }
var secpkCids []cbg.CBORMarshaler var secpkCids []cbg.CBORMarshaler
@ -537,9 +550,25 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
if err := checkMsg(&m.Message); err != nil { if err := checkMsg(&m.Message); err != nil {
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
} }
kaddr, err := syncer.sm.ResolveToKeyAddress(ctx, m.Message.From, baseTs)
if err != nil {
return xerrors.Errorf("failed to resolve key addr: %w", err)
}
if err := m.Signature.Verify(kaddr, m.Message.Cid().Bytes()); err != nil {
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
}
c := cbg.CborCid(m.Cid()) c := cbg.CborCid(m.Cid())
secpkCids = append(secpkCids, &c) secpkCids = append(secpkCids, &c)
} }
bmroot, err := amt.FromArray(bs, blsCids)
if err != nil {
return xerrors.Errorf("failed to build amt from bls msg cids: %w", err)
}
smroot, err := amt.FromArray(bs, secpkCids) smroot, err := amt.FromArray(bs, secpkCids)
if err != nil { if err != nil {
return xerrors.Errorf("failed to build amt from bls msg cids: %w", err) return xerrors.Errorf("failed to build amt from bls msg cids: %w", err)
@ -560,6 +589,21 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return nil return nil
} }
func (syncer *Syncer) verifyBlsAggregate(sig types.Signature, msgs []cid.Cid, pubks []bls.PublicKey) error {
var digests []bls.Digest
for _, c := range msgs {
digests = append(digests, bls.Hash(bls.Message(c.Bytes())))
}
var bsig bls.Signature
copy(bsig[:], sig.Data)
if !bls.Verify(bsig, digests, pubks) {
return xerrors.New("bls aggregate signature failed to verify")
}
return nil
}
func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) { func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
blockSet := []*types.TipSet{from} blockSet := []*types.TipSet{from}

View File

@ -40,12 +40,9 @@ func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byt
} }
func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) { func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) {
msgbytes, err := msg.Serialize() mcid := msg.Cid()
if err != nil {
return nil, err
}
sig, err := a.WalletSign(ctx, k, msgbytes) sig, err := a.WalletSign(ctx, k, mcid.Bytes())
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w", err) return nil, xerrors.Errorf("failed to sign message: %w", err)
} }