From f3d2c5429e934804a06b8b380819d0d9810914e6 Mon Sep 17 00:00:00 2001 From: donutnomad Date: Wed, 16 Oct 2024 16:37:09 +0800 Subject: [PATCH] refactor: optimized --- go.mod | 6 +++- go.sum | 6 ++-- xcurve25519/sign.go | 48 ++++++++++++------------- xcurve25519/sign_test.go | 7 ++-- xcurve25519/signature.go | 6 ++++ xed25519/edwards.go | 14 -------- xed25519/pubkey.go | 50 ++++++++++++++++++++++++++ xed25519/sign.go | 4 +++ xsecp256k1/{publickey.go => pubkey.go} | 0 9 files changed, 97 insertions(+), 44 deletions(-) create mode 100644 xed25519/pubkey.go rename xsecp256k1/{publickey.go => pubkey.go} (100%) diff --git a/go.mod b/go.mod index 512bfec..ee0cf36 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,12 @@ go 1.23.0 require ( filippo.io/edwards25519 v1.1.0 + github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/samber/lo v1.47.0 ) -require golang.org/x/text v0.19.0 // indirect +require ( + github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect + golang.org/x/text v0.19.0 // indirect +) diff --git a/go.sum b/go.sum index a205a7a..bc5cd6a 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,14 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= +github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3 h1:l/lhv2aJCUignzls81+wvga0TFlyoZx8QxRMQgXpZik= +github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3/go.mod h1:AKpV6+wZ2MfPRJnTbQ6NPgWrKzbe9RCIlCF/FKzMtM8= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= diff --git a/xcurve25519/sign.go b/xcurve25519/sign.go index f4221c0..a836f0e 100644 --- a/xcurve25519/sign.go +++ b/xcurve25519/sign.go @@ -6,10 +6,9 @@ import ( "github.com/donutnomad/blockchain-alg/internal/hashs" "github.com/donutnomad/blockchain-alg/xed25519" "github.com/samber/lo" - "strconv" ) -type PublicKey []byte +type PublicKey = xed25519.PublicKey const SignatureSize = 64 @@ -19,40 +18,36 @@ func Sign(priKey [32]byte, message []byte, random []byte) [64]byte { priKey[0] &= 248 priKey[31] &= 127 priKey[31] |= 64 - - pubBs := scalarBaseMult(priKey) - signature := xed25519.SignFromScalar(priKey, pubBs, generateNonce(priKey, message, random), message, "", "") - return UniformSignature(pubBs[31], signature) + var ed25519PriKey = priKey + var ed25519PubKey = scalarBaseMult(ed25519PriKey) + var nonce = generateNonce(ed25519PriKey, message, random) + var signature = xed25519.SignFromScalar(ed25519PriKey, ed25519PubKey, nonce, message, "", "") + return UniformSignature(ed25519PubKey[31], signature) } -func Verify(pubCurve25519 PublicKey, message, sig []byte) bool { - if l := len(pubCurve25519); l != ed25519.PublicKeySize { - panic("ed25519: bad public key length: " + strconv.Itoa(l)) - } - if len(sig) != ed25519.SignatureSize { - return false - } - sig[63] &= 127 - return ed25519.Verify(ed25519.PublicKey(pubCurve25519), message, sig) +func Verify(pubCurve25519 PublicKey, message []byte, sig [64]byte) bool { + return VerifyByEd25519(pubCurve25519.ToEd25519WithSig(sig[63]), message, sig) } // SignByEd25519 signs a message using an Ed25519 private key and converts the resulting signature to Curve25519 format. func SignByEd25519(priEd25519 ed25519.PrivateKey, message []byte) Signature { - pubEd25519 := priEd25519[32:64] - signature := [64]byte(xed25519.Sign(priEd25519[:], message)) - return UniformSignature(pubEd25519[31], signature) + signature := xed25519.Sign(priEd25519[:], message) + return UniformSignature(priEd25519[63], [64]byte(signature)) } -// VerifyByEd25519 verifies a message signature using an Ed25519 public key. -// It checks if the provided signature, which is in Curve25519 format, is valid for the given message. -func VerifyByEd25519(pubEd25519 ed25519.PublicKey, message []byte, sig Signature) bool { - if l := len(pubEd25519); l != ed25519.PublicKeySize { - panic("ed25519: bad public key length: " + strconv.Itoa(l)) - } +func VerifyByEd25519(pubEd25519 xed25519.PublicKey, message []byte, sig Signature) bool { + orig := sig[63] + defer func() { + sig[63] = orig + }() sig[63] &= 127 return ed25519.Verify(pubEd25519[:], message, sig[:]) } +func GenPubKey(pri [32]byte) [32]byte { + return scalarBaseMultMontgomery(pri) +} + var magic = [32]byte{0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} // signs a message 'hash' using the given private scalar priv. @@ -70,6 +65,11 @@ func scalarBaseMult(v [32]byte) [32]byte { return [32]byte(new(edwards25519.Point).ScalarBaseMult(scalar).Bytes()) } +func scalarBaseMultMontgomery(v [32]byte) [32]byte { + scalar := lo.Must1(edwards25519.NewScalar().SetBytesWithClamping(v[:])) + return [32]byte(new(edwards25519.Point).ScalarBaseMult(scalar).BytesMontgomery()) +} + func mod(v [64]byte) (*edwards25519.Scalar, [32]byte) { scalar := lo.Must1(edwards25519.NewScalar().SetUniformBytes(v[:])) return scalar, [32]byte(scalar.Bytes()) diff --git a/xcurve25519/sign_test.go b/xcurve25519/sign_test.go index 8fc26c6..1be105d 100644 --- a/xcurve25519/sign_test.go +++ b/xcurve25519/sign_test.go @@ -5,6 +5,7 @@ import ( "crypto/ed25519" "crypto/rand" "github.com/donutnomad/blockchain-alg/internal/utils" + "github.com/donutnomad/blockchain-alg/xed25519" "github.com/samber/lo" "io" "testing" @@ -33,10 +34,10 @@ func TestSign2(t *testing.T) { message := []byte("data to be sign") for i := 0; i < 10000; i++ { var priBs = [32]byte(randBs(32)) - var pub = scalarBaseMult(priBs) + var pub = GenPubKey(priBs) var random = randBs(64) var sig = Sign(priBs, message, random) - if !Verify(pub[:], message, sig[:]) { + if !Verify(pub, message, sig) { panic("invalid signature") } } @@ -47,7 +48,7 @@ func TestSignByEd25519Key(t *testing.T) { for i := 0; i < 1; i++ { publicKey, privateKey := lo.Must2(ed25519.GenerateKey(rand.Reader)) sig := SignByEd25519(privateKey, message) - if !VerifyByEd25519(publicKey[:], message, sig) { + if !VerifyByEd25519(xed25519.PublicKey(publicKey), message, sig) { panic("invalid signature") } } diff --git a/xcurve25519/signature.go b/xcurve25519/signature.go index 56e5ca5..dd99b80 100644 --- a/xcurve25519/signature.go +++ b/xcurve25519/signature.go @@ -1,7 +1,13 @@ package xcurve25519 +import "github.com/donutnomad/blockchain-alg/xed25519" + func UniformSignature(pubEndByte byte, signature [64]byte) Signature { signature[63] &= 127 /*bbbbbbbb & 01111111 ==> clear first byte*/ signature[63] |= pubEndByte & 128 /*endByte & 10000000 ==> keep the first byte when it is 0*/ return signature } + +func ConvertEd25519PubKeyAndSig(pub xed25519.PublicKey, sig [64]byte) (pubCurve25519 PublicKey, _ Signature) { + return pub.ToEd25519(), UniformSignature(pub[len(pub)-1], sig) +} diff --git a/xed25519/edwards.go b/xed25519/edwards.go index 26e9586..513a191 100644 --- a/xed25519/edwards.go +++ b/xed25519/edwards.go @@ -5,20 +5,6 @@ import ( "filippo.io/edwards25519/field" ) -type PublicKey [32]byte - -// ToCurve25519 Ed25519's PublicKey to Curve25519 -func (pub PublicKey) ToCurve25519() (PublicKey, error) { - return edwardsToMontgomery(pub) -} - -// ToEd25519 Curve25519's PublicKey to Ed25519 -func (pub PublicKey) ToEd25519() (out PublicKey) { - res := montgomeryToEdwards(pub) - copy(out[:], res) - return out -} - var one = new(field.Element).One() func edwardsToMontgomery(publicKey [32]byte) (out [32]byte, _ error) { diff --git a/xed25519/pubkey.go b/xed25519/pubkey.go new file mode 100644 index 0000000..1918bd0 --- /dev/null +++ b/xed25519/pubkey.go @@ -0,0 +1,50 @@ +package xed25519 + +import ( + "errors" + "github.com/decred/dcrd/dcrec/edwards/v2" + "github.com/donutnomad/blockchain-alg/xasn1" +) + +var BadFormatPublicKeyErr = errors.New("bad format") + +type PublicKey [32]byte + +// ToCurve25519 Ed25519's PublicKey to Curve25519 +func (pub PublicKey) ToCurve25519() (PublicKey, error) { + return edwardsToMontgomery(pub) +} + +// ToEd25519 Curve25519's PublicKey to Ed25519 +func (pub PublicKey) ToEd25519() (out PublicKey) { + res := montgomeryToEdwards(pub) + copy(out[:], res) + return out +} + +// ToEd25519WithSig Curve25519's PublicKey to Ed25519 with last signature byte +func (pub PublicKey) ToEd25519WithSig(sigEndByte byte) PublicKey { + res := pub.ToEd25519() + res[31] &= 127 + res[31] |= sigEndByte & 128 + return res +} + +func ParsePubKey(serialized [32]byte) (key PublicKey, err error) { + pubKey, err := edwards.ParsePubKey(serialized[:]) + if err != nil { + return PublicKey{}, err + } + return PublicKey(pubKey.Serialize()), nil +} + +func ParsePubKeyASN1(bs []byte) (key PublicKey, err error) { + serialized, err := xasn1.ParsePKIXPublicKey(bs) + if err != nil { + return PublicKey{}, err + } + if len(serialized) != 32 { + return PublicKey{}, BadFormatPublicKeyErr + } + return ParsePubKey([32]byte(serialized)) +} diff --git a/xed25519/sign.go b/xed25519/sign.go index 0ba9ed4..dd25b29 100644 --- a/xed25519/sign.go +++ b/xed25519/sign.go @@ -48,6 +48,10 @@ func SignFromScalar(privateKey, publicKey, r [32]byte, message []byte, domPrefix return signature } +func Verify(publicKey PublicKey, message, sig []byte) bool { + return ed25519.Verify(publicKey[:], message, sig) +} + func must[T any](v T, err error) T { if err != nil { panic(err) diff --git a/xsecp256k1/publickey.go b/xsecp256k1/pubkey.go similarity index 100% rename from xsecp256k1/publickey.go rename to xsecp256k1/pubkey.go