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

BM-17: Add basic functianalities of bls crypto #12

Merged
merged 4 commits into from
Jun 16, 2022
Merged

Conversation

gitferry
Copy link
Contributor

Fixes https://babylon-chain.atlassian.net/browse/BM-17

This PR adds a wrapper of blst's go binding: https://github.com/supranational/blst/tree/1bd5899e4af46375d58fdfcb21c5ccf74181a35c/bindings/go

It implements basic functionalities around bls crypto as follows:

  • GenerateBlsKeyPair
  • SignMsg
  • VerifyBlsSig
  • AggregateBlsSigs
  • AggregateBlsPubKeys
  • VerifyBlsMultiSig

@SebastianElvis
Copy link
Member

SebastianElvis commented Jun 14, 2022

Great work! Two quick comments:

  1. Perhaps we need to ignore .idea/ stuff
  2. Can we have shorter API names such as Gen, Sign, Verify, AggSigs, AggPKs, and VerifyMulti?
  3. Since we have VerifyBlsMultiSig and do not invoke AggregateBlsPubKeys from outsides, can we make AggregateBlsPubKeys a private function (eg something like aggregateBlsPubKeys)?

@gitferry
Copy link
Contributor Author

Great work! Two quick comments:

  1. Perhaps we need to ignore .idea/ stuff
  2. Can we have shorter API names such as Gen, Sign, Verify, AggSigs, AggPKs, and VerifyMulti?
  3. Since we have VerifyBlsMultiSig and do not invoke AggregateBlsPubKeys from outsides, can we make AggregateBlsPubKeys a private function (eg something like aggregateBlsPubKeys)?

Thanks, @SebastianElvis! Re

  1. Absolutely! Nice catch.
  2. I'm not sure shorter API name is better since it may confuse with other crypto APIs that we might use in the future.
  3. Actually, we might use AggregateBlsPubKeys to cache aggregated pubkeys or to shorten the pubkey size. This API can also be used along with VerifyBlsSig. This is because, with an aggregated bls sig and an aggregated pub key, the verification of the sig is no different from the verification of an individual bls sig.

@SebastianElvis
Copy link
Member

  • I'm not sure shorter API name is better since it may confuse with other crypto APIs that we might use in the future.

When we use these APIs we need to write stuff like bls.Sign anyway. I don't have strong objection in this though.

@gitferry
Copy link
Contributor Author

  • I'm not sure shorter API name is better since it may confuse with other crypto APIs that we might use in the future.

When we use these APIs we need to write stuff like bls.Sign anyway. I don't have strong objection in this though.

Ah, you are right. Let's hear opinions from others.

@aakoshh
Copy link
Contributor

aakoshh commented Jun 14, 2022

Regarding naming, here's some advice: https://go.dev/doc/effective_go#names

As I understand you always evoke functions through the package name, so in this case it would be bls_multisig.AggregateBlsPubKeys. I reckon there's no need to have "BLS" twice in there, bls.AggrPubKeys would be enough, so I would remove Bls from all methods (SignMsg didn't have it anyway).

I don't know if it should be bls_multisig or bls; the former is a bit long, but it can always be renamed during import.
Also don't mind Generate or Gen - I think both Gen and Aggr are easy to recognise.

// SignMsg signs on a msg using a bls secret key
// the returned sig is compressed version with 48 byte size
func SignMsg(sk *blst.SecretKey, msg []byte) []byte {
return new(BlsSig).Sign(sk, msg, dst).Compress()
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't dst be the name of the return value? I can't see how this works.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is the Domain Separation Tag for signatures on G1 (minimal-signature-size). See https://github.com/apache/incubator-milagro-crypto-rust/blob/develop/src/bls381/basic.rs.


// GenerateBlsKeyPair generates a random bls key pair based on a given seed
// the public key is compressed with 96 byte size
func GenerateBlsKeyPair(seed []byte) (*blst.SecretKey, []byte) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It might help to have a struct to wrap the compressed public key, to track the type later.


// VerifyBlsSig verifies a bls sig over msg with a bls public key
// the sig and public key are all compressed
func VerifyBlsSig(sig []byte, pk []byte, msg []byte) bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wrapping signatures and public keys could help make sure we're not mixing them up.

Copy link
Contributor

Choose a reason for hiding this comment

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

So it would be something like

type Signature []byte 
type PublicKey []byte 

func VerifySig(sig Signature, pk PublicKey, msg []byte) bool

}

// AggregateBlsSigs aggregates bls sigs into a single bls signature
func AggregateBlsSigs(sigs [][]byte) ([]byte, bool) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to differentiate a type Sig []byte from a type MultiSig []byte ? Same for the public key types?

Copy link
Contributor

Choose a reason for hiding this comment

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

Can it be used to add individual signatures to an already aggregated signature? It should, right?

Copy link
Contributor Author

@gitferry gitferry Jun 15, 2022

Choose a reason for hiding this comment

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

Can it be used to add individual signatures to an already aggregated signature? It should, right?

Yes. Do I need to add a function like AggrSig(existingSig Signature, newSig Signature)? I think it relates to our previous discussion about accumulating options, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would it make sense to differentiate a type Sig []byte from a type MultiSig []byte ? Same for the public key types?

Would it be better if MultiSig and Sig are both represented as type Signature []byte? They are essentially points on a curve. Also, we can use Verify() to verify both a single bls sig or an aggregated bls sig.

}

// AggregateBlsPubKeys aggregates bls public keys into a single bls public key
func AggregateBlsPubKeys(pks [][]byte) ([]byte, bool) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this aggregate an already aggregated key plus a non-aggregated key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@aakoshh Yes, a public key and a sig are essentially points on the curve. Do I need to add a function like AggrPK(existingPK PublicKey, newPK PublicKey)?

@gitferry
Copy link
Contributor Author

@SebastianElvis @aakoshh, thanks for your review. I changed the API names to a shorter version and added a wrapper for the signature and public key. Please review it again. Thanks!

type Signature []byte
type PublicKey []byte

func (sig Signature) ToByte() []byte {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
func (sig Signature) ToByte() []byte {
func (sig Signature) Bytes() []byte {

Copy link
Member

Choose a reason for hiding this comment

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

This seems to be more consistent with existing Go functions like String(). Not strong objection though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Thanks!

return sig
}

func (pk PublicKey) ToByte() []byte {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
func (pk PublicKey) ToByte() []byte {
func (pk PublicKey) Bytes() []byte {

@SebastianElvis
Copy link
Member

LGTM except for the above two minor comments without strong objection.

Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Nice work! Some minor comments:


// GeneKeyPair generates a random bls key pair based on a given seed
// the public key is compressed with 96 byte size
func GeneKeyPair(seed []byte) (*blst.SecretKey, PublicKey) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
func GeneKeyPair(seed []byte) (*blst.SecretKey, PublicKey) {
func GenKeyPair(seed []byte) (*blst.SecretKey, PublicKey) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch! Thanks.

sigBytes[i] = sigs[i].ToByte()
}
if !aggSig.AggregateCompressed(sigBytes, false) {
return nil, false
Copy link
Member

Choose a reason for hiding this comment

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

Maybe it would be better if an error was returned.

Copy link
Member

Choose a reason for hiding this comment

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

or an explanation why we are returning a boolean value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Thanks!

pkBytes[i] = pks[i].ToByte()
}
if !aggPk.AggregateCompressed(pkBytes, false) {
return nil, false
Copy link
Member

Choose a reason for hiding this comment

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

Maybe an error is appropriate here as well.

type BlsMultiPubKey = blst.P2Aggregate

// Domain Separation Tag for signatures on G1 (minimal-signature-size)
var dst = []byte("BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_")
Copy link
Member

Choose a reason for hiding this comment

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

Can this be a constant? Also, upper case letters might separate the confusion from the common variable name dst referring to destination.

Copy link
Contributor Author

@gitferry gitferry Jun 16, 2022

Choose a reason for hiding this comment

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

Nice point. Thanks!

I just found that we may not be able to have this as a constant because Go does not support const array. See https://stackoverflow.com/questions/13137463/declare-a-constant-array

@gitferry
Copy link
Contributor Author

@SebastianElvis @vitsalis Thanks for your comments. I added error return and addressed naming issues.

Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Thanks for resolving! Some extra very minor comments mostly related to capitalization of BLS across the codebase.

.gitignore Show resolved Hide resolved
crypto/bls12381/bls.go Show resolved Hide resolved
crypto/bls12381/bls.go Outdated Show resolved Hide resolved
crypto/bls12381/bls.go Outdated Show resolved Hide resolved
crypto/bls12381/bls.go Outdated Show resolved Hide resolved
crypto/bls12381/bls.go Outdated Show resolved Hide resolved
crypto/bls12381/bls.go Outdated Show resolved Hide resolved
crypto/bls12381/bls_test.go Outdated Show resolved Hide resolved
crypto/bls12381/bls_test.go Outdated Show resolved Hide resolved
crypto/bls12381/types.go Show resolved Hide resolved
@gitferry
Copy link
Contributor Author

Thanks @vitsalis for the follow-up comments. I capitalized "bls" in comments but when I changed DST to const, an error occurred. Please see it in the reply. Thanks!

Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Thanks for the changes! LGTM 🚀

@gitferry gitferry merged commit a8c0aa1 into main Jun 16, 2022
@gitferry gitferry deleted the gai-add-bls-wrapper branch June 16, 2022 12:26
@aakoshh
Copy link
Contributor

aakoshh commented Jun 22, 2022

@gitferry when you merge a PR, please use the "Squash" functionality of Github so main ends up with one commit for your whole PR.

Look, your individual commits are all visible in the main history, versus the other PRs that have a nice commit message pointing at the PR
image

It's this button you want to click, you can switch to it with the drop down:
image

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.

4 participants