-
Notifications
You must be signed in to change notification settings - Fork 18
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
Define an abstract type for wallet.Sig #293
Conversation
- 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]>
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]>
Signed-off-by: Manoranjith <[email protected]>
3915786
to
0ecc12a
Compare
- 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]>
0ecc12a
to
be3a590
Compare
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) |
There was a problem hiding this comment.
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.
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() |
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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.
ethSigCopy := make([]byte, sigLen) | ||
copy(ethSigCopy, *ethSig) | ||
if ethSigCopy[sigLen-1] >= sigVSubtract { | ||
ethSigCopy[sigLen-1] -= sigVSubtract | ||
} |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
?
// | ||
// It is sent over wire as a binary data. |
There was a problem hiding this comment.
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.
// | |
// 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]) |
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) { |
There was a problem hiding this comment.
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?
General concern regarding this change: #295 (comment) |
Closed. See #233 for more details. |
Closes #292