Repository: lestrrat-go/jwx
Pull request #438 (2021-08-17 21:11:28)

Play the coverage game

codecov-commenter: # [Codecov](https://codecov.io/gh/lestrrat-go/jwx/pull/438?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) Report
> Merging [#438](https://codecov.io/gh/lestrrat-go/jwx/pull/438?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) (157c20a) into [main](https://codecov.io/gh/lestrrat-go/jwx/commit/422ff6c18807b95deced9a817b175798ff6024ba?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) (422ff6c) will **increase** coverage by `0.03%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/lestrrat-go/jwx/pull/438/graphs/tree.svg?width=650&height=150&src=pr&token=kU2RSDosPt&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go)](https://codecov.io/gh/lestrrat-go/jwx/pull/438?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go)

```diff
@@            Coverage Diff             @@
##             main     #438      +/-   ##
==========================================
+ Coverage   70.36%   70.40%   +0.03%     
==========================================
  Files          80       79       -1     
  Lines        9233     9223      -10     
==========================================
- Hits         6497     6493       -4     
+ Misses       1883     1877       -6     
  Partials      853      853              
```


| [Impacted Files](https://codecov.io/gh/lestrrat-go/jwx/pull/438?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) | Coverage Δ | |
|---|---|---|
| [internal/json/goccy.go](https://codecov.io/gh/lestrrat-go/jwx/pull/438/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-aW50ZXJuYWwvanNvbi9nb2NjeS5nbw==) | | |
| [jwe/internal/keyenc/keyenc.go](https://codecov.io/gh/lestrrat-go/jwx/pull/438/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andlL2ludGVybmFsL2tleWVuYy9rZXllbmMuZ28=) | `64.98% <0.00%> (+0.89%)` | :arrow_up: |
| [jwe/decrypt.go](https://codecov.io/gh/lestrrat-go/jwx/pull/438/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andlL2RlY3J5cHQuZ28=) | `52.07% <0.00%> (+1.77%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/lestrrat-go/jwx/pull/438?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/lestrrat-go/jwx/pull/438?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go). Last update [422ff6c...157c20a](https://codecov.io/gh/lestrrat-go/jwx/pull/438?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go).


Patch:
diff --git a/go.mod b/go.mod
index 5ed87997..62fdfc01 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,6 @@ require (
 	github.com/lestrrat-go/httpcc v1.0.0
 	github.com/lestrrat-go/iter v1.0.1
 	github.com/lestrrat-go/option v1.0.0
-	github.com/lestrrat-go/pdebug/v3 v3.0.1
 	github.com/pkg/errors v0.9.1
 	github.com/stretchr/testify v1.7.0
 	golang.org/x/crypto v0.0.0-20201217014255-9d1352758620
diff --git a/go.sum b/go.sum
index 982b1d6a..a096821c 100644
--- a/go.sum
+++ b/go.sum
@@ -16,11 +16,8 @@ github.com/lestrrat-go/httpcc v1.0.0 h1:FszVC6cKfDvBKcJv646+lkh4GydQg2Z29scgUfkO
 github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE=
 github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A=
 github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
-github.com/lestrrat-go/option v0.0.0-20210103042652-6f1ecfceda35/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
-github.com/lestrrat-go/pdebug/v3 v3.0.1 h1:3G5sX/aw/TbMTtVc9U7IHBWRZtMvwvBziF1e4HoQtv8=
-github.com/lestrrat-go/pdebug/v3 v3.0.1/go.mod h1:za+m+Ve24yCxTEhR59N7UlnJomWwCiIqbJRmKeiADU4=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
diff --git a/internal/jose/jose.go b/internal/jose/jose.go
index 7842d149..19245fcd 100644
--- a/internal/jose/jose.go
+++ b/internal/jose/jose.go
@@ -5,14 +5,12 @@ import (
 	"context"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os/exec"
 	"strings"
 	"sync"
 	"testing"
 
 	"github.com/lestrrat-go/jwx/internal/jwxtest"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -158,13 +156,6 @@ func DecryptJwe(ctx context.Context, t *testing.T, cfile, kfile string) ([]byte,
 	t.Helper()
 
 	cmdargs := []string{"jwe", "dec", "-i", cfile, "-k", kfile}
-	if pdebug.Enabled {
-		cbuf, _ := ioutil.ReadFile(cfile)
-		pdebug.Printf(`JWE message file contains "%s"`, cbuf)
-		kbuf, _ := ioutil.ReadFile(kfile)
-		pdebug.Printf(`JWK key file contains "%s"`, kbuf)
-	}
-
 	var output bytes.Buffer
 	if err := RunJoseCommand(ctx, t, cmdargs, &output, nil); err != nil {
 		jwxtest.DumpFile(t, cfile)
@@ -244,13 +235,6 @@ func VerifyJws(ctx context.Context, t *testing.T, cfile, kfile string) ([]byte,
 	t.Helper()
 
 	cmdargs := []string{"jws", "ver", "-i", cfile, "-k", kfile, "-O-"}
-	if pdebug.Enabled {
-		cbuf, _ := ioutil.ReadFile(cfile)
-		pdebug.Printf(`JWE message file contains "%s"`, cbuf)
-		kbuf, _ := ioutil.ReadFile(kfile)
-		pdebug.Printf(`JWK key file contains "%s"`, kbuf)
-	}
-
 	var output bytes.Buffer
 	if err := RunJoseCommand(ctx, t, cmdargs, &output, nil); err != nil {
 		jwxtest.DumpFile(t, cfile)
diff --git a/jwe/decrypt.go b/jwe/decrypt.go
index df6c4fba..4fc2ef30 100644
--- a/jwe/decrypt.go
+++ b/jwe/decrypt.go
@@ -17,7 +17,6 @@ import (
 	"github.com/lestrrat-go/jwx/jwe/internal/content_crypt"
 	"github.com/lestrrat-go/jwx/jwe/internal/keyenc"
 	"github.com/lestrrat-go/jwx/x25519"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -138,11 +137,6 @@ func (d *Decrypter) ContentCipher() (content_crypt.Cipher, error) {
 }
 
 func (d *Decrypter) Decrypt(recipientKey, ciphertext []byte) (plaintext []byte, err error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker().BindError(&err)
-		defer g.End()
-	}
-
 	cek, keyerr := d.DecryptKey(recipientKey)
 	if keyerr != nil {
 		err = errors.Wrap(keyerr, `failed to decrypt key`)
@@ -160,32 +154,18 @@ func (d *Decrypter) Decrypt(recipientKey, ciphertext []byte) (plaintext []byte,
 		computedAad = append(append(computedAad, '.'), d.aad...)
 	}
 
-	if pdebug.Enabled {
-		pdebug.Printf("Calling cipher.Decrypt (cipher = %T, cek len = %d)", cipher, len(cek))
-	}
-
 	plaintext, err = cipher.Decrypt(cek, d.iv, ciphertext, d.tag, computedAad)
 	if err != nil {
 		err = errors.Wrap(err, `failed to decrypt payload`)
 		return
 	}
 
-	if pdebug.Enabled {
-		pdebug.Printf("Successfully decrypted payload")
-	}
 	return plaintext, nil
 }
 
 func (d *Decrypter) decryptSymmetricKey(recipientKey, cek []byte) ([]byte, error) {
-	if pdebug.Enabled {
-		pdebug.Printf("Detected symmetric key algorithm %s", d.keyalg)
-	}
-
 	switch d.keyalg {
 	case jwa.DIRECT:
-		if pdebug.Enabled {
-			pdebug.Printf("Successfully decrypted symmetric key (key len = %d)", len(cek))
-		}
 		return cek, nil
 	case jwa.PBES2_HS256_A128KW, jwa.PBES2_HS384_A192KW, jwa.PBES2_HS512_A256KW:
 		var hashFunc func() hash.Hash
@@ -217,15 +197,8 @@ func (d *Decrypter) decryptSymmetricKey(recipientKey, cek []byte) ([]byte, error
 			return nil, errors.Wrap(err, `failed to unwrap key`)
 		}
 
-		if pdebug.Enabled {
-			pdebug.Printf("cek len = %d", len(cek))
-			pdebug.Printf("Wrapped key len = %d", len(jek))
-		}
 		return jek, nil
 	case jwa.A128GCMKW, jwa.A192GCMKW, jwa.A256GCMKW:
-		if pdebug.Enabled {
-			pdebug.Printf("cek len = %d", len(cek))
-		}
 		if len(d.keyiv) != 12 {
 			return nil, errors.Errorf("GCM requires 96-bit iv, got %d", len(d.keyiv)*8)
 		}
@@ -253,10 +226,6 @@ func (d *Decrypter) decryptSymmetricKey(recipientKey, cek []byte) ([]byte, error
 }
 
 func (d *Decrypter) DecryptKey(recipientKey []byte) (cek []byte, err error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker().BindError(&err)
-		defer g.End()
-	}
 	if d.keyalg.IsSymmetric() {
 		var ok bool
 		cek, ok = d.privkey.([]byte)
@@ -277,10 +246,6 @@ func (d *Decrypter) DecryptKey(recipientKey []byte) (cek []byte, err error) {
 		return nil, errors.Wrap(err, `failed to decrypt key`)
 	}
 
-	if pdebug.Enabled {
-		pdebug.Printf("Successfully decrypted key")
-	}
-
 	return cek, nil
 }
 
diff --git a/jwe/encrypt.go b/jwe/encrypt.go
index 0b15053b..0b1b40bf 100644
--- a/jwe/encrypt.go
+++ b/jwe/encrypt.go
@@ -6,7 +6,6 @@ import (
 
 	"github.com/lestrrat-go/jwx/internal/base64"
 	"github.com/lestrrat-go/jwx/jwa"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -31,24 +30,12 @@ func releaseEncryptCtx(ctx *encryptCtx) {
 
 // Encrypt takes the plaintext and encrypts into a JWE message.
 func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	bk, err := e.generator.Generate()
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("Failed to generate key: %s", err)
-		}
 		return nil, errors.Wrap(err, "failed to generate key")
 	}
 	cek := bk.Bytes()
 
-	if pdebug.Enabled {
-		pdebug.Printf("Encrypt: generated cek len = %d", len(cek))
-	}
-
 	if e.protected == nil {
 		// shouldn't happen, but...
 		e.protected = NewHeaders()
@@ -82,9 +69,6 @@ func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
 
 		enckey, err := enc.Encrypt(cek)
 		if err != nil {
-			if pdebug.Enabled {
-				pdebug.Printf("Failed to encrypt key: %s", err)
-			}
 			return nil, errors.Wrap(err, `failed to encrypt key`)
 		}
 		if enc.Algorithm() == jwa.ECDH_ES || enc.Algorithm() == jwa.DIRECT {
@@ -102,9 +86,6 @@ func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
 				return nil, errors.Wrap(err, "failed to populate")
 			}
 		}
-		if pdebug.Enabled {
-			pdebug.Printf("Encrypt: encrypted_key = %x (%d)", enckey.Bytes(), len(enckey.Bytes()))
-		}
 		recipients[i] = r
 	}
 
@@ -131,20 +112,9 @@ func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
 	// ...on the other hand, there's only one content cipher.
 	iv, ciphertext, tag, err := e.contentEncrypter.Encrypt(cek, plaintext, aad)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("Failed to encrypt: %s", err)
-		}
 		return nil, errors.Wrap(err, "failed to encrypt payload")
 	}
 
-	if pdebug.Enabled {
-		pdebug.Printf("Encrypt.Encrypt: cek        = %x (%d)", cek, len(cek))
-		pdebug.Printf("Encrypt.Encrypt: aad        = %x (%d)", aad, len(aad))
-		pdebug.Printf("Encrypt.Encrypt: ciphertext = %x (%d)", ciphertext, len(ciphertext))
-		pdebug.Printf("Encrypt.Encrypt: iv         = %x (%d)", iv, len(iv))
-		pdebug.Printf("Encrypt.Encrypt: tag        = %x (%d)", tag, len(tag))
-	}
-
 	msg := NewMessage()
 
 	decodedAad, err := base64.Decode(aad)
diff --git a/jwe/internal/aescbc/aescbc.go b/jwe/internal/aescbc/aescbc.go
index 9e6d5b2d..f08f2cbe 100644
--- a/jwe/internal/aescbc/aescbc.go
+++ b/jwe/internal/aescbc/aescbc.go
@@ -10,7 +10,6 @@ import (
 	"fmt"
 	"hash"
 
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -66,21 +65,10 @@ type Hmac struct {
 type BlockCipherFunc func([]byte) (cipher.Block, error)
 
 func New(key []byte, f BlockCipherFunc) (hmac *Hmac, err error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker().BindError(&err)
-		defer g.End()
-	}
 	keysize := len(key) / 2
 	ikey := key[:keysize]
 	ekey := key[keysize:]
 
-	if pdebug.Enabled {
-		pdebug.Printf("New: keysize               = %d", keysize)
-		pdebug.Printf("New: cek (key)             = %x (%d)\n", key, len(key))
-		pdebug.Printf("New: ikey                  = %x (%d)\n", ikey, len(ikey))
-		pdebug.Printf("New: ekey                  = %x (%d)\n", ekey, len(ekey))
-	}
-
 	bc, ciphererr := f(ekey)
 	if ciphererr != nil {
 		err = errors.Wrap(ciphererr, `failed to execute block cipher function`)
@@ -123,13 +111,6 @@ func (c Hmac) Overhead() int {
 }
 
 func (c Hmac) ComputeAuthTag(aad, nonce, ciphertext []byte) ([]byte, error) {
-	if pdebug.Enabled {
-		pdebug.Printf("ComputeAuthTag: aad        = %x (%d)\n", aad, len(aad))
-		pdebug.Printf("ComputeAuthTag: ciphertext = %x (%d)\n", ciphertext, len(ciphertext))
-		pdebug.Printf("ComputeAuthTag: iv (nonce) = %x (%d)\n", nonce, len(nonce))
-		pdebug.Printf("ComputeAuthTag: integrity  = %x (%d)\n", c.integrityKey, len(c.integrityKey))
-	}
-
 	buf := make([]byte, len(aad)+len(nonce)+len(ciphertext)+8)
 	n := 0
 	n += copy(buf, aad)
@@ -142,10 +123,6 @@ func (c Hmac) ComputeAuthTag(aad, nonce, ciphertext []byte) ([]byte, error) {
 		return nil, errors.Wrap(err, "failed to write ComputeAuthTag using Hmac")
 	}
 	s := h.Sum(nil)
-	if pdebug.Enabled {
-		pdebug.Printf("ComputeAuthTag: buf        = %x (%d)\n", buf, len(buf))
-		pdebug.Printf("ComputeAuthTag: computed   = %x (%d)\n", s[:c.tagsize], len(s[:c.tagsize]))
-	}
 	return s[:c.tagsize], nil
 }
 
@@ -186,21 +163,11 @@ func (c Hmac) Seal(dst, nonce, plaintext, data []byte) []byte {
 	n := copy(out, ciphertext)
 	copy(out[n:], authtag)
 
-	if pdebug.Enabled {
-		pdebug.Printf("Seal: ciphertext = %x (%d)\n", ciphertext, len(ciphertext))
-		pdebug.Printf("Seal: authtag    = %x (%d)\n", authtag, len(authtag))
-		pdebug.Printf("Seal: ret        = %x (%d)\n", ret, len(ret))
-	}
 	return ret
 }
 
 // Open fulfills the crypto.AEAD interface
 func (c Hmac) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	if len(ciphertext) < c.keysize {
 		return nil, errors.New("invalid ciphertext (too short)")
 	}
@@ -222,10 +189,6 @@ func (c Hmac) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
 	}
 
 	if subtle.ConstantTimeCompare(expectedTag, tag) != 1 {
-		if pdebug.Enabled {
-			pdebug.Printf("provided tag = %x\n", tag)
-			pdebug.Printf("expected tag = %x\n", expectedTag)
-		}
 		return nil, errors.New("invalid ciphertext (tag mismatch)")
 	}
 
diff --git a/jwe/internal/cipher/cipher.go b/jwe/internal/cipher/cipher.go
index 772be5ce..586feff8 100644
--- a/jwe/internal/cipher/cipher.go
+++ b/jwe/internal/cipher/cipher.go
@@ -8,7 +8,6 @@ import (
 	"github.com/lestrrat-go/jwx/jwa"
 	"github.com/lestrrat-go/jwx/jwe/internal/aescbc"
 	"github.com/lestrrat-go/jwx/jwe/internal/keygen"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -18,9 +17,6 @@ var cbc = &cbcFetcher{}
 func (f gcmFetcher) Fetch(key []byte) (cipher.AEAD, error) {
 	aescipher, err := aes.NewCipher(key)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("gcmFetcher: failed to create cipher")
-		}
 		return nil, errors.Wrap(err, "cipher: failed to create AES cipher for GCM")
 	}
 
@@ -32,15 +28,8 @@ func (f gcmFetcher) Fetch(key []byte) (cipher.AEAD, error) {
 }
 
 func (f cbcFetcher) Fetch(key []byte) (cipher.AEAD, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
 	aead, err := aescbc.New(key, aes.NewCipher)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("CbcAeadFetch: failed to create aead fetcher %v (%d): %s", key, len(key), err)
-		}
 		return nil, errors.Wrap(err, "cipher: failed to create AES cipher for CBC")
 	}
 	return aead, nil
@@ -55,11 +44,6 @@ func (c AesContentCipher) TagSize() int {
 }
 
 func NewAES(alg jwa.ContentEncryptionAlgorithm) (*AesContentCipher, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	var keysize int
 	var tagsize int
 	var fetcher Fetcher
@@ -92,14 +76,6 @@ func NewAES(alg jwa.ContentEncryptionAlgorithm) (*AesContentCipher, error) {
 		return nil, errors.Errorf("failed to create AES content cipher: invalid algorithm (%s)", alg)
 	}
 
-	if pdebug.Enabled {
-		if fetcher == gcm {
-			pdebug.Printf("Using GCM")
-		} else {
-			pdebug.Printf("using CBC")
-		}
-	}
-
 	return &AesContentCipher{
 		keysize: keysize,
 		tagsize: tagsize,
@@ -111,9 +87,6 @@ func (c AesContentCipher) Encrypt(cek, plaintext, aad []byte) (iv, ciphertext, t
 	var aead cipher.AEAD
 	aead, err = c.fetch.Fetch(cek)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("AeadFetch failed: %s", err)
-		}
 		return nil, nil, nil, errors.Wrap(err, "failed to fetch AEAD")
 	}
 
@@ -150,33 +123,16 @@ func (c AesContentCipher) Encrypt(cek, plaintext, aad []byte) (iv, ciphertext, t
 		panic(fmt.Sprintf("tag offset is less than 0 (combined len = %d, tagsize = %d)", len(combined), c.TagSize()))
 	}
 
-	if pdebug.Enabled {
-		pdebug.Printf("tagsize = %d", c.TagSize())
-	}
 	tag = combined[tagoffset:]
 	ciphertext = make([]byte, tagoffset)
 	copy(ciphertext, combined[:tagoffset])
 
-	if pdebug.Enabled {
-		pdebug.Printf("encrypt: combined   = %x (%d)\n", combined, len(combined))
-		pdebug.Printf("encrypt: ciphertext = %x (%d)\n", ciphertext, len(ciphertext))
-		pdebug.Printf("encrypt: tag        = %x (%d)\n", tag, len(tag))
-		pdebug.Printf("finally ciphertext = %x\n", ciphertext)
-	}
 	return
 }
 
 func (c AesContentCipher) Decrypt(cek, iv, ciphertxt, tag, aad []byte) (plaintext []byte, err error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker().BindError(&err)
-		defer g.End()
-	}
-
 	aead, err := c.fetch.Fetch(cek)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("AeadFetch failed for %x: %s", cek, err)
-		}
 		return nil, errors.Wrap(err, "failed to fetch AEAD data")
 	}
 
@@ -200,14 +156,6 @@ func (c AesContentCipher) Decrypt(cek, iv, ciphertxt, tag, aad []byte) (plaintex
 	copy(combined, ciphertxt)
 	copy(combined[len(ciphertxt):], tag)
 
-	if pdebug.Enabled {
-		pdebug.Printf("AesContentCipher.decrypt: cek      = %x (%d)", cek, len(cek))
-		pdebug.Printf("AesContentCipher.decrypt: iv       = %x (%d)", iv, len(iv))
-		pdebug.Printf("AesContentCipher.decrypt: tag      = %x (%d)", tag, len(tag))
-		pdebug.Printf("AesContentCipher.decrypt: aad      = %x (%d)", aad, len(aad))
-		pdebug.Printf("AesContentCipher.decrypt: combined = %x (%d)", combined, len(combined))
-	}
-
 	buf, aeaderr := aead.Open(nil, iv, combined, aad)
 	if aeaderr != nil {
 		err = errors.Wrap(aeaderr, `aead.Open failed`)
diff --git a/jwe/internal/concatkdf/concatkdf.go b/jwe/internal/concatkdf/concatkdf.go
index 87a0e3b9..777c1a5b 100644
--- a/jwe/internal/concatkdf/concatkdf.go
+++ b/jwe/internal/concatkdf/concatkdf.go
@@ -4,7 +4,6 @@ import (
 	"crypto"
 	"encoding/binary"
 
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -27,15 +26,6 @@ func New(hash crypto.Hash, alg, Z, apu, apv, pubinfo, privinfo []byte) *KDF {
 	apubuf := ndata(apu)
 	apvbuf := ndata(apv)
 
-	if pdebug.Enabled {
-		pdebug.Printf("alg          = %s", alg)
-		pdebug.Printf("algID   (%d) = %x", len(algbuf), algbuf)
-		pdebug.Printf("zBytes  (%d) = %x", len(Z), Z)
-		pdebug.Printf("apu     (%d) = %x", len(apubuf), apubuf)
-		pdebug.Printf("apv     (%d) = %x", len(apvbuf), apvbuf)
-		pdebug.Printf("pubinfo (%d) = %x", len(pubinfo), pubinfo)
-	}
-
 	concat := make([]byte, len(algbuf)+len(apubuf)+len(apvbuf)+len(pubinfo)+len(privinfo))
 	n := copy(concat, algbuf)
 	n += copy(concat[n:], apubuf)
diff --git a/jwe/internal/content_crypt/content_crypt.go b/jwe/internal/content_crypt/content_crypt.go
index 5f4ac86b..b83af42d 100644
--- a/jwe/internal/content_crypt/content_crypt.go
+++ b/jwe/internal/content_crypt/content_crypt.go
@@ -3,7 +3,6 @@ package content_crypt //nolint:golint
 import (
 	"github.com/lestrrat-go/jwx/jwa"
 	"github.com/lestrrat-go/jwx/jwe/internal/cipher"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -12,17 +11,8 @@ func (c Generic) Algorithm() jwa.ContentEncryptionAlgorithm {
 }
 
 func (c Generic) Encrypt(cek, plaintext, aad []byte) ([]byte, []byte, []byte, error) {
-	if pdebug.Enabled {
-		pdebug.Printf("ContentCrypt.Encrypt: cek        = %x (%d)", cek, len(cek))
-		pdebug.Printf("ContentCrypt.Encrypt: plaintext  = %x (%d)", plaintext, len(plaintext))
-		pdebug.Printf("ContentCrypt.Encrypt: aad        = %x (%d)", aad, len(aad))
-	}
 	iv, encrypted, tag, err := c.cipher.Encrypt(cek, plaintext, aad)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("cipher.encrypt failed")
-		}
-
 		return nil, nil, nil, errors.Wrap(err, `failed to crypt content`)
 	}
 
@@ -34,20 +24,11 @@ func (c Generic) Decrypt(cek, iv, ciphertext, tag, aad []byte) ([]byte, error) {
 }
 
 func NewGeneric(alg jwa.ContentEncryptionAlgorithm) (*Generic, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	c, err := cipher.NewAES(alg)
 	if err != nil {
 		return nil, errors.Wrap(err, `aes crypt: failed to create content cipher`)
 	}
 
-	if pdebug.Enabled {
-		pdebug.Printf("AES Crypt: cipher.keysize = %d", c.KeySize())
-	}
-
 	return &Generic{
 		alg:     alg,
 		cipher:  c,
diff --git a/jwe/internal/keyenc/keyenc.go b/jwe/internal/keyenc/keyenc.go
index f1c9aa5a..ffa0033b 100644
--- a/jwe/internal/keyenc/keyenc.go
+++ b/jwe/internal/keyenc/keyenc.go
@@ -25,7 +25,6 @@ import (
 	"github.com/lestrrat-go/jwx/jwe/internal/concatkdf"
 	"github.com/lestrrat-go/jwx/jwe/internal/keygen"
 	"github.com/lestrrat-go/jwx/x25519"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -309,11 +308,6 @@ func DeriveZ(privkeyif interface{}, pubkeyif interface{}) ([]byte, error) {
 }
 
 func DeriveECDHES(alg, apu, apv []byte, privkey interface{}, pubkey interface{}, keysize uint32) ([]byte, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	pubinfo := make([]byte, 4)
 	binary.BigEndian.PutUint32(pubinfo, keysize*8)
 	zBytes, err := DeriveZ(privkey, pubkey)
@@ -331,11 +325,6 @@ func DeriveECDHES(alg, apu, apv []byte, privkey interface{}, pubkey interface{},
 
 // Decrypt decrypts the encrypted key using ECDH-ES
 func (kw ECDHESDecrypt) Decrypt(enckey []byte) ([]byte, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	var algBytes []byte
 	var keysize uint32
 
@@ -349,10 +338,6 @@ func (kw ECDHESDecrypt) Decrypt(enckey []byte) ([]byte, error) {
 		if err != nil {
 			return nil, errors.Wrapf(err, `failed to create content cipher for %s`, kw.contentalg)
 		}
-		if pdebug.Enabled {
-			pdebug.Printf("Using keysize (%d) from content cipher %s", c.KeySize(), kw.contentalg)
-		}
-
 		keysize = uint32(c.KeySize())
 		algBytes = []byte(kw.contentalg.String())
 	case jwa.ECDH_ES_A128KW:
@@ -372,9 +357,6 @@ func (kw ECDHESDecrypt) Decrypt(enckey []byte) ([]byte, error) {
 
 	// ECDH-ES does not wrap keys
 	if kw.keyalg == jwa.ECDH_ES {
-		if pdebug.Enabled {
-			pdebug.Printf("Skip unwrapping for ECHD-ES")
-		}
 		return key, nil
 	}
 
@@ -480,9 +462,6 @@ func (d RSAPKCS15Decrypt) Algorithm() jwa.KeyEncryptionAlgorithm {
 
 // Decrypt decrypts the encrypted key using RSA PKCS1v1.5
 func (d RSAPKCS15Decrypt) Decrypt(enckey []byte) ([]byte, error) {
-	if pdebug.Enabled {
-		pdebug.Printf("START PKCS.Decrypt")
-	}
 	// Hey, these notes and workarounds were stolen from go-jose
 	defer func() {
 		// DecryptPKCS1v15SessionKey sometimes panics on an invalid payload
@@ -548,9 +527,6 @@ func (d RSAOAEPDecrypt) Algorithm() jwa.KeyEncryptionAlgorithm {
 
 // Decrypt decrypts the encrypted key using RSA OAEP
 func (d RSAOAEPDecrypt) Decrypt(enckey []byte) ([]byte, error) {
-	if pdebug.Enabled {
-		pdebug.Printf("START OAEP.Decrypt")
-	}
 	var hash hash.Hash
 	switch d.alg {
 	case jwa.RSA_OAEP:
@@ -615,11 +591,6 @@ func Wrap(kek cipher.Block, cek []byte) ([]byte, error) {
 }
 
 func Unwrap(block cipher.Block, ciphertxt []byte) ([]byte, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	if len(ciphertxt)%keywrapChunkLen != 0 {
 		return nil, errors.Errorf(`keyunwrap input must be %d byte blocks`, keywrapChunkLen)
 	}
@@ -650,11 +621,6 @@ func Unwrap(block cipher.Block, ciphertxt []byte) ([]byte, error) {
 	}
 
 	if subtle.ConstantTimeCompare(buffer[:keywrapChunkLen], keywrapDefaultIV) == 0 {
-		if pdebug.Enabled {
-			pdebug.Printf("buffer prefix does not match default iv")
-			pdebug.Printf("prefix  = %x", buffer[:keywrapChunkLen])
-			pdebug.Printf("default = %x", keywrapDefaultIV)
-		}
 		return nil, errors.New("key unwrap: failed to unwrap key")
 	}
 
diff --git a/jwe/jwe.go b/jwe/jwe.go
index 565a2343..ccd3a467 100644
--- a/jwe/jwe.go
+++ b/jwe/jwe.go
@@ -20,7 +20,6 @@ import (
 	"github.com/lestrrat-go/jwx/jwe/internal/keyenc"
 	"github.com/lestrrat-go/jwx/jwe/internal/keygen"
 	"github.com/lestrrat-go/jwx/x25519"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -31,11 +30,6 @@ var registry = json.NewRegistry()
 //
 // Encrypt currently does not support multi-recipient messages.
 func Encrypt(payload []byte, keyalg jwa.KeyEncryptionAlgorithm, key interface{}, contentalg jwa.ContentEncryptionAlgorithm, compressalg jwa.CompressionAlgorithm, options ...EncryptOption) ([]byte, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	var protected Headers
 	for _, option := range options {
 		//nolint:forcetypeassert
@@ -142,16 +136,10 @@ func Encrypt(payload []byte, keyalg jwa.KeyEncryptionAlgorithm, key interface{},
 		}
 		enc, _ = keyenc.NewNoop(keyalg, sharedkey)
 	default:
-		if pdebug.Enabled {
-			pdebug.Printf("Encrypt: unknown key encryption algorithm: %s", keyalg)
-		}
 		return nil, errors.Errorf(`invalid key encryption algorithm (%s)`, keyalg)
 	}
 
 	keysize := contentcrypt.KeySize()
-	if pdebug.Enabled {
-		pdebug.Printf("Encrypt: keysize = %d", keysize)
-	}
 	encctx := getEncryptCtx()
 	defer releaseEncryptCtx(encctx)
 
@@ -162,9 +150,6 @@ func Encrypt(payload []byte, keyalg jwa.KeyEncryptionAlgorithm, key interface{},
 	encctx.compress = compressalg
 	msg, err := encctx.Encrypt(payload)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("Encrypt: failed to encrypt: %s", err)
-		}
 		return nil, errors.Wrap(err, "failed to encrypt payload")
 	}
 
@@ -306,9 +291,6 @@ func parseJSON(buf []byte, storeProtectedHeaders bool) (*Message, error) {
 }
 
 func parseCompact(buf []byte, storeProtectedHeaders bool) (*Message, error) {
-	if pdebug.Enabled {
-		pdebug.Printf("Parse(Compact): buf = '%s'", buf)
-	}
 	parts := bytes.Split(buf, []byte{'.'})
 	if len(parts) != 5 {
 		return nil, errors.Errorf(`compact JWE format must have five parts (%d)`, len(parts))
@@ -318,9 +300,6 @@ func parseCompact(buf []byte, storeProtectedHeaders bool) (*Message, error) {
 	if err != nil {
 		return nil, errors.Wrap(err, `failed to parse first part of compact form`)
 	}
-	if pdebug.Enabled {
-		pdebug.Printf("hdrbuf = %s", hdrbuf)
-	}
 
 	protected := NewHeaders()
 	if err := json.Unmarshal(hdrbuf, protected); err != nil {
diff --git a/jwe/message.go b/jwe/message.go
index f3e52f0c..d3dc2535 100644
--- a/jwe/message.go
+++ b/jwe/message.go
@@ -11,7 +11,6 @@ import (
 
 	"github.com/lestrrat-go/jwx/internal/base64"
 	"github.com/lestrrat-go/jwx/jwa"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 )
 
@@ -456,11 +455,6 @@ func (m *Message) Decrypt(alg jwa.KeyEncryptionAlgorithm, key interface{}) ([]by
 }
 
 func doDecryptCtx(dctx *decryptCtx) ([]byte, error) {
-	if pdebug.Enabled {
-		g := pdebug.FuncMarker()
-		defer g.End()
-	}
-
 	m := dctx.msg
 	alg := dctx.alg
 	key := dctx.key
@@ -481,9 +475,6 @@ func doDecryptCtx(dctx *decryptCtx) ([]byte, error) {
 	}
 	h, err = h.Merge(ctx, m.unprotectedHeaders)
 	if err != nil {
-		if pdebug.Enabled {
-			pdebug.Printf("failed to merge unprotected header")
-		}
 		return nil, errors.Wrap(err, "failed to merge headers for message decryption")
 	}
 
@@ -527,11 +518,6 @@ func doDecryptCtx(dctx *decryptCtx) ([]byte, error) {
 	for _, recipient := range recipients {
 		// strategy: try each recipient. If we fail in one of the steps,
 		// keep looping because there might be another key with the same algo
-
-		if pdebug.Enabled {
-			pdebug.Printf("Attempting to check if we can decode for recipient (alg = %s)", recipient.Headers().Algorithm())
-		}
-
 		if recipient.Headers().Algorithm() != alg {
 			// algorithms don't match
 			continue
@@ -540,18 +526,12 @@ func doDecryptCtx(dctx *decryptCtx) ([]byte, error) {
 		h2, err := h.Clone(ctx)
 		if err != nil {
 			lastError = errors.Wrap(err, `failed to copy headers (1)`)
-			if pdebug.Enabled {
-				pdebug.Printf(`%s`, lastError)
-			}
 			continue
 		}
 
 		h2, err = h2.Merge(ctx, recipient.Headers())
 		if err != nil {
 			lastError = errors.Wrap(err, `failed to copy headers (2)`)
-			if pdebug.Enabled {
-				pdebug.Printf(`%s`, lastError)
-			}
 			continue
 		}
 
@@ -644,24 +624,10 @@ func doDecryptCtx(dctx *decryptCtx) ([]byte, error) {
 			continue
 		}
 
-		if pdebug.Enabled {
-			pdebug.Printf("Successfully decrypted message (len %d). Checking for compression...", len(plaintext))
-		}
-
-		if h2.Compression() != jwa.Deflate {
-			if pdebug.Enabled {
-				pdebug.Printf("No compression handling necessary.")
-			}
-		} else {
-			if pdebug.Enabled {
-				pdebug.Printf("Uncompressing plaintext")
-			}
+		if h2.Compression() == jwa.Deflate {
 			buf, err := uncompress(plaintext)
 			if err != nil {
 				lastError = errors.Wrap(err, `failed to uncompress payload`)
-				if pdebug.Enabled {
-					pdebug.Printf(`%s`, lastError)
-				}
 				continue
 			}
 			plaintext = buf
diff --git a/jwt/jwt.go b/jwt/jwt.go
index 906efeee..3b888e40 100644
--- a/jwt/jwt.go
+++ b/jwt/jwt.go
@@ -10,7 +10,6 @@ import (
 	"io/ioutil"
 	"strings"
 	"sync/atomic"
-	"time"
 
 	"github.com/lestrrat-go/jwx"
 	"github.com/lestrrat-go/jwx/internal/json"
@@ -365,9 +364,6 @@ func Sign(t Token, alg jwa.SignatureAlgorithm, key interface{}, options ...SignO
 //
 // if both t1 and t2 are nil, returns true
 func Equal(t1, t2 Token) bool {
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-
 	if t1 == nil && t2 == nil {
 		return true
 	}
@@ -377,36 +373,17 @@ func Equal(t1, t2 Token) bool {
 		return false
 	}
 
-	m1, err := t1.AsMap(ctx)
+	j1, err := json.Marshal(t1)
 	if err != nil {
 		return false
 	}
 
-	for iter := t2.Iterate(ctx); iter.Next(ctx); {
-		pair := iter.Pair()
-
-		v1 := m1[pair.Key.(string)]
-		v2 := pair.Value
-		switch tmp := v1.(type) {
-		case time.Time:
-			tmp2, ok := v2.(time.Time)
-			if !ok {
-				return false
-			}
-			tmp = tmp.Round(0).Truncate(time.Second)
-			tmp2 = tmp2.Round(0).Truncate(time.Second)
-			if !tmp.Equal(tmp2) {
-				return false
-			}
-		default:
-			if v1 != v2 {
-				return false
-			}
-		}
-		delete(m1, pair.Key.(string))
+	j2, err := json.Marshal(t2)
+	if err != nil {
+		return false
 	}
 
-	return len(m1) == 0
+	return bytes.Equal(j1, j2)
 }
 
 func (t *stdToken) Clone() (Token, error) {
diff --git a/jwt/openid/birthdate.go b/jwt/openid/birthdate.go
index 9ae2e6d4..ac1a81db 100644
--- a/jwt/openid/birthdate.go
+++ b/jwt/openid/birthdate.go
@@ -59,13 +59,35 @@ func (b *BirthdateClaim) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
+func tointptr(v int64) *int {
+	i := int(v)
+	return &i
+}
+
 var birthdateRx = regexp.MustCompile(`^(\d{4})-(\d{2})-(\d{2})$`)
 
 // Accepts a value read from JSON, and converts it to a BirthdateClaim.
 // This method DOES NOT verify the correctness of a date.
 // Consumers should check for validity of dates such as Apr 31 et al
 func (b *BirthdateClaim) Accept(v interface{}) error {
+	b.year = nil
+	b.month = nil
+	b.day = nil
 	switch v := v.(type) {
+	case *BirthdateClaim:
+		if ptr := v.year; ptr != nil {
+			year := *ptr
+			b.year = &year
+		}
+		if ptr := v.month; ptr != nil {
+			month := *ptr
+			b.month = &month
+		}
+		if ptr := v.day; ptr != nil {
+			day := *ptr
+			b.day = &day
+		}
+		return nil
 	case string:
 		// yeah, yeah, regexp is slow. PR's welcome
 		indices := birthdateRx.FindStringSubmatchIndex(v)
@@ -74,32 +96,29 @@ func (b *BirthdateClaim) Accept(v interface{}) error {
 		}
 		var tmp BirthdateClaim
 
-		year, err := strconv.ParseInt(v[indices[2]:indices[3]], 10, 64)
-		if err != nil {
+		// Okay, this really isn't kosher, but we're doing this for
+		// the coverage game... Because birthdateRx already checked that
+		// the string contains 3 strings with consecutive decimal values
+		// we can assume that strconv.ParseInt always succeeds.
+		// strconv.ParseInt (and strconv.ParseUint that it uses internally)
+		// only returns range errors, so we should be safe.
+		year, _ := strconv.ParseInt(v[indices[2]:indices[3]], 10, 64)
+		if year <= 0 {
 			return errors.New(`failed to parse birthdate year`)
 		}
-		if year > 0 {
-			var v = int(year)
-			tmp.year = &v
-		}
+		tmp.year = tointptr(year)
 
-		month, err := strconv.ParseInt(v[indices[4]:indices[5]], 10, 64)
-		if err != nil {
+		month, _ := strconv.ParseInt(v[indices[4]:indices[5]], 10, 64)
+		if month <= 0 {
 			return errors.New(`failed to parse birthdate month`)
 		}
-		if month > 0 {
-			var v = int(month)
-			tmp.month = &v
-		}
+		tmp.month = tointptr(month)
 
-		day, err := strconv.ParseInt(v[indices[6]:indices[7]], 10, 64)
-		if err != nil {
+		day, _ := strconv.ParseInt(v[indices[6]:indices[7]], 10, 64)
+		if day <= 0 {
 			return errors.New(`failed to parse birthdate day`)
 		}
-		if day > 0 {
-			var v = int(day)
-			tmp.day = &v
-		}
+		tmp.day = tointptr(day)
 
 		*b = tmp
 		return nil
@@ -109,7 +128,7 @@ func (b *BirthdateClaim) Accept(v interface{}) error {
 }
 
 func (b BirthdateClaim) encode(dst io.Writer) {
-	fmt.Fprintf(dst, "%d-%02d-%02d", b.Year(), b.Month(), b.Day())
+	fmt.Fprintf(dst, "%04d-%02d-%02d", b.Year(), b.Month(), b.Day())
 }
 
 func (b BirthdateClaim) String() string {


Test patch:
diff --git a/internal/jwxtest/jwxtest.go b/internal/jwxtest/jwxtest.go
index d1d09673..673203da 100644
--- a/internal/jwxtest/jwxtest.go
+++ b/internal/jwxtest/jwxtest.go
@@ -21,7 +21,6 @@ import (
 	"github.com/lestrrat-go/jwx/jwk"
 	"github.com/lestrrat-go/jwx/jws"
 	"github.com/lestrrat-go/jwx/x25519"
-	"github.com/lestrrat-go/pdebug/v3"
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
@@ -258,11 +257,6 @@ func ParseJwkFile(_ context.Context, file string) (jwk.Key, error) {
 		return nil, errors.Wrapf(err, `filed to parse JWK in key file %s`, file)
 	}
 
-	if pdebug.Enabled {
-		buf, _ := json.MarshalIndent(key, "", "  ")
-		pdebug.Printf("%s", buf)
-	}
-
 	return key, nil
 }
 
diff --git a/jwt/openid/openid_test.go b/jwt/openid/openid_test.go
index 427d6366..23329d06 100644
--- a/jwt/openid/openid_test.go
+++ b/jwt/openid/openid_test.go
@@ -3,6 +3,7 @@ package openid_test
 import (
 	"context"
 	"fmt"
+	"strconv"
 	"testing"
 	"time"
 
@@ -527,6 +528,16 @@ func TestOpenIDClaims(t *testing.T) {
 				return
 			}
 		})
+		t.Run("Clone", func(t *testing.T) {
+			cloned, err := v.Clone()
+			if !assert.NoError(t, err, `v.Clone should succeed`) {
+				return
+			}
+
+			if !assert.True(t, jwt.Equal(v, cloned), `values should match`) {
+				return
+			}
+		})
 	})
 }
 
@@ -534,26 +545,101 @@ func TestBirthdateClaim(t *testing.T) {
 	t.Parallel()
 	t.Run("regular date", func(t *testing.T) {
 		t.Parallel()
-		const src = `"2015-11-04"`
-		var b openid.BirthdateClaim
-		if !assert.NoError(t, json.Unmarshal([]byte(src), &b), `json.Unmarshal should succeed`) {
-			return
+		testcases := []struct {
+			Source string
+			Year   int
+			Month  int
+			Day    int
+			Error  bool
+		}{
+			{
+				Source: `"2015-11-04"`,
+				Year:   2015,
+				Month:  11,
+				Day:    4,
+			},
+			{
+				Source: `"0009-09-09"`,
+				Year:   9,
+				Month:  9,
+				Day:    9,
+			},
+			{
+				Source: `{}`,
+				Error:  true,
+			},
+			{
+				Source: `"202X-01-01"`,
+				Error:  true,
+			},
+			{
+				Source: `"0000-01-01"`,
+				Error:  true,
+			},
+			{
+				Source: `"0001-00-01"`,
+				Error:  true,
+			},
+			{
+				Source: `"0001-01-00"`,
+				Error:  true,
+			},
 		}
 
-		if !assert.Equal(t, b.Year(), 2015, "year should match") {
-			return
+		for _, tc := range testcases {
+			tc := tc
+			t.Run(tc.Source, func(t *testing.T) {
+				var b openid.BirthdateClaim
+				if tc.Error {
+					assert.Error(t, json.Unmarshal([]byte(tc.Source), &b), `json.Unmarshal should fail`)
+					return
+				}
+
+				if !assert.NoError(t, json.Unmarshal([]byte(tc.Source), &b), `json.Unmarshal should succeed`) {
+					return
+				}
+
+				if !assert.Equal(t, b.Year(), tc.Year, "year should match") {
+					return
+				}
+				if !assert.Equal(t, b.Month(), tc.Month, "month should match") {
+					return
+				}
+				if !assert.Equal(t, b.Day(), tc.Day, "day should match") {
+					return
+				}
+				serialized, err := json.Marshal(b)
+				if !assert.NoError(t, err, `json.Marshal should succeed`) {
+					return
+				}
+				if !assert.Equal(t, string(serialized), tc.Source, `serialized format should be the same`) {
+					return
+				}
+				stringified := b.String()
+				expectedString, _ := strconv.Unquote(tc.Source)
+				if !assert.Equal(t, stringified, expectedString, `stringified format should be the same`) {
+					return
+				}
+			})
 		}
-		if !assert.Equal(t, b.Month(), 11, "month should match") {
+	})
+	t.Run("empty date", func(t *testing.T) {
+		t.Parallel()
+		var b openid.BirthdateClaim
+		if !assert.Equal(t, b.Year(), 0, "year should match") {
 			return
 		}
-		if !assert.Equal(t, b.Day(), 4, "day should match") {
+		if !assert.Equal(t, b.Month(), 0, "month should match") {
 			return
 		}
-		serialized, err := json.Marshal(b)
-		if !assert.NoError(t, err, `json.Marshal should succeed`) {
+		if !assert.Equal(t, b.Day(), 0, "day should match") {
 			return
 		}
-		if !assert.Equal(t, string(serialized), src, `serialized format should be the same`) {
+	})
+	t.Run("invalid accept", func(t *testing.T) {
+		t.Parallel()
+		var b openid.BirthdateClaim
+		if !assert.Error(t, b.Accept(nil)) {
 			return
 		}
 	})
diff --git a/jwx_test.go b/jwx_test.go
index 04aa4178..b36a5abd 100644
--- a/jwx_test.go
+++ b/jwx_test.go
@@ -202,6 +202,8 @@ func TestJoseCompatibility(t *testing.T) {
 			{jwa.A256GCMKW, jwa.A256CBC_HS512},
 			{jwa.PBES2_HS256_A128KW, jwa.A128GCM},
 			{jwa.PBES2_HS256_A128KW, jwa.A128CBC_HS256},
+			{jwa.PBES2_HS384_A192KW, jwa.A192GCM},
+			{jwa.PBES2_HS384_A192KW, jwa.A192CBC_HS384},
 			{jwa.PBES2_HS512_A256KW, jwa.A256GCM},
 			{jwa.PBES2_HS512_A256KW, jwa.A256CBC_HS512},
 			{jwa.DIRECT, jwa.A128GCM},
diff --git a/x25519/x25519_test.go b/x25519/x25519_test.go
index 4cc8110d..2842d48c 100644
--- a/x25519/x25519_test.go
+++ b/x25519/x25519_test.go
@@ -1,12 +1,29 @@
-package x25519
+package x25519_test
 
 import (
 	"encoding/hex"
 	"testing"
 
+	"github.com/lestrrat-go/jwx/x25519"
 	"github.com/stretchr/testify/assert"
 )
 
+func TestGenerateKey(t *testing.T) {
+	t.Run("x25519.GenerateKey(nil)", func(t *testing.T) {
+		_, _, err := x25519.GenerateKey(nil)
+		if !assert.NoError(t, err, `x25519.GenerateKey should work even if argument is nil`) {
+			return
+		}
+	})
+	t.Run("x25519.NewKeyFromSeed(wrongSeedLength)", func(t *testing.T) {
+		dummy := make([]byte, x25519.SeedSize-1)
+		_, err := x25519.NewKeyFromSeed(dummy)
+		if !assert.Error(t, err, `wrong seed size should result in error`) {
+			return
+		}
+	})
+}
+
 func TestNewKeyFromSeed(t *testing.T) {
 	// These test vectors are from RFC7748 Section 6.1
 	const alicePrivHex = `77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a`
@@ -18,12 +35,12 @@ func TestNewKeyFromSeed(t *testing.T) {
 	if !assert.NoError(t, err, `alice seed decoded`) {
 		return
 	}
-	alicePriv, err := NewKeyFromSeed(alicePrivSeed)
+	alicePriv, err := x25519.NewKeyFromSeed(alicePrivSeed)
 	if !assert.NoError(t, err, `alice private key`) {
 		return
 	}
 
-	alicePub := alicePriv.Public().(PublicKey)
+	alicePub := alicePriv.Public().(x25519.PublicKey)
 	if !assert.Equal(t, hex.EncodeToString(alicePub), alicePubHex, `alice public key`) {
 		return
 	}
@@ -32,13 +49,26 @@ func TestNewKeyFromSeed(t *testing.T) {
 	if !assert.NoError(t, err, `bob seed decoded`) {
 		return
 	}
-	bobPriv, err := NewKeyFromSeed(bobPrivSeed)
+	bobPriv, err := x25519.NewKeyFromSeed(bobPrivSeed)
 	if !assert.NoError(t, err, `bob private key`) {
 		return
 	}
 
-	bobPub := bobPriv.Public().(PublicKey)
+	bobPub := bobPriv.Public().(x25519.PublicKey)
 	if !assert.Equal(t, hex.EncodeToString(bobPub), bobPubHex, `bob public key`) {
 		return
 	}
+
+	if !assert.True(t, bobPriv.Equal(bobPriv), `bobPriv should equal bobPriv`) {
+		return
+	}
+	if !assert.True(t, bobPub.Equal(bobPub), `bobPub should equal bobPub`) {
+		return
+	}
+	if !assert.False(t, bobPriv.Equal(bobPub), `bobPriv should NOT equal bobPub`) {
+		return
+	}
+	if !assert.False(t, bobPub.Equal(bobPriv), `bobPub should NOT equal bobPriv`) {
+		return
+	}
 }