diff --git a/packages/binary/valuetransfer/address/address.go b/packages/binary/valuetransfer/address/address.go
index d721526f521976bd7890e49e0dd11166c7e8ebb3..b73092fd6fd8d9c522be45fd802fda80824088fe 100644
--- a/packages/binary/valuetransfer/address/address.go
+++ b/packages/binary/valuetransfer/address/address.go
@@ -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
diff --git a/packages/binary/valuetransfer/address/signaturescheme/bls-bdn.go b/packages/binary/valuetransfer/address/signaturescheme/bls-bdn.go
deleted file mode 100644
index fe001cbda901c639c68ce2bb71aeacee04705405..0000000000000000000000000000000000000000
--- a/packages/binary/valuetransfer/address/signaturescheme/bls-bdn.go
+++ /dev/null
@@ -1,103 +0,0 @@
-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{}
diff --git a/packages/binary/valuetransfer/address/signaturescheme/bls.go b/packages/binary/valuetransfer/address/signaturescheme/bls.go
new file mode 100644
index 0000000000000000000000000000000000000000..b20d3273933d17a7ea1a41c1f77892bd4deb3335
--- /dev/null
+++ b/packages/binary/valuetransfer/address/signaturescheme/bls.go
@@ -0,0 +1,232 @@
+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{}
diff --git a/packages/binary/valuetransfer/address/signaturescheme/bls_test.go b/packages/binary/valuetransfer/address/signaturescheme/bls_test.go
index b181fc5926477c20586cf29fe0a05f92fe327773..28e1a3a78b508d3d304f2aa365eabeb696e44694 100644
--- a/packages/binary/valuetransfer/address/signaturescheme/bls_test.go
+++ b/packages/binary/valuetransfer/address/signaturescheme/bls_test.go
@@ -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)
+	}
 }