forked from axieinfinity/ronin
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement high level function for bls_12381 (axieinfinity#296)
- Loading branch information
Showing
30 changed files
with
2,997 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//go:build go1.20 | ||
// +build go1.20 | ||
|
||
package common | ||
|
||
// These methods use go1.20 syntax to convert a byte slice to a fixed size array. | ||
|
||
// ToBytes4 is a convenience method for converting a byte slice to a fix | ||
// sized 4 byte array. This method will truncate the input if it is larger | ||
// than 4 bytes. | ||
func ToBytes4(x []byte) [4]byte { | ||
return [4]byte(PadTo(x, 4)) | ||
} | ||
|
||
// ToBytes20 is a convenience method for converting a byte slice to a fix | ||
// sized 20 byte array. This method will truncate the input if it is larger | ||
// than 20 bytes. | ||
func ToBytes20(x []byte) [20]byte { | ||
return [20]byte(PadTo(x, 20)) | ||
} | ||
|
||
// ToBytes32 is a convenience method for converting a byte slice to a fix | ||
// sized 32 byte array. This method will truncate the input if it is larger | ||
// than 32 bytes. | ||
func ToBytes32(x []byte) [32]byte { | ||
return [32]byte(PadTo(x, 32)) | ||
} | ||
|
||
// ToBytes48 is a convenience method for converting a byte slice to a fix | ||
// sized 48 byte array. This method will truncate the input if it is larger | ||
// than 48 bytes. | ||
func ToBytes48(x []byte) [48]byte { | ||
return [48]byte(PadTo(x, 48)) | ||
} | ||
|
||
// ToBytes64 is a convenience method for converting a byte slice to a fix | ||
// sized 64 byte array. This method will truncate the input if it is larger | ||
// than 64 bytes. | ||
func ToBytes64(x []byte) [64]byte { | ||
return [64]byte(PadTo(x, 64)) | ||
} | ||
|
||
// ToBytes96 is a convenience method for converting a byte slice to a fix | ||
// sized 96 byte array. This method will truncate the input if it is larger | ||
// than 96 bytes. | ||
func ToBytes96(x []byte) [96]byte { | ||
return [96]byte(PadTo(x, 96)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Package bls implements a go-wrapper around a library implementing the | ||
// BLS12-381 curve and signature scheme. This package exposes a public API for | ||
// verifying and aggregating BLS signatures used by Ethereum. | ||
package bls | ||
|
||
import ( | ||
"github.com/ethereum/go-ethereum/crypto/bls/blst" | ||
"github.com/ethereum/go-ethereum/crypto/bls/common" | ||
"github.com/ethereum/go-ethereum/crypto/bls/herumi" | ||
) | ||
|
||
// Initialize herumi temporarily while we transition to blst for ethdo. | ||
func init() { | ||
herumi.HerumiInit() | ||
} | ||
|
||
// SecretKeyFromBytes creates a BLS private key from a BigEndian byte slice. | ||
func SecretKeyFromBytes(privKey []byte) (SecretKey, error) { | ||
return blst.SecretKeyFromBytes(privKey) | ||
} | ||
|
||
// PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice. | ||
func PublicKeyFromBytes(pubKey []byte) (PublicKey, error) { | ||
return blst.PublicKeyFromBytes(pubKey) | ||
} | ||
|
||
// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice. | ||
func SignatureFromBytes(sig []byte) (Signature, error) { | ||
return blst.SignatureFromBytes(sig) | ||
} | ||
|
||
// MultipleSignaturesFromBytes creates a slice of BLS signatures from a LittleEndian 2d-byte slice. | ||
func MultipleSignaturesFromBytes(sigs [][]byte) ([]Signature, error) { | ||
return blst.MultipleSignaturesFromBytes(sigs) | ||
} | ||
|
||
// AggregatePublicKeys aggregates the provided raw public keys into a single key. | ||
func AggregatePublicKeys(pubs [][]byte) (PublicKey, error) { | ||
return blst.AggregatePublicKeys(pubs) | ||
} | ||
|
||
// AggregateMultiplePubkeys aggregates the provided decompressed keys into a single key. | ||
func AggregateMultiplePubkeys(pubs []PublicKey) PublicKey { | ||
return blst.AggregateMultiplePubkeys(pubs) | ||
} | ||
|
||
// AggregateSignatures converts a list of signatures into a single, aggregated sig. | ||
func AggregateSignatures(sigs []common.Signature) common.Signature { | ||
return blst.AggregateSignatures(sigs) | ||
} | ||
|
||
// AggregateCompressedSignatures converts a list of compressed signatures into a single, aggregated sig. | ||
func AggregateCompressedSignatures(multiSigs [][]byte) (common.Signature, error) { | ||
return blst.AggregateCompressedSignatures(multiSigs) | ||
} | ||
|
||
// VerifySignature verifies a single signature. For performance reason, always use VerifyMultipleSignatures if possible. | ||
func VerifySignature(sig []byte, msg [32]byte, pubKey common.PublicKey) (bool, error) { | ||
return blst.VerifySignature(sig, msg, pubKey) | ||
} | ||
|
||
// VerifyMultipleSignatures verifies multiple signatures for distinct messages securely. | ||
func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []common.PublicKey) (bool, error) { | ||
return blst.VerifyMultipleSignatures(sigs, msgs, pubKeys) | ||
} | ||
|
||
// NewAggregateSignature creates a blank aggregate signature. | ||
func NewAggregateSignature() common.Signature { | ||
return blst.NewAggregateSignature() | ||
} | ||
|
||
// RandKey creates a new private key using a random input. | ||
func RandKey() (common.SecretKey, error) { | ||
return blst.RandKey() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package bls | ||
|
||
import ( | ||
"github.com/stretchr/testify/require" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/crypto/bls/common" | ||
) | ||
|
||
func TestDisallowZeroSecretKeys(t *testing.T) { | ||
t.Run("blst", func(t *testing.T) { | ||
// Blst does a zero check on the key during deserialization. | ||
_, err := SecretKeyFromBytes(common.ZeroSecretKey[:]) | ||
require.Equal(t, common.ErrSecretUnmarshal, err) | ||
}) | ||
} | ||
|
||
func TestDisallowZeroPublicKeys(t *testing.T) { | ||
t.Run("blst", func(t *testing.T) { | ||
_, err := PublicKeyFromBytes(common.InfinitePublicKey[:]) | ||
require.Equal(t, common.ErrInfinitePubKey, err) | ||
}) | ||
} | ||
|
||
func TestDisallowZeroPublicKeys_AggregatePubkeys(t *testing.T) { | ||
t.Run("blst", func(t *testing.T) { | ||
_, err := AggregatePublicKeys([][]byte{common.InfinitePublicKey[:], common.InfinitePublicKey[:]}) | ||
require.Equal(t, common.ErrInfinitePubKey, err) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//go:build ((linux && amd64) || (linux && arm64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && !blst_disabled | ||
|
||
package blst | ||
|
||
import blst "github.com/supranational/blst/bindings/go" | ||
|
||
// Internal types for blst. | ||
type blstPublicKey = blst.P1Affine | ||
type blstSignature = blst.P2Affine | ||
type blstAggregateSignature = blst.P2Aggregate | ||
type blstAggregatePublicKey = blst.P1Aggregate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
//go:build ((linux && amd64) || (linux && arm64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && !blst_disabled | ||
|
||
package blst_test | ||
|
||
import ( | ||
"github.com/stretchr/testify/require" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/crypto/bls/blst" | ||
"github.com/ethereum/go-ethereum/crypto/bls/common" | ||
) | ||
|
||
func BenchmarkSignature_Verify(b *testing.B) { | ||
sk, err := blst.RandKey() | ||
require.NoError(b, err) | ||
|
||
msg := []byte("Some msg") | ||
sig := sk.Sign(msg) | ||
|
||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
if !sig.Verify(sk.PublicKey(), msg) { | ||
b.Fatal("could not verify sig") | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkSignature_AggregateVerify(b *testing.B) { | ||
sigN := 128 // MAX_ATTESTATIONS per block. | ||
|
||
var pks []common.PublicKey | ||
var sigs []common.Signature | ||
var msgs [][32]byte | ||
for i := 0; i < sigN; i++ { | ||
msg := [32]byte{'s', 'i', 'g', 'n', 'e', 'd', byte(i)} | ||
sk, err := blst.RandKey() | ||
require.NoError(b, err) | ||
sig := sk.Sign(msg[:]) | ||
pks = append(pks, sk.PublicKey()) | ||
sigs = append(sigs, sig) | ||
msgs = append(msgs, msg) | ||
} | ||
aggregated := blst.AggregateSignatures(sigs) | ||
|
||
b.ResetTimer() | ||
b.ReportAllocs() | ||
for i := 0; i < b.N; i++ { | ||
if !aggregated.AggregateVerify(pks, msgs) { | ||
b.Fatal("could not verify aggregate sig") | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkSecretKey_Marshal(b *testing.B) { | ||
key, err := blst.RandKey() | ||
require.NoError(b, err) | ||
d := key.Marshal() | ||
|
||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
_, err := blst.SecretKeyFromBytes(d) | ||
_ = err | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Package blst implements a go-wrapper around a library implementing the | ||
// BLS12-381 curve and signature scheme. This package exposes a public API for | ||
// verifying and aggregating BLS signatures used by Ethereum. | ||
// | ||
// This implementation uses the library written by Supranational, blst. | ||
package blst |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
//go:build ((linux && amd64) || (linux && arm64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && !blst_disabled | ||
|
||
package blst | ||
|
||
import ( | ||
"runtime" | ||
|
||
blst "github.com/supranational/blst/bindings/go" | ||
) | ||
|
||
func init() { | ||
// Reserve 1 core for general application work | ||
maxProcs := runtime.GOMAXPROCS(0) - 1 | ||
if maxProcs <= 0 { | ||
maxProcs = 1 | ||
} | ||
blst.SetMaxProcs(maxProcs) | ||
} |
Oops, something went wrong.