From 698b605eec06517a73d394107bcd692af43c7ab9 Mon Sep 17 00:00:00 2001 From: lunfardo314 <evaldas.drasutis@iota.org> Date: Wed, 25 Mar 2020 20:55:23 +0200 Subject: [PATCH] added BLS-BDN signature scheme and address --- go.mod | 1 + go.sum | 11 +++ .../binary/valuetransfer/address/address.go | 39 +++++++- .../address/signaturescheme/bls-bdn.go | 99 +++++++++++++++++++ .../address/signaturescheme/bls_test.go | 16 +++ .../address/signaturescheme/ed25519.go | 11 +-- .../valuetransfer/transaction/signatures.go | 2 +- 7 files changed, 168 insertions(+), 11 deletions(-) create mode 100644 packages/binary/valuetransfer/address/signaturescheme/bls-bdn.go create mode 100644 packages/binary/valuetransfer/address/signaturescheme/bls_test.go diff --git a/go.mod b/go.mod index a838712d..5cbc7fa9 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/spf13/viper v1.6.2 github.com/stretchr/testify v1.5.1 github.com/valyala/fasttemplate v1.1.0 // indirect + go.dedis.ch/kyber/v3 v3.0.12 go.uber.org/atomic v1.6.0 go.uber.org/zap v1.14.0 golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 diff --git a/go.sum b/go.sum index 9fca25e7..af601bdf 100644 --- a/go.sum +++ b/go.sum @@ -311,6 +311,15 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhe github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= +go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg= +go.dedis.ch/kyber/v3 v3.0.12 h1:15d61EyBcBoFIS97kS2c/Vz4o3FR8ALnZ2ck9J/ebYM= +go.dedis.ch/kyber/v3 v3.0.12/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U= +go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= +go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= +go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= @@ -334,6 +343,7 @@ golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -386,6 +396,7 @@ golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/packages/binary/valuetransfer/address/address.go b/packages/binary/valuetransfer/address/address.go index 265fbf0c..3af046a4 100644 --- a/packages/binary/valuetransfer/address/address.go +++ b/packages/binary/valuetransfer/address/address.go @@ -3,7 +3,6 @@ package address import ( "crypto/rand" "fmt" - "github.com/mr-tron/base58" "golang.org/x/crypto/blake2b" @@ -17,7 +16,15 @@ type Digest = []byte type Address [Length]byte +const ( + // every signature scheme has a version byte associated to it. + VERSION_ED25519 = byte(1) + VERSION_BLS_BDN = byte(2) +) + // Random creates a random address, which can for example be used in unit tests. +// first byte (version) is also random + func Random() (address Address) { // generate a random sequence of bytes addressBytes := make([]byte, Length) @@ -31,6 +38,22 @@ func Random() (address Address) { return } +// Random creates a random address of the given type, +// first byte (version) is given + +func RandomOfType(addrVersion byte) (address Address) { + // generate a random sequence of bytes + addressBytes := make([]byte, Length-1) + if _, err := rand.Read(addressBytes); err != nil { + panic(err) + } + + // copy the generated bytes into the result + copy(address[1:], addressBytes) + addressBytes[0] = addrVersion + return +} + // FromBase58 creates an address from a base58 encoded string. func FromBase58(base58String string) (address Address, err error) { // decode string @@ -56,7 +79,19 @@ func FromBase58(base58String string) (address Address, err error) { func FromED25519PubKey(key ed25119.PublicKey) (address Address) { digest := blake2b.Sum256(key[:]) - address[0] = 0 + address[0] = VERSION_ED25519 + copy(address[1:], digest[:]) + + return +} + +// FromBLSPubKey creates an address from marshaled BLS public key +// unmarshaled BLS public key conforms to interface kyber.Point + +func FromBLSPubKey(pubKey []byte) (address Address) { + digest := blake2b.Sum256(pubKey) + + address[0] = VERSION_BLS_BDN 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 new file mode 100644 index 00000000..fd3bb535 --- /dev/null +++ b/packages/binary/valuetransfer/address/signaturescheme/bls-bdn.go @@ -0,0 +1,99 @@ +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 { + suite.ScalarLen() + 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) + } + return &blsBdnSignature{ + pubKey: pubKeyBin, + signature: sig, + } +} + +// 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 + +type blsBdnSignature struct { + pubKey []byte + signature []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+len(sig.pubKey)+len(sig.signature)) + 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_test.go b/packages/binary/valuetransfer/address/signaturescheme/bls_test.go new file mode 100644 index 00000000..b181fc59 --- /dev/null +++ b/packages/binary/valuetransfer/address/signaturescheme/bls_test.go @@ -0,0 +1,16 @@ +package signaturescheme + +import ( + "github.com/magiconair/properties/assert" + "testing" +) + +func TestBLS_BDN(t *testing.T) { + dataToSign := []byte("testtesttest") + + blsSigScheme := RandBLS_BDN() + signature := blsSigScheme.Sign(dataToSign) + + assert.Equal(t, blsSigScheme.Address() == signature.Address(), true) + assert.Equal(t, signature.IsValid(dataToSign), true) +} diff --git a/packages/binary/valuetransfer/address/signaturescheme/ed25519.go b/packages/binary/valuetransfer/address/signaturescheme/ed25519.go index 997de93a..4a3db62f 100644 --- a/packages/binary/valuetransfer/address/signaturescheme/ed25519.go +++ b/packages/binary/valuetransfer/address/signaturescheme/ed25519.go @@ -10,11 +10,6 @@ import ( // region PUBLIC API /////////////////////////////////////////////////////////////////////////////////////////////////// -const ( - // every signature scheme has a version byte associated to it. - VERSION_ED25519 = byte(1) -) - // ED25519 creates an instance of a signature scheme, that is used to sign the corresponding address. func ED25519(keyPair ed25119.KeyPair) SignatureScheme { return &ed25519SignatureScheme{ @@ -33,7 +28,7 @@ type ed25519SignatureScheme struct { // Version returns the version byte that is associated to this signature scheme. func (signatureScheme *ed25519SignatureScheme) Version() byte { - return VERSION_ED25519 + return address.VERSION_ED25519 } // Address returns the address that this signature scheme instance is securing. @@ -82,7 +77,7 @@ func Ed25519SignatureFromBytes(bytes []byte, optionalTargetObject ...*ed25519Sig versionByte, err := marshalUtil.ReadByte() if err != nil { return - } else if versionByte != VERSION_ED25519 { + } else if versionByte != address.VERSION_ED25519 { err = fmt.Errorf("invalid version byte when parsing ed25519 signature") return @@ -116,7 +111,7 @@ func (signature *ed25519Signature) IsValid(signedData []byte) bool { // Bytes returns a marshaled version of the signature. func (signature *ed25519Signature) Bytes() []byte { marshalUtil := marshalutil.New(1 + ed25119.PublicKeySize + ed25119.SignatureSize) - marshalUtil.WriteByte(VERSION_ED25519) + marshalUtil.WriteByte(address.VERSION_ED25519) marshalUtil.WriteBytes(signature.publicKey[:]) marshalUtil.WriteBytes(signature.signature[:]) diff --git a/packages/binary/valuetransfer/transaction/signatures.go b/packages/binary/valuetransfer/transaction/signatures.go index 26f3f45f..ca2faf3f 100644 --- a/packages/binary/valuetransfer/transaction/signatures.go +++ b/packages/binary/valuetransfer/transaction/signatures.go @@ -47,7 +47,7 @@ func SignaturesFromBytes(bytes []byte, optionalTargetObject ...*Signatures) (res for versionByte != 0 { // perform signature scheme specific decoding switch versionByte { - case signaturescheme.VERSION_ED25519: + case address.VERSION_ED25519: marshalUtil.ReadSeek(-1) signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return signaturescheme.Ed25519SignatureFromBytes(data) }) if signatureErr != nil { -- GitLab