Skip to content

Commit

Permalink
Schnorr Verification Checks
Browse files Browse the repository at this point in the history
Added `schnorr.VerifyWithChecks` which checks if the scalars and
points are canonical and ensures the points do not have a small
order for Edwards25519 Group.

Builds on top of #432 and closes #431

Co-authored-by: David Cerezo <[email protected]>
  • Loading branch information
gnarula and calctopian committed Aug 12, 2020
1 parent 88245de commit ae2b6ff
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 3 deletions.
32 changes: 29 additions & 3 deletions sign/schnorr/schnorr.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"fmt"

"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/group/edwards25519"
"go.dedis.ch/kyber/v3/sign/eddsa"
)

// Suite represents the set of functionalities needed by the package schnorr.
Expand Down Expand Up @@ -57,9 +59,16 @@ func Sign(s Suite, private kyber.Scalar, msg []byte) ([]byte, error) {
return b.Bytes(), nil
}

// Verify verifies a given Schnorr signature. It returns nil iff the
// given signature is valid.
func Verify(g kyber.Group, public kyber.Point, msg, sig []byte) error {
// VerifyWithChecks uses a public key buffer, a message and a signature.
// It will return nil if sig is a valid signature for msg created by
// key public, or an error otherwise. Compared to `Verify`, it performs
// additional checks around the canonicality and ensures the public key
// does not have a small order when using `edwards25519` group.
func VerifyWithChecks(g kyber.Group, pub, msg, sig []byte) error {
if _, ok := g.(*edwards25519.SuiteEd25519); ok {
return eddsa.VerifyWithChecks(pub, msg, sig)
}

R := g.Point()
s := g.Scalar()
pointSize := R.MarshalSize()
Expand All @@ -74,6 +83,12 @@ func Verify(g kyber.Group, public kyber.Point, msg, sig []byte) error {
if err := s.UnmarshalBinary(sig[pointSize:]); err != nil {
return err
}

public := g.Point()
err := public.UnmarshalBinary(pub)
if err != nil {
return fmt.Errorf("schnorr: error unmarshalling public key")
}
// recompute hash(public || R || msg)
h, err := hash(g, public, R, msg)
if err != nil {
Expand All @@ -91,6 +106,17 @@ func Verify(g kyber.Group, public kyber.Point, msg, sig []byte) error {
}

return nil

}

// Verify verifies a given Schnorr signature. It returns nil iff the
// given signature is valid.
func Verify(g kyber.Group, public kyber.Point, msg, sig []byte) error {
PBuf, err := public.MarshalBinary()
if err != nil {
return fmt.Errorf("error unmarshalling public key: %s", err)
}
return VerifyWithChecks(g, PBuf, msg, sig)
}

func hash(g kyber.Group, public, r kyber.Point, msg []byte) (kyber.Scalar, error) {
Expand Down
29 changes: 29 additions & 0 deletions sign/schnorr/schnorr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,32 @@ func TestQuickSchnorrSignature(t *testing.T) {
t.Error(err)
}
}

func TestSchnorrMalleability(t *testing.T) {
/* l = 2^252+27742317777372353535851937790883648493, prime order of the base point */
var L []uint16 = []uint16{0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}
var c uint16 = 0

msg := []byte("Hello Schnorr")
suite := edwards25519.NewBlakeSHA256Ed25519()
kp := key.NewKeyPair(suite)

s, err := Sign(suite, kp.Private, msg)
assert.NoErrorf(t, err, "Couldn't sign msg: %s: %v", msg, err)

err = Verify(suite, kp.Public, msg, s)
assert.NoErrorf(t, err, "Couldn't verify signature (schnorr.Verify): \n%+v\nfor msg:'%s'. Error:\n%v", s, msg, err)

// Add l to signature
for i := 0; i < 32; i++ {
c += uint16(s[32+i]) + L[i]
s[32+i] = byte(c)
c >>= 8
}
assert.Error(t, eddsa.Verify(kp.Public, msg, s))

err = Verify(suite, kp.Public, msg, s)
assert.Error(t, err, "schnorr signature malleable")
}

0 comments on commit ae2b6ff

Please sign in to comment.