Skip to content
Snippets Groups Projects
Commit 864405f8 authored by lunfardo314's avatar lunfardo314
Browse files

added BLS signature aggregation added

parent 3535036a
Branches
Tags
No related merge requests found
......@@ -19,7 +19,7 @@ type Address [Length]byte
const (
// every signature scheme has a version byte associated to it.
VERSION_ED25519 = byte(1)
VERSION_BLS_BDN = byte(2)
VERSION_BLS = byte(2)
)
// Random creates a random address, which can for example be used in unit tests.
......@@ -70,7 +70,7 @@ func FromED25519PubKey(key ed25119.PublicKey) (address Address) {
func FromBLSPubKey(pubKey []byte) (address Address) {
digest := blake2b.Sum256(pubKey)
address[0] = VERSION_BLS_BDN
address[0] = VERSION_BLS
copy(address[1:], digest[:])
return
......
package signaturescheme
import (
"bytes"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/pairing/bn256"
"go.dedis.ch/kyber/v3/sign/bdn"
"go.dedis.ch/kyber/v3/util/random"
)
// BLS_BDN implements BLS signature scheme which is robust agains rogue public key attacks
// it uses go.dedis/kyber library
// more info https://github.com/dedis/kyber/blob/master/sign/bdn/bdn.go
// usually BLS signatures are used as threshold signatures.
// This package don't implement any threshold signature related primitives.
// it only implements what is needed for the node to check validity of the BLS signatures against addresses
// and also minimum signing required for testing
var suite = bn256.NewSuite()
// blsBdnSignatureScheme defines an interface for the BLS signatures.
// here it is unmarshaled because only used for testing
type blsBdnSignatureScheme struct {
privKey kyber.Scalar
pubKey kyber.Point
}
// RandBLS_BDN creates an RANDOM instance of a signature scheme, that is used to sign the corresponding address.
// mostly intended for testing.
func RandBLS_BDN() SignatureScheme {
ret := &blsBdnSignatureScheme{}
ret.privKey, ret.pubKey = bdn.NewKeyPair(suite, random.New()) // only for testing: deterministic!
return ret
}
func (sigscheme *blsBdnSignatureScheme) Version() byte {
return address.VERSION_BLS_BDN
}
func (sigscheme *blsBdnSignatureScheme) Address() address.Address {
b, err := sigscheme.pubKey.MarshalBinary()
if err != nil {
panic(err)
}
return address.FromBLSPubKey(b)
}
func (sigscheme *blsBdnSignatureScheme) Sign(data []byte) Signature {
sig, err := bdn.Sign(suite, sigscheme.privKey, data)
if err != nil {
panic(err)
}
pubKeyBin, err := sigscheme.pubKey.MarshalBinary()
if err != nil {
panic(err)
}
ret := &blsBdnSignature{}
copy(ret.pubKey[:], pubKeyBin)
copy(ret.signature[:], sig)
return ret
}
// interface contract (allow the compiler to check if the implementation has all of the required methods).
var _ SignatureScheme = &blsBdnSignatureScheme{}
// BLS-BDN signature, in binary marshaled form
const (
BLS_SIGNATURE_SIZE = 64
BLS_PUBLIC_KEY_SIZE = 128
)
type blsBdnSignature struct {
pubKey [BLS_PUBLIC_KEY_SIZE]byte
signature [BLS_SIGNATURE_SIZE]byte
}
func (sig *blsBdnSignature) IsValid(signedData []byte) bool {
// unmarshal public key
pubKey := suite.G2().Point()
if err := pubKey.UnmarshalBinary(sig.pubKey[:]); err != nil {
return false
}
return bdn.Verify(suite, pubKey, signedData, sig.signature[:]) == nil
}
func (sig *blsBdnSignature) Bytes() []byte {
b := make([]byte, 1+BLS_PUBLIC_KEY_SIZE+BLS_SIGNATURE_SIZE)
buf := bytes.NewBuffer(b)
buf.WriteByte(address.VERSION_BLS_BDN)
buf.Write(sig.pubKey[:])
buf.Write(sig.signature[:])
return b
}
func (sig *blsBdnSignature) Address() address.Address {
return address.FromBLSPubKey(sig.pubKey[:])
}
// interface contract (allow the compiler to check if the implementation has all of the required methods).
var _ Signature = &blsBdnSignature{}
package signaturescheme
import (
"fmt"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
"github.com/mr-tron/base58"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/pairing/bn256"
"go.dedis.ch/kyber/v3/sign"
"go.dedis.ch/kyber/v3/sign/bdn"
"go.dedis.ch/kyber/v3/util/random"
"math/rand"
)
// BLS implements BLS signature scheme which is robust against rogue public key attacks, or BDN
// it uses go.dedis/kyber library
// more info https://github.com/dedis/kyber/blob/master/sign/bdn/bdn.go
// usually BLS signatures are used as threshold signatures.
// This package doesn't implement any threshold signature related primitives.
// it only contains what is needed for the node to check validity of the BLS signatures against addresses
// and also minimum signing required for testing
var suite = bn256.NewSuite()
const (
BLS_SIGNATURE_SIZE = 64
BLS_PUBLIC_KEY_SIZE = 128
BLS_PRIVATE_KEY_SIZE = 32
)
// ---------------- implements SignatureScheme interface
// blsSignatureScheme defines an interface for the key pairs of BLS signatures.
type blsSignatureScheme struct {
priKey kyber.Scalar
pubKey kyber.Point
}
// deterministic sequence
var rnd = random.New(rand.New(rand.NewSource(42)))
// RandBLS creates a RANDOM instance of a signature scheme, that is used to sign the corresponding address.
// mostly intended for testing.
// only for testing: each time same sequence!
func RandBLS() SignatureScheme {
ret := &blsSignatureScheme{}
ret.priKey, ret.pubKey = bdn.NewKeyPair(suite, rnd)
return ret
}
// BLS creates an instance of BLS signature scheme
// from given private and public keys in marshaled binary form
func BLS(priKey, pubKey []byte) (SignatureScheme, error) {
if len(priKey) != BLS_PRIVATE_KEY_SIZE || len(pubKey) != BLS_PUBLIC_KEY_SIZE {
return nil, fmt.Errorf("wrong key size")
}
ret := &blsSignatureScheme{
priKey: suite.G2().Scalar(),
pubKey: suite.G2().Point(),
}
if err := ret.pubKey.UnmarshalBinary(pubKey); err != nil {
return nil, err
}
if err := ret.priKey.UnmarshalBinary(priKey); err != nil {
return nil, err
}
return ret, nil
}
func (sigscheme *blsSignatureScheme) Version() byte {
return address.VERSION_BLS
}
func (sigscheme *blsSignatureScheme) Address() address.Address {
b, err := sigscheme.pubKey.MarshalBinary()
if err != nil {
panic(err)
}
return address.FromBLSPubKey(b)
}
func (sigscheme *blsSignatureScheme) Sign(data []byte) Signature {
sig, err := bdn.Sign(suite, sigscheme.priKey, data)
if err != nil {
panic(err)
}
pubKeyBin, err := sigscheme.pubKey.MarshalBinary()
if err != nil {
panic(err)
}
return newBLSSignature(pubKeyBin, sig)
}
func (sigscheme *blsSignatureScheme) String() string {
pri, err := sigscheme.priKey.MarshalBinary()
if err != nil {
return fmt.Sprintf("BLS sigsheme: %v", err)
}
pub, err := sigscheme.pubKey.MarshalBinary()
if err != nil {
return fmt.Sprintf("BLS sigsheme: %v", err)
}
return base58.Encode(pri) + ", " + base58.Encode(pub)
}
// interface contract (allow the compiler to check if the implementation has all of the required methods).
var _ SignatureScheme = &blsSignatureScheme{}
// ---------------- implements Signature interface
type blsSignature [1 + BLS_PUBLIC_KEY_SIZE + BLS_SIGNATURE_SIZE]byte
func newBLSSignature(pubKey, signature []byte) *blsSignature {
var ret blsSignature
ret[0] = address.VERSION_BLS
copy(ret.pubKey(), pubKey)
copy(ret.signature(), signature)
return &ret
}
func (sig *blsSignature) pubKey() []byte {
return sig[1 : BLS_PUBLIC_KEY_SIZE+1]
}
func (sig *blsSignature) signature() []byte {
return sig[1+BLS_PUBLIC_KEY_SIZE:]
}
func (sig *blsSignature) IsValid(signedData []byte) bool {
if sig[0] != address.VERSION_BLS {
return false
}
// unmarshal public key
pubKey := suite.G2().Point()
if err := pubKey.UnmarshalBinary(sig.pubKey()); err != nil {
return false
}
return bdn.Verify(suite, pubKey, signedData, sig.signature()) == nil
}
func (sig *blsSignature) Bytes() []byte {
return sig[:]
}
func (sig *blsSignature) Address() address.Address {
return address.FromBLSPubKey(sig.pubKey())
}
func (sig *blsSignature) String() string {
return base58.Encode(sig[:])
}
func AggregateBLSSignatureSchemes(sigSchemes ...SignatureScheme) (SignatureScheme, error) {
priKeys := make([]kyber.Scalar, len(sigSchemes))
pubKeys := make([]kyber.Point, len(sigSchemes))
for i, s := range sigSchemes {
ss, ok := s.(*blsSignatureScheme)
if !ok {
return nil, fmt.Errorf("not a BLS signature scheme")
}
priKeys[i] = ss.priKey
pubKeys[i] = ss.pubKey
}
aggregatedPriKey := suite.G2().Scalar().Zero()
// sum up all private keys
for i := range priKeys {
aggregatedPriKey = aggregatedPriKey.Add(aggregatedPriKey, priKeys[i])
}
mask, _ := sign.NewMask(suite, pubKeys, nil)
for i := range pubKeys {
_ = mask.SetBit(i, true)
}
aggregatedPubKey, err := bdn.AggregatePublicKeys(suite, mask)
if err != nil {
return nil, err
}
return &blsSignatureScheme{
priKey: aggregatedPriKey,
pubKey: aggregatedPubKey,
}, nil
}
func AggregateBLSSignatures(sigs ...Signature) (Signature, error) {
if len(sigs) == 0 {
return nil, fmt.Errorf("must be at least one signature to aggregate")
}
if len(sigs) == 1 {
return sigs[0], nil
}
pubKeys := make([]kyber.Point, len(sigs))
signatures := make([][]byte, len(sigs))
var err error
for i, sig := range sigs {
sigBls, ok := sig.(*blsSignature)
if !ok {
return nil, fmt.Errorf("not a BLS signature")
}
pubKeys[i] = suite.G2().Point()
if err = pubKeys[i].UnmarshalBinary(sigBls.pubKey()); err != nil {
return nil, err
}
signatures[i] = sigBls.signature()
}
mask, _ := sign.NewMask(suite, pubKeys, nil)
for i := range pubKeys {
_ = mask.SetBit(i, true)
}
aggregatedSignature, err := bdn.AggregateSignatures(suite, signatures, mask)
if err != nil {
return nil, err
}
sigBin, err := aggregatedSignature.MarshalBinary()
if err != nil {
return nil, err
}
aggregatedPubKey, err := bdn.AggregatePublicKeys(suite, mask)
if err != nil {
return nil, err
}
pubKeyBin, err := aggregatedPubKey.MarshalBinary()
if err != nil {
return nil, err
}
return newBLSSignature(pubKeyBin, sigBin), nil
}
// interface contract (allow the compiler to check if the implementation has all of the required methods).
var _ Signature = &blsSignature{}
......@@ -5,12 +5,40 @@ import (
"testing"
)
func TestBLS_BDN(t *testing.T) {
dataToSign := []byte("testtesttest")
var dataToSign = []byte("Hello Boneh-Lynn-Shacham (BLS) --> Boneh-Drijvers-Neven (BDN)")
blsSigScheme := RandBLS_BDN()
func TestBLS_base(t *testing.T) {
blsSigScheme := RandBLS()
t.Logf("generating random BLS signature scheme: %s\n", blsSigScheme.(*blsSignatureScheme).String())
signature := blsSigScheme.Sign(dataToSign)
assert.Equal(t, blsSigScheme.Address() == signature.Address(), true)
assert.Equal(t, signature.IsValid(dataToSign), true)
assert.Equal(t, blsSigScheme.Address(), signature.Address())
res := signature.IsValid(dataToSign)
assert.Equal(t, res, true)
}
// number of signatures to aggregate
const numSigs = 100
func TestBLS_aggregation(t *testing.T) {
sigs := make([]Signature, numSigs)
sigSchemes := make([]SignatureScheme, numSigs)
for i := range sigs {
sigSchemes[i] = RandBLS()
sigs[i] = sigSchemes[i].Sign(dataToSign)
}
aggregatedSig1, err := AggregateBLSSignatures(sigs...)
assert.Equal(t, err, nil)
assert.Equal(t, aggregatedSig1.IsValid(dataToSign), true)
aggregatedScheme, err := AggregateBLSSignatureSchemes(sigSchemes...)
assert.Equal(t, err, nil)
if err == nil {
aggregatedSig2 := aggregatedScheme.Sign(dataToSign)
assert.Equal(t, aggregatedSig2, aggregatedSig2)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment