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

Introduce composite key to delegate features to each function key #101

Merged
merged 2 commits into from
Aug 17, 2020

Conversation

torao
Copy link
Contributor

@torao torao commented Jul 3, 2020

Closes: #95

Summary

  • Added BLS and Composite key definitions.
    • Changed the default key generation to Composite (BLS for signature and Ed25519 for VRF).
    • Added definitions to serialize BLS and Composite key to Amino and ProtocolBuffers.
    • Added methods to the PrivKey and PubKey interfaces to abstract VRF proving and verifying operation.
      • Move Proof and Output from vrf to crypto to avoid import circular references.
      • Added default implementations of those methods to existing ECDSA, Ed25519, Sr25519, and MultisigThreshold keys.
    • Changed the size of keys, signatures, and blocks that were hard-corded as expectations in the test.
    • Changed from a Ed25519-fixed part to a Composite key (maybe test only).
    • Added build tasks of the BLS native library to make it work properly on the target environment, Alpine.
      • CircleCI, Github workflow, Makefile, and Dockerfile.

Description

Introduces the BLS and Composite keys into the LINE Blockchain. This PR enables the BLS signature on the LINE Blockchain (VRF functionality remains with the Ed25519 key). It also enables the Composite key to differentiate between BSL and Ed25519 keys depending on their function.

Please note that BLS signature aggregation is a modification of the following.


For contributor use:

  • Wrote tests
  • Updated CHANGELOG_PENDING.md
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Updated relevant documentation (docs/) and code comments
  • Re-reviewed Files changed in the Github PR explorer

@torao torao added C: enhancement Classification: New feature or its request, or improvement in maintainability of code WIP labels Jul 3, 2020
@torao torao self-assigned this Jul 3, 2020
@torao torao force-pushed the feature/signature_aggregation branch 3 times, most recently from 4edece2 to e6d875b Compare July 6, 2020 07:56
@torao torao changed the base branch from master to develop July 6, 2020 07:58
@torao torao force-pushed the feature/signature_aggregation branch 11 times, most recently from 477d819 to b6715d4 Compare July 9, 2020 12:27
crypto/crypto.go Outdated
Comment on lines 98 to 100
Identity PrivKey `json:"identity"`
SignKey PrivKey `json:"sign"`
VrfKey PrivKey `json:"vrf"`
Copy link
Member

Choose a reason for hiding this comment

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

Do we need three keys?
As I said in the previous meeting, we're not going to use HSM, so I think we'll only need 2 keys.
And three keys are too many.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed VRF key to be the role of Identity.

crypto/crypto.go Outdated
func (pk PubKeyComposite) Validate() bool {
msg := b.NewBuffer(pk.SignKey.Bytes())
msg.Write(pk.VrfKey.Bytes())
return pk.Identity.VerifyBytes(msg.Bytes(), pk.Seal) &&
Copy link
Member

Choose a reason for hiding this comment

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

Is it works well?
Because the msg to be made with SignKey's PubKey byte and VrfKey's Pubkey byte is difference the msg to be made with SIgnKey's PrivKey bytes and VrfKey's PrivKey bytes.

(SignKey PubKe bytes + VrfKey PubKey bytes) != (SignKey PrivKey bytes + VrfKey PrivKey bytes)

The place to create the msg to generate the seal is is https:/line/tendermint/pull/101/files#diff-31c4aa3a4249d4755fc652d3e0087b98R121-R122

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The source is out of date, but this part was a bug. Now it doesn't use the seal (the signature of two-keys) and instead calculates its Address from the two-keys. Therefore, if one of the keys is tampered with, the address will always change.

@zemyblue
Copy link
Member

I think it's better that PubKeyComposite and PrivKeyComposite in the crypto.go file move to composite directory under cryto directory. If then, we can resolve the import cycle problem.

@torao torao force-pushed the feature/signature_aggregation branch from d2a2bbb to 9499629 Compare July 10, 2020 09:30
@torao
Copy link
Contributor Author

torao commented Jul 10, 2020

I was concerned about where to define this Composite key type, but I put it in crypto.go because it's not itself an implementation of a specific public key algorithm. However, the latest sources also seem to sub-package keys like multisig, similar to composite, so I'll do the same.

And there were two reasons for the cyclic import error. One will resolve by such a deployment, but another was due to the strong coupling between VRF and ed25519, which I solved both by interfacing the Proof and Output (thus, the current vrf probably should be placed under ed25519).

@torao torao force-pushed the feature/signature_aggregation branch from a28dab3 to f8d41a8 Compare July 10, 2020 10:35
@@ -688,6 +687,8 @@ type Commit struct {
BlockID BlockID `json:"block_id"`
Signatures []CommitSig `json:"signatures"`
Copy link
Member

Choose a reason for hiding this comment

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

Do you remove signature of CommitSig later?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The CommitSig contains the address of "who signed" information, so I'll leave it in the block. I'm considering to set the Signature []byte field in the CommitSig to nil or byte[0]after aggregating the signatures.

Copy link
Contributor Author

@torao torao Jul 10, 2020

Choose a reason for hiding this comment

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

I misunderstood a little bit; The CommitSig is not only a meta-information of the block, but also used by each Voter to send their signatures, so I'm considering to leave the Signature field in CommitSig.

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 it is better to define and use different types explicitly.
How about this

type Commit struct {
	Height     int64       `json:"height"`
	Round      int         `json:"round"`
	BlockID    BlockID     `json:"block_id"`
	Signers []CommitSigner `json:"signers"`
	AggregatedSignature []byte `json:"aggregated_signature"`
	hash     tmbytes.HexBytes
	bitArray *bits.BitArray
}
type CommitSigner struct {
	BlockIDFlag      BlockIDFlag `json:"block_id_flag"`
	ValidatorAddress Address     `json:"validator_address"`
	Timestamp        time.Time   `json:"timestamp"`
}

@torao torao force-pushed the feature/signature_aggregation branch from 0f3c118 to 642e48c Compare July 16, 2020 06:03
@torao torao force-pushed the feature/signature_aggregation branch 2 times, most recently from 6a504de to f72afd4 Compare July 17, 2020 04:51
@torao torao force-pushed the feature/signature_aggregation branch 9 times, most recently from 8eda5fc to 2838143 Compare August 6, 2020 08:18
@torao torao force-pushed the feature/signature_aggregation branch from 2838143 to 6994d02 Compare August 7, 2020 05:45
@torao torao changed the title WIP: Introduce composite key to delegate features to each function key Introduce composite key to delegate features to each function key Aug 7, 2020
@torao torao removed the WIP label Aug 7, 2020
@torao
Copy link
Contributor Author

torao commented Aug 7, 2020

I'll write down the problems that took a long time to solve.

  • A problem with multi-node tests (localnet, contract_test) that caused the test to fail due to a SIGTRAP issue was avoided by building a BLS native library on Alpine Docker container with nodes running. The cause is unclear, but it seems to be a conflict between Alpine and BLS pre-compiled binary, as this doesn't occur in Debian even in the same Docker container environment.
  • The actions/cache@v1 was used in test_abci_cli on Github workflow. However, the fix was not tested correctly because the cache-key was unchanged so previously built binaries were restored. This has been fixed to rebuild the cache by adding a hash value with hashFiles() to the key. This problem has existed since Tendermint release v0.33.4 and is not fixed in the latest v0.33.7. However, in the master branch, test_abci_cli itself has been largely fixed.

@@ -205,15 +204,20 @@ func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) types.Respon
}

// update
return app.updateValidator(types.Ed25519ValidatorUpdate(pubkey, power))
// TODO The type of public key to be restored should be kept its original type.
Copy link
Member

Choose a reason for hiding this comment

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

Do you have any plan to change the type of public key later?
Because you point it as TODO.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This TODO is a comment intended for #107. It'll be fixed when #107 fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I fixed the relevant part, but since there is no NewValidatorUpdate in the develop branch, the PR of 107 needs to wait for the source code of 101 to be merged.

power := tmrand.Int()
vals[i] = types.Ed25519ValidatorUpdate(pubkey, int64(power))
vals[i] = types.NewValidatorUpdate("composite", pubkey, int64(power))
Copy link
Member

Choose a reason for hiding this comment

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

I know ABCIPubKeyTypeComposite is same string const type with "composite".
So, I think it's the better to use ABCIPubKeyTypeComposite if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly, I'll fix it.

@@ -5,10 +5,10 @@ import (
"fmt"
"strings"

"github.com/tendermint/tendermint/cmd/contract_tests/unmarshaler"
Copy link
Member

Choose a reason for hiding this comment

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

Do you know why this import sorting is changed?
lint version is changed? or golang version is changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do different versions of goimports give different results? I'm not sure why it was corrected, but this is the result of applying make format (gofmt) locally.

% go version
go version go1.14.4 darwin/amd64

if !cpk.Equals(pk) {
t.Fatalf("The retrieved composite public key was not match: %+v != %+v", cpk, pk)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

How about adding more test for BLS12?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll fix it.

Comment on lines 77 to 79
//signKey := bls.GenPrivKey()
//vrfKey := ed25519.GenPrivKey()
//return composite.NewPrivKeyComposite(signKey, vrfKey).PubKey(), nil
Copy link
Member

Choose a reason for hiding this comment

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

If this lines don't need anymore, please remove this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see.

)

// RandVal creates one random validator, with a key derived
// from the input value
func RandVal(i int) types.ValidatorUpdate {
pubkey := tmrand.Bytes(32)
pk := composite.GenPrivKey().PubKey()
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 choosing which key to use should be handled in one place. The same is true in codes for testing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've defined another function that generates a private key for the example and tests.

type vrfEd25519 interface {
Prove(privateKey ed25519.PrivKeyEd25519, message []byte) (Proof, error)
Verify(publicKey ed25519.PubKeyEd25519, proof Proof, message []byte) (bool, error)
Prove(privateKey []byte, publicKey []byte, message []byte) (Proof, error)
Copy link
Contributor

@egonspace egonspace Aug 11, 2020

Choose a reason for hiding this comment

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

Can I ask the reason why you modified more specific parameter type(ed25519.PrivKeyEd25519) to general type([]byte)? I think it's better that vrfEd25519 interface methods use the type concerned with Ed25519.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a fix intended to eliminate circular references in import: since crypto/ed25519 must reference crypt/vrf, a reference to crypto/ed25519 in crypt/vrf will cause a circular reference. Indeed, passing the Ed25519 key type is better abstraction and natural, but we have to give preference to one over the other.

If golang supported type-class or generics, there would be a better way to write this, but for now, we use the generic notation as byte[].

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay I see.

@torao torao force-pushed the feature/signature_aggregation branch from 70cead1 to 0b9f890 Compare August 13, 2020 09:31
@torao torao force-pushed the feature/signature_aggregation branch from 0b9f890 to c6e66bc Compare August 13, 2020 09:56
Copy link
Contributor

@egonspace egonspace left a comment

Choose a reason for hiding this comment

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

LGTM

@torao torao merged commit 40a2944 into develop Aug 17, 2020
@tnasu tnasu deleted the feature/signature_aggregation branch December 24, 2020 08:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: enhancement Classification: New feature or its request, or improvement in maintainability of code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Aggregate Voter signatures on blocks
5 participants