Snap for 8249732 from 5e51be81e1dd965daebf1c13a5fd76a0ec09738e to tm-d1-release

Change-Id: I0ee3b4d8abb20ccbecfd5f6117f71a0fe1b60255
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..2fcab48
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "818bd1e3b3ff44e9b179532d2b4d942ea34bd1a1"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/.codecov.yml b/.codecov.yml
new file mode 100644
index 0000000..82141e1
--- /dev/null
+++ b/.codecov.yml
@@ -0,0 +1,25 @@
+codecov:
+  require_ci_to_pass: yes
+
+coverage:
+  precision: 2
+  round: down
+  range: "70...100"
+
+parsers:
+  gcov:
+    branch_detection:
+      conditional: yes
+      loop: yes
+      method: no
+      macro: no
+
+comment: false
+
+ignore:
+  - "**/build.rs"
+  - "**/benches/"
+  - "**/tests/"
+  - "**/codegen/"
+  - "**/*_test.rs"
+  - "**/*tests.rs"
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..7d87c2f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,9 @@
+# Please see the documentation for all configuration options:
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+  - package-ecosystem: "cargo"
+    directory: "/"
+    schedule:
+      interval: "daily"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..3430ad1
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,182 @@
+name: CI
+permissions:
+  contents: read
+on:
+  pull_request:
+    paths-ignore:
+      - README.md
+  push:
+    branches: main
+    paths-ignore:
+      - README.md
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        rust:
+          - stable
+          - beta
+          - nightly-2022-01-01
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: ${{ matrix.rust }}
+          components: rustfmt
+          override: true
+      - run: cargo build --release --workspace
+
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        rust:
+          - stable
+          - beta
+          - nightly-2022-01-01
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+        with:
+          submodules: true
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: ${{ matrix.rust }}
+          components: rustfmt
+          override: true
+      - run: cargo test --workspace -- --nocapture
+
+  no_std:
+    name: Build for a no_std target
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        rust:
+          - stable
+          - beta
+          - nightly-2022-01-01
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: ${{ matrix.rust }}
+          components: rustfmt
+          target: thumbv6m-none-eabi
+          override: true
+      - run: cargo build --release --workspace --target thumbv6m-none-eabi
+
+  msrv:
+    name: Rust ${{matrix.rust}} MSRV
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        rust: [1.56.0, 1.57.0]
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+        with:
+          submodules: true
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: ${{ matrix.rust }}
+          components: rustfmt
+          override: true
+      - run: rustc --version
+      - run: cargo build --release --workspace --all-features
+
+  formatting:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+      - uses: actions/setup-go@424fc82d43fa5a37540bae62709ddcc23d9520d4 # v2
+      - run: go get github.com/campoy/embedmd
+      - uses: actions/setup-ruby@b007fae6f1ffbe3a51c00a6df6f5ff01184d5340 # v1
+      - run: gem install mdl
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: nightly-2022-01-01
+          override: true
+          components: rustfmt
+      - run: cargo fmt --all -- --check
+      - run: scripts/check-format.sh
+
+  clippy:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: nightly-2022-01-01
+          override: true
+          components: rustfmt, clippy
+      - run: cargo clippy --all-features --all-targets
+      - run: git diff --exit-code
+
+  doc:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: stable
+      - run: RUSTDOCFLAGS="-Dwarnings" cargo doc --no-deps --document-private-items
+
+  udeps:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: nightly-2022-01-01
+          override: true
+          components: rustfmt
+      - uses: actions-rs/install@69ec87709ffb5b19a7b5ddbf610cb221498bb1eb # v0.1.2
+        with:
+          crate: cargo-udeps
+          use-tool-cache: true
+          version: 0.1.25
+      - run: cargo udeps
+
+  deny:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: nightly-2022-01-01
+          override: true
+          components: rustfmt
+      - run: cargo install --locked --version 0.8.5 cargo-deny
+      - run: cargo deny check
+
+  coverage:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+        with:
+          submodules: true
+          fetch-depth: 0
+      - uses: actions-rs/toolchain@63eb9591781c46a70274cb3ebdf190fce92702e8 # v1
+        with:
+          profile: minimal
+          toolchain: nightly-2022-01-01
+          override: true
+          components: rustfmt
+      - uses: actions-rs/install@69ec87709ffb5b19a7b5ddbf610cb221498bb1eb # v0.1.2
+        with:
+          crate: cargo-tarpaulin
+          use-tool-cache: true
+      - run: cargo tarpaulin --verbose --ignore-tests --all-features --timeout=600 --out Xml
+      - name: Upload to codecov.io
+        run: |
+          bash <(curl -s https://codecov.io/bash)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/.mdl-style.rb b/.mdl-style.rb
new file mode 100644
index 0000000..f10cb94
--- /dev/null
+++ b/.mdl-style.rb
@@ -0,0 +1,18 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+all
+rule 'MD013', :line_length => 120
+rule 'MD007', :indent => 4
+exclude_rule 'MD031' # embedmd markers are next to fenced code blocks
+exclude_rule 'MD033' # allow inline HTML, esp. <sup>
diff --git a/.mdlrc b/.mdlrc
new file mode 100644
index 0000000..20c534f
--- /dev/null
+++ b/.mdlrc
@@ -0,0 +1 @@
+style "#{File.dirname(__FILE__)}/.mdl-style.rb"
\ No newline at end of file
diff --git a/.rustfmt.toml b/.rustfmt.toml
new file mode 100644
index 0000000..3bc3e9a
--- /dev/null
+++ b/.rustfmt.toml
@@ -0,0 +1,9 @@
+# See https://github.com/rust-lang/rustfmt/blob/master/Configurations.md
+comment_width = 100
+format_code_in_doc_comments = true
+max_width = 100
+normalize_doc_attributes = true
+wrap_comments = true
+imports_granularity = "Crate"
+imports_layout = "mixed"
+edition = "2018"
diff --git a/Android.bp b/Android.bp
index fa30f0f..4c0f293 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,6 @@
 // This file is generated by cargo2android.py --run --device --dependencies.
 // Do not modify this file as changes will be overridden on upgrade.
 
-
-
 package {
     default_applicable_licenses: ["external_rust_crates_coset_license"],
 }
@@ -25,7 +23,7 @@
     host_supported: true,
     crate_name: "coset",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.3.0",
+    cargo_pkg_version: "0.3.1",
     srcs: ["src/lib.rs"],
     edition: "2018",
     rustlibs: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97eb7ff..f8d4915 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Change Log
 
+## 0.3.1 - 2022-02-23
+
+- Implement `Display` for `CoseError`.
+- Fix `Cargo.toml` to indicate reliance on `alloc` feature of `ciborium-io`.
+- Make `AsCborValue` trait public.
+
 ## 0.3.0 - 2022-01-19
 
 - Change to use `ciborium` as CBOR library. Breaking change with many knock-on effects:
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..d257ebb
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,106 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "ciborium"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "coset"
+version = "0.3.1"
+dependencies = [
+ "ciborium",
+ "ciborium-io",
+ "hex",
+]
+
+[[package]]
+name = "half"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.132"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.132"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23a1dfb999630e338648c83e91c59a4e9fb7620f520c3194b6b89e276f2f1959"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
diff --git a/Cargo.toml b/Cargo.toml
index 774a9b7..eb4661b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,17 +1,30 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
 [package]
-name = "coset"
-version = "0.3.0"
-authors = ["David Drysdale <drysdale@google.com>", "Paul Crowley <paulcrowley@google.com>"]
 edition = "2018"
-license = "Apache-2.0"
+name = "coset"
+version = "0.3.1"
+authors = ["David Drysdale <drysdale@google.com>", "Paul Crowley <paulcrowley@google.com>"]
 description = "Set of types for supporting COSE"
-repository = "https://github.com/google/coset"
 keywords = ["cryptography", "cose"]
 categories = ["cryptography"]
+license = "Apache-2.0"
+repository = "https://github.com/google/coset"
+[dependencies.ciborium]
+version = "^0.2.0"
+default-features = false
 
-[dependencies]
-ciborium = { version = "^0.2.0", default-features = false }
-ciborium-io = "^0.2.0"
-
-[dev-dependencies]
-hex = "^0.4.2"
+[dependencies.ciborium-io]
+version = "^0.2.0"
+features = ["alloc"]
+[dev-dependencies.hex]
+version = "^0.4.2"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..9555fdf
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,17 @@
+[package]
+name = "coset"
+version = "0.3.1"
+authors = ["David Drysdale <drysdale@google.com>", "Paul Crowley <paulcrowley@google.com>"]
+edition = "2018"
+license = "Apache-2.0"
+description = "Set of types for supporting COSE"
+repository = "https://github.com/google/coset"
+keywords = ["cryptography", "cose"]
+categories = ["cryptography"]
+
+[dependencies]
+ciborium = { version = "^0.2.0", default-features = false }
+ciborium-io = { version = "^0.2.0", features = ["alloc"] }
+
+[dev-dependencies]
+hex = "^0.4.2"
diff --git a/METADATA b/METADATA
index 1faae87..c3bb0c2 100644
--- a/METADATA
+++ b/METADATA
@@ -1,7 +1,5 @@
 name: "coset"
-description:
-    "Set of types for supporting CBOR Object Signing and Encryption (COSE)."
-
+description: "Set of types for supporting COSE"
 third_party {
   url {
     type: HOMEPAGE
@@ -9,10 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/coset/coset-0.3.0.crate"
+    value: "https://static.crates.io/crates/coset/coset-0.3.1.crate"
   }
-  version: "0.3.0"
-  last_upgrade_date { year: 2022 month: 1 day: 26 }
+  version: "0.3.1"
   license_type: NOTICE
+  last_upgrade_date {
+    year: 2022
+    month: 3
+    day: 1
+  }
 }
-
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..2f7de78
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,13 @@
+// Generated by update_crate_tests.py for tests that depend on this crate.
+{
+  "presubmit": [
+    {
+      "name": "libcert_request_validator_tests"
+    }
+  ],
+  "presubmit-rust": [
+    {
+      "name": "libcert_request_validator_tests"
+    }
+  ]
+}
diff --git a/fuzz/.gitignore b/fuzz/.gitignore
deleted file mode 100644
index 572e03b..0000000
--- a/fuzz/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-
-target
-corpus
-artifacts
diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock
deleted file mode 100644
index 443dab6..0000000
--- a/fuzz/Cargo.lock
+++ /dev/null
@@ -1,46 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "arbitrary"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "698b65a961a9d730fb45b6b0327e20207810c9f61ee421b082b27ba003f49e2b"
-
-[[package]]
-name = "cc"
-version = "1.0.67"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
-
-[[package]]
-name = "coset"
-version = "0.2.0"
-dependencies = [
- "sk-cbor",
-]
-
-[[package]]
-name = "coset-fuzz"
-version = "0.0.0"
-dependencies = [
- "coset",
- "libfuzzer-sys",
-]
-
-[[package]]
-name = "libfuzzer-sys"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86c975d637bc2a2f99440932b731491fc34c7f785d239e38af3addd3c2fd0e46"
-dependencies = [
- "arbitrary",
- "cc",
-]
-
-[[package]]
-name = "sk-cbor"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e94879a793aba6e65d691f345cfd172c4cc924a78259d5f9612a2cbfb78847a"
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
deleted file mode 100644
index 435f2c0..0000000
--- a/fuzz/Cargo.toml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-[package]
-name = "coset-fuzz"
-version = "0.0.0"
-authors = ["Automatically generated"]
-publish = false
-edition = "2018"
-
-[package.metadata]
-cargo-fuzz = true
-
-[dependencies]
-libfuzzer-sys = "0.4"
-
-[dependencies.coset]
-path = ".."
-
-# Prevent this from interfering with workspaces
-[workspace]
-members = ["."]
-
-[[bin]]
-name = "encrypt"
-path = "fuzz_targets/encrypt.rs"
-test = false
-doc = false
-
-[[bin]]
-name = "key"
-path = "fuzz_targets/key.rs"
-test = false
-doc = false
-
-[[bin]]
-name = "mac"
-path = "fuzz_targets/mac.rs"
-test = false
-doc = false
-
-[[bin]]
-name = "sign"
-path = "fuzz_targets/sign.rs"
-test = false
-doc = false
diff --git a/fuzz/fuzz_targets/encrypt.rs b/fuzz/fuzz_targets/encrypt.rs
deleted file mode 100644
index b579053..0000000
--- a/fuzz/fuzz_targets/encrypt.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-//! Fuzz COSE_Encrypt* parsing.
-
-#![no_main]
-use libfuzzer_sys::fuzz_target;
-
-use coset::CborSerializable;
-
-fuzz_target!(|data: &[u8]| {
-    let _recipient = coset::CoseRecipient::from_slice(data);
-    let _encrypt = coset::CoseEncrypt::from_slice(data);
-    let _encrypt0 = coset::CoseEncrypt0::from_slice(data);
-});
diff --git a/fuzz/fuzz_targets/key.rs b/fuzz/fuzz_targets/key.rs
deleted file mode 100644
index 24217e9..0000000
--- a/fuzz/fuzz_targets/key.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-//! Fuzz COSE_Key parsing.
-
-#![no_main]
-use libfuzzer_sys::fuzz_target;
-
-use coset::CborSerializable;
-
-fuzz_target!(|data: &[u8]| {
-    let _key = coset::CoseKey::from_slice(data);
-});
diff --git a/fuzz/fuzz_targets/mac.rs b/fuzz/fuzz_targets/mac.rs
deleted file mode 100644
index 5d5ec09..0000000
--- a/fuzz/fuzz_targets/mac.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-//! Fuzz COSE_Mac* parsing.
-
-#![no_main]
-use libfuzzer_sys::fuzz_target;
-
-use coset::CborSerializable;
-
-fuzz_target!(|data: &[u8]| {
-    let _mac = coset::CoseMac::from_slice(data);
-    let _mac0 = coset::CoseMac0::from_slice(data);
-});
diff --git a/fuzz/fuzz_targets/sign.rs b/fuzz/fuzz_targets/sign.rs
deleted file mode 100644
index 56242d4..0000000
--- a/fuzz/fuzz_targets/sign.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-//! Fuzz COSE_Sign* parsing.
-
-#![no_main]
-use libfuzzer_sys::fuzz_target;
-
-use coset::CborSerializable;
-
-fuzz_target!(|data: &[u8]| {
-    let _signature = coset::CoseSignature::from_slice(data);
-    let _sign = coset::CoseSign::from_slice(data);
-    let _sign1 = coset::CoseSign1::from_slice(data);
-});
diff --git a/src/common/mod.rs b/src/common/mod.rs
index bc602e6..c1f2973 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -21,7 +21,7 @@
     cbor::value::Value,
     iana,
     iana::{EnumI64, WithPrivateRange},
-    util::{cbor_type_error, AsCborValue, ValueTryAs},
+    util::{cbor_type_error, ValueTryAs},
 };
 use alloc::{boxed::Box, string::String, vec::Vec};
 use core::{cmp::Ordering, convert::TryInto};
@@ -77,6 +77,18 @@
 
 impl core::fmt::Debug for CoseError {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        self.fmt_msg(f)
+    }
+}
+
+impl core::fmt::Display for CoseError {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        self.fmt_msg(f)
+    }
+}
+
+impl CoseError {
+    fn fmt_msg(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {
             CoseError::DecodeFailed(e) => write!(f, "decode CBOR failure: {}", e),
             CoseError::DuplicateMapKey => write!(f, "duplicate map key"),
@@ -132,6 +144,14 @@
     }
 }
 
+/// Trait for types that can be converted to/from a [`Value`].
+pub trait AsCborValue: Sized {
+    /// Convert a [`Value`] into an instance of the type.
+    fn from_cbor_value(value: Value) -> Result<Self>;
+    /// Convert the object into a [`Value`], consuming it along the way.
+    fn to_cbor_value(self) -> Result<Value>;
+}
+
 /// Extension trait that adds serialization/deserialization methods.
 pub trait CborSerializable: AsCborValue {
     /// Create an object instance from serialized CBOR data in a slice.
diff --git a/src/common/tests.rs b/src/common/tests.rs
index 5cde798..ed6f82b 100644
--- a/src/common/tests.rs
+++ b/src/common/tests.rs
@@ -27,6 +27,7 @@
     match e {
         CoseError::EncodeFailed => {
             assert!(format!("{:?}", e).contains("encode CBOR failure"));
+            assert!(format!("{}", e).contains("encode CBOR failure"));
         }
         _ => panic!("unexpected error enum after conversion"),
     }
diff --git a/src/context/mod.rs b/src/context/mod.rs
index ee53afe..708e67c 100644
--- a/src/context/mod.rs
+++ b/src/context/mod.rs
@@ -18,8 +18,9 @@
 
 use crate::{
     cbor::value::Value,
+    common::AsCborValue,
     iana,
-    util::{cbor_type_error, AsCborValue, ValueTryAs},
+    util::{cbor_type_error, ValueTryAs},
     Algorithm, CoseError, ProtectedHeader, Result,
 };
 use alloc::{vec, vec::Vec};
diff --git a/src/encrypt/mod.rs b/src/encrypt/mod.rs
index 589f611..22f9777 100644
--- a/src/encrypt/mod.rs
+++ b/src/encrypt/mod.rs
@@ -19,8 +19,9 @@
 use crate::{
     cbor,
     cbor::value::Value,
+    common::AsCborValue,
     iana,
-    util::{cbor_type_error, to_cbor_array, AsCborValue, ValueTryAs},
+    util::{cbor_type_error, to_cbor_array, ValueTryAs},
     CoseError, Header, ProtectedHeader, Result,
 };
 use alloc::{borrow::ToOwned, vec, vec::Vec};
diff --git a/src/header/mod.rs b/src/header/mod.rs
index aa11174..c19835f 100644
--- a/src/header/mod.rs
+++ b/src/header/mod.rs
@@ -18,9 +18,10 @@
 
 use crate::{
     cbor::value::Value,
+    common::AsCborValue,
     iana,
     iana::EnumI64,
-    util::{cbor_type_error, to_cbor_array, AsCborValue, ValueTryAs},
+    util::{cbor_type_error, to_cbor_array, ValueTryAs},
     Algorithm, CborSerializable, CoseError, CoseSignature, Label, RegisteredLabel, Result,
 };
 use alloc::{collections::BTreeSet, string::String, vec, vec::Vec};
diff --git a/src/key/mod.rs b/src/key/mod.rs
index f0c1eea..b81ea8c 100644
--- a/src/key/mod.rs
+++ b/src/key/mod.rs
@@ -18,9 +18,10 @@
 
 use crate::{
     cbor::value::Value,
+    common::AsCborValue,
     iana,
     iana::EnumI64,
-    util::{to_cbor_array, AsCborValue, ValueTryAs},
+    util::{to_cbor_array, ValueTryAs},
     Algorithm, CoseError, Label, Result,
 };
 use alloc::{collections::BTreeSet, vec, vec::Vec};
diff --git a/src/mac/mod.rs b/src/mac/mod.rs
index 1fb47b1..a16bfa3 100644
--- a/src/mac/mod.rs
+++ b/src/mac/mod.rs
@@ -19,8 +19,9 @@
 use crate::{
     cbor,
     cbor::value::Value,
+    common::AsCborValue,
     iana,
-    util::{cbor_type_error, to_cbor_array, AsCborValue, ValueTryAs},
+    util::{cbor_type_error, to_cbor_array, ValueTryAs},
     CoseError, CoseRecipient, Header, ProtectedHeader, Result,
 };
 use alloc::{borrow::ToOwned, vec, vec::Vec};
diff --git a/src/sign/mod.rs b/src/sign/mod.rs
index d945244..a6bb344 100644
--- a/src/sign/mod.rs
+++ b/src/sign/mod.rs
@@ -19,8 +19,9 @@
 use crate::{
     cbor,
     cbor::value::Value,
+    common::AsCborValue,
     iana,
-    util::{cbor_type_error, to_cbor_array, AsCborValue, ValueTryAs},
+    util::{cbor_type_error, to_cbor_array, ValueTryAs},
     CoseError, Header, ProtectedHeader, Result,
 };
 use alloc::{borrow::ToOwned, vec, vec::Vec};
diff --git a/src/util/mod.rs b/src/util/mod.rs
index b24ae7b..d12337c 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -18,6 +18,7 @@
 
 use crate::{
     cbor::value::{Integer, Value},
+    common::AsCborValue,
     CoseError, Result,
 };
 use alloc::{boxed::Box, vec::Vec};
@@ -132,14 +133,6 @@
     }
 }
 
-/// Trait for types that can be converted to/from a [`Value`].
-pub trait AsCborValue: Sized {
-    /// Convert a [`Value`] into an instance of the type.
-    fn from_cbor_value(value: Value) -> Result<Self>;
-    /// Convert the object into a [`Value`], consuming it along the way.
-    fn to_cbor_value(self) -> Result<Value>;
-}
-
 /// Convert each item of an iterator to CBOR, and wrap the lot in
 /// a [`Value::Array`]
 pub fn to_cbor_array<C>(c: C) -> Result<Value>
@@ -156,21 +149,35 @@
 
 /// Check for an expected error.
 #[cfg(test)]
-pub fn expect_err<T: core::fmt::Debug, E: core::fmt::Debug>(result: Result<T, E>, err_msg: &str) {
+pub fn expect_err<T: core::fmt::Debug, E: core::fmt::Debug + core::fmt::Display>(
+    result: Result<T, E>,
+    err_msg: &str,
+) {
     use alloc::format;
-    assert!(
-        result.is_err(),
-        "expected error containing '{}', got success {:?}",
-        err_msg,
-        result
-    );
-    let err = result.err();
-    assert!(
-        format!("{:?}", err).contains(err_msg),
-        "unexpected error {:?}, doesn't contain '{}'",
-        err,
-        err_msg
-    );
+    match result {
+        Ok(_) => {
+            assert!(
+                result.is_err(),
+                "expected error containing '{}', got success {:?}",
+                err_msg,
+                result
+            );
+        }
+        Err(err) => {
+            assert!(
+                format!("{:?}", err).contains(err_msg),
+                "unexpected error {:?}, doesn't contain '{}' (Debug impl)",
+                err,
+                err_msg
+            );
+            assert!(
+                format!("{}", err).contains(err_msg),
+                "unexpected error {:?}, doesn't contain '{}' (Display impl)",
+                err,
+                err_msg
+            );
+        }
+    }
 }
 
 // Macros to reduce boilerplate when creating `CoseSomethingBuilder` structures.