diff --git a/distribution/pull_v2.go b/distribution/pull_v2.go
index 59ed9025c2..e3a459933c 100644
--- a/distribution/pull_v2.go
+++ b/distribution/pull_v2.go
@@ -14,6 +14,7 @@ import (
 	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/manifest/schema1"
 	"github.com/docker/distribution/registry/api/errcode"
+	"github.com/docker/distribution/registry/client"
 	"github.com/docker/docker/distribution/metadata"
 	"github.com/docker/docker/distribution/xfer"
 	"github.com/docker/docker/image"
@@ -61,18 +62,12 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (err error) {
 func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) {
 	var layersDownloaded bool
 	if !reference.IsNameOnly(ref) {
-		var err error
 		layersDownloaded, err = p.pullV2Tag(ctx, ref)
 		if err != nil {
 			return err
 		}
 	} else {
-		manSvc, err := p.repo.Manifests(ctx)
-		if err != nil {
-			return err
-		}
-
-		tags, err := manSvc.Tags()
+		tags, err := p.repo.Tags(ctx).All(ctx)
 		if err != nil {
 			// If this repository doesn't exist on V2, we should
 			// permit a fallback to V1.
@@ -84,8 +79,6 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
 		// error later on.
 		p.confirmedV2 = true
 
-		// This probably becomes a lot nicer after the manifest
-		// refactor...
 		for _, tag := range tags {
 			tagRef, err := reference.WithTag(ref, tag)
 			if err != nil {
@@ -203,58 +196,92 @@ func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
 }
 
 func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
-	tagOrDigest := ""
-	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
-		tagOrDigest = tagged.Tag()
-	} else if digested, isCanonical := ref.(reference.Canonical); isCanonical {
-		tagOrDigest = digested.Digest().String()
-	} else {
-		return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
-	}
-
-	logrus.Debugf("Pulling ref from V2 registry: %s:%s", ref.FullName(), tagOrDigest)
-
 	manSvc, err := p.repo.Manifests(ctx)
 	if err != nil {
 		return false, err
 	}
 
-	unverifiedManifest, err := manSvc.GetByTag(tagOrDigest)
-	if err != nil {
-		// If this manifest did not exist, we should allow a possible
-		// fallback to the v1 protocol, because dual-version setups may
-		// not host all manifests with the v2 protocol. We may also get
-		// a "not authorized" error if the manifest doesn't exist.
-		return false, allowV1Fallback(err)
+	var (
+		manifest    distribution.Manifest
+		tagOrDigest string // Used for logging/progress only
+	)
+	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
+		// NOTE: not using TagService.Get, since it uses HEAD requests
+		// against the manifests endpoint, which are not supported by
+		// all registry versions.
+		manifest, err = manSvc.Get(ctx, "", client.WithTag(tagged.Tag()))
+		if err != nil {
+			return false, allowV1Fallback(err)
+		}
+		tagOrDigest = tagged.Tag()
+	} else if digested, isDigested := ref.(reference.Canonical); isDigested {
+		manifest, err = manSvc.Get(ctx, digested.Digest())
+		if err != nil {
+			return false, err
+		}
+		tagOrDigest = digested.Digest().String()
+	} else {
+		return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
 	}
-	if unverifiedManifest == nil {
+
+	if manifest == nil {
 		return false, fmt.Errorf("image manifest does not exist for tag or digest %q", tagOrDigest)
 	}
 
-	// If GetByTag succeeded, we can be confident that the registry on
+	// If manSvc.Get succeeded, we can be confident that the registry on
 	// the other side speaks the v2 protocol.
 	p.confirmedV2 = true
 
+	logrus.Debugf("Pulling ref from V2 registry: %s", ref.String())
+	progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+p.repo.Name())
+
+	var imageID image.ID
+
+	switch v := manifest.(type) {
+	case *schema1.SignedManifest:
+		imageID, err = p.pullSchema1(ctx, ref, v)
+		if err != nil {
+			return false, err
+		}
+	default:
+		return false, errors.New("unsupported manifest format")
+	}
+
+	oldTagImageID, err := p.config.ReferenceStore.Get(ref)
+	if err == nil && oldTagImageID == imageID {
+		return false, nil
+	}
+
+	if canonical, ok := ref.(reference.Canonical); ok {
+		if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
+			return false, err
+		}
+	} else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
+
+func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Named, unverifiedManifest *schema1.SignedManifest) (imageID image.ID, err error) {
 	var verifiedManifest *schema1.Manifest
 	verifiedManifest, err = verifyManifest(unverifiedManifest, ref)
 	if err != nil {
-		return false, err
+		return "", err
 	}
 
 	rootFS := image.NewRootFS()
 
 	if err := detectBaseLayer(p.config.ImageStore, verifiedManifest, rootFS); err != nil {
-		return false, err
+		return "", err
 	}
 
 	// remove duplicate layers and check parent chain validity
 	err = fixManifestLayers(verifiedManifest)
 	if err != nil {
-		return false, err
+		return "", err
 	}
 
-	progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+p.repo.Name())
-
 	var descriptors []xfer.DownloadDescriptor
 
 	// Image history converted to the new format
@@ -269,12 +296,12 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
 			ThrowAway bool `json:"throwaway,omitempty"`
 		}
 		if err := json.Unmarshal([]byte(verifiedManifest.History[i].V1Compatibility), &throwAway); err != nil {
-			return false, err
+			return "", err
 		}
 
 		h, err := v1.HistoryFromConfig([]byte(verifiedManifest.History[i].V1Compatibility), throwAway.ThrowAway)
 		if err != nil {
-			return false, err
+			return "", err
 		}
 		history = append(history, h)
 
@@ -293,43 +320,30 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
 
 	resultRootFS, release, err := p.config.DownloadManager.Download(ctx, *rootFS, descriptors, p.config.ProgressOutput)
 	if err != nil {
-		return false, err
+		return "", err
 	}
 	defer release()
 
 	config, err := v1.MakeConfigFromV1Config([]byte(verifiedManifest.History[0].V1Compatibility), &resultRootFS, history)
 	if err != nil {
-		return false, err
+		return "", err
 	}
 
-	imageID, err := p.config.ImageStore.Create(config)
+	imageID, err = p.config.ImageStore.Create(config)
 	if err != nil {
-		return false, err
+		return "", err
 	}
 
 	manifestDigest, _, err := digestFromManifest(unverifiedManifest, p.repoInfo)
 	if err != nil {
-		return false, err
+		return "", err
 	}
 
 	if manifestDigest != "" {
 		progress.Message(p.config.ProgressOutput, "", "Digest: "+manifestDigest.String())
 	}
 
-	oldTagImageID, err := p.config.ReferenceStore.Get(ref)
-	if err == nil && oldTagImageID == imageID {
-		return false, nil
-	}
-
-	if canonical, ok := ref.(reference.Canonical); ok {
-		if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
-			return false, err
-		}
-	} else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil {
-		return false, err
-	}
-
-	return true, nil
+	return imageID, nil
 }
 
 // allowV1Fallback checks if the error is a possible reason to fallback to v1
@@ -362,13 +376,7 @@ func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Named)
 		if err != nil {
 			return nil, err
 		}
-		payload, err := signedManifest.Payload()
-		if err != nil {
-			// If this failed, the signatures section was corrupted
-			// or missing. Treat the entire manifest as the payload.
-			payload = signedManifest.Raw
-		}
-		if _, err := verifier.Write(payload); err != nil {
+		if _, err := verifier.Write(signedManifest.Canonical); err != nil {
 			return nil, err
 		}
 		if !verifier.Verified() {
@@ -376,15 +384,8 @@ func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Named)
 			logrus.Error(err)
 			return nil, err
 		}
-
-		var verifiedManifest schema1.Manifest
-		if err = json.Unmarshal(payload, &verifiedManifest); err != nil {
-			return nil, err
-		}
-		m = &verifiedManifest
-	} else {
-		m = &signedManifest.Manifest
 	}
+	m = &signedManifest.Manifest
 
 	if m.SchemaVersion != 1 {
 		return nil, fmt.Errorf("unsupported schema version %d for %q", m.SchemaVersion, ref.String())
diff --git a/distribution/push_v2.go b/distribution/push_v2.go
index bf68c94c48..a94db2a47b 100644
--- a/distribution/push_v2.go
+++ b/distribution/push_v2.go
@@ -194,7 +194,9 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association reference.Associat
 	if err != nil {
 		return err
 	}
-	return manSvc.Put(signed)
+	_, err = manSvc.Put(ctx, signed)
+	// FIXME create a tag
+	return err
 }
 
 type v2PushDescriptor struct {
@@ -370,10 +372,7 @@ func CreateV2Manifest(name, tag string, img *image.Image, fsLayers map[layer.Dif
 		if !present {
 			return nil, fmt.Errorf("missing layer in CreateV2Manifest: %s", diffID.String())
 		}
-		dgst, err := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent))
-		if err != nil {
-			return nil, err
-		}
+		dgst := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent))
 		v1ID := dgst.Hex()
 
 		v1Compatibility := v1Compatibility{
@@ -414,11 +413,8 @@ func CreateV2Manifest(name, tag string, img *image.Image, fsLayers map[layer.Dif
 		return nil, fmt.Errorf("missing layer in CreateV2Manifest: %s", diffID.String())
 	}
 
-	dgst, err := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent + " " + string(img.RawJSON())))
-	if err != nil {
-		return nil, err
-	}
 	fsLayerList[0] = schema1.FSLayer{BlobSum: fsLayer}
+	dgst := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent + " " + string(img.RawJSON())))
 
 	// Top-level v1compatibility string should be a modified version of the
 	// image config.
diff --git a/distribution/registry.go b/distribution/registry.go
index d39a44411f..d01be73c45 100644
--- a/distribution/registry.go
+++ b/distribution/registry.go
@@ -8,7 +8,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/Sirupsen/logrus"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/manifest/schema1"
@@ -126,17 +125,7 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
 }
 
 func digestFromManifest(m *schema1.SignedManifest, name reference.Named) (digest.Digest, int, error) {
-	payload, err := m.Payload()
-	if err != nil {
-		// If this failed, the signatures section was corrupted
-		// or missing. Treat the entire manifest as the payload.
-		payload = m.Raw
-	}
-	manifestDigest, err := digest.FromBytes(payload)
-	if err != nil {
-		logrus.Infof("Could not compute manifest digest for %s:%s : %v", name.Name(), m.Tag, err)
-	}
-	return manifestDigest, len(payload), nil
+	return digest.FromBytes(m.Canonical), len(m.Canonical), nil
 }
 
 type existingTokenHandler struct {
diff --git a/distribution/xfer/download_test.go b/distribution/xfer/download_test.go
index 5d42703e63..587b2b24ab 100644
--- a/distribution/xfer/download_test.go
+++ b/distribution/xfer/download_test.go
@@ -65,12 +65,7 @@ func createChainIDFromParent(parent layer.ChainID, dgsts ...layer.DiffID) layer.
 		return createChainIDFromParent(layer.ChainID(dgsts[0]), dgsts[1:]...)
 	}
 	// H = "H(n-1) SHA256(n)"
-	dgst, err := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
-	if err != nil {
-		// Digest calculation is not expected to throw an error,
-		// any error at this point is a program error
-		panic(err)
-	}
+	dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
 	return createChainIDFromParent(layer.ChainID(dgst), dgsts[1:]...)
 }
 
@@ -92,11 +87,7 @@ func (ls *mockLayerStore) Register(reader io.Reader, parentID layer.ChainID) (la
 	if err != nil {
 		return nil, err
 	}
-	diffID, err := digest.FromBytes(l.layerData.Bytes())
-	if err != nil {
-		return nil, err
-	}
-	l.diffID = layer.DiffID(diffID)
+	l.diffID = layer.DiffID(digest.FromBytes(l.layerData.Bytes()))
 	l.chainID = createChainIDFromParent(parentID, l.diffID)
 
 	ls.layers[l.chainID] = l
diff --git a/distribution/xfer/upload_test.go b/distribution/xfer/upload_test.go
index df5b2ba9c0..70ca76c08d 100644
--- a/distribution/xfer/upload_test.go
+++ b/distribution/xfer/upload_test.go
@@ -62,7 +62,7 @@ func (u *mockUploadDescriptor) Upload(ctx context.Context, progressOutput progre
 
 	// For the mock implementation, use SHA256(DiffID) as the returned
 	// digest.
-	return digest.FromBytes([]byte(u.diffID.String()))
+	return digest.FromBytes([]byte(u.diffID.String())), nil
 }
 
 func uploadDescriptors(currentUploads *int32) []UploadDescriptor {
diff --git a/image/fs.go b/image/fs.go
index 7c1c4c22d6..72c9ab424b 100644
--- a/image/fs.go
+++ b/image/fs.go
@@ -101,11 +101,7 @@ func (s *fs) get(id ID) ([]byte, error) {
 	}
 
 	// todo: maybe optional
-	validated, err := digest.FromBytes(content)
-	if err != nil {
-		return nil, err
-	}
-	if ID(validated) != id {
+	if ID(digest.FromBytes(content)) != id {
 		return nil, fmt.Errorf("failed to verify image: %v", id)
 	}
 
@@ -121,11 +117,7 @@ func (s *fs) Set(data []byte) (ID, error) {
 		return "", fmt.Errorf("Invalid empty data")
 	}
 
-	dgst, err := digest.FromBytes(data)
-	if err != nil {
-		return "", err
-	}
-	id := ID(dgst)
+	id := ID(digest.FromBytes(data))
 	filePath := s.contentFile(id)
 	tempFilePath := s.contentFile(id) + ".tmp"
 	if err := ioutil.WriteFile(tempFilePath, data, 0600); err != nil {
diff --git a/image/fs_test.go b/image/fs_test.go
index 35ea3c25ea..1a6f849f6b 100644
--- a/image/fs_test.go
+++ b/image/fs_test.go
@@ -67,10 +67,7 @@ func TestFSInvalidSet(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	id, err := digest.FromBytes([]byte("foobar"))
-	if err != nil {
-		t.Fatal(err)
-	}
+	id := digest.FromBytes([]byte("foobar"))
 	err = os.Mkdir(filepath.Join(tmpdir, contentDirName, string(id.Algorithm()), id.Hex()), 0700)
 	if err != nil {
 		t.Fatal(err)
@@ -160,11 +157,7 @@ func testMetadataGetSet(t *testing.T, store StoreBackend) {
 		t.Fatal("Expected error for getting metadata for unknown key")
 	}
 
-	id3, err := digest.FromBytes([]byte("baz"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
+	id3 := digest.FromBytes([]byte("baz"))
 	err = store.SetMetadata(ID(id3), "tkey", []byte("tval"))
 	if err == nil {
 		t.Fatal("Expected error for setting metadata for unknown ID.")
diff --git a/image/rootfs_windows.go b/image/rootfs_windows.go
index 45db04bfda..10b854978c 100644
--- a/image/rootfs_windows.go
+++ b/image/rootfs_windows.go
@@ -27,7 +27,7 @@ func (r *RootFS) BaseLayerID() string {
 
 // ChainID returns the ChainID for the top layer in RootFS.
 func (r *RootFS) ChainID() layer.ChainID {
-	baseDiffID, _ := digest.FromBytes([]byte(r.BaseLayerID())) // can never error
+	baseDiffID := digest.FromBytes([]byte(r.BaseLayerID()))
 	return layer.CreateChainID(append([]layer.DiffID{layer.DiffID(baseDiffID)}, r.DiffIDs...))
 }
 
diff --git a/image/v1/imagev1.go b/image/v1/imagev1.go
index 4a67c017b3..cdea0e7270 100644
--- a/image/v1/imagev1.go
+++ b/image/v1/imagev1.go
@@ -63,7 +63,7 @@ func CreateID(v1Image image.V1Image, layerID layer.ChainID, parent digest.Digest
 	}
 	logrus.Debugf("CreateV1ID %s", configJSON)
 
-	return digest.FromBytes(configJSON)
+	return digest.FromBytes(configJSON), nil
 }
 
 // MakeConfigFromV1Config creates an image config from the legacy V1 config format.
diff --git a/layer/filestore_test.go b/layer/filestore_test.go
index 4dae3f8300..7b55e4d9ec 100644
--- a/layer/filestore_test.go
+++ b/layer/filestore_test.go
@@ -15,12 +15,8 @@ import (
 
 func randomLayerID(seed int64) ChainID {
 	r := rand.New(rand.NewSource(seed))
-	dgst, err := digest.FromBytes([]byte(fmt.Sprintf("%d", r.Int63())))
-	if err != nil {
-		panic(err)
-	}
 
-	return ChainID(dgst)
+	return ChainID(digest.FromBytes([]byte(fmt.Sprintf("%d", r.Int63()))))
 }
 
 func newFileMetadataStore(t *testing.T) (*fileMetadataStore, string, func()) {
diff --git a/layer/layer.go b/layer/layer.go
index 0c6d60c575..ef2ac7adc5 100644
--- a/layer/layer.go
+++ b/layer/layer.go
@@ -233,12 +233,7 @@ func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
 		return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
 	}
 	// H = "H(n-1) SHA256(n)"
-	dgst, err := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
-	if err != nil {
-		// Digest calculation is not expected to throw an error,
-		// any error at this point is a program error
-		panic(err)
-	}
+	dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
 	return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
 }
 
diff --git a/layer/layer_test.go b/layer/layer_test.go
index 5a96b7c209..a0ecb53d22 100644
--- a/layer/layer_test.go
+++ b/layer/layer_test.go
@@ -548,10 +548,7 @@ func TestTarStreamStability(t *testing.T) {
 }
 
 func assertLayerDiff(t *testing.T, expected []byte, layer Layer) {
-	expectedDigest, err := digest.FromBytes(expected)
-	if err != nil {
-		t.Fatal(err)
-	}
+	expectedDigest := digest.FromBytes(expected)
 
 	if digest.Digest(layer.DiffID()) != expectedDigest {
 		t.Fatalf("Mismatched diff id for %s, got %s, expected %s", layer.ChainID(), layer.DiffID(), expected)
@@ -573,10 +570,7 @@ func assertLayerDiff(t *testing.T, expected []byte, layer Layer) {
 		t.Fatalf("Mismatched tar stream size for %s, got %d, expected %d", layer.ChainID(), len(actual), len(expected))
 	}
 
-	actualDigest, err := digest.FromBytes(actual)
-	if err != nil {
-		t.Fatal(err)
-	}
+	actualDigest := digest.FromBytes(actual)
 
 	if actualDigest != expectedDigest {
 		logByteDiff(t, actual, expected)
diff --git a/layer/layer_windows.go b/layer/layer_windows.go
index e6396fa997..e20311a091 100644
--- a/layer/layer_windows.go
+++ b/layer/layer_windows.go
@@ -37,10 +37,7 @@ func GetLayerPath(s Store, layer ChainID) (string, error) {
 
 func (ls *layerStore) RegisterDiffID(graphID string, size int64) (Layer, error) {
 	var err error // this is used for cleanup in existingLayer case
-	diffID, err := digest.FromBytes([]byte(graphID))
-	if err != nil {
-		return nil, err
-	}
+	diffID := digest.FromBytes([]byte(graphID))
 
 	// Create new roLayer
 	layer := &roLayer{