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

refactor(auth): Move sig verification out of the for loop, into the authenticate method. #18780

Merged
merged 3 commits into from
Dec 19, 2023
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
2 changes: 2 additions & 0 deletions x/auth/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* [#18780](https://github.com/cosmos/cosmos-sdk/pull/18780) Move sig verification out of the for loop, into the authenticate method.

### API Breaking Changes

### Bug Fixes
122 changes: 65 additions & 57 deletions x/auth/ante/sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul

// stdSigs contains the sequence number, account number, and signatures.
// When simulating, this would just be a 0-length slice.
sigs, err := sigTx.GetSignaturesV2()
signatures, err := sigTx.GetSignaturesV2()
if err != nil {
return ctx, err
testinginprod marked this conversation as resolved.
Show resolved Hide resolved
}
Expand All @@ -320,77 +320,85 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
}

// check that signer length and signature length are the same
if len(sigs) != len(signers) {
return ctx, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signers), len(sigs))
if len(signatures) != len(signers) {
return ctx, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signers), len(signatures))
}

for i, sig := range sigs {
acc, err := GetSignerAcc(ctx, svd.ak, signers[i])
for i := range signers {
err = svd.authenticate(ctx, tx, simulate, signers[i], signatures[i])
if err != nil {
return ctx, err
}
}

// retrieve pubkey
pubKey := acc.GetPubKey()
if !simulate && pubKey == nil {
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
}
return next(ctx, tx, simulate)
}

if err := verifyIsOnCurve(pubKey); err != nil {
return ctx, err
}
// authenticate the authentication of the TX for a specific tx signer.
func (svd SigVerificationDecorator) authenticate(ctx sdk.Context, tx sdk.Tx, simulate bool, signer []byte, sig signing.SignatureV2) error {
acc, err := GetSignerAcc(ctx, svd.ak, signer)
if err != nil {
return err
}

if sig.Sequence != acc.GetSequence() {
return ctx, errorsmod.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}
// retrieve pubkey
pubKey := acc.GetPubKey()
if !simulate && pubKey == nil {
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
}

// retrieve signer data
genesis := ctx.BlockHeight() == 0
chainID := ctx.ChainID()
var accNum uint64
if !genesis {
accNum = acc.GetAccountNumber()
}
if err := verifyIsOnCurve(pubKey); err != nil {
return err
}

// no need to verify signatures on recheck tx
if !simulate && !ctx.IsReCheckTx() && ctx.IsSigverifyTx() {
anyPk, _ := codectypes.NewAnyWithValue(pubKey)
if sig.Sequence != acc.GetSequence() {
return errorsmod.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}

signerData := txsigning.SignerData{
Address: acc.GetAddress().String(),
ChainID: chainID,
AccountNumber: accNum,
Sequence: acc.GetSequence(),
PubKey: &anypb.Any{
TypeUrl: anyPk.TypeUrl,
Value: anyPk.Value,
},
}
adaptableTx, ok := tx.(authsigning.V2AdaptableTx)
if !ok {
return ctx, fmt.Errorf("expected tx to implement V2AdaptableTx, got %T", tx)
}
txData := adaptableTx.GetSigningTxData()
err = authsigning.VerifySignature(ctx, pubKey, signerData, sig.Data, svd.signModeHandler, txData)
if err != nil {
var errMsg string
if OnlyLegacyAminoSigners(sig.Data) {
// If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number,
// and therefore communicate sequence number as a potential cause of error.
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID)
} else {
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s): (%s)", accNum, chainID, err.Error())
}
return ctx, errorsmod.Wrap(sdkerrors.ErrUnauthorized, errMsg)
// retrieve signer data
genesis := ctx.BlockHeight() == 0
chainID := ctx.ChainID()
var accNum uint64
if !genesis {
accNum = acc.GetAccountNumber()
}

// no need to verify signatures on recheck tx
if !simulate && !ctx.IsReCheckTx() && ctx.IsSigverifyTx() {
anyPk, _ := codectypes.NewAnyWithValue(pubKey)

signerData := txsigning.SignerData{
Address: acc.GetAddress().String(),
ChainID: chainID,
AccountNumber: accNum,
Sequence: acc.GetSequence(),
PubKey: &anypb.Any{
TypeUrl: anyPk.TypeUrl,
Value: anyPk.Value,
},
}
adaptableTx, ok := tx.(authsigning.V2AdaptableTx)
if !ok {
return fmt.Errorf("expected tx to implement V2AdaptableTx, got %T", tx)
}
txData := adaptableTx.GetSigningTxData()
err = authsigning.VerifySignature(ctx, pubKey, signerData, sig.Data, svd.signModeHandler, txData)
if err != nil {
var errMsg string
if OnlyLegacyAminoSigners(sig.Data) {
// If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number,
// and therefore communicate sequence number as a potential cause of error.
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID)
} else {
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s): (%s)", accNum, chainID, err.Error())
}
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, errMsg)
}
}

return next(ctx, tx, simulate)
return nil
testinginprod marked this conversation as resolved.
Show resolved Hide resolved
}

// IncrementSequenceDecorator handles incrementing sequences of all signers.
Expand Down