diff --git a/CHANGELOG.md b/CHANGELOG.md
index dbae7f7..2020c47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# 1.4.0 (January 5, 2021)
+
+FEATURES:
+
+ - Introduce `MustConstraints()` ([#87](https://github.com/hashicorp/go-version/pull/87))
+ - `Constraints`: Introduce `Equals()` and `sort.Interface` methods ([#88](https://github.com/hashicorp/go-version/pull/88))
+
 # 1.3.0 (March 31, 2021)
 
 Please note that CHANGELOG.md does not exist in the source code prior to this release.
diff --git a/constraint.go b/constraint.go
index d055759..1d88090 100644
--- a/constraint.go
+++ b/constraint.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"reflect"
 	"regexp"
+	"sort"
 	"strings"
 )
 
@@ -11,30 +12,40 @@ import (
 // ">= 1.0".
 type Constraint struct {
 	f        constraintFunc
+	op       operator
 	check    *Version
 	original string
 }
 
+func (c *Constraint) Equals(con *Constraint) bool {
+	return c.op == con.op && c.check.Equal(con.check)
+}
+
 // Constraints is a slice of constraints. We make a custom type so that
 // we can add methods to it.
 type Constraints []*Constraint
 
 type constraintFunc func(v, c *Version) bool
 
-var constraintOperators map[string]constraintFunc
+var constraintOperators map[string]constraintOperation
+
+type constraintOperation struct {
+	op operator
+	f  constraintFunc
+}
 
 var constraintRegexp *regexp.Regexp
 
 func init() {
-	constraintOperators = map[string]constraintFunc{
-		"":   constraintEqual,
-		"=":  constraintEqual,
-		"!=": constraintNotEqual,
-		">":  constraintGreaterThan,
-		"<":  constraintLessThan,
-		">=": constraintGreaterThanEqual,
-		"<=": constraintLessThanEqual,
-		"~>": constraintPessimistic,
+	constraintOperators = map[string]constraintOperation{
+		"":   {op: equal, f: constraintEqual},
+		"=":  {op: equal, f: constraintEqual},
+		"!=": {op: notEqual, f: constraintNotEqual},
+		">":  {op: greaterThan, f: constraintGreaterThan},
+		"<":  {op: lessThan, f: constraintLessThan},
+		">=": {op: greaterThanEqual, f: constraintGreaterThanEqual},
+		"<=": {op: lessThanEqual, f: constraintLessThanEqual},
+		"~>": {op: pessimistic, f: constraintPessimistic},
 	}
 
 	ops := make([]string, 0, len(constraintOperators))
@@ -66,6 +77,16 @@ func NewConstraint(v string) (Constraints, error) {
 	return Constraints(result), nil
 }
 
+// MustConstraints is a helper that wraps a call to a function
+// returning (Constraints, error) and panics if error is non-nil.
+func MustConstraints(c Constraints, err error) Constraints {
+	if err != nil {
+		panic(err)
+	}
+
+	return c
+}
+
 // Check tests if a version satisfies all the constraints.
 func (cs Constraints) Check(v *Version) bool {
 	for _, c := range cs {
@@ -77,6 +98,56 @@ func (cs Constraints) Check(v *Version) bool {
 	return true
 }
 
+// Equals compares Constraints with other Constraints
+// for equality. This may not represent logical equivalence
+// of compared constraints.
+// e.g. even though '>0.1,>0.2' is logically equivalent
+// to '>0.2' it is *NOT* treated as equal.
+//
+// Missing operator is treated as equal to '=', whitespaces
+// are ignored and constraints are sorted before comaparison.
+func (cs Constraints) Equals(c Constraints) bool {
+	if len(cs) != len(c) {
+		return false
+	}
+
+	// make copies to retain order of the original slices
+	left := make(Constraints, len(cs))
+	copy(left, cs)
+	sort.Stable(left)
+	right := make(Constraints, len(c))
+	copy(right, c)
+	sort.Stable(right)
+
+	// compare sorted slices
+	for i, con := range left {
+		if !con.Equals(right[i]) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (cs Constraints) Len() int {
+	return len(cs)
+}
+
+func (cs Constraints) Less(i, j int) bool {
+	if cs[i].op < cs[j].op {
+		return true
+	}
+	if cs[i].op > cs[j].op {
+		return false
+	}
+
+	return cs[i].check.LessThan(cs[j].check)
+}
+
+func (cs Constraints) Swap(i, j int) {
+	cs[i], cs[j] = cs[j], cs[i]
+}
+
 // Returns the string format of the constraints
 func (cs Constraints) String() string {
 	csStr := make([]string, len(cs))
@@ -107,8 +178,11 @@ func parseSingle(v string) (*Constraint, error) {
 		return nil, err
 	}
 
+	cop := constraintOperators[matches[1]]
+
 	return &Constraint{
-		f:        constraintOperators[matches[1]],
+		f:        cop.f,
+		op:       cop.op,
 		check:    check,
 		original: v,
 	}, nil
@@ -138,6 +212,18 @@ func prereleaseCheck(v, c *Version) bool {
 // Constraint functions
 //-------------------------------------------------------------------
 
+type operator rune
+
+const (
+	equal            operator = '='
+	notEqual         operator = '≠'
+	greaterThan      operator = '>'
+	lessThan         operator = '<'
+	greaterThanEqual operator = '≥'
+	lessThanEqual    operator = '≤'
+	pessimistic      operator = '~'
+)
+
 func constraintEqual(v, c *Version) bool {
 	return v.Equal(c)
 }
diff --git a/constraint_test.go b/constraint_test.go
index 9c5bee3..a6f90d7 100644
--- a/constraint_test.go
+++ b/constraint_test.go
@@ -1,6 +1,9 @@
 package version
 
 import (
+	"fmt"
+	"reflect"
+	"sort"
 	"testing"
 )
 
@@ -97,6 +100,104 @@ func TestConstraintCheck(t *testing.T) {
 	}
 }
 
+func TestConstraintEqual(t *testing.T) {
+	cases := []struct {
+		leftConstraint  string
+		rightConstraint string
+		expectedEqual   bool
+	}{
+		{
+			"0.0.1",
+			"0.0.1",
+			true,
+		},
+		{ // whitespaces
+			" 0.0.1 ",
+			"0.0.1",
+			true,
+		},
+		{ // equal op implied
+			"=0.0.1 ",
+			"0.0.1",
+			true,
+		},
+		{ // version difference
+			"=0.0.1",
+			"=0.0.2",
+			false,
+		},
+		{ // operator difference
+			">0.0.1",
+			"=0.0.1",
+			false,
+		},
+		{ // different order
+			">0.1.0, <=1.0.0",
+			"<=1.0.0, >0.1.0",
+			true,
+		},
+	}
+
+	for _, tc := range cases {
+		leftCon, err := NewConstraint(tc.leftConstraint)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		rightCon, err := NewConstraint(tc.rightConstraint)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := leftCon.Equals(rightCon)
+		if actual != tc.expectedEqual {
+			t.Fatalf("Constraints: %s vs %s\nExpected: %t\nActual: %t",
+				tc.leftConstraint, tc.rightConstraint, tc.expectedEqual, actual)
+		}
+	}
+}
+
+func TestConstraint_sort(t *testing.T) {
+	cases := []struct {
+		constraint          string
+		expectedConstraints string
+	}{
+		{
+			">= 0.1.0,< 1.12",
+			"< 1.12,>= 0.1.0",
+		},
+		{
+			"< 1.12,>= 0.1.0",
+			"< 1.12,>= 0.1.0",
+		},
+		{
+			"< 1.12,>= 0.1.0,0.2.0",
+			"< 1.12,0.2.0,>= 0.1.0",
+		},
+		{
+			">1.0,>0.1.0,>0.3.0,>0.2.0",
+			">0.1.0,>0.2.0,>0.3.0,>1.0",
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			c, err := NewConstraint(tc.constraint)
+			if err != nil {
+				t.Fatalf("err: %s", err)
+			}
+
+			sort.Sort(c)
+
+			actual := c.String()
+
+			if !reflect.DeepEqual(actual, tc.expectedConstraints) {
+				t.Fatalf("unexpected order\nexpected: %#v\nactual: %#v",
+					tc.expectedConstraints, actual)
+			}
+		})
+	}
+}
+
 func TestConstraintsString(t *testing.T) {
 	cases := []struct {
 		constraint string
diff --git a/debian/changelog b/debian/changelog
index 2eefa3a..4983e56 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-hashicorp-go-version (1.4.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 16 May 2022 08:45:33 -0000
+
 golang-github-hashicorp-go-version (1.3.0-1) unstable; urgency=medium
 
   * Team upload.
diff --git a/version.go b/version.go
index 8068834..116a744 100644
--- a/version.go
+++ b/version.go
@@ -64,7 +64,6 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
 	}
 	segmentsStr := strings.Split(matches[1], ".")
 	segments := make([]int64, len(segmentsStr))
-	si := 0
 	for i, str := range segmentsStr {
 		val, err := strconv.ParseInt(str, 10, 64)
 		if err != nil {
@@ -72,8 +71,7 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
 				"Error parsing version: %s", err)
 		}
 
-		segments[i] = int64(val)
-		si++
+		segments[i] = val
 	}
 
 	// Even though we could support more than three segments, if we
@@ -92,7 +90,7 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
 		metadata: matches[10],
 		pre:      pre,
 		segments: segments,
-		si:       si,
+		si:       len(segmentsStr),
 		original: v,
 	}, nil
 }