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

Define an abstract type for wallet.Sig #293

Conversation

manoranjith
Copy link

Closes #292

Manoranjith added 7 commits December 14, 2021 16:03
- Previously Sig was defined as a variable length byte array and was
  encoded/decoded using the Encode/DecodeSig methods.

- But, its length depends upon the wallet backend. So, redefine it as an
  interface that implements binary.(Un)marshaler interfaces.

- Now, the wallet backend should implement the logic for converting a
  Sig to/from its binary representation. The perunio serializer can then
  directly Encode/Decode this binary representation as a byte array.

Signed-off-by: Manoranjith <[email protected]>
- Use a struct for storing the r and s components of the ECDSA
  signature.

- This eliminates the need for serializing / deserializing the
  signature each time when it is generated / verified respectively.

- Also, replace the test TestSignatureSerialize with
  GenericMarshalerTest

Signed-off-by: Manoranjith <[email protected]>
- Unexport the SigLen field, as it is not needed outside of the wallet
  package.

- Remove the length check in signature tests. Because, VerifySignature
  function checks if the signature was generated by the corresponding
  wallet, before verifying it it.

- In transactor tests, use the sigLen variable defined within the
  package.

Signed-off-by: Manoranjith <[email protected]>
- (En|De)code signatures directly using perunio.(En|De)code.

- SignData method on dummy account returns a Sig instead of byte array.

Signed-off-by: Manoranjith <[email protected]>
- After the wallet.Sig interface was introduced, each wallet backend
  defines its own concrete type for implementing the Sig interface.

- These implementations also include an UnmarshalBinary function, which
  is used for unmarshalling signatures from their binary representation.

- Because of this, when binary representations of signatures have
  incorrect length (when they are tampered), the unmarshalling of these
  signatures themselves fail. Which removes the need for checking the
  response of VerifySignature function for signatures of incorrect
  length.

- Hence, the tests are updated accordingly.

Signed-off-by: Manoranjith <[email protected]>
- Previously, signatures used in tests were directly generated as byte
  arrays.

- After the changing type of wallet.Sig from byte array to interface,
  this does not work.

- Hence, use the wallet randomizer to generate signatures needed for
  tests.

Signed-off-by: Manoranjith <[email protected]>
@manoranjith manoranjith force-pushed the 292-abstract-type-for-sig branch from 0ecc12a to be3a590 Compare December 14, 2021 12:39
Comment on lines +86 to +90
sigBytes, err := req.Sig.MarshalBinary()
if err != nil {
return nil, errors.WithMessage(err, "converting to byte array")
}
return a.contract.Progress(opts, params, state, ethNewState, ethActorIndex, sigBytes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a bit like you are mixing concerns here. MarshalBinary should typically be used by a marshaler that doesn't know much about the concrete type and just wants some byte representation. However, here we know the type and the contract expects a very specific byte representation.

Suggested change
sigBytes, err := req.Sig.MarshalBinary()
if err != nil {
return nil, errors.WithMessage(err, "converting to byte array")
}
return a.contract.Progress(opts, params, state, ethNewState, ethActorIndex, sigBytes)
sig, ok := req.Sig.(*ethwallet.Sig)
if !ok {
return nil, errors.Errorf("invalid signature type: %T", req.Sig)
}
return a.contract.Progress(opts, params, state, ethNewState, ethActorIndex, *sig)

var err error
for i := range signs {
if signs[i] != nil {
byteArrays[i], err = signs[i].MarshalBinary()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments as above (regarding concerns of MarshalBinary vs byte representation for a contract call) applies here.

if err != nil {
return assetholder.AssetHolderWithdrawalAuth{}, nil, errors.WithMessage(err, "sign data")
}
sigBytes, err := sig.MarshalBinary()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comments as above regarding byte representation for contract call applies here.

Comment on lines +59 to 63
ethSigCopy := make([]byte, sigLen)
copy(ethSigCopy, *ethSig)
if ethSigCopy[sigLen-1] >= sigVSubtract {
ethSigCopy[sigLen-1] -= sigVSubtract
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add a comment that explains what is happening here.

@@ -35,14 +35,15 @@ func (a *Account) Address() wallet.Address {
}

// SignData is used to sign data with this account.
func (a *Account) SignData(data []byte) ([]byte, error) {
func (a *Account) SignData(data []byte) (wallet.Sig, error) {
hash := crypto.Keccak256(data)
sig, err := a.wallet.SignText(a.Account, hash)
if err != nil {
return nil, errors.Wrap(err, "SignText")
}
sig[64] += 27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add a comment that explains what is happening here.

Should use a const instead of 27. Why is the linter not catching this?

c.Sig, err = wallet.DecodeSig(r)
return err
c.Sig = wallet.NewSig()
return perunio.Decode(r, c.Sig)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there is still a direct dependency from client onto perunio?

Comment on lines +30 to +31
//
// It is sent over wire as a binary data.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is not useful to mention here as it explains the functionality of a different package.

Suggested change
//
// It is sent over wire as a binary data.
//
// It is sent over wire as a binary data.

@@ -99,7 +116,8 @@ func DecodeSparseSigs(r io.Reader, sigs *[]Sig) (err error) {
if ((mask[maskIdx] >> bitIdx) % binaryModulo) == 0 {
(*sigs)[sigIdx] = nil
} else {
(*sigs)[sigIdx], err = DecodeSig(r)
(*sigs)[sigIdx] = NewSig()
err = perunio.Decode(r, (*sigs)[sigIdx])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there is still a direct dependency from wallet onto perunio?

@@ -111,15 +118,20 @@ func GenericSignatureSizeTest(t *testing.T, s *Setup) {
sign, err := acc.SignData(s.DataToSign)
require.NoError(t, err, "Sign with unlocked account should succeed")

signRaw, err := sign.MarshalBinary()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
signRaw, err := sign.MarshalBinary()
sigRaw, err := sig.MarshalBinary()

tamperer(&sigBytes)
return sigBytes
}

// GenericSignatureSizeTest tests that the size of the signatures produced by
// Account.Sign(…) does not vary between executions (tested with 2048 samples).
func GenericSignatureSizeTest(t *testing.T, s *Setup) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can throw that test out. Where do we specify that a signature byte representation must always have the same length?

@matthiasgeihs
Copy link
Contributor

General concern regarding this change: #295 (comment)

@matthiasgeihs
Copy link
Contributor

Closed. See #233 for more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add an abstract type for wallet.Sig
2 participants