diff --git a/cmd/init.go b/cmd/init.go
index b9874cbd6e..d5fc041289 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -561,7 +561,7 @@ func (cmd *InitCmd) initDockerCompose(f factory.Factory, composePath string) err
project.Name = projectName
// Prompt user for entrypoints for each container with sync folders.
- for idx, service := range project.Services {
+ for name, service := range project.Services {
localPaths := compose.GetServiceSyncPaths(project, service)
noEntryPoint := len(service.Entrypoint) == 0
hasSyncEndpoints := len(localPaths) > 0
@@ -574,8 +574,8 @@ func (cmd *InitCmd) initDockerCompose(f factory.Factory, composePath string) err
return err
}
- entrypoint := strings.Split(entrypointStr, " ")
- project.Services[idx].Entrypoint = entrypoint
+ service.Entrypoint = strings.Split(entrypointStr, " ")
+ project.Services[name] = service
}
}
diff --git a/go.mod b/go.mod
index 428ba7f7a0..02199f228a 100644
--- a/go.mod
+++ b/go.mod
@@ -1,28 +1,27 @@
module github.com/loft-sh/devspace
-go 1.25.0
-
-toolchain go1.25.9
+go 1.26.0
require (
github.com/AlecAivazis/survey/v2 v2.3.2
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/blang/semver v3.5.1+incompatible
github.com/bmatcuk/doublestar v1.1.1
- github.com/compose-spec/compose-go v1.2.2
+ github.com/compose-spec/compose-go/v2 v2.16.1
github.com/containers/storage v1.59.0
- github.com/creack/pty v1.1.18
+ github.com/creack/pty v1.1.24
github.com/distribution/reference v0.6.0
- github.com/docker/cli v28.2.2+incompatible
- github.com/docker/docker v28.3.3+incompatible
- github.com/docker/go-connections v0.5.0
+ github.com/docker/cli v29.5.3+incompatible
+ github.com/docker/docker v28.5.2+incompatible
+ github.com/docker/go-connections v0.7.0
github.com/evanphx/json-patch v5.9.11+incompatible
github.com/evanphx/json-patch/v5 v5.1.0
github.com/fujiwara/shapeio v1.0.0
github.com/gertd/go-pluralize v0.2.0
- github.com/gliderlabs/ssh v0.3.5
+ github.com/gliderlabs/ssh v0.3.8
+ github.com/go-git/go-git/v5 v5.19.2
github.com/go-resty/resty/v2 v2.17.2
- github.com/google/go-containerregistry v0.20.6
+ github.com/google/go-containerregistry v0.21.6
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674
github.com/invopop/jsonschema v0.4.0
@@ -36,9 +35,10 @@ require (
github.com/loft-sh/utils v0.0.16
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
github.com/mitchellh/go-homedir v1.1.0
- github.com/moby/buildkit v0.11.4
- github.com/moby/patternmatcher v0.6.0
- github.com/moby/term v0.5.0
+ github.com/moby/buildkit v0.31.1
+ github.com/moby/moby/client v0.4.1
+ github.com/moby/patternmatcher v0.6.1
+ github.com/moby/term v0.5.2
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo/v2 v2.27.2
github.com/onsi/gomega v1.38.2
@@ -46,172 +46,193 @@ require (
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.10
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94
- github.com/sirupsen/logrus v1.9.4
+ github.com/sirupsen/logrus v1.10.1
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c
- github.com/spf13/cobra v1.10.0
+ github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/vmware-labs/yaml-jsonpath v0.3.2
- golang.org/x/crypto v0.44.0
- golang.org/x/net v0.47.0
- golang.org/x/text v0.31.0
- google.golang.org/grpc v1.74.2
- google.golang.org/protobuf v1.36.8
+ golang.org/x/crypto v0.56.0
+ golang.org/x/net v0.58.0
+ golang.org/x/text v0.41.0
+ google.golang.org/grpc v1.83.2
+ google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af
gopkg.in/natefinch/lumberjack.v2 v2.0.0
- gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.1
gotest.tools v2.2.0+incompatible
- k8s.io/api v0.35.0
- k8s.io/apimachinery v0.35.0
- k8s.io/client-go v0.35.0
+ k8s.io/api v0.35.8
+ k8s.io/apimachinery v0.35.8
+ k8s.io/client-go v0.35.8
k8s.io/klog v1.0.0
- k8s.io/klog/v2 v2.130.1
- k8s.io/kubectl v0.35.0
+ k8s.io/klog/v2 v2.140.0
+ k8s.io/kubectl v0.35.8
mvdan.cc/sh/v3 v3.5.1
sigs.k8s.io/yaml v1.6.0
)
require (
- cloud.google.com/go/compute/metadata v0.7.0 // indirect
- github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
+ dario.cat/mergo v1.0.2 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/ProtonMail/go-crypto v1.3.0 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
- github.com/containerd/console v1.0.3 // indirect
- github.com/containerd/containerd v1.6.18 // indirect
- github.com/containerd/continuity v0.3.0 // indirect
+ github.com/cloudflare/circl v1.6.3 // indirect
+ github.com/containerd/console v1.0.5 // indirect
+ github.com/containerd/containerd/api v1.10.0 // indirect
+ github.com/containerd/containerd/v2 v2.2.4 // indirect
+ github.com/containerd/continuity v0.5.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
- github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
- github.com/containerd/typeurl v1.0.2 // indirect
+ github.com/containerd/platforms v1.0.0-rc.4 // indirect
+ github.com/containerd/ttrpc v1.2.8 // indirect
+ github.com/containerd/typeurl/v2 v2.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
+ github.com/cyphar/filepath-securejoin v0.6.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
- github.com/docker/docker-credential-helpers v0.9.3 // indirect
+ github.com/docker/docker-credential-helpers v0.9.8 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
+ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 // indirect
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960 // indirect
- github.com/emicklei/go-restful/v3 v3.12.2 // indirect
- github.com/emirpasic/gods v1.12.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.13.0 // indirect
+ github.com/emirpasic/gods v1.18.1 // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
+ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
+ github.com/go-git/go-billy/v5 v5.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/jsonreference v0.20.2 // indirect
- github.com/go-openapi/swag v0.23.0 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
+ github.com/go-openapi/jsonreference v0.21.6 // indirect
+ github.com/go-openapi/swag v0.26.0 // indirect
+ github.com/go-openapi/swag/cmdutils v0.26.0 // indirect
+ github.com/go-openapi/swag/conv v0.26.0 // indirect
+ github.com/go-openapi/swag/fileutils v0.26.0 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.0 // indirect
+ github.com/go-openapi/swag/jsonutils v0.26.0 // indirect
+ github.com/go-openapi/swag/loading v0.26.0 // indirect
+ github.com/go-openapi/swag/mangling v0.26.0 // indirect
+ github.com/go-openapi/swag/netutils v0.26.0 // indirect
+ github.com/go-openapi/swag/stringutils v0.26.0 // indirect
+ github.com/go-openapi/swag/typeutils v0.26.0 // indirect
+ github.com/go-openapi/swag/yamlutils v0.26.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
- github.com/gofrs/flock v0.8.1 // indirect
- github.com/gogo/googleapis v1.4.1 // indirect
- github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/protobuf v1.5.4 // indirect
+ github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
+ github.com/gofrs/flock v0.13.0 // indirect
+ github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-github/v30 v30.1.0 // indirect
github.com/google/go-querystring v1.0.0 // indirect
- github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
+ github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
- github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
+ github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
- github.com/imdario/mergo v0.3.12 // indirect
+ github.com/in-toto/attestation v1.2.0 // indirect
+ github.com/in-toto/in-toto-golang v0.11.0 // indirect
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
- github.com/josharian/intern v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
- github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
- github.com/klauspost/compress v1.18.0 // indirect
+ github.com/kevinburke/ssh_config v1.2.0 // indirect
+ github.com/klauspost/compress v1.18.7 // indirect
+ github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/kr/fs v0.1.0 // indirect
+ github.com/kr/pty v1.1.8 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
- github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
- github.com/moby/go-archive v0.1.0 // indirect
- github.com/moby/spdystream v0.5.0 // indirect
+ github.com/moby/go-archive v0.3.0 // indirect
+ github.com/moby/locker v1.0.1 // indirect
+ github.com/moby/moby/api v1.54.2 // indirect
+ github.com/moby/spdystream v0.5.1 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/sys/capability v0.4.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect
- github.com/moby/sys/sequential v0.6.0 // indirect
- github.com/moby/sys/signal v0.7.0 // indirect
- github.com/moby/sys/symlink v0.2.0 // indirect
- github.com/moby/sys/user v0.4.0 // indirect
+ github.com/moby/sys/sequential v0.7.0 // indirect
+ github.com/moby/sys/signal v0.7.1 // indirect
+ github.com/moby/sys/symlink v0.3.0 // indirect
+ github.com/moby/sys/user v0.4.1 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
- github.com/morikuni/aec v1.0.0 // indirect
+ github.com/morikuni/aec v1.1.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
- github.com/opencontainers/runtime-spec v1.2.1 // indirect
+ github.com/opencontainers/runtime-spec v1.3.0 // indirect
github.com/otiai10/mint v1.6.3 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
+ github.com/pjbgf/sha1cd v0.6.0 // indirect
+ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
- github.com/prometheus/common v0.66.1 // indirect
- github.com/prometheus/procfs v0.16.1 // indirect
+ github.com/prometheus/common v0.67.5 // indirect
+ github.com/prometheus/procfs v0.20.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
- github.com/sergi/go-diff v1.2.0 // indirect
- github.com/src-d/gcfg v1.4.0 // indirect
+ github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
+ github.com/secure-systems-lab/go-securesystemslib v0.11.0 // indirect
+ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
+ github.com/shibumi/go-pathspec v1.3.0 // indirect
+ github.com/skeema/knownhosts v1.3.1 // indirect
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465 // indirect
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
- github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa // indirect
+ github.com/tonistiigi/fsutil v0.0.0-20260609091201-0257b3308df4 // indirect
+ github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
- github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f // indirect
+ github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
- github.com/vbatts/tar-split v0.12.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
- github.com/xanzy/ssh-agent v0.2.1 // indirect
- github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
- github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
- github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+ github.com/xanzy/ssh-agent v0.3.3 // indirect
+ github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
- go.opentelemetry.io/auto/sdk v1.1.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.36.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
- go.opentelemetry.io/otel/metric v1.36.0 // indirect
- go.opentelemetry.io/otel/sdk v1.36.0 // indirect
- go.opentelemetry.io/otel/trace v1.36.0 // indirect
- go.opentelemetry.io/proto/otlp v1.5.0 // indirect
- go.yaml.in/yaml/v2 v2.4.3 // indirect
+ go.opentelemetry.io/auto/sdk v1.2.1 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
+ go.opentelemetry.io/otel v1.44.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect
+ go.opentelemetry.io/otel/metric v1.44.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.44.0 // indirect
+ go.opentelemetry.io/otel/trace v1.44.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.10.0 // indirect
+ go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/mod v0.29.0 // indirect
- golang.org/x/oauth2 v0.30.0 // indirect
- golang.org/x/sync v0.18.0 // indirect
- golang.org/x/sys v0.38.0 // indirect
- golang.org/x/term v0.37.0 // indirect
- golang.org/x/time v0.12.0 // indirect
- golang.org/x/tools v0.38.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
+ go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect
+ golang.org/x/mod v0.38.0 // indirect
+ golang.org/x/oauth2 v0.36.0 // indirect
+ golang.org/x/sync v0.22.0 // indirect
+ golang.org/x/sys v0.47.0 // indirect
+ golang.org/x/term v0.45.0 // indirect
+ golang.org/x/time v0.15.0 // indirect
+ golang.org/x/tools v0.48.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- k8s.io/cli-runtime v0.35.0 // indirect
- k8s.io/component-base v0.35.0 // indirect
+ k8s.io/cli-runtime v0.35.8 // indirect
+ k8s.io/component-base v0.35.8 // indirect
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
diff --git a/go.sum b/go.sum
index 0705c5405e..82e27419ce 100644
--- a/go.sum
+++ b/go.sum
@@ -1,135 +1,118 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
-cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
+cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8=
+cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
+dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
+dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AlecAivazis/survey/v2 v2.3.2 h1:TqTB+aDDCLYhf9/bD2TwSO8u8jDSmMUd2SUVO4gCnU8=
github.com/AlecAivazis/survey/v2 v2.3.2/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg=
-github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
-github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/Microsoft/hcsshim v0.13.0 h1:/BcXOiS6Qi7N9XqUcv27vkIuVOkBEcWstd2pMlWSeaA=
-github.com/Microsoft/hcsshim v0.13.0/go.mod h1:9KWJ/8DgU+QzYGupX4tzMhRQE8h6w90lH6HAaclpEok=
+github.com/Microsoft/hcsshim v0.14.1 h1:CMuB3fqQVfPdhyXhUqYdUmPUIOhJkmghCx3dJet8Cqs=
+github.com/Microsoft/hcsshim v0.14.1/go.mod h1:VnzvPLyWUhxiPVsJ31P6XadxCcTogTguBFDy/1GR/OM=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
-github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
+github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
-github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
-github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/anchore/go-struct-converter v0.1.0 h1:2rDRssAl6mgKBSLNiVCMADgZRhoqtw9dedlWa0OhD30=
+github.com/anchore/go-struct-converter v0.1.0/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
-github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
-github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
-github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
-github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
+github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
-github.com/compose-spec/compose-go v1.2.2 h1:y1dwl3KUTBnWPVur6EZno9zUIum6Q87/F5keljnGQB4=
-github.com/compose-spec/compose-go v1.2.2/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8=
-github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA=
-github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
-github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
-github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
-github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
-github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns=
-github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw=
-github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
-github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
+github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
+github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
+github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
+github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
+github.com/compose-spec/compose-go/v2 v2.16.1 h1:xuEQu32ghB2AK023Beumm//K8bz8u1AHC9P0zKp8jlw=
+github.com/compose-spec/compose-go/v2 v2.16.1/go.mod h1:Q1+qtN4vhzEjGrnqRtzx1xa8raDZQlMUe3WJxndYNiQ=
+github.com/containerd/cgroups/v3 v3.1.3 h1:eUNflyMddm18+yrDmZPn3jI7C5hJ9ahABE5q6dyLYXQ=
+github.com/containerd/cgroups/v3 v3.1.3/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=
+github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
+github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
+github.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o=
+github.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM=
+github.com/containerd/containerd/v2 v2.2.4 h1:8x2UdXqww7NYqGNabQ7i1nAgB5LegzjC9KQzO/900iA=
+github.com/containerd/containerd/v2 v2.2.4/go.mod h1:YBcTO8D9149QY9zNmUjy04Mhuc4DlrZQ8FIOwKZEM7o=
+github.com/containerd/continuity v0.5.0 h1:7a85HZpCSs+1Zps0Ee3DPSuAWY+0SJM1JNM51nlEVDg=
+github.com/containerd/continuity v0.5.0/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
-github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU=
-github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
+github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
-github.com/containerd/nydus-snapshotter v0.3.1 h1:b8WahTrPkt3XsabjG2o/leN4fw3HWZYr+qxo/Z8Mfzk=
-github.com/containerd/nydus-snapshotter v0.3.1/go.mod h1:+8R7NX7vrjlxAgtidnsstwIhpzyTlriYPssTxH++uiM=
-github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8=
-github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU=
-github.com/containerd/ttrpc v1.1.0 h1:GbtyLRxb0gOLR0TYQWt3O6B0NvT8tMdorEHqIQo/lWI=
-github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
-github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
-github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
-github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso=
-github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g=
+github.com/containerd/nydus-snapshotter v0.15.15 h1:kVYbFpYA4K43qxGVoc/VBwRXLAVWn4X9mdwGrR+HsLk=
+github.com/containerd/nydus-snapshotter v0.15.15/go.mod h1:L96yO+4iE6qqDiqXKhxMXBoPeaE7JgzXir9yanUVuOY=
+github.com/containerd/platforms v1.0.0-rc.4 h1:M42JrUT4zfZTqtkUwkr0GzmUWbfyO5VO0Q5b3op97T4=
+github.com/containerd/platforms v1.0.0-rc.4/go.mod h1:lKlMXyLybmBedS/JJm11uDofzI8L2v0J2ZbYvNsbq1A=
+github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=
+github.com/containerd/plugin v1.0.0/go.mod h1:hQfJe5nmWfImiqT1q8Si3jLv3ynMUIBB47bQ+KexvO8=
+github.com/containerd/stargz-snapshotter v0.18.2 h1:Ev/sxfQUjwzJQ9eqy3XzttcQ3osMIqkQgMYlcET+10M=
+github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw=
+github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY=
+github.com/containerd/ttrpc v1.2.8 h1:xbVu6D4qF2jihdh9rDVOKqUMiFBQk6YctTdo1zk087Y=
+github.com/containerd/ttrpc v1.2.8/go.mod h1:wyZW2K79t4Hfcxl+GUvkZqRBzJlqFFvgEeeWXa42tyE=
+github.com/containerd/typeurl/v2 v2.3.0 h1:HZHPhRWo5XMy3QGQoPrUzbW/2ckwjfweHmOwlkIrPAQ=
+github.com/containerd/typeurl/v2 v2.3.0/go.mod h1:Qk+PAdUYArVj41TnGi6rJ+48RF0PkcTc4i/taoBcK0w=
github.com/containers/storage v1.59.0 h1:r2pYSTzQpJTROZbjJQ54Z0GT+rUC6+wHzlSY8yPjsXk=
github.com/containers/storage v1.59.0/go.mod h1:KoAYHnAjP3/cTsRS+mmWZGkufSY2GACiKQ4V3ZLQnR0=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
-github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
+github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
+github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
+github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e h1:n81KvOMrLZa+VWHwST7dun9f0G98X3zREHS1ztYzZKU=
-github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e/go.mod h1:xpWTC2KnJMiDLkoawhsPQcXjvwATEBcbq0xevG2YR9M=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
-github.com/docker/cli v28.2.2+incompatible h1:qzx5BNUDFqlvyq4AHzdNB7gSyVTmU4cgsyN9SdInc1A=
-github.com/docker/cli v28.2.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/docker/cli v29.5.3+incompatible h1:nbEFfz774vBwQ5KRYv7c/AghjReqnGISvrRhzjV0evs=
+github.com/docker/cli v29.5.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
-github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
-github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
-github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
-github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
+github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.8 h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q=
+github.com/docker/docker-credential-helpers v0.9.8/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
+github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
+github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -140,28 +123,20 @@ github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960 h1:aRd8M7HJVZOqn/v
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
-github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
-github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
-github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
+github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
+github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
+github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
+github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg=
github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
-github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -171,20 +146,25 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gertd/go-pluralize v0.2.0 h1:VzWNnxkUo3wkW2Nmp+3ieHSTQQ0LBHeSVxlKsQPQ+UY=
github.com/gertd/go-pluralize v0.2.0/go.mod h1:4ouO1Ndf/r7sZMorwp4Sbfw80lUni+sd+o3qJR8L9To=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE=
github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
-github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
-github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
+github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
+github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
+github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA=
+github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw=
+github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
+github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
+github.com/go-git/go-git/v5 v5.19.2 h1:wkfn7vOlUBu8ivAWKBWisTiwJK4jYHzTF8Ndv1LyGqY=
+github.com/go-git/go-git/v5 v5.19.2/go.mod h1:QqCBE1EFN5ddFmrliLQ3/ntRCUjZU3EJuwuB/jWEHjk=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
@@ -193,102 +173,101 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
-github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
-github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
+github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y=
+github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY=
+github.com/go-openapi/swag v0.26.0 h1:GVDXCmfvhfu1BxiHo8/FA+BbKmhecHnG3varjON5/RI=
+github.com/go-openapi/swag v0.26.0/go.mod h1:82g3193sZJRbocs7bNCqGfIgq8pkuwVwCfhKIRlEQF0=
+github.com/go-openapi/swag/cmdutils v0.26.0 h1:iowihOcvq7y4egO8cOq0dmfohz6wfeQ63U1EnuhO2TU=
+github.com/go-openapi/swag/cmdutils v0.26.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
+github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I=
+github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE=
+github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU=
+github.com/go-openapi/swag/fileutils v0.26.0/go.mod h1:0WDJ7lp67eNjPMO50wAWYlKvhOb6CQ37rzR7wrgI8Tc=
+github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
+github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
+github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA=
+github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y=
+github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko=
+github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg=
+github.com/go-openapi/swag/mangling v0.26.0 h1:Du2YC4YLA/Y5m/YKQd7AnY5qq0wRKSFZTTt8ktFaXcQ=
+github.com/go-openapi/swag/mangling v0.26.0/go.mod h1:jifS7W9vbg+pw63bT+GI53otluMQL3CeemuyCHKwVx0=
+github.com/go-openapi/swag/netutils v0.26.0 h1:CmZp+ZT7HrmFwrC3GdGsXBq2+42T1bjKBapcqVpIs3c=
+github.com/go-openapi/swag/netutils v0.26.0/go.mod h1:5iK+Ok3ZohWWex1C50BFTPexi03UaPwjW4Oj8kgrpwo=
+github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg=
+github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE=
+github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4=
+github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE=
+github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ=
+github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE=
+github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo=
+github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
-github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
+github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
-github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
-github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
-github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
-github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
+github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
+github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
-github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU=
-github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
+github.com/google/go-containerregistry v0.21.6 h1:T+yqQIlJXKrM98Om4DlW3GoWQAmhZuLMwoDOvVrtiUM=
+github.com/google/go-containerregistry v0.21.6/go.mod h1:U7MMSBIJynke2MVQrQk19NP9k/uQsGz/h0amIFSHMbo=
github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
+github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg=
+github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
-github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
-github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/in-toto/in-toto-golang v0.5.0 h1:hb8bgwr0M2hGdDsLjkJ3ZqJ8JFLL/tgYdAxF/XEFBbY=
-github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1GdHMCq8+WPxw8/BE=
+github.com/in-toto/attestation v1.2.0 h1:aPRUZ3azbqD7yEBD5fP3TD8Dszf+YHo284SOcpahjQk=
+github.com/in-toto/attestation v1.2.0/go.mod h1:r79G45gOmzPismgObLSL+rZTFxUgZLOQJI6LofTZgXk=
+github.com/in-toto/in-toto-golang v0.11.0 h1:nfidMYBFx+E0lnmX5KUnN2Pdm8zdNKal1ayjJuzzRoA=
+github.com/in-toto/in-toto-golang v0.11.0/go.mod h1:u3PjTnwFKjp5a1YCcw8SJg0G+tMeKfVoWsWeFMDCMtw=
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/jsonschema v0.4.0 h1:Yuy/unfgCnfV5Wl7H0HgFufp/rlurqPOOuacqyByrws=
@@ -297,11 +276,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
-github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
-github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE=
github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -313,21 +289,19 @@ github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcM
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
-github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
-github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
-github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
-github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/klauspost/compress v1.18.7 h1:aUyZsS4kH3QTKurYhAOwAHxllVPnOthb3vPfnF1Ehjw=
+github.com/klauspost/compress v1.18.7/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
+github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
+github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -349,9 +323,6 @@ github.com/loft-sh/programming-language-detection v0.0.5 h1:XiWlxtrf4t6Z7SQiob0J
github.com/loft-sh/programming-language-detection v0.0.5/go.mod h1:QGPQGKr9q1+rQS4OyisS5CPGY1a76SdNaZuk9oy+2cE=
github.com/loft-sh/utils v0.0.16 h1:XnD6Sb6gRWIHgM34U94dHcQ5MtxN5kAGZQ5eddAxC+c=
github.com/loft-sh/utils v0.0.16/go.mod h1:n2L3X4i7d8kb2NF+q5duKa41N+N6fBde6XY2AolgSBI=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -374,40 +345,42 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
-github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
-github.com/moby/buildkit v0.11.4 h1:mleVHr+n7HUD65QNUkgkT3d8muTzhYUoHE9FM3Ej05s=
-github.com/moby/buildkit v0.11.4/go.mod h1:P5Qi041LvCfhkfYBHry+Rwoo3Wi6H971J2ggE+PcIoo=
+github.com/moby/buildkit v0.31.1 h1:j3p55abBl4kiXXPZgYX+6zWgB2aefqHXoPown12fIzU=
+github.com/moby/buildkit v0.31.1/go.mod h1:YM5iNEbNCc6L1Zt3YWFB/aXNLufvf4Rcu0DPlc9HwQg=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
-github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
-github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
+github.com/moby/go-archive v0.3.0 h1:nos4BtzzUIqB406BgQnWGMI4qib9BZ8XUHU+ucv/n1c=
+github.com/moby/go-archive v0.3.0/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
-github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
-github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
-github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
-github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
+github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg=
+github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
+github.com/moby/moby/client v0.4.1 h1:DMQgisVoMkmMs7fp3ROSdiBnoAu8+vo3GggFl06M/wY=
+github.com/moby/moby/client v0.4.1/go.mod h1:z52C9O2POPOsnxZAy//WtKcQ32P+jT/NGeXu/7nfjGQ=
+github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
+github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+github.com/moby/policy-helpers v0.0.0-20260612073044-d5411a945cfc h1:dvhPFj1niuMP3CBCjhiZWJQr//+w1LOA8cHclFJnNe0=
+github.com/moby/policy-helpers v0.0.0-20260612073044-d5411a945cfc/go.mod h1:frGYJTxenVCGPa9doaqZSU9FqzT7bt+1dFeVAaCFoyQ=
+github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y=
+github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
-github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
-github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
-github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
-github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
-github.com/moby/sys/symlink v0.2.0 h1:tk1rOM+Ljp0nFmfOIBtlV3rTDlWOwFRhjEeAhZB0nZc=
-github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
-github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
-github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
+github.com/moby/sys/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8=
+github.com/moby/sys/sequential v0.7.0/go.mod h1:NfSTAp6V3fw4tmkD62PEcOKeZKquXT8VKCkf7aVR79o=
+github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
+github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=
+github.com/moby/sys/symlink v0.3.0 h1:GZX89mEZ9u53f97npBy4Rc3vJKj7JBDj/PN2I22GrNU=
+github.com/moby/sys/symlink v0.3.0/go.mod h1:3eNdhduHmYPcgsJtZXW1W4XUJdZGBIkttZ8xKqPUJq0=
+github.com/moby/sys/user v0.4.1 h1:RgjRlaDKi/Xmyrz4t8lyzXT6v2ooFeO/7xtchmhVWE0=
+github.com/moby/sys/user v0.4.1/go.mod h1:E9QsW5WRe1kUAf7kW8hXKwu1uhsZEAdPLYHYSDudF4Y=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
-github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
-github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
+github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
+github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -418,14 +391,13 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
-github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
-github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
+github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -439,33 +411,32 @@ github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
-github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
-github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
-github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
-github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplUkdTrmPb8=
-github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=
+github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/selinux v1.15.1 h1:ERxeh5caJvCzNAKdI8WQbJmB1LDTn4BuaAg8wihLBpA=
+github.com/opencontainers/selinux v1.15.1/go.mod h1:LenyElirjUHszfxrjuFqC85HIeXZKumHcKMQtnaDlQQ=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
-github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiLBVp4DAcZlBVBEtJpNWZpZVq0AEeCY7Hqk8URVs4o=
-github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c=
-github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
-github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
-github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/package-url/packageurl-go v0.1.1 h1:KTRE0bK3sKbFKAk3yy63DpeskU7Cvs/x/Da5l+RtzyU=
+github.com/package-url/packageurl-go v0.1.1/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c=
+github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc=
+github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU=
+github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.10 h1:+5FbKNTe5Z9aspU88DPIKJ9z2KZoaGCu6Sr6kKR/5mU=
github.com/pkg/sftp v1.13.10/go.mod h1:bJ1a7uDhrX/4OII+agvy28lzRvQrmIQuaHrcI1HbeGA=
+github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
+github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -476,57 +447,53 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
-github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
+github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
+github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
-github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
+github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0=
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
-github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
+github.com/secure-systems-lab/go-securesystemslib v0.11.0 h1:iuCR9kcMFD4QurdKrGvPLoKZLv9YvwPYVr0473BdtFs=
+github.com/secure-systems-lab/go-securesystemslib v0.11.0/go.mod h1:+PMOTjUGwHj2vcZ+TFKlb1tXRbrdWE1LYDT5i9JC80Q=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
-github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
+github.com/sigstore/sigstore v1.10.8 h1:1Mgkxvkw4AXMfIP1DOjc6kw0GkUgA8pGVpveN/EfOq4=
+github.com/sigstore/sigstore v1.10.8/go.mod h1:f9+B/4iaYimvUkySyb2mvc73n3RLqNn24grHZM/ET8M=
+github.com/sigstore/sigstore-go v1.2.1 h1:YWP/rDbBaEBvtbkj6xtwsSj38ZCFEhTVVadNOXjVe3A=
+github.com/sigstore/sigstore-go v1.2.1/go.mod h1:I8BqVwAb/SaQJ5pBu5IDFY+ksq8O/1/kCag8XUgrsko=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
-github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.10.1 h1:xi4336Zh11WpU14fXR6I67V3yaTPQYwRx2WEtHbRg4Q=
+github.com/sirupsen/logrus v1.10.1/go.mod h1:vsQHnG7xzNsxk3NrwboUiWPnIC3dmbjcGPykD7+tiHk=
+github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
+github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c h1:fyKiXKO1/I/B6Y2U8T7WdQGWzwehOuGIrljPtt7YTTI=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
-github.com/spdx/tools-golang v0.3.1-0.20230104082527-d6f58551be3f h1:9B623Cfs+mclYK6dsae7gLSwuIBHvlgmEup87qpqsAQ=
-github.com/spdx/tools-golang v0.3.1-0.20230104082527-d6f58551be3f/go.mod h1:VHzvNsKAfAGqs4ZvwRL+7a0dNsL20s7lGui4K9C0xQM=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v1.10.0 h1:a5/WeUlSDCvV5a45ljW2ZFtV0bTDpkfSAj3uqB6Sc+0=
-github.com/spf13/cobra v1.10.0/go.mod h1:9dhySC7dnTtEiqzmqfkLj47BslqLCUPMXjG2lj/NgoE=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.8/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spdx/tools-golang v0.5.7 h1:+sWcKGnhwp3vLdMqPcLdA6QK679vd86cK9hQWH3AwCg=
+github.com/spdx/tools-golang v0.5.7/go.mod h1:jg7w0LOpoNAw6OxKEzCoqPC2GCTj45LyTlVmXubDsYw=
+github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
+github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
-github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -537,11 +504,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
-github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
+github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465 h1:yhxdTGmFkAM2TFA65c3NgGwpnIkUM8oVqPX2e9S7IVg=
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y=
github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw=
@@ -554,225 +518,142 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
-github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa h1:XOFp/3aBXlqmOFAg3r6e0qQjPnK5I970LilqX+Is1W8=
-github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa/go.mod h1:AvLEd1LEIl64G2Jpgwo7aVV5lGH0ePcKl0ygGIHNYl8=
+github.com/tonistiigi/fsutil v0.0.0-20260609091201-0257b3308df4 h1:tJkv/edHw9FXVtbHxc6cpqDttiCLNzhqI1W40fcnxIY=
+github.com/tonistiigi/fsutil v0.0.0-20260609091201-0257b3308df4/go.mod h1:K5zrLch9UaSGNiek5XHZeqZUf1zPWJHqDfLIcnpquQ4=
+github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 h1:2f304B10LaZdB8kkVEaoXvAMVan2tl9AiK4G0odjQtE=
+github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0/go.mod h1:278M4p8WsNh3n4a1eqiFcV2FGk7wE5fwUpUom9mK9lE=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
-github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f h1:DLpt6B5oaaS8jyXHa9VA4rrZloBVPVXeCtrOsrFauxc=
-github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc=
+github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab h1:H6aJ0yKQ0gF49Qb2z5hI1UHxSQt4JMyxebFR15KnApw=
+github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc=
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
-github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
-github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
+github.com/vbatts/tar-split v0.12.3 h1:Cd46rkGXI3Td4yrVNwU8ripbxFaQbmesqhjBUUYAJSw=
+github.com/vbatts/tar-split v0.12.3/go.mod h1:sQOc6OlqGCr7HkGx/IDBeKiTIvqhmj8KffNhEXG4Nq0=
github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
-github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
-github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
-github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
+github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
-github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
-github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
-go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 h1:n9b7AAdbQtQ0k9dm0Dm2/KUcUqtG8i2O15KzNaDze8c=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0/go.mod h1:LsankqVDx4W+RhZNA5uWarULII/MBhF5qwCYxTuyXjs=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
-go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
-go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
-go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
-go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
-go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
-go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
-go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
-go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
-go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
-go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
-go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
-go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
+go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0 h1:MCcYL7J6Vt/X0kjqbMZkekCmwsurbQRbL69vkiye2lk=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0/go.mod h1:3jnStNwSufK+f5ktjL4EPcwtig4rtd81NS70lqHuXl8=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
+go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
+go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s=
+go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
+go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
+go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
+go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
+go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
+go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
+go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
+go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
+go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
+go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
-go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
+go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
+go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U=
+go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
-golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
-golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
-golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y=
+golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I=
+golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
+golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
-golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
+golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
+golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
-golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
+golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
+golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
-golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
+golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
-golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
+golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
-golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
+golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
+golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
-golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
+golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
+golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
-golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
-golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
+golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
-google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
-google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
-google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
+google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
+google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -785,21 +666,13 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
-gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
-gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
-gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
-gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
-gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -810,30 +683,30 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY=
-k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA=
-k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8=
-k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
-k8s.io/cli-runtime v0.35.0 h1:PEJtYS/Zr4p20PfZSLCbY6YvaoLrfByd6THQzPworUE=
-k8s.io/cli-runtime v0.35.0/go.mod h1:VBRvHzosVAoVdP3XwUQn1Oqkvaa8facnokNkD7jOTMY=
-k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE=
-k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o=
-k8s.io/component-base v0.35.0 h1:+yBrOhzri2S1BVqyVSvcM3PtPyx5GUxCK2tinZz1G94=
-k8s.io/component-base v0.35.0/go.mod h1:85SCX4UCa6SCFt6p3IKAPej7jSnF3L8EbfSyMZayJR0=
+k8s.io/api v0.35.8 h1:hxpmPYdneQPKNh0cZyB09Hwd3vgXzdcJs5R3toDXsvU=
+k8s.io/api v0.35.8/go.mod h1:I5gVNknFd4hfVVcMCixrenD7V38JUY78q3jtpGyC19c=
+k8s.io/apimachinery v0.35.8 h1:piOyQQgse1sGztJVfy3B8f11YpT+KwK5KkD5Jie1EK0=
+k8s.io/apimachinery v0.35.8/go.mod h1:z9Vq5oR1X38pkhh0wV531iKSeqmOVjqgHdYMjvzq2+o=
+k8s.io/cli-runtime v0.35.8 h1:5rfvENhl4HklU8wUHVRPwUH/xHxgrK3Ly9c0dU4nDCg=
+k8s.io/cli-runtime v0.35.8/go.mod h1:TSinz+vrk8BTO2+Kd6BePZyW40YuK9W8m+5V4X6fTjQ=
+k8s.io/client-go v0.35.8 h1:tIW2sirCQMiGoCSvtOYqS059CDQ5n1nrDQa+PVt4nqY=
+k8s.io/client-go v0.35.8/go.mod h1:fT8dATMU8FHMq4hlOudbsxihQ1LIQfDaLNDXBnIk6OQ=
+k8s.io/component-base v0.35.8 h1:71CLVx1zho3wxSpKroYAzaV5e1yexwWFQqUxIEimGGk=
+k8s.io/component-base v0.35.8/go.mod h1:kM4Ide4Gh+bdZElhhgVvx5fC7oK39Smy8F3PbxEvV5o=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
-k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
-k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
+k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
-k8s.io/kubectl v0.35.0 h1:cL/wJKHDe8E8+rP3G7avnymcMg6bH6JEcR5w5uo06wc=
-k8s.io/kubectl v0.35.0/go.mod h1:VR5/TSkYyxZwrRwY5I5dDq6l5KXmiCb+9w8IKplk3Qo=
+k8s.io/kubectl v0.35.8 h1:bhfqvUYygfEFGeGjOfjkWSZ+gSG4TySnycrwHC2OzTs=
+k8s.io/kubectl v0.35.8/go.mod h1:mJgoBx+ROWm7REDEm5/KFuYfiWI/6leFtKZ9pA7l1ec=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
mvdan.cc/sh/v3 v3.5.1 h1:hmP3UOw4f+EYexsJjFxvU38+kn+V/s2CclXHanIBkmQ=
mvdan.cc/sh/v3 v3.5.1/go.mod h1:1JcoyAKm1lZw/2bZje/iYKWicU/KMd0rsyJeKHnsK4E=
+pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
+pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kustomize/api v0.20.1 h1:iWP1Ydh3/lmldBnH/S5RXgT98vWYMaTUL1ADcr+Sv7I=
diff --git a/pkg/devspace/build/builder/kaniko/kaniko.go b/pkg/devspace/build/builder/kaniko/kaniko.go
index 5034e7a0d8..5bca207870 100644
--- a/pkg/devspace/build/builder/kaniko/kaniko.go
+++ b/pkg/devspace/build/builder/kaniko/kaniko.go
@@ -111,7 +111,7 @@ func (b *Builder) ShouldRebuild(ctx devspacecontext.Context, forceRebuild bool)
func (b *Builder) BuildImage(ctx devspacecontext.Context, contextPath, dockerfilePath string, entrypoint []string, cmd []string) error {
var err error
- contextPath, err = build.ResolveAndValidateContextPath(contextPath)
+ contextPath, err = resolveAndValidateContextPath(contextPath)
if err != nil {
return errors.Wrap(err, "resolve context path")
}
@@ -417,3 +417,28 @@ func (b *Builder) BuildImage(ctx devspacecontext.Context, contextPath, dockerfil
return nil
}
+
+// resolveAndValidateContextPath returns the absolute, symlink-resolved path of the given build context directory
+func resolveAndValidateContextPath(givenContextDir string) (string, error) {
+ absContextDir, err := filepath.Abs(givenContextDir)
+ if err != nil {
+ return "", errors.Errorf("unable to get absolute context directory of given context directory %q: %v", givenContextDir, err)
+ }
+
+ // EvalSymlinks does not work on Windows UNC paths, so those are not followed
+ if !strings.HasPrefix(absContextDir, `\\`) {
+ absContextDir, err = filepath.EvalSymlinks(absContextDir)
+ if err != nil {
+ return "", errors.Errorf("unable to evaluate symlinks in context path: %v", err)
+ }
+ }
+
+ stat, err := os.Lstat(absContextDir)
+ if err != nil {
+ return "", errors.Errorf("unable to stat context directory %q: %v", absContextDir, err)
+ }
+ if !stat.IsDir() {
+ return "", errors.Errorf("context must be a directory: %s", absContextDir)
+ }
+ return absContextDir, nil
+}
diff --git a/pkg/devspace/build/builder/localregistry/build.go b/pkg/devspace/build/builder/localregistry/build.go
index 394cd824c0..a499965e94 100644
--- a/pkg/devspace/build/builder/localregistry/build.go
+++ b/pkg/devspace/build/builder/localregistry/build.go
@@ -21,6 +21,7 @@ import (
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth/authprovider"
"github.com/moby/buildkit/session/upload/uploadprovider"
+ mobyclient "github.com/moby/moby/client"
"github.com/docker/docker/api/types/build"
)
@@ -51,9 +52,9 @@ func RemoteBuild(ctx devspacecontext.Context, podName, namespace string, buildCo
FrontendAttrs: map[string]string{
"filename": buildOptions.Dockerfile,
"target": buildOptions.Target,
- "context": up.Add(buildContext),
+ "context": up.Add(io.NopCloser(buildContext)),
},
- Session: []session.Attachable{up, authprovider.NewDockerAuthProvider(dockerConfig)},
+ Session: []session.Attachable{up, authprovider.NewDockerAuthProvider(authprovider.DockerAuthProviderConfig{AuthConfigProvider: authprovider.LoadAuthConfig(dockerConfig)})},
Exports: []buildkit.ExportEntry{
{
Type: buildkit.ExporterImage,
@@ -142,7 +143,12 @@ func CopyImageToRemote(ctx context.Context, client dockerclient.Client, imageNam
return err
}
// get image data from local registry
- image, err := daemon.Image(localRef, daemon.WithContext(ctx), daemon.WithClient(client.DockerAPIClient()))
+ daemonClient, err := mobyclient.New(mobyclient.WithHost(client.DockerAPIClient().DaemonHost()), mobyclient.WithAPIVersionFromEnv())
+ if err != nil {
+ return err
+ }
+ defer daemonClient.Close()
+ image, err := daemon.Image(localRef, daemon.WithContext(ctx), daemon.WithClient(daemonClient))
if err != nil {
return err
}
diff --git a/pkg/devspace/build/builder/localregistry/printer.go b/pkg/devspace/build/builder/localregistry/printer.go
index 7e204b8f7d..ffac97ea6a 100644
--- a/pkg/devspace/build/builder/localregistry/printer.go
+++ b/pkg/devspace/build/builder/localregistry/printer.go
@@ -39,7 +39,11 @@ func NewPrinter(ctx context.Context, out io.Writer) (progresswriter.Writer, erro
}
go func() {
// not using shared context to not disrupt display but let is finish reporting errors
- _, pw.err = progressui.DisplaySolveStatus(ctx, "", nil, out, statusCh)
+ var display progressui.Display
+ display, pw.err = progressui.NewDisplay(out, progressui.PlainMode)
+ if pw.err == nil {
+ _, pw.err = display.UpdateFrom(ctx, statusCh)
+ }
close(doneCh)
}()
return pw, nil
diff --git a/pkg/devspace/compose/config_builder.go b/pkg/devspace/compose/config_builder.go
index 093bfef259..b5c1dbcc07 100644
--- a/pkg/devspace/compose/config_builder.go
+++ b/pkg/devspace/compose/config_builder.go
@@ -3,7 +3,7 @@ package compose
import (
"regexp"
- composetypes "github.com/compose-spec/compose-go/types"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
"github.com/loft-sh/devspace/pkg/util/log"
)
diff --git a/pkg/devspace/compose/dependency.go b/pkg/devspace/compose/dependency.go
index a5b61fc52a..7b891d4161 100644
--- a/pkg/devspace/compose/dependency.go
+++ b/pkg/devspace/compose/dependency.go
@@ -3,7 +3,7 @@ package compose
import (
"path/filepath"
- composetypes "github.com/compose-spec/compose-go/types"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
)
diff --git a/pkg/devspace/compose/deployment.go b/pkg/devspace/compose/deployment.go
index 778157ef2a..049198c26f 100644
--- a/pkg/devspace/compose/deployment.go
+++ b/pkg/devspace/compose/deployment.go
@@ -4,10 +4,9 @@ import (
"fmt"
"sort"
"strconv"
- "strings"
"time"
- composetypes "github.com/compose-spec/compose-go/types"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
v1 "k8s.io/api/core/v1"
)
@@ -84,11 +83,10 @@ func (cb *configBuilder) AddDeployment(dockerCompose *composetypes.Project, serv
if len(service.ExtraHosts) > 0 {
hostsMap := map[string][]interface{}{}
- for _, host := range service.ExtraHosts {
- hostTokens := strings.Split(host, ":")
- hostName := hostTokens[0]
- hostIP := hostTokens[1]
- hostsMap[hostIP] = append(hostsMap[hostIP], hostName)
+ for hostName, hostIPs := range service.ExtraHosts {
+ for _, hostIP := range hostIPs {
+ hostsMap[hostIP] = append(hostsMap[hostIP], hostName)
+ }
}
hostAliases := []interface{}{}
diff --git a/pkg/devspace/compose/dev.go b/pkg/devspace/compose/dev.go
index d5491e52f2..0d293a232d 100644
--- a/pkg/devspace/compose/dev.go
+++ b/pkg/devspace/compose/dev.go
@@ -7,7 +7,7 @@ import (
"strconv"
"strings"
- composetypes "github.com/compose-spec/compose-go/types"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
)
diff --git a/pkg/devspace/compose/image.go b/pkg/devspace/compose/image.go
index c0c07bcf91..3c0e0e4c2f 100644
--- a/pkg/devspace/compose/image.go
+++ b/pkg/devspace/compose/image.go
@@ -3,7 +3,7 @@ package compose
import (
"path/filepath"
- composetypes "github.com/compose-spec/compose-go/types"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
)
diff --git a/pkg/devspace/compose/manager.go b/pkg/devspace/compose/manager.go
index 6b48a5d8b5..1bd40766af 100644
--- a/pkg/devspace/compose/manager.go
+++ b/pkg/devspace/compose/manager.go
@@ -1,14 +1,15 @@
package compose
import (
+ "context"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
- composeloader "github.com/compose-spec/compose-go/loader"
- composetypes "github.com/compose-spec/compose-go/types"
+ composeloader "github.com/compose-spec/compose-go/v2/loader"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
"github.com/loft-sh/devspace/pkg/devspace/config/constants"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
"github.com/loft-sh/devspace/pkg/util/log"
@@ -38,20 +39,22 @@ func LoadDockerComposeProject(path string) (*composetypes.Project, error) {
return nil, err
}
- project, err := composeloader.Load(composetypes.ConfigDetails{
+ project, err := composeloader.LoadWithContext(context.Background(), composetypes.ConfigDetails{
ConfigFiles: []composetypes.ConfigFile{
{
Content: composeFile,
},
},
Environment: map[string]string{},
+ }, func(o *composeloader.Options) {
+ o.SetProjectName("devspace", false)
})
if err != nil {
return nil, err
}
// Expand service ports
- for idx, service := range project.Services {
+ for name, service := range project.Services {
ports := []composetypes.ServicePortConfig{}
for _, port := range service.Ports {
expandedPorts, err := expandPublishedPortRange(port)
@@ -60,7 +63,8 @@ func LoadDockerComposeProject(path string) (*composetypes.Project, error) {
}
ports = append(ports, expandedPorts...)
}
- project.Services[idx].Ports = ports
+ service.Ports = ports
+ project.Services[name] = service
}
return project, nil
@@ -91,7 +95,8 @@ func (cm *composeManager) Load(log log.Logger) error {
}
builders := map[string]ConfigBuilder{}
- err = cm.project.WithServices(nil, func(service composetypes.ServiceConfig) error {
+ err = cm.project.ForEachService(nil, func(_ string, svc *composetypes.ServiceConfig) error {
+ service := *svc
configName := "docker-compose"
workingDir := cm.project.WorkingDir
@@ -142,7 +147,8 @@ func (cm *composeManager) Load(log log.Logger) error {
return err
}
- err = cm.project.WithServices(nil, func(service composetypes.ServiceConfig) error {
+ err = cm.project.ForEachService(nil, func(_ string, svc *composetypes.ServiceConfig) error {
+ service := *svc
configName := "docker-compose"
path := constants.DefaultConfigPath
@@ -194,7 +200,7 @@ func (cm *composeManager) Save() error {
func calculateDependentsMap(dockerCompose *composetypes.Project) (map[string][]string, error) {
tree := map[string][]string{}
- err := dockerCompose.WithServices(nil, func(service composetypes.ServiceConfig) error {
+ err := dockerCompose.ForEachService(nil, func(_ string, service *composetypes.ServiceConfig) error {
for _, name := range service.GetDependencies() {
tree[name] = append(tree[name], service.Name)
}
diff --git a/pkg/devspace/compose/secret.go b/pkg/devspace/compose/secret.go
index fb3049e1e9..4aff51b988 100644
--- a/pkg/devspace/compose/secret.go
+++ b/pkg/devspace/compose/secret.go
@@ -4,7 +4,7 @@ import (
"fmt"
"path/filepath"
- composetypes "github.com/compose-spec/compose-go/types"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
)
diff --git a/pkg/devspace/compose/volume.go b/pkg/devspace/compose/volume.go
index 72a770142d..b2c356026a 100644
--- a/pkg/devspace/compose/volume.go
+++ b/pkg/devspace/compose/volume.go
@@ -5,7 +5,7 @@ import (
"github.com/loft-sh/devspace/pkg/util/log"
- composetypes "github.com/compose-spec/compose-go/types"
+ composetypes "github.com/compose-spec/compose-go/v2/types"
)
func GetServiceSyncPaths(
diff --git a/pkg/devspace/docker/config_test.go b/pkg/devspace/docker/config_test.go
index a61ba3cb50..66f9a9ef9c 100644
--- a/pkg/devspace/docker/config_test.go
+++ b/pkg/devspace/docker/config_test.go
@@ -36,7 +36,6 @@ func TestGetAllAuthConfigs(t *testing.T) {
"key": {
Username: "ValUser",
Password: "ValPass",
- Email: "ValEmail",
ServerAddress: "ValServerAddress",
IdentityToken: "ValIdentityToken",
RegistryToken: "ValRegistryToken",
@@ -48,7 +47,6 @@ func TestGetAllAuthConfigs(t *testing.T) {
"key": {
Username: "ValUser",
Password: "ValPass",
- Email: "ValEmail",
ServerAddress: "key",
IdentityToken: "ValIdentityToken",
RegistryToken: "ValRegistryToken",
diff --git a/pkg/util/git/go_git.go b/pkg/util/git/go_git.go
index d3374063e5..a93296d17f 100644
--- a/pkg/util/git/go_git.go
+++ b/pkg/util/git/go_git.go
@@ -4,9 +4,9 @@ import (
"fmt"
"os"
+ git "github.com/go-git/go-git/v5"
+ plumbing "github.com/go-git/go-git/v5/plumbing"
"github.com/pkg/errors"
- git "gopkg.in/src-d/go-git.v4"
- plumbing "gopkg.in/src-d/go-git.v4/plumbing"
)
// GoGitRepository holds the information about a repository
diff --git a/pkg/util/git/helper.go b/pkg/util/git/helper.go
index 29ee16a81a..39a7988e3b 100644
--- a/pkg/util/git/helper.go
+++ b/pkg/util/git/helper.go
@@ -11,8 +11,8 @@ import (
"github.com/loft-sh/utils/pkg/command"
"mvdan.cc/sh/v3/expand"
+ git "github.com/go-git/go-git/v5"
"github.com/pkg/errors"
- "gopkg.in/src-d/go-git.v4"
)
var LatestTagRegEx = regexp.MustCompile(`\/tag\/(.*)$`)
diff --git a/vendor/dario.cat/mergo/.deepsource.toml b/vendor/dario.cat/mergo/.deepsource.toml
new file mode 100644
index 0000000000..a8bc979e02
--- /dev/null
+++ b/vendor/dario.cat/mergo/.deepsource.toml
@@ -0,0 +1,12 @@
+version = 1
+
+test_patterns = [
+ "*_test.go"
+]
+
+[[analyzers]]
+name = "go"
+enabled = true
+
+ [analyzers.meta]
+ import_path = "dario.cat/mergo"
\ No newline at end of file
diff --git a/vendor/dario.cat/mergo/.gitignore b/vendor/dario.cat/mergo/.gitignore
new file mode 100644
index 0000000000..45ad0f1ae3
--- /dev/null
+++ b/vendor/dario.cat/mergo/.gitignore
@@ -0,0 +1,36 @@
+#### joe made this: http://goel.io/joe
+
+#### go ####
+# Binaries for programs and plugins
+*.exe
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Golang/Intellij
+.idea
+
+# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
+.glide/
+
+#### vim ####
+# Swap
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-v][a-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+
+# Temporary
+.netrwhist
+*~
+# Auto-generated tag files
+tags
diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/dario.cat/mergo/.travis.yml
similarity index 100%
rename from vendor/github.com/imdario/mergo/.travis.yml
rename to vendor/dario.cat/mergo/.travis.yml
diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
similarity index 100%
rename from vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
rename to vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
diff --git a/vendor/dario.cat/mergo/CONTRIBUTING.md b/vendor/dario.cat/mergo/CONTRIBUTING.md
new file mode 100644
index 0000000000..0a1ff9f94d
--- /dev/null
+++ b/vendor/dario.cat/mergo/CONTRIBUTING.md
@@ -0,0 +1,112 @@
+
+# Contributing to mergo
+
+First off, thanks for taking the time to contribute! ❤️
+
+All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
+
+> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
+> - Star the project
+> - Tweet about it
+> - Refer this project in your project's readme
+> - Mention the project at local meetups and tell your friends/colleagues
+
+
+## Table of Contents
+
+- [Code of Conduct](#code-of-conduct)
+- [I Have a Question](#i-have-a-question)
+- [I Want To Contribute](#i-want-to-contribute)
+- [Reporting Bugs](#reporting-bugs)
+- [Suggesting Enhancements](#suggesting-enhancements)
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by the
+[mergo Code of Conduct](https://github.com/imdario/mergoblob/master/CODE_OF_CONDUCT.md).
+By participating, you are expected to uphold this code. Please report unacceptable behavior
+to <>.
+
+
+## I Have a Question
+
+> If you want to ask a question, we assume that you have read the available [Documentation](https://pkg.go.dev/github.com/imdario/mergo).
+
+Before you ask a question, it is best to search for existing [Issues](https://github.com/imdario/mergo/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
+
+If you then still feel the need to ask a question and need clarification, we recommend the following:
+
+- Open an [Issue](https://github.com/imdario/mergo/issues/new).
+- Provide as much context as you can about what you're running into.
+- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
+
+We will then take care of the issue as soon as possible.
+
+## I Want To Contribute
+
+> ### Legal Notice
+> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
+
+### Reporting Bugs
+
+
+#### Before Submitting a Bug Report
+
+A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
+
+- Make sure that you are using the latest version.
+- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](). If you are looking for support, you might want to check [this section](#i-have-a-question)).
+- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/imdario/mergoissues?q=label%3Abug).
+- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
+- Collect information about the bug:
+- Stack trace (Traceback)
+- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
+- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
+- Possibly your input and the output
+- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
+
+
+#### How Do I Submit a Good Bug Report?
+
+> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to .
+
+
+We use GitHub issues to track bugs and errors. If you run into an issue with the project:
+
+- Open an [Issue](https://github.com/imdario/mergo/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
+- Explain the behavior you would expect and the actual behavior.
+- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
+- Provide the information you collected in the previous section.
+
+Once it's filed:
+
+- The project team will label the issue accordingly.
+- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
+- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be implemented by someone.
+
+### Suggesting Enhancements
+
+This section guides you through submitting an enhancement suggestion for mergo, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
+
+
+#### Before Submitting an Enhancement
+
+- Make sure that you are using the latest version.
+- Read the [documentation]() carefully and find out if the functionality is already covered, maybe by an individual configuration.
+- Perform a [search](https://github.com/imdario/mergo/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
+- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
+
+
+#### How Do I Submit a Good Enhancement Suggestion?
+
+Enhancement suggestions are tracked as [GitHub issues](https://github.com/imdario/mergo/issues).
+
+- Use a **clear and descriptive title** for the issue to identify the suggestion.
+- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
+- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
+- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.
+- **Explain why this enhancement would be useful** to most mergo users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
+
+
+## Attribution
+This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
diff --git a/vendor/dario.cat/mergo/FUNDING.json b/vendor/dario.cat/mergo/FUNDING.json
new file mode 100644
index 0000000000..0585e1fe13
--- /dev/null
+++ b/vendor/dario.cat/mergo/FUNDING.json
@@ -0,0 +1,7 @@
+{
+ "drips": {
+ "ethereum": {
+ "ownedBy": "0x6160020e7102237aC41bdb156e94401692D76930"
+ }
+ }
+}
diff --git a/vendor/github.com/imdario/mergo/LICENSE b/vendor/dario.cat/mergo/LICENSE
similarity index 100%
rename from vendor/github.com/imdario/mergo/LICENSE
rename to vendor/dario.cat/mergo/LICENSE
diff --git a/vendor/dario.cat/mergo/README.md b/vendor/dario.cat/mergo/README.md
new file mode 100644
index 0000000000..0e4a59afd9
--- /dev/null
+++ b/vendor/dario.cat/mergo/README.md
@@ -0,0 +1,253 @@
+# Mergo
+
+[![GitHub release][5]][6]
+[![GoCard][7]][8]
+[![Test status][1]][2]
+[![OpenSSF Scorecard][21]][22]
+[![OpenSSF Best Practices][19]][20]
+[![Coverage status][9]][10]
+[![Sourcegraph][11]][12]
+[![FOSSA status][13]][14]
+
+[![GoDoc][3]][4]
+[![Become my sponsor][15]][16]
+[![Tidelift][17]][18]
+
+[1]: https://github.com/imdario/mergo/workflows/tests/badge.svg?branch=master
+[2]: https://github.com/imdario/mergo/actions/workflows/tests.yml
+[3]: https://godoc.org/github.com/imdario/mergo?status.svg
+[4]: https://godoc.org/github.com/imdario/mergo
+[5]: https://img.shields.io/github/release/imdario/mergo.svg
+[6]: https://github.com/imdario/mergo/releases
+[7]: https://goreportcard.com/badge/imdario/mergo
+[8]: https://goreportcard.com/report/github.com/imdario/mergo
+[9]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
+[10]: https://coveralls.io/github/imdario/mergo?branch=master
+[11]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
+[12]: https://sourcegraph.com/github.com/imdario/mergo?badge
+[13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
+[14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
+[15]: https://img.shields.io/github/sponsors/imdario
+[16]: https://github.com/sponsors/imdario
+[17]: https://tidelift.com/badges/package/go/github.com%2Fimdario%2Fmergo
+[18]: https://tidelift.com/subscription/pkg/go-github.com-imdario-mergo
+[19]: https://bestpractices.coreinfrastructure.org/projects/7177/badge
+[20]: https://bestpractices.coreinfrastructure.org/projects/7177
+[21]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo/badge
+[22]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo
+
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
+
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
+
+## Status
+
+Mergo is stable and frozen, ready for production. Check a short list of the projects using at large scale it [here](https://github.com/imdario/mergo#mergo-in-the-wild).
+
+No new features are accepted. They will be considered for a future v2 that improves the implementation and fixes bugs for corner cases.
+
+### Important notes
+
+#### 1.0.0
+
+In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`. No more v1 versions will be released.
+
+If the vanity URL is causing issues in your project due to a dependency pulling Mergo - it isn't a direct dependency in your project - it is recommended to use [replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to pin the version to the last one with the old import URL:
+
+```
+replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
+```
+
+#### 0.3.9
+
+Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds support for go modules.
+
+Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u dario.cat/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
+
+### Donations
+
+If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
+
+
+
+
+### Mergo in the wild
+
+Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/dependents) [of](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.16/dependents) [projects](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.12), including:
+
+* [containerd/containerd](https://github.com/containerd/containerd)
+* [datadog/datadog-agent](https://github.com/datadog/datadog-agent)
+* [docker/cli/](https://github.com/docker/cli/)
+* [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
+* [go-micro/go-micro](https://github.com/go-micro/go-micro)
+* [grafana/loki](https://github.com/grafana/loki)
+* [masterminds/sprig](github.com/Masterminds/sprig)
+* [moby/moby](https://github.com/moby/moby)
+* [slackhq/nebula](https://github.com/slackhq/nebula)
+* [volcano-sh/volcano](https://github.com/volcano-sh/volcano)
+
+## Install
+
+ go get dario.cat/mergo
+
+ // use in your .go code
+ import (
+ "dario.cat/mergo"
+ )
+
+## Usage
+
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are zero values](https://golang.org/ref/spec#The_zero_value) too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+```go
+if err := mergo.Merge(&dst, src); err != nil {
+ // ...
+}
+```
+
+Also, you can merge overwriting values using the transformer `WithOverride`.
+
+```go
+if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+ // ...
+}
+```
+
+If you need to override pointers, so the source pointer's value is assigned to the destination's pointer, you must use `WithoutDereference`:
+
+```go
+package main
+
+import (
+ "fmt"
+
+ "dario.cat/mergo"
+)
+
+type Foo struct {
+ A *string
+ B int64
+}
+
+func main() {
+ first := "first"
+ second := "second"
+ src := Foo{
+ A: &first,
+ B: 2,
+ }
+
+ dest := Foo{
+ A: &second,
+ B: 1,
+ }
+
+ mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference)
+}
+```
+
+Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
+
+```go
+if err := mergo.Map(&dst, srcMap); err != nil {
+ // ...
+}
+```
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
+
+Here is a nice example:
+
+```go
+package main
+
+import (
+ "fmt"
+ "dario.cat/mergo"
+)
+
+type Foo struct {
+ A string
+ B int64
+}
+
+func main() {
+ src := Foo{
+ A: "one",
+ B: 2,
+ }
+ dest := Foo{
+ A: "two",
+ }
+ mergo.Merge(&dest, src)
+ fmt.Println(dest)
+ // Will print
+ // {two 2}
+}
+```
+
+### Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`?
+
+```go
+package main
+
+import (
+ "fmt"
+ "dario.cat/mergo"
+ "reflect"
+ "time"
+)
+
+type timeTransformer struct {
+}
+
+func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+ if typ == reflect.TypeOf(time.Time{}) {
+ return func(dst, src reflect.Value) error {
+ if dst.CanSet() {
+ isZero := dst.MethodByName("IsZero")
+ result := isZero.Call([]reflect.Value{})
+ if result[0].Bool() {
+ dst.Set(src)
+ }
+ }
+ return nil
+ }
+ }
+ return nil
+}
+
+type Snapshot struct {
+ Time time.Time
+ // ...
+}
+
+func main() {
+ src := Snapshot{time.Now()}
+ dest := Snapshot{}
+ mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
+ fmt.Println(dest)
+ // Will print
+ // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+}
+```
+
+## Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
+
+## About
+
+Written by [Dario Castañé](http://dario.im).
+
+## License
+
+[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
+
+[](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
diff --git a/vendor/dario.cat/mergo/SECURITY.md b/vendor/dario.cat/mergo/SECURITY.md
new file mode 100644
index 0000000000..3788fcc1c2
--- /dev/null
+++ b/vendor/dario.cat/mergo/SECURITY.md
@@ -0,0 +1,14 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | ------------------ |
+| 1.x.x | :white_check_mark: |
+| < 1.0 | :x: |
+
+## Security contact information
+
+To report a security vulnerability, please use the
+[Tidelift security contact](https://tidelift.com/security).
+Tidelift will coordinate the fix and disclosure.
diff --git a/vendor/dario.cat/mergo/doc.go b/vendor/dario.cat/mergo/doc.go
new file mode 100644
index 0000000000..7d96ec0546
--- /dev/null
+++ b/vendor/dario.cat/mergo/doc.go
@@ -0,0 +1,148 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
+
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+# Status
+
+It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc.
+
+# Important notes
+
+1.0.0
+
+In 1.0.0 Mergo moves to a vanity URL `dario.cat/mergo`.
+
+0.3.9
+
+Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules.
+
+Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u dario.cat/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
+
+# Install
+
+Do your usual installation procedure:
+
+ go get dario.cat/mergo
+
+ // use in your .go code
+ import (
+ "dario.cat/mergo"
+ )
+
+# Usage
+
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+ if err := mergo.Merge(&dst, src); err != nil {
+ // ...
+ }
+
+Also, you can merge overwriting values using the transformer WithOverride.
+
+ if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+ // ...
+ }
+
+Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
+
+ if err := mergo.Map(&dst, srcMap); err != nil {
+ // ...
+ }
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values.
+
+Here is a nice example:
+
+ package main
+
+ import (
+ "fmt"
+ "dario.cat/mergo"
+ )
+
+ type Foo struct {
+ A string
+ B int64
+ }
+
+ func main() {
+ src := Foo{
+ A: "one",
+ B: 2,
+ }
+ dest := Foo{
+ A: "two",
+ }
+ mergo.Merge(&dest, src)
+ fmt.Println(dest)
+ // Will print
+ // {two 2}
+ }
+
+# Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time?
+
+ package main
+
+ import (
+ "fmt"
+ "dario.cat/mergo"
+ "reflect"
+ "time"
+ )
+
+ type timeTransformer struct {
+ }
+
+ func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+ if typ == reflect.TypeOf(time.Time{}) {
+ return func(dst, src reflect.Value) error {
+ if dst.CanSet() {
+ isZero := dst.MethodByName("IsZero")
+ result := isZero.Call([]reflect.Value{})
+ if result[0].Bool() {
+ dst.Set(src)
+ }
+ }
+ return nil
+ }
+ }
+ return nil
+ }
+
+ type Snapshot struct {
+ Time time.Time
+ // ...
+ }
+
+ func main() {
+ src := Snapshot{time.Now()}
+ dest := Snapshot{}
+ mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
+ fmt.Println(dest)
+ // Will print
+ // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+ }
+
+# Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario
+
+# About
+
+Written by Dario Castañé: https://da.rio.hn
+
+# License
+
+BSD 3-Clause license, as Go language.
+*/
+package mergo
diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/dario.cat/mergo/map.go
similarity index 95%
rename from vendor/github.com/imdario/mergo/map.go
rename to vendor/dario.cat/mergo/map.go
index a13a7ee46c..759b4f74fd 100644
--- a/vendor/github.com/imdario/mergo/map.go
+++ b/vendor/dario.cat/mergo/map.go
@@ -44,7 +44,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf
}
}
// Remember, remember...
- visited[h] = &visit{addr, typ, seen}
+ visited[h] = &visit{typ, seen, addr}
}
zeroValue := reflect.Value{}
switch dst.Kind() {
@@ -58,7 +58,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf
}
fieldName := field.Name
fieldName = changeInitialCase(fieldName, unicode.ToLower)
- if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
+ if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue {
dstMap[fieldName] = src.Field(i).Interface()
}
}
@@ -142,7 +142,7 @@ func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
func _map(dst, src interface{}, opts ...func(*Config)) error {
if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
- return ErrNonPointerAgument
+ return ErrNonPointerArgument
}
var (
vDst, vSrc reflect.Value
diff --git a/vendor/dario.cat/mergo/merge.go b/vendor/dario.cat/mergo/merge.go
new file mode 100644
index 0000000000..fd47c95b2b
--- /dev/null
+++ b/vendor/dario.cat/mergo/merge.go
@@ -0,0 +1,409 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func hasMergeableFields(dst reflect.Value) (exported bool) {
+ for i, n := 0, dst.NumField(); i < n; i++ {
+ field := dst.Type().Field(i)
+ if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
+ exported = exported || hasMergeableFields(dst.Field(i))
+ } else if isExportedComponent(&field) {
+ exported = exported || len(field.PkgPath) == 0
+ }
+ }
+ return
+}
+
+func isExportedComponent(field *reflect.StructField) bool {
+ pkgPath := field.PkgPath
+ if len(pkgPath) > 0 {
+ return false
+ }
+ c := field.Name[0]
+ if 'a' <= c && c <= 'z' || c == '_' {
+ return false
+ }
+ return true
+}
+
+type Config struct {
+ Transformers Transformers
+ Overwrite bool
+ ShouldNotDereference bool
+ AppendSlice bool
+ TypeCheck bool
+ overwriteWithEmptyValue bool
+ overwriteSliceWithEmptyValue bool
+ sliceDeepCopy bool
+ debug bool
+}
+
+type Transformers interface {
+ Transformer(reflect.Type) func(dst, src reflect.Value) error
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
+ overwrite := config.Overwrite
+ typeCheck := config.TypeCheck
+ overwriteWithEmptySrc := config.overwriteWithEmptyValue
+ overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
+ sliceDeepCopy := config.sliceDeepCopy
+
+ if !src.IsValid() {
+ return
+ }
+ if dst.CanAddr() {
+ addr := dst.UnsafeAddr()
+ h := 17 * addr
+ seen := visited[h]
+ typ := dst.Type()
+ for p := seen; p != nil; p = p.next {
+ if p.ptr == addr && p.typ == typ {
+ return nil
+ }
+ }
+ // Remember, remember...
+ visited[h] = &visit{typ, seen, addr}
+ }
+
+ if config.Transformers != nil && !isReflectNil(dst) && dst.IsValid() {
+ if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
+ err = fn(dst, src)
+ return
+ }
+ }
+
+ switch dst.Kind() {
+ case reflect.Struct:
+ if hasMergeableFields(dst) {
+ for i, n := 0, dst.NumField(); i < n; i++ {
+ if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
+ return
+ }
+ }
+ } else {
+ if dst.CanSet() && (isReflectNil(dst) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc) {
+ dst.Set(src)
+ }
+ }
+ case reflect.Map:
+ if dst.IsNil() && !src.IsNil() {
+ if dst.CanSet() {
+ dst.Set(reflect.MakeMap(dst.Type()))
+ } else {
+ dst = src
+ return
+ }
+ }
+
+ if src.Kind() != reflect.Map {
+ if overwrite && dst.CanSet() {
+ dst.Set(src)
+ }
+ return
+ }
+
+ for _, key := range src.MapKeys() {
+ srcElement := src.MapIndex(key)
+ if !srcElement.IsValid() {
+ continue
+ }
+ dstElement := dst.MapIndex(key)
+ switch srcElement.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
+ if srcElement.IsNil() {
+ if overwrite {
+ dst.SetMapIndex(key, srcElement)
+ }
+ continue
+ }
+ fallthrough
+ default:
+ if !srcElement.CanInterface() {
+ continue
+ }
+ switch reflect.TypeOf(srcElement.Interface()).Kind() {
+ case reflect.Struct:
+ fallthrough
+ case reflect.Ptr:
+ fallthrough
+ case reflect.Map:
+ srcMapElm := srcElement
+ dstMapElm := dstElement
+ if srcMapElm.CanInterface() {
+ srcMapElm = reflect.ValueOf(srcMapElm.Interface())
+ if dstMapElm.IsValid() {
+ dstMapElm = reflect.ValueOf(dstMapElm.Interface())
+ }
+ }
+ if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
+ return
+ }
+ case reflect.Slice:
+ srcSlice := reflect.ValueOf(srcElement.Interface())
+
+ var dstSlice reflect.Value
+ if !dstElement.IsValid() || dstElement.IsNil() {
+ dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
+ } else {
+ dstSlice = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
+ if typeCheck && srcSlice.Type() != dstSlice.Type() {
+ return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+ }
+ dstSlice = srcSlice
+ } else if config.AppendSlice {
+ if srcSlice.Type() != dstSlice.Type() {
+ return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+ }
+ dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
+ } else if sliceDeepCopy {
+ i := 0
+ for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ {
+ srcElement := srcSlice.Index(i)
+ dstElement := dstSlice.Index(i)
+
+ if srcElement.CanInterface() {
+ srcElement = reflect.ValueOf(srcElement.Interface())
+ }
+ if dstElement.CanInterface() {
+ dstElement = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ }
+
+ }
+ dst.SetMapIndex(key, dstSlice)
+ }
+ }
+
+ if dstElement.IsValid() && !isEmptyValue(dstElement, !config.ShouldNotDereference) {
+ if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice {
+ continue
+ }
+ if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map && reflect.TypeOf(dstElement.Interface()).Kind() == reflect.Map {
+ continue
+ }
+ }
+
+ if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement, !config.ShouldNotDereference)) {
+ if dst.IsNil() {
+ dst.Set(reflect.MakeMap(dst.Type()))
+ }
+ dst.SetMapIndex(key, srcElement)
+ }
+ }
+
+ // Ensure that all keys in dst are deleted if they are not in src.
+ if overwriteWithEmptySrc {
+ for _, key := range dst.MapKeys() {
+ srcElement := src.MapIndex(key)
+ if !srcElement.IsValid() {
+ dst.SetMapIndex(key, reflect.Value{})
+ }
+ }
+ }
+ case reflect.Slice:
+ if !dst.CanSet() {
+ break
+ }
+ if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
+ dst.Set(src)
+ } else if config.AppendSlice {
+ if src.Type() != dst.Type() {
+ return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
+ }
+ dst.Set(reflect.AppendSlice(dst, src))
+ } else if sliceDeepCopy {
+ for i := 0; i < src.Len() && i < dst.Len(); i++ {
+ srcElement := src.Index(i)
+ dstElement := dst.Index(i)
+ if srcElement.CanInterface() {
+ srcElement = reflect.ValueOf(srcElement.Interface())
+ }
+ if dstElement.CanInterface() {
+ dstElement = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ }
+ }
+ case reflect.Ptr:
+ fallthrough
+ case reflect.Interface:
+ if isReflectNil(src) {
+ if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) {
+ dst.Set(src)
+ }
+ break
+ }
+
+ if src.Kind() != reflect.Interface {
+ if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
+ if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
+ dst.Set(src)
+ }
+ } else if src.Kind() == reflect.Ptr {
+ if !config.ShouldNotDereference {
+ if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+ return
+ }
+ } else if src.Elem().Kind() != reflect.Struct {
+ if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
+ dst.Set(src)
+ }
+ }
+ } else if dst.Elem().Type() == src.Type() {
+ if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
+ return
+ }
+ } else {
+ return ErrDifferentArgumentsTypes
+ }
+ break
+ }
+
+ if dst.IsNil() || overwrite {
+ if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
+ dst.Set(src)
+ }
+ break
+ }
+
+ if dst.Elem().Kind() == src.Elem().Kind() {
+ if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+ return
+ }
+ break
+ }
+ default:
+ mustSet := (isEmptyValue(dst, !config.ShouldNotDereference) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc)
+ if mustSet {
+ if dst.CanSet() {
+ dst.Set(src)
+ } else {
+ dst = src
+ }
+ }
+ }
+
+ return
+}
+
+// Merge will fill any empty for value type attributes on the dst struct using corresponding
+// src attributes if they themselves are not empty. dst and src must be valid same-type structs
+// and dst must be a pointer to struct.
+// It won't merge unexported (private) fields and will do recursively any exported field.
+func Merge(dst, src interface{}, opts ...func(*Config)) error {
+ return merge(dst, src, opts...)
+}
+
+// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
+// non-empty src attribute values.
+// Deprecated: use Merge(…) with WithOverride
+func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
+ return merge(dst, src, append(opts, WithOverride)...)
+}
+
+// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
+func WithTransformers(transformers Transformers) func(*Config) {
+ return func(config *Config) {
+ config.Transformers = transformers
+ }
+}
+
+// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
+func WithOverride(config *Config) {
+ config.Overwrite = true
+}
+
+// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
+func WithOverwriteWithEmptyValue(config *Config) {
+ config.Overwrite = true
+ config.overwriteWithEmptyValue = true
+}
+
+// WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
+func WithOverrideEmptySlice(config *Config) {
+ config.overwriteSliceWithEmptyValue = true
+}
+
+// WithoutDereference prevents dereferencing pointers when evaluating whether they are empty
+// (i.e. a non-nil pointer is never considered empty).
+func WithoutDereference(config *Config) {
+ config.ShouldNotDereference = true
+}
+
+// WithAppendSlice will make merge append slices instead of overwriting it.
+func WithAppendSlice(config *Config) {
+ config.AppendSlice = true
+}
+
+// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
+func WithTypeCheck(config *Config) {
+ config.TypeCheck = true
+}
+
+// WithSliceDeepCopy will merge slice element one by one with Overwrite flag.
+func WithSliceDeepCopy(config *Config) {
+ config.sliceDeepCopy = true
+ config.Overwrite = true
+}
+
+func merge(dst, src interface{}, opts ...func(*Config)) error {
+ if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
+ return ErrNonPointerArgument
+ }
+ var (
+ vDst, vSrc reflect.Value
+ err error
+ )
+
+ config := &Config{}
+
+ for _, opt := range opts {
+ opt(config)
+ }
+
+ if vDst, vSrc, err = resolveValues(dst, src); err != nil {
+ return err
+ }
+ if vDst.Type() != vSrc.Type() {
+ return ErrDifferentArgumentsTypes
+ }
+ return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+}
+
+// IsReflectNil is the reflect value provided nil
+func isReflectNil(v reflect.Value) bool {
+ k := v.Kind()
+ switch k {
+ case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
+ // Both interface and slice are nil if first word is 0.
+ // Both are always bigger than a word; assume flagIndir.
+ return v.IsNil()
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/dario.cat/mergo/mergo.go
similarity index 85%
rename from vendor/github.com/imdario/mergo/mergo.go
rename to vendor/dario.cat/mergo/mergo.go
index 3cc926c7f6..0a721e2d85 100644
--- a/vendor/github.com/imdario/mergo/mergo.go
+++ b/vendor/dario.cat/mergo/mergo.go
@@ -17,10 +17,10 @@ import (
var (
ErrNilArguments = errors.New("src and dst must not be nil")
ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
- ErrNotSupported = errors.New("only structs and maps are supported")
+ ErrNotSupported = errors.New("only structs, maps, and slices are supported")
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
- ErrNonPointerAgument = errors.New("dst must be a pointer")
+ ErrNonPointerArgument = errors.New("dst must be a pointer")
)
// During deepMerge, must keep track of checks that are
@@ -28,13 +28,13 @@ var (
// checks in progress are true when it reencounters them.
// Visited are stored in a map indexed by 17 * a1 + a2;
type visit struct {
- ptr uintptr
typ reflect.Type
next *visit
+ ptr uintptr
}
// From src/pkg/encoding/json/encode.go.
-func isEmptyValue(v reflect.Value) bool {
+func isEmptyValue(v reflect.Value, shouldDereference bool) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
@@ -50,7 +50,10 @@ func isEmptyValue(v reflect.Value) bool {
if v.IsNil() {
return true
}
- return isEmptyValue(v.Elem())
+ if shouldDereference {
+ return isEmptyValue(v.Elem(), shouldDereference)
+ }
+ return false
case reflect.Func:
return v.IsNil()
case reflect.Invalid:
@@ -65,7 +68,7 @@ func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
return
}
vDst = reflect.ValueOf(dst).Elem()
- if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
+ if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map && vDst.Kind() != reflect.Slice {
err = ErrNotSupported
return
}
diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
index 593b10ab69..194d5e9c94 100644
--- a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
+++ b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
@@ -11,21 +11,13 @@ func (oscState oscStringState) Handle(b byte) (s state, e error) {
return nextState, err
}
- switch {
- case isOscStringTerminator(b):
+ // There are several control characters and sequences which can
+ // terminate an OSC string. Most of them are handled by the baseState
+ // handler. The ANSI_BEL character is a special case which behaves as a
+ // terminator only for an OSC string.
+ if b == ANSI_BEL {
return oscState.parser.ground, nil
}
return oscState, nil
}
-
-// See below for OSC string terminators for linux
-// http://man7.org/linux/man-pages/man4/console_codes.4.html
-func isOscStringTerminator(b byte) bool {
-
- if b == ANSI_BEL || b == 0x5C {
- return true
- }
-
- return false
-}
diff --git a/vendor/github.com/ProtonMail/go-crypto/AUTHORS b/vendor/github.com/ProtonMail/go-crypto/AUTHORS
new file mode 100644
index 0000000000..2b00ddba0d
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at https://tip.golang.org/AUTHORS.
diff --git a/vendor/github.com/ProtonMail/go-crypto/CONTRIBUTORS b/vendor/github.com/ProtonMail/go-crypto/CONTRIBUTORS
new file mode 100644
index 0000000000..1fbd3e976f
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at https://tip.golang.org/CONTRIBUTORS.
diff --git a/vendor/github.com/ProtonMail/go-crypto/LICENSE b/vendor/github.com/ProtonMail/go-crypto/LICENSE
new file mode 100644
index 0000000000..6a66aea5ea
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/ProtonMail/go-crypto/PATENTS b/vendor/github.com/ProtonMail/go-crypto/PATENTS
new file mode 100644
index 0000000000..733099041f
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/github.com/ProtonMail/go-crypto/bitcurves/bitcurve.go b/vendor/github.com/ProtonMail/go-crypto/bitcurves/bitcurve.go
new file mode 100644
index 0000000000..c85e6befec
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/bitcurves/bitcurve.go
@@ -0,0 +1,381 @@
+package bitcurves
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2011 ThePiachu. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bitelliptic implements several Koblitz elliptic curves over prime
+// fields.
+
+// This package operates, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
+// calculation can be performed within the transform (as in ScalarMult and
+// ScalarBaseMult). But even for Add and Double, it's faster to apply and
+// reverse the transform than to operate in affine coordinates.
+
+import (
+ "crypto/elliptic"
+ "io"
+ "math/big"
+ "sync"
+)
+
+// A BitCurve represents a Koblitz Curve with a=0.
+// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+type BitCurve struct {
+ Name string
+ P *big.Int // the order of the underlying field
+ N *big.Int // the order of the base point
+ B *big.Int // the constant of the BitCurve equation
+ Gx, Gy *big.Int // (x,y) of the base point
+ BitSize int // the size of the underlying field
+}
+
+// Params returns the parameters of the given BitCurve (see BitCurve struct)
+func (bitCurve *BitCurve) Params() (cp *elliptic.CurveParams) {
+ cp = new(elliptic.CurveParams)
+ cp.Name = bitCurve.Name
+ cp.P = bitCurve.P
+ cp.N = bitCurve.N
+ cp.Gx = bitCurve.Gx
+ cp.Gy = bitCurve.Gy
+ cp.BitSize = bitCurve.BitSize
+ return cp
+}
+
+// IsOnCurve returns true if the given (x,y) lies on the BitCurve.
+func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool {
+ // y² = x³ + b
+ y2 := new(big.Int).Mul(y, y) //y²
+ y2.Mod(y2, bitCurve.P) //y²%P
+
+ x3 := new(big.Int).Mul(x, x) //x²
+ x3.Mul(x3, x) //x³
+
+ x3.Add(x3, bitCurve.B) //x³+B
+ x3.Mod(x3, bitCurve.P) //(x³+B)%P
+
+ return x3.Cmp(y2) == 0
+}
+
+// affineFromJacobian reverses the Jacobian transform. See the comment at the
+// top of the file.
+func (bitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
+ if z.Cmp(big.NewInt(0)) == 0 {
+ panic("bitcurve: Can't convert to affine with Jacobian Z = 0")
+ }
+ // x = YZ^2 mod P
+ zinv := new(big.Int).ModInverse(z, bitCurve.P)
+ zinvsq := new(big.Int).Mul(zinv, zinv)
+
+ xOut = new(big.Int).Mul(x, zinvsq)
+ xOut.Mod(xOut, bitCurve.P)
+ // y = YZ^3 mod P
+ zinvsq.Mul(zinvsq, zinv)
+ yOut = new(big.Int).Mul(y, zinvsq)
+ yOut.Mod(yOut, bitCurve.P)
+ return xOut, yOut
+}
+
+// Add returns the sum of (x1,y1) and (x2,y2)
+func (bitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ z := new(big.Int).SetInt64(1)
+ x, y, z := bitCurve.addJacobian(x1, y1, z, x2, y2, z)
+ return bitCurve.affineFromJacobian(x, y, z)
+}
+
+// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
+// (x2, y2, z2) and returns their sum, also in Jacobian form.
+func (bitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ z1z1 := new(big.Int).Mul(z1, z1)
+ z1z1.Mod(z1z1, bitCurve.P)
+ z2z2 := new(big.Int).Mul(z2, z2)
+ z2z2.Mod(z2z2, bitCurve.P)
+
+ u1 := new(big.Int).Mul(x1, z2z2)
+ u1.Mod(u1, bitCurve.P)
+ u2 := new(big.Int).Mul(x2, z1z1)
+ u2.Mod(u2, bitCurve.P)
+ h := new(big.Int).Sub(u2, u1)
+ if h.Sign() == -1 {
+ h.Add(h, bitCurve.P)
+ }
+ i := new(big.Int).Lsh(h, 1)
+ i.Mul(i, i)
+ j := new(big.Int).Mul(h, i)
+
+ s1 := new(big.Int).Mul(y1, z2)
+ s1.Mul(s1, z2z2)
+ s1.Mod(s1, bitCurve.P)
+ s2 := new(big.Int).Mul(y2, z1)
+ s2.Mul(s2, z1z1)
+ s2.Mod(s2, bitCurve.P)
+ r := new(big.Int).Sub(s2, s1)
+ if r.Sign() == -1 {
+ r.Add(r, bitCurve.P)
+ }
+ r.Lsh(r, 1)
+ v := new(big.Int).Mul(u1, i)
+
+ x3 := new(big.Int).Set(r)
+ x3.Mul(x3, x3)
+ x3.Sub(x3, j)
+ x3.Sub(x3, v)
+ x3.Sub(x3, v)
+ x3.Mod(x3, bitCurve.P)
+
+ y3 := new(big.Int).Set(r)
+ v.Sub(v, x3)
+ y3.Mul(y3, v)
+ s1.Mul(s1, j)
+ s1.Lsh(s1, 1)
+ y3.Sub(y3, s1)
+ y3.Mod(y3, bitCurve.P)
+
+ z3 := new(big.Int).Add(z1, z2)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, z1z1)
+ if z3.Sign() == -1 {
+ z3.Add(z3, bitCurve.P)
+ }
+ z3.Sub(z3, z2z2)
+ if z3.Sign() == -1 {
+ z3.Add(z3, bitCurve.P)
+ }
+ z3.Mul(z3, h)
+ z3.Mod(z3, bitCurve.P)
+
+ return x3, y3, z3
+}
+
+// Double returns 2*(x,y)
+func (bitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ z1 := new(big.Int).SetInt64(1)
+ return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z1))
+}
+
+// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
+// returns its double, also in Jacobian form.
+func (bitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+
+ a := new(big.Int).Mul(x, x) //X1²
+ b := new(big.Int).Mul(y, y) //Y1²
+ c := new(big.Int).Mul(b, b) //B²
+
+ d := new(big.Int).Add(x, b) //X1+B
+ d.Mul(d, d) //(X1+B)²
+ d.Sub(d, a) //(X1+B)²-A
+ d.Sub(d, c) //(X1+B)²-A-C
+ d.Mul(d, big.NewInt(2)) //2*((X1+B)²-A-C)
+
+ e := new(big.Int).Mul(big.NewInt(3), a) //3*A
+ f := new(big.Int).Mul(e, e) //E²
+
+ x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D
+ x3.Sub(f, x3) //F-2*D
+ x3.Mod(x3, bitCurve.P)
+
+ y3 := new(big.Int).Sub(d, x3) //D-X3
+ y3.Mul(e, y3) //E*(D-X3)
+ y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C
+ y3.Mod(y3, bitCurve.P)
+
+ z3 := new(big.Int).Mul(y, z) //Y1*Z1
+ z3.Mul(big.NewInt(2), z3) //3*Y1*Z1
+ z3.Mod(z3, bitCurve.P)
+
+ return x3, y3, z3
+}
+
+// TODO: double check if it is okay
+// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
+func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+ // We have a slight problem in that the identity of the group (the
+ // point at infinity) cannot be represented in (x, y) form on a finite
+ // machine. Thus the standard add/double algorithm has to be tweaked
+ // slightly: our initial state is not the identity, but x, and we
+ // ignore the first true bit in |k|. If we don't find any true bits in
+ // |k|, then we return nil, nil, because we cannot return the identity
+ // element.
+
+ Bz := new(big.Int).SetInt64(1)
+ x := Bx
+ y := By
+ z := Bz
+
+ seenFirstTrue := false
+ for _, byte := range k {
+ for bitNum := 0; bitNum < 8; bitNum++ {
+ if seenFirstTrue {
+ x, y, z = bitCurve.doubleJacobian(x, y, z)
+ }
+ if byte&0x80 == 0x80 {
+ if !seenFirstTrue {
+ seenFirstTrue = true
+ } else {
+ x, y, z = bitCurve.addJacobian(Bx, By, Bz, x, y, z)
+ }
+ }
+ byte <<= 1
+ }
+ }
+
+ if !seenFirstTrue {
+ return nil, nil
+ }
+
+ return bitCurve.affineFromJacobian(x, y, z)
+}
+
+// ScalarBaseMult returns k*G, where G is the base point of the group and k is
+// an integer in big-endian form.
+func (bitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ return bitCurve.ScalarMult(bitCurve.Gx, bitCurve.Gy, k)
+}
+
+var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
+
+// TODO: double check if it is okay
+// GenerateKey returns a public/private key pair. The private key is generated
+// using the given reader, which must return random data.
+func (bitCurve *BitCurve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err error) {
+ byteLen := (bitCurve.BitSize + 7) >> 3
+ priv = make([]byte, byteLen)
+
+ for x == nil {
+ _, err = io.ReadFull(rand, priv)
+ if err != nil {
+ return
+ }
+ // We have to mask off any excess bits in the case that the size of the
+ // underlying field is not a whole number of bytes.
+ priv[0] &= mask[bitCurve.BitSize%8]
+ // This is because, in tests, rand will return all zeros and we don't
+ // want to get the point at infinity and loop forever.
+ priv[1] ^= 0x42
+ x, y = bitCurve.ScalarBaseMult(priv)
+ }
+ return
+}
+
+// Marshal converts a point into the form specified in section 4.3.6 of ANSI
+// X9.62.
+func (bitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
+ byteLen := (bitCurve.BitSize + 7) >> 3
+
+ ret := make([]byte, 1+2*byteLen)
+ ret[0] = 4 // uncompressed point
+
+ xBytes := x.Bytes()
+ copy(ret[1+byteLen-len(xBytes):], xBytes)
+ yBytes := y.Bytes()
+ copy(ret[1+2*byteLen-len(yBytes):], yBytes)
+ return ret
+}
+
+// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
+// error, x = nil.
+func (bitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
+ byteLen := (bitCurve.BitSize + 7) >> 3
+ if len(data) != 1+2*byteLen {
+ return
+ }
+ if data[0] != 4 { // uncompressed form
+ return
+ }
+ x = new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(data[1+byteLen:])
+ return
+}
+
+//curve parameters taken from:
+//http://www.secg.org/collateral/sec2_final.pdf
+
+var initonce sync.Once
+var secp160k1 *BitCurve
+var secp192k1 *BitCurve
+var secp224k1 *BitCurve
+var secp256k1 *BitCurve
+
+func initAll() {
+ initS160()
+ initS192()
+ initS224()
+ initS256()
+}
+
+func initS160() {
+ // See SEC 2 section 2.4.1
+ secp160k1 = new(BitCurve)
+ secp160k1.Name = "secp160k1"
+ secp160k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", 16)
+ secp160k1.N, _ = new(big.Int).SetString("0100000000000000000001B8FA16DFAB9ACA16B6B3", 16)
+ secp160k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000007", 16)
+ secp160k1.Gx, _ = new(big.Int).SetString("3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", 16)
+ secp160k1.Gy, _ = new(big.Int).SetString("938CF935318FDCED6BC28286531733C3F03C4FEE", 16)
+ secp160k1.BitSize = 160
+}
+
+func initS192() {
+ // See SEC 2 section 2.5.1
+ secp192k1 = new(BitCurve)
+ secp192k1.Name = "secp192k1"
+ secp192k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", 16)
+ secp192k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 16)
+ secp192k1.B, _ = new(big.Int).SetString("000000000000000000000000000000000000000000000003", 16)
+ secp192k1.Gx, _ = new(big.Int).SetString("DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", 16)
+ secp192k1.Gy, _ = new(big.Int).SetString("9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", 16)
+ secp192k1.BitSize = 192
+}
+
+func initS224() {
+ // See SEC 2 section 2.6.1
+ secp224k1 = new(BitCurve)
+ secp224k1.Name = "secp224k1"
+ secp224k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", 16)
+ secp224k1.N, _ = new(big.Int).SetString("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 16)
+ secp224k1.B, _ = new(big.Int).SetString("00000000000000000000000000000000000000000000000000000005", 16)
+ secp224k1.Gx, _ = new(big.Int).SetString("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16)
+ secp224k1.Gy, _ = new(big.Int).SetString("7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16)
+ secp224k1.BitSize = 224
+}
+
+func initS256() {
+ // See SEC 2 section 2.7.1
+ secp256k1 = new(BitCurve)
+ secp256k1.Name = "secp256k1"
+ secp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
+ secp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
+ secp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
+ secp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
+ secp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
+ secp256k1.BitSize = 256
+}
+
+// S160 returns a BitCurve which implements secp160k1 (see SEC 2 section 2.4.1)
+func S160() *BitCurve {
+ initonce.Do(initAll)
+ return secp160k1
+}
+
+// S192 returns a BitCurve which implements secp192k1 (see SEC 2 section 2.5.1)
+func S192() *BitCurve {
+ initonce.Do(initAll)
+ return secp192k1
+}
+
+// S224 returns a BitCurve which implements secp224k1 (see SEC 2 section 2.6.1)
+func S224() *BitCurve {
+ initonce.Do(initAll)
+ return secp224k1
+}
+
+// S256 returns a BitCurve which implements bitcurves (see SEC 2 section 2.7.1)
+func S256() *BitCurve {
+ initonce.Do(initAll)
+ return secp256k1
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/brainpool/brainpool.go b/vendor/github.com/ProtonMail/go-crypto/brainpool/brainpool.go
new file mode 100644
index 0000000000..cb6676de24
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/brainpool/brainpool.go
@@ -0,0 +1,134 @@
+// Package brainpool implements Brainpool elliptic curves.
+// Implementation of rcurves is from github.com/ebfe/brainpool
+// Note that these curves are implemented with naive, non-constant time operations
+// and are likely not suitable for environments where timing attacks are a concern.
+package brainpool
+
+import (
+ "crypto/elliptic"
+ "math/big"
+ "sync"
+)
+
+var (
+ once sync.Once
+ p256t1, p384t1, p512t1 *elliptic.CurveParams
+ p256r1, p384r1, p512r1 *rcurve
+)
+
+func initAll() {
+ initP256t1()
+ initP384t1()
+ initP512t1()
+ initP256r1()
+ initP384r1()
+ initP512r1()
+}
+
+func initP256t1() {
+ p256t1 = &elliptic.CurveParams{Name: "brainpoolP256t1"}
+ p256t1.P, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16)
+ p256t1.N, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16)
+ p256t1.B, _ = new(big.Int).SetString("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16)
+ p256t1.Gx, _ = new(big.Int).SetString("A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4", 16)
+ p256t1.Gy, _ = new(big.Int).SetString("2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE", 16)
+ p256t1.BitSize = 256
+}
+
+func initP256r1() {
+ twisted := p256t1
+ params := &elliptic.CurveParams{
+ Name: "brainpoolP256r1",
+ P: twisted.P,
+ N: twisted.N,
+ BitSize: twisted.BitSize,
+ }
+ params.Gx, _ = new(big.Int).SetString("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16)
+ params.Gy, _ = new(big.Int).SetString("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16)
+ z, _ := new(big.Int).SetString("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0", 16)
+ p256r1 = newrcurve(twisted, params, z)
+}
+
+func initP384t1() {
+ p384t1 = &elliptic.CurveParams{Name: "brainpoolP384t1"}
+ p384t1.P, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16)
+ p384t1.N, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16)
+ p384t1.B, _ = new(big.Int).SetString("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16)
+ p384t1.Gx, _ = new(big.Int).SetString("18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC", 16)
+ p384t1.Gy, _ = new(big.Int).SetString("25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928", 16)
+ p384t1.BitSize = 384
+}
+
+func initP384r1() {
+ twisted := p384t1
+ params := &elliptic.CurveParams{
+ Name: "brainpoolP384r1",
+ P: twisted.P,
+ N: twisted.N,
+ BitSize: twisted.BitSize,
+ }
+ params.Gx, _ = new(big.Int).SetString("1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", 16)
+ params.Gy, _ = new(big.Int).SetString("8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", 16)
+ z, _ := new(big.Int).SetString("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C", 16)
+ p384r1 = newrcurve(twisted, params, z)
+}
+
+func initP512t1() {
+ p512t1 = &elliptic.CurveParams{Name: "brainpoolP512t1"}
+ p512t1.P, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16)
+ p512t1.N, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16)
+ p512t1.B, _ = new(big.Int).SetString("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16)
+ p512t1.Gx, _ = new(big.Int).SetString("640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA", 16)
+ p512t1.Gy, _ = new(big.Int).SetString("5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332", 16)
+ p512t1.BitSize = 512
+}
+
+func initP512r1() {
+ twisted := p512t1
+ params := &elliptic.CurveParams{
+ Name: "brainpoolP512r1",
+ P: twisted.P,
+ N: twisted.N,
+ BitSize: twisted.BitSize,
+ }
+ params.Gx, _ = new(big.Int).SetString("81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", 16)
+ params.Gy, _ = new(big.Int).SetString("7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", 16)
+ z, _ := new(big.Int).SetString("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB", 16)
+ p512r1 = newrcurve(twisted, params, z)
+}
+
+// P256t1 returns a Curve which implements Brainpool P256t1 (see RFC 5639, section 3.4)
+func P256t1() elliptic.Curve {
+ once.Do(initAll)
+ return p256t1
+}
+
+// P256r1 returns a Curve which implements Brainpool P256r1 (see RFC 5639, section 3.4)
+func P256r1() elliptic.Curve {
+ once.Do(initAll)
+ return p256r1
+}
+
+// P384t1 returns a Curve which implements Brainpool P384t1 (see RFC 5639, section 3.6)
+func P384t1() elliptic.Curve {
+ once.Do(initAll)
+ return p384t1
+}
+
+// P384r1 returns a Curve which implements Brainpool P384r1 (see RFC 5639, section 3.6)
+func P384r1() elliptic.Curve {
+ once.Do(initAll)
+ return p384r1
+}
+
+// P512t1 returns a Curve which implements Brainpool P512t1 (see RFC 5639, section 3.7)
+func P512t1() elliptic.Curve {
+ once.Do(initAll)
+ return p512t1
+}
+
+// P512r1 returns a Curve which implements Brainpool P512r1 (see RFC 5639, section 3.7)
+func P512r1() elliptic.Curve {
+ once.Do(initAll)
+ return p512r1
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/brainpool/rcurve.go b/vendor/github.com/ProtonMail/go-crypto/brainpool/rcurve.go
new file mode 100644
index 0000000000..7e291d6aa4
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/brainpool/rcurve.go
@@ -0,0 +1,83 @@
+package brainpool
+
+import (
+ "crypto/elliptic"
+ "math/big"
+)
+
+var _ elliptic.Curve = (*rcurve)(nil)
+
+type rcurve struct {
+ twisted elliptic.Curve
+ params *elliptic.CurveParams
+ z *big.Int
+ zinv *big.Int
+ z2 *big.Int
+ z3 *big.Int
+ zinv2 *big.Int
+ zinv3 *big.Int
+}
+
+var (
+ two = big.NewInt(2)
+ three = big.NewInt(3)
+)
+
+func newrcurve(twisted elliptic.Curve, params *elliptic.CurveParams, z *big.Int) *rcurve {
+ zinv := new(big.Int).ModInverse(z, params.P)
+ return &rcurve{
+ twisted: twisted,
+ params: params,
+ z: z,
+ zinv: zinv,
+ z2: new(big.Int).Exp(z, two, params.P),
+ z3: new(big.Int).Exp(z, three, params.P),
+ zinv2: new(big.Int).Exp(zinv, two, params.P),
+ zinv3: new(big.Int).Exp(zinv, three, params.P),
+ }
+}
+
+func (curve *rcurve) toTwisted(x, y *big.Int) (*big.Int, *big.Int) {
+ var tx, ty big.Int
+ tx.Mul(x, curve.z2)
+ tx.Mod(&tx, curve.params.P)
+ ty.Mul(y, curve.z3)
+ ty.Mod(&ty, curve.params.P)
+ return &tx, &ty
+}
+
+func (curve *rcurve) fromTwisted(tx, ty *big.Int) (*big.Int, *big.Int) {
+ var x, y big.Int
+ x.Mul(tx, curve.zinv2)
+ x.Mod(&x, curve.params.P)
+ y.Mul(ty, curve.zinv3)
+ y.Mod(&y, curve.params.P)
+ return &x, &y
+}
+
+func (curve *rcurve) Params() *elliptic.CurveParams {
+ return curve.params
+}
+
+func (curve *rcurve) IsOnCurve(x, y *big.Int) bool {
+ return curve.twisted.IsOnCurve(curve.toTwisted(x, y))
+}
+
+func (curve *rcurve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) {
+ tx1, ty1 := curve.toTwisted(x1, y1)
+ tx2, ty2 := curve.toTwisted(x2, y2)
+ return curve.fromTwisted(curve.twisted.Add(tx1, ty1, tx2, ty2))
+}
+
+func (curve *rcurve) Double(x1, y1 *big.Int) (x, y *big.Int) {
+ return curve.fromTwisted(curve.twisted.Double(curve.toTwisted(x1, y1)))
+}
+
+func (curve *rcurve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) {
+ tx1, ty1 := curve.toTwisted(x1, y1)
+ return curve.fromTwisted(curve.twisted.ScalarMult(tx1, ty1, scalar))
+}
+
+func (curve *rcurve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
+ return curve.fromTwisted(curve.twisted.ScalarBaseMult(scalar))
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/eax/eax.go b/vendor/github.com/ProtonMail/go-crypto/eax/eax.go
new file mode 100644
index 0000000000..3ae91d594c
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/eax/eax.go
@@ -0,0 +1,162 @@
+// Copyright (C) 2019 ProtonTech AG
+
+// Package eax provides an implementation of the EAX
+// (encrypt-authenticate-translate) mode of operation, as described in
+// Bellare, Rogaway, and Wagner "THE EAX MODE OF OPERATION: A TWO-PASS
+// AUTHENTICATED-ENCRYPTION SCHEME OPTIMIZED FOR SIMPLICITY AND EFFICIENCY."
+// In FSE'04, volume 3017 of LNCS, 2004
+package eax
+
+import (
+ "crypto/cipher"
+ "crypto/subtle"
+ "errors"
+ "github.com/ProtonMail/go-crypto/internal/byteutil"
+)
+
+const (
+ defaultTagSize = 16
+ defaultNonceSize = 16
+)
+
+type eax struct {
+ block cipher.Block // Only AES-{128, 192, 256} supported
+ tagSize int // At least 12 bytes recommended
+ nonceSize int
+}
+
+func (e *eax) NonceSize() int {
+ return e.nonceSize
+}
+
+func (e *eax) Overhead() int {
+ return e.tagSize
+}
+
+// NewEAX returns an EAX instance with AES-{KEYLENGTH} and default nonce and
+// tag lengths. Supports {128, 192, 256}- bit key length.
+func NewEAX(block cipher.Block) (cipher.AEAD, error) {
+ return NewEAXWithNonceAndTagSize(block, defaultNonceSize, defaultTagSize)
+}
+
+// NewEAXWithNonceAndTagSize returns an EAX instance with AES-{keyLength} and
+// given nonce and tag lengths in bytes. Panics on zero nonceSize and
+// exceedingly long tags.
+//
+// It is recommended to use at least 12 bytes as tag length (see, for instance,
+// NIST SP 800-38D).
+//
+// Only to be used for compatibility with existing cryptosystems with
+// non-standard parameters. For all other cases, prefer NewEAX.
+func NewEAXWithNonceAndTagSize(
+ block cipher.Block, nonceSize, tagSize int) (cipher.AEAD, error) {
+ if nonceSize < 1 {
+ return nil, eaxError("Cannot initialize EAX with nonceSize = 0")
+ }
+ if tagSize > block.BlockSize() {
+ return nil, eaxError("Custom tag length exceeds blocksize")
+ }
+ return &eax{
+ block: block,
+ tagSize: tagSize,
+ nonceSize: nonceSize,
+ }, nil
+}
+
+func (e *eax) Seal(dst, nonce, plaintext, adata []byte) []byte {
+ if len(nonce) > e.nonceSize {
+ panic("crypto/eax: Nonce too long for this instance")
+ }
+ ret, out := byteutil.SliceForAppend(dst, len(plaintext)+e.tagSize)
+ omacNonce := e.omacT(0, nonce)
+ omacAdata := e.omacT(1, adata)
+
+ // Encrypt message using CTR mode and omacNonce as IV
+ ctr := cipher.NewCTR(e.block, omacNonce)
+ ciphertextData := out[:len(plaintext)]
+ ctr.XORKeyStream(ciphertextData, plaintext)
+
+ omacCiphertext := e.omacT(2, ciphertextData)
+
+ tag := out[len(plaintext):]
+ for i := 0; i < e.tagSize; i++ {
+ tag[i] = omacCiphertext[i] ^ omacNonce[i] ^ omacAdata[i]
+ }
+ return ret
+}
+
+func (e *eax) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) {
+ if len(nonce) > e.nonceSize {
+ panic("crypto/eax: Nonce too long for this instance")
+ }
+ if len(ciphertext) < e.tagSize {
+ return nil, eaxError("Ciphertext shorter than tag length")
+ }
+ sep := len(ciphertext) - e.tagSize
+
+ // Compute tag
+ omacNonce := e.omacT(0, nonce)
+ omacAdata := e.omacT(1, adata)
+ omacCiphertext := e.omacT(2, ciphertext[:sep])
+
+ tag := make([]byte, e.tagSize)
+ for i := 0; i < e.tagSize; i++ {
+ tag[i] = omacCiphertext[i] ^ omacNonce[i] ^ omacAdata[i]
+ }
+
+ // Compare tags
+ if subtle.ConstantTimeCompare(ciphertext[sep:], tag) != 1 {
+ return nil, eaxError("Tag authentication failed")
+ }
+
+ // Decrypt ciphertext
+ ret, out := byteutil.SliceForAppend(dst, len(ciphertext))
+ ctr := cipher.NewCTR(e.block, omacNonce)
+ ctr.XORKeyStream(out, ciphertext[:sep])
+
+ return ret[:sep], nil
+}
+
+// Tweakable OMAC - Calls OMAC_K([t]_n || plaintext)
+func (e *eax) omacT(t byte, plaintext []byte) []byte {
+ blockSize := e.block.BlockSize()
+ byteT := make([]byte, blockSize)
+ byteT[blockSize-1] = t
+ concat := append(byteT, plaintext...)
+ return e.omac(concat)
+}
+
+func (e *eax) omac(plaintext []byte) []byte {
+ blockSize := e.block.BlockSize()
+ // L ← E_K(0^n); B ← 2L; P ← 4L
+ L := make([]byte, blockSize)
+ e.block.Encrypt(L, L)
+ B := byteutil.GfnDouble(L)
+ P := byteutil.GfnDouble(B)
+
+ // CBC with IV = 0
+ cbc := cipher.NewCBCEncrypter(e.block, make([]byte, blockSize))
+ padded := e.pad(plaintext, B, P)
+ cbcCiphertext := make([]byte, len(padded))
+ cbc.CryptBlocks(cbcCiphertext, padded)
+
+ return cbcCiphertext[len(cbcCiphertext)-blockSize:]
+}
+
+func (e *eax) pad(plaintext, B, P []byte) []byte {
+ // if |M| in {n, 2n, 3n, ...}
+ blockSize := e.block.BlockSize()
+ if len(plaintext) != 0 && len(plaintext)%blockSize == 0 {
+ return byteutil.RightXor(plaintext, B)
+ }
+
+ // else return (M || 1 || 0^(n−1−(|M| % n))) xor→ P
+ ending := make([]byte, blockSize-len(plaintext)%blockSize)
+ ending[0] = 0x80
+ padded := append(plaintext, ending...)
+ return byteutil.RightXor(padded, P)
+}
+
+func eaxError(err string) error {
+ return errors.New("crypto/eax: " + err)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/eax/eax_test_vectors.go b/vendor/github.com/ProtonMail/go-crypto/eax/eax_test_vectors.go
new file mode 100644
index 0000000000..ddb53d0790
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/eax/eax_test_vectors.go
@@ -0,0 +1,58 @@
+package eax
+
+// Test vectors from
+// https://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+var testVectors = []struct {
+ msg, key, nonce, header, ciphertext string
+}{
+ {"",
+ "233952DEE4D5ED5F9B9C6D6FF80FF478",
+ "62EC67F9C3A4A407FCB2A8C49031A8B3",
+ "6BFB914FD07EAE6B",
+ "E037830E8389F27B025A2D6527E79D01"},
+ {"F7FB",
+ "91945D3F4DCBEE0BF45EF52255F095A4",
+ "BECAF043B0A23D843194BA972C66DEBD",
+ "FA3BFD4806EB53FA",
+ "19DD5C4C9331049D0BDAB0277408F67967E5"},
+ {"1A47CB4933",
+ "01F74AD64077F2E704C0F60ADA3DD523",
+ "70C3DB4F0D26368400A10ED05D2BFF5E",
+ "234A3463C1264AC6",
+ "D851D5BAE03A59F238A23E39199DC9266626C40F80"},
+ {"481C9E39B1",
+ "D07CF6CBB7F313BDDE66B727AFD3C5E8",
+ "8408DFFF3C1A2B1292DC199E46B7D617",
+ "33CCE2EABFF5A79D",
+ "632A9D131AD4C168A4225D8E1FF755939974A7BEDE"},
+ {"40D0C07DA5E4",
+ "35B6D0580005BBC12B0587124557D2C2",
+ "FDB6B06676EEDC5C61D74276E1F8E816",
+ "AEB96EAEBE2970E9",
+ "071DFE16C675CB0677E536F73AFE6A14B74EE49844DD"},
+ {"4DE3B35C3FC039245BD1FB7D",
+ "BD8E6E11475E60B268784C38C62FEB22",
+ "6EAC5C93072D8E8513F750935E46DA1B",
+ "D4482D1CA78DCE0F",
+ "835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F"},
+ {"8B0A79306C9CE7ED99DAE4F87F8DD61636",
+ "7C77D6E813BED5AC98BAA417477A2E7D",
+ "1A8C98DCD73D38393B2BF1569DEEFC19",
+ "65D2017990D62528",
+ "02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2"},
+ {"1BDA122BCE8A8DBAF1877D962B8592DD2D56",
+ "5FFF20CAFAB119CA2FC73549E20F5B0D",
+ "DDE59B97D722156D4D9AFF2BC7559826",
+ "54B9F04E6A09189A",
+ "2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A"},
+ {"6CF36720872B8513F6EAB1A8A44438D5EF11",
+ "A4A4782BCFFD3EC5E7EF6D8C34A56123",
+ "B781FCF2F75FA5A8DE97A9CA48E522EC",
+ "899A175897561D7E",
+ "0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700"},
+ {"CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7",
+ "8395FCF1E95BEBD697BD010BC766AAC3",
+ "22E7ADD93CFC6393C57EC0B3C17D6B44",
+ "126735FCC320D25A",
+ "CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E"},
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/eax/random_vectors.go b/vendor/github.com/ProtonMail/go-crypto/eax/random_vectors.go
new file mode 100644
index 0000000000..4eb19f28d9
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/eax/random_vectors.go
@@ -0,0 +1,131 @@
+// These vectors include key length in {128, 192, 256}, tag size 128, and
+// random nonce, header, and plaintext lengths.
+
+// This file was automatically generated.
+
+package eax
+
+var randomVectors = []struct {
+ key, nonce, header, plaintext, ciphertext string
+}{
+ {"DFDE093F36B0356E5A81F609786982E3",
+ "1D8AC604419001816905BA72B14CED7E",
+ "152A1517A998D7A24163FCDD146DE81AC347C8B97088F502093C1ABB8F6E33D9A219C34D7603A18B1F5ABE02E56661B7D7F67E81EC08C1302EF38D80A859486D450E94A4F26AD9E68EEBBC0C857A0FC5CF9E641D63D565A7E361BC8908F5A8DC8FD6",
+ "1C8EAAB71077FE18B39730A3156ADE29C5EE824C7EE86ED2A253B775603FB237116E654F6FEC588DD27F523A0E01246FE73FE348491F2A8E9ABC6CA58D663F71CDBCF4AD798BE46C42AE6EE8B599DB44A1A48D7BBBBA0F7D2750181E1C5E66967F7D57CBD30AFBDA5727",
+ "79E7E150934BBEBF7013F61C60462A14D8B15AF7A248AFB8A344EF021C1500E16666891D6E973D8BB56B71A371F12CA34660C4410C016982B20F547E3762A58B7BF4F20236CADCF559E2BE7D783B13723B2741FC7CDC8997D839E39A3DDD2BADB96743DD7049F1BDB0516A262869915B3F70498AFB7B191BF960"},
+ {"F10619EF02E5D94D7550EB84ED364A21",
+ "8DC0D4F2F745BBAE835CC5574B942D20",
+ "FE561358F2E8DF7E1024FF1AE9A8D36EBD01352214505CB99D644777A8A1F6027FA2BDBFC529A9B91136D5F2416CFC5F0F4EC3A1AFD32BDDA23CA504C5A5CB451785FABF4DFE4CD50D817491991A60615B30286361C100A95D1712F2A45F8E374461F4CA2B",
+ "D7B5A971FC219631D30EFC3664AE3127D9CF3097DAD9C24AC7905D15E8D9B25B026B31D68CAE00975CDB81EB1FD96FD5E1A12E2BB83FA25F1B1D91363457657FC03875C27F2946C5",
+ "2F336ED42D3CC38FC61660C4CD60BA4BD438B05F5965D8B7B399D2E7167F5D34F792D318F94DB15D67463AC449E13D568CC09BFCE32A35EE3EE96A041927680AE329811811E27F2D1E8E657707AF99BA96D13A478D695D59"},
+ {"429F514EFC64D98A698A9247274CFF45",
+ "976AA5EB072F912D126ACEBC954FEC38",
+ "A71D89DC5B6CEDBB7451A27C3C2CAE09126DB4C421",
+ "5632FE62AB1DC549D54D3BC3FC868ACCEDEFD9ECF5E9F8",
+ "848AE4306CA8C7F416F8707625B7F55881C0AB430353A5C967CDA2DA787F581A70E34DBEBB2385"},
+ {"398138F309085F47F8457CDF53895A63",
+ "F8A8A7F2D28E5FFF7BBC2F24353F7A36",
+ "5D633C21BA7764B8855CAB586F3746E236AD486039C83C6B56EFA9C651D38A41D6B20DAEE3418BFEA44B8BD6",
+ "A3BBAA91920AF5E10659818B1B3B300AC79BFC129C8329E75251F73A66D3AE0128EB91D5031E0A65C329DB7D1E9C0493E268",
+ "D078097267606E5FB07CFB7E2B4B718172A82C6A4CEE65D549A4DFB9838003BD2FBF64A7A66988AC1A632FD88F9E9FBB57C5A78AD2E086EACBA3DB68511D81C2970A"},
+ {"7A4151EBD3901B42CBA45DAFB2E931BA",
+ "0FC88ACEE74DD538040321C330974EB8",
+ "250464FB04733BAB934C59E6AD2D6AE8D662CBCFEFBE61E5A308D4211E58C4C25935B72C69107722E946BFCBF416796600542D76AEB73F2B25BF53BAF97BDEB36ED3A7A51C31E7F170EB897457E7C17571D1BA0A908954E9",
+ "88C41F3EBEC23FAB8A362D969CAC810FAD4F7CA6A7F7D0D44F060F92E37E1183768DD4A8C733F71C96058D362A39876D183B86C103DE",
+ "74A25B2182C51096D48A870D80F18E1CE15867778E34FCBA6BD7BFB3739FDCD42AD0F2D9F4EBA29085285C6048C15BCE5E5166F1F962D3337AA88E6062F05523029D0A7F0BF9"},
+ {"BFB147E1CD5459424F8C0271FC0E0DC5",
+ "EABCC126442BF373969EA3015988CC45",
+ "4C0880E1D71AA2C7",
+ "BE1B5EC78FBF73E7A6682B21BA7E0E5D2D1C7ABE",
+ "5660D7C1380E2F306895B1402CB2D6C37876504276B414D120F4CF92FDDDBB293A238EA0"},
+ {"595DD6F52D18BC2CA8EB4EDAA18D9FA3",
+ "0F84B5D36CF4BC3B863313AF3B4D2E97",
+ "30AE6CC5F99580F12A779D98BD379A60948020C0B6FBD5746B30BA3A15C6CD33DAF376C70A9F15B6C0EB410A93161F7958AE23",
+ "8EF3687A1642B070970B0B91462229D1D76ABC154D18211F7152AA9FF368",
+ "317C1DDB11417E5A9CC4DDE7FDFF6659A5AC4B31DE025212580A05CDAC6024D3E4AE7C2966E52B9129E9ECDBED86"},
+ {"44E6F2DC8FDC778AD007137D11410F50",
+ "270A237AD977F7187AA6C158A0BAB24F",
+ "509B0F0EB12E2AA5C5BA2DE553C07FAF4CE0C9E926531AA709A3D6224FCB783ACCF1559E10B1123EBB7D52E8AB54E6B5352A9ED0D04124BF0E9D9BACFD7E32B817B2E625F5EE94A64EDE9E470DE7FE6886C19B294F9F828209FE257A78",
+ "8B3D7815DF25618A5D0C55A601711881483878F113A12EC36CF64900549A3199555528559DC118F789788A55FAFD944E6E99A9CA3F72F238CD3F4D88223F7A745992B3FAED1848",
+ "1CC00D79F7AD82FDA71B58D286E5F34D0CC4CEF30704E771CC1E50746BDF83E182B078DB27149A42BAE619DF0F85B0B1090AD55D3B4471B0D6F6ECCD09C8F876B30081F0E7537A9624F8AAF29DA85E324122EFB4D68A56"},
+ {"BB7BC352A03044B4428D8DBB4B0701FDEC4649FD17B81452",
+ "8B4BBE26CCD9859DCD84884159D6B0A4",
+ "2212BEB0E78E0F044A86944CF33C8D5C80D9DBE1034BF3BCF73611835C7D3A52F5BD2D81B68FD681B68540A496EE5DA16FD8AC8824E60E1EC2042BE28FB0BFAD4E4B03596446BDD8C37D936D9B3D5295BE19F19CF5ACE1D33A46C952CE4DE5C12F92C1DD051E04AEED",
+ "9037234CC44FFF828FABED3A7084AF40FA7ABFF8E0C0EFB57A1CC361E18FC4FAC1AB54F3ABFE9FF77263ACE16C3A",
+ "A9391B805CCD956081E0B63D282BEA46E7025126F1C1631239C33E92AA6F92CD56E5A4C56F00FF9658E93D48AF4EF0EF81628E34AD4DB0CDAEDCD2A17EE7"},
+ {"99C0AD703196D2F60A74E6B378B838B31F82EA861F06FC4E",
+ "92745C018AA708ECFEB1667E9F3F1B01",
+ "828C69F376C0C0EC651C67749C69577D589EE39E51404D80EBF70C8660A8F5FD375473F4A7C611D59CB546A605D67446CE2AA844135FCD78BB5FBC90222A00D42920BB1D7EEDFB0C4672554F583EF23184F89063CDECBE482367B5F9AF3ACBC3AF61392BD94CBCD9B64677",
+ "A879214658FD0A5B0E09836639BF82E05EC7A5EF71D4701934BDA228435C68AC3D5CEB54997878B06A655EEACEFB1345C15867E7FE6C6423660C8B88DF128EBD6BCD85118DBAE16E9252FFB204324E5C8F38CA97759BDBF3CB0083",
+ "51FE87996F194A2585E438B023B345439EA60D1AEBED4650CDAF48A4D4EEC4FC77DC71CC4B09D3BEEF8B7B7AF716CE2B4EFFB3AC9E6323C18AC35E0AA6E2BBBC8889490EB6226C896B0D105EAB42BFE7053CCF00ED66BA94C1BA09A792AA873F0C3B26C5C5F9A936E57B25"},
+ {"7086816D00D648FB8304AA8C9E552E1B69A9955FB59B25D1",
+ "0F45CF7F0BF31CCEB85D9DA10F4D749F",
+ "93F27C60A417D9F0669E86ACC784FC8917B502DAF30A6338F11B30B94D74FEFE2F8BE1BBE2EAD10FAB7EED3C6F72B7C3ECEE1937C32ED4970A6404E139209C05",
+ "877F046601F3CBE4FB1491943FA29487E738F94B99AF206262A1D6FF856C9AA0B8D4D08A54370C98F8E88FA3DCC2B14C1F76D71B2A4C7963AEE8AF960464C5BEC8357AD00DC8",
+ "FE96906B895CE6A8E72BC72344E2C8BB3C63113D70EAFA26C299BAFE77A8A6568172EB447FB3E86648A0AF3512DEB1AAC0819F3EC553903BF28A9FB0F43411237A774BF9EE03E445D280FBB9CD12B9BAAB6EF5E52691"},
+ {"062F65A896D5BF1401BADFF70E91B458E1F9BD4888CB2E4D",
+ "5B11EA1D6008EBB41CF892FCA5B943D1",
+ "BAF4FF5C8242",
+ "A8870E091238355984EB2F7D61A865B9170F440BFF999A5993DD41A10F4440D21FF948DDA2BF663B2E03AC3324492DC5E40262ECC6A65C07672353BE23E7FB3A9D79FF6AA38D97960905A38DECC312CB6A59E5467ECF06C311CD43ADC0B543EDF34FE8BE611F176460D5627CA51F8F8D9FED71F55C",
+ "B10E127A632172CF8AA7539B140D2C9C2590E6F28C3CB892FC498FCE56A34F732FBFF32E79C7B9747D9094E8635A0C084D6F0247F9768FB5FF83493799A9BEC6C39572120C40E9292C8C947AE8573462A9108C36D9D7112E6995AE5867E6C8BB387D1C5D4BEF524F391B9FD9F0A3B4BFA079E915BCD920185CFD38D114C558928BD7D47877"},
+ {"38A8E45D6D705A11AF58AED5A1344896998EACF359F2E26A",
+ "FD82B5B31804FF47D44199B533D0CF84",
+ "DE454D4E62FE879F2050EE3E25853623D3E9AC52EEC1A1779A48CFAF5ECA0BFDE44749391866D1",
+ "B804",
+ "164BB965C05EBE0931A1A63293EDF9C38C27"},
+ {"34C33C97C6D7A0850DA94D78A58DC61EC717CD7574833068",
+ "343BE00DA9483F05C14F2E9EB8EA6AE8",
+ "78312A43EFDE3CAE34A65796FF059A3FE15304EEA5CF1D9306949FE5BF3349D4977D4EBE76C040FE894C5949E4E4D6681153DA87FB9AC5062063CA2EA183566343362370944CE0362D25FC195E124FD60E8682E665D13F2229DDA3E4B2CB1DCA",
+ "CC11BB284B1153578E4A5ED9D937B869DAF00F5B1960C23455CA9CC43F486A3BE0B66254F1041F04FDF459C8640465B6E1D2CF899A381451E8E7FCB50CF87823BE77E24B132BBEEDC72E53369B275E1D8F49ECE59F4F215230AC4FE133FC80E4F634EE80BA4682B62C86",
+ "E7F703DC31A95E3A4919FF957836CB76C063D81702AEA4703E1C2BF30831E58C4609D626EC6810E12EAA5B930F049FF9EFC22C3E3F1EBD4A1FB285CB02A1AC5AD46B425199FC0A85670A5C4E3DAA9636C8F64C199F42F18AAC8EA7457FD377F322DD7752D7D01B946C8F0A97E6113F0D50106F319AFD291AAACE"},
+ {"C6ECF7F053573E403E61B83052A343D93CBCC179D1E835BE",
+ "E280E13D7367042E3AA09A80111B6184",
+ "21486C9D7A9647",
+ "5F2639AFA6F17931853791CD8C92382BBB677FD72D0AB1A080D0E49BFAA21810E963E4FACD422E92F65CBFAD5884A60CD94740DF31AF02F95AA57DA0C4401B0ED906",
+ "5C51DB20755302070C45F52E50128A67C8B2E4ED0EACB7E29998CCE2E8C289DD5655913EC1A51CC3AABE5CDC2402B2BE7D6D4BF6945F266FBD70BA9F37109067157AE7530678B45F64475D4EBFCB5FFF46A5"},
+ {"5EC6CF7401BC57B18EF154E8C38ACCA8959E57D2F3975FF5",
+ "656B41CB3F9CF8C08BAD7EBFC80BD225",
+ "6B817C2906E2AF425861A7EF59BA5801F143EE2A139EE72697CDE168B4",
+ "2C0E1DDC9B1E5389BA63845B18B1F8A1DB062037151BCC56EF7C21C0BB4DAE366636BBA975685D7CC5A94AFBE89C769016388C56FB7B57CE750A12B718A8BDCF70E80E8659A8330EFC8F86640F21735E8C80E23FE43ABF23507CE3F964AE4EC99D",
+ "ED780CF911E6D1AA8C979B889B0B9DC1ABE261832980BDBFB576901D9EF5AB8048998E31A15BE54B3E5845A4D136AD24D0BDA1C3006168DF2F8AC06729CB0818867398150020131D8F04EDF1923758C9EABB5F735DE5EA1758D4BC0ACFCA98AFD202E9839B8720253693B874C65586C6F0"},
+ {"C92F678EB2208662F5BCF3403EC05F5961E957908A3E79421E1D25FC19054153",
+ "DA0F3A40983D92F2D4C01FED33C7A192",
+ "2B6E9D26DB406A0FAB47608657AA10EFC2B4AA5F459B29FF85AC9A40BFFE7AEB04F77E9A11FAAA116D7F6D4DA417671A9AB02C588E0EF59CB1BFB4B1CC931B63A3B3A159FCEC97A04D1E6F0C7E6A9CEF6B0ABB04758A69F1FE754DF4C2610E8C46B6CF413BDB31351D55BEDCB7B4A13A1C98E10984475E0F2F957853",
+ "F37326A80E08",
+ "83519E53E321D334F7C10B568183775C0E9AAE55F806"},
+ {"6847E0491BE57E72995D186D50094B0B3593957A5146798FCE68B287B2FB37B5",
+ "3EE1182AEBB19A02B128F28E1D5F7F99",
+ "D9F35ABB16D776CE",
+ "DB7566ED8EA95BDF837F23DB277BAFBC5E70D1105ADFD0D9EF15475051B1EF94709C67DCA9F8D5",
+ "2CDCED0C9EBD6E2A508822A685F7DCD1CDD99E7A5FCA786C234E7F7F1D27EC49751AD5DCFA30C5EDA87C43CAE3B919B6BBCFE34C8EDA59"},
+ {"82B019673642C08388D3E42075A4D5D587558C229E4AB8F660E37650C4C41A0A",
+ "336F5D681E0410FAE7B607246092C6DC",
+ "D430CBD8FE435B64214E9E9CDC5DE99D31CFCFB8C10AA0587A49DF276611",
+ "998404153AD77003E1737EDE93ED79859EE6DCCA93CB40C4363AA817ABF2DBBD46E42A14A7183B6CC01E12A577888141363D0AE011EB6E8D28C0B235",
+ "9BEF69EEB60BD3D6065707B7557F25292A8872857CFBD24F2F3C088E4450995333088DA50FD9121221C504DF1D0CD5EFE6A12666C5D5BB12282CF4C19906E9CFAB97E9BDF7F49DC17CFC384B"},
+ {"747B2E269B1859F0622C15C8BAD6A725028B1F94B8DB7326948D1E6ED663A8BC",
+ "AB91F7245DDCE3F1C747872D47BE0A8A",
+ "3B03F786EF1DDD76E1D42646DA4CD2A5165DC5383CE86D1A0B5F13F910DC278A4E451EE0192CBA178E13B3BA27FDC7840DF73D2E104B",
+ "6B803F4701114F3E5FE21718845F8416F70F626303F545BE197189E0A2BA396F37CE06D389EB2658BC7D56D67868708F6D0D32",
+ "1570DDB0BCE75AA25D1957A287A2C36B1A5F2270186DA81BA6112B7F43B0F3D1D0ED072591DCF1F1C99BBB25621FC39B896FF9BD9413A2845363A9DCD310C32CF98E57"},
+ {"02E59853FB29AEDA0FE1C5F19180AD99A12FF2F144670BB2B8BADF09AD812E0A",
+ "C691294EF67CD04D1B9242AF83DD1421",
+ "879334DAE3",
+ "1E17F46A98FEF5CBB40759D95354",
+ "FED8C3FF27DDF6313AED444A2985B36CBA268AAD6AAC563C0BA28F6DB5DB"},
+ {"F6C1FB9B4188F2288FF03BD716023198C3582CF2A037FC2F29760916C2B7FCDB",
+ "4228DA0678CA3534588859E77DFF014C",
+ "D8153CAF35539A61DD8D05B3C9B44F01E564FB9348BCD09A1C23B84195171308861058F0A3CD2A55B912A3AAEE06FF4D356C77275828F2157C2FC7C115DA39E443210CCC56BEDB0CC99BBFB227ABD5CC454F4E7F547C7378A659EEB6A7E809101A84F866503CB18D4484E1FA09B3EC7FC75EB2E35270800AA7",
+ "23B660A779AD285704B12EC1C580387A47BEC7B00D452C6570",
+ "5AA642BBABA8E49849002A2FAF31DB8FC7773EFDD656E469CEC19B3206D4174C9A263D0A05484261F6"},
+ {"8FF6086F1FADB9A3FBE245EAC52640C43B39D43F89526BB5A6EBA47710931446",
+ "943188480C99437495958B0AE4831AA9",
+ "AD5CD0BDA426F6EBA23C8EB23DC73FF9FEC173355EDBD6C9344C4C4383F211888F7CE6B29899A6801DF6B38651A7C77150941A",
+ "80CD5EA8D7F81DDF5070B934937912E8F541A5301877528EB41AB60C020968D459960ED8FB73083329841A",
+ "ABAE8EB7F36FCA2362551E72DAC890BA1BB6794797E0FC3B67426EC9372726ED4725D379EA0AC9147E48DCD0005C502863C2C5358A38817C8264B5"},
+ {"A083B54E6B1FE01B65D42FCD248F97BB477A41462BBFE6FD591006C022C8FD84",
+ "B0490F5BD68A52459556B3749ACDF40E",
+ "8892E047DA5CFBBDF7F3CFCBD1BD21C6D4C80774B1826999234394BD3E513CC7C222BB40E1E3140A152F19B3802F0D036C24A590512AD0E8",
+ "D7B15752789DC94ED0F36778A5C7BBB207BEC32BAC66E702B39966F06E381E090C6757653C3D26A81EC6AD6C364D66867A334C91BB0B8A8A4B6EACDF0783D09010AEBA2DD2062308FE99CC1F",
+ "C071280A732ADC93DF272BF1E613B2BB7D46FC6665EF2DC1671F3E211D6BDE1D6ADDD28DF3AA2E47053FC8BB8AE9271EC8BC8B2CFFA320D225B451685B6D23ACEFDD241FE284F8ADC8DB07F456985B14330BBB66E0FB212213E05B3E"},
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go b/vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go
new file mode 100644
index 0000000000..d558b9bd82
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go
@@ -0,0 +1,90 @@
+// Copyright (C) 2019 ProtonTech AG
+// This file contains necessary tools for the aex and ocb packages.
+//
+// These functions SHOULD NOT be used elsewhere, since they are optimized for
+// specific input nature in the EAX and OCB modes of operation.
+
+package byteutil
+
+// GfnDouble computes 2 * input in the field of 2^n elements.
+// The irreducible polynomial in the finite field for n=128 is
+// x^128 + x^7 + x^2 + x + 1 (equals 0x87)
+// Constant-time execution in order to avoid side-channel attacks
+func GfnDouble(input []byte) []byte {
+ if len(input) != 16 {
+ panic("Doubling in GFn only implemented for n = 128")
+ }
+ // If the first bit is zero, return 2L = L << 1
+ // Else return (L << 1) xor 0^120 10000111
+ shifted := ShiftBytesLeft(input)
+ shifted[15] ^= ((input[0] >> 7) * 0x87)
+ return shifted
+}
+
+// ShiftBytesLeft outputs the byte array corresponding to x << 1 in binary.
+func ShiftBytesLeft(x []byte) []byte {
+ l := len(x)
+ dst := make([]byte, l)
+ for i := 0; i < l-1; i++ {
+ dst[i] = (x[i] << 1) | (x[i+1] >> 7)
+ }
+ dst[l-1] = x[l-1] << 1
+ return dst
+}
+
+// ShiftNBytesLeft puts in dst the byte array corresponding to x << n in binary.
+func ShiftNBytesLeft(dst, x []byte, n int) {
+ // Erase first n / 8 bytes
+ copy(dst, x[n/8:])
+
+ // Shift the remaining n % 8 bits
+ bits := uint(n % 8)
+ l := len(dst)
+ for i := 0; i < l-1; i++ {
+ dst[i] = (dst[i] << bits) | (dst[i+1] >> uint(8-bits))
+ }
+ dst[l-1] = dst[l-1] << bits
+
+ // Append trailing zeroes
+ dst = append(dst, make([]byte, n/8)...)
+}
+
+// XorBytesMut replaces X with X XOR Y. len(X) must be >= len(Y).
+func XorBytesMut(X, Y []byte) {
+ for i := 0; i < len(Y); i++ {
+ X[i] ^= Y[i]
+ }
+}
+
+// XorBytes puts X XOR Y into Z. len(Z) and len(X) must be >= len(Y).
+func XorBytes(Z, X, Y []byte) {
+ for i := 0; i < len(Y); i++ {
+ Z[i] = X[i] ^ Y[i]
+ }
+}
+
+// RightXor XORs smaller input (assumed Y) at the right of the larger input (assumed X)
+func RightXor(X, Y []byte) []byte {
+ offset := len(X) - len(Y)
+ xored := make([]byte, len(X))
+ copy(xored, X)
+ for i := 0; i < len(Y); i++ {
+ xored[offset+i] ^= Y[i]
+ }
+ return xored
+}
+
+// SliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func SliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go b/vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
new file mode 100644
index 0000000000..24f893017b
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
@@ -0,0 +1,313 @@
+// Copyright (C) 2019 ProtonTech AG
+
+// Package ocb provides an implementation of the OCB (offset codebook) mode of
+// operation, as described in RFC-7253 of the IRTF and in Rogaway, Bellare,
+// Black and Krovetz - OCB: A BLOCK-CIPHER MODE OF OPERATION FOR EFFICIENT
+// AUTHENTICATED ENCRYPTION (2003).
+// Security considerations (from RFC-7253): A private key MUST NOT be used to
+// encrypt more than 2^48 blocks. Tag length should be at least 12 bytes (a
+// brute-force forging adversary succeeds after 2^{tag length} attempts). A
+// single key SHOULD NOT be used to decrypt ciphertext with different tag
+// lengths. Nonces need not be secret, but MUST NOT be reused.
+// This package only supports underlying block ciphers with 128-bit blocks,
+// such as AES-{128, 192, 256}, but may be extended to other sizes.
+package ocb
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/subtle"
+ "errors"
+ "math/bits"
+
+ "github.com/ProtonMail/go-crypto/internal/byteutil"
+)
+
+type ocb struct {
+ block cipher.Block
+ tagSize int
+ nonceSize int
+ mask mask
+ // Optimized en/decrypt: For each nonce N used to en/decrypt, the 'Ktop'
+ // internal variable can be reused for en/decrypting with nonces sharing
+ // all but the last 6 bits with N. The prefix of the first nonce used to
+ // compute the new Ktop, and the Ktop value itself, are stored in
+ // reusableKtop. If using incremental nonces, this saves one block cipher
+ // call every 63 out of 64 OCB encryptions, and stores one nonce and one
+ // output of the block cipher in memory only.
+ reusableKtop reusableKtop
+}
+
+type mask struct {
+ // L_*, L_$, (L_i)_{i ∈ N}
+ lAst []byte
+ lDol []byte
+ L [][]byte
+}
+
+type reusableKtop struct {
+ noncePrefix []byte
+ Ktop []byte
+}
+
+const (
+ defaultTagSize = 16
+ defaultNonceSize = 15
+)
+
+const (
+ enc = iota
+ dec
+)
+
+func (o *ocb) NonceSize() int {
+ return o.nonceSize
+}
+
+func (o *ocb) Overhead() int {
+ return o.tagSize
+}
+
+// NewOCB returns an OCB instance with the given block cipher and default
+// tag and nonce sizes.
+func NewOCB(block cipher.Block) (cipher.AEAD, error) {
+ return NewOCBWithNonceAndTagSize(block, defaultNonceSize, defaultTagSize)
+}
+
+// NewOCBWithNonceAndTagSize returns an OCB instance with the given block
+// cipher, nonce length, and tag length. Panics on zero nonceSize and
+// exceedingly long tag size.
+//
+// It is recommended to use at least 12 bytes as tag length.
+func NewOCBWithNonceAndTagSize(
+ block cipher.Block, nonceSize, tagSize int) (cipher.AEAD, error) {
+ if block.BlockSize() != 16 {
+ return nil, ocbError("Block cipher must have 128-bit blocks")
+ }
+ if nonceSize < 1 {
+ return nil, ocbError("Incorrect nonce length")
+ }
+ if nonceSize >= block.BlockSize() {
+ return nil, ocbError("Nonce length exceeds blocksize - 1")
+ }
+ if tagSize > block.BlockSize() {
+ return nil, ocbError("Custom tag length exceeds blocksize")
+ }
+ return &ocb{
+ block: block,
+ tagSize: tagSize,
+ nonceSize: nonceSize,
+ mask: initializeMaskTable(block),
+ reusableKtop: reusableKtop{
+ noncePrefix: nil,
+ Ktop: nil,
+ },
+ }, nil
+}
+
+func (o *ocb) Seal(dst, nonce, plaintext, adata []byte) []byte {
+ if len(nonce) > o.nonceSize {
+ panic("crypto/ocb: Incorrect nonce length given to OCB")
+ }
+ sep := len(plaintext)
+ ret, out := byteutil.SliceForAppend(dst, sep+o.tagSize)
+ tag := o.crypt(enc, out[:sep], nonce, adata, plaintext)
+ copy(out[sep:], tag)
+ return ret
+}
+
+func (o *ocb) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) {
+ if len(nonce) > o.nonceSize {
+ panic("Nonce too long for this instance")
+ }
+ if len(ciphertext) < o.tagSize {
+ return nil, ocbError("Ciphertext shorter than tag length")
+ }
+ sep := len(ciphertext) - o.tagSize
+ ret, out := byteutil.SliceForAppend(dst, sep)
+ ciphertextData := ciphertext[:sep]
+ tag := o.crypt(dec, out, nonce, adata, ciphertextData)
+ if subtle.ConstantTimeCompare(tag, ciphertext[sep:]) == 1 {
+ return ret, nil
+ }
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, ocbError("Tag authentication failed")
+}
+
+// On instruction enc (resp. dec), crypt is the encrypt (resp. decrypt)
+// function. It writes the resulting plain/ciphertext into Y and returns
+// the tag.
+func (o *ocb) crypt(instruction int, Y, nonce, adata, X []byte) []byte {
+ //
+ // Consider X as a sequence of 128-bit blocks
+ //
+ // Note: For encryption (resp. decryption), X is the plaintext (resp., the
+ // ciphertext without the tag).
+ blockSize := o.block.BlockSize()
+
+ //
+ // Nonce-dependent and per-encryption variables
+ //
+ // Zero out the last 6 bits of the nonce into truncatedNonce to see if Ktop
+ // is already computed.
+ truncatedNonce := make([]byte, len(nonce))
+ copy(truncatedNonce, nonce)
+ truncatedNonce[len(truncatedNonce)-1] &= 192
+ var Ktop []byte
+ if bytes.Equal(truncatedNonce, o.reusableKtop.noncePrefix) {
+ Ktop = o.reusableKtop.Ktop
+ } else {
+ // Nonce = num2str(TAGLEN mod 128, 7) || zeros(120 - bitlen(N)) || 1 || N
+ paddedNonce := append(make([]byte, blockSize-1-len(nonce)), 1)
+ paddedNonce = append(paddedNonce, truncatedNonce...)
+ paddedNonce[0] |= byte(((8 * o.tagSize) % (8 * blockSize)) << 1)
+ // Last 6 bits of paddedNonce are already zero. Encrypt into Ktop
+ paddedNonce[blockSize-1] &= 192
+ Ktop = paddedNonce
+ o.block.Encrypt(Ktop, Ktop)
+ o.reusableKtop.noncePrefix = truncatedNonce
+ o.reusableKtop.Ktop = Ktop
+ }
+
+ // Stretch = Ktop || ((lower half of Ktop) XOR (lower half of Ktop << 8))
+ xorHalves := make([]byte, blockSize/2)
+ byteutil.XorBytes(xorHalves, Ktop[:blockSize/2], Ktop[1:1+blockSize/2])
+ stretch := append(Ktop, xorHalves...)
+ bottom := int(nonce[len(nonce)-1] & 63)
+ offset := make([]byte, len(stretch))
+ byteutil.ShiftNBytesLeft(offset, stretch, bottom)
+ offset = offset[:blockSize]
+
+ //
+ // Process any whole blocks
+ //
+ // Note: For encryption Y is ciphertext || tag, for decryption Y is
+ // plaintext || tag.
+ checksum := make([]byte, blockSize)
+ m := len(X) / blockSize
+ for i := 0; i < m; i++ {
+ index := bits.TrailingZeros(uint(i + 1))
+ if len(o.mask.L)-1 < index {
+ o.mask.extendTable(index)
+ }
+ byteutil.XorBytesMut(offset, o.mask.L[bits.TrailingZeros(uint(i+1))])
+ blockX := X[i*blockSize : (i+1)*blockSize]
+ blockY := Y[i*blockSize : (i+1)*blockSize]
+ switch instruction {
+ case enc:
+ byteutil.XorBytesMut(checksum, blockX)
+ byteutil.XorBytes(blockY, blockX, offset)
+ o.block.Encrypt(blockY, blockY)
+ byteutil.XorBytesMut(blockY, offset)
+ case dec:
+ byteutil.XorBytes(blockY, blockX, offset)
+ o.block.Decrypt(blockY, blockY)
+ byteutil.XorBytesMut(blockY, offset)
+ byteutil.XorBytesMut(checksum, blockY)
+ }
+ }
+ //
+ // Process any final partial block and compute raw tag
+ //
+ tag := make([]byte, blockSize)
+ if len(X)%blockSize != 0 {
+ byteutil.XorBytesMut(offset, o.mask.lAst)
+ pad := make([]byte, blockSize)
+ o.block.Encrypt(pad, offset)
+ chunkX := X[blockSize*m:]
+ chunkY := Y[blockSize*m : len(X)]
+ switch instruction {
+ case enc:
+ byteutil.XorBytesMut(checksum, chunkX)
+ checksum[len(chunkX)] ^= 128
+ byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)])
+ // P_* || bit(1) || zeroes(127) - len(P_*)
+ case dec:
+ byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)])
+ // P_* || bit(1) || zeroes(127) - len(P_*)
+ byteutil.XorBytesMut(checksum, chunkY)
+ checksum[len(chunkY)] ^= 128
+ }
+ }
+ byteutil.XorBytes(tag, checksum, offset)
+ byteutil.XorBytesMut(tag, o.mask.lDol)
+ o.block.Encrypt(tag, tag)
+ byteutil.XorBytesMut(tag, o.hash(adata))
+ return tag[:o.tagSize]
+}
+
+// This hash function is used to compute the tag. Per design, on empty input it
+// returns a slice of zeros, of the same length as the underlying block cipher
+// block size.
+func (o *ocb) hash(adata []byte) []byte {
+ //
+ // Consider A as a sequence of 128-bit blocks
+ //
+ A := make([]byte, len(adata))
+ copy(A, adata)
+ blockSize := o.block.BlockSize()
+
+ //
+ // Process any whole blocks
+ //
+ sum := make([]byte, blockSize)
+ offset := make([]byte, blockSize)
+ m := len(A) / blockSize
+ for i := 0; i < m; i++ {
+ chunk := A[blockSize*i : blockSize*(i+1)]
+ index := bits.TrailingZeros(uint(i + 1))
+ // If the mask table is too short
+ if len(o.mask.L)-1 < index {
+ o.mask.extendTable(index)
+ }
+ byteutil.XorBytesMut(offset, o.mask.L[index])
+ byteutil.XorBytesMut(chunk, offset)
+ o.block.Encrypt(chunk, chunk)
+ byteutil.XorBytesMut(sum, chunk)
+ }
+
+ //
+ // Process any final partial block; compute final hash value
+ //
+ if len(A)%blockSize != 0 {
+ byteutil.XorBytesMut(offset, o.mask.lAst)
+ // Pad block with 1 || 0 ^ 127 - bitlength(a)
+ ending := make([]byte, blockSize-len(A)%blockSize)
+ ending[0] = 0x80
+ encrypted := append(A[blockSize*m:], ending...)
+ byteutil.XorBytesMut(encrypted, offset)
+ o.block.Encrypt(encrypted, encrypted)
+ byteutil.XorBytesMut(sum, encrypted)
+ }
+ return sum
+}
+
+func initializeMaskTable(block cipher.Block) mask {
+ //
+ // Key-dependent variables
+ //
+ lAst := make([]byte, block.BlockSize())
+ block.Encrypt(lAst, lAst)
+ lDol := byteutil.GfnDouble(lAst)
+ L := make([][]byte, 1)
+ L[0] = byteutil.GfnDouble(lDol)
+
+ return mask{
+ lAst: lAst,
+ lDol: lDol,
+ L: L,
+ }
+}
+
+// Extends the L array of mask m up to L[limit], with L[i] = GfnDouble(L[i-1])
+func (m *mask) extendTable(limit int) {
+ for i := len(m.L); i <= limit; i++ {
+ m.L = append(m.L, byteutil.GfnDouble(m.L[i-1]))
+ }
+}
+
+func ocbError(err string) error {
+ return errors.New("crypto/ocb: " + err)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/ocb/random_vectors.go b/vendor/github.com/ProtonMail/go-crypto/ocb/random_vectors.go
new file mode 100644
index 0000000000..0efaf344fd
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/ocb/random_vectors.go
@@ -0,0 +1,136 @@
+// In the test vectors provided by RFC 7253, the "bottom"
+// internal variable, which defines "offset" for the first time, does not
+// exceed 15. However, it can attain values up to 63.
+
+// These vectors include key length in {128, 192, 256}, tag size 128, and
+// random nonce, header, and plaintext lengths.
+
+// This file was automatically generated.
+
+package ocb
+
+var randomVectors = []struct {
+ key, nonce, header, plaintext, ciphertext string
+}{
+
+ {"9438C5D599308EAF13F800D2D31EA7F0",
+ "C38EE4801BEBFFA1CD8635BE",
+ "0E507B7DADD8A98CDFE272D3CB6B3E8332B56AE583FB049C0874D4200BED16BD1A044182434E9DA0E841F182DFD5B3016B34641CED0784F1745F63AB3D0DA22D3351C9EF9A658B8081E24498EBF61FCE40DA6D8E184536",
+ "962D227786FB8913A8BAD5DC3250",
+ "EEDEF5FFA5986D1E3BF86DDD33EF9ADC79DCA06E215FA772CCBA814F63AD"},
+ {"BA7DE631C7D6712167C6724F5B9A2B1D",
+ "35263EBDA05765DC0E71F1F5",
+ "0103257B4224507C0242FEFE821EA7FA42E0A82863E5F8B68F7D881B4B44FA428A2B6B21D2F591260802D8AB6D83",
+ "9D6D1FC93AE8A64E7889B7B2E3521EFA9B920A8DDB692E6F833DDC4A38AFA535E5E2A3ED82CB7E26404AB86C54D01C4668F28398C2DF33D5D561CBA1C8DCFA7A912F5048E545B59483C0E3221F54B14DAA2E4EB657B3BEF9554F34CAD69B2724AE962D3D8A",
+ "E93852D1985C5E775655E937FA79CE5BF28A585F2AF53A5018853B9634BE3C84499AC0081918FDCE0624494D60E25F76ACD6853AC7576E3C350F332249BFCABD4E73CEABC36BE4EDDA40914E598AE74174A0D7442149B26990899491BDDFE8FC54D6C18E83AE9E9A6FFBF5D376565633862EEAD88D"},
+ {"2E74B25289F6FD3E578C24866E9C72A5",
+ "FD912F15025AF8414642BA1D1D",
+ "FB5FB8C26F365EEDAB5FE260C6E3CCD27806729C8335F146063A7F9EA93290E56CF84576EB446350D22AD730547C267B1F0BBB97EB34E1E2C41A",
+ "6C092EBF78F76EE8C1C6E592277D9545BA16EDB67BC7D8480B9827702DC2F8A129E2B08A2CE710CA7E1DA45CE162BB6CD4B512E632116E2211D3C90871EFB06B8D4B902681C7FB",
+ "6AC0A77F26531BF4F354A1737F99E49BE32ECD909A7A71AD69352906F54B08A9CE9B8CA5D724CBFFC5673437F23F630697F3B84117A1431D6FA8CC13A974FB4AD360300522E09511B99E71065D5AC4BBCB1D791E864EF4"},
+ {"E7EC507C802528F790AFF5303A017B17",
+ "4B97A7A568940A9E3CE7A99E93031E",
+ "28349BDC5A09390C480F9B8AA3EDEA3DDB8B9D64BCA322C570B8225DF0E31190DAB25A4014BA39519E02ABFB12B89AA28BBFD29E486E7FB28734258C817B63CED9912DBAFEBB93E2798AB2890DE3B0ACFCFF906AB15563EF7823CE83D27CDB251195E22BD1337BCBDE65E7C2C427321C463C2777BFE5AEAA",
+ "9455B3EA706B74",
+ "7F33BA3EA848D48A96B9530E26888F43EBD4463C9399B6"},
+ {"6C928AA3224736F28EE7378DE0090191",
+ "8936138E2E4C6A13280017A1622D",
+ "6202717F2631565BDCDC57C6584543E72A7C8BD444D0D108ED35069819633C",
+ "DA0691439E5F035F3E455269D14FE5C201C8C9B0A3FE2D3F86BCC59387C868FE65733D388360B31E3CE28B4BF6A8BE636706B536D5720DB66B47CF1C7A5AFD6F61E0EF90F1726D6B0E169F9A768B2B7AE4EE00A17F630AC905FCAAA1B707FFF25B3A1AAE83B504837C64A5639B2A34002B300EC035C9B43654DA55",
+ "B8804D182AB0F0EEB464FA7BD1329AD6154F982013F3765FEDFE09E26DAC078C9C1439BFC1159D6C02A25E3FF83EF852570117B315852AD5EE20E0FA3AA0A626B0E43BC0CEA38B44579DD36803455FB46989B90E6D229F513FD727AF8372517E9488384C515D6067704119C931299A0982EDDFB9C2E86A90C450C077EB222511EC9CCABC9FCFDB19F70088"},
+ {"ECEA315CA4B3F425B0C9957A17805EA4",
+ "664CDAE18403F4F9BA13015A44FC",
+ "642AFB090D6C6DB46783F08B01A3EF2A8FEB5736B531EAC226E7888FCC8505F396818F83105065FACB3267485B9E5E4A0261F621041C08FCCB2A809A49AB5252A91D0971BCC620B9D614BD77E57A0EED2FA5",
+ "6852C31F8083E20E364CEA21BB7854D67CEE812FE1C9ED2425C0932A90D3780728D1BB",
+ "2ECEF962A9695A463ADABB275BDA9FF8B2BA57AEC2F52EFFB700CD9271A74D2A011C24AEA946051BD6291776429B7E681BA33E"},
+ {"4EE616C4A58AAA380878F71A373461F6",
+ "91B8C9C176D9C385E9C47E52",
+ "CDA440B7F9762C572A718AC754EDEECC119E5EE0CCB9FEA4FFB22EEE75087C032EBF3DA9CDD8A28CC010B99ED45143B41A4BA50EA2A005473F89639237838867A57F23B0F0ED3BF22490E4501DAC9C658A9B9F",
+ "D6E645FA9AE410D15B8123FD757FA356A8DBE9258DDB5BE88832E615910993F497EC",
+ "B70ED7BF959FB2AAED4F36174A2A99BFB16992C8CDF369C782C4DB9C73DE78C5DB8E0615F647243B97ACDB24503BC9CADC48"},
+ {"DCD475773136C830D5E3D0C5FE05B7FF",
+ "BB8E1FBB483BE7616A922C4A",
+ "36FEF2E1CB29E76A6EA663FC3AF66ECD7404F466382F7B040AABED62293302B56E8783EF7EBC21B4A16C3E78A7483A0A403F253A2CDC5BBF79DC3DAE6C73F39A961D8FBBE8D41B",
+ "441E886EA38322B2437ECA7DEB5282518865A66780A454E510878E61BFEC3106A3CD93D2A02052E6F9E1832F9791053E3B76BF4C07EFDD6D4106E3027FABB752E60C1AA425416A87D53938163817A1051EBA1D1DEEB4B9B25C7E97368B52E5911A31810B0EC5AF547559B6142D9F4C4A6EF24A4CF75271BF9D48F62B",
+ "1BE4DD2F4E25A6512C2CC71D24BBB07368589A94C2714962CD0ACE5605688F06342587521E75F0ACAFFD86212FB5C34327D238DB36CF2B787794B9A4412E7CD1410EA5DDD2450C265F29CF96013CD213FD2880657694D718558964BC189B4A84AFCF47EB012935483052399DBA5B088B0A0477F20DFE0E85DCB735E21F22A439FB837DD365A93116D063E607"},
+ {"3FBA2B3D30177FFE15C1C59ED2148BB2C091F5615FBA7C07",
+ "FACF804A4BEBF998505FF9DE",
+ "8213B9263B2971A5BDA18DBD02208EE1",
+ "15B323926993B326EA19F892D704439FC478828322AF72118748284A1FD8A6D814E641F70512FD706980337379F31DC63355974738D7FEA87AD2858C0C2EBBFBE74371C21450072373C7B651B334D7C4D43260B9D7CCD3AF9EDB",
+ "6D35DC1469B26E6AAB26272A41B46916397C24C485B61162E640A062D9275BC33DDCFD3D9E1A53B6C8F51AC89B66A41D59B3574197A40D9B6DCF8A4E2A001409C8112F16B9C389E0096179DB914E05D6D11ED0005AD17E1CE105A2F0BAB8F6B1540DEB968B7A5428FF44"},
+ {"53B52B8D4D748BCDF1DDE68857832FA46227FA6E2F32EFA1",
+ "0B0EF53D4606B28D1398355F",
+ "F23882436349094AF98BCACA8218E81581A043B19009E28EFBF2DE37883E04864148CC01D240552CA8844EC1456F42034653067DA67E80F87105FD06E14FF771246C9612867BE4D215F6D761",
+ "F15030679BD4088D42CAC9BF2E9606EAD4798782FA3ED8C57EBE7F84A53236F51B25967C6489D0CD20C9EEA752F9BC",
+ "67B96E2D67C3729C96DAEAEDF821D61C17E648643A2134C5621FEC621186915AD80864BFD1EB5B238BF526A679385E012A457F583AFA78134242E9D9C1B4E4"},
+ {"0272DD80F23399F49BFC320381A5CD8225867245A49A7D41",
+ "5C83F4896D0738E1366B1836",
+ "69B0337289B19F73A12BAEEA857CCAF396C11113715D9500CCCF48BA08CFF12BC8B4BADB3084E63B85719DB5058FA7C2C11DEB096D7943CFA7CAF5",
+ "C01AD10FC8B562CD17C7BC2FAB3E26CBDFF8D7F4DEA816794BBCC12336991712972F52816AABAB244EB43B0137E2BAC1DD413CE79531E78BEF782E6B439612BB3AEF154DE3502784F287958EBC159419F9EBA27916A28D6307324129F506B1DE80C1755A929F87",
+ "FEFE52DD7159C8DD6E8EC2D3D3C0F37AB6CB471A75A071D17EC4ACDD8F3AA4D7D4F7BB559F3C09099E3D9003E5E8AA1F556B79CECDE66F85B08FA5955E6976BF2695EA076388A62D2AD5BAB7CBF1A7F3F4C8D5CDF37CDE99BD3E30B685D9E5EEE48C7C89118EF4878EB89747F28271FA2CC45F8E9E7601"},
+ {"3EEAED04A455D6E5E5AB53CFD5AFD2F2BC625C7BF4BE49A5",
+ "36B88F63ADBB5668588181D774",
+ "D367E3CB3703E762D23C6533188EF7028EFF9D935A3977150361997EC9DEAF1E4794BDE26AA8B53C124980B1362EC86FCDDFC7A90073171C1BAEE351A53234B86C66E8AB92FAE99EC6967A6D3428892D80",
+ "573454C719A9A55E04437BF7CBAAF27563CCCD92ADD5E515CD63305DFF0687E5EEF790C5DCA5C0033E9AB129505E2775438D92B38F08F3B0356BA142C6F694",
+ "E9F79A5B432D9E682C9AAA5661CFC2E49A0FCB81A431E54B42EB73DD3BED3F377FEC556ABA81624BA64A5D739AD41467460088F8D4F442180A9382CA635745473794C382FCDDC49BA4EB6D8A44AE3C"},
+ {"B695C691538F8CBD60F039D0E28894E3693CC7C36D92D79D",
+ "BC099AEB637361BAC536B57618",
+ "BFFF1A65AE38D1DC142C71637319F5F6508E2CB33C9DCB94202B359ED5A5ED8042E7F4F09231D32A7242976677E6F4C549BF65FADC99E5AF43F7A46FD95E16C2",
+ "081DF3FD85B415D803F0BE5AC58CFF0023FDDED99788296C3731D8",
+ "E50C64E3614D94FE69C47092E46ACC9957C6FEA2CCBF96BC62FBABE7424753C75F9C147C42AE26FE171531"},
+ {"C9ACBD2718F0689A1BE9802A551B6B8D9CF5614DAF5E65ED",
+ "B1B0AAF373B8B026EB80422051D8",
+ "6648C0E61AC733C76119D23FB24548D637751387AA2EAE9D80E912B7BD486CAAD9EAF4D7A5FE2B54AAD481E8EC94BB4D558000896E2010462B70C9FED1E7273080D1",
+ "189F591F6CB6D59AFEDD14C341741A8F1037DC0DF00FC57CE65C30F49E860255CEA5DC6019380CC0FE8880BC1A9E685F41C239C38F36E3F2A1388865C5C311059C0A",
+ "922A5E949B61D03BE34AB5F4E58607D4504EA14017BB363DAE3C873059EA7A1C77A746FB78981671D26C2CF6D9F24952D510044CE02A10177E9DB42D0145211DFE6E84369C5E3BC2669EAB4147B2822895F9"},
+ {"7A832BD2CF5BF4919F353CE2A8C86A5E406DA2D52BE16A72",
+ "2F2F17CECF7E5A756D10785A3CB9DB",
+ "61DA05E3788CC2D8405DBA70C7A28E5AF699863C9F72E6C6770126929F5D6FA267F005EBCF49495CB46400958A3AE80D1289D1C671",
+ "44E91121195A41AF14E8CFDBD39A4B517BE0DF1A72977ED8A3EEF8EEDA1166B2EB6DB2C4AE2E74FA0F0C74537F659BFBD141E5DDEC67E64EDA85AABD3F52C85A785B9FB3CECD70E7DF",
+ "BEDF596EA21288D2B84901E188F6EE1468B14D5161D3802DBFE00D60203A24E2AB62714BF272A45551489838C3A7FEAADC177B591836E73684867CCF4E12901DCF2064058726BBA554E84ADC5136F507E961188D4AF06943D3"},
+ {"1508E8AE9079AA15F1CEC4F776B4D11BCCB061B58AA56C18",
+ "BCA625674F41D1E3AB47672DC0C3",
+ "8B12CF84F16360F0EAD2A41BC021530FFCEC7F3579CAE658E10E2D3D81870F65AFCED0C77C6C4C6E6BA424FF23088C796BA6195ABA35094BF1829E089662E7A95FC90750AE16D0C8AFA55DAC789D7735B970B58D4BE7CEC7341DA82A0179A01929C27A59C5063215B859EA43",
+ "E525422519ECE070E82C",
+ "B47BC07C3ED1C0A43BA52C43CBACBCDBB29CAF1001E09FDF7107"},
+ {"7550C2761644E911FE9ADD119BAC07376BEA442845FEAD876D7E7AC1B713E464",
+ "36D2EC25ADD33CDEDF495205BBC923",
+ "7FCFE81A3790DE97FFC3DE160C470847EA7E841177C2F759571CBD837EA004A6CA8C6F4AEBFF2E9FD552D73EB8A30705D58D70C0B67AEEA280CBBF0A477358ACEF1E7508F2735CD9A0E4F9AC92B8C008F575D3B6278F1C18BD01227E3502E5255F3AB1893632AD00C717C588EF652A51A43209E7EE90",
+ "2B1A62F8FDFAA3C16470A21AD307C9A7D03ADE8EF72C69B06F8D738CDE578D7AEFD0D40BD9C022FB9F580DF5394C998ACCCEFC5471A3996FB8F1045A81FDC6F32D13502EA65A211390C8D882B8E0BEFD8DD8CBEF51D1597B124E9F7F",
+ "C873E02A22DB89EB0787DB6A60B99F7E4A0A085D5C4232A81ADCE2D60AA36F92DDC33F93DD8640AC0E08416B187FB382B3EC3EE85A64B0E6EE41C1366A5AD2A282F66605E87031CCBA2FA7B2DA201D975994AADE3DD1EE122AE09604AD489B84BF0C1AB7129EE16C6934850E"},
+ {"A51300285E554FDBDE7F771A9A9A80955639DD87129FAEF74987C91FB9687C71",
+ "81691D5D20EC818FCFF24B33DECC",
+ "C948093218AA9EB2A8E44A87EEA73FC8B6B75A196819A14BD83709EA323E8DF8B491045220E1D88729A38DBCFFB60D3056DAD4564498FD6574F74512945DEB34B69329ACED9FFC05D5D59DFCD5B973E2ACAFE6AD1EF8BBBC49351A2DD12508ED89ED",
+ "EB861165DAF7625F827C6B574ED703F03215",
+ "C6CD1CE76D2B3679C1B5AA1CFD67CCB55444B6BFD3E22C81CBC9BB738796B83E54E3"},
+ {"8CE0156D26FAEB7E0B9B800BBB2E9D4075B5EAC5C62358B0E7F6FCE610223282",
+ "D2A7B94DD12CDACA909D3AD7",
+ "E021A78F374FC271389AB9A3E97077D755",
+ "7C26000B58929F5095E1CEE154F76C2A299248E299F9B5ADE6C403AA1FD4A67FD4E0232F214CE7B919EE7A1027D2B76C57475715CD078461",
+ "C556FB38DF069B56F337B5FF5775CE6EAA16824DFA754F20B78819028EA635C3BB7AA731DE8776B2DCB67DCA2D33EEDF3C7E52EA450013722A41755A0752433ED17BDD5991AAE77A"},
+ {"1E8000A2CE00A561C9920A30BF0D7B983FEF8A1014C8F04C35CA6970E6BA02BD",
+ "65ED3D63F79F90BBFD19775E",
+ "336A8C0B7243582A46B221AA677647FCAE91",
+ "134A8B34824A290E7B",
+ "914FBEF80D0E6E17F8BDBB6097EBF5FBB0554952DC2B9E5151"},
+ {"53D5607BBE690B6E8D8F6D97F3DF2BA853B682597A214B8AA0EA6E598650AF15",
+ "C391A856B9FE234E14BA1AC7BB40FF",
+ "479682BC21349C4BE1641D5E78FE2C79EC1B9CF5470936DCAD9967A4DCD7C4EFADA593BC9EDE71E6A08829B8580901B61E274227E9D918502DE3",
+ "EAD154DC09C5E26C5D26FF33ED148B27120C7F2C23225CC0D0631B03E1F6C6D96FEB88C1A4052ACB4CE746B884B6502931F407021126C6AAB8C514C077A5A38438AE88EE",
+ "938821286EBB671D999B87C032E1D6055392EB564E57970D55E545FC5E8BAB90E6E3E3C0913F6320995FC636D72CD9919657CC38BD51552F4A502D8D1FE56DB33EBAC5092630E69EBB986F0E15CEE9FC8C052501"},
+ {"294362FCC984F440CEA3E9F7D2C06AF20C53AAC1B3738CA2186C914A6E193ABB",
+ "B15B61C8BB39261A8F55AB178EC3",
+ "D0729B6B75BB",
+ "2BD089ADCE9F334BAE3B065996C7D616DD0C27DF4218DCEEA0FBCA0F968837CE26B0876083327E25681FDDD620A32EC0DA12F73FAE826CC94BFF2B90A54D2651",
+ "AC94B25E4E21DE2437B806966CCD5D9385EF0CD4A51AB9FA6DE675C7B8952D67802E9FEC1FDE9F5D1EAB06057498BC0EEA454804FC9D2068982A3E24182D9AC2E7AB9994DDC899A604264583F63D066B"},
+ {"959DBFEB039B1A5B8CE6A44649B602AAA5F98A906DB96143D202CD2024F749D9",
+ "01D7BDB1133E9C347486C1EFA6",
+ "F3843955BD741F379DD750585EDC55E2CDA05CCBA8C1F4622AC2FE35214BC3A019B8BD12C4CC42D9213D1E1556941E8D8450830287FFB3B763A13722DD4140ED9846FB5FFF745D7B0B967D810A068222E10B259AF1D392035B0D83DC1498A6830B11B2418A840212599171E0258A1C203B05362978",
+ "A21811232C950FA8B12237C2EBD6A7CD2C3A155905E9E0C7C120",
+ "63C1CE397B22F1A03F1FA549B43178BC405B152D3C95E977426D519B3DFCA28498823240592B6EEE7A14"},
+ {"096AE499F5294173F34FF2B375F0E5D5AB79D0D03B33B1A74D7D576826345DF4",
+ "0C52B3D11D636E5910A4DD76D32C",
+ "229E9ECA3053789E937447BC719467075B6138A142DA528DA8F0CF8DDF022FD9AF8E74779BA3AC306609",
+ "8B7A00038783E8BAF6EDEAE0C4EAB48FC8FD501A588C7E4A4DB71E3604F2155A97687D3D2FFF8569261375A513CF4398CE0F87CA1658A1050F6EF6C4EA3E25",
+ "C20B6CF8D3C8241825FD90B2EDAC7593600646E579A8D8DAAE9E2E40C3835FE801B2BE4379131452BC5182C90307B176DFBE2049544222FE7783147B690774F6D9D7CEF52A91E61E298E9AA15464AC"},
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_a.go b/vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_a.go
new file mode 100644
index 0000000000..330309ff5f
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_a.go
@@ -0,0 +1,78 @@
+package ocb
+
+import (
+ "encoding/hex"
+)
+
+// Test vectors from https://tools.ietf.org/html/rfc7253. Note that key is
+// shared across tests.
+var testKey, _ = hex.DecodeString("000102030405060708090A0B0C0D0E0F")
+
+var rfc7253testVectors = []struct {
+ nonce, header, plaintext, ciphertext string
+}{
+ {"BBAA99887766554433221100",
+ "",
+ "",
+ "785407BFFFC8AD9EDCC5520AC9111EE6"},
+ {"BBAA99887766554433221101",
+ "0001020304050607",
+ "0001020304050607",
+ "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009"},
+ {"BBAA99887766554433221102",
+ "0001020304050607",
+ "",
+ "81017F8203F081277152FADE694A0A00"},
+ {"BBAA99887766554433221103",
+ "",
+ "0001020304050607",
+ "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9"},
+ {"BBAA99887766554433221104",
+ "000102030405060708090A0B0C0D0E0F",
+ "000102030405060708090A0B0C0D0E0F",
+ "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5701C1CCEC8FC3358"},
+ {"BBAA99887766554433221105",
+ "000102030405060708090A0B0C0D0E0F",
+ "",
+ "8CF761B6902EF764462AD86498CA6B97"},
+ {"BBAA99887766554433221106",
+ "",
+ "000102030405060708090A0B0C0D0E0F",
+ "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436BDF06D8FA1ECA343D"},
+ {"BBAA99887766554433221107",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "1CA2207308C87C010756104D8840CE1952F09673A448A122C92C62241051F57356D7F3C90BB0E07F"},
+ {"BBAA99887766554433221108",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "",
+ "6DC225A071FC1B9F7C69F93B0F1E10DE"},
+ {"BBAA99887766554433221109",
+ "",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3CE725F32494B9F914D85C0B1EB38357FF"},
+ {"BBAA9988776655443322110A",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+ "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DEAFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240"},
+ {"BBAA9988776655443322110B",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+ "",
+ "FE80690BEE8A485D11F32965BC9D2A32"},
+ {"BBAA9988776655443322110C",
+ "",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+ "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF46040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF"},
+ {"BBAA9988776655443322110D",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+ "D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483A7035490C5769E60"},
+ {"BBAA9988776655443322110E",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+ "",
+ "C5CD9D1850C141E358649994EE701B68"},
+ {"BBAA9988776655443322110F",
+ "",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+ "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95A98CA5F3000B1479"},
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go b/vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go
new file mode 100644
index 0000000000..14a3c336fb
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go
@@ -0,0 +1,25 @@
+package ocb
+
+// Second set of test vectors from https://tools.ietf.org/html/rfc7253
+var rfc7253TestVectorTaglen96 = struct {
+ key, nonce, header, plaintext, ciphertext string
+}{"0F0E0D0C0B0A09080706050403020100",
+ "BBAA9988776655443322110D",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+ "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FDAC4F02AA"}
+
+var rfc7253AlgorithmTest = []struct {
+ KEYLEN, TAGLEN int
+ OUTPUT string
+}{
+ {128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"},
+ {192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"},
+ {256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"},
+ {128, 96, "77A3D8E73589158D25D01209"},
+ {192, 96, "05D56EAD2752C86BE6932C5E"},
+ {256, 96, "5458359AC23B0CBA9E6330DD"},
+ {128, 64, "192C9B7BD90BA06A"},
+ {192, 64, "0066BC6E0EF34E24"},
+ {256, 64, "7D4EA5D445501CBE"},
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go
new file mode 100644
index 0000000000..3c6251d1ce
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go
@@ -0,0 +1,153 @@
+// Copyright 2014 Matthew Endsley
+// All rights reserved
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted providing that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+// Package keywrap is an implementation of the RFC 3394 AES key wrapping
+// algorithm. This is used in OpenPGP with elliptic curve keys.
+package keywrap
+
+import (
+ "crypto/aes"
+ "encoding/binary"
+ "errors"
+)
+
+var (
+ // ErrWrapPlaintext is returned if the plaintext is not a multiple
+ // of 64 bits.
+ ErrWrapPlaintext = errors.New("keywrap: plainText must be a multiple of 64 bits")
+
+ // ErrUnwrapCiphertext is returned if the ciphertext is not a
+ // multiple of 64 bits.
+ ErrUnwrapCiphertext = errors.New("keywrap: cipherText must by a multiple of 64 bits")
+
+ // ErrUnwrapFailed is returned if unwrapping a key fails.
+ ErrUnwrapFailed = errors.New("keywrap: failed to unwrap key")
+
+ // NB: the AES NewCipher call only fails if the key is an invalid length.
+
+ // ErrInvalidKey is returned when the AES key is invalid.
+ ErrInvalidKey = errors.New("keywrap: invalid AES key")
+)
+
+// Wrap a key using the RFC 3394 AES Key Wrap Algorithm.
+func Wrap(key, plainText []byte) ([]byte, error) {
+ if len(plainText)%8 != 0 {
+ return nil, ErrWrapPlaintext
+ }
+
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, ErrInvalidKey
+ }
+
+ nblocks := len(plainText) / 8
+
+ // 1) Initialize variables.
+ var block [aes.BlockSize]byte
+ // - Set A = IV, an initial value (see 2.2.3)
+ for ii := 0; ii < 8; ii++ {
+ block[ii] = 0xA6
+ }
+
+ // - For i = 1 to n
+ // - Set R[i] = P[i]
+ intermediate := make([]byte, len(plainText))
+ copy(intermediate, plainText)
+
+ // 2) Calculate intermediate values.
+ for ii := 0; ii < 6; ii++ {
+ for jj := 0; jj < nblocks; jj++ {
+ // - B = AES(K, A | R[i])
+ copy(block[8:], intermediate[jj*8:jj*8+8])
+ c.Encrypt(block[:], block[:])
+
+ // - A = MSB(64, B) ^ t where t = (n*j)+1
+ t := uint64(ii*nblocks + jj + 1)
+ val := binary.BigEndian.Uint64(block[:8]) ^ t
+ binary.BigEndian.PutUint64(block[:8], val)
+
+ // - R[i] = LSB(64, B)
+ copy(intermediate[jj*8:jj*8+8], block[8:])
+ }
+ }
+
+ // 3) Output results.
+ // - Set C[0] = A
+ // - For i = 1 to n
+ // - C[i] = R[i]
+ return append(block[:8], intermediate...), nil
+}
+
+// Unwrap a key using the RFC 3394 AES Key Wrap Algorithm.
+func Unwrap(key, cipherText []byte) ([]byte, error) {
+ if len(cipherText)%8 != 0 {
+ return nil, ErrUnwrapCiphertext
+ }
+
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, ErrInvalidKey
+ }
+
+ nblocks := len(cipherText)/8 - 1
+
+ // 1) Initialize variables.
+ var block [aes.BlockSize]byte
+ // - Set A = C[0]
+ copy(block[:8], cipherText[:8])
+
+ // - For i = 1 to n
+ // - Set R[i] = C[i]
+ intermediate := make([]byte, len(cipherText)-8)
+ copy(intermediate, cipherText[8:])
+
+ // 2) Compute intermediate values.
+ for jj := 5; jj >= 0; jj-- {
+ for ii := nblocks - 1; ii >= 0; ii-- {
+ // - B = AES-1(K, (A ^ t) | R[i]) where t = n*j+1
+ // - A = MSB(64, B)
+ t := uint64(jj*nblocks + ii + 1)
+ val := binary.BigEndian.Uint64(block[:8]) ^ t
+ binary.BigEndian.PutUint64(block[:8], val)
+
+ copy(block[8:], intermediate[ii*8:ii*8+8])
+ c.Decrypt(block[:], block[:])
+
+ // - R[i] = LSB(B, 64)
+ copy(intermediate[ii*8:ii*8+8], block[8:])
+ }
+ }
+
+ // 3) Output results.
+ // - If A is an appropriate initial value (see 2.2.3),
+ for ii := 0; ii < 8; ii++ {
+ if block[ii] != 0xA6 {
+ return nil, ErrUnwrapFailed
+ }
+ }
+
+ // - For i = 1 to n
+ // - P[i] = R[i]
+ return intermediate, nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
new file mode 100644
index 0000000000..e0a677f284
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
@@ -0,0 +1,183 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
+// very similar to PEM except that it has an additional CRC checksum.
+package armor // import "github.com/ProtonMail/go-crypto/openpgp/armor"
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+// A Block represents an OpenPGP armored structure.
+//
+// The encoded form is:
+//
+// -----BEGIN Type-----
+// Headers
+//
+// base64-encoded Bytes
+// '=' base64 encoded checksum (optional) not checked anymore
+// -----END Type-----
+//
+// where Headers is a possibly empty sequence of Key: Value lines.
+//
+// Since the armored data can be very large, this package presents a streaming
+// interface.
+type Block struct {
+ Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
+ Header map[string]string // Optional headers.
+ Body io.Reader // A Reader from which the contents can be read
+ lReader lineReader
+ oReader openpgpReader
+}
+
+var ArmorCorrupt error = errors.StructuralError("armor invalid")
+
+var armorStart = []byte("-----BEGIN ")
+var armorEnd = []byte("-----END ")
+var armorEndOfLine = []byte("-----")
+
+// lineReader wraps a line based reader. It watches for the end of an armor block
+type lineReader struct {
+ in *bufio.Reader
+ buf []byte
+ eof bool
+}
+
+func (l *lineReader) Read(p []byte) (n int, err error) {
+ if l.eof {
+ return 0, io.EOF
+ }
+
+ if len(l.buf) > 0 {
+ n = copy(p, l.buf)
+ l.buf = l.buf[n:]
+ return
+ }
+
+ line, isPrefix, err := l.in.ReadLine()
+ if err != nil {
+ return
+ }
+ if isPrefix {
+ return 0, ArmorCorrupt
+ }
+
+ if bytes.HasPrefix(line, armorEnd) {
+ l.eof = true
+ return 0, io.EOF
+ }
+
+ if len(line) == 5 && line[0] == '=' {
+ // This is the checksum line
+ // Don't check the checksum
+
+ l.eof = true
+ return 0, io.EOF
+ }
+
+ if len(line) > 96 {
+ return 0, ArmorCorrupt
+ }
+
+ n = copy(p, line)
+ bytesToSave := len(line) - n
+ if bytesToSave > 0 {
+ if cap(l.buf) < bytesToSave {
+ l.buf = make([]byte, 0, bytesToSave)
+ }
+ l.buf = l.buf[0:bytesToSave]
+ copy(l.buf, line[n:])
+ }
+
+ return
+}
+
+// openpgpReader passes Read calls to the underlying base64 decoder.
+type openpgpReader struct {
+ lReader *lineReader
+ b64Reader io.Reader
+}
+
+func (r *openpgpReader) Read(p []byte) (n int, err error) {
+ n, err = r.b64Reader.Read(p)
+ return
+}
+
+// Decode reads a PGP armored block from the given Reader. It will ignore
+// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The
+// given Reader is not usable after calling this function: an arbitrary amount
+// of data may have been read past the end of the block.
+func Decode(in io.Reader) (p *Block, err error) {
+ r := bufio.NewReaderSize(in, 100)
+ var line []byte
+ ignoreNext := false
+
+TryNextBlock:
+ p = nil
+
+ // Skip leading garbage
+ for {
+ ignoreThis := ignoreNext
+ line, ignoreNext, err = r.ReadLine()
+ if err != nil {
+ return
+ }
+ if ignoreNext || ignoreThis {
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
+ break
+ }
+ }
+
+ p = new(Block)
+ p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
+ p.Header = make(map[string]string)
+ nextIsContinuation := false
+ var lastKey string
+
+ // Read headers
+ for {
+ isContinuation := nextIsContinuation
+ line, nextIsContinuation, err = r.ReadLine()
+ if err != nil {
+ p = nil
+ return
+ }
+ if isContinuation {
+ p.Header[lastKey] += string(line)
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 {
+ break
+ }
+
+ i := bytes.Index(line, []byte(":"))
+ if i == -1 {
+ goto TryNextBlock
+ }
+ lastKey = string(line[:i])
+ var value string
+ if len(line) > i+2 {
+ value = string(line[i+2:])
+ }
+ p.Header[lastKey] = value
+ }
+
+ p.lReader.in = r
+ p.oReader.lReader = &p.lReader
+ p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
+ p.Body = &p.oReader
+
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go
new file mode 100644
index 0000000000..550efddf05
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go
@@ -0,0 +1,206 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "encoding/base64"
+ "io"
+ "sort"
+)
+
+var armorHeaderSep = []byte(": ")
+var blockEnd = []byte("\n=")
+var newline = []byte("\n")
+var armorEndOfLineOut = []byte("-----\n")
+
+const crc24Init = 0xb704ce
+const crc24Poly = 0x1864cfb
+
+// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
+func crc24(crc uint32, d []byte) uint32 {
+ for _, b := range d {
+ crc ^= uint32(b) << 16
+ for i := 0; i < 8; i++ {
+ crc <<= 1
+ if crc&0x1000000 != 0 {
+ crc ^= crc24Poly
+ }
+ }
+ }
+ return crc
+}
+
+// writeSlices writes its arguments to the given Writer.
+func writeSlices(out io.Writer, slices ...[]byte) (err error) {
+ for _, s := range slices {
+ _, err = out.Write(s)
+ if err != nil {
+ return err
+ }
+ }
+ return
+}
+
+// lineBreaker breaks data across several lines, all of the same byte length
+// (except possibly the last). Lines are broken with a single '\n'.
+type lineBreaker struct {
+ lineLength int
+ line []byte
+ used int
+ out io.Writer
+ haveWritten bool
+}
+
+func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
+ return &lineBreaker{
+ lineLength: lineLength,
+ line: make([]byte, lineLength),
+ used: 0,
+ out: out,
+ }
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err error) {
+ n = len(b)
+
+ if n == 0 {
+ return
+ }
+
+ if l.used == 0 && l.haveWritten {
+ _, err = l.out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+ }
+
+ if l.used+len(b) < l.lineLength {
+ l.used += copy(l.line[l.used:], b)
+ return
+ }
+
+ l.haveWritten = true
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ excess := l.lineLength - l.used
+ l.used = 0
+
+ _, err = l.out.Write(b[0:excess])
+ if err != nil {
+ return
+ }
+
+ _, err = l.Write(b[excess:])
+ return
+}
+
+func (l *lineBreaker) Close() (err error) {
+ if l.used > 0 {
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+// encoding keeps track of a running CRC24 over the data which has been written
+// to it and outputs a OpenPGP checksum when closed, followed by an armor
+// trailer.
+//
+// It's built into a stack of io.Writers:
+//
+// encoding -> base64 encoder -> lineBreaker -> out
+type encoding struct {
+ out io.Writer
+ breaker *lineBreaker
+ b64 io.WriteCloser
+ crc uint32
+ crcEnabled bool
+ blockType []byte
+}
+
+func (e *encoding) Write(data []byte) (n int, err error) {
+ if e.crcEnabled {
+ e.crc = crc24(e.crc, data)
+ }
+ return e.b64.Write(data)
+}
+
+func (e *encoding) Close() (err error) {
+ err = e.b64.Close()
+ if err != nil {
+ return
+ }
+ e.breaker.Close()
+
+ if e.crcEnabled {
+ var checksumBytes [3]byte
+ checksumBytes[0] = byte(e.crc >> 16)
+ checksumBytes[1] = byte(e.crc >> 8)
+ checksumBytes[2] = byte(e.crc)
+
+ var b64ChecksumBytes [4]byte
+ base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
+
+ return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
+ }
+ return writeSlices(e.out, newline, armorEnd, e.blockType, armorEndOfLine)
+}
+
+func encode(out io.Writer, blockType string, headers map[string]string, checksum bool) (w io.WriteCloser, err error) {
+ bType := []byte(blockType)
+ err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
+ if err != nil {
+ return
+ }
+
+ keys := make([]string, len(headers))
+ i := 0
+ for k := range headers {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ err = writeSlices(out, []byte(k), armorHeaderSep, []byte(headers[k]), newline)
+ if err != nil {
+ return
+ }
+ }
+
+ _, err = out.Write(newline)
+ if err != nil {
+ return
+ }
+
+ e := &encoding{
+ out: out,
+ breaker: newLineBreaker(out, 64),
+ blockType: bType,
+ crc: crc24Init,
+ crcEnabled: checksum,
+ }
+ e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
+ return e, nil
+}
+
+// Encode returns a WriteCloser which will encode the data written to it in
+// OpenPGP armor.
+func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
+ return encode(out, blockType, headers, true)
+}
+
+// EncodeWithChecksumOption returns a WriteCloser which will encode the data written to it in
+// OpenPGP armor and provides the option to include a checksum.
+// When forming ASCII Armor, the CRC24 footer SHOULD NOT be generated,
+// unless interoperability with implementations that require the CRC24 footer
+// to be present is a concern.
+func EncodeWithChecksumOption(out io.Writer, blockType string, headers map[string]string, doChecksum bool) (w io.WriteCloser, err error) {
+ return encode(out, blockType, headers, doChecksum)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go
new file mode 100644
index 0000000000..5b40e1375d
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go
@@ -0,0 +1,71 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "hash"
+ "io"
+)
+
+// NewCanonicalTextHash reformats text written to it into the canonical
+// form and then applies the hash h. See RFC 4880, section 5.2.1.
+func NewCanonicalTextHash(h hash.Hash) hash.Hash {
+ return &canonicalTextHash{h, 0}
+}
+
+type canonicalTextHash struct {
+ h hash.Hash
+ s int
+}
+
+var newline = []byte{'\r', '\n'}
+
+func writeCanonical(cw io.Writer, buf []byte, s *int) (int, error) {
+ start := 0
+ for i, c := range buf {
+ switch *s {
+ case 0:
+ if c == '\r' {
+ *s = 1
+ } else if c == '\n' {
+ if _, err := cw.Write(buf[start:i]); err != nil {
+ return 0, err
+ }
+ if _, err := cw.Write(newline); err != nil {
+ return 0, err
+ }
+ start = i + 1
+ }
+ case 1:
+ *s = 0
+ }
+ }
+
+ if _, err := cw.Write(buf[start:]); err != nil {
+ return 0, err
+ }
+ return len(buf), nil
+}
+
+func (cth *canonicalTextHash) Write(buf []byte) (int, error) {
+ return writeCanonical(cth.h, buf, &cth.s)
+}
+
+func (cth *canonicalTextHash) Sum(in []byte) []byte {
+ return cth.h.Sum(in)
+}
+
+func (cth *canonicalTextHash) Reset() {
+ cth.h.Reset()
+ cth.s = 0
+}
+
+func (cth *canonicalTextHash) Size() int {
+ return cth.h.Size()
+}
+
+func (cth *canonicalTextHash) BlockSize() int {
+ return cth.h.BlockSize()
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
new file mode 100644
index 0000000000..db8fb163b6
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
@@ -0,0 +1,206 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ecdh implements ECDH encryption, suitable for OpenPGP,
+// as specified in RFC 6637, section 8.
+package ecdh
+
+import (
+ "bytes"
+ "errors"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/aes/keywrap"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
+)
+
+type KDF struct {
+ Hash algorithm.Hash
+ Cipher algorithm.Cipher
+}
+
+type PublicKey struct {
+ curve ecc.ECDHCurve
+ Point []byte
+ KDF
+}
+
+type PrivateKey struct {
+ PublicKey
+ D []byte
+}
+
+func NewPublicKey(curve ecc.ECDHCurve, kdfHash algorithm.Hash, kdfCipher algorithm.Cipher) *PublicKey {
+ return &PublicKey{
+ curve: curve,
+ KDF: KDF{
+ Hash: kdfHash,
+ Cipher: kdfCipher,
+ },
+ }
+}
+
+func NewPrivateKey(key PublicKey) *PrivateKey {
+ return &PrivateKey{
+ PublicKey: key,
+ }
+}
+
+func (pk *PublicKey) GetCurve() ecc.ECDHCurve {
+ return pk.curve
+}
+
+func (pk *PublicKey) MarshalPoint() []byte {
+ return pk.curve.MarshalBytePoint(pk.Point)
+}
+
+func (pk *PublicKey) UnmarshalPoint(p []byte) error {
+ pk.Point = pk.curve.UnmarshalBytePoint(p)
+ if pk.Point == nil {
+ return errors.New("ecdh: failed to parse EC point")
+ }
+ return nil
+}
+
+func (sk *PrivateKey) MarshalByteSecret() []byte {
+ return sk.curve.MarshalByteSecret(sk.D)
+}
+
+func (sk *PrivateKey) UnmarshalByteSecret(d []byte) error {
+ sk.D = sk.curve.UnmarshalByteSecret(d)
+
+ if sk.D == nil {
+ return errors.New("ecdh: failed to parse scalar")
+ }
+ return nil
+}
+
+func GenerateKey(rand io.Reader, c ecc.ECDHCurve, kdf KDF) (priv *PrivateKey, err error) {
+ priv = new(PrivateKey)
+ priv.PublicKey.curve = c
+ priv.PublicKey.KDF = kdf
+ priv.PublicKey.Point, priv.D, err = c.GenerateECDH(rand)
+ return
+}
+
+func Encrypt(random io.Reader, pub *PublicKey, msg, curveOID, fingerprint []byte) (vsG, c []byte, err error) {
+ if len(msg) > 40 {
+ return nil, nil, errors.New("ecdh: message too long")
+ }
+ // the sender MAY use 21, 13, and 5 bytes of padding for AES-128,
+ // AES-192, and AES-256, respectively, to provide the same number of
+ // octets, 40 total, as an input to the key wrapping method.
+ padding := make([]byte, 40-len(msg))
+ for i := range padding {
+ padding[i] = byte(40 - len(msg))
+ }
+ m := append(msg, padding...)
+
+ ephemeral, zb, err := pub.curve.Encaps(random, pub.Point)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ vsG = pub.curve.MarshalBytePoint(ephemeral)
+
+ z, err := buildKey(pub, zb, curveOID, fingerprint, false, false)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if c, err = keywrap.Wrap(z, m); err != nil {
+ return nil, nil, err
+ }
+
+ return vsG, c, nil
+
+}
+
+func Decrypt(priv *PrivateKey, vsG, c, curveOID, fingerprint []byte) (msg []byte, err error) {
+ var m []byte
+ zb, err := priv.PublicKey.curve.Decaps(priv.curve.UnmarshalBytePoint(vsG), priv.D)
+
+ // Try buildKey three times to workaround an old bug, see comments in buildKey.
+ for i := 0; i < 3; i++ {
+ var z []byte
+ // RFC6637 §8: "Compute Z = KDF( S, Z_len, Param );"
+ z, err = buildKey(&priv.PublicKey, zb, curveOID, fingerprint, i == 1, i == 2)
+ if err != nil {
+ return nil, err
+ }
+
+ // RFC6637 §8: "Compute C = AESKeyWrap( Z, c ) as per [RFC3394]"
+ m, err = keywrap.Unwrap(z, c)
+ if err == nil {
+ break
+ }
+ }
+
+ // Only return an error after we've tried all (required) variants of buildKey.
+ if err != nil {
+ return nil, err
+ }
+
+ // RFC6637 §8: "m = symm_alg_ID || session key || checksum || pkcs5_padding"
+ // The last byte should be the length of the padding, as per PKCS5; strip it off.
+ return m[:len(m)-int(m[len(m)-1])], nil
+}
+
+func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLeading, stripTrailing bool) ([]byte, error) {
+ // Param = curve_OID_len || curve_OID || public_key_alg_ID || 03
+ // || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap
+ // || "Anonymous Sender " || recipient_fingerprint;
+ param := new(bytes.Buffer)
+ if _, err := param.Write(curveOID); err != nil {
+ return nil, err
+ }
+ algKDF := []byte{18, 3, 1, pub.KDF.Hash.Id(), pub.KDF.Cipher.Id()}
+ if _, err := param.Write(algKDF); err != nil {
+ return nil, err
+ }
+ if _, err := param.Write([]byte("Anonymous Sender ")); err != nil {
+ return nil, err
+ }
+ if _, err := param.Write(fingerprint[:]); err != nil {
+ return nil, err
+ }
+
+ // MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param );
+ h := pub.KDF.Hash.New()
+ if _, err := h.Write([]byte{0x0, 0x0, 0x0, 0x1}); err != nil {
+ return nil, err
+ }
+ zbLen := len(zb)
+ i := 0
+ j := zbLen - 1
+ if stripLeading {
+ // Work around old go crypto bug where the leading zeros are missing.
+ for i < zbLen && zb[i] == 0 {
+ i++
+ }
+ }
+ if stripTrailing {
+ // Work around old OpenPGP.js bug where insignificant trailing zeros in
+ // this little-endian number are missing.
+ // (See https://github.com/openpgpjs/openpgpjs/pull/853.)
+ for j >= 0 && zb[j] == 0 {
+ j--
+ }
+ }
+ if _, err := h.Write(zb[i : j+1]); err != nil {
+ return nil, err
+ }
+ if _, err := h.Write(param.Bytes()); err != nil {
+ return nil, err
+ }
+ mb := h.Sum(nil)
+
+ return mb[:pub.KDF.Cipher.KeySize()], nil // return oBits leftmost bits of MB.
+
+}
+
+func Validate(priv *PrivateKey) error {
+ return priv.curve.ValidateECDH(priv.Point, priv.D)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdsa/ecdsa.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdsa/ecdsa.go
new file mode 100644
index 0000000000..f94ae1b2f5
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdsa/ecdsa.go
@@ -0,0 +1,80 @@
+// Package ecdsa implements ECDSA signature, suitable for OpenPGP,
+// as specified in RFC 6637, section 5.
+package ecdsa
+
+import (
+ "errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
+ "io"
+ "math/big"
+)
+
+type PublicKey struct {
+ X, Y *big.Int
+ curve ecc.ECDSACurve
+}
+
+type PrivateKey struct {
+ PublicKey
+ D *big.Int
+}
+
+func NewPublicKey(curve ecc.ECDSACurve) *PublicKey {
+ return &PublicKey{
+ curve: curve,
+ }
+}
+
+func NewPrivateKey(key PublicKey) *PrivateKey {
+ return &PrivateKey{
+ PublicKey: key,
+ }
+}
+
+func (pk *PublicKey) GetCurve() ecc.ECDSACurve {
+ return pk.curve
+}
+
+func (pk *PublicKey) MarshalPoint() []byte {
+ return pk.curve.MarshalIntegerPoint(pk.X, pk.Y)
+}
+
+func (pk *PublicKey) UnmarshalPoint(p []byte) error {
+ pk.X, pk.Y = pk.curve.UnmarshalIntegerPoint(p)
+ if pk.X == nil {
+ return errors.New("ecdsa: failed to parse EC point")
+ }
+ return nil
+}
+
+func (sk *PrivateKey) MarshalIntegerSecret() []byte {
+ return sk.curve.MarshalIntegerSecret(sk.D)
+}
+
+func (sk *PrivateKey) UnmarshalIntegerSecret(d []byte) error {
+ sk.D = sk.curve.UnmarshalIntegerSecret(d)
+
+ if sk.D == nil {
+ return errors.New("ecdsa: failed to parse scalar")
+ }
+ return nil
+}
+
+func GenerateKey(rand io.Reader, c ecc.ECDSACurve) (priv *PrivateKey, err error) {
+ priv = new(PrivateKey)
+ priv.PublicKey.curve = c
+ priv.PublicKey.X, priv.PublicKey.Y, priv.D, err = c.GenerateECDSA(rand)
+ return
+}
+
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
+ return priv.PublicKey.curve.Sign(rand, priv.X, priv.Y, priv.D, hash)
+}
+
+func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+ return pub.curve.Verify(pub.X, pub.Y, hash, r, s)
+}
+
+func Validate(priv *PrivateKey) error {
+ return priv.curve.ValidateECDSA(priv.X, priv.Y, priv.D.Bytes())
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/ed25519/ed25519.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/ed25519/ed25519.go
new file mode 100644
index 0000000000..6abdf7c446
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/ed25519/ed25519.go
@@ -0,0 +1,115 @@
+// Package ed25519 implements the ed25519 signature algorithm for OpenPGP
+// as defined in the Open PGP crypto refresh.
+package ed25519
+
+import (
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ ed25519lib "github.com/cloudflare/circl/sign/ed25519"
+)
+
+const (
+ // PublicKeySize is the size, in bytes, of public keys in this package.
+ PublicKeySize = ed25519lib.PublicKeySize
+ // SeedSize is the size, in bytes, of private key seeds.
+ // The private key representation used by RFC 8032.
+ SeedSize = ed25519lib.SeedSize
+ // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
+ SignatureSize = ed25519lib.SignatureSize
+)
+
+type PublicKey struct {
+ // Point represents the elliptic curve point of the public key.
+ Point []byte
+}
+
+type PrivateKey struct {
+ PublicKey
+ // Key the private key representation by RFC 8032,
+ // encoded as seed | pub key point.
+ Key []byte
+}
+
+// NewPublicKey creates a new empty ed25519 public key.
+func NewPublicKey() *PublicKey {
+ return &PublicKey{}
+}
+
+// NewPrivateKey creates a new empty private key referencing the public key.
+func NewPrivateKey(key PublicKey) *PrivateKey {
+ return &PrivateKey{
+ PublicKey: key,
+ }
+}
+
+// Seed returns the ed25519 private key secret seed.
+// The private key representation by RFC 8032.
+func (pk *PrivateKey) Seed() []byte {
+ return pk.Key[:SeedSize]
+}
+
+// MarshalByteSecret returns the underlying 32 byte seed of the private key.
+func (pk *PrivateKey) MarshalByteSecret() []byte {
+ return pk.Seed()
+}
+
+// UnmarshalByteSecret computes the private key from the secret seed
+// and stores it in the private key object.
+func (sk *PrivateKey) UnmarshalByteSecret(seed []byte) error {
+ sk.Key = ed25519lib.NewKeyFromSeed(seed)
+ return nil
+}
+
+// GenerateKey generates a fresh private key with the provided randomness source.
+func GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ publicKey, privateKey, err := ed25519lib.GenerateKey(rand)
+ if err != nil {
+ return nil, err
+ }
+ privateKeyOut := new(PrivateKey)
+ privateKeyOut.PublicKey.Point = publicKey[:]
+ privateKeyOut.Key = privateKey[:]
+ return privateKeyOut, nil
+}
+
+// Sign signs a message with the ed25519 algorithm.
+// priv MUST be a valid key! Check this with Validate() before use.
+func Sign(priv *PrivateKey, message []byte) ([]byte, error) {
+ return ed25519lib.Sign(priv.Key, message), nil
+}
+
+// Verify verifies an ed25519 signature.
+func Verify(pub *PublicKey, message []byte, signature []byte) bool {
+ return ed25519lib.Verify(pub.Point, message, signature)
+}
+
+// Validate checks if the ed25519 private key is valid.
+func Validate(priv *PrivateKey) error {
+ expectedPrivateKey := ed25519lib.NewKeyFromSeed(priv.Seed())
+ if subtle.ConstantTimeCompare(priv.Key, expectedPrivateKey) == 0 {
+ return errors.KeyInvalidError("ed25519: invalid ed25519 secret")
+ }
+ if subtle.ConstantTimeCompare(priv.PublicKey.Point, expectedPrivateKey[SeedSize:]) == 0 {
+ return errors.KeyInvalidError("ed25519: invalid ed25519 public key")
+ }
+ return nil
+}
+
+// ENCODING/DECODING signature:
+
+// WriteSignature encodes and writes an ed25519 signature to writer.
+func WriteSignature(writer io.Writer, signature []byte) error {
+ _, err := writer.Write(signature)
+ return err
+}
+
+// ReadSignature decodes an ed25519 signature from a reader.
+func ReadSignature(reader io.Reader) ([]byte, error) {
+ signature := make([]byte, SignatureSize)
+ if _, err := io.ReadFull(reader, signature); err != nil {
+ return nil, err
+ }
+ return signature, nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/ed448/ed448.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/ed448/ed448.go
new file mode 100644
index 0000000000..b11fb4fb17
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/ed448/ed448.go
@@ -0,0 +1,119 @@
+// Package ed448 implements the ed448 signature algorithm for OpenPGP
+// as defined in the Open PGP crypto refresh.
+package ed448
+
+import (
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ ed448lib "github.com/cloudflare/circl/sign/ed448"
+)
+
+const (
+ // PublicKeySize is the size, in bytes, of public keys in this package.
+ PublicKeySize = ed448lib.PublicKeySize
+ // SeedSize is the size, in bytes, of private key seeds.
+ // The private key representation used by RFC 8032.
+ SeedSize = ed448lib.SeedSize
+ // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
+ SignatureSize = ed448lib.SignatureSize
+)
+
+type PublicKey struct {
+ // Point represents the elliptic curve point of the public key.
+ Point []byte
+}
+
+type PrivateKey struct {
+ PublicKey
+ // Key the private key representation by RFC 8032,
+ // encoded as seed | public key point.
+ Key []byte
+}
+
+// NewPublicKey creates a new empty ed448 public key.
+func NewPublicKey() *PublicKey {
+ return &PublicKey{}
+}
+
+// NewPrivateKey creates a new empty private key referencing the public key.
+func NewPrivateKey(key PublicKey) *PrivateKey {
+ return &PrivateKey{
+ PublicKey: key,
+ }
+}
+
+// Seed returns the ed448 private key secret seed.
+// The private key representation by RFC 8032.
+func (pk *PrivateKey) Seed() []byte {
+ return pk.Key[:SeedSize]
+}
+
+// MarshalByteSecret returns the underlying seed of the private key.
+func (pk *PrivateKey) MarshalByteSecret() []byte {
+ return pk.Seed()
+}
+
+// UnmarshalByteSecret computes the private key from the secret seed
+// and stores it in the private key object.
+func (sk *PrivateKey) UnmarshalByteSecret(seed []byte) error {
+ sk.Key = ed448lib.NewKeyFromSeed(seed)
+ return nil
+}
+
+// GenerateKey generates a fresh private key with the provided randomness source.
+func GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ publicKey, privateKey, err := ed448lib.GenerateKey(rand)
+ if err != nil {
+ return nil, err
+ }
+ privateKeyOut := new(PrivateKey)
+ privateKeyOut.PublicKey.Point = publicKey[:]
+ privateKeyOut.Key = privateKey[:]
+ return privateKeyOut, nil
+}
+
+// Sign signs a message with the ed448 algorithm.
+// priv MUST be a valid key! Check this with Validate() before use.
+func Sign(priv *PrivateKey, message []byte) ([]byte, error) {
+ // Ed448 is used with the empty string as a context string.
+ // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-08#section-13.7
+ return ed448lib.Sign(priv.Key, message, ""), nil
+}
+
+// Verify verifies a ed448 signature
+func Verify(pub *PublicKey, message []byte, signature []byte) bool {
+ // Ed448 is used with the empty string as a context string.
+ // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-08#section-13.7
+ return ed448lib.Verify(pub.Point, message, signature, "")
+}
+
+// Validate checks if the ed448 private key is valid
+func Validate(priv *PrivateKey) error {
+ expectedPrivateKey := ed448lib.NewKeyFromSeed(priv.Seed())
+ if subtle.ConstantTimeCompare(priv.Key, expectedPrivateKey) == 0 {
+ return errors.KeyInvalidError("ed448: invalid ed448 secret")
+ }
+ if subtle.ConstantTimeCompare(priv.PublicKey.Point, expectedPrivateKey[SeedSize:]) == 0 {
+ return errors.KeyInvalidError("ed448: invalid ed448 public key")
+ }
+ return nil
+}
+
+// ENCODING/DECODING signature:
+
+// WriteSignature encodes and writes an ed448 signature to writer.
+func WriteSignature(writer io.Writer, signature []byte) error {
+ _, err := writer.Write(signature)
+ return err
+}
+
+// ReadSignature decodes an ed448 signature from a reader.
+func ReadSignature(reader io.Reader) ([]byte, error) {
+ signature := make([]byte, SignatureSize)
+ if _, err := io.ReadFull(reader, signature); err != nil {
+ return nil, err
+ }
+ return signature, nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/eddsa/eddsa.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/eddsa/eddsa.go
new file mode 100644
index 0000000000..99ecfc7f12
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/eddsa/eddsa.go
@@ -0,0 +1,91 @@
+// Package eddsa implements EdDSA signature, suitable for OpenPGP, as specified in
+// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
+package eddsa
+
+import (
+ "errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
+ "io"
+)
+
+type PublicKey struct {
+ X []byte
+ curve ecc.EdDSACurve
+}
+
+type PrivateKey struct {
+ PublicKey
+ D []byte
+}
+
+func NewPublicKey(curve ecc.EdDSACurve) *PublicKey {
+ return &PublicKey{
+ curve: curve,
+ }
+}
+
+func NewPrivateKey(key PublicKey) *PrivateKey {
+ return &PrivateKey{
+ PublicKey: key,
+ }
+}
+
+func (pk *PublicKey) GetCurve() ecc.EdDSACurve {
+ return pk.curve
+}
+
+func (pk *PublicKey) MarshalPoint() []byte {
+ return pk.curve.MarshalBytePoint(pk.X)
+}
+
+func (pk *PublicKey) UnmarshalPoint(x []byte) error {
+ pk.X = pk.curve.UnmarshalBytePoint(x)
+
+ if pk.X == nil {
+ return errors.New("eddsa: failed to parse EC point")
+ }
+ return nil
+}
+
+func (sk *PrivateKey) MarshalByteSecret() []byte {
+ return sk.curve.MarshalByteSecret(sk.D)
+}
+
+func (sk *PrivateKey) UnmarshalByteSecret(d []byte) error {
+ sk.D = sk.curve.UnmarshalByteSecret(d)
+
+ if sk.D == nil {
+ return errors.New("eddsa: failed to parse scalar")
+ }
+ return nil
+}
+
+func GenerateKey(rand io.Reader, c ecc.EdDSACurve) (priv *PrivateKey, err error) {
+ priv = new(PrivateKey)
+ priv.PublicKey.curve = c
+ priv.PublicKey.X, priv.D, err = c.GenerateEdDSA(rand)
+ return
+}
+
+func Sign(priv *PrivateKey, message []byte) (r, s []byte, err error) {
+ sig, err := priv.PublicKey.curve.Sign(priv.PublicKey.X, priv.D, message)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ r, s = priv.PublicKey.curve.MarshalSignature(sig)
+ return
+}
+
+func Verify(pub *PublicKey, message, r, s []byte) bool {
+ sig := pub.curve.UnmarshalSignature(r, s)
+ if sig == nil {
+ return false
+ }
+
+ return pub.curve.Verify(pub.X, message, sig)
+}
+
+func Validate(priv *PrivateKey) error {
+ return priv.curve.ValidateEdDSA(priv.PublicKey.X, priv.D)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go
new file mode 100644
index 0000000000..bad2774344
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go
@@ -0,0 +1,124 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
+// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
+// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
+// n. 4, 1985, pp. 469-472.
+//
+// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
+// unsuitable for other protocols. RSA should be used in preference in any
+// case.
+package elgamal // import "github.com/ProtonMail/go-crypto/openpgp/elgamal"
+
+import (
+ "crypto/rand"
+ "crypto/subtle"
+ "errors"
+ "io"
+ "math/big"
+)
+
+// PublicKey represents an ElGamal public key.
+type PublicKey struct {
+ G, P, Y *big.Int
+}
+
+// PrivateKey represents an ElGamal private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+// Encrypt encrypts the given message to the given public key. The result is a
+// pair of integers. Errors can result from reading random, or because msg is
+// too large to be encrypted to the public key.
+func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
+ pLen := (pub.P.BitLen() + 7) / 8
+ if len(msg) > pLen-11 {
+ err = errors.New("elgamal: message too long")
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, pLen-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, random)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+
+ k, err := rand.Int(random, pub.P)
+ if err != nil {
+ return
+ }
+
+ c1 = new(big.Int).Exp(pub.G, k, pub.P)
+ s := new(big.Int).Exp(pub.Y, k, pub.P)
+ c2 = s.Mul(s, m)
+ c2.Mod(c2, pub.P)
+
+ return
+}
+
+// Decrypt takes two integers, resulting from an ElGamal encryption, and
+// returns the plaintext of the message. An error can result only if the
+// ciphertext is invalid. Users should keep in mind that this is a padding
+// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
+// be used to break the cryptosystem. See “Chosen Ciphertext Attacks
+// Against Protocols Based on the RSA Encryption Standard PKCS #1”, Daniel
+// Bleichenbacher, Advances in Cryptology (Crypto '98),
+func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
+ s := new(big.Int).Exp(c1, priv.X, priv.P)
+ if s.ModInverse(s, priv.P) == nil {
+ return nil, errors.New("elgamal: invalid private key")
+ }
+ s.Mul(s, c2)
+ s.Mod(s, priv.P)
+ em := s.Bytes()
+
+ firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ var lookingForIndex, index int
+ lookingForIndex = 1
+
+ for i := 1; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
+ return nil, errors.New("elgamal: decryption error")
+ }
+ return em[index+1:], nil
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
+ _, err = io.ReadFull(rand, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(rand, s[i:i+1])
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
new file mode 100644
index 0000000000..2e341507a7
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
@@ -0,0 +1,210 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package errors contains common error types for the OpenPGP packages.
+package errors // import "github.com/ProtonMail/go-crypto/openpgp/errors"
+
+import (
+ "fmt"
+ "strconv"
+)
+
+var (
+ // ErrDecryptSessionKeyParsing is a generic error message for parsing errors in decrypted data
+ // to reduce the risk of oracle attacks.
+ ErrDecryptSessionKeyParsing = DecryptWithSessionKeyError("parsing error")
+ // ErrAEADTagVerification is returned if one of the tag verifications in SEIPDv2 fails
+ ErrAEADTagVerification error = DecryptWithSessionKeyError("AEAD tag verification failed")
+ // ErrMDCHashMismatch
+ ErrMDCHashMismatch error = SignatureError("MDC hash mismatch")
+ // ErrMDCMissing
+ ErrMDCMissing error = SignatureError("MDC packet not found")
+)
+
+// A StructuralError is returned when OpenPGP data is found to be syntactically
+// invalid.
+type StructuralError string
+
+func (s StructuralError) Error() string {
+ return "openpgp: invalid data: " + string(s)
+}
+
+// A DecryptWithSessionKeyError is returned when a failure occurs when reading from symmetrically decrypted data or
+// an authentication tag verification fails.
+// Such an error indicates that the supplied session key is likely wrong or the data got corrupted.
+type DecryptWithSessionKeyError string
+
+func (s DecryptWithSessionKeyError) Error() string {
+ return "openpgp: decryption with session key failed: " + string(s)
+}
+
+// HandleSensitiveParsingError handles parsing errors when reading data from potentially decrypted data.
+// The function makes parsing errors generic to reduce the risk of oracle attacks in SEIPDv1.
+func HandleSensitiveParsingError(err error, decrypted bool) error {
+ if !decrypted {
+ // Data was not encrypted so we return the inner error.
+ return err
+ }
+ // The data is read from a stream that decrypts using a session key;
+ // therefore, we need to handle parsing errors appropriately.
+ // This is essential to mitigate the risk of oracle attacks.
+ if decError, ok := err.(*DecryptWithSessionKeyError); ok {
+ return decError
+ }
+ if decError, ok := err.(DecryptWithSessionKeyError); ok {
+ return decError
+ }
+ return ErrDecryptSessionKeyParsing
+}
+
+// UnsupportedError indicates that, although the OpenPGP data is valid, it
+// makes use of currently unimplemented features.
+type UnsupportedError string
+
+func (s UnsupportedError) Error() string {
+ return "openpgp: unsupported feature: " + string(s)
+}
+
+// InvalidArgumentError indicates that the caller is in error and passed an
+// incorrect value.
+type InvalidArgumentError string
+
+func (i InvalidArgumentError) Error() string {
+ return "openpgp: invalid argument: " + string(i)
+}
+
+// SignatureError indicates that a syntactically valid signature failed to
+// validate.
+type SignatureError string
+
+func (b SignatureError) Error() string {
+ return "openpgp: invalid signature: " + string(b)
+}
+
+type signatureExpiredError int
+
+func (se signatureExpiredError) Error() string {
+ return "openpgp: signature expired"
+}
+
+var ErrSignatureExpired error = signatureExpiredError(0)
+
+type keyExpiredError int
+
+func (ke keyExpiredError) Error() string {
+ return "openpgp: key expired"
+}
+
+var ErrSignatureOlderThanKey error = signatureOlderThanKeyError(0)
+
+type signatureOlderThanKeyError int
+
+func (ske signatureOlderThanKeyError) Error() string {
+ return "openpgp: signature is older than the key"
+}
+
+var ErrKeyExpired error = keyExpiredError(0)
+
+type keyIncorrectError int
+
+func (ki keyIncorrectError) Error() string {
+ return "openpgp: incorrect key"
+}
+
+var ErrKeyIncorrect error = keyIncorrectError(0)
+
+// KeyInvalidError indicates that the public key parameters are invalid
+// as they do not match the private ones
+type KeyInvalidError string
+
+func (e KeyInvalidError) Error() string {
+ return "openpgp: invalid key: " + string(e)
+}
+
+type unknownIssuerError int
+
+func (unknownIssuerError) Error() string {
+ return "openpgp: signature made by unknown entity"
+}
+
+var ErrUnknownIssuer error = unknownIssuerError(0)
+
+type keyRevokedError int
+
+func (keyRevokedError) Error() string {
+ return "openpgp: signature made by revoked key"
+}
+
+var ErrKeyRevoked error = keyRevokedError(0)
+
+type WeakAlgorithmError string
+
+func (e WeakAlgorithmError) Error() string {
+ return "openpgp: weak algorithms are rejected: " + string(e)
+}
+
+type UnknownPacketTypeError uint8
+
+func (upte UnknownPacketTypeError) Error() string {
+ return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
+}
+
+type CriticalUnknownPacketTypeError uint8
+
+func (upte CriticalUnknownPacketTypeError) Error() string {
+ return "openpgp: unknown critical packet type: " + strconv.Itoa(int(upte))
+}
+
+// AEADError indicates that there is a problem when initializing or using a
+// AEAD instance, configuration struct, nonces or index values.
+type AEADError string
+
+func (ae AEADError) Error() string {
+ return "openpgp: aead error: " + string(ae)
+}
+
+// ErrDummyPrivateKey results when operations are attempted on a private key
+// that is just a dummy key. See
+// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109
+type ErrDummyPrivateKey string
+
+func (dke ErrDummyPrivateKey) Error() string {
+ return "openpgp: s2k GNU dummy key: " + string(dke)
+}
+
+// ErrMalformedMessage results when the packet sequence is incorrect
+type ErrMalformedMessage string
+
+func (dke ErrMalformedMessage) Error() string {
+ return "openpgp: malformed message " + string(dke)
+}
+
+type messageTooLargeError int
+
+func (e messageTooLargeError) Error() string {
+ return "openpgp: decompressed message size exceeds provided limit"
+}
+
+// ErrMessageTooLarge is returned if the read data from
+// a compressed packet exceeds the provided limit.
+var ErrMessageTooLarge error = messageTooLargeError(0)
+
+// ErrEncryptionKeySelection is returned if encryption key selection fails (v2 API).
+type ErrEncryptionKeySelection struct {
+ PrimaryKeyId string
+ PrimaryKeyErr error
+ EncSelectionKeyId *string
+ EncSelectionErr error
+}
+
+func (eks ErrEncryptionKeySelection) Error() string {
+ prefix := fmt.Sprintf("openpgp: key selection for primary key %s:", eks.PrimaryKeyId)
+ if eks.PrimaryKeyErr != nil {
+ return fmt.Sprintf("%s invalid primary key: %s", prefix, eks.PrimaryKeyErr)
+ }
+ if eks.EncSelectionKeyId != nil {
+ return fmt.Sprintf("%s invalid encryption key %s: %s", prefix, *eks.EncSelectionKeyId, eks.EncSelectionErr)
+ }
+ return fmt.Sprintf("%s no encryption key: %s", prefix, eks.EncSelectionErr)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/hash.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/hash.go
new file mode 100644
index 0000000000..526bd7777f
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/hash.go
@@ -0,0 +1,24 @@
+package openpgp
+
+import (
+ "crypto"
+
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+)
+
+// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
+// hash id.
+func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
+ return algorithm.HashIdToHash(id)
+}
+
+// HashIdToString returns the name of the hash function corresponding to the
+// given OpenPGP hash id.
+func HashIdToString(id byte) (name string, ok bool) {
+ return algorithm.HashIdToString(id)
+}
+
+// HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
+func HashToHashId(h crypto.Hash) (id byte, ok bool) {
+ return algorithm.HashToHashId(h)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go
new file mode 100644
index 0000000000..d067065186
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go
@@ -0,0 +1,65 @@
+// Copyright (C) 2019 ProtonTech AG
+
+package algorithm
+
+import (
+ "crypto/cipher"
+ "github.com/ProtonMail/go-crypto/eax"
+ "github.com/ProtonMail/go-crypto/ocb"
+)
+
+// AEADMode defines the Authenticated Encryption with Associated Data mode of
+// operation.
+type AEADMode uint8
+
+// Supported modes of operation (see RFC4880bis [EAX] and RFC7253)
+const (
+ AEADModeEAX = AEADMode(1)
+ AEADModeOCB = AEADMode(2)
+ AEADModeGCM = AEADMode(3)
+)
+
+// TagLength returns the length in bytes of authentication tags.
+func (mode AEADMode) TagLength() int {
+ switch mode {
+ case AEADModeEAX:
+ return 16
+ case AEADModeOCB:
+ return 16
+ case AEADModeGCM:
+ return 16
+ default:
+ return 0
+ }
+}
+
+// NonceLength returns the length in bytes of nonces.
+func (mode AEADMode) NonceLength() int {
+ switch mode {
+ case AEADModeEAX:
+ return 16
+ case AEADModeOCB:
+ return 15
+ case AEADModeGCM:
+ return 12
+ default:
+ return 0
+ }
+}
+
+// New returns a fresh instance of the given mode
+func (mode AEADMode) New(block cipher.Block) (alg cipher.AEAD) {
+ var err error
+ switch mode {
+ case AEADModeEAX:
+ alg, err = eax.NewEAX(block)
+ case AEADModeOCB:
+ alg, err = ocb.NewOCB(block)
+ case AEADModeGCM:
+ alg, err = cipher.NewGCM(block)
+ }
+ if err != nil {
+ panic(err.Error())
+ }
+ return alg
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
new file mode 100644
index 0000000000..c76a75bcda
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
@@ -0,0 +1,97 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package algorithm
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+
+ "golang.org/x/crypto/cast5"
+)
+
+// Cipher is an official symmetric key cipher algorithm. See RFC 4880,
+// section 9.2.
+type Cipher interface {
+ // Id returns the algorithm ID, as a byte, of the cipher.
+ Id() uint8
+ // KeySize returns the key size, in bytes, of the cipher.
+ KeySize() int
+ // BlockSize returns the block size, in bytes, of the cipher.
+ BlockSize() int
+ // New returns a fresh instance of the given cipher.
+ New(key []byte) cipher.Block
+}
+
+// The following constants mirror the OpenPGP standard (RFC 4880).
+const (
+ TripleDES = CipherFunction(2)
+ CAST5 = CipherFunction(3)
+ AES128 = CipherFunction(7)
+ AES192 = CipherFunction(8)
+ AES256 = CipherFunction(9)
+)
+
+// CipherById represents the different block ciphers specified for OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
+var CipherById = map[uint8]Cipher{
+ TripleDES.Id(): TripleDES,
+ CAST5.Id(): CAST5,
+ AES128.Id(): AES128,
+ AES192.Id(): AES192,
+ AES256.Id(): AES256,
+}
+
+type CipherFunction uint8
+
+// ID returns the algorithm Id, as a byte, of cipher.
+func (sk CipherFunction) Id() uint8 {
+ return uint8(sk)
+}
+
+// KeySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) KeySize() int {
+ switch cipher {
+ case CAST5:
+ return cast5.KeySize
+ case AES128:
+ return 16
+ case AES192, TripleDES:
+ return 24
+ case AES256:
+ return 32
+ }
+ return 0
+}
+
+// BlockSize returns the block size, in bytes, of cipher.
+func (cipher CipherFunction) BlockSize() int {
+ switch cipher {
+ case TripleDES:
+ return des.BlockSize
+ case CAST5:
+ return 8
+ case AES128, AES192, AES256:
+ return 16
+ }
+ return 0
+}
+
+// New returns a fresh instance of the given cipher.
+func (cipher CipherFunction) New(key []byte) (block cipher.Block) {
+ var err error
+ switch cipher {
+ case TripleDES:
+ block, err = des.NewTripleDESCipher(key)
+ case CAST5:
+ block, err = cast5.NewCipher(key)
+ case AES128, AES192, AES256:
+ block, err = aes.NewCipher(key)
+ }
+ if err != nil {
+ panic(err.Error())
+ }
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
new file mode 100644
index 0000000000..d1a00fc749
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
@@ -0,0 +1,143 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package algorithm
+
+import (
+ "crypto"
+ "fmt"
+ "hash"
+)
+
+// Hash is an official hash function algorithm. See RFC 4880, section 9.4.
+type Hash interface {
+ // Id returns the algorithm ID, as a byte, of Hash.
+ Id() uint8
+ // Available reports whether the given hash function is linked into the binary.
+ Available() bool
+ // HashFunc simply returns the value of h so that Hash implements SignerOpts.
+ HashFunc() crypto.Hash
+ // New returns a new hash.Hash calculating the given hash function. New
+ // panics if the hash function is not linked into the binary.
+ New() hash.Hash
+ // Size returns the length, in bytes, of a digest resulting from the given
+ // hash function. It doesn't require that the hash function in question be
+ // linked into the program.
+ Size() int
+ // String is the name of the hash function corresponding to the given
+ // OpenPGP hash id.
+ String() string
+}
+
+// The following vars mirror the crypto/Hash supported hash functions.
+var (
+ SHA1 Hash = cryptoHash{2, crypto.SHA1}
+ SHA256 Hash = cryptoHash{8, crypto.SHA256}
+ SHA384 Hash = cryptoHash{9, crypto.SHA384}
+ SHA512 Hash = cryptoHash{10, crypto.SHA512}
+ SHA224 Hash = cryptoHash{11, crypto.SHA224}
+ SHA3_256 Hash = cryptoHash{12, crypto.SHA3_256}
+ SHA3_512 Hash = cryptoHash{14, crypto.SHA3_512}
+)
+
+// HashById represents the different hash functions specified for OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-14
+var (
+ HashById = map[uint8]Hash{
+ SHA256.Id(): SHA256,
+ SHA384.Id(): SHA384,
+ SHA512.Id(): SHA512,
+ SHA224.Id(): SHA224,
+ SHA3_256.Id(): SHA3_256,
+ SHA3_512.Id(): SHA3_512,
+ }
+)
+
+// cryptoHash contains pairs relating OpenPGP's hash identifier with
+// Go's crypto.Hash type. See RFC 4880, section 9.4.
+type cryptoHash struct {
+ id uint8
+ crypto.Hash
+}
+
+// Id returns the algorithm ID, as a byte, of cryptoHash.
+func (h cryptoHash) Id() uint8 {
+ return h.id
+}
+
+var hashNames = map[uint8]string{
+ SHA256.Id(): "SHA256",
+ SHA384.Id(): "SHA384",
+ SHA512.Id(): "SHA512",
+ SHA224.Id(): "SHA224",
+ SHA3_256.Id(): "SHA3-256",
+ SHA3_512.Id(): "SHA3-512",
+}
+
+func (h cryptoHash) String() string {
+ s, ok := hashNames[h.id]
+ if !ok {
+ panic(fmt.Sprintf("Unsupported hash function %d", h.id))
+ }
+ return s
+}
+
+// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
+// hash id.
+func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
+ if hash, ok := HashById[id]; ok {
+ return hash.HashFunc(), true
+ }
+ return 0, false
+}
+
+// HashIdToHashWithSha1 returns a crypto.Hash which corresponds to the given OpenPGP
+// hash id, allowing sha1.
+func HashIdToHashWithSha1(id byte) (h crypto.Hash, ok bool) {
+ if hash, ok := HashById[id]; ok {
+ return hash.HashFunc(), true
+ }
+
+ if id == SHA1.Id() {
+ return SHA1.HashFunc(), true
+ }
+
+ return 0, false
+}
+
+// HashIdToString returns the name of the hash function corresponding to the
+// given OpenPGP hash id.
+func HashIdToString(id byte) (name string, ok bool) {
+ if hash, ok := HashById[id]; ok {
+ return hash.String(), true
+ }
+ return "", false
+}
+
+// HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
+func HashToHashId(h crypto.Hash) (id byte, ok bool) {
+ for id, hash := range HashById {
+ if hash.HashFunc() == h {
+ return id, true
+ }
+ }
+
+ return 0, false
+}
+
+// HashToHashIdWithSha1 returns an OpenPGP hash id which corresponds the given Hash,
+// allowing instances of SHA1
+func HashToHashIdWithSha1(h crypto.Hash) (id byte, ok bool) {
+ for id, hash := range HashById {
+ if hash.HashFunc() == h {
+ return id, true
+ }
+ }
+
+ if h == SHA1.HashFunc() {
+ return SHA1.Id(), true
+ }
+
+ return 0, false
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go
new file mode 100644
index 0000000000..888767c4e4
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go
@@ -0,0 +1,171 @@
+// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
+package ecc
+
+import (
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ x25519lib "github.com/cloudflare/circl/dh/x25519"
+)
+
+type curve25519 struct{}
+
+func NewCurve25519() *curve25519 {
+ return &curve25519{}
+}
+
+func (c *curve25519) GetCurveName() string {
+ return "curve25519"
+}
+
+// MarshalBytePoint encodes the public point from native format, adding the prefix.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
+func (c *curve25519) MarshalBytePoint(point []byte) []byte {
+ return append([]byte{0x40}, point...)
+}
+
+// UnmarshalBytePoint decodes the public point to native format, removing the prefix.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
+func (c *curve25519) UnmarshalBytePoint(point []byte) []byte {
+ if len(point) != x25519lib.Size+1 {
+ return nil
+ }
+
+ // Remove prefix
+ return point[1:]
+}
+
+// MarshalByteSecret encodes the secret scalar from native format.
+// Note that the EC secret scalar differs from the definition of public keys in
+// [Curve25519] in two ways: (1) the byte-ordering is big-endian, which is
+// more uniform with how big integers are represented in OpenPGP, and (2) the
+// leading zeros are truncated.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.1
+// Note that leading zero bytes are stripped later when encoding as an MPI.
+func (c *curve25519) MarshalByteSecret(secret []byte) []byte {
+ d := make([]byte, x25519lib.Size)
+ copyReversed(d, secret)
+
+ // The following ensures that the private key is a number of the form
+ // 2^{254} + 8 * [0, 2^{251}), in order to avoid the small subgroup of
+ // the curve.
+ //
+ // This masking is done internally in the underlying lib and so is unnecessary
+ // for security, but OpenPGP implementations require that private keys be
+ // pre-masked.
+ d[0] &= 127
+ d[0] |= 64
+ d[31] &= 248
+
+ return d
+}
+
+// UnmarshalByteSecret decodes the secret scalar from native format.
+// Note that the EC secret scalar differs from the definition of public keys in
+// [Curve25519] in two ways: (1) the byte-ordering is big-endian, which is
+// more uniform with how big integers are represented in OpenPGP, and (2) the
+// leading zeros are truncated.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.1
+func (c *curve25519) UnmarshalByteSecret(d []byte) []byte {
+ if len(d) > x25519lib.Size {
+ return nil
+ }
+
+ // Ensure truncated leading bytes are re-added
+ secret := make([]byte, x25519lib.Size)
+ copyReversed(secret, d)
+
+ return secret
+}
+
+// generateKeyPairBytes Generates a private-public key-pair.
+// 'priv' is a private key; a little-endian scalar belonging to the set
+// 2^{254} + 8 * [0, 2^{251}), in order to avoid the small subgroup of the
+// curve. 'pub' is simply 'priv' * G where G is the base point.
+// See https://cr.yp.to/ecdh.html and RFC7748, sec 5.
+func (c *curve25519) generateKeyPairBytes(rand io.Reader) (priv, pub x25519lib.Key, err error) {
+ _, err = io.ReadFull(rand, priv[:])
+ if err != nil {
+ return
+ }
+
+ x25519lib.KeyGen(&pub, &priv)
+ return
+}
+
+func (c *curve25519) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
+ priv, pub, err := c.generateKeyPairBytes(rand)
+ if err != nil {
+ return
+ }
+
+ return pub[:], priv[:], nil
+}
+
+func (c *genericCurve) MaskSecret(secret []byte) []byte {
+ return secret
+}
+
+func (c *curve25519) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
+ // RFC6637 §8: "Generate an ephemeral key pair {v, V=vG}"
+ // ephemeralPrivate corresponds to `v`.
+ // ephemeralPublic corresponds to `V`.
+ ephemeralPrivate, ephemeralPublic, err := c.generateKeyPairBytes(rand)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // RFC6637 §8: "Obtain the authenticated recipient public key R"
+ // pubKey corresponds to `R`.
+ var pubKey x25519lib.Key
+ copy(pubKey[:], point)
+
+ // RFC6637 §8: "Compute the shared point S = vR"
+ // "VB = convert point V to the octet string"
+ // sharedPoint corresponds to `VB`.
+ var sharedPoint x25519lib.Key
+ x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey)
+
+ return ephemeralPublic[:], sharedPoint[:], nil
+}
+
+func (c *curve25519) Decaps(vsG, secret []byte) (sharedSecret []byte, err error) {
+ var ephemeralPublic, decodedPrivate, sharedPoint x25519lib.Key
+ // RFC6637 §8: "The decryption is the inverse of the method given."
+ // All quoted descriptions in comments below describe encryption, and
+ // the reverse is performed.
+ // vsG corresponds to `VB` in RFC6637 §8 .
+
+ // RFC6637 §8: "VB = convert point V to the octet string"
+ copy(ephemeralPublic[:], vsG)
+
+ // decodedPrivate corresponds to `r` in RFC6637 §8 .
+ copy(decodedPrivate[:], secret)
+
+ // RFC6637 §8: "Note that the recipient obtains the shared secret by calculating
+ // S = rV = rvG, where (r,R) is the recipient's key pair."
+ // sharedPoint corresponds to `S`.
+ x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic)
+
+ return sharedPoint[:], nil
+}
+
+func (c *curve25519) ValidateECDH(point []byte, secret []byte) (err error) {
+ var pk, sk x25519lib.Key
+ copy(sk[:], secret)
+ x25519lib.KeyGen(&pk, &sk)
+
+ if subtle.ConstantTimeCompare(point, pk[:]) == 0 {
+ return errors.KeyInvalidError("ecc: invalid curve25519 public point")
+ }
+
+ return nil
+}
+
+func copyReversed(out []byte, in []byte) {
+ l := len(in)
+ for i := 0; i < l; i++ {
+ out[i] = in[l-i-1]
+ }
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
new file mode 100644
index 0000000000..0da2d0d852
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
@@ -0,0 +1,143 @@
+// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
+package ecc
+
+import (
+ "bytes"
+ "crypto/elliptic"
+
+ "github.com/ProtonMail/go-crypto/bitcurves"
+ "github.com/ProtonMail/go-crypto/brainpool"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
+)
+
+const Curve25519GenName = "Curve25519"
+
+type CurveInfo struct {
+ GenName string
+ Oid *encoding.OID
+ Curve Curve
+}
+
+var Curves = []CurveInfo{
+ {
+ // NIST P-256
+ GenName: "P256",
+ Oid: encoding.NewOID([]byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}),
+ Curve: NewGenericCurve(elliptic.P256()),
+ },
+ {
+ // NIST P-384
+ GenName: "P384",
+ Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x22}),
+ Curve: NewGenericCurve(elliptic.P384()),
+ },
+ {
+ // NIST P-521
+ GenName: "P521",
+ Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x23}),
+ Curve: NewGenericCurve(elliptic.P521()),
+ },
+ {
+ // SecP256k1
+ GenName: "SecP256k1",
+ Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x0A}),
+ Curve: NewGenericCurve(bitcurves.S256()),
+ },
+ {
+ // Curve25519
+ GenName: Curve25519GenName,
+ Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}),
+ Curve: NewCurve25519(),
+ },
+ {
+ // x448
+ GenName: "Curve448",
+ Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x6F}),
+ Curve: NewX448(),
+ },
+ {
+ // Ed25519
+ GenName: Curve25519GenName,
+ Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}),
+ Curve: NewEd25519(),
+ },
+ {
+ // Ed448
+ GenName: "Curve448",
+ Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x71}),
+ Curve: NewEd448(),
+ },
+ {
+ // BrainpoolP256r1
+ GenName: "BrainpoolP256",
+ Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}),
+ Curve: NewGenericCurve(brainpool.P256r1()),
+ },
+ {
+ // BrainpoolP384r1
+ GenName: "BrainpoolP384",
+ Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}),
+ Curve: NewGenericCurve(brainpool.P384r1()),
+ },
+ {
+ // BrainpoolP512r1
+ GenName: "BrainpoolP512",
+ Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}),
+ Curve: NewGenericCurve(brainpool.P512r1()),
+ },
+}
+
+func FindByCurve(curve Curve) *CurveInfo {
+ for _, curveInfo := range Curves {
+ if curveInfo.Curve.GetCurveName() == curve.GetCurveName() {
+ return &curveInfo
+ }
+ }
+ return nil
+}
+
+func FindByOid(oid encoding.Field) *CurveInfo {
+ var rawBytes = oid.Bytes()
+ for _, curveInfo := range Curves {
+ if bytes.Equal(curveInfo.Oid.Bytes(), rawBytes) {
+ return &curveInfo
+ }
+ }
+ return nil
+}
+
+func FindEdDSAByGenName(curveGenName string) EdDSACurve {
+ for _, curveInfo := range Curves {
+ if curveInfo.GenName == curveGenName {
+ curve, ok := curveInfo.Curve.(EdDSACurve)
+ if ok {
+ return curve
+ }
+ }
+ }
+ return nil
+}
+
+func FindECDSAByGenName(curveGenName string) ECDSACurve {
+ for _, curveInfo := range Curves {
+ if curveInfo.GenName == curveGenName {
+ curve, ok := curveInfo.Curve.(ECDSACurve)
+ if ok {
+ return curve
+ }
+ }
+ }
+ return nil
+}
+
+func FindECDHByGenName(curveGenName string) ECDHCurve {
+ for _, curveInfo := range Curves {
+ if curveInfo.GenName == curveGenName {
+ curve, ok := curveInfo.Curve.(ECDHCurve)
+ if ok {
+ return curve
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go
new file mode 100644
index 0000000000..5ed9c93b3d
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go
@@ -0,0 +1,48 @@
+// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
+package ecc
+
+import (
+ "io"
+ "math/big"
+)
+
+type Curve interface {
+ GetCurveName() string
+}
+
+type ECDSACurve interface {
+ Curve
+ MarshalIntegerPoint(x, y *big.Int) []byte
+ UnmarshalIntegerPoint([]byte) (x, y *big.Int)
+ MarshalIntegerSecret(d *big.Int) []byte
+ UnmarshalIntegerSecret(d []byte) *big.Int
+ GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error)
+ Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error)
+ Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool
+ ValidateECDSA(x, y *big.Int, secret []byte) error
+}
+
+type EdDSACurve interface {
+ Curve
+ MarshalBytePoint(x []byte) []byte
+ UnmarshalBytePoint([]byte) (x []byte)
+ MarshalByteSecret(d []byte) []byte
+ UnmarshalByteSecret(d []byte) []byte
+ MarshalSignature(sig []byte) (r, s []byte)
+ UnmarshalSignature(r, s []byte) (sig []byte)
+ GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error)
+ Sign(publicKey, privateKey, message []byte) (sig []byte, err error)
+ Verify(publicKey, message, sig []byte) bool
+ ValidateEdDSA(publicKey, privateKey []byte) (err error)
+}
+type ECDHCurve interface {
+ Curve
+ MarshalBytePoint([]byte) (encoded []byte)
+ UnmarshalBytePoint(encoded []byte) []byte
+ MarshalByteSecret(d []byte) []byte
+ UnmarshalByteSecret(d []byte) []byte
+ GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error)
+ Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error)
+ Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error)
+ ValidateECDH(public []byte, secret []byte) error
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
new file mode 100644
index 0000000000..5a4c3a8596
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
@@ -0,0 +1,120 @@
+// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
+package ecc
+
+import (
+ "bytes"
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ ed25519lib "github.com/cloudflare/circl/sign/ed25519"
+)
+
+const ed25519Size = 32
+
+type ed25519 struct{}
+
+func NewEd25519() *ed25519 {
+ return &ed25519{}
+}
+
+func (c *ed25519) GetCurveName() string {
+ return "ed25519"
+}
+
+// MarshalBytePoint encodes the public point from native format, adding the prefix.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed25519) MarshalBytePoint(x []byte) []byte {
+ return append([]byte{0x40}, x...)
+}
+
+// UnmarshalBytePoint decodes a point from prefixed format to native.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed25519) UnmarshalBytePoint(point []byte) (x []byte) {
+ if len(point) != ed25519lib.PublicKeySize+1 {
+ return nil
+ }
+
+ // Return unprefixed
+ return point[1:]
+}
+
+// MarshalByteSecret encodes a scalar in native format.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed25519) MarshalByteSecret(d []byte) []byte {
+ return d
+}
+
+// UnmarshalByteSecret decodes a scalar in native format and re-adds the stripped leading zeroes
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed25519) UnmarshalByteSecret(s []byte) (d []byte) {
+ if len(s) > ed25519lib.SeedSize {
+ return nil
+ }
+
+ // Handle stripped leading zeroes
+ d = make([]byte, ed25519lib.SeedSize)
+ copy(d[ed25519lib.SeedSize-len(s):], s)
+ return
+}
+
+// MarshalSignature splits a signature in R and S.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
+func (c *ed25519) MarshalSignature(sig []byte) (r, s []byte) {
+ return sig[:ed25519Size], sig[ed25519Size:]
+}
+
+// UnmarshalSignature decodes R and S in the native format, re-adding the stripped leading zeroes
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
+func (c *ed25519) UnmarshalSignature(r, s []byte) (sig []byte) {
+ // Check size
+ if len(r) > 32 || len(s) > 32 {
+ return nil
+ }
+
+ sig = make([]byte, ed25519lib.SignatureSize)
+
+ // Handle stripped leading zeroes
+ copy(sig[ed25519Size-len(r):ed25519Size], r)
+ copy(sig[ed25519lib.SignatureSize-len(s):], s)
+ return sig
+}
+
+func (c *ed25519) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
+ pk, sk, err := ed25519lib.GenerateKey(rand)
+
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return pk, sk[:ed25519lib.SeedSize], nil
+}
+
+func getEd25519Sk(publicKey, privateKey []byte) ed25519lib.PrivateKey {
+ privateKeyCap, privateKeyLen, publicKeyLen := cap(privateKey), len(privateKey), len(publicKey)
+
+ if privateKeyCap >= privateKeyLen+publicKeyLen &&
+ bytes.Equal(privateKey[privateKeyLen:privateKeyLen+publicKeyLen], publicKey) {
+ return privateKey[:privateKeyLen+publicKeyLen]
+ }
+
+ return append(privateKey[:privateKeyLen:privateKeyLen], publicKey...)
+}
+
+func (c *ed25519) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
+ sig = ed25519lib.Sign(getEd25519Sk(publicKey, privateKey), message)
+ return sig, nil
+}
+
+func (c *ed25519) Verify(publicKey, message, sig []byte) bool {
+ return ed25519lib.Verify(publicKey, message, sig)
+}
+
+func (c *ed25519) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
+ priv := getEd25519Sk(publicKey, privateKey)
+ expectedPriv := ed25519lib.NewKeyFromSeed(priv.Seed())
+ if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 {
+ return errors.KeyInvalidError("ecc: invalid ed25519 secret")
+ }
+ return nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
new file mode 100644
index 0000000000..b6edda7480
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
@@ -0,0 +1,119 @@
+// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
+package ecc
+
+import (
+ "bytes"
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ ed448lib "github.com/cloudflare/circl/sign/ed448"
+)
+
+type ed448 struct{}
+
+func NewEd448() *ed448 {
+ return &ed448{}
+}
+
+func (c *ed448) GetCurveName() string {
+ return "ed448"
+}
+
+// MarshalBytePoint encodes the public point from native format, adding the prefix.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed448) MarshalBytePoint(x []byte) []byte {
+ // Return prefixed
+ return append([]byte{0x40}, x...)
+}
+
+// UnmarshalBytePoint decodes a point from prefixed format to native.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed448) UnmarshalBytePoint(point []byte) (x []byte) {
+ if len(point) != ed448lib.PublicKeySize+1 {
+ return nil
+ }
+
+ // Strip prefix
+ return point[1:]
+}
+
+// MarshalByteSecret encoded a scalar from native format to prefixed.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed448) MarshalByteSecret(d []byte) []byte {
+ // Return prefixed
+ return append([]byte{0x40}, d...)
+}
+
+// UnmarshalByteSecret decodes a scalar from prefixed format to native.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
+func (c *ed448) UnmarshalByteSecret(s []byte) (d []byte) {
+ // Check prefixed size
+ if len(s) != ed448lib.SeedSize+1 {
+ return nil
+ }
+
+ // Strip prefix
+ return s[1:]
+}
+
+// MarshalSignature splits a signature in R and S, where R is in prefixed native format and
+// S is an MPI with value zero.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
+func (c *ed448) MarshalSignature(sig []byte) (r, s []byte) {
+ return append([]byte{0x40}, sig...), []byte{}
+}
+
+// UnmarshalSignature decodes R and S in the native format. Only R is used, in prefixed native format.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
+func (c *ed448) UnmarshalSignature(r, s []byte) (sig []byte) {
+ if len(r) != ed448lib.SignatureSize+1 {
+ return nil
+ }
+
+ return r[1:]
+}
+
+func (c *ed448) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
+ pk, sk, err := ed448lib.GenerateKey(rand)
+
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return pk, sk[:ed448lib.SeedSize], nil
+}
+
+func getEd448Sk(publicKey, privateKey []byte) ed448lib.PrivateKey {
+ privateKeyCap, privateKeyLen, publicKeyLen := cap(privateKey), len(privateKey), len(publicKey)
+
+ if privateKeyCap >= privateKeyLen+publicKeyLen &&
+ bytes.Equal(privateKey[privateKeyLen:privateKeyLen+publicKeyLen], publicKey) {
+ return privateKey[:privateKeyLen+publicKeyLen]
+ }
+
+ return append(privateKey[:privateKeyLen:privateKeyLen], publicKey...)
+}
+
+func (c *ed448) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
+ // Ed448 is used with the empty string as a context string.
+ // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
+ sig = ed448lib.Sign(getEd448Sk(publicKey, privateKey), message, "")
+
+ return sig, nil
+}
+
+func (c *ed448) Verify(publicKey, message, sig []byte) bool {
+ // Ed448 is used with the empty string as a context string.
+ // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
+ return ed448lib.Verify(publicKey, message, sig, "")
+}
+
+func (c *ed448) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
+ priv := getEd448Sk(publicKey, privateKey)
+ expectedPriv := ed448lib.NewKeyFromSeed(priv.Seed())
+ if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 {
+ return errors.KeyInvalidError("ecc: invalid ed448 secret")
+ }
+ return nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go
new file mode 100644
index 0000000000..e28d7c7106
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go
@@ -0,0 +1,149 @@
+// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
+package ecc
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "fmt"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "io"
+ "math/big"
+)
+
+type genericCurve struct {
+ Curve elliptic.Curve
+}
+
+func NewGenericCurve(c elliptic.Curve) *genericCurve {
+ return &genericCurve{
+ Curve: c,
+ }
+}
+
+func (c *genericCurve) GetCurveName() string {
+ return c.Curve.Params().Name
+}
+
+func (c *genericCurve) MarshalBytePoint(point []byte) []byte {
+ return point
+}
+
+func (c *genericCurve) UnmarshalBytePoint(point []byte) []byte {
+ return point
+}
+
+func (c *genericCurve) MarshalIntegerPoint(x, y *big.Int) []byte {
+ return elliptic.Marshal(c.Curve, x, y)
+}
+
+func (c *genericCurve) UnmarshalIntegerPoint(point []byte) (x, y *big.Int) {
+ return elliptic.Unmarshal(c.Curve, point)
+}
+
+func (c *genericCurve) MarshalByteSecret(d []byte) []byte {
+ return d
+}
+
+func (c *genericCurve) UnmarshalByteSecret(d []byte) []byte {
+ return d
+}
+
+func (c *genericCurve) MarshalIntegerSecret(d *big.Int) []byte {
+ return d.Bytes()
+}
+
+func (c *genericCurve) UnmarshalIntegerSecret(d []byte) *big.Int {
+ return new(big.Int).SetBytes(d)
+}
+
+func (c *genericCurve) GenerateECDH(rand io.Reader) (point, secret []byte, err error) {
+ secret, x, y, err := elliptic.GenerateKey(c.Curve, rand)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ point = elliptic.Marshal(c.Curve, x, y)
+ return point, secret, nil
+}
+
+func (c *genericCurve) GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error) {
+ priv, err := ecdsa.GenerateKey(c.Curve, rand)
+ if err != nil {
+ return
+ }
+
+ return priv.X, priv.Y, priv.D, nil
+}
+
+func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
+ xP, yP := elliptic.Unmarshal(c.Curve, point)
+ if xP == nil {
+ panic("invalid point")
+ }
+
+ d, x, y, err := elliptic.GenerateKey(c.Curve, rand)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ vsG := elliptic.Marshal(c.Curve, x, y)
+ zbBig, _ := c.Curve.ScalarMult(xP, yP, d)
+
+ byteLen := (c.Curve.Params().BitSize + 7) >> 3
+ zb := make([]byte, byteLen)
+ zbBytes := zbBig.Bytes()
+ copy(zb[byteLen-len(zbBytes):], zbBytes)
+
+ return vsG, zb, nil
+}
+
+func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
+ x, y := elliptic.Unmarshal(c.Curve, ephemeral)
+ zbBig, _ := c.Curve.ScalarMult(x, y, secret)
+ byteLen := (c.Curve.Params().BitSize + 7) >> 3
+ zb := make([]byte, byteLen)
+ zbBytes := zbBig.Bytes()
+ copy(zb[byteLen-len(zbBytes):], zbBytes)
+
+ return zb, nil
+}
+
+func (c *genericCurve) Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error) {
+ priv := &ecdsa.PrivateKey{D: d, PublicKey: ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}}
+ return ecdsa.Sign(rand, priv, hash)
+}
+
+func (c *genericCurve) Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool {
+ pub := &ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}
+ return ecdsa.Verify(pub, hash, r, s)
+}
+
+func (c *genericCurve) validate(xP, yP *big.Int, secret []byte) error {
+ // the public point should not be at infinity (0,0)
+ zero := new(big.Int)
+ if xP.Cmp(zero) == 0 && yP.Cmp(zero) == 0 {
+ return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): infinity point", c.Curve.Params().Name))
+ }
+
+ // re-derive the public point Q' = (X,Y) = dG
+ // to compare to declared Q in public key
+ expectedX, expectedY := c.Curve.ScalarBaseMult(secret)
+ if xP.Cmp(expectedX) != 0 || yP.Cmp(expectedY) != 0 {
+ return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
+ }
+
+ return nil
+}
+
+func (c *genericCurve) ValidateECDSA(xP, yP *big.Int, secret []byte) error {
+ return c.validate(xP, yP, secret)
+}
+
+func (c *genericCurve) ValidateECDH(point []byte, secret []byte) error {
+ xP, yP := elliptic.Unmarshal(c.Curve, point)
+ if xP == nil {
+ return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
+ }
+
+ return c.validate(xP, yP, secret)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go
new file mode 100644
index 0000000000..df04262e9e
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go
@@ -0,0 +1,107 @@
+// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
+package ecc
+
+import (
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ x448lib "github.com/cloudflare/circl/dh/x448"
+)
+
+type x448 struct{}
+
+func NewX448() *x448 {
+ return &x448{}
+}
+
+func (c *x448) GetCurveName() string {
+ return "x448"
+}
+
+// MarshalBytePoint encodes the public point from native format, adding the prefix.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
+func (c *x448) MarshalBytePoint(point []byte) []byte {
+ return append([]byte{0x40}, point...)
+}
+
+// UnmarshalBytePoint decodes a point from prefixed format to native.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
+func (c *x448) UnmarshalBytePoint(point []byte) []byte {
+ if len(point) != x448lib.Size+1 {
+ return nil
+ }
+
+ return point[1:]
+}
+
+// MarshalByteSecret encoded a scalar from native format to prefixed.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
+func (c *x448) MarshalByteSecret(d []byte) []byte {
+ return append([]byte{0x40}, d...)
+}
+
+// UnmarshalByteSecret decodes a scalar from prefixed format to native.
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
+func (c *x448) UnmarshalByteSecret(d []byte) []byte {
+ if len(d) != x448lib.Size+1 {
+ return nil
+ }
+
+ // Store without prefix
+ return d[1:]
+}
+
+func (c *x448) generateKeyPairBytes(rand io.Reader) (sk, pk x448lib.Key, err error) {
+ if _, err = rand.Read(sk[:]); err != nil {
+ return
+ }
+
+ x448lib.KeyGen(&pk, &sk)
+ return
+}
+
+func (c *x448) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
+ priv, pub, err := c.generateKeyPairBytes(rand)
+ if err != nil {
+ return
+ }
+
+ return pub[:], priv[:], nil
+}
+
+func (c *x448) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
+ var pk, ss x448lib.Key
+ seed, e, err := c.generateKeyPairBytes(rand)
+ if err != nil {
+ return nil, nil, err
+ }
+ copy(pk[:], point)
+ x448lib.Shared(&ss, &seed, &pk)
+
+ return e[:], ss[:], nil
+}
+
+func (c *x448) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
+ var ss, sk, e x448lib.Key
+
+ copy(sk[:], secret)
+ copy(e[:], ephemeral)
+ x448lib.Shared(&ss, &sk, &e)
+
+ return ss[:], nil
+}
+
+func (c *x448) ValidateECDH(point []byte, secret []byte) error {
+ var sk, pk, expectedPk x448lib.Key
+
+ copy(pk[:], point)
+ copy(sk[:], secret)
+ x448lib.KeyGen(&expectedPk, &sk)
+
+ if subtle.ConstantTimeCompare(expectedPk[:], pk[:]) == 0 {
+ return errors.KeyInvalidError("ecc: invalid curve25519 public point")
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/encoding.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/encoding.go
new file mode 100644
index 0000000000..6c921481b7
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/encoding.go
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package encoding implements openpgp packet field encodings as specified in
+// RFC 4880 and 6637.
+package encoding
+
+import "io"
+
+// Field is an encoded field of an openpgp packet.
+type Field interface {
+ // Bytes returns the decoded data.
+ Bytes() []byte
+
+ // BitLength is the size in bits of the decoded data.
+ BitLength() uint16
+
+ // EncodedBytes returns the encoded data.
+ EncodedBytes() []byte
+
+ // EncodedLength is the size in bytes of the encoded data.
+ EncodedLength() uint16
+
+ // ReadFrom reads the next Field from r.
+ ReadFrom(r io.Reader) (int64, error)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/mpi.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/mpi.go
new file mode 100644
index 0000000000..02e5e695c3
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/mpi.go
@@ -0,0 +1,91 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package encoding
+
+import (
+ "io"
+ "math/big"
+ "math/bits"
+)
+
+// An MPI is used to store the contents of a big integer, along with the bit
+// length that was specified in the original input. This allows the MPI to be
+// reserialized exactly.
+type MPI struct {
+ bytes []byte
+ bitLength uint16
+}
+
+// NewMPI returns a MPI initialized with bytes.
+func NewMPI(bytes []byte) *MPI {
+ for len(bytes) != 0 && bytes[0] == 0 {
+ bytes = bytes[1:]
+ }
+ if len(bytes) == 0 {
+ bitLength := uint16(0)
+ return &MPI{bytes, bitLength}
+ }
+ bitLength := 8*uint16(len(bytes)-1) + uint16(bits.Len8(bytes[0]))
+ return &MPI{bytes, bitLength}
+}
+
+// Bytes returns the decoded data.
+func (m *MPI) Bytes() []byte {
+ return m.bytes
+}
+
+// BitLength is the size in bits of the decoded data.
+func (m *MPI) BitLength() uint16 {
+ return m.bitLength
+}
+
+// EncodedBytes returns the encoded data.
+func (m *MPI) EncodedBytes() []byte {
+ return append([]byte{byte(m.bitLength >> 8), byte(m.bitLength)}, m.bytes...)
+}
+
+// EncodedLength is the size in bytes of the encoded data.
+func (m *MPI) EncodedLength() uint16 {
+ return uint16(2 + len(m.bytes))
+}
+
+// ReadFrom reads into m the next MPI from r.
+func (m *MPI) ReadFrom(r io.Reader) (int64, error) {
+ var buf [2]byte
+ n, err := io.ReadFull(r, buf[0:])
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return int64(n), err
+ }
+
+ m.bitLength = uint16(buf[0])<<8 | uint16(buf[1])
+ m.bytes = make([]byte, (int(m.bitLength)+7)/8)
+
+ nn, err := io.ReadFull(r, m.bytes)
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+
+ // remove leading zero bytes from malformed GnuPG encoded MPIs:
+ // https://bugs.gnupg.org/gnupg/issue1853
+ // for _, b := range m.bytes {
+ // if b != 0 {
+ // break
+ // }
+ // m.bytes = m.bytes[1:]
+ // m.bitLength -= 8
+ // }
+
+ return int64(n) + int64(nn), err
+}
+
+// SetBig initializes m with the bits from n.
+func (m *MPI) SetBig(n *big.Int) *MPI {
+ m.bytes = n.Bytes()
+ m.bitLength = uint16(n.BitLen())
+ return m
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/oid.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/oid.go
new file mode 100644
index 0000000000..c9df9fe232
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/oid.go
@@ -0,0 +1,88 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package encoding
+
+import (
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+// OID is used to store a variable-length field with a one-octet size
+// prefix. See https://tools.ietf.org/html/rfc6637#section-9.
+type OID struct {
+ bytes []byte
+}
+
+const (
+ // maxOID is the maximum number of bytes in a OID.
+ maxOID = 254
+ // reservedOIDLength1 and reservedOIDLength2 are OID lengths that the RFC
+ // specifies are reserved.
+ reservedOIDLength1 = 0
+ reservedOIDLength2 = 0xff
+)
+
+// NewOID returns a OID initialized with bytes.
+func NewOID(bytes []byte) *OID {
+ switch len(bytes) {
+ case reservedOIDLength1, reservedOIDLength2:
+ panic("encoding: NewOID argument length is reserved")
+ default:
+ if len(bytes) > maxOID {
+ panic("encoding: NewOID argument too large")
+ }
+ }
+
+ return &OID{
+ bytes: bytes,
+ }
+}
+
+// Bytes returns the decoded data.
+func (o *OID) Bytes() []byte {
+ return o.bytes
+}
+
+// BitLength is the size in bits of the decoded data.
+func (o *OID) BitLength() uint16 {
+ return uint16(len(o.bytes) * 8)
+}
+
+// EncodedBytes returns the encoded data.
+func (o *OID) EncodedBytes() []byte {
+ return append([]byte{byte(len(o.bytes))}, o.bytes...)
+}
+
+// EncodedLength is the size in bytes of the encoded data.
+func (o *OID) EncodedLength() uint16 {
+ return uint16(1 + len(o.bytes))
+}
+
+// ReadFrom reads into b the next OID from r.
+func (o *OID) ReadFrom(r io.Reader) (int64, error) {
+ var buf [1]byte
+ n, err := io.ReadFull(r, buf[:])
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return int64(n), err
+ }
+
+ switch buf[0] {
+ case reservedOIDLength1, reservedOIDLength2:
+ return int64(n), errors.UnsupportedError("reserved for future extensions")
+ }
+
+ o.bytes = make([]byte, buf[0])
+
+ nn, err := io.ReadFull(r, o.bytes)
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+
+ return int64(n) + int64(nn), err
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
new file mode 100644
index 0000000000..77213f66be
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
@@ -0,0 +1,456 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+ goerrors "errors"
+ "io"
+ "math/big"
+ "time"
+
+ "github.com/ProtonMail/go-crypto/openpgp/ecdh"
+ "github.com/ProtonMail/go-crypto/openpgp/ecdsa"
+ "github.com/ProtonMail/go-crypto/openpgp/ed25519"
+ "github.com/ProtonMail/go-crypto/openpgp/ed448"
+ "github.com/ProtonMail/go-crypto/openpgp/eddsa"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
+ "github.com/ProtonMail/go-crypto/openpgp/packet"
+ "github.com/ProtonMail/go-crypto/openpgp/x25519"
+ "github.com/ProtonMail/go-crypto/openpgp/x448"
+)
+
+// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
+// single identity composed of the given full name, comment and email, any of
+// which may be empty but must not contain any of "()<>\x00".
+// If config is nil, sensible defaults will be used.
+func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
+ creationTime := config.Now()
+ keyLifetimeSecs := config.KeyLifetime()
+
+ // Generate a primary signing key
+ primaryPrivRaw, err := newSigner(config)
+ if err != nil {
+ return nil, err
+ }
+ primary := packet.NewSignerPrivateKey(creationTime, primaryPrivRaw)
+ if config.V6() {
+ if err := primary.UpgradeToV6(); err != nil {
+ return nil, err
+ }
+ }
+
+ e := &Entity{
+ PrimaryKey: &primary.PublicKey,
+ PrivateKey: primary,
+ Identities: make(map[string]*Identity),
+ Subkeys: []Subkey{},
+ Signatures: []*packet.Signature{},
+ }
+
+ if config.V6() {
+ // In v6 keys algorithm preferences should be stored in direct key signatures
+ selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypeDirectSignature, config)
+ err = writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
+ if err != nil {
+ return nil, err
+ }
+ err = selfSignature.SignDirectKeyBinding(&primary.PublicKey, primary, config)
+ if err != nil {
+ return nil, err
+ }
+ e.Signatures = append(e.Signatures, selfSignature)
+ e.SelfSignature = selfSignature
+ }
+
+ err = e.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs, !config.V6())
+ if err != nil {
+ return nil, err
+ }
+
+ // NOTE: No key expiry here, but we will not return this subkey in EncryptionKey()
+ // if the primary/master key has expired.
+ err = e.addEncryptionSubkey(config, creationTime, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ return e, nil
+}
+
+func (t *Entity) AddUserId(name, comment, email string, config *packet.Config) error {
+ creationTime := config.Now()
+ keyLifetimeSecs := config.KeyLifetime()
+ return t.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs, !config.V6())
+}
+
+func writeKeyProperties(selfSignature *packet.Signature, creationTime time.Time, keyLifetimeSecs uint32, config *packet.Config) error {
+ advertiseAead := config.AEAD() != nil
+
+ selfSignature.CreationTime = creationTime
+ selfSignature.KeyLifetimeSecs = &keyLifetimeSecs
+ selfSignature.FlagsValid = true
+ selfSignature.FlagSign = true
+ selfSignature.FlagCertify = true
+ selfSignature.SEIPDv1 = true // true by default, see 5.8 vs. 5.14
+ selfSignature.SEIPDv2 = advertiseAead
+
+ // Set the PreferredHash for the SelfSignature from the packet.Config.
+ // If it is not the must-implement algorithm from rfc4880bis, append that.
+ hash, ok := algorithm.HashToHashId(config.Hash())
+ if !ok {
+ return errors.UnsupportedError("unsupported preferred hash function")
+ }
+
+ selfSignature.PreferredHash = []uint8{hash}
+ if config.Hash() != crypto.SHA256 {
+ selfSignature.PreferredHash = append(selfSignature.PreferredHash, hashToHashId(crypto.SHA256))
+ }
+
+ // Likewise for DefaultCipher.
+ selfSignature.PreferredSymmetric = []uint8{uint8(config.Cipher())}
+ if config.Cipher() != packet.CipherAES128 {
+ selfSignature.PreferredSymmetric = append(selfSignature.PreferredSymmetric, uint8(packet.CipherAES128))
+ }
+
+ // We set CompressionNone as the preferred compression algorithm because
+ // of compression side channel attacks, then append the configured
+ // DefaultCompressionAlgo if any is set (to signal support for cases
+ // where the application knows that using compression is safe).
+ selfSignature.PreferredCompression = []uint8{uint8(packet.CompressionNone)}
+ if config.Compression() != packet.CompressionNone {
+ selfSignature.PreferredCompression = append(selfSignature.PreferredCompression, uint8(config.Compression()))
+ }
+
+ if advertiseAead {
+ // Get the preferred AEAD mode from the packet.Config.
+ // If it is not the must-implement algorithm from rfc9580, append that.
+ modes := []uint8{uint8(config.AEAD().Mode())}
+ if config.AEAD().Mode() != packet.AEADModeOCB {
+ modes = append(modes, uint8(packet.AEADModeOCB))
+ }
+
+ // For preferred (AES256, GCM), we'll generate (AES256, GCM), (AES256, OCB), (AES128, GCM), (AES128, OCB)
+ for _, cipher := range selfSignature.PreferredSymmetric {
+ for _, mode := range modes {
+ selfSignature.PreferredCipherSuites = append(selfSignature.PreferredCipherSuites, [2]uint8{cipher, mode})
+ }
+ }
+ }
+ return nil
+}
+
+func (t *Entity) addUserId(name, comment, email string, config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32, writeProperties bool) error {
+ uid := packet.NewUserId(name, comment, email)
+ if uid == nil {
+ return errors.InvalidArgumentError("user id field contained invalid characters")
+ }
+
+ if _, ok := t.Identities[uid.Id]; ok {
+ return errors.InvalidArgumentError("user id exist")
+ }
+
+ primary := t.PrivateKey
+ isPrimaryId := len(t.Identities) == 0
+ selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypePositiveCert, config)
+ if writeProperties {
+ err := writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
+ if err != nil {
+ return err
+ }
+ }
+ selfSignature.IsPrimaryId = &isPrimaryId
+
+ // User ID binding signature
+ err := selfSignature.SignUserId(uid.Id, &primary.PublicKey, primary, config)
+ if err != nil {
+ return err
+ }
+ t.Identities[uid.Id] = &Identity{
+ Name: uid.Id,
+ UserId: uid,
+ SelfSignature: selfSignature,
+ Signatures: []*packet.Signature{selfSignature},
+ }
+ return nil
+}
+
+// AddSigningSubkey adds a signing keypair as a subkey to the Entity.
+// If config is nil, sensible defaults will be used.
+func (e *Entity) AddSigningSubkey(config *packet.Config) error {
+ creationTime := config.Now()
+ keyLifetimeSecs := config.KeyLifetime()
+
+ subPrivRaw, err := newSigner(config)
+ if err != nil {
+ return err
+ }
+ sub := packet.NewSignerPrivateKey(creationTime, subPrivRaw)
+ sub.IsSubkey = true
+ if config.V6() {
+ if err := sub.UpgradeToV6(); err != nil {
+ return err
+ }
+ }
+
+ subkey := Subkey{
+ PublicKey: &sub.PublicKey,
+ PrivateKey: sub,
+ }
+ subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config)
+ subkey.Sig.CreationTime = creationTime
+ subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs
+ subkey.Sig.FlagsValid = true
+ subkey.Sig.FlagSign = true
+ subkey.Sig.EmbeddedSignature = createSignaturePacket(subkey.PublicKey, packet.SigTypePrimaryKeyBinding, config)
+ subkey.Sig.EmbeddedSignature.CreationTime = creationTime
+
+ err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey, subkey.PrivateKey, config)
+ if err != nil {
+ return err
+ }
+
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
+ if err != nil {
+ return err
+ }
+
+ e.Subkeys = append(e.Subkeys, subkey)
+ return nil
+}
+
+// AddEncryptionSubkey adds an encryption keypair as a subkey to the Entity.
+// If config is nil, sensible defaults will be used.
+func (e *Entity) AddEncryptionSubkey(config *packet.Config) error {
+ creationTime := config.Now()
+ keyLifetimeSecs := config.KeyLifetime()
+ return e.addEncryptionSubkey(config, creationTime, keyLifetimeSecs)
+}
+
+func (e *Entity) addEncryptionSubkey(config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error {
+ subPrivRaw, err := newDecrypter(config)
+ if err != nil {
+ return err
+ }
+ sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw)
+ sub.IsSubkey = true
+ if config.V6() {
+ if err := sub.UpgradeToV6(); err != nil {
+ return err
+ }
+ }
+
+ subkey := Subkey{
+ PublicKey: &sub.PublicKey,
+ PrivateKey: sub,
+ }
+ subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config)
+ subkey.Sig.CreationTime = creationTime
+ subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs
+ subkey.Sig.FlagsValid = true
+ subkey.Sig.FlagEncryptStorage = true
+ subkey.Sig.FlagEncryptCommunications = true
+
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
+ if err != nil {
+ return err
+ }
+
+ e.Subkeys = append(e.Subkeys, subkey)
+ return nil
+}
+
+// Generates a signing key
+func newSigner(config *packet.Config) (signer interface{}, err error) {
+ switch config.PublicKeyAlgorithm() {
+ case packet.PubKeyAlgoRSA:
+ bits := config.RSAModulusBits()
+ if bits < 1024 {
+ return nil, errors.InvalidArgumentError("bits must be >= 1024")
+ }
+ if config != nil && len(config.RSAPrimes) >= 2 {
+ primes := config.RSAPrimes[0:2]
+ config.RSAPrimes = config.RSAPrimes[2:]
+ return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
+ }
+ return rsa.GenerateKey(config.Random(), bits)
+ case packet.PubKeyAlgoEdDSA:
+ if config.V6() {
+ // Implementations MUST NOT accept or generate v6 key material
+ // using the deprecated OIDs.
+ return nil, errors.InvalidArgumentError("EdDSALegacy cannot be used for v6 keys")
+ }
+ curve := ecc.FindEdDSAByGenName(string(config.CurveName()))
+ if curve == nil {
+ return nil, errors.InvalidArgumentError("unsupported curve")
+ }
+
+ priv, err := eddsa.GenerateKey(config.Random(), curve)
+ if err != nil {
+ return nil, err
+ }
+ return priv, nil
+ case packet.PubKeyAlgoECDSA:
+ curve := ecc.FindECDSAByGenName(string(config.CurveName()))
+ if curve == nil {
+ return nil, errors.InvalidArgumentError("unsupported curve")
+ }
+
+ priv, err := ecdsa.GenerateKey(config.Random(), curve)
+ if err != nil {
+ return nil, err
+ }
+ return priv, nil
+ case packet.PubKeyAlgoEd25519:
+ priv, err := ed25519.GenerateKey(config.Random())
+ if err != nil {
+ return nil, err
+ }
+ return priv, nil
+ case packet.PubKeyAlgoEd448:
+ priv, err := ed448.GenerateKey(config.Random())
+ if err != nil {
+ return nil, err
+ }
+ return priv, nil
+ default:
+ return nil, errors.InvalidArgumentError("unsupported public key algorithm")
+ }
+}
+
+// Generates an encryption/decryption key
+func newDecrypter(config *packet.Config) (decrypter interface{}, err error) {
+ switch config.PublicKeyAlgorithm() {
+ case packet.PubKeyAlgoRSA:
+ bits := config.RSAModulusBits()
+ if bits < 1024 {
+ return nil, errors.InvalidArgumentError("bits must be >= 1024")
+ }
+ if config != nil && len(config.RSAPrimes) >= 2 {
+ primes := config.RSAPrimes[0:2]
+ config.RSAPrimes = config.RSAPrimes[2:]
+ return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
+ }
+ return rsa.GenerateKey(config.Random(), bits)
+ case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA:
+ fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey
+ case packet.PubKeyAlgoECDH:
+ if config.V6() &&
+ (config.CurveName() == packet.Curve25519 ||
+ config.CurveName() == packet.Curve448) {
+ // Implementations MUST NOT accept or generate v6 key material
+ // using the deprecated OIDs.
+ return nil, errors.InvalidArgumentError("ECDH with Curve25519/448 legacy cannot be used for v6 keys")
+ }
+ var kdf = ecdh.KDF{
+ Hash: algorithm.SHA512,
+ Cipher: algorithm.AES256,
+ }
+ curve := ecc.FindECDHByGenName(string(config.CurveName()))
+ if curve == nil {
+ return nil, errors.InvalidArgumentError("unsupported curve")
+ }
+ return ecdh.GenerateKey(config.Random(), curve, kdf)
+ case packet.PubKeyAlgoEd25519, packet.PubKeyAlgoX25519: // When passing Ed25519, we generate an x25519 subkey
+ return x25519.GenerateKey(config.Random())
+ case packet.PubKeyAlgoEd448, packet.PubKeyAlgoX448: // When passing Ed448, we generate an x448 subkey
+ return x448.GenerateKey(config.Random())
+ default:
+ return nil, errors.InvalidArgumentError("unsupported public key algorithm")
+ }
+}
+
+var bigOne = big.NewInt(1)
+
+// generateRSAKeyWithPrimes generates a multi-prime RSA keypair of the
+// given bit size, using the given random source and pre-populated primes.
+func generateRSAKeyWithPrimes(random io.Reader, nprimes int, bits int, prepopulatedPrimes []*big.Int) (*rsa.PrivateKey, error) {
+ priv := new(rsa.PrivateKey)
+ priv.E = 65537
+
+ if nprimes < 2 {
+ return nil, goerrors.New("generateRSAKeyWithPrimes: nprimes must be >= 2")
+ }
+
+ if bits < 1024 {
+ return nil, goerrors.New("generateRSAKeyWithPrimes: bits must be >= 1024")
+ }
+
+ primes := make([]*big.Int, nprimes)
+
+NextSetOfPrimes:
+ for {
+ todo := bits
+ // crypto/rand should set the top two bits in each prime.
+ // Thus each prime has the form
+ // p_i = 2^bitlen(p_i) × 0.11... (in base 2).
+ // And the product is:
+ // P = 2^todo × α
+ // where α is the product of nprimes numbers of the form 0.11...
+ //
+ // If α < 1/2 (which can happen for nprimes > 2), we need to
+ // shift todo to compensate for lost bits: the mean value of 0.11...
+ // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
+ // will give good results.
+ if nprimes >= 7 {
+ todo += (nprimes - 2) / 5
+ }
+ for i := 0; i < nprimes; i++ {
+ var err error
+ if len(prepopulatedPrimes) == 0 {
+ primes[i], err = rand.Prime(random, todo/(nprimes-i))
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ primes[i] = prepopulatedPrimes[0]
+ prepopulatedPrimes = prepopulatedPrimes[1:]
+ }
+
+ todo -= primes[i].BitLen()
+ }
+
+ // Make sure that primes is pairwise unequal.
+ for i, prime := range primes {
+ for j := 0; j < i; j++ {
+ if prime.Cmp(primes[j]) == 0 {
+ continue NextSetOfPrimes
+ }
+ }
+ }
+
+ n := new(big.Int).Set(bigOne)
+ totient := new(big.Int).Set(bigOne)
+ pminus1 := new(big.Int)
+ for _, prime := range primes {
+ n.Mul(n, prime)
+ pminus1.Sub(prime, bigOne)
+ totient.Mul(totient, pminus1)
+ }
+ if n.BitLen() != bits {
+ // This should never happen for nprimes == 2 because
+ // crypto/rand should set the top two bits in each prime.
+ // For nprimes > 2 we hope it does not happen often.
+ continue NextSetOfPrimes
+ }
+
+ priv.D = new(big.Int)
+ e := big.NewInt(int64(priv.E))
+ ok := priv.D.ModInverse(e, totient)
+
+ if ok != nil {
+ priv.Primes = primes
+ priv.N = n
+ break
+ }
+ }
+
+ priv.Precompute()
+ return priv, nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
new file mode 100644
index 0000000000..a071353e2e
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
@@ -0,0 +1,901 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ goerrors "errors"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/ProtonMail/go-crypto/openpgp/armor"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/packet"
+)
+
+// PublicKeyType is the armor type for a PGP public key.
+var PublicKeyType = "PGP PUBLIC KEY BLOCK"
+
+// PrivateKeyType is the armor type for a PGP private key.
+var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
+
+// An Entity represents the components of an OpenPGP key: a primary public key
+// (which must be a signing key), one or more identities claimed by that key,
+// and zero or more subkeys, which may be encryption keys.
+type Entity struct {
+ PrimaryKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ Identities map[string]*Identity // indexed by Identity.Name
+ Revocations []*packet.Signature
+ Subkeys []Subkey
+ SelfSignature *packet.Signature // Direct-key self signature of the PrimaryKey (contains primary key properties in v6)
+ Signatures []*packet.Signature // all (potentially unverified) self-signatures, revocations, and third-party signatures
+}
+
+// An Identity represents an identity claimed by an Entity and zero or more
+// assertions by other entities about that claim.
+type Identity struct {
+ Name string // by convention, has the form "Full Name (comment) "
+ UserId *packet.UserId
+ SelfSignature *packet.Signature
+ Revocations []*packet.Signature
+ Signatures []*packet.Signature // all (potentially unverified) self-signatures, revocations, and third-party signatures
+}
+
+// A Subkey is an additional public key in an Entity. Subkeys can be used for
+// encryption.
+type Subkey struct {
+ PublicKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ Sig *packet.Signature
+ Revocations []*packet.Signature
+}
+
+// A Key identifies a specific public key in an Entity. This is either the
+// Entity's primary key or a subkey.
+type Key struct {
+ Entity *Entity
+ PublicKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ SelfSignature *packet.Signature
+ Revocations []*packet.Signature
+}
+
+// A KeyRing provides access to public and private keys.
+type KeyRing interface {
+ // KeysById returns the set of keys that have the given key id.
+ KeysById(id uint64) []Key
+ // KeysByIdAndUsage returns the set of keys with the given id
+ // that also meet the key usage given by requiredUsage.
+ // The requiredUsage is expressed as the bitwise-OR of
+ // packet.KeyFlag* values.
+ KeysByIdUsage(id uint64, requiredUsage byte) []Key
+ // DecryptionKeys returns all private keys that are valid for
+ // decryption.
+ DecryptionKeys() []Key
+}
+
+// PrimaryIdentity returns an Identity, preferring non-revoked identities,
+// identities marked as primary, or the latest-created identity, in that order.
+func (e *Entity) PrimaryIdentity() *Identity {
+ var primaryIdentity *Identity
+ for _, ident := range e.Identities {
+ if shouldPreferIdentity(primaryIdentity, ident) {
+ primaryIdentity = ident
+ }
+ }
+ return primaryIdentity
+}
+
+func shouldPreferIdentity(existingId, potentialNewId *Identity) bool {
+ if existingId == nil {
+ return true
+ }
+
+ if len(existingId.Revocations) > len(potentialNewId.Revocations) {
+ return true
+ }
+
+ if len(existingId.Revocations) < len(potentialNewId.Revocations) {
+ return false
+ }
+
+ if existingId.SelfSignature == nil {
+ return true
+ }
+
+ if existingId.SelfSignature.IsPrimaryId != nil && *existingId.SelfSignature.IsPrimaryId &&
+ !(potentialNewId.SelfSignature.IsPrimaryId != nil && *potentialNewId.SelfSignature.IsPrimaryId) {
+ return false
+ }
+
+ if !(existingId.SelfSignature.IsPrimaryId != nil && *existingId.SelfSignature.IsPrimaryId) &&
+ potentialNewId.SelfSignature.IsPrimaryId != nil && *potentialNewId.SelfSignature.IsPrimaryId {
+ return true
+ }
+
+ return potentialNewId.SelfSignature.CreationTime.After(existingId.SelfSignature.CreationTime)
+}
+
+// EncryptionKey returns the best candidate Key for encrypting a message to the
+// given Entity.
+func (e *Entity) EncryptionKey(now time.Time) (Key, bool) {
+ // Fail to find any encryption key if the...
+ primarySelfSignature, primaryIdentity := e.PrimarySelfSignature()
+ if primarySelfSignature == nil || // no self-signature found
+ e.PrimaryKey.KeyExpired(primarySelfSignature, now) || // primary key has expired
+ e.Revoked(now) || // primary key has been revoked
+ primarySelfSignature.SigExpired(now) || // user ID or or direct self-signature has expired
+ (primaryIdentity != nil && primaryIdentity.Revoked(now)) { // user ID has been revoked (for v4 keys)
+ return Key{}, false
+ }
+
+ // Iterate the keys to find the newest, unexpired one
+ candidateSubkey := -1
+ var maxTime time.Time
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid &&
+ subkey.Sig.FlagEncryptCommunications &&
+ subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
+ !subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
+ !subkey.Sig.SigExpired(now) &&
+ !subkey.Revoked(now) &&
+ (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
+ candidateSubkey = i
+ maxTime = subkey.Sig.CreationTime
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
+ }
+
+ // If we don't have any subkeys for encryption and the primary key
+ // is marked as OK to encrypt with, then we can use it.
+ if primarySelfSignature.FlagsValid && primarySelfSignature.FlagEncryptCommunications &&
+ e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
+ return Key{e, e.PrimaryKey, e.PrivateKey, primarySelfSignature, e.Revocations}, true
+ }
+
+ return Key{}, false
+}
+
+// CertificationKey return the best candidate Key for certifying a key with this
+// Entity.
+func (e *Entity) CertificationKey(now time.Time) (Key, bool) {
+ return e.CertificationKeyById(now, 0)
+}
+
+// CertificationKeyById return the Key for key certification with this
+// Entity and keyID.
+func (e *Entity) CertificationKeyById(now time.Time, id uint64) (Key, bool) {
+ return e.signingKeyByIdUsage(now, id, packet.KeyFlagCertify)
+}
+
+// SigningKey return the best candidate Key for signing a message with this
+// Entity.
+func (e *Entity) SigningKey(now time.Time) (Key, bool) {
+ return e.SigningKeyById(now, 0)
+}
+
+// SigningKeyById return the Key for signing a message with this
+// Entity and keyID.
+func (e *Entity) SigningKeyById(now time.Time, id uint64) (Key, bool) {
+ return e.signingKeyByIdUsage(now, id, packet.KeyFlagSign)
+}
+
+func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key, bool) {
+ // Fail to find any signing key if the...
+ primarySelfSignature, primaryIdentity := e.PrimarySelfSignature()
+ if primarySelfSignature == nil || // no self-signature found
+ e.PrimaryKey.KeyExpired(primarySelfSignature, now) || // primary key has expired
+ e.Revoked(now) || // primary key has been revoked
+ primarySelfSignature.SigExpired(now) || // user ID or direct self-signature has expired
+ (primaryIdentity != nil && primaryIdentity.Revoked(now)) { // user ID has been revoked (for v4 keys)
+ return Key{}, false
+ }
+
+ // Iterate the keys to find the newest, unexpired one
+ candidateSubkey := -1
+ var maxTime time.Time
+ for idx, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid &&
+ (flags&packet.KeyFlagCertify == 0 || subkey.Sig.FlagCertify) &&
+ (flags&packet.KeyFlagSign == 0 || subkey.Sig.FlagSign) &&
+ subkey.PublicKey.PubKeyAlgo.CanSign() &&
+ !subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
+ !subkey.Sig.SigExpired(now) &&
+ !subkey.Revoked(now) &&
+ (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) &&
+ (id == 0 || subkey.PublicKey.KeyId == id) {
+ candidateSubkey = idx
+ maxTime = subkey.Sig.CreationTime
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
+ }
+
+ // If we don't have any subkeys for signing and the primary key
+ // is marked as OK to sign with, then we can use it.
+ if primarySelfSignature.FlagsValid &&
+ (flags&packet.KeyFlagCertify == 0 || primarySelfSignature.FlagCertify) &&
+ (flags&packet.KeyFlagSign == 0 || primarySelfSignature.FlagSign) &&
+ e.PrimaryKey.PubKeyAlgo.CanSign() &&
+ (id == 0 || e.PrimaryKey.KeyId == id) {
+ return Key{e, e.PrimaryKey, e.PrivateKey, primarySelfSignature, e.Revocations}, true
+ }
+
+ // No keys with a valid Signing Flag or no keys matched the id passed in
+ return Key{}, false
+}
+
+func revoked(revocations []*packet.Signature, now time.Time) bool {
+ for _, revocation := range revocations {
+ if revocation.RevocationReason != nil && *revocation.RevocationReason == packet.KeyCompromised {
+ // If the key is compromised, the key is considered revoked even before the revocation date.
+ return true
+ }
+ if !revocation.SigExpired(now) {
+ return true
+ }
+ }
+ return false
+}
+
+// Revoked returns whether the entity has any direct key revocation signatures.
+// Note that third-party revocation signatures are not supported.
+// Note also that Identity and Subkey revocation should be checked separately.
+func (e *Entity) Revoked(now time.Time) bool {
+ return revoked(e.Revocations, now)
+}
+
+// EncryptPrivateKeys encrypts all non-encrypted keys in the entity with the same key
+// derived from the provided passphrase. Public keys and dummy keys are ignored,
+// and don't cause an error to be returned.
+func (e *Entity) EncryptPrivateKeys(passphrase []byte, config *packet.Config) error {
+ var keysToEncrypt []*packet.PrivateKey
+ // Add entity private key to encrypt.
+ if e.PrivateKey != nil && !e.PrivateKey.Dummy() && !e.PrivateKey.Encrypted {
+ keysToEncrypt = append(keysToEncrypt, e.PrivateKey)
+ }
+
+ // Add subkeys to encrypt.
+ for _, sub := range e.Subkeys {
+ if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && !sub.PrivateKey.Encrypted {
+ keysToEncrypt = append(keysToEncrypt, sub.PrivateKey)
+ }
+ }
+ return packet.EncryptPrivateKeys(keysToEncrypt, passphrase, config)
+}
+
+// DecryptPrivateKeys decrypts all encrypted keys in the entity with the given passphrase.
+// Avoids recomputation of similar s2k key derivations. Public keys and dummy keys are ignored,
+// and don't cause an error to be returned.
+func (e *Entity) DecryptPrivateKeys(passphrase []byte) error {
+ var keysToDecrypt []*packet.PrivateKey
+ // Add entity private key to decrypt.
+ if e.PrivateKey != nil && !e.PrivateKey.Dummy() && e.PrivateKey.Encrypted {
+ keysToDecrypt = append(keysToDecrypt, e.PrivateKey)
+ }
+
+ // Add subkeys to decrypt.
+ for _, sub := range e.Subkeys {
+ if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted {
+ keysToDecrypt = append(keysToDecrypt, sub.PrivateKey)
+ }
+ }
+ return packet.DecryptPrivateKeys(keysToDecrypt, passphrase)
+}
+
+// Revoked returns whether the identity has been revoked by a self-signature.
+// Note that third-party revocation signatures are not supported.
+func (i *Identity) Revoked(now time.Time) bool {
+ return revoked(i.Revocations, now)
+}
+
+// Revoked returns whether the subkey has been revoked by a self-signature.
+// Note that third-party revocation signatures are not supported.
+func (s *Subkey) Revoked(now time.Time) bool {
+ return revoked(s.Revocations, now)
+}
+
+// Revoked returns whether the key or subkey has been revoked by a self-signature.
+// Note that third-party revocation signatures are not supported.
+// Note also that Identity revocation should be checked separately.
+// Normally, it's not necessary to call this function, except on keys returned by
+// KeysById or KeysByIdUsage.
+func (key *Key) Revoked(now time.Time) bool {
+ return revoked(key.Revocations, now)
+}
+
+// An EntityList contains one or more Entities.
+type EntityList []*Entity
+
+// KeysById returns the set of keys that have the given key id.
+func (el EntityList) KeysById(id uint64) (keys []Key) {
+ for _, e := range el {
+ if e.PrimaryKey.KeyId == id {
+ selfSig, _ := e.PrimarySelfSignature()
+ keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, e.Revocations})
+ }
+
+ for _, subKey := range e.Subkeys {
+ if subKey.PublicKey.KeyId == id {
+ keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations})
+ }
+ }
+ }
+ return
+}
+
+// KeysByIdAndUsage returns the set of keys with the given id that also meet
+// the key usage given by requiredUsage. The requiredUsage is expressed as
+// the bitwise-OR of packet.KeyFlag* values.
+func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
+ for _, key := range el.KeysById(id) {
+ if requiredUsage != 0 {
+ if key.SelfSignature == nil || !key.SelfSignature.FlagsValid {
+ continue
+ }
+
+ var usage byte
+ if key.SelfSignature.FlagCertify {
+ usage |= packet.KeyFlagCertify
+ }
+ if key.SelfSignature.FlagSign {
+ usage |= packet.KeyFlagSign
+ }
+ if key.SelfSignature.FlagEncryptCommunications {
+ usage |= packet.KeyFlagEncryptCommunications
+ }
+ if key.SelfSignature.FlagEncryptStorage {
+ usage |= packet.KeyFlagEncryptStorage
+ }
+ if usage&requiredUsage != requiredUsage {
+ continue
+ }
+ }
+
+ keys = append(keys, key)
+ }
+ return
+}
+
+// DecryptionKeys returns all private keys that are valid for decryption.
+func (el EntityList) DecryptionKeys() (keys []Key) {
+ for _, e := range el {
+ for _, subKey := range e.Subkeys {
+ if subKey.PrivateKey != nil && subKey.Sig.FlagsValid && (subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
+ keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations})
+ }
+ }
+ }
+ return
+}
+
+// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
+func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
+ block, err := armor.Decode(r)
+ if err == io.EOF {
+ return nil, errors.InvalidArgumentError("no armored data found")
+ }
+ if err != nil {
+ return nil, err
+ }
+ if block.Type != PublicKeyType && block.Type != PrivateKeyType {
+ return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
+ }
+
+ return ReadKeyRing(block.Body)
+}
+
+// ReadKeyRing reads one or more public/private keys. Unsupported keys are
+// ignored as long as at least a single valid key is found.
+func ReadKeyRing(r io.Reader) (el EntityList, err error) {
+ packets := packet.NewReader(r)
+ var lastUnsupportedError error
+
+ for {
+ var e *Entity
+ e, err = ReadEntity(packets)
+ if err != nil {
+ // TODO: warn about skipped unsupported/unreadable keys
+ if _, ok := err.(errors.UnsupportedError); ok {
+ lastUnsupportedError = err
+ err = readToNextPublicKey(packets)
+ } else if _, ok := err.(errors.StructuralError); ok {
+ // Skip unreadable, badly-formatted keys
+ lastUnsupportedError = err
+ err = readToNextPublicKey(packets)
+ }
+ if err == io.EOF {
+ err = nil
+ break
+ }
+ if err != nil {
+ el = nil
+ break
+ }
+ } else {
+ el = append(el, e)
+ }
+ }
+
+ if len(el) == 0 && err == nil {
+ err = lastUnsupportedError
+ }
+ return
+}
+
+// readToNextPublicKey reads packets until the start of the entity and leaves
+// the first packet of the new entity in the Reader.
+func readToNextPublicKey(packets *packet.Reader) (err error) {
+ var p packet.Packet
+ for {
+ p, err = packets.Next()
+ if err == io.EOF {
+ return
+ } else if err != nil {
+ if _, ok := err.(errors.UnsupportedError); ok {
+ continue
+ }
+ return
+ }
+
+ if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
+ packets.Unread(p)
+ return
+ }
+ }
+}
+
+// ReadEntity reads an entity (public key, identities, subkeys etc) from the
+// given Reader.
+func ReadEntity(packets *packet.Reader) (*Entity, error) {
+ e := new(Entity)
+ e.Identities = make(map[string]*Identity)
+
+ p, err := packets.Next()
+ if err != nil {
+ return nil, err
+ }
+
+ var ok bool
+ if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
+ if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
+ packets.Unread(p)
+ return nil, errors.StructuralError("first packet was not a public/private key")
+ }
+ e.PrimaryKey = &e.PrivateKey.PublicKey
+ }
+
+ if !e.PrimaryKey.PubKeyAlgo.CanSign() {
+ return nil, errors.StructuralError("primary key cannot be used for signatures")
+ }
+
+ var revocations []*packet.Signature
+ var directSignatures []*packet.Signature
+EachPacket:
+ for {
+ p, err := packets.Next()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return nil, err
+ }
+
+ switch pkt := p.(type) {
+ case *packet.UserId:
+ if err := addUserID(e, packets, pkt); err != nil {
+ return nil, err
+ }
+ case *packet.Signature:
+ if pkt.SigType == packet.SigTypeKeyRevocation {
+ revocations = append(revocations, pkt)
+ } else if pkt.SigType == packet.SigTypeDirectSignature {
+ directSignatures = append(directSignatures, pkt)
+ }
+ // Else, ignoring the signature as it does not follow anything
+ // we would know to attach it to.
+ case *packet.PrivateKey:
+ if !pkt.IsSubkey {
+ packets.Unread(p)
+ break EachPacket
+ }
+ err = addSubkey(e, packets, &pkt.PublicKey, pkt)
+ if err != nil {
+ return nil, err
+ }
+ case *packet.PublicKey:
+ if !pkt.IsSubkey {
+ packets.Unread(p)
+ break EachPacket
+ }
+ err = addSubkey(e, packets, pkt, nil)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ // we ignore unknown packets.
+ }
+ }
+
+ if len(e.Identities) == 0 && e.PrimaryKey.Version < 6 {
+ return nil, errors.StructuralError(fmt.Sprintf("v%d entity without any identities", e.PrimaryKey.Version))
+ }
+
+ // An implementation MUST ensure that a valid direct-key signature is present before using a v6 key.
+ if e.PrimaryKey.Version == 6 {
+ if len(directSignatures) == 0 {
+ return nil, errors.StructuralError("v6 entity without a valid direct-key signature")
+ }
+ // Select main direct key signature.
+ var mainDirectKeySelfSignature *packet.Signature
+ for _, directSignature := range directSignatures {
+ if directSignature.SigType == packet.SigTypeDirectSignature &&
+ directSignature.CheckKeyIdOrFingerprint(e.PrimaryKey) &&
+ (mainDirectKeySelfSignature == nil ||
+ directSignature.CreationTime.After(mainDirectKeySelfSignature.CreationTime)) {
+ mainDirectKeySelfSignature = directSignature
+ }
+ }
+ if mainDirectKeySelfSignature == nil {
+ return nil, errors.StructuralError("no valid direct-key self-signature for v6 primary key found")
+ }
+ // Check that the main self-signature is valid.
+ err = e.PrimaryKey.VerifyDirectKeySignature(mainDirectKeySelfSignature)
+ if err != nil {
+ return nil, errors.StructuralError("invalid direct-key self-signature for v6 primary key")
+ }
+ e.SelfSignature = mainDirectKeySelfSignature
+ e.Signatures = directSignatures
+ }
+
+ for _, revocation := range revocations {
+ err = e.PrimaryKey.VerifyRevocationSignature(revocation)
+ if err == nil {
+ e.Revocations = append(e.Revocations, revocation)
+ } else {
+ // TODO: RFC 4880 5.2.3.15 defines revocation keys.
+ return nil, errors.StructuralError("revocation signature signed by alternate key")
+ }
+ }
+
+ return e, nil
+}
+
+func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error {
+ // Make a new Identity object, that we might wind up throwing away.
+ // We'll only add it if we get a valid self-signature over this
+ // userID.
+ identity := new(Identity)
+ identity.Name = pkt.Id
+ identity.UserId = pkt
+
+ for {
+ p, err := packets.Next()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return err
+ }
+
+ sig, ok := p.(*packet.Signature)
+ if !ok {
+ packets.Unread(p)
+ break
+ }
+
+ if sig.SigType != packet.SigTypeGenericCert &&
+ sig.SigType != packet.SigTypePersonaCert &&
+ sig.SigType != packet.SigTypeCasualCert &&
+ sig.SigType != packet.SigTypePositiveCert &&
+ sig.SigType != packet.SigTypeCertificationRevocation {
+ return errors.StructuralError("user ID signature with wrong type")
+ }
+
+ if sig.CheckKeyIdOrFingerprint(e.PrimaryKey) {
+ if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil {
+ return errors.StructuralError("user ID self-signature invalid: " + err.Error())
+ }
+ if sig.SigType == packet.SigTypeCertificationRevocation {
+ identity.Revocations = append(identity.Revocations, sig)
+ } else if identity.SelfSignature == nil || sig.CreationTime.After(identity.SelfSignature.CreationTime) {
+ identity.SelfSignature = sig
+ }
+ identity.Signatures = append(identity.Signatures, sig)
+ e.Identities[pkt.Id] = identity
+ } else {
+ identity.Signatures = append(identity.Signatures, sig)
+ }
+ }
+
+ return nil
+}
+
+func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
+ var subKey Subkey
+ subKey.PublicKey = pub
+ subKey.PrivateKey = priv
+
+ for {
+ p, err := packets.Next()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return errors.StructuralError("subkey signature invalid: " + err.Error())
+ }
+
+ sig, ok := p.(*packet.Signature)
+ if !ok {
+ packets.Unread(p)
+ break
+ }
+
+ if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation {
+ return errors.StructuralError("subkey signature with wrong type")
+ }
+
+ if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil {
+ return errors.StructuralError("subkey signature invalid: " + err.Error())
+ }
+
+ switch sig.SigType {
+ case packet.SigTypeSubkeyRevocation:
+ subKey.Revocations = append(subKey.Revocations, sig)
+ case packet.SigTypeSubkeyBinding:
+ if subKey.Sig == nil || sig.CreationTime.After(subKey.Sig.CreationTime) {
+ subKey.Sig = sig
+ }
+ }
+ }
+
+ if subKey.Sig == nil {
+ return errors.StructuralError("subkey packet not followed by signature")
+ }
+
+ e.Subkeys = append(e.Subkeys, subKey)
+
+ return nil
+}
+
+// SerializePrivate serializes an Entity, including private key material, but
+// excluding signatures from other entities, to the given Writer.
+// Identities and subkeys are re-signed in case they changed since NewEntry.
+// If config is nil, sensible defaults will be used.
+func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
+ if e.PrivateKey.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy private key cannot re-sign identities")
+ }
+ return e.serializePrivate(w, config, true)
+}
+
+// SerializePrivateWithoutSigning serializes an Entity, including private key
+// material, but excluding signatures from other entities, to the given Writer.
+// Self-signatures of identities and subkeys are not re-signed. This is useful
+// when serializing GNU dummy keys, among other things.
+// If config is nil, sensible defaults will be used.
+func (e *Entity) SerializePrivateWithoutSigning(w io.Writer, config *packet.Config) (err error) {
+ return e.serializePrivate(w, config, false)
+}
+
+func (e *Entity) serializePrivate(w io.Writer, config *packet.Config, reSign bool) (err error) {
+ if e.PrivateKey == nil {
+ return goerrors.New("openpgp: private key is missing")
+ }
+ err = e.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ for _, revocation := range e.Revocations {
+ err := revocation.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ for _, directSignature := range e.Signatures {
+ err := directSignature.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return
+ }
+ if reSign {
+ if ident.SelfSignature == nil {
+ return goerrors.New("openpgp: can't re-sign identity without valid self-signature")
+ }
+ err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config)
+ if err != nil {
+ return
+ }
+ }
+ for _, sig := range ident.Signatures {
+ err = sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ if reSign {
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
+ if err != nil {
+ return
+ }
+ if subkey.Sig.EmbeddedSignature != nil {
+ err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey,
+ subkey.PrivateKey, config)
+ if err != nil {
+ return
+ }
+ }
+ }
+ for _, revocation := range subkey.Revocations {
+ err := revocation.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ return nil
+}
+
+// Serialize writes the public part of the given Entity to w, including
+// signatures from other entities. No private key material will be output.
+func (e *Entity) Serialize(w io.Writer) error {
+ err := e.PrimaryKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, revocation := range e.Revocations {
+ err := revocation.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ for _, directSignature := range e.Signatures {
+ err := directSignature.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, sig := range ident.Signatures {
+ err = sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PublicKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, revocation := range subkey.Revocations {
+ err := revocation.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SignIdentity adds a signature to e, from signer, attesting that identity is
+// associated with e. The provided identity must already be an element of
+// e.Identities and the private key of signer must have been decrypted if
+// necessary.
+// If config is nil, sensible defaults will be used.
+func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error {
+ certificationKey, ok := signer.CertificationKey(config.Now())
+ if !ok {
+ return errors.InvalidArgumentError("no valid certification key found")
+ }
+
+ if certificationKey.PrivateKey.Encrypted {
+ return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
+ }
+
+ ident, ok := e.Identities[identity]
+ if !ok {
+ return errors.InvalidArgumentError("given identity string not found in Entity")
+ }
+
+ sig := createSignaturePacket(certificationKey.PublicKey, packet.SigTypeGenericCert, config)
+
+ signingUserID := config.SigningUserId()
+ if signingUserID != "" {
+ if _, ok := signer.Identities[signingUserID]; !ok {
+ return errors.InvalidArgumentError("signer identity string not found in signer Entity")
+ }
+ sig.SignerUserId = &signingUserID
+ }
+
+ if err := sig.SignUserId(identity, e.PrimaryKey, certificationKey.PrivateKey, config); err != nil {
+ return err
+ }
+ ident.Signatures = append(ident.Signatures, sig)
+ return nil
+}
+
+// RevokeKey generates a key revocation signature (packet.SigTypeKeyRevocation) with the
+// specified reason code and text (RFC4880 section-5.2.3.23).
+// If config is nil, sensible defaults will be used.
+func (e *Entity) RevokeKey(reason packet.ReasonForRevocation, reasonText string, config *packet.Config) error {
+ revSig := createSignaturePacket(e.PrimaryKey, packet.SigTypeKeyRevocation, config)
+ revSig.RevocationReason = &reason
+ revSig.RevocationReasonText = reasonText
+
+ if err := revSig.RevokeKey(e.PrimaryKey, e.PrivateKey, config); err != nil {
+ return err
+ }
+ e.Revocations = append(e.Revocations, revSig)
+ return nil
+}
+
+// RevokeSubkey generates a subkey revocation signature (packet.SigTypeSubkeyRevocation) for
+// a subkey with the specified reason code and text (RFC4880 section-5.2.3.23).
+// If config is nil, sensible defaults will be used.
+func (e *Entity) RevokeSubkey(sk *Subkey, reason packet.ReasonForRevocation, reasonText string, config *packet.Config) error {
+ if err := e.PrimaryKey.VerifyKeySignature(sk.PublicKey, sk.Sig); err != nil {
+ return errors.InvalidArgumentError("given subkey is not associated with this key")
+ }
+
+ revSig := createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyRevocation, config)
+ revSig.RevocationReason = &reason
+ revSig.RevocationReasonText = reasonText
+
+ if err := revSig.RevokeSubkey(sk.PublicKey, e.PrivateKey, config); err != nil {
+ return err
+ }
+
+ sk.Revocations = append(sk.Revocations, revSig)
+ return nil
+}
+
+func (e *Entity) primaryDirectSignature() *packet.Signature {
+ return e.SelfSignature
+}
+
+// PrimarySelfSignature searches the entity for the self-signature that stores key preferences.
+// For V4 keys, returns the self-signature of the primary identity, and the identity.
+// For V6 keys, returns the latest valid direct-key self-signature, and no identity (nil).
+// This self-signature is to be used to check the key expiration,
+// algorithm preferences, and so on.
+func (e *Entity) PrimarySelfSignature() (*packet.Signature, *Identity) {
+ if e.PrimaryKey.Version == 6 {
+ return e.primaryDirectSignature(), nil
+ }
+ primaryIdentity := e.PrimaryIdentity()
+ if primaryIdentity == nil {
+ return nil, nil
+ }
+ return primaryIdentity.SelfSignature, primaryIdentity
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go
new file mode 100644
index 0000000000..108fd096f3
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go
@@ -0,0 +1,538 @@
+package openpgp
+
+const expiringKeyHex = "c6c04d0451d0c680010800abbb021fd03ffc4e96618901180c3fdcb060ee69eeead97b91256d11420d80b5f1b51930248044130bd300605cf8a05b7a40d3d8cfb0a910be2e3db50dcd50a9c54064c2a5550801daa834ff4480b33d3d3ca495ff8a4e84a886977d17d998f881241a874083d8b995beab555b6d22b8a4817ab17ac3e7304f7d4d2c05c495fb2218348d3bc13651db1d92732e368a9dd7dcefa6eddff30b94706a9aaee47e9d39321460b740c59c6fc3c2fd8ab6c0fb868cb87c0051f0321301fe0f0e1820b15e7fb7063395769b525005c7e30a7ce85984f5cac00504e7b4fdc45d74958de8388436fd5c7ba9ea121f1c851b5911dd1b47a14d81a09e92ef37721e2325b6790011010001cd00c2c07b041001080025050251d0c680050900278d00060b09070803020415080a0203160201021901021b03021e01000a0910e7b484133a890a35ae4b0800a1beb82e7f28eaf5273d6af9d3391314f6280b2b624eaca2851f89a9ebcaf80ac589ebd509f168bc4322106ca2e2ce77a76e071a3c7444787d65216b5f05e82c77928860b92aace3b7d0327db59492f422eb9dfab7249266d37429870b091a98aba8724c2259ebf8f85093f21255eafa75aa841e31d94f2ac891b9755fed455e539044ee69fc47950b80e003fc9f298d695660f28329eaa38037c367efde1727458e514faf990d439a21461b719edaddf9296d3d0647b43ca56cb8dbf63b4fcf8b9968e7928c463470fab3b98e44d0d95645062f94b2d04fe56bd52822b71934db8ce845622c40b92fcbe765a142e7f38b61a6aa9606c8e8858dcd3b6eb1894acec04d0451d1f06b01080088bea67444e1789390e7c0335c86775502d58ec783d99c8ef4e06de235ed3dd4b0467f6f358d818c7d8989d43ec6d69fcbc8c32632d5a1b605e3fa8e41d695fcdcaa535936cd0157f9040dce362519803b908eafe838bb13216c885c6f93e9e8d5745607f0d062322085d6bdc760969149a8ff8dd9f5c18d9bfe2e6f63a06e17694cf1f67587c6fb70e9aebf90ffc528ca3b615ac7c9d4a21ea4f7c06f2e98fbbd90a859b8608bf9ea638e3a54289ce44c283110d0c45fa458de6251cd6e7baf71f80f12c8978340490fd90c92b81736ae902ed958e478dceae2835953d189c45d182aff02ea2be61b81d8e94430f041d638647b43e2fcb45fd512fbf5068b810011010001c2c06504180108000f050251d1f06b050900081095021b0c000a0910e7b484133a890a35e63407fe2ec88d6d1e6c9ce7553ece0cb2524747217bad29f251d33df84599ffcc900141a355abd62126800744068a5e05dc167056aa9205273dc7765a2ed49db15c2a83b8d6e6429c902136f1e12229086c1c10c0053242c2a4ae1930db58163387a48cad64607ff2153c320e42843dec28e3fce90e7399d63ac0affa2fee1f0adc0953c89eb3f46ef1d6c04328ed13b491669d5120a3782e3ffb7c69575fb77eebd108794f4dda9d34be2bae57e8e59ec8ebfda2f6f06104b2321be408ea146e2db482b00c5055c8618de36ac9716f80da2617e225556d0fce61b01c8cea2d1e0ea982c31711060ca370f2739366e1e708f38405d784b49d16a26cf62d152eae734327cec04d0451d1f07b010800d5af91c5e7c2fd8951c8d254eab0c97cdcb66822f868b79b78c366255059a68fd74ebca9adb9b970cd9e586690e6e0756705432306878c897b10a4b4ca0005966f99ac8fa4e6f9caf54bf8e53844544beee9872a7ac64c119cf1393d96e674254b661f61ee975633d0e8a8672531edb6bb8e211204e7754a9efa802342118eee850beea742bac95a3f706cc2024cf6037a308bb68162b2f53b9a6346a96e6d31871a2456186e24a1c7a82b82ac04afdfd57cd7fb9ba77a9c760d40b76a170f7be525e5fb6a9848cc726e806187710d9b190387df28700f321f988a392899f93815cc937f309129eb94d5299c5547cb2c085898e6639496e70d746c9d3fb9881d0011010001c2c06504180108000f050251d1f07b050900266305021b0c000a0910e7b484133a890a35bff207fd10dfe8c4a6ea1dd30568012b6fd6891a763c87ad0f7a1d112aad9e8e3239378a3b85588c235865bac2e614348cb4f216d7217f53b3ef48c192e0a4d31d64d7bfa5faccf21155965fa156e887056db644a05ad08a85cc6152d1377d9e37b46f4ff462bbe68ace2dc586ef90070314576c985d8037c2ba63f0a7dc17a62e15bd77e88bc61d9d00858979709f12304264a4cf4225c5cf86f12c8e19486cb9cdcc69f18f027e5f16f4ca8b50e28b3115eaff3a345acd21f624aef81f6ede515c1b55b26b84c1e32264754eab672d5489b287e7277ea855e0a5ff2aa9e8b8c76d579a964ec225255f4d57bf66639ccb34b64798846943e162a41096a7002ca21c7f56"
+const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98"
+const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f"
+const revokedSubkeyHex = "988d04533121f6010400aefc803a3e4bb1a61c86e8a86d2726c6a43e0079e9f2713f1fa017e9854c83877f4aced8e331d675c67ea83ddab80aacbfa0b9040bb12d96f5a3d6be09455e2a76546cbd21677537db941cab710216b6d24ec277ee0bd65b910f416737ed120f6b93a9d3b306245c8cfd8394606fdb462e5cf43c551438d2864506c63367fc890011010001b41d416c696365203c616c69636540626d626172697374612e636f2e61753e88bb041301020025021b03060b090807030206150802090a0b0416020301021e01021780050253312798021901000a09104ef7e4beccde97f015a803ff5448437780f63263b0df8442a995e7f76c221351a51edd06f2063d8166cf3157aada4923dfc44aa0f2a6a4da5cf83b7fe722ba8ab416c976e77c6b5682e7f1069026673bd0de56ba06fd5d7a9f177607f277d9b55ff940a638c3e68525c67517e2b3d976899b93ca267f705b3e5efad7d61220e96b618a4497eab8d04403d23f8846041011020006050253312910000a09107b15a67f0b3ddc03d96e009f50b6365d86c4be5d5e9d0ea42d5e56f5794c617700a0ab274e19c2827780016d23417ce89e0a2c0d987d889c04100102000605025331cf7a000a0910a401d9f09a34f7c0ee970400aca292f213041c9f3b3fc49148cbda9d84afee6183c8dd6c5ff2600b29482db5fecd4303797be1ee6d544a20a858080fec43412061c9a71fae4039fd58013b4ae341273e6c66ad4c7cdd9e68245bedb260562e7b166f2461a1032f2b38c0e0e5715fb3d1656979e052b55ca827a76f872b78a9fdae64bc298170bfcebedc1271b41a416c696365203c616c696365407379646973702e6f722e61753e88b804130102002205025331278b021b03060b090807030206150802090a0b0416020301021e01021780000a09104ef7e4beccde97f06a7003fa03c3af68d272ebc1fa08aa72a03b02189c26496a2833d90450801c4e42c5b5f51ad96ce2d2c9cef4b7c02a6a2fcf1412d6a2d486098eb762f5010a201819c17fd2888aec8eda20c65a3b75744de7ee5cc8ac7bfc470cbe3cb982720405a27a3c6a8c229cfe36905f881b02ed5680f6a8f05866efb9d6c5844897e631deb949ca8846041011020006050253312910000a09107b15a67f0b3ddc0347bc009f7fa35db59147469eb6f2c5aaf6428accb138b22800a0caa2f5f0874bacc5909c652a57a31beda65eddd5889c04100102000605025331cf7a000a0910a401d9f09a34f7c0316403ff46f2a5c101256627f16384d34a38fb47a6c88ba60506843e532d91614339fccae5f884a5741e7582ffaf292ba38ee10a270a05f139bde3814b6a077e8cd2db0f105ebea2a83af70d385f13b507fac2ad93ff79d84950328bb86f3074745a8b7f9b64990fb142e2a12976e27e8d09a28dc5621f957ac49091116da410ac3cbde1b88d04533121f6010400cbd785b56905e4192e2fb62a720727d43c4fa487821203cf72138b884b78b701093243e1d8c92a0248a6c0203a5a88693da34af357499abacaf4b3309c640797d03093870a323b4b6f37865f6eaa2838148a67df4735d43a90ca87942554cdf1c4a751b1e75f9fd4ce4e97e278d6c1c7ed59d33441df7d084f3f02beb68896c70011010001889f0418010200090502533121f6021b0c000a09104ef7e4beccde97f0b98b03fc0a5ccf6a372995835a2f5da33b282a7d612c0ab2a97f59cf9fff73e9110981aac2858c41399afa29624a7fd8a0add11654e3d882c0fd199e161bdad65e5e2548f7b68a437ea64293db1246e3011cbb94dc1bcdeaf0f2539bd88ff16d95547144d97cead6a8c5927660a91e6db0d16eb36b7b49a3525b54d1644e65599b032b7eb901a204533127a0110400bd3edaa09eff9809c4edc2c2a0ebe52e53c50a19c1e49ab78e6167bf61473bb08f2050d78a5cbbc6ed66aff7b42cd503f16b4a0b99fa1609681fca9b7ce2bbb1a5b3864d6cdda4d7ef7849d156d534dea30fb0efb9e4cf8959a2b2ce623905882d5430b995a15c3b9fe92906086788b891002924f94abe139b42cbbfaaabe42f00a0b65dc1a1ad27d798adbcb5b5ad02d2688c89477b03ff4eebb6f7b15a73b96a96bed201c0e5e4ea27e4c6e2dd1005b94d4b90137a5b1cf5e01c6226c070c4cc999938101578877ee76d296b9aab8246d57049caacf489e80a3f40589cade790a020b1ac146d6f7a6241184b8c7fcde680eae3188f5dcbe846d7f7bdad34f6fcfca08413e19c1d5df83fc7c7c627d493492e009c2f52a80400a2fe82de87136fd2e8845888c4431b032ba29d9a29a804277e31002a8201fb8591a3e55c7a0d0881496caf8b9fb07544a5a4879291d0dc026a0ea9e5bd88eb4aa4947bbd694b25012e208a250d65ddc6f1eea59d3aed3b4ec15fcab85e2afaa23a40ab1ef9ce3e11e1bc1c34a0e758e7aa64deb8739276df0af7d4121f834a9b88e70418010200090502533127a0021b02005209104ef7e4beccde97f047200419110200060502533127a0000a0910dbce4ee19529437fe045009c0b32f5ead48ee8a7e98fac0dea3d3e6c0e2c552500a0ad71fadc5007cfaf842d9b7db3335a8cdad15d3d1a6404009b08e2c68fe8f3b45c1bb72a4b3278cdf3012aa0f229883ad74aa1f6000bb90b18301b2f85372ca5d6b9bf478d235b733b1b197d19ccca48e9daf8e890cb64546b4ce1b178faccfff07003c172a2d4f5ebaba9f57153955f3f61a9b80a4f5cb959908f8b211b03b7026a8a82fc612bfedd3794969bcf458c4ce92be215a1176ab88d045331d144010400a5063000c5aaf34953c1aa3bfc95045b3aab9882b9a8027fecfe2142dc6b47ba8aca667399990244d513dd0504716908c17d92c65e74219e004f7b83fc125e575dd58efec3ab6dd22e3580106998523dea42ec75bf9aa111734c82df54630bebdff20fe981cfc36c76f865eb1c2fb62c9e85bc3a6e5015a361a2eb1c8431578d0011010001889f04280102000905025331d433021d03000a09104ef7e4beccde97f02e5503ff5e0630d1b65291f4882b6d40a29da4616bb5088717d469fbcc3648b8276de04a04988b1f1b9f3e18f52265c1f8b6c85861691c1a6b8a3a25a1809a0b32ad330aec5667cb4262f4450649184e8113849b05e5ad06a316ea80c001e8e71838190339a6e48bbde30647bcf245134b9a97fa875c1d83a9862cae87ffd7e2c4ce3a1b89013d04180102000905025331d144021b0200a809104ef7e4beccde97f09d2004190102000605025331d144000a0910677815e371c2fd23522203fe22ab62b8e7a151383cea3edd3a12995693911426f8ccf125e1f6426388c0010f88d9ca7da2224aee8d1c12135998640c5e1813d55a93df472faae75bef858457248db41b4505827590aeccf6f9eb646da7f980655dd3050c6897feddddaca90676dee856d66db8923477d251712bb9b3186b4d0114daf7d6b59272b53218dd1da94a03ff64006fcbe71211e5daecd9961fba66cdb6de3f914882c58ba5beddeba7dcb950c1156d7fba18c19ea880dccc800eae335deec34e3b84ac75ffa24864f782f87815cda1c0f634b3dd2fa67cea30811d21723d21d9551fa12ccbcfa62b6d3a15d01307b99925707992556d50065505b090aadb8579083a20fe65bd2a270da9b011"
+
+const missingCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Charset: UTF-8
+
+mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY
+ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG
+zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54
+QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ
+QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo
+9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu
+Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/
+dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R
+JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL
+ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew
+RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW
+/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu
+yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAJcXQeP+NmuciE99YcJoffxv
+2gVLU4ZXBNHEaP0mgaJ1+tmMD089vUQAcyGRvw8jfsNsVZQIOAuRxY94aHQhIRHR
+bUzBN28ofo/AJJtfx62C15xt6fDKRV6HXYqAiygrHIpEoRLyiN69iScUsjIJeyFL
+C8wa72e8pSL6dkHoaV1N9ZH/xmrJ+k0vsgkQaAh9CzYufncDxcwkoP+aOlGtX1gP
+WwWoIbz0JwLEMPHBWvDDXQcQPQTYQyj+LGC9U6f9VZHN25E94subM1MjuT9OhN9Y
+MLfWaaIc5WyhLFyQKW2Upofn9wSFi8ubyBnv640Dfd0rVmaWv7LNTZpoZ/GbJAMA
+EQEAAYkBHwQYAQIACQUCU5ygeQIbAgAKCRDt1A0FCB6SP0zCB/sEzaVR38vpx+OQ
+MMynCBJrakiqDmUZv9xtplY7zsHSQjpd6xGflbU2n+iX99Q+nav0ETQZifNUEd4N
+1ljDGQejcTyKD6Pkg6wBL3x9/RJye7Zszazm4+toJXZ8xJ3800+BtaPoI39akYJm
++ijzbskvN0v/j5GOFJwQO0pPRAFtdHqRs9Kf4YanxhedB4dIUblzlIJuKsxFit6N
+lgGRblagG3Vv2eBszbxzPbJjHCgVLR3RmrVezKOsZjr/2i7X+xLWIR0uD3IN1qOW
+CXQxLBizEEmSNVNxsp7KPGTLnqO3bPtqFirxS9PJLIMPTPLNBY7ZYuPNTMqVIUWF
+4artDmrG
+=7FfJ
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const invalidCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY
+ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG
+zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54
+QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ
+QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo
+9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu
+Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/
+dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R
+JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL
+ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew
+RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW
+/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu
+yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAIINDqlj7X6jYKc6DjwrOkjQ
+UIRWbQQar0LwmNilehmt70g5DCL1SYm9q4LcgJJ2Nhxj0/5qqsYib50OSWMcKeEe
+iRXpXzv1ObpcQtI5ithp0gR53YPXBib80t3bUzomQ5UyZqAAHzMp3BKC54/vUrSK
+FeRaxDzNLrCeyI00+LHNUtwghAqHvdNcsIf8VRumK8oTm3RmDh0TyjASWYbrt9c8
+R1Um3zuoACOVy+mEIgIzsfHq0u7dwYwJB5+KeM7ZLx+HGIYdUYzHuUE1sLwVoELh
++SHIGHI1HDicOjzqgajShuIjj5hZTyQySVprrsLKiXS6NEwHAP20+XjayJ/R3tEA
+EQEAAYkCPgQYAQIBKAUCU5ygeQIbAsBdIAQZAQIABgUCU5ygeQAKCRCpVlnFZmhO
+52RJB/9uD1MSa0wjY6tHOIgquZcP3bHBvHmrHNMw9HR2wRCMO91ZkhrpdS3ZHtgb
+u3/55etj0FdvDo1tb8P8FGSVtO5Vcwf5APM8sbbqoi8L951Q3i7qt847lfhu6sMl
+w0LWFvPTOLHrliZHItPRjOltS1WAWfr2jUYhsU9ytaDAJmvf9DujxEOsN5G1YJep
+54JCKVCkM/y585Zcnn+yxk/XwqoNQ0/iJUT9qRrZWvoeasxhl1PQcwihCwss44A+
+YXaAt3hbk+6LEQuZoYS73yR3WHj+42tfm7YxRGeubXfgCEz/brETEWXMh4pe0vCL
+bfWrmfSPq2rDegYcAybxRQz0lF8PAAoJEO3UDQUIHpI/exkH/0vQfdHA8g/N4T6E
+i6b1CUVBAkvtdJpCATZjWPhXmShOw62gkDw306vHPilL4SCvEEi4KzG72zkp6VsB
+DSRcpxCwT4mHue+duiy53/aRMtSJ+vDfiV1Vhq+3sWAck/yUtfDU9/u4eFaiNok1
+8/Gd7reyuZt5CiJnpdPpjCwelK21l2w7sHAnJF55ITXdOxI8oG3BRKufz0z5lyDY
+s2tXYmhhQIggdgelN8LbcMhWs/PBbtUr6uZlNJG2lW1yscD4aI529VjwJlCeo745
+U7pO4eF05VViUJ2mmfoivL3tkhoTUWhx8xs8xCUcCg8DoEoSIhxtOmoTPR22Z9BL
+6LCg2mg=
+=Dhm4
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const goodCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mI0EVUqeVwEEAMufHRrMPWK3gyvi0O0tABCs/oON9zV9KDZlr1a1M91ShCSFwCPo
+7r80PxdWVWcj0V5h50/CJYtpN3eE/mUIgW2z1uDYQF1OzrQ8ubrksfsJvpAhENom
+lTQEppv9mV8qhcM278teb7TX0pgrUHLYF5CfPdp1L957JLLXoQR/lwLVABEBAAG0
+E2dvb2Qtc2lnbmluZy1zdWJrZXmIuAQTAQIAIgUCVUqeVwIbAwYLCQgHAwIGFQgC
+CQoLBBYCAwECHgECF4AACgkQNRjL95IRWP69XQQAlH6+eyXJN4DZTLX78KGjHrsw
+6FCvxxClEPtPUjcJy/1KCRQmtLAt9PbbA78dvgzjDeZMZqRAwdjyJhjyg/fkU2OH
+7wq4ktjUu+dLcOBb+BFMEY+YjKZhf6EJuVfxoTVr5f82XNPbYHfTho9/OABKH6kv
+X70PaKZhbwnwij8Nts65AaIEVUqftREEAJ3WxZfqAX0bTDbQPf2CMT2IVMGDfhK7
+GyubOZgDFFjwUJQvHNvsrbeGLZ0xOBumLINyPO1amIfTgJNm1iiWFWfmnHReGcDl
+y5mpYG60Mb79Whdcer7CMm3AqYh/dW4g6IB02NwZMKoUHo3PXmFLxMKXnWyJ0clw
+R0LI/Qn509yXAKDh1SO20rqrBM+EAP2c5bfI98kyNwQAi3buu94qo3RR1ZbvfxgW
+CKXDVm6N99jdZGNK7FbRifXqzJJDLcXZKLnstnC4Sd3uyfyf1uFhmDLIQRryn5m+
+LBYHfDBPN3kdm7bsZDDq9GbTHiFZUfm/tChVKXWxkhpAmHhU/tH6GGzNSMXuIWSO
+aOz3Rqq0ED4NXyNKjdF9MiwD/i83S0ZBc0LmJYt4Z10jtH2B6tYdqnAK29uQaadx
+yZCX2scE09UIm32/w7pV77CKr1Cp/4OzAXS1tmFzQ+bX7DR+Gl8t4wxr57VeEMvl
+BGw4Vjh3X8//m3xynxycQU18Q1zJ6PkiMyPw2owZ/nss3hpSRKFJsxMLhW3fKmKr
+Ey2KiOcEGAECAAkFAlVKn7UCGwIAUgkQNRjL95IRWP5HIAQZEQIABgUCVUqftQAK
+CRD98VjDN10SqkWrAKDTpEY8D8HC02E/KVC5YUI01B30wgCgurpILm20kXEDCeHp
+C5pygfXw1DJrhAP+NyPJ4um/bU1I+rXaHHJYroYJs8YSweiNcwiHDQn0Engh/mVZ
+SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/
+MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70=
+=vtbN
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const revokedUserIDKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFsgO5EBCADhREPmcjsPkXe1z7ctvyWL0S7oa9JaoGZ9oPDHFDlQxd0qlX2e
+DZJZDg0qYvVixmaULIulApq1puEsaJCn3lHUbHlb4PYKwLEywYXM28JN91KtLsz/
+uaEX2KC5WqeP40utmzkNLq+oRX/xnRMgwbO7yUNVG2UlEa6eI+xOXO3YtLdmJMBW
+ClQ066ZnOIzEo1JxnIwha1CDBMWLLfOLrg6l8InUqaXbtEBbnaIYO6fXVXELUjkx
+nmk7t/QOk0tXCy8muH9UDqJkwDUESY2l79XwBAcx9riX8vY7vwC34pm22fAUVLCJ
+x1SJx0J8bkeNp38jKM2Zd9SUQqSbfBopQ4pPABEBAAG0I0dvbGFuZyBHb3BoZXIg
+PG5vLXJlcGx5QGdvbGFuZy5jb20+iQFUBBMBCgA+FiEE5Ik5JLcNx6l6rZfw1oFy
+9I6cUoMFAlsgO5ECGwMFCQPCZwAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ
+1oFy9I6cUoMIkwf8DNPeD23i4jRwd/pylbvxwZintZl1fSwTJW1xcOa1emXaEtX2
+depuqhP04fjlRQGfsYAQh7X9jOJxAHjTmhqFBi5sD7QvKU00cPFYbJ/JTx0B41bl
+aXnSbGhRPh63QtEZL7ACAs+shwvvojJqysx7kyVRu0EW2wqjXdHwR/SJO6nhNBa2
+DXzSiOU/SUA42mmG+5kjF8Aabq9wPwT9wjraHShEweNerNMmOqJExBOy3yFeyDpa
+XwEZFzBfOKoxFNkIaVf5GSdIUGhFECkGvBMB935khftmgR8APxdU4BE7XrXexFJU
+8RCuPXonm4WQOwTWR0vQg64pb2WKAzZ8HhwTGbQiR29sYW5nIEdvcGhlciA8cmV2
+b2tlZEBnb2xhbmcuY29tPokBNgQwAQoAIBYhBOSJOSS3Dcepeq2X8NaBcvSOnFKD
+BQJbIDv3Ah0AAAoJENaBcvSOnFKDfWMIAKhI/Tvu3h8fSUxp/gSAcduT6bC1JttG
+0lYQ5ilKB/58lBUA5CO3ZrKDKlzW3M8VEcvohVaqeTMKeoQd5rCZq8KxHn/KvN6N
+s85REfXfniCKfAbnGgVXX3kDmZ1g63pkxrFu0fDZjVDXC6vy+I0sGyI/Inro0Pzb
+tvn0QCsxjapKK15BtmSrpgHgzVqVg0cUp8vqZeKFxarYbYB2idtGRci4b9tObOK0
+BSTVFy26+I/mrFGaPrySYiy2Kz5NMEcRhjmTxJ8jSwEr2O2sUR0yjbgUAXbTxDVE
+/jg5fQZ1ACvBRQnB7LvMHcInbzjyeTM3FazkkSYQD6b97+dkWwb1iWG5AQ0EWyA7
+kQEIALkg04REDZo1JgdYV4x8HJKFS4xAYWbIva1ZPqvDNmZRUbQZR2+gpJGEwn7z
+VofGvnOYiGW56AS5j31SFf5kro1+1bZQ5iOONBng08OOo58/l1hRseIIVGB5TGSa
+PCdChKKHreJI6hS3mShxH6hdfFtiZuB45rwoaArMMsYcjaezLwKeLc396cpUwwcZ
+snLUNd1Xu5EWEF2OdFkZ2a1qYdxBvAYdQf4+1Nr+NRIx1u1NS9c8jp3PuMOkrQEi
+bNtc1v6v0Jy52mKLG4y7mC/erIkvkQBYJdxPaP7LZVaPYc3/xskcyijrJ/5ufoD8
+K71/ShtsZUXSQn9jlRaYR0EbojMAEQEAAYkBPAQYAQoAJhYhBOSJOSS3Dcepeq2X
+8NaBcvSOnFKDBQJbIDuRAhsMBQkDwmcAAAoJENaBcvSOnFKDkFMIAIt64bVZ8x7+
+TitH1bR4pgcNkaKmgKoZz6FXu80+SnbuEt2NnDyf1cLOSimSTILpwLIuv9Uft5Pb
+OraQbYt3xi9yrqdKqGLv80bxqK0NuryNkvh9yyx5WoG1iKqMj9/FjGghuPrRaT4l
+QinNAghGVkEy1+aXGFrG2DsOC1FFI51CC2WVTzZ5RwR2GpiNRfESsU1rZAUqf/2V
+yJl9bD5R4SUNy8oQmhOxi+gbhD4Ao34e4W0ilibslI/uawvCiOwlu5NGd8zv5n+U
+heiQvzkApQup5c+BhH5zFDFdKJ2CBByxw9+7QjMFI/wgLixKuE0Ob2kAokXf7RlB
+7qTZOahrETw=
+=IKnw
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const keyWithFirstUserIDRevoked = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: OpenPGP.js v4.10.10
+Comment: https://openpgpjs.org
+
+xsBNBFsgO5EBCADhREPmcjsPkXe1z7ctvyWL0S7oa9JaoGZ9oPDHFDlQxd0q
+lX2eDZJZDg0qYvVixmaULIulApq1puEsaJCn3lHUbHlb4PYKwLEywYXM28JN
+91KtLsz/uaEX2KC5WqeP40utmzkNLq+oRX/xnRMgwbO7yUNVG2UlEa6eI+xO
+XO3YtLdmJMBWClQ066ZnOIzEo1JxnIwha1CDBMWLLfOLrg6l8InUqaXbtEBb
+naIYO6fXVXELUjkxnmk7t/QOk0tXCy8muH9UDqJkwDUESY2l79XwBAcx9riX
+8vY7vwC34pm22fAUVLCJx1SJx0J8bkeNp38jKM2Zd9SUQqSbfBopQ4pPABEB
+AAHNIkdvbGFuZyBHb3BoZXIgPHJldm9rZWRAZ29sYW5nLmNvbT7CwI0EMAEK
+ACAWIQTkiTkktw3HqXqtl/DWgXL0jpxSgwUCWyA79wIdAAAhCRDWgXL0jpxS
+gxYhBOSJOSS3Dcepeq2X8NaBcvSOnFKDfWMIAKhI/Tvu3h8fSUxp/gSAcduT
+6bC1JttG0lYQ5ilKB/58lBUA5CO3ZrKDKlzW3M8VEcvohVaqeTMKeoQd5rCZ
+q8KxHn/KvN6Ns85REfXfniCKfAbnGgVXX3kDmZ1g63pkxrFu0fDZjVDXC6vy
++I0sGyI/Inro0Pzbtvn0QCsxjapKK15BtmSrpgHgzVqVg0cUp8vqZeKFxarY
+bYB2idtGRci4b9tObOK0BSTVFy26+I/mrFGaPrySYiy2Kz5NMEcRhjmTxJ8j
+SwEr2O2sUR0yjbgUAXbTxDVE/jg5fQZ1ACvBRQnB7LvMHcInbzjyeTM3Fazk
+kSYQD6b97+dkWwb1iWHNI0dvbGFuZyBHb3BoZXIgPG5vLXJlcGx5QGdvbGFu
+Zy5jb20+wsCrBBMBCgA+FiEE5Ik5JLcNx6l6rZfw1oFy9I6cUoMFAlsgO5EC
+GwMFCQPCZwAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AAIQkQ1oFy9I6cUoMW
+IQTkiTkktw3HqXqtl/DWgXL0jpxSgwiTB/wM094PbeLiNHB3+nKVu/HBmKe1
+mXV9LBMlbXFw5rV6ZdoS1fZ16m6qE/Th+OVFAZ+xgBCHtf2M4nEAeNOaGoUG
+LmwPtC8pTTRw8Vhsn8lPHQHjVuVpedJsaFE+HrdC0RkvsAICz6yHC++iMmrK
+zHuTJVG7QRbbCqNd0fBH9Ik7qeE0FrYNfNKI5T9JQDjaaYb7mSMXwBpur3A/
+BP3COtodKETB416s0yY6okTEE7LfIV7IOlpfARkXMF84qjEU2QhpV/kZJ0hQ
+aEUQKQa8EwH3fmSF+2aBHwA/F1TgETtetd7EUlTxEK49eiebhZA7BNZHS9CD
+rilvZYoDNnweHBMZzsBNBFsgO5EBCAC5INOERA2aNSYHWFeMfByShUuMQGFm
+yL2tWT6rwzZmUVG0GUdvoKSRhMJ+81aHxr5zmIhluegEuY99UhX+ZK6NftW2
+UOYjjjQZ4NPDjqOfP5dYUbHiCFRgeUxkmjwnQoSih63iSOoUt5kocR+oXXxb
+YmbgeOa8KGgKzDLGHI2nsy8Cni3N/enKVMMHGbJy1DXdV7uRFhBdjnRZGdmt
+amHcQbwGHUH+PtTa/jUSMdbtTUvXPI6dz7jDpK0BImzbXNb+r9CcudpiixuM
+u5gv3qyJL5EAWCXcT2j+y2VWj2HN/8bJHMoo6yf+bn6A/Cu9f0obbGVF0kJ/
+Y5UWmEdBG6IzABEBAAHCwJMEGAEKACYWIQTkiTkktw3HqXqtl/DWgXL0jpxS
+gwUCWyA7kQIbDAUJA8JnAAAhCRDWgXL0jpxSgxYhBOSJOSS3Dcepeq2X8NaB
+cvSOnFKDkFMIAIt64bVZ8x7+TitH1bR4pgcNkaKmgKoZz6FXu80+SnbuEt2N
+nDyf1cLOSimSTILpwLIuv9Uft5PbOraQbYt3xi9yrqdKqGLv80bxqK0NuryN
+kvh9yyx5WoG1iKqMj9/FjGghuPrRaT4lQinNAghGVkEy1+aXGFrG2DsOC1FF
+I51CC2WVTzZ5RwR2GpiNRfESsU1rZAUqf/2VyJl9bD5R4SUNy8oQmhOxi+gb
+hD4Ao34e4W0ilibslI/uawvCiOwlu5NGd8zv5n+UheiQvzkApQup5c+BhH5z
+FDFdKJ2CBByxw9+7QjMFI/wgLixKuE0Ob2kAokXf7RlB7qTZOahrETw=
+=+2T8
+-----END PGP PUBLIC KEY BLOCK-----
+`
+
+const keyWithOnlyUserIDRevoked = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEYYwB7RYJKwYBBAHaRw8BAQdARimqhPPzyGAXmfQJjcqM1QVPzLtURJSzNVll
+JV4tEaW0KVJldm9rZWQgUHJpbWFyeSBVc2VyIElEIDxyZXZva2VkQGtleS5jb20+
+iHgEMBYIACAWIQSpyJZAXYqVEFkjyKutFcS0yeB0LQUCYYwCtgIdAAAKCRCtFcS0
+yeB0LbSsAQD8OYMaaBjrdzzpwIkP1stgmPd4/kzN/ZG28Ywl6a5F5QEA5Xg7aq4e
+/t6Fsb4F5iqB956kSPe6YJrikobD/tBbMwSIkAQTFggAOBYhBKnIlkBdipUQWSPI
+q60VxLTJ4HQtBQJhjAHtAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEK0V
+xLTJ4HQtBaoBAPZL7luTCji+Tqhn7XNfFE/0QIahCt8k9wfO1cGlB3inAQDf8Tzw
+ZGR5fNluUcNoVxQT7bUSFStbaGo3k0BaOYPbCLg4BGGMAe0SCisGAQQBl1UBBQEB
+B0DLwSpveSrbIO/IVZD13yrs1XuB3FURZUnafGrRq7+jUAMBCAeIeAQYFggAIBYh
+BKnIlkBdipUQWSPIq60VxLTJ4HQtBQJhjAHtAhsMAAoJEK0VxLTJ4HQtZ1oA/j9u
+8+p3xTNzsmabTL6BkNbMeB/RUKCrlm6woM6AV+vxAQCcXTn3JC2sNoNrLoXuVzaA
+mcG3/TwG5GSQUUPkrDsGDA==
+=mFWy
+-----END PGP PUBLIC KEY BLOCK-----
+`
+
+const keyWithSubKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mI0EWyKwKQEEALwXhKBnyaaNFeK3ljfc/qn9X/QFw+28EUfgZPHjRmHubuXLE2uR
+s3ZoSXY2z7Dkv+NyHYMt8p+X8q5fR7JvUjK2XbPyKoiJVnHINll83yl67DaWfKNL
+EjNoO0kIfbXfCkZ7EG6DL+iKtuxniGTcnGT47e+HJSqb/STpLMnWwXjBABEBAAG0
+I0dvbGFuZyBHb3BoZXIgPG5vLXJlcGx5QGdvbGFuZy5jb20+iM4EEwEKADgWIQQ/
+lRafP/p9PytHbwxMvYJsOQdOOAUCWyKwKQIbAwULCQgHAwUVCgkICwUWAgMBAAIe
+AQIXgAAKCRBMvYJsOQdOOOsFBAC62mXww8XuqvYLcVOvHkWLT6mhxrQOJXnlfpn7
+2uBV9CMhoG/Ycd43NONsJrB95Apr9TDIqWnVszNbqPCuBhZQSGLdbiDKjxnCWBk0
+69qv4RNtkpOhYB7jK4s8F5oQZqId6JasT/PmJTH92mhBYhhTQr0GYFuPX2UJdkw9
+Sn9C67iNBFsisDUBBAC3A+Yo9lgCnxi/pfskyLrweYif6kIXWLAtLTsM6g/6jt7b
+wTrknuCPyTv0QKGXsAEe/cK/Xq3HvX9WfXPGIHc/X56ZIsHQ+RLowbZV/Lhok1IW
+FAuQm8axr/by80cRwFnzhfPc/ukkAq2Qyj4hLsGblu6mxeAhzcp8aqmWOO2H9QAR
+AQABiLYEKAEKACAWIQQ/lRafP/p9PytHbwxMvYJsOQdOOAUCWyK16gIdAAAKCRBM
+vYJsOQdOOB1vA/4u4uLONsE+2GVOyBsHyy7uTdkuxaR9b54A/cz6jT/tzUbeIzgx
+22neWhgvIEghnUZd0vEyK9k1wy5vbDlEo6nKzHso32N1QExGr5upRERAxweDxGOj
+7luDwNypI7QcifE64lS/JmlnunwRCdRWMKc0Fp+7jtRc5mpwyHN/Suf5RokBagQY
+AQoAIBYhBD+VFp8/+n0/K0dvDEy9gmw5B044BQJbIrA1AhsCAL8JEEy9gmw5B044
+tCAEGQEKAB0WIQSNdnkaWY6t62iX336UXbGvYdhXJwUCWyKwNQAKCRCUXbGvYdhX
+JxJSA/9fCPHP6sUtGF1o3G1a3yvOUDGr1JWcct9U+QpbCt1mZoNopCNDDQAJvDWl
+mvDgHfuogmgNJRjOMznvahbF+wpTXmB7LS0SK412gJzl1fFIpK4bgnhu0TwxNsO1
+8UkCZWqxRMgcNUn9z6XWONK8dgt5JNvHSHrwF4CxxwjL23AAtK+FA/UUoi3U4kbC
+0XnSr1Sl+mrzQi1+H7xyMe7zjqe+gGANtskqexHzwWPUJCPZ5qpIa2l8ghiUim6b
+4ymJ+N8/T8Yva1FaPEqfMzzqJr8McYFm0URioXJPvOAlRxdHPteZ0qUopt/Jawxl
+Xt6B9h1YpeLoJwjwsvbi98UTRs0jXwoY
+=3fWu
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const keyWithSubKeyAndBadSelfSigOrder = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mI0EWyLLDQEEAOqIOpJ/ha1OYAGduu9tS3rBz5vyjbNgJO4sFveEM0mgsHQ0X9/L
+plonW+d0gRoO1dhJ8QICjDAc6+cna1DE3tEb5m6JtQ30teLZuqrR398Cf6w7NNVz
+r3lrlmnH9JaKRuXl7tZciwyovneBfZVCdtsRZjaLI1uMQCz/BToiYe3DABEBAAG0
+I0dvbGFuZyBHb3BoZXIgPG5vLXJlcGx5QGdvbGFuZy5jb20+iM4EEwEKADgWIQRZ
+sixZOfQcZdW0wUqmgmdsv1O9xgUCWyLLDQIbAwULCQgHAwUVCgkICwUWAgMBAAIe
+AQIXgAAKCRCmgmdsv1O9xql2A/4pix98NxjhdsXtazA9agpAKeADf9tG4Za27Gj+
+3DCww/E4iP2X35jZimSm/30QRB6j08uGCqd9vXkkJxtOt63y/IpVOtWX6vMWSTUm
+k8xKkaYMP0/IzKNJ1qC/qYEUYpwERBKg9Z+k99E2Ql4kRHdxXUHq6OzY79H18Y+s
+GdeM/riNBFsiyxsBBAC54Pxg/8ZWaZX1phGdwfe5mek27SOYpC0AxIDCSOdMeQ6G
+HPk38pywl1d+S+KmF/F4Tdi+kWro62O4eG2uc/T8JQuRDUhSjX0Qa51gPzJrUOVT
+CFyUkiZ/3ZDhtXkgfuso8ua2ChBgR9Ngr4v43tSqa9y6AK7v0qjxD1x+xMrjXQAR
+AQABiQFxBBgBCgAmAhsCFiEEWbIsWTn0HGXVtMFKpoJnbL9TvcYFAlsizTIFCQAN
+MRcAv7QgBBkBCgAdFiEEJcoVUVJIk5RWj1c/o62jUpRPICQFAlsiyxsACgkQo62j
+UpRPICQq5gQApoWIigZxXFoM0uw4uJBS5JFZtirTANvirZV5RhndwHeMN6JttaBS
+YnjyA4+n1D+zB2VqliD2QrsX12KJN6rGOehCtEIClQ1Hodo9nC6kMzzAwW1O8bZs
+nRJmXV+bsvD4sidLZLjdwOVa3Cxh6pvq4Uur6a7/UYx121hEY0Qx0s8JEKaCZ2y/
+U73GGi0D/i20VW8AWYAPACm2zMlzExKTOAV01YTQH/3vW0WLrOse53WcIVZga6es
+HuO4So0SOEAvxKMe5HpRIu2dJxTvd99Bo9xk9xJU0AoFrO0vNCRnL+5y68xMlODK
+lEw5/kl0jeaTBp6xX0HDQOEVOpPGUwWV4Ij2EnvfNDXaE1vK1kffiQFrBBgBCgAg
+AhsCFiEEWbIsWTn0HGXVtMFKpoJnbL9TvcYFAlsi0AYAv7QgBBkBCgAdFiEEJcoV
+UVJIk5RWj1c/o62jUpRPICQFAlsiyxsACgkQo62jUpRPICQq5gQApoWIigZxXFoM
+0uw4uJBS5JFZtirTANvirZV5RhndwHeMN6JttaBSYnjyA4+n1D+zB2VqliD2QrsX
+12KJN6rGOehCtEIClQ1Hodo9nC6kMzzAwW1O8bZsnRJmXV+bsvD4sidLZLjdwOVa
+3Cxh6pvq4Uur6a7/UYx121hEY0Qx0s8JEKaCZ2y/U73GRl0EAJokkXmy4zKDHWWi
+wvK9gi2gQgRkVnu2AiONxJb5vjeLhM/07BRmH6K1o+w3fOeEQp4FjXj1eQ5fPSM6
+Hhwx2CTl9SDnPSBMiKXsEFRkmwQ2AAsQZLmQZvKBkLZYeBiwf+IY621eYDhZfo+G
+1dh1WoUCyREZsJQg2YoIpWIcvw+a
+=bNRo
+-----END PGP PUBLIC KEY BLOCK-----
+`
+
+const onlySubkeyNoPrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQCVBFggvocBBAC7vBsHn7MKmS6IiiZNTXdciplVgS9cqVd+RTdIAoyNTcsiV1H0
+GQ3QtodOPeDlQDNoqinqaobd7R9g3m3hS53Nor7yBZkCWQ5x9v9JxRtoAq0sklh1
+I1X2zEqZk2l6YrfBF/64zWrhjnW3j23szkrAIVu0faQXbQ4z56tmZrw11wARAQAB
+/gdlAkdOVQG0CUdOVSBEdW1teYi4BBMBAgAiBQJYIL6HAhsDBgsJCAcDAgYVCAIJ
+CgsEFgIDAQIeAQIXgAAKCRCd1xxWp1CYAnjGA/9synn6ZXJUKAXQzySgmCZvCIbl
+rqBfEpxwLG4Q/lONhm5vthAE0z49I8hj5Gc5e2tLYUtq0o0OCRdCrYHa/efOYWpJ
+6RsK99bePOisVzmOABLIgZkcr022kHoMCmkPgv9CUGKP1yqbGl+zzAwQfUjRUmvD
+ZIcWLHi2ge4GzPMPi50B2ARYIL6cAQQAxWHnicKejAFcFcF1/3gUSgSH7eiwuBPX
+M7vDdgGzlve1o1jbV4tzrjN9jsCl6r0nJPDMfBSzgLr1auNTRG6HpJ4abcOx86ED
+Ad+avDcQPZb7z3dPhH/gb2lQejZsHh7bbeOS8WMSzHV3RqCLd8J/xwWPNR5zKn1f
+yp4IGfopidMAEQEAAQAD+wQOelnR82+dxyM2IFmZdOB9wSXQeCVOvxSaNMh6Y3lk
+UOOkO8Nlic4x0ungQRvjoRs4wBmCuwFK/MII6jKui0B7dn/NDf51i7rGdNGuJXDH
+e676By1sEY/NGkc74jr74T+5GWNU64W0vkpfgVmjSAzsUtpmhJMXsc7beBhJdnVl
+AgDKCb8hZqj1alcdmLoNvb7ibA3K/V8J462CPD7bMySPBa/uayoFhNxibpoXml2r
+oOtHa5izF3b0/9JY97F6rqkdAgD6GdTJ+xmlCoz1Sewoif1I6krq6xoa7gOYpIXo
+UL1Afr+LiJeyAnF/M34j/kjIVmPanZJjry0kkjHE5ILjH3uvAf4/6n9np+Th8ujS
+YDCIzKwR7639+H+qccOaddCep8Y6KGUMVdD/vTKEx1rMtK+hK/CDkkkxnFslifMJ
+kqoqv3WUqCWJAT0EGAECAAkFAlggvpwCGwIAqAkQndccVqdQmAKdIAQZAQIABgUC
+WCC+nAAKCRDmGUholQPwvQk+A/9latnSsR5s5/1A9TFki11GzSEnfLbx46FYOdkW
+n3YBxZoPQGxNA1vIn8GmouxZInw9CF4jdOJxEdzLlYQJ9YLTLtN5tQEMl/19/bR8
+/qLacAZ9IOezYRWxxZsyn6//jfl7A0Y+FV59d4YajKkEfItcIIlgVBSW6T+TNQT3
+R+EH5HJ/A/4/AN0CmBhhE2vGzTnVU0VPrE4V64pjn1rufFdclgpixNZCuuqpKpoE
+VVHn6mnBf4njKjZrAGPs5kfQ+H4NsM7v3Zz4yV6deu9FZc4O6E+V1WJ38rO8eBix
+7G2jko106CC6vtxsCPVIzY7aaG3H5pjRtomw+pX7SzrQ7FUg2PGumg==
+=F/T0
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const ecdsaPrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xaUEX1KsSRMIKoZIzj0DAQcCAwTpYqJsnJiFhKKh+8TulWD+lVmerBFNS+Ii
+B+nlG3T0xQQ4Sy5eIjJ0CExIQQzi3EElF/Z2l4F3WC5taFA11NgA/gkDCHSS
+PThf1M2K4LN8F1MRcvR+sb7i0nH55ojkwuVB1DE6jqIT9m9i+mX1tzjSAS+6
+lPQiweCJvG7xTC7Hs3AzRapf/r1At4TB+v+5G2/CKynNFEJpbGwgPGJpbGxA
+aG9tZS5jb20+wncEEBMIAB8FAl9SrEkGCwkHCAMCBBUICgIDFgIBAhkBAhsD
+Ah4BAAoJEMpwT3+q3+xqw5UBAMebZN9isEZ1ML+R/jWAAWMwa/knMugrEZ1v
+Bl9+ZwM0AQCZdf80/wYY4Nve01qSRFv8OmKswLli3TvDv6FKc4cLz8epBF9S
+rEkSCCqGSM49AwEHAgMEAjKnT9b5wY2bf9TpAV3d7OUfPOxKj9c4VzeVzSrH
+AtQgo/MuI1cdYVURicV4i76DNjFhQHQFTk7BrC+C2u1yqQMBCAf+CQMIHImA
+iYfzQtjgQWSFZYUkCFpbbwhNF0ch+3HNaZkaHCnZRIsWsRnc6FCb6lRQyK9+
+Dq59kHlduE5QgY40894jfmP2JdJHU6nBdYrivbEdbMJhBBgTCAAJBQJfUqxJ
+AhsMAAoJEMpwT3+q3+xqUI0BAMykhV08kQ4Ip9Qlbss6Jdufv7YrU0Vd5hou
+b5TmiPd0APoDBh3qIic+aLLUcAuG3+Gt1P1AbUlmqV61ozn1WfHxfw==
+=KLN8
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const dsaPrivateKeyWithElGamalSubkey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lQOBBF9/MLsRCACeaF6BI0jTgDAs86t8/kXPfwlPvR2MCYzB0BCqAdcq1hV/GTYd
+oNmJRna/ZJfsI/vf+d8Nv+EYOQkPheFS1MJVBitkAXjQPgm8i1tQWen1FCWZxqGk
+/vwZYF4yo8GhZ+Wxi3w09W9Cp9QM/CTmyE1Xe7wpPBGe+oD+me8Zxjyt8JBS4Qx+
+gvWbfHxfHnggh4pz7U8QkItlLsBNQEdX4R5+zwRN66g2ZSX/shaa/EkVnihUhD7r
+njP9I51ORWucTQD6OvgooaNQZCkQ/Se9TzdakwWKS2XSIFXiY/e2E5ZgKI/pfKDU
+iA/KessxddPb7nP/05OIJqg9AoDrD4vmehLzAQD+zsUS3LDU1m9/cG4LMsQbT2VK
+Te4HqbGIAle+eu/asQf8DDJMrbZpiJZvADum9j0TJ0oep6VdMbzo9RSDKvlLKT9m
+kG63H8oDWnCZm1a+HmGq9YIX+JHWmsLXXsFLeEouLzHO+mZo0X28eji3V2T87hyR
+MmUM0wFo4k7jK8uVmkDXv3XwNp2uByWxUKZd7EnWmcEZWqIiexJ7XpCS0Pg3tRaI
+zxve0SRe/dxfUPnTk/9KQ9hS6DWroBKquL182zx1Fggh4LIWWE2zq+UYn8BI0E8A
+rmIDFJdF8ymFQGRrEy6g79NnkPmkrZWsgMRYY65P6v4zLVmqohJKkpm3/Uxa6QAP
+CCoPh/JTOvPeCP2bOJH8z4Z9Py3ouMIjofQW8sXqRgf/RIHbh0KsINHrwwZ4gVIr
+MK3RofpaYxw1ztPIWb4cMWoWZHH1Pxh7ggTGSBpAhKXkiWw2Rxat8QF5aA7e962c
+bLvVv8dqsPrD/RnVJHag89cbPTzjn7gY9elE8EM8ithV3oQkwHTr4avYlpDZsgNd
+hUW3YgRwGo31tdzxoG04AcpV2t+07P8XMPr9hsfWs4rHohXPi38Hseu1Ji+dBoWQ
+3+1w/HH3o55s+jy4Ruaz78AIrjbmAJq+6rA2mIcCgrhw3DnzuwQAKeBvSeqn9zfS
+ZC812osMBVmkycwelpaIh64WZ0vWL3GvdXDctV2kXM+qVpDTLEny0LuiXxrwCKQL
+Ev4HAwK9uQBcreDEEud7pfRb8EYP5lzO2ZA7RaIvje6EWAGBvJGMRT0QQE5SGqc7
+Fw5geigBdt+vVyRuNNhg3c2fdn/OBQaYu0J/8AiOogG8EaM8tCFlbGdhbWFsQGRz
+YS5jb20gPGVsZ2FtYWxAZHNhLmNvbT6IkAQTEQgAOBYhBI+gnfiHQxB35/Dp0XAQ
+aE/rsWC5BQJffzC7AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEHAQaE/r
+sWC5A4EA/0GcJmyPtN+Klc7b9sVT3JgKTRnB/URxOJfYJofP0hZLAQCkqyMO+adV
+JvbgDH0zaITQWZSSXPqpgMpCA6juTrDsd50CawRffzC7EAgAxFFFSAAEQzWTgKU5
+EBtpxxoPzHqcChawTHRxHxjcELXzmUBS5PzfA1HXSPnNqK/x3Ut5ycC3CsW41Fnt
+Gm3706Wu9VFbFZVn55F9lPiplUo61n5pqMvOr1gmuQsdXiTa0t5FRa4TZ2VSiHFw
+vdAVSPTUsT4ZxJ1rPyFYRtq1n3pQcvdZowd07r0JnzTMjLLMFYCKhwIowoOC4zqJ
+iB8enjwOlpaqBATRm9xpVF7SJkroPF6/B1vdhj7E3c1aJyHlo0PYBAg756sSHWHg
+UuLyUQ4TA0hcCVenn/L/aSY2LnbdZB1EBhlYjA7dTCgwIqsQhfQmPkjz6g64A7+Y
+HbbrLwADBQgAk14QIEQ+J/VHetpQV/jt2pNsFK1kVK7mXK0spTExaC2yj2sXlHjL
+Ie3bO5T/KqmIaBEB5db5fA5xK9cZt79qrQHDKsEqUetUeMUWLBx77zBsus3grIgy
+bwDZKseRzQ715pwxquxQlScGoDIBKEh08HpwHkq140eIj3w+MAIfndaZaSCNaxaP
+Snky7BQmJ7Wc7qrIwoQP6yrnUqyW2yNi81nJYUhxjChqaFSlwzLs/iNGryBKo0ic
+BqVIRjikKHBlwBng6WyrltQo/Vt9GG8w+lqaAVXbJRlaBZJUR+2NKi/YhP3qQse3
+v8fi4kns0gh5LK+2C01RvdX4T49QSExuIf4HAwLJqYIGwadA2uem5v7/765ZtFWV
+oL0iZ0ueTJDby4wTFDpLVzzDi/uVcB0ZRFrGOp7w6OYcNYTtV8n3xmli2Q5Trw0c
+wZVzvg+ABKWiv7faBjMczIFF8y6WZKOIeAQYEQgAIBYhBI+gnfiHQxB35/Dp0XAQ
+aE/rsWC5BQJffzC7AhsMAAoJEHAQaE/rsWC5ZmIA/jhS4r4lClbvjuPWt0Yqdn7R
+fss2SPMYvMrrDh42aE0OAQD8xn4G6CN8UtW9xihXOY6FpxiJ/sMc2VaneeUd34oa
+4g==
+=XZm8
+-----END PGP PRIVATE KEY BLOCK-----`
+
+// https://tests.sequoia-pgp.org/#Certificate_expiration
+// P _ U p
+const expiringPrimaryUIDKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xsDNBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv
+/seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz
+/56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/
+5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3
+X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv
+9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0
+qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb
+SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb
+vLIwa3T4CyshfT0AEQEAAc0hQm9iIEJhYmJhZ2UgPGJvYkBvcGVucGdwLmV4YW1w
+bGU+wsFcBBMBCgCQBYJhesp/BYkEWQPJBQsJCAcCCRD7/MgqAV5zMEcUAAAAAAAe
+ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeEOQlNyTLFkc9I/elp+BpY
+495V7KatqtDmsyDr+zDAdwYVCgkICwIEFgIDAQIXgAIbAwIeARYhBNGmbhojsYLJ
+mA94jPv8yCoBXnMwAABSCQv/av8hKyynMtXVKFuWOGJw0mR8auDm84WdhMFRZg8t
+yTJ1L88+Ny4WUAFeqo2j7DU2yPGrm5rmuvzlEedFYFeOWt+A4adz+oumgRd0nsgG
+Lf3QYUWQhLWVlz+H7zubgKqSB2A2RqV65S7mTTVro42nb2Mng6rvGWiqeKG5nrXN
+/01p1mIBQGR/KnZSqYLzA2Pw2PiJoSkXT26PDz/kiEMXpjKMR6sicV4bKVlEdUvm
+pIImIPBHZq1EsKXEyWtWC41w/pc+FofGE+uSFs2aef1vvEHFkj3BHSK8gRcH3kfR
+eFroTET8C2q9V1AOELWm+Ys6PzGzF72URK1MKXlThuL4t4LjvXWGNA78IKW+/RQH
+DzK4U0jqSO0mL6qxqVS5Ij6jjL6OTrVEGdtDf5n0vI8tcUTBKtVqYAYk+t2YGT05
+ayxALtb7viVKo8f10WEcCuKshn0gdsEFMRZQzJ89uQIY3R3FbsdRCaE6OEaDgKMQ
+UTFROyfhthgzRKbRxfcplMUCzsDNBF2lnPIBDADWML9cbGMrp12CtF9b2P6z9TTT
+74S8iyBOzaSvdGDQY/sUtZXRg21HWamXnn9sSXvIDEINOQ6A9QxdxoqWdCHrOuW3
+ofneYXoG+zeKc4dC86wa1TR2q9vW+RMXSO4uImA+Uzula/6k1DogDf28qhCxMwG/
+i/m9g1c/0aApuDyKdQ1PXsHHNlgd/Dn6rrd5y2AObaifV7wIhEJnvqgFXDN2RXGj
+LeCOHV4Q2WTYPg/S4k1nMXVDwZXrvIsA0YwIMgIT86Rafp1qKlgPNbiIlC1g9RY/
+iFaGN2b4Ir6GDohBQSfZW2+LXoPZuVE/wGlQ01rh827KVZW4lXvqsge+wtnWlszc
+selGATyzqOK9LdHPdZGzROZYI2e8c+paLNDdVPL6vdRBUnkCaEkOtl1mr2JpQi5n
+TU+gTX4IeInC7E+1a9UDF/Y85ybUz8XV8rUnR76UqVC7KidNepdHbZjjXCt8/Zo+
+Tec9JNbYNQB/e9ExmDntmlHEsSEQzFwzj8sxH48AEQEAAcLA9gQYAQoAIBYhBNGm
+bhojsYLJmA94jPv8yCoBXnMwBQJdpZzyAhsMAAoJEPv8yCoBXnMw6f8L/26C34dk
+jBffTzMj5Bdzm8MtF67OYneJ4TQMw7+41IL4rVcSKhIhk/3Ud5knaRtP2ef1+5F6
+6h9/RPQOJ5+tvBwhBAcUWSupKnUrdVaZQanYmtSxcVV2PL9+QEiNN3tzluhaWO//
+rACxJ+K/ZXQlIzwQVTpNhfGzAaMVV9zpf3u0k14itcv6alKY8+rLZvO1wIIeRZLm
+U0tZDD5HtWDvUV7rIFI1WuoLb+KZgbYn3OWjCPHVdTrdZ2CqnZbG3SXw6awH9bzR
+LV9EXkbhIMez0deCVdeo+wFFklh8/5VK2b0vk/+wqMJxfpa1lHvJLobzOP9fvrsw
+sr92MA2+k901WeISR7qEzcI0Fdg8AyFAExaEK6VyjP7SXGLwvfisw34OxuZr3qmx
+1Sufu4toH3XrB7QJN8XyqqbsGxUCBqWif9RSK4xjzRTe56iPeiSJJOIciMP9i2ld
+I+KgLycyeDvGoBj0HCLO3gVaBe4ubVrj5KjhX2PVNEJd3XZRzaXZE2aAMQ==
+=AmgT
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const rsa2048PrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Comment: gpg (GnuPG) 2.2.27 with libgcrypt 1.9.4
+
+lQPGBGL07P0BCADL0etN8efyAXA6sL2WfQvHe5wEKYXPWeN2+jiqSppfeRZAOlzP
+kZ3U+cloeJriplYvVJwI3ID2aw52Z/TRn8iKRP5eOUFrEgcgl06lazLtOndK7o7p
+oBV5mLtHEirFHm6W61fNt10jzM0jx0PV6nseLhFB2J42F1cmU/aBgFo41wjLSZYr
+owR+v+O9S5sUXblQF6sEDcY01sBEu09zrIgT49VFwQ1Cvdh9XZEOTQBfdiugoj5a
+DS3fAqAka3r1VoQK4eR7/upnYSgSACGeaQ4pUelKku5rpm50gdWTY8ppq0k9e1eT
+y2x0OQcW3hWE+j4os1ca0ZEADMdqr/99MOxrABEBAAH+BwMCJWxU4VOZOJ7/I6vX
+FxdfBhIBEXlJ52FM3S/oYtXqLhkGyrtmZOeEazVvUtuCe3M3ScHI8xCthcmE8E0j
+bi+ZEHPS2NiBZtgHFF27BLn7zZuTc+oD5WKduZdK3463egnyThTqIIMl25WZBuab
+k5ycwYrWwBH0jfA4gwJ13ai4pufKC2RM8qIu6YAVPglYBKFLKGvvJHa5vI+LuA0E
+K+k35hIic7yVUcQneNnAF2598X5yWiieYnOZpmHlRw1zfbMwOJr3ZNj2v94u7b+L
+sTa/1Uv9887Vb6sJp0c2Sh4cwEccoPYkvMqFn3ZrJUr3UdDu1K2vWohPtswzhrYV
++RdPZE5RLoCQufKvlPezk0Pzhzb3bBU7XjUbdGY1nH/EyQeBNp+Gw6qldKvzcBaB
+cyOK1c6hPSszpJX93m5UxCN55IeifmcNjmbDh8vGCCdajy6d56qV2n4F3k7vt1J1
+0UlxIGhqijJoaTCX66xjLMC6VXkSz6aHQ35rnXosm/cqPcQshsZTdlfSyWkorfdr
+4Hj8viBER26mjYurTMLBKDtUN724ZrR0Ev5jorX9uoKlgl87bDZHty2Ku2S+vR68
+VAvnj6Fi1BYNclnDoqxdRB2z5T9JbWE52HuG83/QsplhEqXxESDxriTyTHMbNxEe
+88soVCDh4tgflZFa2ucUr6gEKJKij7jgahARnyaXfPZlQBUAS1YUeILYmN+VR+M/
+sHENpwDWc7TInn8VN638nJV+ScZGMih3AwWZTIoiLju3MMt1K0YZ3NuiqwGH4Jwg
+/BbEdTWeCci9y3NEQHQ3uZZ5p6j2CwFVlK11idemCMvAiTVxF+gKdaLMkeCwKxru
+J3YzhKEo+iDVYbPYBYizx/EHBn2U5kITQ5SBXzjTaaFMNZJEf9JYsL1ybPB6HOFY
+VNVB2KT8CGVwtCJHb2xhbmcgR29waGVyIDxnb2xhbmdAZXhhbXBsZS5vcmc+iQFO
+BBMBCgA4FiEEC6K7U7f4qesybTnqSkra7gHusm0FAmL07P0CGwMFCwkIBwIGFQoJ
+CAsCBBYCAwECHgECF4AACgkQSkra7gHusm1MvwgAxpClWkeSqIhMQfbiuz0+lOkE
+89y1DCFw8bHjZoUf4/4K8hFA3dGkk+q72XFgiyaCpfXxMt6Gi+dN47t+tTv9NIqC
+sukbaoJBmJDhN6+djmJOgOYy+FWsW2LAk2LOwKYulpnBZdcA5rlMAhBg7gevQpF+
+ruSU69P7UUaFJl/DC7hDmaIcj+4cjBE/HO26SnVQjoTfjZT82rDh1Wsuf8LnkJUk
+b3wezBLpXKjDvdHikdv4gdlR4AputVM38aZntYYglh/EASo5TneyZ7ZscdLNRdcF
+r5O2fKqrOJLOdaoYRFZZWOvP5GtEVFDU7WGivOSVfiszBE0wZR3dgZRJipHCXJ0D
+xgRi9Oz9AQgAtMJcJqLLVANJHl90tWuoizDkm+Imcwq2ubQAjpclnNrODnDK+7o4
+pBsWmXbZSdkC4gY+LhOQA6bPDD0JEHM58DOnrm49BddxXAyK0HPsk4sGGt2SS86B
+OawWNdfJVyqw4bAiHWDmQg4PcjBbt3ocOIxAR6I5kBSiQVxuGQs9T+Zvg3G1r3Or
+fS6DzlgY3HFUML5YsGH4lOxNSOoKAP68GIH/WNdUZ+feiRg9knIib6I3Hgtf5eO8
+JRH7aWE/TD7eNu36bLLjT5TZPq5r6xaD2plbtPOyXbNPWs9qI1yG+VnErfaLY0w8
+Qo0aqzbgID+CTZVomXSOpOcQseaFKw8ZfQARAQAB/gcDArha6+/+d4OY/w9N32K9
+hFNYt4LufTETMQ+k/sBeaMuAVzmT47DlAXzkrZhGW4dZOtXMu1rXaUwHlqkhEyzL
+L4MYEWVXfD+LbZNEK3MEFss6RK+UAMeT/PTV9aA8cXQVPcSJYzfBXHQ1U1hnOgrO
+apn92MN8RmkhX8wJLyeWTMMuP4lXByJMmmGo8WvifeRD2kFY4y0WVBDAXJAV4Ljf
+Di/bBiwoc5a+gxHuZT2W9ZSxBQJNXdt4Un2IlyZuo58s5MLx2N0EaNJ8PwRUE6fM
+RZYO8aZCEPUtINE4njbvsWOMCtrblsMPwZ1B0SiIaWmLaNyGdCNKea+fCIW7kasC
+JYMhnLumpUTXg5HNexkCsl7ABWj0PYBflOE61h8EjWpnQ7JBBVKS2ua4lMjwHRX7
+5o5yxym9k5UZNFdGoXVL7xpizCcdGawxTJvwhs3vBqu1ZWYCegOAZWDrOkCyhUpq
+8uKMROZFbn+FwE+7tjt+v2ed62FVEvD6g4V3ThCA6mQqeOARfJWN8GZY8BDm8lht
+crOXriUkrx+FlrgGtm2CkwjW5/9Xd7AhFpHnQdFeozOHyq1asNSgJF9sNi9Lz94W
+skQSVRi0IExxSXYGI3Y0nnAZUe2BAQflYPJdEveSr3sKlUqXiETTA1VXsTPK3kOC
+92CbLzj/Hz199jZvywwyu53I+GKMpF42rMq7zxr2oa61YWY4YE/GDezwwys/wLx/
+QpCW4X3ppI7wJjCSSqEV0baYZSSli1ayheS6dxi8QnSpX1Bmpz6gU7m/M9Sns+hl
+J7ZvgpjCAiV7KJTjtclr5/S02zP78LTVkoTWoz/6MOTROwaP63VBUXX8pbJhf/vu
+DLmNnDk8joMJxoDXWeNU0EnNl4hP7Z/jExRBOEO4oAnUf/Sf6gCWQhL5qcajtg6w
+tGv7vx3f2IkBNgQYAQoAIBYhBAuiu1O3+KnrMm056kpK2u4B7rJtBQJi9Oz9AhsM
+AAoJEEpK2u4B7rJt6lgIAMBWqP4BCOGnQXBbgJ0+ACVghpkFUXZTb/tXJc8UUvTM
+8uov6k/RsqDGZrvhhufD7Wwt7j9v7dD7VPp7bPyjVWyimglQzWguTUUqLDGlstYH
+5uYv1pzma0ZsAGNqFeGlTLsKOSGKFMH4rB2KfN2n51L8POvtp1y7GKZQbWIWneaB
+cZr3BINU5GMvYYU7pAYcoR+mJPdJx5Up3Ocn+bn8Tu1sy9C/ArtCQucazGnoE9u1
+HhNLrh0CdzzX7TNH6TQ8LwPOvq0K5l/WqbN9lE0WBBhMv2HydxhluO8AhU+A5GqC
+C+wET7nVDnhoOm/fstIeb7/LN7OYejKPeHdFBJEL9GA=
+=u442
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const curve25519PrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Comment: gpg (GnuPG) 2.2.27 with libgcrypt 1.9.4
+
+lFgEYvTtQBYJKwYBBAHaRw8BAQdAxsNXLbrk5xOjpO24VhOMvQ0/F+JcyIkckMDH
+X3FIGxcAAQDFOlunZWYuPsCx5JLp78vKqUTfgef9TGG4oD6I/Sa0zBMstCJHb2xh
+bmcgR29waGVyIDxnb2xhbmdAZXhhbXBsZS5vcmc+iJAEExYIADgWIQSFQHEOazmo
+h1ldII4MvfnLQ4JBNwUCYvTtQAIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK
+CRAMvfnLQ4JBN5yeAQCKdry8B5ScCPrev2+UByMCss7Sdu5RhomCFsHdNPLcKAEA
+8ugei+1owHsV+3cGwWWzKk6sLa8ZN87i3SKuOGp9DQycXQRi9O1AEgorBgEEAZdV
+AQUBAQdA5CubPp8l7lrVQ25h7Hx5XN2C8xanRnnpcjzEooCaEA0DAQgHAAD/Rpc+
+sOZUXrFk9HOWB1XU41LoWbDBoG8sP8RWAVYwD5AQRYh4BBgWCAAgFiEEhUBxDms5
+qIdZXSCODL35y0OCQTcFAmL07UACGwwACgkQDL35y0OCQTcvdwEA7lb5g/YisrEf
+iq660uwMGoepLUfvtqKzuQ6heYe83y0BAN65Ffg5HYOJzUEi0kZQRf7OhdtuL2kJ
+SRXn8DmCTfEB
+=cELM
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const curve448PrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Comment: C1DB 65D5 80D7 B922 7254 4B1E A699 9895 FABA CE52
+
+xYUEYV2UmRYDK2VxAc9AFyxgh5xnSbyt50TWl558mw9xdMN+/UBLr5+UMP8IsrvV
+MdXuTIE8CyaUQKSotHtH2RkYEXj5nsMAAAHPQIbTMSzjIWug8UFECzAex5FHgAgH
+gYF3RK+TS8D24wX8kOu2C/NoVxwGY+p+i0JHaB+7yljriSKAGxs6wsBEBB8WCgCD
+BYJhXZSZBYkFpI+9AwsJBwkQppmYlfq6zlJHFAAAAAAAHgAgc2FsdEBub3RhdGlv
+bnMuc2VxdW9pYS1wZ3Aub3Jn5wSpIutJ5HncJWk4ruUV8GzQF390rR5+qWEAnAoY
+akcDFQoIApsBAh4BFiEEwdtl1YDXuSJyVEseppmYlfq6zlIAALzdA5dA/fsgYg/J
+qaQriYKaPUkyHL7EB3BXhV2d1h/gk+qJLvXQuU2WEJ/XSs3GrsBRiiZwvPH4o+7b
+mleAxjy5wpS523vqrrBR2YZ5FwIku7WS4litSdn4AtVam/TlLdMNIf41CtFeZKBe
+c5R5VNdQy8y7qy8AAADNEUN1cnZlNDQ4IE9wdGlvbiA4wsBHBBMWCgCGBYJhXZSZ
+BYkFpI+9AwsJBwkQppmYlfq6zlJHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2Vx
+dW9pYS1wZ3Aub3JnD55UsYMzE6OACP+mgw5zvT+BBgol8/uFQjHg4krjUCMDFQoI
+ApkBApsBAh4BFiEEwdtl1YDXuSJyVEseppmYlfq6zlIAAPQJA5dA0Xqwzn/0uwCq
+RlsOVCB3f5NOj1exKnlBvRw0xT1VBee1yxvlUt5eIAoCxWoRlWBJob3TTkhm9AEA
+8dyhwPmyGfWHzPw5NFG3xsXrZdNXNvit9WMVAPcmsyR7teXuDlJItxRAdJJc/qfJ
+YVbBFoaNrhYAAADHhQRhXZSZFgMrZXEBz0BL7THZ9MnCLfSPJ1FMLim9eGkQ3Bfn
+M3he5rOwO3t14QI1LjI96OjkeJipMgcFAmEP1Bq/ZHGO7oAAAc9AFnE8iNBaT3OU
+EFtxkmWHXtdaYMmGGRdopw9JPXr/UxuunDln5o9dxPxf7q7z26zXrZen+qed/Isa
+HsDCwSwEGBYKAWsFgmFdlJkFiQWkj70JEKaZmJX6us5SRxQAAAAAAB4AIHNhbHRA
+bm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZxREUizdTcepBzgSMOv2VWQCWbl++3CZ
+EbgAWDryvSsyApsCwDGgBBkWCgBvBYJhXZSZCRBKo3SL4S5djkcUAAAAAAAeACBz
+YWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmemoGTDjmNQiIzw6HOEddvS0OB7
+UZ/P07jM/EVmnYxTlBYhBAxsnkGpx1UCiH6gUUqjdIvhLl2OAAALYQOXQAMB1oKq
+OWxSFmvmgCKNcbAAyA3piF5ERIqs4z07oJvqDYrOWt75UsEIH/04gU/vHc4EmfG2
+JDLJgOLlyTUPkL/08f0ydGZPofFQBhn8HkuFFjnNtJ5oz3GIP4cdWMQFaUw0uvjb
+PM9Tm3ptENGd6Ts1AAAAFiEEwdtl1YDXuSJyVEseppmYlfq6zlIAAGpTA5dATR6i
+U2GrpUcQgpG+JqfAsGmF4yAOhgFxc1UfidFk3nTup3fLgjipkYY170WLRNbyKkVO
+Sodx93GAs58rizO1acDAWiLq3cyEPBFXbyFThbcNPcLl+/77Uk/mgkYrPQFAQWdK
+1kSRm4SizDBK37K8ChAAAADHhwRhXZSZEgMrZW8Bx0DMhzvhQo+OsXeqQ6QVw4sF
+CaexHh6rLohh7TzL3hQSjoJ27fV6JBkIWdn0LfrMlJIDbSv2SLdlgQMBCgkAAcdA
+MO7Dc1myF6Co1fAH+EuP+OxhxP/7V6ljuSCZENDfA49tQkzTta+PniG+pOVB2LHb
+huyaKBkqiaogo8LAOQQYFgoAeAWCYV2UmQWJBaSPvQkQppmYlfq6zlJHFAAAAAAA
+HgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JnEjBMQAmc/2u45u5FQGmB
+QAytjSG2LM3JQN+PPVl5vEkCmwwWIQTB22XVgNe5InJUSx6mmZiV+rrOUgAASdYD
+l0DXEHQ9ykNP2rZP35ET1dmiFagFtTj/hLQcWlg16LqvJNGqOgYXuqTerbiOOt02
+XLCBln+wdewpU4ChEffMUDRBfqfQco/YsMqWV7bHJHAO0eC/DMKCjyU90xdH7R/d
+QgqsfguR1PqPuJxpXV4bSr6CGAAAAA==
+=MSvh
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const keyWithNotation = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xVgEY9gIshYJKwYBBAHaRw8BAQdAF25fSM8OpFlXZhop4Qpqo5ywGZ4jgWlR
+ppjhIKDthREAAQC+LFpzFcMJYcjxGKzBGHN0Px2jU4d04YSRnFAik+lVVQ6u
+zRdUZXN0IDx0ZXN0QGV4YW1wbGUuY29tPsLACgQQFgoAfAUCY9gIsgQLCQcI
+CRD/utJOCym8pR0UgAAAAAAQAAR0ZXh0QGV4YW1wbGUuY29tdGVzdB8UAAAA
+AAASAARiaW5hcnlAZXhhbXBsZS5jb20AAQIDAxUICgQWAAIBAhkBAhsDAh4B
+FiEEEMCQTUVGKgCX5rDQ/7rSTgspvKUAAPl5AP9Npz90LxzrB97Qr2DrGwfG
+wuYn4FSYwtuPfZHHeoIabwD/QEbvpQJ/NBb9EAZuow4Rirlt1yv19mmnF+j5
+8yUzhQjHXQRj2AiyEgorBgEEAZdVAQUBAQdARXAo30DmKcyUg6co7OUm0RNT
+z9iqFbDBzA8A47JEt1MDAQgHAAD/XKK3lBm0SqMR558HLWdBrNG6NqKuqb5X
+joCML987ZNgRD8J4BBgWCAAqBQJj2AiyCRD/utJOCym8pQIbDBYhBBDAkE1F
+RioAl+aw0P+60k4LKbylAADRxgEAg7UfBDiDPp5LHcW9D+SgFHk6+GyEU4ev
+VppQxdtxPvAA/34snHBX7Twnip1nMt7P4e2hDiw/hwQ7oqioOvc6jMkP
+=Z8YJ
+-----END PGP PRIVATE KEY BLOCK-----
+`
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
new file mode 100644
index 0000000000..ef100d372b
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
@@ -0,0 +1,67 @@
+// Copyright (C) 2019 ProtonTech AG
+
+package packet
+
+import "math/bits"
+
+// CipherSuite contains a combination of Cipher and Mode
+type CipherSuite struct {
+ // The cipher function
+ Cipher CipherFunction
+ // The AEAD mode of operation.
+ Mode AEADMode
+}
+
+// AEADConfig collects a number of AEAD parameters along with sensible defaults.
+// A nil AEADConfig is valid and results in all default values.
+type AEADConfig struct {
+ // The AEAD mode of operation.
+ DefaultMode AEADMode
+ // Amount of octets in each chunk of data
+ ChunkSize uint64
+}
+
+// Mode returns the AEAD mode of operation.
+func (conf *AEADConfig) Mode() AEADMode {
+ // If no preference is specified, OCB is used (which is mandatory to implement).
+ if conf == nil || conf.DefaultMode == 0 {
+ return AEADModeOCB
+ }
+
+ mode := conf.DefaultMode
+ if mode != AEADModeEAX && mode != AEADModeOCB && mode != AEADModeGCM {
+ panic("AEAD mode unsupported")
+ }
+ return mode
+}
+
+// ChunkSizeByte returns the byte indicating the chunk size. The effective
+// chunk size is computed with the formula uint64(1) << (chunkSizeByte + 6)
+// limit chunkSizeByte to 16 which equals to 2^22 = 4 MiB
+// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2
+func (conf *AEADConfig) ChunkSizeByte() byte {
+ if conf == nil || conf.ChunkSize == 0 {
+ return 12 // 1 << (12 + 6) == 262144 bytes
+ }
+
+ chunkSize := conf.ChunkSize
+ exponent := bits.Len64(chunkSize) - 1
+ switch {
+ case exponent < 6:
+ exponent = 6
+ case exponent > 22:
+ exponent = 22
+ }
+
+ return byte(exponent - 6)
+}
+
+// decodeAEADChunkSize returns the effective chunk size. In 32-bit systems, the
+// maximum returned value is 1 << 30.
+func decodeAEADChunkSize(c byte) int {
+ size := uint64(1 << (c + 6))
+ if size != uint64(int(size)) {
+ return 1 << 30
+ }
+ return int(size)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go
new file mode 100644
index 0000000000..5e46046563
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go
@@ -0,0 +1,250 @@
+// Copyright (C) 2019 ProtonTech AG
+
+package packet
+
+import (
+ "crypto/cipher"
+ "encoding/binary"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+// aeadCrypter is an AEAD opener/sealer, its configuration, and data for en/decryption.
+type aeadCrypter struct {
+ aead cipher.AEAD
+ chunkSize int
+ nonce []byte
+ associatedData []byte // Chunk-independent associated data
+ chunkIndex []byte // Chunk counter
+ packetTag packetType // SEIP packet (v2) or AEAD Encrypted Data packet
+ bytesProcessed int // Amount of plaintext bytes encrypted/decrypted
+}
+
+// computeNonce takes the incremental index and computes an eXclusive OR with
+// the least significant 8 bytes of the receivers' initial nonce (see sec.
+// 5.16.1 and 5.16.2). It returns the resulting nonce.
+func (wo *aeadCrypter) computeNextNonce() (nonce []byte) {
+ if wo.packetTag == packetTypeSymmetricallyEncryptedIntegrityProtected {
+ return wo.nonce
+ }
+
+ nonce = make([]byte, len(wo.nonce))
+ copy(nonce, wo.nonce)
+ offset := len(wo.nonce) - 8
+ for i := 0; i < 8; i++ {
+ nonce[i+offset] ^= wo.chunkIndex[i]
+ }
+ return
+}
+
+// incrementIndex performs an integer increment by 1 of the integer represented by the
+// slice, modifying it accordingly.
+func (wo *aeadCrypter) incrementIndex() error {
+ index := wo.chunkIndex
+ if len(index) == 0 {
+ return errors.AEADError("Index has length 0")
+ }
+ for i := len(index) - 1; i >= 0; i-- {
+ if index[i] < 255 {
+ index[i]++
+ return nil
+ }
+ index[i] = 0
+ }
+ return errors.AEADError("cannot further increment index")
+}
+
+// aeadDecrypter reads and decrypts bytes. It buffers extra decrypted bytes when
+// necessary, similar to aeadEncrypter.
+type aeadDecrypter struct {
+ aeadCrypter // Embedded ciphertext opener
+ reader io.Reader // 'reader' is a partialLengthReader
+ chunkBytes []byte
+ peekedBytes []byte // Used to detect last chunk
+ buffer []byte // Buffered decrypted bytes
+}
+
+// Read decrypts bytes and reads them into dst. It decrypts when necessary and
+// buffers extra decrypted bytes. It returns the number of bytes copied into dst
+// and an error.
+func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) {
+ // Return buffered plaintext bytes from previous calls
+ if len(ar.buffer) > 0 {
+ n = copy(dst, ar.buffer)
+ ar.buffer = ar.buffer[n:]
+ return
+ }
+
+ // Read a chunk
+ tagLen := ar.aead.Overhead()
+ copy(ar.chunkBytes, ar.peekedBytes) // Copy bytes peeked in previous chunk or in initialization
+ bytesRead, errRead := io.ReadFull(ar.reader, ar.chunkBytes[tagLen:])
+ if errRead != nil && errRead != io.EOF && errRead != io.ErrUnexpectedEOF {
+ return 0, errRead
+ }
+
+ if bytesRead > 0 {
+ ar.peekedBytes = ar.chunkBytes[bytesRead:bytesRead+tagLen]
+
+ decrypted, errChunk := ar.openChunk(ar.chunkBytes[:bytesRead])
+ if errChunk != nil {
+ return 0, errChunk
+ }
+
+ // Return decrypted bytes, buffering if necessary
+ n = copy(dst, decrypted)
+ ar.buffer = decrypted[n:]
+ return
+ }
+
+ return 0, io.EOF
+}
+
+// Close checks the final authentication tag of the stream.
+// In the future, this function could also be used to wipe the reader
+// and peeked & decrypted bytes, if necessary.
+func (ar *aeadDecrypter) Close() (err error) {
+ errChunk := ar.validateFinalTag(ar.peekedBytes)
+ if errChunk != nil {
+ return errChunk
+ }
+ return nil
+}
+
+// openChunk decrypts and checks integrity of an encrypted chunk, returning
+// the underlying plaintext and an error. It accesses peeked bytes from next
+// chunk, to identify the last chunk and decrypt/validate accordingly.
+func (ar *aeadDecrypter) openChunk(data []byte) ([]byte, error) {
+ adata := ar.associatedData
+ if ar.aeadCrypter.packetTag == packetTypeAEADEncrypted {
+ adata = append(ar.associatedData, ar.chunkIndex...)
+ }
+
+ nonce := ar.computeNextNonce()
+ plainChunk, err := ar.aead.Open(data[:0:len(data)], nonce, data, adata)
+ if err != nil {
+ return nil, errors.ErrAEADTagVerification
+ }
+ ar.bytesProcessed += len(plainChunk)
+ if err = ar.aeadCrypter.incrementIndex(); err != nil {
+ return nil, err
+ }
+ return plainChunk, nil
+}
+
+// Checks the summary tag. It takes into account the total decrypted bytes into
+// the associated data. It returns an error, or nil if the tag is valid.
+func (ar *aeadDecrypter) validateFinalTag(tag []byte) error {
+ // Associated: tag, version, cipher, aead, chunk size, ...
+ amountBytes := make([]byte, 8)
+ binary.BigEndian.PutUint64(amountBytes, uint64(ar.bytesProcessed))
+
+ adata := ar.associatedData
+ if ar.aeadCrypter.packetTag == packetTypeAEADEncrypted {
+ // ... index ...
+ adata = append(ar.associatedData, ar.chunkIndex...)
+ }
+
+ // ... and total number of encrypted octets
+ adata = append(adata, amountBytes...)
+ nonce := ar.computeNextNonce()
+ if _, err := ar.aead.Open(nil, nonce, tag, adata); err != nil {
+ return errors.ErrAEADTagVerification
+ }
+ return nil
+}
+
+// aeadEncrypter encrypts and writes bytes. It encrypts when necessary according
+// to the AEAD block size, and buffers the extra encrypted bytes for next write.
+type aeadEncrypter struct {
+ aeadCrypter // Embedded plaintext sealer
+ writer io.WriteCloser // 'writer' is a partialLengthWriter
+ chunkBytes []byte
+ offset int
+}
+
+// Write encrypts and writes bytes. It encrypts when necessary and buffers extra
+// plaintext bytes for next call. When the stream is finished, Close() MUST be
+// called to append the final tag.
+func (aw *aeadEncrypter) Write(plaintextBytes []byte) (n int, err error) {
+ for n != len(plaintextBytes) {
+ copied := copy(aw.chunkBytes[aw.offset:aw.chunkSize], plaintextBytes[n:])
+ n += copied
+ aw.offset += copied
+
+ if aw.offset == aw.chunkSize {
+ encryptedChunk, err := aw.sealChunk(aw.chunkBytes[:aw.offset])
+ if err != nil {
+ return n, err
+ }
+ _, err = aw.writer.Write(encryptedChunk)
+ if err != nil {
+ return n, err
+ }
+ aw.offset = 0
+ }
+ }
+ return
+}
+
+// Close encrypts and writes the remaining buffered plaintext if any, appends
+// the final authentication tag, and closes the embedded writer. This function
+// MUST be called at the end of a stream.
+func (aw *aeadEncrypter) Close() (err error) {
+ // Encrypt and write a chunk if there's buffered data left, or if we haven't
+ // written any chunks yet.
+ if aw.offset > 0 || aw.bytesProcessed == 0 {
+ lastEncryptedChunk, err := aw.sealChunk(aw.chunkBytes[:aw.offset])
+ if err != nil {
+ return err
+ }
+ _, err = aw.writer.Write(lastEncryptedChunk)
+ if err != nil {
+ return err
+ }
+ }
+ // Compute final tag (associated data: packet tag, version, cipher, aead,
+ // chunk size...
+ adata := aw.associatedData
+
+ if aw.aeadCrypter.packetTag == packetTypeAEADEncrypted {
+ // ... index ...
+ adata = append(aw.associatedData, aw.chunkIndex...)
+ }
+
+ // ... and total number of encrypted octets
+ amountBytes := make([]byte, 8)
+ binary.BigEndian.PutUint64(amountBytes, uint64(aw.bytesProcessed))
+ adata = append(adata, amountBytes...)
+
+ nonce := aw.computeNextNonce()
+ finalTag := aw.aead.Seal(nil, nonce, nil, adata)
+ _, err = aw.writer.Write(finalTag)
+ if err != nil {
+ return err
+ }
+ return aw.writer.Close()
+}
+
+// sealChunk Encrypts and authenticates the given chunk.
+func (aw *aeadEncrypter) sealChunk(data []byte) ([]byte, error) {
+ if len(data) > aw.chunkSize {
+ return nil, errors.AEADError("chunk exceeds maximum length")
+ }
+ if aw.associatedData == nil {
+ return nil, errors.AEADError("can't seal without headers")
+ }
+ adata := aw.associatedData
+ if aw.aeadCrypter.packetTag == packetTypeAEADEncrypted {
+ adata = append(aw.associatedData, aw.chunkIndex...)
+ }
+
+ nonce := aw.computeNextNonce()
+ encrypted := aw.aead.Seal(data[:0], nonce, data, adata)
+ aw.bytesProcessed += len(data)
+ if err := aw.aeadCrypter.incrementIndex(); err != nil {
+ return nil, err
+ }
+ return encrypted, nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
new file mode 100644
index 0000000000..583765d87c
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
@@ -0,0 +1,100 @@
+// Copyright (C) 2019 ProtonTech AG
+
+package packet
+
+import (
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+)
+
+// AEADEncrypted represents an AEAD Encrypted Packet.
+// See https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t
+type AEADEncrypted struct {
+ cipher CipherFunction
+ mode AEADMode
+ chunkSizeByte byte
+ Contents io.Reader // Encrypted chunks and tags
+ initialNonce []byte // Referred to as IV in RFC4880-bis
+}
+
+// Only currently defined version
+const aeadEncryptedVersion = 1
+
+func (ae *AEADEncrypted) parse(buf io.Reader) error {
+ headerData := make([]byte, 4)
+ if n, err := io.ReadFull(buf, headerData); n < 4 {
+ return errors.AEADError("could not read aead header:" + err.Error())
+ }
+ // Read initial nonce
+ mode := AEADMode(headerData[2])
+ nonceLen := mode.IvLength()
+
+ // This packet supports only EAX and OCB
+ // https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t
+ if nonceLen == 0 || mode > AEADModeOCB {
+ return errors.AEADError("unknown mode")
+ }
+
+ initialNonce := make([]byte, nonceLen)
+ if n, err := io.ReadFull(buf, initialNonce); n < nonceLen {
+ return errors.AEADError("could not read aead nonce:" + err.Error())
+ }
+ ae.Contents = buf
+ ae.initialNonce = initialNonce
+ c := headerData[1]
+ if _, ok := algorithm.CipherById[c]; !ok {
+ return errors.UnsupportedError("unknown cipher: " + string(c))
+ }
+ ae.cipher = CipherFunction(c)
+ ae.mode = mode
+ ae.chunkSizeByte = headerData[3]
+ return nil
+}
+
+// Decrypt returns a io.ReadCloser from which decrypted bytes can be read, or
+// an error.
+func (ae *AEADEncrypted) Decrypt(ciph CipherFunction, key []byte) (io.ReadCloser, error) {
+ return ae.decrypt(key)
+}
+
+// decrypt prepares an aeadCrypter and returns a ReadCloser from which
+// decrypted bytes can be read (see aeadDecrypter.Read()).
+func (ae *AEADEncrypted) decrypt(key []byte) (io.ReadCloser, error) {
+ blockCipher := ae.cipher.new(key)
+ aead := ae.mode.new(blockCipher)
+ // Carry the first tagLen bytes
+ chunkSize := decodeAEADChunkSize(ae.chunkSizeByte)
+ tagLen := ae.mode.TagLength()
+ chunkBytes := make([]byte, chunkSize+tagLen*2)
+ peekedBytes := chunkBytes[chunkSize+tagLen:]
+ n, err := io.ReadFull(ae.Contents, peekedBytes)
+ if n < tagLen || (err != nil && err != io.EOF) {
+ return nil, errors.AEADError("Not enough data to decrypt:" + err.Error())
+ }
+
+ return &aeadDecrypter{
+ aeadCrypter: aeadCrypter{
+ aead: aead,
+ chunkSize: chunkSize,
+ nonce: ae.initialNonce,
+ associatedData: ae.associatedData(),
+ chunkIndex: make([]byte, 8),
+ packetTag: packetTypeAEADEncrypted,
+ },
+ reader: ae.Contents,
+ chunkBytes: chunkBytes,
+ peekedBytes: peekedBytes,
+ }, nil
+}
+
+// associatedData for chunks: tag, version, cipher, mode, chunk size byte
+func (ae *AEADEncrypted) associatedData() []byte {
+ return []byte{
+ 0xD4,
+ aeadEncryptedVersion,
+ byte(ae.cipher),
+ byte(ae.mode),
+ ae.chunkSizeByte}
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
new file mode 100644
index 0000000000..931f55a4e8
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
@@ -0,0 +1,192 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "compress/bzip2"
+ "compress/flate"
+ "compress/zlib"
+ "io"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+// Compressed represents a compressed OpenPGP packet. The decompressed contents
+// will contain more OpenPGP packets. See RFC 4880, section 5.6.
+type Compressed struct {
+ Body io.Reader
+}
+
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+)
+
+// CompressionConfig contains compressor configuration settings.
+type CompressionConfig struct {
+ // Level is the compression level to use. It must be set to
+ // between -1 and 9, with -1 causing the compressor to use the
+ // default compression level, 0 causing the compressor to use
+ // no compression and 1 to 9 representing increasing (better,
+ // slower) compression levels. If Level is less than -1 or
+ // more then 9, a non-nil error will be returned during
+ // encryption. See the constants above for convenient common
+ // settings for Level.
+ Level int
+}
+
+// decompressionReader ensures that the whole compression packet is read.
+type decompressionReader struct {
+ compressed io.Reader
+ decompressed io.ReadCloser
+ readAll bool
+}
+
+func newDecompressionReader(r io.Reader, decompressor io.ReadCloser) *decompressionReader {
+ return &decompressionReader{
+ compressed: r,
+ decompressed: decompressor,
+ }
+}
+
+func (dr *decompressionReader) Read(data []byte) (n int, err error) {
+ if dr.readAll {
+ return 0, io.EOF
+ }
+ n, err = dr.decompressed.Read(data)
+ if err == io.EOF {
+ dr.readAll = true
+ // Close the decompressor.
+ if errDec := dr.decompressed.Close(); errDec != nil {
+ return n, errDec
+ }
+ // Consume all remaining data from the compressed packet.
+ consumeAll(dr.compressed)
+ }
+ return n, err
+}
+
+func (c *Compressed) parse(r io.Reader) error {
+ var buf [1]byte
+ _, err := readFull(r, buf[:])
+ if err != nil {
+ return err
+ }
+
+ switch buf[0] {
+ case 0:
+ c.Body = r
+ case 1:
+ c.Body = newDecompressionReader(r, flate.NewReader(r))
+ case 2:
+ decompressor, err := zlib.NewReader(r)
+ if err != nil {
+ return err
+ }
+ c.Body = newDecompressionReader(r, decompressor)
+ case 3:
+ c.Body = newDecompressionReader(r, io.NopCloser(bzip2.NewReader(r)))
+ default:
+ err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
+ }
+
+ return err
+}
+
+// LimitedBodyReader wraps the provided body reader with a limiter that restricts
+// the number of bytes read to the specified limit.
+// If limit is nil, the reader is unbounded.
+func (c *Compressed) LimitedBodyReader(limit *int64) io.Reader {
+ if limit == nil {
+ return c.Body
+ }
+ return &LimitReader{R: c.Body, N: *limit}
+}
+
+// compressedWriterCloser represents the serialized compression stream
+// header and the compressor. Its Close() method ensures that both the
+// compressor and serialized stream header are closed. Its Write()
+// method writes to the compressor.
+type compressedWriteCloser struct {
+ sh io.Closer // Stream Header
+ c io.WriteCloser // Compressor
+}
+
+func (cwc compressedWriteCloser) Write(p []byte) (int, error) {
+ return cwc.c.Write(p)
+}
+
+func (cwc compressedWriteCloser) Close() (err error) {
+ err = cwc.c.Close()
+ if err != nil {
+ return err
+ }
+
+ return cwc.sh.Close()
+}
+
+// SerializeCompressed serializes a compressed data packet to w and
+// returns a WriteCloser to which the literal data packets themselves
+// can be written and which MUST be closed on completion. If cc is
+// nil, sensible defaults will be used to configure the compression
+// algorithm.
+func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) {
+ compressed, err := serializeStreamHeader(w, packetTypeCompressed)
+ if err != nil {
+ return
+ }
+
+ _, err = compressed.Write([]byte{uint8(algo)})
+ if err != nil {
+ return
+ }
+
+ level := DefaultCompression
+ if cc != nil {
+ level = cc.Level
+ }
+
+ var compressor io.WriteCloser
+ switch algo {
+ case CompressionZIP:
+ compressor, err = flate.NewWriter(compressed, level)
+ case CompressionZLIB:
+ compressor, err = zlib.NewWriterLevel(compressed, level)
+ default:
+ s := strconv.Itoa(int(algo))
+ err = errors.UnsupportedError("Unsupported compression algorithm: " + s)
+ }
+ if err != nil {
+ return
+ }
+
+ literaldata = compressedWriteCloser{compressed, compressor}
+
+ return
+}
+
+// LimitReader is an io.Reader that fails with MessageToLarge if read bytes exceed N.
+type LimitReader struct {
+ R io.Reader // underlying reader
+ N int64 // max bytes allowed
+}
+
+func (l *LimitReader) Read(p []byte) (int, error) {
+ if l.N <= 0 {
+ return 0, errors.ErrMessageTooLarge
+ }
+
+ n, err := l.R.Read(p)
+ l.N -= int64(n)
+
+ if err == nil && l.N <= 0 {
+ err = errors.ErrMessageTooLarge
+ }
+
+ return n, err
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
new file mode 100644
index 0000000000..30167ed9de
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
@@ -0,0 +1,434 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "crypto/rand"
+ "io"
+ "math/big"
+ "time"
+
+ "github.com/ProtonMail/go-crypto/openpgp/s2k"
+)
+
+var (
+ defaultRejectPublicKeyAlgorithms = map[PublicKeyAlgorithm]bool{
+ PubKeyAlgoElGamal: true,
+ PubKeyAlgoDSA: true,
+ }
+ defaultRejectHashAlgorithms = map[crypto.Hash]bool{
+ crypto.MD5: true,
+ crypto.RIPEMD160: true,
+ }
+ defaultRejectMessageHashAlgorithms = map[crypto.Hash]bool{
+ crypto.SHA1: true,
+ crypto.MD5: true,
+ crypto.RIPEMD160: true,
+ }
+ defaultRejectCurves = map[Curve]bool{
+ CurveSecP256k1: true,
+ }
+)
+
+// A global feature flag to indicate v5 support.
+// Can be set via a build tag, e.g.: `go build -tags v5 ./...`
+// If the build tag is missing config_v5.go will set it to true.
+//
+// Disables parsing of v5 keys and v5 signatures.
+// These are non-standard entities, which in the crypto-refresh have been superseded
+// by v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively.
+var V5Disabled = false
+
+// Config collects a number of parameters along with sensible defaults.
+// A nil *Config is valid and results in all default values.
+type Config struct {
+ // Rand provides the source of entropy.
+ // If nil, the crypto/rand Reader is used.
+ Rand io.Reader
+ // DefaultHash is the default hash function to be used.
+ // If zero, SHA-256 is used.
+ DefaultHash crypto.Hash
+ // DefaultCipher is the cipher to be used.
+ // If zero, AES-128 is used.
+ DefaultCipher CipherFunction
+ // Time returns the current time as the number of seconds since the
+ // epoch. If Time is nil, time.Now is used.
+ Time func() time.Time
+ // DefaultCompressionAlgo is the compression algorithm to be
+ // applied to the plaintext before encryption. If zero, no
+ // compression is done.
+ DefaultCompressionAlgo CompressionAlgo
+ // CompressionConfig configures the compression settings.
+ CompressionConfig *CompressionConfig
+ // S2K (String to Key) config, used for key derivation in the context of secret key encryption
+ // and password-encrypted data.
+ // If nil, the default configuration is used
+ S2KConfig *s2k.Config
+ // Iteration count for Iterated S2K (String to Key).
+ // Only used if sk2.Mode is nil.
+ // This value is duplicated here from s2k.Config for backwards compatibility.
+ // It determines the strength of the passphrase stretching when
+ // the said passphrase is hashed to produce a key. S2KCount
+ // should be between 65536 and 65011712, inclusive. If Config
+ // is nil or S2KCount is 0, the value 16777216 used. Not all
+ // values in the above range can be represented. S2KCount will
+ // be rounded up to the next representable value if it cannot
+ // be encoded exactly. When set, it is strongly encrouraged to
+ // use a value that is at least 65536. See RFC 4880 Section
+ // 3.7.1.3.
+ //
+ // Deprecated: SK2Count should be configured in S2KConfig instead.
+ S2KCount int
+ // RSABits is the number of bits in new RSA keys made with NewEntity.
+ // If zero, then 2048 bit keys are created.
+ RSABits int
+ // The public key algorithm to use - will always create a signing primary
+ // key and encryption subkey.
+ Algorithm PublicKeyAlgorithm
+ // Some known primes that are optionally prepopulated by the caller
+ RSAPrimes []*big.Int
+ // Curve configures the desired packet.Curve if the Algorithm is PubKeyAlgoECDSA,
+ // PubKeyAlgoEdDSA, or PubKeyAlgoECDH. If empty Curve25519 is used.
+ Curve Curve
+ // AEADConfig configures the use of the new AEAD Encrypted Data Packet,
+ // defined in the draft of the next version of the OpenPGP specification.
+ // If a non-nil AEADConfig is passed, usage of this packet is enabled. By
+ // default, it is disabled. See the documentation of AEADConfig for more
+ // configuration options related to AEAD.
+ // **Note: using this option may break compatibility with other OpenPGP
+ // implementations, as well as future versions of this library.**
+ AEADConfig *AEADConfig
+ // V6Keys configures version 6 key generation. If false, this package still
+ // supports version 6 keys, but produces version 4 keys.
+ V6Keys bool
+ // Minimum RSA key size allowed for key generation and message signing, verification and encryption.
+ MinRSABits uint16
+ // Reject insecure algorithms, only works with v2 api
+ RejectPublicKeyAlgorithms map[PublicKeyAlgorithm]bool
+ RejectHashAlgorithms map[crypto.Hash]bool
+ RejectMessageHashAlgorithms map[crypto.Hash]bool
+ RejectCurves map[Curve]bool
+ // "The validity period of the key. This is the number of seconds after
+ // the key creation time that the key expires. If this is not present
+ // or has a value of zero, the key never expires. This is found only on
+ // a self-signature.""
+ // https://tools.ietf.org/html/rfc4880#section-5.2.3.6
+ KeyLifetimeSecs uint32
+ // "The validity period of the signature. This is the number of seconds
+ // after the signature creation time that the signature expires. If
+ // this is not present or has a value of zero, it never expires."
+ // https://tools.ietf.org/html/rfc4880#section-5.2.3.10
+ SigLifetimeSecs uint32
+ // SigningKeyId is used to specify the signing key to use (by Key ID).
+ // By default, the signing key is selected automatically, preferring
+ // signing subkeys if available.
+ SigningKeyId uint64
+ // SigningIdentity is used to specify a user ID (packet Signer's User ID, type 28)
+ // when producing a generic certification signature onto an existing user ID.
+ // The identity must be present in the signer Entity.
+ SigningIdentity string
+ // InsecureAllowUnauthenticatedMessages controls, whether it is tolerated to read
+ // encrypted messages without Modification Detection Code (MDC).
+ // MDC is mandated by the IETF OpenPGP Crypto Refresh draft and has long been implemented
+ // in most OpenPGP implementations. Messages without MDC are considered unnecessarily
+ // insecure and should be prevented whenever possible.
+ // In case one needs to deal with messages from very old OpenPGP implementations, there
+ // might be no other way than to tolerate the missing MDC. Setting this flag, allows this
+ // mode of operation. It should be considered a measure of last resort.
+ InsecureAllowUnauthenticatedMessages bool
+ // InsecureAllowDecryptionWithSigningKeys allows decryption with keys marked as signing keys in the v2 API.
+ // This setting is potentially insecure, but it is needed as some libraries
+ // ignored key flags when selecting a key for encryption.
+ // Not relevant for the v1 API, as all keys were allowed in decryption.
+ InsecureAllowDecryptionWithSigningKeys bool
+ // KnownNotations is a map of Notation Data names to bools, which controls
+ // the notation names that are allowed to be present in critical Notation Data
+ // signature subpackets.
+ KnownNotations map[string]bool
+ // SignatureNotations is a list of Notations to be added to any signatures.
+ SignatureNotations []*Notation
+ // CheckIntendedRecipients controls, whether the OpenPGP Intended Recipient Fingerprint feature
+ // should be enabled for encryption and decryption.
+ // (See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-intended-recipient-fingerpr).
+ // When the flag is set, encryption produces Intended Recipient Fingerprint signature sub-packets and decryption
+ // checks whether the key it was encrypted to is one of the included fingerprints in the signature.
+ // If the flag is disabled, no Intended Recipient Fingerprint sub-packets are created or checked.
+ // The default behavior, when the config or flag is nil, is to enable the feature.
+ CheckIntendedRecipients *bool
+ // CacheSessionKey controls if decryption should return the session key used for decryption.
+ // If the flag is set, the session key is cached in the message details struct.
+ CacheSessionKey bool
+ // CheckPacketSequence is a flag that controls if the pgp message reader should strictly check
+ // that the packet sequence conforms with the grammar mandated by rfc4880.
+ // The default behavior, when the config or flag is nil, is to check the packet sequence.
+ CheckPacketSequence *bool
+ // NonDeterministicSignaturesViaNotation is a flag to enable randomization of signatures.
+ // If true, a salt notation is used to randomize signatures generated by v4 and v5 keys
+ // (v6 signatures are always non-deterministic, by design).
+ // This protects EdDSA signatures from potentially leaking the secret key in case of faults (i.e. bitflips) which, in principle, could occur
+ // during the signing computation. It is added to signatures of any algo for simplicity, and as it may also serve as protection in case of
+ // weaknesses in the hash algo, potentially hindering e.g. some chosen-prefix attacks.
+ // The default behavior, when the config or flag is nil, is to enable the feature.
+ NonDeterministicSignaturesViaNotation *bool
+
+ // InsecureAllowAllKeyFlagsWhenMissing determines how a key without valid key flags is handled.
+ // When set to true, a key without flags is treated as if all flags are enabled.
+ // This behavior is consistent with GPG.
+ InsecureAllowAllKeyFlagsWhenMissing bool
+
+ // MaxDecompressedMessageSize specifies the maximum number of bytes that can be
+ // read from a compressed packet. This serves as an upper limit to prevent
+ // excessively large decompressed messages.
+ MaxDecompressedMessageSize *int64
+}
+
+func (c *Config) Random() io.Reader {
+ if c == nil || c.Rand == nil {
+ return rand.Reader
+ }
+ return c.Rand
+}
+
+func (c *Config) Hash() crypto.Hash {
+ if c == nil || uint(c.DefaultHash) == 0 {
+ return crypto.SHA256
+ }
+ return c.DefaultHash
+}
+
+func (c *Config) Cipher() CipherFunction {
+ if c == nil || uint8(c.DefaultCipher) == 0 {
+ return CipherAES128
+ }
+ return c.DefaultCipher
+}
+
+func (c *Config) Now() time.Time {
+ if c == nil || c.Time == nil {
+ return time.Now().Truncate(time.Second)
+ }
+ return c.Time().Truncate(time.Second)
+}
+
+// KeyLifetime returns the validity period of the key.
+func (c *Config) KeyLifetime() uint32 {
+ if c == nil {
+ return 0
+ }
+ return c.KeyLifetimeSecs
+}
+
+// SigLifetime returns the validity period of the signature.
+func (c *Config) SigLifetime() uint32 {
+ if c == nil {
+ return 0
+ }
+ return c.SigLifetimeSecs
+}
+
+func (c *Config) Compression() CompressionAlgo {
+ if c == nil {
+ return CompressionNone
+ }
+ return c.DefaultCompressionAlgo
+}
+
+func (c *Config) RSAModulusBits() int {
+ if c == nil || c.RSABits == 0 {
+ return 2048
+ }
+ return c.RSABits
+}
+
+func (c *Config) PublicKeyAlgorithm() PublicKeyAlgorithm {
+ if c == nil || c.Algorithm == 0 {
+ return PubKeyAlgoRSA
+ }
+ return c.Algorithm
+}
+
+func (c *Config) CurveName() Curve {
+ if c == nil || c.Curve == "" {
+ return Curve25519
+ }
+ return c.Curve
+}
+
+// Deprecated: The hash iterations should now be queried via the S2K() method.
+func (c *Config) PasswordHashIterations() int {
+ if c == nil || c.S2KCount == 0 {
+ return 0
+ }
+ return c.S2KCount
+}
+
+func (c *Config) S2K() *s2k.Config {
+ if c == nil {
+ return nil
+ }
+ // for backwards compatibility
+ if c.S2KCount > 0 && c.S2KConfig == nil {
+ return &s2k.Config{
+ S2KCount: c.S2KCount,
+ }
+ }
+ return c.S2KConfig
+}
+
+func (c *Config) AEAD() *AEADConfig {
+ if c == nil {
+ return nil
+ }
+ return c.AEADConfig
+}
+
+func (c *Config) SigningKey() uint64 {
+ if c == nil {
+ return 0
+ }
+ return c.SigningKeyId
+}
+
+func (c *Config) SigningUserId() string {
+ if c == nil {
+ return ""
+ }
+ return c.SigningIdentity
+}
+
+func (c *Config) AllowUnauthenticatedMessages() bool {
+ if c == nil {
+ return false
+ }
+ return c.InsecureAllowUnauthenticatedMessages
+}
+
+func (c *Config) AllowDecryptionWithSigningKeys() bool {
+ if c == nil {
+ return false
+ }
+ return c.InsecureAllowDecryptionWithSigningKeys
+}
+
+func (c *Config) KnownNotation(notationName string) bool {
+ if c == nil {
+ return false
+ }
+ return c.KnownNotations[notationName]
+}
+
+func (c *Config) Notations() []*Notation {
+ if c == nil {
+ return nil
+ }
+ return c.SignatureNotations
+}
+
+func (c *Config) V6() bool {
+ if c == nil {
+ return false
+ }
+ return c.V6Keys
+}
+
+func (c *Config) IntendedRecipients() bool {
+ if c == nil || c.CheckIntendedRecipients == nil {
+ return true
+ }
+ return *c.CheckIntendedRecipients
+}
+
+func (c *Config) RetrieveSessionKey() bool {
+ if c == nil {
+ return false
+ }
+ return c.CacheSessionKey
+}
+
+func (c *Config) MinimumRSABits() uint16 {
+ if c == nil || c.MinRSABits == 0 {
+ return 2047
+ }
+ return c.MinRSABits
+}
+
+func (c *Config) RejectPublicKeyAlgorithm(alg PublicKeyAlgorithm) bool {
+ var rejectedAlgorithms map[PublicKeyAlgorithm]bool
+ if c == nil || c.RejectPublicKeyAlgorithms == nil {
+ // Default
+ rejectedAlgorithms = defaultRejectPublicKeyAlgorithms
+ } else {
+ rejectedAlgorithms = c.RejectPublicKeyAlgorithms
+ }
+ return rejectedAlgorithms[alg]
+}
+
+func (c *Config) RejectHashAlgorithm(hash crypto.Hash) bool {
+ var rejectedAlgorithms map[crypto.Hash]bool
+ if c == nil || c.RejectHashAlgorithms == nil {
+ // Default
+ rejectedAlgorithms = defaultRejectHashAlgorithms
+ } else {
+ rejectedAlgorithms = c.RejectHashAlgorithms
+ }
+ return rejectedAlgorithms[hash]
+}
+
+func (c *Config) RejectMessageHashAlgorithm(hash crypto.Hash) bool {
+ var rejectedAlgorithms map[crypto.Hash]bool
+ if c == nil || c.RejectMessageHashAlgorithms == nil {
+ // Default
+ rejectedAlgorithms = defaultRejectMessageHashAlgorithms
+ } else {
+ rejectedAlgorithms = c.RejectMessageHashAlgorithms
+ }
+ return rejectedAlgorithms[hash]
+}
+
+func (c *Config) RejectCurve(curve Curve) bool {
+ var rejectedCurve map[Curve]bool
+ if c == nil || c.RejectCurves == nil {
+ // Default
+ rejectedCurve = defaultRejectCurves
+ } else {
+ rejectedCurve = c.RejectCurves
+ }
+ return rejectedCurve[curve]
+}
+
+func (c *Config) StrictPacketSequence() bool {
+ if c == nil || c.CheckPacketSequence == nil {
+ return true
+ }
+ return *c.CheckPacketSequence
+}
+
+func (c *Config) RandomizeSignaturesViaNotation() bool {
+ if c == nil || c.NonDeterministicSignaturesViaNotation == nil {
+ return true
+ }
+ return *c.NonDeterministicSignaturesViaNotation
+}
+
+func (c *Config) AllowAllKeyFlagsWhenMissing() bool {
+ if c == nil {
+ return false
+ }
+ return c.InsecureAllowAllKeyFlagsWhenMissing
+}
+
+func (c *Config) DecompressedMessageSizeLimit() *int64 {
+ if c == nil {
+ return nil
+ }
+ return c.MaxDecompressedMessageSize
+}
+
+// BoolPointer is a helper function to set a boolean pointer in the Config.
+// e.g., config.CheckPacketSequence = BoolPointer(true)
+func BoolPointer(value bool) *bool {
+ return &value
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config_v5.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config_v5.go
new file mode 100644
index 0000000000..f2415906b9
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config_v5.go
@@ -0,0 +1,7 @@
+//go:build !v5
+
+package packet
+
+func init() {
+ V5Disabled = true
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
new file mode 100644
index 0000000000..b90bb28911
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
@@ -0,0 +1,584 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/rsa"
+ "encoding/binary"
+ "encoding/hex"
+ "io"
+ "math/big"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/ecdh"
+ "github.com/ProtonMail/go-crypto/openpgp/elgamal"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
+ "github.com/ProtonMail/go-crypto/openpgp/x25519"
+ "github.com/ProtonMail/go-crypto/openpgp/x448"
+)
+
+// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
+// section 5.1.
+type EncryptedKey struct {
+ Version int
+ KeyId uint64
+ KeyVersion int // v6
+ KeyFingerprint []byte // v6
+ Algo PublicKeyAlgorithm
+ CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet
+ Key []byte // only valid after a successful Decrypt
+
+ encryptedMPI1, encryptedMPI2 encoding.Field
+ ephemeralPublicX25519 *x25519.PublicKey // used for x25519
+ ephemeralPublicX448 *x448.PublicKey // used for x448
+ encryptedSession []byte // used for x25519 and x448
+}
+
+func (e *EncryptedKey) parse(r io.Reader) (err error) {
+ var buf [8]byte
+ _, err = readFull(r, buf[:versionSize])
+ if err != nil {
+ return
+ }
+ e.Version = int(buf[0])
+ if e.Version != 3 && e.Version != 6 {
+ return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
+ }
+ if e.Version == 6 {
+ //Read a one-octet size of the following two fields.
+ if _, err = readFull(r, buf[:1]); err != nil {
+ return
+ }
+ // The size may also be zero, and the key version and
+ // fingerprint omitted for an "anonymous recipient"
+ if buf[0] != 0 {
+ // non-anonymous case
+ _, err = readFull(r, buf[:versionSize])
+ if err != nil {
+ return
+ }
+ e.KeyVersion = int(buf[0])
+ if e.KeyVersion != 4 && e.KeyVersion != 6 {
+ return errors.UnsupportedError("unknown public key version " + strconv.Itoa(e.KeyVersion))
+ }
+ var fingerprint []byte
+ if e.KeyVersion == 6 {
+ fingerprint = make([]byte, fingerprintSizeV6)
+ } else if e.KeyVersion == 4 {
+ fingerprint = make([]byte, fingerprintSize)
+ }
+ _, err = readFull(r, fingerprint)
+ if err != nil {
+ return
+ }
+ e.KeyFingerprint = fingerprint
+ if e.KeyVersion == 6 {
+ e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[:keyIdSize])
+ } else if e.KeyVersion == 4 {
+ e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[fingerprintSize-keyIdSize : fingerprintSize])
+ }
+ }
+ } else {
+ _, err = readFull(r, buf[:8])
+ if err != nil {
+ return
+ }
+ e.KeyId = binary.BigEndian.Uint64(buf[:keyIdSize])
+ }
+
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ e.Algo = PublicKeyAlgorithm(buf[0])
+ var cipherFunction byte
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ e.encryptedMPI1 = new(encoding.MPI)
+ if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
+ return
+ }
+ case PubKeyAlgoElGamal:
+ e.encryptedMPI1 = new(encoding.MPI)
+ if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
+ return
+ }
+
+ e.encryptedMPI2 = new(encoding.MPI)
+ if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
+ return
+ }
+ case PubKeyAlgoECDH:
+ e.encryptedMPI1 = new(encoding.MPI)
+ if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
+ return
+ }
+
+ e.encryptedMPI2 = new(encoding.OID)
+ if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
+ return
+ }
+ case PubKeyAlgoX25519:
+ e.ephemeralPublicX25519, e.encryptedSession, cipherFunction, err = x25519.DecodeFields(r, e.Version == 6)
+ if err != nil {
+ return
+ }
+ case PubKeyAlgoX448:
+ e.ephemeralPublicX448, e.encryptedSession, cipherFunction, err = x448.DecodeFields(r, e.Version == 6)
+ if err != nil {
+ return
+ }
+ }
+ if e.Version < 6 {
+ switch e.Algo {
+ case PubKeyAlgoX25519, PubKeyAlgoX448:
+ e.CipherFunc = CipherFunction(cipherFunction)
+ // Check for validiy is in the Decrypt method
+ }
+ }
+
+ _, err = consumeAll(r)
+ return
+}
+
+// Decrypt decrypts an encrypted session key with the given private key. The
+// private key must have been decrypted first.
+// If config is nil, sensible defaults will be used.
+func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
+ if e.Version < 6 && e.KeyId != 0 && e.KeyId != priv.KeyId {
+ return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16))
+ }
+ if e.Version == 6 && e.KeyVersion != 0 && !bytes.Equal(e.KeyFingerprint, priv.Fingerprint) {
+ return errors.InvalidArgumentError("cannot decrypt encrypted session key for key fingerprint " + hex.EncodeToString(e.KeyFingerprint) + " with private key fingerprint " + hex.EncodeToString(priv.Fingerprint))
+ }
+ if e.Algo != priv.PubKeyAlgo {
+ return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
+ }
+ if priv.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+
+ var err error
+ var b []byte
+
+ // TODO(agl): use session key decryption routines here to avoid
+ // padding oracle attacks.
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ // Supports both *rsa.PrivateKey and crypto.Decrypter
+ k := priv.PrivateKey.(crypto.Decrypter)
+ b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil)
+ case PubKeyAlgoElGamal:
+ c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes())
+ c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes())
+ b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
+ case PubKeyAlgoECDH:
+ vsG := e.encryptedMPI1.Bytes()
+ m := e.encryptedMPI2.Bytes()
+ oid := priv.PublicKey.oid.EncodedBytes()
+ fp := priv.PublicKey.Fingerprint[:]
+ if priv.PublicKey.Version == 5 {
+ // For v5 the, the fingerprint must be restricted to 20 bytes
+ fp = fp[:20]
+ }
+ b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, fp)
+ case PubKeyAlgoX25519:
+ b, err = x25519.Decrypt(priv.PrivateKey.(*x25519.PrivateKey), e.ephemeralPublicX25519, e.encryptedSession)
+ case PubKeyAlgoX448:
+ b, err = x448.Decrypt(priv.PrivateKey.(*x448.PrivateKey), e.ephemeralPublicX448, e.encryptedSession)
+ default:
+ err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
+ }
+ if err != nil {
+ return err
+ }
+
+ var key []byte
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
+ keyOffset := 0
+ if e.Version < 6 {
+ e.CipherFunc = CipherFunction(b[0])
+ keyOffset = 1
+ if !e.CipherFunc.IsSupported() {
+ return errors.UnsupportedError("unsupported encryption function")
+ }
+ }
+ key, err = decodeChecksumKey(b[keyOffset:])
+ if err != nil {
+ return err
+ }
+ case PubKeyAlgoX25519, PubKeyAlgoX448:
+ if e.Version < 6 {
+ switch e.CipherFunc {
+ case CipherAES128, CipherAES192, CipherAES256:
+ break
+ default:
+ return errors.StructuralError("v3 PKESK mandates AES as cipher function for x25519 and x448")
+ }
+ }
+ key = b[:]
+ default:
+ return errors.UnsupportedError("unsupported algorithm for decryption")
+ }
+ e.Key = key
+ return nil
+}
+
+// Serialize writes the encrypted key packet, e, to w.
+func (e *EncryptedKey) Serialize(w io.Writer) error {
+ var encodedLength int
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ encodedLength = int(e.encryptedMPI1.EncodedLength())
+ case PubKeyAlgoElGamal:
+ encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
+ case PubKeyAlgoECDH:
+ encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
+ case PubKeyAlgoX25519:
+ encodedLength = x25519.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
+ case PubKeyAlgoX448:
+ encodedLength = x448.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
+ default:
+ return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
+ }
+
+ packetLen := versionSize /* version */ + keyIdSize /* key id */ + algorithmSize /* algo */ + encodedLength
+ if e.Version == 6 {
+ packetLen = versionSize /* version */ + algorithmSize /* algo */ + encodedLength + keyVersionSize /* key version */
+ if e.KeyVersion == 6 {
+ packetLen += fingerprintSizeV6
+ } else if e.KeyVersion == 4 {
+ packetLen += fingerprintSize
+ }
+ }
+
+ err := serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write([]byte{byte(e.Version)})
+ if err != nil {
+ return err
+ }
+ if e.Version == 6 {
+ _, err = w.Write([]byte{byte(e.KeyVersion)})
+ if err != nil {
+ return err
+ }
+ // The key version number may also be zero,
+ // and the fingerprint omitted
+ if e.KeyVersion != 0 {
+ _, err = w.Write(e.KeyFingerprint)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ // Write KeyID
+ err = binary.Write(w, binary.BigEndian, e.KeyId)
+ if err != nil {
+ return err
+ }
+ }
+ _, err = w.Write([]byte{byte(e.Algo)})
+ if err != nil {
+ return err
+ }
+
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ _, err := w.Write(e.encryptedMPI1.EncodedBytes())
+ return err
+ case PubKeyAlgoElGamal:
+ if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
+ return err
+ }
+ _, err := w.Write(e.encryptedMPI2.EncodedBytes())
+ return err
+ case PubKeyAlgoECDH:
+ if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
+ return err
+ }
+ _, err := w.Write(e.encryptedMPI2.EncodedBytes())
+ return err
+ case PubKeyAlgoX25519:
+ err := x25519.EncodeFields(w, e.ephemeralPublicX25519, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
+ return err
+ case PubKeyAlgoX448:
+ err := x448.EncodeFields(w, e.ephemeralPublicX448, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
+ return err
+ default:
+ panic("internal error")
+ }
+}
+
+// SerializeEncryptedKeyAEAD serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+// If aeadSupported is set, PKESK v6 is used, otherwise v3.
+// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
+// If config is nil, sensible defaults will be used.
+func SerializeEncryptedKeyAEAD(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, config *Config) error {
+ return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, aeadSupported, key, false, config)
+}
+
+// SerializeEncryptedKeyAEADwithHiddenOption serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+// Offers the hidden flag option to indicated if the PKESK packet should include a wildcard KeyID.
+// If aeadSupported is set, PKESK v6 is used, otherwise v3.
+// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
+// If config is nil, sensible defaults will be used.
+func SerializeEncryptedKeyAEADwithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, hidden bool, config *Config) error {
+ var buf [36]byte // max possible header size is v6
+ lenHeaderWritten := versionSize
+ version := 3
+
+ if aeadSupported {
+ version = 6
+ }
+ // An implementation MUST NOT generate ElGamal v6 PKESKs.
+ if version == 6 && pub.PubKeyAlgo == PubKeyAlgoElGamal {
+ return errors.InvalidArgumentError("ElGamal v6 PKESK are not allowed")
+ }
+ // In v3 PKESKs, for x25519 and x448, mandate using AES
+ if version == 3 && (pub.PubKeyAlgo == PubKeyAlgoX25519 || pub.PubKeyAlgo == PubKeyAlgoX448) {
+ switch cipherFunc {
+ case CipherAES128, CipherAES192, CipherAES256:
+ break
+ default:
+ return errors.InvalidArgumentError("v3 PKESK mandates AES for x25519 and x448")
+ }
+ }
+
+ buf[0] = byte(version)
+
+ // If hidden is set, the key should be hidden
+ // An implementation MAY accept or use a Key ID of all zeros,
+ // or a key version of zero and no key fingerprint, to hide the intended decryption key.
+ // See Section 5.1.8. in the open pgp crypto refresh
+ if version == 6 {
+ if !hidden {
+ // A one-octet size of the following two fields.
+ buf[1] = byte(keyVersionSize + len(pub.Fingerprint))
+ // A one octet key version number.
+ buf[2] = byte(pub.Version)
+ lenHeaderWritten += keyVersionSize + 1
+ // The fingerprint of the public key
+ copy(buf[lenHeaderWritten:lenHeaderWritten+len(pub.Fingerprint)], pub.Fingerprint)
+ lenHeaderWritten += len(pub.Fingerprint)
+ } else {
+ // The size may also be zero, and the key version
+ // and fingerprint omitted for an "anonymous recipient"
+ buf[1] = 0
+ lenHeaderWritten += 1
+ }
+ } else {
+ if !hidden {
+ binary.BigEndian.PutUint64(buf[versionSize:(versionSize+keyIdSize)], pub.KeyId)
+ }
+ lenHeaderWritten += keyIdSize
+ }
+ buf[lenHeaderWritten] = byte(pub.PubKeyAlgo)
+ lenHeaderWritten += algorithmSize
+
+ var keyBlock []byte
+ switch pub.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
+ lenKeyBlock := len(key) + 2
+ if version < 6 {
+ lenKeyBlock += 1 // cipher type included
+ }
+ keyBlock = make([]byte, lenKeyBlock)
+ keyOffset := 0
+ if version < 6 {
+ keyBlock[0] = byte(cipherFunc)
+ keyOffset = 1
+ }
+ encodeChecksumKey(keyBlock[keyOffset:], key)
+ case PubKeyAlgoX25519, PubKeyAlgoX448:
+ // algorithm is added in plaintext below
+ keyBlock = key
+ }
+
+ switch pub.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ return serializeEncryptedKeyRSA(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*rsa.PublicKey), keyBlock)
+ case PubKeyAlgoElGamal:
+ return serializeEncryptedKeyElGamal(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*elgamal.PublicKey), keyBlock)
+ case PubKeyAlgoECDH:
+ return serializeEncryptedKeyECDH(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
+ case PubKeyAlgoX25519:
+ return serializeEncryptedKeyX25519(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x25519.PublicKey), keyBlock, byte(cipherFunc), version)
+ case PubKeyAlgoX448:
+ return serializeEncryptedKeyX448(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x448.PublicKey), keyBlock, byte(cipherFunc), version)
+ case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
+ return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+ }
+
+ return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+}
+
+// SerializeEncryptedKey serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+// PKESKv6 is used if config.AEAD() is not nil.
+// If config is nil, sensible defaults will be used.
+// Deprecated: Use SerializeEncryptedKeyAEAD instead.
+func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
+ return SerializeEncryptedKeyAEAD(w, pub, cipherFunc, config.AEAD() != nil, key, config)
+}
+
+// SerializeEncryptedKeyWithHiddenOption serializes an encrypted key packet to w that contains
+// key, encrypted to pub. PKESKv6 is used if config.AEAD() is not nil.
+// The hidden option controls if the packet should be anonymous, i.e., omit key metadata.
+// If config is nil, sensible defaults will be used.
+// Deprecated: Use SerializeEncryptedKeyAEADwithHiddenOption instead.
+func SerializeEncryptedKeyWithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, hidden bool, config *Config) error {
+ return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, config.AEAD() != nil, key, hidden, config)
+}
+
+func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header []byte, pub *rsa.PublicKey, keyBlock []byte) error {
+ cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
+ if err != nil {
+ return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
+ }
+
+ cipherMPI := encoding.NewMPI(cipherText)
+ packetLen := len(header) /* header length */ + int(cipherMPI.EncodedLength())
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(cipherMPI.EncodedBytes())
+ return err
+}
+
+func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header []byte, pub *elgamal.PublicKey, keyBlock []byte) error {
+ c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
+ }
+
+ packetLen := len(header) /* header length */
+ packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
+ packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ if _, err = w.Write(new(encoding.MPI).SetBig(c1).EncodedBytes()); err != nil {
+ return err
+ }
+ _, err = w.Write(new(encoding.MPI).SetBig(c2).EncodedBytes())
+ return err
+}
+
+func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header []byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error {
+ vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint)
+ if err != nil {
+ return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error())
+ }
+
+ g := encoding.NewMPI(vsG)
+ m := encoding.NewOID(c)
+
+ packetLen := len(header) /* header length */
+ packetLen += int(g.EncodedLength()) + int(m.EncodedLength())
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ if _, err = w.Write(g.EncodedBytes()); err != nil {
+ return err
+ }
+ _, err = w.Write(m.EncodedBytes())
+ return err
+}
+
+func serializeEncryptedKeyX25519(w io.Writer, rand io.Reader, header []byte, pub *x25519.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
+ ephemeralPublicX25519, ciphertext, err := x25519.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return errors.InvalidArgumentError("x25519 encryption failed: " + err.Error())
+ }
+
+ packetLen := len(header) /* header length */
+ packetLen += x25519.EncodedFieldsLength(ciphertext, version == 6)
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ return x25519.EncodeFields(w, ephemeralPublicX25519, ciphertext, cipherFunc, version == 6)
+}
+
+func serializeEncryptedKeyX448(w io.Writer, rand io.Reader, header []byte, pub *x448.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
+ ephemeralPublicX448, ciphertext, err := x448.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return errors.InvalidArgumentError("x448 encryption failed: " + err.Error())
+ }
+
+ packetLen := len(header) /* header length */
+ packetLen += x448.EncodedFieldsLength(ciphertext, version == 6)
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ return x448.EncodeFields(w, ephemeralPublicX448, ciphertext, cipherFunc, version == 6)
+}
+
+func checksumKeyMaterial(key []byte) uint16 {
+ var checksum uint16
+ for _, v := range key {
+ checksum += uint16(v)
+ }
+ return checksum
+}
+
+func decodeChecksumKey(msg []byte) (key []byte, err error) {
+ key = msg[:len(msg)-2]
+ expectedChecksum := uint16(msg[len(msg)-2])<<8 | uint16(msg[len(msg)-1])
+ checksum := checksumKeyMaterial(key)
+ if checksum != expectedChecksum {
+ err = errors.StructuralError("session key checksum is incorrect")
+ }
+ return
+}
+
+func encodeChecksumKey(buffer []byte, key []byte) {
+ copy(buffer, key)
+ checksum := checksumKeyMaterial(key)
+ buffer[len(key)] = byte(checksum >> 8)
+ buffer[len(key)+1] = byte(checksum)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
new file mode 100644
index 0000000000..8a028c8a17
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
@@ -0,0 +1,91 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "encoding/binary"
+ "io"
+)
+
+// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
+type LiteralData struct {
+ Format uint8
+ IsBinary bool
+ FileName string
+ Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined.
+ Body io.Reader
+}
+
+// ForEyesOnly returns whether the contents of the LiteralData have been marked
+// as especially sensitive.
+func (l *LiteralData) ForEyesOnly() bool {
+ return l.FileName == "_CONSOLE"
+}
+
+func (l *LiteralData) parse(r io.Reader) (err error) {
+ var buf [256]byte
+
+ _, err = readFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+
+ l.Format = buf[0]
+ l.IsBinary = l.Format == 'b'
+ fileNameLen := int(buf[1])
+
+ _, err = readFull(r, buf[:fileNameLen])
+ if err != nil {
+ return
+ }
+
+ l.FileName = string(buf[:fileNameLen])
+
+ _, err = readFull(r, buf[:4])
+ if err != nil {
+ return
+ }
+
+ l.Time = binary.BigEndian.Uint32(buf[:4])
+ l.Body = r
+ return
+}
+
+// SerializeLiteral serializes a literal data packet to w and returns a
+// WriteCloser to which the data itself can be written and which MUST be closed
+// on completion. The fileName is truncated to 255 bytes.
+func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) {
+ var buf [4]byte
+ buf[0] = 'b'
+ if !isBinary {
+ buf[0] = 'u'
+ }
+ if len(fileName) > 255 {
+ fileName = fileName[:255]
+ }
+ buf[1] = byte(len(fileName))
+
+ inner, err := serializeStreamHeader(w, packetTypeLiteralData)
+ if err != nil {
+ return
+ }
+
+ _, err = inner.Write(buf[:2])
+ if err != nil {
+ return
+ }
+ _, err = inner.Write([]byte(fileName))
+ if err != nil {
+ return
+ }
+ binary.BigEndian.PutUint32(buf[:], time)
+ _, err = inner.Write(buf[:])
+ if err != nil {
+ return
+ }
+
+ plaintext = inner
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/marker.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/marker.go
new file mode 100644
index 0000000000..1ee378ba3c
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/marker.go
@@ -0,0 +1,33 @@
+package packet
+
+import (
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+type Marker struct{}
+
+const markerString = "PGP"
+
+// parse just checks if the packet contains "PGP".
+func (m *Marker) parse(reader io.Reader) error {
+ var buffer [3]byte
+ if _, err := io.ReadFull(reader, buffer[:]); err != nil {
+ return err
+ }
+ if string(buffer[:]) != markerString {
+ return errors.StructuralError("invalid marker packet")
+ }
+ return nil
+}
+
+// SerializeMarker writes a marker packet to writer.
+func SerializeMarker(writer io.Writer) error {
+ err := serializeHeader(writer, packetTypeMarker, len(markerString))
+ if err != nil {
+ return err
+ }
+ _, err = writer.Write([]byte(markerString))
+ return err
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/notation.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/notation.go
new file mode 100644
index 0000000000..2c3e3f50b2
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/notation.go
@@ -0,0 +1,29 @@
+package packet
+
+// Notation type represents a Notation Data subpacket
+// see https://tools.ietf.org/html/rfc4880#section-5.2.3.16
+type Notation struct {
+ Name string
+ Value []byte
+ IsCritical bool
+ IsHumanReadable bool
+}
+
+func (notation *Notation) getData() []byte {
+ nameData := []byte(notation.Name)
+ nameLen := len(nameData)
+ valueLen := len(notation.Value)
+
+ data := make([]byte, 8+nameLen+valueLen)
+ if notation.IsHumanReadable {
+ data[0] = 0x80
+ }
+
+ data[4] = byte(nameLen >> 8)
+ data[5] = byte(nameLen)
+ data[6] = byte(valueLen >> 8)
+ data[7] = byte(valueLen)
+ copy(data[8:8+nameLen], nameData)
+ copy(data[8+nameLen:], notation.Value)
+ return data
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go
new file mode 100644
index 0000000000..4f26d0a00b
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go
@@ -0,0 +1,137 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
+
+package packet
+
+import (
+ "crypto/cipher"
+)
+
+type ocfbEncrypter struct {
+ b cipher.Block
+ fre []byte
+ outUsed int
+}
+
+// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
+// performed.
+type OCFBResyncOption bool
+
+const (
+ OCFBResync OCFBResyncOption = true
+ OCFBNoResync OCFBResyncOption = false
+)
+
+// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's
+// cipher feedback mode using the given cipher.Block, and an initial amount of
+// ciphertext. randData must be random bytes and be the same length as the
+// cipher.Block's block size. Resync determines if the "resynchronization step"
+// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on
+// this point.
+func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) {
+ blockSize := block.BlockSize()
+ if len(randData) != blockSize {
+ return nil, nil
+ }
+
+ x := &ocfbEncrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefix := make([]byte, blockSize+2)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefix[i] = randData[i] ^ x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
+ prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
+
+ if resync {
+ block.Encrypt(x.fre, prefix[2:])
+ } else {
+ x.fre[0] = prefix[blockSize]
+ x.fre[1] = prefix[blockSize+1]
+ x.outUsed = 2
+ }
+ return x, prefix
+}
+
+func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ x.fre[x.outUsed] ^= src[i]
+ dst[i] = x.fre[x.outUsed]
+ x.outUsed++
+ }
+}
+
+type ocfbDecrypter struct {
+ b cipher.Block
+ fre []byte
+ outUsed int
+}
+
+// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's
+// cipher feedback mode using the given cipher.Block. Prefix must be the first
+// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's
+// block size. On successful exit, blockSize+2 bytes of decrypted data are written into
+// prefix. Resync determines if the "resynchronization step" from RFC 4880,
+// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point.
+func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream {
+ blockSize := block.BlockSize()
+ if len(prefix) != blockSize+2 {
+ return nil
+ }
+
+ x := &ocfbDecrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefixCopy := make([]byte, len(prefix))
+ copy(prefixCopy, prefix)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefixCopy[i] ^= x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefixCopy[blockSize] ^= x.fre[0]
+ prefixCopy[blockSize+1] ^= x.fre[1]
+
+ if resync {
+ block.Encrypt(x.fre, prefix[2:])
+ } else {
+ x.fre[0] = prefix[blockSize]
+ x.fre[1] = prefix[blockSize+1]
+ x.outUsed = 2
+ }
+ copy(prefix, prefixCopy)
+ return x
+}
+
+func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ c := src[i]
+ dst[i] = x.fre[x.outUsed] ^ src[i]
+ x.fre[x.outUsed] = c
+ x.outUsed++
+ }
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
new file mode 100644
index 0000000000..f393c4063b
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
@@ -0,0 +1,157 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "encoding/binary"
+ "io"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+)
+
+// OnePassSignature represents a one-pass signature packet. See RFC 4880,
+// section 5.4.
+type OnePassSignature struct {
+ Version int
+ SigType SignatureType
+ Hash crypto.Hash
+ PubKeyAlgo PublicKeyAlgorithm
+ KeyId uint64
+ IsLast bool
+ Salt []byte // v6 only
+ KeyFingerprint []byte // v6 only
+}
+
+func (ops *OnePassSignature) parse(r io.Reader) (err error) {
+ var buf [8]byte
+ // Read: version | signature type | hash algorithm | public-key algorithm
+ _, err = readFull(r, buf[:4])
+ if err != nil {
+ return
+ }
+ if buf[0] != 3 && buf[0] != 6 {
+ return errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
+ }
+ ops.Version = int(buf[0])
+
+ var ok bool
+ ops.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2])
+ if !ok {
+ return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
+ }
+
+ ops.SigType = SignatureType(buf[1])
+ ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
+
+ if ops.Version == 6 {
+ // Only for v6, a variable-length field containing the salt
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ saltLength := int(buf[0])
+ var expectedSaltLength int
+ expectedSaltLength, err = SaltLengthForHash(ops.Hash)
+ if err != nil {
+ return
+ }
+ if saltLength != expectedSaltLength {
+ err = errors.StructuralError("unexpected salt size for the given hash algorithm")
+ return
+ }
+ salt := make([]byte, expectedSaltLength)
+ _, err = readFull(r, salt)
+ if err != nil {
+ return
+ }
+ ops.Salt = salt
+
+ // Only for v6 packets, 32 octets of the fingerprint of the signing key.
+ fingerprint := make([]byte, 32)
+ _, err = readFull(r, fingerprint)
+ if err != nil {
+ return
+ }
+ ops.KeyFingerprint = fingerprint
+ ops.KeyId = binary.BigEndian.Uint64(ops.KeyFingerprint[:8])
+ } else {
+ _, err = readFull(r, buf[:8])
+ if err != nil {
+ return
+ }
+ ops.KeyId = binary.BigEndian.Uint64(buf[:8])
+ }
+
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ ops.IsLast = buf[0] != 0
+ return
+}
+
+// Serialize marshals the given OnePassSignature to w.
+func (ops *OnePassSignature) Serialize(w io.Writer) error {
+ //v3 length 1+1+1+1+8+1 =
+ packetLength := 13
+ if ops.Version == 6 {
+ // v6 length 1+1+1+1+1+len(salt)+32+1 =
+ packetLength = 38 + len(ops.Salt)
+ }
+
+ if err := serializeHeader(w, packetTypeOnePassSignature, packetLength); err != nil {
+ return err
+ }
+
+ var buf [8]byte
+ buf[0] = byte(ops.Version)
+ buf[1] = uint8(ops.SigType)
+ var ok bool
+ buf[2], ok = algorithm.HashToHashIdWithSha1(ops.Hash)
+ if !ok {
+ return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
+ }
+ buf[3] = uint8(ops.PubKeyAlgo)
+
+ _, err := w.Write(buf[:4])
+ if err != nil {
+ return err
+ }
+
+ if ops.Version == 6 {
+ // write salt for v6 signatures
+ _, err := w.Write([]byte{uint8(len(ops.Salt))})
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(ops.Salt)
+ if err != nil {
+ return err
+ }
+
+ // write fingerprint v6 signatures
+ _, err = w.Write(ops.KeyFingerprint)
+ if err != nil {
+ return err
+ }
+ } else {
+ binary.BigEndian.PutUint64(buf[:8], ops.KeyId)
+ _, err := w.Write(buf[:8])
+ if err != nil {
+ return err
+ }
+ }
+
+ isLast := []byte{byte(0)}
+ if ops.IsLast {
+ isLast[0] = 1
+ }
+
+ _, err = w.Write(isLast)
+ return err
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
new file mode 100644
index 0000000000..cef7c661d3
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
@@ -0,0 +1,170 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is
+// useful for splitting and storing the original packet contents separately,
+// handling unsupported packet types or accessing parts of the packet not yet
+// implemented by this package.
+type OpaquePacket struct {
+ // Packet type
+ Tag uint8
+ // Reason why the packet was parsed opaquely
+ Reason error
+ // Binary contents of the packet data
+ Contents []byte
+}
+
+func (op *OpaquePacket) parse(r io.Reader) (err error) {
+ op.Contents, err = io.ReadAll(r)
+ return
+}
+
+// Serialize marshals the packet to a writer in its original form, including
+// the packet header.
+func (op *OpaquePacket) Serialize(w io.Writer) (err error) {
+ err = serializeHeader(w, packetType(op.Tag), len(op.Contents))
+ if err == nil {
+ _, err = w.Write(op.Contents)
+ }
+ return
+}
+
+// Parse attempts to parse the opaque contents into a structure supported by
+// this package. If the packet is not known then the result will be another
+// OpaquePacket.
+func (op *OpaquePacket) Parse() (p Packet, err error) {
+ hdr := bytes.NewBuffer(nil)
+ err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents))
+ if err != nil {
+ op.Reason = err
+ return op, err
+ }
+ p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents)))
+ if err != nil {
+ op.Reason = err
+ p = op
+ }
+ return
+}
+
+// OpaqueReader reads OpaquePackets from an io.Reader.
+type OpaqueReader struct {
+ r io.Reader
+}
+
+func NewOpaqueReader(r io.Reader) *OpaqueReader {
+ return &OpaqueReader{r: r}
+}
+
+// Read the next OpaquePacket.
+func (or *OpaqueReader) Next() (op *OpaquePacket, err error) {
+ tag, _, contents, err := readHeader(or.r)
+ if err != nil {
+ return
+ }
+ op = &OpaquePacket{Tag: uint8(tag), Reason: err}
+ err = op.parse(contents)
+ if err != nil {
+ consumeAll(contents)
+ }
+ return
+}
+
+// OpaqueSubpacket represents an unparsed OpenPGP subpacket,
+// as found in signature and user attribute packets.
+type OpaqueSubpacket struct {
+ SubType uint8
+ EncodedLength []byte // Store the original encoded length for signature verifications.
+ Contents []byte
+}
+
+// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from
+// their byte representation.
+func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) {
+ var (
+ subHeaderLen int
+ subPacket *OpaqueSubpacket
+ )
+ for len(contents) > 0 {
+ subHeaderLen, subPacket, err = nextSubpacket(contents)
+ if err != nil {
+ break
+ }
+ result = append(result, subPacket)
+ contents = contents[subHeaderLen+len(subPacket.Contents):]
+ }
+ return
+}
+
+func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) {
+ // RFC 4880, section 5.2.3.1
+ var subLen uint32
+ var encodedLength []byte
+ if len(contents) < 1 {
+ goto Truncated
+ }
+ subPacket = &OpaqueSubpacket{}
+ switch {
+ case contents[0] < 192:
+ subHeaderLen = 2 // 1 length byte, 1 subtype byte
+ if len(contents) < subHeaderLen {
+ goto Truncated
+ }
+ encodedLength = contents[0:1]
+ subLen = uint32(contents[0])
+ contents = contents[1:]
+ case contents[0] < 255:
+ subHeaderLen = 3 // 2 length bytes, 1 subtype
+ if len(contents) < subHeaderLen {
+ goto Truncated
+ }
+ encodedLength = contents[0:2]
+ subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192
+ contents = contents[2:]
+ default:
+ subHeaderLen = 6 // 5 length bytes, 1 subtype
+ if len(contents) < subHeaderLen {
+ goto Truncated
+ }
+ encodedLength = contents[0:5]
+ subLen = uint32(contents[1])<<24 |
+ uint32(contents[2])<<16 |
+ uint32(contents[3])<<8 |
+ uint32(contents[4])
+ contents = contents[5:]
+
+ }
+ if subLen > uint32(len(contents)) || subLen == 0 {
+ goto Truncated
+ }
+ subPacket.SubType = contents[0]
+ subPacket.EncodedLength = encodedLength
+ subPacket.Contents = contents[1:subLen]
+ return
+Truncated:
+ err = errors.StructuralError("subpacket truncated")
+ return
+}
+
+func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) {
+ buf := make([]byte, 6)
+ copy(buf, osp.EncodedLength)
+ n := len(osp.EncodedLength)
+
+ buf[n] = osp.SubType
+ if _, err = w.Write(buf[:n+1]); err != nil {
+ return
+ }
+ _, err = w.Write(osp.Contents)
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
new file mode 100644
index 0000000000..1e92e22c97
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
@@ -0,0 +1,675 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package packet implements parsing and serialization of OpenPGP packets, as
+// specified in RFC 4880.
+package packet // import "github.com/ProtonMail/go-crypto/openpgp/packet"
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/rsa"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+)
+
+// readFull is the same as io.ReadFull except that reading zero bytes returns
+// ErrUnexpectedEOF rather than EOF.
+func readFull(r io.Reader, buf []byte) (n int, err error) {
+ n, err = io.ReadFull(r, buf)
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
+func readLength(r io.Reader) (length int64, isPartial bool, err error) {
+ var buf [4]byte
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ switch {
+ case buf[0] < 192:
+ length = int64(buf[0])
+ case buf[0] < 224:
+ length = int64(buf[0]-192) << 8
+ _, err = readFull(r, buf[0:1])
+ if err != nil {
+ return
+ }
+ length += int64(buf[0]) + 192
+ case buf[0] < 255:
+ length = int64(1) << (buf[0] & 0x1f)
+ isPartial = true
+ default:
+ _, err = readFull(r, buf[0:4])
+ if err != nil {
+ return
+ }
+ length = int64(buf[0])<<24 |
+ int64(buf[1])<<16 |
+ int64(buf[2])<<8 |
+ int64(buf[3])
+ }
+ return
+}
+
+// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
+// The continuation lengths are parsed and removed from the stream and EOF is
+// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
+type partialLengthReader struct {
+ r io.Reader
+ remaining int64
+ isPartial bool
+}
+
+func (r *partialLengthReader) Read(p []byte) (n int, err error) {
+ for r.remaining == 0 {
+ if !r.isPartial {
+ return 0, io.EOF
+ }
+ r.remaining, r.isPartial, err = readLength(r.r)
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ toRead := int64(len(p))
+ if toRead > r.remaining {
+ toRead = r.remaining
+ }
+
+ n, err = r.r.Read(p[:int(toRead)])
+ r.remaining -= int64(n)
+ if n < int(toRead) && err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
+// See RFC 4880, section 4.2.2.4.
+type partialLengthWriter struct {
+ w io.WriteCloser
+ buf bytes.Buffer
+ lengthByte [1]byte
+}
+
+func (w *partialLengthWriter) Write(p []byte) (n int, err error) {
+ bufLen := w.buf.Len()
+ if bufLen > 512 {
+ for power := uint(30); ; power-- {
+ l := 1 << power
+ if bufLen >= l {
+ w.lengthByte[0] = 224 + uint8(power)
+ _, err = w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return
+ }
+ var m int
+ m, err = w.w.Write(w.buf.Next(l))
+ if err != nil {
+ return
+ }
+ if m != l {
+ return 0, io.ErrShortWrite
+ }
+ break
+ }
+ }
+ }
+ return w.buf.Write(p)
+}
+
+func (w *partialLengthWriter) Close() (err error) {
+ len := w.buf.Len()
+ err = serializeLength(w.w, len)
+ if err != nil {
+ return err
+ }
+ _, err = w.buf.WriteTo(w.w)
+ if err != nil {
+ return err
+ }
+ return w.w.Close()
+}
+
+// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
+// underlying Reader returns EOF before the limit has been reached.
+type spanReader struct {
+ r io.Reader
+ n int64
+}
+
+func (l *spanReader) Read(p []byte) (n int, err error) {
+ if l.n <= 0 {
+ return 0, io.EOF
+ }
+ if int64(len(p)) > l.n {
+ p = p[0:l.n]
+ }
+ n, err = l.r.Read(p)
+ l.n -= int64(n)
+ if l.n > 0 && err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// readHeader parses a packet header and returns an io.Reader which will return
+// the contents of the packet. See RFC 4880, section 4.2.
+func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) {
+ var buf [4]byte
+ _, err = io.ReadFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ if buf[0]&0x80 == 0 {
+ err = errors.StructuralError("tag byte does not have MSB set")
+ return
+ }
+ if buf[0]&0x40 == 0 {
+ // Old format packet
+ tag = packetType((buf[0] & 0x3f) >> 2)
+ lengthType := buf[0] & 3
+ if lengthType == 3 {
+ length = -1
+ contents = r
+ return
+ }
+ lengthBytes := 1 << lengthType
+ _, err = readFull(r, buf[0:lengthBytes])
+ if err != nil {
+ return
+ }
+ for i := 0; i < lengthBytes; i++ {
+ length <<= 8
+ length |= int64(buf[i])
+ }
+ contents = &spanReader{r, length}
+ return
+ }
+
+ // New format packet
+ tag = packetType(buf[0] & 0x3f)
+ length, isPartial, err := readLength(r)
+ if err != nil {
+ return
+ }
+ if isPartial {
+ contents = &partialLengthReader{
+ remaining: length,
+ isPartial: true,
+ r: r,
+ }
+ length = -1
+ } else {
+ contents = &spanReader{r, length}
+ }
+ return
+}
+
+// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
+// 4.2.
+func serializeHeader(w io.Writer, ptype packetType, length int) (err error) {
+ err = serializeType(w, ptype)
+ if err != nil {
+ return
+ }
+ return serializeLength(w, length)
+}
+
+// serializeType writes an OpenPGP packet type to w. See RFC 4880, section
+// 4.2.
+func serializeType(w io.Writer, ptype packetType) (err error) {
+ var buf [1]byte
+ buf[0] = 0x80 | 0x40 | byte(ptype)
+ _, err = w.Write(buf[:])
+ return
+}
+
+// serializeLength writes an OpenPGP packet length to w. See RFC 4880, section
+// 4.2.2.
+func serializeLength(w io.Writer, length int) (err error) {
+ var buf [5]byte
+ var n int
+
+ if length < 192 {
+ buf[0] = byte(length)
+ n = 1
+ } else if length < 8384 {
+ length -= 192
+ buf[0] = 192 + byte(length>>8)
+ buf[1] = byte(length)
+ n = 2
+ } else {
+ buf[0] = 255
+ buf[1] = byte(length >> 24)
+ buf[2] = byte(length >> 16)
+ buf[3] = byte(length >> 8)
+ buf[4] = byte(length)
+ n = 5
+ }
+
+ _, err = w.Write(buf[:n])
+ return
+}
+
+// serializeStreamHeader writes an OpenPGP packet header to w where the
+// length of the packet is unknown. It returns a io.WriteCloser which can be
+// used to write the contents of the packet. See RFC 4880, section 4.2.
+func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) {
+ err = serializeType(w, ptype)
+ if err != nil {
+ return
+ }
+ out = &partialLengthWriter{w: w}
+ return
+}
+
+// Packet represents an OpenPGP packet. Users are expected to try casting
+// instances of this interface to specific packet types.
+type Packet interface {
+ parse(io.Reader) error
+}
+
+// consumeAll reads from the given Reader until error, returning the number of
+// bytes read.
+func consumeAll(r io.Reader) (n int64, err error) {
+ var m int
+ var buf [1024]byte
+
+ for {
+ m, err = r.Read(buf[:])
+ n += int64(m)
+ if err == io.EOF {
+ err = nil
+ return
+ }
+ if err != nil {
+ return
+ }
+ }
+}
+
+// packetType represents the numeric ids of the different OpenPGP packet types. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
+type packetType uint8
+
+const (
+ packetTypeEncryptedKey packetType = 1
+ packetTypeSignature packetType = 2
+ packetTypeSymmetricKeyEncrypted packetType = 3
+ packetTypeOnePassSignature packetType = 4
+ packetTypePrivateKey packetType = 5
+ packetTypePublicKey packetType = 6
+ packetTypePrivateSubkey packetType = 7
+ packetTypeCompressed packetType = 8
+ packetTypeSymmetricallyEncrypted packetType = 9
+ packetTypeMarker packetType = 10
+ packetTypeLiteralData packetType = 11
+ packetTypeTrust packetType = 12
+ packetTypeUserId packetType = 13
+ packetTypePublicSubkey packetType = 14
+ packetTypeUserAttribute packetType = 17
+ packetTypeSymmetricallyEncryptedIntegrityProtected packetType = 18
+ packetTypeAEADEncrypted packetType = 20
+ packetPadding packetType = 21
+)
+
+// EncryptedDataPacket holds encrypted data. It is currently implemented by
+// SymmetricallyEncrypted and AEADEncrypted.
+type EncryptedDataPacket interface {
+ Decrypt(CipherFunction, []byte) (io.ReadCloser, error)
+}
+
+// Read reads a single OpenPGP packet from the given io.Reader. If there is an
+// error parsing a packet, the whole packet is consumed from the input.
+func Read(r io.Reader) (p Packet, err error) {
+ tag, len, contents, err := readHeader(r)
+ if err != nil {
+ return
+ }
+
+ switch tag {
+ case packetTypeEncryptedKey:
+ p = new(EncryptedKey)
+ case packetTypeSignature:
+ p = new(Signature)
+ case packetTypeSymmetricKeyEncrypted:
+ p = new(SymmetricKeyEncrypted)
+ case packetTypeOnePassSignature:
+ p = new(OnePassSignature)
+ case packetTypePrivateKey, packetTypePrivateSubkey:
+ pk := new(PrivateKey)
+ if tag == packetTypePrivateSubkey {
+ pk.IsSubkey = true
+ }
+ p = pk
+ case packetTypePublicKey, packetTypePublicSubkey:
+ isSubkey := tag == packetTypePublicSubkey
+ p = &PublicKey{IsSubkey: isSubkey}
+ case packetTypeCompressed:
+ p = new(Compressed)
+ case packetTypeSymmetricallyEncrypted:
+ p = new(SymmetricallyEncrypted)
+ case packetTypeLiteralData:
+ p = new(LiteralData)
+ case packetTypeUserId:
+ p = new(UserId)
+ case packetTypeUserAttribute:
+ p = new(UserAttribute)
+ case packetTypeSymmetricallyEncryptedIntegrityProtected:
+ se := new(SymmetricallyEncrypted)
+ se.IntegrityProtected = true
+ p = se
+ case packetTypeAEADEncrypted:
+ p = new(AEADEncrypted)
+ case packetPadding:
+ p = Padding(len)
+ case packetTypeMarker:
+ p = new(Marker)
+ case packetTypeTrust:
+ // Not implemented, just consume
+ err = errors.UnknownPacketTypeError(tag)
+ default:
+ // Packet Tags from 0 to 39 are critical.
+ // Packet Tags from 40 to 63 are non-critical.
+ if tag < 40 {
+ err = errors.CriticalUnknownPacketTypeError(tag)
+ } else {
+ err = errors.UnknownPacketTypeError(tag)
+ }
+ }
+ if p != nil {
+ err = p.parse(contents)
+ }
+ if err != nil {
+ consumeAll(contents)
+ }
+ return
+}
+
+// ReadWithCheck reads a single OpenPGP message packet from the given io.Reader. If there is an
+// error parsing a packet, the whole packet is consumed from the input.
+// ReadWithCheck additionally checks if the OpenPGP message packet sequence adheres
+// to the packet composition rules in rfc4880, if not throws an error.
+func ReadWithCheck(r io.Reader, sequence *SequenceVerifier) (p Packet, msgErr error, err error) {
+ tag, len, contents, err := readHeader(r)
+ if err != nil {
+ return
+ }
+ switch tag {
+ case packetTypeEncryptedKey:
+ msgErr = sequence.Next(ESKSymbol)
+ p = new(EncryptedKey)
+ case packetTypeSignature:
+ msgErr = sequence.Next(SigSymbol)
+ p = new(Signature)
+ case packetTypeSymmetricKeyEncrypted:
+ msgErr = sequence.Next(ESKSymbol)
+ p = new(SymmetricKeyEncrypted)
+ case packetTypeOnePassSignature:
+ msgErr = sequence.Next(OPSSymbol)
+ p = new(OnePassSignature)
+ case packetTypeCompressed:
+ msgErr = sequence.Next(CompSymbol)
+ p = new(Compressed)
+ case packetTypeSymmetricallyEncrypted:
+ msgErr = sequence.Next(EncSymbol)
+ p = new(SymmetricallyEncrypted)
+ case packetTypeLiteralData:
+ msgErr = sequence.Next(LDSymbol)
+ p = new(LiteralData)
+ case packetTypeSymmetricallyEncryptedIntegrityProtected:
+ msgErr = sequence.Next(EncSymbol)
+ se := new(SymmetricallyEncrypted)
+ se.IntegrityProtected = true
+ p = se
+ case packetTypeAEADEncrypted:
+ msgErr = sequence.Next(EncSymbol)
+ p = new(AEADEncrypted)
+ case packetPadding:
+ p = Padding(len)
+ case packetTypeMarker:
+ p = new(Marker)
+ case packetTypeTrust:
+ // Not implemented, just consume
+ err = errors.UnknownPacketTypeError(tag)
+ case packetTypePrivateKey,
+ packetTypePrivateSubkey,
+ packetTypePublicKey,
+ packetTypePublicSubkey,
+ packetTypeUserId,
+ packetTypeUserAttribute:
+ msgErr = sequence.Next(UnknownSymbol)
+ consumeAll(contents)
+ default:
+ // Packet Tags from 0 to 39 are critical.
+ // Packet Tags from 40 to 63 are non-critical.
+ if tag < 40 {
+ err = errors.CriticalUnknownPacketTypeError(tag)
+ } else {
+ err = errors.UnknownPacketTypeError(tag)
+ }
+ }
+ if p != nil {
+ err = p.parse(contents)
+ }
+ if err != nil {
+ consumeAll(contents)
+ }
+ return
+}
+
+// SignatureType represents the different semantic meanings of an OpenPGP
+// signature. See RFC 4880, section 5.2.1.
+type SignatureType uint8
+
+const (
+ SigTypeBinary SignatureType = 0x00
+ SigTypeText SignatureType = 0x01
+ SigTypeGenericCert SignatureType = 0x10
+ SigTypePersonaCert SignatureType = 0x11
+ SigTypeCasualCert SignatureType = 0x12
+ SigTypePositiveCert SignatureType = 0x13
+ SigTypeSubkeyBinding SignatureType = 0x18
+ SigTypePrimaryKeyBinding SignatureType = 0x19
+ SigTypeDirectSignature SignatureType = 0x1F
+ SigTypeKeyRevocation SignatureType = 0x20
+ SigTypeSubkeyRevocation SignatureType = 0x28
+ SigTypeCertificationRevocation SignatureType = 0x30
+)
+
+// PublicKeyAlgorithm represents the different public key system specified for
+// OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
+type PublicKeyAlgorithm uint8
+
+const (
+ PubKeyAlgoRSA PublicKeyAlgorithm = 1
+ PubKeyAlgoElGamal PublicKeyAlgorithm = 16
+ PubKeyAlgoDSA PublicKeyAlgorithm = 17
+ // RFC 6637, Section 5.
+ PubKeyAlgoECDH PublicKeyAlgorithm = 18
+ PubKeyAlgoECDSA PublicKeyAlgorithm = 19
+ // https://www.ietf.org/archive/id/draft-koch-eddsa-for-openpgp-04.txt
+ PubKeyAlgoEdDSA PublicKeyAlgorithm = 22
+ // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh
+ PubKeyAlgoX25519 PublicKeyAlgorithm = 25
+ PubKeyAlgoX448 PublicKeyAlgorithm = 26
+ PubKeyAlgoEd25519 PublicKeyAlgorithm = 27
+ PubKeyAlgoEd448 PublicKeyAlgorithm = 28
+
+ // Deprecated in RFC 4880, Section 13.5. Use key flags instead.
+ PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
+ PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
+)
+
+// CanEncrypt returns true if it's possible to encrypt a message to a public
+// key of the given type.
+func (pka PublicKeyAlgorithm) CanEncrypt() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH, PubKeyAlgoX25519, PubKeyAlgoX448:
+ return true
+ }
+ return false
+}
+
+// CanSign returns true if it's possible for a public key of the given type to
+// sign a message.
+func (pka PublicKeyAlgorithm) CanSign() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA, PubKeyAlgoEd25519, PubKeyAlgoEd448:
+ return true
+ }
+ return false
+}
+
+// CipherFunction represents the different block ciphers specified for OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
+type CipherFunction algorithm.CipherFunction
+
+const (
+ Cipher3DES CipherFunction = 2
+ CipherCAST5 CipherFunction = 3
+ CipherAES128 CipherFunction = 7
+ CipherAES192 CipherFunction = 8
+ CipherAES256 CipherFunction = 9
+)
+
+// KeySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) KeySize() int {
+ return algorithm.CipherFunction(cipher).KeySize()
+}
+
+// IsSupported returns true if the cipher is supported from the library
+func (cipher CipherFunction) IsSupported() bool {
+ return algorithm.CipherFunction(cipher).KeySize() > 0
+}
+
+// blockSize returns the block size, in bytes, of cipher.
+func (cipher CipherFunction) blockSize() int {
+ return algorithm.CipherFunction(cipher).BlockSize()
+}
+
+// new returns a fresh instance of the given cipher.
+func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
+ return algorithm.CipherFunction(cipher).New(key)
+}
+
+// padToKeySize left-pads a MPI with zeroes to match the length of the
+// specified RSA public.
+func padToKeySize(pub *rsa.PublicKey, b []byte) []byte {
+ k := (pub.N.BitLen() + 7) / 8
+ if len(b) >= k {
+ return b
+ }
+ bb := make([]byte, k)
+ copy(bb[len(bb)-len(b):], b)
+ return bb
+}
+
+// CompressionAlgo Represents the different compression algorithms
+// supported by OpenPGP (except for BZIP2, which is not currently
+// supported). See Section 9.3 of RFC 4880.
+type CompressionAlgo uint8
+
+const (
+ CompressionNone CompressionAlgo = 0
+ CompressionZIP CompressionAlgo = 1
+ CompressionZLIB CompressionAlgo = 2
+)
+
+// AEADMode represents the different Authenticated Encryption with Associated
+// Data specified for OpenPGP.
+// See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-9.6
+type AEADMode algorithm.AEADMode
+
+const (
+ AEADModeEAX AEADMode = 1
+ AEADModeOCB AEADMode = 2
+ AEADModeGCM AEADMode = 3
+)
+
+func (mode AEADMode) IvLength() int {
+ return algorithm.AEADMode(mode).NonceLength()
+}
+
+func (mode AEADMode) TagLength() int {
+ return algorithm.AEADMode(mode).TagLength()
+}
+
+// IsSupported returns true if the aead mode is supported from the library
+func (mode AEADMode) IsSupported() bool {
+ return algorithm.AEADMode(mode).TagLength() > 0
+}
+
+// new returns a fresh instance of the given mode.
+func (mode AEADMode) new(block cipher.Block) cipher.AEAD {
+ return algorithm.AEADMode(mode).New(block)
+}
+
+// ReasonForRevocation represents a revocation reason code as per RFC4880
+// section 5.2.3.23.
+type ReasonForRevocation uint8
+
+const (
+ NoReason ReasonForRevocation = 0
+ KeySuperseded ReasonForRevocation = 1
+ KeyCompromised ReasonForRevocation = 2
+ KeyRetired ReasonForRevocation = 3
+ UserIDNotValid ReasonForRevocation = 32
+ Unknown ReasonForRevocation = 200
+)
+
+func NewReasonForRevocation(value byte) ReasonForRevocation {
+ if value < 4 || value == 32 {
+ return ReasonForRevocation(value)
+ }
+ return Unknown
+}
+
+// Curve is a mapping to supported ECC curves for key generation.
+// See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-06.html#name-curve-specific-wire-formats
+type Curve string
+
+const (
+ Curve25519 Curve = "Curve25519"
+ Curve448 Curve = "Curve448"
+ CurveNistP256 Curve = "P256"
+ CurveNistP384 Curve = "P384"
+ CurveNistP521 Curve = "P521"
+ CurveSecP256k1 Curve = "SecP256k1"
+ CurveBrainpoolP256 Curve = "BrainpoolP256"
+ CurveBrainpoolP384 Curve = "BrainpoolP384"
+ CurveBrainpoolP512 Curve = "BrainpoolP512"
+)
+
+// TrustLevel represents a trust level per RFC4880 5.2.3.13
+type TrustLevel uint8
+
+// TrustAmount represents a trust amount per RFC4880 5.2.3.13
+type TrustAmount uint8
+
+const (
+ // versionSize is the length in bytes of the version value.
+ versionSize = 1
+ // algorithmSize is the length in bytes of the key algorithm value.
+ algorithmSize = 1
+ // keyVersionSize is the length in bytes of the key version value
+ keyVersionSize = 1
+ // keyIdSize is the length in bytes of the key identifier value.
+ keyIdSize = 8
+ // timestampSize is the length in bytes of encoded timestamps.
+ timestampSize = 4
+ // fingerprintSizeV6 is the length in bytes of the key fingerprint in v6.
+ fingerprintSizeV6 = 32
+ // fingerprintSize is the length in bytes of the key fingerprint.
+ fingerprintSize = 20
+)
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_sequence.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_sequence.go
new file mode 100644
index 0000000000..55a8a56c2d
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_sequence.go
@@ -0,0 +1,222 @@
+package packet
+
+// This file implements the pushdown automata (PDA) from PGPainless (Paul Schaub)
+// to verify pgp packet sequences. See Paul's blogpost for more details:
+// https://blog.jabberhead.tk/2022/10/26/implementing-packet-sequence-validation-using-pushdown-automata/
+import (
+ "fmt"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+func NewErrMalformedMessage(from State, input InputSymbol, stackSymbol StackSymbol) errors.ErrMalformedMessage {
+ return errors.ErrMalformedMessage(fmt.Sprintf("state %d, input symbol %d, stack symbol %d ", from, input, stackSymbol))
+}
+
+// InputSymbol defines the input alphabet of the PDA
+type InputSymbol uint8
+
+const (
+ LDSymbol InputSymbol = iota
+ SigSymbol
+ OPSSymbol
+ CompSymbol
+ ESKSymbol
+ EncSymbol
+ EOSSymbol
+ UnknownSymbol
+)
+
+// StackSymbol defines the stack alphabet of the PDA
+type StackSymbol int8
+
+const (
+ MsgStackSymbol StackSymbol = iota
+ OpsStackSymbol
+ KeyStackSymbol
+ EndStackSymbol
+ EmptyStackSymbol
+)
+
+// State defines the states of the PDA
+type State int8
+
+const (
+ OpenPGPMessage State = iota
+ ESKMessage
+ LiteralMessage
+ CompressedMessage
+ EncryptedMessage
+ ValidMessage
+)
+
+// transition represents a state transition in the PDA
+type transition func(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error)
+
+// SequenceVerifier is a pushdown automata to verify
+// PGP messages packet sequences according to rfc4880.
+type SequenceVerifier struct {
+ stack []StackSymbol
+ state State
+}
+
+// Next performs a state transition with the given input symbol.
+// If the transition fails a ErrMalformedMessage is returned.
+func (sv *SequenceVerifier) Next(input InputSymbol) error {
+ for {
+ stackSymbol := sv.popStack()
+ transitionFunc := getTransition(sv.state)
+ nextState, newStackSymbols, redo, err := transitionFunc(input, stackSymbol)
+ if err != nil {
+ return err
+ }
+ if redo {
+ sv.pushStack(stackSymbol)
+ }
+ for _, newStackSymbol := range newStackSymbols {
+ sv.pushStack(newStackSymbol)
+ }
+ sv.state = nextState
+ if !redo {
+ break
+ }
+ }
+ return nil
+}
+
+// Valid returns true if RDA is in a valid state.
+func (sv *SequenceVerifier) Valid() bool {
+ return sv.state == ValidMessage && len(sv.stack) == 0
+}
+
+func (sv *SequenceVerifier) AssertValid() error {
+ if !sv.Valid() {
+ return errors.ErrMalformedMessage("invalid message")
+ }
+ return nil
+}
+
+func NewSequenceVerifier() *SequenceVerifier {
+ return &SequenceVerifier{
+ stack: []StackSymbol{EndStackSymbol, MsgStackSymbol},
+ state: OpenPGPMessage,
+ }
+}
+
+func (sv *SequenceVerifier) popStack() StackSymbol {
+ if len(sv.stack) == 0 {
+ return EmptyStackSymbol
+ }
+ elemIndex := len(sv.stack) - 1
+ stackSymbol := sv.stack[elemIndex]
+ sv.stack = sv.stack[:elemIndex]
+ return stackSymbol
+}
+
+func (sv *SequenceVerifier) pushStack(stackSymbol StackSymbol) {
+ sv.stack = append(sv.stack, stackSymbol)
+}
+
+func getTransition(from State) transition {
+ switch from {
+ case OpenPGPMessage:
+ return fromOpenPGPMessage
+ case LiteralMessage:
+ return fromLiteralMessage
+ case CompressedMessage:
+ return fromCompressedMessage
+ case EncryptedMessage:
+ return fromEncryptedMessage
+ case ESKMessage:
+ return fromESKMessage
+ case ValidMessage:
+ return fromValidMessage
+ }
+ return nil
+}
+
+// fromOpenPGPMessage is the transition for the state OpenPGPMessage.
+func fromOpenPGPMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
+ if stackSymbol != MsgStackSymbol {
+ return 0, nil, false, NewErrMalformedMessage(OpenPGPMessage, input, stackSymbol)
+ }
+ switch input {
+ case LDSymbol:
+ return LiteralMessage, nil, false, nil
+ case SigSymbol:
+ return OpenPGPMessage, []StackSymbol{MsgStackSymbol}, false, nil
+ case OPSSymbol:
+ return OpenPGPMessage, []StackSymbol{OpsStackSymbol, MsgStackSymbol}, false, nil
+ case CompSymbol:
+ return CompressedMessage, nil, false, nil
+ case ESKSymbol:
+ return ESKMessage, []StackSymbol{KeyStackSymbol}, false, nil
+ case EncSymbol:
+ return EncryptedMessage, nil, false, nil
+ }
+ return 0, nil, false, NewErrMalformedMessage(OpenPGPMessage, input, stackSymbol)
+}
+
+// fromESKMessage is the transition for the state ESKMessage.
+func fromESKMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
+ if stackSymbol != KeyStackSymbol {
+ return 0, nil, false, NewErrMalformedMessage(ESKMessage, input, stackSymbol)
+ }
+ switch input {
+ case ESKSymbol:
+ return ESKMessage, []StackSymbol{KeyStackSymbol}, false, nil
+ case EncSymbol:
+ return EncryptedMessage, nil, false, nil
+ }
+ return 0, nil, false, NewErrMalformedMessage(ESKMessage, input, stackSymbol)
+}
+
+// fromLiteralMessage is the transition for the state LiteralMessage.
+func fromLiteralMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
+ switch input {
+ case SigSymbol:
+ if stackSymbol == OpsStackSymbol {
+ return LiteralMessage, nil, false, nil
+ }
+ case EOSSymbol:
+ if stackSymbol == EndStackSymbol {
+ return ValidMessage, nil, false, nil
+ }
+ }
+ return 0, nil, false, NewErrMalformedMessage(LiteralMessage, input, stackSymbol)
+}
+
+// fromLiteralMessage is the transition for the state CompressedMessage.
+func fromCompressedMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
+ switch input {
+ case SigSymbol:
+ if stackSymbol == OpsStackSymbol {
+ return CompressedMessage, nil, false, nil
+ }
+ case EOSSymbol:
+ if stackSymbol == EndStackSymbol {
+ return ValidMessage, nil, false, nil
+ }
+ }
+ return OpenPGPMessage, []StackSymbol{MsgStackSymbol}, true, nil
+}
+
+// fromEncryptedMessage is the transition for the state EncryptedMessage.
+func fromEncryptedMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
+ switch input {
+ case SigSymbol:
+ if stackSymbol == OpsStackSymbol {
+ return EncryptedMessage, nil, false, nil
+ }
+ case EOSSymbol:
+ if stackSymbol == EndStackSymbol {
+ return ValidMessage, nil, false, nil
+ }
+ }
+ return OpenPGPMessage, []StackSymbol{MsgStackSymbol}, true, nil
+}
+
+// fromValidMessage is the transition for the state ValidMessage.
+func fromValidMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
+ return 0, nil, false, NewErrMalformedMessage(ValidMessage, input, stackSymbol)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_unsupported.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_unsupported.go
new file mode 100644
index 0000000000..2d714723cf
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_unsupported.go
@@ -0,0 +1,24 @@
+package packet
+
+import (
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+// UnsupportedPackage represents a OpenPGP packet with a known packet type
+// but with unsupported content.
+type UnsupportedPacket struct {
+ IncompletePacket Packet
+ Error errors.UnsupportedError
+}
+
+// Implements the Packet interface
+func (up *UnsupportedPacket) parse(read io.Reader) error {
+ err := up.IncompletePacket.parse(read)
+ if castedErr, ok := err.(errors.UnsupportedError); ok {
+ up.Error = castedErr
+ return nil
+ }
+ return err
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/padding.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/padding.go
new file mode 100644
index 0000000000..3b6a7045d1
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/padding.go
@@ -0,0 +1,26 @@
+package packet
+
+import (
+ "io"
+)
+
+// Padding type represents a Padding Packet (Tag 21).
+// The padding type is represented by the length of its padding.
+// see https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-padding-packet-tag-21
+type Padding int
+
+// parse just ignores the padding content.
+func (pad Padding) parse(reader io.Reader) error {
+ _, err := io.CopyN(io.Discard, reader, int64(pad))
+ return err
+}
+
+// SerializePadding writes the padding to writer.
+func (pad Padding) SerializePadding(writer io.Writer, rand io.Reader) error {
+ err := serializeHeader(writer, packetPadding, int(pad))
+ if err != nil {
+ return err
+ }
+ _, err = io.CopyN(writer, rand, int64(pad))
+ return err
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
new file mode 100644
index 0000000000..f04e6c6b87
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
@@ -0,0 +1,1191 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/cipher"
+ "crypto/dsa"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/subtle"
+ "fmt"
+ "io"
+ "math/big"
+ "strconv"
+ "time"
+
+ "github.com/ProtonMail/go-crypto/openpgp/ecdh"
+ "github.com/ProtonMail/go-crypto/openpgp/ecdsa"
+ "github.com/ProtonMail/go-crypto/openpgp/ed25519"
+ "github.com/ProtonMail/go-crypto/openpgp/ed448"
+ "github.com/ProtonMail/go-crypto/openpgp/eddsa"
+ "github.com/ProtonMail/go-crypto/openpgp/elgamal"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
+ "github.com/ProtonMail/go-crypto/openpgp/s2k"
+ "github.com/ProtonMail/go-crypto/openpgp/x25519"
+ "github.com/ProtonMail/go-crypto/openpgp/x448"
+ "golang.org/x/crypto/hkdf"
+)
+
+// PrivateKey represents a possibly encrypted private key. See RFC 4880,
+// section 5.5.3.
+type PrivateKey struct {
+ PublicKey
+ Encrypted bool // if true then the private key is unavailable until Decrypt has been called.
+ encryptedData []byte
+ cipher CipherFunction
+ s2k func(out, in []byte)
+ aead AEADMode // only relevant if S2KAEAD is enabled
+ // An *{rsa|dsa|elgamal|ecdh|ecdsa|ed25519|ed448}.PrivateKey or
+ // crypto.Signer/crypto.Decrypter (Decryptor RSA only).
+ PrivateKey interface{}
+ iv []byte
+
+ // Type of encryption of the S2K packet
+ // Allowed values are 0 (Not encrypted), 253 (AEAD), 254 (SHA1), or
+ // 255 (2-byte checksum)
+ s2kType S2KType
+ // Full parameters of the S2K packet
+ s2kParams *s2k.Params
+}
+
+// S2KType s2k packet type
+type S2KType uint8
+
+const (
+ // S2KNON unencrypt
+ S2KNON S2KType = 0
+ // S2KAEAD use authenticated encryption
+ S2KAEAD S2KType = 253
+ // S2KSHA1 sha1 sum check
+ S2KSHA1 S2KType = 254
+ // S2KCHECKSUM sum check
+ S2KCHECKSUM S2KType = 255
+)
+
+func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewEdDSAPrivateKey(creationTime time.Time, priv *eddsa.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewEdDSAPublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewECDHPrivateKey(creationTime time.Time, priv *ecdh.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewX25519PrivateKey(creationTime time.Time, priv *x25519.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewX25519PublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewX448PrivateKey(creationTime time.Time, priv *x448.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewX448PublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewEd25519PrivateKey(creationTime time.Time, priv *ed25519.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewEd25519PublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewEd448PrivateKey(creationTime time.Time, priv *ed448.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewEd448PublicKey(creationTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that
+// implements RSA, ECDSA or EdDSA.
+func NewSignerPrivateKey(creationTime time.Time, signer interface{}) *PrivateKey {
+ pk := new(PrivateKey)
+ // In general, the public Keys should be used as pointers. We still
+ // type-switch on the values, for backwards-compatibility.
+ switch pubkey := signer.(type) {
+ case *rsa.PrivateKey:
+ pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey.PublicKey)
+ case rsa.PrivateKey:
+ pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey.PublicKey)
+ case *ecdsa.PrivateKey:
+ pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey.PublicKey)
+ case ecdsa.PrivateKey:
+ pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey.PublicKey)
+ case *eddsa.PrivateKey:
+ pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
+ case eddsa.PrivateKey:
+ pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
+ case *ed25519.PrivateKey:
+ pk.PublicKey = *NewEd25519PublicKey(creationTime, &pubkey.PublicKey)
+ case ed25519.PrivateKey:
+ pk.PublicKey = *NewEd25519PublicKey(creationTime, &pubkey.PublicKey)
+ case *ed448.PrivateKey:
+ pk.PublicKey = *NewEd448PublicKey(creationTime, &pubkey.PublicKey)
+ case ed448.PrivateKey:
+ pk.PublicKey = *NewEd448PublicKey(creationTime, &pubkey.PublicKey)
+ default:
+ panic("openpgp: unknown signer type in NewSignerPrivateKey")
+ }
+ pk.PrivateKey = signer
+ return pk
+}
+
+// NewDecrypterPrivateKey creates a PrivateKey from a *{rsa|elgamal|ecdh|x25519|x448}.PrivateKey.
+func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *PrivateKey {
+ pk := new(PrivateKey)
+ switch priv := decrypter.(type) {
+ case *rsa.PrivateKey:
+ pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey)
+ case *elgamal.PrivateKey:
+ pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey)
+ case *ecdh.PrivateKey:
+ pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey)
+ case *x25519.PrivateKey:
+ pk.PublicKey = *NewX25519PublicKey(creationTime, &priv.PublicKey)
+ case *x448.PrivateKey:
+ pk.PublicKey = *NewX448PublicKey(creationTime, &priv.PublicKey)
+ default:
+ panic("openpgp: unknown decrypter type in NewDecrypterPrivateKey")
+ }
+ pk.PrivateKey = decrypter
+ return pk
+}
+
+func (pk *PrivateKey) parse(r io.Reader) (err error) {
+ err = (&pk.PublicKey).parse(r)
+ if err != nil {
+ return
+ }
+ v5 := pk.PublicKey.Version == 5
+ v6 := pk.PublicKey.Version == 6
+
+ if V5Disabled && v5 {
+ return errors.UnsupportedError("support for parsing v5 entities is disabled; build with `-tags v5` if needed")
+ }
+
+ var buf [1]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ pk.s2kType = S2KType(buf[0])
+ var optCount [1]byte
+ if v5 || (v6 && pk.s2kType != S2KNON) {
+ if _, err = readFull(r, optCount[:]); err != nil {
+ return
+ }
+ }
+
+ switch pk.s2kType {
+ case S2KNON:
+ pk.s2k = nil
+ pk.Encrypted = false
+ case S2KSHA1, S2KCHECKSUM, S2KAEAD:
+ if (v5 || v6) && pk.s2kType == S2KCHECKSUM {
+ return errors.StructuralError(fmt.Sprintf("wrong s2k identifier for version %d", pk.Version))
+ }
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ pk.cipher = CipherFunction(buf[0])
+ if pk.cipher != 0 && !pk.cipher.IsSupported() {
+ return errors.UnsupportedError("unsupported cipher function in private key")
+ }
+ // [Optional] If string-to-key usage octet was 253,
+ // a one-octet AEAD algorithm.
+ if pk.s2kType == S2KAEAD {
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ pk.aead = AEADMode(buf[0])
+ if !pk.aead.IsSupported() {
+ return errors.UnsupportedError("unsupported aead mode in private key")
+ }
+ }
+
+ // [Optional] Only for a version 6 packet,
+ // and if string-to-key usage octet was 255, 254, or 253,
+ // an one-octet count of the following field.
+ if v6 {
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ }
+
+ pk.s2kParams, err = s2k.ParseIntoParams(r)
+ if err != nil {
+ return
+ }
+ if pk.s2kParams.Dummy() {
+ return
+ }
+ if pk.s2kParams.Mode() == s2k.Argon2S2K && pk.s2kType != S2KAEAD {
+ return errors.StructuralError("using Argon2 S2K without AEAD is not allowed")
+ }
+ if pk.s2kParams.Mode() == s2k.SimpleS2K && pk.Version == 6 {
+ return errors.StructuralError("using Simple S2K with version 6 keys is not allowed")
+ }
+ pk.s2k, err = pk.s2kParams.Function()
+ if err != nil {
+ return
+ }
+ pk.Encrypted = true
+ default:
+ return errors.UnsupportedError("deprecated s2k function in private key")
+ }
+
+ if pk.Encrypted {
+ var ivSize int
+ // If the S2K usage octet was 253, the IV is of the size expected by the AEAD mode,
+ // unless it's a version 5 key, in which case it's the size of the symmetric cipher's block size.
+ // For all other S2K modes, it's always the block size.
+ if !v5 && pk.s2kType == S2KAEAD {
+ ivSize = pk.aead.IvLength()
+ } else {
+ ivSize = pk.cipher.blockSize()
+ }
+
+ if ivSize == 0 {
+ return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
+ }
+ pk.iv = make([]byte, ivSize)
+ _, err = readFull(r, pk.iv)
+ if err != nil {
+ return
+ }
+ if v5 && pk.s2kType == S2KAEAD {
+ pk.iv = pk.iv[:pk.aead.IvLength()]
+ }
+ }
+
+ var privateKeyData []byte
+ if v5 {
+ var n [4]byte /* secret material four octet count */
+ _, err = readFull(r, n[:])
+ if err != nil {
+ return
+ }
+ count := uint32(uint32(n[0])<<24 | uint32(n[1])<<16 | uint32(n[2])<<8 | uint32(n[3]))
+ if !pk.Encrypted {
+ count = count + 2 /* two octet checksum */
+ }
+ privateKeyData = make([]byte, count)
+ _, err = readFull(r, privateKeyData)
+ if err != nil {
+ return
+ }
+ } else {
+ privateKeyData, err = io.ReadAll(r)
+ if err != nil {
+ return
+ }
+ }
+ if !pk.Encrypted {
+ if len(privateKeyData) < 2 {
+ return errors.StructuralError("truncated private key data")
+ }
+ if pk.Version != 6 {
+ // checksum
+ var sum uint16
+ for i := 0; i < len(privateKeyData)-2; i++ {
+ sum += uint16(privateKeyData[i])
+ }
+ if privateKeyData[len(privateKeyData)-2] != uint8(sum>>8) ||
+ privateKeyData[len(privateKeyData)-1] != uint8(sum) {
+ return errors.StructuralError("private key checksum failure")
+ }
+ privateKeyData = privateKeyData[:len(privateKeyData)-2]
+ return pk.parsePrivateKey(privateKeyData)
+ } else {
+ // No checksum
+ return pk.parsePrivateKey(privateKeyData)
+ }
+ }
+
+ pk.encryptedData = privateKeyData
+ return
+}
+
+// Dummy returns true if the private key is a dummy key. This is a GNU extension.
+func (pk *PrivateKey) Dummy() bool {
+ return pk.s2kParams.Dummy()
+}
+
+func mod64kHash(d []byte) uint16 {
+ var h uint16
+ for _, b := range d {
+ h += uint16(b)
+ }
+ return h
+}
+
+func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
+ contents := bytes.NewBuffer(nil)
+ err = pk.PublicKey.serializeWithoutHeaders(contents)
+ if err != nil {
+ return
+ }
+ if _, err = contents.Write([]byte{uint8(pk.s2kType)}); err != nil {
+ return
+ }
+
+ optional := bytes.NewBuffer(nil)
+ if pk.Encrypted || pk.Dummy() {
+ // [Optional] If string-to-key usage octet was 255, 254, or 253,
+ // a one-octet symmetric encryption algorithm.
+ if _, err = optional.Write([]byte{uint8(pk.cipher)}); err != nil {
+ return
+ }
+ // [Optional] If string-to-key usage octet was 253,
+ // a one-octet AEAD algorithm.
+ if pk.s2kType == S2KAEAD {
+ if _, err = optional.Write([]byte{uint8(pk.aead)}); err != nil {
+ return
+ }
+ }
+
+ s2kBuffer := bytes.NewBuffer(nil)
+ if err := pk.s2kParams.Serialize(s2kBuffer); err != nil {
+ return err
+ }
+ // [Optional] Only for a version 6 packet, and if string-to-key
+ // usage octet was 255, 254, or 253, an one-octet
+ // count of the following field.
+ if pk.Version == 6 {
+ if _, err = optional.Write([]byte{uint8(s2kBuffer.Len())}); err != nil {
+ return
+ }
+ }
+ // [Optional] If string-to-key usage octet was 255, 254, or 253,
+ // a string-to-key (S2K) specifier. The length of the string-to-key specifier
+ // depends on its type
+ if _, err = io.Copy(optional, s2kBuffer); err != nil {
+ return
+ }
+
+ // IV
+ if pk.Encrypted {
+ if _, err = optional.Write(pk.iv); err != nil {
+ return
+ }
+ if pk.Version == 5 && pk.s2kType == S2KAEAD {
+ // Add padding for version 5
+ padding := make([]byte, pk.cipher.blockSize()-len(pk.iv))
+ if _, err = optional.Write(padding); err != nil {
+ return
+ }
+ }
+ }
+ }
+ if pk.Version == 5 || (pk.Version == 6 && pk.s2kType != S2KNON) {
+ contents.Write([]byte{uint8(optional.Len())})
+ }
+
+ if _, err := io.Copy(contents, optional); err != nil {
+ return err
+ }
+
+ if !pk.Dummy() {
+ l := 0
+ var priv []byte
+ if !pk.Encrypted {
+ buf := bytes.NewBuffer(nil)
+ err = pk.serializePrivateKey(buf)
+ if err != nil {
+ return err
+ }
+ l = buf.Len()
+ if pk.Version != 6 {
+ checksum := mod64kHash(buf.Bytes())
+ buf.Write([]byte{byte(checksum >> 8), byte(checksum)})
+ }
+ priv = buf.Bytes()
+ } else {
+ priv, l = pk.encryptedData, len(pk.encryptedData)
+ }
+
+ if pk.Version == 5 {
+ contents.Write([]byte{byte(l >> 24), byte(l >> 16), byte(l >> 8), byte(l)})
+ }
+ contents.Write(priv)
+ }
+
+ ptype := packetTypePrivateKey
+ if pk.IsSubkey {
+ ptype = packetTypePrivateSubkey
+ }
+ err = serializeHeader(w, ptype, contents.Len())
+ if err != nil {
+ return
+ }
+ _, err = io.Copy(w, contents)
+ if err != nil {
+ return
+ }
+ return
+}
+
+func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error {
+ if _, err := w.Write(new(encoding.MPI).SetBig(priv.D).EncodedBytes()); err != nil {
+ return err
+ }
+ if _, err := w.Write(new(encoding.MPI).SetBig(priv.Primes[1]).EncodedBytes()); err != nil {
+ return err
+ }
+ if _, err := w.Write(new(encoding.MPI).SetBig(priv.Primes[0]).EncodedBytes()); err != nil {
+ return err
+ }
+ _, err := w.Write(new(encoding.MPI).SetBig(priv.Precomputed.Qinv).EncodedBytes())
+ return err
+}
+
+func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error {
+ _, err := w.Write(new(encoding.MPI).SetBig(priv.X).EncodedBytes())
+ return err
+}
+
+func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error {
+ _, err := w.Write(new(encoding.MPI).SetBig(priv.X).EncodedBytes())
+ return err
+}
+
+func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error {
+ _, err := w.Write(encoding.NewMPI(priv.MarshalIntegerSecret()).EncodedBytes())
+ return err
+}
+
+func serializeEdDSAPrivateKey(w io.Writer, priv *eddsa.PrivateKey) error {
+ _, err := w.Write(encoding.NewMPI(priv.MarshalByteSecret()).EncodedBytes())
+ return err
+}
+
+func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error {
+ _, err := w.Write(encoding.NewMPI(priv.MarshalByteSecret()).EncodedBytes())
+ return err
+}
+
+func serializeX25519PrivateKey(w io.Writer, priv *x25519.PrivateKey) error {
+ _, err := w.Write(priv.Secret)
+ return err
+}
+
+func serializeX448PrivateKey(w io.Writer, priv *x448.PrivateKey) error {
+ _, err := w.Write(priv.Secret)
+ return err
+}
+
+func serializeEd25519PrivateKey(w io.Writer, priv *ed25519.PrivateKey) error {
+ _, err := w.Write(priv.MarshalByteSecret())
+ return err
+}
+
+func serializeEd448PrivateKey(w io.Writer, priv *ed448.PrivateKey) error {
+ _, err := w.Write(priv.MarshalByteSecret())
+ return err
+}
+
+// decrypt decrypts an encrypted private key using a decryption key.
+func (pk *PrivateKey) decrypt(decryptionKey []byte) error {
+ if pk.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ if !pk.Encrypted {
+ return nil
+ }
+ block := pk.cipher.new(decryptionKey)
+ var data []byte
+ switch pk.s2kType {
+ case S2KAEAD:
+ aead := pk.aead.new(block)
+ additionalData, err := pk.additionalData()
+ if err != nil {
+ return err
+ }
+ // Decrypt the encrypted key material with aead
+ data, err = aead.Open(nil, pk.iv, pk.encryptedData, additionalData)
+ if err != nil {
+ return err
+ }
+ case S2KSHA1, S2KCHECKSUM:
+ cfb := cipher.NewCFBDecrypter(block, pk.iv)
+ data = make([]byte, len(pk.encryptedData))
+ cfb.XORKeyStream(data, pk.encryptedData)
+ if pk.s2kType == S2KSHA1 {
+ if len(data) < sha1.Size {
+ return errors.StructuralError("truncated private key data")
+ }
+ h := sha1.New()
+ h.Write(data[:len(data)-sha1.Size])
+ sum := h.Sum(nil)
+ if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
+ return errors.StructuralError("private key checksum failure")
+ }
+ data = data[:len(data)-sha1.Size]
+ } else {
+ if len(data) < 2 {
+ return errors.StructuralError("truncated private key data")
+ }
+ var sum uint16
+ for i := 0; i < len(data)-2; i++ {
+ sum += uint16(data[i])
+ }
+ if data[len(data)-2] != uint8(sum>>8) ||
+ data[len(data)-1] != uint8(sum) {
+ return errors.StructuralError("private key checksum failure")
+ }
+ data = data[:len(data)-2]
+ }
+ default:
+ return errors.InvalidArgumentError("invalid s2k type")
+ }
+
+ err := pk.parsePrivateKey(data)
+ if _, ok := err.(errors.KeyInvalidError); ok {
+ return errors.KeyInvalidError("invalid key parameters")
+ }
+ if err != nil {
+ return err
+ }
+
+ // Mark key as unencrypted
+ pk.s2kType = S2KNON
+ pk.s2k = nil
+ pk.Encrypted = false
+ pk.encryptedData = nil
+ return nil
+}
+
+func (pk *PrivateKey) decryptWithCache(passphrase []byte, keyCache *s2k.Cache) error {
+ if pk.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ if !pk.Encrypted {
+ return nil
+ }
+
+ key, err := keyCache.GetOrComputeDerivedKey(passphrase, pk.s2kParams, pk.cipher.KeySize())
+ if err != nil {
+ return err
+ }
+ if pk.s2kType == S2KAEAD {
+ key = pk.applyHKDF(key)
+ }
+ return pk.decrypt(key)
+}
+
+// Decrypt decrypts an encrypted private key using a passphrase.
+func (pk *PrivateKey) Decrypt(passphrase []byte) error {
+ if pk.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ if !pk.Encrypted {
+ return nil
+ }
+
+ key := make([]byte, pk.cipher.KeySize())
+ pk.s2k(key, passphrase)
+ if pk.s2kType == S2KAEAD {
+ key = pk.applyHKDF(key)
+ }
+ return pk.decrypt(key)
+}
+
+// DecryptPrivateKeys decrypts all encrypted keys with the given config and passphrase.
+// Avoids recomputation of similar s2k key derivations.
+func DecryptPrivateKeys(keys []*PrivateKey, passphrase []byte) error {
+ // Create a cache to avoid recomputation of key derviations for the same passphrase.
+ s2kCache := &s2k.Cache{}
+ for _, key := range keys {
+ if key != nil && !key.Dummy() && key.Encrypted {
+ err := key.decryptWithCache(passphrase, s2kCache)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// encrypt encrypts an unencrypted private key.
+func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, s2kType S2KType, cipherFunction CipherFunction, rand io.Reader) error {
+ if pk.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ if pk.Encrypted {
+ return nil
+ }
+ // check if encryptionKey has the correct size
+ if len(key) != cipherFunction.KeySize() {
+ return errors.InvalidArgumentError("supplied encryption key has the wrong size")
+ }
+
+ if params.Mode() == s2k.Argon2S2K && s2kType != S2KAEAD {
+ return errors.InvalidArgumentError("using Argon2 S2K without AEAD is not allowed")
+ }
+ if params.Mode() != s2k.Argon2S2K && params.Mode() != s2k.IteratedSaltedS2K &&
+ params.Mode() != s2k.SaltedS2K { // only allowed for high-entropy passphrases
+ return errors.InvalidArgumentError("insecure S2K mode")
+ }
+
+ priv := bytes.NewBuffer(nil)
+ err := pk.serializePrivateKey(priv)
+ if err != nil {
+ return err
+ }
+
+ pk.cipher = cipherFunction
+ pk.s2kParams = params
+ pk.s2k, err = pk.s2kParams.Function()
+ if err != nil {
+ return err
+ }
+
+ privateKeyBytes := priv.Bytes()
+ pk.s2kType = s2kType
+ block := pk.cipher.new(key)
+ switch s2kType {
+ case S2KAEAD:
+ if pk.aead == 0 {
+ return errors.StructuralError("aead mode is not set on key")
+ }
+ aead := pk.aead.new(block)
+ additionalData, err := pk.additionalData()
+ if err != nil {
+ return err
+ }
+ pk.iv = make([]byte, aead.NonceSize())
+ _, err = io.ReadFull(rand, pk.iv)
+ if err != nil {
+ return err
+ }
+ // Decrypt the encrypted key material with aead
+ pk.encryptedData = aead.Seal(nil, pk.iv, privateKeyBytes, additionalData)
+ case S2KSHA1, S2KCHECKSUM:
+ pk.iv = make([]byte, pk.cipher.blockSize())
+ _, err = io.ReadFull(rand, pk.iv)
+ if err != nil {
+ return err
+ }
+ cfb := cipher.NewCFBEncrypter(block, pk.iv)
+ if s2kType == S2KSHA1 {
+ h := sha1.New()
+ h.Write(privateKeyBytes)
+ sum := h.Sum(nil)
+ privateKeyBytes = append(privateKeyBytes, sum...)
+ } else {
+ var sum uint16
+ for _, b := range privateKeyBytes {
+ sum += uint16(b)
+ }
+ privateKeyBytes = append(privateKeyBytes, []byte{uint8(sum >> 8), uint8(sum)}...)
+ }
+ pk.encryptedData = make([]byte, len(privateKeyBytes))
+ cfb.XORKeyStream(pk.encryptedData, privateKeyBytes)
+ default:
+ return errors.InvalidArgumentError("invalid s2k type for encryption")
+ }
+
+ pk.Encrypted = true
+ pk.PrivateKey = nil
+ return err
+}
+
+// EncryptWithConfig encrypts an unencrypted private key using the passphrase and the config.
+func (pk *PrivateKey) EncryptWithConfig(passphrase []byte, config *Config) error {
+ params, err := s2k.Generate(config.Random(), config.S2K())
+ if err != nil {
+ return err
+ }
+ // Derive an encryption key with the configured s2k function.
+ key := make([]byte, config.Cipher().KeySize())
+ s2k, err := params.Function()
+ if err != nil {
+ return err
+ }
+ s2k(key, passphrase)
+ s2kType := S2KSHA1
+ if config.AEAD() != nil {
+ s2kType = S2KAEAD
+ pk.aead = config.AEAD().Mode()
+ pk.cipher = config.Cipher()
+ key = pk.applyHKDF(key)
+ }
+ // Encrypt the private key with the derived encryption key.
+ return pk.encrypt(key, params, s2kType, config.Cipher(), config.Random())
+}
+
+// EncryptPrivateKeys encrypts all unencrypted keys with the given config and passphrase.
+// Only derives one key from the passphrase, which is then used to encrypt each key.
+func EncryptPrivateKeys(keys []*PrivateKey, passphrase []byte, config *Config) error {
+ params, err := s2k.Generate(config.Random(), config.S2K())
+ if err != nil {
+ return err
+ }
+ // Derive an encryption key with the configured s2k function.
+ encryptionKey := make([]byte, config.Cipher().KeySize())
+ s2k, err := params.Function()
+ if err != nil {
+ return err
+ }
+ s2k(encryptionKey, passphrase)
+ for _, key := range keys {
+ if key != nil && !key.Dummy() && !key.Encrypted {
+ s2kType := S2KSHA1
+ if config.AEAD() != nil {
+ s2kType = S2KAEAD
+ key.aead = config.AEAD().Mode()
+ key.cipher = config.Cipher()
+ derivedKey := key.applyHKDF(encryptionKey)
+ err = key.encrypt(derivedKey, params, s2kType, config.Cipher(), config.Random())
+ } else {
+ err = key.encrypt(encryptionKey, params, s2kType, config.Cipher(), config.Random())
+ }
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// Encrypt encrypts an unencrypted private key using a passphrase.
+func (pk *PrivateKey) Encrypt(passphrase []byte) error {
+ // Default config of private key encryption
+ config := &Config{
+ S2KConfig: &s2k.Config{
+ S2KMode: s2k.IteratedSaltedS2K,
+ S2KCount: 65536,
+ Hash: crypto.SHA256,
+ },
+ DefaultCipher: CipherAES256,
+ }
+ return pk.EncryptWithConfig(passphrase, config)
+}
+
+func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) {
+ switch priv := pk.PrivateKey.(type) {
+ case *rsa.PrivateKey:
+ err = serializeRSAPrivateKey(w, priv)
+ case *dsa.PrivateKey:
+ err = serializeDSAPrivateKey(w, priv)
+ case *elgamal.PrivateKey:
+ err = serializeElGamalPrivateKey(w, priv)
+ case *ecdsa.PrivateKey:
+ err = serializeECDSAPrivateKey(w, priv)
+ case *eddsa.PrivateKey:
+ err = serializeEdDSAPrivateKey(w, priv)
+ case *ecdh.PrivateKey:
+ err = serializeECDHPrivateKey(w, priv)
+ case *x25519.PrivateKey:
+ err = serializeX25519PrivateKey(w, priv)
+ case *x448.PrivateKey:
+ err = serializeX448PrivateKey(w, priv)
+ case *ed25519.PrivateKey:
+ err = serializeEd25519PrivateKey(w, priv)
+ case *ed448.PrivateKey:
+ err = serializeEd448PrivateKey(w, priv)
+ default:
+ err = errors.InvalidArgumentError("unknown private key type")
+ }
+ return
+}
+
+func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
+ switch pk.PublicKey.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly:
+ return pk.parseRSAPrivateKey(data)
+ case PubKeyAlgoDSA:
+ return pk.parseDSAPrivateKey(data)
+ case PubKeyAlgoElGamal:
+ return pk.parseElGamalPrivateKey(data)
+ case PubKeyAlgoECDSA:
+ return pk.parseECDSAPrivateKey(data)
+ case PubKeyAlgoECDH:
+ return pk.parseECDHPrivateKey(data)
+ case PubKeyAlgoEdDSA:
+ return pk.parseEdDSAPrivateKey(data)
+ case PubKeyAlgoX25519:
+ return pk.parseX25519PrivateKey(data)
+ case PubKeyAlgoX448:
+ return pk.parseX448PrivateKey(data)
+ case PubKeyAlgoEd25519:
+ return pk.parseEd25519PrivateKey(data)
+ case PubKeyAlgoEd448:
+ return pk.parseEd448PrivateKey(data)
+ default:
+ err = errors.StructuralError("unknown private key type")
+ return
+ }
+}
+
+func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) {
+ rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
+ rsaPriv := new(rsa.PrivateKey)
+ rsaPriv.PublicKey = *rsaPub
+
+ buf := bytes.NewBuffer(data)
+ d := new(encoding.MPI)
+ if _, err := d.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ p := new(encoding.MPI)
+ if _, err := p.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ q := new(encoding.MPI)
+ if _, err := q.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ rsaPriv.D = new(big.Int).SetBytes(d.Bytes())
+ rsaPriv.Primes = make([]*big.Int, 2)
+ rsaPriv.Primes[0] = new(big.Int).SetBytes(p.Bytes())
+ rsaPriv.Primes[1] = new(big.Int).SetBytes(q.Bytes())
+ if err := rsaPriv.Validate(); err != nil {
+ return errors.KeyInvalidError(err.Error())
+ }
+ rsaPriv.Precompute()
+ pk.PrivateKey = rsaPriv
+
+ return nil
+}
+
+func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) {
+ dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey)
+ dsaPriv := new(dsa.PrivateKey)
+ dsaPriv.PublicKey = *dsaPub
+
+ buf := bytes.NewBuffer(data)
+ x := new(encoding.MPI)
+ if _, err := x.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ dsaPriv.X = new(big.Int).SetBytes(x.Bytes())
+ if err := validateDSAParameters(dsaPriv); err != nil {
+ return err
+ }
+ pk.PrivateKey = dsaPriv
+
+ return nil
+}
+
+func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) {
+ pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
+ priv := new(elgamal.PrivateKey)
+ priv.PublicKey = *pub
+
+ buf := bytes.NewBuffer(data)
+ x := new(encoding.MPI)
+ if _, err := x.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ priv.X = new(big.Int).SetBytes(x.Bytes())
+ if err := validateElGamalParameters(priv); err != nil {
+ return err
+ }
+ pk.PrivateKey = priv
+
+ return nil
+}
+
+func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) {
+ ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey)
+ ecdsaPriv := ecdsa.NewPrivateKey(*ecdsaPub)
+
+ buf := bytes.NewBuffer(data)
+ d := new(encoding.MPI)
+ if _, err := d.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ if err := ecdsaPriv.UnmarshalIntegerSecret(d.Bytes()); err != nil {
+ return err
+ }
+ if err := ecdsa.Validate(ecdsaPriv); err != nil {
+ return err
+ }
+ pk.PrivateKey = ecdsaPriv
+
+ return nil
+}
+
+func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) {
+ ecdhPub := pk.PublicKey.PublicKey.(*ecdh.PublicKey)
+ ecdhPriv := ecdh.NewPrivateKey(*ecdhPub)
+
+ buf := bytes.NewBuffer(data)
+ d := new(encoding.MPI)
+ if _, err := d.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ if err := ecdhPriv.UnmarshalByteSecret(d.Bytes()); err != nil {
+ return err
+ }
+
+ if err := ecdh.Validate(ecdhPriv); err != nil {
+ return err
+ }
+
+ pk.PrivateKey = ecdhPriv
+
+ return nil
+}
+
+func (pk *PrivateKey) parseX25519PrivateKey(data []byte) (err error) {
+ publicKey := pk.PublicKey.PublicKey.(*x25519.PublicKey)
+ privateKey := x25519.NewPrivateKey(*publicKey)
+ privateKey.PublicKey = *publicKey
+
+ privateKey.Secret = make([]byte, x25519.KeySize)
+
+ if len(data) != x25519.KeySize {
+ err = errors.StructuralError("wrong x25519 key size")
+ return err
+ }
+ subtle.ConstantTimeCopy(1, privateKey.Secret, data)
+ if err = x25519.Validate(privateKey); err != nil {
+ return err
+ }
+ pk.PrivateKey = privateKey
+ return nil
+}
+
+func (pk *PrivateKey) parseX448PrivateKey(data []byte) (err error) {
+ publicKey := pk.PublicKey.PublicKey.(*x448.PublicKey)
+ privateKey := x448.NewPrivateKey(*publicKey)
+ privateKey.PublicKey = *publicKey
+
+ privateKey.Secret = make([]byte, x448.KeySize)
+
+ if len(data) != x448.KeySize {
+ err = errors.StructuralError("wrong x448 key size")
+ return err
+ }
+ subtle.ConstantTimeCopy(1, privateKey.Secret, data)
+ if err = x448.Validate(privateKey); err != nil {
+ return err
+ }
+ pk.PrivateKey = privateKey
+ return nil
+}
+
+func (pk *PrivateKey) parseEd25519PrivateKey(data []byte) (err error) {
+ publicKey := pk.PublicKey.PublicKey.(*ed25519.PublicKey)
+ privateKey := ed25519.NewPrivateKey(*publicKey)
+ privateKey.PublicKey = *publicKey
+
+ if len(data) != ed25519.SeedSize {
+ err = errors.StructuralError("wrong ed25519 key size")
+ return err
+ }
+ err = privateKey.UnmarshalByteSecret(data)
+ if err != nil {
+ return err
+ }
+ err = ed25519.Validate(privateKey)
+ if err != nil {
+ return err
+ }
+ pk.PrivateKey = privateKey
+ return nil
+}
+
+func (pk *PrivateKey) parseEd448PrivateKey(data []byte) (err error) {
+ publicKey := pk.PublicKey.PublicKey.(*ed448.PublicKey)
+ privateKey := ed448.NewPrivateKey(*publicKey)
+ privateKey.PublicKey = *publicKey
+
+ if len(data) != ed448.SeedSize {
+ err = errors.StructuralError("wrong ed448 key size")
+ return err
+ }
+ err = privateKey.UnmarshalByteSecret(data)
+ if err != nil {
+ return err
+ }
+ err = ed448.Validate(privateKey)
+ if err != nil {
+ return err
+ }
+ pk.PrivateKey = privateKey
+ return nil
+}
+
+func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) {
+ eddsaPub := pk.PublicKey.PublicKey.(*eddsa.PublicKey)
+ eddsaPriv := eddsa.NewPrivateKey(*eddsaPub)
+ eddsaPriv.PublicKey = *eddsaPub
+
+ buf := bytes.NewBuffer(data)
+ d := new(encoding.MPI)
+ if _, err := d.ReadFrom(buf); err != nil {
+ return err
+ }
+
+ if err = eddsaPriv.UnmarshalByteSecret(d.Bytes()); err != nil {
+ return err
+ }
+
+ if err := eddsa.Validate(eddsaPriv); err != nil {
+ return err
+ }
+
+ pk.PrivateKey = eddsaPriv
+
+ return nil
+}
+
+func (pk *PrivateKey) additionalData() ([]byte, error) {
+ additionalData := bytes.NewBuffer(nil)
+ // Write additional data prefix based on packet type
+ var packetByte byte
+ if pk.PublicKey.IsSubkey {
+ packetByte = 0xc7
+ } else {
+ packetByte = 0xc5
+ }
+ // Write public key to additional data
+ _, err := additionalData.Write([]byte{packetByte})
+ if err != nil {
+ return nil, err
+ }
+ err = pk.PublicKey.serializeWithoutHeaders(additionalData)
+ if err != nil {
+ return nil, err
+ }
+ return additionalData.Bytes(), nil
+}
+
+func (pk *PrivateKey) applyHKDF(inputKey []byte) []byte {
+ var packetByte byte
+ if pk.PublicKey.IsSubkey {
+ packetByte = 0xc7
+ } else {
+ packetByte = 0xc5
+ }
+ associatedData := []byte{packetByte, byte(pk.Version), byte(pk.cipher), byte(pk.aead)}
+ hkdfReader := hkdf.New(sha256.New, inputKey, []byte{}, associatedData)
+ encryptionKey := make([]byte, pk.cipher.KeySize())
+ _, _ = readFull(hkdfReader, encryptionKey)
+ return encryptionKey
+}
+
+func validateDSAParameters(priv *dsa.PrivateKey) error {
+ p := priv.P // group prime
+ q := priv.Q // subgroup order
+ g := priv.G // g has order q mod p
+ x := priv.X // secret
+ y := priv.Y // y == g**x mod p
+ one := big.NewInt(1)
+ // expect g, y >= 2 and g < p
+ if g.Cmp(one) <= 0 || y.Cmp(one) <= 0 || g.Cmp(p) > 0 {
+ return errors.KeyInvalidError("dsa: invalid group")
+ }
+ // expect p > q
+ if p.Cmp(q) <= 0 {
+ return errors.KeyInvalidError("dsa: invalid group prime")
+ }
+ // q should be large enough and divide p-1
+ pSub1 := new(big.Int).Sub(p, one)
+ if q.BitLen() < 150 || new(big.Int).Mod(pSub1, q).Cmp(big.NewInt(0)) != 0 {
+ return errors.KeyInvalidError("dsa: invalid order")
+ }
+ // confirm that g has order q mod p
+ if !q.ProbablyPrime(32) || new(big.Int).Exp(g, q, p).Cmp(one) != 0 {
+ return errors.KeyInvalidError("dsa: invalid order")
+ }
+ // check y
+ if new(big.Int).Exp(g, x, p).Cmp(y) != 0 {
+ return errors.KeyInvalidError("dsa: mismatching values")
+ }
+
+ return nil
+}
+
+func validateElGamalParameters(priv *elgamal.PrivateKey) error {
+ p := priv.P // group prime
+ g := priv.G // g has order p-1 mod p
+ x := priv.X // secret
+ y := priv.Y // y == g**x mod p
+ one := big.NewInt(1)
+ // Expect g, y >= 2 and g < p
+ if g.Cmp(one) <= 0 || y.Cmp(one) <= 0 || g.Cmp(p) > 0 {
+ return errors.KeyInvalidError("elgamal: invalid group")
+ }
+ if p.BitLen() < 1024 {
+ return errors.KeyInvalidError("elgamal: group order too small")
+ }
+ pSub1 := new(big.Int).Sub(p, one)
+ if new(big.Int).Exp(g, pSub1, p).Cmp(one) != 0 {
+ return errors.KeyInvalidError("elgamal: invalid group")
+ }
+ // Since p-1 is not prime, g might have a smaller order that divides p-1.
+ // We cannot confirm the exact order of g, but we make sure it is not too small.
+ gExpI := new(big.Int).Set(g)
+ i := 1
+ threshold := 2 << 17 // we want order > threshold
+ for i < threshold {
+ i++ // we check every order to make sure key validation is not easily bypassed by guessing y'
+ gExpI.Mod(new(big.Int).Mul(gExpI, g), p)
+ if gExpI.Cmp(one) == 0 {
+ return errors.KeyInvalidError("elgamal: order too small")
+ }
+ }
+ // Check y
+ if new(big.Int).Exp(g, x, p).Cmp(y) != 0 {
+ return errors.KeyInvalidError("elgamal: mismatching values")
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go
new file mode 100644
index 0000000000..029b8f1aab
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go
@@ -0,0 +1,12 @@
+package packet
+
+// Generated with `gpg --export-secret-keys "Test Key 2"`
+const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+
+// Generated by `gpg --export-secret-keys` followed by a manual extraction of
+// the ElGamal subkey from the packets.
+const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
+
+// pkcs1PrivKeyHex is a PKCS#1, RSA private key.
+// Generated by `openssl genrsa 1024 | openssl rsa -outform DER | xxd -p`
+const pkcs1PrivKeyHex = "3082025d02010002818100e98edfa1c3b35884a54d0b36a6a603b0290fa85e49e30fa23fc94fef9c6790bc4849928607aa48d809da326fb42a969d06ad756b98b9c1a90f5d4a2b6d0ac05953c97f4da3120164a21a679793ce181c906dc01d235cc085ddcdf6ea06c389b6ab8885dfd685959e693138856a68a7e5db263337ff82a088d583a897cf2d59e9020301000102818100b6d5c9eb70b02d5369b3ee5b520a14490b5bde8a317d36f7e4c74b7460141311d1e5067735f8f01d6f5908b2b96fbd881f7a1ab9a84d82753e39e19e2d36856be960d05ac9ef8e8782ea1b6d65aee28fdfe1d61451e8cff0adfe84322f12cf455028b581cf60eb9e0e140ba5d21aeba6c2634d7c65318b9a665fc01c3191ca21024100fa5e818da3705b0fa33278bb28d4b6f6050388af2d4b75ec9375dd91ccf2e7d7068086a8b82a8f6282e4fbbdb8a7f2622eb97295249d87acea7f5f816f54d347024100eecf9406d7dc49cdfb95ab1eff4064de84c7a30f64b2798936a0d2018ba9eb52e4b636f82e96c49cc63b80b675e91e40d1b2e4017d4b9adaf33ab3d9cf1c214f024100c173704ace742c082323066226a4655226819a85304c542b9dacbeacbf5d1881ee863485fcf6f59f3a604f9b42289282067447f2b13dfeed3eab7851fc81e0550240741fc41f3fc002b382eed8730e33c5d8de40256e4accee846667f536832f711ab1d4590e7db91a8a116ac5bff3be13d3f9243ff2e976662aa9b395d907f8e9c9024046a5696c9ef882363e06c9fa4e2f5b580906452befba03f4a99d0f873697ef1f851d2226ca7934b30b7c3e80cb634a67172bbbf4781735fe3e09263e2dd723e7"
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
new file mode 100644
index 0000000000..e2813396e3
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
@@ -0,0 +1,1125 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto/dsa"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
+ _ "crypto/sha512"
+ "encoding/binary"
+ "fmt"
+ "hash"
+ "io"
+ "math/big"
+ "strconv"
+ "time"
+
+ "github.com/ProtonMail/go-crypto/openpgp/ecdh"
+ "github.com/ProtonMail/go-crypto/openpgp/ecdsa"
+ "github.com/ProtonMail/go-crypto/openpgp/ed25519"
+ "github.com/ProtonMail/go-crypto/openpgp/ed448"
+ "github.com/ProtonMail/go-crypto/openpgp/eddsa"
+ "github.com/ProtonMail/go-crypto/openpgp/elgamal"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
+ "github.com/ProtonMail/go-crypto/openpgp/x25519"
+ "github.com/ProtonMail/go-crypto/openpgp/x448"
+)
+
+// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
+type PublicKey struct {
+ Version int
+ CreationTime time.Time
+ PubKeyAlgo PublicKeyAlgorithm
+ PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey or *eddsa.PublicKey, *x25519.PublicKey, *x448.PublicKey, *ed25519.PublicKey, *ed448.PublicKey
+ Fingerprint []byte
+ KeyId uint64
+ IsSubkey bool
+
+ // RFC 4880 fields
+ n, e, p, q, g, y encoding.Field
+
+ // RFC 6637 fields
+ // oid contains the OID byte sequence identifying the elliptic curve used
+ oid encoding.Field
+
+ // kdf stores key derivation function parameters
+ // used for ECDH encryption. See RFC 6637, Section 9.
+ kdf encoding.Field
+}
+
+// UpgradeToV5 updates the version of the key to v5, and updates all necessary
+// fields.
+func (pk *PublicKey) UpgradeToV5() {
+ pk.Version = 5
+ pk.setFingerprintAndKeyId()
+}
+
+// UpgradeToV6 updates the version of the key to v6, and updates all necessary
+// fields.
+func (pk *PublicKey) UpgradeToV6() error {
+ pk.Version = 6
+ pk.setFingerprintAndKeyId()
+ return pk.checkV6Compatibility()
+}
+
+// signingKey provides a convenient abstraction over signature verification
+// for v3 and v4 public keys.
+type signingKey interface {
+ SerializeForHash(io.Writer) error
+ SerializeSignaturePrefix(io.Writer) error
+ serializeWithoutHeaders(io.Writer) error
+}
+
+// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
+func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoRSA,
+ PublicKey: pub,
+ n: new(encoding.MPI).SetBig(pub.N),
+ e: new(encoding.MPI).SetBig(big.NewInt(int64(pub.E))),
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey.
+func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoDSA,
+ PublicKey: pub,
+ p: new(encoding.MPI).SetBig(pub.P),
+ q: new(encoding.MPI).SetBig(pub.Q),
+ g: new(encoding.MPI).SetBig(pub.G),
+ y: new(encoding.MPI).SetBig(pub.Y),
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+// NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey.
+func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoElGamal,
+ PublicKey: pub,
+ p: new(encoding.MPI).SetBig(pub.P),
+ g: new(encoding.MPI).SetBig(pub.G),
+ y: new(encoding.MPI).SetBig(pub.Y),
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoECDSA,
+ PublicKey: pub,
+ p: encoding.NewMPI(pub.MarshalPoint()),
+ }
+
+ curveInfo := ecc.FindByCurve(pub.GetCurve())
+ if curveInfo == nil {
+ panic("unknown elliptic curve")
+ }
+ pk.oid = curveInfo.Oid
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func NewECDHPublicKey(creationTime time.Time, pub *ecdh.PublicKey) *PublicKey {
+ var pk *PublicKey
+ var kdf = encoding.NewOID([]byte{0x1, pub.Hash.Id(), pub.Cipher.Id()})
+ pk = &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoECDH,
+ PublicKey: pub,
+ p: encoding.NewMPI(pub.MarshalPoint()),
+ kdf: kdf,
+ }
+
+ curveInfo := ecc.FindByCurve(pub.GetCurve())
+
+ if curveInfo == nil {
+ panic("unknown elliptic curve")
+ }
+
+ pk.oid = curveInfo.Oid
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func NewEdDSAPublicKey(creationTime time.Time, pub *eddsa.PublicKey) *PublicKey {
+ curveInfo := ecc.FindByCurve(pub.GetCurve())
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoEdDSA,
+ PublicKey: pub,
+ oid: curveInfo.Oid,
+ // Native point format, see draft-koch-eddsa-for-openpgp-04, Appendix B
+ p: encoding.NewMPI(pub.MarshalPoint()),
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func NewX25519PublicKey(creationTime time.Time, pub *x25519.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoX25519,
+ PublicKey: pub,
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func NewX448PublicKey(creationTime time.Time, pub *x448.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoX448,
+ PublicKey: pub,
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func NewEd25519PublicKey(creationTime time.Time, pub *ed25519.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoEd25519,
+ PublicKey: pub,
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func NewEd448PublicKey(creationTime time.Time, pub *ed448.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ Version: 4,
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoEd448,
+ PublicKey: pub,
+ }
+
+ pk.setFingerprintAndKeyId()
+ return pk
+}
+
+func (pk *PublicKey) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.5.2
+ var buf [6]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+
+ pk.Version = int(buf[0])
+ if pk.Version != 4 && pk.Version != 5 && pk.Version != 6 {
+ return errors.UnsupportedError("public key version " + strconv.Itoa(int(buf[0])))
+ }
+
+ if V5Disabled && pk.Version == 5 {
+ return errors.UnsupportedError("support for parsing v5 entities is disabled; build with `-tags v5` if needed")
+ }
+
+ if pk.Version >= 5 {
+ // Read the four-octet scalar octet count
+ // The count is not used in this implementation
+ var n [4]byte
+ _, err = readFull(r, n[:])
+ if err != nil {
+ return
+ }
+ }
+ pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
+ pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
+ // Ignore four-ocet length
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ err = pk.parseRSA(r)
+ case PubKeyAlgoDSA:
+ err = pk.parseDSA(r)
+ case PubKeyAlgoElGamal:
+ err = pk.parseElGamal(r)
+ case PubKeyAlgoECDSA:
+ err = pk.parseECDSA(r)
+ case PubKeyAlgoECDH:
+ err = pk.parseECDH(r)
+ case PubKeyAlgoEdDSA:
+ err = pk.parseEdDSA(r)
+ case PubKeyAlgoX25519:
+ err = pk.parseX25519(r)
+ case PubKeyAlgoX448:
+ err = pk.parseX448(r)
+ case PubKeyAlgoEd25519:
+ err = pk.parseEd25519(r)
+ case PubKeyAlgoEd448:
+ err = pk.parseEd448(r)
+ default:
+ err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
+ }
+ if err != nil {
+ return
+ }
+
+ pk.setFingerprintAndKeyId()
+ return
+}
+
+func (pk *PublicKey) setFingerprintAndKeyId() {
+ // RFC 4880, section 12.2
+ if pk.Version >= 5 {
+ fingerprint := sha256.New()
+ if err := pk.SerializeForHash(fingerprint); err != nil {
+ // Should not happen for a hash.
+ panic(err)
+ }
+ pk.Fingerprint = make([]byte, 32)
+ copy(pk.Fingerprint, fingerprint.Sum(nil))
+ pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[:8])
+ } else {
+ fingerprint := sha1.New()
+ if err := pk.SerializeForHash(fingerprint); err != nil {
+ // Should not happen for a hash.
+ panic(err)
+ }
+ pk.Fingerprint = make([]byte, 20)
+ copy(pk.Fingerprint, fingerprint.Sum(nil))
+ pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
+ }
+}
+
+func (pk *PublicKey) checkV6Compatibility() error {
+ // Implementations MUST NOT accept or generate version 6 key material using the deprecated OIDs.
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoECDH:
+ curveInfo := ecc.FindByOid(pk.oid)
+ if curveInfo == nil {
+ return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
+ }
+ if curveInfo.GenName == ecc.Curve25519GenName {
+ return errors.StructuralError("cannot generate v6 key with deprecated OID: Curve25519Legacy")
+ }
+ case PubKeyAlgoEdDSA:
+ return errors.StructuralError("cannot generate v6 key with deprecated algorithm: EdDSALegacy")
+ }
+ return nil
+}
+
+// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
+ pk.n = new(encoding.MPI)
+ if _, err = pk.n.ReadFrom(r); err != nil {
+ return
+ }
+ pk.e = new(encoding.MPI)
+ if _, err = pk.e.ReadFrom(r); err != nil {
+ return
+ }
+
+ if len(pk.e.Bytes()) > 3 {
+ err = errors.UnsupportedError("large public exponent")
+ return
+ }
+ rsa := &rsa.PublicKey{
+ N: new(big.Int).SetBytes(pk.n.Bytes()),
+ E: 0,
+ }
+ for i := 0; i < len(pk.e.Bytes()); i++ {
+ rsa.E <<= 8
+ rsa.E |= int(pk.e.Bytes()[i])
+ }
+ pk.PublicKey = rsa
+ return
+}
+
+// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseDSA(r io.Reader) (err error) {
+ pk.p = new(encoding.MPI)
+ if _, err = pk.p.ReadFrom(r); err != nil {
+ return
+ }
+ pk.q = new(encoding.MPI)
+ if _, err = pk.q.ReadFrom(r); err != nil {
+ return
+ }
+ pk.g = new(encoding.MPI)
+ if _, err = pk.g.ReadFrom(r); err != nil {
+ return
+ }
+ pk.y = new(encoding.MPI)
+ if _, err = pk.y.ReadFrom(r); err != nil {
+ return
+ }
+
+ dsa := new(dsa.PublicKey)
+ dsa.P = new(big.Int).SetBytes(pk.p.Bytes())
+ dsa.Q = new(big.Int).SetBytes(pk.q.Bytes())
+ dsa.G = new(big.Int).SetBytes(pk.g.Bytes())
+ dsa.Y = new(big.Int).SetBytes(pk.y.Bytes())
+ pk.PublicKey = dsa
+ return
+}
+
+// parseElGamal parses ElGamal public key material from the given Reader. See
+// RFC 4880, section 5.5.2.
+func (pk *PublicKey) parseElGamal(r io.Reader) (err error) {
+ pk.p = new(encoding.MPI)
+ if _, err = pk.p.ReadFrom(r); err != nil {
+ return
+ }
+ pk.g = new(encoding.MPI)
+ if _, err = pk.g.ReadFrom(r); err != nil {
+ return
+ }
+ pk.y = new(encoding.MPI)
+ if _, err = pk.y.ReadFrom(r); err != nil {
+ return
+ }
+
+ elgamal := new(elgamal.PublicKey)
+ elgamal.P = new(big.Int).SetBytes(pk.p.Bytes())
+ elgamal.G = new(big.Int).SetBytes(pk.g.Bytes())
+ elgamal.Y = new(big.Int).SetBytes(pk.y.Bytes())
+ pk.PublicKey = elgamal
+ return
+}
+
+// parseECDSA parses ECDSA public key material from the given Reader. See
+// RFC 6637, Section 9.
+func (pk *PublicKey) parseECDSA(r io.Reader) (err error) {
+ pk.oid = new(encoding.OID)
+ if _, err = pk.oid.ReadFrom(r); err != nil {
+ return
+ }
+
+ curveInfo := ecc.FindByOid(pk.oid)
+ if curveInfo == nil {
+ return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
+ }
+
+ pk.p = new(encoding.MPI)
+ if _, err = pk.p.ReadFrom(r); err != nil {
+ return
+ }
+
+ c, ok := curveInfo.Curve.(ecc.ECDSACurve)
+ if !ok {
+ return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
+ }
+
+ ecdsaKey := ecdsa.NewPublicKey(c)
+ err = ecdsaKey.UnmarshalPoint(pk.p.Bytes())
+ pk.PublicKey = ecdsaKey
+
+ return
+}
+
+// parseECDH parses ECDH public key material from the given Reader. See
+// RFC 6637, Section 9.
+func (pk *PublicKey) parseECDH(r io.Reader) (err error) {
+ pk.oid = new(encoding.OID)
+ if _, err = pk.oid.ReadFrom(r); err != nil {
+ return
+ }
+
+ curveInfo := ecc.FindByOid(pk.oid)
+ if curveInfo == nil {
+ return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
+ }
+
+ if pk.Version == 6 && curveInfo.GenName == ecc.Curve25519GenName {
+ // Implementations MUST NOT accept or generate version 6 key material using the deprecated OIDs.
+ return errors.StructuralError("cannot read v6 key with deprecated OID: Curve25519Legacy")
+ }
+
+ pk.p = new(encoding.MPI)
+ if _, err = pk.p.ReadFrom(r); err != nil {
+ return
+ }
+ pk.kdf = new(encoding.OID)
+ if _, err = pk.kdf.ReadFrom(r); err != nil {
+ return
+ }
+
+ c, ok := curveInfo.Curve.(ecc.ECDHCurve)
+ if !ok {
+ return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
+ }
+
+ if kdfLen := len(pk.kdf.Bytes()); kdfLen < 3 {
+ return errors.UnsupportedError("unsupported ECDH KDF length: " + strconv.Itoa(kdfLen))
+ }
+ if reserved := pk.kdf.Bytes()[0]; reserved != 0x01 {
+ return errors.UnsupportedError("unsupported KDF reserved field: " + strconv.Itoa(int(reserved)))
+ }
+ kdfHash, ok := algorithm.HashById[pk.kdf.Bytes()[1]]
+ if !ok {
+ return errors.UnsupportedError("unsupported ECDH KDF hash: " + strconv.Itoa(int(pk.kdf.Bytes()[1])))
+ }
+ kdfCipher, ok := algorithm.CipherById[pk.kdf.Bytes()[2]]
+ if !ok {
+ return errors.UnsupportedError("unsupported ECDH KDF cipher: " + strconv.Itoa(int(pk.kdf.Bytes()[2])))
+ }
+
+ ecdhKey := ecdh.NewPublicKey(c, kdfHash, kdfCipher)
+ err = ecdhKey.UnmarshalPoint(pk.p.Bytes())
+ pk.PublicKey = ecdhKey
+
+ return
+}
+
+func (pk *PublicKey) parseEdDSA(r io.Reader) (err error) {
+ if pk.Version == 6 {
+ // Implementations MUST NOT accept or generate version 6 key material using the deprecated OIDs.
+ return errors.StructuralError("cannot generate v6 key with deprecated algorithm: EdDSALegacy")
+ }
+
+ pk.oid = new(encoding.OID)
+ if _, err = pk.oid.ReadFrom(r); err != nil {
+ return
+ }
+
+ curveInfo := ecc.FindByOid(pk.oid)
+ if curveInfo == nil {
+ return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
+ }
+
+ c, ok := curveInfo.Curve.(ecc.EdDSACurve)
+ if !ok {
+ return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
+ }
+
+ pk.p = new(encoding.MPI)
+ if _, err = pk.p.ReadFrom(r); err != nil {
+ return
+ }
+
+ if len(pk.p.Bytes()) == 0 {
+ return errors.StructuralError("empty EdDSA public key")
+ }
+
+ pub := eddsa.NewPublicKey(c)
+
+ switch flag := pk.p.Bytes()[0]; flag {
+ case 0x04:
+ // TODO: see _grcy_ecc_eddsa_ensure_compact in grcypt
+ return errors.UnsupportedError("unsupported EdDSA compression: " + strconv.Itoa(int(flag)))
+ case 0x40:
+ err = pub.UnmarshalPoint(pk.p.Bytes())
+ default:
+ return errors.UnsupportedError("unsupported EdDSA compression: " + strconv.Itoa(int(flag)))
+ }
+
+ pk.PublicKey = pub
+ return
+}
+
+func (pk *PublicKey) parseX25519(r io.Reader) (err error) {
+ point := make([]byte, x25519.KeySize)
+ _, err = io.ReadFull(r, point)
+ if err != nil {
+ return
+ }
+ pub := &x25519.PublicKey{
+ Point: point,
+ }
+ pk.PublicKey = pub
+ return
+}
+
+func (pk *PublicKey) parseX448(r io.Reader) (err error) {
+ point := make([]byte, x448.KeySize)
+ _, err = io.ReadFull(r, point)
+ if err != nil {
+ return
+ }
+ pub := &x448.PublicKey{
+ Point: point,
+ }
+ pk.PublicKey = pub
+ return
+}
+
+func (pk *PublicKey) parseEd25519(r io.Reader) (err error) {
+ point := make([]byte, ed25519.PublicKeySize)
+ _, err = io.ReadFull(r, point)
+ if err != nil {
+ return
+ }
+ pub := &ed25519.PublicKey{
+ Point: point,
+ }
+ pk.PublicKey = pub
+ return
+}
+
+func (pk *PublicKey) parseEd448(r io.Reader) (err error) {
+ point := make([]byte, ed448.PublicKeySize)
+ _, err = io.ReadFull(r, point)
+ if err != nil {
+ return
+ }
+ pub := &ed448.PublicKey{
+ Point: point,
+ }
+ pk.PublicKey = pub
+ return
+}
+
+// SerializeForHash serializes the PublicKey to w with the special packet
+// header format needed for hashing.
+func (pk *PublicKey) SerializeForHash(w io.Writer) error {
+ if err := pk.SerializeSignaturePrefix(w); err != nil {
+ return err
+ }
+ return pk.serializeWithoutHeaders(w)
+}
+
+// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
+// The prefix is used when calculating a signature over this public key. See
+// RFC 4880, section 5.2.4.
+func (pk *PublicKey) SerializeSignaturePrefix(w io.Writer) error {
+ var pLength = pk.algorithmSpecificByteCount()
+ // version, timestamp, algorithm
+ pLength += versionSize + timestampSize + algorithmSize
+ if pk.Version >= 5 {
+ // key octet count (4).
+ pLength += 4
+ _, err := w.Write([]byte{
+ // When a v4 signature is made over a key, the hash data starts with the octet 0x99, followed by a two-octet length
+ // of the key, and then the body of the key packet. When a v6 signature is made over a key, the hash data starts
+ // with the salt, then octet 0x9B, followed by a four-octet length of the key, and then the body of the key packet.
+ 0x95 + byte(pk.Version),
+ byte(pLength >> 24),
+ byte(pLength >> 16),
+ byte(pLength >> 8),
+ byte(pLength),
+ })
+ return err
+ }
+ if _, err := w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (pk *PublicKey) Serialize(w io.Writer) (err error) {
+ length := uint32(versionSize + timestampSize + algorithmSize) // 6 byte header
+ length += pk.algorithmSpecificByteCount()
+ if pk.Version >= 5 {
+ length += 4 // octet key count
+ }
+ packetType := packetTypePublicKey
+ if pk.IsSubkey {
+ packetType = packetTypePublicSubkey
+ }
+ err = serializeHeader(w, packetType, int(length))
+ if err != nil {
+ return
+ }
+ return pk.serializeWithoutHeaders(w)
+}
+
+func (pk *PublicKey) algorithmSpecificByteCount() uint32 {
+ length := uint32(0)
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ length += uint32(pk.n.EncodedLength())
+ length += uint32(pk.e.EncodedLength())
+ case PubKeyAlgoDSA:
+ length += uint32(pk.p.EncodedLength())
+ length += uint32(pk.q.EncodedLength())
+ length += uint32(pk.g.EncodedLength())
+ length += uint32(pk.y.EncodedLength())
+ case PubKeyAlgoElGamal:
+ length += uint32(pk.p.EncodedLength())
+ length += uint32(pk.g.EncodedLength())
+ length += uint32(pk.y.EncodedLength())
+ case PubKeyAlgoECDSA:
+ length += uint32(pk.oid.EncodedLength())
+ length += uint32(pk.p.EncodedLength())
+ case PubKeyAlgoECDH:
+ length += uint32(pk.oid.EncodedLength())
+ length += uint32(pk.p.EncodedLength())
+ length += uint32(pk.kdf.EncodedLength())
+ case PubKeyAlgoEdDSA:
+ length += uint32(pk.oid.EncodedLength())
+ length += uint32(pk.p.EncodedLength())
+ case PubKeyAlgoX25519:
+ length += x25519.KeySize
+ case PubKeyAlgoX448:
+ length += x448.KeySize
+ case PubKeyAlgoEd25519:
+ length += ed25519.PublicKeySize
+ case PubKeyAlgoEd448:
+ length += ed448.PublicKeySize
+ default:
+ panic("unknown public key algorithm")
+ }
+ return length
+}
+
+// serializeWithoutHeaders marshals the PublicKey to w in the form of an
+// OpenPGP public key packet, not including the packet header.
+func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
+ t := uint32(pk.CreationTime.Unix())
+ if _, err = w.Write([]byte{
+ byte(pk.Version),
+ byte(t >> 24), byte(t >> 16), byte(t >> 8), byte(t),
+ byte(pk.PubKeyAlgo),
+ }); err != nil {
+ return
+ }
+
+ if pk.Version >= 5 {
+ n := pk.algorithmSpecificByteCount()
+ if _, err = w.Write([]byte{
+ byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n),
+ }); err != nil {
+ return
+ }
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ if _, err = w.Write(pk.n.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(pk.e.EncodedBytes())
+ return
+ case PubKeyAlgoDSA:
+ if _, err = w.Write(pk.p.EncodedBytes()); err != nil {
+ return
+ }
+ if _, err = w.Write(pk.q.EncodedBytes()); err != nil {
+ return
+ }
+ if _, err = w.Write(pk.g.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(pk.y.EncodedBytes())
+ return
+ case PubKeyAlgoElGamal:
+ if _, err = w.Write(pk.p.EncodedBytes()); err != nil {
+ return
+ }
+ if _, err = w.Write(pk.g.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(pk.y.EncodedBytes())
+ return
+ case PubKeyAlgoECDSA:
+ if _, err = w.Write(pk.oid.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(pk.p.EncodedBytes())
+ return
+ case PubKeyAlgoECDH:
+ if _, err = w.Write(pk.oid.EncodedBytes()); err != nil {
+ return
+ }
+ if _, err = w.Write(pk.p.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(pk.kdf.EncodedBytes())
+ return
+ case PubKeyAlgoEdDSA:
+ if _, err = w.Write(pk.oid.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(pk.p.EncodedBytes())
+ return
+ case PubKeyAlgoX25519:
+ publicKey := pk.PublicKey.(*x25519.PublicKey)
+ _, err = w.Write(publicKey.Point)
+ return
+ case PubKeyAlgoX448:
+ publicKey := pk.PublicKey.(*x448.PublicKey)
+ _, err = w.Write(publicKey.Point)
+ return
+ case PubKeyAlgoEd25519:
+ publicKey := pk.PublicKey.(*ed25519.PublicKey)
+ _, err = w.Write(publicKey.Point)
+ return
+ case PubKeyAlgoEd448:
+ publicKey := pk.PublicKey.(*ed448.PublicKey)
+ _, err = w.Write(publicKey.Point)
+ return
+ }
+ return errors.InvalidArgumentError("bad public-key algorithm")
+}
+
+// CanSign returns true iff this public key can generate signatures
+func (pk *PublicKey) CanSign() bool {
+ return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal && pk.PubKeyAlgo != PubKeyAlgoECDH
+}
+
+// VerifyHashTag returns nil iff sig appears to be a plausible signature of the data
+// hashed into signed, based solely on its HashTag. signed is mutated by this call.
+func VerifyHashTag(signed hash.Hash, sig *Signature) (err error) {
+ if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) {
+ sig.AddMetadataToHashSuffix()
+ }
+ signed.Write(sig.HashSuffix)
+ hashBytes := signed.Sum(nil)
+ if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
+ return errors.SignatureError("hash tag doesn't match")
+ }
+ return nil
+}
+
+// VerifySignature returns nil iff sig is a valid signature, made by this
+// public key, of the data hashed into signed. signed is mutated by this call.
+func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
+ if !pk.CanSign() {
+ return errors.InvalidArgumentError("public key cannot generate signatures")
+ }
+ if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) {
+ sig.AddMetadataToHashSuffix()
+ }
+ signed.Write(sig.HashSuffix)
+ hashBytes := signed.Sum(nil)
+ // see discussion https://github.com/ProtonMail/go-crypto/issues/107
+ if sig.Version >= 5 && (hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1]) {
+ return errors.SignatureError("hash tag doesn't match")
+ }
+
+ if pk.PubKeyAlgo != sig.PubKeyAlgo {
+ return errors.InvalidArgumentError("public key and signature use different algorithms")
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
+ err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.Bytes()))
+ if err != nil {
+ return errors.SignatureError("RSA verification failure")
+ }
+ return nil
+ case PubKeyAlgoDSA:
+ dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
+ // Need to truncate hashBytes to match FIPS 186-3 section 4.6.
+ subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
+ if len(hashBytes) > subgroupSize {
+ hashBytes = hashBytes[:subgroupSize]
+ }
+ if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.Bytes()), new(big.Int).SetBytes(sig.DSASigS.Bytes())) {
+ return errors.SignatureError("DSA verification failure")
+ }
+ return nil
+ case PubKeyAlgoECDSA:
+ ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey)
+ if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.Bytes()), new(big.Int).SetBytes(sig.ECDSASigS.Bytes())) {
+ return errors.SignatureError("ECDSA verification failure")
+ }
+ return nil
+ case PubKeyAlgoEdDSA:
+ eddsaPublicKey := pk.PublicKey.(*eddsa.PublicKey)
+ if !eddsa.Verify(eddsaPublicKey, hashBytes, sig.EdDSASigR.Bytes(), sig.EdDSASigS.Bytes()) {
+ return errors.SignatureError("EdDSA verification failure")
+ }
+ return nil
+ case PubKeyAlgoEd25519:
+ ed25519PublicKey := pk.PublicKey.(*ed25519.PublicKey)
+ if !ed25519.Verify(ed25519PublicKey, hashBytes, sig.EdSig) {
+ return errors.SignatureError("Ed25519 verification failure")
+ }
+ return nil
+ case PubKeyAlgoEd448:
+ ed448PublicKey := pk.PublicKey.(*ed448.PublicKey)
+ if !ed448.Verify(ed448PublicKey, hashBytes, sig.EdSig) {
+ return errors.SignatureError("ed448 verification failure")
+ }
+ return nil
+ default:
+ return errors.SignatureError("Unsupported public key algorithm used in signature")
+ }
+}
+
+// keySignatureHash returns a Hash of the message that needs to be signed for
+// pk to assert a subkey relationship to signed.
+func keySignatureHash(pk, signed signingKey, hashFunc hash.Hash) (h hash.Hash, err error) {
+ h = hashFunc
+
+ // RFC 4880, section 5.2.4
+ err = pk.SerializeForHash(h)
+ if err != nil {
+ return nil, err
+ }
+
+ err = signed.SerializeForHash(h)
+ return
+}
+
+// VerifyKeyHashTag returns nil iff sig appears to be a plausible signature over this
+// primary key and subkey, based solely on its HashTag.
+func (pk *PublicKey) VerifyKeyHashTag(signed *PublicKey, sig *Signature) error {
+ preparedHash, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ h, err := keySignatureHash(pk, signed, preparedHash)
+ if err != nil {
+ return err
+ }
+ return VerifyHashTag(h, sig)
+}
+
+// VerifyKeySignature returns nil iff sig is a valid signature, made by this
+// public key, of signed.
+func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error {
+ preparedHash, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ h, err := keySignatureHash(pk, signed, preparedHash)
+ if err != nil {
+ return err
+ }
+ if err = pk.VerifySignature(h, sig); err != nil {
+ return err
+ }
+
+ if sig.FlagSign {
+ // Signing subkeys must be cross-signed. See
+ // https://www.gnupg.org/faq/subkey-cross-certify.html.
+ if sig.EmbeddedSignature == nil {
+ return errors.StructuralError("signing subkey is missing cross-signature")
+ }
+ preparedHashEmbedded, err := sig.EmbeddedSignature.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ // Verify the cross-signature. This is calculated over the same
+ // data as the main signature, so we cannot just recursively
+ // call signed.VerifyKeySignature(...)
+ if h, err = keySignatureHash(pk, signed, preparedHashEmbedded); err != nil {
+ return errors.StructuralError("error while hashing for cross-signature: " + err.Error())
+ }
+ if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil {
+ return errors.StructuralError("error while verifying cross-signature: " + err.Error())
+ }
+ }
+
+ return nil
+}
+
+func keyRevocationHash(pk signingKey, hashFunc hash.Hash) (err error) {
+ return pk.SerializeForHash(hashFunc)
+}
+
+// VerifyRevocationHashTag returns nil iff sig appears to be a plausible signature
+// over this public key, based solely on its HashTag.
+func (pk *PublicKey) VerifyRevocationHashTag(sig *Signature) (err error) {
+ preparedHash, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ if err = keyRevocationHash(pk, preparedHash); err != nil {
+ return err
+ }
+ return VerifyHashTag(preparedHash, sig)
+}
+
+// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this
+// public key.
+func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) {
+ preparedHash, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ if err = keyRevocationHash(pk, preparedHash); err != nil {
+ return err
+ }
+ return pk.VerifySignature(preparedHash, sig)
+}
+
+// VerifySubkeyRevocationSignature returns nil iff sig is a valid subkey revocation signature,
+// made by this public key, of signed.
+func (pk *PublicKey) VerifySubkeyRevocationSignature(sig *Signature, signed *PublicKey) (err error) {
+ preparedHash, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ h, err := keySignatureHash(pk, signed, preparedHash)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignature(h, sig)
+}
+
+// userIdSignatureHash returns a Hash of the message that needs to be signed
+// to assert that pk is a valid key for id.
+func userIdSignatureHash(id string, pk *PublicKey, h hash.Hash) (err error) {
+
+ // RFC 4880, section 5.2.4
+ if err := pk.SerializeSignaturePrefix(h); err != nil {
+ return err
+ }
+ if err := pk.serializeWithoutHeaders(h); err != nil {
+ return err
+ }
+
+ var buf [5]byte
+ buf[0] = 0xb4
+ buf[1] = byte(len(id) >> 24)
+ buf[2] = byte(len(id) >> 16)
+ buf[3] = byte(len(id) >> 8)
+ buf[4] = byte(len(id))
+ h.Write(buf[:])
+ h.Write([]byte(id))
+
+ return nil
+}
+
+// directKeySignatureHash returns a Hash of the message that needs to be signed.
+func directKeySignatureHash(pk *PublicKey, h hash.Hash) (err error) {
+ return pk.SerializeForHash(h)
+}
+
+// VerifyUserIdHashTag returns nil iff sig appears to be a plausible signature over this
+// public key and UserId, based solely on its HashTag
+func (pk *PublicKey) VerifyUserIdHashTag(id string, sig *Signature) (err error) {
+ preparedHash, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ err = userIdSignatureHash(id, pk, preparedHash)
+ if err != nil {
+ return err
+ }
+ return VerifyHashTag(preparedHash, sig)
+}
+
+// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
+// public key, that id is the identity of pub.
+func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) {
+ h, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ if err := userIdSignatureHash(id, pub, h); err != nil {
+ return err
+ }
+ return pk.VerifySignature(h, sig)
+}
+
+// VerifyDirectKeySignature returns nil iff sig is a valid signature, made by this
+// public key.
+func (pk *PublicKey) VerifyDirectKeySignature(sig *Signature) (err error) {
+ h, err := sig.PrepareVerify()
+ if err != nil {
+ return err
+ }
+ if err := directKeySignatureHash(pk, h); err != nil {
+ return err
+ }
+ return pk.VerifySignature(h, sig)
+}
+
+// KeyIdString returns the public key's fingerprint in capital hex
+// (e.g. "6C7EE1B8621CC013").
+func (pk *PublicKey) KeyIdString() string {
+ return fmt.Sprintf("%016X", pk.KeyId)
+}
+
+// KeyIdShortString returns the short form of public key's fingerprint
+// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
+// This function will return the full key id for v5 and v6 keys
+// since the short key id is undefined for them.
+func (pk *PublicKey) KeyIdShortString() string {
+ if pk.Version >= 5 {
+ return pk.KeyIdString()
+ }
+ return fmt.Sprintf("%X", pk.Fingerprint[16:20])
+}
+
+// BitLength returns the bit length for the given public key.
+func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ bitLength = pk.n.BitLength()
+ case PubKeyAlgoDSA:
+ bitLength = pk.p.BitLength()
+ case PubKeyAlgoElGamal:
+ bitLength = pk.p.BitLength()
+ case PubKeyAlgoECDSA:
+ bitLength = pk.p.BitLength()
+ case PubKeyAlgoECDH:
+ bitLength = pk.p.BitLength()
+ case PubKeyAlgoEdDSA:
+ bitLength = pk.p.BitLength()
+ case PubKeyAlgoX25519:
+ bitLength = x25519.KeySize * 8
+ case PubKeyAlgoX448:
+ bitLength = x448.KeySize * 8
+ case PubKeyAlgoEd25519:
+ bitLength = ed25519.PublicKeySize * 8
+ case PubKeyAlgoEd448:
+ bitLength = ed448.PublicKeySize * 8
+ default:
+ err = errors.InvalidArgumentError("bad public-key algorithm")
+ }
+ return
+}
+
+// Curve returns the used elliptic curve of this public key.
+// Returns an error if no elliptic curve is used.
+func (pk *PublicKey) Curve() (curve Curve, err error) {
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoECDSA, PubKeyAlgoECDH, PubKeyAlgoEdDSA:
+ curveInfo := ecc.FindByOid(pk.oid)
+ if curveInfo == nil {
+ return "", errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
+ }
+ curve = Curve(curveInfo.GenName)
+ case PubKeyAlgoEd25519, PubKeyAlgoX25519:
+ curve = Curve25519
+ case PubKeyAlgoEd448, PubKeyAlgoX448:
+ curve = Curve448
+ default:
+ err = errors.InvalidArgumentError("public key does not operate with an elliptic curve")
+ }
+ return
+}
+
+// KeyExpired returns whether sig is a self-signature of a key that has
+// expired or is created in the future.
+func (pk *PublicKey) KeyExpired(sig *Signature, currentTime time.Time) bool {
+ if pk.CreationTime.Unix() > currentTime.Unix() {
+ return true
+ }
+ if sig.KeyLifetimeSecs == nil || *sig.KeyLifetimeSecs == 0 {
+ return false
+ }
+ expiry := pk.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second)
+ return currentTime.Unix() > expiry.Unix()
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go
new file mode 100644
index 0000000000..b255f1f6f8
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go
@@ -0,0 +1,24 @@
+package packet
+
+const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb"
+
+const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001"
+
+const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed"
+
+const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0"
+
+const ecdsaFingerprintHex = "9892270b38b8980b05c8d56d43fe956c542ca00b"
+
+const ecdsaPkDataHex = "9893045071c29413052b8104002304230401f4867769cedfa52c325018896245443968e52e51d0c2df8d939949cb5b330f2921711fbee1c9b9dddb95d15cb0255e99badeddda7cc23d9ddcaacbc290969b9f24019375d61c2e4e3b36953a28d8b2bc95f78c3f1d592fb24499be348656a7b17e3963187b4361afe497bc5f9f81213f04069f8e1fb9e6a6290ae295ca1a92b894396cb4"
+
+const ecdhFingerprintHex = "722354df2475a42164d1d49faa8b938f9a201946"
+
+const ecdhPkDataHex = "b90073044d53059212052b810400220303042faa84024a20b6735c4897efa5bfb41bf85b7eefeab5ca0cb9ffc8ea04a46acb25534a577694f9e25340a4ab5223a9dd1eda530c8aa2e6718db10d7e672558c7736fe09369ea5739a2a3554bf16d41faa50562f11c6d39bbd5dffb6b9a9ec91803010909"
+
+const eddsaFingerprintHex = "b2d5e5ec0e6deca6bc8eeeb00907e75e1dd99ad8"
+
+const eddsaPkDataHex = "98330456e2132b16092b06010401da470f01010740bbda39266affa511a8c2d02edf690fb784b0499c4406185811a163539ef11dc1b41d74657374696e67203c74657374696e674074657374696e672e636f6d3e8879041316080021050256e2132b021b03050b09080702061508090a0b020416020301021e01021780000a09100907e75e1dd99ad86d0c00fe39d2008359352782bc9b61ac382584cd8eff3f57a18c2287e3afeeb05d1f04ba00fe2d0bc1ddf3ff8adb9afa3e7d9287244b4ec567f3db4d60b74a9b5465ed528203"
+
+// Source: https://sites.google.com/site/brainhub/pgpecckeys#TOC-ECC-NIST-P-384-key
+const ecc384PubHex = `99006f044d53059213052b81040022030304f6b8c5aced5b84ef9f4a209db2e4a9dfb70d28cb8c10ecd57674a9fa5a67389942b62d5e51367df4c7bfd3f8e500feecf07ed265a621a8ebbbe53e947ec78c677eba143bd1533c2b350e1c29f82313e1e1108eba063be1e64b10e6950e799c2db42465635f6473615f64685f333834203c6f70656e70677040627261696e6875622e6f72673e8900cb04101309005305024d530592301480000000002000077072656665727265642d656d61696c2d656e636f64696e67407067702e636f6d7067706d696d65040b090807021901051b03000000021602051e010000000415090a08000a0910098033880f54719fca2b0180aa37350968bd5f115afd8ce7bc7b103822152dbff06d0afcda835329510905b98cb469ba208faab87c7412b799e7b633017f58364ea480e8a1a3f253a0c5f22c446e8be9a9fce6210136ee30811abbd49139de28b5bdf8dc36d06ae748579e9ff503b90073044d53059212052b810400220303042faa84024a20b6735c4897efa5bfb41bf85b7eefeab5ca0cb9ffc8ea04a46acb25534a577694f9e25340a4ab5223a9dd1eda530c8aa2e6718db10d7e672558c7736fe09369ea5739a2a3554bf16d41faa50562f11c6d39bbd5dffb6b9a9ec9180301090989008404181309000c05024d530592051b0c000000000a0910098033880f54719f80970180eee7a6d8fcee41ee4f9289df17f9bcf9d955dca25c583b94336f3a2b2d4986dc5cf417b8d2dc86f741a9e1a6d236c0e3017d1c76575458a0cfb93ae8a2b274fcc65ceecd7a91eec83656ba13219969f06945b48c56bd04152c3a0553c5f2f4bd1267`
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
new file mode 100644
index 0000000000..dd84092392
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
@@ -0,0 +1,209 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+type PacketReader interface {
+ Next() (p Packet, err error)
+ Push(reader io.Reader) (err error)
+ Unread(p Packet)
+}
+
+// Reader reads packets from an io.Reader and allows packets to be 'unread' so
+// that they result from the next call to Next.
+type Reader struct {
+ q []Packet
+ readers []io.Reader
+}
+
+// New io.Readers are pushed when a compressed or encrypted packet is processed
+// and recursively treated as a new source of packets. However, a carefully
+// crafted packet can trigger an infinite recursive sequence of packets. See
+// http://mumble.net/~campbell/misc/pgp-quine
+// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402
+// This constant limits the number of recursive packets that may be pushed.
+const maxReaders = 32
+
+// Next returns the most recently unread Packet, or reads another packet from
+// the top-most io.Reader. Unknown/unsupported/Marker packet types are skipped.
+func (r *Reader) Next() (p Packet, err error) {
+ for {
+ p, err := r.read()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ if _, ok := err.(errors.UnknownPacketTypeError); ok {
+ continue
+ }
+ if _, ok := err.(errors.UnsupportedError); ok {
+ switch p.(type) {
+ case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
+ return nil, err
+ }
+ continue
+ }
+ return nil, err
+ } else {
+ //A marker packet MUST be ignored when received
+ switch p.(type) {
+ case *Marker:
+ continue
+ }
+ return p, nil
+ }
+ }
+ return nil, io.EOF
+}
+
+// Next returns the most recently unread Packet, or reads another packet from
+// the top-most io.Reader. Unknown/Marker packet types are skipped while unsupported
+// packets are returned as UnsupportedPacket type.
+func (r *Reader) NextWithUnsupported() (p Packet, err error) {
+ for {
+ p, err = r.read()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ if _, ok := err.(errors.UnknownPacketTypeError); ok {
+ continue
+ }
+ if casteErr, ok := err.(errors.UnsupportedError); ok {
+ return &UnsupportedPacket{
+ IncompletePacket: p,
+ Error: casteErr,
+ }, nil
+ }
+ return
+ } else {
+ //A marker packet MUST be ignored when received
+ switch p.(type) {
+ case *Marker:
+ continue
+ }
+ return
+ }
+ }
+ return nil, io.EOF
+}
+
+func (r *Reader) read() (p Packet, err error) {
+ if len(r.q) > 0 {
+ p = r.q[len(r.q)-1]
+ r.q = r.q[:len(r.q)-1]
+ return
+ }
+ for len(r.readers) > 0 {
+ p, err = Read(r.readers[len(r.readers)-1])
+ if err == io.EOF {
+ r.readers = r.readers[:len(r.readers)-1]
+ continue
+ }
+ return p, err
+ }
+ return nil, io.EOF
+}
+
+// Push causes the Reader to start reading from a new io.Reader. When an EOF
+// error is seen from the new io.Reader, it is popped and the Reader continues
+// to read from the next most recent io.Reader. Push returns a StructuralError
+// if pushing the reader would exceed the maximum recursion level, otherwise it
+// returns nil.
+func (r *Reader) Push(reader io.Reader) (err error) {
+ if len(r.readers) >= maxReaders {
+ return errors.StructuralError("too many layers of packets")
+ }
+ r.readers = append(r.readers, reader)
+ return nil
+}
+
+// Unread causes the given Packet to be returned from the next call to Next.
+func (r *Reader) Unread(p Packet) {
+ r.q = append(r.q, p)
+}
+
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ q: nil,
+ readers: []io.Reader{r},
+ }
+}
+
+// CheckReader is similar to Reader but additionally
+// uses the pushdown automata to verify the read packet sequence.
+type CheckReader struct {
+ Reader
+ verifier *SequenceVerifier
+ fullyRead bool
+}
+
+// Next returns the most recently unread Packet, or reads another packet from
+// the top-most io.Reader. Unknown packet types are skipped.
+// If the read packet sequence does not conform to the packet composition
+// rules in rfc4880, it returns an error.
+func (r *CheckReader) Next() (p Packet, err error) {
+ if r.fullyRead {
+ return nil, io.EOF
+ }
+ if len(r.q) > 0 {
+ p = r.q[len(r.q)-1]
+ r.q = r.q[:len(r.q)-1]
+ return
+ }
+ var errMsg error
+ for len(r.readers) > 0 {
+ p, errMsg, err = ReadWithCheck(r.readers[len(r.readers)-1], r.verifier)
+ if errMsg != nil {
+ err = errMsg
+ return
+ }
+ if err == nil {
+ return
+ }
+ if err == io.EOF {
+ r.readers = r.readers[:len(r.readers)-1]
+ continue
+ }
+ //A marker packet MUST be ignored when received
+ switch p.(type) {
+ case *Marker:
+ continue
+ }
+ if _, ok := err.(errors.UnknownPacketTypeError); ok {
+ continue
+ }
+ if _, ok := err.(errors.UnsupportedError); ok {
+ switch p.(type) {
+ case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
+ return nil, err
+ }
+ continue
+ }
+ return nil, err
+ }
+ if errMsg = r.verifier.Next(EOSSymbol); errMsg != nil {
+ return nil, errMsg
+ }
+ if errMsg = r.verifier.AssertValid(); errMsg != nil {
+ return nil, errMsg
+ }
+ r.fullyRead = true
+ return nil, io.EOF
+}
+
+func NewCheckReader(r io.Reader) *CheckReader {
+ return &CheckReader{
+ Reader: Reader{
+ q: nil,
+ readers: []io.Reader{r},
+ },
+ verifier: NewSequenceVerifier(),
+ fullyRead: false,
+ }
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/recipient.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/recipient.go
new file mode 100644
index 0000000000..fb2e362e4a
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/recipient.go
@@ -0,0 +1,15 @@
+package packet
+
+// Recipient type represents a Intended Recipient Fingerprint subpacket
+// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-intended-recipient-fingerpr
+type Recipient struct {
+ KeyVersion int
+ Fingerprint []byte
+}
+
+func (r *Recipient) Serialize() []byte {
+ packet := make([]byte, len(r.Fingerprint)+1)
+ packet[0] = byte(r.KeyVersion)
+ copy(packet[1:], r.Fingerprint)
+ return packet
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
new file mode 100644
index 0000000000..84dd3b86f8
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
@@ -0,0 +1,1511 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/dsa"
+ "encoding/asn1"
+ "encoding/binary"
+ "hash"
+ "io"
+ "math/big"
+ "strconv"
+ "time"
+
+ "github.com/ProtonMail/go-crypto/openpgp/ecdsa"
+ "github.com/ProtonMail/go-crypto/openpgp/ed25519"
+ "github.com/ProtonMail/go-crypto/openpgp/ed448"
+ "github.com/ProtonMail/go-crypto/openpgp/eddsa"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
+)
+
+const (
+ // First octet of key flags.
+ // See RFC 9580, section 5.2.3.29 for details.
+ KeyFlagCertify = 1 << iota
+ KeyFlagSign
+ KeyFlagEncryptCommunications
+ KeyFlagEncryptStorage
+ KeyFlagSplitKey
+ KeyFlagAuthenticate
+ _
+ KeyFlagGroupKey
+)
+
+const (
+ // First octet of keyserver preference flags.
+ // See RFC 9580, section 5.2.3.25 for details.
+ _ = 1 << iota
+ _
+ _
+ _
+ _
+ _
+ _
+ KeyserverPrefNoModify
+)
+
+const SaltNotationName = "salt@notations.openpgpjs.org"
+
+// Signature represents a signature. See RFC 9580, section 5.2.
+type Signature struct {
+ Version int
+ SigType SignatureType
+ PubKeyAlgo PublicKeyAlgorithm
+ Hash crypto.Hash
+ // salt contains a random salt value for v6 signatures
+ // See RFC 9580 Section 5.2.4.
+ salt []byte
+
+ // HashSuffix is extra data that is hashed in after the signed data.
+ HashSuffix []byte
+ // HashTag contains the first two bytes of the hash for fast rejection
+ // of bad signed data.
+ HashTag [2]byte
+
+ // Metadata includes format, filename and time, and is protected by v5
+ // signatures of type 0x00 or 0x01. This metadata is included into the hash
+ // computation; if nil, six 0x00 bytes are used instead. See section 5.2.4.
+ Metadata *LiteralData
+
+ CreationTime time.Time
+
+ RSASignature encoding.Field
+ DSASigR, DSASigS encoding.Field
+ ECDSASigR, ECDSASigS encoding.Field
+ EdDSASigR, EdDSASigS encoding.Field
+ EdSig []byte
+
+ // rawSubpackets contains the unparsed subpackets, in order.
+ rawSubpackets []outputSubpacket
+
+ // The following are optional so are nil when not included in the
+ // signature.
+
+ SigLifetimeSecs, KeyLifetimeSecs *uint32
+ PreferredSymmetric, PreferredHash, PreferredCompression []uint8
+ PreferredCipherSuites [][2]uint8
+ IssuerKeyId *uint64
+ IssuerFingerprint []byte
+ SignerUserId *string
+ IsPrimaryId *bool
+ Notations []*Notation
+ IntendedRecipients []*Recipient
+
+ // TrustLevel and TrustAmount can be set by the signer to assert that
+ // the key is not only valid but also trustworthy at the specified
+ // level.
+ // See RFC 9580, section 5.2.3.21 for details.
+ TrustLevel TrustLevel
+ TrustAmount TrustAmount
+
+ // TrustRegularExpression can be used in conjunction with trust Signature
+ // packets to limit the scope of the trust that is extended.
+ // See RFC 9580, section 5.2.3.22 for details.
+ TrustRegularExpression *string
+
+ // KeyserverPrefsValid is set if any keyserver preferences were given. See RFC 9580, section
+ // 5.2.3.25 for details.
+ KeyserverPrefsValid bool
+ KeyserverPrefNoModify bool
+
+ // PreferredKeyserver can be set to a URI where the latest version of the
+ // key that this signature is made over can be found. See RFC 9580, section
+ // 5.2.3.26 for details.
+ PreferredKeyserver string
+
+ // PolicyURI can be set to the URI of a document that describes the
+ // policy under which the signature was issued. See RFC 9580, section
+ // 5.2.3.28 for details.
+ PolicyURI string
+
+ // FlagsValid is set if any flags were given. See RFC 9580, section
+ // 5.2.3.29 for details.
+ FlagsValid bool
+ FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage, FlagSplitKey, FlagAuthenticate, FlagGroupKey bool
+
+ // RevocationReason is set if this signature has been revoked.
+ // See RFC 9580, section 5.2.3.31 for details.
+ RevocationReason *ReasonForRevocation
+ RevocationReasonText string
+
+ // In a self-signature, these flags are set there is a features subpacket
+ // indicating that the issuer implementation supports these features
+ // see https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#features-subpacket
+ SEIPDv1, SEIPDv2 bool
+
+ // EmbeddedSignature, if non-nil, is a signature of the parent key, by
+ // this key. This prevents an attacker from claiming another's signing
+ // subkey as their own.
+ EmbeddedSignature *Signature
+
+ outSubpackets []outputSubpacket
+}
+
+// VerifiableSignature internally keeps state if the
+// the signature has been verified before.
+type VerifiableSignature struct {
+ Valid *bool // nil if it has not been verified yet
+ Packet *Signature
+}
+
+// NewVerifiableSig returns a struct of type VerifiableSignature referencing the input signature.
+func NewVerifiableSig(signature *Signature) *VerifiableSignature {
+ return &VerifiableSignature{
+ Packet: signature,
+ }
+}
+
+// Salt returns the signature salt for v6 signatures.
+func (sig *Signature) Salt() []byte {
+ if sig == nil {
+ return nil
+ }
+ return sig.salt
+}
+
+func (sig *Signature) parse(r io.Reader) (err error) {
+ // RFC 9580, section 5.2.3
+ var buf [7]byte
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ sig.Version = int(buf[0])
+ if sig.Version != 4 && sig.Version != 5 && sig.Version != 6 {
+ err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
+ return
+ }
+
+ if V5Disabled && sig.Version == 5 {
+ return errors.UnsupportedError("support for parsing v5 entities is disabled; build with `-tags v5` if needed")
+ }
+
+ if sig.Version == 6 {
+ _, err = readFull(r, buf[:7])
+ } else {
+ _, err = readFull(r, buf[:5])
+ }
+ if err != nil {
+ return
+ }
+ sig.SigType = SignatureType(buf[0])
+ sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA, PubKeyAlgoEd25519, PubKeyAlgoEd448:
+ default:
+ err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ return
+ }
+
+ var ok bool
+
+ if sig.Version < 5 {
+ sig.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2])
+ } else {
+ sig.Hash, ok = algorithm.HashIdToHash(buf[2])
+ }
+
+ if !ok {
+ return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
+ }
+
+ var hashedSubpacketsLength int
+ if sig.Version == 6 {
+ // For a v6 signature, a four-octet length is used.
+ hashedSubpacketsLength =
+ int(buf[3])<<24 |
+ int(buf[4])<<16 |
+ int(buf[5])<<8 |
+ int(buf[6])
+ } else {
+ hashedSubpacketsLength = int(buf[3])<<8 | int(buf[4])
+ }
+ hashedSubpackets := make([]byte, hashedSubpacketsLength)
+ _, err = readFull(r, hashedSubpackets)
+ if err != nil {
+ return
+ }
+ err = sig.buildHashSuffix(hashedSubpackets)
+ if err != nil {
+ return
+ }
+
+ err = parseSignatureSubpackets(sig, hashedSubpackets, true)
+ if err != nil {
+ return
+ }
+
+ if sig.Version == 6 {
+ _, err = readFull(r, buf[:4])
+ } else {
+ _, err = readFull(r, buf[:2])
+ }
+
+ if err != nil {
+ return
+ }
+ var unhashedSubpacketsLength uint32
+ if sig.Version == 6 {
+ unhashedSubpacketsLength = uint32(buf[0])<<24 | uint32(buf[1])<<16 | uint32(buf[2])<<8 | uint32(buf[3])
+ } else {
+ unhashedSubpacketsLength = uint32(buf[0])<<8 | uint32(buf[1])
+ }
+ unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
+ _, err = readFull(r, unhashedSubpackets)
+ if err != nil {
+ return
+ }
+ err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
+ if err != nil {
+ return
+ }
+
+ _, err = readFull(r, sig.HashTag[:2])
+ if err != nil {
+ return
+ }
+
+ if sig.Version == 6 {
+ // Only for v6 signatures, a variable-length field containing the salt
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ saltLength := int(buf[0])
+ var expectedSaltLength int
+ expectedSaltLength, err = SaltLengthForHash(sig.Hash)
+ if err != nil {
+ return
+ }
+ if saltLength != expectedSaltLength {
+ err = errors.StructuralError("unexpected salt size for the given hash algorithm")
+ return
+ }
+ salt := make([]byte, expectedSaltLength)
+ _, err = readFull(r, salt)
+ if err != nil {
+ return
+ }
+ sig.salt = salt
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature = new(encoding.MPI)
+ _, err = sig.RSASignature.ReadFrom(r)
+ case PubKeyAlgoDSA:
+ sig.DSASigR = new(encoding.MPI)
+ if _, err = sig.DSASigR.ReadFrom(r); err != nil {
+ return
+ }
+
+ sig.DSASigS = new(encoding.MPI)
+ _, err = sig.DSASigS.ReadFrom(r)
+ case PubKeyAlgoECDSA:
+ sig.ECDSASigR = new(encoding.MPI)
+ if _, err = sig.ECDSASigR.ReadFrom(r); err != nil {
+ return
+ }
+
+ sig.ECDSASigS = new(encoding.MPI)
+ _, err = sig.ECDSASigS.ReadFrom(r)
+ case PubKeyAlgoEdDSA:
+ sig.EdDSASigR = new(encoding.MPI)
+ if _, err = sig.EdDSASigR.ReadFrom(r); err != nil {
+ return
+ }
+
+ sig.EdDSASigS = new(encoding.MPI)
+ if _, err = sig.EdDSASigS.ReadFrom(r); err != nil {
+ return
+ }
+ case PubKeyAlgoEd25519:
+ sig.EdSig, err = ed25519.ReadSignature(r)
+ if err != nil {
+ return
+ }
+ case PubKeyAlgoEd448:
+ sig.EdSig, err = ed448.ReadSignature(r)
+ if err != nil {
+ return
+ }
+ default:
+ panic("unreachable")
+ }
+ return
+}
+
+// parseSignatureSubpackets parses subpackets of the main signature packet. See
+// RFC 9580, section 5.2.3.1.
+func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) {
+ for len(subpackets) > 0 {
+ subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
+ if err != nil {
+ return
+ }
+ }
+
+ if sig.CreationTime.IsZero() {
+ err = errors.StructuralError("no creation time in signature")
+ }
+
+ return
+}
+
+type signatureSubpacketType uint8
+
+const (
+ creationTimeSubpacket signatureSubpacketType = 2
+ signatureExpirationSubpacket signatureSubpacketType = 3
+ exportableCertSubpacket signatureSubpacketType = 4
+ trustSubpacket signatureSubpacketType = 5
+ regularExpressionSubpacket signatureSubpacketType = 6
+ keyExpirationSubpacket signatureSubpacketType = 9
+ prefSymmetricAlgosSubpacket signatureSubpacketType = 11
+ issuerSubpacket signatureSubpacketType = 16
+ notationDataSubpacket signatureSubpacketType = 20
+ prefHashAlgosSubpacket signatureSubpacketType = 21
+ prefCompressionSubpacket signatureSubpacketType = 22
+ keyserverPrefsSubpacket signatureSubpacketType = 23
+ prefKeyserverSubpacket signatureSubpacketType = 24
+ primaryUserIdSubpacket signatureSubpacketType = 25
+ policyUriSubpacket signatureSubpacketType = 26
+ keyFlagsSubpacket signatureSubpacketType = 27
+ signerUserIdSubpacket signatureSubpacketType = 28
+ reasonForRevocationSubpacket signatureSubpacketType = 29
+ featuresSubpacket signatureSubpacketType = 30
+ embeddedSignatureSubpacket signatureSubpacketType = 32
+ issuerFingerprintSubpacket signatureSubpacketType = 33
+ intendedRecipientSubpacket signatureSubpacketType = 35
+ prefCipherSuitesSubpacket signatureSubpacketType = 39
+)
+
+// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
+func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) {
+ // RFC 9580, section 5.2.3.7
+ var (
+ length uint32
+ packetType signatureSubpacketType
+ isCritical bool
+ )
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("zero length signature subpacket")
+ return
+ }
+ switch {
+ case subpacket[0] < 192:
+ length = uint32(subpacket[0])
+ subpacket = subpacket[1:]
+ case subpacket[0] < 255:
+ if len(subpacket) < 2 {
+ goto Truncated
+ }
+ length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
+ subpacket = subpacket[2:]
+ default:
+ if len(subpacket) < 5 {
+ goto Truncated
+ }
+ length = uint32(subpacket[1])<<24 |
+ uint32(subpacket[2])<<16 |
+ uint32(subpacket[3])<<8 |
+ uint32(subpacket[4])
+ subpacket = subpacket[5:]
+ }
+ if length > uint32(len(subpacket)) {
+ goto Truncated
+ }
+ rest = subpacket[length:]
+ subpacket = subpacket[:length]
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("zero length signature subpacket")
+ return
+ }
+ packetType = signatureSubpacketType(subpacket[0] & 0x7f)
+ isCritical = subpacket[0]&0x80 == 0x80
+ subpacket = subpacket[1:]
+ sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
+ if !isHashed &&
+ packetType != issuerSubpacket &&
+ packetType != issuerFingerprintSubpacket &&
+ packetType != embeddedSignatureSubpacket {
+ return
+ }
+ switch packetType {
+ case creationTimeSubpacket:
+ if len(subpacket) != 4 {
+ err = errors.StructuralError("signature creation time not four bytes")
+ return
+ }
+ t := binary.BigEndian.Uint32(subpacket)
+ sig.CreationTime = time.Unix(int64(t), 0)
+ case signatureExpirationSubpacket:
+ // Signature expiration time, section 5.2.3.18
+ if len(subpacket) != 4 {
+ err = errors.StructuralError("expiration subpacket with bad length")
+ return
+ }
+ sig.SigLifetimeSecs = new(uint32)
+ *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+ case exportableCertSubpacket:
+ if subpacket[0] == 0 {
+ err = errors.UnsupportedError("signature with non-exportable certification")
+ return
+ }
+ case trustSubpacket:
+ if len(subpacket) != 2 {
+ err = errors.StructuralError("trust subpacket with bad length")
+ return
+ }
+ // Trust level and amount, section 5.2.3.21
+ sig.TrustLevel = TrustLevel(subpacket[0])
+ sig.TrustAmount = TrustAmount(subpacket[1])
+ case regularExpressionSubpacket:
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("regexp subpacket with bad length")
+ return
+ }
+ // Trust regular expression, section 5.2.3.22
+ // RFC specifies the string should be null-terminated; remove a null byte from the end
+ if subpacket[len(subpacket)-1] != 0x00 {
+ err = errors.StructuralError("expected regular expression to be null-terminated")
+ return
+ }
+ trustRegularExpression := string(subpacket[:len(subpacket)-1])
+ sig.TrustRegularExpression = &trustRegularExpression
+ case keyExpirationSubpacket:
+ // Key expiration time, section 5.2.3.13
+ if len(subpacket) != 4 {
+ err = errors.StructuralError("key expiration subpacket with bad length")
+ return
+ }
+ sig.KeyLifetimeSecs = new(uint32)
+ *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+ case prefSymmetricAlgosSubpacket:
+ // Preferred symmetric algorithms, section 5.2.3.14
+ sig.PreferredSymmetric = make([]byte, len(subpacket))
+ copy(sig.PreferredSymmetric, subpacket)
+ case issuerSubpacket:
+ // Issuer, section 5.2.3.12
+ if sig.Version > 4 && isHashed {
+ err = errors.StructuralError("issuer subpacket found in v6 key")
+ return
+ }
+ if len(subpacket) != 8 {
+ err = errors.StructuralError("issuer subpacket with bad length")
+ return
+ }
+ if sig.Version <= 4 {
+ sig.IssuerKeyId = new(uint64)
+ *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
+ }
+ case notationDataSubpacket:
+ // Notation data, section 5.2.3.24
+ if len(subpacket) < 8 {
+ err = errors.StructuralError("notation data subpacket with bad length")
+ return
+ }
+
+ nameLength := uint32(subpacket[4])<<8 | uint32(subpacket[5])
+ valueLength := uint32(subpacket[6])<<8 | uint32(subpacket[7])
+ if len(subpacket) != int(nameLength)+int(valueLength)+8 {
+ err = errors.StructuralError("notation data subpacket with bad length")
+ return
+ }
+
+ notation := Notation{
+ IsHumanReadable: (subpacket[0] & 0x80) == 0x80,
+ Name: string(subpacket[8:(nameLength + 8)]),
+ Value: subpacket[(nameLength + 8):(valueLength + nameLength + 8)],
+ IsCritical: isCritical,
+ }
+
+ sig.Notations = append(sig.Notations, ¬ation)
+ case prefHashAlgosSubpacket:
+ // Preferred hash algorithms, section 5.2.3.16
+ sig.PreferredHash = make([]byte, len(subpacket))
+ copy(sig.PreferredHash, subpacket)
+ case prefCompressionSubpacket:
+ // Preferred compression algorithms, section 5.2.3.17
+ sig.PreferredCompression = make([]byte, len(subpacket))
+ copy(sig.PreferredCompression, subpacket)
+ case keyserverPrefsSubpacket:
+ // Keyserver preferences, section 5.2.3.25
+ sig.KeyserverPrefsValid = true
+ if len(subpacket) == 0 {
+ return
+ }
+ if subpacket[0]&KeyserverPrefNoModify != 0 {
+ sig.KeyserverPrefNoModify = true
+ }
+ case prefKeyserverSubpacket:
+ // Preferred keyserver, section 5.2.3.26
+ sig.PreferredKeyserver = string(subpacket)
+ case primaryUserIdSubpacket:
+ // Primary User ID, section 5.2.3.27
+ if len(subpacket) != 1 {
+ err = errors.StructuralError("primary user id subpacket with bad length")
+ return
+ }
+ sig.IsPrimaryId = new(bool)
+ if subpacket[0] > 0 {
+ *sig.IsPrimaryId = true
+ }
+ case keyFlagsSubpacket:
+ // Key flags, section 5.2.3.29
+ sig.FlagsValid = true
+ if len(subpacket) == 0 {
+ return
+ }
+ if subpacket[0]&KeyFlagCertify != 0 {
+ sig.FlagCertify = true
+ }
+ if subpacket[0]&KeyFlagSign != 0 {
+ sig.FlagSign = true
+ }
+ if subpacket[0]&KeyFlagEncryptCommunications != 0 {
+ sig.FlagEncryptCommunications = true
+ }
+ if subpacket[0]&KeyFlagEncryptStorage != 0 {
+ sig.FlagEncryptStorage = true
+ }
+ if subpacket[0]&KeyFlagSplitKey != 0 {
+ sig.FlagSplitKey = true
+ }
+ if subpacket[0]&KeyFlagAuthenticate != 0 {
+ sig.FlagAuthenticate = true
+ }
+ if subpacket[0]&KeyFlagGroupKey != 0 {
+ sig.FlagGroupKey = true
+ }
+ case signerUserIdSubpacket:
+ userId := string(subpacket)
+ sig.SignerUserId = &userId
+ case reasonForRevocationSubpacket:
+ // Reason For Revocation, section 5.2.3.31
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("empty revocation reason subpacket")
+ return
+ }
+ sig.RevocationReason = new(ReasonForRevocation)
+ *sig.RevocationReason = NewReasonForRevocation(subpacket[0])
+ sig.RevocationReasonText = string(subpacket[1:])
+ case featuresSubpacket:
+ // Features subpacket, section 5.2.3.32 specifies a very general
+ // mechanism for OpenPGP implementations to signal support for new
+ // features.
+ if len(subpacket) > 0 {
+ if subpacket[0]&0x01 != 0 {
+ sig.SEIPDv1 = true
+ }
+ // 0x02 and 0x04 are reserved
+ if subpacket[0]&0x08 != 0 {
+ sig.SEIPDv2 = true
+ }
+ }
+ case embeddedSignatureSubpacket:
+ // Only usage is in signatures that cross-certify
+ // signing subkeys. section 5.2.3.34 describes the
+ // format, with its usage described in section 11.1
+ if sig.EmbeddedSignature != nil {
+ err = errors.StructuralError("Cannot have multiple embedded signatures")
+ return
+ }
+ sig.EmbeddedSignature = new(Signature)
+ if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil {
+ return nil, err
+ }
+ if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding {
+ return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType)))
+ }
+ case policyUriSubpacket:
+ // Policy URI, section 5.2.3.28
+ sig.PolicyURI = string(subpacket)
+ case issuerFingerprintSubpacket:
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("empty issuer fingerprint subpacket")
+ return
+ }
+ v, l := subpacket[0], len(subpacket[1:])
+ if v >= 5 && l != 32 || v < 5 && l != 20 {
+ return nil, errors.StructuralError("bad fingerprint length")
+ }
+ sig.IssuerFingerprint = make([]byte, l)
+ copy(sig.IssuerFingerprint, subpacket[1:])
+ sig.IssuerKeyId = new(uint64)
+ if v >= 5 {
+ *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket[1:9])
+ } else {
+ *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket[13:21])
+ }
+ case intendedRecipientSubpacket:
+ // Intended Recipient Fingerprint, section 5.2.3.36
+ if len(subpacket) < 1 {
+ return nil, errors.StructuralError("invalid intended recipient fingerpring length")
+ }
+ version, length := subpacket[0], len(subpacket[1:])
+ if version >= 5 && length != 32 || version < 5 && length != 20 {
+ return nil, errors.StructuralError("invalid fingerprint length")
+ }
+ fingerprint := make([]byte, length)
+ copy(fingerprint, subpacket[1:])
+ sig.IntendedRecipients = append(sig.IntendedRecipients, &Recipient{int(version), fingerprint})
+ case prefCipherSuitesSubpacket:
+ // Preferred AEAD cipher suites, section 5.2.3.15
+ if len(subpacket)%2 != 0 {
+ err = errors.StructuralError("invalid aead cipher suite length")
+ return
+ }
+
+ sig.PreferredCipherSuites = make([][2]byte, len(subpacket)/2)
+
+ for i := 0; i < len(subpacket)/2; i++ {
+ sig.PreferredCipherSuites[i] = [2]uint8{subpacket[2*i], subpacket[2*i+1]}
+ }
+ default:
+ if isCritical {
+ err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
+ return
+ }
+ }
+ return
+
+Truncated:
+ err = errors.StructuralError("signature subpacket truncated")
+ return
+}
+
+// subpacketLengthLength returns the length, in bytes, of an encoded length value.
+func subpacketLengthLength(length int) int {
+ if length < 192 {
+ return 1
+ }
+ if length < 16320 {
+ return 2
+ }
+ return 5
+}
+
+func (sig *Signature) CheckKeyIdOrFingerprint(pk *PublicKey) bool {
+ if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) >= 20 {
+ return bytes.Equal(sig.IssuerFingerprint, pk.Fingerprint)
+ }
+ return sig.IssuerKeyId != nil && *sig.IssuerKeyId == pk.KeyId
+}
+
+func (sig *Signature) CheckKeyIdOrFingerprintExplicit(fingerprint []byte, keyId uint64) bool {
+ if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) >= 20 && fingerprint != nil {
+ return bytes.Equal(sig.IssuerFingerprint, fingerprint)
+ }
+ return sig.IssuerKeyId != nil && *sig.IssuerKeyId == keyId
+}
+
+// serializeSubpacketLength marshals the given length into to.
+func serializeSubpacketLength(to []byte, length int) int {
+ // RFC 9580, Section 4.2.1.
+ if length < 192 {
+ to[0] = byte(length)
+ return 1
+ }
+ if length < 16320 {
+ length -= 192
+ to[0] = byte((length >> 8) + 192)
+ to[1] = byte(length)
+ return 2
+ }
+ to[0] = 255
+ to[1] = byte(length >> 24)
+ to[2] = byte(length >> 16)
+ to[3] = byte(length >> 8)
+ to[4] = byte(length)
+ return 5
+}
+
+// subpacketsLength returns the serialized length, in bytes, of the given
+// subpackets.
+func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
+ for _, subpacket := range subpackets {
+ if subpacket.hashed == hashed {
+ length += subpacketLengthLength(len(subpacket.contents) + 1)
+ length += 1 // type byte
+ length += len(subpacket.contents)
+ }
+ }
+ return
+}
+
+// serializeSubpackets marshals the given subpackets into to.
+func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
+ for _, subpacket := range subpackets {
+ if subpacket.hashed == hashed {
+ n := serializeSubpacketLength(to, len(subpacket.contents)+1)
+ to[n] = byte(subpacket.subpacketType)
+ if subpacket.isCritical {
+ to[n] |= 0x80
+ }
+ to = to[1+n:]
+ n = copy(to, subpacket.contents)
+ to = to[n:]
+ }
+ }
+}
+
+// SigExpired returns whether sig is a signature that has expired or is created
+// in the future.
+func (sig *Signature) SigExpired(currentTime time.Time) bool {
+ if sig.CreationTime.Unix() > currentTime.Unix() {
+ return true
+ }
+ if sig.SigLifetimeSecs == nil || *sig.SigLifetimeSecs == 0 {
+ return false
+ }
+ expiry := sig.CreationTime.Add(time.Duration(*sig.SigLifetimeSecs) * time.Second)
+ return currentTime.Unix() > expiry.Unix()
+}
+
+// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
+func (sig *Signature) buildHashSuffix(hashedSubpackets []byte) (err error) {
+ var hashId byte
+ var ok bool
+
+ if sig.Version < 5 {
+ hashId, ok = algorithm.HashToHashIdWithSha1(sig.Hash)
+ } else {
+ hashId, ok = algorithm.HashToHashId(sig.Hash)
+ }
+
+ if !ok {
+ sig.HashSuffix = nil
+ return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
+ }
+
+ hashedFields := bytes.NewBuffer([]byte{
+ uint8(sig.Version),
+ uint8(sig.SigType),
+ uint8(sig.PubKeyAlgo),
+ uint8(hashId),
+ })
+ hashedSubpacketsLength := len(hashedSubpackets)
+ if sig.Version == 6 {
+ // v6 signatures store the length in 4 octets
+ hashedFields.Write([]byte{
+ uint8(hashedSubpacketsLength >> 24),
+ uint8(hashedSubpacketsLength >> 16),
+ uint8(hashedSubpacketsLength >> 8),
+ uint8(hashedSubpacketsLength),
+ })
+ } else {
+ hashedFields.Write([]byte{
+ uint8(hashedSubpacketsLength >> 8),
+ uint8(hashedSubpacketsLength),
+ })
+ }
+ lenPrefix := hashedFields.Len()
+ hashedFields.Write(hashedSubpackets)
+
+ var l uint64 = uint64(lenPrefix + len(hashedSubpackets))
+ if sig.Version == 5 {
+ // v5 case
+ hashedFields.Write([]byte{0x05, 0xff})
+ hashedFields.Write([]byte{
+ uint8(l >> 56), uint8(l >> 48), uint8(l >> 40), uint8(l >> 32),
+ uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l),
+ })
+ } else {
+ // v4 and v6 case
+ hashedFields.Write([]byte{byte(sig.Version), 0xff})
+ hashedFields.Write([]byte{
+ uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l),
+ })
+ }
+ sig.HashSuffix = make([]byte, hashedFields.Len())
+ copy(sig.HashSuffix, hashedFields.Bytes())
+ return
+}
+
+func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) {
+ hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
+ hashedSubpackets := make([]byte, hashedSubpacketsLen)
+ serializeSubpackets(hashedSubpackets, sig.outSubpackets, true)
+ err = sig.buildHashSuffix(hashedSubpackets)
+ if err != nil {
+ return
+ }
+ if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) {
+ sig.AddMetadataToHashSuffix()
+ }
+
+ h.Write(sig.HashSuffix)
+ digest = h.Sum(nil)
+ copy(sig.HashTag[:], digest)
+ return
+}
+
+// PrepareSign must be called to create a hash object before Sign for v6 signatures.
+// The created hash object initially hashes a randomly generated salt
+// as required by v6 signatures. The generated salt is stored in sig. If the signature is not v6,
+// the method returns an empty hash object.
+// See RFC 9580 Section 5.2.4.
+func (sig *Signature) PrepareSign(config *Config) (hash.Hash, error) {
+ if !sig.Hash.Available() {
+ return nil, errors.UnsupportedError("hash function")
+ }
+ hasher := sig.Hash.New()
+ if sig.Version == 6 {
+ if sig.salt == nil {
+ var err error
+ sig.salt, err = SignatureSaltForHash(sig.Hash, config.Random())
+ if err != nil {
+ return nil, err
+ }
+ }
+ hasher.Write(sig.salt)
+ }
+ return hasher, nil
+}
+
+// SetSalt sets the signature salt for v6 signatures.
+// Assumes salt is generated correctly and checks if length matches.
+// If the signature is not v6, the method ignores the salt.
+// Use PrepareSign whenever possible instead of generating and
+// hashing the salt externally.
+// See RFC 9580 Section 5.2.4.
+func (sig *Signature) SetSalt(salt []byte) error {
+ if sig.Version == 6 {
+ expectedSaltLength, err := SaltLengthForHash(sig.Hash)
+ if err != nil {
+ return err
+ }
+ if salt == nil || len(salt) != expectedSaltLength {
+ return errors.InvalidArgumentError("unexpected salt size for the given hash algorithm")
+ }
+ sig.salt = salt
+ }
+ return nil
+}
+
+// PrepareVerify must be called to create a hash object before verifying v6 signatures.
+// The created hash object initially hashes the internally stored salt.
+// If the signature is not v6, the method returns an empty hash object.
+// See RFC 9580 Section 5.2.4.
+func (sig *Signature) PrepareVerify() (hash.Hash, error) {
+ if !sig.Hash.Available() {
+ return nil, errors.UnsupportedError("hash function")
+ }
+ hasher := sig.Hash.New()
+ if sig.Version == 6 {
+ if sig.salt == nil {
+ return nil, errors.StructuralError("v6 requires a salt for the hash to be signed")
+ }
+ hasher.Write(sig.salt)
+ }
+ return hasher, nil
+}
+
+// Sign signs a message with a private key. The hash, h, must contain
+// the hash of the message to be signed and will be mutated by this function.
+// On success, the signature is stored in sig. Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) {
+ if priv.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ sig.Version = priv.PublicKey.Version
+ sig.IssuerFingerprint = priv.PublicKey.Fingerprint
+ if sig.Version < 6 && config.RandomizeSignaturesViaNotation() {
+ sig.removeNotationsWithName(SaltNotationName)
+ salt, err := SignatureSaltForHash(sig.Hash, config.Random())
+ if err != nil {
+ return err
+ }
+ notation := Notation{
+ Name: SaltNotationName,
+ Value: salt,
+ IsCritical: false,
+ IsHumanReadable: false,
+ }
+ sig.Notations = append(sig.Notations, ¬ation)
+ }
+ sig.outSubpackets, err = sig.buildSubpackets(priv.PublicKey)
+ if err != nil {
+ return err
+ }
+ digest, err := sig.signPrepareHash(h)
+ if err != nil {
+ return
+ }
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ // supports both *rsa.PrivateKey and crypto.Signer
+ sigdata, err := priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash)
+ if err == nil {
+ sig.RSASignature = encoding.NewMPI(sigdata)
+ }
+ case PubKeyAlgoDSA:
+ dsaPriv := priv.PrivateKey.(*dsa.PrivateKey)
+
+ // Need to truncate hashBytes to match FIPS 186-3 section 4.6.
+ subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8
+ if len(digest) > subgroupSize {
+ digest = digest[:subgroupSize]
+ }
+ r, s, err := dsa.Sign(config.Random(), dsaPriv, digest)
+ if err == nil {
+ sig.DSASigR = new(encoding.MPI).SetBig(r)
+ sig.DSASigS = new(encoding.MPI).SetBig(s)
+ }
+ case PubKeyAlgoECDSA:
+ var r, s *big.Int
+ if sk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok {
+ r, s, err = ecdsa.Sign(config.Random(), sk, digest)
+ } else {
+ var b []byte
+ b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash)
+ if err == nil {
+ r, s, err = unwrapECDSASig(b)
+ }
+ }
+
+ if err == nil {
+ sig.ECDSASigR = new(encoding.MPI).SetBig(r)
+ sig.ECDSASigS = new(encoding.MPI).SetBig(s)
+ }
+ case PubKeyAlgoEdDSA:
+ sk := priv.PrivateKey.(*eddsa.PrivateKey)
+ r, s, err := eddsa.Sign(sk, digest)
+ if err == nil {
+ sig.EdDSASigR = encoding.NewMPI(r)
+ sig.EdDSASigS = encoding.NewMPI(s)
+ }
+ case PubKeyAlgoEd25519:
+ sk := priv.PrivateKey.(*ed25519.PrivateKey)
+ signature, err := ed25519.Sign(sk, digest)
+ if err == nil {
+ sig.EdSig = signature
+ }
+ case PubKeyAlgoEd448:
+ sk := priv.PrivateKey.(*ed448.PrivateKey)
+ signature, err := ed448.Sign(sk, digest)
+ if err == nil {
+ sig.EdSig = signature
+ }
+ default:
+ err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ }
+
+ return
+}
+
+// unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA signature.
+func unwrapECDSASig(b []byte) (r, s *big.Int, err error) {
+ var ecsdaSig struct {
+ R, S *big.Int
+ }
+ _, err = asn1.Unmarshal(b, &ecsdaSig)
+ if err != nil {
+ return
+ }
+ return ecsdaSig.R, ecsdaSig.S, nil
+}
+
+// SignUserId computes a signature from priv, asserting that pub is a valid
+// key for the identity id. On success, the signature is stored in sig. Call
+// Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error {
+ if priv.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ prepareHash, err := sig.PrepareSign(config)
+ if err != nil {
+ return err
+ }
+ if err := userIdSignatureHash(id, pub, prepareHash); err != nil {
+ return err
+ }
+ return sig.Sign(prepareHash, priv, config)
+}
+
+// SignDirectKeyBinding computes a signature from priv
+// On success, the signature is stored in sig.
+// Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) SignDirectKeyBinding(pub *PublicKey, priv *PrivateKey, config *Config) error {
+ if priv.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ prepareHash, err := sig.PrepareSign(config)
+ if err != nil {
+ return err
+ }
+ if err := directKeySignatureHash(pub, prepareHash); err != nil {
+ return err
+ }
+ return sig.Sign(prepareHash, priv, config)
+}
+
+// CrossSignKey computes a signature from signingKey on pub hashed using hashKey. On success,
+// the signature is stored in sig. Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) CrossSignKey(pub *PublicKey, hashKey *PublicKey, signingKey *PrivateKey,
+ config *Config) error {
+ prepareHash, err := sig.PrepareSign(config)
+ if err != nil {
+ return err
+ }
+ h, err := keySignatureHash(hashKey, pub, prepareHash)
+ if err != nil {
+ return err
+ }
+ return sig.Sign(h, signingKey, config)
+}
+
+// SignKey computes a signature from priv, asserting that pub is a subkey. On
+// success, the signature is stored in sig. Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error {
+ if priv.Dummy() {
+ return errors.ErrDummyPrivateKey("dummy key found")
+ }
+ prepareHash, err := sig.PrepareSign(config)
+ if err != nil {
+ return err
+ }
+ h, err := keySignatureHash(&priv.PublicKey, pub, prepareHash)
+ if err != nil {
+ return err
+ }
+ return sig.Sign(h, priv, config)
+}
+
+// RevokeKey computes a revocation signature of pub using priv. On success, the signature is
+// stored in sig. Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) RevokeKey(pub *PublicKey, priv *PrivateKey, config *Config) error {
+ prepareHash, err := sig.PrepareSign(config)
+ if err != nil {
+ return err
+ }
+ if err := keyRevocationHash(pub, prepareHash); err != nil {
+ return err
+ }
+ return sig.Sign(prepareHash, priv, config)
+}
+
+// RevokeSubkey computes a subkey revocation signature of pub using priv.
+// On success, the signature is stored in sig. Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) RevokeSubkey(pub *PublicKey, priv *PrivateKey, config *Config) error {
+ // Identical to a subkey binding signature
+ return sig.SignKey(pub, priv, config)
+}
+
+// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
+// called first.
+func (sig *Signature) Serialize(w io.Writer) (err error) {
+ if len(sig.outSubpackets) == 0 {
+ sig.outSubpackets = sig.rawSubpackets
+ }
+ if sig.RSASignature == nil && sig.DSASigR == nil && sig.ECDSASigR == nil && sig.EdDSASigR == nil && sig.EdSig == nil {
+ return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
+ }
+
+ sigLength := 0
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sigLength = int(sig.RSASignature.EncodedLength())
+ case PubKeyAlgoDSA:
+ sigLength = int(sig.DSASigR.EncodedLength())
+ sigLength += int(sig.DSASigS.EncodedLength())
+ case PubKeyAlgoECDSA:
+ sigLength = int(sig.ECDSASigR.EncodedLength())
+ sigLength += int(sig.ECDSASigS.EncodedLength())
+ case PubKeyAlgoEdDSA:
+ sigLength = int(sig.EdDSASigR.EncodedLength())
+ sigLength += int(sig.EdDSASigS.EncodedLength())
+ case PubKeyAlgoEd25519:
+ sigLength = ed25519.SignatureSize
+ case PubKeyAlgoEd448:
+ sigLength = ed448.SignatureSize
+ default:
+ panic("impossible")
+ }
+
+ hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
+ unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
+ length := 4 + /* length of version|signature type|public-key algorithm|hash algorithm */
+ 2 /* length of hashed subpackets */ + hashedSubpacketsLen +
+ 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
+ 2 /* hash tag */ + sigLength
+ if sig.Version == 6 {
+ length += 4 + /* the two length fields are four-octet instead of two */
+ 1 + /* salt length */
+ len(sig.salt) /* length salt */
+ }
+ err = serializeHeader(w, packetTypeSignature, length)
+ if err != nil {
+ return
+ }
+ err = sig.serializeBody(w)
+ if err != nil {
+ return err
+ }
+ return
+}
+
+func (sig *Signature) serializeBody(w io.Writer) (err error) {
+ var fields []byte
+ if sig.Version == 6 {
+ // v6 signatures use 4 octets for length
+ hashedSubpacketsLen :=
+ uint32(uint32(sig.HashSuffix[4])<<24) |
+ uint32(uint32(sig.HashSuffix[5])<<16) |
+ uint32(uint32(sig.HashSuffix[6])<<8) |
+ uint32(sig.HashSuffix[7])
+ fields = sig.HashSuffix[:8+hashedSubpacketsLen]
+ } else {
+ hashedSubpacketsLen := uint16(uint16(sig.HashSuffix[4])<<8) |
+ uint16(sig.HashSuffix[5])
+ fields = sig.HashSuffix[:6+hashedSubpacketsLen]
+
+ }
+ _, err = w.Write(fields)
+ if err != nil {
+ return
+ }
+
+ unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
+ var unhashedSubpackets []byte
+ if sig.Version == 6 {
+ unhashedSubpackets = make([]byte, 4+unhashedSubpacketsLen)
+ unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 24)
+ unhashedSubpackets[1] = byte(unhashedSubpacketsLen >> 16)
+ unhashedSubpackets[2] = byte(unhashedSubpacketsLen >> 8)
+ unhashedSubpackets[3] = byte(unhashedSubpacketsLen)
+ serializeSubpackets(unhashedSubpackets[4:], sig.outSubpackets, false)
+ } else {
+ unhashedSubpackets = make([]byte, 2+unhashedSubpacketsLen)
+ unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
+ unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
+ serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
+ }
+
+ _, err = w.Write(unhashedSubpackets)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(sig.HashTag[:])
+ if err != nil {
+ return
+ }
+
+ if sig.Version == 6 {
+ // write salt for v6 signatures
+ _, err = w.Write([]byte{uint8(len(sig.salt))})
+ if err != nil {
+ return
+ }
+ _, err = w.Write(sig.salt)
+ if err != nil {
+ return
+ }
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ _, err = w.Write(sig.RSASignature.EncodedBytes())
+ case PubKeyAlgoDSA:
+ if _, err = w.Write(sig.DSASigR.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(sig.DSASigS.EncodedBytes())
+ case PubKeyAlgoECDSA:
+ if _, err = w.Write(sig.ECDSASigR.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(sig.ECDSASigS.EncodedBytes())
+ case PubKeyAlgoEdDSA:
+ if _, err = w.Write(sig.EdDSASigR.EncodedBytes()); err != nil {
+ return
+ }
+ _, err = w.Write(sig.EdDSASigS.EncodedBytes())
+ case PubKeyAlgoEd25519:
+ err = ed25519.WriteSignature(w, sig.EdSig)
+ case PubKeyAlgoEd448:
+ err = ed448.WriteSignature(w, sig.EdSig)
+ default:
+ panic("impossible")
+ }
+ return
+}
+
+// outputSubpacket represents a subpacket to be marshaled.
+type outputSubpacket struct {
+ hashed bool // true if this subpacket is in the hashed area.
+ subpacketType signatureSubpacketType
+ isCritical bool
+ contents []byte
+}
+
+func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubpacket, err error) {
+ creationTime := make([]byte, 4)
+ binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
+ // Signature Creation Time
+ subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, true, creationTime})
+ // Signature Expiration Time
+ if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 {
+ sigLifetime := make([]byte, 4)
+ binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs)
+ subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime})
+ }
+ // Trust Signature
+ if sig.TrustLevel != 0 {
+ subpackets = append(subpackets, outputSubpacket{true, trustSubpacket, true, []byte{byte(sig.TrustLevel), byte(sig.TrustAmount)}})
+ }
+ // Regular Expression
+ if sig.TrustRegularExpression != nil {
+ // RFC specifies the string should be null-terminated; add a null byte to the end
+ subpackets = append(subpackets, outputSubpacket{true, regularExpressionSubpacket, true, []byte(*sig.TrustRegularExpression + "\000")})
+ }
+ // Key Expiration Time
+ if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 {
+ keyLifetime := make([]byte, 4)
+ binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs)
+ subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime})
+ }
+ // Preferred Symmetric Ciphers for v1 SEIPD
+ if len(sig.PreferredSymmetric) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric})
+ }
+ // Issuer Key ID
+ if sig.IssuerKeyId != nil && sig.Version == 4 {
+ keyId := make([]byte, 8)
+ binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
+ // Note: making this critical breaks RPM <=4.16.
+ // See: https://github.com/ProtonMail/go-crypto/issues/263
+ subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
+ }
+ // Notation Data
+ for _, notation := range sig.Notations {
+ subpackets = append(
+ subpackets,
+ outputSubpacket{
+ true,
+ notationDataSubpacket,
+ notation.IsCritical,
+ notation.getData(),
+ })
+ }
+ // Preferred Hash Algorithms
+ if len(sig.PreferredHash) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash})
+ }
+ // Preferred Compression Algorithms
+ if len(sig.PreferredCompression) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression})
+ }
+ // Keyserver Preferences
+ // Keyserver preferences may only appear in self-signatures or certification signatures.
+ if sig.KeyserverPrefsValid {
+ var prefs byte
+ if sig.KeyserverPrefNoModify {
+ prefs |= KeyserverPrefNoModify
+ }
+ subpackets = append(subpackets, outputSubpacket{true, keyserverPrefsSubpacket, false, []byte{prefs}})
+ }
+ // Preferred Keyserver
+ if len(sig.PreferredKeyserver) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, prefKeyserverSubpacket, false, []uint8(sig.PreferredKeyserver)})
+ }
+ // Primary User ID
+ if sig.IsPrimaryId != nil && *sig.IsPrimaryId {
+ subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}})
+ }
+ // Policy URI
+ if len(sig.PolicyURI) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, policyUriSubpacket, false, []uint8(sig.PolicyURI)})
+ }
+ // Key Flags
+ // Key flags may only appear in self-signatures or certification signatures.
+ if sig.FlagsValid {
+ var flags byte
+ if sig.FlagCertify {
+ flags |= KeyFlagCertify
+ }
+ if sig.FlagSign {
+ flags |= KeyFlagSign
+ }
+ if sig.FlagEncryptCommunications {
+ flags |= KeyFlagEncryptCommunications
+ }
+ if sig.FlagEncryptStorage {
+ flags |= KeyFlagEncryptStorage
+ }
+ if sig.FlagSplitKey {
+ flags |= KeyFlagSplitKey
+ }
+ if sig.FlagAuthenticate {
+ flags |= KeyFlagAuthenticate
+ }
+ if sig.FlagGroupKey {
+ flags |= KeyFlagGroupKey
+ }
+ subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, true, []byte{flags}})
+ }
+ // Signer's User ID
+ if sig.SignerUserId != nil {
+ subpackets = append(subpackets, outputSubpacket{true, signerUserIdSubpacket, false, []byte(*sig.SignerUserId)})
+ }
+ // Reason for Revocation
+ // Revocation reason appears only in revocation signatures and is serialized as per section 5.2.3.31.
+ if sig.RevocationReason != nil {
+ subpackets = append(subpackets, outputSubpacket{true, reasonForRevocationSubpacket, true,
+ append([]uint8{uint8(*sig.RevocationReason)}, []uint8(sig.RevocationReasonText)...)})
+ }
+ // Features
+ var features = byte(0x00)
+ if sig.SEIPDv1 {
+ features |= 0x01
+ }
+ if sig.SEIPDv2 {
+ features |= 0x08
+ }
+ if features != 0x00 {
+ subpackets = append(subpackets, outputSubpacket{true, featuresSubpacket, false, []byte{features}})
+ }
+ // Embedded Signature
+ // EmbeddedSignature appears only in subkeys capable of signing and is serialized as per section 5.2.3.34.
+ if sig.EmbeddedSignature != nil {
+ var buf bytes.Buffer
+ err = sig.EmbeddedSignature.serializeBody(&buf)
+ if err != nil {
+ return
+ }
+ subpackets = append(subpackets, outputSubpacket{true, embeddedSignatureSubpacket, true, buf.Bytes()})
+ }
+ // Issuer Fingerprint
+ if sig.IssuerFingerprint != nil {
+ contents := append([]uint8{uint8(issuer.Version)}, sig.IssuerFingerprint...)
+ subpackets = append(subpackets, outputSubpacket{true, issuerFingerprintSubpacket, sig.Version >= 5, contents})
+ }
+ // Intended Recipient Fingerprint
+ for _, recipient := range sig.IntendedRecipients {
+ subpackets = append(
+ subpackets,
+ outputSubpacket{
+ true,
+ intendedRecipientSubpacket,
+ false,
+ recipient.Serialize(),
+ })
+ }
+ // Preferred AEAD Ciphersuites
+ if len(sig.PreferredCipherSuites) > 0 {
+ serialized := make([]byte, len(sig.PreferredCipherSuites)*2)
+ for i, cipherSuite := range sig.PreferredCipherSuites {
+ serialized[2*i] = cipherSuite[0]
+ serialized[2*i+1] = cipherSuite[1]
+ }
+ subpackets = append(subpackets, outputSubpacket{true, prefCipherSuitesSubpacket, false, serialized})
+ }
+ return
+}
+
+// AddMetadataToHashSuffix modifies the current hash suffix to include metadata
+// (format, filename, and time). Version 5 keys protect this data including it
+// in the hash computation. See section 5.2.4.
+func (sig *Signature) AddMetadataToHashSuffix() {
+ if sig == nil || sig.Version != 5 {
+ return
+ }
+ if sig.SigType != 0x00 && sig.SigType != 0x01 {
+ return
+ }
+ lit := sig.Metadata
+ if lit == nil {
+ // This will translate into six 0x00 bytes.
+ lit = &LiteralData{}
+ }
+
+ // Extract the current byte count
+ n := sig.HashSuffix[len(sig.HashSuffix)-8:]
+ l := uint64(
+ uint64(n[0])<<56 | uint64(n[1])<<48 | uint64(n[2])<<40 | uint64(n[3])<<32 |
+ uint64(n[4])<<24 | uint64(n[5])<<16 | uint64(n[6])<<8 | uint64(n[7]))
+
+ suffix := bytes.NewBuffer(nil)
+ suffix.Write(sig.HashSuffix[:l])
+
+ // Add the metadata
+ var buf [4]byte
+ buf[0] = lit.Format
+ fileName := lit.FileName
+ if len(lit.FileName) > 255 {
+ fileName = fileName[:255]
+ }
+ buf[1] = byte(len(fileName))
+ suffix.Write(buf[:2])
+ suffix.Write([]byte(lit.FileName))
+ binary.BigEndian.PutUint32(buf[:], lit.Time)
+ suffix.Write(buf[:])
+
+ suffix.Write([]byte{0x05, 0xff})
+ suffix.Write([]byte{
+ uint8(l >> 56), uint8(l >> 48), uint8(l >> 40), uint8(l >> 32),
+ uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l),
+ })
+ sig.HashSuffix = suffix.Bytes()
+}
+
+// SaltLengthForHash selects the required salt length for the given hash algorithm,
+// as per Table 23 (Hash algorithm registry) of the crypto refresh.
+// See RFC 9580 Section 9.5.
+func SaltLengthForHash(hash crypto.Hash) (int, error) {
+ switch hash {
+ case crypto.SHA256, crypto.SHA224, crypto.SHA3_256:
+ return 16, nil
+ case crypto.SHA384:
+ return 24, nil
+ case crypto.SHA512, crypto.SHA3_512:
+ return 32, nil
+ default:
+ return 0, errors.UnsupportedError("hash function not supported for V6 signatures")
+ }
+}
+
+// SignatureSaltForHash generates a random signature salt
+// with the length for the given hash algorithm.
+// See RFC 9580 Section 9.5.
+func SignatureSaltForHash(hash crypto.Hash, randReader io.Reader) ([]byte, error) {
+ saltLength, err := SaltLengthForHash(hash)
+ if err != nil {
+ return nil, err
+ }
+ salt := make([]byte, saltLength)
+ _, err = io.ReadFull(randReader, salt)
+ if err != nil {
+ return nil, err
+ }
+ return salt, nil
+}
+
+// removeNotationsWithName removes all notations in this signature with the given name.
+func (sig *Signature) removeNotationsWithName(name string) {
+ if sig == nil || sig.Notations == nil {
+ return
+ }
+ updatedNotations := make([]*Notation, 0, len(sig.Notations))
+ for _, notation := range sig.Notations {
+ if notation.Name != name {
+ updatedNotations = append(updatedNotations, notation)
+ }
+ }
+ sig.Notations = updatedNotations
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
new file mode 100644
index 0000000000..2812a1db88
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -0,0 +1,331 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/sha256"
+ "io"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/s2k"
+ "golang.org/x/crypto/hkdf"
+)
+
+// This is the largest session key that we'll support. Since at most 256-bit cipher
+// is supported in OpenPGP, this is large enough to contain also the auth tag.
+const maxSessionKeySizeInBytes = 64
+
+// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
+// 4880, section 5.3.
+type SymmetricKeyEncrypted struct {
+ Version int
+ CipherFunc CipherFunction
+ Mode AEADMode
+ s2k func(out, in []byte)
+ iv []byte
+ encryptedKey []byte // Contains also the authentication tag for AEAD
+}
+
+// parse parses an SymmetricKeyEncrypted packet as specified in
+// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#name-symmetric-key-encrypted-ses
+func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
+ var buf [1]byte
+
+ // Version
+ if _, err := readFull(r, buf[:]); err != nil {
+ return err
+ }
+ ske.Version = int(buf[0])
+ if ske.Version != 4 && ske.Version != 5 && ske.Version != 6 {
+ return errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
+ }
+
+ if V5Disabled && ske.Version == 5 {
+ return errors.UnsupportedError("support for parsing v5 entities is disabled; build with `-tags v5` if needed")
+ }
+
+ if ske.Version > 5 {
+ // Scalar octet count
+ if _, err := readFull(r, buf[:]); err != nil {
+ return err
+ }
+ }
+
+ // Cipher function
+ if _, err := readFull(r, buf[:]); err != nil {
+ return err
+ }
+ ske.CipherFunc = CipherFunction(buf[0])
+ if !ske.CipherFunc.IsSupported() {
+ return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[0])))
+ }
+
+ if ske.Version >= 5 {
+ // AEAD mode
+ if _, err := readFull(r, buf[:]); err != nil {
+ return errors.StructuralError("cannot read AEAD octet from packet")
+ }
+ ske.Mode = AEADMode(buf[0])
+ }
+
+ if ske.Version > 5 {
+ // Scalar octet count
+ if _, err := readFull(r, buf[:]); err != nil {
+ return err
+ }
+ }
+
+ var err error
+ if ske.s2k, err = s2k.Parse(r); err != nil {
+ if _, ok := err.(errors.ErrDummyPrivateKey); ok {
+ return errors.UnsupportedError("missing key GNU extension in session key")
+ }
+ return err
+ }
+
+ if ske.Version >= 5 {
+ // AEAD IV
+ iv := make([]byte, ske.Mode.IvLength())
+ _, err := readFull(r, iv)
+ if err != nil {
+ return errors.StructuralError("cannot read AEAD IV")
+ }
+
+ ske.iv = iv
+ }
+
+ encryptedKey := make([]byte, maxSessionKeySizeInBytes)
+ // The session key may follow. We just have to try and read to find
+ // out. If it exists then we limit it to maxSessionKeySizeInBytes.
+ n, err := readFull(r, encryptedKey)
+ if err != nil && err != io.ErrUnexpectedEOF {
+ return err
+ }
+
+ if n != 0 {
+ if n == maxSessionKeySizeInBytes {
+ return errors.UnsupportedError("oversized encrypted session key")
+ }
+ ske.encryptedKey = encryptedKey[:n]
+ }
+ return nil
+}
+
+// Decrypt attempts to decrypt an encrypted session key and returns the key and
+// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
+// packet.
+func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) {
+ key := make([]byte, ske.CipherFunc.KeySize())
+ ske.s2k(key, passphrase)
+ if len(ske.encryptedKey) == 0 {
+ return key, ske.CipherFunc, nil
+ }
+ switch ske.Version {
+ case 4:
+ plaintextKey, cipherFunc, err := ske.decryptV4(key)
+ return plaintextKey, cipherFunc, err
+ case 5, 6:
+ plaintextKey, err := ske.aeadDecrypt(ske.Version, key)
+ return plaintextKey, CipherFunction(0), err
+ }
+ err := errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
+ return nil, CipherFunction(0), err
+}
+
+func (ske *SymmetricKeyEncrypted) decryptV4(key []byte) ([]byte, CipherFunction, error) {
+ // the IV is all zeros
+ iv := make([]byte, ske.CipherFunc.blockSize())
+ c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
+ plaintextKey := make([]byte, len(ske.encryptedKey))
+ c.XORKeyStream(plaintextKey, ske.encryptedKey)
+ cipherFunc := CipherFunction(plaintextKey[0])
+ if cipherFunc.blockSize() == 0 {
+ return nil, ske.CipherFunc, errors.UnsupportedError(
+ "unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+ }
+ plaintextKey = plaintextKey[1:]
+ if len(plaintextKey) != cipherFunc.KeySize() {
+ return nil, cipherFunc, errors.StructuralError(
+ "length of decrypted key not equal to cipher keysize")
+ }
+ return plaintextKey, cipherFunc, nil
+}
+
+func (ske *SymmetricKeyEncrypted) aeadDecrypt(version int, key []byte) ([]byte, error) {
+ adata := []byte{0xc3, byte(version), byte(ske.CipherFunc), byte(ske.Mode)}
+ aead := getEncryptedKeyAeadInstance(ske.CipherFunc, ske.Mode, key, adata, version)
+
+ plaintextKey, err := aead.Open(nil, ske.iv, ske.encryptedKey, adata)
+ if err != nil {
+ return nil, err
+ }
+ return plaintextKey, nil
+}
+
+// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w.
+// The packet contains a random session key, encrypted by a key derived from
+// the given passphrase. The session key is returned and must be passed to
+// SerializeSymmetricallyEncrypted.
+// If config is nil, sensible defaults will be used.
+func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
+ cipherFunc := config.Cipher()
+
+ sessionKey := make([]byte, cipherFunc.KeySize())
+ _, err = io.ReadFull(config.Random(), sessionKey)
+ if err != nil {
+ return
+ }
+
+ err = SerializeSymmetricKeyEncryptedReuseKey(w, sessionKey, passphrase, config)
+ if err != nil {
+ return
+ }
+
+ key = sessionKey
+ return
+}
+
+// SerializeSymmetricKeyEncryptedReuseKey serializes a symmetric key packet to w.
+// The packet contains the given session key, encrypted by a key derived from
+// the given passphrase. The returned session key must be passed to
+// SerializeSymmetricallyEncrypted.
+// If config is nil, sensible defaults will be used.
+// Deprecated: Use SerializeSymmetricKeyEncryptedAEADReuseKey instead.
+func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, config *Config) (err error) {
+ return SerializeSymmetricKeyEncryptedAEADReuseKey(w, sessionKey, passphrase, config.AEAD() != nil, config)
+}
+
+// SerializeSymmetricKeyEncryptedAEADReuseKey serializes a symmetric key packet to w.
+// The packet contains the given session key, encrypted by a key derived from
+// the given passphrase. The returned session key must be passed to
+// SerializeSymmetricallyEncrypted.
+// If aeadSupported is set, SKESK v6 is used, otherwise v4.
+// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
+// If config is nil, sensible defaults will be used.
+func SerializeSymmetricKeyEncryptedAEADReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, aeadSupported bool, config *Config) (err error) {
+ var version int
+ if aeadSupported {
+ version = 6
+ } else {
+ version = 4
+ }
+ cipherFunc := config.Cipher()
+ // cipherFunc must be AES
+ if !cipherFunc.IsSupported() || cipherFunc < CipherAES128 || cipherFunc > CipherAES256 {
+ return errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(cipherFunc)))
+ }
+
+ keySize := cipherFunc.KeySize()
+ s2kBuf := new(bytes.Buffer)
+ keyEncryptingKey := make([]byte, keySize)
+ // s2k.Serialize salts and stretches the passphrase, and writes the
+ // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
+ err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, config.S2K())
+ if err != nil {
+ return
+ }
+ s2kBytes := s2kBuf.Bytes()
+
+ var packetLength int
+ switch version {
+ case 4:
+ packetLength = 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
+ case 5, 6:
+ ivLen := config.AEAD().Mode().IvLength()
+ tagLen := config.AEAD().Mode().TagLength()
+ packetLength = 3 + len(s2kBytes) + ivLen + keySize + tagLen
+ }
+ if version > 5 {
+ packetLength += 2 // additional octet count fields
+ }
+
+ err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
+ if err != nil {
+ return
+ }
+
+ // Symmetric Key Encrypted Version
+ buf := []byte{byte(version)}
+
+ if version > 5 {
+ // Scalar octet count
+ buf = append(buf, byte(3+len(s2kBytes)+config.AEAD().Mode().IvLength()))
+ }
+
+ // Cipher function
+ buf = append(buf, byte(cipherFunc))
+
+ if version >= 5 {
+ // AEAD mode
+ buf = append(buf, byte(config.AEAD().Mode()))
+ }
+ if version > 5 {
+ // Scalar octet count
+ buf = append(buf, byte(len(s2kBytes)))
+ }
+ _, err = w.Write(buf)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(s2kBytes)
+ if err != nil {
+ return
+ }
+
+ switch version {
+ case 4:
+ iv := make([]byte, cipherFunc.blockSize())
+ c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
+ encryptedCipherAndKey := make([]byte, keySize+1)
+ c.XORKeyStream(encryptedCipherAndKey, buf[1:])
+ c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
+ _, err = w.Write(encryptedCipherAndKey)
+ if err != nil {
+ return
+ }
+ case 5, 6:
+ mode := config.AEAD().Mode()
+ adata := []byte{0xc3, byte(version), byte(cipherFunc), byte(mode)}
+ aead := getEncryptedKeyAeadInstance(cipherFunc, mode, keyEncryptingKey, adata, version)
+
+ // Sample iv using random reader
+ iv := make([]byte, config.AEAD().Mode().IvLength())
+ _, err = io.ReadFull(config.Random(), iv)
+ if err != nil {
+ return
+ }
+ // Seal and write (encryptedData includes auth. tag)
+
+ encryptedData := aead.Seal(nil, iv, sessionKey, adata)
+ _, err = w.Write(iv)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(encryptedData)
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+func getEncryptedKeyAeadInstance(c CipherFunction, mode AEADMode, inputKey, associatedData []byte, version int) (aead cipher.AEAD) {
+ var blockCipher cipher.Block
+ if version > 5 {
+ hkdfReader := hkdf.New(sha256.New, inputKey, []byte{}, associatedData)
+
+ encryptionKey := make([]byte, c.KeySize())
+ _, _ = readFull(hkdfReader, encryptionKey)
+
+ blockCipher = c.new(encryptionKey)
+ } else {
+ blockCipher = c.new(inputKey)
+ }
+ return mode.new(blockCipher)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
new file mode 100644
index 0000000000..0e898742cf
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
@@ -0,0 +1,94 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+const aeadSaltSize = 32
+
+// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
+// encrypted Contents will consist of more OpenPGP packets. See RFC 4880,
+// sections 5.7 and 5.13.
+type SymmetricallyEncrypted struct {
+ Version int
+ Contents io.Reader // contains tag for version 2
+ IntegrityProtected bool // If true it is type 18 (with MDC or AEAD). False is packet type 9
+
+ // Specific to version 1
+ prefix []byte
+
+ // Specific to version 2
+ Cipher CipherFunction
+ Mode AEADMode
+ ChunkSizeByte byte
+ Salt [aeadSaltSize]byte
+}
+
+const (
+ symmetricallyEncryptedVersionMdc = 1
+ symmetricallyEncryptedVersionAead = 2
+)
+
+func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
+ if se.IntegrityProtected {
+ // See RFC 4880, section 5.13.
+ var buf [1]byte
+ _, err := readFull(r, buf[:])
+ if err != nil {
+ return err
+ }
+
+ switch buf[0] {
+ case symmetricallyEncryptedVersionMdc:
+ se.Version = symmetricallyEncryptedVersionMdc
+ case symmetricallyEncryptedVersionAead:
+ se.Version = symmetricallyEncryptedVersionAead
+ if err := se.parseAead(r); err != nil {
+ return err
+ }
+ default:
+ return errors.UnsupportedError("unknown SymmetricallyEncrypted version")
+ }
+ }
+ se.Contents = r
+ return nil
+}
+
+// Decrypt returns a ReadCloser, from which the decrypted Contents of the
+// packet can be read. An incorrect key will only be detected after trying
+// to decrypt the entire data.
+func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
+ if se.Version == symmetricallyEncryptedVersionAead {
+ return se.decryptAead(key)
+ }
+
+ return se.decryptMdc(c, key)
+}
+
+// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
+// to w and returns a WriteCloser to which the to-be-encrypted packets can be
+// written.
+// If aeadSupported is set to true, SEIPDv2 is used with the indicated CipherSuite.
+// Otherwise, SEIPDv1 is used with the indicated CipherFunction.
+// Note: aeadSupported MUST match the value passed to SerializeEncryptedKeyAEAD
+// and/or SerializeSymmetricKeyEncryptedAEADReuseKey.
+// If config is nil, sensible defaults will be used.
+func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, aeadSupported bool, cipherSuite CipherSuite, key []byte, config *Config) (Contents io.WriteCloser, err error) {
+ writeCloser := noOpCloser{w}
+ ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedIntegrityProtected)
+ if err != nil {
+ return
+ }
+
+ if aeadSupported {
+ return serializeSymmetricallyEncryptedAead(ciphertext, cipherSuite, config.AEADConfig.ChunkSizeByte(), config.Random(), key)
+ }
+
+ return serializeSymmetricallyEncryptedMdc(ciphertext, c, key, config)
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go
new file mode 100644
index 0000000000..3ddc4fe4a9
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go
@@ -0,0 +1,168 @@
+// Copyright 2023 Proton AG. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto/cipher"
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "golang.org/x/crypto/hkdf"
+)
+
+// parseAead parses a V2 SEIPD packet (AEAD) as specified in
+// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2
+func (se *SymmetricallyEncrypted) parseAead(r io.Reader) error {
+ headerData := make([]byte, 3)
+ if n, err := io.ReadFull(r, headerData); n < 3 {
+ return errors.StructuralError("could not read aead header: " + err.Error())
+ }
+
+ // Cipher
+ se.Cipher = CipherFunction(headerData[0])
+ // cipherFunc must have block size 16 to use AEAD
+ if se.Cipher.blockSize() != 16 {
+ return errors.UnsupportedError("invalid aead cipher: " + strconv.Itoa(int(se.Cipher)))
+ }
+
+ // Mode
+ se.Mode = AEADMode(headerData[1])
+ if se.Mode.TagLength() == 0 {
+ return errors.UnsupportedError("unknown aead mode: " + strconv.Itoa(int(se.Mode)))
+ }
+
+ // Chunk size
+ se.ChunkSizeByte = headerData[2]
+ if se.ChunkSizeByte > 16 {
+ return errors.UnsupportedError("invalid aead chunk size byte: " + strconv.Itoa(int(se.ChunkSizeByte)))
+ }
+
+ // Salt
+ if n, err := io.ReadFull(r, se.Salt[:]); n < aeadSaltSize {
+ return errors.StructuralError("could not read aead salt: " + err.Error())
+ }
+
+ return nil
+}
+
+// associatedData for chunks: tag, version, cipher, mode, chunk size byte
+func (se *SymmetricallyEncrypted) associatedData() []byte {
+ return []byte{
+ 0xD2,
+ symmetricallyEncryptedVersionAead,
+ byte(se.Cipher),
+ byte(se.Mode),
+ se.ChunkSizeByte,
+ }
+}
+
+// decryptAead decrypts a V2 SEIPD packet (AEAD) as specified in
+// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2
+func (se *SymmetricallyEncrypted) decryptAead(inputKey []byte) (io.ReadCloser, error) {
+ if se.Cipher.KeySize() != len(inputKey) {
+ return nil, errors.StructuralError(fmt.Sprintf("invalid session key length for cipher: got %d bytes, but expected %d bytes", len(inputKey), se.Cipher.KeySize()))
+ }
+
+ aead, nonce := getSymmetricallyEncryptedAeadInstance(se.Cipher, se.Mode, inputKey, se.Salt[:], se.associatedData())
+ // Carry the first tagLen bytes
+ chunkSize := decodeAEADChunkSize(se.ChunkSizeByte)
+ tagLen := se.Mode.TagLength()
+ chunkBytes := make([]byte, chunkSize+tagLen*2)
+ peekedBytes := chunkBytes[chunkSize+tagLen:]
+ n, err := io.ReadFull(se.Contents, peekedBytes)
+ if n < tagLen || (err != nil && err != io.EOF) {
+ return nil, errors.StructuralError("not enough data to decrypt:" + err.Error())
+ }
+
+ return &aeadDecrypter{
+ aeadCrypter: aeadCrypter{
+ aead: aead,
+ chunkSize: decodeAEADChunkSize(se.ChunkSizeByte),
+ nonce: nonce,
+ associatedData: se.associatedData(),
+ chunkIndex: nonce[len(nonce)-8:],
+ packetTag: packetTypeSymmetricallyEncryptedIntegrityProtected,
+ },
+ reader: se.Contents,
+ chunkBytes: chunkBytes,
+ peekedBytes: peekedBytes,
+ }, nil
+}
+
+// serializeSymmetricallyEncryptedAead encrypts to a writer a V2 SEIPD packet (AEAD) as specified in
+// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2
+func serializeSymmetricallyEncryptedAead(ciphertext io.WriteCloser, cipherSuite CipherSuite, chunkSizeByte byte, rand io.Reader, inputKey []byte) (Contents io.WriteCloser, err error) {
+ // cipherFunc must have block size 16 to use AEAD
+ if cipherSuite.Cipher.blockSize() != 16 {
+ return nil, errors.InvalidArgumentError("invalid aead cipher function")
+ }
+
+ if cipherSuite.Cipher.KeySize() != len(inputKey) {
+ return nil, errors.InvalidArgumentError("error in aead serialization: bad key length")
+ }
+
+ // Data for en/decryption: tag, version, cipher, aead mode, chunk size
+ prefix := []byte{
+ 0xD2,
+ symmetricallyEncryptedVersionAead,
+ byte(cipherSuite.Cipher),
+ byte(cipherSuite.Mode),
+ chunkSizeByte,
+ }
+
+ // Write header (that correspond to prefix except first byte)
+ n, err := ciphertext.Write(prefix[1:])
+ if err != nil || n < 4 {
+ return nil, err
+ }
+
+ // Random salt
+ salt := make([]byte, aeadSaltSize)
+ if _, err := io.ReadFull(rand, salt); err != nil {
+ return nil, err
+ }
+
+ if _, err := ciphertext.Write(salt); err != nil {
+ return nil, err
+ }
+
+ aead, nonce := getSymmetricallyEncryptedAeadInstance(cipherSuite.Cipher, cipherSuite.Mode, inputKey, salt, prefix)
+
+ chunkSize := decodeAEADChunkSize(chunkSizeByte)
+ tagLen := aead.Overhead()
+ chunkBytes := make([]byte, chunkSize+tagLen)
+ return &aeadEncrypter{
+ aeadCrypter: aeadCrypter{
+ aead: aead,
+ chunkSize: chunkSize,
+ associatedData: prefix,
+ nonce: nonce,
+ chunkIndex: nonce[len(nonce)-8:],
+ packetTag: packetTypeSymmetricallyEncryptedIntegrityProtected,
+ },
+ writer: ciphertext,
+ chunkBytes: chunkBytes,
+ }, nil
+}
+
+func getSymmetricallyEncryptedAeadInstance(c CipherFunction, mode AEADMode, inputKey, salt, associatedData []byte) (aead cipher.AEAD, nonce []byte) {
+ hkdfReader := hkdf.New(sha256.New, inputKey, salt, associatedData)
+
+ encryptionKey := make([]byte, c.KeySize())
+ _, _ = readFull(hkdfReader, encryptionKey)
+
+ nonce = make([]byte, mode.IvLength())
+
+ // Last 64 bits of nonce are the counter
+ _, _ = readFull(hkdfReader, nonce[:len(nonce)-8])
+
+ blockCipher := c.new(encryptionKey)
+ aead = mode.new(blockCipher)
+
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_mdc.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_mdc.go
new file mode 100644
index 0000000000..8b18623684
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_mdc.go
@@ -0,0 +1,256 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto/cipher"
+ "crypto/sha1"
+ "crypto/subtle"
+ "hash"
+ "io"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+)
+
+// seMdcReader wraps an io.Reader with a no-op Close method.
+type seMdcReader struct {
+ in io.Reader
+}
+
+func (ser seMdcReader) Read(buf []byte) (int, error) {
+ return ser.in.Read(buf)
+}
+
+func (ser seMdcReader) Close() error {
+ return nil
+}
+
+func (se *SymmetricallyEncrypted) decryptMdc(c CipherFunction, key []byte) (io.ReadCloser, error) {
+ if !c.IsSupported() {
+ return nil, errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(c)))
+ }
+
+ if len(key) != c.KeySize() {
+ return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
+ }
+
+ if se.prefix == nil {
+ se.prefix = make([]byte, c.blockSize()+2)
+ _, err := readFull(se.Contents, se.prefix)
+ if err != nil {
+ return nil, err
+ }
+ } else if len(se.prefix) != c.blockSize()+2 {
+ return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
+ }
+
+ ocfbResync := OCFBResync
+ if se.IntegrityProtected {
+ // MDC packets use a different form of OCFB mode.
+ ocfbResync = OCFBNoResync
+ }
+
+ s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
+
+ plaintext := cipher.StreamReader{S: s, R: se.Contents}
+
+ if se.IntegrityProtected {
+ // IntegrityProtected packets have an embedded hash that we need to check.
+ h := sha1.New()
+ h.Write(se.prefix)
+ return &seMDCReader{in: plaintext, h: h}, nil
+ }
+
+ // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
+ return seMdcReader{plaintext}, nil
+}
+
+const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
+
+// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
+// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
+// MDC packet containing a hash of the previous Contents which is checked
+// against the running hash. See RFC 4880, section 5.13.
+type seMDCReader struct {
+ in io.Reader
+ h hash.Hash
+ trailer [mdcTrailerSize]byte
+ scratch [mdcTrailerSize]byte
+ trailerUsed int
+ error bool
+ eof bool
+}
+
+func (ser *seMDCReader) Read(buf []byte) (n int, err error) {
+ if ser.error {
+ err = io.ErrUnexpectedEOF
+ return
+ }
+ if ser.eof {
+ err = io.EOF
+ return
+ }
+
+ // If we haven't yet filled the trailer buffer then we must do that
+ // first.
+ for ser.trailerUsed < mdcTrailerSize {
+ n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
+ ser.trailerUsed += n
+ if err == io.EOF {
+ if ser.trailerUsed != mdcTrailerSize {
+ n = 0
+ err = io.ErrUnexpectedEOF
+ ser.error = true
+ return
+ }
+ ser.eof = true
+ n = 0
+ return
+ }
+
+ if err != nil {
+ n = 0
+ return
+ }
+ }
+
+ // If it's a short read then we read into a temporary buffer and shift
+ // the data into the caller's buffer.
+ if len(buf) <= mdcTrailerSize {
+ n, err = readFull(ser.in, ser.scratch[:len(buf)])
+ copy(buf, ser.trailer[:n])
+ ser.h.Write(buf[:n])
+ copy(ser.trailer[:], ser.trailer[n:])
+ copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
+ if n < len(buf) {
+ ser.eof = true
+ err = io.EOF
+ }
+ return
+ }
+
+ n, err = ser.in.Read(buf[mdcTrailerSize:])
+ copy(buf, ser.trailer[:])
+ ser.h.Write(buf[:n])
+ copy(ser.trailer[:], buf[n:])
+
+ if err == io.EOF {
+ ser.eof = true
+ }
+ return
+}
+
+// This is a new-format packet tag byte for a type 19 (Integrity Protected) packet.
+const mdcPacketTagByte = byte(0x80) | 0x40 | 19
+
+func (ser *seMDCReader) Close() error {
+ if ser.error {
+ return errors.ErrMDCHashMismatch
+ }
+
+ for !ser.eof {
+ // We haven't seen EOF so we need to read to the end
+ var buf [1024]byte
+ _, err := ser.Read(buf[:])
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return errors.ErrMDCHashMismatch
+ }
+ }
+
+ ser.h.Write(ser.trailer[:2])
+
+ final := ser.h.Sum(nil)
+ if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
+ return errors.ErrMDCHashMismatch
+ }
+ // The hash already includes the MDC header, but we still check its value
+ // to confirm encryption correctness
+ if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
+ return errors.ErrMDCHashMismatch
+ }
+ return nil
+}
+
+// An seMDCWriter writes through to an io.WriteCloser while maintains a running
+// hash of the data written. On close, it emits an MDC packet containing the
+// running hash.
+type seMDCWriter struct {
+ w io.WriteCloser
+ h hash.Hash
+}
+
+func (w *seMDCWriter) Write(buf []byte) (n int, err error) {
+ w.h.Write(buf)
+ return w.w.Write(buf)
+}
+
+func (w *seMDCWriter) Close() (err error) {
+ var buf [mdcTrailerSize]byte
+
+ buf[0] = mdcPacketTagByte
+ buf[1] = sha1.Size
+ w.h.Write(buf[:2])
+ digest := w.h.Sum(nil)
+ copy(buf[2:], digest)
+
+ _, err = w.w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ return w.w.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() error {
+ return nil
+}
+
+func serializeSymmetricallyEncryptedMdc(ciphertext io.WriteCloser, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) {
+ // Disallow old cipher suites
+ if !c.IsSupported() || c < CipherAES128 {
+ return nil, errors.InvalidArgumentError("invalid mdc cipher function")
+ }
+
+ if c.KeySize() != len(key) {
+ return nil, errors.InvalidArgumentError("error in mdc serialization: bad key length")
+ }
+
+ _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersionMdc})
+ if err != nil {
+ return
+ }
+
+ block := c.new(key)
+ blockSize := block.BlockSize()
+ iv := make([]byte, blockSize)
+ _, err = io.ReadFull(config.Random(), iv)
+ if err != nil {
+ return nil, err
+ }
+ s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
+ _, err = ciphertext.Write(prefix)
+ if err != nil {
+ return
+ }
+ plaintext := cipher.StreamWriter{S: s, W: ciphertext}
+
+ h := sha1.New()
+ h.Write(iv)
+ h.Write(iv[blockSize-2:])
+ Contents = &seMDCWriter{w: plaintext, h: h}
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
new file mode 100644
index 0000000000..63814ed132
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
@@ -0,0 +1,100 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "image"
+ "image/jpeg"
+ "io"
+)
+
+const UserAttrImageSubpacket = 1
+
+// UserAttribute is capable of storing other types of data about a user
+// beyond name, email and a text comment. In practice, user attributes are typically used
+// to store a signed thumbnail photo JPEG image of the user.
+// See RFC 4880, section 5.12.
+type UserAttribute struct {
+ Contents []*OpaqueSubpacket
+}
+
+// NewUserAttributePhoto creates a user attribute packet
+// containing the given images.
+func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) {
+ uat = new(UserAttribute)
+ for _, photo := range photos {
+ var buf bytes.Buffer
+ // RFC 4880, Section 5.12.1.
+ data := []byte{
+ 0x10, 0x00, // Little-endian image header length (16 bytes)
+ 0x01, // Image header version 1
+ 0x01, // JPEG
+ 0, 0, 0, 0, // 12 reserved octets, must be all zero.
+ 0, 0, 0, 0,
+ 0, 0, 0, 0}
+ if _, err = buf.Write(data); err != nil {
+ return
+ }
+ if err = jpeg.Encode(&buf, photo, nil); err != nil {
+ return
+ }
+
+ lengthBuf := make([]byte, 5)
+ n := serializeSubpacketLength(lengthBuf, len(buf.Bytes())+1)
+ lengthBuf = lengthBuf[:n]
+
+ uat.Contents = append(uat.Contents, &OpaqueSubpacket{
+ SubType: UserAttrImageSubpacket,
+ EncodedLength: lengthBuf,
+ Contents: buf.Bytes(),
+ })
+ }
+ return
+}
+
+// NewUserAttribute creates a new user attribute packet containing the given subpackets.
+func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute {
+ return &UserAttribute{Contents: contents}
+}
+
+func (uat *UserAttribute) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.13
+ b, err := io.ReadAll(r)
+ if err != nil {
+ return
+ }
+ uat.Contents, err = OpaqueSubpackets(b)
+ return
+}
+
+// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including
+// header.
+func (uat *UserAttribute) Serialize(w io.Writer) (err error) {
+ var buf bytes.Buffer
+ for _, sp := range uat.Contents {
+ err = sp.Serialize(&buf)
+ if err != nil {
+ return err
+ }
+ }
+ if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil {
+ return err
+ }
+ _, err = w.Write(buf.Bytes())
+ return
+}
+
+// ImageData returns zero or more byte slices, each containing
+// JPEG File Interchange Format (JFIF), for each photo in the
+// user attribute packet.
+func (uat *UserAttribute) ImageData() (imageData [][]byte) {
+ for _, sp := range uat.Contents {
+ if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 {
+ imageData = append(imageData, sp.Contents[16:])
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
new file mode 100644
index 0000000000..3c7451a3c3
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
@@ -0,0 +1,166 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "io"
+ "strings"
+)
+
+// UserId contains text that is intended to represent the name and email
+// address of the key holder. See RFC 4880, section 5.11. By convention, this
+// takes the form "Full Name (Comment) "
+type UserId struct {
+ Id string // By convention, this takes the form "Full Name (Comment) " which is split out in the fields below.
+
+ Name, Comment, Email string
+}
+
+func hasInvalidCharacters(s string) bool {
+ for _, c := range s {
+ switch c {
+ case '(', ')', '<', '>', 0:
+ return true
+ }
+ }
+ return false
+}
+
+// NewUserId returns a UserId or nil if any of the arguments contain invalid
+// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
+func NewUserId(name, comment, email string) *UserId {
+ // RFC 4880 doesn't deal with the structure of userid strings; the
+ // name, comment and email form is just a convention. However, there's
+ // no convention about escaping the metacharacters and GPG just refuses
+ // to create user ids where, say, the name contains a '('. We mirror
+ // this behaviour.
+
+ if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
+ return nil
+ }
+
+ uid := new(UserId)
+ uid.Name, uid.Comment, uid.Email = name, comment, email
+ uid.Id = name
+ if len(comment) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "("
+ uid.Id += comment
+ uid.Id += ")"
+ }
+ if len(email) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "<"
+ uid.Id += email
+ uid.Id += ">"
+ }
+ return uid
+}
+
+func (uid *UserId) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.11
+ b, err := io.ReadAll(r)
+ if err != nil {
+ return
+ }
+ uid.Id = string(b)
+ uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
+ return
+}
+
+// Serialize marshals uid to w in the form of an OpenPGP packet, including
+// header.
+func (uid *UserId) Serialize(w io.Writer) error {
+ err := serializeHeader(w, packetTypeUserId, len(uid.Id))
+ if err != nil {
+ return err
+ }
+ _, err = w.Write([]byte(uid.Id))
+ return err
+}
+
+// parseUserId extracts the name, comment and email from a user id string that
+// is formatted as "Full Name (Comment) ".
+func parseUserId(id string) (name, comment, email string) {
+ var n, c, e struct {
+ start, end int
+ }
+ var state int
+
+ for offset, rune := range id {
+ switch state {
+ case 0:
+ // Entering name
+ n.start = offset
+ state = 1
+ fallthrough
+ case 1:
+ // In name
+ if rune == '(' {
+ state = 2
+ n.end = offset
+ } else if rune == '<' {
+ state = 5
+ n.end = offset
+ }
+ case 2:
+ // Entering comment
+ c.start = offset
+ state = 3
+ fallthrough
+ case 3:
+ // In comment
+ if rune == ')' {
+ state = 4
+ c.end = offset
+ }
+ case 4:
+ // Between comment and email
+ if rune == '<' {
+ state = 5
+ }
+ case 5:
+ // Entering email
+ e.start = offset
+ state = 6
+ fallthrough
+ case 6:
+ // In email
+ if rune == '>' {
+ state = 7
+ e.end = offset
+ }
+ default:
+ // After email
+ }
+ }
+ switch state {
+ case 1:
+ // ended in the name
+ n.end = len(id)
+ case 3:
+ // ended in comment
+ c.end = len(id)
+ case 6:
+ // ended in email
+ e.end = len(id)
+ }
+
+ name = strings.TrimSpace(id[n.start:n.end])
+ comment = strings.TrimSpace(id[c.start:c.end])
+ email = strings.TrimSpace(id[e.start:e.end])
+
+ // RFC 2822 3.4: alternate simple form of a mailbox
+ if email == "" && strings.ContainsRune(name, '@') {
+ email = name
+ name = ""
+ }
+
+ return
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/read.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/read.go
new file mode 100644
index 0000000000..5578797edf
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/read.go
@@ -0,0 +1,619 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package openpgp implements high level operations on OpenPGP messages.
+package openpgp // import "github.com/ProtonMail/go-crypto/openpgp"
+
+import (
+ "crypto"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+ "hash"
+ "io"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/armor"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+ "github.com/ProtonMail/go-crypto/openpgp/packet"
+ _ "golang.org/x/crypto/sha3"
+)
+
+// SignatureType is the armor type for a PGP signature.
+var SignatureType = "PGP SIGNATURE"
+
+// readArmored reads an armored block with the given type.
+func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) {
+ block, err := armor.Decode(r)
+ if err != nil {
+ return
+ }
+
+ if block.Type != expectedType {
+ return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
+ }
+
+ return block.Body, nil
+}
+
+// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
+// signed message.
+type MessageDetails struct {
+ IsEncrypted bool // true if the message was encrypted.
+ EncryptedToKeyIds []uint64 // the list of recipient key ids.
+ IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message.
+ DecryptedWith Key // the private key used to decrypt the message, if any.
+ IsSigned bool // true if the message is signed.
+ SignedByKeyId uint64 // the key id of the signer, if any.
+ SignedByFingerprint []byte // the key fingerprint of the signer, if any.
+ SignedBy *Key // the key of the signer, if available.
+ LiteralData *packet.LiteralData // the metadata of the contents
+ UnverifiedBody io.Reader // the contents of the message.
+
+ // If IsSigned is true and SignedBy is non-zero then the signature will
+ // be verified as UnverifiedBody is read. The signature cannot be
+ // checked until the whole of UnverifiedBody is read so UnverifiedBody
+ // must be consumed until EOF before the data can be trusted. Even if a
+ // message isn't signed (or the signer is unknown) the data may contain
+ // an authentication code that is only checked once UnverifiedBody has
+ // been consumed. Once EOF has been seen, the following fields are
+ // valid. (An authentication code failure is reported as a
+ // SignatureError error when reading from UnverifiedBody.)
+ Signature *packet.Signature // the signature packet itself.
+ SignatureError error // nil if the signature is good.
+ UnverifiedSignatures []*packet.Signature // all other unverified signature packets.
+
+ decrypted io.ReadCloser
+}
+
+// A PromptFunction is used as a callback by functions that may need to decrypt
+// a private key, or prompt for a passphrase. It is called with a list of
+// acceptable, encrypted private keys and a boolean that indicates whether a
+// passphrase is usable. It should either decrypt a private key or return a
+// passphrase to try. If the decrypted private key or given passphrase isn't
+// correct, the function will be called again, forever. Any error returned will
+// be passed up.
+type PromptFunction func(keys []Key, symmetric bool) ([]byte, error)
+
+// A keyEnvelopePair is used to store a private key with the envelope that
+// contains a symmetric key, encrypted with that key.
+type keyEnvelopePair struct {
+ key Key
+ encryptedKey *packet.EncryptedKey
+}
+
+// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
+// The given KeyRing should contain both public keys (for signature
+// verification) and, possibly encrypted, private keys for decrypting.
+// If config is nil, sensible defaults will be used.
+func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) {
+ var p packet.Packet
+
+ var symKeys []*packet.SymmetricKeyEncrypted
+ var pubKeys []keyEnvelopePair
+ // Integrity protected encrypted packet: SymmetricallyEncrypted or AEADEncrypted
+ var edp packet.EncryptedDataPacket
+
+ packets := packet.NewReader(r)
+ md = new(MessageDetails)
+ md.IsEncrypted = true
+
+ // The message, if encrypted, starts with a number of packets
+ // containing an encrypted decryption key. The decryption key is either
+ // encrypted to a public key, or with a passphrase. This loop
+ // collects these packets.
+ParsePackets:
+ for {
+ p, err = packets.Next()
+ if err != nil {
+ return nil, err
+ }
+ switch p := p.(type) {
+ case *packet.SymmetricKeyEncrypted:
+ // This packet contains the decryption key encrypted with a passphrase.
+ md.IsSymmetricallyEncrypted = true
+ symKeys = append(symKeys, p)
+ case *packet.EncryptedKey:
+ // This packet contains the decryption key encrypted to a public key.
+ md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
+ switch p.Algo {
+ case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH, packet.PubKeyAlgoX25519, packet.PubKeyAlgoX448:
+ break
+ default:
+ continue
+ }
+ if keyring != nil {
+ var keys []Key
+ if p.KeyId == 0 {
+ keys = keyring.DecryptionKeys()
+ } else {
+ keys = keyring.KeysById(p.KeyId)
+ }
+ for _, k := range keys {
+ pubKeys = append(pubKeys, keyEnvelopePair{k, p})
+ }
+ }
+ case *packet.SymmetricallyEncrypted:
+ if !p.IntegrityProtected && !config.AllowUnauthenticatedMessages() {
+ return nil, errors.UnsupportedError("message is not integrity protected")
+ }
+ edp = p
+ break ParsePackets
+ case *packet.AEADEncrypted:
+ edp = p
+ break ParsePackets
+ case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
+ // This message isn't encrypted.
+ if len(symKeys) != 0 || len(pubKeys) != 0 {
+ return nil, errors.StructuralError("key material not followed by encrypted message")
+ }
+ packets.Unread(p)
+ return readSignedMessage(packets, nil, keyring, config)
+ }
+ }
+
+ var candidates []Key
+ var decrypted io.ReadCloser
+
+ // Now that we have the list of encrypted keys we need to decrypt at
+ // least one of them or, if we cannot, we need to call the prompt
+ // function so that it can decrypt a key or give us a passphrase.
+FindKey:
+ for {
+ // See if any of the keys already have a private key available
+ candidates = candidates[:0]
+ candidateFingerprints := make(map[string]bool)
+
+ for _, pk := range pubKeys {
+ if pk.key.PrivateKey == nil {
+ continue
+ }
+ if !pk.key.PrivateKey.Encrypted {
+ if len(pk.encryptedKey.Key) == 0 {
+ errDec := pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
+ if errDec != nil {
+ continue
+ }
+ }
+ // Try to decrypt symmetrically encrypted
+ decrypted, err = edp.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
+ if err != nil && err != errors.ErrKeyIncorrect {
+ return nil, err
+ }
+ if decrypted != nil {
+ md.DecryptedWith = pk.key
+ break FindKey
+ }
+ } else {
+ fpr := string(pk.key.PublicKey.Fingerprint[:])
+ if v := candidateFingerprints[fpr]; v {
+ continue
+ }
+ candidates = append(candidates, pk.key)
+ candidateFingerprints[fpr] = true
+ }
+ }
+
+ if len(candidates) == 0 && len(symKeys) == 0 {
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ if prompt == nil {
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ passphrase, err := prompt(candidates, len(symKeys) != 0)
+ if err != nil {
+ return nil, err
+ }
+
+ // Try the symmetric passphrase first
+ if len(symKeys) != 0 && passphrase != nil {
+ for _, s := range symKeys {
+ key, cipherFunc, err := s.Decrypt(passphrase)
+ // In v4, on wrong passphrase, session key decryption is very likely to result in an invalid cipherFunc:
+ // only for < 5% of cases we will proceed to decrypt the data
+ if err == nil {
+ decrypted, err = edp.Decrypt(cipherFunc, key)
+ if err != nil {
+ return nil, err
+ }
+ if decrypted != nil {
+ break FindKey
+ }
+ }
+ }
+ }
+ }
+
+ md.decrypted = decrypted
+ if err := packets.Push(decrypted); err != nil {
+ return nil, err
+ }
+ mdFinal, sensitiveParsingErr := readSignedMessage(packets, md, keyring, config)
+ if sensitiveParsingErr != nil {
+ return nil, errors.HandleSensitiveParsingError(sensitiveParsingErr, md.decrypted != nil)
+ }
+ return mdFinal, nil
+}
+
+// readSignedMessage reads a possibly signed message if mdin is non-zero then
+// that structure is updated and returned. Otherwise a fresh MessageDetails is
+// used.
+func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing, config *packet.Config) (md *MessageDetails, err error) {
+ if mdin == nil {
+ mdin = new(MessageDetails)
+ }
+ md = mdin
+
+ var p packet.Packet
+ var h hash.Hash
+ var wrappedHash hash.Hash
+ var prevLast bool
+FindLiteralData:
+ for {
+ p, err = packets.Next()
+ if err != nil {
+ return nil, err
+ }
+ switch p := p.(type) {
+ case *packet.Compressed:
+ if err := packets.Push(p.LimitedBodyReader(config.DecompressedMessageSizeLimit())); err != nil {
+ return nil, err
+ }
+ case *packet.OnePassSignature:
+ if prevLast {
+ return nil, errors.UnsupportedError("nested signature packets")
+ }
+
+ if p.IsLast {
+ prevLast = true
+ }
+
+ h, wrappedHash, err = hashForSignature(p.Hash, p.SigType, p.Salt)
+ if err != nil {
+ md.SignatureError = err
+ }
+
+ md.IsSigned = true
+ if p.Version == 6 {
+ md.SignedByFingerprint = p.KeyFingerprint
+ }
+ md.SignedByKeyId = p.KeyId
+
+ if keyring != nil {
+ keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
+ if len(keys) > 0 {
+ md.SignedBy = &keys[0]
+ }
+ }
+ case *packet.LiteralData:
+ md.LiteralData = p
+ break FindLiteralData
+ }
+ }
+
+ if md.IsSigned && md.SignatureError == nil {
+ md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md, config}
+ } else if md.decrypted != nil {
+ md.UnverifiedBody = &checkReader{md, false}
+ } else {
+ md.UnverifiedBody = md.LiteralData.Body
+ }
+
+ return md, nil
+}
+
+func wrapHashForSignature(hashFunc hash.Hash, sigType packet.SignatureType) (hash.Hash, error) {
+ switch sigType {
+ case packet.SigTypeBinary:
+ return hashFunc, nil
+ case packet.SigTypeText:
+ return NewCanonicalTextHash(hashFunc), nil
+ }
+ return nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
+}
+
+// hashForSignature returns a pair of hashes that can be used to verify a
+// signature. The signature may specify that the contents of the signed message
+// should be preprocessed (i.e. to normalize line endings). Thus this function
+// returns two hashes. The second should be used to hash the message itself and
+// performs any needed preprocessing.
+func hashForSignature(hashFunc crypto.Hash, sigType packet.SignatureType, sigSalt []byte) (hash.Hash, hash.Hash, error) {
+ if _, ok := algorithm.HashToHashIdWithSha1(hashFunc); !ok {
+ return nil, nil, errors.UnsupportedError("unsupported hash function")
+ }
+ if !hashFunc.Available() {
+ return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashFunc)))
+ }
+ h := hashFunc.New()
+ if sigSalt != nil {
+ h.Write(sigSalt)
+ }
+ wrappedHash, err := wrapHashForSignature(h, sigType)
+ if err != nil {
+ return nil, nil, err
+ }
+ switch sigType {
+ case packet.SigTypeBinary:
+ return h, wrappedHash, nil
+ case packet.SigTypeText:
+ return h, wrappedHash, nil
+ }
+ return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
+}
+
+// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
+// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
+// MDC checks.
+type checkReader struct {
+ md *MessageDetails
+ checked bool
+}
+
+func (cr *checkReader) Read(buf []byte) (int, error) {
+ n, sensitiveParsingError := cr.md.LiteralData.Body.Read(buf)
+ if sensitiveParsingError == io.EOF {
+ if cr.checked {
+ // Only check once
+ return n, io.EOF
+ }
+ mdcErr := cr.md.decrypted.Close()
+ if mdcErr != nil {
+ return n, mdcErr
+ }
+ cr.checked = true
+ return n, io.EOF
+ }
+
+ if sensitiveParsingError != nil {
+ return n, errors.HandleSensitiveParsingError(sensitiveParsingError, true)
+ }
+
+ return n, nil
+}
+
+// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
+// the data as it is read. When it sees an EOF from the underlying io.Reader
+// it parses and checks a trailing Signature packet and triggers any MDC checks.
+type signatureCheckReader struct {
+ packets *packet.Reader
+ h, wrappedHash hash.Hash
+ md *MessageDetails
+ config *packet.Config
+}
+
+func (scr *signatureCheckReader) Read(buf []byte) (int, error) {
+ n, sensitiveParsingError := scr.md.LiteralData.Body.Read(buf)
+
+ // Hash only if required
+ if scr.md.SignedBy != nil {
+ scr.wrappedHash.Write(buf[:n])
+ }
+
+ readsDecryptedData := scr.md.decrypted != nil
+ if sensitiveParsingError == io.EOF {
+ var p packet.Packet
+ var readError error
+ var sig *packet.Signature
+
+ p, readError = scr.packets.Next()
+ for readError == nil {
+ var ok bool
+ if sig, ok = p.(*packet.Signature); ok {
+ if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) {
+ sig.Metadata = scr.md.LiteralData
+ }
+
+ // If signature KeyID matches
+ if scr.md.SignedBy != nil && *sig.IssuerKeyId == scr.md.SignedByKeyId {
+ key := scr.md.SignedBy
+ signatureError := key.PublicKey.VerifySignature(scr.h, sig)
+ if signatureError == nil {
+ signatureError = checkMessageSignatureDetails(key, sig, scr.config)
+ }
+ scr.md.Signature = sig
+ scr.md.SignatureError = signatureError
+ } else {
+ scr.md.UnverifiedSignatures = append(scr.md.UnverifiedSignatures, sig)
+ }
+ }
+
+ p, readError = scr.packets.Next()
+ }
+
+ if scr.md.SignedBy != nil && scr.md.Signature == nil {
+ if scr.md.UnverifiedSignatures == nil {
+ scr.md.SignatureError = errors.StructuralError("LiteralData not followed by signature")
+ } else {
+ scr.md.SignatureError = errors.StructuralError("No matching signature found")
+ }
+ }
+
+ // The SymmetricallyEncrypted packet, if any, might have an
+ // unsigned hash of its own. In order to check this we need to
+ // close that Reader.
+ if scr.md.decrypted != nil {
+ if sensitiveParsingError := scr.md.decrypted.Close(); sensitiveParsingError != nil {
+ return n, errors.HandleSensitiveParsingError(sensitiveParsingError, true)
+ }
+ }
+ return n, io.EOF
+ }
+
+ if sensitiveParsingError != nil {
+ return n, errors.HandleSensitiveParsingError(sensitiveParsingError, readsDecryptedData)
+ }
+
+ return n, nil
+}
+
+// VerifyDetachedSignature takes a signed file and a detached signature and
+// returns the signature packet and the entity the signature was signed by,
+// if any, and a possible signature verification error.
+// If the signer isn't known, ErrUnknownIssuer is returned.
+func VerifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
+ return verifyDetachedSignature(keyring, signed, signature, nil, false, config)
+}
+
+// VerifyDetachedSignatureAndHash performs the same actions as
+// VerifyDetachedSignature and checks that the expected hash functions were used.
+func VerifyDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
+ return verifyDetachedSignature(keyring, signed, signature, expectedHashes, true, config)
+}
+
+// CheckDetachedSignature takes a signed file and a detached signature and
+// returns the entity the signature was signed by, if any, and a possible
+// signature verification error. If the signer isn't known,
+// ErrUnknownIssuer is returned.
+func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
+ _, signer, err = verifyDetachedSignature(keyring, signed, signature, nil, false, config)
+ return
+}
+
+// CheckDetachedSignatureAndHash performs the same actions as
+// CheckDetachedSignature and checks that the expected hash functions were used.
+func CheckDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (signer *Entity, err error) {
+ _, signer, err = verifyDetachedSignature(keyring, signed, signature, expectedHashes, true, config)
+ return
+}
+
+func verifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, checkHashes bool, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
+ var issuerKeyId uint64
+ var hashFunc crypto.Hash
+ var sigType packet.SignatureType
+ var keys []Key
+ var p packet.Packet
+
+ packets := packet.NewReader(signature)
+ for {
+ p, err = packets.Next()
+ if err == io.EOF {
+ return nil, nil, errors.ErrUnknownIssuer
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+
+ var ok bool
+ sig, ok = p.(*packet.Signature)
+ if !ok {
+ return nil, nil, errors.StructuralError("non signature packet found")
+ }
+ if sig.IssuerKeyId == nil {
+ return nil, nil, errors.StructuralError("signature doesn't have an issuer")
+ }
+ issuerKeyId = *sig.IssuerKeyId
+ hashFunc = sig.Hash
+ sigType = sig.SigType
+ if checkHashes {
+ matchFound := false
+ // check for hashes
+ for _, expectedHash := range expectedHashes {
+ if hashFunc == expectedHash {
+ matchFound = true
+ break
+ }
+ }
+ if !matchFound {
+ return nil, nil, errors.StructuralError("hash algorithm or salt mismatch with cleartext message headers")
+ }
+ }
+ keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
+ if len(keys) > 0 {
+ break
+ }
+ }
+
+ if len(keys) == 0 {
+ panic("unreachable")
+ }
+
+ h, err := sig.PrepareVerify()
+ if err != nil {
+ return nil, nil, err
+ }
+ wrappedHash, err := wrapHashForSignature(h, sigType)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF {
+ return nil, nil, err
+ }
+
+ for _, key := range keys {
+ err = key.PublicKey.VerifySignature(h, sig)
+ if err == nil {
+ return sig, key.Entity, checkMessageSignatureDetails(&key, sig, config)
+ }
+ }
+
+ return nil, nil, err
+}
+
+// CheckArmoredDetachedSignature performs the same actions as
+// CheckDetachedSignature but expects the signature to be armored.
+func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
+ body, err := readArmored(signature, SignatureType)
+ if err != nil {
+ return
+ }
+
+ return CheckDetachedSignature(keyring, signed, body, config)
+}
+
+// checkMessageSignatureDetails returns an error if:
+// - The signature (or one of the binding signatures mentioned below)
+// has a unknown critical notation data subpacket
+// - The primary key of the signing entity is revoked
+// - The primary identity is revoked
+// - The signature is expired
+// - The primary key of the signing entity is expired according to the
+// primary identity binding signature
+//
+// ... or, if the signature was signed by a subkey and:
+// - The signing subkey is revoked
+// - The signing subkey is expired according to the subkey binding signature
+// - The signing subkey binding signature is expired
+// - The signing subkey cross-signature is expired
+//
+// NOTE: The order of these checks is important, as the caller may choose to
+// ignore ErrSignatureExpired or ErrKeyExpired errors, but should never
+// ignore any other errors.
+func checkMessageSignatureDetails(key *Key, signature *packet.Signature, config *packet.Config) error {
+ now := config.Now()
+ primarySelfSignature, primaryIdentity := key.Entity.PrimarySelfSignature()
+ signedBySubKey := key.PublicKey != key.Entity.PrimaryKey
+ sigsToCheck := []*packet.Signature{signature, primarySelfSignature}
+ if signedBySubKey {
+ sigsToCheck = append(sigsToCheck, key.SelfSignature, key.SelfSignature.EmbeddedSignature)
+ }
+ for _, sig := range sigsToCheck {
+ for _, notation := range sig.Notations {
+ if notation.IsCritical && !config.KnownNotation(notation.Name) {
+ return errors.SignatureError("unknown critical notation: " + notation.Name)
+ }
+ }
+ }
+ if key.Entity.Revoked(now) || // primary key is revoked
+ (signedBySubKey && key.Revoked(now)) || // subkey is revoked
+ (primaryIdentity != nil && primaryIdentity.Revoked(now)) { // primary identity is revoked for v4
+ return errors.ErrKeyRevoked
+ }
+ if key.Entity.PrimaryKey.KeyExpired(primarySelfSignature, now) { // primary key is expired
+ return errors.ErrKeyExpired
+ }
+ if signedBySubKey {
+ if key.PublicKey.KeyExpired(key.SelfSignature, now) { // subkey is expired
+ return errors.ErrKeyExpired
+ }
+ }
+ for _, sig := range sigsToCheck {
+ if sig.SigExpired(now) { // any of the relevant signatures are expired
+ return errors.ErrSignatureExpired
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
new file mode 100644
index 0000000000..670d60226a
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
@@ -0,0 +1,457 @@
+package openpgp
+
+const testKey1KeyId uint64 = 0xA34D7E18C20C31BB
+const testKey3KeyId uint64 = 0x338934250CCC0360
+const testKeyP256KeyId uint64 = 0xd44a2c495918513e
+
+const signedInput = "Signed message\nline 2\nline 3\n"
+const signedTextInput = "Signed message\r\nline 2\r\nline 3\r\n"
+
+const recipientUnspecifiedHex = "848c0300000000000000000103ff62d4d578d03cf40c3da998dfe216c074fa6ddec5e31c197c9666ba292830d91d18716a80f699f9d897389a90e6d62d0238f5f07a5248073c0f24920e4bc4a30c2d17ee4e0cae7c3d4aaa4e8dced50e3010a80ee692175fa0385f62ecca4b56ee6e9980aa3ec51b61b077096ac9e800edaf161268593eedb6cc7027ff5cb32745d250010d407a6221ae22ef18469b444f2822478c4d190b24d36371a95cb40087cdd42d9399c3d06a53c0673349bfb607927f20d1e122bde1e2bf3aa6cae6edf489629bcaa0689539ae3b718914d88ededc3b"
+
+const detachedSignatureHex = "889c04000102000605024d449cd1000a0910a34d7e18c20c31bb167603ff57718d09f28a519fdc7b5a68b6a3336da04df85e38c5cd5d5bd2092fa4629848a33d85b1729402a2aab39c3ac19f9d573f773cc62c264dc924c067a79dfd8a863ae06c7c8686120760749f5fd9b1e03a64d20a7df3446ddc8f0aeadeaeba7cbaee5c1e366d65b6a0c6cc749bcb912d2f15013f812795c2e29eb7f7b77f39ce77"
+
+const detachedSignatureTextHex = "889c04010102000605024d449d21000a0910a34d7e18c20c31bbc8c60400a24fbef7342603a41cb1165767bd18985d015fb72fe05db42db36cfb2f1d455967f1e491194fbf6cf88146222b23bf6ffbd50d17598d976a0417d3192ff9cc0034fd00f287b02e90418bbefe609484b09231e4e7a5f3562e199bf39909ab5276c4d37382fe088f6b5c3426fc1052865da8b3ab158672d58b6264b10823dc4b39"
+
+const detachedSignatureDSAHex = "884604001102000605024d6c4eac000a0910338934250ccc0360f18d00a087d743d6405ed7b87755476629600b8b694a39e900a0abff8126f46faf1547c1743c37b21b4ea15b8f83"
+
+const detachedSignatureP256Hex = "885e0400130a0006050256e5bb00000a0910d44a2c495918513edef001009841a4f792beb0befccb35c8838a6a87d9b936beaa86db6745ddc7b045eee0cf00fd1ac1f78306b17e965935dd3f8bae4587a76587e4af231efe19cc4011a8434817"
+
+// The plaintext is https://www.gutenberg.org/cache/epub/1080/pg1080.txt
+const modestProposalSha512 = "lbbrB1+WP3T9AaC9OQqBdOcCjgeEQadlulXsNPgVx0tyqPzDHwUugZ2gE7V0ESKAw6kAVfgkcuvfgxAAGaeHtw=="
+
+const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b0020003b88d044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f0011010001889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab0020003988d044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b0020003b88d044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020003"
+
+const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
+
+const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
+
+const ed25519wX25519Key = "c54b0663877fe31b00000020f94da7bb48d60a61e567706a6587d0331999bb9d891a08242ead84543df895a3001972817b12be707e8d5f586ce61361201d344eb266a2c82fde6835762b65b0b7c2b1061f1b0a00000042058263877fe3030b090705150a0e080c021600029b03021e09222106cb186c4f0609a697e4d52dfa6c722b0c1f1e27c18a56708f6525ec27bad9acc905270902070200000000ad2820103e2d7d227ec0e6d7ce4471db36bfc97083253690271498a7ef0576c07faae14585b3b903b0127ec4fda2f023045a2ec76bcb4f9571a9651e14aee1137a1d668442c88f951e33c4ffd33fb9a17d511eed758fc6d9cc50cb5fd793b2039d5804c74b0663877fe319000000208693248367f9e5015db922f8f48095dda784987f2d5985b12fbad16caf5e4435004d600a4f794d44775c57a26e0feefed558e9afffd6ad0d582d57fb2ba2dcedb8c29b06181b0a0000002c050263877fe322a106cb186c4f0609a697e4d52dfa6c722b0c1f1e27c18a56708f6525ec27bad9acc9021b0c00000000defa20a6e9186d9d5935fc8fe56314cdb527486a5a5120f9b762a235a729f039010a56b89c658568341fbef3b894e9834ad9bc72afae2f4c9c47a43855e65f1cb0a3f77bbc5f61085c1f8249fe4e7ca59af5f0bcee9398e0fa8d76e522e1d8ab42bb0d"
+
+const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
+
+const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
+
+const signedEncryptedMessageHex = "c18c032a67d68660df41c70103ff5a84c9a72f80e74ef0384c2d6a9ebfe2b09e06a8f298394f6d2abf174e40934ab0ec01fb2d0ddf21211c6fe13eb238563663b017a6b44edca552eb4736c4b7dc6ed907dd9e12a21b51b64b46f902f76fb7aaf805c1db8070574d8d0431a23e324a750f77fb72340a17a42300ee4ca8207301e95a731da229a63ab9c6b44541fbd2c11d016d810b3b3b2b38f15b5b40f0a4910332829c2062f1f7cc61f5b03677d73c54cafa1004ced41f315d46444946faae571d6f426e6dbd45d9780eb466df042005298adabf7ce0ef766dfeb94cd449c7ed0046c880339599c4711af073ce649b1e237c40b50a5536283e03bdbb7afad78bd08707715c67fb43295f905b4c479178809d429a8e167a9a8c6dfd8ab20b4edebdc38d6dec879a3202e1b752690d9bb5b0c07c5a227c79cc200e713a99251a4219d62ad5556900cf69bd384b6c8e726c7be267471d0d23af956da165af4af757246c2ebcc302b39e8ef2fccb4971b234fcda22d759ddb20e27269ee7f7fe67898a9de721bfa02ab0becaa046d00ea16cb1afc4e2eab40d0ac17121c565686e5cbd0cbdfbd9d6db5c70278b9c9db5a83176d04f61fbfbc4471d721340ede2746e5c312ded4f26787985af92b64fae3f253dbdde97f6a5e1996fd4d865599e32ff76325d3e9abe93184c02988ee89a4504356a4ef3b9b7a57cbb9637ca90af34a7676b9ef559325c3cca4e29d69fec1887f5440bb101361d744ad292a8547f22b4f22b419a42aa836169b89190f46d9560824cb2ac6e8771de8223216a5e647e132ab9eebcba89569ab339cb1c3d70fe806b31f4f4c600b4103b8d7583ebff16e43dcda551e6530f975122eb8b29"
+
+const verifiedSignatureEncryptedMessageHex = "c2b304000108000605026048f6d600210910a34d7e18c20c31bb1621045fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb9a3b0400a32ddac1af259c1b0abab0041327ea04970944401978fb647dd1cf9aba4f164e43f0d8a9389501886474bdd4a6e77f6aea945c07dfbf87743835b44cc2c39a1f9aeecfa83135abc92e18e50396f2e6a06c44e0188b0081effbfb4160d28f118d4ff73dd199a102e47cffd8c7ff2bacd83ae72b5820c021a486766dd587b5da61"
+
+const unverifiedSignatureEncryptedMessageHex = "c2b304000108000605026048f6d600210910a34d7e18c20c31bb1621045fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb9a3b0400a32ddac1af259c1b0abab0041327ea04970944401978fb647dd1cf9aba4f164e43f0d8a9389501886474bdd4a6e77f6aea945c07dfbf87743835b44cc2c39a1f9aeecfa83135abc92e18e50396f2e6a06c44e0188b0081effbfb4160d28f118d4ff73dd199a102e47cffd8c7ff2bacd83ae72b5820c021a486766dd587b5da61"
+
+const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
+
+const signatureEncryptedMessage2Hex = "c24604001102000605024dfd0166000a091033af447ccd759b09bae600a096ec5e63ecf0a403085e10f75cc3bab327663282009f51fad9df457ed8d2b70d8a73c76e0443eac0f377"
+
+const symmetricallyEncryptedCompressedHex = "c32e040903085a357c1a7b5614ed00cc0d1d92f428162058b3f558a0fb0980d221ebac6c97d5eda4e0fe32f6e706e94dd263012d6ca1ef8c4bbd324098225e603a10c85ebf09cbf7b5aeeb5ce46381a52edc51038b76a8454483be74e6dcd1e50d5689a8ae7eceaeefed98a0023d49b22eb1f65c2aa1ef1783bb5e1995713b0457102ec3c3075fe871267ffa4b686ad5d52000d857"
+
+const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const dsaTestKeyPrivateHex = "9501bb044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4d00009f592e0619d823953577d4503061706843317e4fee083db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const p256TestKeyHex = "98520456e5b83813082a8648ce3d030107020304a2072cd6d21321266c758cc5b83fab0510f751cb8d91897cddb7047d8d6f185546e2107111b0a95cb8ef063c33245502af7a65f004d5919d93ee74eb71a66253b424502d3235362054657374204b6579203c696e76616c6964406578616d706c652e636f6d3e8879041313080021050256e5b838021b03050b09080702061508090a0b020416020301021e01021780000a0910d44a2c495918513e54e50100dfa64f97d9b47766fc1943c6314ba3f2b2a103d71ad286dc5b1efb96a345b0c80100dbc8150b54241f559da6ef4baacea6d31902b4f4b1bdc09b34bf0502334b7754b8560456e5b83812082a8648ce3d030107020304bfe3cea9cee13486f8d518aa487fecab451f25467d2bf08e58f63e5fa525d5482133e6a79299c274b068ef0be448152ad65cf11cf764348588ca4f6a0bcf22b6030108078861041813080009050256e5b838021b0c000a0910d44a2c495918513e4a4800ff49d589fa64024ad30be363a032e3a0e0e6f5db56ba4c73db850518bf0121b8f20100fd78e065f4c70ea5be9df319ea67e493b936fc78da834a71828043d3154af56e"
+
+const p256TestKeyPrivateHex = "94a50456e5b83813082a8648ce3d030107020304a2072cd6d21321266c758cc5b83fab0510f751cb8d91897cddb7047d8d6f185546e2107111b0a95cb8ef063c33245502af7a65f004d5919d93ee74eb71a66253fe070302f0c2bfb0b6c30f87ee1599472b8636477eab23ced13b271886a4b50ed34c9d8436af5af5b8f88921f0efba6ef8c37c459bbb88bc1c6a13bbd25c4ce9b1e97679569ee77645d469bf4b43de637f5561b424502d3235362054657374204b6579203c696e76616c6964406578616d706c652e636f6d3e8879041313080021050256e5b838021b03050b09080702061508090a0b020416020301021e01021780000a0910d44a2c495918513e54e50100dfa64f97d9b47766fc1943c6314ba3f2b2a103d71ad286dc5b1efb96a345b0c80100dbc8150b54241f559da6ef4baacea6d31902b4f4b1bdc09b34bf0502334b77549ca90456e5b83812082a8648ce3d030107020304bfe3cea9cee13486f8d518aa487fecab451f25467d2bf08e58f63e5fa525d5482133e6a79299c274b068ef0be448152ad65cf11cf764348588ca4f6a0bcf22b603010807fe0703027510012471a603cfee2968dce19f732721ddf03e966fd133b4e3c7a685b788705cbc46fb026dc94724b830c9edbaecd2fb2c662f23169516cacd1fe423f0475c364ecc10abcabcfd4bbbda1a36a1bd8861041813080009050256e5b838021b0c000a0910d44a2c495918513e4a4800ff49d589fa64024ad30be363a032e3a0e0e6f5db56ba4c73db850518bf0121b8f20100fd78e065f4c70ea5be9df319ea67e493b936fc78da834a71828043d3154af56e"
+
+const armoredPrivateKeyBlock = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
+idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
+vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
+AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
+0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
+IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
+VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
+gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
+TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
+q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
+dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
+CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
+ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
+eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
+AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
+bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
+/UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
+A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
+TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
+lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
+rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
+oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
+QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
+nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
+AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
+BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
+AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
+VrM0m72/jnpKo04=
+=zNCn
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const e2ePublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Charset: UTF-8
+
+xv8AAABSBAAAAAATCCqGSM49AwEHAgME1LRoXSpOxtHXDUdmuvzchyg6005qIBJ4
+sfaSxX7QgH9RV2ONUhC+WiayCNADq+UMzuR/vunSr4aQffXvuGnR383/AAAAFDxk
+Z2lsQHlhaG9vLWluYy5jb20+wv8AAACGBBATCAA4/wAAAAWCVGvAG/8AAAACiwn/
+AAAACZC2VkQCOjdvYf8AAAAFlQgJCgv/AAAAA5YBAv8AAAACngEAAE1BAP0X8veD
+24IjmI5/C6ZAfVNXxgZZFhTAACFX75jUA3oD6AEAzoSwKf1aqH6oq62qhCN/pekX
++WAsVMBhNwzLpqtCRjLO/wAAAFYEAAAAABIIKoZIzj0DAQcCAwT50ain7vXiIRv8
+B1DO3x3cE/aattZ5sHNixJzRCXi2vQIA5QmOxZ6b5jjUekNbdHG3SZi1a2Ak5mfX
+fRxC/5VGAwEIB8L/AAAAZQQYEwgAGP8AAAAFglRrwBz/AAAACZC2VkQCOjdvYQAA
+FJAA9isX3xtGyMLYwp2F3nXm7QEdY5bq5VUcD/RJlj792VwA/1wH0pCzVLl4Q9F9
+ex7En5r7rHR5xwX82Msc+Rq9dSyO
+=7MrZ
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const dsaKeyWithSHA512 = `9901a2044f04b07f110400db244efecc7316553ee08d179972aab87bb1214de7692593fcf5b6feb1c80fba268722dd464748539b85b81d574cd2d7ad0ca2444de4d849b8756bad7768c486c83a824f9bba4af773d11742bdfb4ac3b89ef8cc9452d4aad31a37e4b630d33927bff68e879284a1672659b8b298222fc68f370f3e24dccacc4a862442b9438b00a0ea444a24088dc23e26df7daf8f43cba3bffc4fe703fe3d6cd7fdca199d54ed8ae501c30e3ec7871ea9cdd4cf63cfe6fc82281d70a5b8bb493f922cd99fba5f088935596af087c8d818d5ec4d0b9afa7f070b3d7c1dd32a84fca08d8280b4890c8da1dde334de8e3cad8450eed2a4a4fcc2db7b8e5528b869a74a7f0189e11ef097ef1253582348de072bb07a9fa8ab838e993cef0ee203ff49298723e2d1f549b00559f886cd417a41692ce58d0ac1307dc71d85a8af21b0cf6eaa14baf2922d3a70389bedf17cc514ba0febbd107675a372fe84b90162a9e88b14d4b1c6be855b96b33fb198c46f058568817780435b6936167ebb3724b680f32bf27382ada2e37a879b3d9de2abe0c3f399350afd1ad438883f4791e2e3b4184453412068617368207472756e636174696f6e207465737488620413110a002205024f04b07f021b03060b090807030206150802090a0b0416020301021e01021780000a0910ef20e0cefca131581318009e2bf3bf047a44d75a9bacd00161ee04d435522397009a03a60d51bd8a568c6c021c8d7cf1be8d990d6417b0020003`
+
+const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const rsaSignatureBadMPIlength = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000`
+
+const keyV4forVerifyingSignedMessageV3 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: GPGTools - https://gpgtools.org
+
+mI0EVfxoFQEEAMBIqmbDfYygcvP6Phr1wr1XI41IF7Qixqybs/foBF8qqblD9gIY
+BKpXjnBOtbkcVOJ0nljd3/sQIfH4E0vQwK5/4YRQSI59eKOqd6Fx+fWQOLG+uu6z
+tewpeCj9LLHvibx/Sc7VWRnrznia6ftrXxJ/wHMezSab3tnGC0YPVdGNABEBAAG0
+JEdvY3J5cHRvIFRlc3QgS2V5IDx0aGVtYXhAZ21haWwuY29tPoi5BBMBCgAjBQJV
+/GgVAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQeXnQmhdGW9PFVAP+
+K7TU0qX5ArvIONIxh/WAweyOk884c5cE8f+3NOPOOCRGyVy0FId5A7MmD5GOQh4H
+JseOZVEVCqlmngEvtHZb3U1VYtVGE5WZ+6rQhGsMcWP5qaT4soYwMBlSYxgYwQcx
+YhN9qOr292f9j2Y//TTIJmZT4Oa+lMxhWdqTfX+qMgG4jQRV/GgVAQQArhFSiij1
+b+hT3dnapbEU+23Z1yTu1DfF6zsxQ4XQWEV3eR8v+8mEDDNcz8oyyF56k6UQ3rXi
+UMTIwRDg4V6SbZmaFbZYCOwp/EmXJ3rfhm7z7yzXj2OFN22luuqbyVhuL7LRdB0M
+pxgmjXb4tTvfgKd26x34S+QqUJ7W6uprY4sAEQEAAYifBBgBCgAJBQJV/GgVAhsM
+AAoJEHl50JoXRlvT7y8D/02ckx4OMkKBZo7viyrBw0MLG92i+DC2bs35PooHR6zz
+786mitjOp5z2QWNLBvxC70S0qVfCIz8jKupO1J6rq6Z8CcbLF3qjm6h1omUBf8Nd
+EfXKD2/2HV6zMKVknnKzIEzauh+eCKS2CeJUSSSryap/QLVAjRnckaES/OsEWhNB
+=RZia
+-----END PGP PUBLIC KEY BLOCK-----
+`
+
+const signedMessageV3 = `-----BEGIN PGP MESSAGE-----
+Comment: GPGTools - https://gpgtools.org
+
+owGbwMvMwMVYWXlhlrhb9GXG03JJDKF/MtxDMjKLFYAoUaEktbhEITe1uDgxPVWP
+q5NhKjMrWAVcC9evD8z/bF/uWNjqtk/X3y5/38XGRQHm/57rrDRYuGnTw597Xqka
+uM3137/hH3Os+Jf2dc0fXOITKwJvXJvecPVs0ta+Vg7ZO1MLn8w58Xx+6L58mbka
+DGHyU9yTueZE8D+QF/Tz28Y78dqtF56R1VPn9Xw4uJqrWYdd7b3vIZ1V6R4Nh05d
+iT57d/OhWwA=
+=hG7R
+-----END PGP MESSAGE-----
+`
+
+// https://mailarchive.ietf.org/arch/msg/openpgp/9SheW_LENE0Kxf7haNllovPyAdY/
+const v5PrivKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lGEFXJH05BYAAAAtCSsGAQQB2kcPAQEHQFhZlVcVVtwf+21xNQPX+ecMJJBL0MPd
+fj75iux+my8QAAAAAAAiAQCHZ1SnSUmWqxEsoI6facIVZQu6mph3cBFzzTvcm5lA
+Ng5ctBhlbW1hLmdvbGRtYW5AZXhhbXBsZS5uZXSIlgUTFggASCIhBRk0e8mHJGQC
+X5nfPsLgAA7ZiEiS4fez6kyUAJFZVptUBQJckfTkAhsDBQsJCAcCAyICAQYVCgkI
+CwIEFgIDAQIeBwIXgAAA9cAA/jiR3yMsZMeEQ40u6uzEoXa6UXeV/S3wwJAXRJy9
+M8s0AP9vuL/7AyTfFXwwzSjDnYmzS0qAhbLDQ643N+MXGBJ2BZxmBVyR9OQSAAAA
+MgorBgEEAZdVAQUBAQdA+nysrzml2UCweAqtpDuncSPlvrcBWKU0yfU0YvYWWAoD
+AQgHAAAAAAAiAP9OdAPppjU1WwpqjIItkxr+VPQRT8Zm/Riw7U3F6v3OiBFHiHoF
+GBYIACwiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACRWVabVAUCXJH05AIb
+DAAAOSQBAP4BOOIR/sGLNMOfeb5fPs/02QMieoiSjIBnijhob2U5AQC+RtOHCHx7
+TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw==
+=IiS2
+-----END PGP PRIVATE KEY BLOCK-----`
+
+// See OpenPGP crypto refresh Section A.3.
+const v6PrivKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----`
+
+// See OpenPGP crypto refresh merge request:
+// https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/304
+const v6PrivKeyMsg = `-----BEGIN PGP MESSAGE-----
+
+wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
+WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
+aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
+yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
+bhF30A+IitsxxA==
+-----END PGP MESSAGE-----`
+
+// See OpenPGP crypto refresh merge request:
+// https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/305
+const v6PrivKeyInlineSignMsg = `-----BEGIN PGP MESSAGE-----
+
+wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
+WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
+aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
+yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
+bhF30A+IitsxxA==
+-----END PGP MESSAGE-----`
+
+// See https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/274
+// decryption password: "correct horse battery staple"
+const v6ArgonSealedPrivKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYIGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laP9JgkC
+FARdb9ccngltHraRe25uHuyuAQQVtKipJ0+r5jL4dacGWSAheCWPpITYiyfyIOPS
+3gIDyg8f7strd1OB4+LZsUhcIjOMpVHgmiY/IutJkulneoBYwrEGHxsKAAAAQgWC
+Y4d/4wMLCQcFFQoOCAwCFgACmwMCHgkiIQbLGGxPBgmml+TVLfpscisMHx4nwYpW
+cI9lJewnutmsyQUnCQIHAgAAAACtKCAQPi19In7A5tfORHHbNr/JcIMlNpAnFJin
+7wV2wH+q4UWFs7kDsBJ+xP2i8CMEWi7Ha8tPlXGpZR4UruETeh1mhELIj5UeM8T/
+0z+5oX1RHu11j8bZzFDLX9eTsgOdWATHggZjh3/jGQAAACCGkySDZ/nlAV25Ivj0
+gJXdp4SYfy1ZhbEvutFsr15ENf0mCQIUBA5hhGgp2oaavg6mFUXcFMwBBBUuE8qf
+9Ock+xwusd+GAglBr5LVyr/lup3xxQvHXFSjjA2haXfoN6xUGRdDEHI6+uevKjVR
+v5oAxgu7eJpaXNjCmwYYGwoAAAAsBYJjh3/jApsMIiEGyxhsTwYJppfk1S36bHIr
+DB8eJ8GKVnCPZSXsJ7rZrMkAAAAABAEgpukYbZ1ZNfyP5WMUzbUnSGpaUSD5t2Ki
+Nacp8DkBClZRa2c3AMQzSDXa9jGhYzxjzVb5scHDzTkjyRZWRdTq8U6L4da+/+Kt
+ruh8m7Xo2ehSSFyWRSuTSZe5tm/KXgYG
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const v4Key25519 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUkEZB3qzRto01j2k2pwN5ux9w70stPinAdXULLr20CRW7U7h2GSeACch0M+
+qzQg8yjFQ8VBvu3uwgKH9senoHmj72lLSCLTmhFKzQR0ZXN0wogEEBsIAD4F
+gmQd6s0ECwkHCAmQIf45+TuC+xMDFQgKBBYAAgECGQECmwMCHgEWIQSWEzMi
+jJUHvyIbVKIh/jn5O4L7EwAAUhaHNlgudvxARdPPETUzVgjuWi+YIz8w1xIb
+lHQMvIrbe2sGCQIethpWofd0x7DHuv/ciHg+EoxJ/Td6h4pWtIoKx0kEZB3q
+zRm4CyA7quliq7yx08AoOqHTuuCgvpkSdEhpp3pEyejQOgBo0p6ywIiLPllY
+0t+jpNspHpAGfXID6oqjpYuJw3AfVRBlwnQEGBsIACoFgmQd6s0JkCH+Ofk7
+gvsTApsMFiEElhMzIoyVB78iG1SiIf45+TuC+xMAAGgQuN9G73446ykvJ/mL
+sCZ7zGFId2gBd1EnG0FTC4npfOKpck0X8dngByrCxU8LDSfvjsEp/xDAiKsQ
+aU71tdtNBQ==
+=e7jT
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const keyWithExpiredCrossSig = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xsDNBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv
+/seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz
+/56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/
+5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3
+X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv
+9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0
+qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb
+SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb
+vLIwa3T4CyshfT0AEQEAAc0hQm9iIEJhYmJhZ2UgPGJvYkBvcGVucGdwLmV4YW1w
+bGU+wsEABBMBCgATBYJeO2eVAgsJAxUICgKbAQIeAQAhCRD7/MgqAV5zMBYhBNGm
+bhojsYLJmA94jPv8yCoBXnMwKWUMAJ3FKZfJ2mXvh+GFqgymvK4NoKkDRPB0CbUN
+aDdG7ZOizQrWXo7Da2MYIZ6eZUDqBKLdhZ5gZfVnisDfu/yeCgpENaKib1MPHpA8
+nZQjnPejbBDomNqY8HRzr5jvXNlwywBpjWGtegCKUY9xbSynjbfzIlMrWL4S+Rfl
++bOOQKRyYJWXmECmVyqY8cz2VUYmETjNcwC8VCDUxQnhtcCJ7Aej22hfYwVEPb/J
+BsJBPq8WECCiGfJ9Y2y6TF+62KzG9Kfs5hqUeHhQy8V4TSi479ewwL7DH86XmIIK
+chSANBS+7iyMtctjNZfmF9zYdGJFvjI/mbBR/lK66E515Inuf75XnL8hqlXuwqvG
+ni+i03Aet1DzULZEIio4uIU6ioc1lGO9h7K2Xn4S7QQH1QoISNMWqXibUR0RCGjw
+FsEDTt2QwJl8XXxoJCooM7BCcCQo+rMNVUHDjIwrdoQjPld3YZsUQQRcqH6bLuln
+cfn5ufl8zTGWKydoj/iTz8KcjZ7w187AzQRdpZzyAQwA1jC/XGxjK6ddgrRfW9j+
+s/U00++EvIsgTs2kr3Rg0GP7FLWV0YNtR1mpl55/bEl7yAxCDTkOgPUMXcaKlnQh
+6zrlt6H53mF6Bvs3inOHQvOsGtU0dqvb1vkTF0juLiJgPlM7pWv+pNQ6IA39vKoQ
+sTMBv4v5vYNXP9GgKbg8inUNT17BxzZYHfw5+q63ectgDm2on1e8CIRCZ76oBVwz
+dkVxoy3gjh1eENlk2D4P0uJNZzF1Q8GV67yLANGMCDICE/OkWn6daipYDzW4iJQt
+YPUWP4hWhjdm+CK+hg6IQUEn2Vtvi16D2blRP8BpUNNa4fNuylWVuJV76rIHvsLZ
+1pbM3LHpRgE8s6jivS3Rz3WRs0TmWCNnvHPqWizQ3VTy+r3UQVJ5AmhJDrZdZq9i
+aUIuZ01PoE1+CHiJwuxPtWvVAxf2POcm1M/F1fK1J0e+lKlQuyonTXqXR22Y41wr
+fP2aPk3nPSTW2DUAf3vRMZg57ZpRxLEhEMxcM4/LMR+PABEBAAHCwrIEGAEKAAkF
+gl8sAVYCmwIB3QkQ+/zIKgFeczDA+qAEGQEKAAwFgl47Z5UFgwB4TOAAIQkQfC+q
+Tfk8N7IWIQQd3OFfCSF87i87N2B8L6pN+Tw3st58C/0exp0X2U4LqicSHEOSqHZj
+jiysdqIELHGyo5DSPv92UFPp36aqjF9OFgtNNwSa56fmAVCD4+hor/fKARRIeIjF
+qdIC5Y/9a4B10NQFJa5lsvB38x/d39LI2kEoglZnqWgdJskROo3vNQF4KlIcm6FH
+dn4WI8UkC5oUUcrpZVMSKoacIaxLwqnXT42nIVgYYuqrd/ZagZZjG5WlrTOd5+NI
+zi/l0fWProcPHGLjmAh4Thu8i7omtVw1nQaMnq9I77ffg3cPDgXknYrLL+q8xXh/
+0mEJyIhnmPwllWCSZuLv9DrD5pOexFfdlwXhf6cLzNpW6QhXD/Tf5KrqIPr9aOv8
+9xaEEXWh0vEby2kIsI2++ft+vfdIyxYw/wKqx0awTSnuBV1rG3z1dswX4BfoY66x
+Bz3KOVqlz9+mG/FTRQwrgPvR+qgLCHbuotxoGN7fzW+PI75hQG5JQAqhsC9sHjQH
+UrI21/VUNwzfw3v5pYsWuFb5bdQ3ASJetICQiMy7IW8WIQTRpm4aI7GCyZgPeIz7
+/MgqAV5zMG6/C/wLpPl/9e6Hf5wmXIUwpZNQbNZvpiCcyx9sXsHXaycOQVxn3McZ
+nYOUP9/mobl1tIeDQyTNbkxWjU0zzJl8XQsDZerb5098pg+x7oGIL7M1vn5s5JMl
+owROourqF88JEtOBxLMxlAM7X4hB48xKQ3Hu9hS1GdnqLKki4MqRGl4l5FUwyGOM
+GjyS3TzkfiDJNwQxybQiC9n57ij20ieNyLfuWCMLcNNnZUgZtnF6wCctoq/0ZIWu
+a7nvuA/XC2WW9YjEJJiWdy5109pqac+qWiY11HWy/nms4gpMdxVpT0RhrKGWq4o0
+M5q3ZElOoeN70UO3OSbU5EVrG7gB1GuwF9mTHUVlV0veSTw0axkta3FGT//XfSpD
+lRrCkyLzwq0M+UUHQAuYpAfobDlDdnxxOD2jm5GyTzak3GSVFfjW09QFVO6HlGp5
+01/jtzkUiS6nwoHHkfnyn0beZuR8X6KlcrzLB0VFgQFLmkSM9cSOgYhD0PTu9aHb
+hW1Hj9AO8lzggBQ=
+=Nt+N
+-----END PGP PUBLIC KEY BLOCK-----
+`
+
+const sigFromKeyWithExpiredCrossSig = `-----BEGIN PGP SIGNATURE-----
+
+wsDzBAABCgAGBYJfLAFsACEJEHwvqk35PDeyFiEEHdzhXwkhfO4vOzdgfC+qTfk8
+N7KiqwwAts4QGB7v9bABCC2qkTxJhmStC0wQMcHRcjL/qAiVnmasQWmvE9KVsdm3
+AaXd8mIx4a37/RRvr9dYrY2eE4uw72cMqPxNja2tvVXkHQvk1oEUqfkvbXs4ypKI
+NyeTWjXNOTZEbg0hbm3nMy+Wv7zgB1CEvAsEboLDJlhGqPcD+X8a6CJGrBGUBUrv
+KVmZr3U6vEzClz3DBLpoddCQseJRhT4YM1nKmBlZ5quh2LFgTSpajv5OsZheqt9y
+EZAPbqmLhDmWRQwGzkWHKceKS7nZ/ox2WK6OS7Ob8ZGZkM64iPo6/EGj5Yc19vQN
+AGiIaPEGszBBWlOpHTPhNm0LB0nMWqqaT87oNYwP8CQuuxDb6rKJ2lffCmZH27Lb
+UbQZcH8J+0UhpeaiadPZxH5ATJAcenmVtVVMLVOFnm+eIlxzov9ntpgGYt8hLdXB
+ITEG9mMgp3TGS9ZzSifMZ8UGtHdp9QdBg8NEVPFzDOMGxpc/Bftav7RRRuPiAER+
+7A5CBid5
+=aQkm
+-----END PGP SIGNATURE-----
+`
+
+const signedMessageWithCriticalNotation = `-----BEGIN PGP MESSAGE-----
+
+owGbwMvMwMH4oOW7S46CznTG09xJDDE3Wl1KUotLuDousDAwcjBYiSmyXL+48d6x
+U1PSGUxcj8IUszKBVMpMaWAAAgEGZpAeh9SKxNyCnFS95PzcytRiBi5OAZjyXXzM
+f8WYLqv7TXP61Sa4rqT12CI3xaN73YS2pt089f96odCKaEPnWJ3iSGmzJaW/ug10
+2Zo8Wj2k4s7t8wt4H3HtTu+y5UZfV3VOO+l//sdE/o+Lsub8FZH7/eOq7OnbNp4n
+vwjE8mqJXetNMfj8r2SCyvkEnlVRYR+/mnge+ib56FdJ8uKtqSxyvgA=
+=fRXs
+-----END PGP MESSAGE-----`
+
+const criticalNotationSigner = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+
+fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5
+GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0
+JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS
+YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6
+AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki
+Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf
+9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa
+JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag
+Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr
+woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb
+LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA
+SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP
+GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2
+bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X
+W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD
+AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY
+hz3tYjKhoFTKEIq3y3Pp
+=h/aX
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const keyv5Test = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Comment: Bob's OpenPGP Transferable Secret Key
+
+lQVYBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv
+/seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz
+/56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/
+5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3
+X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv
+9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0
+qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb
+SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb
+vLIwa3T4CyshfT0AEQEAAQAL/RZqbJW2IqQDCnJi4Ozm++gPqBPiX1RhTWSjwxfM
+cJKUZfzLj414rMKm6Jh1cwwGY9jekROhB9WmwaaKT8HtcIgrZNAlYzANGRCM4TLK
+3VskxfSwKKna8l+s+mZglqbAjUg3wmFuf9Tj2xcUZYmyRm1DEmcN2ZzpvRtHgX7z
+Wn1mAKUlSDJZSQks0zjuMNbupcpyJokdlkUg2+wBznBOTKzgMxVNC9b2g5/tMPUs
+hGGWmF1UH+7AHMTaS6dlmr2ZBIyogdnfUqdNg5sZwsxSNrbglKP4sqe7X61uEAIQ
+bD7rT3LonLbhkrj3I8wilUD8usIwt5IecoHhd9HziqZjRCc1BUBkboUEoyedbDV4
+i4qfsFZ6CEWoLuD5pW7dEp0M+WeuHXO164Rc+LnH6i1VQrpb1Okl4qO6ejIpIjBI
+1t3GshtUu/mwGBBxs60KBX5g77mFQ9lLCRj8lSYqOsHRKBhUp4qM869VA+fD0BRP
+fqPT0I9IH4Oa/A3jYJcg622GwQYA1LhnP208Waf6PkQSJ6kyr8ymY1yVh9VBE/g6
+fRDYA+pkqKnw9wfH2Qho3ysAA+OmVOX8Hldg+Pc0Zs0e5pCavb0En8iFLvTA0Q2E
+LR5rLue9uD7aFuKFU/VdcddY9Ww/vo4k5p/tVGp7F8RYCFn9rSjIWbfvvZi1q5Tx
++akoZbga+4qQ4WYzB/obdX6SCmi6BndcQ1QdjCCQU6gpYx0MddVERbIp9+2SXDyL
+hpxjSyz+RGsZi/9UAshT4txP4+MZBgDfK3ZqtW+h2/eMRxkANqOJpxSjMyLO/FXN
+WxzTDYeWtHNYiAlOwlQZEPOydZFty9IVzzNFQCIUCGjQ/nNyhw7adSgUk3+BXEx/
+MyJPYY0BYuhLxLYcrfQ9nrhaVKxRJj25SVHj2ASsiwGJRZW4CC3uw40OYxfKEvNC
+mer/VxM3kg8qqGf9KUzJ1dVdAvjyx2Hz6jY2qWCyRQ6IMjWHyd43C4r3jxooYKUC
+YnstRQyb/gCSKahveSEjo07CiXMr88UGALwzEr3npFAsPW3osGaFLj49y1oRe11E
+he9gCHFm+fuzbXrWmdPjYU5/ZdqdojzDqfu4ThfnipknpVUM1o6MQqkjM896FHm8
+zbKVFSMhEP6DPHSCexMFrrSgN03PdwHTO6iBaIBBFqmGY01tmJ03SxvSpiBPON9P
+NVvy/6UZFedTq8A07OUAxO62YUSNtT5pmK2vzs3SAZJmbFbMh+NN204TRI72GlqT
+t5hcfkuv8hrmwPS/ZR6q312mKQ6w/1pqO9qitCFCb2IgQmFiYmFnZSA8Ym9iQG9w
+ZW5wZ3AuZXhhbXBsZT6JAc4EEwEKADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgEC
+F4AWIQTRpm4aI7GCyZgPeIz7/MgqAV5zMAUCXaWe+gAKCRD7/MgqAV5zMG9sC/9U
+2T3RrqEbw533FPNfEflhEVRIZ8gDXKM8hU6cqqEzCmzZT6xYTe6sv4y+PJBGXJFX
+yhj0g6FDkSyboM5litOcTupURObVqMgA/Y4UKERznm4fzzH9qek85c4ljtLyNufe
+doL2pp3vkGtn7eD0QFRaLLmnxPKQ/TlZKdLE1G3u8Uot8QHicaR6GnAdc5UXQJE3
+BiV7jZuDyWmZ1cUNwJkKL6oRtp+ZNDOQCrLNLecKHcgCqrpjSQG5oouba1I1Q6Vl
+sP44dhA1nkmLHtxlTOzpeHj4jnk1FaXmyasurrrI5CgU/L2Oi39DGKTH/A/cywDN
+4ZplIQ9zR8enkbXquUZvFDe+Xz+6xRXtb5MwQyWODB3nHw85HocLwRoIN9WdQEI+
+L8a/56AuOwhs8llkSuiITjR7r9SgKJC2WlAHl7E8lhJ3VDW3ELC56KH308d6mwOG
+ZRAqIAKzM1T5FGjMBhq7ZV0eqdEntBh3EcOIfj2M8rg1MzJv+0mHZOIjByawikad
+BVgEXaWc8gEMANYwv1xsYyunXYK0X1vY/rP1NNPvhLyLIE7NpK90YNBj+xS1ldGD
+bUdZqZeef2xJe8gMQg05DoD1DF3GipZ0Ies65beh+d5hegb7N4pzh0LzrBrVNHar
+29b5ExdI7i4iYD5TO6Vr/qTUOiAN/byqELEzAb+L+b2DVz/RoCm4PIp1DU9ewcc2
+WB38Ofqut3nLYA5tqJ9XvAiEQme+qAVcM3ZFcaMt4I4dXhDZZNg+D9LiTWcxdUPB
+leu8iwDRjAgyAhPzpFp+nWoqWA81uIiULWD1Fj+IVoY3ZvgivoYOiEFBJ9lbb4te
+g9m5UT/AaVDTWuHzbspVlbiVe+qyB77C2daWzNyx6UYBPLOo4r0t0c91kbNE5lgj
+Z7xz6los0N1U8vq91EFSeQJoSQ62XWavYmlCLmdNT6BNfgh4icLsT7Vr1QMX9jzn
+JtTPxdXytSdHvpSpULsqJ016l0dtmONcK3z9mj5N5z0k1tg1AH970TGYOe2aUcSx
+IRDMXDOPyzEfjwARAQABAAv9F2CwsjS+Sjh1M1vegJbZjei4gF1HHpEM0K0PSXsp
+SfVvpR4AoSJ4He6CXSMWg0ot8XKtDuZoV9jnJaES5UL9pMAD7JwIOqZm/DYVJM5h
+OASCh1c356/wSbFbzRHPtUdZO9Q30WFNJM5pHbCJPjtNoRmRGkf71RxtvHBzy7np
+Ga+W6U/NVKHw0i0CYwMI0YlKDakYW3Pm+QL+gHZFvngGweTod0f9l2VLLAmeQR/c
++EZs7lNumhuZ8mXcwhUc9JQIhOkpO+wreDysEFkAcsKbkQP3UDUsA1gFx9pbMzT0
+tr1oZq2a4QBtxShHzP/ph7KLpN+6qtjks3xB/yjTgaGmtrwM8tSe0wD1RwXS+/1o
+BHpXTnQ7TfeOGUAu4KCoOQLv6ELpKWbRBLWuiPwMdbGpvVFALO8+kvKAg9/r+/ny
+zM2GQHY+J3Jh5JxPiJnHfXNZjIKLbFbIPdSKNyJBuazXW8xIa//mEHMI5OcvsZBK
+clAIp7LXzjEjKXIwHwDcTn9pBgDpdOKTHOtJ3JUKx0rWVsDH6wq6iKV/FTVSY5jl
+zN+puOEsskF1Lfxn9JsJihAVO3yNsp6RvkKtyNlFazaCVKtDAmkjoh60XNxcNRqr
+gCnwdpbgdHP6v/hvZY54ZaJjz6L2e8unNEkYLxDt8cmAyGPgH2XgL7giHIp9jrsQ
+aS381gnYwNX6wE1aEikgtY91nqJjwPlibF9avSyYQoMtEqM/1UjTjB2KdD/MitK5
+fP0VpvuXpNYZedmyq4UOMwdkiNMGAOrfmOeT0olgLrTMT5H97Cn3Yxbk13uXHNu/
+ZUZZNe8s+QtuLfUlKAJtLEUutN33TlWQY522FV0m17S+b80xJib3yZVJteVurrh5
+HSWHAM+zghQAvCesg5CLXa2dNMkTCmZKgCBvfDLZuZbjFwnwCI6u/NhOY9egKuUf
+SA/je/RXaT8m5VxLYMxwqQXKApzD87fv0tLPlVIEvjEsaf992tFEFSNPcG1l/jpd
+5AVXw6kKuf85UkJtYR1x2MkQDrqY1QX/XMw00kt8y9kMZUre19aCArcmor+hDhRJ
+E3Gt4QJrD9z/bICESw4b4z2DbgD/Xz9IXsA/r9cKiM1h5QMtXvuhyfVeM01enhxM
+GbOH3gjqqGNKysx0UODGEwr6AV9hAd8RWXMchJLaExK9J5SRawSg671ObAU24SdY
+vMQ9Z4kAQ2+1ReUZzf3ogSMRZtMT+d18gT6L90/y+APZIaoArLPhebIAGq39HLmJ
+26x3z0WAgrpA1kNsjXEXkoiZGPLKIGoe3hqJAbYEGAEKACAWIQTRpm4aI7GCyZgP
+eIz7/MgqAV5zMAUCXaWc8gIbDAAKCRD7/MgqAV5zMOn/C/9ugt+HZIwX308zI+QX
+c5vDLReuzmJ3ieE0DMO/uNSC+K1XEioSIZP91HeZJ2kbT9nn9fuReuoff0T0Dief
+rbwcIQQHFFkrqSp1K3VWmUGp2JrUsXFVdjy/fkBIjTd7c5boWljv/6wAsSfiv2V0
+JSM8EFU6TYXxswGjFVfc6X97tJNeIrXL+mpSmPPqy2bztcCCHkWS5lNLWQw+R7Vg
+71Fe6yBSNVrqC2/imYG2J9zlowjx1XU63Wdgqp2Wxt0l8OmsB/W80S1fRF5G4SDH
+s9HXglXXqPsBRZJYfP+VStm9L5P/sKjCcX6WtZR7yS6G8zj/X767MLK/djANvpPd
+NVniEke6hM3CNBXYPAMhQBMWhCulcoz+0lxi8L34rMN+Dsbma96psdUrn7uLaB91
+6we0CTfF8qqm7BsVAgalon/UUiuMY80U3ueoj3okiSTiHIjD/YtpXSPioC8nMng7
+xqAY9Bwizt4FWgXuLm1a4+So4V9j1TRCXd12Uc2l2RNmgDE=
+=miES
+-----END PGP PRIVATE KEY BLOCK-----
+`
+
+const certv5Test = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lGEFXJH05BYAAAAtCSsGAQQB2kcPAQEHQFhZlVcVVtwf+21xNQPX+ecMJJBL0MPd
+fj75iux+my8QAAAAAAAiAQCHZ1SnSUmWqxEsoI6facIVZQu6mph3cBFzzTvcm5lA
+Ng5ctBhlbW1hLmdvbGRtYW5AZXhhbXBsZS5uZXSIlgUTFggASCIhBRk0e8mHJGQC
+X5nfPsLgAA7ZiEiS4fez6kyUAJFZVptUBQJckfTkAhsDBQsJCAcCAyICAQYVCgkI
+CwIEFgIDAQIeBwIXgAAA9cAA/jiR3yMsZMeEQ40u6uzEoXa6UXeV/S3wwJAXRJy9
+M8s0AP9vuL/7AyTfFXwwzSjDnYmzS0qAhbLDQ643N+MXGBJ2BZxmBVyR9OQSAAAA
+MgorBgEEAZdVAQUBAQdA+nysrzml2UCweAqtpDuncSPlvrcBWKU0yfU0YvYWWAoD
+AQgHAAAAAAAiAP9OdAPppjU1WwpqjIItkxr+VPQRT8Zm/Riw7U3F6v3OiBFHiHoF
+GBYIACwiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACRWVabVAUCXJH05AIb
+DAAAOSQBAP4BOOIR/sGLNMOfeb5fPs/02QMieoiSjIBnijhob2U5AQC+RtOHCHx7
+TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw==
+=IiS2
+-----END PGP PRIVATE KEY BLOCK-----
+`
+
+const msgv5Test = `-----BEGIN PGP MESSAGE-----
+
+wcDMA3wvqk35PDeyAQv+PcQiLsoYTH30nJYQh3j3cJaO2+jErtVCrIQRIU0+
+rmgMddERYST4A9mA0DQIiTI4FQ0Lp440D3BWCgpq3LlNWewGzduaWwym5rN6
+cwHz5ccDqOcqbd9X0GXXGy/ZH/ljSgzuVMIytMAXKdF/vrRrVgH/+I7cxvm9
+HwnhjMN5dF0j4aEt996H2T7cbtzSr2GN9SWGW8Gyu7I8Zx73hgrGUI7gDiJB
+Afaff+P6hfkkHSGOItr94dde8J/7AUF4VEwwxdVVPvsNEFyvv6gRIbYtOCa2
+6RE6h1V/QTxW2O7zZgzWALrE2ui0oaYr9QuqQSssd9CdgExLfdPbI+3/ZAnE
+v31Idzpk3/6ILiakYHtXkElPXvf46mCNpobty8ysT34irF+fy3C1p3oGwAsx
+5VDV9OSFU6z5U+UPbSPYAy9rkc5ZssuIKxCER2oTvZ2L8Q5cfUvEUiJtRGGn
+CJlHrVDdp3FssKv2tlKgLkvxJLyoOjuEkj44H1qRk+D02FzmmUT/0sAHAYYx
+lTir6mjHeLpcGjn4waUuWIAJyph8SxUexP60bic0L0NBa6Qp5SxxijKsPIDb
+FPHxWwfJSDZRrgUyYT7089YFB/ZM4FHyH9TZcnxn0f0xIB7NS6YNDsxzN2zT
+EVEYf+De4qT/dQTsdww78Chtcv9JY9r2kDm77dk2MUGHL2j7n8jasbLtgA7h
+pn2DMIWLrGamMLWRmlwslolKr1sMV5x8w+5Ias6C33iBMl9phkg42an0gYmc
+byVJHvLO/XErtC+GNIJeMg==
+=liRq
+-----END PGP MESSAGE-----
+`
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
new file mode 100644
index 0000000000..6871b84fc9
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
@@ -0,0 +1,436 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package s2k implements the various OpenPGP string-to-key transforms as
+// specified in RFC 4800 section 3.7.1, and Argon2 specified in
+// draft-ietf-openpgp-crypto-refresh-08 section 3.7.1.4.
+package s2k // import "github.com/ProtonMail/go-crypto/openpgp/s2k"
+
+import (
+ "crypto"
+ "hash"
+ "io"
+ "strconv"
+
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+ "golang.org/x/crypto/argon2"
+)
+
+type Mode uint8
+
+// Defines the default S2KMode constants
+//
+// 0 (simple), 1(salted), 3(iterated), 4(argon2)
+const (
+ SimpleS2K Mode = 0
+ SaltedS2K Mode = 1
+ IteratedSaltedS2K Mode = 3
+ Argon2S2K Mode = 4
+ GnuS2K Mode = 101
+)
+
+const Argon2SaltSize int = 16
+
+// Params contains all the parameters of the s2k packet
+type Params struct {
+ // mode is the mode of s2k function.
+ // It can be 0 (simple), 1(salted), 3(iterated)
+ // 2(reserved) 100-110(private/experimental).
+ mode Mode
+ // hashId is the ID of the hash function used in any of the modes
+ hashId byte
+ // salt is a byte array to use as a salt in hashing process or argon2
+ saltBytes [Argon2SaltSize]byte
+ // countByte is used to determine how many rounds of hashing are to
+ // be performed in s2k mode 3. See RFC 4880 Section 3.7.1.3.
+ countByte byte
+ // passes is a parameter in Argon2 to determine the number of iterations
+ // See RFC the crypto refresh Section 3.7.1.4.
+ passes byte
+ // parallelism is a parameter in Argon2 to determine the degree of paralellism
+ // See RFC the crypto refresh Section 3.7.1.4.
+ parallelism byte
+ // memoryExp is a parameter in Argon2 to determine the memory usage
+ // i.e., 2 ** memoryExp kibibytes
+ // See RFC the crypto refresh Section 3.7.1.4.
+ memoryExp byte
+}
+
+// encodeCount converts an iterative "count" in the range 1024 to
+// 65011712, inclusive, to an encoded count. The return value is the
+// octet that is actually stored in the GPG file. encodeCount panics
+// if i is not in the above range (encodedCount above takes care to
+// pass i in the correct range). See RFC 4880 Section 3.7.7.1.
+func encodeCount(i int) uint8 {
+ if i < 65536 || i > 65011712 {
+ panic("count arg i outside the required range")
+ }
+
+ for encoded := 96; encoded < 256; encoded++ {
+ count := decodeCount(uint8(encoded))
+ if count >= i {
+ return uint8(encoded)
+ }
+ }
+
+ return 255
+}
+
+// decodeCount returns the s2k mode 3 iterative "count" corresponding to
+// the encoded octet c.
+func decodeCount(c uint8) int {
+ return (16 + int(c&15)) << (uint32(c>>4) + 6)
+}
+
+// encodeMemory converts the Argon2 "memory" in the range parallelism*8 to
+// 2**31, inclusive, to an encoded memory. The return value is the
+// octet that is actually stored in the GPG file. encodeMemory panics
+// if is not in the above range
+// See OpenPGP crypto refresh Section 3.7.1.4.
+func encodeMemory(memory uint32, parallelism uint8) uint8 {
+ if memory < (8*uint32(parallelism)) || memory > uint32(2147483648) {
+ panic("Memory argument memory is outside the required range")
+ }
+
+ for exp := 3; exp < 31; exp++ {
+ compare := decodeMemory(uint8(exp))
+ if compare >= memory {
+ return uint8(exp)
+ }
+ }
+
+ return 31
+}
+
+// decodeMemory computes the decoded memory in kibibytes as 2**memoryExponent
+func decodeMemory(memoryExponent uint8) uint32 {
+ return uint32(1) << memoryExponent
+}
+
+// Simple writes to out the result of computing the Simple S2K function (RFC
+// 4880, section 3.7.1.1) using the given hash and input passphrase.
+func Simple(out []byte, h hash.Hash, in []byte) {
+ Salted(out, h, in, nil)
+}
+
+var zero [1]byte
+
+// Salted writes to out the result of computing the Salted S2K function (RFC
+// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
+func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
+ done := 0
+ var digest []byte
+
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ h.Write(salt)
+ h.Write(in)
+ digest = h.Sum(digest[:0])
+ n := copy(out[done:], digest)
+ done += n
+ }
+}
+
+// Iterated writes to out the result of computing the Iterated and Salted S2K
+// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
+// salt and iteration count.
+func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
+ combined := make([]byte, len(in)+len(salt))
+ copy(combined, salt)
+ copy(combined[len(salt):], in)
+
+ if count < len(combined) {
+ count = len(combined)
+ }
+
+ done := 0
+ var digest []byte
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ written := 0
+ for written < count {
+ if written+len(combined) > count {
+ todo := count - written
+ h.Write(combined[:todo])
+ written = count
+ } else {
+ h.Write(combined)
+ written += len(combined)
+ }
+ }
+ digest = h.Sum(digest[:0])
+ n := copy(out[done:], digest)
+ done += n
+ }
+}
+
+// Argon2 writes to out the key derived from the password (in) with the Argon2
+// function (the crypto refresh, section 3.7.1.4)
+func Argon2(out []byte, in []byte, salt []byte, passes uint8, paralellism uint8, memoryExp uint8) {
+ key := argon2.IDKey(in, salt, uint32(passes), decodeMemory(memoryExp), paralellism, uint32(len(out)))
+ copy(out[:], key)
+}
+
+// Generate generates valid parameters from given configuration.
+// It will enforce the Iterated and Salted or Argon2 S2K method.
+func Generate(rand io.Reader, c *Config) (*Params, error) {
+ var params *Params
+ if c != nil && c.Mode() == Argon2S2K {
+ // handle Argon2 case
+ argonConfig := c.Argon2()
+ params = &Params{
+ mode: Argon2S2K,
+ passes: argonConfig.Passes(),
+ parallelism: argonConfig.Parallelism(),
+ memoryExp: argonConfig.EncodedMemory(),
+ }
+ } else if c != nil && c.PassphraseIsHighEntropy && c.Mode() == SaltedS2K { // Allow SaltedS2K if PassphraseIsHighEntropy
+ hashId, ok := algorithm.HashToHashId(c.hash())
+ if !ok {
+ return nil, errors.UnsupportedError("no such hash")
+ }
+
+ params = &Params{
+ mode: SaltedS2K,
+ hashId: hashId,
+ }
+ } else { // Enforce IteratedSaltedS2K method otherwise
+ hashId, ok := algorithm.HashToHashId(c.hash())
+ if !ok {
+ return nil, errors.UnsupportedError("no such hash")
+ }
+ if c != nil {
+ c.S2KMode = IteratedSaltedS2K
+ }
+ params = &Params{
+ mode: IteratedSaltedS2K,
+ hashId: hashId,
+ countByte: c.EncodedCount(),
+ }
+ }
+ if _, err := io.ReadFull(rand, params.salt()); err != nil {
+ return nil, err
+ }
+ return params, nil
+}
+
+// Parse reads a binary specification for a string-to-key transformation from r
+// and returns a function which performs that transform. If the S2K is a special
+// GNU extension that indicates that the private key is missing, then the error
+// returned is errors.ErrDummyPrivateKey.
+func Parse(r io.Reader) (f func(out, in []byte), err error) {
+ params, err := ParseIntoParams(r)
+ if err != nil {
+ return nil, err
+ }
+
+ return params.Function()
+}
+
+// ParseIntoParams reads a binary specification for a string-to-key
+// transformation from r and returns a struct describing the s2k parameters.
+func ParseIntoParams(r io.Reader) (params *Params, err error) {
+ var buf [Argon2SaltSize + 3]byte
+
+ _, err = io.ReadFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+
+ params = &Params{
+ mode: Mode(buf[0]),
+ }
+
+ switch params.mode {
+ case SimpleS2K:
+ _, err = io.ReadFull(r, buf[:1])
+ if err != nil {
+ return nil, err
+ }
+ params.hashId = buf[0]
+ return params, nil
+ case SaltedS2K:
+ _, err = io.ReadFull(r, buf[:9])
+ if err != nil {
+ return nil, err
+ }
+ params.hashId = buf[0]
+ copy(params.salt(), buf[1:9])
+ return params, nil
+ case IteratedSaltedS2K:
+ _, err = io.ReadFull(r, buf[:10])
+ if err != nil {
+ return nil, err
+ }
+ params.hashId = buf[0]
+ copy(params.salt(), buf[1:9])
+ params.countByte = buf[9]
+ return params, nil
+ case Argon2S2K:
+ _, err = io.ReadFull(r, buf[:Argon2SaltSize+3])
+ if err != nil {
+ return nil, err
+ }
+ copy(params.salt(), buf[:Argon2SaltSize])
+ params.passes = buf[Argon2SaltSize]
+ params.parallelism = buf[Argon2SaltSize+1]
+ params.memoryExp = buf[Argon2SaltSize+2]
+ if err := validateArgon2Params(params); err != nil {
+ return nil, err
+ }
+ return params, nil
+ case GnuS2K:
+ // This is a GNU extension. See
+ // https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109
+ if _, err = io.ReadFull(r, buf[:5]); err != nil {
+ return nil, err
+ }
+ params.hashId = buf[0]
+ if buf[1] == 'G' && buf[2] == 'N' && buf[3] == 'U' && buf[4] == 1 {
+ return params, nil
+ }
+ return nil, errors.UnsupportedError("GNU S2K extension")
+ }
+
+ return nil, errors.UnsupportedError("S2K function")
+}
+
+func (params *Params) Mode() Mode {
+ return params.mode
+}
+
+func (params *Params) Dummy() bool {
+ return params != nil && params.mode == GnuS2K
+}
+
+func (params *Params) salt() []byte {
+ switch params.mode {
+ case SaltedS2K, IteratedSaltedS2K:
+ return params.saltBytes[:8]
+ case Argon2S2K:
+ return params.saltBytes[:Argon2SaltSize]
+ default:
+ return nil
+ }
+}
+
+func (params *Params) Function() (f func(out, in []byte), err error) {
+ if params.Dummy() {
+ return nil, errors.ErrDummyPrivateKey("dummy key found")
+ }
+ var hashObj crypto.Hash
+ if params.mode != Argon2S2K {
+ var ok bool
+ hashObj, ok = algorithm.HashIdToHashWithSha1(params.hashId)
+ if !ok {
+ return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(params.hashId)))
+ }
+ if !hashObj.Available() {
+ return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashObj)))
+ }
+ }
+
+ switch params.mode {
+ case SimpleS2K:
+ f := func(out, in []byte) {
+ Simple(out, hashObj.New(), in)
+ }
+
+ return f, nil
+ case SaltedS2K:
+ f := func(out, in []byte) {
+ Salted(out, hashObj.New(), in, params.salt())
+ }
+
+ return f, nil
+ case IteratedSaltedS2K:
+ f := func(out, in []byte) {
+ Iterated(out, hashObj.New(), in, params.salt(), decodeCount(params.countByte))
+ }
+
+ return f, nil
+ case Argon2S2K:
+ f := func(out, in []byte) {
+ Argon2(out, in, params.salt(), params.passes, params.parallelism, params.memoryExp)
+ }
+ return f, nil
+ }
+
+ return nil, errors.UnsupportedError("S2K function")
+}
+
+func (params *Params) Serialize(w io.Writer) (err error) {
+ if _, err = w.Write([]byte{uint8(params.mode)}); err != nil {
+ return
+ }
+ if params.mode != Argon2S2K {
+ if _, err = w.Write([]byte{params.hashId}); err != nil {
+ return
+ }
+ }
+ if params.Dummy() {
+ _, err = w.Write(append([]byte("GNU"), 1))
+ return
+ }
+ if params.mode > 0 {
+ if _, err = w.Write(params.salt()); err != nil {
+ return
+ }
+ if params.mode == IteratedSaltedS2K {
+ _, err = w.Write([]byte{params.countByte})
+ }
+ if params.mode == Argon2S2K {
+ _, err = w.Write([]byte{params.passes, params.parallelism, params.memoryExp})
+ }
+ }
+ return
+}
+
+// Serialize salts and stretches the given passphrase and writes the
+// resulting key into key. It also serializes an S2K descriptor to
+// w. The key stretching can be configured with c, which may be
+// nil. In that case, sensible defaults will be used.
+func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
+ params, err := Generate(rand, c)
+ if err != nil {
+ return err
+ }
+ err = params.Serialize(w)
+ if err != nil {
+ return err
+ }
+
+ f, err := params.Function()
+ if err != nil {
+ return err
+ }
+ f(key, passphrase)
+ return nil
+}
+
+// validateArgon2Params checks that the argon2 parameters are valid according to RFC9580.
+func validateArgon2Params(params *Params) error {
+ // The number of passes t and the degree of parallelism p MUST be non-zero.
+ if params.parallelism == 0 {
+ return errors.StructuralError("invalid argon2 params: parallelism is 0")
+ }
+ if params.passes == 0 {
+ return errors.StructuralError("invalid argon2 params: iterations is 0")
+ }
+
+ // The encoded memory size MUST be a value from 3+ceil(log2(p)) to 31,
+ // such that the decoded memory size m is a value from 8*p to 2^31.
+ if params.memoryExp > 31 || decodeMemory(params.memoryExp) < 8*uint32(params.parallelism) {
+ return errors.StructuralError("invalid argon2 params: memory is out of bounds")
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_cache.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_cache.go
new file mode 100644
index 0000000000..616e0d12c6
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_cache.go
@@ -0,0 +1,26 @@
+package s2k
+
+// Cache stores keys derived with s2k functions from one passphrase
+// to avoid recomputation if multiple items are encrypted with
+// the same parameters.
+type Cache map[Params][]byte
+
+// GetOrComputeDerivedKey tries to retrieve the key
+// for the given s2k parameters from the cache.
+// If there is no hit, it derives the key with the s2k function from the passphrase,
+// updates the cache, and returns the key.
+func (c *Cache) GetOrComputeDerivedKey(passphrase []byte, params *Params, expectedKeySize int) ([]byte, error) {
+ key, found := (*c)[*params]
+ if !found || len(key) != expectedKeySize {
+ var err error
+ derivedKey := make([]byte, expectedKeySize)
+ s2k, err := params.Function()
+ if err != nil {
+ return nil, err
+ }
+ s2k(derivedKey, passphrase)
+ (*c)[*params] = key
+ return derivedKey, nil
+ }
+ return key, nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_config.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_config.go
new file mode 100644
index 0000000000..b93db1ab85
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_config.go
@@ -0,0 +1,129 @@
+package s2k
+
+import "crypto"
+
+// Config collects configuration parameters for s2k key-stretching
+// transformations. A nil *Config is valid and results in all default
+// values.
+type Config struct {
+ // S2K (String to Key) mode, used for key derivation in the context of secret key encryption
+ // and passphrase-encrypted data. Either s2k.Argon2S2K or s2k.IteratedSaltedS2K may be used.
+ // If the passphrase is a high-entropy key, indicated by setting PassphraseIsHighEntropy to true,
+ // s2k.SaltedS2K can also be used.
+ // Note: Argon2 is the strongest option but not all OpenPGP implementations are compatible with it
+ //(pending standardisation).
+ // 0 (simple), 1(salted), 3(iterated), 4(argon2)
+ // 2(reserved) 100-110(private/experimental).
+ S2KMode Mode
+ // Only relevant if S2KMode is not set to s2k.Argon2S2K.
+ // Hash is the default hash function to be used. If
+ // nil, SHA256 is used.
+ Hash crypto.Hash
+ // Argon2 parameters for S2K (String to Key).
+ // Only relevant if S2KMode is set to s2k.Argon2S2K.
+ // If nil, default parameters are used.
+ // For more details on the choice of parameters, see https://tools.ietf.org/html/rfc9106#section-4.
+ Argon2Config *Argon2Config
+ // Only relevant if S2KMode is set to s2k.IteratedSaltedS2K.
+ // Iteration count for Iterated S2K (String to Key). It
+ // determines the strength of the passphrase stretching when
+ // the said passphrase is hashed to produce a key. S2KCount
+ // should be between 65536 and 65011712, inclusive. If Config
+ // is nil or S2KCount is 0, the value 16777216 used. Not all
+ // values in the above range can be represented. S2KCount will
+ // be rounded up to the next representable value if it cannot
+ // be encoded exactly. When set, it is strongly encrouraged to
+ // use a value that is at least 65536. See RFC 4880 Section
+ // 3.7.1.3.
+ S2KCount int
+ // Indicates whether the passphrase passed by the application is a
+ // high-entropy key (e.g. it's randomly generated or derived from
+ // another passphrase using a strong key derivation function).
+ // When true, allows the S2KMode to be s2k.SaltedS2K.
+ // When the passphrase is not a high-entropy key, using SaltedS2K is
+ // insecure, and not allowed by draft-ietf-openpgp-crypto-refresh-08.
+ PassphraseIsHighEntropy bool
+}
+
+// Argon2Config stores the Argon2 parameters
+// A nil *Argon2Config is valid and results in all default
+type Argon2Config struct {
+ NumberOfPasses uint8
+ DegreeOfParallelism uint8
+ // Memory specifies the desired Argon2 memory usage in kibibytes.
+ // For example memory=64*1024 sets the memory cost to ~64 MB.
+ Memory uint32
+}
+
+func (c *Config) Mode() Mode {
+ if c == nil {
+ return IteratedSaltedS2K
+ }
+ return c.S2KMode
+}
+
+func (c *Config) hash() crypto.Hash {
+ if c == nil || uint(c.Hash) == 0 {
+ return crypto.SHA256
+ }
+
+ return c.Hash
+}
+
+func (c *Config) Argon2() *Argon2Config {
+ if c == nil || c.Argon2Config == nil {
+ return nil
+ }
+ return c.Argon2Config
+}
+
+// EncodedCount get encoded count
+func (c *Config) EncodedCount() uint8 {
+ if c == nil || c.S2KCount == 0 {
+ return 224 // The common case. Corresponding to 16777216
+ }
+
+ i := c.S2KCount
+
+ switch {
+ case i < 65536:
+ i = 65536
+ case i > 65011712:
+ i = 65011712
+ }
+
+ return encodeCount(i)
+}
+
+func (c *Argon2Config) Passes() uint8 {
+ if c == nil || c.NumberOfPasses == 0 {
+ return 3
+ }
+ return c.NumberOfPasses
+}
+
+func (c *Argon2Config) Parallelism() uint8 {
+ if c == nil || c.DegreeOfParallelism == 0 {
+ return 4
+ }
+ return c.DegreeOfParallelism
+}
+
+func (c *Argon2Config) EncodedMemory() uint8 {
+ if c == nil || c.Memory == 0 {
+ return 16 // 64 MiB of RAM
+ }
+
+ memory := c.Memory
+ lowerBound := uint32(c.Parallelism()) * 8
+ upperBound := uint32(2147483648)
+
+ switch {
+ case memory < lowerBound:
+ memory = lowerBound
+ case memory > upperBound:
+ memory = upperBound
+ }
+
+ return encodeMemory(memory, c.Parallelism())
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/write.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/write.go
new file mode 100644
index 0000000000..84bc27d83e
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/write.go
@@ -0,0 +1,690 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "crypto"
+ "hash"
+ "io"
+ "strconv"
+ "time"
+
+ "github.com/ProtonMail/go-crypto/openpgp/armor"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
+ "github.com/ProtonMail/go-crypto/openpgp/packet"
+)
+
+// DetachSign signs message with the private key from signer (which must
+// already have been decrypted) and writes the signature to w.
+// If config is nil, sensible defaults will be used.
+func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+ return detachSign(w, signer, message, packet.SigTypeBinary, config)
+}
+
+// ArmoredDetachSign signs message with the private key from signer (which
+// must already have been decrypted) and writes an armored signature to w.
+// If config is nil, sensible defaults will be used.
+func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) {
+ return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config)
+}
+
+// DetachSignText signs message (after canonicalising the line endings) with
+// the private key from signer (which must already have been decrypted) and
+// writes the signature to w.
+// If config is nil, sensible defaults will be used.
+func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+ return detachSign(w, signer, message, packet.SigTypeText, config)
+}
+
+// ArmoredDetachSignText signs message (after canonicalising the line endings)
+// with the private key from signer (which must already have been decrypted)
+// and writes an armored signature to w.
+// If config is nil, sensible defaults will be used.
+func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+ return armoredDetachSign(w, signer, message, packet.SigTypeText, config)
+}
+
+func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
+ out, err := armor.Encode(w, SignatureType, nil)
+ if err != nil {
+ return
+ }
+ err = detachSign(out, signer, message, sigType, config)
+ if err != nil {
+ return
+ }
+ return out.Close()
+}
+
+func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
+ signingKey, ok := signer.SigningKeyById(config.Now(), config.SigningKey())
+ if !ok {
+ return errors.InvalidArgumentError("no valid signing keys")
+ }
+ if signingKey.PrivateKey == nil {
+ return errors.InvalidArgumentError("signing key doesn't have a private key")
+ }
+ if signingKey.PrivateKey.Encrypted {
+ return errors.InvalidArgumentError("signing key is encrypted")
+ }
+ if _, ok := algorithm.HashToHashId(config.Hash()); !ok {
+ return errors.InvalidArgumentError("invalid hash function")
+ }
+
+ sig := createSignaturePacket(signingKey.PublicKey, sigType, config)
+
+ h, err := sig.PrepareSign(config)
+ if err != nil {
+ return
+ }
+ wrappedHash, err := wrapHashForSignature(h, sig.SigType)
+ if err != nil {
+ return
+ }
+ if _, err = io.Copy(wrappedHash, message); err != nil {
+ return err
+ }
+
+ err = sig.Sign(h, signingKey.PrivateKey, config)
+ if err != nil {
+ return
+ }
+
+ return sig.Serialize(w)
+}
+
+// FileHints contains metadata about encrypted files. This metadata is, itself,
+// encrypted.
+type FileHints struct {
+ // IsBinary can be set to hint that the contents are binary data.
+ IsBinary bool
+ // FileName hints at the name of the file that should be written. It's
+ // truncated to 255 bytes if longer. It may be empty to suggest that the
+ // file should not be written to disk. It may be equal to "_CONSOLE" to
+ // suggest the data should not be written to disk.
+ FileName string
+ // ModTime contains the modification time of the file, or the zero time if not applicable.
+ ModTime time.Time
+}
+
+// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
+// The resulting WriteCloser must be closed after the contents of the file have
+// been written.
+// If config is nil, sensible defaults will be used.
+func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config)
+ if err != nil {
+ return
+ }
+
+ var w io.WriteCloser
+ cipherSuite := packet.CipherSuite{
+ Cipher: config.Cipher(),
+ Mode: config.AEAD().Mode(),
+ }
+ w, err = packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), config.AEAD() != nil, cipherSuite, key, config)
+ if err != nil {
+ return
+ }
+
+ literalData := w
+ if algo := config.Compression(); algo != packet.CompressionNone {
+ var compConfig *packet.CompressionConfig
+ if config != nil {
+ compConfig = config.CompressionConfig
+ }
+ literalData, err = packet.SerializeCompressed(w, algo, compConfig)
+ if err != nil {
+ return
+ }
+ }
+
+ var epochSeconds uint32
+ if !hints.ModTime.IsZero() {
+ epochSeconds = uint32(hints.ModTime.Unix())
+ }
+ return packet.SerializeLiteral(literalData, hints.IsBinary, hints.FileName, epochSeconds)
+}
+
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
+ var j int
+ for _, v := range a {
+ for _, v2 := range b {
+ if v == v2 {
+ a[j] = v
+ j++
+ break
+ }
+ }
+ }
+
+ return a[:j]
+}
+
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectCipherSuites(a [][2]uint8, b [][2]uint8) (intersection [][2]uint8) {
+ var j int
+ for _, v := range a {
+ for _, v2 := range b {
+ if v[0] == v2[0] && v[1] == v2[1] {
+ a[j] = v
+ j++
+ break
+ }
+ }
+ }
+
+ return a[:j]
+}
+
+func hashToHashId(h crypto.Hash) uint8 {
+ v, ok := algorithm.HashToHashId(h)
+ if !ok {
+ panic("tried to convert unknown hash")
+ }
+ return v
+}
+
+// EncryptText encrypts a message to a number of recipients and, optionally,
+// signs it. Optional information is contained in 'hints', also encrypted, that
+// aids the recipients in processing the message. The resulting WriteCloser
+// must be closed after the contents of the file have been written. If config
+// is nil, sensible defaults will be used. The signing is done in text mode.
+func EncryptText(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ return encrypt(ciphertext, ciphertext, to, signed, hints, packet.SigTypeText, config)
+}
+
+// Encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+// If config is nil, sensible defaults will be used.
+func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ return encrypt(ciphertext, ciphertext, to, signed, hints, packet.SigTypeBinary, config)
+}
+
+// EncryptSplit encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+// If config is nil, sensible defaults will be used.
+func EncryptSplit(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ return encrypt(keyWriter, dataWriter, to, signed, hints, packet.SigTypeBinary, config)
+}
+
+// EncryptTextSplit encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+// If config is nil, sensible defaults will be used.
+func EncryptTextSplit(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ return encrypt(keyWriter, dataWriter, to, signed, hints, packet.SigTypeText, config)
+}
+
+// writeAndSign writes the data as a payload package and, optionally, signs
+// it. hints contains optional information, that is also encrypted,
+// that aids the recipients in processing the message. The resulting
+// WriteCloser must be closed after the contents of the file have been
+// written. If config is nil, sensible defaults will be used.
+func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, sigType packet.SignatureType, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ var signer *packet.PrivateKey
+ if signed != nil {
+ signKey, ok := signed.SigningKeyById(config.Now(), config.SigningKey())
+ if !ok {
+ return nil, errors.InvalidArgumentError("no valid signing keys")
+ }
+ signer = signKey.PrivateKey
+ if signer == nil {
+ return nil, errors.InvalidArgumentError("no private key in signing key")
+ }
+ if signer.Encrypted {
+ return nil, errors.InvalidArgumentError("signing key must be decrypted")
+ }
+ }
+
+ var hash crypto.Hash
+ var salt []byte
+ if signer != nil {
+ if hash, err = selectHash(candidateHashes, config.Hash(), signer); err != nil {
+ return nil, err
+ }
+
+ var opsVersion = 3
+ if signer.Version == 6 {
+ opsVersion = signer.Version
+ }
+ ops := &packet.OnePassSignature{
+ Version: opsVersion,
+ SigType: sigType,
+ Hash: hash,
+ PubKeyAlgo: signer.PubKeyAlgo,
+ KeyId: signer.KeyId,
+ IsLast: true,
+ }
+ if opsVersion == 6 {
+ ops.KeyFingerprint = signer.Fingerprint
+ salt, err = packet.SignatureSaltForHash(hash, config.Random())
+ if err != nil {
+ return nil, err
+ }
+ ops.Salt = salt
+ }
+ if err := ops.Serialize(payload); err != nil {
+ return nil, err
+ }
+ }
+
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ w := payload
+ if signer != nil {
+ // If we need to write a signature packet after the literal
+ // data then we need to stop literalData from closing
+ // encryptedData.
+ w = noOpCloser{w}
+
+ }
+ var epochSeconds uint32
+ if !hints.ModTime.IsZero() {
+ epochSeconds = uint32(hints.ModTime.Unix())
+ }
+ literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
+ if err != nil {
+ return nil, err
+ }
+
+ if signer != nil {
+ h, wrappedHash, err := hashForSignature(hash, sigType, salt)
+ if err != nil {
+ return nil, err
+ }
+ metadata := &packet.LiteralData{
+ Format: 'u',
+ FileName: hints.FileName,
+ Time: epochSeconds,
+ }
+ if hints.IsBinary {
+ metadata.Format = 'b'
+ }
+ return signatureWriter{payload, literalData, hash, wrappedHash, h, salt, signer, sigType, config, metadata}, nil
+ }
+ return literalData, nil
+}
+
+// encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+// If config is nil, sensible defaults will be used.
+func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, sigType packet.SignatureType, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ if len(to) == 0 {
+ return nil, errors.InvalidArgumentError("no encryption recipient provided")
+ }
+
+ // These are the possible ciphers that we'll use for the message.
+ candidateCiphers := []uint8{
+ uint8(packet.CipherAES256),
+ uint8(packet.CipherAES128),
+ }
+
+ // These are the possible hash functions that we'll use for the signature.
+ candidateHashes := []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA384),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA3_256),
+ hashToHashId(crypto.SHA3_512),
+ }
+
+ // Prefer GCM if everyone supports it
+ candidateCipherSuites := [][2]uint8{
+ {uint8(packet.CipherAES256), uint8(packet.AEADModeGCM)},
+ {uint8(packet.CipherAES256), uint8(packet.AEADModeEAX)},
+ {uint8(packet.CipherAES256), uint8(packet.AEADModeOCB)},
+ {uint8(packet.CipherAES128), uint8(packet.AEADModeGCM)},
+ {uint8(packet.CipherAES128), uint8(packet.AEADModeEAX)},
+ {uint8(packet.CipherAES128), uint8(packet.AEADModeOCB)},
+ }
+
+ candidateCompression := []uint8{
+ uint8(packet.CompressionNone),
+ uint8(packet.CompressionZIP),
+ uint8(packet.CompressionZLIB),
+ }
+
+ encryptKeys := make([]Key, len(to))
+
+ // AEAD is used only if config enables it and every key supports it
+ aeadSupported := config.AEAD() != nil
+
+ for i := range to {
+ var ok bool
+ encryptKeys[i], ok = to[i].EncryptionKey(config.Now())
+ if !ok {
+ return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no valid encryption keys")
+ }
+
+ primarySelfSignature, _ := to[i].PrimarySelfSignature()
+ if primarySelfSignature == nil {
+ return nil, errors.InvalidArgumentError("entity without a self-signature")
+ }
+
+ if !primarySelfSignature.SEIPDv2 {
+ aeadSupported = false
+ }
+
+ candidateCiphers = intersectPreferences(candidateCiphers, primarySelfSignature.PreferredSymmetric)
+ candidateHashes = intersectPreferences(candidateHashes, primarySelfSignature.PreferredHash)
+ candidateCipherSuites = intersectCipherSuites(candidateCipherSuites, primarySelfSignature.PreferredCipherSuites)
+ candidateCompression = intersectPreferences(candidateCompression, primarySelfSignature.PreferredCompression)
+ }
+
+ // In the event that the intersection of supported algorithms is empty we use the ones
+ // labelled as MUST that every implementation supports.
+ if len(candidateCiphers) == 0 {
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-9.3
+ candidateCiphers = []uint8{uint8(packet.CipherAES128)}
+ }
+ if len(candidateHashes) == 0 {
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#hash-algos
+ candidateHashes = []uint8{hashToHashId(crypto.SHA256)}
+ }
+ if len(candidateCipherSuites) == 0 {
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-9.6
+ candidateCipherSuites = [][2]uint8{{uint8(packet.CipherAES128), uint8(packet.AEADModeOCB)}}
+ }
+
+ cipher := packet.CipherFunction(candidateCiphers[0])
+ aeadCipherSuite := packet.CipherSuite{
+ Cipher: packet.CipherFunction(candidateCipherSuites[0][0]),
+ Mode: packet.AEADMode(candidateCipherSuites[0][1]),
+ }
+
+ // If the cipher specified by config is a candidate, we'll use that.
+ configuredCipher := config.Cipher()
+ for _, c := range candidateCiphers {
+ cipherFunc := packet.CipherFunction(c)
+ if cipherFunc == configuredCipher {
+ cipher = cipherFunc
+ break
+ }
+ }
+
+ var symKey []byte
+ if aeadSupported {
+ symKey = make([]byte, aeadCipherSuite.Cipher.KeySize())
+ } else {
+ symKey = make([]byte, cipher.KeySize())
+ }
+
+ if _, err := io.ReadFull(config.Random(), symKey); err != nil {
+ return nil, err
+ }
+
+ for _, key := range encryptKeys {
+ if err := packet.SerializeEncryptedKeyAEAD(keyWriter, key.PublicKey, cipher, aeadSupported, symKey, config); err != nil {
+ return nil, err
+ }
+ }
+
+ var payload io.WriteCloser
+ payload, err = packet.SerializeSymmetricallyEncrypted(dataWriter, cipher, aeadSupported, aeadCipherSuite, symKey, config)
+ if err != nil {
+ return
+ }
+
+ payload, err = handleCompression(payload, candidateCompression, config)
+ if err != nil {
+ return nil, err
+ }
+
+ return writeAndSign(payload, candidateHashes, signed, hints, sigType, config)
+}
+
+// Sign signs a message. The resulting WriteCloser must be closed after the
+// contents of the file have been written. hints contains optional information
+// that aids the recipients in processing the message.
+// If config is nil, sensible defaults will be used.
+func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) {
+ if signed == nil {
+ return nil, errors.InvalidArgumentError("no signer provided")
+ }
+
+ // These are the possible hash functions that we'll use for the signature.
+ candidateHashes := []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA384),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA3_256),
+ hashToHashId(crypto.SHA3_512),
+ }
+ defaultHashes := candidateHashes[0:1]
+ primarySelfSignature, _ := signed.PrimarySelfSignature()
+ if primarySelfSignature == nil {
+ return nil, errors.StructuralError("signed entity has no self-signature")
+ }
+ preferredHashes := primarySelfSignature.PreferredHash
+ if len(preferredHashes) == 0 {
+ preferredHashes = defaultHashes
+ }
+ candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
+ if len(candidateHashes) == 0 {
+ return nil, errors.StructuralError("cannot sign because signing key shares no common algorithms with candidate hashes")
+ }
+
+ return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, packet.SigTypeBinary, config)
+}
+
+// signatureWriter hashes the contents of a message while passing it along to
+// literalData. When closed, it closes literalData, writes a signature packet
+// to encryptedData and then also closes encryptedData.
+type signatureWriter struct {
+ encryptedData io.WriteCloser
+ literalData io.WriteCloser
+ hashType crypto.Hash
+ wrappedHash hash.Hash
+ h hash.Hash
+ salt []byte // v6 only
+ signer *packet.PrivateKey
+ sigType packet.SignatureType
+ config *packet.Config
+ metadata *packet.LiteralData // V5 signatures protect document metadata
+}
+
+func (s signatureWriter) Write(data []byte) (int, error) {
+ s.wrappedHash.Write(data)
+ switch s.sigType {
+ case packet.SigTypeBinary:
+ return s.literalData.Write(data)
+ case packet.SigTypeText:
+ flag := 0
+ return writeCanonical(s.literalData, data, &flag)
+ }
+ return 0, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(s.sigType)))
+}
+
+func (s signatureWriter) Close() error {
+ sig := createSignaturePacket(&s.signer.PublicKey, s.sigType, s.config)
+ sig.Hash = s.hashType
+ sig.Metadata = s.metadata
+
+ if err := sig.SetSalt(s.salt); err != nil {
+ return err
+ }
+
+ if err := sig.Sign(s.h, s.signer, s.config); err != nil {
+ return err
+ }
+ if err := s.literalData.Close(); err != nil {
+ return err
+ }
+ if err := sig.Serialize(s.encryptedData); err != nil {
+ return err
+ }
+ return s.encryptedData.Close()
+}
+
+func selectHashForSigningKey(config *packet.Config, signer *packet.PublicKey) crypto.Hash {
+ acceptableHashes := acceptableHashesToWrite(signer)
+ hash, ok := algorithm.HashToHashId(config.Hash())
+ if !ok {
+ return config.Hash()
+ }
+ for _, acceptableHashes := range acceptableHashes {
+ if acceptableHashes == hash {
+ return config.Hash()
+ }
+ }
+ if len(acceptableHashes) > 0 {
+ defaultAcceptedHash, ok := algorithm.HashIdToHash(acceptableHashes[0])
+ if ok {
+ return defaultAcceptedHash
+ }
+ }
+ return config.Hash()
+}
+
+func createSignaturePacket(signer *packet.PublicKey, sigType packet.SignatureType, config *packet.Config) *packet.Signature {
+ sigLifetimeSecs := config.SigLifetime()
+ hash := selectHashForSigningKey(config, signer)
+ return &packet.Signature{
+ Version: signer.Version,
+ SigType: sigType,
+ PubKeyAlgo: signer.PubKeyAlgo,
+ Hash: hash,
+ CreationTime: config.Now(),
+ IssuerKeyId: &signer.KeyId,
+ IssuerFingerprint: signer.Fingerprint,
+ Notations: config.Notations(),
+ SigLifetimeSecs: &sigLifetimeSecs,
+ }
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+// TODO: we have two of these in OpenPGP packages alone. This probably needs
+// to be promoted somewhere more common.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() error {
+ return nil
+}
+
+func handleCompression(compressed io.WriteCloser, candidateCompression []uint8, config *packet.Config) (data io.WriteCloser, err error) {
+ data = compressed
+ confAlgo := config.Compression()
+ if confAlgo == packet.CompressionNone {
+ return
+ }
+
+ // Set algorithm labelled as MUST as fallback
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-9.4
+ finalAlgo := packet.CompressionNone
+ // if compression specified by config available we will use it
+ for _, c := range candidateCompression {
+ if uint8(confAlgo) == c {
+ finalAlgo = confAlgo
+ break
+ }
+ }
+
+ if finalAlgo != packet.CompressionNone {
+ var compConfig *packet.CompressionConfig
+ if config != nil {
+ compConfig = config.CompressionConfig
+ }
+ data, err = packet.SerializeCompressed(compressed, finalAlgo, compConfig)
+ if err != nil {
+ return
+ }
+ }
+ return data, nil
+}
+
+// selectHash selects the preferred hash given the candidateHashes and the configuredHash
+func selectHash(candidateHashes []byte, configuredHash crypto.Hash, signer *packet.PrivateKey) (hash crypto.Hash, err error) {
+ acceptableHashes := acceptableHashesToWrite(&signer.PublicKey)
+ candidateHashes = intersectPreferences(acceptableHashes, candidateHashes)
+
+ for _, hashId := range candidateHashes {
+ if h, ok := algorithm.HashIdToHash(hashId); ok && h.Available() {
+ hash = h
+ break
+ }
+ }
+
+ // If the hash specified by config is a candidate, we'll use that.
+ if configuredHash.Available() {
+ for _, hashId := range candidateHashes {
+ if h, ok := algorithm.HashIdToHash(hashId); ok && h == configuredHash {
+ hash = h
+ break
+ }
+ }
+ }
+
+ if hash == 0 {
+ if len(acceptableHashes) > 0 {
+ if h, ok := algorithm.HashIdToHash(acceptableHashes[0]); ok {
+ hash = h
+ } else {
+ return 0, errors.UnsupportedError("no candidate hash functions are compiled in.")
+ }
+ } else {
+ return 0, errors.UnsupportedError("no candidate hash functions are compiled in.")
+ }
+ }
+ return
+}
+
+func acceptableHashesToWrite(singingKey *packet.PublicKey) []uint8 {
+ switch singingKey.PubKeyAlgo {
+ case packet.PubKeyAlgoEd448:
+ return []uint8{
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA3_512),
+ }
+ case packet.PubKeyAlgoECDSA, packet.PubKeyAlgoEdDSA:
+ if curve, err := singingKey.Curve(); err == nil {
+ if curve == packet.Curve448 ||
+ curve == packet.CurveNistP521 ||
+ curve == packet.CurveBrainpoolP512 {
+ return []uint8{
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA3_512),
+ }
+ } else if curve == packet.CurveBrainpoolP384 ||
+ curve == packet.CurveNistP384 {
+ return []uint8{
+ hashToHashId(crypto.SHA384),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA3_512),
+ }
+ }
+ }
+ }
+ return []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA384),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA3_256),
+ hashToHashId(crypto.SHA3_512),
+ }
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go
new file mode 100644
index 0000000000..38afcc74fa
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go
@@ -0,0 +1,221 @@
+package x25519
+
+import (
+ "crypto/sha256"
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/aes/keywrap"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ x25519lib "github.com/cloudflare/circl/dh/x25519"
+ "golang.org/x/crypto/hkdf"
+)
+
+const (
+ hkdfInfo = "OpenPGP X25519"
+ aes128KeySize = 16
+ // The size of a public or private key in bytes.
+ KeySize = x25519lib.Size
+)
+
+type PublicKey struct {
+ // Point represents the encoded elliptic curve point of the public key.
+ Point []byte
+}
+
+type PrivateKey struct {
+ PublicKey
+ // Secret represents the secret of the private key.
+ Secret []byte
+}
+
+// NewPrivateKey creates a new empty private key including the public key.
+func NewPrivateKey(key PublicKey) *PrivateKey {
+ return &PrivateKey{
+ PublicKey: key,
+ }
+}
+
+// Validate validates that the provided public key matches the private key.
+func Validate(pk *PrivateKey) (err error) {
+ var expectedPublicKey, privateKey x25519lib.Key
+ subtle.ConstantTimeCopy(1, privateKey[:], pk.Secret)
+ x25519lib.KeyGen(&expectedPublicKey, &privateKey)
+ if subtle.ConstantTimeCompare(expectedPublicKey[:], pk.PublicKey.Point) == 0 {
+ return errors.KeyInvalidError("x25519: invalid key")
+ }
+ return nil
+}
+
+// GenerateKey generates a new x25519 key pair.
+func GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ var privateKey, publicKey x25519lib.Key
+ privateKeyOut := new(PrivateKey)
+ err := generateKey(rand, &privateKey, &publicKey)
+ if err != nil {
+ return nil, err
+ }
+ privateKeyOut.PublicKey.Point = publicKey[:]
+ privateKeyOut.Secret = privateKey[:]
+ return privateKeyOut, nil
+}
+
+func generateKey(rand io.Reader, privateKey *x25519lib.Key, publicKey *x25519lib.Key) error {
+ maxRounds := 10
+ isZero := true
+ for round := 0; isZero; round++ {
+ if round == maxRounds {
+ return errors.InvalidArgumentError("x25519: zero keys only, randomness source might be corrupt")
+ }
+ _, err := io.ReadFull(rand, privateKey[:])
+ if err != nil {
+ return err
+ }
+ isZero = constantTimeIsZero(privateKey[:])
+ }
+ x25519lib.KeyGen(publicKey, privateKey)
+ return nil
+}
+
+// Encrypt encrypts a sessionKey with x25519 according to
+// the OpenPGP crypto refresh specification section 5.1.6. The function assumes that the
+// sessionKey has the correct format and padding according to the specification.
+func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, err error) {
+ var ephemeralPrivate, ephemeralPublic, staticPublic, shared x25519lib.Key
+ // Check that the input static public key has 32 bytes
+ if len(publicKey.Point) != KeySize {
+ err = errors.KeyInvalidError("x25519: the public key has the wrong size")
+ return
+ }
+ copy(staticPublic[:], publicKey.Point)
+ // Generate ephemeral keyPair
+ err = generateKey(rand, &ephemeralPrivate, &ephemeralPublic)
+ if err != nil {
+ return
+ }
+ // Compute shared key
+ ok := x25519lib.Shared(&shared, &ephemeralPrivate, &staticPublic)
+ if !ok {
+ err = errors.KeyInvalidError("x25519: the public key is a low order point")
+ return
+ }
+ // Derive the encryption key from the shared secret
+ encryptionKey := applyHKDF(ephemeralPublic[:], publicKey.Point[:], shared[:])
+ ephemeralPublicKey = &PublicKey{
+ Point: ephemeralPublic[:],
+ }
+ // Encrypt the sessionKey with aes key wrapping
+ encryptedSessionKey, err = keywrap.Wrap(encryptionKey, sessionKey)
+ return
+}
+
+// Decrypt decrypts a session key stored in ciphertext with the provided x25519
+// private key and ephemeral public key.
+func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) {
+ var ephemeralPublic, staticPrivate, shared x25519lib.Key
+ // Check that the input ephemeral public key has 32 bytes
+ if len(ephemeralPublicKey.Point) != KeySize {
+ err = errors.KeyInvalidError("x25519: the public key has the wrong size")
+ return
+ }
+ copy(ephemeralPublic[:], ephemeralPublicKey.Point)
+ subtle.ConstantTimeCopy(1, staticPrivate[:], privateKey.Secret)
+ // Compute shared key
+ ok := x25519lib.Shared(&shared, &staticPrivate, &ephemeralPublic)
+ if !ok {
+ err = errors.KeyInvalidError("x25519: the ephemeral public key is a low order point")
+ return
+ }
+ // Derive the encryption key from the shared secret
+ encryptionKey := applyHKDF(ephemeralPublicKey.Point[:], privateKey.PublicKey.Point[:], shared[:])
+ // Decrypt the session key with aes key wrapping
+ encodedSessionKey, err = keywrap.Unwrap(encryptionKey, ciphertext)
+ return
+}
+
+func applyHKDF(ephemeralPublicKey []byte, publicKey []byte, sharedSecret []byte) []byte {
+ inputKey := make([]byte, 3*KeySize)
+ // ephemeral public key | recipient public key | shared secret
+ subtle.ConstantTimeCopy(1, inputKey[:KeySize], ephemeralPublicKey)
+ subtle.ConstantTimeCopy(1, inputKey[KeySize:2*KeySize], publicKey)
+ subtle.ConstantTimeCopy(1, inputKey[2*KeySize:], sharedSecret)
+ hkdfReader := hkdf.New(sha256.New, inputKey, []byte{}, []byte(hkdfInfo))
+ encryptionKey := make([]byte, aes128KeySize)
+ _, _ = io.ReadFull(hkdfReader, encryptionKey)
+ return encryptionKey
+}
+
+func constantTimeIsZero(bytes []byte) bool {
+ isZero := byte(0)
+ for _, b := range bytes {
+ isZero |= b
+ }
+ return isZero == 0
+}
+
+// ENCODING/DECODING ciphertexts:
+
+// EncodeFieldsLength returns the length of the ciphertext encoding
+// given the encrypted session key.
+func EncodedFieldsLength(encryptedSessionKey []byte, v6 bool) int {
+ lenCipherFunction := 0
+ if !v6 {
+ lenCipherFunction = 1
+ }
+ return KeySize + 1 + len(encryptedSessionKey) + lenCipherFunction
+}
+
+// EncodeField encodes x25519 session key encryption fields as
+// ephemeral x25519 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey
+// and writes it to writer.
+func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) {
+ lenAlgorithm := 0
+ if !v6 {
+ lenAlgorithm = 1
+ }
+ if _, err = writer.Write(ephemeralPublicKey.Point); err != nil {
+ return err
+ }
+ if _, err = writer.Write([]byte{byte(len(encryptedSessionKey) + lenAlgorithm)}); err != nil {
+ return err
+ }
+ if !v6 {
+ if _, err = writer.Write([]byte{cipherFunction}); err != nil {
+ return err
+ }
+ }
+ _, err = writer.Write(encryptedSessionKey)
+ return err
+}
+
+// DecodeField decodes a x25519 session key encryption as
+// ephemeral x25519 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey.
+func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) {
+ var buf [1]byte
+ ephemeralPublicKey = &PublicKey{
+ Point: make([]byte, KeySize),
+ }
+ // 32 octets representing an ephemeral x25519 public key.
+ if _, err = io.ReadFull(reader, ephemeralPublicKey.Point); err != nil {
+ return nil, nil, 0, err
+ }
+ // A one-octet size of the following fields.
+ if _, err = io.ReadFull(reader, buf[:]); err != nil {
+ return nil, nil, 0, err
+ }
+ followingLen := buf[0]
+ // The one-octet algorithm identifier, if it was passed (in the case of a v3 PKESK packet).
+ if !v6 {
+ if _, err = io.ReadFull(reader, buf[:]); err != nil {
+ return nil, nil, 0, err
+ }
+ cipherFunction = buf[0]
+ followingLen -= 1
+ }
+ // The encrypted session key.
+ encryptedSessionKey = make([]byte, followingLen)
+ if _, err = io.ReadFull(reader, encryptedSessionKey); err != nil {
+ return nil, nil, 0, err
+ }
+ return ephemeralPublicKey, encryptedSessionKey, cipherFunction, nil
+}
diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go
new file mode 100644
index 0000000000..65a082dabd
--- /dev/null
+++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go
@@ -0,0 +1,229 @@
+package x448
+
+import (
+ "crypto/sha512"
+ "crypto/subtle"
+ "io"
+
+ "github.com/ProtonMail/go-crypto/openpgp/aes/keywrap"
+ "github.com/ProtonMail/go-crypto/openpgp/errors"
+ x448lib "github.com/cloudflare/circl/dh/x448"
+ "golang.org/x/crypto/hkdf"
+)
+
+const (
+ hkdfInfo = "OpenPGP X448"
+ aes256KeySize = 32
+ // The size of a public or private key in bytes.
+ KeySize = x448lib.Size
+)
+
+type PublicKey struct {
+ // Point represents the encoded elliptic curve point of the public key.
+ Point []byte
+}
+
+type PrivateKey struct {
+ PublicKey
+ // Secret represents the secret of the private key.
+ Secret []byte
+}
+
+// NewPrivateKey creates a new empty private key including the public key.
+func NewPrivateKey(key PublicKey) *PrivateKey {
+ return &PrivateKey{
+ PublicKey: key,
+ }
+}
+
+// Validate validates that the provided public key matches
+// the private key.
+func Validate(pk *PrivateKey) (err error) {
+ var expectedPublicKey, privateKey x448lib.Key
+ subtle.ConstantTimeCopy(1, privateKey[:], pk.Secret)
+ x448lib.KeyGen(&expectedPublicKey, &privateKey)
+ if subtle.ConstantTimeCompare(expectedPublicKey[:], pk.PublicKey.Point) == 0 {
+ return errors.KeyInvalidError("x448: invalid key")
+ }
+ return nil
+}
+
+// GenerateKey generates a new x448 key pair.
+func GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ var privateKey, publicKey x448lib.Key
+ privateKeyOut := new(PrivateKey)
+ err := generateKey(rand, &privateKey, &publicKey)
+ if err != nil {
+ return nil, err
+ }
+ privateKeyOut.PublicKey.Point = publicKey[:]
+ privateKeyOut.Secret = privateKey[:]
+ return privateKeyOut, nil
+}
+
+func generateKey(rand io.Reader, privateKey *x448lib.Key, publicKey *x448lib.Key) error {
+ maxRounds := 10
+ isZero := true
+ for round := 0; isZero; round++ {
+ if round == maxRounds {
+ return errors.InvalidArgumentError("x448: zero keys only, randomness source might be corrupt")
+ }
+ _, err := io.ReadFull(rand, privateKey[:])
+ if err != nil {
+ return err
+ }
+ isZero = constantTimeIsZero(privateKey[:])
+ }
+ x448lib.KeyGen(publicKey, privateKey)
+ return nil
+}
+
+// Encrypt encrypts a sessionKey with x448 according to
+// the OpenPGP crypto refresh specification section 5.1.7. The function assumes that the
+// sessionKey has the correct format and padding according to the specification.
+func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, err error) {
+ var ephemeralPrivate, ephemeralPublic, staticPublic, shared x448lib.Key
+ // Check that the input static public key has 56 bytes.
+ if len(publicKey.Point) != KeySize {
+ err = errors.KeyInvalidError("x448: the public key has the wrong size")
+ return nil, nil, err
+ }
+ copy(staticPublic[:], publicKey.Point)
+ // Generate ephemeral keyPair.
+ if err = generateKey(rand, &ephemeralPrivate, &ephemeralPublic); err != nil {
+ return nil, nil, err
+ }
+ // Compute shared key.
+ ok := x448lib.Shared(&shared, &ephemeralPrivate, &staticPublic)
+ if !ok {
+ err = errors.KeyInvalidError("x448: the public key is a low order point")
+ return nil, nil, err
+ }
+ // Derive the encryption key from the shared secret.
+ encryptionKey := applyHKDF(ephemeralPublic[:], publicKey.Point[:], shared[:])
+ ephemeralPublicKey = &PublicKey{
+ Point: ephemeralPublic[:],
+ }
+ // Encrypt the sessionKey with aes key wrapping.
+ encryptedSessionKey, err = keywrap.Wrap(encryptionKey, sessionKey)
+ if err != nil {
+ return nil, nil, err
+ }
+ return ephemeralPublicKey, encryptedSessionKey, nil
+}
+
+// Decrypt decrypts a session key stored in ciphertext with the provided x448
+// private key and ephemeral public key.
+func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) {
+ var ephemeralPublic, staticPrivate, shared x448lib.Key
+ // Check that the input ephemeral public key has 56 bytes.
+ if len(ephemeralPublicKey.Point) != KeySize {
+ err = errors.KeyInvalidError("x448: the public key has the wrong size")
+ return nil, err
+ }
+ copy(ephemeralPublic[:], ephemeralPublicKey.Point)
+ subtle.ConstantTimeCopy(1, staticPrivate[:], privateKey.Secret)
+ // Compute shared key.
+ ok := x448lib.Shared(&shared, &staticPrivate, &ephemeralPublic)
+ if !ok {
+ err = errors.KeyInvalidError("x448: the ephemeral public key is a low order point")
+ return nil, err
+ }
+ // Derive the encryption key from the shared secret.
+ encryptionKey := applyHKDF(ephemeralPublicKey.Point[:], privateKey.PublicKey.Point[:], shared[:])
+ // Decrypt the session key with aes key wrapping.
+ encodedSessionKey, err = keywrap.Unwrap(encryptionKey, ciphertext)
+ if err != nil {
+ return nil, err
+ }
+ return encodedSessionKey, nil
+}
+
+func applyHKDF(ephemeralPublicKey []byte, publicKey []byte, sharedSecret []byte) []byte {
+ inputKey := make([]byte, 3*KeySize)
+ // ephemeral public key | recipient public key | shared secret.
+ subtle.ConstantTimeCopy(1, inputKey[:KeySize], ephemeralPublicKey)
+ subtle.ConstantTimeCopy(1, inputKey[KeySize:2*KeySize], publicKey)
+ subtle.ConstantTimeCopy(1, inputKey[2*KeySize:], sharedSecret)
+ hkdfReader := hkdf.New(sha512.New, inputKey, []byte{}, []byte(hkdfInfo))
+ encryptionKey := make([]byte, aes256KeySize)
+ _, _ = io.ReadFull(hkdfReader, encryptionKey)
+ return encryptionKey
+}
+
+func constantTimeIsZero(bytes []byte) bool {
+ isZero := byte(0)
+ for _, b := range bytes {
+ isZero |= b
+ }
+ return isZero == 0
+}
+
+// ENCODING/DECODING ciphertexts:
+
+// EncodeFieldsLength returns the length of the ciphertext encoding
+// given the encrypted session key.
+func EncodedFieldsLength(encryptedSessionKey []byte, v6 bool) int {
+ lenCipherFunction := 0
+ if !v6 {
+ lenCipherFunction = 1
+ }
+ return KeySize + 1 + len(encryptedSessionKey) + lenCipherFunction
+}
+
+// EncodeField encodes x448 session key encryption fields as
+// ephemeral x448 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey
+// and writes it to writer.
+func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) {
+ lenAlgorithm := 0
+ if !v6 {
+ lenAlgorithm = 1
+ }
+ if _, err = writer.Write(ephemeralPublicKey.Point); err != nil {
+ return err
+ }
+ if _, err = writer.Write([]byte{byte(len(encryptedSessionKey) + lenAlgorithm)}); err != nil {
+ return err
+ }
+ if !v6 {
+ if _, err = writer.Write([]byte{cipherFunction}); err != nil {
+ return err
+ }
+ }
+ if _, err = writer.Write(encryptedSessionKey); err != nil {
+ return err
+ }
+ return nil
+}
+
+// DecodeField decodes a x448 session key encryption as
+// ephemeral x448 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey.
+func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) {
+ var buf [1]byte
+ ephemeralPublicKey = &PublicKey{
+ Point: make([]byte, KeySize),
+ }
+ // 56 octets representing an ephemeral x448 public key.
+ if _, err = io.ReadFull(reader, ephemeralPublicKey.Point); err != nil {
+ return nil, nil, 0, err
+ }
+ // A one-octet size of the following fields.
+ if _, err = io.ReadFull(reader, buf[:]); err != nil {
+ return nil, nil, 0, err
+ }
+ followingLen := buf[0]
+ // The one-octet algorithm identifier, if it was passed (in the case of a v3 PKESK packet).
+ if !v6 {
+ if _, err = io.ReadFull(reader, buf[:]); err != nil {
+ return nil, nil, 0, err
+ }
+ cipherFunction = buf[0]
+ followingLen -= 1
+ }
+ // The encrypted session key.
+ encryptedSessionKey = make([]byte, followingLen)
+ if _, err = io.ReadFull(reader, encryptedSessionKey); err != nil {
+ return nil, nil, 0, err
+ }
+ return ephemeralPublicKey, encryptedSessionKey, cipherFunction, nil
+}
diff --git a/vendor/github.com/cloudflare/circl/LICENSE b/vendor/github.com/cloudflare/circl/LICENSE
new file mode 100644
index 0000000000..67edaa90a0
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/LICENSE
@@ -0,0 +1,57 @@
+Copyright (c) 2019 Cloudflare. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Cloudflare nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+========================================================================
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/curve.go b/vendor/github.com/cloudflare/circl/dh/x25519/curve.go
new file mode 100644
index 0000000000..f9057c2b86
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/curve.go
@@ -0,0 +1,96 @@
+package x25519
+
+import (
+ fp "github.com/cloudflare/circl/math/fp25519"
+)
+
+// ladderJoye calculates a fixed-point multiplication with the generator point.
+// The algorithm is the right-to-left Joye's ladder as described
+// in "How to precompute a ladder" in SAC'2017.
+func ladderJoye(k *Key) {
+ w := [5]fp.Elt{} // [mu,x1,z1,x2,z2] order must be preserved.
+ fp.SetOne(&w[1]) // x1 = 1
+ fp.SetOne(&w[2]) // z1 = 1
+ w[3] = fp.Elt{ // x2 = G-S
+ 0xbd, 0xaa, 0x2f, 0xc8, 0xfe, 0xe1, 0x94, 0x7e,
+ 0xf8, 0xed, 0xb2, 0x14, 0xae, 0x95, 0xf0, 0xbb,
+ 0xe2, 0x48, 0x5d, 0x23, 0xb9, 0xa0, 0xc7, 0xad,
+ 0x34, 0xab, 0x7c, 0xe2, 0xee, 0xcd, 0xae, 0x1e,
+ }
+ fp.SetOne(&w[4]) // z2 = 1
+
+ const n = 255
+ const h = 3
+ swap := uint(1)
+ for s := 0; s < n-h; s++ {
+ i := (s + h) / 8
+ j := (s + h) % 8
+ bit := uint((k[i] >> uint(j)) & 1)
+ copy(w[0][:], tableGenerator[s*Size:(s+1)*Size])
+ diffAdd(&w, swap^bit)
+ swap = bit
+ }
+ for s := 0; s < h; s++ {
+ double(&w[1], &w[2])
+ }
+ toAffine((*[fp.Size]byte)(k), &w[1], &w[2])
+}
+
+// ladderMontgomery calculates a generic scalar point multiplication
+// The algorithm implemented is the left-to-right Montgomery's ladder.
+func ladderMontgomery(k, xP *Key) {
+ w := [5]fp.Elt{} // [x1, x2, z2, x3, z3] order must be preserved.
+ w[0] = *(*fp.Elt)(xP) // x1 = xP
+ fp.SetOne(&w[1]) // x2 = 1
+ w[3] = *(*fp.Elt)(xP) // x3 = xP
+ fp.SetOne(&w[4]) // z3 = 1
+
+ move := uint(0)
+ for s := 255 - 1; s >= 0; s-- {
+ i := s / 8
+ j := s % 8
+ bit := uint((k[i] >> uint(j)) & 1)
+ ladderStep(&w, move^bit)
+ move = bit
+ }
+ toAffine((*[fp.Size]byte)(k), &w[1], &w[2])
+}
+
+func toAffine(k *[fp.Size]byte, x, z *fp.Elt) {
+ fp.Inv(z, z)
+ fp.Mul(x, x, z)
+ _ = fp.ToBytes(k[:], x)
+}
+
+var lowOrderPoints = [5]fp.Elt{
+ { /* (0,_,1) point of order 2 on Curve25519 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* (1,_,1) point of order 4 on Curve25519 */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* (x,_,1) first point of order 8 on Curve25519 */
+ 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
+ 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
+ 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
+ 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00,
+ },
+ { /* (x,_,1) second point of order 8 on Curve25519 */
+ 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
+ 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
+ 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
+ 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57,
+ },
+ { /* (-1,_,1) a point of order 4 on the twist of Curve25519 */
+ 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ },
+}
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.go b/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.go
new file mode 100644
index 0000000000..8a3d54c570
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.go
@@ -0,0 +1,30 @@
+//go:build amd64 && !purego
+// +build amd64,!purego
+
+package x25519
+
+import (
+ fp "github.com/cloudflare/circl/math/fp25519"
+ "golang.org/x/sys/cpu"
+)
+
+var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX
+
+var _ = hasBmi2Adx
+
+func double(x, z *fp.Elt) { doubleAmd64(x, z) }
+func diffAdd(w *[5]fp.Elt, b uint) { diffAddAmd64(w, b) }
+func ladderStep(w *[5]fp.Elt, b uint) { ladderStepAmd64(w, b) }
+func mulA24(z, x *fp.Elt) { mulA24Amd64(z, x) }
+
+//go:noescape
+func ladderStepAmd64(w *[5]fp.Elt, b uint)
+
+//go:noescape
+func diffAddAmd64(w *[5]fp.Elt, b uint)
+
+//go:noescape
+func doubleAmd64(x, z *fp.Elt)
+
+//go:noescape
+func mulA24Amd64(z, x *fp.Elt)
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.h b/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.h
new file mode 100644
index 0000000000..8c1ae4d0fb
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.h
@@ -0,0 +1,111 @@
+#define ladderStepLeg \
+ addSub(x2,z2) \
+ addSub(x3,z3) \
+ integerMulLeg(b0,x2,z3) \
+ integerMulLeg(b1,x3,z2) \
+ reduceFromDoubleLeg(t0,b0) \
+ reduceFromDoubleLeg(t1,b1) \
+ addSub(t0,t1) \
+ cselect(x2,x3,regMove) \
+ cselect(z2,z3,regMove) \
+ integerSqrLeg(b0,t0) \
+ integerSqrLeg(b1,t1) \
+ reduceFromDoubleLeg(x3,b0) \
+ reduceFromDoubleLeg(z3,b1) \
+ integerMulLeg(b0,x1,z3) \
+ reduceFromDoubleLeg(z3,b0) \
+ integerSqrLeg(b0,x2) \
+ integerSqrLeg(b1,z2) \
+ reduceFromDoubleLeg(x2,b0) \
+ reduceFromDoubleLeg(z2,b1) \
+ subtraction(t0,x2,z2) \
+ multiplyA24Leg(t1,t0) \
+ additionLeg(t1,t1,z2) \
+ integerMulLeg(b0,x2,z2) \
+ integerMulLeg(b1,t0,t1) \
+ reduceFromDoubleLeg(x2,b0) \
+ reduceFromDoubleLeg(z2,b1)
+
+#define ladderStepBmi2Adx \
+ addSub(x2,z2) \
+ addSub(x3,z3) \
+ integerMulAdx(b0,x2,z3) \
+ integerMulAdx(b1,x3,z2) \
+ reduceFromDoubleAdx(t0,b0) \
+ reduceFromDoubleAdx(t1,b1) \
+ addSub(t0,t1) \
+ cselect(x2,x3,regMove) \
+ cselect(z2,z3,regMove) \
+ integerSqrAdx(b0,t0) \
+ integerSqrAdx(b1,t1) \
+ reduceFromDoubleAdx(x3,b0) \
+ reduceFromDoubleAdx(z3,b1) \
+ integerMulAdx(b0,x1,z3) \
+ reduceFromDoubleAdx(z3,b0) \
+ integerSqrAdx(b0,x2) \
+ integerSqrAdx(b1,z2) \
+ reduceFromDoubleAdx(x2,b0) \
+ reduceFromDoubleAdx(z2,b1) \
+ subtraction(t0,x2,z2) \
+ multiplyA24Adx(t1,t0) \
+ additionAdx(t1,t1,z2) \
+ integerMulAdx(b0,x2,z2) \
+ integerMulAdx(b1,t0,t1) \
+ reduceFromDoubleAdx(x2,b0) \
+ reduceFromDoubleAdx(z2,b1)
+
+#define difAddLeg \
+ addSub(x1,z1) \
+ integerMulLeg(b0,z1,ui) \
+ reduceFromDoubleLeg(z1,b0) \
+ addSub(x1,z1) \
+ integerSqrLeg(b0,x1) \
+ integerSqrLeg(b1,z1) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1) \
+ integerMulLeg(b0,x1,z2) \
+ integerMulLeg(b1,z1,x2) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1)
+
+#define difAddBmi2Adx \
+ addSub(x1,z1) \
+ integerMulAdx(b0,z1,ui) \
+ reduceFromDoubleAdx(z1,b0) \
+ addSub(x1,z1) \
+ integerSqrAdx(b0,x1) \
+ integerSqrAdx(b1,z1) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1) \
+ integerMulAdx(b0,x1,z2) \
+ integerMulAdx(b1,z1,x2) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1)
+
+#define doubleLeg \
+ addSub(x1,z1) \
+ integerSqrLeg(b0,x1) \
+ integerSqrLeg(b1,z1) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1) \
+ subtraction(t0,x1,z1) \
+ multiplyA24Leg(t1,t0) \
+ additionLeg(t1,t1,z1) \
+ integerMulLeg(b0,x1,z1) \
+ integerMulLeg(b1,t0,t1) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1)
+
+#define doubleBmi2Adx \
+ addSub(x1,z1) \
+ integerSqrAdx(b0,x1) \
+ integerSqrAdx(b1,z1) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1) \
+ subtraction(t0,x1,z1) \
+ multiplyA24Adx(t1,t0) \
+ additionAdx(t1,t1,z1) \
+ integerMulAdx(b0,x1,z1) \
+ integerMulAdx(b1,t0,t1) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1)
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.s b/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.s
new file mode 100644
index 0000000000..ce9f062894
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.s
@@ -0,0 +1,157 @@
+//go:build amd64 && !purego
+// +build amd64,!purego
+
+#include "textflag.h"
+
+// Depends on circl/math/fp25519 package
+#include "../../math/fp25519/fp_amd64.h"
+#include "curve_amd64.h"
+
+// CTE_A24 is (A+2)/4 from Curve25519
+#define CTE_A24 121666
+
+#define Size 32
+
+// multiplyA24Leg multiplies x times CTE_A24 and stores in z
+// Uses: AX, DX, R8-R13, FLAGS
+// Instr: x86_64, cmov
+#define multiplyA24Leg(z,x) \
+ MOVL $CTE_A24, AX; MULQ 0+x; MOVQ AX, R8; MOVQ DX, R9; \
+ MOVL $CTE_A24, AX; MULQ 8+x; MOVQ AX, R12; MOVQ DX, R10; \
+ MOVL $CTE_A24, AX; MULQ 16+x; MOVQ AX, R13; MOVQ DX, R11; \
+ MOVL $CTE_A24, AX; MULQ 24+x; \
+ ADDQ R12, R9; \
+ ADCQ R13, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, DX; \
+ MOVL $38, AX; /* 2*C = 38 = 2^256 MOD 2^255-19*/ \
+ IMULQ AX, DX; \
+ ADDQ DX, R8; \
+ ADCQ $0, R9; MOVQ R9, 8+z; \
+ ADCQ $0, R10; MOVQ R10, 16+z; \
+ ADCQ $0, R11; MOVQ R11, 24+z; \
+ MOVQ $0, DX; \
+ CMOVQCS AX, DX; \
+ ADDQ DX, R8; MOVQ R8, 0+z;
+
+// multiplyA24Adx multiplies x times CTE_A24 and stores in z
+// Uses: AX, DX, R8-R12, FLAGS
+// Instr: x86_64, cmov, bmi2
+#define multiplyA24Adx(z,x) \
+ MOVQ $CTE_A24, DX; \
+ MULXQ 0+x, R8, R10; \
+ MULXQ 8+x, R9, R11; ADDQ R10, R9; \
+ MULXQ 16+x, R10, AX; ADCQ R11, R10; \
+ MULXQ 24+x, R11, R12; ADCQ AX, R11; \
+ ;;;;;;;;;;;;;;;;;;;;; ADCQ $0, R12; \
+ MOVL $38, DX; /* 2*C = 38 = 2^256 MOD 2^255-19*/ \
+ IMULQ DX, R12; \
+ ADDQ R12, R8; \
+ ADCQ $0, R9; MOVQ R9, 8+z; \
+ ADCQ $0, R10; MOVQ R10, 16+z; \
+ ADCQ $0, R11; MOVQ R11, 24+z; \
+ MOVQ $0, R12; \
+ CMOVQCS DX, R12; \
+ ADDQ R12, R8; MOVQ R8, 0+z;
+
+#define mulA24Legacy \
+ multiplyA24Leg(0(DI),0(SI))
+#define mulA24Bmi2Adx \
+ multiplyA24Adx(0(DI),0(SI))
+
+// func mulA24Amd64(z, x *fp255.Elt)
+TEXT ·mulA24Amd64(SB),NOSPLIT,$0-16
+ MOVQ z+0(FP), DI
+ MOVQ x+8(FP), SI
+ CHECK_BMI2ADX(LMA24, mulA24Legacy, mulA24Bmi2Adx)
+
+
+// func ladderStepAmd64(w *[5]fp255.Elt, b uint)
+// ladderStepAmd64 calculates a point addition and doubling as follows:
+// (x2,z2) = 2*(x2,z2) and (x3,z3) = (x2,z2)+(x3,z3) using as a difference (x1,-).
+// work = (x1,x2,z2,x3,z3) are five fp255.Elt of 32 bytes.
+// stack = (t0,t1) are two fp.Elt of fp.Size bytes, and
+// (b0,b1) are two-double precision fp.Elt of 2*fp.Size bytes.
+TEXT ·ladderStepAmd64(SB),NOSPLIT,$192-16
+ // Parameters
+ #define regWork DI
+ #define regMove SI
+ #define x1 0*Size(regWork)
+ #define x2 1*Size(regWork)
+ #define z2 2*Size(regWork)
+ #define x3 3*Size(regWork)
+ #define z3 4*Size(regWork)
+ // Local variables
+ #define t0 0*Size(SP)
+ #define t1 1*Size(SP)
+ #define b0 2*Size(SP)
+ #define b1 4*Size(SP)
+ MOVQ w+0(FP), regWork
+ MOVQ b+8(FP), regMove
+ CHECK_BMI2ADX(LLADSTEP, ladderStepLeg, ladderStepBmi2Adx)
+ #undef regWork
+ #undef regMove
+ #undef x1
+ #undef x2
+ #undef z2
+ #undef x3
+ #undef z3
+ #undef t0
+ #undef t1
+ #undef b0
+ #undef b1
+
+// func diffAddAmd64(w *[5]fp255.Elt, b uint)
+// diffAddAmd64 calculates a differential point addition using a precomputed point.
+// (x1,z1) = (x1,z1)+(mu) using a difference point (x2,z2)
+// w = (mu,x1,z1,x2,z2) are five fp.Elt, and
+// stack = (b0,b1) are two-double precision fp.Elt of 2*fp.Size bytes.
+TEXT ·diffAddAmd64(SB),NOSPLIT,$128-16
+ // Parameters
+ #define regWork DI
+ #define regSwap SI
+ #define ui 0*Size(regWork)
+ #define x1 1*Size(regWork)
+ #define z1 2*Size(regWork)
+ #define x2 3*Size(regWork)
+ #define z2 4*Size(regWork)
+ // Local variables
+ #define b0 0*Size(SP)
+ #define b1 2*Size(SP)
+ MOVQ w+0(FP), regWork
+ MOVQ b+8(FP), regSwap
+ cswap(x1,x2,regSwap)
+ cswap(z1,z2,regSwap)
+ CHECK_BMI2ADX(LDIFADD, difAddLeg, difAddBmi2Adx)
+ #undef regWork
+ #undef regSwap
+ #undef ui
+ #undef x1
+ #undef z1
+ #undef x2
+ #undef z2
+ #undef b0
+ #undef b1
+
+// func doubleAmd64(x, z *fp255.Elt)
+// doubleAmd64 calculates a point doubling (x1,z1) = 2*(x1,z1).
+// stack = (t0,t1) are two fp.Elt of fp.Size bytes, and
+// (b0,b1) are two-double precision fp.Elt of 2*fp.Size bytes.
+TEXT ·doubleAmd64(SB),NOSPLIT,$192-16
+ // Parameters
+ #define x1 0(DI)
+ #define z1 0(SI)
+ // Local variables
+ #define t0 0*Size(SP)
+ #define t1 1*Size(SP)
+ #define b0 2*Size(SP)
+ #define b1 4*Size(SP)
+ MOVQ x+0(FP), DI
+ MOVQ z+8(FP), SI
+ CHECK_BMI2ADX(LDOUB,doubleLeg,doubleBmi2Adx)
+ #undef x1
+ #undef z1
+ #undef t0
+ #undef t1
+ #undef b0
+ #undef b1
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/curve_generic.go b/vendor/github.com/cloudflare/circl/dh/x25519/curve_generic.go
new file mode 100644
index 0000000000..dae67ea37d
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/curve_generic.go
@@ -0,0 +1,85 @@
+package x25519
+
+import (
+ "encoding/binary"
+ "math/bits"
+
+ fp "github.com/cloudflare/circl/math/fp25519"
+)
+
+func doubleGeneric(x, z *fp.Elt) {
+ t0, t1 := &fp.Elt{}, &fp.Elt{}
+ fp.AddSub(x, z)
+ fp.Sqr(x, x)
+ fp.Sqr(z, z)
+ fp.Sub(t0, x, z)
+ mulA24Generic(t1, t0)
+ fp.Add(t1, t1, z)
+ fp.Mul(x, x, z)
+ fp.Mul(z, t0, t1)
+}
+
+func diffAddGeneric(w *[5]fp.Elt, b uint) {
+ mu, x1, z1, x2, z2 := &w[0], &w[1], &w[2], &w[3], &w[4]
+ fp.Cswap(x1, x2, b)
+ fp.Cswap(z1, z2, b)
+ fp.AddSub(x1, z1)
+ fp.Mul(z1, z1, mu)
+ fp.AddSub(x1, z1)
+ fp.Sqr(x1, x1)
+ fp.Sqr(z1, z1)
+ fp.Mul(x1, x1, z2)
+ fp.Mul(z1, z1, x2)
+}
+
+func ladderStepGeneric(w *[5]fp.Elt, b uint) {
+ x1, x2, z2, x3, z3 := &w[0], &w[1], &w[2], &w[3], &w[4]
+ t0 := &fp.Elt{}
+ t1 := &fp.Elt{}
+ fp.AddSub(x2, z2)
+ fp.AddSub(x3, z3)
+ fp.Mul(t0, x2, z3)
+ fp.Mul(t1, x3, z2)
+ fp.AddSub(t0, t1)
+ fp.Cmov(x2, x3, b)
+ fp.Cmov(z2, z3, b)
+ fp.Sqr(x3, t0)
+ fp.Sqr(z3, t1)
+ fp.Mul(z3, x1, z3)
+ fp.Sqr(x2, x2)
+ fp.Sqr(z2, z2)
+ fp.Sub(t0, x2, z2)
+ mulA24Generic(t1, t0)
+ fp.Add(t1, t1, z2)
+ fp.Mul(x2, x2, z2)
+ fp.Mul(z2, t0, t1)
+}
+
+func mulA24Generic(z, x *fp.Elt) {
+ const A24 = 121666
+ const n = 8
+ var xx [4]uint64
+ for i := range xx {
+ xx[i] = binary.LittleEndian.Uint64(x[i*n : (i+1)*n])
+ }
+
+ h0, l0 := bits.Mul64(xx[0], A24)
+ h1, l1 := bits.Mul64(xx[1], A24)
+ h2, l2 := bits.Mul64(xx[2], A24)
+ h3, l3 := bits.Mul64(xx[3], A24)
+
+ var c3 uint64
+ l1, c0 := bits.Add64(h0, l1, 0)
+ l2, c1 := bits.Add64(h1, l2, c0)
+ l3, c2 := bits.Add64(h2, l3, c1)
+ l4, _ := bits.Add64(h3, 0, c2)
+ _, l4 = bits.Mul64(l4, 38)
+ l0, c0 = bits.Add64(l0, l4, 0)
+ xx[1], c1 = bits.Add64(l1, 0, c0)
+ xx[2], c2 = bits.Add64(l2, 0, c1)
+ xx[3], c3 = bits.Add64(l3, 0, c2)
+ xx[0], _ = bits.Add64(l0, (-c3)&38, 0)
+ for i := range xx {
+ binary.LittleEndian.PutUint64(z[i*n:(i+1)*n], xx[i])
+ }
+}
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/curve_noasm.go b/vendor/github.com/cloudflare/circl/dh/x25519/curve_noasm.go
new file mode 100644
index 0000000000..07fab97d2a
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/curve_noasm.go
@@ -0,0 +1,11 @@
+//go:build !amd64 || purego
+// +build !amd64 purego
+
+package x25519
+
+import fp "github.com/cloudflare/circl/math/fp25519"
+
+func double(x, z *fp.Elt) { doubleGeneric(x, z) }
+func diffAdd(w *[5]fp.Elt, b uint) { diffAddGeneric(w, b) }
+func ladderStep(w *[5]fp.Elt, b uint) { ladderStepGeneric(w, b) }
+func mulA24(z, x *fp.Elt) { mulA24Generic(z, x) }
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/doc.go b/vendor/github.com/cloudflare/circl/dh/x25519/doc.go
new file mode 100644
index 0000000000..3ce102d145
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/doc.go
@@ -0,0 +1,19 @@
+/*
+Package x25519 provides Diffie-Hellman functions as specified in RFC-7748.
+
+Validation of public keys.
+
+The Diffie-Hellman function, as described in RFC-7748 [1], works for any
+public key. However, if a different protocol requires contributory
+behaviour [2,3], then the public keys must be validated against low-order
+points [3,4]. To do that, the Shared function performs this validation
+internally and returns false when the public key is invalid (i.e., it
+is a low-order point).
+
+References:
+ - [1] RFC7748 by Langley, Hamburg, Turner (https://rfc-editor.org/rfc/rfc7748.txt)
+ - [2] Curve25519 by Bernstein (https://cr.yp.to/ecdh.html)
+ - [3] Bernstein (https://cr.yp.to/ecdh.html#validate)
+ - [4] Cremers&Jackson (https://eprint.iacr.org/2019/526)
+*/
+package x25519
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/key.go b/vendor/github.com/cloudflare/circl/dh/x25519/key.go
new file mode 100644
index 0000000000..c76f72ac7f
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/key.go
@@ -0,0 +1,47 @@
+package x25519
+
+import (
+ "crypto/subtle"
+
+ fp "github.com/cloudflare/circl/math/fp25519"
+)
+
+// Size is the length in bytes of a X25519 key.
+const Size = 32
+
+// Key represents a X25519 key.
+type Key [Size]byte
+
+func (k *Key) clamp(in *Key) *Key {
+ *k = *in
+ k[0] &= 248
+ k[31] = (k[31] & 127) | 64
+ return k
+}
+
+// isValidPubKey verifies if the public key is not a low-order point.
+func (k *Key) isValidPubKey() bool {
+ fp.Modp((*fp.Elt)(k))
+ var isLowOrder int
+ for _, P := range lowOrderPoints {
+ isLowOrder |= subtle.ConstantTimeCompare(P[:], k[:])
+ }
+ return isLowOrder == 0
+}
+
+// KeyGen obtains a public key given a secret key.
+func KeyGen(public, secret *Key) {
+ ladderJoye(public.clamp(secret))
+}
+
+// Shared calculates Alice's shared key from Alice's secret key and Bob's
+// public key returning true on success. A failure case happens when the public
+// key is a low-order point, thus the shared key is all-zeros and the function
+// returns false.
+func Shared(shared, secret, public *Key) bool {
+ validPk := *public
+ validPk[31] &= (1 << (255 % 8)) - 1
+ ok := validPk.isValidPubKey()
+ ladderMontgomery(shared.clamp(secret), &validPk)
+ return ok
+}
diff --git a/vendor/github.com/cloudflare/circl/dh/x25519/table.go b/vendor/github.com/cloudflare/circl/dh/x25519/table.go
new file mode 100644
index 0000000000..28c8c4ac03
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x25519/table.go
@@ -0,0 +1,268 @@
+package x25519
+
+import "github.com/cloudflare/circl/math/fp25519"
+
+// tableGenerator contains the set of points:
+//
+// t[i] = (xi+1)/(xi-1),
+//
+// where (xi,yi) = 2^iG and G is the generator point
+// Size = (256)*(256/8) = 8192 bytes.
+var tableGenerator = [256 * fp25519.Size]byte{
+ /* (2^ 0)P */ 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f,
+ /* (2^ 1)P */ 0x96, 0xfe, 0xaa, 0x16, 0xf4, 0x20, 0x82, 0x6b, 0x34, 0x6a, 0x56, 0x4f, 0x2b, 0xeb, 0xeb, 0x82, 0x0f, 0x95, 0xa5, 0x75, 0xb0, 0xa5, 0xa9, 0xd5, 0xf4, 0x88, 0x24, 0x4b, 0xcf, 0xb2, 0x42, 0x51,
+ /* (2^ 2)P */ 0x0c, 0x68, 0x69, 0x00, 0x75, 0xbc, 0xae, 0x6a, 0x41, 0x9c, 0xf9, 0xa0, 0x20, 0x78, 0xcf, 0x89, 0xf4, 0xd0, 0x56, 0x3b, 0x18, 0xd9, 0x58, 0x2a, 0xa4, 0x11, 0x60, 0xe3, 0x80, 0xca, 0x5a, 0x4b,
+ /* (2^ 3)P */ 0x5d, 0x74, 0x29, 0x8c, 0x34, 0x32, 0x91, 0x32, 0xd7, 0x2f, 0x64, 0xe1, 0x16, 0xe6, 0xa2, 0xf4, 0x34, 0xbc, 0x67, 0xff, 0x03, 0xbb, 0x45, 0x1e, 0x4a, 0x9b, 0x2a, 0xf4, 0xd0, 0x12, 0x69, 0x30,
+ /* (2^ 4)P */ 0x54, 0x71, 0xaf, 0xe6, 0x07, 0x65, 0x88, 0xff, 0x2f, 0xc8, 0xee, 0xdf, 0x13, 0x0e, 0xf5, 0x04, 0xce, 0xb5, 0xba, 0x2a, 0xe8, 0x2f, 0x51, 0xaa, 0x22, 0xf2, 0xd5, 0x68, 0x1a, 0x25, 0x4e, 0x17,
+ /* (2^ 5)P */ 0x98, 0x88, 0x02, 0x82, 0x0d, 0x70, 0x96, 0xcf, 0xc5, 0x02, 0x2c, 0x0a, 0x37, 0xe3, 0x43, 0x17, 0xaa, 0x6e, 0xe8, 0xb4, 0x98, 0xec, 0x9e, 0x37, 0x2e, 0x48, 0xe0, 0x51, 0x8a, 0x88, 0x59, 0x0c,
+ /* (2^ 6)P */ 0x89, 0xd1, 0xb5, 0x99, 0xd6, 0xf1, 0xcb, 0xfb, 0x84, 0xdc, 0x9f, 0x8e, 0xd5, 0xf0, 0xae, 0xac, 0x14, 0x76, 0x1f, 0x23, 0x06, 0x0d, 0xc2, 0xc1, 0x72, 0xf9, 0x74, 0xa2, 0x8d, 0x21, 0x38, 0x29,
+ /* (2^ 7)P */ 0x18, 0x7f, 0x1d, 0xff, 0xbe, 0x49, 0xaf, 0xf6, 0xc2, 0xc9, 0x7a, 0x38, 0x22, 0x1c, 0x54, 0xcc, 0x6b, 0xc5, 0x15, 0x40, 0xef, 0xc9, 0xfc, 0x96, 0xa9, 0x13, 0x09, 0x69, 0x7c, 0x62, 0xc1, 0x69,
+ /* (2^ 8)P */ 0x0e, 0xdb, 0x33, 0x47, 0x2f, 0xfd, 0x86, 0x7a, 0xe9, 0x7d, 0x08, 0x9e, 0xf2, 0xc4, 0xb8, 0xfd, 0x29, 0xa2, 0xa2, 0x8e, 0x1a, 0x4b, 0x5e, 0x09, 0x79, 0x7a, 0xb3, 0x29, 0xc8, 0xa7, 0xd7, 0x1a,
+ /* (2^ 9)P */ 0xc0, 0xa0, 0x7e, 0xd1, 0xca, 0x89, 0x2d, 0x34, 0x51, 0x20, 0xed, 0xcc, 0xa6, 0xdd, 0xbe, 0x67, 0x74, 0x2f, 0xb4, 0x2b, 0xbf, 0x31, 0xca, 0x19, 0xbb, 0xac, 0x80, 0x49, 0xc8, 0xb4, 0xf7, 0x3d,
+ /* (2^ 10)P */ 0x83, 0xd8, 0x0a, 0xc8, 0x4d, 0x44, 0xc6, 0xa8, 0x85, 0xab, 0xe3, 0x66, 0x03, 0x44, 0x1e, 0xb9, 0xd8, 0xf6, 0x64, 0x01, 0xa0, 0xcd, 0x15, 0xc2, 0x68, 0xe6, 0x47, 0xf2, 0x6e, 0x7c, 0x86, 0x3d,
+ /* (2^ 11)P */ 0x8c, 0x65, 0x3e, 0xcc, 0x2b, 0x58, 0xdd, 0xc7, 0x28, 0x55, 0x0e, 0xee, 0x48, 0x47, 0x2c, 0xfd, 0x71, 0x4f, 0x9f, 0xcc, 0x95, 0x9b, 0xfd, 0xa0, 0xdf, 0x5d, 0x67, 0xb0, 0x71, 0xd8, 0x29, 0x75,
+ /* (2^ 12)P */ 0x78, 0xbd, 0x3c, 0x2d, 0xb4, 0x68, 0xf5, 0xb8, 0x82, 0xda, 0xf3, 0x91, 0x1b, 0x01, 0x33, 0x12, 0x62, 0x3b, 0x7c, 0x4a, 0xcd, 0x6c, 0xce, 0x2d, 0x03, 0x86, 0x49, 0x9e, 0x8e, 0xfc, 0xe7, 0x75,
+ /* (2^ 13)P */ 0xec, 0xb6, 0xd0, 0xfc, 0xf1, 0x13, 0x4f, 0x2f, 0x45, 0x7a, 0xff, 0x29, 0x1f, 0xca, 0xa8, 0xf1, 0x9b, 0xe2, 0x81, 0x29, 0xa7, 0xc1, 0x49, 0xc2, 0x6a, 0xb5, 0x83, 0x8c, 0xbb, 0x0d, 0xbe, 0x6e,
+ /* (2^ 14)P */ 0x22, 0xb2, 0x0b, 0x17, 0x8d, 0xfa, 0x14, 0x71, 0x5f, 0x93, 0x93, 0xbf, 0xd5, 0xdc, 0xa2, 0x65, 0x9a, 0x97, 0x9c, 0xb5, 0x68, 0x1f, 0xc4, 0xbd, 0x89, 0x92, 0xce, 0xa2, 0x79, 0xef, 0x0e, 0x2f,
+ /* (2^ 15)P */ 0xce, 0x37, 0x3c, 0x08, 0x0c, 0xbf, 0xec, 0x42, 0x22, 0x63, 0x49, 0xec, 0x09, 0xbc, 0x30, 0x29, 0x0d, 0xac, 0xfe, 0x9c, 0xc1, 0xb0, 0x94, 0xf2, 0x80, 0xbb, 0xfa, 0xed, 0x4b, 0xaa, 0x80, 0x37,
+ /* (2^ 16)P */ 0x29, 0xd9, 0xea, 0x7c, 0x3e, 0x7d, 0xc1, 0x56, 0xc5, 0x22, 0x57, 0x2e, 0xeb, 0x4b, 0xcb, 0xe7, 0x5a, 0xe1, 0xbf, 0x2d, 0x73, 0x31, 0xe9, 0x0c, 0xf8, 0x52, 0x10, 0x62, 0xc7, 0x83, 0xb8, 0x41,
+ /* (2^ 17)P */ 0x50, 0x53, 0xd2, 0xc3, 0xa0, 0x5c, 0xf7, 0xdb, 0x51, 0xe3, 0xb1, 0x6e, 0x08, 0xbe, 0x36, 0x29, 0x12, 0xb2, 0xa9, 0xb4, 0x3c, 0xe0, 0x36, 0xc9, 0xaa, 0x25, 0x22, 0x32, 0x82, 0xbf, 0x45, 0x1d,
+ /* (2^ 18)P */ 0xc5, 0x4c, 0x02, 0x6a, 0x03, 0xb1, 0x1a, 0xe8, 0x72, 0x9a, 0x4c, 0x30, 0x1c, 0x20, 0x12, 0xe2, 0xfc, 0xb1, 0x32, 0x68, 0xba, 0x3f, 0xd7, 0xc5, 0x81, 0x95, 0x83, 0x4d, 0x5a, 0xdb, 0xff, 0x20,
+ /* (2^ 19)P */ 0xad, 0x0f, 0x5d, 0xbe, 0x67, 0xd3, 0x83, 0xa2, 0x75, 0x44, 0x16, 0x8b, 0xca, 0x25, 0x2b, 0x6c, 0x2e, 0xf2, 0xaa, 0x7c, 0x46, 0x35, 0x49, 0x9d, 0x49, 0xff, 0x85, 0xee, 0x8e, 0x40, 0x66, 0x51,
+ /* (2^ 20)P */ 0x61, 0xe3, 0xb4, 0xfa, 0xa2, 0xba, 0x67, 0x3c, 0xef, 0x5c, 0xf3, 0x7e, 0xc6, 0x33, 0xe4, 0xb3, 0x1c, 0x9b, 0x15, 0x41, 0x92, 0x72, 0x59, 0x52, 0x33, 0xab, 0xb0, 0xd5, 0x92, 0x18, 0x62, 0x6a,
+ /* (2^ 21)P */ 0xcb, 0xcd, 0x55, 0x75, 0x38, 0x4a, 0xb7, 0x20, 0x3f, 0x92, 0x08, 0x12, 0x0e, 0xa1, 0x2a, 0x53, 0xd1, 0x1d, 0x28, 0x62, 0x77, 0x7b, 0xa1, 0xea, 0xbf, 0x44, 0x5c, 0xf0, 0x43, 0x34, 0xab, 0x61,
+ /* (2^ 22)P */ 0xf8, 0xde, 0x24, 0x23, 0x42, 0x6c, 0x7a, 0x25, 0x7f, 0xcf, 0xe3, 0x17, 0x10, 0x6c, 0x1c, 0x13, 0x57, 0xa2, 0x30, 0xf6, 0x39, 0x87, 0x75, 0x23, 0x80, 0x85, 0xa7, 0x01, 0x7a, 0x40, 0x5a, 0x29,
+ /* (2^ 23)P */ 0xd9, 0xa8, 0x5d, 0x6d, 0x24, 0x43, 0xc4, 0xf8, 0x5d, 0xfa, 0x52, 0x0c, 0x45, 0x75, 0xd7, 0x19, 0x3d, 0xf8, 0x1b, 0x73, 0x92, 0xfc, 0xfc, 0x2a, 0x00, 0x47, 0x2b, 0x1b, 0xe8, 0xc8, 0x10, 0x7d,
+ /* (2^ 24)P */ 0x0b, 0xa2, 0xba, 0x70, 0x1f, 0x27, 0xe0, 0xc8, 0x57, 0x39, 0xa6, 0x7c, 0x86, 0x48, 0x37, 0x99, 0xbb, 0xd4, 0x7e, 0xcb, 0xb3, 0xef, 0x12, 0x54, 0x75, 0x29, 0xe6, 0x73, 0x61, 0xd3, 0x96, 0x31,
+ /* (2^ 25)P */ 0xfc, 0xdf, 0xc7, 0x41, 0xd1, 0xca, 0x5b, 0xde, 0x48, 0xc8, 0x95, 0xb3, 0xd2, 0x8c, 0xcc, 0x47, 0xcb, 0xf3, 0x1a, 0xe1, 0x42, 0xd9, 0x4c, 0xa3, 0xc2, 0xce, 0x4e, 0xd0, 0xf2, 0xdb, 0x56, 0x02,
+ /* (2^ 26)P */ 0x7f, 0x66, 0x0e, 0x4b, 0xe9, 0xb7, 0x5a, 0x87, 0x10, 0x0d, 0x85, 0xc0, 0x83, 0xdd, 0xd4, 0xca, 0x9f, 0xc7, 0x72, 0x4e, 0x8f, 0x2e, 0xf1, 0x47, 0x9b, 0xb1, 0x85, 0x8c, 0xbb, 0x87, 0x1a, 0x5f,
+ /* (2^ 27)P */ 0xb8, 0x51, 0x7f, 0x43, 0xb6, 0xd0, 0xe9, 0x7a, 0x65, 0x90, 0x87, 0x18, 0x55, 0xce, 0xc7, 0x12, 0xee, 0x7a, 0xf7, 0x5c, 0xfe, 0x09, 0xde, 0x2a, 0x27, 0x56, 0x2c, 0x7d, 0x2f, 0x5a, 0xa0, 0x23,
+ /* (2^ 28)P */ 0x9a, 0x16, 0x7c, 0xf1, 0x28, 0xe1, 0x08, 0x59, 0x2d, 0x85, 0xd0, 0x8a, 0xdd, 0x98, 0x74, 0xf7, 0x64, 0x2f, 0x10, 0xab, 0xce, 0xc4, 0xb4, 0x74, 0x45, 0x98, 0x13, 0x10, 0xdd, 0xba, 0x3a, 0x18,
+ /* (2^ 29)P */ 0xac, 0xaa, 0x92, 0xaa, 0x8d, 0xba, 0x65, 0xb1, 0x05, 0x67, 0x38, 0x99, 0x95, 0xef, 0xc5, 0xd5, 0xd1, 0x40, 0xfc, 0xf8, 0x0c, 0x8f, 0x2f, 0xbe, 0x14, 0x45, 0x20, 0xee, 0x35, 0xe6, 0x01, 0x27,
+ /* (2^ 30)P */ 0x14, 0x65, 0x15, 0x20, 0x00, 0xa8, 0x9f, 0x62, 0xce, 0xc1, 0xa8, 0x64, 0x87, 0x86, 0x23, 0xf2, 0x0e, 0x06, 0x3f, 0x0b, 0xff, 0x4f, 0x89, 0x5b, 0xfa, 0xa3, 0x08, 0xf7, 0x4c, 0x94, 0xd9, 0x60,
+ /* (2^ 31)P */ 0x1f, 0x20, 0x7a, 0x1c, 0x1a, 0x00, 0xea, 0xae, 0x63, 0xce, 0xe2, 0x3e, 0x63, 0x6a, 0xf1, 0xeb, 0xe1, 0x07, 0x7a, 0x4c, 0x59, 0x09, 0x77, 0x6f, 0xcb, 0x08, 0x02, 0x0d, 0x15, 0x58, 0xb9, 0x79,
+ /* (2^ 32)P */ 0xe7, 0x10, 0xd4, 0x01, 0x53, 0x5e, 0xb5, 0x24, 0x4d, 0xc8, 0xfd, 0xf3, 0xdf, 0x4e, 0xa3, 0xe3, 0xd8, 0x32, 0x40, 0x90, 0xe4, 0x68, 0x87, 0xd8, 0xec, 0xae, 0x3a, 0x7b, 0x42, 0x84, 0x13, 0x13,
+ /* (2^ 33)P */ 0x14, 0x4f, 0x23, 0x86, 0x12, 0xe5, 0x05, 0x84, 0x29, 0xc5, 0xb4, 0xad, 0x39, 0x47, 0xdc, 0x14, 0xfd, 0x4f, 0x63, 0x50, 0xb2, 0xb5, 0xa2, 0xb8, 0x93, 0xff, 0xa7, 0xd8, 0x4a, 0xa9, 0xe2, 0x2f,
+ /* (2^ 34)P */ 0xdd, 0xfa, 0x43, 0xe8, 0xef, 0x57, 0x5c, 0xec, 0x18, 0x99, 0xbb, 0xf0, 0x40, 0xce, 0x43, 0x28, 0x05, 0x63, 0x3d, 0xcf, 0xd6, 0x61, 0xb5, 0xa4, 0x7e, 0x77, 0xfb, 0xe8, 0xbd, 0x29, 0x36, 0x74,
+ /* (2^ 35)P */ 0x8f, 0x73, 0xaf, 0xbb, 0x46, 0xdd, 0x3e, 0x34, 0x51, 0xa6, 0x01, 0xb1, 0x28, 0x18, 0x98, 0xed, 0x7a, 0x79, 0x2c, 0x88, 0x0b, 0x76, 0x01, 0xa4, 0x30, 0x87, 0xc8, 0x8d, 0xe2, 0x23, 0xc2, 0x1f,
+ /* (2^ 36)P */ 0x0e, 0xba, 0x0f, 0xfc, 0x91, 0x4e, 0x60, 0x48, 0xa4, 0x6f, 0x2c, 0x05, 0x8f, 0xf7, 0x37, 0xb6, 0x9c, 0x23, 0xe9, 0x09, 0x3d, 0xac, 0xcc, 0x91, 0x7c, 0x68, 0x7a, 0x43, 0xd4, 0xee, 0xf7, 0x23,
+ /* (2^ 37)P */ 0x00, 0xd8, 0x9b, 0x8d, 0x11, 0xb1, 0x73, 0x51, 0xa7, 0xd4, 0x89, 0x31, 0xb6, 0x41, 0xd6, 0x29, 0x86, 0xc5, 0xbb, 0x88, 0x79, 0x17, 0xbf, 0xfd, 0xf5, 0x1d, 0xd8, 0xca, 0x4f, 0x89, 0x59, 0x29,
+ /* (2^ 38)P */ 0x99, 0xc8, 0xbb, 0xb4, 0xf3, 0x8e, 0xbc, 0xae, 0xb9, 0x92, 0x69, 0xb2, 0x5a, 0x99, 0x48, 0x41, 0xfb, 0x2c, 0xf9, 0x34, 0x01, 0x0b, 0xe2, 0x24, 0xe8, 0xde, 0x05, 0x4a, 0x89, 0x58, 0xd1, 0x40,
+ /* (2^ 39)P */ 0xf6, 0x76, 0xaf, 0x85, 0x11, 0x0b, 0xb0, 0x46, 0x79, 0x7a, 0x18, 0x73, 0x78, 0xc7, 0xba, 0x26, 0x5f, 0xff, 0x8f, 0xab, 0x95, 0xbf, 0xc0, 0x3d, 0xd7, 0x24, 0x55, 0x94, 0xd8, 0x8b, 0x60, 0x2a,
+ /* (2^ 40)P */ 0x02, 0x63, 0x44, 0xbd, 0x88, 0x95, 0x44, 0x26, 0x9c, 0x43, 0x88, 0x03, 0x1c, 0xc2, 0x4b, 0x7c, 0xb2, 0x11, 0xbd, 0x83, 0xf3, 0xa4, 0x98, 0x8e, 0xb9, 0x76, 0xd8, 0xc9, 0x7b, 0x8d, 0x21, 0x26,
+ /* (2^ 41)P */ 0x8a, 0x17, 0x7c, 0x99, 0x42, 0x15, 0x08, 0xe3, 0x6f, 0x60, 0xb6, 0x6f, 0xa8, 0x29, 0x2d, 0x3c, 0x74, 0x93, 0x27, 0xfa, 0x36, 0x77, 0x21, 0x5c, 0xfa, 0xb1, 0xfe, 0x4a, 0x73, 0x05, 0xde, 0x7d,
+ /* (2^ 42)P */ 0xab, 0x2b, 0xd4, 0x06, 0x39, 0x0e, 0xf1, 0x3b, 0x9c, 0x64, 0x80, 0x19, 0x3e, 0x80, 0xf7, 0xe4, 0x7a, 0xbf, 0x95, 0x95, 0xf8, 0x3b, 0x05, 0xe6, 0x30, 0x55, 0x24, 0xda, 0x38, 0xaf, 0x4f, 0x39,
+ /* (2^ 43)P */ 0xf4, 0x28, 0x69, 0x89, 0x58, 0xfb, 0x8e, 0x7a, 0x3c, 0x11, 0x6a, 0xcc, 0xe9, 0x78, 0xc7, 0xfb, 0x6f, 0x59, 0xaf, 0x30, 0xe3, 0x0c, 0x67, 0x72, 0xf7, 0x6c, 0x3d, 0x1d, 0xa8, 0x22, 0xf2, 0x48,
+ /* (2^ 44)P */ 0xa7, 0xca, 0x72, 0x0d, 0x41, 0xce, 0x1f, 0xf0, 0x95, 0x55, 0x3b, 0x21, 0xc7, 0xec, 0x20, 0x5a, 0x83, 0x14, 0xfa, 0xc1, 0x65, 0x11, 0xc2, 0x7b, 0x41, 0xa7, 0xa8, 0x1d, 0xe3, 0x9a, 0xf8, 0x07,
+ /* (2^ 45)P */ 0xf9, 0x0f, 0x83, 0xc6, 0xb4, 0xc2, 0xd2, 0x05, 0x93, 0x62, 0x31, 0xc6, 0x0f, 0x33, 0x3e, 0xd4, 0x04, 0xa9, 0xd3, 0x96, 0x0a, 0x59, 0xa5, 0xa5, 0xb6, 0x33, 0x53, 0xa6, 0x91, 0xdb, 0x5e, 0x70,
+ /* (2^ 46)P */ 0xf7, 0xa5, 0xb9, 0x0b, 0x5e, 0xe1, 0x8e, 0x04, 0x5d, 0xaf, 0x0a, 0x9e, 0xca, 0xcf, 0x40, 0x32, 0x0b, 0xa4, 0xc4, 0xed, 0xce, 0x71, 0x4b, 0x8f, 0x6d, 0x4a, 0x54, 0xde, 0xa3, 0x0d, 0x1c, 0x62,
+ /* (2^ 47)P */ 0x91, 0x40, 0x8c, 0xa0, 0x36, 0x28, 0x87, 0x92, 0x45, 0x14, 0xc9, 0x10, 0xb0, 0x75, 0x83, 0xce, 0x94, 0x63, 0x27, 0x4f, 0x52, 0xeb, 0x72, 0x8a, 0x35, 0x36, 0xc8, 0x7e, 0xfa, 0xfc, 0x67, 0x26,
+ /* (2^ 48)P */ 0x2a, 0x75, 0xe8, 0x45, 0x33, 0x17, 0x4c, 0x7f, 0xa5, 0x79, 0x70, 0xee, 0xfe, 0x47, 0x1b, 0x06, 0x34, 0xff, 0x86, 0x9f, 0xfa, 0x9a, 0xdd, 0x25, 0x9c, 0xc8, 0x5d, 0x42, 0xf5, 0xce, 0x80, 0x37,
+ /* (2^ 49)P */ 0xe9, 0xb4, 0x3b, 0x51, 0x5a, 0x03, 0x46, 0x1a, 0xda, 0x5a, 0x57, 0xac, 0x79, 0xf3, 0x1e, 0x3e, 0x50, 0x4b, 0xa2, 0x5f, 0x1c, 0x5f, 0x8c, 0xc7, 0x22, 0x9f, 0xfd, 0x34, 0x76, 0x96, 0x1a, 0x32,
+ /* (2^ 50)P */ 0xfa, 0x27, 0x6e, 0x82, 0xb8, 0x07, 0x67, 0x94, 0xd0, 0x6f, 0x50, 0x4c, 0xd6, 0x84, 0xca, 0x3d, 0x36, 0x14, 0xe9, 0x75, 0x80, 0x21, 0x89, 0xc1, 0x84, 0x84, 0x3b, 0x9b, 0x16, 0x84, 0x92, 0x6d,
+ /* (2^ 51)P */ 0xdf, 0x2d, 0x3f, 0x38, 0x40, 0xe8, 0x67, 0x3a, 0x75, 0x9b, 0x4f, 0x0c, 0xa3, 0xc9, 0xee, 0x33, 0x47, 0xef, 0x83, 0xa7, 0x6f, 0xc8, 0xc7, 0x3e, 0xc4, 0xfb, 0xc9, 0xba, 0x9f, 0x44, 0xec, 0x26,
+ /* (2^ 52)P */ 0x7d, 0x9e, 0x9b, 0xa0, 0xcb, 0x38, 0x0f, 0x5c, 0x8c, 0x47, 0xa3, 0x62, 0xc7, 0x8c, 0x16, 0x81, 0x1c, 0x12, 0xfc, 0x06, 0xd3, 0xb0, 0x23, 0x3e, 0xdd, 0xdc, 0xef, 0xa5, 0xa0, 0x8a, 0x23, 0x5a,
+ /* (2^ 53)P */ 0xff, 0x43, 0xea, 0xc4, 0x21, 0x61, 0xa2, 0x1b, 0xb5, 0x32, 0x88, 0x7c, 0x7f, 0xc7, 0xf8, 0x36, 0x9a, 0xf9, 0xdc, 0x0a, 0x0b, 0xea, 0xfb, 0x88, 0xf9, 0xeb, 0x5b, 0xc2, 0x8e, 0x93, 0xa9, 0x5c,
+ /* (2^ 54)P */ 0xa0, 0xcd, 0xfc, 0x51, 0x5e, 0x6a, 0x43, 0xd5, 0x3b, 0x89, 0xcd, 0xc2, 0x97, 0x47, 0xbc, 0x1d, 0x08, 0x4a, 0x22, 0xd3, 0x65, 0x6a, 0x34, 0x19, 0x66, 0xf4, 0x9a, 0x9b, 0xe4, 0x34, 0x50, 0x0f,
+ /* (2^ 55)P */ 0x6e, 0xb9, 0xe0, 0xa1, 0x67, 0x39, 0x3c, 0xf2, 0x88, 0x4d, 0x7a, 0x86, 0xfa, 0x08, 0x8b, 0xe5, 0x79, 0x16, 0x34, 0xa7, 0xc6, 0xab, 0x2f, 0xfb, 0x46, 0x69, 0x02, 0xb6, 0x1e, 0x38, 0x75, 0x2a,
+ /* (2^ 56)P */ 0xac, 0x20, 0x94, 0xc1, 0xe4, 0x3b, 0x0a, 0xc8, 0xdc, 0xb6, 0xf2, 0x81, 0xc6, 0xf6, 0xb1, 0x66, 0x88, 0x33, 0xe9, 0x61, 0x67, 0x03, 0xf7, 0x7c, 0xc4, 0xa4, 0x60, 0xa6, 0xd8, 0xbb, 0xab, 0x25,
+ /* (2^ 57)P */ 0x98, 0x51, 0xfd, 0x14, 0xba, 0x12, 0xea, 0x91, 0xa9, 0xff, 0x3c, 0x4a, 0xfc, 0x50, 0x49, 0x68, 0x28, 0xad, 0xf5, 0x30, 0x21, 0x84, 0x26, 0xf8, 0x41, 0xa4, 0x01, 0x53, 0xf7, 0x88, 0xa9, 0x3e,
+ /* (2^ 58)P */ 0x6f, 0x8c, 0x5f, 0x69, 0x9a, 0x10, 0x78, 0xc9, 0xf3, 0xc3, 0x30, 0x05, 0x4a, 0xeb, 0x46, 0x17, 0x95, 0x99, 0x45, 0xb4, 0x77, 0x6d, 0x4d, 0x44, 0xc7, 0x5c, 0x4e, 0x05, 0x8c, 0x2b, 0x95, 0x75,
+ /* (2^ 59)P */ 0xaa, 0xd6, 0xf4, 0x15, 0x79, 0x3f, 0x70, 0xa3, 0xd8, 0x47, 0x26, 0x2f, 0x20, 0x46, 0xc3, 0x66, 0x4b, 0x64, 0x1d, 0x81, 0xdf, 0x69, 0x14, 0xd0, 0x1f, 0xd7, 0xa5, 0x81, 0x7d, 0xa4, 0xfe, 0x77,
+ /* (2^ 60)P */ 0x81, 0xa3, 0x7c, 0xf5, 0x9e, 0x52, 0xe9, 0xc5, 0x1a, 0x88, 0x2f, 0xce, 0xb9, 0xb4, 0xee, 0x6e, 0xd6, 0x9b, 0x00, 0xe8, 0x28, 0x1a, 0xe9, 0xb6, 0xec, 0x3f, 0xfc, 0x9a, 0x3e, 0xbe, 0x80, 0x4b,
+ /* (2^ 61)P */ 0xc5, 0xd2, 0xae, 0x26, 0xc5, 0x73, 0x37, 0x7e, 0x9d, 0xa4, 0xc9, 0x53, 0xb4, 0xfc, 0x4a, 0x1b, 0x4d, 0xb2, 0xff, 0xba, 0xd7, 0xbd, 0x20, 0xa9, 0x0e, 0x40, 0x2d, 0x12, 0x9f, 0x69, 0x54, 0x7c,
+ /* (2^ 62)P */ 0xc8, 0x4b, 0xa9, 0x4f, 0xe1, 0xc8, 0x46, 0xef, 0x5e, 0xed, 0x52, 0x29, 0xce, 0x74, 0xb0, 0xe0, 0xd5, 0x85, 0xd8, 0xdb, 0xe1, 0x50, 0xa4, 0xbe, 0x2c, 0x71, 0x0f, 0x32, 0x49, 0x86, 0xb6, 0x61,
+ /* (2^ 63)P */ 0xd1, 0xbd, 0xcc, 0x09, 0x73, 0x5f, 0x48, 0x8a, 0x2d, 0x1a, 0x4d, 0x7d, 0x0d, 0x32, 0x06, 0xbd, 0xf4, 0xbe, 0x2d, 0x32, 0x73, 0x29, 0x23, 0x25, 0x70, 0xf7, 0x17, 0x8c, 0x75, 0xc4, 0x5d, 0x44,
+ /* (2^ 64)P */ 0x3c, 0x93, 0xc8, 0x7c, 0x17, 0x34, 0x04, 0xdb, 0x9f, 0x05, 0xea, 0x75, 0x21, 0xe8, 0x6f, 0xed, 0x34, 0xdb, 0x53, 0xc0, 0xfd, 0xbe, 0xfe, 0x1e, 0x99, 0xaf, 0x5d, 0xc6, 0x67, 0xe8, 0xdb, 0x4a,
+ /* (2^ 65)P */ 0xdf, 0x09, 0x06, 0xa9, 0xa2, 0x71, 0xcd, 0x3a, 0x50, 0x40, 0xd0, 0x6d, 0x85, 0x91, 0xe9, 0xe5, 0x3c, 0xc2, 0x57, 0x81, 0x68, 0x9b, 0xc6, 0x1e, 0x4d, 0xfe, 0x5c, 0x88, 0xf6, 0x27, 0x74, 0x69,
+ /* (2^ 66)P */ 0x51, 0xa8, 0xe1, 0x65, 0x9b, 0x7b, 0xbe, 0xd7, 0xdd, 0x36, 0xc5, 0x22, 0xd5, 0x28, 0x3d, 0xa0, 0x45, 0xb6, 0xd2, 0x8f, 0x65, 0x9d, 0x39, 0x28, 0xe1, 0x41, 0x26, 0x7c, 0xe1, 0xb7, 0xe5, 0x49,
+ /* (2^ 67)P */ 0xa4, 0x57, 0x04, 0x70, 0x98, 0x3a, 0x8c, 0x6f, 0x78, 0x67, 0xbb, 0x5e, 0xa2, 0xf0, 0x78, 0x50, 0x0f, 0x96, 0x82, 0xc3, 0xcb, 0x3c, 0x3c, 0xd1, 0xb1, 0x84, 0xdf, 0xa7, 0x58, 0x32, 0x00, 0x2e,
+ /* (2^ 68)P */ 0x1c, 0x6a, 0x29, 0xe6, 0x9b, 0xf3, 0xd1, 0x8a, 0xb2, 0xbf, 0x5f, 0x2a, 0x65, 0xaa, 0xee, 0xc1, 0xcb, 0xf3, 0x26, 0xfd, 0x73, 0x06, 0xee, 0x33, 0xcc, 0x2c, 0x9d, 0xa6, 0x73, 0x61, 0x25, 0x59,
+ /* (2^ 69)P */ 0x41, 0xfc, 0x18, 0x4e, 0xaa, 0x07, 0xea, 0x41, 0x1e, 0xa5, 0x87, 0x7c, 0x52, 0x19, 0xfc, 0xd9, 0x6f, 0xca, 0x31, 0x58, 0x80, 0xcb, 0xaa, 0xbd, 0x4f, 0x69, 0x16, 0xc9, 0x2d, 0x65, 0x5b, 0x44,
+ /* (2^ 70)P */ 0x15, 0x23, 0x17, 0xf2, 0xa7, 0xa3, 0x92, 0xce, 0x64, 0x99, 0x1b, 0xe1, 0x2d, 0x28, 0xdc, 0x1e, 0x4a, 0x31, 0x4c, 0xe0, 0xaf, 0x3a, 0x82, 0xa1, 0x86, 0xf5, 0x7c, 0x43, 0x94, 0x2d, 0x0a, 0x79,
+ /* (2^ 71)P */ 0x09, 0xe0, 0xf6, 0x93, 0xfb, 0x47, 0xc4, 0x71, 0x76, 0x52, 0x84, 0x22, 0x67, 0xa5, 0x22, 0x89, 0x69, 0x51, 0x4f, 0x20, 0x3b, 0x90, 0x70, 0xbf, 0xfe, 0x19, 0xa3, 0x1b, 0x89, 0x89, 0x7a, 0x2f,
+ /* (2^ 72)P */ 0x0c, 0x14, 0xe2, 0x77, 0xb5, 0x8e, 0xa0, 0x02, 0xf4, 0xdc, 0x7b, 0x42, 0xd4, 0x4e, 0x9a, 0xed, 0xd1, 0x3c, 0x32, 0xe4, 0x44, 0xec, 0x53, 0x52, 0x5b, 0x35, 0xe9, 0x14, 0x3c, 0x36, 0x88, 0x3e,
+ /* (2^ 73)P */ 0x8c, 0x0b, 0x11, 0x77, 0x42, 0xc1, 0x66, 0xaa, 0x90, 0x33, 0xa2, 0x10, 0x16, 0x39, 0xe0, 0x1a, 0xa2, 0xc2, 0x3f, 0xc9, 0x12, 0xbd, 0x30, 0x20, 0xab, 0xc7, 0x55, 0x95, 0x57, 0x41, 0xe1, 0x3e,
+ /* (2^ 74)P */ 0x41, 0x7d, 0x6e, 0x6d, 0x3a, 0xde, 0x14, 0x92, 0xfe, 0x7e, 0xf1, 0x07, 0x86, 0xd8, 0xcd, 0x3c, 0x17, 0x12, 0xe1, 0xf8, 0x88, 0x12, 0x4f, 0x67, 0xd0, 0x93, 0x9f, 0x32, 0x0f, 0x25, 0x82, 0x56,
+ /* (2^ 75)P */ 0x6e, 0x39, 0x2e, 0x6d, 0x13, 0x0b, 0xf0, 0x6c, 0xbf, 0xde, 0x14, 0x10, 0x6f, 0xf8, 0x4c, 0x6e, 0x83, 0x4e, 0xcc, 0xbf, 0xb5, 0xb1, 0x30, 0x59, 0xb6, 0x16, 0xba, 0x8a, 0xb4, 0x69, 0x70, 0x04,
+ /* (2^ 76)P */ 0x93, 0x07, 0xb2, 0x69, 0xab, 0xe4, 0x4c, 0x0d, 0x9e, 0xfb, 0xd0, 0x97, 0x1a, 0xb9, 0x4d, 0xb2, 0x1d, 0xd0, 0x00, 0x4e, 0xf5, 0x50, 0xfa, 0xcd, 0xb5, 0xdd, 0x8b, 0x36, 0x85, 0x10, 0x1b, 0x22,
+ /* (2^ 77)P */ 0xd2, 0xd8, 0xe3, 0xb1, 0x68, 0x94, 0xe5, 0xe7, 0x93, 0x2f, 0x12, 0xbd, 0x63, 0x65, 0xc5, 0x53, 0x09, 0x3f, 0x66, 0xe0, 0x03, 0xa9, 0xe8, 0xee, 0x42, 0x3d, 0xbe, 0xcb, 0x62, 0xa6, 0xef, 0x61,
+ /* (2^ 78)P */ 0x2a, 0xab, 0x6e, 0xde, 0xdd, 0xdd, 0xf8, 0x2c, 0x31, 0xf2, 0x35, 0x14, 0xd5, 0x0a, 0xf8, 0x9b, 0x73, 0x49, 0xf0, 0xc9, 0xce, 0xda, 0xea, 0x5d, 0x27, 0x9b, 0xd2, 0x41, 0x5d, 0x5b, 0x27, 0x29,
+ /* (2^ 79)P */ 0x4f, 0xf1, 0xeb, 0x95, 0x08, 0x0f, 0xde, 0xcf, 0xa7, 0x05, 0x49, 0x05, 0x6b, 0xb9, 0xaa, 0xb9, 0xfd, 0x20, 0xc4, 0xa1, 0xd9, 0x0d, 0xe8, 0xca, 0xc7, 0xbb, 0x73, 0x16, 0x2f, 0xbf, 0x63, 0x0a,
+ /* (2^ 80)P */ 0x8c, 0xbc, 0x8f, 0x95, 0x11, 0x6e, 0x2f, 0x09, 0xad, 0x2f, 0x82, 0x04, 0xe8, 0x81, 0x2a, 0x67, 0x17, 0x25, 0xd5, 0x60, 0x15, 0x35, 0xc8, 0xca, 0xf8, 0x92, 0xf1, 0xc8, 0x22, 0x77, 0x3f, 0x6f,
+ /* (2^ 81)P */ 0xb7, 0x94, 0xe8, 0xc2, 0xcc, 0x90, 0xba, 0xf8, 0x0d, 0x9f, 0xff, 0x38, 0xa4, 0x57, 0x75, 0x2c, 0x59, 0x23, 0xe5, 0x5a, 0x85, 0x1d, 0x4d, 0x89, 0x69, 0x3d, 0x74, 0x7b, 0x15, 0x22, 0xe1, 0x68,
+ /* (2^ 82)P */ 0xf3, 0x19, 0xb9, 0xcf, 0x70, 0x55, 0x7e, 0xd8, 0xb9, 0x8d, 0x79, 0x95, 0xcd, 0xde, 0x2c, 0x3f, 0xce, 0xa2, 0xc0, 0x10, 0x47, 0x15, 0x21, 0x21, 0xb2, 0xc5, 0x6d, 0x24, 0x15, 0xa1, 0x66, 0x3c,
+ /* (2^ 83)P */ 0x72, 0xcb, 0x4e, 0x29, 0x62, 0xc5, 0xed, 0xcb, 0x16, 0x0b, 0x28, 0x6a, 0xc3, 0x43, 0x71, 0xba, 0x67, 0x8b, 0x07, 0xd4, 0xef, 0xc2, 0x10, 0x96, 0x1e, 0x4b, 0x6a, 0x94, 0x5d, 0x73, 0x44, 0x61,
+ /* (2^ 84)P */ 0x50, 0x33, 0x5b, 0xd7, 0x1e, 0x11, 0x6f, 0x53, 0x1b, 0xd8, 0x41, 0x20, 0x8c, 0xdb, 0x11, 0x02, 0x3c, 0x41, 0x10, 0x0e, 0x00, 0xb1, 0x3c, 0xf9, 0x76, 0x88, 0x9e, 0x03, 0x3c, 0xfd, 0x9d, 0x14,
+ /* (2^ 85)P */ 0x5b, 0x15, 0x63, 0x6b, 0xe4, 0xdd, 0x79, 0xd4, 0x76, 0x79, 0x83, 0x3c, 0xe9, 0x15, 0x6e, 0xb6, 0x38, 0xe0, 0x13, 0x1f, 0x3b, 0xe4, 0xfd, 0xda, 0x35, 0x0b, 0x4b, 0x2e, 0x1a, 0xda, 0xaf, 0x5f,
+ /* (2^ 86)P */ 0x81, 0x75, 0x19, 0x17, 0xdf, 0xbb, 0x00, 0x36, 0xc2, 0xd2, 0x3c, 0xbe, 0x0b, 0x05, 0x72, 0x39, 0x86, 0xbe, 0xd5, 0xbd, 0x6d, 0x90, 0x38, 0x59, 0x0f, 0x86, 0x9b, 0x3f, 0xe4, 0xe5, 0xfc, 0x34,
+ /* (2^ 87)P */ 0x02, 0x4d, 0xd1, 0x42, 0xcd, 0xa4, 0xa8, 0x75, 0x65, 0xdf, 0x41, 0x34, 0xc5, 0xab, 0x8d, 0x82, 0xd3, 0x31, 0xe1, 0xd2, 0xed, 0xab, 0xdc, 0x33, 0x5f, 0xd2, 0x14, 0xb8, 0x6f, 0xd7, 0xba, 0x3e,
+ /* (2^ 88)P */ 0x0f, 0xe1, 0x70, 0x6f, 0x56, 0x6f, 0x90, 0xd4, 0x5a, 0x0f, 0x69, 0x51, 0xaa, 0xf7, 0x12, 0x5d, 0xf2, 0xfc, 0xce, 0x76, 0x6e, 0xb1, 0xad, 0x45, 0x99, 0x29, 0x23, 0xad, 0xae, 0x68, 0xf7, 0x01,
+ /* (2^ 89)P */ 0xbd, 0xfe, 0x48, 0x62, 0x7b, 0xc7, 0x6c, 0x2b, 0xfd, 0xaf, 0x3a, 0xec, 0x28, 0x06, 0xd3, 0x3c, 0x6a, 0x48, 0xef, 0xd4, 0x80, 0x0b, 0x1c, 0xce, 0x23, 0x6c, 0xf6, 0xa6, 0x2e, 0xff, 0x3b, 0x4c,
+ /* (2^ 90)P */ 0x5f, 0xeb, 0xea, 0x4a, 0x09, 0xc4, 0x2e, 0x3f, 0xa7, 0x2c, 0x37, 0x6e, 0x28, 0x9b, 0xb1, 0x61, 0x1d, 0x70, 0x2a, 0xde, 0x66, 0xa9, 0xef, 0x5e, 0xef, 0xe3, 0x55, 0xde, 0x65, 0x05, 0xb2, 0x23,
+ /* (2^ 91)P */ 0x57, 0x85, 0xd5, 0x79, 0x52, 0xca, 0x01, 0xe3, 0x4f, 0x87, 0xc2, 0x27, 0xce, 0xd4, 0xb2, 0x07, 0x67, 0x1d, 0xcf, 0x9d, 0x8a, 0xcd, 0x32, 0xa5, 0x56, 0xff, 0x2b, 0x3f, 0xe2, 0xfe, 0x52, 0x2a,
+ /* (2^ 92)P */ 0x3d, 0x66, 0xd8, 0x7c, 0xb3, 0xef, 0x24, 0x86, 0x94, 0x75, 0xbd, 0xff, 0x20, 0xac, 0xc7, 0xbb, 0x45, 0x74, 0xd3, 0x82, 0x9c, 0x5e, 0xb8, 0x57, 0x66, 0xec, 0xa6, 0x86, 0xcb, 0x52, 0x30, 0x7b,
+ /* (2^ 93)P */ 0x1e, 0xe9, 0x25, 0x25, 0xad, 0xf0, 0x82, 0x34, 0xa0, 0xdc, 0x8e, 0xd2, 0x43, 0x80, 0xb6, 0x2c, 0x3a, 0x00, 0x1b, 0x2e, 0x05, 0x6d, 0x4f, 0xaf, 0x0a, 0x1b, 0x78, 0x29, 0x25, 0x8c, 0x5f, 0x18,
+ /* (2^ 94)P */ 0xd6, 0xe0, 0x0c, 0xd8, 0x5b, 0xde, 0x41, 0xaa, 0xd6, 0xe9, 0x53, 0x68, 0x41, 0xb2, 0x07, 0x94, 0x3a, 0x4c, 0x7f, 0x35, 0x6e, 0xc3, 0x3e, 0x56, 0xce, 0x7b, 0x29, 0x0e, 0xdd, 0xb8, 0xc4, 0x4c,
+ /* (2^ 95)P */ 0x0e, 0x73, 0xb8, 0xff, 0x52, 0x1a, 0xfc, 0xa2, 0x37, 0x8e, 0x05, 0x67, 0x6e, 0xf1, 0x11, 0x18, 0xe1, 0x4e, 0xdf, 0xcd, 0x66, 0xa3, 0xf9, 0x10, 0x99, 0xf0, 0xb9, 0xa0, 0xc4, 0xa0, 0xf4, 0x72,
+ /* (2^ 96)P */ 0xa7, 0x4e, 0x3f, 0x66, 0x6f, 0xc0, 0x16, 0x8c, 0xba, 0x0f, 0x97, 0x4e, 0xf7, 0x3a, 0x3b, 0x69, 0x45, 0xc3, 0x9e, 0xd6, 0xf1, 0xe7, 0x02, 0x21, 0x89, 0x80, 0x8a, 0x96, 0xbc, 0x3c, 0xa5, 0x0b,
+ /* (2^ 97)P */ 0x37, 0x55, 0xa1, 0xfe, 0xc7, 0x9d, 0x3d, 0xca, 0x93, 0x64, 0x53, 0x51, 0xbb, 0x24, 0x68, 0x4c, 0xb1, 0x06, 0x40, 0x84, 0x14, 0x63, 0x88, 0xb9, 0x60, 0xcc, 0x54, 0xb4, 0x2a, 0xa7, 0xd2, 0x40,
+ /* (2^ 98)P */ 0x75, 0x09, 0x57, 0x12, 0xb7, 0xa1, 0x36, 0x59, 0x57, 0xa6, 0xbd, 0xde, 0x48, 0xd6, 0xb9, 0x91, 0xea, 0x30, 0x43, 0xb6, 0x4b, 0x09, 0x44, 0x33, 0xd0, 0x51, 0xee, 0x12, 0x0d, 0xa1, 0x6b, 0x00,
+ /* (2^ 99)P */ 0x58, 0x5d, 0xde, 0xf5, 0x68, 0x84, 0x22, 0x19, 0xb0, 0x05, 0xcc, 0x38, 0x4c, 0x2f, 0xb1, 0x0e, 0x90, 0x19, 0x60, 0xd5, 0x9d, 0x9f, 0x03, 0xa1, 0x0b, 0x0e, 0xff, 0x4f, 0xce, 0xd4, 0x02, 0x45,
+ /* (2^100)P */ 0x89, 0xc1, 0x37, 0x68, 0x10, 0x54, 0x20, 0xeb, 0x3c, 0xb9, 0xd3, 0x6d, 0x4c, 0x54, 0xf6, 0xd0, 0x4f, 0xd7, 0x16, 0xc4, 0x64, 0x70, 0x72, 0x40, 0xf0, 0x2e, 0x50, 0x4b, 0x11, 0xc6, 0x15, 0x6e,
+ /* (2^101)P */ 0x6b, 0xa7, 0xb1, 0xcf, 0x98, 0xa3, 0xf2, 0x4d, 0xb1, 0xf6, 0xf2, 0x19, 0x74, 0x6c, 0x25, 0x11, 0x43, 0x60, 0x6e, 0x06, 0x62, 0x79, 0x49, 0x4a, 0x44, 0x5b, 0x35, 0x41, 0xab, 0x3a, 0x5b, 0x70,
+ /* (2^102)P */ 0xd8, 0xb1, 0x97, 0xd7, 0x36, 0xf5, 0x5e, 0x36, 0xdb, 0xf0, 0xdd, 0x22, 0xd6, 0x6b, 0x07, 0x00, 0x88, 0x5a, 0x57, 0xe0, 0xb0, 0x33, 0xbf, 0x3b, 0x4d, 0xca, 0xe4, 0xc8, 0x05, 0xaa, 0x77, 0x37,
+ /* (2^103)P */ 0x5f, 0xdb, 0x78, 0x55, 0xc8, 0x45, 0x27, 0x39, 0xe2, 0x5a, 0xae, 0xdb, 0x49, 0x41, 0xda, 0x6f, 0x67, 0x98, 0xdc, 0x8a, 0x0b, 0xb0, 0xf0, 0xb1, 0xa3, 0x1d, 0x6f, 0xd3, 0x37, 0x34, 0x96, 0x09,
+ /* (2^104)P */ 0x53, 0x38, 0xdc, 0xa5, 0x90, 0x4e, 0x82, 0x7e, 0xbd, 0x5c, 0x13, 0x1f, 0x64, 0xf6, 0xb5, 0xcc, 0xcc, 0x8f, 0xce, 0x87, 0x6c, 0xd8, 0x36, 0x67, 0x9f, 0x24, 0x04, 0x66, 0xe2, 0x3c, 0x5f, 0x62,
+ /* (2^105)P */ 0x3f, 0xf6, 0x02, 0x95, 0x05, 0xc8, 0x8a, 0xaf, 0x69, 0x14, 0x35, 0x2e, 0x0a, 0xe7, 0x05, 0x0c, 0x05, 0x63, 0x4b, 0x76, 0x9c, 0x2e, 0x29, 0x35, 0xc3, 0x3a, 0xe2, 0xc7, 0x60, 0x43, 0x39, 0x1a,
+ /* (2^106)P */ 0x64, 0x32, 0x18, 0x51, 0x32, 0xd5, 0xc6, 0xd5, 0x4f, 0xb7, 0xc2, 0x43, 0xbd, 0x5a, 0x06, 0x62, 0x9b, 0x3f, 0x97, 0x3b, 0xd0, 0xf5, 0xfb, 0xb5, 0x5e, 0x6e, 0x20, 0x61, 0x36, 0xda, 0xa3, 0x13,
+ /* (2^107)P */ 0xe5, 0x94, 0x5d, 0x72, 0x37, 0x58, 0xbd, 0xc6, 0xc5, 0x16, 0x50, 0x20, 0x12, 0x09, 0xe3, 0x18, 0x68, 0x3c, 0x03, 0x70, 0x15, 0xce, 0x88, 0x20, 0x87, 0x79, 0x83, 0x5c, 0x49, 0x1f, 0xba, 0x7f,
+ /* (2^108)P */ 0x9d, 0x07, 0xf9, 0xf2, 0x23, 0x74, 0x8c, 0x5a, 0xc5, 0x3f, 0x02, 0x34, 0x7b, 0x15, 0x35, 0x17, 0x51, 0xb3, 0xfa, 0xd2, 0x9a, 0xb4, 0xf9, 0xe4, 0x3c, 0xe3, 0x78, 0xc8, 0x72, 0xff, 0x91, 0x66,
+ /* (2^109)P */ 0x3e, 0xff, 0x5e, 0xdc, 0xde, 0x2a, 0x2c, 0x12, 0xf4, 0x6c, 0x95, 0xd8, 0xf1, 0x4b, 0xdd, 0xf8, 0xda, 0x5b, 0x9e, 0x9e, 0x5d, 0x20, 0x86, 0xeb, 0x43, 0xc7, 0x75, 0xd9, 0xb9, 0x92, 0x9b, 0x04,
+ /* (2^110)P */ 0x5a, 0xc0, 0xf6, 0xb0, 0x30, 0x97, 0x37, 0xa5, 0x53, 0xa5, 0xf3, 0xc6, 0xac, 0xff, 0xa0, 0x72, 0x6d, 0xcd, 0x0d, 0xb2, 0x34, 0x2c, 0x03, 0xb0, 0x4a, 0x16, 0xd5, 0x88, 0xbc, 0x9d, 0x0e, 0x47,
+ /* (2^111)P */ 0x47, 0xc0, 0x37, 0xa2, 0x0c, 0xf1, 0x9c, 0xb1, 0xa2, 0x81, 0x6c, 0x1f, 0x71, 0x66, 0x54, 0xb6, 0x43, 0x0b, 0xd8, 0x6d, 0xd1, 0x1b, 0x32, 0xb3, 0x8e, 0xbe, 0x5f, 0x0c, 0x60, 0x4f, 0xc1, 0x48,
+ /* (2^112)P */ 0x03, 0xc8, 0xa6, 0x4a, 0x26, 0x1c, 0x45, 0x66, 0xa6, 0x7d, 0xfa, 0xa4, 0x04, 0x39, 0x6e, 0xb6, 0x95, 0x83, 0x12, 0xb3, 0xb0, 0x19, 0x5f, 0xd4, 0x10, 0xbc, 0xc9, 0xc3, 0x27, 0x26, 0x60, 0x31,
+ /* (2^113)P */ 0x0d, 0xe1, 0xe4, 0x32, 0x48, 0xdc, 0x20, 0x31, 0xf7, 0x17, 0xc7, 0x56, 0x67, 0xc4, 0x20, 0xeb, 0x94, 0x02, 0x28, 0x67, 0x3f, 0x2e, 0xf5, 0x00, 0x09, 0xc5, 0x30, 0x47, 0xc1, 0x4f, 0x6d, 0x56,
+ /* (2^114)P */ 0x06, 0x72, 0x83, 0xfd, 0x40, 0x5d, 0x3a, 0x7e, 0x7a, 0x54, 0x59, 0x71, 0xdc, 0x26, 0xe9, 0xc1, 0x95, 0x60, 0x8d, 0xa6, 0xfb, 0x30, 0x67, 0x21, 0xa7, 0xce, 0x69, 0x3f, 0x84, 0xc3, 0xe8, 0x22,
+ /* (2^115)P */ 0x2b, 0x4b, 0x0e, 0x93, 0xe8, 0x74, 0xd0, 0x33, 0x16, 0x58, 0xd1, 0x84, 0x0e, 0x35, 0xe4, 0xb6, 0x65, 0x23, 0xba, 0xd6, 0x6a, 0xc2, 0x34, 0x55, 0xf3, 0xf3, 0xf1, 0x89, 0x2f, 0xc1, 0x73, 0x77,
+ /* (2^116)P */ 0xaa, 0x62, 0x79, 0xa5, 0x4d, 0x40, 0xba, 0x8c, 0x56, 0xce, 0x99, 0x19, 0xa8, 0x97, 0x98, 0x5b, 0xfc, 0x92, 0x16, 0x12, 0x2f, 0x86, 0x8e, 0x50, 0x91, 0xc2, 0x93, 0xa0, 0x7f, 0x90, 0x81, 0x3a,
+ /* (2^117)P */ 0x10, 0xa5, 0x25, 0x47, 0xff, 0xd0, 0xde, 0x0d, 0x03, 0xc5, 0x3f, 0x67, 0x10, 0xcc, 0xd8, 0x10, 0x89, 0x4e, 0x1f, 0x9f, 0x1c, 0x15, 0x9d, 0x5b, 0x4c, 0xa4, 0x09, 0xcb, 0xd5, 0xc1, 0xa5, 0x32,
+ /* (2^118)P */ 0xfb, 0x41, 0x05, 0xb9, 0x42, 0xa4, 0x0a, 0x1e, 0xdb, 0x85, 0xb4, 0xc1, 0x7c, 0xeb, 0x85, 0x5f, 0xe5, 0xf2, 0x9d, 0x8a, 0xce, 0x95, 0xe5, 0xbe, 0x36, 0x22, 0x42, 0x22, 0xc7, 0x96, 0xe4, 0x25,
+ /* (2^119)P */ 0xb9, 0xe5, 0x0f, 0xcd, 0x46, 0x3c, 0xdf, 0x5e, 0x88, 0x33, 0xa4, 0xd2, 0x7e, 0x5a, 0xe7, 0x34, 0x52, 0xe3, 0x61, 0xd7, 0x11, 0xde, 0x88, 0xe4, 0x5c, 0x54, 0x85, 0xa0, 0x01, 0x8a, 0x87, 0x0e,
+ /* (2^120)P */ 0x04, 0xbb, 0x21, 0xe0, 0x77, 0x3c, 0x49, 0xba, 0x9a, 0x89, 0xdf, 0xc7, 0x43, 0x18, 0x4d, 0x2b, 0x67, 0x0d, 0xe8, 0x7a, 0x48, 0x7a, 0xa3, 0x9e, 0x94, 0x17, 0xe4, 0x11, 0x80, 0x95, 0xa9, 0x67,
+ /* (2^121)P */ 0x65, 0xb0, 0x97, 0x66, 0x1a, 0x05, 0x58, 0x4b, 0xd4, 0xa6, 0x6b, 0x8d, 0x7d, 0x3f, 0xe3, 0x47, 0xc1, 0x46, 0xca, 0x83, 0xd4, 0xa8, 0x4d, 0xbb, 0x0d, 0xdb, 0xc2, 0x81, 0xa1, 0xca, 0xbe, 0x68,
+ /* (2^122)P */ 0xa5, 0x9a, 0x98, 0x0b, 0xe9, 0x80, 0x89, 0x8d, 0x9b, 0xc9, 0x93, 0x2c, 0x4a, 0xb1, 0x5e, 0xf9, 0xa2, 0x73, 0x6e, 0x79, 0xc4, 0xc7, 0xc6, 0x51, 0x69, 0xb5, 0xef, 0xb5, 0x63, 0x83, 0x22, 0x6e,
+ /* (2^123)P */ 0xc8, 0x24, 0xd6, 0x2d, 0xb0, 0xc0, 0xbb, 0xc6, 0xee, 0x70, 0x81, 0xec, 0x7d, 0xb4, 0x7e, 0x77, 0xa9, 0xaf, 0xcf, 0x04, 0xa0, 0x15, 0xde, 0x3c, 0x9b, 0xbf, 0x60, 0x71, 0x08, 0xbc, 0xc6, 0x1d,
+ /* (2^124)P */ 0x02, 0x40, 0xc3, 0xee, 0x43, 0xe0, 0x07, 0x2e, 0x7f, 0xdc, 0x68, 0x7a, 0x67, 0xfc, 0xe9, 0x18, 0x9a, 0x5b, 0xd1, 0x8b, 0x18, 0x03, 0xda, 0xd8, 0x53, 0x82, 0x56, 0x00, 0xbb, 0xc3, 0xfb, 0x48,
+ /* (2^125)P */ 0xe1, 0x4c, 0x65, 0xfb, 0x4c, 0x7d, 0x54, 0x57, 0xad, 0xe2, 0x58, 0xa0, 0x82, 0x5b, 0x56, 0xd3, 0x78, 0x44, 0x15, 0xbf, 0x0b, 0xaf, 0x3e, 0xf6, 0x18, 0xbb, 0xdf, 0x14, 0xf1, 0x1e, 0x53, 0x47,
+ /* (2^126)P */ 0x87, 0xc5, 0x78, 0x42, 0x0a, 0x63, 0xec, 0xe1, 0xf3, 0x83, 0x8e, 0xca, 0x46, 0xd5, 0x07, 0x55, 0x2b, 0x0c, 0xdc, 0x3a, 0xc6, 0x35, 0xe1, 0x85, 0x4e, 0x84, 0x82, 0x56, 0xa8, 0xef, 0xa7, 0x0a,
+ /* (2^127)P */ 0x15, 0xf6, 0xe1, 0xb3, 0xa8, 0x1b, 0x69, 0x72, 0xfa, 0x3f, 0xbe, 0x1f, 0x70, 0xe9, 0xb4, 0x32, 0x68, 0x78, 0xbb, 0x39, 0x2e, 0xd9, 0xb6, 0x97, 0xe8, 0x39, 0x2e, 0xa0, 0xde, 0x53, 0xfe, 0x2c,
+ /* (2^128)P */ 0xb0, 0x52, 0xcd, 0x85, 0xcd, 0x92, 0x73, 0x68, 0x31, 0x98, 0xe2, 0x10, 0xc9, 0x66, 0xff, 0x27, 0x06, 0x2d, 0x83, 0xa9, 0x56, 0x45, 0x13, 0x97, 0xa0, 0xf8, 0x84, 0x0a, 0x36, 0xb0, 0x9b, 0x26,
+ /* (2^129)P */ 0x5c, 0xf8, 0x43, 0x76, 0x45, 0x55, 0x6e, 0x70, 0x1b, 0x7d, 0x59, 0x9b, 0x8c, 0xa4, 0x34, 0x37, 0x72, 0xa4, 0xef, 0xc6, 0xe8, 0x91, 0xee, 0x7a, 0xe0, 0xd9, 0xa9, 0x98, 0xc1, 0xab, 0xd6, 0x5c,
+ /* (2^130)P */ 0x1a, 0xe4, 0x3c, 0xcb, 0x06, 0xde, 0x04, 0x0e, 0x38, 0xe1, 0x02, 0x34, 0x89, 0xeb, 0xc6, 0xd8, 0x72, 0x37, 0x6e, 0x68, 0xbb, 0x59, 0x46, 0x90, 0xc8, 0xa8, 0x6b, 0x74, 0x71, 0xc3, 0x15, 0x72,
+ /* (2^131)P */ 0xd9, 0xa2, 0xe4, 0xea, 0x7e, 0xa9, 0x12, 0xfd, 0xc5, 0xf2, 0x94, 0x63, 0x51, 0xb7, 0x14, 0x95, 0x94, 0xf2, 0x08, 0x92, 0x80, 0xd5, 0x6f, 0x26, 0xb9, 0x26, 0x9a, 0x61, 0x85, 0x70, 0x84, 0x5c,
+ /* (2^132)P */ 0xea, 0x94, 0xd6, 0xfe, 0x10, 0x54, 0x98, 0x52, 0x54, 0xd2, 0x2e, 0x4a, 0x93, 0x5b, 0x90, 0x3c, 0x67, 0xe4, 0x3b, 0x2d, 0x69, 0x47, 0xbb, 0x10, 0xe1, 0xe9, 0xe5, 0x69, 0x2d, 0x3d, 0x3b, 0x06,
+ /* (2^133)P */ 0xeb, 0x7d, 0xa5, 0xdd, 0xee, 0x26, 0x27, 0x47, 0x91, 0x18, 0xf4, 0x10, 0xae, 0xc4, 0xb6, 0xef, 0x14, 0x76, 0x30, 0x7b, 0x91, 0x41, 0x16, 0x2b, 0x7c, 0x5b, 0xf4, 0xc4, 0x4f, 0x55, 0x7c, 0x11,
+ /* (2^134)P */ 0x12, 0x88, 0x9d, 0x8f, 0x11, 0xf3, 0x7c, 0xc0, 0x39, 0x79, 0x01, 0x50, 0x20, 0xd8, 0xdb, 0x01, 0x27, 0x28, 0x1b, 0x17, 0xf4, 0x03, 0xe8, 0xd7, 0xea, 0x25, 0xd2, 0x87, 0x74, 0xe8, 0x15, 0x10,
+ /* (2^135)P */ 0x4d, 0xcc, 0x3a, 0xd2, 0xfe, 0xe3, 0x8d, 0xc5, 0x2d, 0xbe, 0xa7, 0x94, 0xc2, 0x91, 0xdb, 0x50, 0x57, 0xf4, 0x9c, 0x1c, 0x3d, 0xd4, 0x94, 0x0b, 0x4a, 0x52, 0x37, 0x6e, 0xfa, 0x40, 0x16, 0x6b,
+ /* (2^136)P */ 0x09, 0x0d, 0xda, 0x5f, 0x6c, 0x34, 0x2f, 0x69, 0x51, 0x31, 0x4d, 0xfa, 0x59, 0x1c, 0x0b, 0x20, 0x96, 0xa2, 0x77, 0x07, 0x76, 0x6f, 0xc4, 0xb8, 0xcf, 0xfb, 0xfd, 0x3f, 0x5f, 0x39, 0x38, 0x4b,
+ /* (2^137)P */ 0x71, 0xd6, 0x54, 0xbe, 0x00, 0x5e, 0xd2, 0x18, 0xa6, 0xab, 0xc8, 0xbe, 0x82, 0x05, 0xd5, 0x60, 0x82, 0xb9, 0x78, 0x3b, 0x26, 0x8f, 0xad, 0x87, 0x32, 0x04, 0xda, 0x9c, 0x4e, 0xf6, 0xfd, 0x50,
+ /* (2^138)P */ 0xf0, 0xdc, 0x78, 0xc5, 0xaa, 0x67, 0xf5, 0x90, 0x3b, 0x13, 0xa3, 0xf2, 0x0e, 0x9b, 0x1e, 0xef, 0x71, 0xde, 0xd9, 0x42, 0x92, 0xba, 0xeb, 0x0e, 0xc7, 0x01, 0x31, 0xf0, 0x9b, 0x3c, 0x47, 0x15,
+ /* (2^139)P */ 0x95, 0x80, 0xb7, 0x56, 0xae, 0xe8, 0x77, 0x7c, 0x8e, 0x07, 0x6f, 0x6e, 0x66, 0xe7, 0x78, 0xb6, 0x1f, 0xba, 0x48, 0x53, 0x61, 0xb9, 0xa0, 0x2d, 0x0b, 0x3f, 0x73, 0xff, 0xc1, 0x31, 0xf9, 0x7c,
+ /* (2^140)P */ 0x6c, 0x36, 0x0a, 0x0a, 0xf5, 0x57, 0xb3, 0x26, 0x32, 0xd7, 0x87, 0x2b, 0xf4, 0x8c, 0x70, 0xe9, 0xc0, 0xb2, 0x1c, 0xf9, 0xa5, 0xee, 0x3a, 0xc1, 0x4c, 0xbb, 0x43, 0x11, 0x99, 0x0c, 0xd9, 0x35,
+ /* (2^141)P */ 0xdc, 0xd9, 0xa0, 0xa9, 0x04, 0xc4, 0xc1, 0x47, 0x51, 0xd2, 0x72, 0x19, 0x45, 0x58, 0x9e, 0x65, 0x31, 0x8c, 0xb3, 0x73, 0xc4, 0xa8, 0x75, 0x38, 0x24, 0x1f, 0x56, 0x79, 0xd3, 0x9e, 0xbd, 0x1f,
+ /* (2^142)P */ 0x8d, 0xc2, 0x1e, 0xd4, 0x6f, 0xbc, 0xfa, 0x11, 0xca, 0x2d, 0x2a, 0xcd, 0xe3, 0xdf, 0xf8, 0x7e, 0x95, 0x45, 0x40, 0x8c, 0x5d, 0x3b, 0xe7, 0x72, 0x27, 0x2f, 0xb7, 0x54, 0x49, 0xfa, 0x35, 0x61,
+ /* (2^143)P */ 0x9c, 0xb6, 0x24, 0xde, 0xa2, 0x32, 0xfc, 0xcc, 0x88, 0x5d, 0x09, 0x1f, 0x8c, 0x69, 0x55, 0x3f, 0x29, 0xf9, 0xc3, 0x5a, 0xed, 0x50, 0x33, 0xbe, 0xeb, 0x7e, 0x47, 0xca, 0x06, 0xf8, 0x9b, 0x5e,
+ /* (2^144)P */ 0x68, 0x9f, 0x30, 0x3c, 0xb6, 0x8f, 0xce, 0xe9, 0xf4, 0xf9, 0xe1, 0x65, 0x35, 0xf6, 0x76, 0x53, 0xf1, 0x93, 0x63, 0x5a, 0xb3, 0xcf, 0xaf, 0xd1, 0x06, 0x35, 0x62, 0xe5, 0xed, 0xa1, 0x32, 0x66,
+ /* (2^145)P */ 0x4c, 0xed, 0x2d, 0x0c, 0x39, 0x6c, 0x7d, 0x0b, 0x1f, 0xcb, 0x04, 0xdf, 0x81, 0x32, 0xcb, 0x56, 0xc7, 0xc3, 0xec, 0x49, 0x12, 0x5a, 0x30, 0x66, 0x2a, 0xa7, 0x8c, 0xa3, 0x60, 0x8b, 0x58, 0x5d,
+ /* (2^146)P */ 0x2d, 0xf4, 0xe5, 0xe8, 0x78, 0xbf, 0xec, 0xa6, 0xec, 0x3e, 0x8a, 0x3c, 0x4b, 0xb4, 0xee, 0x86, 0x04, 0x16, 0xd2, 0xfb, 0x48, 0x9c, 0x21, 0xec, 0x31, 0x67, 0xc3, 0x17, 0xf5, 0x1a, 0xaf, 0x1a,
+ /* (2^147)P */ 0xe7, 0xbd, 0x69, 0x67, 0x83, 0xa2, 0x06, 0xc3, 0xdb, 0x2a, 0x1e, 0x2b, 0x62, 0x80, 0x82, 0x20, 0xa6, 0x94, 0xff, 0xfb, 0x1f, 0xf5, 0x27, 0x80, 0x6b, 0xf2, 0x24, 0x11, 0xce, 0xa1, 0xcf, 0x76,
+ /* (2^148)P */ 0xb6, 0xab, 0x22, 0x24, 0x56, 0x00, 0xeb, 0x18, 0xc3, 0x29, 0x8c, 0x8f, 0xd5, 0xc4, 0x77, 0xf3, 0x1a, 0x56, 0x31, 0xf5, 0x07, 0xc2, 0xbb, 0x4d, 0x27, 0x8a, 0x12, 0x82, 0xf0, 0xb7, 0x53, 0x02,
+ /* (2^149)P */ 0xe0, 0x17, 0x2c, 0xb6, 0x1c, 0x09, 0x1f, 0x3d, 0xa9, 0x28, 0x46, 0xd6, 0xab, 0xe1, 0x60, 0x48, 0x53, 0x42, 0x9d, 0x30, 0x36, 0x74, 0xd1, 0x52, 0x76, 0xe5, 0xfa, 0x3e, 0xe1, 0x97, 0x6f, 0x35,
+ /* (2^150)P */ 0x5b, 0x53, 0x50, 0xa1, 0x1a, 0xe1, 0x51, 0xd3, 0xcc, 0x78, 0xd8, 0x1d, 0xbb, 0x45, 0x6b, 0x3e, 0x98, 0x2c, 0xd9, 0xbe, 0x28, 0x61, 0x77, 0x0c, 0xb8, 0x85, 0x28, 0x03, 0x93, 0xae, 0x34, 0x1d,
+ /* (2^151)P */ 0xc3, 0xa4, 0x5b, 0xa8, 0x8c, 0x48, 0xa0, 0x4b, 0xce, 0xe6, 0x9c, 0x3c, 0xc3, 0x48, 0x53, 0x98, 0x70, 0xa7, 0xbd, 0x97, 0x6f, 0x4c, 0x12, 0x66, 0x4a, 0x12, 0x54, 0x06, 0x29, 0xa0, 0x81, 0x0f,
+ /* (2^152)P */ 0xfd, 0x86, 0x9b, 0x56, 0xa6, 0x9c, 0xd0, 0x9e, 0x2d, 0x9a, 0xaf, 0x18, 0xfd, 0x09, 0x10, 0x81, 0x0a, 0xc2, 0xd8, 0x93, 0x3f, 0xd0, 0x08, 0xff, 0x6b, 0xf2, 0xae, 0x9f, 0x19, 0x48, 0xa1, 0x52,
+ /* (2^153)P */ 0x73, 0x1b, 0x8d, 0x2d, 0xdc, 0xf9, 0x03, 0x3e, 0x70, 0x1a, 0x96, 0x73, 0x18, 0x80, 0x05, 0x42, 0x70, 0x59, 0xa3, 0x41, 0xf0, 0x87, 0xd9, 0xc0, 0x49, 0xd5, 0xc0, 0xa1, 0x15, 0x1f, 0xaa, 0x07,
+ /* (2^154)P */ 0x24, 0x72, 0xd2, 0x8c, 0xe0, 0x6c, 0xd4, 0xdf, 0x39, 0x42, 0x4e, 0x93, 0x4f, 0x02, 0x0a, 0x6d, 0x59, 0x7b, 0x89, 0x99, 0x63, 0x7a, 0x8a, 0x80, 0xa2, 0x95, 0x3d, 0xe1, 0xe9, 0x56, 0x45, 0x0a,
+ /* (2^155)P */ 0x45, 0x30, 0xc1, 0xe9, 0x1f, 0x99, 0x1a, 0xd2, 0xb8, 0x51, 0x77, 0xfe, 0x48, 0x85, 0x0e, 0x9b, 0x35, 0x00, 0xf3, 0x4b, 0xcb, 0x43, 0xa6, 0x5d, 0x21, 0xf7, 0x40, 0x39, 0xd6, 0x28, 0xdb, 0x77,
+ /* (2^156)P */ 0x11, 0x90, 0xdc, 0x4a, 0x61, 0xeb, 0x5e, 0xfc, 0xeb, 0x11, 0xc4, 0xe8, 0x9a, 0x41, 0x29, 0x52, 0x74, 0xcf, 0x1d, 0x7d, 0x78, 0xe7, 0xc3, 0x9e, 0xb5, 0x4c, 0x6e, 0x21, 0x3e, 0x05, 0x0d, 0x34,
+ /* (2^157)P */ 0xb4, 0xf2, 0x8d, 0xb4, 0x39, 0xaf, 0xc7, 0xca, 0x94, 0x0a, 0xa1, 0x71, 0x28, 0xec, 0xfa, 0xc0, 0xed, 0x75, 0xa5, 0x5c, 0x24, 0x69, 0x0a, 0x14, 0x4c, 0x3a, 0x27, 0x34, 0x71, 0xc3, 0xf1, 0x0c,
+ /* (2^158)P */ 0xa5, 0xb8, 0x24, 0xc2, 0x6a, 0x30, 0xee, 0xc8, 0xb0, 0x30, 0x49, 0xcb, 0x7c, 0xee, 0xea, 0x57, 0x4f, 0xe7, 0xcb, 0xaa, 0xbd, 0x06, 0xe8, 0xa1, 0x7d, 0x65, 0xeb, 0x2e, 0x74, 0x62, 0x9a, 0x7d,
+ /* (2^159)P */ 0x30, 0x48, 0x6c, 0x54, 0xef, 0xb6, 0xb6, 0x9e, 0x2e, 0x6e, 0xb3, 0xdd, 0x1f, 0xca, 0x5c, 0x88, 0x05, 0x71, 0x0d, 0xef, 0x83, 0xf3, 0xb9, 0xe6, 0x12, 0x04, 0x2e, 0x9d, 0xef, 0x4f, 0x65, 0x58,
+ /* (2^160)P */ 0x26, 0x8e, 0x0e, 0xbe, 0xff, 0xc4, 0x05, 0xa9, 0x6e, 0x81, 0x31, 0x9b, 0xdf, 0xe5, 0x2d, 0x94, 0xe1, 0x88, 0x2e, 0x80, 0x3f, 0x72, 0x7d, 0x49, 0x8d, 0x40, 0x2f, 0x60, 0xea, 0x4d, 0x68, 0x30,
+ /* (2^161)P */ 0x34, 0xcb, 0xe6, 0xa3, 0x78, 0xa2, 0xe5, 0x21, 0xc4, 0x1d, 0x15, 0x5b, 0x6f, 0x6e, 0xfb, 0xae, 0x15, 0xca, 0x77, 0x9d, 0x04, 0x8e, 0x0b, 0xb3, 0x81, 0x89, 0xb9, 0x53, 0xcf, 0xc9, 0xc3, 0x28,
+ /* (2^162)P */ 0x2a, 0xdd, 0x6c, 0x55, 0x21, 0xb7, 0x7f, 0x28, 0x74, 0x22, 0x02, 0x97, 0xa8, 0x7c, 0x31, 0x0d, 0x58, 0x32, 0x54, 0x3a, 0x42, 0xc7, 0x68, 0x74, 0x2f, 0x64, 0xb5, 0x4e, 0x46, 0x11, 0x7f, 0x4a,
+ /* (2^163)P */ 0xa6, 0x3a, 0x19, 0x4d, 0x77, 0xa4, 0x37, 0xa2, 0xa1, 0x29, 0x21, 0xa9, 0x6e, 0x98, 0x65, 0xd8, 0x88, 0x1a, 0x7c, 0xf8, 0xec, 0x15, 0xc5, 0x24, 0xeb, 0xf5, 0x39, 0x5f, 0x57, 0x03, 0x40, 0x60,
+ /* (2^164)P */ 0x27, 0x9b, 0x0a, 0x57, 0x89, 0xf1, 0xb9, 0x47, 0x78, 0x4b, 0x5e, 0x46, 0xde, 0xce, 0x98, 0x2b, 0x20, 0x5c, 0xb8, 0xdb, 0x51, 0xf5, 0x6d, 0x02, 0x01, 0x19, 0xe2, 0x47, 0x10, 0xd9, 0xfc, 0x74,
+ /* (2^165)P */ 0xa3, 0xbf, 0xc1, 0x23, 0x0a, 0xa9, 0xe2, 0x13, 0xf6, 0x19, 0x85, 0x47, 0x4e, 0x07, 0xb0, 0x0c, 0x44, 0xcf, 0xf6, 0x3a, 0xbe, 0xcb, 0xf1, 0x5f, 0xbe, 0x2d, 0x81, 0xbe, 0x38, 0x54, 0xfe, 0x67,
+ /* (2^166)P */ 0xb0, 0x05, 0x0f, 0xa4, 0x4f, 0xf6, 0x3c, 0xd1, 0x87, 0x37, 0x28, 0x32, 0x2f, 0xfb, 0x4d, 0x05, 0xea, 0x2a, 0x0d, 0x7f, 0x5b, 0x91, 0x73, 0x41, 0x4e, 0x0d, 0x61, 0x1f, 0x4f, 0x14, 0x2f, 0x48,
+ /* (2^167)P */ 0x34, 0x82, 0x7f, 0xb4, 0x01, 0x02, 0x21, 0xf6, 0x90, 0xb9, 0x70, 0x9e, 0x92, 0xe1, 0x0a, 0x5d, 0x7c, 0x56, 0x49, 0xb0, 0x55, 0xf4, 0xd7, 0xdc, 0x01, 0x6f, 0x91, 0xf0, 0xf1, 0xd0, 0x93, 0x7e,
+ /* (2^168)P */ 0xfa, 0xb4, 0x7d, 0x8a, 0xf1, 0xcb, 0x79, 0xdd, 0x2f, 0xc6, 0x74, 0x6f, 0xbf, 0x91, 0x83, 0xbe, 0xbd, 0x91, 0x82, 0x4b, 0xd1, 0x45, 0x71, 0x02, 0x05, 0x17, 0xbf, 0x2c, 0xea, 0x73, 0x5a, 0x58,
+ /* (2^169)P */ 0xb2, 0x0d, 0x8a, 0x92, 0x3e, 0xa0, 0x5c, 0x48, 0xe7, 0x57, 0x28, 0x74, 0xa5, 0x01, 0xfc, 0x10, 0xa7, 0x51, 0xd5, 0xd6, 0xdb, 0x2e, 0x48, 0x2f, 0x8a, 0xdb, 0x8f, 0x04, 0xb5, 0x33, 0x04, 0x0f,
+ /* (2^170)P */ 0x47, 0x62, 0xdc, 0xd7, 0x8d, 0x2e, 0xda, 0x60, 0x9a, 0x81, 0xd4, 0x8c, 0xd3, 0xc9, 0xb4, 0x88, 0x97, 0x66, 0xf6, 0x01, 0xc0, 0x3a, 0x03, 0x13, 0x75, 0x7d, 0x36, 0x3b, 0xfe, 0x24, 0x3b, 0x27,
+ /* (2^171)P */ 0xd4, 0xb9, 0xb3, 0x31, 0x6a, 0xf6, 0xe8, 0xc6, 0xd5, 0x49, 0xdf, 0x94, 0xa4, 0x14, 0x15, 0x28, 0xa7, 0x3d, 0xb2, 0xc8, 0xdf, 0x6f, 0x72, 0xd1, 0x48, 0xe5, 0xde, 0x03, 0xd1, 0xe7, 0x3a, 0x4b,
+ /* (2^172)P */ 0x7e, 0x9d, 0x4b, 0xce, 0x19, 0x6e, 0x25, 0xc6, 0x1c, 0xc6, 0xe3, 0x86, 0xf1, 0x5c, 0x5c, 0xff, 0x45, 0xc1, 0x8e, 0x4b, 0xa3, 0x3c, 0xc6, 0xac, 0x74, 0x65, 0xe6, 0xfe, 0x88, 0x18, 0x62, 0x74,
+ /* (2^173)P */ 0x1e, 0x0a, 0x29, 0x45, 0x96, 0x40, 0x6f, 0x95, 0x2e, 0x96, 0x3a, 0x26, 0xe3, 0xf8, 0x0b, 0xef, 0x7b, 0x64, 0xc2, 0x5e, 0xeb, 0x50, 0x6a, 0xed, 0x02, 0x75, 0xca, 0x9d, 0x3a, 0x28, 0x94, 0x06,
+ /* (2^174)P */ 0xd1, 0xdc, 0xa2, 0x43, 0x36, 0x96, 0x9b, 0x76, 0x53, 0x53, 0xfc, 0x09, 0xea, 0xc8, 0xb7, 0x42, 0xab, 0x7e, 0x39, 0x13, 0xee, 0x2a, 0x00, 0x4f, 0x3a, 0xd6, 0xb7, 0x19, 0x2c, 0x5e, 0x00, 0x63,
+ /* (2^175)P */ 0xea, 0x3b, 0x02, 0x63, 0xda, 0x36, 0x67, 0xca, 0xb7, 0x99, 0x2a, 0xb1, 0x6d, 0x7f, 0x6c, 0x96, 0xe1, 0xc5, 0x37, 0xc5, 0x90, 0x93, 0xe0, 0xac, 0xee, 0x89, 0xaa, 0xa1, 0x63, 0x60, 0x69, 0x0b,
+ /* (2^176)P */ 0xe5, 0x56, 0x8c, 0x28, 0x97, 0x3e, 0xb0, 0xeb, 0xe8, 0x8b, 0x8c, 0x93, 0x9f, 0x9f, 0x2a, 0x43, 0x71, 0x7f, 0x71, 0x5b, 0x3d, 0xa9, 0xa5, 0xa6, 0x97, 0x9d, 0x8f, 0xe1, 0xc3, 0xb4, 0x5f, 0x1a,
+ /* (2^177)P */ 0xce, 0xcd, 0x60, 0x1c, 0xad, 0xe7, 0x94, 0x1c, 0xa0, 0xc4, 0x02, 0xfc, 0x43, 0x2a, 0x20, 0xee, 0x20, 0x6a, 0xc4, 0x67, 0xd8, 0xe4, 0xaf, 0x8d, 0x58, 0x7b, 0xc2, 0x8a, 0x3c, 0x26, 0x10, 0x0a,
+ /* (2^178)P */ 0x4a, 0x2a, 0x43, 0xe4, 0xdf, 0xa9, 0xde, 0xd0, 0xc5, 0x77, 0x92, 0xbe, 0x7b, 0xf8, 0x6a, 0x85, 0x1a, 0xc7, 0x12, 0xc2, 0xac, 0x72, 0x84, 0xce, 0x91, 0x1e, 0xbb, 0x9b, 0x6d, 0x1b, 0x15, 0x6f,
+ /* (2^179)P */ 0x6a, 0xd5, 0xee, 0x7c, 0x52, 0x6c, 0x77, 0x26, 0xec, 0xfa, 0xf8, 0xfb, 0xb7, 0x1c, 0x21, 0x7d, 0xcc, 0x09, 0x46, 0xfd, 0xa6, 0x66, 0xae, 0x37, 0x42, 0x0c, 0x77, 0xd2, 0x02, 0xb7, 0x81, 0x1f,
+ /* (2^180)P */ 0x92, 0x83, 0xc5, 0xea, 0x57, 0xb0, 0xb0, 0x2f, 0x9d, 0x4e, 0x74, 0x29, 0xfe, 0x89, 0xdd, 0xe1, 0xf8, 0xb4, 0xbe, 0x17, 0xeb, 0xf8, 0x64, 0xc9, 0x1e, 0xd4, 0xa2, 0xc9, 0x73, 0x10, 0x57, 0x29,
+ /* (2^181)P */ 0x54, 0xe2, 0xc0, 0x81, 0x89, 0xa1, 0x48, 0xa9, 0x30, 0x28, 0xb2, 0x65, 0x9b, 0x36, 0xf6, 0x2d, 0xc6, 0xd3, 0xcf, 0x5f, 0xd7, 0xb2, 0x3e, 0xa3, 0x1f, 0xa0, 0x99, 0x41, 0xec, 0xd6, 0x8c, 0x07,
+ /* (2^182)P */ 0x2f, 0x0d, 0x90, 0xad, 0x41, 0x4a, 0x58, 0x4a, 0x52, 0x4c, 0xc7, 0xe2, 0x78, 0x2b, 0x14, 0x32, 0x78, 0xc9, 0x31, 0x84, 0x33, 0xe8, 0xc4, 0x68, 0xc2, 0x9f, 0x68, 0x08, 0x90, 0xea, 0x69, 0x7f,
+ /* (2^183)P */ 0x65, 0x82, 0xa3, 0x46, 0x1e, 0xc8, 0xf2, 0x52, 0xfd, 0x32, 0xa8, 0x04, 0x2d, 0x07, 0x78, 0xfd, 0x94, 0x9e, 0x35, 0x25, 0xfa, 0xd5, 0xd7, 0x8c, 0xd2, 0x29, 0xcc, 0x54, 0x74, 0x1b, 0xe7, 0x4d,
+ /* (2^184)P */ 0xc9, 0x6a, 0xda, 0x1e, 0xad, 0x60, 0xeb, 0x42, 0x3a, 0x9c, 0xc0, 0xdb, 0xdf, 0x37, 0xad, 0x0a, 0x91, 0xc1, 0x3c, 0xe3, 0x71, 0x4b, 0x00, 0x81, 0x3c, 0x80, 0x22, 0x51, 0x34, 0xbe, 0xe6, 0x44,
+ /* (2^185)P */ 0xdb, 0x20, 0x19, 0xba, 0x88, 0x83, 0xfe, 0x03, 0x08, 0xb0, 0x0d, 0x15, 0x32, 0x7c, 0xd5, 0xf5, 0x29, 0x0c, 0xf6, 0x1a, 0x28, 0xc4, 0xc8, 0x49, 0xee, 0x1a, 0x70, 0xde, 0x18, 0xb5, 0xed, 0x21,
+ /* (2^186)P */ 0x99, 0xdc, 0x06, 0x8f, 0x41, 0x3e, 0xb6, 0x7f, 0xb8, 0xd7, 0x66, 0xc1, 0x99, 0x0d, 0x46, 0xa4, 0x83, 0x0a, 0x52, 0xce, 0x48, 0x52, 0xdd, 0x24, 0x58, 0x83, 0x92, 0x2b, 0x71, 0xad, 0xc3, 0x5e,
+ /* (2^187)P */ 0x0f, 0x93, 0x17, 0xbd, 0x5f, 0x2a, 0x02, 0x15, 0xe3, 0x70, 0x25, 0xd8, 0x77, 0x4a, 0xf6, 0xa4, 0x12, 0x37, 0x78, 0x15, 0x69, 0x8d, 0xbc, 0x12, 0xbb, 0x0a, 0x62, 0xfc, 0xc0, 0x94, 0x81, 0x49,
+ /* (2^188)P */ 0x82, 0x6c, 0x68, 0x55, 0xd2, 0xd9, 0xa2, 0x38, 0xf0, 0x21, 0x3e, 0x19, 0xd9, 0x6b, 0x5c, 0x78, 0x84, 0x54, 0x4a, 0xb2, 0x1a, 0xc8, 0xd5, 0xe4, 0x89, 0x09, 0xe2, 0xb2, 0x60, 0x78, 0x30, 0x56,
+ /* (2^189)P */ 0xc4, 0x74, 0x4d, 0x8b, 0xf7, 0x55, 0x9d, 0x42, 0x31, 0x01, 0x35, 0x43, 0x46, 0x83, 0xf1, 0x22, 0xff, 0x1f, 0xc7, 0x98, 0x45, 0xc2, 0x60, 0x1e, 0xef, 0x83, 0x99, 0x97, 0x14, 0xf0, 0xf2, 0x59,
+ /* (2^190)P */ 0x44, 0x4a, 0x49, 0xeb, 0x56, 0x7d, 0xa4, 0x46, 0x8e, 0xa1, 0x36, 0xd6, 0x54, 0xa8, 0x22, 0x3e, 0x3b, 0x1c, 0x49, 0x74, 0x52, 0xe1, 0x46, 0xb3, 0xe7, 0xcd, 0x90, 0x53, 0x4e, 0xfd, 0xea, 0x2c,
+ /* (2^191)P */ 0x75, 0x66, 0x0d, 0xbe, 0x38, 0x85, 0x8a, 0xba, 0x23, 0x8e, 0x81, 0x50, 0xbb, 0x74, 0x90, 0x4b, 0xc3, 0x04, 0xd3, 0x85, 0x90, 0xb8, 0xda, 0xcb, 0xc4, 0x92, 0x61, 0xe5, 0xe0, 0x4f, 0xa2, 0x61,
+ /* (2^192)P */ 0xcb, 0x5b, 0x52, 0xdb, 0xe6, 0x15, 0x76, 0xcb, 0xca, 0xe4, 0x67, 0xa5, 0x35, 0x8c, 0x7d, 0xdd, 0x69, 0xdd, 0xfc, 0xca, 0x3a, 0x15, 0xb4, 0xe6, 0x66, 0x97, 0x3c, 0x7f, 0x09, 0x8e, 0x66, 0x2d,
+ /* (2^193)P */ 0xf0, 0x5e, 0xe5, 0x5c, 0x26, 0x7e, 0x7e, 0xa5, 0x67, 0xb9, 0xd4, 0x7c, 0x52, 0x4e, 0x9f, 0x5d, 0xe5, 0xd1, 0x2f, 0x49, 0x06, 0x36, 0xc8, 0xfb, 0xae, 0xf7, 0xc3, 0xb7, 0xbe, 0x52, 0x0d, 0x09,
+ /* (2^194)P */ 0x7c, 0x4d, 0x7b, 0x1e, 0x5a, 0x51, 0xb9, 0x09, 0xc0, 0x44, 0xda, 0x99, 0x25, 0x6a, 0x26, 0x1f, 0x04, 0x55, 0xc5, 0xe2, 0x48, 0x95, 0xc4, 0xa1, 0xcc, 0x15, 0x6f, 0x12, 0x87, 0x42, 0xf0, 0x7e,
+ /* (2^195)P */ 0x15, 0xef, 0x30, 0xbd, 0x9d, 0x65, 0xd1, 0xfe, 0x7b, 0x27, 0xe0, 0xc4, 0xee, 0xb9, 0x4a, 0x8b, 0x91, 0x32, 0xdf, 0xa5, 0x36, 0x62, 0x4d, 0x88, 0x88, 0xf7, 0x5c, 0xbf, 0xa6, 0x6e, 0xd9, 0x1f,
+ /* (2^196)P */ 0x9a, 0x0d, 0x19, 0x1f, 0x98, 0x61, 0xa1, 0x42, 0xc1, 0x52, 0x60, 0x7e, 0x50, 0x49, 0xd8, 0x61, 0xd5, 0x2c, 0x5a, 0x28, 0xbf, 0x13, 0xe1, 0x9f, 0xd8, 0x85, 0xad, 0xdb, 0x76, 0xd6, 0x22, 0x7c,
+ /* (2^197)P */ 0x7d, 0xd2, 0xfb, 0x2b, 0xed, 0x70, 0xe7, 0x82, 0xa5, 0xf5, 0x96, 0xe9, 0xec, 0xb2, 0x05, 0x4c, 0x50, 0x01, 0x90, 0xb0, 0xc2, 0xa9, 0x40, 0xcd, 0x64, 0xbf, 0xd9, 0x13, 0x92, 0x31, 0x95, 0x58,
+ /* (2^198)P */ 0x08, 0x2e, 0xea, 0x3f, 0x70, 0x5d, 0xcc, 0xe7, 0x8c, 0x18, 0xe2, 0x58, 0x12, 0x49, 0x0c, 0xb5, 0xf0, 0x5b, 0x20, 0x48, 0xaa, 0x0b, 0xe3, 0xcc, 0x62, 0x2d, 0xa3, 0xcf, 0x9c, 0x65, 0x7c, 0x53,
+ /* (2^199)P */ 0x88, 0xc0, 0xcf, 0x98, 0x3a, 0x62, 0xb6, 0x37, 0xa4, 0xac, 0xd6, 0xa4, 0x1f, 0xed, 0x9b, 0xfe, 0xb0, 0xd1, 0xa8, 0x56, 0x8e, 0x9b, 0xd2, 0x04, 0x75, 0x95, 0x51, 0x0b, 0xc4, 0x71, 0x5f, 0x72,
+ /* (2^200)P */ 0xe6, 0x9c, 0x33, 0xd0, 0x9c, 0xf8, 0xc7, 0x28, 0x8b, 0xc1, 0xdd, 0x69, 0x44, 0xb1, 0x67, 0x83, 0x2c, 0x65, 0xa1, 0xa6, 0x83, 0xda, 0x3a, 0x88, 0x17, 0x6c, 0x4d, 0x03, 0x74, 0x19, 0x5f, 0x58,
+ /* (2^201)P */ 0x88, 0x91, 0xb1, 0xf1, 0x66, 0xb2, 0xcf, 0x89, 0x17, 0x52, 0xc3, 0xe7, 0x63, 0x48, 0x3b, 0xe6, 0x6a, 0x52, 0xc0, 0xb4, 0xa6, 0x9d, 0x8c, 0xd8, 0x35, 0x46, 0x95, 0xf0, 0x9d, 0x5c, 0x03, 0x3e,
+ /* (2^202)P */ 0x9d, 0xde, 0x45, 0xfb, 0x12, 0x54, 0x9d, 0xdd, 0x0d, 0xf4, 0xcf, 0xe4, 0x32, 0x45, 0x68, 0xdd, 0x1c, 0x67, 0x1d, 0x15, 0x9b, 0x99, 0x5c, 0x4b, 0x90, 0xf6, 0xe7, 0x11, 0xc8, 0x2c, 0x8c, 0x2d,
+ /* (2^203)P */ 0x40, 0x5d, 0x05, 0x90, 0x1d, 0xbe, 0x54, 0x7f, 0x40, 0xaf, 0x4a, 0x46, 0xdf, 0xc5, 0x64, 0xa4, 0xbe, 0x17, 0xe9, 0xf0, 0x24, 0x96, 0x97, 0x33, 0x30, 0x6b, 0x35, 0x27, 0xc5, 0x8d, 0x01, 0x2c,
+ /* (2^204)P */ 0xd4, 0xb3, 0x30, 0xe3, 0x24, 0x50, 0x41, 0xa5, 0xd3, 0x52, 0x16, 0x69, 0x96, 0x3d, 0xff, 0x73, 0xf1, 0x59, 0x9b, 0xef, 0xc4, 0x42, 0xec, 0x94, 0x5a, 0x8e, 0xd0, 0x18, 0x16, 0x20, 0x47, 0x07,
+ /* (2^205)P */ 0x53, 0x1c, 0x41, 0xca, 0x8a, 0xa4, 0x6c, 0x4d, 0x19, 0x61, 0xa6, 0xcf, 0x2f, 0x5f, 0x41, 0x66, 0xff, 0x27, 0xe2, 0x51, 0x00, 0xd4, 0x4d, 0x9c, 0xeb, 0xf7, 0x02, 0x9a, 0xc0, 0x0b, 0x81, 0x59,
+ /* (2^206)P */ 0x1d, 0x10, 0xdc, 0xb3, 0x71, 0xb1, 0x7e, 0x2a, 0x8e, 0xf6, 0xfe, 0x9f, 0xb9, 0x5a, 0x1c, 0x44, 0xea, 0x59, 0xb3, 0x93, 0x9b, 0x5c, 0x02, 0x32, 0x2f, 0x11, 0x9d, 0x1e, 0xa7, 0xe0, 0x8c, 0x5e,
+ /* (2^207)P */ 0xfd, 0x03, 0x95, 0x42, 0x92, 0xcb, 0xcc, 0xbf, 0x55, 0x5d, 0x09, 0x2f, 0x75, 0xba, 0x71, 0xd2, 0x1e, 0x09, 0x2d, 0x97, 0x5e, 0xad, 0x5e, 0x34, 0xba, 0x03, 0x31, 0xa8, 0x11, 0xdf, 0xc8, 0x18,
+ /* (2^208)P */ 0x4c, 0x0f, 0xed, 0x9a, 0x9a, 0x94, 0xcd, 0x90, 0x7e, 0xe3, 0x60, 0x66, 0xcb, 0xf4, 0xd1, 0xc5, 0x0b, 0x2e, 0xc5, 0x56, 0x2d, 0xc5, 0xca, 0xb8, 0x0d, 0x8e, 0x80, 0xc5, 0x00, 0xe4, 0x42, 0x6e,
+ /* (2^209)P */ 0x23, 0xfd, 0xae, 0xee, 0x66, 0x69, 0xb4, 0xa3, 0xca, 0xcd, 0x9e, 0xe3, 0x0b, 0x1f, 0x4f, 0x0c, 0x1d, 0xa5, 0x83, 0xd6, 0xc9, 0xc8, 0x9d, 0x18, 0x1b, 0x35, 0x09, 0x4c, 0x05, 0x7f, 0xf2, 0x51,
+ /* (2^210)P */ 0x82, 0x06, 0x32, 0x2a, 0xcd, 0x7c, 0x48, 0x4c, 0x96, 0x1c, 0xdf, 0xb3, 0x5b, 0xa9, 0x7e, 0x58, 0xe8, 0xb8, 0x5c, 0x55, 0x9e, 0xf7, 0xcc, 0xc8, 0x3d, 0xd7, 0x06, 0xa2, 0x29, 0xc8, 0x7d, 0x54,
+ /* (2^211)P */ 0x06, 0x9b, 0xc3, 0x80, 0xcd, 0xa6, 0x22, 0xb8, 0xc6, 0xd4, 0x00, 0x20, 0x73, 0x54, 0x6d, 0xe9, 0x4d, 0x3b, 0x46, 0x91, 0x6f, 0x5b, 0x53, 0x28, 0x1d, 0x6e, 0x48, 0xe2, 0x60, 0x46, 0x8f, 0x22,
+ /* (2^212)P */ 0xbf, 0x3a, 0x8d, 0xde, 0x38, 0x95, 0x79, 0x98, 0x6e, 0xca, 0xeb, 0x45, 0x00, 0x33, 0xd8, 0x8c, 0x38, 0xe7, 0x21, 0x82, 0x00, 0x2a, 0x95, 0x79, 0xbb, 0xd2, 0x5c, 0x53, 0xa7, 0xe1, 0x22, 0x43,
+ /* (2^213)P */ 0x1c, 0x80, 0xd1, 0x19, 0x18, 0xc1, 0x14, 0xb1, 0xc7, 0x5e, 0x3f, 0x4f, 0xd8, 0xe4, 0x16, 0x20, 0x4c, 0x0f, 0x26, 0x09, 0xf4, 0x2d, 0x0e, 0xdd, 0x66, 0x72, 0x5f, 0xae, 0xc0, 0x62, 0xc3, 0x5e,
+ /* (2^214)P */ 0xee, 0xb4, 0xb2, 0xb8, 0x18, 0x2b, 0x46, 0xc0, 0xfb, 0x1a, 0x4d, 0x27, 0x50, 0xd9, 0xc8, 0x7c, 0xd2, 0x02, 0x6b, 0x43, 0x05, 0x71, 0x5f, 0xf2, 0xd3, 0xcc, 0xf9, 0xbf, 0xdc, 0xf8, 0xbb, 0x43,
+ /* (2^215)P */ 0xdf, 0xe9, 0x39, 0xa0, 0x67, 0x17, 0xad, 0xb6, 0x83, 0x35, 0x9d, 0xf6, 0xa8, 0x4d, 0x71, 0xb0, 0xf5, 0x31, 0x29, 0xb4, 0x18, 0xfa, 0x55, 0x5e, 0x61, 0x09, 0xc6, 0x33, 0x8f, 0x55, 0xd5, 0x4e,
+ /* (2^216)P */ 0xdd, 0xa5, 0x47, 0xc6, 0x01, 0x79, 0xe3, 0x1f, 0x57, 0xd3, 0x81, 0x80, 0x1f, 0xdf, 0x3d, 0x59, 0xa6, 0xd7, 0x3f, 0x81, 0xfd, 0xa4, 0x49, 0x02, 0x61, 0xaf, 0x9c, 0x4e, 0x27, 0xca, 0xac, 0x69,
+ /* (2^217)P */ 0xc9, 0x21, 0x07, 0x33, 0xea, 0xa3, 0x7b, 0x04, 0xa0, 0x1e, 0x7e, 0x0e, 0xc2, 0x3f, 0x42, 0x83, 0x60, 0x4a, 0x31, 0x01, 0xaf, 0xc0, 0xf4, 0x1d, 0x27, 0x95, 0x28, 0x89, 0xab, 0x2d, 0xa6, 0x09,
+ /* (2^218)P */ 0x00, 0xcb, 0xc6, 0x9c, 0xa4, 0x25, 0xb3, 0xa5, 0xb6, 0x6c, 0xb5, 0x54, 0xc6, 0x5d, 0x4b, 0xe9, 0xa0, 0x94, 0xc9, 0xad, 0x79, 0x87, 0xe2, 0x3b, 0xad, 0x4a, 0x3a, 0xba, 0xf8, 0xe8, 0x96, 0x42,
+ /* (2^219)P */ 0xab, 0x1e, 0x45, 0x1e, 0x76, 0x89, 0x86, 0x32, 0x4a, 0x59, 0x59, 0xff, 0x8b, 0x59, 0x4d, 0x2e, 0x4a, 0x08, 0xa7, 0xd7, 0x53, 0x68, 0xb9, 0x49, 0xa8, 0x20, 0x14, 0x60, 0x19, 0xa3, 0x80, 0x49,
+ /* (2^220)P */ 0x42, 0x2c, 0x55, 0x2f, 0xe1, 0xb9, 0x65, 0x95, 0x96, 0xfe, 0x00, 0x71, 0xdb, 0x18, 0x53, 0x8a, 0xd7, 0xd0, 0xad, 0x43, 0x4d, 0x0b, 0xc9, 0x05, 0xda, 0x4e, 0x5d, 0x6a, 0xd6, 0x4c, 0x8b, 0x53,
+ /* (2^221)P */ 0x9f, 0x03, 0x9f, 0xe8, 0xc3, 0x4f, 0xe9, 0xf4, 0x45, 0x80, 0x61, 0x6f, 0xf2, 0x9a, 0x2c, 0x59, 0x50, 0x95, 0x4b, 0xfd, 0xb5, 0x6e, 0xa3, 0x08, 0x19, 0x14, 0xed, 0xc2, 0xf6, 0xfa, 0xff, 0x25,
+ /* (2^222)P */ 0x54, 0xd3, 0x79, 0xcc, 0x59, 0x44, 0x43, 0x34, 0x6b, 0x47, 0xd5, 0xb1, 0xb4, 0xbf, 0xec, 0xee, 0x99, 0x5d, 0x61, 0x61, 0xa0, 0x34, 0xeb, 0xdd, 0x73, 0xb7, 0x64, 0xeb, 0xcc, 0xce, 0x29, 0x51,
+ /* (2^223)P */ 0x20, 0x35, 0x99, 0x94, 0x58, 0x21, 0x43, 0xee, 0x3b, 0x0b, 0x4c, 0xf1, 0x7c, 0x9c, 0x2f, 0x77, 0xd5, 0xda, 0xbe, 0x06, 0xe3, 0xfc, 0xe2, 0xd2, 0x97, 0x6a, 0xf0, 0x46, 0xb5, 0x42, 0x5f, 0x71,
+ /* (2^224)P */ 0x1a, 0x5f, 0x5b, 0xda, 0xce, 0xcd, 0x4e, 0x43, 0xa9, 0x41, 0x97, 0xa4, 0x15, 0x71, 0xa1, 0x0d, 0x2e, 0xad, 0xed, 0x73, 0x7c, 0xd7, 0x0b, 0x68, 0x41, 0x90, 0xdd, 0x4e, 0x35, 0x02, 0x7c, 0x48,
+ /* (2^225)P */ 0xc4, 0xd9, 0x0e, 0xa7, 0xf3, 0xef, 0xef, 0xb8, 0x02, 0xe3, 0x57, 0xe8, 0xa3, 0x2a, 0xa3, 0x56, 0xa0, 0xa5, 0xa2, 0x48, 0xbd, 0x68, 0x3a, 0xdf, 0x44, 0xc4, 0x76, 0x31, 0xb7, 0x50, 0xf6, 0x07,
+ /* (2^226)P */ 0xb1, 0xcc, 0xe0, 0x26, 0x16, 0x9b, 0x8b, 0xe3, 0x36, 0xfb, 0x09, 0x8b, 0xc1, 0x53, 0xe0, 0x79, 0x64, 0x49, 0xf9, 0xc9, 0x19, 0x03, 0xd9, 0x56, 0xc4, 0xf5, 0x9f, 0xac, 0xe7, 0x41, 0xa9, 0x1c,
+ /* (2^227)P */ 0xbb, 0xa0, 0x2f, 0x16, 0x29, 0xdf, 0xc4, 0x49, 0x05, 0x33, 0xb3, 0x82, 0x32, 0xcf, 0x88, 0x84, 0x7d, 0x43, 0xbb, 0xca, 0x14, 0xda, 0xdf, 0x95, 0x86, 0xad, 0xd5, 0x64, 0x82, 0xf7, 0x91, 0x33,
+ /* (2^228)P */ 0x5d, 0x09, 0xb5, 0xe2, 0x6a, 0xe0, 0x9a, 0x72, 0x46, 0xa9, 0x59, 0x32, 0xd7, 0x58, 0x8a, 0xd5, 0xed, 0x21, 0x39, 0xd1, 0x62, 0x42, 0x83, 0xe9, 0x92, 0xb5, 0x4b, 0xa5, 0xfa, 0xda, 0xfe, 0x27,
+ /* (2^229)P */ 0xbb, 0x48, 0xad, 0x29, 0xb8, 0xc5, 0x9d, 0xa9, 0x60, 0xe2, 0x9e, 0x49, 0x42, 0x57, 0x02, 0x5f, 0xfd, 0x13, 0x75, 0x5d, 0xcd, 0x8e, 0x2c, 0x80, 0x38, 0xd9, 0x6d, 0x3f, 0xef, 0xb3, 0xce, 0x78,
+ /* (2^230)P */ 0x94, 0x5d, 0x13, 0x8a, 0x4f, 0xf4, 0x42, 0xc3, 0xa3, 0xdd, 0x8c, 0x82, 0x44, 0xdb, 0x9e, 0x7b, 0xe7, 0xcf, 0x37, 0x05, 0x1a, 0xd1, 0x36, 0x94, 0xc8, 0xb4, 0x1a, 0xec, 0x64, 0xb1, 0x64, 0x50,
+ /* (2^231)P */ 0xfc, 0xb2, 0x7e, 0xd3, 0xcf, 0xec, 0x20, 0x70, 0xfc, 0x25, 0x0d, 0xd9, 0x3e, 0xea, 0x31, 0x1f, 0x34, 0xbb, 0xa1, 0xdf, 0x7b, 0x0d, 0x93, 0x1b, 0x44, 0x30, 0x11, 0x48, 0x7a, 0x46, 0x44, 0x53,
+ /* (2^232)P */ 0xfb, 0x6d, 0x5e, 0xf2, 0x70, 0x31, 0x07, 0x70, 0xc8, 0x4c, 0x11, 0x50, 0x1a, 0xdc, 0x85, 0xe3, 0x00, 0x4f, 0xfc, 0xc8, 0x8a, 0x69, 0x48, 0x23, 0xd8, 0x40, 0xdd, 0x84, 0x52, 0xa5, 0x77, 0x2a,
+ /* (2^233)P */ 0xe4, 0x6c, 0x8c, 0xc9, 0xe0, 0xaf, 0x06, 0xfe, 0xe4, 0xd6, 0xdf, 0xdd, 0x96, 0xdf, 0x35, 0xc2, 0xd3, 0x1e, 0xbf, 0x33, 0x1e, 0xd0, 0x28, 0x14, 0xaf, 0xbd, 0x00, 0x93, 0xec, 0x68, 0x57, 0x78,
+ /* (2^234)P */ 0x3b, 0xb6, 0xde, 0x91, 0x7a, 0xe5, 0x02, 0x97, 0x80, 0x8b, 0xce, 0xe5, 0xbf, 0xb8, 0xbd, 0x61, 0xac, 0x58, 0x1d, 0x3d, 0x6f, 0x42, 0x5b, 0x64, 0xbc, 0x57, 0xa5, 0x27, 0x22, 0xa8, 0x04, 0x48,
+ /* (2^235)P */ 0x01, 0x26, 0x4d, 0xb4, 0x8a, 0x04, 0x57, 0x8e, 0x35, 0x69, 0x3a, 0x4b, 0x1a, 0x50, 0xd6, 0x68, 0x93, 0xc2, 0xe1, 0xf9, 0xc3, 0x9e, 0x9c, 0xc3, 0xe2, 0x63, 0xde, 0xd4, 0x57, 0xf2, 0x72, 0x41,
+ /* (2^236)P */ 0x01, 0x64, 0x0c, 0x33, 0x50, 0xb4, 0x68, 0xd3, 0x91, 0x23, 0x8f, 0x41, 0x17, 0x30, 0x0d, 0x04, 0x0d, 0xd9, 0xb7, 0x90, 0x60, 0xbb, 0x34, 0x2c, 0x1f, 0xd5, 0xdf, 0x8f, 0x22, 0x49, 0xf6, 0x16,
+ /* (2^237)P */ 0xf5, 0x8e, 0x92, 0x2b, 0x8e, 0x81, 0xa6, 0xbe, 0x72, 0x1e, 0xc1, 0xcd, 0x91, 0xcf, 0x8c, 0xe2, 0xcd, 0x36, 0x7a, 0xe7, 0x68, 0xaa, 0x4a, 0x59, 0x0f, 0xfd, 0x7f, 0x6c, 0x80, 0x34, 0x30, 0x31,
+ /* (2^238)P */ 0x65, 0xbd, 0x49, 0x22, 0xac, 0x27, 0x9d, 0x8a, 0x12, 0x95, 0x8e, 0x01, 0x64, 0xb4, 0xa3, 0x19, 0xc7, 0x7e, 0xb3, 0x52, 0xf3, 0xcf, 0x6c, 0xc2, 0x21, 0x7b, 0x79, 0x1d, 0x34, 0x68, 0x6f, 0x05,
+ /* (2^239)P */ 0x27, 0x23, 0xfd, 0x7e, 0x75, 0xd6, 0x79, 0x5e, 0x15, 0xfe, 0x3a, 0x55, 0xb6, 0xbc, 0xbd, 0xfa, 0x60, 0x5a, 0xaf, 0x6e, 0x2c, 0x22, 0xe7, 0xd3, 0x3b, 0x74, 0xae, 0x4d, 0x6d, 0xc7, 0x46, 0x70,
+ /* (2^240)P */ 0x55, 0x4a, 0x8d, 0xb1, 0x72, 0xe8, 0x0b, 0x66, 0x96, 0x14, 0x4e, 0x57, 0x18, 0x25, 0x99, 0x19, 0xbb, 0xdc, 0x2b, 0x30, 0x3a, 0x05, 0x03, 0xc1, 0x8e, 0x8e, 0x21, 0x0b, 0x80, 0xe9, 0xd8, 0x3e,
+ /* (2^241)P */ 0x3e, 0xe0, 0x75, 0xfa, 0x39, 0x92, 0x0b, 0x7b, 0x83, 0xc0, 0x33, 0x46, 0x68, 0xfb, 0xe9, 0xef, 0x93, 0x77, 0x1a, 0x39, 0xbe, 0x5f, 0xa3, 0x98, 0x34, 0xfe, 0xd0, 0xe2, 0x0f, 0x51, 0x65, 0x60,
+ /* (2^242)P */ 0x0c, 0xad, 0xab, 0x48, 0x85, 0x66, 0xcb, 0x55, 0x27, 0xe5, 0x87, 0xda, 0x48, 0x45, 0x58, 0xb4, 0xdd, 0xc1, 0x07, 0x01, 0xea, 0xec, 0x43, 0x2c, 0x35, 0xde, 0x72, 0x93, 0x80, 0x28, 0x60, 0x52,
+ /* (2^243)P */ 0x1f, 0x3b, 0x21, 0xf9, 0x6a, 0xc5, 0x15, 0x34, 0xdb, 0x98, 0x7e, 0x01, 0x4d, 0x1a, 0xee, 0x5b, 0x9b, 0x70, 0xcf, 0xb5, 0x05, 0xb1, 0xf6, 0x13, 0xb6, 0x9a, 0xb2, 0x82, 0x34, 0x0e, 0xf2, 0x5f,
+ /* (2^244)P */ 0x90, 0x6c, 0x2e, 0xcc, 0x75, 0x9c, 0xa2, 0x0a, 0x06, 0xe2, 0x70, 0x3a, 0xca, 0x73, 0x7d, 0xfc, 0x15, 0xc5, 0xb5, 0xc4, 0x8f, 0xc3, 0x9f, 0x89, 0x07, 0xc2, 0xff, 0x24, 0xb1, 0x86, 0x03, 0x25,
+ /* (2^245)P */ 0x56, 0x2b, 0x3d, 0xae, 0xd5, 0x28, 0xea, 0x54, 0xce, 0x60, 0xde, 0xd6, 0x9d, 0x14, 0x13, 0x99, 0xc1, 0xd6, 0x06, 0x8f, 0xc5, 0x4f, 0x69, 0x16, 0xc7, 0x8f, 0x01, 0xeb, 0x75, 0x39, 0xb2, 0x46,
+ /* (2^246)P */ 0xe2, 0xb4, 0xb7, 0xb4, 0x0f, 0x6a, 0x0a, 0x47, 0xde, 0x53, 0x72, 0x8f, 0x5a, 0x47, 0x92, 0x5d, 0xdb, 0x3a, 0xbd, 0x2f, 0xb5, 0xe5, 0xee, 0xab, 0x68, 0x69, 0x80, 0xa0, 0x01, 0x08, 0xa2, 0x7f,
+ /* (2^247)P */ 0xd2, 0x14, 0x77, 0x9f, 0xf1, 0xfa, 0xf3, 0x76, 0xc3, 0x60, 0x46, 0x2f, 0xc1, 0x40, 0xe8, 0xb3, 0x4e, 0x74, 0x12, 0xf2, 0x8d, 0xcd, 0xb4, 0x0f, 0xd2, 0x2d, 0x3a, 0x1d, 0x25, 0x5a, 0x06, 0x4b,
+ /* (2^248)P */ 0x4a, 0xcd, 0x77, 0x3d, 0x38, 0xde, 0xeb, 0x5c, 0xb1, 0x9c, 0x2c, 0x88, 0xdf, 0x39, 0xdf, 0x6a, 0x59, 0xf7, 0x9a, 0xb0, 0x2e, 0x24, 0xdd, 0xa2, 0x22, 0x64, 0x5f, 0x0e, 0xe5, 0xc0, 0x47, 0x31,
+ /* (2^249)P */ 0xdb, 0x50, 0x13, 0x1d, 0x10, 0xa5, 0x4c, 0x16, 0x62, 0xc9, 0x3f, 0xc3, 0x79, 0x34, 0xd1, 0xf8, 0x08, 0xda, 0xe5, 0x13, 0x4d, 0xce, 0x40, 0xe6, 0xba, 0xf8, 0x61, 0x50, 0xc4, 0xe0, 0xde, 0x4b,
+ /* (2^250)P */ 0xc9, 0xb1, 0xed, 0xa4, 0xc1, 0x6d, 0xc4, 0xd7, 0x8a, 0xd9, 0x7f, 0x43, 0xb6, 0xd7, 0x14, 0x55, 0x0b, 0xc0, 0xa1, 0xb2, 0x6b, 0x2f, 0x94, 0x58, 0x0e, 0x71, 0x70, 0x1d, 0xab, 0xb2, 0xff, 0x2d,
+ /* (2^251)P */ 0x68, 0x6d, 0x8b, 0xc1, 0x2f, 0xcf, 0xdf, 0xcc, 0x67, 0x61, 0x80, 0xb7, 0xa8, 0xcb, 0xeb, 0xa8, 0xe3, 0x37, 0x29, 0x5e, 0xf9, 0x97, 0x06, 0x98, 0x8c, 0x6e, 0x12, 0xd0, 0x1c, 0xba, 0xfb, 0x02,
+ /* (2^252)P */ 0x65, 0x45, 0xff, 0xad, 0x60, 0xc3, 0x98, 0xcb, 0x19, 0x15, 0xdb, 0x4b, 0xd2, 0x01, 0x71, 0x44, 0xd5, 0x15, 0xfb, 0x75, 0x74, 0xc8, 0xc4, 0x98, 0x7d, 0xa2, 0x22, 0x6e, 0x6d, 0xc7, 0xf8, 0x05,
+ /* (2^253)P */ 0x94, 0xf4, 0xb9, 0xfe, 0xdf, 0xe5, 0x69, 0xab, 0x75, 0x6b, 0x40, 0x18, 0x9d, 0xc7, 0x09, 0xae, 0x1d, 0x2d, 0xa4, 0x94, 0xfb, 0x45, 0x9b, 0x19, 0x84, 0xfa, 0x2a, 0xae, 0xeb, 0x0a, 0x71, 0x79,
+ /* (2^254)P */ 0xdf, 0xd2, 0x34, 0xf3, 0xa7, 0xed, 0xad, 0xa6, 0xb4, 0x57, 0x2a, 0xaf, 0x51, 0x9c, 0xde, 0x7b, 0xa8, 0xea, 0xdc, 0x86, 0x4f, 0xc6, 0x8f, 0xa9, 0x7b, 0xd0, 0x0e, 0xc2, 0x35, 0x03, 0xbe, 0x6b,
+ /* (2^255)P */ 0x44, 0x43, 0x98, 0x53, 0xbe, 0xdc, 0x7f, 0x66, 0xa8, 0x49, 0x59, 0x00, 0x1c, 0xbc, 0x72, 0x07, 0x8e, 0xd6, 0xbe, 0x4e, 0x9f, 0xa4, 0x07, 0xba, 0xbf, 0x30, 0xdf, 0xba, 0x85, 0xb0, 0xa7, 0x1f,
+}
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/curve.go b/vendor/github.com/cloudflare/circl/dh/x448/curve.go
new file mode 100644
index 0000000000..d59564e4b4
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/curve.go
@@ -0,0 +1,104 @@
+package x448
+
+import (
+ fp "github.com/cloudflare/circl/math/fp448"
+)
+
+// ladderJoye calculates a fixed-point multiplication with the generator point.
+// The algorithm is the right-to-left Joye's ladder as described
+// in "How to precompute a ladder" in SAC'2017.
+func ladderJoye(k *Key) {
+ w := [5]fp.Elt{} // [mu,x1,z1,x2,z2] order must be preserved.
+ w[1] = fp.Elt{ // x1 = S
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ }
+ fp.SetOne(&w[2]) // z1 = 1
+ w[3] = fp.Elt{ // x2 = G-S
+ 0x20, 0x27, 0x9d, 0xc9, 0x7d, 0x19, 0xb1, 0xac,
+ 0xf8, 0xba, 0x69, 0x1c, 0xff, 0x33, 0xac, 0x23,
+ 0x51, 0x1b, 0xce, 0x3a, 0x64, 0x65, 0xbd, 0xf1,
+ 0x23, 0xf8, 0xc1, 0x84, 0x9d, 0x45, 0x54, 0x29,
+ 0x67, 0xb9, 0x81, 0x1c, 0x03, 0xd1, 0xcd, 0xda,
+ 0x7b, 0xeb, 0xff, 0x1a, 0x88, 0x03, 0xcf, 0x3a,
+ 0x42, 0x44, 0x32, 0x01, 0x25, 0xb7, 0xfa, 0xf0,
+ }
+ fp.SetOne(&w[4]) // z2 = 1
+
+ const n = 448
+ const h = 2
+ swap := uint(1)
+ for s := 0; s < n-h; s++ {
+ i := (s + h) / 8
+ j := (s + h) % 8
+ bit := uint((k[i] >> uint(j)) & 1)
+ copy(w[0][:], tableGenerator[s*Size:(s+1)*Size])
+ diffAdd(&w, swap^bit)
+ swap = bit
+ }
+ for s := 0; s < h; s++ {
+ double(&w[1], &w[2])
+ }
+ toAffine((*[fp.Size]byte)(k), &w[1], &w[2])
+}
+
+// ladderMontgomery calculates a generic scalar point multiplication
+// The algorithm implemented is the left-to-right Montgomery's ladder.
+func ladderMontgomery(k, xP *Key) {
+ w := [5]fp.Elt{} // [x1, x2, z2, x3, z3] order must be preserved.
+ w[0] = *(*fp.Elt)(xP) // x1 = xP
+ fp.SetOne(&w[1]) // x2 = 1
+ w[3] = *(*fp.Elt)(xP) // x3 = xP
+ fp.SetOne(&w[4]) // z3 = 1
+
+ move := uint(0)
+ for s := 448 - 1; s >= 0; s-- {
+ i := s / 8
+ j := s % 8
+ bit := uint((k[i] >> uint(j)) & 1)
+ ladderStep(&w, move^bit)
+ move = bit
+ }
+ toAffine((*[fp.Size]byte)(k), &w[1], &w[2])
+}
+
+func toAffine(k *[fp.Size]byte, x, z *fp.Elt) {
+ fp.Inv(z, z)
+ fp.Mul(x, x, z)
+ _ = fp.ToBytes(k[:], x)
+}
+
+var lowOrderPoints = [3]fp.Elt{
+ { /* (0,_,1) point of order 2 on Curve448 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* (1,_,1) a point of order 4 on the twist of Curve448 */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* (-1,_,1) point of order 4 on Curve448 */
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+}
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.go b/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.go
new file mode 100644
index 0000000000..a062266613
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.go
@@ -0,0 +1,30 @@
+//go:build amd64 && !purego
+// +build amd64,!purego
+
+package x448
+
+import (
+ fp "github.com/cloudflare/circl/math/fp448"
+ "golang.org/x/sys/cpu"
+)
+
+var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX
+
+var _ = hasBmi2Adx
+
+func double(x, z *fp.Elt) { doubleAmd64(x, z) }
+func diffAdd(w *[5]fp.Elt, b uint) { diffAddAmd64(w, b) }
+func ladderStep(w *[5]fp.Elt, b uint) { ladderStepAmd64(w, b) }
+func mulA24(z, x *fp.Elt) { mulA24Amd64(z, x) }
+
+//go:noescape
+func doubleAmd64(x, z *fp.Elt)
+
+//go:noescape
+func diffAddAmd64(w *[5]fp.Elt, b uint)
+
+//go:noescape
+func ladderStepAmd64(w *[5]fp.Elt, b uint)
+
+//go:noescape
+func mulA24Amd64(z, x *fp.Elt)
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.h b/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.h
new file mode 100644
index 0000000000..8c1ae4d0fb
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.h
@@ -0,0 +1,111 @@
+#define ladderStepLeg \
+ addSub(x2,z2) \
+ addSub(x3,z3) \
+ integerMulLeg(b0,x2,z3) \
+ integerMulLeg(b1,x3,z2) \
+ reduceFromDoubleLeg(t0,b0) \
+ reduceFromDoubleLeg(t1,b1) \
+ addSub(t0,t1) \
+ cselect(x2,x3,regMove) \
+ cselect(z2,z3,regMove) \
+ integerSqrLeg(b0,t0) \
+ integerSqrLeg(b1,t1) \
+ reduceFromDoubleLeg(x3,b0) \
+ reduceFromDoubleLeg(z3,b1) \
+ integerMulLeg(b0,x1,z3) \
+ reduceFromDoubleLeg(z3,b0) \
+ integerSqrLeg(b0,x2) \
+ integerSqrLeg(b1,z2) \
+ reduceFromDoubleLeg(x2,b0) \
+ reduceFromDoubleLeg(z2,b1) \
+ subtraction(t0,x2,z2) \
+ multiplyA24Leg(t1,t0) \
+ additionLeg(t1,t1,z2) \
+ integerMulLeg(b0,x2,z2) \
+ integerMulLeg(b1,t0,t1) \
+ reduceFromDoubleLeg(x2,b0) \
+ reduceFromDoubleLeg(z2,b1)
+
+#define ladderStepBmi2Adx \
+ addSub(x2,z2) \
+ addSub(x3,z3) \
+ integerMulAdx(b0,x2,z3) \
+ integerMulAdx(b1,x3,z2) \
+ reduceFromDoubleAdx(t0,b0) \
+ reduceFromDoubleAdx(t1,b1) \
+ addSub(t0,t1) \
+ cselect(x2,x3,regMove) \
+ cselect(z2,z3,regMove) \
+ integerSqrAdx(b0,t0) \
+ integerSqrAdx(b1,t1) \
+ reduceFromDoubleAdx(x3,b0) \
+ reduceFromDoubleAdx(z3,b1) \
+ integerMulAdx(b0,x1,z3) \
+ reduceFromDoubleAdx(z3,b0) \
+ integerSqrAdx(b0,x2) \
+ integerSqrAdx(b1,z2) \
+ reduceFromDoubleAdx(x2,b0) \
+ reduceFromDoubleAdx(z2,b1) \
+ subtraction(t0,x2,z2) \
+ multiplyA24Adx(t1,t0) \
+ additionAdx(t1,t1,z2) \
+ integerMulAdx(b0,x2,z2) \
+ integerMulAdx(b1,t0,t1) \
+ reduceFromDoubleAdx(x2,b0) \
+ reduceFromDoubleAdx(z2,b1)
+
+#define difAddLeg \
+ addSub(x1,z1) \
+ integerMulLeg(b0,z1,ui) \
+ reduceFromDoubleLeg(z1,b0) \
+ addSub(x1,z1) \
+ integerSqrLeg(b0,x1) \
+ integerSqrLeg(b1,z1) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1) \
+ integerMulLeg(b0,x1,z2) \
+ integerMulLeg(b1,z1,x2) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1)
+
+#define difAddBmi2Adx \
+ addSub(x1,z1) \
+ integerMulAdx(b0,z1,ui) \
+ reduceFromDoubleAdx(z1,b0) \
+ addSub(x1,z1) \
+ integerSqrAdx(b0,x1) \
+ integerSqrAdx(b1,z1) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1) \
+ integerMulAdx(b0,x1,z2) \
+ integerMulAdx(b1,z1,x2) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1)
+
+#define doubleLeg \
+ addSub(x1,z1) \
+ integerSqrLeg(b0,x1) \
+ integerSqrLeg(b1,z1) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1) \
+ subtraction(t0,x1,z1) \
+ multiplyA24Leg(t1,t0) \
+ additionLeg(t1,t1,z1) \
+ integerMulLeg(b0,x1,z1) \
+ integerMulLeg(b1,t0,t1) \
+ reduceFromDoubleLeg(x1,b0) \
+ reduceFromDoubleLeg(z1,b1)
+
+#define doubleBmi2Adx \
+ addSub(x1,z1) \
+ integerSqrAdx(b0,x1) \
+ integerSqrAdx(b1,z1) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1) \
+ subtraction(t0,x1,z1) \
+ multiplyA24Adx(t1,t0) \
+ additionAdx(t1,t1,z1) \
+ integerMulAdx(b0,x1,z1) \
+ integerMulAdx(b1,t0,t1) \
+ reduceFromDoubleAdx(x1,b0) \
+ reduceFromDoubleAdx(z1,b1)
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.s b/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.s
new file mode 100644
index 0000000000..ed33ba3d03
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/curve_amd64.s
@@ -0,0 +1,194 @@
+//go:build amd64 && !purego
+// +build amd64,!purego
+
+#include "textflag.h"
+
+// Depends on circl/math/fp448 package
+#include "../../math/fp448/fp_amd64.h"
+#include "curve_amd64.h"
+
+// CTE_A24 is (A+2)/4 from Curve448
+#define CTE_A24 39082
+
+#define Size 56
+
+// multiplyA24Leg multiplies x times CTE_A24 and stores in z
+// Uses: AX, DX, R8-R15, FLAGS
+// Instr: x86_64, cmov, adx
+#define multiplyA24Leg(z,x) \
+ MOVQ $CTE_A24, R15; \
+ MOVQ 0+x, AX; MULQ R15; MOVQ AX, R8; ;;;;;;;;;;;; MOVQ DX, R9; \
+ MOVQ 8+x, AX; MULQ R15; ADDQ AX, R9; ADCQ $0, DX; MOVQ DX, R10; \
+ MOVQ 16+x, AX; MULQ R15; ADDQ AX, R10; ADCQ $0, DX; MOVQ DX, R11; \
+ MOVQ 24+x, AX; MULQ R15; ADDQ AX, R11; ADCQ $0, DX; MOVQ DX, R12; \
+ MOVQ 32+x, AX; MULQ R15; ADDQ AX, R12; ADCQ $0, DX; MOVQ DX, R13; \
+ MOVQ 40+x, AX; MULQ R15; ADDQ AX, R13; ADCQ $0, DX; MOVQ DX, R14; \
+ MOVQ 48+x, AX; MULQ R15; ADDQ AX, R14; ADCQ $0, DX; \
+ MOVQ DX, AX; \
+ SHLQ $32, AX; \
+ ADDQ DX, R8; MOVQ $0, DX; \
+ ADCQ $0, R9; \
+ ADCQ $0, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, R12; \
+ ADCQ $0, R13; \
+ ADCQ $0, R14; \
+ ADCQ $0, DX; \
+ MOVQ DX, AX; \
+ SHLQ $32, AX; \
+ ADDQ DX, R8; \
+ ADCQ $0, R9; \
+ ADCQ $0, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, R12; \
+ ADCQ $0, R13; \
+ ADCQ $0, R14; \
+ MOVQ R8, 0+z; \
+ MOVQ R9, 8+z; \
+ MOVQ R10, 16+z; \
+ MOVQ R11, 24+z; \
+ MOVQ R12, 32+z; \
+ MOVQ R13, 40+z; \
+ MOVQ R14, 48+z;
+
+// multiplyA24Adx multiplies x times CTE_A24 and stores in z
+// Uses: AX, DX, R8-R14, FLAGS
+// Instr: x86_64, bmi2
+#define multiplyA24Adx(z,x) \
+ MOVQ $CTE_A24, DX; \
+ MULXQ 0+x, R8, R9; \
+ MULXQ 8+x, AX, R10; ADDQ AX, R9; \
+ MULXQ 16+x, AX, R11; ADCQ AX, R10; \
+ MULXQ 24+x, AX, R12; ADCQ AX, R11; \
+ MULXQ 32+x, AX, R13; ADCQ AX, R12; \
+ MULXQ 40+x, AX, R14; ADCQ AX, R13; \
+ MULXQ 48+x, AX, DX; ADCQ AX, R14; \
+ ;;;;;;;;;;;;;;;;;;;; ADCQ $0, DX; \
+ MOVQ DX, AX; \
+ SHLQ $32, AX; \
+ ADDQ DX, R8; MOVQ $0, DX; \
+ ADCQ $0, R9; \
+ ADCQ $0, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, R12; \
+ ADCQ $0, R13; \
+ ADCQ $0, R14; \
+ ADCQ $0, DX; \
+ MOVQ DX, AX; \
+ SHLQ $32, AX; \
+ ADDQ DX, R8; \
+ ADCQ $0, R9; \
+ ADCQ $0, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, R12; \
+ ADCQ $0, R13; \
+ ADCQ $0, R14; \
+ MOVQ R8, 0+z; \
+ MOVQ R9, 8+z; \
+ MOVQ R10, 16+z; \
+ MOVQ R11, 24+z; \
+ MOVQ R12, 32+z; \
+ MOVQ R13, 40+z; \
+ MOVQ R14, 48+z;
+
+#define mulA24Legacy \
+ multiplyA24Leg(0(DI),0(SI))
+#define mulA24Bmi2Adx \
+ multiplyA24Adx(0(DI),0(SI))
+
+// func mulA24Amd64(z, x *fp448.Elt)
+TEXT ·mulA24Amd64(SB),NOSPLIT,$0-16
+ MOVQ z+0(FP), DI
+ MOVQ x+8(FP), SI
+ CHECK_BMI2ADX(LMA24, mulA24Legacy, mulA24Bmi2Adx)
+
+// func ladderStepAmd64(w *[5]fp448.Elt, b uint)
+// ladderStepAmd64 calculates a point addition and doubling as follows:
+// (x2,z2) = 2*(x2,z2) and (x3,z3) = (x2,z2)+(x3,z3) using as a difference (x1,-).
+// w = {x1,x2,z2,x3,z4} are five fp255.Elt of 56 bytes.
+// stack = (t0,t1) are two fp.Elt of fp.Size bytes, and
+// (b0,b1) are two-double precision fp.Elt of 2*fp.Size bytes.
+TEXT ·ladderStepAmd64(SB),NOSPLIT,$336-16
+ // Parameters
+ #define regWork DI
+ #define regMove SI
+ #define x1 0*Size(regWork)
+ #define x2 1*Size(regWork)
+ #define z2 2*Size(regWork)
+ #define x3 3*Size(regWork)
+ #define z3 4*Size(regWork)
+ // Local variables
+ #define t0 0*Size(SP)
+ #define t1 1*Size(SP)
+ #define b0 2*Size(SP)
+ #define b1 4*Size(SP)
+ MOVQ w+0(FP), regWork
+ MOVQ b+8(FP), regMove
+ CHECK_BMI2ADX(LLADSTEP, ladderStepLeg, ladderStepBmi2Adx)
+ #undef regWork
+ #undef regMove
+ #undef x1
+ #undef x2
+ #undef z2
+ #undef x3
+ #undef z3
+ #undef t0
+ #undef t1
+ #undef b0
+ #undef b1
+
+// func diffAddAmd64(work *[5]fp.Elt, swap uint)
+// diffAddAmd64 calculates a differential point addition using a precomputed point.
+// (x1,z1) = (x1,z1)+(mu) using a difference point (x2,z2)
+// work = {mu,x1,z1,x2,z2} are five fp448.Elt of 56 bytes, and
+// stack = (b0,b1) are two-double precision fp.Elt of 2*fp.Size bytes.
+// This is Equation 7 at https://eprint.iacr.org/2017/264.
+TEXT ·diffAddAmd64(SB),NOSPLIT,$224-16
+ // Parameters
+ #define regWork DI
+ #define regSwap SI
+ #define ui 0*Size(regWork)
+ #define x1 1*Size(regWork)
+ #define z1 2*Size(regWork)
+ #define x2 3*Size(regWork)
+ #define z2 4*Size(regWork)
+ // Local variables
+ #define b0 0*Size(SP)
+ #define b1 2*Size(SP)
+ MOVQ w+0(FP), regWork
+ MOVQ b+8(FP), regSwap
+ cswap(x1,x2,regSwap)
+ cswap(z1,z2,regSwap)
+ CHECK_BMI2ADX(LDIFADD, difAddLeg, difAddBmi2Adx)
+ #undef regWork
+ #undef regSwap
+ #undef ui
+ #undef x1
+ #undef z1
+ #undef x2
+ #undef z2
+ #undef b0
+ #undef b1
+
+// func doubleAmd64(x, z *fp448.Elt)
+// doubleAmd64 calculates a point doubling (x1,z1) = 2*(x1,z1).
+// stack = (t0,t1) are two fp.Elt of fp.Size bytes, and
+// (b0,b1) are two-double precision fp.Elt of 2*fp.Size bytes.
+TEXT ·doubleAmd64(SB),NOSPLIT,$336-16
+ // Parameters
+ #define x1 0(DI)
+ #define z1 0(SI)
+ // Local variables
+ #define t0 0*Size(SP)
+ #define t1 1*Size(SP)
+ #define b0 2*Size(SP)
+ #define b1 4*Size(SP)
+ MOVQ x+0(FP), DI
+ MOVQ z+8(FP), SI
+ CHECK_BMI2ADX(LDOUB,doubleLeg,doubleBmi2Adx)
+ #undef x1
+ #undef z1
+ #undef t0
+ #undef t1
+ #undef b0
+ #undef b1
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/curve_generic.go b/vendor/github.com/cloudflare/circl/dh/x448/curve_generic.go
new file mode 100644
index 0000000000..b0b65ccf7e
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/curve_generic.go
@@ -0,0 +1,100 @@
+package x448
+
+import (
+ "encoding/binary"
+ "math/bits"
+
+ "github.com/cloudflare/circl/math/fp448"
+)
+
+func doubleGeneric(x, z *fp448.Elt) {
+ t0, t1 := &fp448.Elt{}, &fp448.Elt{}
+ fp448.AddSub(x, z)
+ fp448.Sqr(x, x)
+ fp448.Sqr(z, z)
+ fp448.Sub(t0, x, z)
+ mulA24Generic(t1, t0)
+ fp448.Add(t1, t1, z)
+ fp448.Mul(x, x, z)
+ fp448.Mul(z, t0, t1)
+}
+
+func diffAddGeneric(w *[5]fp448.Elt, b uint) {
+ mu, x1, z1, x2, z2 := &w[0], &w[1], &w[2], &w[3], &w[4]
+ fp448.Cswap(x1, x2, b)
+ fp448.Cswap(z1, z2, b)
+ fp448.AddSub(x1, z1)
+ fp448.Mul(z1, z1, mu)
+ fp448.AddSub(x1, z1)
+ fp448.Sqr(x1, x1)
+ fp448.Sqr(z1, z1)
+ fp448.Mul(x1, x1, z2)
+ fp448.Mul(z1, z1, x2)
+}
+
+func ladderStepGeneric(w *[5]fp448.Elt, b uint) {
+ x1, x2, z2, x3, z3 := &w[0], &w[1], &w[2], &w[3], &w[4]
+ t0 := &fp448.Elt{}
+ t1 := &fp448.Elt{}
+ fp448.AddSub(x2, z2)
+ fp448.AddSub(x3, z3)
+ fp448.Mul(t0, x2, z3)
+ fp448.Mul(t1, x3, z2)
+ fp448.AddSub(t0, t1)
+ fp448.Cmov(x2, x3, b)
+ fp448.Cmov(z2, z3, b)
+ fp448.Sqr(x3, t0)
+ fp448.Sqr(z3, t1)
+ fp448.Mul(z3, x1, z3)
+ fp448.Sqr(x2, x2)
+ fp448.Sqr(z2, z2)
+ fp448.Sub(t0, x2, z2)
+ mulA24Generic(t1, t0)
+ fp448.Add(t1, t1, z2)
+ fp448.Mul(x2, x2, z2)
+ fp448.Mul(z2, t0, t1)
+}
+
+func mulA24Generic(z, x *fp448.Elt) {
+ const A24 = 39082
+ const n = 8
+ var xx [7]uint64
+ for i := range xx {
+ xx[i] = binary.LittleEndian.Uint64(x[i*n : (i+1)*n])
+ }
+ h0, l0 := bits.Mul64(xx[0], A24)
+ h1, l1 := bits.Mul64(xx[1], A24)
+ h2, l2 := bits.Mul64(xx[2], A24)
+ h3, l3 := bits.Mul64(xx[3], A24)
+ h4, l4 := bits.Mul64(xx[4], A24)
+ h5, l5 := bits.Mul64(xx[5], A24)
+ h6, l6 := bits.Mul64(xx[6], A24)
+
+ l1, c0 := bits.Add64(h0, l1, 0)
+ l2, c1 := bits.Add64(h1, l2, c0)
+ l3, c2 := bits.Add64(h2, l3, c1)
+ l4, c3 := bits.Add64(h3, l4, c2)
+ l5, c4 := bits.Add64(h4, l5, c3)
+ l6, c5 := bits.Add64(h5, l6, c4)
+ l7, _ := bits.Add64(h6, 0, c5)
+
+ l0, c0 = bits.Add64(l0, l7, 0)
+ l1, c1 = bits.Add64(l1, 0, c0)
+ l2, c2 = bits.Add64(l2, 0, c1)
+ l3, c3 = bits.Add64(l3, l7<<32, c2)
+ l4, c4 = bits.Add64(l4, 0, c3)
+ l5, c5 = bits.Add64(l5, 0, c4)
+ l6, l7 = bits.Add64(l6, 0, c5)
+
+ xx[0], c0 = bits.Add64(l0, l7, 0)
+ xx[1], c1 = bits.Add64(l1, 0, c0)
+ xx[2], c2 = bits.Add64(l2, 0, c1)
+ xx[3], c3 = bits.Add64(l3, l7<<32, c2)
+ xx[4], c4 = bits.Add64(l4, 0, c3)
+ xx[5], c5 = bits.Add64(l5, 0, c4)
+ xx[6], _ = bits.Add64(l6, 0, c5)
+
+ for i := range xx {
+ binary.LittleEndian.PutUint64(z[i*n:(i+1)*n], xx[i])
+ }
+}
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/curve_noasm.go b/vendor/github.com/cloudflare/circl/dh/x448/curve_noasm.go
new file mode 100644
index 0000000000..3755b7c83b
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/curve_noasm.go
@@ -0,0 +1,11 @@
+//go:build !amd64 || purego
+// +build !amd64 purego
+
+package x448
+
+import fp "github.com/cloudflare/circl/math/fp448"
+
+func double(x, z *fp.Elt) { doubleGeneric(x, z) }
+func diffAdd(w *[5]fp.Elt, b uint) { diffAddGeneric(w, b) }
+func ladderStep(w *[5]fp.Elt, b uint) { ladderStepGeneric(w, b) }
+func mulA24(z, x *fp.Elt) { mulA24Generic(z, x) }
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/doc.go b/vendor/github.com/cloudflare/circl/dh/x448/doc.go
new file mode 100644
index 0000000000..c02904feda
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/doc.go
@@ -0,0 +1,19 @@
+/*
+Package x448 provides Diffie-Hellman functions as specified in RFC-7748.
+
+Validation of public keys.
+
+The Diffie-Hellman function, as described in RFC-7748 [1], works for any
+public key. However, if a different protocol requires contributory
+behaviour [2,3], then the public keys must be validated against low-order
+points [3,4]. To do that, the Shared function performs this validation
+internally and returns false when the public key is invalid (i.e., it
+is a low-order point).
+
+References:
+ - [1] RFC7748 by Langley, Hamburg, Turner (https://rfc-editor.org/rfc/rfc7748.txt)
+ - [2] Curve25519 by Bernstein (https://cr.yp.to/ecdh.html)
+ - [3] Bernstein (https://cr.yp.to/ecdh.html#validate)
+ - [4] Cremers&Jackson (https://eprint.iacr.org/2019/526)
+*/
+package x448
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/key.go b/vendor/github.com/cloudflare/circl/dh/x448/key.go
new file mode 100644
index 0000000000..2fdde51168
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/key.go
@@ -0,0 +1,46 @@
+package x448
+
+import (
+ "crypto/subtle"
+
+ fp "github.com/cloudflare/circl/math/fp448"
+)
+
+// Size is the length in bytes of a X448 key.
+const Size = 56
+
+// Key represents a X448 key.
+type Key [Size]byte
+
+func (k *Key) clamp(in *Key) *Key {
+ *k = *in
+ k[0] &= 252
+ k[55] |= 128
+ return k
+}
+
+// isValidPubKey verifies if the public key is not a low-order point.
+func (k *Key) isValidPubKey() bool {
+ fp.Modp((*fp.Elt)(k))
+ var isLowOrder int
+ for _, P := range lowOrderPoints {
+ isLowOrder |= subtle.ConstantTimeCompare(P[:], k[:])
+ }
+ return isLowOrder == 0
+}
+
+// KeyGen obtains a public key given a secret key.
+func KeyGen(public, secret *Key) {
+ ladderJoye(public.clamp(secret))
+}
+
+// Shared calculates Alice's shared key from Alice's secret key and Bob's
+// public key returning true on success. A failure case happens when the public
+// key is a low-order point, thus the shared key is all-zeros and the function
+// returns false.
+func Shared(shared, secret, public *Key) bool {
+ validPk := *public
+ ok := validPk.isValidPubKey()
+ ladderMontgomery(shared.clamp(secret), &validPk)
+ return ok
+}
diff --git a/vendor/github.com/cloudflare/circl/dh/x448/table.go b/vendor/github.com/cloudflare/circl/dh/x448/table.go
new file mode 100644
index 0000000000..eef53c30f8
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/dh/x448/table.go
@@ -0,0 +1,460 @@
+package x448
+
+import fp "github.com/cloudflare/circl/math/fp448"
+
+// tableGenerator contains the set of points:
+//
+// t[i] = (xi+1)/(xi-1),
+//
+// where (xi,yi) = 2^iG and G is the generator point
+// Size = (448)*(448/8) = 25088 bytes.
+var tableGenerator = [448 * fp.Size]byte{
+ /* (2^ 0)P */ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ /* (2^ 1)P */ 0x37, 0xfa, 0xaa, 0x0d, 0x86, 0xa6, 0x24, 0xe9, 0x6c, 0x95, 0x08, 0x34, 0xba, 0x1a, 0x81, 0x3a, 0xae, 0x01, 0xa5, 0xa7, 0x05, 0x85, 0x96, 0x00, 0x06, 0x5a, 0xd7, 0xff, 0xee, 0x8e, 0x8f, 0x94, 0xd2, 0xdc, 0xd7, 0xfc, 0xe7, 0xe5, 0x99, 0x1d, 0x05, 0x46, 0x43, 0xe8, 0xbc, 0x12, 0xb7, 0xeb, 0x30, 0x5e, 0x7a, 0x85, 0x68, 0xed, 0x9d, 0x28,
+ /* (2^ 2)P */ 0xf1, 0x7d, 0x08, 0x2b, 0x32, 0x4a, 0x62, 0x80, 0x36, 0xe7, 0xa4, 0x76, 0x5a, 0x2a, 0x1e, 0xf7, 0x9e, 0x3c, 0x40, 0x46, 0x9a, 0x1b, 0x61, 0xc1, 0xbf, 0x1a, 0x1b, 0xae, 0x91, 0x80, 0xa3, 0x76, 0x6c, 0xd4, 0x8f, 0xa4, 0xee, 0x26, 0x39, 0x23, 0xa4, 0x80, 0xf4, 0x66, 0x92, 0xe4, 0xe1, 0x18, 0x76, 0xc5, 0xe2, 0x19, 0x87, 0xd5, 0xc3, 0xe8,
+ /* (2^ 3)P */ 0xfb, 0xc9, 0xf0, 0x07, 0xf2, 0x93, 0xd8, 0x50, 0x36, 0xed, 0xfb, 0xbd, 0xb2, 0xd3, 0xfc, 0xdf, 0xd5, 0x2a, 0x6e, 0x26, 0x09, 0xce, 0xd4, 0x07, 0x64, 0x9f, 0x40, 0x74, 0xad, 0x98, 0x2f, 0x1c, 0xb6, 0xdc, 0x2d, 0x42, 0xff, 0xbf, 0x97, 0xd8, 0xdb, 0xef, 0x99, 0xca, 0x73, 0x99, 0x1a, 0x04, 0x3b, 0x56, 0x2c, 0x1f, 0x87, 0x9d, 0x9f, 0x03,
+ /* (2^ 4)P */ 0x4c, 0x35, 0x97, 0xf7, 0x81, 0x2c, 0x84, 0xa6, 0xe0, 0xcb, 0xce, 0x37, 0x4c, 0x21, 0x1c, 0x67, 0xfa, 0xab, 0x18, 0x4d, 0xef, 0xd0, 0xf0, 0x44, 0xa9, 0xfb, 0xc0, 0x8e, 0xda, 0x57, 0xa1, 0xd8, 0xeb, 0x87, 0xf4, 0x17, 0xea, 0x66, 0x0f, 0x16, 0xea, 0xcd, 0x5f, 0x3e, 0x88, 0xea, 0x09, 0x68, 0x40, 0xdf, 0x43, 0xcc, 0x54, 0x61, 0x58, 0xaa,
+ /* (2^ 5)P */ 0x8d, 0xe7, 0x59, 0xd7, 0x5e, 0x63, 0x37, 0xa7, 0x3f, 0xd1, 0x49, 0x85, 0x01, 0xdd, 0x5e, 0xb3, 0xe6, 0x29, 0xcb, 0x25, 0x93, 0xdd, 0x08, 0x96, 0x83, 0x52, 0x76, 0x85, 0xf5, 0x5d, 0x02, 0xbf, 0xe9, 0x6d, 0x15, 0x27, 0xc1, 0x09, 0xd1, 0x14, 0x4d, 0x6e, 0xe8, 0xaf, 0x59, 0x58, 0x34, 0x9d, 0x2a, 0x99, 0x85, 0x26, 0xbe, 0x4b, 0x1e, 0xb9,
+ /* (2^ 6)P */ 0x8d, 0xce, 0x94, 0xe2, 0x18, 0x56, 0x0d, 0x82, 0x8e, 0xdf, 0x85, 0x01, 0x8f, 0x93, 0x3c, 0xc6, 0xbd, 0x61, 0xfb, 0xf4, 0x22, 0xc5, 0x16, 0x87, 0xd1, 0xb1, 0x9e, 0x09, 0xc5, 0x83, 0x2e, 0x4a, 0x07, 0x88, 0xee, 0xe0, 0x29, 0x8d, 0x2e, 0x1f, 0x88, 0xad, 0xfd, 0x18, 0x93, 0xb7, 0xed, 0x42, 0x86, 0x78, 0xf0, 0xb8, 0x70, 0xbe, 0x01, 0x67,
+ /* (2^ 7)P */ 0xdf, 0x62, 0x2d, 0x94, 0xc7, 0x35, 0x23, 0xda, 0x27, 0xbb, 0x2b, 0xdb, 0x30, 0x80, 0x68, 0x16, 0xa3, 0xae, 0xd7, 0xd2, 0xa7, 0x7c, 0xbf, 0x6a, 0x1d, 0x83, 0xde, 0x96, 0x0a, 0x43, 0xb6, 0x30, 0x37, 0xd6, 0xee, 0x63, 0x59, 0x9a, 0xbf, 0xa3, 0x30, 0x6c, 0xaf, 0x0c, 0xee, 0x3d, 0xcb, 0x35, 0x4b, 0x55, 0x5f, 0x84, 0x85, 0xcb, 0x4f, 0x1e,
+ /* (2^ 8)P */ 0x9d, 0x04, 0x68, 0x89, 0xa4, 0xa9, 0x0d, 0x87, 0xc1, 0x70, 0xf1, 0xeb, 0xfb, 0x47, 0x0a, 0xf0, 0xde, 0x67, 0xb7, 0x94, 0xcd, 0x36, 0x43, 0xa5, 0x49, 0x43, 0x67, 0xc3, 0xee, 0x3c, 0x6b, 0xec, 0xd0, 0x1a, 0xf4, 0xad, 0xef, 0x06, 0x4a, 0xe8, 0x46, 0x24, 0xd7, 0x93, 0xbf, 0xf0, 0xe3, 0x81, 0x61, 0xec, 0xea, 0x64, 0xfe, 0x67, 0xeb, 0xc7,
+ /* (2^ 9)P */ 0x95, 0x45, 0x79, 0xcf, 0x2c, 0xfd, 0x9b, 0xfe, 0x84, 0x46, 0x4b, 0x8f, 0xa1, 0xcf, 0xc3, 0x04, 0x94, 0x78, 0xdb, 0xc9, 0xa6, 0x01, 0x75, 0xa4, 0xb4, 0x93, 0x72, 0x43, 0xa7, 0x7d, 0xda, 0x31, 0x38, 0x54, 0xab, 0x4e, 0x3f, 0x89, 0xa6, 0xab, 0x57, 0xc0, 0x16, 0x65, 0xdb, 0x92, 0x96, 0xe4, 0xc8, 0xae, 0xe7, 0x4c, 0x7a, 0xeb, 0xbb, 0x5a,
+ /* (2^ 10)P */ 0xbe, 0xfe, 0x86, 0xc3, 0x97, 0xe0, 0x6a, 0x18, 0x20, 0x21, 0xca, 0x22, 0x55, 0xa1, 0xeb, 0xf5, 0x74, 0xe5, 0xc9, 0x59, 0xa7, 0x92, 0x65, 0x15, 0x08, 0x71, 0xd1, 0x09, 0x7e, 0x83, 0xfc, 0xbc, 0x5a, 0x93, 0x38, 0x0d, 0x43, 0x42, 0xfd, 0x76, 0x30, 0xe8, 0x63, 0x60, 0x09, 0x8d, 0x6c, 0xd3, 0xf8, 0x56, 0x3d, 0x68, 0x47, 0xab, 0xa0, 0x1d,
+ /* (2^ 11)P */ 0x38, 0x50, 0x1c, 0xb1, 0xac, 0x88, 0x8f, 0x38, 0xe3, 0x69, 0xe6, 0xfc, 0x4f, 0x8f, 0xe1, 0x9b, 0xb1, 0x1a, 0x09, 0x39, 0x19, 0xdf, 0xcd, 0x98, 0x7b, 0x64, 0x42, 0xf6, 0x11, 0xea, 0xc7, 0xe8, 0x92, 0x65, 0x00, 0x2c, 0x75, 0xb5, 0x94, 0x1e, 0x5b, 0xa6, 0x66, 0x81, 0x77, 0xf3, 0x39, 0x94, 0xac, 0xbd, 0xe4, 0x2a, 0x66, 0x84, 0x9c, 0x60,
+ /* (2^ 12)P */ 0xb5, 0xb6, 0xd9, 0x03, 0x67, 0xa4, 0xa8, 0x0a, 0x4a, 0x2b, 0x9d, 0xfa, 0x13, 0xe1, 0x99, 0x25, 0x4a, 0x5c, 0x67, 0xb9, 0xb2, 0xb7, 0xdd, 0x1e, 0xaf, 0xeb, 0x63, 0x41, 0xb6, 0xb9, 0xa0, 0x87, 0x0a, 0xe0, 0x06, 0x07, 0xaa, 0x97, 0xf8, 0xf9, 0x38, 0x4f, 0xdf, 0x0c, 0x40, 0x7c, 0xc3, 0x98, 0xa9, 0x74, 0xf1, 0x5d, 0xda, 0xd1, 0xc0, 0x0a,
+ /* (2^ 13)P */ 0xf2, 0x0a, 0xab, 0xab, 0x94, 0x50, 0xf0, 0xa3, 0x6f, 0xc6, 0x66, 0xba, 0xa6, 0xdc, 0x44, 0xdd, 0xd6, 0x08, 0xf4, 0xd3, 0xed, 0xb1, 0x40, 0x93, 0xee, 0xf6, 0xb8, 0x8e, 0xb4, 0x7c, 0xb9, 0x82, 0xc9, 0x9d, 0x45, 0x3b, 0x8e, 0x10, 0xcb, 0x70, 0x1e, 0xba, 0x3c, 0x62, 0x50, 0xda, 0xa9, 0x93, 0xb5, 0xd7, 0xd0, 0x6f, 0x29, 0x52, 0x95, 0xae,
+ /* (2^ 14)P */ 0x14, 0x68, 0x69, 0x23, 0xa8, 0x44, 0x87, 0x9e, 0x22, 0x91, 0xe8, 0x92, 0xdf, 0xf7, 0xae, 0xba, 0x1c, 0x96, 0xe1, 0xc3, 0x94, 0xed, 0x6c, 0x95, 0xae, 0x96, 0xa7, 0x15, 0x9f, 0xf1, 0x17, 0x11, 0x92, 0x42, 0xd5, 0xcd, 0x18, 0xe7, 0xa9, 0xb5, 0x2f, 0xcd, 0xde, 0x6c, 0xc9, 0x7d, 0xfc, 0x7e, 0xbd, 0x7f, 0x10, 0x3d, 0x01, 0x00, 0x8d, 0x95,
+ /* (2^ 15)P */ 0x3b, 0x76, 0x72, 0xae, 0xaf, 0x84, 0xf2, 0xf7, 0xd1, 0x6d, 0x13, 0x9c, 0x47, 0xe1, 0xb7, 0xa3, 0x19, 0x16, 0xee, 0x75, 0x45, 0xf6, 0x1a, 0x7b, 0x78, 0x49, 0x79, 0x05, 0x86, 0xf0, 0x7f, 0x9f, 0xfc, 0xc4, 0xbd, 0x86, 0xf3, 0x41, 0xa7, 0xfe, 0x01, 0xd5, 0x67, 0x16, 0x10, 0x5b, 0xa5, 0x16, 0xf3, 0x7f, 0x60, 0xce, 0xd2, 0x0c, 0x8e, 0x4b,
+ /* (2^ 16)P */ 0x4a, 0x07, 0x99, 0x4a, 0x0f, 0x74, 0x91, 0x14, 0x68, 0xb9, 0x48, 0xb7, 0x44, 0x77, 0x9b, 0x4a, 0xe0, 0x68, 0x0e, 0x43, 0x4d, 0x98, 0x98, 0xbf, 0xa8, 0x3a, 0xb7, 0x6d, 0x2a, 0x9a, 0x77, 0x5f, 0x62, 0xf5, 0x6b, 0x4a, 0xb7, 0x7d, 0xe5, 0x09, 0x6b, 0xc0, 0x8b, 0x9c, 0x88, 0x37, 0x33, 0xf2, 0x41, 0xac, 0x22, 0x1f, 0xcf, 0x3b, 0x82, 0x34,
+ /* (2^ 17)P */ 0x00, 0xc3, 0x78, 0x42, 0x32, 0x2e, 0xdc, 0xda, 0xb1, 0x96, 0x21, 0xa4, 0xe4, 0xbb, 0xe9, 0x9d, 0xbb, 0x0f, 0x93, 0xed, 0x26, 0x3d, 0xb5, 0xdb, 0x94, 0x31, 0x37, 0x07, 0xa2, 0xb2, 0xd5, 0x99, 0x0d, 0x93, 0xe1, 0xce, 0x3f, 0x0b, 0x96, 0x82, 0x47, 0xfe, 0x60, 0x6f, 0x8f, 0x61, 0x88, 0xd7, 0x05, 0x95, 0x0b, 0x46, 0x06, 0xb7, 0x32, 0x06,
+ /* (2^ 18)P */ 0x44, 0xf5, 0x34, 0xdf, 0x2f, 0x9c, 0x5d, 0x9f, 0x53, 0x5c, 0x42, 0x8f, 0xc9, 0xdc, 0xd8, 0x40, 0xa2, 0xe7, 0x6a, 0x4a, 0x05, 0xf7, 0x86, 0x77, 0x2b, 0xae, 0x37, 0xed, 0x48, 0xfb, 0xf7, 0x62, 0x7c, 0x17, 0x59, 0x92, 0x41, 0x61, 0x93, 0x38, 0x30, 0xd1, 0xef, 0x54, 0x54, 0x03, 0x17, 0x57, 0x91, 0x15, 0x11, 0x33, 0xb5, 0xfa, 0xfb, 0x17,
+ /* (2^ 19)P */ 0x29, 0xbb, 0xd4, 0xb4, 0x9c, 0xf1, 0x72, 0x94, 0xce, 0x6a, 0x29, 0xa8, 0x89, 0x18, 0x19, 0xf7, 0xb7, 0xcc, 0xee, 0x9a, 0x02, 0xe3, 0xc0, 0xb1, 0xe0, 0xee, 0x83, 0x78, 0xb4, 0x9e, 0x07, 0x87, 0xdf, 0xb0, 0x82, 0x26, 0x4e, 0xa4, 0x0c, 0x33, 0xaf, 0x40, 0x59, 0xb6, 0xdd, 0x52, 0x45, 0xf0, 0xb4, 0xf6, 0xe8, 0x4e, 0x4e, 0x79, 0x1a, 0x5d,
+ /* (2^ 20)P */ 0x27, 0x33, 0x4d, 0x4c, 0x6b, 0x4f, 0x75, 0xb1, 0xbc, 0x1f, 0xab, 0x5b, 0x2b, 0xf0, 0x1c, 0x57, 0x86, 0xdd, 0xfd, 0x60, 0xb0, 0x8c, 0xe7, 0x9a, 0xe5, 0x5c, 0xeb, 0x11, 0x3a, 0xda, 0x22, 0x25, 0x99, 0x06, 0x8d, 0xf4, 0xaf, 0x29, 0x7a, 0xc9, 0xe5, 0xd2, 0x16, 0x9e, 0xd4, 0x63, 0x1d, 0x64, 0xa6, 0x47, 0x96, 0x37, 0x6f, 0x93, 0x2c, 0xcc,
+ /* (2^ 21)P */ 0xc1, 0x94, 0x74, 0x86, 0x75, 0xf2, 0x91, 0x58, 0x23, 0x85, 0x63, 0x76, 0x54, 0xc7, 0xb4, 0x8c, 0xbc, 0x4e, 0xc4, 0xa7, 0xba, 0xa0, 0x55, 0x26, 0x71, 0xd5, 0x33, 0x72, 0xc9, 0xad, 0x1e, 0xf9, 0x5d, 0x78, 0x70, 0x93, 0x4e, 0x85, 0xfc, 0x39, 0x06, 0x73, 0x76, 0xff, 0xe8, 0x64, 0x69, 0x42, 0x45, 0xb2, 0x69, 0xb5, 0x32, 0xe7, 0x2c, 0xde,
+ /* (2^ 22)P */ 0xde, 0x16, 0xd8, 0x33, 0x49, 0x32, 0xe9, 0x0e, 0x3a, 0x60, 0xee, 0x2e, 0x24, 0x75, 0xe3, 0x9c, 0x92, 0x07, 0xdb, 0xad, 0x92, 0xf5, 0x11, 0xdf, 0xdb, 0xb0, 0x17, 0x5c, 0xd6, 0x1a, 0x70, 0x00, 0xb7, 0xe2, 0x18, 0xec, 0xdc, 0xc2, 0x02, 0x93, 0xb3, 0xc8, 0x3f, 0x4f, 0x1b, 0x96, 0xe6, 0x33, 0x8c, 0xfb, 0xcc, 0xa5, 0x4e, 0xe8, 0xe7, 0x11,
+ /* (2^ 23)P */ 0x05, 0x7a, 0x74, 0x52, 0xf8, 0xdf, 0x0d, 0x7c, 0x6a, 0x1a, 0x4e, 0x9a, 0x02, 0x1d, 0xae, 0x77, 0xf8, 0x8e, 0xf9, 0xa2, 0x38, 0x54, 0x50, 0xb2, 0x2c, 0x08, 0x9d, 0x9b, 0x9f, 0xfb, 0x2b, 0x06, 0xde, 0x9d, 0xc2, 0x03, 0x0b, 0x22, 0x2b, 0x10, 0x5b, 0x3a, 0x73, 0x29, 0x8e, 0x3e, 0x37, 0x08, 0x2c, 0x3b, 0xf8, 0x80, 0xc1, 0x66, 0x1e, 0x98,
+ /* (2^ 24)P */ 0xd8, 0xd6, 0x3e, 0xcd, 0x63, 0x8c, 0x2b, 0x41, 0x81, 0xc0, 0x0c, 0x06, 0x87, 0xd6, 0xe7, 0x92, 0xfe, 0xf1, 0x0c, 0x4a, 0x84, 0x5b, 0xaf, 0x40, 0x53, 0x6f, 0x60, 0xd6, 0x6b, 0x76, 0x4b, 0xc2, 0xad, 0xc9, 0xb6, 0xb6, 0x6a, 0xa2, 0xb3, 0xf5, 0xf5, 0xc2, 0x55, 0x83, 0xb2, 0xd3, 0xe9, 0x41, 0x6c, 0x63, 0x51, 0xb8, 0x81, 0x74, 0xc8, 0x2c,
+ /* (2^ 25)P */ 0xb2, 0xaf, 0x1c, 0xee, 0x07, 0xb0, 0x58, 0xa8, 0x2c, 0x6a, 0xc9, 0x2d, 0x62, 0x28, 0x75, 0x0c, 0x40, 0xb6, 0x11, 0x33, 0x96, 0x80, 0x28, 0x6d, 0xd5, 0x9e, 0x87, 0x90, 0x01, 0x66, 0x1d, 0x1c, 0xf8, 0xb4, 0x92, 0xac, 0x38, 0x18, 0x05, 0xc2, 0x4c, 0x4b, 0x54, 0x7d, 0x80, 0x46, 0x87, 0x2d, 0x99, 0x8e, 0x70, 0x80, 0x69, 0x71, 0x8b, 0xed,
+ /* (2^ 26)P */ 0x37, 0xa7, 0x6b, 0x71, 0x36, 0x75, 0x8e, 0xff, 0x0f, 0x42, 0xda, 0x5a, 0x46, 0xa6, 0x97, 0x79, 0x7e, 0x30, 0xb3, 0x8f, 0xc7, 0x3a, 0xa0, 0xcb, 0x1d, 0x9c, 0x78, 0x77, 0x36, 0xc2, 0xe7, 0xf4, 0x2f, 0x29, 0x07, 0xb1, 0x07, 0xfd, 0xed, 0x1b, 0x39, 0x77, 0x06, 0x38, 0x77, 0x0f, 0x50, 0x31, 0x12, 0xbf, 0x92, 0xbf, 0x72, 0x79, 0x54, 0xa9,
+ /* (2^ 27)P */ 0xbd, 0x4d, 0x46, 0x6b, 0x1a, 0x80, 0x46, 0x2d, 0xed, 0xfd, 0x64, 0x6d, 0x94, 0xbc, 0x4a, 0x6e, 0x0c, 0x12, 0xf6, 0x12, 0xab, 0x54, 0x88, 0xd3, 0x85, 0xac, 0x51, 0xae, 0x6f, 0xca, 0xc4, 0xb7, 0xec, 0x22, 0x54, 0x6d, 0x80, 0xb2, 0x1c, 0x63, 0x33, 0x76, 0x6b, 0x8e, 0x6d, 0x59, 0xcd, 0x73, 0x92, 0x5f, 0xff, 0xad, 0x10, 0x35, 0x70, 0x5f,
+ /* (2^ 28)P */ 0xb3, 0x84, 0xde, 0xc8, 0x04, 0x43, 0x63, 0xfa, 0x29, 0xd9, 0xf0, 0x69, 0x65, 0x5a, 0x0c, 0xe8, 0x2e, 0x0b, 0xfe, 0xb0, 0x7a, 0x42, 0xb3, 0xc3, 0xfc, 0xe6, 0xb8, 0x92, 0x29, 0xae, 0xed, 0xec, 0xd5, 0xe8, 0x4a, 0xa1, 0xbd, 0x3b, 0xd3, 0xc0, 0x07, 0xab, 0x65, 0x65, 0x35, 0x9a, 0xa6, 0x5e, 0x78, 0x18, 0x76, 0x1c, 0x15, 0x49, 0xe6, 0x75,
+ /* (2^ 29)P */ 0x45, 0xb3, 0x92, 0xa9, 0xc3, 0xb8, 0x11, 0x68, 0x64, 0x3a, 0x83, 0x5d, 0xa8, 0x94, 0x6a, 0x9d, 0xaa, 0x27, 0x9f, 0x98, 0x5d, 0xc0, 0x29, 0xf0, 0xc0, 0x4b, 0x14, 0x3c, 0x05, 0xe7, 0xf8, 0xbd, 0x38, 0x22, 0x96, 0x75, 0x65, 0x5e, 0x0d, 0x3f, 0xbb, 0x6f, 0xe8, 0x3f, 0x96, 0x76, 0x9f, 0xba, 0xd9, 0x44, 0x92, 0x96, 0x22, 0xe7, 0x52, 0xe7,
+ /* (2^ 30)P */ 0xf4, 0xa3, 0x95, 0x90, 0x47, 0xdf, 0x7d, 0xdc, 0xf4, 0x13, 0x87, 0x67, 0x7d, 0x4f, 0x9d, 0xa0, 0x00, 0x46, 0x72, 0x08, 0xc3, 0xa2, 0x7a, 0x3e, 0xe7, 0x6d, 0x52, 0x7c, 0x11, 0x36, 0x50, 0x83, 0x89, 0x64, 0xcb, 0x1f, 0x08, 0x83, 0x46, 0xcb, 0xac, 0xa6, 0xd8, 0x9c, 0x1b, 0xe8, 0x05, 0x47, 0xc7, 0x26, 0x06, 0x83, 0x39, 0xe9, 0xb1, 0x1c,
+ /* (2^ 31)P */ 0x11, 0xe8, 0xc8, 0x42, 0xbf, 0x30, 0x9c, 0xa3, 0xf1, 0x85, 0x96, 0x95, 0x4f, 0x4f, 0x52, 0xa2, 0xf5, 0x8b, 0x68, 0x24, 0x16, 0xac, 0x9b, 0xa9, 0x27, 0x28, 0x0e, 0x84, 0x03, 0x46, 0x22, 0x5f, 0xf7, 0x0d, 0xa6, 0x85, 0x88, 0xc1, 0x45, 0x4b, 0x85, 0x1a, 0x10, 0x7f, 0xc9, 0x94, 0x20, 0xb0, 0x04, 0x28, 0x12, 0x30, 0xb9, 0xe6, 0x40, 0x6b,
+ /* (2^ 32)P */ 0xac, 0x1b, 0x57, 0xb6, 0x42, 0xdb, 0x81, 0x8d, 0x76, 0xfd, 0x9b, 0x1c, 0x29, 0x30, 0xd5, 0x3a, 0xcc, 0x53, 0xd9, 0x26, 0x7a, 0x0f, 0x9c, 0x2e, 0x79, 0xf5, 0x62, 0xeb, 0x61, 0x9d, 0x9b, 0x80, 0x39, 0xcd, 0x60, 0x2e, 0x1f, 0x08, 0x22, 0xbc, 0x19, 0xb3, 0x2a, 0x43, 0x44, 0xf2, 0x4e, 0x66, 0xf4, 0x36, 0xa6, 0xa7, 0xbc, 0xa4, 0x15, 0x7e,
+ /* (2^ 33)P */ 0xc1, 0x90, 0x8a, 0xde, 0xff, 0x78, 0xc3, 0x73, 0x16, 0xee, 0x76, 0xa0, 0x84, 0x60, 0x8d, 0xe6, 0x82, 0x0f, 0xde, 0x4e, 0xc5, 0x99, 0x34, 0x06, 0x90, 0x44, 0x55, 0xf8, 0x91, 0xd8, 0xe1, 0xe4, 0x2c, 0x8a, 0xde, 0x94, 0x1e, 0x78, 0x25, 0x3d, 0xfd, 0xd8, 0x59, 0x7d, 0xaf, 0x6e, 0xbe, 0x96, 0xbe, 0x3c, 0x16, 0x23, 0x0f, 0x4c, 0xa4, 0x28,
+ /* (2^ 34)P */ 0xba, 0x11, 0x35, 0x57, 0x03, 0xb6, 0xf4, 0x24, 0x89, 0xb8, 0x5a, 0x0d, 0x50, 0x9c, 0xaa, 0x51, 0x7f, 0xa4, 0x0e, 0xfc, 0x71, 0xb3, 0x3b, 0xf1, 0x96, 0x50, 0x23, 0x15, 0xf5, 0xf5, 0xd4, 0x23, 0xdc, 0x8b, 0x26, 0x9e, 0xae, 0xb7, 0x50, 0xcd, 0xc4, 0x25, 0xf6, 0x75, 0x40, 0x9c, 0x37, 0x79, 0x33, 0x60, 0xd4, 0x4b, 0x13, 0x32, 0xee, 0xe2,
+ /* (2^ 35)P */ 0x43, 0xb8, 0x56, 0x59, 0xf0, 0x68, 0x23, 0xb3, 0xea, 0x70, 0x58, 0x4c, 0x1e, 0x5a, 0x16, 0x54, 0x03, 0xb2, 0xf4, 0x73, 0xb6, 0xd9, 0x5c, 0x9c, 0x6f, 0xcf, 0x82, 0x2e, 0x54, 0x15, 0x46, 0x2c, 0xa3, 0xda, 0x4e, 0x87, 0xf5, 0x2b, 0xba, 0x91, 0xa3, 0xa0, 0x89, 0xba, 0x48, 0x2b, 0xfa, 0x64, 0x02, 0x7f, 0x78, 0x03, 0xd1, 0xe8, 0x3b, 0xe9,
+ /* (2^ 36)P */ 0x15, 0xa4, 0x71, 0xd4, 0x0c, 0x24, 0xe9, 0x07, 0xa1, 0x43, 0xf4, 0x7f, 0xbb, 0xa2, 0xa6, 0x6b, 0xfa, 0xb7, 0xea, 0x58, 0xd1, 0x96, 0xb0, 0x24, 0x5c, 0xc7, 0x37, 0x4e, 0x60, 0x0f, 0x40, 0xf2, 0x2f, 0x44, 0x70, 0xea, 0x80, 0x63, 0xfe, 0xfc, 0x46, 0x59, 0x12, 0x27, 0xb5, 0x27, 0xfd, 0xb7, 0x73, 0x0b, 0xca, 0x8b, 0xc2, 0xd3, 0x71, 0x08,
+ /* (2^ 37)P */ 0x26, 0x0e, 0xd7, 0x52, 0x6f, 0xf1, 0xf2, 0x9d, 0xb8, 0x3d, 0xbd, 0xd4, 0x75, 0x97, 0xd8, 0xbf, 0xa8, 0x86, 0x96, 0xa5, 0x80, 0xa0, 0x45, 0x75, 0xf6, 0x77, 0x71, 0xdb, 0x77, 0x96, 0x55, 0x99, 0x31, 0xd0, 0x4f, 0x34, 0xf4, 0x35, 0x39, 0x41, 0xd3, 0x7d, 0xf7, 0xe2, 0x74, 0xde, 0xbe, 0x5b, 0x1f, 0x39, 0x10, 0x21, 0xa3, 0x4d, 0x3b, 0xc8,
+ /* (2^ 38)P */ 0x04, 0x00, 0x2a, 0x45, 0xb2, 0xaf, 0x9b, 0x18, 0x6a, 0xeb, 0x96, 0x28, 0xa4, 0x77, 0xd0, 0x13, 0xcf, 0x17, 0x65, 0xe8, 0xc5, 0x81, 0x28, 0xad, 0x39, 0x7a, 0x0b, 0xaa, 0x55, 0x2b, 0xf3, 0xfc, 0x86, 0x40, 0xad, 0x0d, 0x1e, 0x28, 0xa2, 0x2d, 0xc5, 0xd6, 0x04, 0x15, 0xa2, 0x30, 0x3d, 0x12, 0x8e, 0xd6, 0xb5, 0xf7, 0x69, 0xbb, 0x84, 0x20,
+ /* (2^ 39)P */ 0xd7, 0x7a, 0x77, 0x2c, 0xfb, 0x81, 0x80, 0xe9, 0x1e, 0xc6, 0x36, 0x31, 0x79, 0xc3, 0x7c, 0xa9, 0x57, 0x6b, 0xb5, 0x70, 0xfb, 0xe4, 0xa1, 0xff, 0xfd, 0x21, 0xa5, 0x7c, 0xfa, 0x44, 0xba, 0x0d, 0x96, 0x3d, 0xc4, 0x5c, 0x39, 0x52, 0x87, 0xd7, 0x22, 0x0f, 0x52, 0x88, 0x91, 0x87, 0x96, 0xac, 0xfa, 0x3b, 0xdf, 0xdc, 0x83, 0x8c, 0x99, 0x29,
+ /* (2^ 40)P */ 0x98, 0x6b, 0x3a, 0x8d, 0x83, 0x17, 0xe1, 0x62, 0xd8, 0x80, 0x4c, 0x97, 0xce, 0x6b, 0xaa, 0x10, 0xa7, 0xc4, 0xe9, 0xeb, 0xa5, 0xfb, 0xc9, 0xdd, 0x2d, 0xeb, 0xfc, 0x9a, 0x71, 0xcd, 0x68, 0x6e, 0xc0, 0x35, 0x64, 0x62, 0x1b, 0x95, 0x12, 0xe8, 0x53, 0xec, 0xf0, 0xf4, 0x86, 0x86, 0x78, 0x18, 0xc4, 0xc6, 0xbc, 0x5a, 0x59, 0x8f, 0x7c, 0x7e,
+ /* (2^ 41)P */ 0x7f, 0xd7, 0x1e, 0xc5, 0x83, 0xdc, 0x1f, 0xbe, 0x0b, 0xcf, 0x2e, 0x01, 0x01, 0xed, 0xac, 0x17, 0x3b, 0xed, 0xa4, 0x30, 0x96, 0x0e, 0x14, 0x7e, 0x19, 0x2b, 0xa5, 0x67, 0x1e, 0xb3, 0x34, 0x03, 0xa8, 0xbb, 0x0a, 0x7d, 0x08, 0x2d, 0xd5, 0x53, 0x19, 0x6f, 0x13, 0xd5, 0xc0, 0x90, 0x8a, 0xcc, 0xc9, 0x5c, 0xab, 0x24, 0xd7, 0x03, 0xf6, 0x57,
+ /* (2^ 42)P */ 0x49, 0xcb, 0xb4, 0x96, 0x5f, 0xa6, 0xf8, 0x71, 0x6f, 0x59, 0xad, 0x05, 0x24, 0x2d, 0xaf, 0x67, 0xa8, 0xbe, 0x95, 0xdf, 0x0d, 0x28, 0x5a, 0x7f, 0x6e, 0x87, 0x8c, 0x6e, 0x67, 0x0c, 0xf4, 0xe0, 0x1c, 0x30, 0xc2, 0x66, 0xae, 0x20, 0xa1, 0x34, 0xec, 0x9c, 0xbc, 0xae, 0x3d, 0xa1, 0x28, 0x28, 0x95, 0x1d, 0xc9, 0x3a, 0xa8, 0xfd, 0xfc, 0xa1,
+ /* (2^ 43)P */ 0xe2, 0x2b, 0x9d, 0xed, 0x02, 0x99, 0x67, 0xbb, 0x2e, 0x16, 0x62, 0x05, 0x70, 0xc7, 0x27, 0xb9, 0x1c, 0x3f, 0xf2, 0x11, 0x01, 0xd8, 0x51, 0xa4, 0x18, 0x92, 0xa9, 0x5d, 0xfb, 0xa9, 0xe4, 0x42, 0xba, 0x38, 0x34, 0x1a, 0x4a, 0xc5, 0x6a, 0x37, 0xde, 0xa7, 0x0c, 0xb4, 0x7e, 0x7f, 0xde, 0xa6, 0xee, 0xcd, 0x55, 0x57, 0x05, 0x06, 0xfd, 0x5d,
+ /* (2^ 44)P */ 0x2f, 0x32, 0xcf, 0x2e, 0x2c, 0x7b, 0xbe, 0x9a, 0x0c, 0x57, 0x35, 0xf8, 0x87, 0xda, 0x9c, 0xec, 0x48, 0xf2, 0xbb, 0xe2, 0xda, 0x10, 0x58, 0x20, 0xc6, 0xd3, 0x87, 0xe9, 0xc7, 0x26, 0xd1, 0x9a, 0x46, 0x87, 0x90, 0xda, 0xdc, 0xde, 0xc3, 0xb3, 0xf2, 0xe8, 0x6f, 0x4a, 0xe6, 0xe8, 0x9d, 0x98, 0x36, 0x20, 0x03, 0x47, 0x15, 0x3f, 0x64, 0x59,
+ /* (2^ 45)P */ 0xd4, 0x71, 0x49, 0x0a, 0x67, 0x97, 0xaa, 0x3f, 0xf4, 0x1b, 0x3a, 0x6e, 0x5e, 0x17, 0xcc, 0x0a, 0x8f, 0x81, 0x6a, 0x41, 0x38, 0x77, 0x40, 0x8a, 0x11, 0x42, 0x62, 0xd2, 0x50, 0x32, 0x79, 0x78, 0x28, 0xc2, 0x2e, 0x10, 0x01, 0x94, 0x30, 0x4f, 0x7f, 0x18, 0x17, 0x56, 0x85, 0x4e, 0xad, 0xf7, 0xcb, 0x87, 0x3c, 0x3f, 0x50, 0x2c, 0xc0, 0xba,
+ /* (2^ 46)P */ 0xbc, 0x30, 0x8e, 0x65, 0x8e, 0x57, 0x5b, 0x38, 0x7a, 0xd4, 0x95, 0x52, 0x7a, 0x32, 0x59, 0x69, 0xcd, 0x9d, 0x47, 0x34, 0x5b, 0x55, 0xa5, 0x24, 0x60, 0xdd, 0xc0, 0xc1, 0x62, 0x73, 0x44, 0xae, 0x4c, 0x9c, 0x65, 0x55, 0x1b, 0x9d, 0x8a, 0x29, 0xb0, 0x1a, 0x52, 0xa8, 0xf1, 0xe6, 0x9a, 0xb3, 0xf6, 0xa3, 0xc9, 0x0a, 0x70, 0x7d, 0x0f, 0xee,
+ /* (2^ 47)P */ 0x77, 0xd3, 0xe5, 0x8e, 0xfa, 0x00, 0xeb, 0x1b, 0x7f, 0xdc, 0x68, 0x3f, 0x92, 0xbd, 0xb7, 0x0b, 0xb7, 0xb5, 0x24, 0xdf, 0xc5, 0x67, 0x53, 0xd4, 0x36, 0x79, 0xc4, 0x7b, 0x57, 0xbc, 0x99, 0x97, 0x60, 0xef, 0xe4, 0x01, 0xa1, 0xa7, 0xaa, 0x12, 0x36, 0x29, 0xb1, 0x03, 0xc2, 0x83, 0x1c, 0x2b, 0x83, 0xef, 0x2e, 0x2c, 0x23, 0x92, 0xfd, 0xd1,
+ /* (2^ 48)P */ 0x94, 0xef, 0x03, 0x59, 0xfa, 0x8a, 0x18, 0x76, 0xee, 0x58, 0x08, 0x4d, 0x44, 0xce, 0xf1, 0x52, 0x33, 0x49, 0xf6, 0x69, 0x71, 0xe3, 0xa9, 0xbc, 0x86, 0xe3, 0x43, 0xde, 0x33, 0x7b, 0x90, 0x8b, 0x3e, 0x7d, 0xd5, 0x4a, 0xf0, 0x23, 0x99, 0xa6, 0xea, 0x5f, 0x08, 0xe5, 0xb9, 0x49, 0x8b, 0x0d, 0x6a, 0x21, 0xab, 0x07, 0x62, 0xcd, 0xc4, 0xbe,
+ /* (2^ 49)P */ 0x61, 0xbf, 0x70, 0x14, 0xfa, 0x4e, 0x9e, 0x7c, 0x0c, 0xf8, 0xb2, 0x48, 0x71, 0x62, 0x83, 0xd6, 0xd1, 0xdc, 0x9c, 0x29, 0x66, 0xb1, 0x34, 0x9c, 0x8d, 0xe6, 0x88, 0xaf, 0xbe, 0xdc, 0x4d, 0xeb, 0xb0, 0xe7, 0x28, 0xae, 0xb2, 0x05, 0x56, 0xc6, 0x0e, 0x10, 0x26, 0xab, 0x2c, 0x59, 0x72, 0x03, 0x66, 0xfe, 0x8f, 0x2c, 0x51, 0x2d, 0xdc, 0xae,
+ /* (2^ 50)P */ 0xdc, 0x63, 0xf1, 0x8b, 0x5c, 0x65, 0x0b, 0xf1, 0xa6, 0x22, 0xe2, 0xd9, 0xdb, 0x49, 0xb1, 0x3c, 0x47, 0xc2, 0xfe, 0xac, 0x86, 0x07, 0x52, 0xec, 0xb0, 0x08, 0x69, 0xfb, 0xd1, 0x06, 0xdc, 0x48, 0x5c, 0x3d, 0xb2, 0x4d, 0xb8, 0x1a, 0x4e, 0xda, 0xb9, 0xc1, 0x2b, 0xab, 0x4b, 0x62, 0x81, 0x21, 0x9a, 0xfc, 0x3d, 0x39, 0x83, 0x11, 0x36, 0xeb,
+ /* (2^ 51)P */ 0x94, 0xf3, 0x17, 0xef, 0xf9, 0x60, 0x54, 0xc3, 0xd7, 0x27, 0x35, 0xc5, 0x98, 0x5e, 0xf6, 0x63, 0x6c, 0xa0, 0x4a, 0xd3, 0xa3, 0x98, 0xd9, 0x42, 0xe3, 0xf1, 0xf8, 0x81, 0x96, 0xa9, 0xea, 0x6d, 0x4b, 0x8e, 0x33, 0xca, 0x94, 0x0d, 0xa0, 0xf7, 0xbb, 0x64, 0xa3, 0x36, 0x6f, 0xdc, 0x5a, 0x94, 0x42, 0xca, 0x06, 0xb2, 0x2b, 0x9a, 0x9f, 0x71,
+ /* (2^ 52)P */ 0xec, 0xdb, 0xa6, 0x1f, 0xdf, 0x15, 0x36, 0xa3, 0xda, 0x8a, 0x7a, 0xb6, 0xa7, 0xe3, 0xaf, 0x52, 0xe0, 0x8d, 0xe8, 0xf2, 0x44, 0x20, 0xeb, 0xa1, 0x20, 0xc4, 0x65, 0x3c, 0x7c, 0x6c, 0x49, 0xed, 0x2f, 0x66, 0x23, 0x68, 0x61, 0x91, 0x40, 0x9f, 0x50, 0x19, 0xd1, 0x84, 0xa7, 0xe2, 0xed, 0x34, 0x37, 0xe3, 0xe4, 0x11, 0x7f, 0x87, 0x55, 0x0f,
+ /* (2^ 53)P */ 0xb3, 0xa1, 0x0f, 0xb0, 0x48, 0xc0, 0x4d, 0x96, 0xa7, 0xcf, 0x5a, 0x81, 0xb8, 0x4a, 0x46, 0xef, 0x0a, 0xd3, 0x40, 0x7e, 0x02, 0xe3, 0x63, 0xaa, 0x50, 0xd1, 0x2a, 0x37, 0x22, 0x4a, 0x7f, 0x4f, 0xb6, 0xf9, 0x01, 0x82, 0x78, 0x3d, 0x93, 0x14, 0x11, 0x8a, 0x90, 0x60, 0xcd, 0x45, 0x4e, 0x7b, 0x42, 0xb9, 0x3e, 0x6e, 0x68, 0x1f, 0x36, 0x41,
+ /* (2^ 54)P */ 0x13, 0x73, 0x0e, 0x4f, 0x79, 0x93, 0x9e, 0x29, 0x70, 0x7b, 0x4a, 0x59, 0x1a, 0x9a, 0xf4, 0x55, 0x08, 0xf0, 0xdb, 0x17, 0x58, 0xec, 0x64, 0xad, 0x7f, 0x29, 0xeb, 0x3f, 0x85, 0x4e, 0x60, 0x28, 0x98, 0x1f, 0x73, 0x4e, 0xe6, 0xa8, 0xab, 0xd5, 0xd6, 0xfc, 0xa1, 0x36, 0x6d, 0x15, 0xc6, 0x13, 0x83, 0xa0, 0xc2, 0x6e, 0xd9, 0xdb, 0xc9, 0xcc,
+ /* (2^ 55)P */ 0xff, 0xd8, 0x52, 0xa3, 0xdc, 0x99, 0xcf, 0x3e, 0x19, 0xb3, 0x68, 0xd0, 0xb5, 0x0d, 0xb8, 0xee, 0x3f, 0xef, 0x6e, 0xc0, 0x38, 0x28, 0x44, 0x92, 0x78, 0x91, 0x1a, 0x08, 0x78, 0x6c, 0x65, 0x24, 0xf3, 0xa2, 0x3d, 0xf2, 0xe5, 0x79, 0x62, 0x69, 0x29, 0xf4, 0x22, 0xc5, 0xdb, 0x6a, 0xae, 0xf4, 0x44, 0xa3, 0x6f, 0xc7, 0x86, 0xab, 0xef, 0xef,
+ /* (2^ 56)P */ 0xbf, 0x54, 0x9a, 0x09, 0x5d, 0x17, 0xd0, 0xde, 0xfb, 0xf5, 0xca, 0xff, 0x13, 0x20, 0x88, 0x82, 0x3a, 0xe2, 0xd0, 0x3b, 0xfb, 0x05, 0x76, 0xd1, 0xc0, 0x02, 0x71, 0x3b, 0x94, 0xe8, 0xc9, 0x84, 0xcf, 0xa4, 0xe9, 0x28, 0x7b, 0xf5, 0x09, 0xc3, 0x2b, 0x22, 0x40, 0xf1, 0x68, 0x24, 0x24, 0x7d, 0x9f, 0x6e, 0xcd, 0xfe, 0xb0, 0x19, 0x61, 0xf5,
+ /* (2^ 57)P */ 0xe8, 0x63, 0x51, 0xb3, 0x95, 0x6b, 0x7b, 0x74, 0x92, 0x52, 0x45, 0xa4, 0xed, 0xea, 0x0e, 0x0d, 0x2b, 0x01, 0x1e, 0x2c, 0xbc, 0x91, 0x06, 0x69, 0xdb, 0x1f, 0xb5, 0x77, 0x1d, 0x56, 0xf5, 0xb4, 0x02, 0x80, 0x49, 0x56, 0x12, 0xce, 0x86, 0x05, 0xc9, 0xd9, 0xae, 0xf3, 0x6d, 0xe6, 0x3f, 0x40, 0x52, 0xe9, 0x49, 0x2b, 0x31, 0x06, 0x86, 0x14,
+ /* (2^ 58)P */ 0xf5, 0x09, 0x3b, 0xd2, 0xff, 0xdf, 0x11, 0xa5, 0x1c, 0x99, 0xe8, 0x1b, 0xa4, 0x2c, 0x7d, 0x8e, 0xc8, 0xf7, 0x03, 0x46, 0xfa, 0xb6, 0xde, 0x73, 0x91, 0x7e, 0x5a, 0x7a, 0xd7, 0x9a, 0x5b, 0x80, 0x24, 0x62, 0x5e, 0x92, 0xf1, 0xa3, 0x45, 0xa3, 0x43, 0x92, 0x8a, 0x2a, 0x5b, 0x0c, 0xb4, 0xc8, 0xad, 0x1c, 0xb6, 0x6c, 0x5e, 0x81, 0x18, 0x91,
+ /* (2^ 59)P */ 0x96, 0xb3, 0xca, 0x2b, 0xe3, 0x7a, 0x59, 0x72, 0x17, 0x74, 0x29, 0x21, 0xe7, 0x78, 0x07, 0xad, 0xda, 0xb6, 0xcd, 0xf9, 0x27, 0x4d, 0xc8, 0xf2, 0x98, 0x22, 0xca, 0xf2, 0x33, 0x74, 0x7a, 0xdd, 0x1e, 0x71, 0xec, 0xe3, 0x3f, 0xe2, 0xa2, 0xd2, 0x38, 0x75, 0xb0, 0xd0, 0x0a, 0xcf, 0x7d, 0x36, 0xdc, 0x49, 0x38, 0x25, 0x34, 0x4f, 0x20, 0x9a,
+ /* (2^ 60)P */ 0x2b, 0x6e, 0x04, 0x0d, 0x4f, 0x3d, 0x3b, 0x24, 0xf6, 0x4e, 0x5e, 0x0a, 0xbd, 0x48, 0x96, 0xba, 0x81, 0x8f, 0x39, 0x82, 0x13, 0xe6, 0x72, 0xf3, 0x0f, 0xb6, 0x94, 0xf4, 0xc5, 0x90, 0x74, 0x91, 0xa8, 0xf2, 0xc9, 0xca, 0x9a, 0x4d, 0x98, 0xf2, 0xdf, 0x52, 0x4e, 0x97, 0x2f, 0xeb, 0x84, 0xd3, 0xaf, 0xc2, 0xcc, 0xfb, 0x4c, 0x26, 0x4b, 0xe4,
+ /* (2^ 61)P */ 0x12, 0x9e, 0xfb, 0x9d, 0x78, 0x79, 0x99, 0xdd, 0xb3, 0x0b, 0x2e, 0x56, 0x41, 0x8e, 0x3f, 0x39, 0xb8, 0x97, 0x89, 0x53, 0x9b, 0x8a, 0x3c, 0x40, 0x9d, 0xa4, 0x6c, 0x2e, 0x31, 0x71, 0xc6, 0x0a, 0x41, 0xd4, 0x95, 0x06, 0x5e, 0xc1, 0xab, 0xc2, 0x14, 0xc4, 0xc7, 0x15, 0x08, 0x3a, 0xad, 0x7a, 0xb4, 0x62, 0xa3, 0x0c, 0x90, 0xf4, 0x47, 0x08,
+ /* (2^ 62)P */ 0x7f, 0xec, 0x09, 0x82, 0xf5, 0x94, 0x09, 0x93, 0x32, 0xd3, 0xdc, 0x56, 0x80, 0x7b, 0x5b, 0x22, 0x80, 0x6a, 0x96, 0x72, 0xb1, 0xc2, 0xd9, 0xa1, 0x8b, 0x66, 0x42, 0x16, 0xe2, 0x07, 0xb3, 0x2d, 0xf1, 0x75, 0x35, 0x72, 0xc7, 0x98, 0xbe, 0x63, 0x3b, 0x20, 0x75, 0x05, 0xc1, 0x3e, 0x31, 0x5a, 0xf7, 0xaa, 0xae, 0x4b, 0xdb, 0x1d, 0xd0, 0x74,
+ /* (2^ 63)P */ 0x36, 0x5c, 0x74, 0xe6, 0x5d, 0x59, 0x3f, 0x15, 0x4b, 0x4d, 0x4e, 0x67, 0x41, 0xfe, 0x98, 0x1f, 0x49, 0x76, 0x91, 0x0f, 0x9b, 0xf4, 0xaf, 0x86, 0xaf, 0x66, 0x19, 0xed, 0x46, 0xf1, 0x05, 0x9a, 0xcc, 0xd1, 0x14, 0x1f, 0x82, 0x12, 0x8e, 0xe6, 0xf4, 0xc3, 0x42, 0x5c, 0x4e, 0x33, 0x93, 0xbe, 0x30, 0xe7, 0x64, 0xa9, 0x35, 0x00, 0x4d, 0xf9,
+ /* (2^ 64)P */ 0x1f, 0xc1, 0x1e, 0xb7, 0xe3, 0x7c, 0xfa, 0xa3, 0x6b, 0x76, 0xaf, 0x9c, 0x05, 0x85, 0x4a, 0xa9, 0xfb, 0xe3, 0x7e, 0xf2, 0x49, 0x56, 0xdc, 0x2f, 0x57, 0x10, 0xba, 0x37, 0xb2, 0x62, 0xf5, 0x6b, 0xe5, 0x8f, 0x0a, 0x87, 0xd1, 0x6a, 0xcb, 0x9d, 0x07, 0xd0, 0xf6, 0x38, 0x99, 0x2c, 0x61, 0x4a, 0x4e, 0xd8, 0xd2, 0x88, 0x29, 0x99, 0x11, 0x95,
+ /* (2^ 65)P */ 0x6f, 0xdc, 0xd5, 0xd6, 0xd6, 0xa7, 0x4c, 0x46, 0x93, 0x65, 0x62, 0x23, 0x95, 0x32, 0x9c, 0xde, 0x40, 0x41, 0x68, 0x2c, 0x18, 0x4e, 0x5a, 0x8c, 0xc0, 0xc5, 0xc5, 0xea, 0x5c, 0x45, 0x0f, 0x60, 0x78, 0x39, 0xb6, 0x36, 0x23, 0x12, 0xbc, 0x21, 0x9a, 0xf8, 0x91, 0xac, 0xc4, 0x70, 0xdf, 0x85, 0x8e, 0x3c, 0xec, 0x22, 0x04, 0x98, 0xa8, 0xaa,
+ /* (2^ 66)P */ 0xcc, 0x52, 0x10, 0x5b, 0x4b, 0x6c, 0xc5, 0xfa, 0x3e, 0xd4, 0xf8, 0x1c, 0x04, 0x14, 0x48, 0x33, 0xd9, 0xfc, 0x5f, 0xb0, 0xa5, 0x48, 0x8c, 0x45, 0x8a, 0xee, 0x3e, 0xa7, 0xc1, 0x2e, 0x34, 0xca, 0xf6, 0xc9, 0xeb, 0x10, 0xbb, 0xe1, 0x59, 0x84, 0x25, 0xe8, 0x81, 0x70, 0xc0, 0x09, 0x42, 0xa7, 0x3b, 0x0d, 0x33, 0x00, 0xb5, 0x77, 0xbe, 0x25,
+ /* (2^ 67)P */ 0xcd, 0x1f, 0xbc, 0x7d, 0xef, 0xe5, 0xca, 0x91, 0xaf, 0xa9, 0x59, 0x6a, 0x09, 0xca, 0xd6, 0x1b, 0x3d, 0x55, 0xde, 0xa2, 0x6a, 0x80, 0xd6, 0x95, 0x47, 0xe4, 0x5f, 0x68, 0x54, 0x08, 0xdf, 0x29, 0xba, 0x2a, 0x02, 0x84, 0xe8, 0xe9, 0x00, 0x77, 0x99, 0x36, 0x03, 0xf6, 0x4a, 0x3e, 0x21, 0x81, 0x7d, 0xb8, 0xa4, 0x8a, 0xa2, 0x05, 0xef, 0xbc,
+ /* (2^ 68)P */ 0x7c, 0x59, 0x5f, 0x66, 0xd9, 0xb7, 0x83, 0x43, 0x8a, 0xa1, 0x8d, 0x51, 0x70, 0xba, 0xf2, 0x9b, 0x95, 0xc0, 0x4b, 0x4c, 0xa0, 0x14, 0xd3, 0xa4, 0x5d, 0x4a, 0x37, 0x36, 0x97, 0x31, 0x1e, 0x12, 0xe7, 0xbb, 0x08, 0x67, 0xa5, 0x23, 0xd7, 0xfb, 0x97, 0xd8, 0x6a, 0x03, 0xb1, 0xf8, 0x7f, 0xda, 0x58, 0xd9, 0x3f, 0x73, 0x4a, 0x53, 0xe1, 0x7b,
+ /* (2^ 69)P */ 0x55, 0x83, 0x98, 0x78, 0x6c, 0x56, 0x5e, 0xed, 0xf7, 0x23, 0x3e, 0x4c, 0x7d, 0x09, 0x2d, 0x09, 0x9c, 0x58, 0x8b, 0x32, 0xca, 0xfe, 0xbf, 0x47, 0x03, 0xeb, 0x4d, 0xe7, 0xeb, 0x9c, 0x83, 0x05, 0x68, 0xaa, 0x80, 0x89, 0x44, 0xf9, 0xd4, 0xdc, 0xdb, 0xb1, 0xdb, 0x77, 0xac, 0xf9, 0x2a, 0xae, 0x35, 0xac, 0x74, 0xb5, 0x95, 0x62, 0x18, 0x85,
+ /* (2^ 70)P */ 0xab, 0x82, 0x7e, 0x10, 0xd7, 0xe6, 0x57, 0xd1, 0x66, 0x12, 0x31, 0x9c, 0x9c, 0xa6, 0x27, 0x59, 0x71, 0x2e, 0xeb, 0xa0, 0x68, 0xc5, 0x87, 0x51, 0xf4, 0xca, 0x3f, 0x98, 0x56, 0xb0, 0x89, 0xb1, 0xc7, 0x7b, 0x46, 0xb3, 0xae, 0x36, 0xf2, 0xee, 0x15, 0x1a, 0x60, 0xf4, 0x50, 0x76, 0x4f, 0xc4, 0x53, 0x0d, 0x36, 0x4d, 0x31, 0xb1, 0x20, 0x51,
+ /* (2^ 71)P */ 0xf7, 0x1d, 0x8c, 0x1b, 0x5e, 0xe5, 0x02, 0x6f, 0xc5, 0xa5, 0xe0, 0x5f, 0xc6, 0xb6, 0x63, 0x43, 0xaf, 0x3c, 0x19, 0x6c, 0xf4, 0xaf, 0xa4, 0x33, 0xb1, 0x0a, 0x37, 0x3d, 0xd9, 0x4d, 0xe2, 0x29, 0x24, 0x26, 0x94, 0x7c, 0x02, 0xe4, 0xe2, 0xf2, 0xbe, 0xbd, 0xac, 0x1b, 0x48, 0xb8, 0xdd, 0xe9, 0x0d, 0x9a, 0x50, 0x1a, 0x98, 0x71, 0x6e, 0xdc,
+ /* (2^ 72)P */ 0x9f, 0x40, 0xb1, 0xb3, 0x66, 0x28, 0x6c, 0xfe, 0xa6, 0x7d, 0xf8, 0x3e, 0xb8, 0xf3, 0xde, 0x52, 0x76, 0x52, 0xa3, 0x92, 0x98, 0x23, 0xab, 0x4f, 0x88, 0x97, 0xfc, 0x22, 0xe1, 0x6b, 0x67, 0xcd, 0x13, 0x95, 0xda, 0x65, 0xdd, 0x3b, 0x67, 0x3f, 0x5f, 0x4c, 0xf2, 0x8a, 0xad, 0x98, 0xa7, 0x94, 0x24, 0x45, 0x87, 0x11, 0x7c, 0x75, 0x79, 0x85,
+ /* (2^ 73)P */ 0x70, 0xbf, 0xf9, 0x3b, 0xa9, 0x44, 0x57, 0x72, 0x96, 0xc9, 0xa4, 0x98, 0x65, 0xbf, 0x87, 0xb3, 0x3a, 0x39, 0x12, 0xde, 0xe5, 0x39, 0x01, 0x4f, 0xf7, 0xc0, 0x71, 0x52, 0x36, 0x85, 0xb3, 0x18, 0xf8, 0x14, 0xc0, 0x6d, 0xae, 0x9e, 0x4f, 0xb0, 0x72, 0x87, 0xac, 0x5c, 0xd1, 0x6c, 0x41, 0x6c, 0x90, 0x9d, 0x22, 0x81, 0xe4, 0x2b, 0xea, 0xe5,
+ /* (2^ 74)P */ 0xfc, 0xea, 0x1a, 0x65, 0xd9, 0x49, 0x6a, 0x39, 0xb5, 0x96, 0x72, 0x7b, 0x32, 0xf1, 0xd0, 0xe9, 0x45, 0xd9, 0x31, 0x55, 0xc7, 0x34, 0xe9, 0x5a, 0xec, 0x73, 0x0b, 0x03, 0xc4, 0xb3, 0xe6, 0xc9, 0x5e, 0x0a, 0x17, 0xfe, 0x53, 0x66, 0x7f, 0x21, 0x18, 0x74, 0x54, 0x1b, 0xc9, 0x49, 0x16, 0xd2, 0x48, 0xaf, 0x5b, 0x47, 0x7b, 0xeb, 0xaa, 0xc9,
+ /* (2^ 75)P */ 0x47, 0x04, 0xf5, 0x5a, 0x87, 0x77, 0x9e, 0x21, 0x34, 0x4e, 0x83, 0x88, 0xaf, 0x02, 0x1d, 0xb0, 0x5a, 0x1d, 0x1d, 0x7d, 0x8d, 0x2c, 0xd3, 0x8d, 0x63, 0xa9, 0x45, 0xfb, 0x15, 0x6d, 0x86, 0x45, 0xcd, 0x38, 0x0e, 0xf7, 0x37, 0x79, 0xed, 0x6d, 0x5a, 0xbc, 0x32, 0xcc, 0x66, 0xf1, 0x3a, 0xb2, 0x87, 0x6f, 0x70, 0x71, 0xd9, 0xf2, 0xfa, 0x7b,
+ /* (2^ 76)P */ 0x68, 0x07, 0xdc, 0x61, 0x40, 0xe4, 0xec, 0x32, 0xc8, 0xbe, 0x66, 0x30, 0x54, 0x80, 0xfd, 0x13, 0x7a, 0xef, 0xae, 0xed, 0x2e, 0x00, 0x6d, 0x3f, 0xbd, 0xfc, 0x91, 0x24, 0x53, 0x7f, 0x63, 0x9d, 0x2e, 0xe3, 0x76, 0xe0, 0xf3, 0xe1, 0x8f, 0x7a, 0xc4, 0x77, 0x0c, 0x91, 0xc0, 0xc2, 0x18, 0x6b, 0x04, 0xad, 0xb6, 0x70, 0x9a, 0x64, 0xc5, 0x82,
+ /* (2^ 77)P */ 0x7f, 0xea, 0x13, 0xd8, 0x9e, 0xfc, 0x5b, 0x06, 0xb5, 0x4f, 0xda, 0x38, 0xe0, 0x9c, 0xd2, 0x3a, 0xc1, 0x1c, 0x62, 0x70, 0x7f, 0xc6, 0x24, 0x0a, 0x47, 0x04, 0x01, 0xc4, 0x55, 0x09, 0xd1, 0x7a, 0x07, 0xba, 0xa3, 0x80, 0x4f, 0xc1, 0x65, 0x36, 0x6d, 0xc0, 0x10, 0xcf, 0x94, 0xa9, 0xa2, 0x01, 0x44, 0xd1, 0xf9, 0x1c, 0x4c, 0xfb, 0xf8, 0x99,
+ /* (2^ 78)P */ 0x6c, 0xb9, 0x6b, 0xee, 0x43, 0x5b, 0xb9, 0xbb, 0xee, 0x2e, 0x52, 0xc1, 0xc6, 0xb9, 0x61, 0xd2, 0x93, 0xa5, 0xaf, 0x52, 0xf4, 0xa4, 0x1a, 0x51, 0x61, 0xa7, 0xcb, 0x9e, 0xbb, 0x56, 0x65, 0xe2, 0xbf, 0x75, 0xb9, 0x9c, 0x50, 0x96, 0x60, 0x81, 0x74, 0x47, 0xc0, 0x04, 0x88, 0x71, 0x76, 0x39, 0x9a, 0xa7, 0xb1, 0x4e, 0x43, 0x15, 0xe0, 0xbb,
+ /* (2^ 79)P */ 0xbb, 0xce, 0xe2, 0xbb, 0xf9, 0x17, 0x0f, 0x82, 0x40, 0xad, 0x73, 0xe3, 0xeb, 0x3b, 0x06, 0x1a, 0xcf, 0x8e, 0x6e, 0x28, 0xb8, 0x26, 0xd9, 0x5b, 0xb7, 0xb3, 0xcf, 0xb4, 0x6a, 0x1c, 0xbf, 0x7f, 0xb8, 0xb5, 0x79, 0xcf, 0x45, 0x68, 0x7d, 0xc5, 0xeb, 0xf3, 0xbe, 0x39, 0x40, 0xfc, 0x07, 0x90, 0x7a, 0x62, 0xad, 0x86, 0x08, 0x71, 0x25, 0xe1,
+ /* (2^ 80)P */ 0x9b, 0x46, 0xac, 0xef, 0xc1, 0x4e, 0xa1, 0x97, 0x95, 0x76, 0xf9, 0x1b, 0xc2, 0xb2, 0x6a, 0x41, 0xea, 0x80, 0x3d, 0xe9, 0x08, 0x52, 0x5a, 0xe3, 0xf2, 0x08, 0xc5, 0xea, 0x39, 0x3f, 0x44, 0x71, 0x4d, 0xea, 0x0d, 0x05, 0x23, 0xe4, 0x2e, 0x3c, 0x89, 0xfe, 0x12, 0x8a, 0x95, 0x42, 0x0a, 0x68, 0xea, 0x5a, 0x28, 0x06, 0x9e, 0xe3, 0x5f, 0xe0,
+ /* (2^ 81)P */ 0x00, 0x61, 0x6c, 0x98, 0x9b, 0xe7, 0xb9, 0x06, 0x1c, 0xc5, 0x1b, 0xed, 0xbe, 0xc8, 0xb3, 0xea, 0x87, 0xf0, 0xc4, 0x24, 0x7d, 0xbb, 0x5d, 0xa4, 0x1d, 0x7a, 0x16, 0x00, 0x55, 0x94, 0x67, 0x78, 0xbd, 0x58, 0x02, 0x82, 0x90, 0x53, 0x76, 0xd4, 0x72, 0x99, 0x51, 0x6f, 0x7b, 0xcf, 0x80, 0x30, 0x31, 0x3b, 0x01, 0xc7, 0xc1, 0xef, 0xe6, 0x42,
+ /* (2^ 82)P */ 0xe2, 0x35, 0xaf, 0x4b, 0x79, 0xc6, 0x12, 0x24, 0x99, 0xc0, 0x68, 0xb0, 0x43, 0x3e, 0xe5, 0xef, 0xe2, 0x29, 0xea, 0xb8, 0xb3, 0xbc, 0x6a, 0x53, 0x2c, 0x69, 0x18, 0x5a, 0xf9, 0x15, 0xae, 0x66, 0x58, 0x18, 0xd3, 0x2d, 0x4b, 0x00, 0xfd, 0x84, 0xab, 0x4f, 0xae, 0x70, 0x6b, 0x9e, 0x9a, 0xdf, 0x83, 0xfd, 0x2e, 0x3c, 0xcf, 0xf8, 0x88, 0x5b,
+ /* (2^ 83)P */ 0xa4, 0x90, 0x31, 0x85, 0x13, 0xcd, 0xdf, 0x64, 0xc9, 0xa1, 0x0b, 0xe7, 0xb6, 0x73, 0x8a, 0x1b, 0x22, 0x78, 0x4c, 0xd4, 0xae, 0x48, 0x18, 0x00, 0x00, 0xa8, 0x9f, 0x06, 0xf9, 0xfb, 0x2d, 0xc3, 0xb1, 0x2a, 0xbc, 0x13, 0x99, 0x57, 0xaf, 0xf0, 0x8d, 0x61, 0x54, 0x29, 0xd5, 0xf2, 0x72, 0x00, 0x96, 0xd1, 0x85, 0x12, 0x8a, 0xf0, 0x23, 0xfb,
+ /* (2^ 84)P */ 0x69, 0xc7, 0xdb, 0xd9, 0x92, 0x75, 0x08, 0x9b, 0xeb, 0xa5, 0x93, 0xd1, 0x1a, 0xf4, 0xf5, 0xaf, 0xe6, 0xc4, 0x4a, 0x0d, 0x35, 0x26, 0x39, 0x9d, 0xd3, 0x17, 0x3e, 0xae, 0x2d, 0xbf, 0x73, 0x9f, 0xb7, 0x74, 0x91, 0xd1, 0xd8, 0x5c, 0x14, 0xf9, 0x75, 0xdf, 0xeb, 0xc2, 0x22, 0xd8, 0x14, 0x8d, 0x86, 0x23, 0x4d, 0xd1, 0x2d, 0xdb, 0x6b, 0x42,
+ /* (2^ 85)P */ 0x8c, 0xda, 0xc6, 0xf8, 0x71, 0xba, 0x2b, 0x06, 0x78, 0xae, 0xcc, 0x3a, 0xe3, 0xe3, 0xa1, 0x8b, 0xe2, 0x34, 0x6d, 0x28, 0x9e, 0x46, 0x13, 0x4d, 0x9e, 0xa6, 0x73, 0x49, 0x65, 0x79, 0x88, 0xb9, 0x3a, 0xd1, 0x6d, 0x2f, 0x48, 0x2b, 0x0a, 0x7f, 0x58, 0x20, 0x37, 0xf4, 0x0e, 0xbb, 0x4a, 0x95, 0x58, 0x0c, 0x88, 0x30, 0xc4, 0x74, 0xdd, 0xfd,
+ /* (2^ 86)P */ 0x6d, 0x13, 0x4e, 0x89, 0x2d, 0xa9, 0xa3, 0xed, 0x09, 0xe3, 0x0e, 0x71, 0x3e, 0x4a, 0xab, 0x90, 0xde, 0x03, 0xeb, 0x56, 0x46, 0x60, 0x06, 0xf5, 0x71, 0xe5, 0xee, 0x9b, 0xef, 0xff, 0xc4, 0x2c, 0x9f, 0x37, 0x48, 0x45, 0x94, 0x12, 0x41, 0x81, 0x15, 0x70, 0x91, 0x99, 0x5e, 0x56, 0x6b, 0xf4, 0xa6, 0xc9, 0xf5, 0x69, 0x9d, 0x78, 0x37, 0x57,
+ /* (2^ 87)P */ 0xf3, 0x51, 0x57, 0x7e, 0x43, 0x6f, 0xc6, 0x67, 0x59, 0x0c, 0xcf, 0x94, 0xe6, 0x3d, 0xb5, 0x07, 0xc9, 0x77, 0x48, 0xc9, 0x68, 0x0d, 0x98, 0x36, 0x62, 0x35, 0x38, 0x1c, 0xf5, 0xc5, 0xec, 0x66, 0x78, 0xfe, 0x47, 0xab, 0x26, 0xd6, 0x44, 0xb6, 0x06, 0x0f, 0x89, 0xe3, 0x19, 0x40, 0x1a, 0xe7, 0xd8, 0x65, 0x55, 0xf7, 0x1a, 0xfc, 0xa3, 0x0e,
+ /* (2^ 88)P */ 0x0e, 0x30, 0xa6, 0xb7, 0x58, 0x60, 0x62, 0x2a, 0x6c, 0x13, 0xa8, 0x14, 0x9b, 0xb8, 0xf2, 0x70, 0xd8, 0xb1, 0x71, 0x88, 0x8c, 0x18, 0x31, 0x25, 0x93, 0x90, 0xb4, 0xc7, 0x49, 0xd8, 0xd4, 0xdb, 0x1e, 0x1e, 0x7f, 0xaa, 0xba, 0xc9, 0xf2, 0x5d, 0xa9, 0x3a, 0x43, 0xb4, 0x5c, 0xee, 0x7b, 0xc7, 0x97, 0xb7, 0x66, 0xd7, 0x23, 0xd9, 0x22, 0x59,
+ /* (2^ 89)P */ 0x28, 0x19, 0xa6, 0xf9, 0x89, 0x20, 0x78, 0xd4, 0x6d, 0xcb, 0x79, 0x8f, 0x61, 0x6f, 0xb2, 0x5c, 0x4f, 0xa6, 0x54, 0x84, 0x95, 0x24, 0x36, 0x64, 0xcb, 0x39, 0xe7, 0x8f, 0x97, 0x9c, 0x5c, 0x3c, 0xfb, 0x51, 0x11, 0x01, 0x17, 0xdb, 0xc9, 0x9b, 0x51, 0x03, 0x9a, 0xe9, 0xe5, 0x24, 0x1e, 0xf5, 0xda, 0xe0, 0x48, 0x02, 0x23, 0xd0, 0x2c, 0x81,
+ /* (2^ 90)P */ 0x42, 0x1b, 0xe4, 0x91, 0x85, 0x2a, 0x0c, 0xd2, 0x28, 0x66, 0x57, 0x9e, 0x33, 0x8d, 0x25, 0x71, 0x10, 0x65, 0x76, 0xa2, 0x8c, 0x21, 0x86, 0x81, 0x15, 0xc2, 0x27, 0xeb, 0x54, 0x2d, 0x4f, 0x6c, 0xe6, 0xd6, 0x24, 0x9c, 0x1a, 0x12, 0xb8, 0x81, 0xe2, 0x0a, 0xf3, 0xd3, 0xf0, 0xd3, 0xe1, 0x74, 0x1f, 0x9b, 0x11, 0x47, 0xd0, 0xcf, 0xb6, 0x54,
+ /* (2^ 91)P */ 0x26, 0x45, 0xa2, 0x10, 0xd4, 0x2d, 0xae, 0xc0, 0xb0, 0xe8, 0x86, 0xb3, 0xc7, 0xea, 0x70, 0x87, 0x61, 0xb5, 0xa5, 0x55, 0xbe, 0x88, 0x1d, 0x7a, 0xd9, 0x6f, 0xeb, 0x83, 0xe2, 0x44, 0x7f, 0x98, 0x04, 0xd6, 0x50, 0x9d, 0xa7, 0x86, 0x66, 0x09, 0x63, 0xe1, 0xed, 0x72, 0xb1, 0xe4, 0x1d, 0x3a, 0xfd, 0x47, 0xce, 0x1c, 0xaa, 0x3b, 0x8f, 0x1b,
+ /* (2^ 92)P */ 0xf4, 0x3c, 0x4a, 0xb6, 0xc2, 0x9c, 0xe0, 0x2e, 0xb7, 0x38, 0xea, 0x61, 0x35, 0x97, 0x10, 0x90, 0xae, 0x22, 0x48, 0xb3, 0xa9, 0xc6, 0x7a, 0xbb, 0x23, 0xf2, 0xf8, 0x1b, 0xa7, 0xa1, 0x79, 0xcc, 0xc4, 0xf8, 0x08, 0x76, 0x8a, 0x5a, 0x1c, 0x1b, 0xc5, 0x33, 0x91, 0xa9, 0xb8, 0xb9, 0xd3, 0xf8, 0x49, 0xcd, 0xe5, 0x82, 0x43, 0xf7, 0xca, 0x68,
+ /* (2^ 93)P */ 0x38, 0xba, 0xae, 0x44, 0xfe, 0x57, 0x64, 0x56, 0x7c, 0x0e, 0x9c, 0xca, 0xff, 0xa9, 0x82, 0xbb, 0x38, 0x4a, 0xa7, 0xf7, 0x47, 0xab, 0xbe, 0x6d, 0x23, 0x0b, 0x8a, 0xed, 0xc2, 0xb9, 0x8f, 0xf1, 0xec, 0x91, 0x44, 0x73, 0x64, 0xba, 0xd5, 0x8f, 0x37, 0x38, 0x0d, 0xd5, 0xf8, 0x73, 0x57, 0xb6, 0xc2, 0x45, 0xdc, 0x25, 0xb2, 0xb6, 0xea, 0xd9,
+ /* (2^ 94)P */ 0xbf, 0xe9, 0x1a, 0x40, 0x4d, 0xcc, 0xe6, 0x1d, 0x70, 0x1a, 0x65, 0xcc, 0x34, 0x2c, 0x37, 0x2c, 0x2d, 0x6b, 0x6d, 0xe5, 0x2f, 0x19, 0x9e, 0xe4, 0xe1, 0xaa, 0xd4, 0xab, 0x54, 0xf4, 0xa8, 0xe4, 0x69, 0x2d, 0x8e, 0x4d, 0xd7, 0xac, 0xb0, 0x5b, 0xfe, 0xe3, 0x26, 0x07, 0xc3, 0xf8, 0x1b, 0x43, 0xa8, 0x1d, 0x64, 0xa5, 0x25, 0x88, 0xbb, 0x77,
+ /* (2^ 95)P */ 0x92, 0xcd, 0x6e, 0xa0, 0x79, 0x04, 0x18, 0xf4, 0x11, 0x58, 0x48, 0xb5, 0x3c, 0x7b, 0xd1, 0xcc, 0xd3, 0x14, 0x2c, 0xa0, 0xdd, 0x04, 0x44, 0x11, 0xb3, 0x6d, 0x2f, 0x0d, 0xf5, 0x2a, 0x75, 0x5d, 0x1d, 0xda, 0x86, 0x8d, 0x7d, 0x6b, 0x32, 0x68, 0xb6, 0x6c, 0x64, 0x9e, 0xde, 0x80, 0x88, 0xce, 0x08, 0xbf, 0x0b, 0xe5, 0x8e, 0x4f, 0x1d, 0xfb,
+ /* (2^ 96)P */ 0xaf, 0xe8, 0x85, 0xbf, 0x7f, 0x37, 0x8d, 0x66, 0x7c, 0xd5, 0xd3, 0x96, 0xa5, 0x81, 0x67, 0x95, 0xff, 0x48, 0xde, 0xde, 0xd7, 0x7a, 0x46, 0x34, 0xb1, 0x13, 0x70, 0x29, 0xed, 0x87, 0x90, 0xb0, 0x40, 0x2c, 0xa6, 0x43, 0x6e, 0xb6, 0xbc, 0x48, 0x8a, 0xc1, 0xae, 0xb8, 0xd4, 0xe2, 0xc0, 0x32, 0xb2, 0xa6, 0x2a, 0x8f, 0xb5, 0x16, 0x9e, 0xc3,
+ /* (2^ 97)P */ 0xff, 0x4d, 0xd2, 0xd6, 0x74, 0xef, 0x2c, 0x96, 0xc1, 0x11, 0xa8, 0xb8, 0xfe, 0x94, 0x87, 0x3e, 0xa0, 0xfb, 0x57, 0xa3, 0xfc, 0x7a, 0x7e, 0x6a, 0x59, 0x6c, 0x54, 0xbb, 0xbb, 0xa2, 0x25, 0x38, 0x1b, 0xdf, 0x5d, 0x7b, 0x94, 0x14, 0xde, 0x07, 0x6e, 0xd3, 0xab, 0x02, 0x26, 0x74, 0x16, 0x12, 0xdf, 0x2e, 0x2a, 0xa7, 0xb0, 0xe8, 0x29, 0xc0,
+ /* (2^ 98)P */ 0x6a, 0x38, 0x0b, 0xd3, 0xba, 0x45, 0x23, 0xe0, 0x04, 0x3b, 0x83, 0x39, 0xc5, 0x11, 0xe6, 0xcf, 0x39, 0x0a, 0xb3, 0xb0, 0x3b, 0x27, 0x29, 0x63, 0x1c, 0xf3, 0x00, 0xe6, 0xd2, 0x55, 0x21, 0x1f, 0x84, 0x97, 0x9f, 0x01, 0x49, 0x43, 0x30, 0x5f, 0xe0, 0x1d, 0x24, 0xc4, 0x4e, 0xa0, 0x2b, 0x0b, 0x12, 0x55, 0xc3, 0x27, 0xae, 0x08, 0x83, 0x7c,
+ /* (2^ 99)P */ 0x5d, 0x1a, 0xb7, 0xa9, 0xf5, 0xfd, 0xec, 0xad, 0xb7, 0x87, 0x02, 0x5f, 0x0d, 0x30, 0x4d, 0xe2, 0x65, 0x87, 0xa4, 0x41, 0x45, 0x1d, 0x67, 0xe0, 0x30, 0x5c, 0x13, 0x87, 0xf6, 0x2e, 0x08, 0xc1, 0xc7, 0x12, 0x45, 0xc8, 0x9b, 0xad, 0xb8, 0xd5, 0x57, 0xbb, 0x5c, 0x48, 0x3a, 0xe1, 0x91, 0x5e, 0xf6, 0x4d, 0x8a, 0x63, 0x75, 0x69, 0x0c, 0x01,
+ /* (2^100)P */ 0x8f, 0x53, 0x2d, 0xa0, 0x71, 0x3d, 0xfc, 0x45, 0x10, 0x96, 0xcf, 0x56, 0xf9, 0xbb, 0x40, 0x3c, 0x86, 0x52, 0x76, 0xbe, 0x84, 0xf9, 0xa6, 0x9d, 0x3d, 0x27, 0xbe, 0xb4, 0x00, 0x49, 0x94, 0xf5, 0x5d, 0xe1, 0x62, 0x85, 0x66, 0xe5, 0xb8, 0x20, 0x2c, 0x09, 0x7d, 0x9d, 0x3d, 0x6e, 0x74, 0x39, 0xab, 0xad, 0xa0, 0x90, 0x97, 0x5f, 0xbb, 0xa7,
+ /* (2^101)P */ 0xdb, 0x2d, 0x99, 0x08, 0x16, 0x46, 0x83, 0x7a, 0xa8, 0xea, 0x3d, 0x28, 0x5b, 0x49, 0xfc, 0xb9, 0x6d, 0x00, 0x9e, 0x54, 0x4f, 0x47, 0x64, 0x9b, 0x58, 0x4d, 0x07, 0x0c, 0x6f, 0x29, 0x56, 0x0b, 0x00, 0x14, 0x85, 0x96, 0x41, 0x04, 0xb9, 0x5c, 0xa4, 0xf6, 0x16, 0x73, 0x6a, 0xc7, 0x62, 0x0c, 0x65, 0x2f, 0x93, 0xbf, 0xf7, 0xb9, 0xb7, 0xf1,
+ /* (2^102)P */ 0xeb, 0x6d, 0xb3, 0x46, 0x32, 0xd2, 0xcb, 0x08, 0x94, 0x14, 0xbf, 0x3f, 0xc5, 0xcb, 0x5f, 0x9f, 0x8a, 0x89, 0x0c, 0x1b, 0x45, 0xad, 0x4c, 0x50, 0xb4, 0xe1, 0xa0, 0x6b, 0x11, 0x92, 0xaf, 0x1f, 0x00, 0xcc, 0xe5, 0x13, 0x7e, 0xe4, 0x2e, 0xa0, 0x57, 0xf3, 0xa7, 0x84, 0x79, 0x7a, 0xc2, 0xb7, 0xb7, 0xfc, 0x5d, 0xa5, 0xa9, 0x64, 0xcc, 0xd8,
+ /* (2^103)P */ 0xa9, 0xc4, 0x12, 0x8b, 0x34, 0x78, 0x3e, 0x38, 0xfd, 0x3f, 0x87, 0xfa, 0x88, 0x94, 0xd5, 0xd9, 0x7f, 0xeb, 0x58, 0xff, 0xb9, 0x45, 0xdb, 0xa1, 0xed, 0x22, 0x28, 0x1d, 0x00, 0x6d, 0x79, 0x85, 0x7a, 0x75, 0x5d, 0xf0, 0xb1, 0x9e, 0x47, 0x28, 0x8c, 0x62, 0xdf, 0xfb, 0x4c, 0x7b, 0xc5, 0x1a, 0x42, 0x95, 0xef, 0x9a, 0xb7, 0x27, 0x7e, 0xda,
+ /* (2^104)P */ 0xca, 0xd5, 0xc0, 0x17, 0xa1, 0x66, 0x79, 0x9c, 0x2a, 0xb7, 0x0a, 0xfe, 0x62, 0xe4, 0x26, 0x78, 0x90, 0xa7, 0xcb, 0xb0, 0x4f, 0x6d, 0xf9, 0x8f, 0xf7, 0x7d, 0xac, 0xb8, 0x78, 0x1f, 0x41, 0xea, 0x97, 0x1e, 0x62, 0x97, 0x43, 0x80, 0x58, 0x80, 0xb6, 0x69, 0x7d, 0xee, 0x16, 0xd2, 0xa1, 0x81, 0xd7, 0xb1, 0x27, 0x03, 0x48, 0xda, 0xab, 0xec,
+ /* (2^105)P */ 0x5b, 0xed, 0x40, 0x8e, 0x8c, 0xc1, 0x66, 0x90, 0x7f, 0x0c, 0xb2, 0xfc, 0xbd, 0x16, 0xac, 0x7d, 0x4c, 0x6a, 0xf9, 0xae, 0xe7, 0x4e, 0x11, 0x12, 0xe9, 0xbe, 0x17, 0x09, 0xc6, 0xc1, 0x5e, 0xb5, 0x7b, 0x50, 0x5c, 0x27, 0xfb, 0x80, 0xab, 0x01, 0xfa, 0x5b, 0x9b, 0x75, 0x16, 0x6e, 0xb2, 0x5c, 0x8c, 0x2f, 0xa5, 0x6a, 0x1a, 0x68, 0xa6, 0x90,
+ /* (2^106)P */ 0x75, 0xfe, 0xb6, 0x96, 0x96, 0x87, 0x4c, 0x12, 0xa9, 0xd1, 0xd8, 0x03, 0xa3, 0xc1, 0x15, 0x96, 0xe8, 0xa0, 0x75, 0x82, 0xa0, 0x6d, 0xea, 0x54, 0xdc, 0x5f, 0x0d, 0x7e, 0xf6, 0x70, 0xb5, 0xdc, 0x7a, 0xf6, 0xc4, 0xd4, 0x21, 0x49, 0xf5, 0xd4, 0x14, 0x6d, 0x48, 0x1d, 0x7c, 0x99, 0x42, 0xdf, 0x78, 0x6b, 0x9d, 0xb9, 0x30, 0x3c, 0xd0, 0x29,
+ /* (2^107)P */ 0x85, 0xd6, 0xd8, 0xf3, 0x91, 0x74, 0xdd, 0xbd, 0x72, 0x96, 0x10, 0xe4, 0x76, 0x02, 0x5a, 0x72, 0x67, 0xd3, 0x17, 0x72, 0x14, 0x9a, 0x20, 0x5b, 0x0f, 0x8d, 0xed, 0x6d, 0x4e, 0xe3, 0xd9, 0x82, 0xc2, 0x99, 0xee, 0x39, 0x61, 0x69, 0x8a, 0x24, 0x01, 0x92, 0x15, 0xe7, 0xfc, 0xf9, 0x4d, 0xac, 0xf1, 0x30, 0x49, 0x01, 0x0b, 0x6e, 0x0f, 0x20,
+ /* (2^108)P */ 0xd8, 0x25, 0x94, 0x5e, 0x43, 0x29, 0xf5, 0xcc, 0xe8, 0xe3, 0x55, 0x41, 0x3c, 0x9f, 0x58, 0x5b, 0x00, 0xeb, 0xc5, 0xdf, 0xcf, 0xfb, 0xfd, 0x6e, 0x92, 0xec, 0x99, 0x30, 0xd6, 0x05, 0xdd, 0x80, 0x7a, 0x5d, 0x6d, 0x16, 0x85, 0xd8, 0x9d, 0x43, 0x65, 0xd8, 0x2c, 0x33, 0x2f, 0x5c, 0x41, 0xea, 0xb7, 0x95, 0x77, 0xf2, 0x9e, 0x59, 0x09, 0xe8,
+ /* (2^109)P */ 0x00, 0xa0, 0x03, 0x80, 0xcd, 0x60, 0xe5, 0x17, 0xd4, 0x15, 0x99, 0xdd, 0x4f, 0xbf, 0x66, 0xb8, 0xc0, 0xf5, 0xf9, 0xfc, 0x6d, 0x42, 0x18, 0x34, 0x1c, 0x7d, 0x5b, 0xb5, 0x09, 0xd0, 0x99, 0x57, 0x81, 0x0b, 0x62, 0xb3, 0xa2, 0xf9, 0x0b, 0xae, 0x95, 0xb8, 0xc2, 0x3b, 0x0d, 0x5b, 0x00, 0xf1, 0xed, 0xbc, 0x05, 0x9d, 0x61, 0xbc, 0x73, 0x9d,
+ /* (2^110)P */ 0xd4, 0xdb, 0x29, 0xe5, 0x85, 0xe9, 0xc6, 0x89, 0x2a, 0xa8, 0x54, 0xab, 0xb3, 0x7f, 0x88, 0xc0, 0x4d, 0xe0, 0xd1, 0x74, 0x6e, 0xa3, 0xa7, 0x39, 0xd5, 0xcc, 0xa1, 0x8a, 0xcb, 0x5b, 0x34, 0xad, 0x92, 0xb4, 0xd8, 0xd5, 0x17, 0xf6, 0x77, 0x18, 0x9e, 0xaf, 0x45, 0x3b, 0x03, 0xe2, 0xf8, 0x52, 0x60, 0xdc, 0x15, 0x20, 0x9e, 0xdf, 0xd8, 0x5d,
+ /* (2^111)P */ 0x02, 0xc1, 0xac, 0x1a, 0x15, 0x8e, 0x6c, 0xf5, 0x1e, 0x1e, 0xba, 0x7e, 0xc2, 0xda, 0x7d, 0x02, 0xda, 0x43, 0xae, 0x04, 0x70, 0x28, 0x54, 0x78, 0x94, 0xf5, 0x4f, 0x07, 0x84, 0x8f, 0xed, 0xaa, 0xc0, 0xb8, 0xcd, 0x7f, 0x7e, 0x33, 0xa3, 0xbe, 0x21, 0x29, 0xc8, 0x56, 0x34, 0xc0, 0x76, 0x87, 0x8f, 0xc7, 0x73, 0x58, 0x90, 0x16, 0xfc, 0xd6,
+ /* (2^112)P */ 0xb8, 0x3f, 0xe1, 0xdf, 0x3a, 0x91, 0x25, 0x0c, 0xf6, 0x47, 0xa8, 0x89, 0xc4, 0xc6, 0x61, 0xec, 0x86, 0x2c, 0xfd, 0xbe, 0xa4, 0x6f, 0xc2, 0xd4, 0x46, 0x19, 0x70, 0x5d, 0x09, 0x02, 0x86, 0xd3, 0x4b, 0xe9, 0x16, 0x7b, 0xf0, 0x0d, 0x6c, 0xff, 0x91, 0x05, 0xbf, 0x55, 0xb4, 0x00, 0x8d, 0xe5, 0x6d, 0x68, 0x20, 0x90, 0x12, 0xb5, 0x5c, 0x32,
+ /* (2^113)P */ 0x80, 0x45, 0xc8, 0x51, 0x87, 0xba, 0x1c, 0x5c, 0xcf, 0x5f, 0x4b, 0x3c, 0x9e, 0x3b, 0x36, 0xd2, 0x26, 0xa2, 0x7f, 0xab, 0xb7, 0xbf, 0xda, 0x68, 0x23, 0x8f, 0xc3, 0xa0, 0xfd, 0xad, 0xf1, 0x56, 0x3b, 0xd0, 0x75, 0x2b, 0x44, 0x61, 0xd8, 0xf4, 0xf1, 0x05, 0x49, 0x53, 0x07, 0xee, 0x47, 0xef, 0xc0, 0x7c, 0x9d, 0xe4, 0x15, 0x88, 0xc5, 0x47,
+ /* (2^114)P */ 0x2d, 0xb5, 0x09, 0x80, 0xb9, 0xd3, 0xd8, 0xfe, 0x4c, 0xd2, 0xa6, 0x6e, 0xd3, 0x75, 0xcf, 0xb0, 0x99, 0xcb, 0x50, 0x8d, 0xe9, 0x67, 0x9b, 0x20, 0xe8, 0x57, 0xd8, 0x14, 0x85, 0x73, 0x6a, 0x74, 0xe0, 0x99, 0xf0, 0x6b, 0x6e, 0x59, 0x30, 0x31, 0x33, 0x96, 0x5f, 0xa1, 0x0c, 0x1b, 0xf4, 0xca, 0x09, 0xe1, 0x9b, 0xb5, 0xcf, 0x6d, 0x0b, 0xeb,
+ /* (2^115)P */ 0x1a, 0xde, 0x50, 0xa9, 0xac, 0x3e, 0x10, 0x43, 0x4f, 0x82, 0x4f, 0xc0, 0xfe, 0x3f, 0x33, 0xd2, 0x64, 0x86, 0x50, 0xa9, 0x51, 0x76, 0x5e, 0x50, 0x97, 0x6c, 0x73, 0x8d, 0x77, 0xa3, 0x75, 0x03, 0xbc, 0xc9, 0xfb, 0x50, 0xd9, 0x6d, 0x16, 0xad, 0x5d, 0x32, 0x3d, 0xac, 0x44, 0xdf, 0x51, 0xf7, 0x19, 0xd4, 0x0b, 0x57, 0x78, 0x0b, 0x81, 0x4e,
+ /* (2^116)P */ 0x32, 0x24, 0xf1, 0x6c, 0x55, 0x62, 0x1d, 0xb3, 0x1f, 0xda, 0xfa, 0x6a, 0x8f, 0x98, 0x01, 0x16, 0xde, 0x44, 0x50, 0x0d, 0x2e, 0x6c, 0x0b, 0xa2, 0xd3, 0x74, 0x0e, 0xa9, 0xbf, 0x8d, 0xa9, 0xc8, 0xc8, 0x2f, 0x62, 0xc1, 0x35, 0x5e, 0xfd, 0x3a, 0xb3, 0x83, 0x2d, 0xee, 0x4e, 0xfd, 0x5c, 0x5e, 0xad, 0x85, 0xa5, 0x10, 0xb5, 0x4f, 0x34, 0xa7,
+ /* (2^117)P */ 0xd1, 0x58, 0x6f, 0xe6, 0x54, 0x2c, 0xc2, 0xcd, 0xcf, 0x83, 0xdc, 0x88, 0x0c, 0xb9, 0xb4, 0x62, 0x18, 0x89, 0x65, 0x28, 0xe9, 0x72, 0x4b, 0x65, 0xcf, 0xd6, 0x90, 0x88, 0xd7, 0x76, 0x17, 0x4f, 0x74, 0x64, 0x1e, 0xcb, 0xd3, 0xf5, 0x4b, 0xaa, 0x2e, 0x4d, 0x2d, 0x7c, 0x13, 0x1f, 0xfd, 0xd9, 0x60, 0x83, 0x7e, 0xda, 0x64, 0x1c, 0xdc, 0x9f,
+ /* (2^118)P */ 0xad, 0xef, 0xac, 0x1b, 0xc1, 0x30, 0x5a, 0x15, 0xc9, 0x1f, 0xac, 0xf1, 0xca, 0x44, 0x95, 0x95, 0xea, 0xf2, 0x22, 0xe7, 0x8d, 0x25, 0xf0, 0xff, 0xd8, 0x71, 0xf7, 0xf8, 0x8f, 0x8f, 0xcd, 0xf4, 0x1e, 0xfe, 0x6c, 0x68, 0x04, 0xb8, 0x78, 0xa1, 0x5f, 0xa6, 0x5d, 0x5e, 0xf9, 0x8d, 0xea, 0x80, 0xcb, 0xf3, 0x17, 0xa6, 0x03, 0xc9, 0x38, 0xd5,
+ /* (2^119)P */ 0x79, 0x14, 0x31, 0xc3, 0x38, 0xe5, 0xaa, 0xbf, 0x17, 0xa3, 0x04, 0x4e, 0x80, 0x59, 0x9c, 0x9f, 0x19, 0x39, 0xe4, 0x2d, 0x23, 0x54, 0x4a, 0x7f, 0x3e, 0xf3, 0xd9, 0xc7, 0xba, 0x6c, 0x8f, 0x6b, 0xfa, 0x34, 0xb5, 0x23, 0x17, 0x1d, 0xff, 0x1d, 0xea, 0x1f, 0xd7, 0xba, 0x61, 0xb2, 0xe0, 0x38, 0x6a, 0xe9, 0xcf, 0x48, 0x5d, 0x6a, 0x10, 0x9c,
+ /* (2^120)P */ 0xc8, 0xbb, 0x13, 0x1c, 0x3f, 0x3c, 0x34, 0xfd, 0xac, 0x37, 0x52, 0x44, 0x25, 0xa8, 0xde, 0x1d, 0x63, 0xf4, 0x81, 0x9a, 0xbe, 0x0b, 0x74, 0x2e, 0xc8, 0x51, 0x16, 0xd3, 0xac, 0x4a, 0xaf, 0xe2, 0x5f, 0x3a, 0x89, 0x32, 0xd1, 0x9b, 0x7c, 0x90, 0x0d, 0xac, 0xdc, 0x8b, 0x73, 0x45, 0x45, 0x97, 0xb1, 0x90, 0x2c, 0x1b, 0x31, 0xca, 0xb1, 0x94,
+ /* (2^121)P */ 0x07, 0x28, 0xdd, 0x10, 0x14, 0xa5, 0x95, 0x7e, 0xf3, 0xe4, 0xd4, 0x14, 0xb4, 0x7e, 0x76, 0xdb, 0x42, 0xd6, 0x94, 0x3e, 0xeb, 0x44, 0x64, 0x88, 0x0d, 0xec, 0xc1, 0x21, 0xf0, 0x79, 0xe0, 0x83, 0x67, 0x55, 0x53, 0xc2, 0xf6, 0xc5, 0xc5, 0x89, 0x39, 0xe8, 0x42, 0xd0, 0x17, 0xbd, 0xff, 0x35, 0x59, 0x0e, 0xc3, 0x06, 0x86, 0xd4, 0x64, 0xcf,
+ /* (2^122)P */ 0x91, 0xa8, 0xdb, 0x57, 0x9b, 0xe2, 0x96, 0x31, 0x10, 0x6e, 0xd7, 0x9a, 0x97, 0xb3, 0xab, 0xb5, 0x15, 0x66, 0xbe, 0xcc, 0x6d, 0x9a, 0xac, 0x06, 0xb3, 0x0d, 0xaa, 0x4b, 0x9c, 0x96, 0x79, 0x6c, 0x34, 0xee, 0x9e, 0x53, 0x4d, 0x6e, 0xbd, 0x88, 0x02, 0xbf, 0x50, 0x54, 0x12, 0x5d, 0x01, 0x02, 0x46, 0xc6, 0x74, 0x02, 0x8c, 0x24, 0xae, 0xb1,
+ /* (2^123)P */ 0xf5, 0x22, 0xea, 0xac, 0x7d, 0x9c, 0x33, 0x8a, 0xa5, 0x36, 0x79, 0x6a, 0x4f, 0xa4, 0xdc, 0xa5, 0x73, 0x64, 0xc4, 0x6f, 0x43, 0x02, 0x3b, 0x94, 0x66, 0xd2, 0x4b, 0x4f, 0xf6, 0x45, 0x33, 0x5d, 0x10, 0x33, 0x18, 0x1e, 0xa3, 0xfc, 0xf7, 0xd2, 0xb8, 0xc8, 0xa7, 0xe0, 0x76, 0x8a, 0xcd, 0xff, 0x4f, 0x99, 0x34, 0x47, 0x84, 0x91, 0x96, 0x9f,
+ /* (2^124)P */ 0x8a, 0x48, 0x3b, 0x48, 0x4a, 0xbc, 0xac, 0xe2, 0x80, 0xd6, 0xd2, 0x35, 0xde, 0xd0, 0x56, 0x42, 0x33, 0xb3, 0x56, 0x5a, 0xcd, 0xb8, 0x3d, 0xb5, 0x25, 0xc1, 0xed, 0xff, 0x87, 0x0b, 0x79, 0xff, 0xf2, 0x62, 0xe1, 0x76, 0xc6, 0xa2, 0x0f, 0xa8, 0x9b, 0x0d, 0xcc, 0x3f, 0x3d, 0x35, 0x27, 0x8d, 0x0b, 0x74, 0xb0, 0xc3, 0x78, 0x8c, 0xcc, 0xc8,
+ /* (2^125)P */ 0xfc, 0x9a, 0x0c, 0xa8, 0x49, 0x42, 0xb8, 0xdf, 0xcf, 0xb3, 0x19, 0xa6, 0x64, 0x57, 0xfe, 0xe8, 0xf8, 0xa6, 0x4b, 0x86, 0xa1, 0xd5, 0x83, 0x7f, 0x14, 0x99, 0x18, 0x0c, 0x7d, 0x5b, 0xf7, 0x3d, 0xf9, 0x4b, 0x79, 0xb1, 0x86, 0x30, 0xb4, 0x5e, 0x6a, 0xe8, 0x9d, 0xfa, 0x8a, 0x41, 0xc4, 0x30, 0xfc, 0x56, 0x74, 0x14, 0x42, 0xc8, 0x96, 0x0e,
+ /* (2^126)P */ 0xdf, 0x66, 0xec, 0xbc, 0x44, 0xdb, 0x19, 0xce, 0xd4, 0xb5, 0x49, 0x40, 0x07, 0x49, 0xe0, 0x3a, 0x61, 0x10, 0xfb, 0x7d, 0xba, 0xb1, 0xe0, 0x28, 0x5b, 0x99, 0x59, 0x96, 0xa2, 0xee, 0xe0, 0x23, 0x37, 0x39, 0x1f, 0xe6, 0x57, 0x9f, 0xf8, 0xf8, 0xdc, 0x74, 0xf6, 0x8f, 0x4f, 0x5e, 0x51, 0xa4, 0x12, 0xac, 0xbe, 0xe4, 0xf3, 0xd1, 0xf0, 0x24,
+ /* (2^127)P */ 0x1e, 0x3e, 0x9a, 0x5f, 0xdf, 0x9f, 0xd6, 0x4e, 0x8a, 0x28, 0xc3, 0xcd, 0x96, 0x9d, 0x57, 0xc7, 0x61, 0x81, 0x90, 0xff, 0xae, 0xb1, 0x4f, 0xc2, 0x96, 0x8b, 0x1a, 0x18, 0xf4, 0x50, 0xcb, 0x31, 0xe1, 0x57, 0xf4, 0x90, 0xa8, 0xea, 0xac, 0xe7, 0x61, 0x98, 0xb6, 0x15, 0xc1, 0x7b, 0x29, 0xa4, 0xc3, 0x18, 0xef, 0xb9, 0xd8, 0xdf, 0xf6, 0xac,
+ /* (2^128)P */ 0xca, 0xa8, 0x6c, 0xf1, 0xb4, 0xca, 0xfe, 0x31, 0xee, 0x48, 0x38, 0x8b, 0x0e, 0xbb, 0x7a, 0x30, 0xaa, 0xf9, 0xee, 0x27, 0x53, 0x24, 0xdc, 0x2e, 0x15, 0xa6, 0x48, 0x8f, 0xa0, 0x7e, 0xf1, 0xdc, 0x93, 0x87, 0x39, 0xeb, 0x7f, 0x38, 0x92, 0x92, 0x4c, 0x29, 0xe9, 0x57, 0xd8, 0x59, 0xfc, 0xe9, 0x9c, 0x44, 0xc0, 0x65, 0xcf, 0xac, 0x4b, 0xdc,
+ /* (2^129)P */ 0xa3, 0xd0, 0x37, 0x8f, 0x86, 0x2f, 0xc6, 0x47, 0x55, 0x46, 0x65, 0x26, 0x4b, 0x91, 0xe2, 0x18, 0x5c, 0x4f, 0x23, 0xc1, 0x37, 0x29, 0xb9, 0xc1, 0x27, 0xc5, 0x3c, 0xbf, 0x7e, 0x23, 0xdb, 0x73, 0x99, 0xbd, 0x1b, 0xb2, 0x31, 0x68, 0x3a, 0xad, 0xb7, 0xb0, 0x10, 0xc5, 0xe5, 0x11, 0x51, 0xba, 0xa7, 0x60, 0x66, 0x54, 0xf0, 0x08, 0xd7, 0x69,
+ /* (2^130)P */ 0x89, 0x41, 0x79, 0xcc, 0xeb, 0x0a, 0xf5, 0x4b, 0xa3, 0x4c, 0xce, 0x52, 0xb0, 0xa7, 0xe4, 0x41, 0x75, 0x7d, 0x04, 0xbb, 0x09, 0x4c, 0x50, 0x9f, 0xdf, 0xea, 0x74, 0x61, 0x02, 0xad, 0xb4, 0x9d, 0xb7, 0x05, 0xb9, 0xea, 0xeb, 0x91, 0x35, 0xe7, 0x49, 0xea, 0xd3, 0x4f, 0x3c, 0x60, 0x21, 0x7a, 0xde, 0xc7, 0xe2, 0x5a, 0xee, 0x8e, 0x93, 0xc7,
+ /* (2^131)P */ 0x00, 0xe8, 0xed, 0xd0, 0xb3, 0x0d, 0xaf, 0xb2, 0xde, 0x2c, 0xf6, 0x00, 0xe2, 0xea, 0x6d, 0xf8, 0x0e, 0xd9, 0x67, 0x59, 0xa9, 0x50, 0xbb, 0x17, 0x8f, 0xff, 0xb1, 0x9f, 0x17, 0xb6, 0xf2, 0xb5, 0xba, 0x80, 0xf7, 0x0f, 0xba, 0xd5, 0x09, 0x43, 0xaa, 0x4e, 0x3a, 0x67, 0x6a, 0x89, 0x9b, 0x18, 0x65, 0x35, 0xf8, 0x3a, 0x49, 0x91, 0x30, 0x51,
+ /* (2^132)P */ 0x8d, 0x25, 0xe9, 0x0e, 0x7d, 0x50, 0x76, 0xe4, 0x58, 0x7e, 0xb9, 0x33, 0xe6, 0x65, 0x90, 0xc2, 0x50, 0x9d, 0x50, 0x2e, 0x11, 0xad, 0xd5, 0x43, 0x52, 0x32, 0x41, 0x4f, 0x7b, 0xb6, 0xa0, 0xec, 0x81, 0x75, 0x36, 0x7c, 0x77, 0x85, 0x59, 0x70, 0xe4, 0xf9, 0xef, 0x66, 0x8d, 0x35, 0xc8, 0x2a, 0x6e, 0x5b, 0xc6, 0x0d, 0x0b, 0x29, 0x60, 0x68,
+ /* (2^133)P */ 0xf8, 0xce, 0xb0, 0x3a, 0x56, 0x7d, 0x51, 0x9a, 0x25, 0x73, 0xea, 0xdd, 0xe4, 0xe0, 0x0e, 0xf0, 0x07, 0xc0, 0x31, 0x00, 0x73, 0x35, 0xd0, 0x39, 0xc4, 0x9b, 0xb7, 0x95, 0xe0, 0x62, 0x70, 0x36, 0x0b, 0xcb, 0xa0, 0x42, 0xde, 0x51, 0xcf, 0x41, 0xe0, 0xb8, 0xb4, 0xc0, 0xe5, 0x46, 0x99, 0x9f, 0x02, 0x7f, 0x14, 0x8c, 0xc1, 0x4e, 0xef, 0xe8,
+ /* (2^134)P */ 0x10, 0x01, 0x57, 0x0a, 0xbe, 0x8b, 0x18, 0xc8, 0xca, 0x00, 0x28, 0x77, 0x4a, 0x9a, 0xc7, 0x55, 0x2a, 0xcc, 0x0c, 0x7b, 0xb9, 0xe9, 0xc8, 0x97, 0x7c, 0x02, 0xe3, 0x09, 0x2f, 0x62, 0x30, 0xb8, 0x40, 0x09, 0x65, 0xe9, 0x55, 0x63, 0xb5, 0x07, 0xca, 0x9f, 0x00, 0xdf, 0x9d, 0x5c, 0xc7, 0xee, 0x57, 0xa5, 0x90, 0x15, 0x1e, 0x22, 0xa0, 0x12,
+ /* (2^135)P */ 0x71, 0x2d, 0xc9, 0xef, 0x27, 0xb9, 0xd8, 0x12, 0x43, 0x6b, 0xa8, 0xce, 0x3b, 0x6d, 0x6e, 0x91, 0x43, 0x23, 0xbc, 0x32, 0xb3, 0xbf, 0xe1, 0xc7, 0x39, 0xcf, 0x7c, 0x42, 0x4c, 0xb1, 0x30, 0xe2, 0xdd, 0x69, 0x06, 0xe5, 0xea, 0xf0, 0x2a, 0x16, 0x50, 0x71, 0xca, 0x92, 0xdf, 0xc1, 0xcc, 0xec, 0xe6, 0x54, 0x07, 0xf3, 0x18, 0x8d, 0xd8, 0x29,
+ /* (2^136)P */ 0x98, 0x51, 0x48, 0x8f, 0xfa, 0x2e, 0x5e, 0x67, 0xb0, 0xc6, 0x17, 0x12, 0xb6, 0x7d, 0xc9, 0xad, 0x81, 0x11, 0xad, 0x0c, 0x1c, 0x2d, 0x45, 0xdf, 0xac, 0x66, 0xbd, 0x08, 0x6f, 0x7c, 0xc7, 0x06, 0x6e, 0x19, 0x08, 0x39, 0x64, 0xd7, 0xe4, 0xd1, 0x11, 0x5f, 0x1c, 0xf4, 0x67, 0xc3, 0x88, 0x6a, 0xe6, 0x07, 0xa3, 0x83, 0xd7, 0xfd, 0x2a, 0xf9,
+ /* (2^137)P */ 0x87, 0xed, 0xeb, 0xd9, 0xdf, 0xff, 0x43, 0x8b, 0xaa, 0x20, 0x58, 0xb0, 0xb4, 0x6b, 0x14, 0xb8, 0x02, 0xc5, 0x40, 0x20, 0x22, 0xbb, 0xf7, 0xb4, 0xf3, 0x05, 0x1e, 0x4d, 0x94, 0xff, 0xe3, 0xc5, 0x22, 0x82, 0xfe, 0xaf, 0x90, 0x42, 0x98, 0x6b, 0x76, 0x8b, 0x3e, 0x89, 0x3f, 0x42, 0x2a, 0xa7, 0x26, 0x00, 0xda, 0x5c, 0xa2, 0x2b, 0xec, 0xdd,
+ /* (2^138)P */ 0x5c, 0x21, 0x16, 0x0d, 0x46, 0xb8, 0xd0, 0xa7, 0x88, 0xe7, 0x25, 0xcb, 0x3e, 0x50, 0x73, 0x61, 0xe7, 0xaf, 0x5a, 0x3f, 0x47, 0x8b, 0x3d, 0x97, 0x79, 0x2c, 0xe6, 0x6d, 0x95, 0x74, 0x65, 0x70, 0x36, 0xfd, 0xd1, 0x9e, 0x13, 0x18, 0x63, 0xb1, 0x2d, 0x0b, 0xb5, 0x36, 0x3e, 0xe7, 0x35, 0x42, 0x3b, 0xe6, 0x1f, 0x4d, 0x9d, 0x59, 0xa2, 0x43,
+ /* (2^139)P */ 0x8c, 0x0c, 0x7c, 0x24, 0x9e, 0xe0, 0xf8, 0x05, 0x1c, 0x9e, 0x1f, 0x31, 0xc0, 0x70, 0xb3, 0xfb, 0x4e, 0xf8, 0x0a, 0x57, 0xb7, 0x49, 0xb5, 0x73, 0xa1, 0x5f, 0x9b, 0x6a, 0x07, 0x6c, 0x87, 0x71, 0x87, 0xd4, 0xbe, 0x98, 0x1e, 0x98, 0xee, 0x52, 0xc1, 0x7b, 0x95, 0x0f, 0x28, 0x32, 0x36, 0x28, 0xd0, 0x3a, 0x0f, 0x7d, 0x2a, 0xa9, 0x62, 0xb9,
+ /* (2^140)P */ 0x97, 0xe6, 0x18, 0x77, 0xf9, 0x34, 0xac, 0xbc, 0xe0, 0x62, 0x9f, 0x42, 0xde, 0xbd, 0x2f, 0xf7, 0x1f, 0xb7, 0x14, 0x52, 0x8a, 0x79, 0xb2, 0x3f, 0xd2, 0x95, 0x71, 0x01, 0xe8, 0xaf, 0x8c, 0xa4, 0xa4, 0xa7, 0x27, 0xf3, 0x5c, 0xdf, 0x3e, 0x57, 0x7a, 0xf1, 0x76, 0x49, 0xe6, 0x42, 0x3f, 0x8f, 0x1e, 0x63, 0x4a, 0x65, 0xb5, 0x41, 0xf5, 0x02,
+ /* (2^141)P */ 0x72, 0x85, 0xc5, 0x0b, 0xe1, 0x47, 0x64, 0x02, 0xc5, 0x4d, 0x81, 0x69, 0xb2, 0xcf, 0x0f, 0x6c, 0xd4, 0x6d, 0xd0, 0xc7, 0xb4, 0x1c, 0xd0, 0x32, 0x59, 0x89, 0xe2, 0xe0, 0x96, 0x8b, 0x12, 0x98, 0xbf, 0x63, 0x7a, 0x4c, 0x76, 0x7e, 0x58, 0x17, 0x8f, 0x5b, 0x0a, 0x59, 0x65, 0x75, 0xbc, 0x61, 0x1f, 0xbe, 0xc5, 0x6e, 0x0a, 0x57, 0x52, 0x70,
+ /* (2^142)P */ 0x92, 0x1c, 0x77, 0xbb, 0x62, 0x02, 0x6c, 0x25, 0x9c, 0x66, 0x07, 0x83, 0xab, 0xcc, 0x80, 0x5d, 0xd2, 0x76, 0x0c, 0xa4, 0xc5, 0xb4, 0x8a, 0x68, 0x23, 0x31, 0x32, 0x29, 0x8a, 0x47, 0x92, 0x12, 0x80, 0xb3, 0xfa, 0x18, 0xe4, 0x8d, 0xc0, 0x4d, 0xfe, 0x97, 0x5f, 0x72, 0x41, 0xb5, 0x5c, 0x7a, 0xbd, 0xf0, 0xcf, 0x5e, 0x97, 0xaa, 0x64, 0x32,
+ /* (2^143)P */ 0x35, 0x3f, 0x75, 0xc1, 0x7a, 0x75, 0x7e, 0xa9, 0xc6, 0x0b, 0x4e, 0x32, 0x62, 0xec, 0xe3, 0x5c, 0xfb, 0x01, 0x43, 0xb6, 0xd4, 0x5b, 0x75, 0xd2, 0xee, 0x7f, 0x5d, 0x23, 0x2b, 0xb3, 0x54, 0x34, 0x4c, 0xd3, 0xb4, 0x32, 0x84, 0x81, 0xb5, 0x09, 0x76, 0x19, 0xda, 0x58, 0xda, 0x7c, 0xdb, 0x2e, 0xdd, 0x4c, 0x8e, 0xdd, 0x5d, 0x89, 0x10, 0x10,
+ /* (2^144)P */ 0x57, 0x25, 0x6a, 0x08, 0x37, 0x92, 0xa8, 0xdf, 0x24, 0xef, 0x8f, 0x33, 0x34, 0x52, 0xa4, 0x4c, 0xf0, 0x77, 0x9f, 0x69, 0x77, 0xd5, 0x8f, 0xd2, 0x9a, 0xb3, 0xb6, 0x1d, 0x2d, 0xa6, 0xf7, 0x1f, 0xda, 0xd7, 0xcb, 0x75, 0x11, 0xc3, 0x6b, 0xc0, 0x38, 0xb1, 0xd5, 0x2d, 0x96, 0x84, 0x16, 0xfa, 0x26, 0xb9, 0xcc, 0x3f, 0x16, 0x47, 0x23, 0x74,
+ /* (2^145)P */ 0x9b, 0x61, 0x2a, 0x1c, 0xdd, 0x39, 0xa5, 0xfa, 0x1c, 0x7d, 0x63, 0x50, 0xca, 0xe6, 0x9d, 0xfa, 0xb7, 0xc4, 0x4c, 0x6a, 0x97, 0x5f, 0x36, 0x4e, 0x47, 0xdd, 0x17, 0xf7, 0xf9, 0x19, 0xce, 0x75, 0x17, 0xad, 0xce, 0x2a, 0xf3, 0xfe, 0x27, 0x8f, 0x3e, 0x48, 0xc0, 0x60, 0x87, 0x24, 0x19, 0xae, 0x59, 0xe4, 0x5a, 0x00, 0x2a, 0xba, 0xa2, 0x1f,
+ /* (2^146)P */ 0x26, 0x88, 0x42, 0x60, 0x9f, 0x6e, 0x2c, 0x7c, 0x39, 0x0f, 0x47, 0x6a, 0x0e, 0x02, 0xbb, 0x4b, 0x34, 0x29, 0x55, 0x18, 0x36, 0xcf, 0x3b, 0x47, 0xf1, 0x2e, 0xfc, 0x6e, 0x94, 0xff, 0xe8, 0x6b, 0x06, 0xd2, 0xba, 0x77, 0x5e, 0x60, 0xd7, 0x19, 0xef, 0x02, 0x9d, 0x3a, 0xc2, 0xb7, 0xa9, 0xd8, 0x57, 0xee, 0x7e, 0x2b, 0xf2, 0x6d, 0x28, 0xda,
+ /* (2^147)P */ 0xdf, 0xd9, 0x92, 0x11, 0x98, 0x23, 0xe2, 0x45, 0x2f, 0x74, 0x70, 0xee, 0x0e, 0x55, 0x65, 0x79, 0x86, 0x38, 0x17, 0x92, 0x85, 0x87, 0x99, 0x50, 0xd9, 0x7c, 0xdb, 0xa1, 0x10, 0xec, 0x30, 0xb7, 0x40, 0xa3, 0x23, 0x9b, 0x0e, 0x27, 0x49, 0x29, 0x03, 0x94, 0xff, 0x53, 0xdc, 0xd7, 0xed, 0x49, 0xa9, 0x5a, 0x3b, 0xee, 0xd7, 0xc7, 0x65, 0xaf,
+ /* (2^148)P */ 0xa0, 0xbd, 0xbe, 0x03, 0xee, 0x0c, 0xbe, 0x32, 0x00, 0x7b, 0x52, 0xcb, 0x92, 0x29, 0xbf, 0xa0, 0xc6, 0xd9, 0xd2, 0xd6, 0x15, 0xe8, 0x3a, 0x75, 0x61, 0x65, 0x56, 0xae, 0xad, 0x3c, 0x2a, 0x64, 0x14, 0x3f, 0x8e, 0xc1, 0x2d, 0x0c, 0x8d, 0x20, 0xdb, 0x58, 0x4b, 0xe5, 0x40, 0x15, 0x4b, 0xdc, 0xa8, 0xbd, 0xef, 0x08, 0xa7, 0xd1, 0xf4, 0xb0,
+ /* (2^149)P */ 0xa9, 0x0f, 0x05, 0x94, 0x66, 0xac, 0x1f, 0x65, 0x3f, 0xe1, 0xb8, 0xe1, 0x34, 0x5e, 0x1d, 0x8f, 0xe3, 0x93, 0x03, 0x15, 0xff, 0xb6, 0x65, 0xb6, 0x6e, 0xc0, 0x2f, 0xd4, 0x2e, 0xb9, 0x2c, 0x13, 0x3c, 0x99, 0x1c, 0xb5, 0x87, 0xba, 0x79, 0xcb, 0xf0, 0x18, 0x06, 0x86, 0x04, 0x14, 0x25, 0x09, 0xcd, 0x1c, 0x14, 0xda, 0x35, 0xd0, 0x38, 0x3b,
+ /* (2^150)P */ 0x1b, 0x04, 0xa3, 0x27, 0xb4, 0xd3, 0x37, 0x48, 0x1e, 0x8f, 0x69, 0xd3, 0x5a, 0x2f, 0x20, 0x02, 0x36, 0xbe, 0x06, 0x7b, 0x6b, 0x6c, 0x12, 0x5b, 0x80, 0x74, 0x44, 0xe6, 0xf8, 0xf5, 0x95, 0x59, 0x29, 0xab, 0x51, 0x47, 0x83, 0x28, 0xe0, 0xad, 0xde, 0xaa, 0xd3, 0xb1, 0x1a, 0xcb, 0xa3, 0xcd, 0x8b, 0x6a, 0xb1, 0xa7, 0x0a, 0xd1, 0xf9, 0xbe,
+ /* (2^151)P */ 0xce, 0x2f, 0x85, 0xca, 0x74, 0x6d, 0x49, 0xb8, 0xce, 0x80, 0x44, 0xe0, 0xda, 0x5b, 0xcf, 0x2f, 0x79, 0x74, 0xfe, 0xb4, 0x2c, 0x99, 0x20, 0x6e, 0x09, 0x04, 0xfb, 0x6d, 0x57, 0x5b, 0x95, 0x0c, 0x45, 0xda, 0x4f, 0x7f, 0x63, 0xcc, 0x85, 0x5a, 0x67, 0x50, 0x68, 0x71, 0xb4, 0x67, 0xb1, 0x2e, 0xc1, 0x1c, 0xdc, 0xff, 0x2a, 0x7c, 0x10, 0x5e,
+ /* (2^152)P */ 0xa6, 0xde, 0xf3, 0xd4, 0x22, 0x30, 0x24, 0x9e, 0x0b, 0x30, 0x54, 0x59, 0x7e, 0xa2, 0xeb, 0x89, 0x54, 0x65, 0x3e, 0x40, 0xd1, 0xde, 0xe6, 0xee, 0x4d, 0xbf, 0x5e, 0x40, 0x1d, 0xee, 0x4f, 0x68, 0xd9, 0xa7, 0x2f, 0xb3, 0x64, 0xb3, 0xf5, 0xc8, 0xd3, 0xaa, 0x70, 0x70, 0x3d, 0xef, 0xd3, 0x95, 0x54, 0xdb, 0x3e, 0x94, 0x95, 0x92, 0x1f, 0x45,
+ /* (2^153)P */ 0x22, 0x80, 0x1d, 0x9d, 0x96, 0xa5, 0x78, 0x6f, 0xe0, 0x1e, 0x1b, 0x66, 0x42, 0xc8, 0xae, 0x9e, 0x46, 0x45, 0x08, 0x41, 0xdf, 0x80, 0xae, 0x6f, 0xdb, 0x15, 0x5a, 0x21, 0x31, 0x7a, 0xd0, 0xf2, 0x54, 0x15, 0x88, 0xd3, 0x0f, 0x7f, 0x14, 0x5a, 0x14, 0x97, 0xab, 0xf4, 0x58, 0x6a, 0x9f, 0xea, 0x74, 0xe5, 0x6b, 0x90, 0x59, 0x2b, 0x48, 0xd9,
+ /* (2^154)P */ 0x12, 0x24, 0x04, 0xf5, 0x50, 0xc2, 0x8c, 0xb0, 0x7c, 0x46, 0x98, 0xd5, 0x24, 0xad, 0xf6, 0x72, 0xdc, 0x82, 0x1a, 0x60, 0xc1, 0xeb, 0x48, 0xef, 0x7f, 0x6e, 0xe6, 0xcc, 0xdb, 0x7b, 0xae, 0xbe, 0x5e, 0x1e, 0x5c, 0xe6, 0x0a, 0x70, 0xdf, 0xa4, 0xa3, 0x85, 0x1b, 0x1b, 0x7f, 0x72, 0xb9, 0x96, 0x6f, 0xdc, 0x03, 0x76, 0x66, 0xfb, 0xa0, 0x33,
+ /* (2^155)P */ 0x37, 0x40, 0xbb, 0xbc, 0x68, 0x58, 0x86, 0xca, 0xbb, 0xa5, 0x24, 0x76, 0x3d, 0x48, 0xd1, 0xad, 0xb4, 0xa8, 0xcf, 0xc3, 0xb6, 0xa8, 0xba, 0x1a, 0x3a, 0xbe, 0x33, 0x75, 0x04, 0x5c, 0x13, 0x8c, 0x0d, 0x70, 0x8d, 0xa6, 0x4e, 0x2a, 0xeb, 0x17, 0x3c, 0x22, 0xdd, 0x3e, 0x96, 0x40, 0x11, 0x9e, 0x4e, 0xae, 0x3d, 0xf8, 0x91, 0xd7, 0x50, 0xc8,
+ /* (2^156)P */ 0xd8, 0xca, 0xde, 0x19, 0xcf, 0x00, 0xe4, 0x73, 0x18, 0x7f, 0x9b, 0x9f, 0xf4, 0x5b, 0x49, 0x49, 0x99, 0xdc, 0xa4, 0x46, 0x21, 0xb5, 0xd7, 0x3e, 0xb7, 0x47, 0x1b, 0xa9, 0x9f, 0x4c, 0x69, 0x7d, 0xec, 0x33, 0xd6, 0x1c, 0x51, 0x7f, 0x47, 0x74, 0x7a, 0x6c, 0xf3, 0xd2, 0x2e, 0xbf, 0xdf, 0x6c, 0x9e, 0x77, 0x3b, 0x34, 0xf6, 0x73, 0x80, 0xed,
+ /* (2^157)P */ 0x16, 0xfb, 0x16, 0xc3, 0xc2, 0x83, 0xe4, 0xf4, 0x03, 0x7f, 0x52, 0xb0, 0x67, 0x51, 0x7b, 0x24, 0x5a, 0x51, 0xd3, 0xb6, 0x4e, 0x59, 0x76, 0xcd, 0x08, 0x7b, 0x1d, 0x7a, 0x9c, 0x65, 0xae, 0xce, 0xaa, 0xd2, 0x1c, 0x85, 0x66, 0x68, 0x06, 0x15, 0xa8, 0x06, 0xe6, 0x16, 0x37, 0xf4, 0x49, 0x9e, 0x0f, 0x50, 0x37, 0xb1, 0xb2, 0x93, 0x70, 0x43,
+ /* (2^158)P */ 0x18, 0x3a, 0x16, 0xe5, 0x8d, 0xc8, 0x35, 0xd6, 0x7b, 0x09, 0xec, 0x61, 0x5f, 0x5c, 0x2a, 0x19, 0x96, 0x2e, 0xc3, 0xfd, 0xab, 0xe6, 0x23, 0xae, 0xab, 0xc5, 0xcb, 0xb9, 0x7b, 0x2d, 0x34, 0x51, 0xb9, 0x41, 0x9e, 0x7d, 0xca, 0xda, 0x25, 0x45, 0x14, 0xb0, 0xc7, 0x4d, 0x26, 0x2b, 0xfe, 0x43, 0xb0, 0x21, 0x5e, 0xfa, 0xdc, 0x7c, 0xf9, 0x5a,
+ /* (2^159)P */ 0x94, 0xad, 0x42, 0x17, 0xf5, 0xcd, 0x1c, 0x0d, 0xf6, 0x41, 0xd2, 0x55, 0xbb, 0x50, 0xf1, 0xc6, 0xbc, 0xa6, 0xc5, 0x3a, 0xfd, 0x9b, 0x75, 0x3e, 0xf6, 0x1a, 0xa7, 0xb2, 0x6e, 0x64, 0x12, 0xdc, 0x3c, 0xe5, 0xf6, 0xfc, 0x3b, 0xfa, 0x43, 0x81, 0xd4, 0xa5, 0xee, 0xf5, 0x9c, 0x47, 0x2f, 0xd0, 0x9c, 0xde, 0xa1, 0x48, 0x91, 0x9a, 0x34, 0xc1,
+ /* (2^160)P */ 0x37, 0x1b, 0xb3, 0x88, 0xc9, 0x98, 0x4e, 0xfb, 0x84, 0x4f, 0x2b, 0x0a, 0xb6, 0x8f, 0x35, 0x15, 0xcd, 0x61, 0x7a, 0x5f, 0x5c, 0xa0, 0xca, 0x23, 0xa0, 0x93, 0x1f, 0xcc, 0x3c, 0x39, 0x3a, 0x24, 0xa7, 0x49, 0xad, 0x8d, 0x59, 0xcc, 0x94, 0x5a, 0x16, 0xf5, 0x70, 0xe8, 0x52, 0x1e, 0xee, 0x20, 0x30, 0x17, 0x7e, 0xf0, 0x4c, 0x93, 0x06, 0x5a,
+ /* (2^161)P */ 0x81, 0xba, 0x3b, 0xd7, 0x3e, 0xb4, 0x32, 0x3a, 0x22, 0x39, 0x2a, 0xfc, 0x19, 0xd9, 0xd2, 0xf6, 0xc5, 0x79, 0x6c, 0x0e, 0xde, 0xda, 0x01, 0xff, 0x52, 0xfb, 0xb6, 0x95, 0x4e, 0x7a, 0x10, 0xb8, 0x06, 0x86, 0x3c, 0xcd, 0x56, 0xd6, 0x15, 0xbf, 0x6e, 0x3e, 0x4f, 0x35, 0x5e, 0xca, 0xbc, 0xa5, 0x95, 0xa2, 0xdf, 0x2d, 0x1d, 0xaf, 0x59, 0xf9,
+ /* (2^162)P */ 0x69, 0xe5, 0xe2, 0xfa, 0xc9, 0x7f, 0xdd, 0x09, 0xf5, 0x6b, 0x4e, 0x2e, 0xbe, 0xb4, 0xbf, 0x3e, 0xb2, 0xf2, 0x81, 0x30, 0xe1, 0x07, 0xa8, 0x0d, 0x2b, 0xd2, 0x5a, 0x55, 0xbe, 0x4b, 0x86, 0x5d, 0xb0, 0x5e, 0x7c, 0x8f, 0xc1, 0x3c, 0x81, 0x4c, 0xf7, 0x6d, 0x7d, 0xe6, 0x4f, 0x8a, 0x85, 0xc2, 0x2f, 0x28, 0xef, 0x8c, 0x69, 0xc2, 0xc2, 0x1a,
+ /* (2^163)P */ 0xd9, 0xe4, 0x0e, 0x1e, 0xc2, 0xf7, 0x2f, 0x9f, 0xa1, 0x40, 0xfe, 0x46, 0x16, 0xaf, 0x2e, 0xd1, 0xec, 0x15, 0x9b, 0x61, 0x92, 0xce, 0xfc, 0x10, 0x43, 0x1d, 0x00, 0xf6, 0xbe, 0x20, 0x80, 0x80, 0x6f, 0x3c, 0x16, 0x94, 0x59, 0xba, 0x03, 0x53, 0x6e, 0xb6, 0xdd, 0x25, 0x7b, 0x86, 0xbf, 0x96, 0xf4, 0x2f, 0xa1, 0x96, 0x8d, 0xf9, 0xb3, 0x29,
+ /* (2^164)P */ 0x3b, 0x04, 0x60, 0x6e, 0xce, 0xab, 0xd2, 0x63, 0x18, 0x53, 0x88, 0x16, 0x4a, 0x6a, 0xab, 0x72, 0x03, 0x68, 0xa5, 0xd4, 0x0d, 0xb2, 0x82, 0x81, 0x1f, 0x2b, 0x5c, 0x75, 0xe8, 0xd2, 0x1d, 0x7f, 0xe7, 0x1b, 0x35, 0x02, 0xde, 0xec, 0xbd, 0xcb, 0xc7, 0x01, 0xd3, 0x95, 0x61, 0xfe, 0xb2, 0x7a, 0x66, 0x09, 0x4c, 0x6d, 0xfd, 0x39, 0xf7, 0x52,
+ /* (2^165)P */ 0x42, 0xc1, 0x5f, 0xf8, 0x35, 0x52, 0xc1, 0xfe, 0xc5, 0x11, 0x80, 0x1c, 0x11, 0x46, 0x31, 0x11, 0xbe, 0xd0, 0xc4, 0xb6, 0x07, 0x13, 0x38, 0xa0, 0x8d, 0x65, 0xf0, 0x56, 0x9e, 0x16, 0xbf, 0x9d, 0xcd, 0x51, 0x34, 0xf9, 0x08, 0x48, 0x7b, 0x76, 0x0c, 0x7b, 0x30, 0x07, 0xa8, 0x76, 0xaf, 0xa3, 0x29, 0x38, 0xb0, 0x58, 0xde, 0x72, 0x4b, 0x45,
+ /* (2^166)P */ 0xd4, 0x16, 0xa7, 0xc0, 0xb4, 0x9f, 0xdf, 0x1a, 0x37, 0xc8, 0x35, 0xed, 0xc5, 0x85, 0x74, 0x64, 0x09, 0x22, 0xef, 0xe9, 0x0c, 0xaf, 0x12, 0x4c, 0x9e, 0xf8, 0x47, 0x56, 0xe0, 0x7f, 0x4e, 0x24, 0x6b, 0x0c, 0xe7, 0xad, 0xc6, 0x47, 0x1d, 0xa4, 0x0d, 0x86, 0x89, 0x65, 0xe8, 0x5f, 0x71, 0xc7, 0xe9, 0xcd, 0xec, 0x6c, 0x62, 0xc7, 0xe3, 0xb3,
+ /* (2^167)P */ 0xb5, 0xea, 0x86, 0xe3, 0x15, 0x18, 0x3f, 0x6d, 0x7b, 0x05, 0x95, 0x15, 0x53, 0x26, 0x1c, 0xeb, 0xbe, 0x7e, 0x16, 0x42, 0x4b, 0xa2, 0x3d, 0xdd, 0x0e, 0xff, 0xba, 0x67, 0xb5, 0xae, 0x7a, 0x17, 0xde, 0x23, 0xad, 0x14, 0xcc, 0xd7, 0xaf, 0x57, 0x01, 0xe0, 0xdd, 0x48, 0xdd, 0xd7, 0xe3, 0xdf, 0xe9, 0x2d, 0xda, 0x67, 0xa4, 0x9f, 0x29, 0x04,
+ /* (2^168)P */ 0x16, 0x53, 0xe6, 0x9c, 0x4e, 0xe5, 0x1e, 0x70, 0x81, 0x25, 0x02, 0x9b, 0x47, 0x6d, 0xd2, 0x08, 0x73, 0xbe, 0x0a, 0xf1, 0x7b, 0xeb, 0x24, 0xeb, 0x38, 0x23, 0x5c, 0xb6, 0x3e, 0xce, 0x1e, 0xe3, 0xbc, 0x82, 0x35, 0x1f, 0xaf, 0x3a, 0x3a, 0xe5, 0x4e, 0xc1, 0xca, 0xbf, 0x47, 0xb4, 0xbb, 0xbc, 0x5f, 0xea, 0xc6, 0xca, 0xf3, 0xa0, 0xa2, 0x73,
+ /* (2^169)P */ 0xef, 0xa4, 0x7a, 0x4e, 0xe4, 0xc7, 0xb6, 0x43, 0x2e, 0xa5, 0xe4, 0xa5, 0xba, 0x1e, 0xa5, 0xfe, 0x9e, 0xce, 0xa9, 0x80, 0x04, 0xcb, 0x4f, 0xd8, 0x74, 0x05, 0x48, 0xfa, 0x99, 0x11, 0x5d, 0x97, 0x3b, 0x07, 0x0d, 0xdd, 0xe6, 0xb1, 0x74, 0x87, 0x1a, 0xd3, 0x26, 0xb7, 0x8f, 0xe1, 0x63, 0x3d, 0xec, 0x53, 0x93, 0xb0, 0x81, 0x78, 0x34, 0xa4,
+ /* (2^170)P */ 0xe1, 0xe7, 0xd4, 0x58, 0x9d, 0x0e, 0x8b, 0x65, 0x66, 0x37, 0x16, 0x48, 0x6f, 0xaa, 0x42, 0x37, 0x77, 0xad, 0xb1, 0x56, 0x48, 0xdf, 0x65, 0x36, 0x30, 0xb8, 0x00, 0x12, 0xd8, 0x32, 0x28, 0x7f, 0xc1, 0x71, 0xeb, 0x93, 0x0f, 0x48, 0x04, 0xe1, 0x5a, 0x6a, 0x96, 0xc1, 0xca, 0x89, 0x6d, 0x1b, 0x82, 0x4c, 0x18, 0x6d, 0x55, 0x4b, 0xea, 0xfd,
+ /* (2^171)P */ 0x62, 0x1a, 0x53, 0xb4, 0xb1, 0xbe, 0x6f, 0x15, 0x18, 0x88, 0xd4, 0x66, 0x61, 0xc7, 0x12, 0x69, 0x02, 0xbd, 0x03, 0x23, 0x2b, 0xef, 0xf9, 0x54, 0xa4, 0x85, 0xa8, 0xe3, 0xb7, 0xbd, 0xa9, 0xa3, 0xf3, 0x2a, 0xdd, 0xf1, 0xd4, 0x03, 0x0f, 0xa9, 0xa1, 0xd8, 0xa3, 0xcd, 0xb2, 0x71, 0x90, 0x4b, 0x35, 0x62, 0xf2, 0x2f, 0xce, 0x67, 0x1f, 0xaa,
+ /* (2^172)P */ 0x9e, 0x1e, 0xcd, 0x43, 0x7e, 0x87, 0x37, 0x94, 0x3a, 0x97, 0x4c, 0x7e, 0xee, 0xc9, 0x37, 0x85, 0xf1, 0xd9, 0x4f, 0xbf, 0xf9, 0x6f, 0x39, 0x9a, 0x39, 0x87, 0x2e, 0x25, 0x84, 0x42, 0xc3, 0x80, 0xcb, 0x07, 0x22, 0xae, 0x30, 0xd5, 0x50, 0xa1, 0x23, 0xcc, 0x31, 0x81, 0x9d, 0xf1, 0x30, 0xd9, 0x2b, 0x73, 0x41, 0x16, 0x50, 0xab, 0x2d, 0xa2,
+ /* (2^173)P */ 0xa4, 0x69, 0x4f, 0xa1, 0x4e, 0xb9, 0xbf, 0x14, 0xe8, 0x2b, 0x04, 0x93, 0xb7, 0x6e, 0x9f, 0x7d, 0x73, 0x0a, 0xc5, 0x14, 0xb8, 0xde, 0x8c, 0xc1, 0xfe, 0xc0, 0xa7, 0xa4, 0xcc, 0x42, 0x42, 0x81, 0x15, 0x65, 0x8a, 0x80, 0xb9, 0xde, 0x1f, 0x60, 0x33, 0x0e, 0xcb, 0xfc, 0xe0, 0xdb, 0x83, 0xa1, 0xe5, 0xd0, 0x16, 0x86, 0x2c, 0xe2, 0x87, 0xed,
+ /* (2^174)P */ 0x7a, 0xc0, 0xeb, 0x6b, 0xf6, 0x0d, 0x4c, 0x6d, 0x1e, 0xdb, 0xab, 0xe7, 0x19, 0x45, 0xc6, 0xe3, 0xb2, 0x06, 0xbb, 0xbc, 0x70, 0x99, 0x83, 0x33, 0xeb, 0x28, 0xc8, 0x77, 0xf6, 0x4d, 0x01, 0xb7, 0x59, 0xa0, 0xd2, 0xb3, 0x2a, 0x72, 0x30, 0xe7, 0x11, 0x39, 0xb6, 0x41, 0x29, 0x65, 0x5a, 0x14, 0xb9, 0x86, 0x08, 0xe0, 0x7d, 0x32, 0x8c, 0xf0,
+ /* (2^175)P */ 0x5c, 0x11, 0x30, 0x9e, 0x05, 0x27, 0xf5, 0x45, 0x0f, 0xb3, 0xc9, 0x75, 0xc3, 0xd7, 0xe1, 0x82, 0x3b, 0x8e, 0x87, 0x23, 0x00, 0x15, 0x19, 0x07, 0xd9, 0x21, 0x53, 0xc7, 0xf1, 0xa3, 0xbf, 0x70, 0x64, 0x15, 0x18, 0xca, 0x23, 0x9e, 0xd3, 0x08, 0xc3, 0x2a, 0x8b, 0xe5, 0x83, 0x04, 0x89, 0x14, 0xfd, 0x28, 0x25, 0x1c, 0xe3, 0x26, 0xa7, 0x22,
+ /* (2^176)P */ 0xdc, 0xd4, 0x75, 0x60, 0x99, 0x94, 0xea, 0x09, 0x8e, 0x8a, 0x3c, 0x1b, 0xf9, 0xbd, 0x33, 0x0d, 0x51, 0x3d, 0x12, 0x6f, 0x4e, 0x72, 0xe0, 0x17, 0x20, 0xe9, 0x75, 0xe6, 0x3a, 0xb2, 0x13, 0x83, 0x4e, 0x7a, 0x08, 0x9e, 0xd1, 0x04, 0x5f, 0x6b, 0x42, 0x0b, 0x76, 0x2a, 0x2d, 0x77, 0x53, 0x6c, 0x65, 0x6d, 0x8e, 0x25, 0x3c, 0xb6, 0x8b, 0x69,
+ /* (2^177)P */ 0xb9, 0x49, 0x28, 0xd0, 0xdc, 0x6c, 0x8f, 0x4c, 0xc9, 0x14, 0x8a, 0x38, 0xa3, 0xcb, 0xc4, 0x9d, 0x53, 0xcf, 0xe9, 0xe3, 0xcf, 0xe0, 0xb1, 0xf2, 0x1b, 0x4c, 0x7f, 0x83, 0x2a, 0x7a, 0xe9, 0x8b, 0x3b, 0x86, 0x61, 0x30, 0xe9, 0x99, 0xbd, 0xba, 0x19, 0x6e, 0x65, 0x2a, 0x12, 0x3e, 0x9c, 0xa8, 0xaf, 0xc3, 0xcf, 0xf8, 0x1f, 0x77, 0x86, 0xea,
+ /* (2^178)P */ 0x30, 0xde, 0xe7, 0xff, 0x54, 0xf7, 0xa2, 0x59, 0xf6, 0x0b, 0xfb, 0x7a, 0xf2, 0x39, 0xf0, 0xdb, 0x39, 0xbc, 0xf0, 0xfa, 0x60, 0xeb, 0x6b, 0x4f, 0x47, 0x17, 0xc8, 0x00, 0x65, 0x6d, 0x25, 0x1c, 0xd0, 0x48, 0x56, 0x53, 0x45, 0x11, 0x30, 0x02, 0x49, 0x20, 0x27, 0xac, 0xf2, 0x4c, 0xac, 0x64, 0x3d, 0x52, 0xb8, 0x89, 0xe0, 0x93, 0x16, 0x0f,
+ /* (2^179)P */ 0x84, 0x09, 0xba, 0x40, 0xb2, 0x2f, 0xa3, 0xa8, 0xc2, 0xba, 0x46, 0x33, 0x05, 0x9d, 0x62, 0xad, 0xa1, 0x3c, 0x33, 0xef, 0x0d, 0xeb, 0xf0, 0x77, 0x11, 0x5a, 0xb0, 0x21, 0x9c, 0xdf, 0x55, 0x24, 0x25, 0x35, 0x51, 0x61, 0x92, 0xf0, 0xb1, 0xce, 0xf5, 0xd4, 0x7b, 0x6c, 0x21, 0x9d, 0x56, 0x52, 0xf8, 0xa1, 0x4c, 0xe9, 0x27, 0x55, 0xac, 0x91,
+ /* (2^180)P */ 0x03, 0x3e, 0x30, 0xd2, 0x0a, 0xfa, 0x7d, 0x82, 0x3d, 0x1f, 0x8b, 0xcb, 0xb6, 0x04, 0x5c, 0xcc, 0x8b, 0xda, 0xe2, 0x68, 0x74, 0x08, 0x8c, 0x44, 0x83, 0x57, 0x6d, 0x6f, 0x80, 0xb0, 0x7e, 0xa9, 0x82, 0x91, 0x7b, 0x4c, 0x37, 0x97, 0xd1, 0x63, 0xd1, 0xbd, 0x45, 0xe6, 0x8a, 0x86, 0xd6, 0x89, 0x54, 0xfd, 0xd2, 0xb1, 0xd7, 0x54, 0xad, 0xaf,
+ /* (2^181)P */ 0x8b, 0x33, 0x62, 0x49, 0x9f, 0x63, 0xf9, 0x87, 0x42, 0x58, 0xbf, 0xb3, 0xe6, 0x68, 0x02, 0x60, 0x5c, 0x76, 0x62, 0xf7, 0x61, 0xd7, 0x36, 0x31, 0xf7, 0x9c, 0xb5, 0xe5, 0x13, 0x6c, 0xea, 0x78, 0xae, 0xcf, 0xde, 0xbf, 0xb6, 0xeb, 0x4f, 0xc8, 0x2a, 0xb4, 0x9a, 0x9f, 0xf3, 0xd1, 0x6a, 0xec, 0x0c, 0xbd, 0x85, 0x98, 0x40, 0x06, 0x1c, 0x2a,
+ /* (2^182)P */ 0x74, 0x3b, 0xe7, 0x81, 0xd5, 0xae, 0x54, 0x56, 0x03, 0xe8, 0x97, 0x16, 0x76, 0xcf, 0x24, 0x96, 0x96, 0x5b, 0xcc, 0x09, 0xab, 0x23, 0x6f, 0x54, 0xae, 0x8f, 0xe4, 0x12, 0xcb, 0xfd, 0xbc, 0xac, 0x93, 0x45, 0x3d, 0x68, 0x08, 0x22, 0x59, 0xc6, 0xf0, 0x47, 0x19, 0x8c, 0x79, 0x93, 0x1e, 0x0e, 0x30, 0xb0, 0x94, 0xfb, 0x17, 0x1d, 0x5a, 0x12,
+ /* (2^183)P */ 0x85, 0xff, 0x40, 0x18, 0x85, 0xff, 0x44, 0x37, 0x69, 0x23, 0x4d, 0x34, 0xe1, 0xeb, 0xa3, 0x1b, 0x55, 0x40, 0xc1, 0x64, 0xf4, 0xd4, 0x13, 0x0a, 0x9f, 0xb9, 0x19, 0xfc, 0x88, 0x7d, 0xc0, 0x72, 0xcf, 0x69, 0x2f, 0xd2, 0x0c, 0x82, 0x0f, 0xda, 0x08, 0xba, 0x0f, 0xaa, 0x3b, 0xe9, 0xe5, 0x83, 0x7a, 0x06, 0xe8, 0x1b, 0x38, 0x43, 0xc3, 0x54,
+ /* (2^184)P */ 0x14, 0xaa, 0xb3, 0x6e, 0xe6, 0x28, 0xee, 0xc5, 0x22, 0x6c, 0x7c, 0xf9, 0xa8, 0x71, 0xcc, 0xfe, 0x68, 0x7e, 0xd3, 0xb8, 0x37, 0x96, 0xca, 0x0b, 0xd9, 0xb6, 0x06, 0xa9, 0xf6, 0x71, 0xe8, 0x31, 0xf7, 0xd8, 0xf1, 0x5d, 0xab, 0xb9, 0xf0, 0x5c, 0x98, 0xcf, 0x22, 0xa2, 0x2a, 0xf6, 0xd0, 0x59, 0xf0, 0x9d, 0xd9, 0x6a, 0x4f, 0x59, 0x57, 0xad,
+ /* (2^185)P */ 0xd7, 0x2b, 0x3d, 0x38, 0x4c, 0x2e, 0x23, 0x4d, 0x49, 0xa2, 0x62, 0x62, 0xf9, 0x0f, 0xde, 0x08, 0xf3, 0x86, 0x71, 0xb6, 0xc7, 0xf9, 0x85, 0x9c, 0x33, 0xa1, 0xcf, 0x16, 0xaa, 0x60, 0xb9, 0xb7, 0xea, 0xed, 0x01, 0x1c, 0x59, 0xdb, 0x3f, 0x3f, 0x97, 0x2e, 0xf0, 0x09, 0x9f, 0x10, 0x85, 0x5f, 0x53, 0x39, 0xf3, 0x13, 0x40, 0x56, 0x95, 0xf9,
+ /* (2^186)P */ 0xb4, 0xe3, 0xda, 0xc6, 0x1f, 0x78, 0x8e, 0xac, 0xd4, 0x20, 0x1d, 0xa0, 0xbf, 0x4c, 0x09, 0x16, 0xa7, 0x30, 0xb5, 0x8d, 0x9e, 0xa1, 0x5f, 0x6d, 0x52, 0xf4, 0x71, 0xb6, 0x32, 0x2d, 0x21, 0x51, 0xc6, 0xfc, 0x2f, 0x08, 0xf4, 0x13, 0x6c, 0x55, 0xba, 0x72, 0x81, 0x24, 0x49, 0x0e, 0x4f, 0x06, 0x36, 0x39, 0x6a, 0xc5, 0x81, 0xfc, 0xeb, 0xb2,
+ /* (2^187)P */ 0x7d, 0x8d, 0xc8, 0x6c, 0xea, 0xb4, 0xb9, 0xe8, 0x40, 0xc9, 0x69, 0xc9, 0x30, 0x05, 0xfd, 0x34, 0x46, 0xfd, 0x94, 0x05, 0x16, 0xf5, 0x4b, 0x13, 0x3d, 0x24, 0x1a, 0xd6, 0x64, 0x2b, 0x9c, 0xe2, 0xa5, 0xd9, 0x98, 0xe0, 0xe8, 0xf4, 0xbc, 0x2c, 0xbd, 0xa2, 0x56, 0xe3, 0x9e, 0x14, 0xdb, 0xbf, 0x05, 0xbf, 0x9a, 0x13, 0x5d, 0xf7, 0x91, 0xa3,
+ /* (2^188)P */ 0x8b, 0xcb, 0x27, 0xf3, 0x15, 0x26, 0x05, 0x40, 0x0f, 0xa6, 0x15, 0x13, 0x71, 0x95, 0xa2, 0xc6, 0x38, 0x04, 0x67, 0xf8, 0x9a, 0x83, 0x06, 0xaa, 0x25, 0x36, 0x72, 0x01, 0x6f, 0x74, 0x5f, 0xe5, 0x6e, 0x44, 0x99, 0xce, 0x13, 0xbc, 0x82, 0xc2, 0x0d, 0xa4, 0x98, 0x50, 0x38, 0xf3, 0xa2, 0xc5, 0xe5, 0x24, 0x1f, 0x6f, 0x56, 0x3e, 0x07, 0xb2,
+ /* (2^189)P */ 0xbd, 0x0f, 0x32, 0x60, 0x07, 0xb1, 0xd7, 0x0b, 0x11, 0x07, 0x57, 0x02, 0x89, 0xe8, 0x8b, 0xe8, 0x5a, 0x1f, 0xee, 0x54, 0x6b, 0xff, 0xb3, 0x04, 0x07, 0x57, 0x13, 0x0b, 0x94, 0xa8, 0x4d, 0x81, 0xe2, 0x17, 0x16, 0x45, 0xd4, 0x4b, 0xf7, 0x7e, 0x64, 0x66, 0x20, 0xe8, 0x0b, 0x26, 0xfd, 0xa9, 0x8a, 0x47, 0x52, 0x89, 0x14, 0xd0, 0xd1, 0xa1,
+ /* (2^190)P */ 0xdc, 0x03, 0xe6, 0x20, 0x44, 0x47, 0x8f, 0x04, 0x16, 0x24, 0x22, 0xc1, 0x55, 0x5c, 0xbe, 0x43, 0xc3, 0x92, 0xc5, 0x54, 0x3d, 0x5d, 0xd1, 0x05, 0x9c, 0xc6, 0x7c, 0xbf, 0x23, 0x84, 0x1a, 0xba, 0x4f, 0x1f, 0xfc, 0xa1, 0xae, 0x1a, 0x64, 0x02, 0x51, 0xf1, 0xcb, 0x7a, 0x20, 0xce, 0xb2, 0x34, 0x3c, 0xca, 0xe0, 0xe4, 0xba, 0x22, 0xd4, 0x7b,
+ /* (2^191)P */ 0xca, 0xfd, 0xca, 0xd7, 0xde, 0x61, 0xae, 0xf0, 0x79, 0x0c, 0x20, 0xab, 0xbc, 0x6f, 0x4d, 0x61, 0xf0, 0xc7, 0x9c, 0x8d, 0x4b, 0x52, 0xf3, 0xb9, 0x48, 0x63, 0x0b, 0xb6, 0xd2, 0x25, 0x9a, 0x96, 0x72, 0xc1, 0x6b, 0x0c, 0xb5, 0xfb, 0x71, 0xaa, 0xad, 0x47, 0x5b, 0xe7, 0xc0, 0x0a, 0x55, 0xb2, 0xd4, 0x16, 0x2f, 0xb1, 0x01, 0xfd, 0xce, 0x27,
+ /* (2^192)P */ 0x64, 0x11, 0x4b, 0xab, 0x57, 0x09, 0xc6, 0x49, 0x4a, 0x37, 0xc3, 0x36, 0xc4, 0x7b, 0x81, 0x1f, 0x42, 0xed, 0xbb, 0xe0, 0xa0, 0x8d, 0x51, 0xe6, 0xca, 0x8b, 0xb9, 0xcd, 0x99, 0x2d, 0x91, 0x53, 0xa9, 0x47, 0xcb, 0x32, 0xc7, 0xa4, 0x92, 0xec, 0x46, 0x74, 0x44, 0x6d, 0x71, 0x9f, 0x6d, 0x0c, 0x69, 0xa4, 0xf8, 0xbe, 0x9f, 0x7f, 0xa0, 0xd7,
+ /* (2^193)P */ 0x5f, 0x33, 0xb6, 0x91, 0xc8, 0xa5, 0x3f, 0x5d, 0x7f, 0x38, 0x6e, 0x74, 0x20, 0x4a, 0xd6, 0x2b, 0x98, 0x2a, 0x41, 0x4b, 0x83, 0x64, 0x0b, 0x92, 0x7a, 0x06, 0x1e, 0xc6, 0x2c, 0xf6, 0xe4, 0x91, 0xe5, 0xb1, 0x2e, 0x6e, 0x4e, 0xa8, 0xc8, 0x14, 0x32, 0x57, 0x44, 0x1c, 0xe4, 0xb9, 0x7f, 0x54, 0x51, 0x08, 0x81, 0xaa, 0x4e, 0xce, 0xa1, 0x5d,
+ /* (2^194)P */ 0x5c, 0xd5, 0x9b, 0x5e, 0x7c, 0xb5, 0xb1, 0x52, 0x73, 0x00, 0x41, 0x56, 0x79, 0x08, 0x7e, 0x07, 0x28, 0x06, 0xa6, 0xfb, 0x7f, 0x69, 0xbd, 0x7a, 0x3c, 0xae, 0x9f, 0x39, 0xbb, 0x54, 0xa2, 0x79, 0xb9, 0x0e, 0x7f, 0xbb, 0xe0, 0xe6, 0xb7, 0x27, 0x64, 0x38, 0x45, 0xdb, 0x84, 0xe4, 0x61, 0x72, 0x3f, 0xe2, 0x24, 0xfe, 0x7a, 0x31, 0x9a, 0xc9,
+ /* (2^195)P */ 0xa1, 0xd2, 0xa4, 0xee, 0x24, 0x96, 0xe5, 0x5b, 0x79, 0x78, 0x3c, 0x7b, 0x82, 0x3b, 0x8b, 0x58, 0x0b, 0xa3, 0x63, 0x2d, 0xbc, 0x75, 0x46, 0xe8, 0x83, 0x1a, 0xc0, 0x2a, 0x92, 0x61, 0xa8, 0x75, 0x37, 0x3c, 0xbf, 0x0f, 0xef, 0x8f, 0x6c, 0x97, 0x75, 0x10, 0x05, 0x7a, 0xde, 0x23, 0xe8, 0x2a, 0x35, 0xeb, 0x41, 0x64, 0x7d, 0xcf, 0xe0, 0x52,
+ /* (2^196)P */ 0x4a, 0xd0, 0x49, 0x93, 0xae, 0xf3, 0x24, 0x8c, 0xe1, 0x09, 0x98, 0x45, 0xd8, 0xb9, 0xfe, 0x8e, 0x8c, 0xa8, 0x2c, 0xc9, 0x9f, 0xce, 0x01, 0xdc, 0x38, 0x11, 0xab, 0x85, 0xb9, 0xe8, 0x00, 0x51, 0xfd, 0x82, 0xe1, 0x9b, 0x4e, 0xfc, 0xb5, 0x2a, 0x0f, 0x8b, 0xda, 0x4e, 0x02, 0xca, 0xcc, 0xe3, 0x91, 0xc4, 0xe0, 0xcf, 0x7b, 0xd6, 0xe6, 0x6a,
+ /* (2^197)P */ 0xfe, 0x11, 0xd7, 0xaa, 0xe3, 0x0c, 0x52, 0x2e, 0x04, 0xe0, 0xe0, 0x61, 0xc8, 0x05, 0xd7, 0x31, 0x4c, 0xc3, 0x9b, 0x2d, 0xce, 0x59, 0xbe, 0x12, 0xb7, 0x30, 0x21, 0xfc, 0x81, 0xb8, 0x5e, 0x57, 0x73, 0xd0, 0xad, 0x8e, 0x9e, 0xe4, 0xeb, 0xcd, 0xcf, 0xd2, 0x0f, 0x01, 0x35, 0x16, 0xed, 0x7a, 0x43, 0x8e, 0x42, 0xdc, 0xea, 0x4c, 0xa8, 0x7c,
+ /* (2^198)P */ 0x37, 0x26, 0xcc, 0x76, 0x0b, 0xe5, 0x76, 0xdd, 0x3e, 0x19, 0x3c, 0xc4, 0x6c, 0x7f, 0xd0, 0x03, 0xc1, 0xb8, 0x59, 0x82, 0xca, 0x36, 0xc1, 0xe4, 0xc8, 0xb2, 0x83, 0x69, 0x9c, 0xc5, 0x9d, 0x12, 0x82, 0x1c, 0xea, 0xb2, 0x84, 0x9f, 0xf3, 0x52, 0x6b, 0xbb, 0xd8, 0x81, 0x56, 0x83, 0x04, 0x66, 0x05, 0x22, 0x49, 0x37, 0x93, 0xb1, 0xfd, 0xd5,
+ /* (2^199)P */ 0xaf, 0x96, 0xbf, 0x03, 0xbe, 0xe6, 0x5d, 0x78, 0x19, 0xba, 0x37, 0x46, 0x0a, 0x2b, 0x52, 0x7c, 0xd8, 0x51, 0x9e, 0x3d, 0x29, 0x42, 0xdb, 0x0e, 0x31, 0x20, 0x94, 0xf8, 0x43, 0x9a, 0x2d, 0x22, 0xd3, 0xe3, 0xa1, 0x79, 0x68, 0xfb, 0x2d, 0x7e, 0xd6, 0x79, 0xda, 0x0b, 0xc6, 0x5b, 0x76, 0x68, 0xf0, 0xfe, 0x72, 0x59, 0xbb, 0xa1, 0x9c, 0x74,
+ /* (2^200)P */ 0x0a, 0xd9, 0xec, 0xc5, 0xbd, 0xf0, 0xda, 0xcf, 0x82, 0xab, 0x46, 0xc5, 0x32, 0x13, 0xdc, 0x5b, 0xac, 0xc3, 0x53, 0x9a, 0x7f, 0xef, 0xa5, 0x40, 0x5a, 0x1f, 0xc1, 0x12, 0x91, 0x54, 0x83, 0x6a, 0xb0, 0x9a, 0x85, 0x4d, 0xbf, 0x36, 0x8e, 0xd3, 0xa2, 0x2b, 0xe5, 0xd6, 0xc6, 0xe1, 0x58, 0x5b, 0x82, 0x9b, 0xc8, 0xf2, 0x03, 0xba, 0xf5, 0x92,
+ /* (2^201)P */ 0xfb, 0x21, 0x7e, 0xde, 0xe7, 0xb4, 0xc0, 0x56, 0x86, 0x3a, 0x5b, 0x78, 0xf8, 0xf0, 0xf4, 0xe7, 0x5c, 0x00, 0xd2, 0xd7, 0xd6, 0xf8, 0x75, 0x5e, 0x0f, 0x3e, 0xd1, 0x4b, 0x77, 0xd8, 0xad, 0xb0, 0xc9, 0x8b, 0x59, 0x7d, 0x30, 0x76, 0x64, 0x7a, 0x76, 0xd9, 0x51, 0x69, 0xfc, 0xbd, 0x8e, 0xb5, 0x55, 0xe0, 0xd2, 0x07, 0x15, 0xa9, 0xf7, 0xa4,
+ /* (2^202)P */ 0xaa, 0x2d, 0x2f, 0x2b, 0x3c, 0x15, 0xdd, 0xcd, 0xe9, 0x28, 0x82, 0x4f, 0xa2, 0xaa, 0x31, 0x48, 0xcc, 0xfa, 0x07, 0x73, 0x8a, 0x34, 0x74, 0x0d, 0xab, 0x1a, 0xca, 0xd2, 0xbf, 0x3a, 0xdb, 0x1a, 0x5f, 0x50, 0x62, 0xf4, 0x6b, 0x83, 0x38, 0x43, 0x96, 0xee, 0x6b, 0x39, 0x1e, 0xf0, 0x17, 0x80, 0x1e, 0x9b, 0xed, 0x2b, 0x2f, 0xcc, 0x65, 0xf7,
+ /* (2^203)P */ 0x03, 0xb3, 0x23, 0x9c, 0x0d, 0xd1, 0xeb, 0x7e, 0x34, 0x17, 0x8a, 0x4c, 0xde, 0x54, 0x39, 0xc4, 0x11, 0x82, 0xd3, 0xa4, 0x00, 0x32, 0x95, 0x9c, 0xa6, 0x64, 0x76, 0x6e, 0xd6, 0x53, 0x27, 0xb4, 0x6a, 0x14, 0x8c, 0x54, 0xf6, 0x58, 0x9e, 0x22, 0x4a, 0x55, 0x18, 0x77, 0xd0, 0x08, 0x6b, 0x19, 0x8a, 0xb5, 0xe7, 0x19, 0xb8, 0x60, 0x92, 0xb1,
+ /* (2^204)P */ 0x66, 0xec, 0xf3, 0x12, 0xde, 0x67, 0x7f, 0xd4, 0x5b, 0xf6, 0x70, 0x64, 0x0a, 0xb5, 0xc2, 0xf9, 0xb3, 0x64, 0xab, 0x56, 0x46, 0xc7, 0x93, 0xc2, 0x8b, 0x2d, 0xd0, 0xd6, 0x39, 0x3b, 0x1f, 0xcd, 0xb3, 0xac, 0xcc, 0x2c, 0x27, 0x6a, 0xbc, 0xb3, 0x4b, 0xa8, 0x3c, 0x69, 0x20, 0xe2, 0x18, 0x35, 0x17, 0xe1, 0x8a, 0xd3, 0x11, 0x74, 0xaa, 0x4d,
+ /* (2^205)P */ 0x96, 0xc4, 0x16, 0x7e, 0xfd, 0xf5, 0xd0, 0x7d, 0x1f, 0x32, 0x1b, 0xdb, 0xa6, 0xfd, 0x51, 0x75, 0x4d, 0xd7, 0x00, 0xe5, 0x7f, 0x58, 0x5b, 0xeb, 0x4b, 0x6a, 0x78, 0xfe, 0xe5, 0xd6, 0x8f, 0x99, 0x17, 0xca, 0x96, 0x45, 0xf7, 0x52, 0xdf, 0x84, 0x06, 0x77, 0xb9, 0x05, 0x63, 0x5d, 0xe9, 0x91, 0xb1, 0x4b, 0x82, 0x5a, 0xdb, 0xd7, 0xca, 0x69,
+ /* (2^206)P */ 0x02, 0xd3, 0x38, 0x38, 0x87, 0xea, 0xbd, 0x9f, 0x11, 0xca, 0xf3, 0x21, 0xf1, 0x9b, 0x35, 0x97, 0x98, 0xff, 0x8e, 0x6d, 0x3d, 0xd6, 0xb2, 0xfa, 0x68, 0xcb, 0x7e, 0x62, 0x85, 0xbb, 0xc7, 0x5d, 0xee, 0x32, 0x30, 0x2e, 0x71, 0x96, 0x63, 0x43, 0x98, 0xc4, 0xa7, 0xde, 0x60, 0xb2, 0xd9, 0x43, 0x4a, 0xfa, 0x97, 0x2d, 0x5f, 0x21, 0xd4, 0xfe,
+ /* (2^207)P */ 0x3b, 0x20, 0x29, 0x07, 0x07, 0xb5, 0x78, 0xc3, 0xc7, 0xab, 0x56, 0xba, 0x40, 0xde, 0x1d, 0xcf, 0xc3, 0x00, 0x56, 0x21, 0x0c, 0xc8, 0x42, 0xd9, 0x0e, 0xcd, 0x02, 0x7c, 0x07, 0xb9, 0x11, 0xd7, 0x96, 0xaf, 0xff, 0xad, 0xc5, 0xba, 0x30, 0x6d, 0x82, 0x3a, 0xbf, 0xef, 0x7b, 0xf7, 0x0a, 0x74, 0xbd, 0x31, 0x0c, 0xe4, 0xec, 0x1a, 0xe5, 0xc5,
+ /* (2^208)P */ 0xcc, 0xf2, 0x28, 0x16, 0x12, 0xbf, 0xef, 0x85, 0xbc, 0xf7, 0xcb, 0x9f, 0xdb, 0xa8, 0xb2, 0x49, 0x53, 0x48, 0xa8, 0x24, 0xa8, 0x68, 0x8d, 0xbb, 0x21, 0x0a, 0x5a, 0xbd, 0xb2, 0x91, 0x61, 0x47, 0xc4, 0x43, 0x08, 0xa6, 0x19, 0xef, 0x8e, 0x88, 0x39, 0xc6, 0x33, 0x30, 0xf3, 0x0e, 0xc5, 0x92, 0x66, 0xd6, 0xfe, 0xc5, 0x12, 0xd9, 0x4c, 0x2d,
+ /* (2^209)P */ 0x30, 0x34, 0x07, 0xbf, 0x9c, 0x5a, 0x4e, 0x65, 0xf1, 0x39, 0x35, 0x38, 0xae, 0x7b, 0x55, 0xac, 0x6a, 0x92, 0x24, 0x7e, 0x50, 0xd3, 0xba, 0x78, 0x51, 0xfe, 0x4d, 0x32, 0x05, 0x11, 0xf5, 0x52, 0xf1, 0x31, 0x45, 0x39, 0x98, 0x7b, 0x28, 0x56, 0xc3, 0x5d, 0x4f, 0x07, 0x6f, 0x84, 0xb8, 0x1a, 0x58, 0x0b, 0xc4, 0x7c, 0xc4, 0x8d, 0x32, 0x8e,
+ /* (2^210)P */ 0x7e, 0xaf, 0x98, 0xce, 0xc5, 0x2b, 0x9d, 0xf6, 0xfa, 0x2c, 0xb6, 0x2a, 0x5a, 0x1d, 0xc0, 0x24, 0x8d, 0xa4, 0xce, 0xb1, 0x12, 0x01, 0xf9, 0x79, 0xc6, 0x79, 0x38, 0x0c, 0xd4, 0x07, 0xc9, 0xf7, 0x37, 0xa1, 0x0b, 0xfe, 0x72, 0xec, 0x5d, 0xd6, 0xb0, 0x1c, 0x70, 0xbe, 0x70, 0x01, 0x13, 0xe0, 0x86, 0x95, 0xc7, 0x2e, 0x12, 0x3b, 0xe6, 0xa6,
+ /* (2^211)P */ 0x24, 0x82, 0x67, 0xe0, 0x14, 0x7b, 0x56, 0x08, 0x38, 0x44, 0xdb, 0xa0, 0x3a, 0x05, 0x47, 0xb2, 0xc0, 0xac, 0xd1, 0xcc, 0x3f, 0x82, 0xb8, 0x8a, 0x88, 0xbc, 0xf5, 0x33, 0xa1, 0x35, 0x0f, 0xf6, 0xe2, 0xef, 0x6c, 0xf7, 0x37, 0x9e, 0xe8, 0x10, 0xca, 0xb0, 0x8e, 0x80, 0x86, 0x00, 0x23, 0xd0, 0x4a, 0x76, 0x9f, 0xf7, 0x2c, 0x52, 0x15, 0x0e,
+ /* (2^212)P */ 0x5e, 0x49, 0xe1, 0x2c, 0x9a, 0x01, 0x76, 0xa6, 0xb3, 0x07, 0x5b, 0xa4, 0x07, 0xef, 0x1d, 0xc3, 0x6a, 0xbb, 0x64, 0xbe, 0x71, 0x15, 0x6e, 0x32, 0x31, 0x46, 0x9a, 0x9e, 0x8f, 0x45, 0x73, 0xce, 0x0b, 0x94, 0x1a, 0x52, 0x07, 0xf4, 0x50, 0x30, 0x49, 0x53, 0x50, 0xfb, 0x71, 0x1f, 0x5a, 0x03, 0xa9, 0x76, 0xf2, 0x8f, 0x42, 0xff, 0xed, 0xed,
+ /* (2^213)P */ 0xed, 0x08, 0xdb, 0x91, 0x1c, 0xee, 0xa2, 0xb4, 0x47, 0xa2, 0xfa, 0xcb, 0x03, 0xd1, 0xff, 0x8c, 0xad, 0x64, 0x50, 0x61, 0xcd, 0xfc, 0x88, 0xa0, 0x31, 0x95, 0x30, 0xb9, 0x58, 0xdd, 0xd7, 0x43, 0xe4, 0x46, 0xc2, 0x16, 0xd9, 0x72, 0x4a, 0x56, 0x51, 0x70, 0x85, 0xf1, 0xa1, 0x80, 0x40, 0xd5, 0xba, 0x67, 0x81, 0xda, 0xcd, 0x03, 0xea, 0x51,
+ /* (2^214)P */ 0x42, 0x50, 0xf0, 0xef, 0x37, 0x61, 0x72, 0x85, 0xe1, 0xf1, 0xff, 0x6f, 0x3d, 0xe8, 0x7b, 0x21, 0x5c, 0xe5, 0x50, 0x03, 0xde, 0x00, 0xc1, 0xf7, 0x3a, 0x55, 0x12, 0x1c, 0x9e, 0x1e, 0xce, 0xd1, 0x2f, 0xaf, 0x05, 0x70, 0x5b, 0x47, 0xf2, 0x04, 0x7a, 0x89, 0xbc, 0x78, 0xa6, 0x65, 0x6c, 0xaa, 0x3c, 0xa2, 0x3c, 0x8b, 0x5c, 0xa9, 0x22, 0x48,
+ /* (2^215)P */ 0x7e, 0x8c, 0x8f, 0x2f, 0x60, 0xe3, 0x5a, 0x94, 0xd4, 0xce, 0xdd, 0x9d, 0x83, 0x3b, 0x77, 0x78, 0x43, 0x1d, 0xfd, 0x8f, 0xc8, 0xe8, 0x02, 0x90, 0xab, 0xf6, 0xc9, 0xfc, 0xf1, 0x63, 0xaa, 0x5f, 0x42, 0xf1, 0x78, 0x34, 0x64, 0x16, 0x75, 0x9c, 0x7d, 0xd0, 0xe4, 0x74, 0x5a, 0xa8, 0xfb, 0xcb, 0xac, 0x20, 0xa3, 0xc2, 0xa6, 0x20, 0xf8, 0x1b,
+ /* (2^216)P */ 0x00, 0x4f, 0x1e, 0x56, 0xb5, 0x34, 0xb2, 0x87, 0x31, 0xe5, 0xee, 0x8d, 0xf1, 0x41, 0x67, 0xb7, 0x67, 0x3a, 0x54, 0x86, 0x5c, 0xf0, 0x0b, 0x37, 0x2f, 0x1b, 0x92, 0x5d, 0x58, 0x93, 0xdc, 0xd8, 0x58, 0xcc, 0x9e, 0x67, 0xd0, 0x97, 0x3a, 0xaf, 0x49, 0x39, 0x2d, 0x3b, 0xd8, 0x98, 0xfb, 0x76, 0x6b, 0xe7, 0xaf, 0xc3, 0x45, 0x44, 0x53, 0x94,
+ /* (2^217)P */ 0x30, 0xbd, 0x90, 0x75, 0xd3, 0xbd, 0x3b, 0x58, 0x27, 0x14, 0x9f, 0x6b, 0xd4, 0x31, 0x99, 0xcd, 0xde, 0x3a, 0x21, 0x1e, 0xb4, 0x02, 0xe4, 0x33, 0x04, 0x02, 0xb0, 0x50, 0x66, 0x68, 0x90, 0xdd, 0x7b, 0x69, 0x31, 0xd9, 0xcf, 0x68, 0x73, 0xf1, 0x60, 0xdd, 0xc8, 0x1d, 0x5d, 0xe3, 0xd6, 0x5b, 0x2a, 0xa4, 0xea, 0xc4, 0x3f, 0x08, 0xcd, 0x9c,
+ /* (2^218)P */ 0x6b, 0x1a, 0xbf, 0x55, 0xc1, 0x1b, 0x0c, 0x05, 0x09, 0xdf, 0xf5, 0x5e, 0xa3, 0x77, 0x95, 0xe9, 0xdf, 0x19, 0xdd, 0xc7, 0x94, 0xcb, 0x06, 0x73, 0xd0, 0x88, 0x02, 0x33, 0x94, 0xca, 0x7a, 0x2f, 0x8e, 0x3d, 0x72, 0x61, 0x2d, 0x4d, 0xa6, 0x61, 0x1f, 0x32, 0x5e, 0x87, 0x53, 0x36, 0x11, 0x15, 0x20, 0xb3, 0x5a, 0x57, 0x51, 0x93, 0x20, 0xd8,
+ /* (2^219)P */ 0xb7, 0x56, 0xf4, 0xab, 0x7d, 0x0c, 0xfb, 0x99, 0x1a, 0x30, 0x29, 0xb0, 0x75, 0x2a, 0xf8, 0x53, 0x71, 0x23, 0xbd, 0xa7, 0xd8, 0x0a, 0xe2, 0x27, 0x65, 0xe9, 0x74, 0x26, 0x98, 0x4a, 0x69, 0x19, 0xb2, 0x4d, 0x0a, 0x17, 0x98, 0xb2, 0xa9, 0x57, 0x4e, 0xf6, 0x86, 0xc8, 0x01, 0xa4, 0xc6, 0x98, 0xad, 0x5a, 0x90, 0x2c, 0x05, 0x46, 0x64, 0xb7,
+ /* (2^220)P */ 0x7b, 0x91, 0xdf, 0xfc, 0xf8, 0x1c, 0x8c, 0x15, 0x9e, 0xf7, 0xd5, 0xa8, 0xe8, 0xe7, 0xe3, 0xa3, 0xb0, 0x04, 0x74, 0xfa, 0x78, 0xfb, 0x26, 0xbf, 0x67, 0x42, 0xf9, 0x8c, 0x9b, 0xb4, 0x69, 0x5b, 0x02, 0x13, 0x6d, 0x09, 0x6c, 0xd6, 0x99, 0x61, 0x7b, 0x89, 0x4a, 0x67, 0x75, 0xa3, 0x98, 0x13, 0x23, 0x1d, 0x18, 0x24, 0x0e, 0xef, 0x41, 0x79,
+ /* (2^221)P */ 0x86, 0x33, 0xab, 0x08, 0xcb, 0xbf, 0x1e, 0x76, 0x3c, 0x0b, 0xbd, 0x30, 0xdb, 0xe9, 0xa3, 0x35, 0x87, 0x1b, 0xe9, 0x07, 0x00, 0x66, 0x7f, 0x3b, 0x35, 0x0c, 0x8a, 0x3f, 0x61, 0xbc, 0xe0, 0xae, 0xf6, 0xcc, 0x54, 0xe1, 0x72, 0x36, 0x2d, 0xee, 0x93, 0x24, 0xf8, 0xd7, 0xc5, 0xf9, 0xcb, 0xb0, 0xe5, 0x88, 0x0d, 0x23, 0x4b, 0x76, 0x15, 0xa2,
+ /* (2^222)P */ 0x37, 0xdb, 0x83, 0xd5, 0x6d, 0x06, 0x24, 0x37, 0x1b, 0x15, 0x85, 0x15, 0xe2, 0xc0, 0x4e, 0x02, 0xa9, 0x6d, 0x0a, 0x3a, 0x94, 0x4a, 0x6f, 0x49, 0x00, 0x01, 0x72, 0xbb, 0x60, 0x14, 0x35, 0xae, 0xb4, 0xc6, 0x01, 0x0a, 0x00, 0x9e, 0xc3, 0x58, 0xc5, 0xd1, 0x5e, 0x30, 0x73, 0x96, 0x24, 0x85, 0x9d, 0xf0, 0xf9, 0xec, 0x09, 0xd3, 0xe7, 0x70,
+ /* (2^223)P */ 0xf3, 0xbd, 0x96, 0x87, 0xe9, 0x71, 0xbd, 0xd6, 0xa2, 0x45, 0xeb, 0x0a, 0xcd, 0x2c, 0xf1, 0x72, 0xa6, 0x31, 0xa9, 0x6f, 0x09, 0xa1, 0x5e, 0xdd, 0xc8, 0x8d, 0x0d, 0xbc, 0x5a, 0x8d, 0xb1, 0x2c, 0x9a, 0xcc, 0x37, 0x74, 0xc2, 0xa9, 0x4e, 0xd6, 0xc0, 0x3c, 0xa0, 0x23, 0xb0, 0xa0, 0x77, 0x14, 0x80, 0x45, 0x71, 0x6a, 0x2d, 0x41, 0xc3, 0x82,
+ /* (2^224)P */ 0x37, 0x44, 0xec, 0x8a, 0x3e, 0xc1, 0x0c, 0xa9, 0x12, 0x9c, 0x08, 0x88, 0xcb, 0xd9, 0xf8, 0xba, 0x00, 0xd6, 0xc3, 0xdf, 0xef, 0x7a, 0x44, 0x7e, 0x25, 0x69, 0xc9, 0xc1, 0x46, 0xe5, 0x20, 0x9e, 0xcc, 0x0b, 0x05, 0x3e, 0xf4, 0x78, 0x43, 0x0c, 0xa6, 0x2f, 0xc1, 0xfa, 0x70, 0xb2, 0x3c, 0x31, 0x7a, 0x63, 0x58, 0xab, 0x17, 0xcf, 0x4c, 0x4f,
+ /* (2^225)P */ 0x2b, 0x08, 0x31, 0x59, 0x75, 0x8b, 0xec, 0x0a, 0xa9, 0x79, 0x70, 0xdd, 0xf1, 0x11, 0xc3, 0x11, 0x1f, 0xab, 0x37, 0xaa, 0x26, 0xea, 0x53, 0xc4, 0x79, 0xa7, 0x91, 0x00, 0xaa, 0x08, 0x42, 0xeb, 0x8b, 0x8b, 0xe8, 0xc3, 0x2f, 0xb8, 0x78, 0x90, 0x38, 0x0e, 0x8a, 0x42, 0x0c, 0x0f, 0xbf, 0x3e, 0xf8, 0xd8, 0x07, 0xcf, 0x6a, 0x34, 0xc9, 0xfa,
+ /* (2^226)P */ 0x11, 0xe0, 0x76, 0x4d, 0x23, 0xc5, 0xa6, 0xcc, 0x9f, 0x9a, 0x2a, 0xde, 0x3a, 0xb5, 0x92, 0x39, 0x19, 0x8a, 0xf1, 0x8d, 0xf9, 0x4d, 0xc9, 0xb4, 0x39, 0x9f, 0x57, 0xd8, 0x72, 0xab, 0x1d, 0x61, 0x6a, 0xb2, 0xff, 0x52, 0xba, 0x54, 0x0e, 0xfb, 0x83, 0x30, 0x8a, 0xf7, 0x3b, 0xf4, 0xd8, 0xae, 0x1a, 0x94, 0x3a, 0xec, 0x63, 0xfe, 0x6e, 0x7c,
+ /* (2^227)P */ 0xdc, 0x70, 0x8e, 0x55, 0x44, 0xbf, 0xd2, 0x6a, 0xa0, 0x14, 0x61, 0x89, 0xd5, 0x55, 0x45, 0x3c, 0xf6, 0x40, 0x0d, 0x83, 0x85, 0x44, 0xb4, 0x62, 0x56, 0xfe, 0x60, 0xd7, 0x07, 0x1d, 0x47, 0x30, 0x3b, 0x73, 0xa4, 0xb5, 0xb7, 0xea, 0xac, 0xda, 0xf1, 0x17, 0xaa, 0x60, 0xdf, 0xe9, 0x84, 0xda, 0x31, 0x32, 0x61, 0xbf, 0xd0, 0x7e, 0x8a, 0x02,
+ /* (2^228)P */ 0xb9, 0x51, 0xb3, 0x89, 0x21, 0x5d, 0xa2, 0xfe, 0x79, 0x2a, 0xb3, 0x2a, 0x3b, 0xe6, 0x6f, 0x2b, 0x22, 0x03, 0xea, 0x7b, 0x1f, 0xaf, 0x85, 0xc3, 0x38, 0x55, 0x5b, 0x8e, 0xb4, 0xaa, 0x77, 0xfe, 0x03, 0x6e, 0xda, 0x91, 0x24, 0x0c, 0x48, 0x39, 0x27, 0x43, 0x16, 0xd2, 0x0a, 0x0d, 0x43, 0xa3, 0x0e, 0xca, 0x45, 0xd1, 0x7f, 0xf5, 0xd3, 0x16,
+ /* (2^229)P */ 0x3d, 0x32, 0x9b, 0x38, 0xf8, 0x06, 0x93, 0x78, 0x5b, 0x50, 0x2b, 0x06, 0xd8, 0x66, 0xfe, 0xab, 0x9b, 0x58, 0xc7, 0xd1, 0x4d, 0xd5, 0xf8, 0x3b, 0x10, 0x7e, 0x85, 0xde, 0x58, 0x4e, 0xdf, 0x53, 0xd9, 0x58, 0xe0, 0x15, 0x81, 0x9f, 0x1a, 0x78, 0xfc, 0x9f, 0x10, 0xc2, 0x23, 0xd6, 0x78, 0xd1, 0x9d, 0xd2, 0xd5, 0x1c, 0x53, 0xe2, 0xc9, 0x76,
+ /* (2^230)P */ 0x98, 0x1e, 0x38, 0x7b, 0x71, 0x18, 0x4b, 0x15, 0xaf, 0xa1, 0xa6, 0x98, 0xcb, 0x26, 0xa3, 0xc8, 0x07, 0x46, 0xda, 0x3b, 0x70, 0x65, 0xec, 0x7a, 0x2b, 0x34, 0x94, 0xa8, 0xb6, 0x14, 0xf8, 0x1a, 0xce, 0xf7, 0xc8, 0x60, 0xf3, 0x88, 0xf4, 0x33, 0x60, 0x7b, 0xd1, 0x02, 0xe7, 0xda, 0x00, 0x4a, 0xea, 0xd2, 0xfd, 0x88, 0xd2, 0x99, 0x28, 0xf3,
+ /* (2^231)P */ 0x28, 0x24, 0x1d, 0x26, 0xc2, 0xeb, 0x8b, 0x3b, 0xb4, 0x6b, 0xbe, 0x6b, 0x77, 0xff, 0xf3, 0x21, 0x3b, 0x26, 0x6a, 0x8c, 0x8e, 0x2a, 0x44, 0xa8, 0x01, 0x2b, 0x71, 0xea, 0x64, 0x30, 0xfd, 0xfd, 0x95, 0xcb, 0x39, 0x38, 0x48, 0xfa, 0x96, 0x97, 0x8c, 0x2f, 0x33, 0xca, 0x03, 0xe6, 0xd7, 0x94, 0x55, 0x6c, 0xc3, 0xb3, 0xa8, 0xf7, 0xae, 0x8c,
+ /* (2^232)P */ 0xea, 0x62, 0x8a, 0xb4, 0xeb, 0x74, 0xf7, 0xb8, 0xae, 0xc5, 0x20, 0x71, 0x06, 0xd6, 0x7c, 0x62, 0x9b, 0x69, 0x74, 0xef, 0xa7, 0x6d, 0xd6, 0x8c, 0x37, 0xb9, 0xbf, 0xcf, 0xeb, 0xe4, 0x2f, 0x04, 0x02, 0x21, 0x7d, 0x75, 0x6b, 0x92, 0x48, 0xf8, 0x70, 0xad, 0x69, 0xe2, 0xea, 0x0e, 0x88, 0x67, 0x72, 0xcc, 0x2d, 0x10, 0xce, 0x2d, 0xcf, 0x65,
+ /* (2^233)P */ 0x49, 0xf3, 0x57, 0x64, 0xe5, 0x5c, 0xc5, 0x65, 0x49, 0x97, 0xc4, 0x8a, 0xcc, 0xa9, 0xca, 0x94, 0x7b, 0x86, 0x88, 0xb6, 0x51, 0x27, 0x69, 0xa5, 0x0f, 0x8b, 0x06, 0x59, 0xa0, 0x94, 0xef, 0x63, 0x1a, 0x01, 0x9e, 0x4f, 0xd2, 0x5a, 0x93, 0xc0, 0x7c, 0xe6, 0x61, 0x77, 0xb6, 0xf5, 0x40, 0xd9, 0x98, 0x43, 0x5b, 0x56, 0x68, 0xe9, 0x37, 0x8f,
+ /* (2^234)P */ 0xee, 0x87, 0xd2, 0x05, 0x1b, 0x39, 0x89, 0x10, 0x07, 0x6d, 0xe8, 0xfd, 0x8b, 0x4d, 0xb2, 0xa7, 0x7b, 0x1e, 0xa0, 0x6c, 0x0d, 0x3d, 0x3d, 0x49, 0xba, 0x61, 0x36, 0x1f, 0xc2, 0x84, 0x4a, 0xcc, 0x87, 0xa9, 0x1b, 0x23, 0x04, 0xe2, 0x3e, 0x97, 0xe1, 0xdb, 0xd5, 0x5a, 0xe8, 0x41, 0x6b, 0xe5, 0x5a, 0xa1, 0x99, 0xe5, 0x7b, 0xa7, 0xe0, 0x3b,
+ /* (2^235)P */ 0xea, 0xa3, 0x6a, 0xdd, 0x77, 0x7f, 0x77, 0x41, 0xc5, 0x6a, 0xe4, 0xaf, 0x11, 0x5f, 0x88, 0xa5, 0x10, 0xee, 0xd0, 0x8c, 0x0c, 0xb4, 0xa5, 0x2a, 0xd0, 0xd8, 0x1d, 0x47, 0x06, 0xc0, 0xd5, 0xce, 0x51, 0x54, 0x9b, 0x2b, 0xe6, 0x2f, 0xe7, 0xe7, 0x31, 0x5f, 0x5c, 0x23, 0x81, 0x3e, 0x03, 0x93, 0xaa, 0x2d, 0x71, 0x84, 0xa0, 0x89, 0x32, 0xa6,
+ /* (2^236)P */ 0x55, 0xa3, 0x13, 0x92, 0x4e, 0x93, 0x7d, 0xec, 0xca, 0x57, 0xfb, 0x37, 0xae, 0xd2, 0x18, 0x2e, 0x54, 0x05, 0x6c, 0xd1, 0x28, 0xca, 0x90, 0x40, 0x82, 0x2e, 0x79, 0xc6, 0x5a, 0xc7, 0xdd, 0x84, 0x93, 0xdf, 0x15, 0xb8, 0x1f, 0xb1, 0xf9, 0xaf, 0x2c, 0xe5, 0x32, 0xcd, 0xc2, 0x99, 0x6d, 0xac, 0x85, 0x5c, 0x63, 0xd3, 0xe2, 0xff, 0x24, 0xda,
+ /* (2^237)P */ 0x2d, 0x8d, 0xfd, 0x65, 0xcc, 0xe5, 0x02, 0xa0, 0xe5, 0xb9, 0xec, 0x59, 0x09, 0x50, 0x27, 0xb7, 0x3d, 0x2a, 0x79, 0xb2, 0x76, 0x5d, 0x64, 0x95, 0xf8, 0xc5, 0xaf, 0x8a, 0x62, 0x11, 0x5c, 0x56, 0x1c, 0x05, 0x64, 0x9e, 0x5e, 0xbd, 0x54, 0x04, 0xe6, 0x9e, 0xab, 0xe6, 0x22, 0x7e, 0x42, 0x54, 0xb5, 0xa5, 0xd0, 0x8d, 0x28, 0x6b, 0x0f, 0x0b,
+ /* (2^238)P */ 0x2d, 0xb2, 0x8c, 0x59, 0x10, 0x37, 0x84, 0x3b, 0x9b, 0x65, 0x1b, 0x0f, 0x10, 0xf9, 0xea, 0x60, 0x1b, 0x02, 0xf5, 0xee, 0x8b, 0xe6, 0x32, 0x7d, 0x10, 0x7f, 0x5f, 0x8c, 0x72, 0x09, 0x4e, 0x1f, 0x29, 0xff, 0x65, 0xcb, 0x3e, 0x3a, 0xd2, 0x96, 0x50, 0x1e, 0xea, 0x64, 0x99, 0xb5, 0x4c, 0x7a, 0x69, 0xb8, 0x95, 0xae, 0x48, 0xc0, 0x7c, 0xb1,
+ /* (2^239)P */ 0xcd, 0x7c, 0x4f, 0x3e, 0xea, 0xf3, 0x90, 0xcb, 0x12, 0x76, 0xd1, 0x17, 0xdc, 0x0d, 0x13, 0x0f, 0xfd, 0x4d, 0xb5, 0x1f, 0xe4, 0xdd, 0xf2, 0x4d, 0x58, 0xea, 0xa5, 0x66, 0x92, 0xcf, 0xe5, 0x54, 0xea, 0x9b, 0x35, 0x83, 0x1a, 0x44, 0x8e, 0x62, 0x73, 0x45, 0x98, 0xa3, 0x89, 0x95, 0x52, 0x93, 0x1a, 0x8d, 0x63, 0x0f, 0xc2, 0x57, 0x3c, 0xb1,
+ /* (2^240)P */ 0x72, 0xb4, 0xdf, 0x51, 0xb7, 0xf6, 0x52, 0xa2, 0x14, 0x56, 0xe5, 0x0a, 0x2e, 0x75, 0x81, 0x02, 0xee, 0x93, 0x48, 0x0a, 0x92, 0x4e, 0x0c, 0x0f, 0xdf, 0x09, 0x89, 0x99, 0xf6, 0xf9, 0x22, 0xa2, 0x32, 0xf8, 0xb0, 0x76, 0x0c, 0xb2, 0x4d, 0x6e, 0xbe, 0x83, 0x35, 0x61, 0x44, 0xd2, 0x58, 0xc7, 0xdd, 0x14, 0xcf, 0xc3, 0x4b, 0x7c, 0x07, 0xee,
+ /* (2^241)P */ 0x8b, 0x03, 0xee, 0xcb, 0xa7, 0x2e, 0x28, 0xbd, 0x97, 0xd1, 0x4c, 0x2b, 0xd1, 0x92, 0x67, 0x5b, 0x5a, 0x12, 0xbf, 0x29, 0x17, 0xfc, 0x50, 0x09, 0x74, 0x76, 0xa2, 0xd4, 0x82, 0xfd, 0x2c, 0x0c, 0x90, 0xf7, 0xe7, 0xe5, 0x9a, 0x2c, 0x16, 0x40, 0xb9, 0x6c, 0xd9, 0xe0, 0x22, 0x9e, 0xf8, 0xdd, 0x73, 0xe4, 0x7b, 0x9e, 0xbe, 0x4f, 0x66, 0x22,
+ /* (2^242)P */ 0xa4, 0x10, 0xbe, 0xb8, 0x83, 0x3a, 0x77, 0x8e, 0xea, 0x0a, 0xc4, 0x97, 0x3e, 0xb6, 0x6c, 0x81, 0xd7, 0x65, 0xd9, 0xf7, 0xae, 0xe6, 0xbe, 0xab, 0x59, 0x81, 0x29, 0x4b, 0xff, 0xe1, 0x0f, 0xc3, 0x2b, 0xad, 0x4b, 0xef, 0xc4, 0x50, 0x9f, 0x88, 0x31, 0xf2, 0xde, 0x80, 0xd6, 0xf4, 0x20, 0x9c, 0x77, 0x9b, 0xbe, 0xbe, 0x08, 0xf5, 0xf0, 0x95,
+ /* (2^243)P */ 0x0e, 0x7c, 0x7b, 0x7c, 0xb3, 0xd8, 0x83, 0xfc, 0x8c, 0x75, 0x51, 0x74, 0x1b, 0xe1, 0x6d, 0x11, 0x05, 0x46, 0x24, 0x0d, 0xa4, 0x2b, 0x32, 0xfd, 0x2c, 0x4e, 0x21, 0xdf, 0x39, 0x6b, 0x96, 0xfc, 0xff, 0x92, 0xfc, 0x35, 0x0d, 0x9a, 0x4b, 0xc0, 0x70, 0x46, 0x32, 0x7d, 0xc0, 0xc4, 0x04, 0xe0, 0x2d, 0x83, 0xa7, 0x00, 0xc7, 0xcb, 0xb4, 0x8f,
+ /* (2^244)P */ 0xa9, 0x5a, 0x7f, 0x0e, 0xdd, 0x2c, 0x85, 0xaa, 0x4d, 0xac, 0xde, 0xb3, 0xb6, 0xaf, 0xe6, 0xd1, 0x06, 0x7b, 0x2c, 0xa4, 0x01, 0x19, 0x22, 0x7d, 0x78, 0xf0, 0x3a, 0xea, 0x89, 0xfe, 0x21, 0x61, 0x6d, 0xb8, 0xfe, 0xa5, 0x2a, 0xab, 0x0d, 0x7b, 0x51, 0x39, 0xb6, 0xde, 0xbc, 0xf0, 0xc5, 0x48, 0xd7, 0x09, 0x82, 0x6e, 0x66, 0x75, 0xc5, 0xcd,
+ /* (2^245)P */ 0xee, 0xdf, 0x2b, 0x6c, 0xa8, 0xde, 0x61, 0xe1, 0x27, 0xfa, 0x2a, 0x0f, 0x68, 0xe7, 0x7a, 0x9b, 0x13, 0xe9, 0x56, 0xd2, 0x1c, 0x3d, 0x2f, 0x3c, 0x7a, 0xf6, 0x6f, 0x45, 0xee, 0xe8, 0xf4, 0xa0, 0xa6, 0xe8, 0xa5, 0x27, 0xee, 0xf2, 0x85, 0xa9, 0xd5, 0x0e, 0xa9, 0x26, 0x60, 0xfe, 0xee, 0xc7, 0x59, 0x99, 0x5e, 0xa3, 0xdf, 0x23, 0x36, 0xd5,
+ /* (2^246)P */ 0x15, 0x66, 0x6f, 0xd5, 0x78, 0xa4, 0x0a, 0xf7, 0xb1, 0xe8, 0x75, 0x6b, 0x48, 0x7d, 0xa6, 0x4d, 0x3d, 0x36, 0x9b, 0xc7, 0xcc, 0x68, 0x9a, 0xfe, 0x2f, 0x39, 0x2a, 0x51, 0x31, 0x39, 0x7d, 0x73, 0x6f, 0xc8, 0x74, 0x72, 0x6f, 0x6e, 0xda, 0x5f, 0xad, 0x48, 0xc8, 0x40, 0xe1, 0x06, 0x01, 0x36, 0xa1, 0x88, 0xc8, 0x99, 0x9c, 0xd1, 0x11, 0x8f,
+ /* (2^247)P */ 0xab, 0xc5, 0xcb, 0xcf, 0xbd, 0x73, 0x21, 0xd0, 0x82, 0xb1, 0x2e, 0x2d, 0xd4, 0x36, 0x1b, 0xed, 0xa9, 0x8a, 0x26, 0x79, 0xc4, 0x17, 0xae, 0xe5, 0x09, 0x0a, 0x0c, 0xa4, 0x21, 0xa0, 0x6e, 0xdd, 0x62, 0x8e, 0x44, 0x62, 0xcc, 0x50, 0xff, 0x93, 0xb3, 0x9a, 0x72, 0x8c, 0x3f, 0xa1, 0xa6, 0x4d, 0x87, 0xd5, 0x1c, 0x5a, 0xc0, 0x0b, 0x1a, 0xd6,
+ /* (2^248)P */ 0x67, 0x36, 0x6a, 0x1f, 0x96, 0xe5, 0x80, 0x20, 0xa9, 0xe8, 0x0b, 0x0e, 0x21, 0x29, 0x3f, 0xc8, 0x0a, 0x6d, 0x27, 0x47, 0xca, 0xd9, 0x05, 0x55, 0xbf, 0x11, 0xcf, 0x31, 0x7a, 0x37, 0xc7, 0x90, 0xa9, 0xf4, 0x07, 0x5e, 0xd5, 0xc3, 0x92, 0xaa, 0x95, 0xc8, 0x23, 0x2a, 0x53, 0x45, 0xe3, 0x3a, 0x24, 0xe9, 0x67, 0x97, 0x3a, 0x82, 0xf9, 0xa6,
+ /* (2^249)P */ 0x92, 0x9e, 0x6d, 0x82, 0x67, 0xe9, 0xf9, 0x17, 0x96, 0x2c, 0xa7, 0xd3, 0x89, 0xf9, 0xdb, 0xd8, 0x20, 0xc6, 0x2e, 0xec, 0x4a, 0x76, 0x64, 0xbf, 0x27, 0x40, 0xe2, 0xb4, 0xdf, 0x1f, 0xa0, 0xef, 0x07, 0x80, 0xfb, 0x8e, 0x12, 0xf8, 0xb8, 0xe1, 0xc6, 0xdf, 0x7c, 0x69, 0x35, 0x5a, 0xe1, 0x8e, 0x5d, 0x69, 0x84, 0x56, 0xb6, 0x31, 0x1c, 0x0b,
+ /* (2^250)P */ 0xd6, 0x94, 0x5c, 0xef, 0xbb, 0x46, 0x45, 0x44, 0x5b, 0xa1, 0xae, 0x03, 0x65, 0xdd, 0xb5, 0x66, 0x88, 0x35, 0x29, 0x95, 0x16, 0x54, 0xa6, 0xf5, 0xc9, 0x78, 0x34, 0xe6, 0x0f, 0xc4, 0x2b, 0x5b, 0x79, 0x51, 0x68, 0x48, 0x3a, 0x26, 0x87, 0x05, 0x70, 0xaf, 0x8b, 0xa6, 0xc7, 0x2e, 0xb3, 0xa9, 0x10, 0x01, 0xb0, 0xb9, 0x31, 0xfd, 0xdc, 0x80,
+ /* (2^251)P */ 0x25, 0xf2, 0xad, 0xd6, 0x75, 0xa3, 0x04, 0x05, 0x64, 0x8a, 0x97, 0x60, 0x27, 0x2a, 0xe5, 0x6d, 0xb0, 0x73, 0xf4, 0x07, 0x2a, 0x9d, 0xe9, 0x46, 0xb4, 0x1c, 0x51, 0xf8, 0x63, 0x98, 0x7e, 0xe5, 0x13, 0x51, 0xed, 0x98, 0x65, 0x98, 0x4f, 0x8f, 0xe7, 0x7e, 0x72, 0xd7, 0x64, 0x11, 0x2f, 0xcd, 0x12, 0xf8, 0xc4, 0x63, 0x52, 0x0f, 0x7f, 0xc4,
+ /* (2^252)P */ 0x5c, 0xd9, 0x85, 0x63, 0xc7, 0x8a, 0x65, 0x9a, 0x25, 0x83, 0x31, 0x73, 0x49, 0xf0, 0x93, 0x96, 0x70, 0x67, 0x6d, 0xb1, 0xff, 0x95, 0x54, 0xe4, 0xf8, 0x15, 0x6c, 0x5f, 0xbd, 0xf6, 0x0f, 0x38, 0x7b, 0x68, 0x7d, 0xd9, 0x3d, 0xf0, 0xa9, 0xa0, 0xe4, 0xd1, 0xb6, 0x34, 0x6d, 0x14, 0x16, 0xc2, 0x4c, 0x30, 0x0e, 0x67, 0xd3, 0xbe, 0x2e, 0xc0,
+ /* (2^253)P */ 0x06, 0x6b, 0x52, 0xc8, 0x14, 0xcd, 0xae, 0x03, 0x93, 0xea, 0xc1, 0xf2, 0xf6, 0x8b, 0xc5, 0xb6, 0xdc, 0x82, 0x42, 0x29, 0x94, 0xe0, 0x25, 0x6c, 0x3f, 0x9f, 0x5d, 0xe4, 0x96, 0xf6, 0x8e, 0x3f, 0xf9, 0x72, 0xc4, 0x77, 0x60, 0x8b, 0xa4, 0xf9, 0xa8, 0xc3, 0x0a, 0x81, 0xb1, 0x97, 0x70, 0x18, 0xab, 0xea, 0x37, 0x8a, 0x08, 0xc7, 0xe2, 0x95,
+ /* (2^254)P */ 0x94, 0x49, 0xd9, 0x5f, 0x76, 0x72, 0x82, 0xad, 0x2d, 0x50, 0x1a, 0x7a, 0x5b, 0xe6, 0x95, 0x1e, 0x95, 0x65, 0x87, 0x1c, 0x52, 0xd7, 0x44, 0xe6, 0x9b, 0x56, 0xcd, 0x6f, 0x05, 0xff, 0x67, 0xc5, 0xdb, 0xa2, 0xac, 0xe4, 0xa2, 0x28, 0x63, 0x5f, 0xfb, 0x0c, 0x3b, 0xf1, 0x87, 0xc3, 0x36, 0x78, 0x3f, 0x77, 0xfa, 0x50, 0x85, 0xf9, 0xd7, 0x82,
+ /* (2^255)P */ 0x64, 0xc0, 0xe0, 0xd8, 0x2d, 0xed, 0xcb, 0x6a, 0xfd, 0xcd, 0xbc, 0x7e, 0x9f, 0xc8, 0x85, 0xe9, 0xc1, 0x7c, 0x0f, 0xe5, 0x18, 0xea, 0xd4, 0x51, 0xad, 0x59, 0x13, 0x75, 0xd9, 0x3d, 0xd4, 0x8a, 0xb2, 0xbe, 0x78, 0x52, 0x2b, 0x52, 0x94, 0x37, 0x41, 0xd6, 0xb4, 0xb6, 0x45, 0x20, 0x76, 0xe0, 0x1f, 0x31, 0xdb, 0xb1, 0xa1, 0x43, 0xf0, 0x18,
+ /* (2^256)P */ 0x74, 0xa9, 0xa4, 0xa9, 0xdd, 0x6e, 0x3e, 0x68, 0xe5, 0xc3, 0x2e, 0x92, 0x17, 0xa4, 0xcb, 0x80, 0xb1, 0xf0, 0x06, 0x93, 0xef, 0xe6, 0x00, 0xe6, 0x3b, 0xb1, 0x32, 0x65, 0x7b, 0x83, 0xb6, 0x8a, 0x49, 0x1b, 0x14, 0x89, 0xee, 0xba, 0xf5, 0x6a, 0x8d, 0x36, 0xef, 0xb0, 0xd8, 0xb2, 0x16, 0x99, 0x17, 0x35, 0x02, 0x16, 0x55, 0x58, 0xdd, 0x82,
+ /* (2^257)P */ 0x36, 0x95, 0xe8, 0xf4, 0x36, 0x42, 0xbb, 0xc5, 0x3e, 0xfa, 0x30, 0x84, 0x9e, 0x59, 0xfd, 0xd2, 0x95, 0x42, 0xf8, 0x64, 0xd9, 0xb9, 0x0e, 0x9f, 0xfa, 0xd0, 0x7b, 0x20, 0x31, 0x77, 0x48, 0x29, 0x4d, 0xd0, 0x32, 0x57, 0x56, 0x30, 0xa6, 0x17, 0x53, 0x04, 0xbf, 0x08, 0x28, 0xec, 0xb8, 0x46, 0xc1, 0x03, 0x89, 0xdc, 0xed, 0xa0, 0x35, 0x53,
+ /* (2^258)P */ 0xc5, 0x7f, 0x9e, 0xd8, 0xc5, 0xba, 0x5f, 0x68, 0xc8, 0x23, 0x75, 0xea, 0x0d, 0xd9, 0x5a, 0xfd, 0x61, 0x1a, 0xa3, 0x2e, 0x45, 0x63, 0x14, 0x55, 0x86, 0x21, 0x29, 0xbe, 0xef, 0x5e, 0x50, 0xe5, 0x18, 0x59, 0xe7, 0xe3, 0xce, 0x4d, 0x8c, 0x15, 0x8f, 0x89, 0x66, 0x44, 0x52, 0x3d, 0xfa, 0xc7, 0x9a, 0x59, 0x90, 0x8e, 0xc0, 0x06, 0x3f, 0xc9,
+ /* (2^259)P */ 0x8e, 0x04, 0xd9, 0x16, 0x50, 0x1d, 0x8c, 0x9f, 0xd5, 0xe3, 0xce, 0xfd, 0x47, 0x04, 0x27, 0x4d, 0xc2, 0xfa, 0x71, 0xd9, 0x0b, 0xb8, 0x65, 0xf4, 0x11, 0xf3, 0x08, 0xee, 0x81, 0xc8, 0x67, 0x99, 0x0b, 0x8d, 0x77, 0xa3, 0x4f, 0xb5, 0x9b, 0xdb, 0x26, 0xf1, 0x97, 0xeb, 0x04, 0x54, 0xeb, 0x80, 0x08, 0x1d, 0x1d, 0xf6, 0x3d, 0x1f, 0x5a, 0xb8,
+ /* (2^260)P */ 0xb7, 0x9c, 0x9d, 0xee, 0xb9, 0x5c, 0xad, 0x0d, 0x9e, 0xfd, 0x60, 0x3c, 0x27, 0x4e, 0xa2, 0x95, 0xfb, 0x64, 0x7e, 0x79, 0x64, 0x87, 0x10, 0xb4, 0x73, 0xe0, 0x9d, 0x46, 0x4d, 0x3d, 0xee, 0x83, 0xe4, 0x16, 0x88, 0x97, 0xe6, 0x4d, 0xba, 0x70, 0xb6, 0x96, 0x7b, 0xff, 0x4b, 0xc8, 0xcf, 0x72, 0x83, 0x3e, 0x5b, 0x24, 0x2e, 0x57, 0xf1, 0x82,
+ /* (2^261)P */ 0x30, 0x71, 0x40, 0x51, 0x4f, 0x44, 0xbb, 0xc7, 0xf0, 0x54, 0x6e, 0x9d, 0xeb, 0x15, 0xad, 0xf8, 0x61, 0x43, 0x5a, 0xef, 0xc0, 0xb1, 0x57, 0xae, 0x03, 0x40, 0xe8, 0x68, 0x6f, 0x03, 0x20, 0x4f, 0x8a, 0x51, 0x2a, 0x9e, 0xd2, 0x45, 0xaf, 0xb4, 0xf5, 0xd4, 0x95, 0x7f, 0x3d, 0x3d, 0xb7, 0xb6, 0x28, 0xc5, 0x08, 0x8b, 0x44, 0xd6, 0x3f, 0xe7,
+ /* (2^262)P */ 0xa9, 0x52, 0x04, 0x67, 0xcb, 0x20, 0x63, 0xf8, 0x18, 0x01, 0x44, 0x21, 0x6a, 0x8a, 0x83, 0x48, 0xd4, 0xaf, 0x23, 0x0f, 0x35, 0x8d, 0xe5, 0x5a, 0xc4, 0x7c, 0x55, 0x46, 0x19, 0x5f, 0x35, 0xe0, 0x5d, 0x97, 0x4c, 0x2d, 0x04, 0xed, 0x59, 0xd4, 0xb0, 0xb2, 0xc6, 0xe3, 0x51, 0xe1, 0x38, 0xc6, 0x30, 0x49, 0x8f, 0xae, 0x61, 0x64, 0xce, 0xa8,
+ /* (2^263)P */ 0x9b, 0x64, 0x83, 0x3c, 0xd3, 0xdf, 0xb9, 0x27, 0xe7, 0x5b, 0x7f, 0xeb, 0xf3, 0x26, 0xcf, 0xb1, 0x8f, 0xaf, 0x26, 0xc8, 0x48, 0xce, 0xa1, 0xac, 0x7d, 0x10, 0x34, 0x28, 0xe1, 0x1f, 0x69, 0x03, 0x64, 0x77, 0x61, 0xdd, 0x4a, 0x9b, 0x18, 0x47, 0xf8, 0xca, 0x63, 0xc9, 0x03, 0x2d, 0x20, 0x2a, 0x69, 0x6e, 0x42, 0xd0, 0xe7, 0xaa, 0xb5, 0xf3,
+ /* (2^264)P */ 0xea, 0x31, 0x0c, 0x57, 0x0f, 0x3e, 0xe3, 0x35, 0xd8, 0x30, 0xa5, 0x6f, 0xdd, 0x95, 0x43, 0xc6, 0x66, 0x07, 0x4f, 0x34, 0xc3, 0x7e, 0x04, 0x10, 0x2d, 0xc4, 0x1c, 0x94, 0x52, 0x2e, 0x5b, 0x9a, 0x65, 0x2f, 0x91, 0xaa, 0x4f, 0x3c, 0xdc, 0x23, 0x18, 0xe1, 0x4f, 0x85, 0xcd, 0xf4, 0x8c, 0x51, 0xf7, 0xab, 0x4f, 0xdc, 0x15, 0x5c, 0x9e, 0xc5,
+ /* (2^265)P */ 0x54, 0x57, 0x23, 0x17, 0xe7, 0x82, 0x2f, 0x04, 0x7d, 0xfe, 0xe7, 0x1f, 0xa2, 0x57, 0x79, 0xe9, 0x58, 0x9b, 0xbe, 0xc6, 0x16, 0x4a, 0x17, 0x50, 0x90, 0x4a, 0x34, 0x70, 0x87, 0x37, 0x01, 0x26, 0xd8, 0xa3, 0x5f, 0x07, 0x7c, 0xd0, 0x7d, 0x05, 0x8a, 0x93, 0x51, 0x2f, 0x99, 0xea, 0xcf, 0x00, 0xd8, 0xc7, 0xe6, 0x9b, 0x8c, 0x62, 0x45, 0x87,
+ /* (2^266)P */ 0xc3, 0xfd, 0x29, 0x66, 0xe7, 0x30, 0x29, 0x77, 0xe0, 0x0d, 0x63, 0x5b, 0xe6, 0x90, 0x1a, 0x1e, 0x99, 0xc2, 0xa7, 0xab, 0xff, 0xa7, 0xbd, 0x79, 0x01, 0x97, 0xfd, 0x27, 0x1b, 0x43, 0x2b, 0xe6, 0xfe, 0x5e, 0xf1, 0xb9, 0x35, 0x38, 0x08, 0x25, 0x55, 0x90, 0x68, 0x2e, 0xc3, 0x67, 0x39, 0x9f, 0x2b, 0x2c, 0x70, 0x48, 0x8c, 0x47, 0xee, 0x56,
+ /* (2^267)P */ 0xf7, 0x32, 0x70, 0xb5, 0xe6, 0x42, 0xfd, 0x0a, 0x39, 0x9b, 0x07, 0xfe, 0x0e, 0xf4, 0x47, 0xba, 0x6a, 0x3f, 0xf5, 0x2c, 0x15, 0xf3, 0x60, 0x3f, 0xb1, 0x83, 0x7b, 0x2e, 0x34, 0x58, 0x1a, 0x6e, 0x4a, 0x49, 0x05, 0x45, 0xca, 0xdb, 0x00, 0x01, 0x0c, 0x42, 0x5e, 0x60, 0x40, 0x5f, 0xd9, 0xc7, 0x3a, 0x9e, 0x1c, 0x8d, 0xab, 0x11, 0x55, 0x65,
+ /* (2^268)P */ 0x87, 0x40, 0xb7, 0x0d, 0xaa, 0x34, 0x89, 0x90, 0x75, 0x6d, 0xa2, 0xfe, 0x3b, 0x6d, 0x5c, 0x39, 0x98, 0x10, 0x9e, 0x15, 0xc5, 0x35, 0xa2, 0x27, 0x23, 0x0a, 0x2d, 0x60, 0xe2, 0xa8, 0x7f, 0x3e, 0x77, 0x8f, 0xcc, 0x44, 0xcc, 0x30, 0x28, 0xe2, 0xf0, 0x04, 0x8c, 0xee, 0xe4, 0x5f, 0x68, 0x8c, 0xdf, 0x70, 0xbf, 0x31, 0xee, 0x2a, 0xfc, 0xce,
+ /* (2^269)P */ 0x92, 0xf2, 0xa0, 0xd9, 0x58, 0x3b, 0x7c, 0x1a, 0x99, 0x46, 0x59, 0x54, 0x60, 0x06, 0x8d, 0x5e, 0xf0, 0x22, 0xa1, 0xed, 0x92, 0x8a, 0x4d, 0x76, 0x95, 0x05, 0x0b, 0xff, 0xfc, 0x9a, 0xd1, 0xcc, 0x05, 0xb9, 0x5e, 0x99, 0xe8, 0x2a, 0x76, 0x7b, 0xfd, 0xa6, 0xe2, 0xd1, 0x1a, 0xd6, 0x76, 0x9f, 0x2f, 0x0e, 0xd1, 0xa8, 0x77, 0x5a, 0x40, 0x5a,
+ /* (2^270)P */ 0xff, 0xf9, 0x3f, 0xa9, 0xa6, 0x6c, 0x6d, 0x03, 0x8b, 0xa7, 0x10, 0x5d, 0x3f, 0xec, 0x3e, 0x1c, 0x0b, 0x6b, 0xa2, 0x6a, 0x22, 0xa9, 0x28, 0xd0, 0x66, 0xc9, 0xc2, 0x3d, 0x47, 0x20, 0x7d, 0xa6, 0x1d, 0xd8, 0x25, 0xb5, 0xf2, 0xf9, 0x70, 0x19, 0x6b, 0xf8, 0x43, 0x36, 0xc5, 0x1f, 0xe4, 0x5a, 0x4c, 0x13, 0xe4, 0x6d, 0x08, 0x0b, 0x1d, 0xb1,
+ /* (2^271)P */ 0x3f, 0x20, 0x9b, 0xfb, 0xec, 0x7d, 0x31, 0xc5, 0xfc, 0x88, 0x0b, 0x30, 0xed, 0x36, 0xc0, 0x63, 0xb1, 0x7d, 0x10, 0xda, 0xb6, 0x2e, 0xad, 0xf3, 0xec, 0x94, 0xe7, 0xec, 0xb5, 0x9c, 0xfe, 0xf5, 0x35, 0xf0, 0xa2, 0x2d, 0x7f, 0xca, 0x6b, 0x67, 0x1a, 0xf6, 0xb3, 0xda, 0x09, 0x2a, 0xaa, 0xdf, 0xb1, 0xca, 0x9b, 0xfb, 0xeb, 0xb3, 0xcd, 0xc0,
+ /* (2^272)P */ 0xcd, 0x4d, 0x89, 0x00, 0xa4, 0x3b, 0x48, 0xf0, 0x76, 0x91, 0x35, 0xa5, 0xf8, 0xc9, 0xb6, 0x46, 0xbc, 0xf6, 0x9a, 0x45, 0x47, 0x17, 0x96, 0x80, 0x5b, 0x3a, 0x28, 0x33, 0xf9, 0x5a, 0xef, 0x43, 0x07, 0xfe, 0x3b, 0xf4, 0x8e, 0x19, 0xce, 0xd2, 0x94, 0x4b, 0x6d, 0x8e, 0x67, 0x20, 0xc7, 0x4f, 0x2f, 0x59, 0x8e, 0xe1, 0xa1, 0xa9, 0xf9, 0x0e,
+ /* (2^273)P */ 0xdc, 0x7b, 0xb5, 0x50, 0x2e, 0xe9, 0x7e, 0x8b, 0x78, 0xa1, 0x38, 0x96, 0x22, 0xc3, 0x61, 0x67, 0x6d, 0xc8, 0x58, 0xed, 0x41, 0x1d, 0x5d, 0x86, 0x98, 0x7f, 0x2f, 0x1b, 0x8d, 0x3e, 0xaa, 0xc1, 0xd2, 0x0a, 0xf3, 0xbf, 0x95, 0x04, 0xf3, 0x10, 0x3c, 0x2b, 0x7f, 0x90, 0x46, 0x04, 0xaa, 0x6a, 0xa9, 0x35, 0x76, 0xac, 0x49, 0xb5, 0x00, 0x45,
+ /* (2^274)P */ 0xb1, 0x93, 0x79, 0x84, 0x4a, 0x2a, 0x30, 0x78, 0x16, 0xaa, 0xc5, 0x74, 0x06, 0xce, 0xa5, 0xa7, 0x32, 0x86, 0xe0, 0xf9, 0x10, 0xd2, 0x58, 0x76, 0xfb, 0x66, 0x49, 0x76, 0x3a, 0x90, 0xba, 0xb5, 0xcc, 0x99, 0xcd, 0x09, 0xc1, 0x9a, 0x74, 0x23, 0xdf, 0x0c, 0xfe, 0x99, 0x52, 0x80, 0xa3, 0x7c, 0x1c, 0x71, 0x5f, 0x2c, 0x49, 0x57, 0xf4, 0xf9,
+ /* (2^275)P */ 0x6d, 0xbf, 0x52, 0xe6, 0x25, 0x98, 0xed, 0xcf, 0xe3, 0xbc, 0x08, 0xa2, 0x1a, 0x90, 0xae, 0xa0, 0xbf, 0x07, 0x15, 0xad, 0x0a, 0x9f, 0x3e, 0x47, 0x44, 0xc2, 0x10, 0x46, 0xa6, 0x7a, 0x9e, 0x2f, 0x57, 0xbc, 0xe2, 0xf0, 0x1d, 0xd6, 0x9a, 0x06, 0xed, 0xfc, 0x54, 0x95, 0x92, 0x15, 0xa2, 0xf7, 0x8d, 0x6b, 0xef, 0xb2, 0x05, 0xed, 0x5c, 0x63,
+ /* (2^276)P */ 0xbc, 0x0b, 0x27, 0x3a, 0x3a, 0xf8, 0xe1, 0x48, 0x02, 0x7e, 0x27, 0xe6, 0x81, 0x62, 0x07, 0x73, 0x74, 0xe5, 0x52, 0xd7, 0xf8, 0x26, 0xca, 0x93, 0x4d, 0x3e, 0x9b, 0x55, 0x09, 0x8e, 0xe3, 0xd7, 0xa6, 0xe3, 0xb6, 0x2a, 0xa9, 0xb3, 0xb0, 0xa0, 0x8c, 0x01, 0xbb, 0x07, 0x90, 0x78, 0x6d, 0x6d, 0xe9, 0xf0, 0x7a, 0x90, 0xbd, 0xdc, 0x0c, 0x36,
+ /* (2^277)P */ 0x7f, 0x20, 0x12, 0x0f, 0x40, 0x00, 0x53, 0xd8, 0x0c, 0x27, 0x47, 0x47, 0x22, 0x80, 0xfb, 0x62, 0xe4, 0xa7, 0xf7, 0xbd, 0x42, 0xa5, 0xc3, 0x2b, 0xb2, 0x7f, 0x50, 0xcc, 0xe2, 0xfb, 0xd5, 0xc0, 0x63, 0xdd, 0x24, 0x5f, 0x7c, 0x08, 0x91, 0xbf, 0x6e, 0x47, 0x44, 0xd4, 0x6a, 0xc0, 0xc3, 0x09, 0x39, 0x27, 0xdd, 0xc7, 0xca, 0x06, 0x29, 0x55,
+ /* (2^278)P */ 0x76, 0x28, 0x58, 0xb0, 0xd2, 0xf3, 0x0f, 0x04, 0xe9, 0xc9, 0xab, 0x66, 0x5b, 0x75, 0x51, 0xdc, 0xe5, 0x8f, 0xe8, 0x1f, 0xdb, 0x03, 0x0f, 0xb0, 0x7d, 0xf9, 0x20, 0x64, 0x89, 0xe9, 0xdc, 0xe6, 0x24, 0xc3, 0xd5, 0xd2, 0x41, 0xa6, 0xe4, 0xe3, 0xc4, 0x79, 0x7c, 0x0f, 0xa1, 0x61, 0x2f, 0xda, 0xa4, 0xc9, 0xfd, 0xad, 0x5c, 0x65, 0x6a, 0xf3,
+ /* (2^279)P */ 0xd5, 0xab, 0x72, 0x7a, 0x3b, 0x59, 0xea, 0xcf, 0xd5, 0x17, 0xd2, 0xb2, 0x5f, 0x2d, 0xab, 0xad, 0x9e, 0x88, 0x64, 0x55, 0x96, 0x6e, 0xf3, 0x44, 0xa9, 0x11, 0xf5, 0xf8, 0x3a, 0xf1, 0xcd, 0x79, 0x4c, 0x99, 0x6d, 0x23, 0x6a, 0xa0, 0xc2, 0x1a, 0x19, 0x45, 0xb5, 0xd8, 0x95, 0x2f, 0x49, 0xe9, 0x46, 0x39, 0x26, 0x60, 0x04, 0x15, 0x8b, 0xcc,
+ /* (2^280)P */ 0x66, 0x0c, 0xf0, 0x54, 0x41, 0x02, 0x91, 0xab, 0xe5, 0x85, 0x8a, 0x44, 0xa6, 0x34, 0x96, 0x32, 0xc0, 0xdf, 0x6c, 0x41, 0x39, 0xd4, 0xc6, 0xe1, 0xe3, 0x81, 0xb0, 0x4c, 0x34, 0x4f, 0xe5, 0xf4, 0x35, 0x46, 0x1f, 0xeb, 0x75, 0xfd, 0x43, 0x37, 0x50, 0x99, 0xab, 0xad, 0xb7, 0x8c, 0xa1, 0x57, 0xcb, 0xe6, 0xce, 0x16, 0x2e, 0x85, 0xcc, 0xf9,
+ /* (2^281)P */ 0x63, 0xd1, 0x3f, 0x9e, 0xa2, 0x17, 0x2e, 0x1d, 0x3e, 0xce, 0x48, 0x2d, 0xbb, 0x8f, 0x69, 0xc9, 0xa6, 0x3d, 0x4e, 0xfe, 0x09, 0x56, 0xb3, 0x02, 0x5f, 0x99, 0x97, 0x0c, 0x54, 0xda, 0x32, 0x97, 0x9b, 0xf4, 0x95, 0xf1, 0xad, 0xe3, 0x2b, 0x04, 0xa7, 0x9b, 0x3f, 0xbb, 0xe7, 0x87, 0x2e, 0x1f, 0x8b, 0x4b, 0x7a, 0xa4, 0x43, 0x0c, 0x0f, 0x35,
+ /* (2^282)P */ 0x05, 0xdc, 0xe0, 0x2c, 0xa1, 0xc1, 0xd0, 0xf1, 0x1f, 0x4e, 0xc0, 0x6c, 0x35, 0x7b, 0xca, 0x8f, 0x8b, 0x02, 0xb1, 0xf7, 0xd6, 0x2e, 0xe7, 0x93, 0x80, 0x85, 0x18, 0x88, 0x19, 0xb9, 0xb4, 0x4a, 0xbc, 0xeb, 0x5a, 0x78, 0x38, 0xed, 0xc6, 0x27, 0x2a, 0x74, 0x76, 0xf0, 0x1b, 0x79, 0x92, 0x2f, 0xd2, 0x81, 0x98, 0xdf, 0xa9, 0x50, 0x19, 0xeb,
+ /* (2^283)P */ 0xb5, 0xe7, 0xb4, 0x11, 0x3a, 0x81, 0xb6, 0xb4, 0xf8, 0xa2, 0xb3, 0x6c, 0xfc, 0x9d, 0xe0, 0xc0, 0xe0, 0x59, 0x7f, 0x05, 0x37, 0xef, 0x2c, 0xa9, 0x3a, 0x24, 0xac, 0x7b, 0x25, 0xa0, 0x55, 0xd2, 0x44, 0x82, 0x82, 0x6e, 0x64, 0xa3, 0x58, 0xc8, 0x67, 0xae, 0x26, 0xa7, 0x0f, 0x42, 0x63, 0xe1, 0x93, 0x01, 0x52, 0x19, 0xaf, 0x49, 0x3e, 0x33,
+ /* (2^284)P */ 0x05, 0x85, 0xe6, 0x66, 0xaf, 0x5f, 0xdf, 0xbf, 0x9d, 0x24, 0x62, 0x60, 0x90, 0xe2, 0x4c, 0x7d, 0x4e, 0xc3, 0x74, 0x5d, 0x4f, 0x53, 0xf3, 0x63, 0x13, 0xf4, 0x74, 0x28, 0x6b, 0x7d, 0x57, 0x0c, 0x9d, 0x84, 0xa7, 0x1a, 0xff, 0xa0, 0x79, 0xdf, 0xfc, 0x65, 0x98, 0x8e, 0x22, 0x0d, 0x62, 0x7e, 0xf2, 0x34, 0x60, 0x83, 0x05, 0x14, 0xb1, 0xc1,
+ /* (2^285)P */ 0x64, 0x22, 0xcc, 0xdf, 0x5c, 0xbc, 0x88, 0x68, 0x4c, 0xd9, 0xbc, 0x0e, 0xc9, 0x8b, 0xb4, 0x23, 0x52, 0xad, 0xb0, 0xb3, 0xf1, 0x17, 0xd8, 0x15, 0x04, 0x6b, 0x99, 0xf0, 0xc4, 0x7d, 0x48, 0x22, 0x4a, 0xf8, 0x6f, 0xaa, 0x88, 0x0d, 0xc5, 0x5e, 0xa9, 0x1c, 0x61, 0x3d, 0x95, 0xa9, 0x7b, 0x6a, 0x79, 0x33, 0x0a, 0x2b, 0x99, 0xe3, 0x4e, 0x48,
+ /* (2^286)P */ 0x6b, 0x9b, 0x6a, 0x2a, 0xf1, 0x60, 0x31, 0xb4, 0x73, 0xd1, 0x87, 0x45, 0x9c, 0x15, 0x58, 0x4b, 0x91, 0x6d, 0x94, 0x1c, 0x41, 0x11, 0x4a, 0x83, 0xec, 0xaf, 0x65, 0xbc, 0x34, 0xaa, 0x26, 0xe2, 0xaf, 0xed, 0x46, 0x05, 0x4e, 0xdb, 0xc6, 0x4e, 0x10, 0x28, 0x4e, 0x72, 0xe5, 0x31, 0xa3, 0x20, 0xd7, 0xb1, 0x96, 0x64, 0xf6, 0xce, 0x08, 0x08,
+ /* (2^287)P */ 0x16, 0xa9, 0x5c, 0x9f, 0x9a, 0xb4, 0xb8, 0xc8, 0x32, 0x78, 0xc0, 0x3a, 0xd9, 0x5f, 0x94, 0xac, 0x3a, 0x42, 0x1f, 0x43, 0xd6, 0x80, 0x47, 0x2c, 0xdc, 0x76, 0x27, 0xfa, 0x50, 0xe5, 0xa1, 0xe4, 0xc3, 0xcb, 0x61, 0x31, 0xe1, 0x2e, 0xde, 0x81, 0x3b, 0x77, 0x1c, 0x39, 0x3c, 0xdb, 0xda, 0x87, 0x4b, 0x84, 0x12, 0xeb, 0xdd, 0x54, 0xbf, 0xe7,
+ /* (2^288)P */ 0xbf, 0xcb, 0x73, 0x21, 0x3d, 0x7e, 0x13, 0x8c, 0xa6, 0x34, 0x21, 0x2b, 0xa5, 0xe4, 0x9f, 0x8e, 0x9c, 0x01, 0x9c, 0x43, 0xd9, 0xc7, 0xb9, 0xf1, 0xbe, 0x7f, 0x45, 0x51, 0x97, 0xa1, 0x8e, 0x01, 0xf8, 0xbd, 0xd2, 0xbf, 0x81, 0x3a, 0x8b, 0xab, 0xe4, 0x89, 0xb7, 0xbd, 0xf2, 0xcd, 0xa9, 0x8a, 0x8a, 0xde, 0xfb, 0x8a, 0x55, 0x12, 0x7b, 0x17,
+ /* (2^289)P */ 0x1b, 0x95, 0x58, 0x4d, 0xe6, 0x51, 0x31, 0x52, 0x1c, 0xd8, 0x15, 0x84, 0xb1, 0x0d, 0x36, 0x25, 0x88, 0x91, 0x46, 0x71, 0x42, 0x56, 0xe2, 0x90, 0x08, 0x9e, 0x77, 0x1b, 0xee, 0x22, 0x3f, 0xec, 0xee, 0x8c, 0x7b, 0x2e, 0x79, 0xc4, 0x6c, 0x07, 0xa1, 0x7e, 0x52, 0xf5, 0x26, 0x5c, 0x84, 0x2a, 0x50, 0x6e, 0x82, 0xb3, 0x76, 0xda, 0x35, 0x16,
+ /* (2^290)P */ 0x0a, 0x6f, 0x99, 0x87, 0xc0, 0x7d, 0x8a, 0xb2, 0xca, 0xae, 0xe8, 0x65, 0x98, 0x0f, 0xb3, 0x44, 0xe1, 0xdc, 0x52, 0x79, 0x75, 0xec, 0x8f, 0x95, 0x87, 0x45, 0xd1, 0x32, 0x18, 0x55, 0x15, 0xce, 0x64, 0x9b, 0x08, 0x4f, 0x2c, 0xea, 0xba, 0x1c, 0x57, 0x06, 0x63, 0xc8, 0xb1, 0xfd, 0xc5, 0x67, 0xe7, 0x1f, 0x87, 0x9e, 0xde, 0x72, 0x7d, 0xec,
+ /* (2^291)P */ 0x36, 0x8b, 0x4d, 0x2c, 0xc2, 0x46, 0xe8, 0x96, 0xac, 0x0b, 0x8c, 0xc5, 0x09, 0x10, 0xfc, 0xf2, 0xda, 0xea, 0x22, 0xb2, 0xd3, 0x89, 0xeb, 0xb2, 0x85, 0x0f, 0xff, 0x59, 0x50, 0x2c, 0x99, 0x5a, 0x1f, 0xec, 0x2a, 0x6f, 0xec, 0xcf, 0xe9, 0xce, 0x12, 0x6b, 0x19, 0xd8, 0xde, 0x9b, 0xce, 0x0e, 0x6a, 0xaa, 0xe1, 0x32, 0xea, 0x4c, 0xfe, 0x92,
+ /* (2^292)P */ 0x5f, 0x17, 0x70, 0x53, 0x26, 0x03, 0x0b, 0xab, 0xd1, 0xc1, 0x42, 0x0b, 0xab, 0x2b, 0x3d, 0x31, 0xa4, 0xd5, 0x2b, 0x5e, 0x00, 0xd5, 0x9a, 0x22, 0x34, 0xe0, 0x53, 0x3f, 0x59, 0x7f, 0x2c, 0x6d, 0x72, 0x9a, 0xa4, 0xbe, 0x3d, 0x42, 0x05, 0x1b, 0xf2, 0x7f, 0x88, 0x56, 0xd1, 0x7c, 0x7d, 0x6b, 0x9f, 0x43, 0xfe, 0x65, 0x19, 0xae, 0x9c, 0x4c,
+ /* (2^293)P */ 0xf3, 0x7c, 0x20, 0xa9, 0xfc, 0xf2, 0xf2, 0x3b, 0x3c, 0x57, 0x41, 0x94, 0xe5, 0xcc, 0x6a, 0x37, 0x5d, 0x09, 0xf2, 0xab, 0xc2, 0xca, 0x60, 0x38, 0x6b, 0x7a, 0xe1, 0x78, 0x2b, 0xc1, 0x1d, 0xe8, 0xfd, 0xbc, 0x3d, 0x5c, 0xa2, 0xdb, 0x49, 0x20, 0x79, 0xe6, 0x1b, 0x9b, 0x65, 0xd9, 0x6d, 0xec, 0x57, 0x1d, 0xd2, 0xe9, 0x90, 0xeb, 0x43, 0x7b,
+ /* (2^294)P */ 0x2a, 0x8b, 0x2e, 0x19, 0x18, 0x10, 0xb8, 0x83, 0xe7, 0x7d, 0x2d, 0x9a, 0x3a, 0xe5, 0xd1, 0xe4, 0x7c, 0x38, 0xe5, 0x59, 0x2a, 0x6e, 0xd9, 0x01, 0x29, 0x3d, 0x23, 0xf7, 0x52, 0xba, 0x61, 0x04, 0x9a, 0xde, 0xc4, 0x31, 0x50, 0xeb, 0x1b, 0xaa, 0xde, 0x39, 0x58, 0xd8, 0x1b, 0x1e, 0xfc, 0x57, 0x9a, 0x28, 0x43, 0x9e, 0x97, 0x5e, 0xaa, 0xa3,
+ /* (2^295)P */ 0x97, 0x0a, 0x74, 0xc4, 0x39, 0x99, 0x6b, 0x40, 0xc7, 0x3e, 0x8c, 0xa7, 0xb1, 0x4e, 0x9a, 0x59, 0x6e, 0x1c, 0xfe, 0xfc, 0x2a, 0x5e, 0x73, 0x2b, 0x8c, 0xa9, 0x71, 0xf5, 0xda, 0x6b, 0x15, 0xab, 0xf7, 0xbe, 0x2a, 0x44, 0x5f, 0xba, 0xae, 0x67, 0x93, 0xc5, 0x86, 0xc1, 0xb8, 0xdf, 0xdc, 0xcb, 0xd7, 0xff, 0xb1, 0x71, 0x7c, 0x6f, 0x88, 0xf8,
+ /* (2^296)P */ 0x3f, 0x89, 0xb1, 0xbf, 0x24, 0x16, 0xac, 0x56, 0xfe, 0xdf, 0x94, 0x71, 0xbf, 0xd6, 0x57, 0x0c, 0xb4, 0x77, 0x37, 0xaa, 0x2a, 0x70, 0x76, 0x49, 0xaf, 0x0c, 0x97, 0x8e, 0x78, 0x2a, 0x67, 0xc9, 0x3b, 0x3d, 0x5b, 0x01, 0x2f, 0xda, 0xd5, 0xa8, 0xde, 0x02, 0xa9, 0xac, 0x76, 0x00, 0x0b, 0x46, 0xc6, 0x2d, 0xdc, 0x08, 0xf4, 0x10, 0x2c, 0xbe,
+ /* (2^297)P */ 0xcb, 0x07, 0xf9, 0x91, 0xc6, 0xd5, 0x3e, 0x54, 0x63, 0xae, 0xfc, 0x10, 0xbe, 0x3a, 0x20, 0x73, 0x4e, 0x65, 0x0e, 0x2d, 0x86, 0x77, 0x83, 0x9d, 0xe2, 0x0a, 0xe9, 0xac, 0x22, 0x52, 0x76, 0xd4, 0x6e, 0xfa, 0xe0, 0x09, 0xef, 0x78, 0x82, 0x9f, 0x26, 0xf9, 0x06, 0xb5, 0xe7, 0x05, 0x0e, 0xf2, 0x46, 0x72, 0x93, 0xd3, 0x24, 0xbd, 0x87, 0x60,
+ /* (2^298)P */ 0x14, 0x55, 0x84, 0x7b, 0x6c, 0x60, 0x80, 0x73, 0x8c, 0xbe, 0x2d, 0xd6, 0x69, 0xd6, 0x17, 0x26, 0x44, 0x9f, 0x88, 0xa2, 0x39, 0x7c, 0x89, 0xbc, 0x6d, 0x9e, 0x46, 0xb6, 0x68, 0x66, 0xea, 0xdc, 0x31, 0xd6, 0x21, 0x51, 0x9f, 0x28, 0x28, 0xaf, 0x9e, 0x47, 0x2c, 0x4c, 0x8f, 0xf3, 0xaf, 0x1f, 0xe4, 0xab, 0xac, 0xe9, 0x0c, 0x91, 0x3a, 0x61,
+ /* (2^299)P */ 0xb0, 0x37, 0x55, 0x4b, 0xe9, 0xc3, 0xb1, 0xce, 0x42, 0xe6, 0xc5, 0x11, 0x7f, 0x2c, 0x11, 0xfc, 0x4e, 0x71, 0x17, 0x00, 0x74, 0x7f, 0xbf, 0x07, 0x4d, 0xfd, 0x40, 0xb2, 0x87, 0xb0, 0xef, 0x1f, 0x35, 0x2c, 0x2d, 0xd7, 0xe1, 0xe4, 0xad, 0x0e, 0x7f, 0x63, 0x66, 0x62, 0x23, 0x41, 0xf6, 0xc1, 0x14, 0xa6, 0xd7, 0xa9, 0x11, 0x56, 0x9d, 0x1b,
+ /* (2^300)P */ 0x02, 0x82, 0x42, 0x18, 0x4f, 0x1b, 0xc9, 0x5d, 0x78, 0x5f, 0xee, 0xed, 0x01, 0x49, 0x8f, 0xf2, 0xa0, 0xe2, 0x6e, 0xbb, 0x6b, 0x04, 0x8d, 0xb2, 0x41, 0xae, 0xc8, 0x1b, 0x59, 0x34, 0xb8, 0x2a, 0xdb, 0x1f, 0xd2, 0x52, 0xdf, 0x3f, 0x35, 0x00, 0x8b, 0x61, 0xbc, 0x97, 0xa0, 0xc4, 0x77, 0xd1, 0xe4, 0x2c, 0x59, 0x68, 0xff, 0x30, 0xf2, 0xe2,
+ /* (2^301)P */ 0x79, 0x08, 0xb1, 0xdb, 0x55, 0xae, 0xd0, 0xed, 0xda, 0xa0, 0xec, 0x6c, 0xae, 0x68, 0xf2, 0x0b, 0x61, 0xb3, 0xf5, 0x21, 0x69, 0x87, 0x0b, 0x03, 0xea, 0x8a, 0x15, 0xd9, 0x7e, 0xca, 0xf7, 0xcd, 0xf3, 0x33, 0xb3, 0x4c, 0x5b, 0x23, 0x4e, 0x6f, 0x90, 0xad, 0x91, 0x4b, 0x4f, 0x46, 0x37, 0xe5, 0xe8, 0xb7, 0xeb, 0xd5, 0xca, 0x34, 0x4e, 0x23,
+ /* (2^302)P */ 0x09, 0x02, 0xdd, 0xfd, 0x70, 0xac, 0x56, 0x80, 0x36, 0x5e, 0x49, 0xd0, 0x3f, 0xc2, 0xe0, 0xba, 0x46, 0x7f, 0x5c, 0xf7, 0xc5, 0xbd, 0xd5, 0x55, 0x7d, 0x3f, 0xd5, 0x7d, 0x06, 0xdf, 0x27, 0x20, 0x4f, 0xe9, 0x30, 0xec, 0x1b, 0xa0, 0x0c, 0xd4, 0x2c, 0xe1, 0x2b, 0x65, 0x73, 0xea, 0x75, 0x35, 0xe8, 0xe6, 0x56, 0xd6, 0x07, 0x15, 0x99, 0xdf,
+ /* (2^303)P */ 0x4e, 0x10, 0xb7, 0xd0, 0x63, 0x8c, 0xcf, 0x16, 0x00, 0x7c, 0x58, 0xdf, 0x86, 0xdc, 0x4e, 0xca, 0x9c, 0x40, 0x5a, 0x42, 0xfd, 0xec, 0x98, 0xa4, 0x42, 0x53, 0xae, 0x16, 0x9d, 0xfd, 0x75, 0x5a, 0x12, 0x56, 0x1e, 0xc6, 0x57, 0xcc, 0x79, 0x27, 0x96, 0x00, 0xcf, 0x80, 0x4f, 0x8a, 0x36, 0x5c, 0xbb, 0xe9, 0x12, 0xdb, 0xb6, 0x2b, 0xad, 0x96,
+ /* (2^304)P */ 0x92, 0x32, 0x1f, 0xfd, 0xc6, 0x02, 0x94, 0x08, 0x1b, 0x60, 0x6a, 0x9f, 0x8b, 0xd6, 0xc8, 0xad, 0xd5, 0x1b, 0x27, 0x4e, 0xa4, 0x4d, 0x4a, 0x00, 0x10, 0x5f, 0x86, 0x11, 0xf5, 0xe3, 0x14, 0x32, 0x43, 0xee, 0xb9, 0xc7, 0xab, 0xf4, 0x6f, 0xe5, 0x66, 0x0c, 0x06, 0x0d, 0x96, 0x79, 0x28, 0xaf, 0x45, 0x2b, 0x56, 0xbe, 0xe4, 0x4a, 0x52, 0xd6,
+ /* (2^305)P */ 0x15, 0x16, 0x69, 0xef, 0x60, 0xca, 0x82, 0x25, 0x0f, 0xc6, 0x30, 0xa0, 0x0a, 0xd1, 0x83, 0x29, 0xcd, 0xb6, 0x89, 0x6c, 0xf5, 0xb2, 0x08, 0x38, 0xe6, 0xca, 0x6b, 0x19, 0x93, 0xc6, 0x5f, 0x75, 0x8e, 0x60, 0x34, 0x23, 0xc4, 0x13, 0x17, 0x69, 0x55, 0xcc, 0x72, 0x9c, 0x2b, 0x6c, 0x80, 0xf4, 0x4b, 0x8b, 0xb6, 0x97, 0x65, 0x07, 0xb6, 0xfb,
+ /* (2^306)P */ 0x01, 0x99, 0x74, 0x28, 0xa6, 0x67, 0xa3, 0xe5, 0x25, 0xfb, 0xdf, 0x82, 0x93, 0xe7, 0x35, 0x74, 0xce, 0xe3, 0x15, 0x1c, 0x1d, 0x79, 0x52, 0x84, 0x08, 0x04, 0x2f, 0x5c, 0xb8, 0xcd, 0x7f, 0x89, 0xb0, 0x39, 0x93, 0x63, 0xc9, 0x5d, 0x06, 0x01, 0x59, 0xf7, 0x7e, 0xf1, 0x4c, 0x3d, 0x12, 0x8d, 0x69, 0x1d, 0xb7, 0x21, 0x5e, 0x88, 0x82, 0xa2,
+ /* (2^307)P */ 0x8e, 0x69, 0xaf, 0x9a, 0x41, 0x0d, 0x9d, 0xcf, 0x8e, 0x8d, 0x5c, 0x51, 0x6e, 0xde, 0x0e, 0x48, 0x23, 0x89, 0xe5, 0x37, 0x80, 0xd6, 0x9d, 0x72, 0x32, 0x26, 0x38, 0x2d, 0x63, 0xa0, 0xfa, 0xd3, 0x40, 0xc0, 0x8c, 0x68, 0x6f, 0x2b, 0x1e, 0x9a, 0x39, 0x51, 0x78, 0x74, 0x9a, 0x7b, 0x4a, 0x8f, 0x0c, 0xa0, 0x88, 0x60, 0xa5, 0x21, 0xcd, 0xc7,
+ /* (2^308)P */ 0x3a, 0x7f, 0x73, 0x14, 0xbf, 0x89, 0x6a, 0x4c, 0x09, 0x5d, 0xf2, 0x93, 0x20, 0x2d, 0xc4, 0x29, 0x86, 0x06, 0x95, 0xab, 0x22, 0x76, 0x4c, 0x54, 0xe1, 0x7e, 0x80, 0x6d, 0xab, 0x29, 0x61, 0x87, 0x77, 0xf6, 0xc0, 0x3e, 0xda, 0xab, 0x65, 0x7e, 0x39, 0x12, 0xa1, 0x6b, 0x42, 0xf7, 0xc5, 0x97, 0x77, 0xec, 0x6f, 0x22, 0xbe, 0x44, 0xc7, 0x03,
+ /* (2^309)P */ 0xa5, 0x23, 0x90, 0x41, 0xa3, 0xc5, 0x3e, 0xe0, 0xa5, 0x32, 0x49, 0x1f, 0x39, 0x78, 0xb1, 0xd8, 0x24, 0xea, 0xd4, 0x87, 0x53, 0x42, 0x51, 0xf4, 0xd9, 0x46, 0x25, 0x2f, 0x62, 0xa9, 0x90, 0x9a, 0x4a, 0x25, 0x8a, 0xd2, 0x10, 0xe7, 0x3c, 0xbc, 0x58, 0x8d, 0x16, 0x14, 0x96, 0xa4, 0x6f, 0xf8, 0x12, 0x69, 0x91, 0x73, 0xe2, 0xfa, 0xf4, 0x57,
+ /* (2^310)P */ 0x51, 0x45, 0x3f, 0x96, 0xdc, 0x97, 0x38, 0xa6, 0x01, 0x63, 0x09, 0xea, 0xc2, 0x13, 0x30, 0xb0, 0x00, 0xb8, 0x0a, 0xce, 0xd1, 0x8f, 0x3e, 0x69, 0x62, 0x46, 0x33, 0x9c, 0xbf, 0x4b, 0xcb, 0x0c, 0x90, 0x1c, 0x45, 0xcf, 0x37, 0x5b, 0xf7, 0x4b, 0x5e, 0x95, 0xc3, 0x28, 0x9f, 0x08, 0x83, 0x53, 0x74, 0xab, 0x0c, 0xb4, 0xc0, 0xa1, 0xbc, 0x89,
+ /* (2^311)P */ 0x06, 0xb1, 0x51, 0x15, 0x65, 0x60, 0x21, 0x17, 0x7a, 0x20, 0x65, 0xee, 0x12, 0x35, 0x4d, 0x46, 0xf4, 0xf8, 0xd0, 0xb1, 0xca, 0x09, 0x30, 0x08, 0x89, 0x23, 0x3b, 0xe7, 0xab, 0x8b, 0x77, 0xa6, 0xad, 0x25, 0xdd, 0xea, 0x3c, 0x7d, 0xa5, 0x24, 0xb3, 0xe8, 0xfa, 0xfb, 0xc9, 0xf2, 0x71, 0xe9, 0xfa, 0xf2, 0xdc, 0x54, 0xdd, 0x55, 0x2e, 0x2f,
+ /* (2^312)P */ 0x7f, 0x96, 0x96, 0xfb, 0x52, 0x86, 0xcf, 0xea, 0x62, 0x18, 0xf1, 0x53, 0x1f, 0x61, 0x2a, 0x9f, 0x8c, 0x51, 0xca, 0x2c, 0xde, 0x6d, 0xce, 0xab, 0x58, 0x32, 0x0b, 0x33, 0x9b, 0x99, 0xb4, 0x5c, 0x88, 0x2a, 0x76, 0xcc, 0x3e, 0x54, 0x1e, 0x9d, 0xa2, 0x89, 0xe4, 0x19, 0xba, 0x80, 0xc8, 0x39, 0x32, 0x7f, 0x0f, 0xc7, 0x84, 0xbb, 0x43, 0x56,
+ /* (2^313)P */ 0x9b, 0x07, 0xb4, 0x42, 0xa9, 0xa0, 0x78, 0x4f, 0x28, 0x70, 0x2b, 0x7e, 0x61, 0xe0, 0xdd, 0x02, 0x98, 0xfc, 0xed, 0x31, 0x80, 0xf1, 0x15, 0x52, 0x89, 0x23, 0xcd, 0x5d, 0x2b, 0xc5, 0x19, 0x32, 0xfb, 0x70, 0x50, 0x7a, 0x97, 0x6b, 0x42, 0xdb, 0xca, 0xdb, 0xc4, 0x59, 0x99, 0xe0, 0x12, 0x1f, 0x17, 0xba, 0x8b, 0xf0, 0xc4, 0x38, 0x5d, 0x27,
+ /* (2^314)P */ 0x29, 0x1d, 0xdc, 0x2b, 0xf6, 0x5b, 0x04, 0x61, 0x36, 0x76, 0xa0, 0x56, 0x36, 0x6e, 0xd7, 0x24, 0x4d, 0xe7, 0xef, 0x44, 0xd2, 0xd5, 0x07, 0xcd, 0xc4, 0x9d, 0x80, 0x48, 0xc3, 0x38, 0xcf, 0xd8, 0xa3, 0xdd, 0xb2, 0x5e, 0xb5, 0x70, 0x15, 0xbb, 0x36, 0x85, 0x8a, 0xd7, 0xfb, 0x56, 0x94, 0x73, 0x9c, 0x81, 0xbe, 0xb1, 0x44, 0x28, 0xf1, 0x37,
+ /* (2^315)P */ 0xbf, 0xcf, 0x5c, 0xd2, 0xe2, 0xea, 0xc2, 0xcd, 0x70, 0x7a, 0x9d, 0xcb, 0x81, 0xc1, 0xe9, 0xf1, 0x56, 0x71, 0x52, 0xf7, 0x1b, 0x87, 0xc6, 0xd8, 0xcc, 0xb2, 0x69, 0xf3, 0xb0, 0xbd, 0xba, 0x83, 0x12, 0x26, 0xc4, 0xce, 0x72, 0xde, 0x3b, 0x21, 0x28, 0x9e, 0x5a, 0x94, 0xf5, 0x04, 0xa3, 0xc8, 0x0f, 0x5e, 0xbc, 0x71, 0xf9, 0x0d, 0xce, 0xf5,
+ /* (2^316)P */ 0x93, 0x97, 0x00, 0x85, 0xf4, 0xb4, 0x40, 0xec, 0xd9, 0x2b, 0x6c, 0xd6, 0x63, 0x9e, 0x93, 0x0a, 0x5a, 0xf4, 0xa7, 0x9a, 0xe3, 0x3c, 0xf0, 0x55, 0xd1, 0x96, 0x6c, 0xf5, 0x2a, 0xce, 0xd7, 0x95, 0x72, 0xbf, 0xc5, 0x0c, 0xce, 0x79, 0xa2, 0x0a, 0x78, 0xe0, 0x72, 0xd0, 0x66, 0x28, 0x05, 0x75, 0xd3, 0x23, 0x09, 0x91, 0xed, 0x7e, 0xc4, 0xbc,
+ /* (2^317)P */ 0x77, 0xc2, 0x9a, 0xf7, 0xa6, 0xe6, 0x18, 0xb4, 0xe7, 0xf6, 0xda, 0xec, 0x44, 0x6d, 0xfb, 0x08, 0xee, 0x65, 0xa8, 0x92, 0x85, 0x1f, 0xba, 0x38, 0x93, 0x20, 0x5c, 0x4d, 0xd2, 0x18, 0x0f, 0x24, 0xbe, 0x1a, 0x96, 0x44, 0x7d, 0xeb, 0xb3, 0xda, 0x95, 0xf4, 0xaf, 0x6c, 0x06, 0x0f, 0x47, 0x37, 0xc8, 0x77, 0x63, 0xe1, 0x29, 0xef, 0xff, 0xa5,
+ /* (2^318)P */ 0x16, 0x12, 0xd9, 0x47, 0x90, 0x22, 0x9b, 0x05, 0xf2, 0xa5, 0x9a, 0xae, 0x83, 0x98, 0xb5, 0xac, 0xab, 0x29, 0xaa, 0xdc, 0x5f, 0xde, 0xcd, 0xf7, 0x42, 0xad, 0x3b, 0x96, 0xd6, 0x3e, 0x6e, 0x52, 0x47, 0xb1, 0xab, 0x51, 0xde, 0x49, 0x7c, 0x87, 0x8d, 0x86, 0xe2, 0x70, 0x13, 0x21, 0x51, 0x1c, 0x0c, 0x25, 0xc1, 0xb0, 0xe6, 0x19, 0xcf, 0x12,
+ /* (2^319)P */ 0xf0, 0xbc, 0x97, 0x8f, 0x4b, 0x2f, 0xd1, 0x1f, 0x8c, 0x57, 0xed, 0x3c, 0xf4, 0x26, 0x19, 0xbb, 0x60, 0xca, 0x24, 0xc5, 0xd9, 0x97, 0xe2, 0x5f, 0x76, 0x49, 0x39, 0x7e, 0x2d, 0x12, 0x21, 0x98, 0xda, 0xe6, 0xdb, 0xd2, 0xd8, 0x9f, 0x18, 0xd8, 0x83, 0x6c, 0xba, 0x89, 0x8d, 0x29, 0xfa, 0x46, 0x33, 0x8c, 0x28, 0xdf, 0x6a, 0xb3, 0x69, 0x28,
+ /* (2^320)P */ 0x86, 0x17, 0xbc, 0xd6, 0x7c, 0xba, 0x1e, 0x83, 0xbb, 0x84, 0xb5, 0x8c, 0xad, 0xdf, 0xa1, 0x24, 0x81, 0x70, 0x40, 0x0f, 0xad, 0xad, 0x3b, 0x23, 0xd0, 0x93, 0xa0, 0x49, 0x5c, 0x4b, 0x51, 0xbe, 0x20, 0x49, 0x4e, 0xda, 0x2d, 0xd3, 0xad, 0x1b, 0x74, 0x08, 0x41, 0xf0, 0xef, 0x19, 0xe9, 0x45, 0x5d, 0x02, 0xae, 0x26, 0x25, 0xd9, 0xd1, 0xc2,
+ /* (2^321)P */ 0x48, 0x81, 0x3e, 0xb2, 0x83, 0xf8, 0x4d, 0xb3, 0xd0, 0x4c, 0x75, 0xb3, 0xa0, 0x52, 0x26, 0xf2, 0xaf, 0x5d, 0x36, 0x70, 0x72, 0xd6, 0xb7, 0x88, 0x08, 0x69, 0xbd, 0x15, 0x25, 0xb1, 0x45, 0x1b, 0xb7, 0x0b, 0x5f, 0x71, 0x5d, 0x83, 0x49, 0xb9, 0x84, 0x3b, 0x7c, 0xc1, 0x50, 0x93, 0x05, 0x53, 0xe0, 0x61, 0xea, 0xc1, 0xef, 0xdb, 0x82, 0x97,
+ /* (2^322)P */ 0x00, 0xd5, 0xc3, 0x3a, 0x4d, 0x8a, 0x23, 0x7a, 0xef, 0xff, 0x37, 0xef, 0xf3, 0xbc, 0xa9, 0xb6, 0xae, 0xd7, 0x3a, 0x7b, 0xfd, 0x3e, 0x8e, 0x9b, 0xab, 0x44, 0x54, 0x60, 0x28, 0x6c, 0xbf, 0x15, 0x24, 0x4a, 0x56, 0x60, 0x7f, 0xa9, 0x7a, 0x28, 0x59, 0x2c, 0x8a, 0xd1, 0x7d, 0x6b, 0x00, 0xfd, 0xa5, 0xad, 0xbc, 0x19, 0x3f, 0xcb, 0x73, 0xe0,
+ /* (2^323)P */ 0xcf, 0x9e, 0x66, 0x06, 0x4d, 0x2b, 0xf5, 0x9c, 0xc2, 0x9d, 0x9e, 0xed, 0x5a, 0x5c, 0x2d, 0x00, 0xbf, 0x29, 0x90, 0x88, 0xe4, 0x5d, 0xfd, 0xe2, 0xf0, 0x38, 0xec, 0x4d, 0x26, 0xea, 0x54, 0xf0, 0x3c, 0x84, 0x10, 0x6a, 0xf9, 0x66, 0x9c, 0xe7, 0x21, 0xfd, 0x0f, 0xc7, 0x13, 0x50, 0x81, 0xb6, 0x50, 0xf9, 0x04, 0x7f, 0xa4, 0x37, 0x85, 0x14,
+ /* (2^324)P */ 0xdb, 0x87, 0x49, 0xc7, 0xa8, 0x39, 0x0c, 0x32, 0x98, 0x0c, 0xb9, 0x1a, 0x1b, 0x4d, 0xe0, 0x8a, 0x9a, 0x8e, 0x8f, 0xab, 0x5a, 0x17, 0x3d, 0x04, 0x21, 0xce, 0x3e, 0x2c, 0xf9, 0xa3, 0x97, 0xe4, 0x77, 0x95, 0x0e, 0xb6, 0xa5, 0x15, 0xad, 0x3a, 0x1e, 0x46, 0x53, 0x17, 0x09, 0x83, 0x71, 0x4e, 0x86, 0x38, 0xd5, 0x23, 0x44, 0x16, 0x8d, 0xc8,
+ /* (2^325)P */ 0x05, 0x5e, 0x99, 0x08, 0xbb, 0xc3, 0xc0, 0xb7, 0x6c, 0x12, 0xf2, 0xf3, 0xf4, 0x7c, 0x6a, 0x4d, 0x9e, 0xeb, 0x3d, 0xb9, 0x63, 0x94, 0xce, 0x81, 0xd8, 0x11, 0xcb, 0x55, 0x69, 0x4a, 0x20, 0x0b, 0x4c, 0x2e, 0x14, 0xb8, 0xd4, 0x6a, 0x7c, 0xf0, 0xed, 0xfc, 0x8f, 0xef, 0xa0, 0xeb, 0x6c, 0x01, 0xe2, 0xdc, 0x10, 0x22, 0xa2, 0x01, 0x85, 0x64,
+ /* (2^326)P */ 0x58, 0xe1, 0x9c, 0x27, 0x55, 0xc6, 0x25, 0xa6, 0x7d, 0x67, 0x88, 0x65, 0x99, 0x6c, 0xcb, 0xdb, 0x27, 0x4f, 0x44, 0x29, 0xf5, 0x4a, 0x23, 0x10, 0xbc, 0x03, 0x3f, 0x36, 0x1e, 0xef, 0xb0, 0xba, 0x75, 0xe8, 0x74, 0x5f, 0x69, 0x3e, 0x26, 0x40, 0xb4, 0x2f, 0xdc, 0x43, 0xbf, 0xa1, 0x8b, 0xbd, 0xca, 0x6e, 0xc1, 0x6e, 0x21, 0x79, 0xa0, 0xd0,
+ /* (2^327)P */ 0x78, 0x93, 0x4a, 0x2d, 0x22, 0x6e, 0x6e, 0x7d, 0x74, 0xd2, 0x66, 0x58, 0xce, 0x7b, 0x1d, 0x97, 0xb1, 0xf2, 0xda, 0x1c, 0x79, 0xfb, 0xba, 0xd1, 0xc0, 0xc5, 0x6e, 0xc9, 0x11, 0x89, 0xd2, 0x41, 0x8d, 0x70, 0xb9, 0xcc, 0xea, 0x6a, 0xb3, 0x45, 0xb6, 0x05, 0x2e, 0xf2, 0x17, 0xf1, 0x27, 0xb8, 0xed, 0x06, 0x1f, 0xdb, 0x9d, 0x1f, 0x69, 0x28,
+ /* (2^328)P */ 0x93, 0x12, 0xa8, 0x11, 0xe1, 0x92, 0x30, 0x8d, 0xac, 0xe1, 0x1c, 0x60, 0x7c, 0xed, 0x2d, 0x2e, 0xd3, 0x03, 0x5c, 0x9c, 0xc5, 0xbd, 0x64, 0x4a, 0x8c, 0xba, 0x76, 0xfe, 0xc6, 0xc1, 0xea, 0xc2, 0x4f, 0xbe, 0x70, 0x3d, 0x64, 0xcf, 0x8e, 0x18, 0xcb, 0xcd, 0x57, 0xa7, 0xf7, 0x36, 0xa9, 0x6b, 0x3e, 0xb8, 0x69, 0xee, 0x47, 0xa2, 0x7e, 0xb2,
+ /* (2^329)P */ 0x96, 0xaf, 0x3a, 0xf5, 0xed, 0xcd, 0xaf, 0xf7, 0x82, 0xaf, 0x59, 0x62, 0x0b, 0x36, 0x85, 0xf9, 0xaf, 0xd6, 0x38, 0xff, 0x87, 0x2e, 0x1d, 0x6c, 0x8b, 0xaf, 0x3b, 0xdf, 0x28, 0xa2, 0xd6, 0x4d, 0x80, 0x92, 0xc3, 0x0f, 0x34, 0xa8, 0xae, 0x69, 0x5d, 0x7b, 0x9d, 0xbc, 0xf5, 0xfd, 0x1d, 0xb1, 0x96, 0x55, 0x86, 0xe1, 0x5c, 0xb6, 0xac, 0xb9,
+ /* (2^330)P */ 0x50, 0x9e, 0x37, 0x28, 0x7d, 0xa8, 0x33, 0x63, 0xda, 0x3f, 0x20, 0x98, 0x0e, 0x09, 0xa8, 0x77, 0x3b, 0x7a, 0xfc, 0x16, 0x85, 0x44, 0x64, 0x77, 0x65, 0x68, 0x92, 0x41, 0xc6, 0x1f, 0xdf, 0x27, 0xf9, 0xec, 0xa0, 0x61, 0x22, 0xea, 0x19, 0xe7, 0x75, 0x8b, 0x4e, 0xe5, 0x0f, 0xb7, 0xf7, 0xd2, 0x53, 0xf4, 0xdd, 0x4a, 0xaa, 0x78, 0x40, 0xb7,
+ /* (2^331)P */ 0xd4, 0x89, 0xe3, 0x79, 0xba, 0xb6, 0xc3, 0xda, 0xe6, 0x78, 0x65, 0x7d, 0x6e, 0x22, 0x62, 0xb1, 0x3d, 0xea, 0x90, 0x84, 0x30, 0x5e, 0xd4, 0x39, 0x84, 0x78, 0xd9, 0x75, 0xd6, 0xce, 0x2a, 0x11, 0x29, 0x69, 0xa4, 0x5e, 0xaa, 0x2a, 0x98, 0x5a, 0xe5, 0x91, 0x8f, 0xb2, 0xfb, 0xda, 0x97, 0xe8, 0x83, 0x6f, 0x04, 0xb9, 0x5d, 0xaf, 0xe1, 0x9b,
+ /* (2^332)P */ 0x8b, 0xe4, 0xe1, 0x48, 0x9c, 0xc4, 0x83, 0x89, 0xdf, 0x65, 0xd3, 0x35, 0x55, 0x13, 0xf4, 0x1f, 0x36, 0x92, 0x33, 0x38, 0xcb, 0xed, 0x15, 0xe6, 0x60, 0x2d, 0x25, 0xf5, 0x36, 0x60, 0x3a, 0x37, 0x9b, 0x71, 0x9d, 0x42, 0xb0, 0x14, 0xc8, 0xba, 0x62, 0xa3, 0x49, 0xb0, 0x88, 0xc1, 0x72, 0x73, 0xdd, 0x62, 0x40, 0xa9, 0x62, 0x88, 0x99, 0xca,
+ /* (2^333)P */ 0x47, 0x7b, 0xea, 0xda, 0x46, 0x2f, 0x45, 0xc6, 0xe3, 0xb4, 0x4d, 0x8d, 0xac, 0x0b, 0x54, 0x22, 0x06, 0x31, 0x16, 0x66, 0x3e, 0xe4, 0x38, 0x12, 0xcd, 0xf3, 0xe7, 0x99, 0x37, 0xd9, 0x62, 0x24, 0x4b, 0x05, 0xf2, 0x58, 0xe6, 0x29, 0x4b, 0x0d, 0xf6, 0xc1, 0xba, 0xa0, 0x1e, 0x0f, 0xcb, 0x1f, 0xc6, 0x2b, 0x19, 0xfc, 0x82, 0x01, 0xd0, 0x86,
+ /* (2^334)P */ 0xa2, 0xae, 0x77, 0x20, 0xfb, 0xa8, 0x18, 0xb4, 0x61, 0xef, 0xe8, 0x52, 0x79, 0xbb, 0x86, 0x90, 0x5d, 0x2e, 0x76, 0xed, 0x66, 0x60, 0x5d, 0x00, 0xb5, 0xa4, 0x00, 0x40, 0x89, 0xec, 0xd1, 0xd2, 0x0d, 0x26, 0xb9, 0x30, 0xb2, 0xd2, 0xb8, 0xe8, 0x0e, 0x56, 0xf9, 0x67, 0x94, 0x2e, 0x62, 0xe1, 0x79, 0x48, 0x2b, 0xa9, 0xfa, 0xea, 0xdb, 0x28,
+ /* (2^335)P */ 0x35, 0xf1, 0xb0, 0x43, 0xbd, 0x27, 0xef, 0x18, 0x44, 0xa2, 0x04, 0xb4, 0x69, 0xa1, 0x97, 0x1f, 0x8c, 0x04, 0x82, 0x9b, 0x00, 0x6d, 0xf8, 0xbf, 0x7d, 0xc1, 0x5b, 0xab, 0xe8, 0xb2, 0x34, 0xbd, 0xaf, 0x7f, 0xb2, 0x0d, 0xf3, 0xed, 0xfc, 0x5b, 0x50, 0xee, 0xe7, 0x4a, 0x20, 0xd9, 0xf5, 0xc6, 0x9a, 0x97, 0x6d, 0x07, 0x2f, 0xb9, 0x31, 0x02,
+ /* (2^336)P */ 0xf9, 0x54, 0x4a, 0xc5, 0x61, 0x7e, 0x1d, 0xa6, 0x0e, 0x1a, 0xa8, 0xd3, 0x8c, 0x36, 0x7d, 0xf1, 0x06, 0xb1, 0xac, 0x93, 0xcd, 0xe9, 0x8f, 0x61, 0x6c, 0x5d, 0x03, 0x23, 0xdf, 0x85, 0x53, 0x39, 0x63, 0x5e, 0xeb, 0xf3, 0xd3, 0xd3, 0x75, 0x97, 0x9b, 0x62, 0x9b, 0x01, 0xb3, 0x19, 0xd8, 0x2b, 0x36, 0xf2, 0x2c, 0x2c, 0x6f, 0x36, 0xc6, 0x3c,
+ /* (2^337)P */ 0x05, 0x74, 0x43, 0x10, 0xb6, 0xb0, 0xf8, 0xbf, 0x02, 0x46, 0x9a, 0xee, 0xc1, 0xaf, 0xc1, 0xe5, 0x5a, 0x2e, 0xbb, 0xe1, 0xdc, 0xc6, 0xce, 0x51, 0x29, 0x50, 0xbf, 0x1b, 0xde, 0xff, 0xba, 0x4d, 0x8d, 0x8b, 0x7e, 0xe7, 0xbd, 0x5b, 0x8f, 0xbe, 0xe3, 0x75, 0x71, 0xff, 0x37, 0x05, 0x5a, 0x10, 0xeb, 0x54, 0x7e, 0x44, 0x72, 0x2c, 0xd4, 0xfc,
+ /* (2^338)P */ 0x03, 0x12, 0x1c, 0xb2, 0x08, 0x90, 0xa1, 0x2d, 0x50, 0xa0, 0xad, 0x7f, 0x8d, 0xa6, 0x97, 0xc1, 0xbd, 0xdc, 0xc3, 0xa7, 0xad, 0x31, 0xdf, 0xb8, 0x03, 0x84, 0xc3, 0xb9, 0x29, 0x3d, 0x92, 0x2e, 0xc3, 0x90, 0x07, 0xe8, 0xa7, 0xc7, 0xbc, 0x61, 0xe9, 0x3e, 0xa0, 0x35, 0xda, 0x1d, 0xab, 0x48, 0xfe, 0x50, 0xc9, 0x25, 0x59, 0x23, 0x69, 0x3f,
+ /* (2^339)P */ 0x8e, 0x91, 0xab, 0x6b, 0x91, 0x4f, 0x89, 0x76, 0x67, 0xad, 0xb2, 0x65, 0x9d, 0xad, 0x02, 0x36, 0xdc, 0xac, 0x96, 0x93, 0x97, 0x21, 0x14, 0xd0, 0xe8, 0x11, 0x60, 0x1e, 0xeb, 0x96, 0x06, 0xf2, 0x53, 0xf2, 0x6d, 0xb7, 0x93, 0x6f, 0x26, 0x91, 0x23, 0xe3, 0x34, 0x04, 0x92, 0x91, 0x37, 0x08, 0x50, 0xd6, 0x28, 0x09, 0x27, 0xa1, 0x0c, 0x00,
+ /* (2^340)P */ 0x1f, 0xbb, 0x21, 0x26, 0x33, 0xcb, 0xa4, 0xd1, 0xee, 0x85, 0xf9, 0xd9, 0x3c, 0x90, 0xc3, 0xd1, 0x26, 0xa2, 0x25, 0x93, 0x43, 0x61, 0xed, 0x91, 0x6e, 0x54, 0x03, 0x2e, 0x42, 0x9d, 0xf7, 0xa6, 0x02, 0x0f, 0x2f, 0x9c, 0x7a, 0x8d, 0x12, 0xc2, 0x18, 0xfc, 0x41, 0xff, 0x85, 0x26, 0x1a, 0x44, 0x55, 0x0b, 0x89, 0xab, 0x6f, 0x62, 0x33, 0x8c,
+ /* (2^341)P */ 0xe0, 0x3c, 0x5d, 0x70, 0x64, 0x87, 0x81, 0x35, 0xf2, 0x37, 0xa6, 0x24, 0x3e, 0xe0, 0x62, 0xd5, 0x71, 0xe7, 0x93, 0xfb, 0xac, 0xc3, 0xe7, 0xc7, 0x04, 0xe2, 0x70, 0xd3, 0x29, 0x5b, 0x21, 0xbf, 0xf4, 0x26, 0x5d, 0xf3, 0x95, 0xb4, 0x2a, 0x6a, 0x07, 0x55, 0xa6, 0x4b, 0x3b, 0x15, 0xf2, 0x25, 0x8a, 0x95, 0x3f, 0x63, 0x2f, 0x7a, 0x23, 0x96,
+ /* (2^342)P */ 0x0d, 0x3d, 0xd9, 0x13, 0xa7, 0xb3, 0x5e, 0x67, 0xf7, 0x02, 0x23, 0xee, 0x84, 0xff, 0x99, 0xda, 0xb9, 0x53, 0xf8, 0xf0, 0x0e, 0x39, 0x2f, 0x3c, 0x64, 0x34, 0xe3, 0x09, 0xfd, 0x2b, 0x33, 0xc7, 0xfe, 0x62, 0x2b, 0x84, 0xdf, 0x2b, 0xd2, 0x7c, 0x26, 0x01, 0x70, 0x66, 0x5b, 0x85, 0xc2, 0xbe, 0x88, 0x37, 0xf1, 0x30, 0xac, 0xb8, 0x76, 0xa3,
+ /* (2^343)P */ 0x6e, 0x01, 0xf0, 0x55, 0x35, 0xe4, 0xbd, 0x43, 0x62, 0x9d, 0xd6, 0x11, 0xef, 0x6f, 0xb8, 0x8c, 0xaa, 0x98, 0x87, 0xc6, 0x6d, 0xc4, 0xcc, 0x74, 0x92, 0x53, 0x4a, 0xdf, 0xe4, 0x08, 0x89, 0x17, 0xd0, 0x0f, 0xf4, 0x00, 0x60, 0x78, 0x08, 0x44, 0xb5, 0xda, 0x18, 0xed, 0x98, 0xc8, 0x61, 0x3d, 0x39, 0xdb, 0xcf, 0x1d, 0x49, 0x40, 0x65, 0x75,
+ /* (2^344)P */ 0x8e, 0x10, 0xae, 0x5f, 0x06, 0xd2, 0x95, 0xfd, 0x20, 0x16, 0x49, 0x5b, 0x57, 0xbe, 0x22, 0x8b, 0x43, 0xfb, 0xe6, 0xcc, 0x26, 0xa5, 0x5d, 0xd3, 0x68, 0xc5, 0xf9, 0x5a, 0x86, 0x24, 0x87, 0x27, 0x05, 0xfd, 0xe2, 0xff, 0xb3, 0xa3, 0x7b, 0x37, 0x59, 0xc5, 0x4e, 0x14, 0x94, 0xf9, 0x3b, 0xcb, 0x7c, 0xed, 0xca, 0x1d, 0xb2, 0xac, 0x05, 0x4a,
+ /* (2^345)P */ 0xf4, 0xd1, 0x81, 0xeb, 0x89, 0xbf, 0xfe, 0x1e, 0x41, 0x92, 0x29, 0xee, 0xe1, 0x43, 0xf5, 0x86, 0x1d, 0x2f, 0xbb, 0x1e, 0x84, 0x5d, 0x7b, 0x8d, 0xd5, 0xda, 0xee, 0x1e, 0x8a, 0xd0, 0x27, 0xf2, 0x60, 0x51, 0x59, 0x82, 0xf4, 0x84, 0x2b, 0x5b, 0x14, 0x2d, 0x81, 0x82, 0x3e, 0x2b, 0xb4, 0x6d, 0x51, 0x4f, 0xc5, 0xcb, 0xbf, 0x74, 0xe3, 0xb4,
+ /* (2^346)P */ 0x19, 0x2f, 0x22, 0xb3, 0x04, 0x5f, 0x81, 0xca, 0x05, 0x60, 0xb9, 0xaa, 0xee, 0x0e, 0x2f, 0x48, 0x38, 0xf9, 0x91, 0xb4, 0x66, 0xe4, 0x57, 0x28, 0x54, 0x10, 0xe9, 0x61, 0x9d, 0xd4, 0x90, 0x75, 0xb1, 0x39, 0x23, 0xb6, 0xfc, 0x82, 0xe0, 0xfa, 0xbb, 0x5c, 0x6e, 0xc3, 0x44, 0x13, 0x00, 0x83, 0x55, 0x9e, 0x8e, 0x10, 0x61, 0x81, 0x91, 0x04,
+ /* (2^347)P */ 0x5f, 0x2a, 0xd7, 0x81, 0xd9, 0x9c, 0xbb, 0x79, 0xbc, 0x62, 0x56, 0x98, 0x03, 0x5a, 0x18, 0x85, 0x2a, 0x9c, 0xd0, 0xfb, 0xd2, 0xb1, 0xaf, 0xef, 0x0d, 0x24, 0xc5, 0xfa, 0x39, 0xbb, 0x6b, 0xed, 0xa4, 0xdf, 0xe4, 0x87, 0xcd, 0x41, 0xd3, 0x72, 0x32, 0xc6, 0x28, 0x21, 0xb1, 0xba, 0x8b, 0xa3, 0x91, 0x79, 0x76, 0x22, 0x25, 0x10, 0x61, 0xd1,
+ /* (2^348)P */ 0x73, 0xb5, 0x32, 0x97, 0xdd, 0xeb, 0xdd, 0x22, 0x22, 0xf1, 0x33, 0x3c, 0x77, 0x56, 0x7d, 0x6b, 0x48, 0x2b, 0x05, 0x81, 0x03, 0x03, 0x91, 0x9a, 0xe3, 0x5e, 0xd4, 0xee, 0x3f, 0xf8, 0xbb, 0x50, 0x21, 0x32, 0x4c, 0x4a, 0x58, 0x49, 0xde, 0x0c, 0xde, 0x30, 0x82, 0x3d, 0x92, 0xf0, 0x6c, 0xcc, 0x32, 0x3e, 0xd2, 0x78, 0x8a, 0x6e, 0x2c, 0xd0,
+ /* (2^349)P */ 0xf0, 0xf7, 0xa1, 0x0b, 0xc1, 0x74, 0x85, 0xa8, 0xe9, 0xdd, 0x48, 0xa1, 0xc0, 0x16, 0xd8, 0x2b, 0x61, 0x08, 0xc2, 0x2b, 0x30, 0x26, 0x79, 0xce, 0x9e, 0xfd, 0x39, 0xd7, 0x81, 0xa4, 0x63, 0x8c, 0xd5, 0x74, 0xa0, 0x88, 0xfa, 0x03, 0x30, 0xe9, 0x7f, 0x2b, 0xc6, 0x02, 0xc9, 0x5e, 0xe4, 0xd5, 0x4d, 0x92, 0xd0, 0xf6, 0xf2, 0x5b, 0x79, 0x08,
+ /* (2^350)P */ 0x34, 0x89, 0x81, 0x43, 0xd1, 0x94, 0x2c, 0x10, 0x54, 0x9b, 0xa0, 0xe5, 0x44, 0xe8, 0xc2, 0x2f, 0x3e, 0x0e, 0x74, 0xae, 0xba, 0xe2, 0xac, 0x85, 0x6b, 0xd3, 0x5c, 0x97, 0xf7, 0x90, 0xf1, 0x12, 0xc0, 0x03, 0xc8, 0x1f, 0x37, 0x72, 0x8c, 0x9b, 0x9c, 0x17, 0x96, 0x9d, 0xc7, 0xbf, 0xa3, 0x3f, 0x44, 0x3d, 0x87, 0x81, 0xbd, 0x81, 0xa6, 0x5f,
+ /* (2^351)P */ 0xe4, 0xff, 0x78, 0x62, 0x82, 0x5b, 0x76, 0x58, 0xf5, 0x5b, 0xa6, 0xc4, 0x53, 0x11, 0x3b, 0x7b, 0xaa, 0x67, 0xf8, 0xea, 0x3b, 0x5d, 0x9a, 0x2e, 0x04, 0xeb, 0x4a, 0x24, 0xfb, 0x56, 0xf0, 0xa8, 0xd4, 0x14, 0xed, 0x0f, 0xfd, 0xc5, 0x26, 0x17, 0x2a, 0xf0, 0xb9, 0x13, 0x8c, 0xbd, 0x65, 0x14, 0x24, 0x95, 0x27, 0x12, 0x63, 0x2a, 0x09, 0x18,
+ /* (2^352)P */ 0xe1, 0x5c, 0xe7, 0xe0, 0x00, 0x6a, 0x96, 0xf2, 0x49, 0x6a, 0x39, 0xa5, 0xe0, 0x17, 0x79, 0x4a, 0x63, 0x07, 0x62, 0x09, 0x61, 0x1b, 0x6e, 0xa9, 0xb5, 0x62, 0xb7, 0xde, 0xdf, 0x80, 0x4c, 0x5a, 0x99, 0x73, 0x59, 0x9d, 0xfb, 0xb1, 0x5e, 0xbe, 0xb8, 0xb7, 0x63, 0x93, 0xe8, 0xad, 0x5e, 0x1f, 0xae, 0x59, 0x1c, 0xcd, 0xb4, 0xc2, 0xb3, 0x8a,
+ /* (2^353)P */ 0x78, 0x53, 0xa1, 0x4c, 0x70, 0x9c, 0x63, 0x7e, 0xb3, 0x12, 0x40, 0x5f, 0xbb, 0x23, 0xa7, 0xf7, 0x77, 0x96, 0x5b, 0x4d, 0x91, 0x10, 0x52, 0x85, 0x9e, 0xa5, 0x38, 0x0b, 0xfd, 0x25, 0x01, 0x4b, 0xfa, 0x4d, 0xd3, 0x3f, 0x78, 0x74, 0x42, 0xff, 0x62, 0x2d, 0x27, 0xdc, 0x9d, 0xd1, 0x29, 0x76, 0x2e, 0x78, 0xb3, 0x35, 0xfa, 0x15, 0xd5, 0x38,
+ /* (2^354)P */ 0x8b, 0xc7, 0x43, 0xce, 0xf0, 0x5e, 0xf1, 0x0d, 0x02, 0x38, 0xe8, 0x82, 0xc9, 0x25, 0xad, 0x2d, 0x27, 0xa4, 0x54, 0x18, 0xb2, 0x30, 0x73, 0xa4, 0x41, 0x08, 0xe4, 0x86, 0xe6, 0x8c, 0xe9, 0x2a, 0x34, 0xb3, 0xd6, 0x61, 0x8f, 0x66, 0x26, 0x08, 0xb6, 0x06, 0x33, 0xaa, 0x12, 0xac, 0x72, 0xec, 0x2e, 0x52, 0xa3, 0x25, 0x3e, 0xd7, 0x62, 0xe8,
+ /* (2^355)P */ 0xc4, 0xbb, 0x89, 0xc8, 0x40, 0xcc, 0x84, 0xec, 0x4a, 0xd9, 0xc4, 0x55, 0x78, 0x00, 0xcf, 0xd8, 0xe9, 0x24, 0x59, 0xdc, 0x5e, 0xf0, 0x66, 0xa1, 0x83, 0xae, 0x97, 0x18, 0xc5, 0x54, 0x27, 0xa2, 0x21, 0x52, 0x03, 0x31, 0x5b, 0x11, 0x67, 0xf6, 0x12, 0x00, 0x87, 0x2f, 0xff, 0x59, 0x70, 0x8f, 0x6d, 0x71, 0xab, 0xab, 0x24, 0xb8, 0xba, 0x35,
+ /* (2^356)P */ 0x69, 0x43, 0xa7, 0x14, 0x06, 0x96, 0xe9, 0xc2, 0xe3, 0x2b, 0x45, 0x22, 0xc0, 0xd0, 0x2f, 0x34, 0xd1, 0x01, 0x99, 0xfc, 0x99, 0x38, 0xa1, 0x25, 0x2e, 0x59, 0x6c, 0x27, 0xc9, 0xeb, 0x7b, 0xdc, 0x4e, 0x26, 0x68, 0xba, 0xfa, 0xec, 0x02, 0x05, 0x64, 0x80, 0x30, 0x20, 0x5c, 0x26, 0x7f, 0xaf, 0x95, 0x17, 0x3d, 0x5c, 0x9e, 0x96, 0x96, 0xaf,
+ /* (2^357)P */ 0xa6, 0xba, 0x21, 0x29, 0x32, 0xe2, 0x98, 0xde, 0x9b, 0x6d, 0x0b, 0x44, 0x91, 0xa8, 0x3e, 0xd4, 0xb8, 0x04, 0x6c, 0xf6, 0x04, 0x39, 0xbd, 0x52, 0x05, 0x15, 0x27, 0x78, 0x8e, 0x55, 0xac, 0x79, 0xc5, 0xe6, 0x00, 0x7f, 0x90, 0xa2, 0xdd, 0x07, 0x13, 0xe0, 0x24, 0x70, 0x5c, 0x0f, 0x4d, 0xa9, 0xf9, 0xae, 0xcb, 0x34, 0x10, 0x9d, 0x89, 0x9d,
+ /* (2^358)P */ 0x12, 0xe0, 0xb3, 0x9f, 0xc4, 0x96, 0x1d, 0xcf, 0xed, 0x99, 0x64, 0x28, 0x8d, 0xc7, 0x31, 0x82, 0xee, 0x5e, 0x75, 0x48, 0xff, 0x3a, 0xf2, 0x09, 0x34, 0x03, 0x93, 0x52, 0x19, 0xb2, 0xc5, 0x81, 0x93, 0x45, 0x5e, 0x59, 0x21, 0x2b, 0xec, 0x89, 0xba, 0x36, 0x6e, 0xf9, 0x82, 0x75, 0x7e, 0x82, 0x3f, 0xaa, 0xe2, 0xe3, 0x3b, 0x94, 0xfd, 0x98,
+ /* (2^359)P */ 0x7c, 0xdb, 0x75, 0x31, 0x61, 0xfb, 0x15, 0x28, 0x94, 0xd7, 0xc3, 0x5a, 0xa9, 0xa1, 0x0a, 0x66, 0x0f, 0x2b, 0x13, 0x3e, 0x42, 0xb5, 0x28, 0x3a, 0xca, 0x83, 0xf3, 0x61, 0x22, 0xf4, 0x40, 0xc5, 0xdf, 0xe7, 0x31, 0x9f, 0x7e, 0x51, 0x75, 0x06, 0x9d, 0x51, 0xc8, 0xe7, 0x9f, 0xc3, 0x71, 0x4f, 0x3d, 0x5b, 0xfb, 0xe9, 0x8e, 0x08, 0x40, 0x8e,
+ /* (2^360)P */ 0xf7, 0x31, 0xad, 0x50, 0x5d, 0x25, 0x93, 0x73, 0x68, 0xf6, 0x7c, 0x89, 0x5a, 0x3d, 0x9f, 0x9b, 0x05, 0x82, 0xe7, 0x70, 0x4b, 0x19, 0xaa, 0xcf, 0xff, 0xde, 0x50, 0x8f, 0x2f, 0x69, 0xd3, 0xf0, 0x99, 0x51, 0x6b, 0x9d, 0xb6, 0x56, 0x6f, 0xf8, 0x4c, 0x74, 0x8b, 0x4c, 0x91, 0xf9, 0xa9, 0xb1, 0x3e, 0x07, 0xdf, 0x0b, 0x27, 0x8a, 0xb1, 0xed,
+ /* (2^361)P */ 0xfb, 0x67, 0xd9, 0x48, 0xd2, 0xe4, 0x44, 0x9b, 0x43, 0x15, 0x8a, 0xeb, 0x00, 0x53, 0xad, 0x25, 0xc7, 0x7e, 0x19, 0x30, 0x87, 0xb7, 0xd5, 0x5f, 0x04, 0xf8, 0xaa, 0xdd, 0x57, 0xae, 0x34, 0x75, 0xe2, 0x84, 0x4b, 0x54, 0x60, 0x37, 0x95, 0xe4, 0xd3, 0xec, 0xac, 0xef, 0x47, 0x31, 0xa3, 0xc8, 0x31, 0x22, 0xdb, 0x26, 0xe7, 0x6a, 0xb5, 0xad,
+ /* (2^362)P */ 0x44, 0x09, 0x5c, 0x95, 0xe4, 0x72, 0x3c, 0x1a, 0xd1, 0xac, 0x42, 0x51, 0x99, 0x6f, 0xfa, 0x1f, 0xf2, 0x22, 0xbe, 0xff, 0x7b, 0x66, 0xf5, 0x6c, 0xb3, 0x66, 0xc7, 0x4d, 0x78, 0x31, 0x83, 0x80, 0xf5, 0x41, 0xe9, 0x7f, 0xbe, 0xf7, 0x23, 0x49, 0x6b, 0x84, 0x4e, 0x7e, 0x47, 0x07, 0x6e, 0x74, 0xdf, 0xe5, 0x9d, 0x9e, 0x56, 0x2a, 0xc0, 0xbc,
+ /* (2^363)P */ 0xac, 0x10, 0x80, 0x8c, 0x7c, 0xfa, 0x83, 0xdf, 0xb3, 0xd0, 0xc4, 0xbe, 0xfb, 0x9f, 0xac, 0xc9, 0xc3, 0x40, 0x95, 0x0b, 0x09, 0x23, 0xda, 0x63, 0x67, 0xcf, 0xe7, 0x9f, 0x7d, 0x7b, 0x6b, 0xe2, 0xe6, 0x6d, 0xdb, 0x87, 0x9e, 0xa6, 0xff, 0x6d, 0xab, 0xbd, 0xfb, 0x54, 0x84, 0x68, 0xcf, 0x89, 0xf1, 0xd0, 0xe2, 0x85, 0x61, 0xdc, 0x22, 0xd1,
+ /* (2^364)P */ 0xa8, 0x48, 0xfb, 0x8c, 0x6a, 0x63, 0x01, 0x72, 0x43, 0x43, 0xeb, 0x21, 0xa3, 0x00, 0x8a, 0xc0, 0x87, 0x51, 0x9e, 0x86, 0x75, 0x16, 0x79, 0xf9, 0x6b, 0x11, 0x80, 0x62, 0xc2, 0x9d, 0xb8, 0x8c, 0x30, 0x8e, 0x8d, 0x03, 0x52, 0x7e, 0x31, 0x59, 0x38, 0xf9, 0x25, 0xc7, 0x0f, 0xc7, 0xa8, 0x2b, 0x5c, 0x80, 0xfa, 0x90, 0xa2, 0x63, 0xca, 0xe7,
+ /* (2^365)P */ 0xf1, 0x5d, 0xb5, 0xd9, 0x20, 0x10, 0x7d, 0x0f, 0xc5, 0x50, 0x46, 0x07, 0xff, 0x02, 0x75, 0x2b, 0x4a, 0xf3, 0x39, 0x91, 0x72, 0xb7, 0xd5, 0xcc, 0x38, 0xb8, 0xe7, 0x36, 0x26, 0x5e, 0x11, 0x97, 0x25, 0xfb, 0x49, 0x68, 0xdc, 0xb4, 0x46, 0x87, 0x5c, 0xc2, 0x7f, 0xaa, 0x7d, 0x36, 0x23, 0xa6, 0xc6, 0x53, 0xec, 0xbc, 0x57, 0x47, 0xc1, 0x2b,
+ /* (2^366)P */ 0x25, 0x5d, 0x7d, 0x95, 0xda, 0x0b, 0x8f, 0x78, 0x1e, 0x19, 0x09, 0xfa, 0x67, 0xe0, 0xa0, 0x17, 0x24, 0x76, 0x6c, 0x30, 0x1f, 0x62, 0x3d, 0xbe, 0x45, 0x70, 0xcc, 0xb6, 0x1e, 0x68, 0x06, 0x25, 0x68, 0x16, 0x1a, 0x33, 0x3f, 0x90, 0xc7, 0x78, 0x2d, 0x98, 0x3c, 0x2f, 0xb9, 0x2d, 0x94, 0x0b, 0xfb, 0x49, 0x56, 0x30, 0xd7, 0xc1, 0xe6, 0x48,
+ /* (2^367)P */ 0x7a, 0xd1, 0xe0, 0x8e, 0x67, 0xfc, 0x0b, 0x50, 0x1f, 0x84, 0x98, 0xfa, 0xaf, 0xae, 0x2e, 0x31, 0x27, 0xcf, 0x3f, 0xf2, 0x6e, 0x8d, 0x81, 0x8f, 0xd2, 0x5f, 0xde, 0xd3, 0x5e, 0xe9, 0xe7, 0x13, 0x48, 0x83, 0x5a, 0x4e, 0x84, 0xd1, 0x58, 0xcf, 0x6b, 0x84, 0xdf, 0x13, 0x1d, 0x91, 0x85, 0xe8, 0xcb, 0x29, 0x79, 0xd2, 0xca, 0xac, 0x6a, 0x93,
+ /* (2^368)P */ 0x53, 0x82, 0xce, 0x61, 0x96, 0x88, 0x6f, 0xe1, 0x4a, 0x4c, 0x1e, 0x30, 0x73, 0xe8, 0x74, 0xde, 0x40, 0x2b, 0xe0, 0xc4, 0xb5, 0xd8, 0x7c, 0x15, 0xe7, 0xe1, 0xb1, 0xe0, 0xd6, 0x88, 0xb1, 0x6a, 0x57, 0x19, 0x6a, 0x22, 0x66, 0x57, 0xf6, 0x8d, 0xfd, 0xc0, 0xf2, 0xa3, 0x03, 0x56, 0xfb, 0x2e, 0x75, 0x5e, 0xc7, 0x8e, 0x22, 0x96, 0x5c, 0x06,
+ /* (2^369)P */ 0x98, 0x7e, 0xbf, 0x3e, 0xbf, 0x24, 0x9d, 0x15, 0xd3, 0xf6, 0xd3, 0xd2, 0xf0, 0x11, 0xf2, 0xdb, 0x36, 0x23, 0x38, 0xf7, 0x1d, 0x71, 0x20, 0xd2, 0x54, 0x7f, 0x1e, 0x24, 0x8f, 0xe2, 0xaa, 0xf7, 0x3f, 0x6b, 0x41, 0x4e, 0xdc, 0x0e, 0xec, 0xe8, 0x35, 0x0a, 0x08, 0x6d, 0x89, 0x5b, 0x32, 0x91, 0x01, 0xb6, 0xe0, 0x2c, 0xc6, 0xa1, 0xbe, 0xb4,
+ /* (2^370)P */ 0x29, 0xf2, 0x1e, 0x1c, 0xdc, 0x68, 0x8a, 0x43, 0x87, 0x2c, 0x48, 0xb3, 0x9e, 0xed, 0xd2, 0x82, 0x46, 0xac, 0x2f, 0xef, 0x93, 0x34, 0x37, 0xca, 0x64, 0x8d, 0xc9, 0x06, 0x90, 0xbb, 0x78, 0x0a, 0x3c, 0x4c, 0xcf, 0x35, 0x7a, 0x0f, 0xf7, 0xa7, 0xf4, 0x2f, 0x45, 0x69, 0x3f, 0xa9, 0x5d, 0xce, 0x7b, 0x8a, 0x84, 0xc3, 0xae, 0xf4, 0xda, 0xd5,
+ /* (2^371)P */ 0xca, 0xba, 0x95, 0x43, 0x05, 0x7b, 0x06, 0xd9, 0x5c, 0x0a, 0x18, 0x5f, 0x6a, 0x6a, 0xce, 0xc0, 0x3d, 0x95, 0x51, 0x0e, 0x1a, 0xbe, 0x85, 0x7a, 0xf2, 0x69, 0xec, 0xc0, 0x8c, 0xca, 0xa3, 0x32, 0x0a, 0x76, 0x50, 0xc6, 0x76, 0x61, 0x00, 0x89, 0xbf, 0x6e, 0x0f, 0x48, 0x90, 0x31, 0x93, 0xec, 0x34, 0x70, 0xf0, 0xc3, 0x8d, 0xf0, 0x0f, 0xb5,
+ /* (2^372)P */ 0xbe, 0x23, 0xe2, 0x18, 0x99, 0xf1, 0xed, 0x8a, 0xf6, 0xc9, 0xac, 0xb8, 0x1e, 0x9a, 0x3c, 0x15, 0xae, 0xd7, 0x6d, 0xb3, 0x04, 0xee, 0x5b, 0x0d, 0x1e, 0x79, 0xb7, 0xf9, 0xf9, 0x8d, 0xad, 0xf9, 0x8f, 0x5a, 0x6a, 0x7b, 0xd7, 0x9b, 0xca, 0x62, 0xfe, 0x9c, 0xc0, 0x6f, 0x6d, 0x9d, 0x76, 0xa3, 0x69, 0xb9, 0x4c, 0xa1, 0xc4, 0x0c, 0x76, 0xaa,
+ /* (2^373)P */ 0x1c, 0x06, 0xfe, 0x3f, 0x45, 0x70, 0xcd, 0x97, 0xa9, 0xa2, 0xb1, 0xd3, 0xf2, 0xa5, 0x0c, 0x49, 0x2c, 0x75, 0x73, 0x1f, 0xcf, 0x00, 0xaf, 0xd5, 0x2e, 0xde, 0x0d, 0x8f, 0x8f, 0x7c, 0xc4, 0x58, 0xce, 0xd4, 0xf6, 0x24, 0x19, 0x2e, 0xd8, 0xc5, 0x1d, 0x1a, 0x3f, 0xb8, 0x4f, 0xbc, 0x7d, 0xbd, 0x68, 0xe3, 0x81, 0x98, 0x1b, 0xa8, 0xc9, 0xd9,
+ /* (2^374)P */ 0x39, 0x95, 0x78, 0x24, 0x6c, 0x38, 0xe4, 0xe7, 0xd0, 0x8d, 0xb9, 0x38, 0x71, 0x5e, 0xc1, 0x62, 0x80, 0xcc, 0xcb, 0x8c, 0x97, 0xca, 0xf8, 0xb9, 0xd9, 0x9c, 0xce, 0x72, 0x7b, 0x70, 0xee, 0x5f, 0xea, 0xa2, 0xdf, 0xa9, 0x14, 0x10, 0xf9, 0x6e, 0x59, 0x9f, 0x9c, 0xe0, 0x0c, 0xb2, 0x07, 0x97, 0xcd, 0xd2, 0x89, 0x16, 0xfd, 0x9c, 0xa8, 0xa5,
+ /* (2^375)P */ 0x5a, 0x61, 0xf1, 0x59, 0x7c, 0x38, 0xda, 0xe2, 0x85, 0x99, 0x68, 0xe9, 0xc9, 0xf7, 0x32, 0x7e, 0xc4, 0xca, 0xb7, 0x11, 0x08, 0x69, 0x2b, 0x66, 0x02, 0xf7, 0x2e, 0x18, 0xc3, 0x8e, 0xe1, 0xf9, 0xc5, 0x19, 0x9a, 0x0a, 0x9c, 0x07, 0xba, 0xc7, 0x9c, 0x03, 0x34, 0x89, 0x99, 0x67, 0x0b, 0x16, 0x4b, 0x07, 0x36, 0x16, 0x36, 0x2c, 0xe2, 0xa1,
+ /* (2^376)P */ 0x70, 0x10, 0x91, 0x27, 0xa8, 0x24, 0x8e, 0x29, 0x04, 0x6f, 0x79, 0x1f, 0xd3, 0xa5, 0x68, 0xd3, 0x0b, 0x7d, 0x56, 0x4d, 0x14, 0x57, 0x7b, 0x2e, 0x00, 0x9f, 0x9a, 0xfd, 0x6c, 0x63, 0x18, 0x81, 0xdb, 0x9d, 0xb7, 0xd7, 0xa4, 0x1e, 0xe8, 0x40, 0xf1, 0x4c, 0xa3, 0x01, 0xd5, 0x4b, 0x75, 0xea, 0xdd, 0x97, 0xfd, 0x5b, 0xb2, 0x66, 0x6a, 0x24,
+ /* (2^377)P */ 0x72, 0x11, 0xfe, 0x73, 0x1b, 0xd3, 0xea, 0x7f, 0x93, 0x15, 0x15, 0x05, 0xfe, 0x40, 0xe8, 0x28, 0xd8, 0x50, 0x47, 0x66, 0xfa, 0xb7, 0xb5, 0x04, 0xba, 0x35, 0x1e, 0x32, 0x9f, 0x5f, 0x32, 0xba, 0x3d, 0xd1, 0xed, 0x9a, 0x76, 0xca, 0xa3, 0x3e, 0x77, 0xd8, 0xd8, 0x7c, 0x5f, 0x68, 0x42, 0xb5, 0x86, 0x7f, 0x3b, 0xc9, 0xc1, 0x89, 0x64, 0xda,
+ /* (2^378)P */ 0xd5, 0xd4, 0x17, 0x31, 0xfc, 0x6a, 0xfd, 0xb8, 0xe8, 0xe5, 0x3e, 0x39, 0x06, 0xe4, 0xd1, 0x90, 0x2a, 0xca, 0xf6, 0x54, 0x6c, 0x1b, 0x2f, 0x49, 0x97, 0xb1, 0x2a, 0x82, 0x43, 0x3d, 0x1f, 0x8b, 0xe2, 0x47, 0xc5, 0x24, 0xa8, 0xd5, 0x53, 0x29, 0x7d, 0xc6, 0x87, 0xa6, 0x25, 0x3a, 0x64, 0xdd, 0x71, 0x08, 0x9e, 0xcd, 0xe9, 0x45, 0xc7, 0xba,
+ /* (2^379)P */ 0x37, 0x72, 0x6d, 0x13, 0x7a, 0x8d, 0x04, 0x31, 0xe6, 0xe3, 0x9e, 0x36, 0x71, 0x3e, 0xc0, 0x1e, 0xe3, 0x71, 0xd3, 0x49, 0x4e, 0x4a, 0x36, 0x42, 0x68, 0x68, 0x61, 0xc7, 0x3c, 0xdb, 0x81, 0x49, 0xf7, 0x91, 0x4d, 0xea, 0x4c, 0x4f, 0x98, 0xc6, 0x7e, 0x60, 0x84, 0x4b, 0x6a, 0x37, 0xbb, 0x52, 0xf7, 0xce, 0x02, 0xe4, 0xad, 0xd1, 0x3c, 0xa7,
+ /* (2^380)P */ 0x51, 0x06, 0x2d, 0xf8, 0x08, 0xe8, 0xf1, 0x0c, 0xe5, 0xa9, 0xac, 0x29, 0x73, 0x3b, 0xed, 0x98, 0x5f, 0x55, 0x08, 0x38, 0x51, 0x44, 0x36, 0x5d, 0xea, 0xc3, 0xb8, 0x0e, 0xa0, 0x4f, 0xd2, 0x79, 0xe9, 0x98, 0xc3, 0xf5, 0x00, 0xb9, 0x26, 0x27, 0x42, 0xa8, 0x07, 0xc1, 0x12, 0x31, 0xc1, 0xc3, 0x3c, 0x3b, 0x7a, 0x72, 0x97, 0xc2, 0x70, 0x3a,
+ /* (2^381)P */ 0xf4, 0xb2, 0xba, 0x32, 0xbc, 0xa9, 0x2f, 0x87, 0xc7, 0x3c, 0x45, 0xcd, 0xae, 0xe2, 0x13, 0x6d, 0x3a, 0xf2, 0xf5, 0x66, 0x97, 0x29, 0xaf, 0x53, 0x9f, 0xda, 0xea, 0x14, 0xdf, 0x04, 0x98, 0x19, 0x95, 0x9e, 0x2a, 0x00, 0x5c, 0x9d, 0x1d, 0xf0, 0x39, 0x23, 0xff, 0xfc, 0xca, 0x36, 0xb7, 0xde, 0xdf, 0x37, 0x78, 0x52, 0x21, 0xfa, 0x19, 0x10,
+ /* (2^382)P */ 0x50, 0x20, 0x73, 0x74, 0x62, 0x21, 0xf2, 0xf7, 0x9b, 0x66, 0x85, 0x34, 0x74, 0xd4, 0x9d, 0x60, 0xd7, 0xbc, 0xc8, 0x46, 0x3b, 0xb8, 0x80, 0x42, 0x15, 0x0a, 0x6c, 0x35, 0x1a, 0x69, 0xf0, 0x1d, 0x4b, 0x29, 0x54, 0x5a, 0x9a, 0x48, 0xec, 0x9f, 0x37, 0x74, 0x91, 0xd0, 0xd1, 0x9e, 0x00, 0xc2, 0x76, 0x56, 0xd6, 0xa0, 0x15, 0x14, 0x83, 0x59,
+ /* (2^383)P */ 0xc2, 0xf8, 0x22, 0x20, 0x23, 0x07, 0xbd, 0x1d, 0x6f, 0x1e, 0x8c, 0x56, 0x06, 0x6a, 0x4b, 0x9f, 0xe2, 0xa9, 0x92, 0x46, 0x4b, 0x46, 0x59, 0xd7, 0xe1, 0xda, 0x14, 0x98, 0x07, 0x65, 0x7e, 0x28, 0x20, 0xf2, 0x9d, 0x4f, 0x36, 0x5c, 0x92, 0xe0, 0x9d, 0xfe, 0x3e, 0xda, 0xe4, 0x47, 0x19, 0x3c, 0x00, 0x7f, 0x22, 0xf2, 0x9e, 0x51, 0xae, 0x4d,
+ /* (2^384)P */ 0xbe, 0x8c, 0x1b, 0x10, 0xb6, 0xad, 0xcc, 0xcc, 0xd8, 0x5e, 0x21, 0xa6, 0xfb, 0xf1, 0xf6, 0xbd, 0x0a, 0x24, 0x67, 0xb4, 0x57, 0x7a, 0xbc, 0xe8, 0xe9, 0xff, 0xee, 0x0a, 0x1f, 0xee, 0xbd, 0xc8, 0x44, 0xed, 0x2b, 0xbb, 0x55, 0x1f, 0xdd, 0x7c, 0xb3, 0xeb, 0x3f, 0x63, 0xa1, 0x28, 0x91, 0x21, 0xab, 0x71, 0xc6, 0x4c, 0xd0, 0xe9, 0xb0, 0x21,
+ /* (2^385)P */ 0xad, 0xc9, 0x77, 0x2b, 0xee, 0x89, 0xa4, 0x7b, 0xfd, 0xf9, 0xf6, 0x14, 0xe4, 0xed, 0x1a, 0x16, 0x9b, 0x78, 0x41, 0x43, 0xa8, 0x83, 0x72, 0x06, 0x2e, 0x7c, 0xdf, 0xeb, 0x7e, 0xdd, 0xd7, 0x8b, 0xea, 0x9a, 0x2b, 0x03, 0xba, 0x57, 0xf3, 0xf1, 0xd9, 0xe5, 0x09, 0xc5, 0x98, 0x61, 0x1c, 0x51, 0x6d, 0x5d, 0x6e, 0xfb, 0x5e, 0x95, 0x9f, 0xb5,
+ /* (2^386)P */ 0x23, 0xe2, 0x1e, 0x95, 0xa3, 0x5e, 0x42, 0x10, 0xc7, 0xc3, 0x70, 0xbf, 0x4b, 0x6b, 0x83, 0x36, 0x93, 0xb7, 0x68, 0x47, 0x88, 0x3a, 0x10, 0x88, 0x48, 0x7f, 0x8c, 0xae, 0x54, 0x10, 0x02, 0xa4, 0x52, 0x8f, 0x8d, 0xf7, 0x26, 0x4f, 0x50, 0xc3, 0x6a, 0xe2, 0x4e, 0x3b, 0x4c, 0xb9, 0x8a, 0x14, 0x15, 0x6d, 0x21, 0x29, 0xb3, 0x6e, 0x4e, 0xd0,
+ /* (2^387)P */ 0x4c, 0x8a, 0x18, 0x3f, 0xb7, 0x20, 0xfd, 0x3e, 0x54, 0xca, 0x68, 0x3c, 0xea, 0x6f, 0xf4, 0x6b, 0xa2, 0xbd, 0x01, 0xbd, 0xfe, 0x08, 0xa8, 0xd8, 0xc2, 0x20, 0x36, 0x05, 0xcd, 0xe9, 0xf3, 0x9e, 0xfa, 0x85, 0x66, 0x8f, 0x4b, 0x1d, 0x8c, 0x64, 0x4f, 0xb8, 0xc6, 0x0f, 0x5b, 0x57, 0xd8, 0x24, 0x19, 0x5a, 0x14, 0x4b, 0x92, 0xd3, 0x96, 0xbc,
+ /* (2^388)P */ 0xa9, 0x3f, 0xc9, 0x6c, 0xca, 0x64, 0x1e, 0x6f, 0xdf, 0x65, 0x7f, 0x9a, 0x47, 0x6b, 0x8a, 0x60, 0x31, 0xa6, 0x06, 0xac, 0x69, 0x30, 0xe6, 0xea, 0x63, 0x42, 0x26, 0x5f, 0xdb, 0xd0, 0xf2, 0x8e, 0x34, 0x0a, 0x3a, 0xeb, 0xf3, 0x79, 0xc8, 0xb7, 0x60, 0x56, 0x5c, 0x37, 0x95, 0x71, 0xf8, 0x7f, 0x49, 0x3e, 0x9e, 0x01, 0x26, 0x1e, 0x80, 0x9f,
+ /* (2^389)P */ 0xf8, 0x16, 0x9a, 0xaa, 0xb0, 0x28, 0xb5, 0x8e, 0xd0, 0x60, 0xe5, 0x26, 0xa9, 0x47, 0xc4, 0x5c, 0xa9, 0x39, 0xfe, 0x0a, 0xd8, 0x07, 0x2b, 0xb3, 0xce, 0xf1, 0xea, 0x1a, 0xf4, 0x7b, 0x98, 0x31, 0x3d, 0x13, 0x29, 0x80, 0xe8, 0x0d, 0xcf, 0x56, 0x39, 0x86, 0x50, 0x0c, 0xb3, 0x18, 0xf4, 0xc5, 0xca, 0xf2, 0x6f, 0xcd, 0x8d, 0xd5, 0x02, 0xb0,
+ /* (2^390)P */ 0xbf, 0x39, 0x3f, 0xac, 0x6d, 0x1a, 0x6a, 0xe4, 0x42, 0x24, 0xd6, 0x41, 0x9d, 0xb9, 0x5b, 0x46, 0x73, 0x93, 0x76, 0xaa, 0xb7, 0x37, 0x36, 0xa6, 0x09, 0xe5, 0x04, 0x3b, 0x66, 0xc4, 0x29, 0x3e, 0x41, 0xc2, 0xcb, 0xe5, 0x17, 0xd7, 0x34, 0x67, 0x1d, 0x2c, 0x12, 0xec, 0x24, 0x7a, 0x40, 0xa2, 0x45, 0x41, 0xf0, 0x75, 0xed, 0x43, 0x30, 0xc9,
+ /* (2^391)P */ 0x80, 0xf6, 0x47, 0x5b, 0xad, 0x54, 0x02, 0xbc, 0xdd, 0xa4, 0xb2, 0xd7, 0x42, 0x95, 0xf2, 0x0d, 0x1b, 0xef, 0x37, 0xa7, 0xb4, 0x34, 0x04, 0x08, 0x71, 0x1b, 0xd3, 0xdf, 0xa1, 0xf0, 0x2b, 0xfa, 0xc0, 0x1f, 0xf3, 0x44, 0xb5, 0xc6, 0x47, 0x3d, 0x65, 0x67, 0x45, 0x4d, 0x2f, 0xde, 0x52, 0x73, 0xfc, 0x30, 0x01, 0x6b, 0xc1, 0x03, 0xd8, 0xd7,
+ /* (2^392)P */ 0x1c, 0x67, 0x55, 0x3e, 0x01, 0x17, 0x0f, 0x3e, 0xe5, 0x34, 0x58, 0xfc, 0xcb, 0x71, 0x24, 0x74, 0x5d, 0x36, 0x1e, 0x89, 0x2a, 0x63, 0xf8, 0xf8, 0x9f, 0x50, 0x9f, 0x32, 0x92, 0x29, 0xd8, 0x1a, 0xec, 0x76, 0x57, 0x6c, 0x67, 0x12, 0x6a, 0x6e, 0xef, 0x97, 0x1f, 0xc3, 0x77, 0x60, 0x3c, 0x22, 0xcb, 0xc7, 0x04, 0x1a, 0x89, 0x2d, 0x10, 0xa6,
+ /* (2^393)P */ 0x12, 0xf5, 0xa9, 0x26, 0x16, 0xd9, 0x3c, 0x65, 0x5d, 0x83, 0xab, 0xd1, 0x70, 0x6b, 0x1c, 0xdb, 0xe7, 0x86, 0x0d, 0xfb, 0xe7, 0xf8, 0x2a, 0x58, 0x6e, 0x7a, 0x66, 0x13, 0x53, 0x3a, 0x6f, 0x8d, 0x43, 0x5f, 0x14, 0x23, 0x14, 0xff, 0x3d, 0x52, 0x7f, 0xee, 0xbd, 0x7a, 0x34, 0x8b, 0x35, 0x24, 0xc3, 0x7a, 0xdb, 0xcf, 0x22, 0x74, 0x9a, 0x8f,
+ /* (2^394)P */ 0xdb, 0x20, 0xfc, 0xe5, 0x39, 0x4e, 0x7d, 0x78, 0xee, 0x0b, 0xbf, 0x1d, 0x80, 0xd4, 0x05, 0x4f, 0xb9, 0xd7, 0x4e, 0x94, 0x88, 0x9a, 0x50, 0x78, 0x1a, 0x70, 0x8c, 0xcc, 0x25, 0xb6, 0x61, 0x09, 0xdc, 0x7b, 0xea, 0x3f, 0x7f, 0xea, 0x2a, 0x0d, 0x47, 0x1c, 0x8e, 0xa6, 0x5b, 0xd2, 0xa3, 0x61, 0x93, 0x3c, 0x68, 0x9f, 0x8b, 0xea, 0xb0, 0xcb,
+ /* (2^395)P */ 0xff, 0x54, 0x02, 0x19, 0xae, 0x8b, 0x4c, 0x2c, 0x3a, 0xe0, 0xe4, 0xac, 0x87, 0xf7, 0x51, 0x45, 0x41, 0x43, 0xdc, 0xaa, 0xcd, 0xcb, 0xdc, 0x40, 0xe3, 0x44, 0x3b, 0x1d, 0x9e, 0x3d, 0xb9, 0x82, 0xcc, 0x7a, 0xc5, 0x12, 0xf8, 0x1e, 0xdd, 0xdb, 0x8d, 0xb0, 0x2a, 0xe8, 0xe6, 0x6c, 0x94, 0x3b, 0xb7, 0x2d, 0xba, 0x79, 0x3b, 0xb5, 0x86, 0xfb,
+ /* (2^396)P */ 0x82, 0x88, 0x13, 0xdd, 0x6c, 0xcd, 0x85, 0x2b, 0x90, 0x86, 0xb7, 0xac, 0x16, 0xa6, 0x6e, 0x6a, 0x94, 0xd8, 0x1e, 0x4e, 0x41, 0x0f, 0xce, 0x81, 0x6a, 0xa8, 0x26, 0x56, 0x43, 0x52, 0x52, 0xe6, 0xff, 0x88, 0xcf, 0x47, 0x05, 0x1d, 0xff, 0xf3, 0xa0, 0x10, 0xb2, 0x97, 0x87, 0xeb, 0x47, 0xbb, 0xfa, 0x1f, 0xe8, 0x4c, 0xce, 0xc4, 0xcd, 0x93,
+ /* (2^397)P */ 0xf4, 0x11, 0xf5, 0x8d, 0x89, 0x29, 0x79, 0xb3, 0x59, 0x0b, 0x29, 0x7d, 0x9c, 0x12, 0x4a, 0x65, 0x72, 0x3a, 0xf9, 0xec, 0x37, 0x18, 0x86, 0xef, 0x44, 0x07, 0x25, 0x74, 0x76, 0x53, 0xed, 0x51, 0x01, 0xc6, 0x28, 0xc5, 0xc3, 0x4a, 0x0f, 0x99, 0xec, 0xc8, 0x40, 0x5a, 0x83, 0x30, 0x79, 0xa2, 0x3e, 0x63, 0x09, 0x2d, 0x6f, 0x23, 0x54, 0x1c,
+ /* (2^398)P */ 0x5c, 0x6f, 0x3b, 0x1c, 0x30, 0x77, 0x7e, 0x87, 0x66, 0x83, 0x2e, 0x7e, 0x85, 0x50, 0xfd, 0xa0, 0x7a, 0xc2, 0xf5, 0x0f, 0xc1, 0x64, 0xe7, 0x0b, 0xbd, 0x59, 0xa7, 0xe7, 0x65, 0x53, 0xc3, 0xf5, 0x55, 0x5b, 0xe1, 0x82, 0x30, 0x5a, 0x61, 0xcd, 0xa0, 0x89, 0x32, 0xdb, 0x87, 0xfc, 0x21, 0x8a, 0xab, 0x6d, 0x82, 0xa8, 0x42, 0x81, 0x4f, 0xf2,
+ /* (2^399)P */ 0xb3, 0xeb, 0x88, 0x18, 0xf6, 0x56, 0x96, 0xbf, 0xba, 0x5d, 0x71, 0xa1, 0x5a, 0xd1, 0x04, 0x7b, 0xd5, 0x46, 0x01, 0x74, 0xfe, 0x15, 0x25, 0xb7, 0xff, 0x0c, 0x24, 0x47, 0xac, 0xfd, 0xab, 0x47, 0x32, 0xe1, 0x6a, 0x4e, 0xca, 0xcf, 0x7f, 0xdd, 0xf8, 0xd2, 0x4b, 0x3b, 0xf5, 0x17, 0xba, 0xba, 0x8b, 0xa1, 0xec, 0x28, 0x3f, 0x97, 0xab, 0x2a,
+ /* (2^400)P */ 0x51, 0x38, 0xc9, 0x5e, 0xc6, 0xb3, 0x64, 0xf2, 0x24, 0x4d, 0x04, 0x7d, 0xc8, 0x39, 0x0c, 0x4a, 0xc9, 0x73, 0x74, 0x1b, 0x5c, 0xb2, 0xc5, 0x41, 0x62, 0xa0, 0x4c, 0x6d, 0x8d, 0x91, 0x9a, 0x7b, 0x88, 0xab, 0x9c, 0x7e, 0x23, 0xdb, 0x6f, 0xb5, 0x72, 0xd6, 0x47, 0x40, 0xef, 0x22, 0x58, 0x62, 0x19, 0x6c, 0x38, 0xba, 0x5b, 0x00, 0x30, 0x9f,
+ /* (2^401)P */ 0x65, 0xbb, 0x3b, 0x9b, 0xe9, 0xae, 0xbf, 0xbe, 0xe4, 0x13, 0x95, 0xf3, 0xe3, 0x77, 0xcb, 0xe4, 0x9a, 0x22, 0xb5, 0x4a, 0x08, 0x9d, 0xb3, 0x9e, 0x27, 0xe0, 0x15, 0x6c, 0x9f, 0x7e, 0x9a, 0x5e, 0x15, 0x45, 0x25, 0x8d, 0x01, 0x0a, 0xd2, 0x2b, 0xbd, 0x48, 0x06, 0x0d, 0x18, 0x97, 0x4b, 0xdc, 0xbc, 0xf0, 0xcd, 0xb2, 0x52, 0x3c, 0xac, 0xf5,
+ /* (2^402)P */ 0x3e, 0xed, 0x47, 0x6b, 0x5c, 0xf6, 0x76, 0xd0, 0xe9, 0x15, 0xa3, 0xcb, 0x36, 0x00, 0x21, 0xa3, 0x79, 0x20, 0xa5, 0x3e, 0x88, 0x03, 0xcb, 0x7e, 0x63, 0xbb, 0xed, 0xa9, 0x13, 0x35, 0x16, 0xaf, 0x2e, 0xb4, 0x70, 0x14, 0x93, 0xfb, 0xc4, 0x9b, 0xd8, 0xb1, 0xbe, 0x43, 0xd1, 0x85, 0xb8, 0x97, 0xef, 0xea, 0x88, 0xa1, 0x25, 0x52, 0x62, 0x75,
+ /* (2^403)P */ 0x8e, 0x4f, 0xaa, 0x23, 0x62, 0x7e, 0x2b, 0x37, 0x89, 0x00, 0x11, 0x30, 0xc5, 0x33, 0x4a, 0x89, 0x8a, 0xe2, 0xfc, 0x5c, 0x6a, 0x75, 0xe5, 0xf7, 0x02, 0x4a, 0x9b, 0xf7, 0xb5, 0x6a, 0x85, 0x31, 0xd3, 0x5a, 0xcf, 0xc3, 0xf8, 0xde, 0x2f, 0xcf, 0xb5, 0x24, 0xf4, 0xe3, 0xa1, 0xad, 0x42, 0xae, 0x09, 0xb9, 0x2e, 0x04, 0x2d, 0x01, 0x22, 0x3f,
+ /* (2^404)P */ 0x41, 0x16, 0xfb, 0x7d, 0x50, 0xfd, 0xb5, 0xba, 0x88, 0x24, 0xba, 0xfd, 0x3d, 0xb2, 0x90, 0x15, 0xb7, 0xfa, 0xa2, 0xe1, 0x4c, 0x7d, 0xb9, 0xc6, 0xff, 0x81, 0x57, 0xb6, 0xc2, 0x9e, 0xcb, 0xc4, 0x35, 0xbd, 0x01, 0xb7, 0xaa, 0xce, 0xd0, 0xe9, 0xb5, 0xd6, 0x72, 0xbf, 0xd2, 0xee, 0xc7, 0xac, 0x94, 0xff, 0x29, 0x57, 0x02, 0x49, 0x09, 0xad,
+ /* (2^405)P */ 0x27, 0xa5, 0x78, 0x1b, 0xbf, 0x6b, 0xaf, 0x0b, 0x8c, 0xd9, 0xa8, 0x37, 0xb0, 0x67, 0x18, 0xb6, 0xc7, 0x05, 0x8a, 0x67, 0x03, 0x30, 0x62, 0x6e, 0x56, 0x82, 0xa9, 0x54, 0x3e, 0x0c, 0x4e, 0x07, 0xe1, 0x5a, 0x38, 0xed, 0xfa, 0xc8, 0x55, 0x6b, 0x08, 0xa3, 0x6b, 0x64, 0x2a, 0x15, 0xd6, 0x39, 0x6f, 0x47, 0x99, 0x42, 0x3f, 0x33, 0x84, 0x8f,
+ /* (2^406)P */ 0xbc, 0x45, 0x29, 0x81, 0x0e, 0xa4, 0xc5, 0x72, 0x3a, 0x10, 0xe1, 0xc4, 0x1e, 0xda, 0xc3, 0xfe, 0xb0, 0xce, 0xd2, 0x13, 0x34, 0x67, 0x21, 0xc6, 0x7e, 0xf9, 0x8c, 0xff, 0x39, 0x50, 0xae, 0x92, 0x60, 0x35, 0x2f, 0x8b, 0x6e, 0xc9, 0xc1, 0x27, 0x3a, 0x94, 0x66, 0x3e, 0x26, 0x84, 0x93, 0xc8, 0x6c, 0xcf, 0xd2, 0x03, 0xa1, 0x10, 0xcf, 0xb7,
+ /* (2^407)P */ 0x64, 0xda, 0x19, 0xf6, 0xc5, 0x73, 0x17, 0x44, 0x88, 0x81, 0x07, 0x0d, 0x34, 0xb2, 0x75, 0xf9, 0xd9, 0xe2, 0xe0, 0x8b, 0x71, 0xcf, 0x72, 0x34, 0x83, 0xb4, 0xce, 0xfc, 0xd7, 0x29, 0x09, 0x5a, 0x98, 0xbf, 0x14, 0xac, 0x77, 0x55, 0x38, 0x47, 0x5b, 0x0f, 0x40, 0x24, 0xe5, 0xa5, 0xa6, 0xac, 0x2d, 0xa6, 0xff, 0x9c, 0x73, 0xfe, 0x5c, 0x7e,
+ /* (2^408)P */ 0x1e, 0x33, 0xcc, 0x68, 0xb2, 0xbc, 0x8c, 0x93, 0xaf, 0xcc, 0x38, 0xf8, 0xd9, 0x16, 0x72, 0x50, 0xac, 0xd9, 0xb5, 0x0b, 0x9a, 0xbe, 0x46, 0x7a, 0xf1, 0xee, 0xf1, 0xad, 0xec, 0x5b, 0x59, 0x27, 0x9c, 0x05, 0xa3, 0x87, 0xe0, 0x37, 0x2c, 0x83, 0xce, 0xb3, 0x65, 0x09, 0x8e, 0xc3, 0x9c, 0xbf, 0x6a, 0xa2, 0x00, 0xcc, 0x12, 0x36, 0xc5, 0x95,
+ /* (2^409)P */ 0x36, 0x11, 0x02, 0x14, 0x9c, 0x3c, 0xeb, 0x2f, 0x23, 0x5b, 0x6b, 0x2b, 0x08, 0x54, 0x53, 0xac, 0xb2, 0xa3, 0xe0, 0x26, 0x62, 0x3c, 0xe4, 0xe1, 0x81, 0xee, 0x13, 0x3e, 0xa4, 0x97, 0xef, 0xf9, 0x92, 0x27, 0x01, 0xce, 0x54, 0x8b, 0x3e, 0x31, 0xbe, 0xa7, 0x88, 0xcf, 0x47, 0x99, 0x3c, 0x10, 0x6f, 0x60, 0xb3, 0x06, 0x4e, 0xee, 0x1b, 0xf0,
+ /* (2^410)P */ 0x59, 0x49, 0x66, 0xcf, 0x22, 0xe6, 0xf6, 0x73, 0xfe, 0xa3, 0x1c, 0x09, 0xfa, 0x5f, 0x65, 0xa8, 0xf0, 0x82, 0xc2, 0xef, 0x16, 0x63, 0x6e, 0x79, 0x69, 0x51, 0x39, 0x07, 0x65, 0xc4, 0x81, 0xec, 0x73, 0x0f, 0x15, 0x93, 0xe1, 0x30, 0x33, 0xe9, 0x37, 0x86, 0x42, 0x4c, 0x1f, 0x9b, 0xad, 0xee, 0x3f, 0xf1, 0x2a, 0x8e, 0x6a, 0xa3, 0xc8, 0x35,
+ /* (2^411)P */ 0x1e, 0x49, 0xf1, 0xdd, 0xd2, 0x9c, 0x8e, 0x78, 0xb2, 0x06, 0xe4, 0x6a, 0xab, 0x3a, 0xdc, 0xcd, 0xf4, 0xeb, 0xe1, 0xe7, 0x2f, 0xaa, 0xeb, 0x40, 0x31, 0x9f, 0xb9, 0xab, 0x13, 0xa9, 0x78, 0xbf, 0x38, 0x89, 0x0e, 0x85, 0x14, 0x8b, 0x46, 0x76, 0x14, 0xda, 0xcf, 0x33, 0xc8, 0x79, 0xd3, 0xd5, 0xa3, 0x6a, 0x69, 0x45, 0x70, 0x34, 0xc3, 0xe9,
+ /* (2^412)P */ 0x5e, 0xe7, 0x78, 0xe9, 0x24, 0xcc, 0xe9, 0xf4, 0xc8, 0x6b, 0xe0, 0xfb, 0x3a, 0xbe, 0xcc, 0x42, 0x4a, 0x00, 0x22, 0xf8, 0xe6, 0x32, 0xbe, 0x6d, 0x18, 0x55, 0x60, 0xe9, 0x72, 0x69, 0x50, 0x56, 0xca, 0x04, 0x18, 0x38, 0xa1, 0xee, 0xd8, 0x38, 0x3c, 0xa7, 0x70, 0xe2, 0xb9, 0x4c, 0xa0, 0xc8, 0x89, 0x72, 0xcf, 0x49, 0x7f, 0xdf, 0xbc, 0x67,
+ /* (2^413)P */ 0x1d, 0x17, 0xcb, 0x0b, 0xbd, 0xb2, 0x36, 0xe3, 0xa8, 0x99, 0x31, 0xb6, 0x26, 0x9c, 0x0c, 0x74, 0xaf, 0x4d, 0x24, 0x61, 0xcf, 0x31, 0x7b, 0xed, 0xdd, 0xc3, 0xf6, 0x32, 0x70, 0xfe, 0x17, 0xf6, 0x51, 0x37, 0x65, 0xce, 0x5d, 0xaf, 0xa5, 0x2f, 0x2a, 0xfe, 0x00, 0x71, 0x7c, 0x50, 0xbe, 0x21, 0xc7, 0xed, 0xc6, 0xfc, 0x67, 0xcf, 0x9c, 0xdd,
+ /* (2^414)P */ 0x26, 0x3e, 0xf8, 0xbb, 0xd0, 0xb1, 0x01, 0xd8, 0xeb, 0x0b, 0x62, 0x87, 0x35, 0x4c, 0xde, 0xca, 0x99, 0x9c, 0x6d, 0xf7, 0xb6, 0xf0, 0x57, 0x0a, 0x52, 0x29, 0x6a, 0x3f, 0x26, 0x31, 0x04, 0x07, 0x2a, 0xc9, 0xfa, 0x9b, 0x0e, 0x62, 0x8e, 0x72, 0xf2, 0xad, 0xce, 0xb6, 0x35, 0x7a, 0xc1, 0xae, 0x35, 0xc7, 0xa3, 0x14, 0xcf, 0x0c, 0x28, 0xb7,
+ /* (2^415)P */ 0xa6, 0xf1, 0x32, 0x3a, 0x20, 0xd2, 0x24, 0x97, 0xcf, 0x5d, 0x37, 0x99, 0xaf, 0x33, 0x7a, 0x5b, 0x7a, 0xcc, 0x4e, 0x41, 0x38, 0xb1, 0x4e, 0xad, 0xc9, 0xd9, 0x71, 0x7e, 0xb2, 0xf5, 0xd5, 0x01, 0x6c, 0x4d, 0xfd, 0xa1, 0xda, 0x03, 0x38, 0x9b, 0x3d, 0x92, 0x92, 0xf2, 0xca, 0xbf, 0x1f, 0x24, 0xa4, 0xbb, 0x30, 0x6a, 0x74, 0x56, 0xc8, 0xce,
+ /* (2^416)P */ 0x27, 0xf4, 0xed, 0xc9, 0xc3, 0xb1, 0x79, 0x85, 0xbe, 0xf6, 0xeb, 0xf3, 0x55, 0xc7, 0xaa, 0xa6, 0xe9, 0x07, 0x5d, 0xf4, 0xeb, 0xa6, 0x81, 0xe3, 0x0e, 0xcf, 0xa3, 0xc1, 0xef, 0xe7, 0x34, 0xb2, 0x03, 0x73, 0x8a, 0x91, 0xf1, 0xad, 0x05, 0xc7, 0x0b, 0x43, 0x99, 0x12, 0x31, 0xc8, 0xc7, 0xc5, 0xa4, 0x3d, 0xcd, 0xe5, 0x4e, 0x6d, 0x24, 0xdd,
+ /* (2^417)P */ 0x61, 0x54, 0xd0, 0x95, 0x2c, 0x45, 0x75, 0xac, 0xb5, 0x1a, 0x9d, 0x11, 0xeb, 0xed, 0x6b, 0x57, 0xa3, 0xe6, 0xcd, 0x77, 0xd4, 0x83, 0x8e, 0x39, 0xf1, 0x0f, 0x98, 0xcb, 0x40, 0x02, 0x6e, 0x10, 0x82, 0x9e, 0xb4, 0x93, 0x76, 0xd7, 0x97, 0xa3, 0x53, 0x12, 0x86, 0xc6, 0x15, 0x78, 0x73, 0x93, 0xe7, 0x7f, 0xcf, 0x1f, 0xbf, 0xcd, 0xd2, 0x7a,
+ /* (2^418)P */ 0xc2, 0x21, 0xdc, 0xd5, 0x69, 0xff, 0xca, 0x49, 0x3a, 0xe1, 0xc3, 0x69, 0x41, 0x56, 0xc1, 0x76, 0x63, 0x24, 0xbd, 0x64, 0x1b, 0x3d, 0x92, 0xf9, 0x13, 0x04, 0x25, 0xeb, 0x27, 0xa6, 0xef, 0x39, 0x3a, 0x80, 0xe0, 0xf8, 0x27, 0xee, 0xc9, 0x49, 0x77, 0xef, 0x3f, 0x29, 0x3d, 0x5e, 0xe6, 0x66, 0x83, 0xd1, 0xf6, 0xfe, 0x9d, 0xbc, 0xf1, 0x96,
+ /* (2^419)P */ 0x6b, 0xc6, 0x99, 0x26, 0x3c, 0xf3, 0x63, 0xf9, 0xc7, 0x29, 0x8c, 0x52, 0x62, 0x2d, 0xdc, 0x8a, 0x66, 0xce, 0x2c, 0xa7, 0xe4, 0xf0, 0xd7, 0x37, 0x17, 0x1e, 0xe4, 0xa3, 0x53, 0x7b, 0x29, 0x8e, 0x60, 0x99, 0xf9, 0x0c, 0x7c, 0x6f, 0xa2, 0xcc, 0x9f, 0x80, 0xdd, 0x5e, 0x46, 0xaa, 0x0d, 0x6c, 0xc9, 0x6c, 0xf7, 0x78, 0x5b, 0x38, 0xe3, 0x24,
+ /* (2^420)P */ 0x4b, 0x75, 0x6a, 0x2f, 0x08, 0xe1, 0x72, 0x76, 0xab, 0x82, 0x96, 0xdf, 0x3b, 0x1f, 0x9b, 0xd8, 0xed, 0xdb, 0xcd, 0x15, 0x09, 0x5a, 0x1e, 0xb7, 0xc5, 0x26, 0x72, 0x07, 0x0c, 0x50, 0xcd, 0x3b, 0x4d, 0x3f, 0xa2, 0x67, 0xc2, 0x02, 0x61, 0x2e, 0x68, 0xe9, 0x6f, 0xf0, 0x21, 0x2a, 0xa7, 0x3b, 0x88, 0x04, 0x11, 0x64, 0x49, 0x0d, 0xb4, 0x46,
+ /* (2^421)P */ 0x63, 0x85, 0xf3, 0xc5, 0x2b, 0x5a, 0x9f, 0xf0, 0x17, 0xcb, 0x45, 0x0a, 0xf3, 0x6e, 0x7e, 0xb0, 0x7c, 0xbc, 0xf0, 0x4f, 0x3a, 0xb0, 0xbc, 0x36, 0x36, 0x52, 0x51, 0xcb, 0xfe, 0x9a, 0xcb, 0xe8, 0x7e, 0x4b, 0x06, 0x7f, 0xaa, 0x35, 0xc8, 0x0e, 0x7a, 0x30, 0xa3, 0xb1, 0x09, 0xbb, 0x86, 0x4c, 0xbe, 0xb8, 0xbd, 0xe0, 0x32, 0xa5, 0xd4, 0xf7,
+ /* (2^422)P */ 0x7d, 0x50, 0x37, 0x68, 0x4e, 0x22, 0xb2, 0x2c, 0xd5, 0x0f, 0x2b, 0x6d, 0xb1, 0x51, 0xf2, 0x82, 0xe9, 0x98, 0x7c, 0x50, 0xc7, 0x96, 0x7e, 0x0e, 0xdc, 0xb1, 0x0e, 0xb2, 0x63, 0x8c, 0x30, 0x37, 0x72, 0x21, 0x9c, 0x61, 0xc2, 0xa7, 0x33, 0xd9, 0xb2, 0x63, 0x93, 0xd1, 0x6b, 0x6a, 0x73, 0xa5, 0x58, 0x80, 0xff, 0x04, 0xc7, 0x83, 0x21, 0x29,
+ /* (2^423)P */ 0x29, 0x04, 0xbc, 0x99, 0x39, 0xc9, 0x58, 0xc9, 0x6b, 0x17, 0xe8, 0x90, 0xb3, 0xe6, 0xa9, 0xb6, 0x28, 0x9b, 0xcb, 0x3b, 0x28, 0x90, 0x68, 0x71, 0xff, 0xcf, 0x08, 0x78, 0xc9, 0x8d, 0xa8, 0x4e, 0x43, 0xd1, 0x1c, 0x9e, 0xa4, 0xe3, 0xdf, 0xbf, 0x92, 0xf4, 0xf9, 0x41, 0xba, 0x4d, 0x1c, 0xf9, 0xdd, 0x74, 0x76, 0x1c, 0x6e, 0x3e, 0x94, 0x87,
+ /* (2^424)P */ 0xe4, 0xda, 0xc5, 0xd7, 0xfb, 0x87, 0xc5, 0x4d, 0x6b, 0x19, 0xaa, 0xb9, 0xbc, 0x8c, 0xf2, 0x8a, 0xd8, 0x5d, 0xdb, 0x4d, 0xef, 0xa6, 0xf2, 0x65, 0xf1, 0x22, 0x9c, 0xf1, 0x46, 0x30, 0x71, 0x7c, 0xe4, 0x53, 0x8e, 0x55, 0x2e, 0x9c, 0x9a, 0x31, 0x2a, 0xc3, 0xab, 0x0f, 0xde, 0xe4, 0xbe, 0xd8, 0x96, 0x50, 0x6e, 0x0c, 0x54, 0x49, 0xe6, 0xec,
+ /* (2^425)P */ 0x3c, 0x1d, 0x5a, 0xa5, 0xda, 0xad, 0xdd, 0xc2, 0xae, 0xac, 0x6f, 0x86, 0x75, 0x31, 0x91, 0x64, 0x45, 0x9d, 0xa4, 0xf0, 0x81, 0xf1, 0x0e, 0xba, 0x74, 0xaf, 0x7b, 0xcd, 0x6f, 0xfe, 0xac, 0x4e, 0xdb, 0x4e, 0x45, 0x35, 0x36, 0xc5, 0xc0, 0x6c, 0x3d, 0x64, 0xf4, 0xd8, 0x07, 0x62, 0xd1, 0xec, 0xf3, 0xfc, 0x93, 0xc9, 0x28, 0x0c, 0x2c, 0xf3,
+ /* (2^426)P */ 0x0c, 0x69, 0x2b, 0x5c, 0xb6, 0x41, 0x69, 0xf1, 0xa4, 0xf1, 0x5b, 0x75, 0x4c, 0x42, 0x8b, 0x47, 0xeb, 0x69, 0xfb, 0xa8, 0xe6, 0xf9, 0x7b, 0x48, 0x50, 0xaf, 0xd3, 0xda, 0xb2, 0x35, 0x10, 0xb5, 0x5b, 0x40, 0x90, 0x39, 0xc9, 0x07, 0x06, 0x73, 0x26, 0x20, 0x95, 0x01, 0xa4, 0x2d, 0xf0, 0xe7, 0x2e, 0x00, 0x7d, 0x41, 0x09, 0x68, 0x13, 0xc4,
+ /* (2^427)P */ 0xbe, 0x38, 0x78, 0xcf, 0xc9, 0x4f, 0x36, 0xca, 0x09, 0x61, 0x31, 0x3c, 0x57, 0x2e, 0xec, 0x17, 0xa4, 0x7d, 0x19, 0x2b, 0x9b, 0x5b, 0xbe, 0x8f, 0xd6, 0xc5, 0x2f, 0x86, 0xf2, 0x64, 0x76, 0x17, 0x00, 0x6e, 0x1a, 0x8c, 0x67, 0x1b, 0x68, 0xeb, 0x15, 0xa2, 0xd6, 0x09, 0x91, 0xdd, 0x23, 0x0d, 0x98, 0xb2, 0x10, 0x19, 0x55, 0x9b, 0x63, 0xf2,
+ /* (2^428)P */ 0x51, 0x1f, 0x93, 0xea, 0x2a, 0x3a, 0xfa, 0x41, 0xc0, 0x57, 0xfb, 0x74, 0xa6, 0x65, 0x09, 0x56, 0x14, 0xb6, 0x12, 0xaa, 0xb3, 0x1a, 0x8d, 0x3b, 0x76, 0x91, 0x7a, 0x23, 0x56, 0x9c, 0x6a, 0xc0, 0xe0, 0x3c, 0x3f, 0xb5, 0x1a, 0xf4, 0x57, 0x71, 0x93, 0x2b, 0xb1, 0xa7, 0x70, 0x57, 0x22, 0x80, 0xf5, 0xb8, 0x07, 0x77, 0x87, 0x0c, 0xbe, 0x83,
+ /* (2^429)P */ 0x07, 0x9b, 0x0e, 0x52, 0x38, 0x63, 0x13, 0x86, 0x6a, 0xa6, 0xb4, 0xd2, 0x60, 0x68, 0x9a, 0x99, 0x82, 0x0a, 0x04, 0x5f, 0x89, 0x7a, 0x1a, 0x2a, 0xae, 0x2d, 0x35, 0x0c, 0x1e, 0xad, 0xef, 0x4f, 0x9a, 0xfc, 0xc8, 0xd9, 0xcf, 0x9d, 0x48, 0x71, 0xa5, 0x55, 0x79, 0x73, 0x39, 0x1b, 0xd8, 0x73, 0xec, 0x9b, 0x03, 0x16, 0xd8, 0x82, 0xf7, 0x67,
+ /* (2^430)P */ 0x52, 0x67, 0x42, 0x21, 0xc9, 0x40, 0x78, 0x82, 0x2b, 0x95, 0x2d, 0x20, 0x92, 0xd1, 0xe2, 0x61, 0x25, 0xb0, 0xc6, 0x9c, 0x20, 0x59, 0x8e, 0x28, 0x6f, 0xf3, 0xfd, 0xd3, 0xc1, 0x32, 0x43, 0xc9, 0xa6, 0x08, 0x7a, 0x77, 0x9c, 0x4c, 0x8c, 0x33, 0x71, 0x13, 0x69, 0xe3, 0x52, 0x30, 0xa7, 0xf5, 0x07, 0x67, 0xac, 0xad, 0x46, 0x8a, 0x26, 0x25,
+ /* (2^431)P */ 0xda, 0x86, 0xc4, 0xa2, 0x71, 0x56, 0xdd, 0xd2, 0x48, 0xd3, 0xde, 0x42, 0x63, 0x01, 0xa7, 0x2c, 0x92, 0x83, 0x6f, 0x2e, 0xd8, 0x1e, 0x3f, 0xc1, 0xc5, 0x42, 0x4e, 0x34, 0x19, 0x54, 0x6e, 0x35, 0x2c, 0x51, 0x2e, 0xfd, 0x0f, 0x9a, 0x45, 0x66, 0x5e, 0x4a, 0x83, 0xda, 0x0a, 0x53, 0x68, 0x63, 0xfa, 0xce, 0x47, 0x20, 0xd3, 0x34, 0xba, 0x0d,
+ /* (2^432)P */ 0xd0, 0xe9, 0x64, 0xa4, 0x61, 0x4b, 0x86, 0xe5, 0x93, 0x6f, 0xda, 0x0e, 0x31, 0x7e, 0x6e, 0xe3, 0xc6, 0x73, 0xd8, 0xa3, 0x08, 0x57, 0x52, 0xcd, 0x51, 0x63, 0x1d, 0x9f, 0x93, 0x00, 0x62, 0x91, 0x26, 0x21, 0xa7, 0xdd, 0x25, 0x0f, 0x09, 0x0d, 0x35, 0xad, 0xcf, 0x11, 0x8e, 0x6e, 0xe8, 0xae, 0x1d, 0x95, 0xcb, 0x88, 0xf8, 0x70, 0x7b, 0x91,
+ /* (2^433)P */ 0x0c, 0x19, 0x5c, 0xd9, 0x8d, 0xda, 0x9d, 0x2c, 0x90, 0x54, 0x65, 0xe8, 0xb6, 0x35, 0x50, 0xae, 0xea, 0xae, 0x43, 0xb7, 0x1e, 0x99, 0x8b, 0x4c, 0x36, 0x4e, 0xe4, 0x1e, 0xc4, 0x64, 0x43, 0xb6, 0xeb, 0xd4, 0xe9, 0x60, 0x22, 0xee, 0xcf, 0xb8, 0x52, 0x1b, 0xf0, 0x04, 0xce, 0xbc, 0x2b, 0xf0, 0xbe, 0xcd, 0x44, 0x74, 0x1e, 0x1f, 0x63, 0xf9,
+ /* (2^434)P */ 0xe1, 0x3f, 0x95, 0x94, 0xb2, 0xb6, 0x31, 0xa9, 0x1b, 0xdb, 0xfd, 0x0e, 0xdb, 0xdd, 0x1a, 0x22, 0x78, 0x60, 0x9f, 0x75, 0x5f, 0x93, 0x06, 0x0c, 0xd8, 0xbb, 0xa2, 0x85, 0x2b, 0x5e, 0xc0, 0x9b, 0xa8, 0x5d, 0xaf, 0x93, 0x91, 0x91, 0x47, 0x41, 0x1a, 0xfc, 0xb4, 0x51, 0x85, 0xad, 0x69, 0x4d, 0x73, 0x69, 0xd5, 0x4e, 0x82, 0xfb, 0x66, 0xcb,
+ /* (2^435)P */ 0x7c, 0xbe, 0xc7, 0x51, 0xc4, 0x74, 0x6e, 0xab, 0xfd, 0x41, 0x4f, 0x76, 0x4f, 0x24, 0x03, 0xd6, 0x2a, 0xb7, 0x42, 0xb4, 0xda, 0x41, 0x2c, 0x82, 0x48, 0x4c, 0x7f, 0x6f, 0x25, 0x5d, 0x36, 0xd4, 0x69, 0xf5, 0xef, 0x02, 0x81, 0xea, 0x6f, 0x19, 0x69, 0xe8, 0x6f, 0x5b, 0x2f, 0x14, 0x0e, 0x6f, 0x89, 0xb4, 0xb5, 0xd8, 0xae, 0xef, 0x7b, 0x87,
+ /* (2^436)P */ 0xe9, 0x91, 0xa0, 0x8b, 0xc9, 0xe0, 0x01, 0x90, 0x37, 0xc1, 0x6f, 0xdc, 0x5e, 0xf7, 0xbf, 0x43, 0x00, 0xaa, 0x10, 0x76, 0x76, 0x18, 0x6e, 0x19, 0x1e, 0x94, 0x50, 0x11, 0x0a, 0xd1, 0xe2, 0xdb, 0x08, 0x21, 0xa0, 0x1f, 0xdb, 0x54, 0xfe, 0xea, 0x6e, 0xa3, 0x68, 0x56, 0x87, 0x0b, 0x22, 0x4e, 0x66, 0xf3, 0x82, 0x82, 0x00, 0xcd, 0xd4, 0x12,
+ /* (2^437)P */ 0x25, 0x8e, 0x24, 0x77, 0x64, 0x4c, 0xe0, 0xf8, 0x18, 0xc0, 0xdc, 0xc7, 0x1b, 0x35, 0x65, 0xde, 0x67, 0x41, 0x5e, 0x6f, 0x90, 0x82, 0xa7, 0x2e, 0x6d, 0xf1, 0x47, 0xb4, 0x92, 0x9c, 0xfd, 0x6a, 0x9a, 0x41, 0x36, 0x20, 0x24, 0x58, 0xc3, 0x59, 0x07, 0x9a, 0xfa, 0x9f, 0x03, 0xcb, 0xc7, 0x69, 0x37, 0x60, 0xe1, 0xab, 0x13, 0x72, 0xee, 0xa2,
+ /* (2^438)P */ 0x74, 0x78, 0xfb, 0x13, 0xcb, 0x8e, 0x37, 0x1a, 0xf6, 0x1d, 0x17, 0x83, 0x06, 0xd4, 0x27, 0x06, 0x21, 0xe8, 0xda, 0xdf, 0x6b, 0xf3, 0x83, 0x6b, 0x34, 0x8a, 0x8c, 0xee, 0x01, 0x05, 0x5b, 0xed, 0xd3, 0x1b, 0xc9, 0x64, 0x83, 0xc9, 0x49, 0xc2, 0x57, 0x1b, 0xdd, 0xcf, 0xf1, 0x9d, 0x63, 0xee, 0x1c, 0x0d, 0xa0, 0x0a, 0x73, 0x1f, 0x5b, 0x32,
+ /* (2^439)P */ 0x29, 0xce, 0x1e, 0xc0, 0x6a, 0xf5, 0xeb, 0x99, 0x5a, 0x39, 0x23, 0xe9, 0xdd, 0xac, 0x44, 0x88, 0xbc, 0x80, 0x22, 0xde, 0x2c, 0xcb, 0xa8, 0x3b, 0xff, 0xf7, 0x6f, 0xc7, 0x71, 0x72, 0xa8, 0xa3, 0xf6, 0x4d, 0xc6, 0x75, 0xda, 0x80, 0xdc, 0xd9, 0x30, 0xd9, 0x07, 0x50, 0x5a, 0x54, 0x7d, 0xda, 0x39, 0x6f, 0x78, 0x94, 0xbf, 0x25, 0x98, 0xdc,
+ /* (2^440)P */ 0x01, 0x26, 0x62, 0x44, 0xfb, 0x0f, 0x11, 0x72, 0x73, 0x0a, 0x16, 0xc7, 0x16, 0x9c, 0x9b, 0x37, 0xd8, 0xff, 0x4f, 0xfe, 0x57, 0xdb, 0xae, 0xef, 0x7d, 0x94, 0x30, 0x04, 0x70, 0x83, 0xde, 0x3c, 0xd4, 0xb5, 0x70, 0xda, 0xa7, 0x55, 0xc8, 0x19, 0xe1, 0x36, 0x15, 0x61, 0xe7, 0x3b, 0x7d, 0x85, 0xbb, 0xf3, 0x42, 0x5a, 0x94, 0xf4, 0x53, 0x2a,
+ /* (2^441)P */ 0x14, 0x60, 0xa6, 0x0b, 0x83, 0xe1, 0x23, 0x77, 0xc0, 0xce, 0x50, 0xed, 0x35, 0x8d, 0x98, 0x99, 0x7d, 0xf5, 0x8d, 0xce, 0x94, 0x25, 0xc8, 0x0f, 0x6d, 0xfa, 0x4a, 0xa4, 0x3a, 0x1f, 0x66, 0xfb, 0x5a, 0x64, 0xaf, 0x8b, 0x54, 0x54, 0x44, 0x3f, 0x5b, 0x88, 0x61, 0xe4, 0x48, 0x45, 0x26, 0x20, 0xbe, 0x0d, 0x06, 0xbb, 0x65, 0x59, 0xe1, 0x36,
+ /* (2^442)P */ 0xb7, 0x98, 0xce, 0xa3, 0xe3, 0xee, 0x11, 0x1b, 0x9e, 0x24, 0x59, 0x75, 0x31, 0x37, 0x44, 0x6f, 0x6b, 0x9e, 0xec, 0xb7, 0x44, 0x01, 0x7e, 0xab, 0xbb, 0x69, 0x5d, 0x11, 0xb0, 0x30, 0x64, 0xea, 0x91, 0xb4, 0x7a, 0x8c, 0x02, 0x4c, 0xb9, 0x10, 0xa7, 0xc7, 0x79, 0xe6, 0xdc, 0x77, 0xe3, 0xc8, 0xef, 0x3e, 0xf9, 0x38, 0x81, 0xce, 0x9a, 0xb2,
+ /* (2^443)P */ 0x91, 0x12, 0x76, 0xd0, 0x10, 0xb4, 0xaf, 0xe1, 0x89, 0x3a, 0x93, 0x6b, 0x5c, 0x19, 0x5f, 0x24, 0xed, 0x04, 0x92, 0xc7, 0xf0, 0x00, 0x08, 0xc1, 0x92, 0xff, 0x90, 0xdb, 0xb2, 0xbf, 0xdf, 0x49, 0xcd, 0xbd, 0x5c, 0x6e, 0xbf, 0x16, 0xbb, 0x61, 0xf9, 0x20, 0x33, 0x35, 0x93, 0x11, 0xbc, 0x59, 0x69, 0xce, 0x18, 0x9f, 0xf8, 0x7b, 0xa1, 0x6e,
+ /* (2^444)P */ 0xa1, 0xf4, 0xaf, 0xad, 0xf8, 0xe6, 0x99, 0xd2, 0xa1, 0x4d, 0xde, 0x56, 0xc9, 0x7b, 0x0b, 0x11, 0x3e, 0xbf, 0x89, 0x1a, 0x9a, 0x90, 0xe5, 0xe2, 0xa6, 0x37, 0x88, 0xa1, 0x68, 0x59, 0xae, 0x8c, 0xec, 0x02, 0x14, 0x8d, 0xb7, 0x2e, 0x25, 0x75, 0x7f, 0x76, 0x1a, 0xd3, 0x4d, 0xad, 0x8a, 0x00, 0x6c, 0x96, 0x49, 0xa4, 0xc3, 0x2e, 0x5c, 0x7b,
+ /* (2^445)P */ 0x26, 0x53, 0xf7, 0xda, 0xa8, 0x01, 0x14, 0xb1, 0x63, 0xe3, 0xc3, 0x89, 0x88, 0xb0, 0x85, 0x40, 0x2b, 0x26, 0x9a, 0x10, 0x1a, 0x70, 0x33, 0xf4, 0x50, 0x9d, 0x4d, 0xd8, 0x64, 0xc6, 0x0f, 0xe1, 0x17, 0xc8, 0x10, 0x4b, 0xfc, 0xa0, 0xc9, 0xba, 0x2c, 0x98, 0x09, 0xf5, 0x84, 0xb6, 0x7c, 0x4e, 0xa3, 0xe3, 0x81, 0x1b, 0x32, 0x60, 0x02, 0xdd,
+ /* (2^446)P */ 0xa3, 0xe5, 0x86, 0xd4, 0x43, 0xa8, 0xd1, 0x98, 0x9d, 0x9d, 0xdb, 0x04, 0xcf, 0x6e, 0x35, 0x05, 0x30, 0x53, 0x3b, 0xbc, 0x90, 0x00, 0x4a, 0xc5, 0x40, 0x2a, 0x0f, 0xde, 0x1a, 0xd7, 0x36, 0x27, 0x44, 0x62, 0xa6, 0xac, 0x9d, 0xd2, 0x70, 0x69, 0x14, 0x39, 0x9b, 0xd1, 0xc3, 0x0a, 0x3a, 0x82, 0x0e, 0xf1, 0x94, 0xd7, 0x42, 0x94, 0xd5, 0x7d,
+ /* (2^447)P */ 0x04, 0xc0, 0x6e, 0x12, 0x90, 0x70, 0xf9, 0xdf, 0xf7, 0xc9, 0x86, 0xc0, 0xe6, 0x92, 0x8b, 0x0a, 0xa1, 0xc1, 0x3b, 0xcc, 0x33, 0xb7, 0xf0, 0xeb, 0x51, 0x50, 0x80, 0x20, 0x69, 0x1c, 0x4f, 0x89, 0x05, 0x1e, 0xe4, 0x7a, 0x0a, 0xc2, 0xf0, 0xf5, 0x78, 0x91, 0x76, 0x34, 0x45, 0xdc, 0x24, 0x53, 0x24, 0x98, 0xe2, 0x73, 0x6f, 0xe6, 0x46, 0x67,
+}
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go
new file mode 100644
index 0000000000..b6b236e5d3
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go
@@ -0,0 +1,71 @@
+package goldilocks
+
+import fp "github.com/cloudflare/circl/math/fp448"
+
+var (
+ // genX is the x-coordinate of the generator of Goldilocks curve.
+ genX = fp.Elt{
+ 0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26,
+ 0x8e, 0x93, 0x00, 0x8b, 0xe1, 0x80, 0x3b, 0x43,
+ 0x11, 0x65, 0xb6, 0x2a, 0xf7, 0x1a, 0xae, 0x12,
+ 0x64, 0xa4, 0xd3, 0xa3, 0x24, 0xe3, 0x6d, 0xea,
+ 0x67, 0x17, 0x0f, 0x47, 0x70, 0x65, 0x14, 0x9e,
+ 0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22,
+ 0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f,
+ }
+ // genY is the y-coordinate of the generator of Goldilocks curve.
+ genY = fp.Elt{
+ 0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98,
+ 0xad, 0xc8, 0xd7, 0x4e, 0x2c, 0x13, 0xbd, 0xfd,
+ 0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a,
+ 0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87,
+ 0x40, 0x98, 0xa3, 0x6c, 0x73, 0x73, 0xea, 0x4b,
+ 0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88,
+ 0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69,
+ }
+ // paramD is -39081 in Fp.
+ paramD = fp.Elt{
+ 0x56, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ }
+ // order is 2^446-0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d,
+ // which is the number of points in the prime subgroup.
+ order = Scalar{
+ 0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23,
+ 0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21,
+ 0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4,
+ 0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
+ }
+ // residue448 is 2^448 mod order.
+ residue448 = [4]uint64{
+ 0x721cf5b5529eec34, 0x7a4cf635c8e9c2ab, 0xeec492d944a725bf, 0x20cd77058,
+ }
+ // invFour is 1/4 mod order.
+ invFour = Scalar{
+ 0x3d, 0x11, 0xd6, 0xaa, 0xa4, 0x30, 0xde, 0x48,
+ 0xd5, 0x63, 0x71, 0xa3, 0x9c, 0x30, 0x5b, 0x08,
+ 0xa4, 0x8d, 0xb5, 0x6b, 0xd2, 0xb6, 0x13, 0x71,
+ 0xfa, 0x88, 0x32, 0xdf, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
+ }
+ // paramDTwist is -39082 in Fp. The D parameter of the twist curve.
+ paramDTwist = fp.Elt{
+ 0x55, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ }
+)
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go
new file mode 100644
index 0000000000..1f165141a9
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go
@@ -0,0 +1,84 @@
+// Package goldilocks provides elliptic curve operations over the goldilocks curve.
+package goldilocks
+
+import fp "github.com/cloudflare/circl/math/fp448"
+
+// Curve is the Goldilocks curve x^2+y^2=z^2-39081x^2y^2.
+type Curve struct{}
+
+// Identity returns the identity point.
+func (Curve) Identity() *Point {
+ return &Point{
+ y: fp.One(),
+ z: fp.One(),
+ }
+}
+
+// IsOnCurve returns true if the point lies on the curve.
+func (Curve) IsOnCurve(P *Point) bool {
+ x2, y2, t, t2, z2 := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
+ rhs, lhs := &fp.Elt{}, &fp.Elt{}
+ // Check z != 0
+ eq0 := !fp.IsZero(&P.z)
+
+ fp.Mul(t, &P.ta, &P.tb) // t = ta*tb
+ fp.Sqr(x2, &P.x) // x^2
+ fp.Sqr(y2, &P.y) // y^2
+ fp.Sqr(z2, &P.z) // z^2
+ fp.Sqr(t2, t) // t^2
+ fp.Add(lhs, x2, y2) // x^2 + y^2
+ fp.Mul(rhs, t2, ¶mD) // dt^2
+ fp.Add(rhs, rhs, z2) // z^2 + dt^2
+ fp.Sub(lhs, lhs, rhs) // x^2 + y^2 - (z^2 + dt^2)
+ eq1 := fp.IsZero(lhs)
+
+ fp.Mul(lhs, &P.x, &P.y) // xy
+ fp.Mul(rhs, t, &P.z) // tz
+ fp.Sub(lhs, lhs, rhs) // xy - tz
+ eq2 := fp.IsZero(lhs)
+
+ return eq0 && eq1 && eq2
+}
+
+// Generator returns the generator point.
+func (Curve) Generator() *Point {
+ return &Point{
+ x: genX,
+ y: genY,
+ z: fp.One(),
+ ta: genX,
+ tb: genY,
+ }
+}
+
+// Order returns the number of points in the prime subgroup.
+func (Curve) Order() Scalar { return order }
+
+// Double returns 2P.
+func (Curve) Double(P *Point) *Point { R := *P; R.Double(); return &R }
+
+// Add returns P+Q.
+func (Curve) Add(P, Q *Point) *Point { R := *P; R.Add(Q); return &R }
+
+// ScalarMult returns kP. This function runs in constant time.
+func (e Curve) ScalarMult(k *Scalar, P *Point) *Point {
+ k4 := &Scalar{}
+ k4.divBy4(k)
+ return e.pull(twistCurve{}.ScalarMult(k4, e.push(P)))
+}
+
+// ScalarBaseMult returns kG where G is the generator point. This function runs in constant time.
+func (e Curve) ScalarBaseMult(k *Scalar) *Point {
+ k4 := &Scalar{}
+ k4.divBy4(k)
+ return e.pull(twistCurve{}.ScalarBaseMult(k4))
+}
+
+// CombinedMult returns mG+nP, where G is the generator point. This function is non-constant time.
+func (e Curve) CombinedMult(m, n *Scalar, P *Point) *Point {
+ m4 := &Scalar{}
+ n4 := &Scalar{}
+ m4.divBy4(m)
+ n4.divBy4(n)
+ return e.pull(twistCurve{}.CombinedMult(m4, n4, twistCurve{}.pull(P)))
+}
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go
new file mode 100644
index 0000000000..b1daab851c
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go
@@ -0,0 +1,52 @@
+package goldilocks
+
+import fp "github.com/cloudflare/circl/math/fp448"
+
+func (Curve) pull(P *twistPoint) *Point { return twistCurve{}.push(P) }
+func (twistCurve) pull(P *Point) *twistPoint { return Curve{}.push(P) }
+
+// push sends a point on the Goldilocks curve to a point on the twist curve.
+func (Curve) push(P *Point) *twistPoint {
+ Q := &twistPoint{}
+ Px, Py, Pz := &P.x, &P.y, &P.z
+ a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &fp.Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb
+ fp.Add(e, Px, Py) // x+y
+ fp.Sqr(a, Px) // A = x^2
+ fp.Sqr(b, Py) // B = y^2
+ fp.Sqr(c, Pz) // z^2
+ fp.Add(c, c, c) // C = 2*z^2
+ *d = *a // D = A
+ fp.Sqr(e, e) // (x+y)^2
+ fp.Sub(e, e, a) // (x+y)^2-A
+ fp.Sub(e, e, b) // E = (x+y)^2-A-B
+ fp.Add(h, b, d) // H = B+D
+ fp.Sub(g, b, d) // G = B-D
+ fp.Sub(f, c, h) // F = C-H
+ fp.Mul(&Q.z, f, g) // Z = F * G
+ fp.Mul(&Q.x, e, f) // X = E * F
+ fp.Mul(&Q.y, g, h) // Y = G * H, // T = E * H
+ return Q
+}
+
+// push sends a point on the twist curve to a point on the Goldilocks curve.
+func (twistCurve) push(P *twistPoint) *Point {
+ Q := &Point{}
+ Px, Py, Pz := &P.x, &P.y, &P.z
+ a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &fp.Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb
+ fp.Add(e, Px, Py) // x+y
+ fp.Sqr(a, Px) // A = x^2
+ fp.Sqr(b, Py) // B = y^2
+ fp.Sqr(c, Pz) // z^2
+ fp.Add(c, c, c) // C = 2*z^2
+ fp.Neg(d, a) // D = -A
+ fp.Sqr(e, e) // (x+y)^2
+ fp.Sub(e, e, a) // (x+y)^2-A
+ fp.Sub(e, e, b) // E = (x+y)^2-A-B
+ fp.Add(h, b, d) // H = B+D
+ fp.Sub(g, b, d) // G = B-D
+ fp.Sub(f, c, h) // F = C-H
+ fp.Mul(&Q.z, f, g) // Z = F * G
+ fp.Mul(&Q.x, e, f) // X = E * F
+ fp.Mul(&Q.y, g, h) // Y = G * H, // T = E * H
+ return Q
+}
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go
new file mode 100644
index 0000000000..11f73de054
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go
@@ -0,0 +1,171 @@
+package goldilocks
+
+import (
+ "errors"
+ "fmt"
+
+ fp "github.com/cloudflare/circl/math/fp448"
+)
+
+// Point is a point on the Goldilocks Curve.
+type Point struct{ x, y, z, ta, tb fp.Elt }
+
+func (P Point) String() string {
+ return fmt.Sprintf("x: %v\ny: %v\nz: %v\nta: %v\ntb: %v", P.x, P.y, P.z, P.ta, P.tb)
+}
+
+// FromAffine creates a point from affine coordinates.
+func FromAffine(x, y *fp.Elt) (*Point, error) {
+ P := &Point{
+ x: *x,
+ y: *y,
+ z: fp.One(),
+ ta: *x,
+ tb: *y,
+ }
+ if !(Curve{}).IsOnCurve(P) {
+ return P, errors.New("point not on curve")
+ }
+ return P, nil
+}
+
+// isLessThan returns true if 0 <= x < y, and assumes that slices are of the
+// same length and are interpreted in little-endian order.
+func isLessThan(x, y []byte) bool {
+ i := len(x) - 1
+ for i > 0 && x[i] == y[i] {
+ i--
+ }
+ return x[i] < y[i]
+}
+
+// FromBytes returns a point from the input buffer.
+func FromBytes(in []byte) (*Point, error) {
+ if len(in) < fp.Size+1 {
+ return nil, errors.New("wrong input length")
+ }
+ err := errors.New("invalid decoding")
+ P := &Point{}
+ signX := in[fp.Size] >> 7
+ copy(P.y[:], in[:fp.Size])
+ p := fp.P()
+ if !isLessThan(P.y[:], p[:]) {
+ return nil, err
+ }
+
+ u, v := &fp.Elt{}, &fp.Elt{}
+ one := fp.One()
+ fp.Sqr(u, &P.y) // u = y^2
+ fp.Mul(v, u, ¶mD) // v = dy^2
+ fp.Sub(u, u, &one) // u = y^2-1
+ fp.Sub(v, v, &one) // v = dy^2-1
+ isQR := fp.InvSqrt(&P.x, u, v) // x = sqrt(u/v)
+ if !isQR {
+ return nil, err
+ }
+ fp.Modp(&P.x) // x = x mod p
+ if fp.IsZero(&P.x) && signX == 1 {
+ return nil, err
+ }
+ if signX != (P.x[0] & 1) {
+ fp.Neg(&P.x, &P.x)
+ }
+ P.ta = P.x
+ P.tb = P.y
+ P.z = fp.One()
+ return P, nil
+}
+
+// IsIdentity returns true is P is the identity Point.
+func (P *Point) IsIdentity() bool {
+ return fp.IsZero(&P.x) && !fp.IsZero(&P.y) && !fp.IsZero(&P.z) && P.y == P.z
+}
+
+// IsEqual returns true if P is equivalent to Q.
+func (P *Point) IsEqual(Q *Point) bool {
+ l, r := &fp.Elt{}, &fp.Elt{}
+ fp.Mul(l, &P.x, &Q.z)
+ fp.Mul(r, &Q.x, &P.z)
+ fp.Sub(l, l, r)
+ b := fp.IsZero(l)
+ fp.Mul(l, &P.y, &Q.z)
+ fp.Mul(r, &Q.y, &P.z)
+ fp.Sub(l, l, r)
+ b = b && fp.IsZero(l)
+ fp.Mul(l, &P.ta, &P.tb)
+ fp.Mul(l, l, &Q.z)
+ fp.Mul(r, &Q.ta, &Q.tb)
+ fp.Mul(r, r, &P.z)
+ fp.Sub(l, l, r)
+ b = b && fp.IsZero(l)
+ return b
+}
+
+// Neg obtains the inverse of the Point.
+func (P *Point) Neg() { fp.Neg(&P.x, &P.x); fp.Neg(&P.ta, &P.ta) }
+
+// ToAffine returns the x,y affine coordinates of P.
+func (P *Point) ToAffine() (x, y fp.Elt) {
+ fp.Inv(&P.z, &P.z) // 1/z
+ fp.Mul(&P.x, &P.x, &P.z) // x/z
+ fp.Mul(&P.y, &P.y, &P.z) // y/z
+ fp.Modp(&P.x)
+ fp.Modp(&P.y)
+ fp.SetOne(&P.z)
+ P.ta = P.x
+ P.tb = P.y
+ return P.x, P.y
+}
+
+// ToBytes stores P into a slice of bytes.
+func (P *Point) ToBytes(out []byte) error {
+ if len(out) < fp.Size+1 {
+ return errors.New("invalid decoding")
+ }
+ x, y := P.ToAffine()
+ out[fp.Size] = (x[0] & 1) << 7
+ return fp.ToBytes(out[:fp.Size], &y)
+}
+
+// MarshalBinary encodes the receiver into a binary form and returns the result.
+func (P *Point) MarshalBinary() (data []byte, err error) {
+ data = make([]byte, fp.Size+1)
+ err = P.ToBytes(data[:fp.Size+1])
+ return data, err
+}
+
+// UnmarshalBinary must be able to decode the form generated by MarshalBinary.
+func (P *Point) UnmarshalBinary(data []byte) error { Q, err := FromBytes(data); *P = *Q; return err }
+
+// Double sets P = 2Q.
+func (P *Point) Double() { P.Add(P) }
+
+// Add sets P =P+Q..
+func (P *Point) Add(Q *Point) {
+ // This is formula (5) from "Twisted Edwards Curves Revisited" by
+ // Hisil H., Wong K.KH., Carter G., Dawson E. (2008)
+ // https://doi.org/10.1007/978-3-540-89255-7_20
+ x1, y1, z1, ta1, tb1 := &P.x, &P.y, &P.z, &P.ta, &P.tb
+ x2, y2, z2, ta2, tb2 := &Q.x, &Q.y, &Q.z, &Q.ta, &Q.tb
+ x3, y3, z3, E, H := &P.x, &P.y, &P.z, &P.ta, &P.tb
+ A, B, C, D := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
+ t1, t2, F, G := C, D, &fp.Elt{}, &fp.Elt{}
+ fp.Mul(t1, ta1, tb1) // t1 = ta1*tb1
+ fp.Mul(t2, ta2, tb2) // t2 = ta2*tb2
+ fp.Mul(A, x1, x2) // A = x1*x2
+ fp.Mul(B, y1, y2) // B = y1*y2
+ fp.Mul(C, t1, t2) // t1*t2
+ fp.Mul(C, C, ¶mD) // C = d*t1*t2
+ fp.Mul(D, z1, z2) // D = z1*z2
+ fp.Add(F, x1, y1) // x1+y1
+ fp.Add(E, x2, y2) // x2+y2
+ fp.Mul(E, E, F) // (x1+y1)*(x2+y2)
+ fp.Sub(E, E, A) // (x1+y1)*(x2+y2)-A
+ fp.Sub(E, E, B) // E = (x1+y1)*(x2+y2)-A-B
+ fp.Sub(F, D, C) // F = D-C
+ fp.Add(G, D, C) // G = D+C
+ fp.Sub(H, B, A) // H = B-A
+ fp.Mul(z3, F, G) // Z = F * G
+ fp.Mul(x3, E, F) // X = E * F
+ fp.Mul(y3, G, H) // Y = G * H, T = E * H
+}
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go
new file mode 100644
index 0000000000..f98117b252
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go
@@ -0,0 +1,203 @@
+package goldilocks
+
+import (
+ "encoding/binary"
+ "math/bits"
+)
+
+// ScalarSize is the size (in bytes) of scalars.
+const ScalarSize = 56 // 448 / 8
+
+// _N is the number of 64-bit words to store scalars.
+const _N = 7 // 448 / 64
+
+// Scalar represents a positive integer stored in little-endian order.
+type Scalar [ScalarSize]byte
+
+type scalar64 [_N]uint64
+
+func (z *scalar64) fromScalar(x *Scalar) {
+ z[0] = binary.LittleEndian.Uint64(x[0*8 : 1*8])
+ z[1] = binary.LittleEndian.Uint64(x[1*8 : 2*8])
+ z[2] = binary.LittleEndian.Uint64(x[2*8 : 3*8])
+ z[3] = binary.LittleEndian.Uint64(x[3*8 : 4*8])
+ z[4] = binary.LittleEndian.Uint64(x[4*8 : 5*8])
+ z[5] = binary.LittleEndian.Uint64(x[5*8 : 6*8])
+ z[6] = binary.LittleEndian.Uint64(x[6*8 : 7*8])
+}
+
+func (z *scalar64) toScalar(x *Scalar) {
+ binary.LittleEndian.PutUint64(x[0*8:1*8], z[0])
+ binary.LittleEndian.PutUint64(x[1*8:2*8], z[1])
+ binary.LittleEndian.PutUint64(x[2*8:3*8], z[2])
+ binary.LittleEndian.PutUint64(x[3*8:4*8], z[3])
+ binary.LittleEndian.PutUint64(x[4*8:5*8], z[4])
+ binary.LittleEndian.PutUint64(x[5*8:6*8], z[5])
+ binary.LittleEndian.PutUint64(x[6*8:7*8], z[6])
+}
+
+// add calculates z = x + y. Assumes len(z) > max(len(x),len(y)).
+func add(z, x, y []uint64) uint64 {
+ l, L, zz := len(x), len(y), y
+ if l > L {
+ l, L, zz = L, l, x
+ }
+ c := uint64(0)
+ for i := 0; i < l; i++ {
+ z[i], c = bits.Add64(x[i], y[i], c)
+ }
+ for i := l; i < L; i++ {
+ z[i], c = bits.Add64(zz[i], 0, c)
+ }
+ return c
+}
+
+// sub calculates z = x - y. Assumes len(z) > max(len(x),len(y)).
+func sub(z, x, y []uint64) uint64 {
+ l, L, zz := len(x), len(y), y
+ if l > L {
+ l, L, zz = L, l, x
+ }
+ c := uint64(0)
+ for i := 0; i < l; i++ {
+ z[i], c = bits.Sub64(x[i], y[i], c)
+ }
+ for i := l; i < L; i++ {
+ z[i], c = bits.Sub64(zz[i], 0, c)
+ }
+ return c
+}
+
+// mulWord calculates z = x * y. Assumes len(z) >= len(x)+1.
+func mulWord(z, x []uint64, y uint64) {
+ for i := range z {
+ z[i] = 0
+ }
+ carry := uint64(0)
+ for i := range x {
+ hi, lo := bits.Mul64(x[i], y)
+ lo, cc := bits.Add64(lo, z[i], 0)
+ hi, _ = bits.Add64(hi, 0, cc)
+ z[i], cc = bits.Add64(lo, carry, 0)
+ carry, _ = bits.Add64(hi, 0, cc)
+ }
+ z[len(x)] = carry
+}
+
+// Cmov moves x into z if b=1.
+func (z *scalar64) Cmov(b uint64, x *scalar64) {
+ m := uint64(0) - b
+ for i := range z {
+ z[i] = (z[i] &^ m) | (x[i] & m)
+ }
+}
+
+// leftShift shifts to the left the words of z returning the more significant word.
+func (z *scalar64) leftShift(low uint64) uint64 {
+ high := z[_N-1]
+ for i := _N - 1; i > 0; i-- {
+ z[i] = z[i-1]
+ }
+ z[0] = low
+ return high
+}
+
+// reduceOneWord calculates z = z + 2^448*x such that the result fits in a Scalar.
+func (z *scalar64) reduceOneWord(x uint64) {
+ prod := (&scalar64{})[:]
+ mulWord(prod, residue448[:], x)
+ cc := add(z[:], z[:], prod)
+ mulWord(prod, residue448[:], cc)
+ add(z[:], z[:], prod)
+}
+
+// modOrder reduces z mod order.
+func (z *scalar64) modOrder() {
+ var o64, x scalar64
+ o64.fromScalar(&order)
+ // Performs: while (z >= order) { z = z-order }
+ // At most 8 (eight) iterations reduce 3 bits by subtracting.
+ for i := 0; i < 8; i++ {
+ c := sub(x[:], z[:], o64[:]) // (c || x) = z-order
+ z.Cmov(1-c, &x) // if c != 0 { z = x }
+ }
+}
+
+// FromBytes stores z = x mod order, where x is a number stored in little-endian order.
+func (z *Scalar) FromBytes(x []byte) {
+ n := len(x)
+ nCeil := (n + 7) >> 3
+ for i := range z {
+ z[i] = 0
+ }
+ if nCeil < _N {
+ copy(z[:], x)
+ return
+ }
+ copy(z[:], x[8*(nCeil-_N):])
+ var z64 scalar64
+ z64.fromScalar(z)
+ for i := nCeil - _N - 1; i >= 0; i-- {
+ low := binary.LittleEndian.Uint64(x[8*i:])
+ high := z64.leftShift(low)
+ z64.reduceOneWord(high)
+ }
+ z64.modOrder()
+ z64.toScalar(z)
+}
+
+// divBy4 calculates z = x/4 mod order.
+func (z *Scalar) divBy4(x *Scalar) { z.Mul(x, &invFour) }
+
+// Red reduces z mod order.
+func (z *Scalar) Red() { var t scalar64; t.fromScalar(z); t.modOrder(); t.toScalar(z) }
+
+// Neg calculates z = -z mod order.
+func (z *Scalar) Neg() { z.Sub(&order, z) }
+
+// Add calculates z = x+y mod order.
+func (z *Scalar) Add(x, y *Scalar) {
+ var z64, x64, y64, t scalar64
+ x64.fromScalar(x)
+ y64.fromScalar(y)
+ c := add(z64[:], x64[:], y64[:])
+ add(t[:], z64[:], residue448[:])
+ z64.Cmov(c, &t)
+ z64.modOrder()
+ z64.toScalar(z)
+}
+
+// Sub calculates z = x-y mod order.
+func (z *Scalar) Sub(x, y *Scalar) {
+ var z64, x64, y64, t scalar64
+ x64.fromScalar(x)
+ y64.fromScalar(y)
+ c := sub(z64[:], x64[:], y64[:])
+ sub(t[:], z64[:], residue448[:])
+ z64.Cmov(c, &t)
+ z64.modOrder()
+ z64.toScalar(z)
+}
+
+// Mul calculates z = x*y mod order.
+func (z *Scalar) Mul(x, y *Scalar) {
+ var z64, x64, y64 scalar64
+ prod := (&[_N + 1]uint64{})[:]
+ x64.fromScalar(x)
+ y64.fromScalar(y)
+ mulWord(prod, x64[:], y64[_N-1])
+ copy(z64[:], prod[:_N])
+ z64.reduceOneWord(prod[_N])
+ for i := _N - 2; i >= 0; i-- {
+ h := z64.leftShift(0)
+ z64.reduceOneWord(h)
+ mulWord(prod, x64[:], y64[i])
+ c := add(z64[:], z64[:], prod[:_N])
+ z64.reduceOneWord(prod[_N] + c)
+ }
+ z64.modOrder()
+ z64.toScalar(z)
+}
+
+// IsZero returns true if z=0.
+func (z *Scalar) IsZero() bool { z.Red(); return *z == Scalar{} }
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go
new file mode 100644
index 0000000000..83d7cdadd3
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go
@@ -0,0 +1,138 @@
+package goldilocks
+
+import (
+ "crypto/subtle"
+ "math/bits"
+
+ "github.com/cloudflare/circl/internal/conv"
+ "github.com/cloudflare/circl/math"
+ fp "github.com/cloudflare/circl/math/fp448"
+)
+
+// twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogenous to Goldilocks.
+type twistCurve struct{}
+
+// Identity returns the identity point.
+func (twistCurve) Identity() *twistPoint {
+ return &twistPoint{
+ y: fp.One(),
+ z: fp.One(),
+ }
+}
+
+// subYDiv16 update x = (x - y) / 16.
+func subYDiv16(x *scalar64, y int64) {
+ s := uint64(y >> 63)
+ x0, b0 := bits.Sub64((*x)[0], uint64(y), 0)
+ x1, b1 := bits.Sub64((*x)[1], s, b0)
+ x2, b2 := bits.Sub64((*x)[2], s, b1)
+ x3, b3 := bits.Sub64((*x)[3], s, b2)
+ x4, b4 := bits.Sub64((*x)[4], s, b3)
+ x5, b5 := bits.Sub64((*x)[5], s, b4)
+ x6, _ := bits.Sub64((*x)[6], s, b5)
+ x[0] = (x0 >> 4) | (x1 << 60)
+ x[1] = (x1 >> 4) | (x2 << 60)
+ x[2] = (x2 >> 4) | (x3 << 60)
+ x[3] = (x3 >> 4) | (x4 << 60)
+ x[4] = (x4 >> 4) | (x5 << 60)
+ x[5] = (x5 >> 4) | (x6 << 60)
+ x[6] = (x6 >> 4)
+}
+
+func recodeScalar(d *[113]int8, k *Scalar) {
+ var k64 scalar64
+ k64.fromScalar(k)
+ for i := 0; i < 112; i++ {
+ d[i] = int8((k64[0] & 0x1f) - 16)
+ subYDiv16(&k64, int64(d[i]))
+ }
+ d[112] = int8(k64[0])
+}
+
+// ScalarMult returns kP.
+func (e twistCurve) ScalarMult(k *Scalar, P *twistPoint) *twistPoint {
+ var TabP [8]preTwistPointProy
+ var S preTwistPointProy
+ var d [113]int8
+
+ var isZero int
+ if k.IsZero() {
+ isZero = 1
+ }
+ subtle.ConstantTimeCopy(isZero, k[:], order[:])
+
+ minusK := *k
+ isEven := 1 - int(k[0]&0x1)
+ minusK.Neg()
+ subtle.ConstantTimeCopy(isEven, k[:], minusK[:])
+ recodeScalar(&d, k)
+
+ P.oddMultiples(TabP[:])
+ Q := e.Identity()
+ for i := 112; i >= 0; i-- {
+ Q.Double()
+ Q.Double()
+ Q.Double()
+ Q.Double()
+ mask := d[i] >> 7
+ absDi := (d[i] + mask) ^ mask
+ inx := int32((absDi - 1) >> 1)
+ sig := int((d[i] >> 7) & 0x1)
+ for j := range TabP {
+ S.cmov(&TabP[j], uint(subtle.ConstantTimeEq(inx, int32(j))))
+ }
+ S.cneg(sig)
+ Q.mixAdd(&S)
+ }
+ Q.cneg(uint(isEven))
+ return Q
+}
+
+const (
+ omegaFix = 7
+ omegaVar = 5
+)
+
+// CombinedMult returns mG+nP.
+func (e twistCurve) CombinedMult(m, n *Scalar, P *twistPoint) *twistPoint {
+ nafFix := math.OmegaNAF(conv.BytesLe2BigInt(m[:]), omegaFix)
+ nafVar := math.OmegaNAF(conv.BytesLe2BigInt(n[:]), omegaVar)
+
+ if len(nafFix) > len(nafVar) {
+ nafVar = append(nafVar, make([]int32, len(nafFix)-len(nafVar))...)
+ } else if len(nafFix) < len(nafVar) {
+ nafFix = append(nafFix, make([]int32, len(nafVar)-len(nafFix))...)
+ }
+
+ var TabQ [1 << (omegaVar - 2)]preTwistPointProy
+ P.oddMultiples(TabQ[:])
+ Q := e.Identity()
+ for i := len(nafFix) - 1; i >= 0; i-- {
+ Q.Double()
+ // Generator point
+ if nafFix[i] != 0 {
+ idxM := absolute(nafFix[i]) >> 1
+ R := tabVerif[idxM]
+ if nafFix[i] < 0 {
+ R.neg()
+ }
+ Q.mixAddZ1(&R)
+ }
+ // Variable input point
+ if nafVar[i] != 0 {
+ idxN := absolute(nafVar[i]) >> 1
+ S := TabQ[idxN]
+ if nafVar[i] < 0 {
+ S.neg()
+ }
+ Q.mixAdd(&S)
+ }
+ }
+ return Q
+}
+
+// absolute returns always a positive value.
+func absolute(x int32) int32 {
+ mask := x >> 31
+ return (x + mask) ^ mask
+}
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go
new file mode 100644
index 0000000000..c55db77b06
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go
@@ -0,0 +1,135 @@
+package goldilocks
+
+import (
+ "fmt"
+
+ fp "github.com/cloudflare/circl/math/fp448"
+)
+
+type twistPoint struct{ x, y, z, ta, tb fp.Elt }
+
+type preTwistPointAffine struct{ addYX, subYX, dt2 fp.Elt }
+
+type preTwistPointProy struct {
+ preTwistPointAffine
+ z2 fp.Elt
+}
+
+func (P *twistPoint) String() string {
+ return fmt.Sprintf("x: %v\ny: %v\nz: %v\nta: %v\ntb: %v", P.x, P.y, P.z, P.ta, P.tb)
+}
+
+// cneg conditionally negates the point if b=1.
+func (P *twistPoint) cneg(b uint) {
+ t := &fp.Elt{}
+ fp.Neg(t, &P.x)
+ fp.Cmov(&P.x, t, b)
+ fp.Neg(t, &P.ta)
+ fp.Cmov(&P.ta, t, b)
+}
+
+// Double updates P with 2P.
+func (P *twistPoint) Double() {
+ // This is formula (7) from "Twisted Edwards Curves Revisited" by
+ // Hisil H., Wong K.KH., Carter G., Dawson E. (2008)
+ // https://doi.org/10.1007/978-3-540-89255-7_20
+ Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb
+ a, b, c, e, f, g, h := Px, Py, Pz, Pta, Px, Py, Ptb
+ fp.Add(e, Px, Py) // x+y
+ fp.Sqr(a, Px) // A = x^2
+ fp.Sqr(b, Py) // B = y^2
+ fp.Sqr(c, Pz) // z^2
+ fp.Add(c, c, c) // C = 2*z^2
+ fp.Add(h, a, b) // H = A+B
+ fp.Sqr(e, e) // (x+y)^2
+ fp.Sub(e, e, h) // E = (x+y)^2-A-B
+ fp.Sub(g, b, a) // G = B-A
+ fp.Sub(f, c, g) // F = C-G
+ fp.Mul(Pz, f, g) // Z = F * G
+ fp.Mul(Px, e, f) // X = E * F
+ fp.Mul(Py, g, h) // Y = G * H, T = E * H
+}
+
+// mixAdd calculates P= P+Q, where Q is a precomputed point with Z_Q = 1.
+func (P *twistPoint) mixAddZ1(Q *preTwistPointAffine) {
+ fp.Add(&P.z, &P.z, &P.z) // D = 2*z1 (z2=1)
+ P.coreAddition(Q)
+}
+
+// coreAddition calculates P=P+Q for curves with A=-1.
+func (P *twistPoint) coreAddition(Q *preTwistPointAffine) {
+ // This is the formula following (5) from "Twisted Edwards Curves Revisited" by
+ // Hisil H., Wong K.KH., Carter G., Dawson E. (2008)
+ // https://doi.org/10.1007/978-3-540-89255-7_20
+ Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb
+ addYX2, subYX2, dt2 := &Q.addYX, &Q.subYX, &Q.dt2
+ a, b, c, d, e, f, g, h := Px, Py, &fp.Elt{}, Pz, Pta, Px, Py, Ptb
+ fp.Mul(c, Pta, Ptb) // t1 = ta*tb
+ fp.Sub(h, Py, Px) // y1-x1
+ fp.Add(b, Py, Px) // y1+x1
+ fp.Mul(a, h, subYX2) // A = (y1-x1)*(y2-x2)
+ fp.Mul(b, b, addYX2) // B = (y1+x1)*(y2+x2)
+ fp.Mul(c, c, dt2) // C = 2*D*t1*t2
+ fp.Sub(e, b, a) // E = B-A
+ fp.Add(h, b, a) // H = B+A
+ fp.Sub(f, d, c) // F = D-C
+ fp.Add(g, d, c) // G = D+C
+ fp.Mul(Pz, f, g) // Z = F * G
+ fp.Mul(Px, e, f) // X = E * F
+ fp.Mul(Py, g, h) // Y = G * H, T = E * H
+}
+
+func (P *preTwistPointAffine) neg() {
+ P.addYX, P.subYX = P.subYX, P.addYX
+ fp.Neg(&P.dt2, &P.dt2)
+}
+
+func (P *preTwistPointAffine) cneg(b int) {
+ t := &fp.Elt{}
+ fp.Cswap(&P.addYX, &P.subYX, uint(b))
+ fp.Neg(t, &P.dt2)
+ fp.Cmov(&P.dt2, t, uint(b))
+}
+
+func (P *preTwistPointAffine) cmov(Q *preTwistPointAffine, b uint) {
+ fp.Cmov(&P.addYX, &Q.addYX, b)
+ fp.Cmov(&P.subYX, &Q.subYX, b)
+ fp.Cmov(&P.dt2, &Q.dt2, b)
+}
+
+// mixAdd calculates P= P+Q, where Q is a precomputed point with Z_Q != 1.
+func (P *twistPoint) mixAdd(Q *preTwistPointProy) {
+ fp.Mul(&P.z, &P.z, &Q.z2) // D = 2*z1*z2
+ P.coreAddition(&Q.preTwistPointAffine)
+}
+
+// oddMultiples calculates T[i] = (2*i-1)P for 0 < i < len(T).
+func (P *twistPoint) oddMultiples(T []preTwistPointProy) {
+ if n := len(T); n > 0 {
+ T[0].FromTwistPoint(P)
+ _2P := *P
+ _2P.Double()
+ R := &preTwistPointProy{}
+ R.FromTwistPoint(&_2P)
+ for i := 1; i < n; i++ {
+ P.mixAdd(R)
+ T[i].FromTwistPoint(P)
+ }
+ }
+}
+
+// cmov conditionally moves Q into P if b=1.
+func (P *preTwistPointProy) cmov(Q *preTwistPointProy, b uint) {
+ P.preTwistPointAffine.cmov(&Q.preTwistPointAffine, b)
+ fp.Cmov(&P.z2, &Q.z2, b)
+}
+
+// FromTwistPoint precomputes some coordinates of Q for missed addition.
+func (P *preTwistPointProy) FromTwistPoint(Q *twistPoint) {
+ fp.Add(&P.addYX, &Q.y, &Q.x) // addYX = X + Y
+ fp.Sub(&P.subYX, &Q.y, &Q.x) // subYX = Y - X
+ fp.Mul(&P.dt2, &Q.ta, &Q.tb) // T = ta*tb
+ fp.Mul(&P.dt2, &P.dt2, ¶mDTwist) // D*T
+ fp.Add(&P.dt2, &P.dt2, &P.dt2) // dt2 = 2*D*T
+ fp.Add(&P.z2, &Q.z, &Q.z) // z2 = 2*Z
+}
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go
new file mode 100644
index 0000000000..ed432e02c7
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go
@@ -0,0 +1,216 @@
+package goldilocks
+
+import fp "github.com/cloudflare/circl/math/fp448"
+
+var tabFixMult = [fxV][fx2w1]preTwistPointAffine{
+ {
+ {
+ addYX: fp.Elt{0x65, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2b, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05},
+ subYX: fp.Elt{0x64, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2d, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05},
+ dt2: fp.Elt{0x1a, 0x33, 0xea, 0x64, 0x45, 0x1c, 0xdf, 0x17, 0x1d, 0x16, 0x34, 0x28, 0xd6, 0x61, 0x19, 0x67, 0x79, 0xb4, 0x13, 0xcf, 0x3e, 0x7c, 0x0e, 0x72, 0xda, 0xf1, 0x5f, 0xda, 0xe6, 0xcf, 0x42, 0xd3, 0xb6, 0x17, 0xc2, 0x68, 0x13, 0x2d, 0xd9, 0x60, 0x3e, 0xae, 0xf0, 0x5b, 0x96, 0xf0, 0xcd, 0xaf, 0xea, 0xb7, 0x0d, 0x59, 0x16, 0xa7, 0xff, 0x55},
+ },
+ {
+ addYX: fp.Elt{0xca, 0xd8, 0x7d, 0x86, 0x1a, 0xef, 0xad, 0x11, 0xe3, 0x27, 0x41, 0x7e, 0x7f, 0x3e, 0xa9, 0xd2, 0xb5, 0x4e, 0x50, 0xe0, 0x77, 0x91, 0xc2, 0x13, 0x52, 0x73, 0x41, 0x09, 0xa6, 0x57, 0x9a, 0xc8, 0xa8, 0x90, 0x9d, 0x26, 0x14, 0xbb, 0xa1, 0x2a, 0xf7, 0x45, 0x43, 0x4e, 0xea, 0x35, 0x62, 0xe1, 0x08, 0x85, 0x46, 0xb8, 0x24, 0x05, 0x2d, 0xab},
+ subYX: fp.Elt{0x9b, 0xe6, 0xd3, 0xe5, 0xfe, 0x50, 0x36, 0x3c, 0x3c, 0x6d, 0x74, 0x1d, 0x74, 0xc0, 0xde, 0x5b, 0x45, 0x27, 0xe5, 0x12, 0xee, 0x63, 0x35, 0x6b, 0x13, 0xe2, 0x41, 0x6b, 0x3a, 0x05, 0x2b, 0xb1, 0x89, 0x26, 0xb6, 0xc6, 0xd1, 0x84, 0xff, 0x0e, 0x9b, 0xa3, 0xfb, 0x21, 0x36, 0x6b, 0x01, 0xf7, 0x9f, 0x7c, 0xeb, 0xf5, 0x18, 0x7a, 0x2a, 0x70},
+ dt2: fp.Elt{0x09, 0xad, 0x99, 0x1a, 0x38, 0xd3, 0xdf, 0x22, 0x37, 0x32, 0x61, 0x8b, 0xf3, 0x19, 0x48, 0x08, 0xe8, 0x49, 0xb6, 0x4a, 0xa7, 0xed, 0xa4, 0xa2, 0xee, 0x86, 0xd7, 0x31, 0x5e, 0xce, 0x95, 0x76, 0x86, 0x42, 0x1c, 0x9d, 0x07, 0x14, 0x8c, 0x34, 0x18, 0x9c, 0x6d, 0x3a, 0xdf, 0xa9, 0xe8, 0x36, 0x7e, 0xe4, 0x95, 0xbe, 0xb5, 0x09, 0xf8, 0x9c},
+ },
+ {
+ addYX: fp.Elt{0x51, 0xdb, 0x49, 0xa8, 0x9f, 0xe3, 0xd7, 0xec, 0x0d, 0x0f, 0x49, 0xe8, 0xb6, 0xc5, 0x0f, 0x5a, 0x1c, 0xce, 0x54, 0x0d, 0xb1, 0x8d, 0x5b, 0xbf, 0xf4, 0xaa, 0x34, 0x77, 0xc4, 0x5d, 0x59, 0xb6, 0xc5, 0x0e, 0x5a, 0xd8, 0x5b, 0x30, 0xc2, 0x1d, 0xec, 0x85, 0x1c, 0x42, 0xbe, 0x24, 0x2e, 0x50, 0x55, 0x44, 0xb2, 0x3a, 0x01, 0xaa, 0x98, 0xfb},
+ subYX: fp.Elt{0xe7, 0x29, 0xb7, 0xd0, 0xaa, 0x4f, 0x32, 0x53, 0x56, 0xde, 0xbc, 0xd1, 0x92, 0x5d, 0x19, 0xbe, 0xa3, 0xe3, 0x75, 0x48, 0xe0, 0x7a, 0x1b, 0x54, 0x7a, 0xb7, 0x41, 0x77, 0x84, 0x38, 0xdd, 0x14, 0x9f, 0xca, 0x3f, 0xa3, 0xc8, 0xa7, 0x04, 0x70, 0xf1, 0x4d, 0x3d, 0xb3, 0x84, 0x79, 0xcb, 0xdb, 0xe4, 0xc5, 0x42, 0x9b, 0x57, 0x19, 0xf1, 0x2d},
+ dt2: fp.Elt{0x20, 0xb4, 0x94, 0x9e, 0xdf, 0x31, 0x44, 0x0b, 0xc9, 0x7b, 0x75, 0x40, 0x9d, 0xd1, 0x96, 0x39, 0x70, 0x71, 0x15, 0xc8, 0x93, 0xd5, 0xc5, 0xe5, 0xba, 0xfe, 0xee, 0x08, 0x6a, 0x98, 0x0a, 0x1b, 0xb2, 0xaa, 0x3a, 0xf4, 0xa4, 0x79, 0xf9, 0x8e, 0x4d, 0x65, 0x10, 0x9b, 0x3a, 0x6e, 0x7c, 0x87, 0x94, 0x92, 0x11, 0x65, 0xbf, 0x1a, 0x09, 0xde},
+ },
+ {
+ addYX: fp.Elt{0xf3, 0x84, 0x76, 0x77, 0xa5, 0x6b, 0x27, 0x3b, 0x83, 0x3d, 0xdf, 0xa0, 0xeb, 0x32, 0x6d, 0x58, 0x81, 0x57, 0x64, 0xc2, 0x21, 0x7c, 0x9b, 0xea, 0xe6, 0xb0, 0x93, 0xf9, 0xe7, 0xc3, 0xed, 0x5a, 0x8e, 0xe2, 0xb4, 0x72, 0x76, 0x66, 0x0f, 0x22, 0x29, 0x94, 0x3e, 0x63, 0x48, 0x5e, 0x80, 0xcb, 0xac, 0xfa, 0x95, 0xb6, 0x4b, 0xc4, 0x95, 0x33},
+ subYX: fp.Elt{0x0c, 0x55, 0xd1, 0x5e, 0x5f, 0xbf, 0xbf, 0xe2, 0x4c, 0xfc, 0x37, 0x4a, 0xc4, 0xb1, 0xf4, 0x83, 0x61, 0x93, 0x60, 0x8e, 0x9f, 0x31, 0xf0, 0xa0, 0x41, 0xff, 0x1d, 0xe2, 0x7f, 0xca, 0x40, 0xd6, 0x88, 0xe8, 0x91, 0x61, 0xe2, 0x11, 0x18, 0x83, 0xf3, 0x25, 0x2f, 0x3f, 0x49, 0x40, 0xd4, 0x83, 0xe2, 0xd7, 0x74, 0x6a, 0x16, 0x86, 0x4e, 0xab},
+ dt2: fp.Elt{0xdd, 0x58, 0x65, 0xd8, 0x9f, 0xdd, 0x70, 0x7f, 0x0f, 0xec, 0xbd, 0x5c, 0x5c, 0x9b, 0x7e, 0x1b, 0x9f, 0x79, 0x36, 0x1f, 0xfd, 0x79, 0x10, 0x1c, 0x52, 0xf3, 0x22, 0xa4, 0x1f, 0x71, 0x6e, 0x63, 0x14, 0xf4, 0xa7, 0x3e, 0xbe, 0xad, 0x43, 0x30, 0x38, 0x8c, 0x29, 0xc6, 0xcf, 0x50, 0x75, 0x21, 0xe5, 0x78, 0xfd, 0xb0, 0x9a, 0xc4, 0x6d, 0xd4},
+ },
+ },
+ {
+ {
+ addYX: fp.Elt{0x7a, 0xa1, 0x38, 0xa6, 0xfd, 0x0e, 0x96, 0xd5, 0x26, 0x76, 0x86, 0x70, 0x80, 0x30, 0xa6, 0x67, 0xeb, 0xf4, 0x39, 0xdb, 0x22, 0xf5, 0x9f, 0x98, 0xe4, 0xb5, 0x3a, 0x0c, 0x59, 0xbf, 0x85, 0xc6, 0xf0, 0x0b, 0x1c, 0x41, 0x38, 0x09, 0x01, 0xdb, 0xd6, 0x3c, 0xb7, 0xf1, 0x08, 0x6b, 0x4b, 0x9e, 0x63, 0x53, 0x83, 0xd3, 0xab, 0xa3, 0x72, 0x0d},
+ subYX: fp.Elt{0x84, 0x68, 0x25, 0xe8, 0xe9, 0x8f, 0x91, 0xbf, 0xf7, 0xa4, 0x30, 0xae, 0xea, 0x9f, 0xdd, 0x56, 0x64, 0x09, 0xc9, 0x54, 0x68, 0x4e, 0x33, 0xc5, 0x6f, 0x7b, 0x2d, 0x52, 0x2e, 0x42, 0xbe, 0xbe, 0xf5, 0x64, 0xbf, 0x77, 0x54, 0xdf, 0xb0, 0x10, 0xd2, 0x16, 0x5d, 0xce, 0xaf, 0x9f, 0xfb, 0xa3, 0x63, 0x50, 0xcb, 0xc0, 0xd0, 0x88, 0x44, 0xa3},
+ dt2: fp.Elt{0xc3, 0x8b, 0xa5, 0xf1, 0x44, 0xe4, 0x41, 0xcd, 0x75, 0xe3, 0x17, 0x69, 0x5b, 0xb9, 0xbb, 0xee, 0x82, 0xbb, 0xce, 0x57, 0xdf, 0x2a, 0x9c, 0x12, 0xab, 0x66, 0x08, 0x68, 0x05, 0x1b, 0x87, 0xee, 0x5d, 0x1e, 0x18, 0x14, 0x22, 0x4b, 0x99, 0x61, 0x75, 0x28, 0xe7, 0x65, 0x1c, 0x36, 0xb6, 0x18, 0x09, 0xa8, 0xdf, 0xef, 0x30, 0x35, 0xbc, 0x58},
+ },
+ {
+ addYX: fp.Elt{0xc5, 0xd3, 0x0e, 0x6f, 0xaf, 0x06, 0x69, 0xc4, 0x07, 0x9e, 0x58, 0x6e, 0x3f, 0x49, 0xd9, 0x0a, 0x3c, 0x2c, 0x37, 0xcd, 0x27, 0x4d, 0x87, 0x91, 0x7a, 0xb0, 0x28, 0xad, 0x2f, 0x68, 0x92, 0x05, 0x97, 0xf1, 0x30, 0x5f, 0x4c, 0x10, 0x20, 0x30, 0xd3, 0x08, 0x3f, 0xc1, 0xc6, 0xb7, 0xb5, 0xd1, 0x71, 0x7b, 0xa8, 0x0a, 0xd8, 0xf5, 0x17, 0xcf},
+ subYX: fp.Elt{0x64, 0xd4, 0x8f, 0x91, 0x40, 0xab, 0x6e, 0x1a, 0x62, 0x83, 0xdc, 0xd7, 0x30, 0x1a, 0x4a, 0x2a, 0x4c, 0x54, 0x86, 0x19, 0x81, 0x5d, 0x04, 0x52, 0xa3, 0xca, 0x82, 0x38, 0xdc, 0x1e, 0xf0, 0x7a, 0x78, 0x76, 0x49, 0x4f, 0x71, 0xc4, 0x74, 0x2f, 0xf0, 0x5b, 0x2e, 0x5e, 0xac, 0xef, 0x17, 0xe4, 0x8e, 0x6e, 0xed, 0x43, 0x23, 0x61, 0x99, 0x49},
+ dt2: fp.Elt{0x64, 0x90, 0x72, 0x76, 0xf8, 0x2c, 0x7d, 0x57, 0xf9, 0x30, 0x5e, 0x7a, 0x10, 0x74, 0x19, 0x39, 0xd9, 0xaf, 0x0a, 0xf1, 0x43, 0xed, 0x88, 0x9c, 0x8b, 0xdc, 0x9b, 0x1c, 0x90, 0xe7, 0xf7, 0xa3, 0xa5, 0x0d, 0xc6, 0xbc, 0x30, 0xfb, 0x91, 0x1a, 0x51, 0xba, 0x2d, 0xbe, 0x89, 0xdf, 0x1d, 0xdc, 0x53, 0xa8, 0x82, 0x8a, 0xd3, 0x8d, 0x16, 0x68},
+ },
+ {
+ addYX: fp.Elt{0xef, 0x5c, 0xe3, 0x74, 0xbf, 0x13, 0x4a, 0xbf, 0x66, 0x73, 0x64, 0xb7, 0xd4, 0xce, 0x98, 0x82, 0x05, 0xfa, 0x98, 0x0c, 0x0a, 0xae, 0xe5, 0x6b, 0x9f, 0xac, 0xbb, 0x6e, 0x1f, 0xcf, 0xff, 0xa6, 0x71, 0x9a, 0xa8, 0x7a, 0x9e, 0x64, 0x1f, 0x20, 0x4a, 0x61, 0xa2, 0xd6, 0x50, 0xe3, 0xba, 0x81, 0x0c, 0x50, 0x59, 0x69, 0x59, 0x15, 0x55, 0xdb},
+ subYX: fp.Elt{0xe8, 0x77, 0x4d, 0xe8, 0x66, 0x3d, 0xc1, 0x00, 0x3c, 0xf2, 0x25, 0x00, 0xdc, 0xb2, 0xe5, 0x9b, 0x12, 0x89, 0xf3, 0xd6, 0xea, 0x85, 0x60, 0xfe, 0x67, 0x91, 0xfd, 0x04, 0x7c, 0xe0, 0xf1, 0x86, 0x06, 0x11, 0x66, 0xee, 0xd4, 0xd5, 0xbe, 0x3b, 0x0f, 0xe3, 0x59, 0xb3, 0x4f, 0x00, 0xb6, 0xce, 0x80, 0xc1, 0x61, 0xf7, 0xaf, 0x04, 0x6a, 0x3c},
+ dt2: fp.Elt{0x00, 0xd7, 0x32, 0x93, 0x67, 0x70, 0x6f, 0xd7, 0x69, 0xab, 0xb1, 0xd3, 0xdc, 0xd6, 0xa8, 0xdd, 0x35, 0x25, 0xca, 0xd3, 0x8a, 0x6d, 0xce, 0xfb, 0xfd, 0x2b, 0x83, 0xf0, 0xd4, 0xac, 0x66, 0xfb, 0x72, 0x87, 0x7e, 0x55, 0xb7, 0x91, 0x58, 0x10, 0xc3, 0x11, 0x7e, 0x15, 0xfe, 0x7c, 0x55, 0x90, 0xa3, 0x9e, 0xed, 0x9a, 0x7f, 0xa7, 0xb7, 0xeb},
+ },
+ {
+ addYX: fp.Elt{0x25, 0x0f, 0xc2, 0x09, 0x9c, 0x10, 0xc8, 0x7c, 0x93, 0xa7, 0xbe, 0xe9, 0x26, 0x25, 0x7c, 0x21, 0xfe, 0xe7, 0x5f, 0x3c, 0x02, 0x83, 0xa7, 0x9e, 0xdf, 0xc0, 0x94, 0x2b, 0x7d, 0x1a, 0xd0, 0x1d, 0xcc, 0x2e, 0x7d, 0xd4, 0x85, 0xe7, 0xc1, 0x15, 0x66, 0xd6, 0xd6, 0x32, 0xb8, 0xf7, 0x63, 0xaa, 0x3b, 0xa5, 0xea, 0x49, 0xad, 0x88, 0x9b, 0x66},
+ subYX: fp.Elt{0x09, 0x97, 0x79, 0x36, 0x41, 0x56, 0x9b, 0xdf, 0x15, 0xd8, 0x43, 0x28, 0x17, 0x5b, 0x96, 0xc9, 0xcf, 0x39, 0x1f, 0x13, 0xf7, 0x4d, 0x1d, 0x1f, 0xda, 0x51, 0x56, 0xe7, 0x0a, 0x5a, 0x65, 0xb6, 0x2a, 0x87, 0x49, 0x86, 0xc2, 0x2b, 0xcd, 0xfe, 0x07, 0xf6, 0x4c, 0xe2, 0x1d, 0x9b, 0xd8, 0x82, 0x09, 0x5b, 0x11, 0x10, 0x62, 0x56, 0x89, 0xbd},
+ dt2: fp.Elt{0xd9, 0x15, 0x73, 0xf2, 0x96, 0x35, 0x53, 0xb0, 0xe7, 0xa8, 0x0b, 0x93, 0x35, 0x0b, 0x3a, 0x00, 0xf5, 0x18, 0xb1, 0xc3, 0x12, 0x3f, 0x91, 0x17, 0xc1, 0x4c, 0x15, 0x5a, 0x86, 0x92, 0x11, 0xbd, 0x44, 0x40, 0x5a, 0x7b, 0x15, 0x89, 0xba, 0xc1, 0xc1, 0xbc, 0x43, 0x45, 0xe6, 0x52, 0x02, 0x73, 0x0a, 0xd0, 0x2a, 0x19, 0xda, 0x47, 0xa8, 0xff},
+ },
+ },
+}
+
+// tabVerif contains the odd multiples of P. The entry T[i] = (2i+1)P, where
+// P = phi(G) and G is the generator of the Goldilocks curve, and phi is a
+// 4-degree isogeny.
+var tabVerif = [1 << (omegaFix - 2)]preTwistPointAffine{
+ { /* 1P*/
+ addYX: fp.Elt{0x65, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2b, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05},
+ subYX: fp.Elt{0x64, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2d, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05},
+ dt2: fp.Elt{0x1a, 0x33, 0xea, 0x64, 0x45, 0x1c, 0xdf, 0x17, 0x1d, 0x16, 0x34, 0x28, 0xd6, 0x61, 0x19, 0x67, 0x79, 0xb4, 0x13, 0xcf, 0x3e, 0x7c, 0x0e, 0x72, 0xda, 0xf1, 0x5f, 0xda, 0xe6, 0xcf, 0x42, 0xd3, 0xb6, 0x17, 0xc2, 0x68, 0x13, 0x2d, 0xd9, 0x60, 0x3e, 0xae, 0xf0, 0x5b, 0x96, 0xf0, 0xcd, 0xaf, 0xea, 0xb7, 0x0d, 0x59, 0x16, 0xa7, 0xff, 0x55},
+ },
+ { /* 3P*/
+ addYX: fp.Elt{0xd1, 0xe9, 0xa8, 0x33, 0x20, 0x76, 0x18, 0x08, 0x45, 0x2a, 0xc9, 0x67, 0x2a, 0xc3, 0x15, 0x24, 0xf9, 0x74, 0x21, 0x30, 0x99, 0x59, 0x8b, 0xb2, 0xf0, 0xa4, 0x07, 0xe2, 0x6a, 0x36, 0x8d, 0xd9, 0xd2, 0x4a, 0x7f, 0x73, 0x50, 0x39, 0x3d, 0xaa, 0xa7, 0x51, 0x73, 0x0d, 0x2b, 0x8b, 0x96, 0x47, 0xac, 0x3c, 0x5d, 0xaa, 0x39, 0x9c, 0xcf, 0xd5},
+ subYX: fp.Elt{0x6b, 0x11, 0x5d, 0x1a, 0xf9, 0x41, 0x9d, 0xc5, 0x30, 0x3e, 0xad, 0x25, 0x2c, 0x04, 0x45, 0xea, 0xcc, 0x67, 0x07, 0x85, 0xe9, 0xda, 0x0e, 0xb5, 0x40, 0xb7, 0x32, 0xb4, 0x49, 0xdd, 0xff, 0xaa, 0xfc, 0xbb, 0x19, 0xca, 0x8b, 0x79, 0x2b, 0x8f, 0x8d, 0x00, 0x33, 0xc2, 0xad, 0xe9, 0xd3, 0x12, 0xa8, 0xaa, 0x87, 0x62, 0xad, 0x2d, 0xff, 0xa4},
+ dt2: fp.Elt{0xb0, 0xaf, 0x3b, 0xea, 0xf0, 0x42, 0x0b, 0x5e, 0x88, 0xd3, 0x98, 0x08, 0x87, 0x59, 0x72, 0x0a, 0xc2, 0xdf, 0xcb, 0x7f, 0x59, 0xb5, 0x4c, 0x63, 0x68, 0xe8, 0x41, 0x38, 0x67, 0x4f, 0xe9, 0xc6, 0xb2, 0x6b, 0x08, 0xa7, 0xf7, 0x0e, 0xcd, 0xea, 0xca, 0x3d, 0xaf, 0x8e, 0xda, 0x4b, 0x2e, 0xd2, 0x88, 0x64, 0x8d, 0xc5, 0x5f, 0x76, 0x0f, 0x3d},
+ },
+ { /* 5P*/
+ addYX: fp.Elt{0xe5, 0x65, 0xc9, 0xe2, 0x75, 0xf0, 0x7d, 0x1a, 0xba, 0xa4, 0x40, 0x4b, 0x93, 0x12, 0xa2, 0x80, 0x95, 0x0d, 0x03, 0x93, 0xe8, 0xa5, 0x4d, 0xe2, 0x3d, 0x81, 0xf5, 0xce, 0xd4, 0x2d, 0x25, 0x59, 0x16, 0x5c, 0xe7, 0xda, 0xc7, 0x45, 0xd2, 0x7e, 0x2c, 0x38, 0xd4, 0x37, 0x64, 0xb2, 0xc2, 0x28, 0xc5, 0x72, 0x16, 0x32, 0x45, 0x36, 0x6f, 0x9f},
+ subYX: fp.Elt{0x09, 0xf4, 0x7e, 0xbd, 0x89, 0xdb, 0x19, 0x58, 0xe1, 0x08, 0x00, 0x8a, 0xf4, 0x5f, 0x2a, 0x32, 0x40, 0xf0, 0x2c, 0x3f, 0x5d, 0xe4, 0xfc, 0x89, 0x11, 0x24, 0xb4, 0x2f, 0x97, 0xad, 0xac, 0x8f, 0x19, 0xab, 0xfa, 0x12, 0xe5, 0xf9, 0x50, 0x4e, 0x50, 0x6f, 0x32, 0x30, 0x88, 0xa6, 0xe5, 0x48, 0x28, 0xa2, 0x1b, 0x9f, 0xcd, 0xe2, 0x43, 0x38},
+ dt2: fp.Elt{0xa9, 0xcc, 0x53, 0x39, 0x86, 0x02, 0x60, 0x75, 0x34, 0x99, 0x57, 0xbd, 0xfc, 0x5a, 0x8e, 0xce, 0x5e, 0x98, 0x22, 0xd0, 0xa5, 0x24, 0xff, 0x90, 0x28, 0x9f, 0x58, 0xf3, 0x39, 0xe9, 0xba, 0x36, 0x23, 0xfb, 0x7f, 0x41, 0xcc, 0x2b, 0x5a, 0x25, 0x3f, 0x4c, 0x2a, 0xf1, 0x52, 0x6f, 0x2f, 0x07, 0xe3, 0x88, 0x81, 0x77, 0xdd, 0x7c, 0x88, 0x82},
+ },
+ { /* 7P*/
+ addYX: fp.Elt{0xf7, 0xee, 0x88, 0xfd, 0x3a, 0xbf, 0x7e, 0x28, 0x39, 0x23, 0x79, 0xe6, 0x5c, 0x56, 0xcb, 0xb5, 0x48, 0x6a, 0x80, 0x6d, 0x37, 0x60, 0x6c, 0x10, 0x35, 0x49, 0x4b, 0x46, 0x60, 0xd4, 0x79, 0xd4, 0x53, 0xd3, 0x67, 0x88, 0xd0, 0x41, 0xd5, 0x43, 0x85, 0xc8, 0x71, 0xe3, 0x1c, 0xb6, 0xda, 0x22, 0x64, 0x8f, 0x80, 0xac, 0xad, 0x7d, 0xd5, 0x82},
+ subYX: fp.Elt{0x92, 0x40, 0xc1, 0x83, 0x21, 0x9b, 0xd5, 0x7d, 0x3f, 0x29, 0xb6, 0x26, 0xef, 0x12, 0xb9, 0x27, 0x39, 0x42, 0x37, 0x97, 0x09, 0x9a, 0x08, 0xe1, 0x68, 0xb6, 0x7a, 0x3f, 0x9f, 0x45, 0xf8, 0x37, 0x19, 0x83, 0x97, 0xe6, 0x73, 0x30, 0x32, 0x35, 0xcf, 0xae, 0x5c, 0x12, 0x68, 0xdf, 0x6e, 0x2b, 0xde, 0x83, 0xa0, 0x44, 0x74, 0x2e, 0x4a, 0xe9},
+ dt2: fp.Elt{0xcb, 0x22, 0x0a, 0xda, 0x6b, 0xc1, 0x8a, 0x29, 0xa1, 0xac, 0x8b, 0x5b, 0x8b, 0x32, 0x20, 0xf2, 0x21, 0xae, 0x0c, 0x43, 0xc4, 0xd7, 0x19, 0x37, 0x3d, 0x79, 0x25, 0x98, 0x6c, 0x9c, 0x22, 0x31, 0x2a, 0x55, 0x9f, 0xda, 0x5e, 0xa8, 0x13, 0xdb, 0x8e, 0x2e, 0x16, 0x39, 0xf4, 0x91, 0x6f, 0xec, 0x71, 0x71, 0xc9, 0x10, 0xf2, 0xa4, 0x8f, 0x11},
+ },
+ { /* 9P*/
+ addYX: fp.Elt{0x85, 0xdd, 0x37, 0x62, 0x74, 0x8e, 0x33, 0x5b, 0x25, 0x12, 0x1b, 0xe7, 0xdf, 0x47, 0xe5, 0x12, 0xfd, 0x3a, 0x3a, 0xf5, 0x5d, 0x4c, 0xa2, 0x29, 0x3c, 0x5c, 0x2f, 0xee, 0x18, 0x19, 0x0a, 0x2b, 0xef, 0x67, 0x50, 0x7a, 0x0d, 0x29, 0xae, 0x55, 0x82, 0xcd, 0xd6, 0x41, 0x90, 0xb4, 0x13, 0x31, 0x5d, 0x11, 0xb8, 0xaa, 0x12, 0x86, 0x08, 0xac},
+ subYX: fp.Elt{0xcc, 0x37, 0x8d, 0x83, 0x5f, 0xfd, 0xde, 0xd5, 0xf7, 0xf1, 0xae, 0x0a, 0xa7, 0x0b, 0xeb, 0x6d, 0x19, 0x8a, 0xb6, 0x1a, 0x59, 0xd8, 0xff, 0x3c, 0xbc, 0xbc, 0xef, 0x9c, 0xda, 0x7b, 0x75, 0x12, 0xaf, 0x80, 0x8f, 0x2c, 0x3c, 0xaa, 0x0b, 0x17, 0x86, 0x36, 0x78, 0x18, 0xc8, 0x8a, 0xf6, 0xb8, 0x2c, 0x2f, 0x57, 0x2c, 0x62, 0x57, 0xf6, 0x90},
+ dt2: fp.Elt{0x83, 0xbc, 0xa2, 0x07, 0xa5, 0x38, 0x96, 0xea, 0xfe, 0x11, 0x46, 0x1d, 0x3b, 0xcd, 0x42, 0xc5, 0xee, 0x67, 0x04, 0x72, 0x08, 0xd8, 0xd9, 0x96, 0x07, 0xf7, 0xac, 0xc3, 0x64, 0xf1, 0x98, 0x2c, 0x55, 0xd7, 0x7d, 0xc8, 0x6c, 0xbd, 0x2c, 0xff, 0x15, 0xd6, 0x6e, 0xb8, 0x17, 0x8e, 0xa8, 0x27, 0x66, 0xb1, 0x73, 0x79, 0x96, 0xff, 0x29, 0x10},
+ },
+ { /* 11P*/
+ addYX: fp.Elt{0x76, 0xcb, 0x9b, 0x0c, 0x5b, 0xfe, 0xe1, 0x2a, 0xdd, 0x6f, 0x6c, 0xdd, 0x6f, 0xb4, 0xc0, 0xc2, 0x1b, 0x4b, 0x38, 0xe8, 0x66, 0x8c, 0x1e, 0x31, 0x63, 0xb9, 0x94, 0xcd, 0xc3, 0x8c, 0x44, 0x25, 0x7b, 0xd5, 0x39, 0x80, 0xfc, 0x01, 0xaa, 0xf7, 0x2a, 0x61, 0x8a, 0x25, 0xd2, 0x5f, 0xc5, 0x66, 0x38, 0xa4, 0x17, 0xcf, 0x3e, 0x11, 0x0f, 0xa3},
+ subYX: fp.Elt{0xe0, 0xb6, 0xd1, 0x9c, 0x71, 0x49, 0x2e, 0x7b, 0xde, 0x00, 0xda, 0x6b, 0xf1, 0xec, 0xe6, 0x7a, 0x15, 0x38, 0x71, 0xe9, 0x7b, 0xdb, 0xf8, 0x98, 0xc0, 0x91, 0x2e, 0x53, 0xee, 0x92, 0x87, 0x25, 0xc9, 0xb0, 0xbb, 0x33, 0x15, 0x46, 0x7f, 0xfd, 0x4f, 0x8b, 0x77, 0x05, 0x96, 0xb6, 0xe2, 0x08, 0xdb, 0x0d, 0x09, 0xee, 0x5b, 0xd1, 0x2a, 0x63},
+ dt2: fp.Elt{0x8f, 0x7b, 0x57, 0x8c, 0xbf, 0x06, 0x0d, 0x43, 0x21, 0x92, 0x94, 0x2d, 0x6a, 0x38, 0x07, 0x0f, 0xa0, 0xf1, 0xe3, 0xd8, 0x2a, 0xbf, 0x46, 0xc6, 0x9e, 0x1f, 0x8f, 0x2b, 0x46, 0x84, 0x0b, 0x74, 0xed, 0xff, 0xf8, 0xa5, 0x94, 0xae, 0xf1, 0x67, 0xb1, 0x9b, 0xdd, 0x4a, 0xd0, 0xdb, 0xc2, 0xb5, 0x58, 0x49, 0x0c, 0xa9, 0x1d, 0x7d, 0xa9, 0xd3},
+ },
+ { /* 13P*/
+ addYX: fp.Elt{0x73, 0x84, 0x2e, 0x31, 0x1f, 0xdc, 0xed, 0x9f, 0x74, 0xfa, 0xe0, 0x35, 0xb1, 0x85, 0x6a, 0x8d, 0x86, 0xd0, 0xff, 0xd6, 0x08, 0x43, 0x73, 0x1a, 0xd5, 0xf8, 0x43, 0xd4, 0xb3, 0xe5, 0x3f, 0xa8, 0x84, 0x17, 0x59, 0x65, 0x4e, 0xe6, 0xee, 0x54, 0x9c, 0xda, 0x5e, 0x7e, 0x98, 0x29, 0x6d, 0x73, 0x34, 0x1f, 0x99, 0x80, 0x54, 0x54, 0x81, 0x0b},
+ subYX: fp.Elt{0xb1, 0xe5, 0xbb, 0x80, 0x22, 0x9c, 0x81, 0x6d, 0xaf, 0x27, 0x65, 0x6f, 0x7e, 0x9c, 0xb6, 0x8d, 0x35, 0x5c, 0x2e, 0x20, 0x48, 0x7a, 0x28, 0xf0, 0x97, 0xfe, 0xb7, 0x71, 0xce, 0xd6, 0xad, 0x3a, 0x81, 0xf6, 0x74, 0x5e, 0xf3, 0xfd, 0x1b, 0xd4, 0x1e, 0x7c, 0xc2, 0xb7, 0xc8, 0xa6, 0xc9, 0x89, 0x03, 0x47, 0xec, 0x24, 0xd6, 0x0e, 0xec, 0x9c},
+ dt2: fp.Elt{0x91, 0x0a, 0x43, 0x34, 0x20, 0xc2, 0x64, 0xf7, 0x4e, 0x48, 0xc8, 0xd2, 0x95, 0x83, 0xd1, 0xa4, 0xfb, 0x4e, 0x41, 0x3b, 0x0d, 0xd5, 0x07, 0xd9, 0xf1, 0x13, 0x16, 0x78, 0x54, 0x57, 0xd0, 0xf1, 0x4f, 0x20, 0xac, 0xcf, 0x9c, 0x3b, 0x33, 0x0b, 0x99, 0x54, 0xc3, 0x7f, 0x3e, 0x57, 0x26, 0x86, 0xd5, 0xa5, 0x2b, 0x8d, 0xe3, 0x19, 0x36, 0xf7},
+ },
+ { /* 15P*/
+ addYX: fp.Elt{0x23, 0x69, 0x47, 0x14, 0xf9, 0x9a, 0x50, 0xff, 0x64, 0xd1, 0x50, 0x35, 0xc3, 0x11, 0xd3, 0x19, 0xcf, 0x87, 0xda, 0x30, 0x0b, 0x50, 0xda, 0xc0, 0xe0, 0x25, 0x00, 0xe5, 0x68, 0x93, 0x04, 0xc2, 0xaf, 0xbd, 0x2f, 0x36, 0x5f, 0x47, 0x96, 0x10, 0xa8, 0xbd, 0xe4, 0x88, 0xac, 0x80, 0x52, 0x61, 0x73, 0xe9, 0x63, 0xdd, 0x99, 0xad, 0x20, 0x5b},
+ subYX: fp.Elt{0x1b, 0x5e, 0xa2, 0x2a, 0x25, 0x0f, 0x86, 0xc0, 0xb1, 0x2e, 0x0c, 0x13, 0x40, 0x8d, 0xf0, 0xe6, 0x00, 0x55, 0x08, 0xc5, 0x7d, 0xf4, 0xc9, 0x31, 0x25, 0x3a, 0x99, 0x69, 0xdd, 0x67, 0x63, 0x9a, 0xd6, 0x89, 0x2e, 0xa1, 0x19, 0xca, 0x2c, 0xd9, 0x59, 0x5f, 0x5d, 0xc3, 0x6e, 0x62, 0x36, 0x12, 0x59, 0x15, 0xe1, 0xdc, 0xa4, 0xad, 0xc9, 0xd0},
+ dt2: fp.Elt{0xbc, 0xea, 0xfc, 0xaf, 0x66, 0x23, 0xb7, 0x39, 0x6b, 0x2a, 0x96, 0xa8, 0x54, 0x43, 0xe9, 0xaa, 0x32, 0x40, 0x63, 0x92, 0x5e, 0xdf, 0x35, 0xc2, 0x9f, 0x24, 0x0c, 0xed, 0xfc, 0xde, 0x73, 0x8f, 0xa7, 0xd5, 0xa3, 0x2b, 0x18, 0x1f, 0xb0, 0xf8, 0xeb, 0x55, 0xd9, 0xc3, 0xfd, 0x28, 0x7c, 0x4f, 0xce, 0x0d, 0xf7, 0xae, 0xc2, 0x83, 0xc3, 0x78},
+ },
+ { /* 17P*/
+ addYX: fp.Elt{0x71, 0xe6, 0x60, 0x93, 0x37, 0xdb, 0x01, 0xa5, 0x4c, 0xba, 0xe8, 0x8e, 0xd5, 0xf9, 0xd3, 0x98, 0xe5, 0xeb, 0xab, 0x3a, 0x15, 0x8b, 0x35, 0x60, 0xbe, 0xe5, 0x9c, 0x2d, 0x10, 0x9b, 0x2e, 0xcf, 0x65, 0x64, 0xea, 0x8f, 0x72, 0xce, 0xf5, 0x18, 0xe5, 0xe2, 0xf0, 0x0e, 0xae, 0x04, 0xec, 0xa0, 0x20, 0x65, 0x63, 0x07, 0xb1, 0x9f, 0x03, 0x97},
+ subYX: fp.Elt{0x9e, 0x41, 0x64, 0x30, 0x95, 0x7f, 0x3a, 0x89, 0x7b, 0x0a, 0x79, 0x59, 0x23, 0x9a, 0x3b, 0xfe, 0xa4, 0x13, 0x08, 0xb2, 0x2e, 0x04, 0x50, 0x10, 0x30, 0xcd, 0x2e, 0xa4, 0x91, 0x71, 0x50, 0x36, 0x4a, 0x02, 0xf4, 0x8d, 0xa3, 0x36, 0x1b, 0xf4, 0x52, 0xba, 0x15, 0x04, 0x8b, 0x80, 0x25, 0xd9, 0xae, 0x67, 0x20, 0xd9, 0x88, 0x8f, 0x97, 0xa6},
+ dt2: fp.Elt{0xb5, 0xe7, 0x46, 0xbd, 0x55, 0x23, 0xa0, 0x68, 0xc0, 0x12, 0xd9, 0xf1, 0x0a, 0x75, 0xe2, 0xda, 0xf4, 0x6b, 0xca, 0x14, 0xe4, 0x9f, 0x0f, 0xb5, 0x3c, 0xa6, 0xa5, 0xa2, 0x63, 0x94, 0xd1, 0x1c, 0x39, 0x58, 0x57, 0x02, 0x27, 0x98, 0xb6, 0x47, 0xc6, 0x61, 0x4b, 0x5c, 0xab, 0x6f, 0x2d, 0xab, 0xe3, 0xc1, 0x69, 0xf9, 0x12, 0xb0, 0xc8, 0xd5},
+ },
+ { /* 19P*/
+ addYX: fp.Elt{0x19, 0x7d, 0xd5, 0xac, 0x79, 0xa2, 0x82, 0x9b, 0x28, 0x31, 0x22, 0xc0, 0x73, 0x02, 0x76, 0x17, 0x10, 0x70, 0x79, 0x57, 0xc9, 0x84, 0x62, 0x8e, 0x04, 0x04, 0x61, 0x67, 0x08, 0x48, 0xb4, 0x4b, 0xde, 0x53, 0x8c, 0xff, 0x36, 0x1b, 0x62, 0x86, 0x5d, 0xe1, 0x9b, 0xb1, 0xe5, 0xe8, 0x44, 0x64, 0xa1, 0x68, 0x3f, 0xa8, 0x45, 0x52, 0x91, 0xed},
+ subYX: fp.Elt{0x42, 0x1a, 0x36, 0x1f, 0x90, 0x15, 0x24, 0x8d, 0x24, 0x80, 0xe6, 0xfe, 0x1e, 0xf0, 0xad, 0xaf, 0x6a, 0x93, 0xf0, 0xa6, 0x0d, 0x5d, 0xea, 0xf6, 0x62, 0x96, 0x7a, 0x05, 0x76, 0x85, 0x74, 0x32, 0xc7, 0xc8, 0x64, 0x53, 0x62, 0xe7, 0x54, 0x84, 0xe0, 0x40, 0x66, 0x19, 0x70, 0x40, 0x95, 0x35, 0x68, 0x64, 0x43, 0xcd, 0xba, 0x29, 0x32, 0xa8},
+ dt2: fp.Elt{0x3e, 0xf6, 0xd6, 0xe4, 0x99, 0xeb, 0x20, 0x66, 0x08, 0x2e, 0x26, 0x64, 0xd7, 0x76, 0xf3, 0xb4, 0xc5, 0xa4, 0x35, 0x92, 0xd2, 0x99, 0x70, 0x5a, 0x1a, 0xe9, 0xe9, 0x3d, 0x3b, 0xe1, 0xcd, 0x0e, 0xee, 0x24, 0x13, 0x03, 0x22, 0xd6, 0xd6, 0x72, 0x08, 0x2b, 0xde, 0xfd, 0x93, 0xed, 0x0c, 0x7f, 0x5e, 0x31, 0x22, 0x4d, 0x80, 0x78, 0xc0, 0x48},
+ },
+ { /* 21P*/
+ addYX: fp.Elt{0x8f, 0x72, 0xd2, 0x9e, 0xc4, 0xcd, 0x2c, 0xbf, 0xa8, 0xd3, 0x24, 0x62, 0x28, 0xee, 0x39, 0x0a, 0x19, 0x3a, 0x58, 0xff, 0x21, 0x2e, 0x69, 0x6c, 0x6e, 0x18, 0xd0, 0xcd, 0x61, 0xc1, 0x18, 0x02, 0x5a, 0xe9, 0xe3, 0xef, 0x1f, 0x8e, 0x10, 0xe8, 0x90, 0x2b, 0x48, 0xcd, 0xee, 0x38, 0xbd, 0x3a, 0xca, 0xbc, 0x2d, 0xe2, 0x3a, 0x03, 0x71, 0x02},
+ subYX: fp.Elt{0xf8, 0xa4, 0x32, 0x26, 0x66, 0xaf, 0x3b, 0x53, 0xe7, 0xb0, 0x91, 0x92, 0xf5, 0x3c, 0x74, 0xce, 0xf2, 0xdd, 0x68, 0xa9, 0xf4, 0xcd, 0x5f, 0x60, 0xab, 0x71, 0xdf, 0xcd, 0x5c, 0x5d, 0x51, 0x72, 0x3a, 0x96, 0xea, 0xd6, 0xde, 0x54, 0x8e, 0x55, 0x4c, 0x08, 0x4c, 0x60, 0xdd, 0x34, 0xa9, 0x6f, 0xf3, 0x04, 0x02, 0xa8, 0xa6, 0x4e, 0x4d, 0x62},
+ dt2: fp.Elt{0x76, 0x4a, 0xae, 0x38, 0x62, 0x69, 0x72, 0xdc, 0xe8, 0x43, 0xbe, 0x1d, 0x61, 0xde, 0x31, 0xc3, 0x42, 0x8f, 0x33, 0x9d, 0xca, 0xc7, 0x9c, 0xec, 0x6a, 0xe2, 0xaa, 0x01, 0x49, 0x78, 0x8d, 0x72, 0x4f, 0x38, 0xea, 0x52, 0xc2, 0xd3, 0xc9, 0x39, 0x71, 0xba, 0xb9, 0x09, 0x9b, 0xa3, 0x7f, 0x45, 0x43, 0x65, 0x36, 0x29, 0xca, 0xe7, 0x5c, 0x5f},
+ },
+ { /* 23P*/
+ addYX: fp.Elt{0x89, 0x42, 0x35, 0x48, 0x6d, 0x74, 0xe5, 0x1f, 0xc3, 0xdd, 0x28, 0x5b, 0x84, 0x41, 0x33, 0x9f, 0x42, 0xf3, 0x1d, 0x5d, 0x15, 0x6d, 0x76, 0x33, 0x36, 0xaf, 0xe9, 0xdd, 0xfa, 0x63, 0x4f, 0x7a, 0x9c, 0xeb, 0x1c, 0x4f, 0x34, 0x65, 0x07, 0x54, 0xbb, 0x4c, 0x8b, 0x62, 0x9d, 0xd0, 0x06, 0x99, 0xb3, 0xe9, 0xda, 0x85, 0x19, 0xb0, 0x3d, 0x3c},
+ subYX: fp.Elt{0xbb, 0x99, 0xf6, 0xbf, 0xaf, 0x2c, 0x22, 0x0d, 0x7a, 0xaa, 0x98, 0x6f, 0x01, 0x82, 0x99, 0xcf, 0x88, 0xbd, 0x0e, 0x3a, 0x89, 0xe0, 0x9c, 0x8c, 0x17, 0x20, 0xc4, 0xe0, 0xcf, 0x43, 0x7a, 0xef, 0x0d, 0x9f, 0x87, 0xd4, 0xfb, 0xf2, 0x96, 0xb8, 0x03, 0xe8, 0xcb, 0x5c, 0xec, 0x65, 0x5f, 0x49, 0xa4, 0x7c, 0x85, 0xb4, 0xf6, 0xc7, 0xdb, 0xa3},
+ dt2: fp.Elt{0x11, 0xf3, 0x32, 0xa3, 0xa7, 0xb2, 0x7d, 0x51, 0x82, 0x44, 0xeb, 0xa2, 0x7d, 0x72, 0xcb, 0xc6, 0xf6, 0xc7, 0xb2, 0x38, 0x0e, 0x0f, 0x4f, 0x29, 0x00, 0xe4, 0x5b, 0x94, 0x46, 0x86, 0x66, 0xa1, 0x83, 0xb3, 0xeb, 0x15, 0xb6, 0x31, 0x50, 0x28, 0xeb, 0xed, 0x0d, 0x32, 0x39, 0xe9, 0x23, 0x81, 0x99, 0x3e, 0xff, 0x17, 0x4c, 0x11, 0x43, 0xd1},
+ },
+ { /* 25P*/
+ addYX: fp.Elt{0xce, 0xe7, 0xf8, 0x94, 0x8f, 0x96, 0xf8, 0x96, 0xe6, 0x72, 0x20, 0x44, 0x2c, 0xa7, 0xfc, 0xba, 0xc8, 0xe1, 0xbb, 0xc9, 0x16, 0x85, 0xcd, 0x0b, 0xe5, 0xb5, 0x5a, 0x7f, 0x51, 0x43, 0x63, 0x8b, 0x23, 0x8e, 0x1d, 0x31, 0xff, 0x46, 0x02, 0x66, 0xcc, 0x9e, 0x4d, 0xa2, 0xca, 0xe2, 0xc7, 0xfd, 0x22, 0xb1, 0xdb, 0xdf, 0x6f, 0xe6, 0xa5, 0x82},
+ subYX: fp.Elt{0xd0, 0xf5, 0x65, 0x40, 0xec, 0x8e, 0x65, 0x42, 0x78, 0xc1, 0x65, 0xe4, 0x10, 0xc8, 0x0b, 0x1b, 0xdd, 0x96, 0x68, 0xce, 0xee, 0x45, 0x55, 0xd8, 0x6e, 0xd3, 0xe6, 0x77, 0x19, 0xae, 0xc2, 0x8d, 0x8d, 0x3e, 0x14, 0x3f, 0x6d, 0x00, 0x2f, 0x9b, 0xd1, 0x26, 0x60, 0x28, 0x0f, 0x3a, 0x47, 0xb3, 0xe6, 0x68, 0x28, 0x24, 0x25, 0xca, 0xc8, 0x06},
+ dt2: fp.Elt{0x54, 0xbb, 0x60, 0x92, 0xdb, 0x8f, 0x0f, 0x38, 0xe0, 0xe6, 0xe4, 0xc9, 0xcc, 0x14, 0x62, 0x01, 0xc4, 0x2b, 0x0f, 0xcf, 0xed, 0x7d, 0x8e, 0xa4, 0xd9, 0x73, 0x0b, 0xba, 0x0c, 0xaf, 0x0c, 0xf9, 0xe2, 0xeb, 0x29, 0x2a, 0x53, 0xdf, 0x2c, 0x5a, 0xfa, 0x8f, 0xc1, 0x01, 0xd7, 0xb1, 0x45, 0x73, 0x92, 0x32, 0x83, 0x85, 0x12, 0x74, 0x89, 0x44},
+ },
+ { /* 27P*/
+ addYX: fp.Elt{0x0b, 0x73, 0x3c, 0xc2, 0xb1, 0x2e, 0xe1, 0xa7, 0xf5, 0xc9, 0x7a, 0xfb, 0x3d, 0x2d, 0xac, 0x59, 0xdb, 0xfa, 0x36, 0x11, 0xd1, 0x13, 0x04, 0x51, 0x1d, 0xab, 0x9b, 0x6b, 0x93, 0xfe, 0xda, 0xb0, 0x8e, 0xb4, 0x79, 0x11, 0x21, 0x0f, 0x65, 0xb9, 0xbb, 0x79, 0x96, 0x2a, 0xfd, 0x30, 0xe0, 0xb4, 0x2d, 0x9a, 0x55, 0x25, 0x5d, 0xd4, 0xad, 0x2a},
+ subYX: fp.Elt{0x9e, 0xc5, 0x04, 0xfe, 0xec, 0x3c, 0x64, 0x1c, 0xed, 0x95, 0xed, 0xae, 0xaf, 0x5c, 0x6e, 0x08, 0x9e, 0x02, 0x29, 0x59, 0x7e, 0x5f, 0xc4, 0x9a, 0xd5, 0x32, 0x72, 0x86, 0xe1, 0x4e, 0x3c, 0xce, 0x99, 0x69, 0x3b, 0xc4, 0xdd, 0x4d, 0xb7, 0xbb, 0xda, 0x3b, 0x1a, 0x99, 0xaa, 0x62, 0x15, 0xc1, 0xf0, 0xb6, 0x6c, 0xec, 0x56, 0xc1, 0xff, 0x0c},
+ dt2: fp.Elt{0x2f, 0xf1, 0x3f, 0x7a, 0x2d, 0x56, 0x19, 0x7f, 0xea, 0xbe, 0x59, 0x2e, 0x13, 0x67, 0x81, 0xfb, 0xdb, 0xc8, 0xa3, 0x1d, 0xd5, 0xe9, 0x13, 0x8b, 0x29, 0xdf, 0xcf, 0x9f, 0xe7, 0xd9, 0x0b, 0x70, 0xd3, 0x15, 0x57, 0x4a, 0xe9, 0x50, 0x12, 0x1b, 0x81, 0x4b, 0x98, 0x98, 0xa8, 0x31, 0x1d, 0x27, 0x47, 0x38, 0xed, 0x57, 0x99, 0x26, 0xb2, 0xee},
+ },
+ { /* 29P*/
+ addYX: fp.Elt{0x1c, 0xb2, 0xb2, 0x67, 0x3b, 0x8b, 0x3d, 0x5a, 0x30, 0x7e, 0x38, 0x7e, 0x3c, 0x3d, 0x28, 0x56, 0x59, 0xd8, 0x87, 0x53, 0x8b, 0xe6, 0x6c, 0x5d, 0xe5, 0x0a, 0x33, 0x10, 0xce, 0xa2, 0x17, 0x0d, 0xe8, 0x76, 0xee, 0x68, 0xa8, 0x72, 0x54, 0xbd, 0xa6, 0x24, 0x94, 0x6e, 0x77, 0xc7, 0x53, 0xb7, 0x89, 0x1c, 0x7a, 0xe9, 0x78, 0x9a, 0x74, 0x5f},
+ subYX: fp.Elt{0x76, 0x96, 0x1c, 0xcf, 0x08, 0x55, 0xd8, 0x1e, 0x0d, 0xa3, 0x59, 0x95, 0x32, 0xf4, 0xc2, 0x8e, 0x84, 0x5e, 0x4b, 0x04, 0xda, 0x71, 0xc9, 0x78, 0x52, 0xde, 0x14, 0xb4, 0x31, 0xf4, 0xd4, 0xb8, 0x58, 0xc5, 0x20, 0xe8, 0xdd, 0x15, 0xb5, 0xee, 0xea, 0x61, 0xe0, 0xf5, 0xd6, 0xae, 0x55, 0x59, 0x05, 0x3e, 0xaf, 0x74, 0xac, 0x1f, 0x17, 0x82},
+ dt2: fp.Elt{0x59, 0x24, 0xcd, 0xfc, 0x11, 0x7e, 0x85, 0x18, 0x3d, 0x69, 0xf7, 0x71, 0x31, 0x66, 0x98, 0x42, 0x95, 0x00, 0x8c, 0xb2, 0xae, 0x39, 0x7e, 0x85, 0xd6, 0xb0, 0x02, 0xec, 0xce, 0xfc, 0x25, 0xb2, 0xe3, 0x99, 0x8e, 0x5b, 0x61, 0x96, 0x2e, 0x6d, 0x96, 0x57, 0x71, 0xa5, 0x93, 0x41, 0x0e, 0x6f, 0xfd, 0x0a, 0xbf, 0xa9, 0xf7, 0x56, 0xa9, 0x3e},
+ },
+ { /* 31P*/
+ addYX: fp.Elt{0xa2, 0x2e, 0x0c, 0x17, 0x4d, 0xcc, 0x85, 0x2c, 0x18, 0xa0, 0xd2, 0x08, 0xba, 0x11, 0xfa, 0x47, 0x71, 0x86, 0xaf, 0x36, 0x6a, 0xd7, 0xfe, 0xb9, 0xb0, 0x2f, 0x89, 0x98, 0x49, 0x69, 0xf8, 0x6a, 0xad, 0x27, 0x5e, 0x0a, 0x22, 0x60, 0x5e, 0x5d, 0xca, 0x06, 0x51, 0x27, 0x99, 0x29, 0x85, 0x68, 0x98, 0xe1, 0xc4, 0x21, 0x50, 0xa0, 0xe9, 0xc1},
+ subYX: fp.Elt{0x4d, 0x70, 0xee, 0x91, 0x92, 0x3f, 0xb7, 0xd3, 0x1d, 0xdb, 0x8d, 0x6e, 0x16, 0xf5, 0x65, 0x7d, 0x5f, 0xb5, 0x6c, 0x59, 0x26, 0x70, 0x4b, 0xf2, 0xfc, 0xe7, 0xdf, 0x86, 0xfe, 0xa5, 0xa7, 0xa6, 0x5d, 0xfb, 0x06, 0xe9, 0xf9, 0xcc, 0xc0, 0x37, 0xcc, 0xd8, 0x09, 0x04, 0xd2, 0xa5, 0x1d, 0xd7, 0xb7, 0xce, 0x92, 0xac, 0x3c, 0xad, 0xfb, 0xae},
+ dt2: fp.Elt{0x17, 0xa3, 0x9a, 0xc7, 0x86, 0x2a, 0x51, 0xf7, 0x96, 0x79, 0x49, 0x22, 0x2e, 0x5a, 0x01, 0x5c, 0xb5, 0x95, 0xd4, 0xe8, 0xcb, 0x00, 0xca, 0x2d, 0x55, 0xb6, 0x34, 0x36, 0x0b, 0x65, 0x46, 0xf0, 0x49, 0xfc, 0x87, 0x86, 0xe5, 0xc3, 0x15, 0xdb, 0x32, 0xcd, 0xf2, 0xd3, 0x82, 0x4c, 0xe6, 0x61, 0x8a, 0xaf, 0xd4, 0x9e, 0x0f, 0x5a, 0xf2, 0x81},
+ },
+ { /* 33P*/
+ addYX: fp.Elt{0x88, 0x10, 0xc0, 0xcb, 0xf5, 0x77, 0xae, 0xa5, 0xbe, 0xf6, 0xcd, 0x2e, 0x8b, 0x7e, 0xbd, 0x79, 0x62, 0x4a, 0xeb, 0x69, 0xc3, 0x28, 0xaa, 0x72, 0x87, 0xa9, 0x25, 0x87, 0x46, 0xea, 0x0e, 0x62, 0xa3, 0x6a, 0x1a, 0xe2, 0xba, 0xdc, 0x81, 0x10, 0x33, 0x01, 0xf6, 0x16, 0x89, 0x80, 0xc6, 0xcd, 0xdb, 0xdc, 0xba, 0x0e, 0x09, 0x4a, 0x35, 0x4a},
+ subYX: fp.Elt{0x86, 0xb2, 0x2b, 0xd0, 0xb8, 0x4a, 0x6d, 0x66, 0x7b, 0x32, 0xdf, 0x3b, 0x1a, 0x19, 0x1f, 0x63, 0xee, 0x1f, 0x3d, 0x1c, 0x5c, 0x14, 0x60, 0x5b, 0x72, 0x49, 0x07, 0xb1, 0x0d, 0x72, 0xc6, 0x35, 0xf0, 0xbc, 0x5e, 0xda, 0x80, 0x6b, 0x64, 0x5b, 0xe5, 0x34, 0x54, 0x39, 0xdd, 0xe6, 0x3c, 0xcb, 0xe5, 0x29, 0x32, 0x06, 0xc6, 0xb1, 0x96, 0x34},
+ dt2: fp.Elt{0x85, 0x86, 0xf5, 0x84, 0x86, 0xe6, 0x77, 0x8a, 0x71, 0x85, 0x0c, 0x4f, 0x81, 0x5b, 0x29, 0x06, 0xb5, 0x2e, 0x26, 0x71, 0x07, 0x78, 0x07, 0xae, 0xbc, 0x95, 0x46, 0xc3, 0x65, 0xac, 0xe3, 0x76, 0x51, 0x7d, 0xd4, 0x85, 0x31, 0xe3, 0x43, 0xf3, 0x1b, 0x7c, 0xf7, 0x6b, 0x2c, 0xf8, 0x1c, 0xbb, 0x8d, 0xca, 0xab, 0x4b, 0xba, 0x7f, 0xa4, 0xe2},
+ },
+ { /* 35P*/
+ addYX: fp.Elt{0x1a, 0xee, 0xe7, 0xa4, 0x8a, 0x9d, 0x53, 0x80, 0xc6, 0xb8, 0x4e, 0xdc, 0x89, 0xe0, 0xc4, 0x2b, 0x60, 0x52, 0x6f, 0xec, 0x81, 0xd2, 0x55, 0x6b, 0x1b, 0x6f, 0x17, 0x67, 0x8e, 0x42, 0x26, 0x4c, 0x65, 0x23, 0x29, 0xc6, 0x7b, 0xcd, 0x9f, 0xad, 0x4b, 0x42, 0xd3, 0x0c, 0x75, 0xc3, 0x8a, 0xf5, 0xbe, 0x9e, 0x55, 0xf7, 0x47, 0x5d, 0xbd, 0x3a},
+ subYX: fp.Elt{0x0d, 0xa8, 0x3b, 0xf9, 0xc7, 0x7e, 0xc6, 0x86, 0x94, 0xc0, 0x01, 0xff, 0x27, 0xce, 0x43, 0xac, 0xe5, 0xe1, 0xd2, 0x8d, 0xc1, 0x22, 0x31, 0xbe, 0xe1, 0xaf, 0xf9, 0x4a, 0x78, 0xa1, 0x0c, 0xaa, 0xd4, 0x80, 0xe4, 0x09, 0x8d, 0xfb, 0x1d, 0x52, 0xc8, 0x60, 0x2d, 0xf2, 0xa2, 0x89, 0x02, 0x56, 0x3d, 0x56, 0x27, 0x85, 0xc7, 0xf0, 0x2b, 0x9a},
+ dt2: fp.Elt{0x62, 0x7c, 0xc7, 0x6b, 0x2c, 0x9d, 0x0a, 0x7c, 0xe5, 0x50, 0x3c, 0xe6, 0x87, 0x1c, 0x82, 0x30, 0x67, 0x3c, 0x39, 0xb6, 0xa0, 0x31, 0xfb, 0x03, 0x7b, 0xa1, 0x58, 0xdf, 0x12, 0x76, 0x5d, 0x5d, 0x0a, 0x8f, 0x9b, 0x37, 0x32, 0xc3, 0x60, 0x33, 0xea, 0x9f, 0x0a, 0x99, 0xfa, 0x20, 0xd0, 0x33, 0x21, 0xc3, 0x94, 0xd4, 0x86, 0x49, 0x7c, 0x4e},
+ },
+ { /* 37P*/
+ addYX: fp.Elt{0xc7, 0x0c, 0x71, 0xfe, 0x55, 0xd1, 0x95, 0x8f, 0x43, 0xbb, 0x6b, 0x74, 0x30, 0xbd, 0xe8, 0x6f, 0x1c, 0x1b, 0x06, 0x62, 0xf5, 0xfc, 0x65, 0xa0, 0xeb, 0x81, 0x12, 0xc9, 0x64, 0x66, 0x61, 0xde, 0xf3, 0x6d, 0xd4, 0xae, 0x8e, 0xb1, 0x72, 0xe0, 0xcd, 0x37, 0x01, 0x28, 0x52, 0xd7, 0x39, 0x46, 0x0c, 0x55, 0xcf, 0x47, 0x70, 0xef, 0xa1, 0x17},
+ subYX: fp.Elt{0x8d, 0x58, 0xde, 0x83, 0x88, 0x16, 0x0e, 0x12, 0x42, 0x03, 0x50, 0x60, 0x4b, 0xdf, 0xbf, 0x95, 0xcc, 0x7d, 0x18, 0x17, 0x7e, 0x31, 0x5d, 0x8a, 0x66, 0xc1, 0xcf, 0x14, 0xea, 0xf4, 0xf4, 0xe5, 0x63, 0x2d, 0x32, 0x86, 0x9b, 0xed, 0x1f, 0x4f, 0x03, 0xaf, 0x33, 0x92, 0xcb, 0xaf, 0x9c, 0x05, 0x0d, 0x47, 0x1b, 0x42, 0xba, 0x13, 0x22, 0x98},
+ dt2: fp.Elt{0xb5, 0x48, 0xeb, 0x7d, 0x3d, 0x10, 0x9f, 0x59, 0xde, 0xf8, 0x1c, 0x4f, 0x7d, 0x9d, 0x40, 0x4d, 0x9e, 0x13, 0x24, 0xb5, 0x21, 0x09, 0xb7, 0xee, 0x98, 0x5c, 0x56, 0xbc, 0x5e, 0x2b, 0x78, 0x38, 0x06, 0xac, 0xe3, 0xe0, 0xfa, 0x2e, 0xde, 0x4f, 0xd2, 0xb3, 0xfb, 0x2d, 0x71, 0x84, 0xd1, 0x9d, 0x12, 0x5b, 0x35, 0xc8, 0x03, 0x68, 0x67, 0xc7},
+ },
+ { /* 39P*/
+ addYX: fp.Elt{0xb6, 0x65, 0xfb, 0xa7, 0x06, 0x35, 0xbb, 0xe0, 0x31, 0x8d, 0x91, 0x40, 0x98, 0xab, 0x30, 0xe4, 0xca, 0x12, 0x59, 0x89, 0xed, 0x65, 0x5d, 0x7f, 0xae, 0x69, 0xa0, 0xa4, 0xfa, 0x78, 0xb4, 0xf7, 0xed, 0xae, 0x86, 0x78, 0x79, 0x64, 0x24, 0xa6, 0xd4, 0xe1, 0xf6, 0xd3, 0xa0, 0x89, 0xba, 0x20, 0xf4, 0x54, 0x0d, 0x8f, 0xdb, 0x1a, 0x79, 0xdb},
+ subYX: fp.Elt{0xe1, 0x82, 0x0c, 0x4d, 0xde, 0x9f, 0x40, 0xf0, 0xc1, 0xbd, 0x8b, 0xd3, 0x24, 0x03, 0xcd, 0xf2, 0x92, 0x7d, 0xe2, 0x68, 0x7f, 0xf1, 0xbe, 0x69, 0xde, 0x34, 0x67, 0x4c, 0x85, 0x3b, 0xec, 0x98, 0xcc, 0x4d, 0x3e, 0xc0, 0x96, 0x27, 0xe6, 0x75, 0xfc, 0xdf, 0x37, 0xc0, 0x1e, 0x27, 0xe0, 0xf6, 0xc2, 0xbd, 0xbc, 0x3d, 0x9b, 0x39, 0xdc, 0xe2},
+ dt2: fp.Elt{0xd8, 0x29, 0xa7, 0x39, 0xe3, 0x9f, 0x2f, 0x0e, 0x4b, 0x24, 0x21, 0x70, 0xef, 0xfd, 0x91, 0xea, 0xbf, 0xe1, 0x72, 0x90, 0xcc, 0xc9, 0x84, 0x0e, 0xad, 0xd5, 0xe6, 0xbb, 0xc5, 0x99, 0x7f, 0xa4, 0xf0, 0x2e, 0xcc, 0x95, 0x64, 0x27, 0x19, 0xd8, 0x4c, 0x27, 0x0d, 0xff, 0xb6, 0x29, 0xe2, 0x6c, 0xfa, 0xbb, 0x4d, 0x9c, 0xbb, 0xaf, 0xa5, 0xec},
+ },
+ { /* 41P*/
+ addYX: fp.Elt{0xd6, 0x33, 0x3f, 0x9f, 0xcf, 0xfd, 0x4c, 0xd1, 0xfe, 0xe5, 0xeb, 0x64, 0x27, 0xae, 0x7a, 0xa2, 0x82, 0x50, 0x6d, 0xaa, 0xe3, 0x5d, 0xe2, 0x48, 0x60, 0xb3, 0x76, 0x04, 0xd9, 0x19, 0xa7, 0xa1, 0x73, 0x8d, 0x38, 0xa9, 0xaf, 0x45, 0xb5, 0xb2, 0x62, 0x9b, 0xf1, 0x35, 0x7b, 0x84, 0x66, 0xeb, 0x06, 0xef, 0xf1, 0xb2, 0x2d, 0x6a, 0x61, 0x15},
+ subYX: fp.Elt{0x86, 0x50, 0x42, 0xf7, 0xda, 0x59, 0xb2, 0xcf, 0x0d, 0x3d, 0xee, 0x8e, 0x53, 0x5d, 0xf7, 0x9e, 0x6a, 0x26, 0x2d, 0xc7, 0x8c, 0x8e, 0x18, 0x50, 0x6d, 0xb7, 0x51, 0x4c, 0xa7, 0x52, 0x6e, 0x0e, 0x0a, 0x16, 0x74, 0xb2, 0x81, 0x8b, 0x56, 0x27, 0x22, 0x84, 0xf4, 0x56, 0xc5, 0x06, 0xe1, 0x8b, 0xca, 0x2d, 0xdb, 0x9a, 0xf6, 0x10, 0x9c, 0x51},
+ dt2: fp.Elt{0x1f, 0x16, 0xa2, 0x78, 0x96, 0x1b, 0x85, 0x9c, 0x76, 0x49, 0xd4, 0x0f, 0xac, 0xb0, 0xf4, 0xd0, 0x06, 0x2c, 0x7e, 0x6d, 0x6e, 0x8e, 0xc7, 0x9f, 0x18, 0xad, 0xfc, 0x88, 0x0c, 0x0c, 0x09, 0x05, 0x05, 0xa0, 0x79, 0x72, 0x32, 0x72, 0x87, 0x0f, 0x49, 0x87, 0x0c, 0xb4, 0x12, 0xc2, 0x09, 0xf8, 0x9f, 0x30, 0x72, 0xa9, 0x47, 0x13, 0x93, 0x49},
+ },
+ { /* 43P*/
+ addYX: fp.Elt{0xcc, 0xb1, 0x4c, 0xd3, 0xc0, 0x9e, 0x9e, 0x4d, 0x6d, 0x28, 0x0b, 0xa5, 0x94, 0xa7, 0x2e, 0xc2, 0xc7, 0xaf, 0x29, 0x73, 0xc9, 0x68, 0xea, 0x0f, 0x34, 0x37, 0x8d, 0x96, 0x8f, 0x3a, 0x3d, 0x73, 0x1e, 0x6d, 0x9f, 0xcf, 0x8d, 0x83, 0xb5, 0x71, 0xb9, 0xe1, 0x4b, 0x67, 0x71, 0xea, 0xcf, 0x56, 0xe5, 0xeb, 0x72, 0x15, 0x2f, 0x9e, 0xa8, 0xaa},
+ subYX: fp.Elt{0xf4, 0x3e, 0x85, 0x1c, 0x1a, 0xef, 0x50, 0xd1, 0xb4, 0x20, 0xb2, 0x60, 0x05, 0x98, 0xfe, 0x47, 0x3b, 0xc1, 0x76, 0xca, 0x2c, 0x4e, 0x5a, 0x42, 0xa3, 0xf7, 0x20, 0xaa, 0x57, 0x39, 0xee, 0x34, 0x1f, 0xe1, 0x68, 0xd3, 0x7e, 0x06, 0xc4, 0x6c, 0xc7, 0x76, 0x2b, 0xe4, 0x1c, 0x48, 0x44, 0xe6, 0xe5, 0x44, 0x24, 0x8d, 0xb3, 0xb6, 0x88, 0x32},
+ dt2: fp.Elt{0x18, 0xa7, 0xba, 0xd0, 0x44, 0x6f, 0x33, 0x31, 0x00, 0xf8, 0xf6, 0x12, 0xe3, 0xc5, 0xc7, 0xb5, 0x91, 0x9c, 0x91, 0xb5, 0x75, 0x18, 0x18, 0x8a, 0xab, 0xed, 0x24, 0x11, 0x2e, 0xce, 0x5a, 0x0f, 0x94, 0x5f, 0x2e, 0xca, 0xd3, 0x80, 0xea, 0xe5, 0x34, 0x96, 0x67, 0x8b, 0x6a, 0x26, 0x5e, 0xc8, 0x9d, 0x2c, 0x5e, 0x6c, 0xa2, 0x0c, 0xbf, 0xf0},
+ },
+ { /* 45P*/
+ addYX: fp.Elt{0xb3, 0xbf, 0xa3, 0x85, 0xee, 0xf6, 0x58, 0x02, 0x78, 0xc4, 0x30, 0xd6, 0x57, 0x59, 0x8c, 0x88, 0x08, 0x7c, 0xbc, 0xbe, 0x0a, 0x74, 0xa9, 0xde, 0x69, 0xe7, 0x41, 0xd8, 0xbf, 0x66, 0x8d, 0x3d, 0x28, 0x00, 0x8c, 0x47, 0x65, 0x34, 0xfe, 0x86, 0x9e, 0x6a, 0xf2, 0x41, 0x6a, 0x94, 0xc4, 0x88, 0x75, 0x23, 0x0d, 0x52, 0x69, 0xee, 0x07, 0x89},
+ subYX: fp.Elt{0x22, 0x3c, 0xa1, 0x70, 0x58, 0x97, 0x93, 0xbe, 0x59, 0xa8, 0x0b, 0x8a, 0x46, 0x2a, 0x38, 0x1e, 0x08, 0x6b, 0x61, 0x9f, 0xf2, 0x4a, 0x8b, 0x80, 0x68, 0x6e, 0xc8, 0x92, 0x60, 0xf3, 0xc9, 0x89, 0xb2, 0x6d, 0x63, 0xb0, 0xeb, 0x83, 0x15, 0x63, 0x0e, 0x64, 0xbb, 0xb8, 0xfe, 0xb4, 0x81, 0x90, 0x01, 0x28, 0x10, 0xb9, 0x74, 0x6e, 0xde, 0xa4},
+ dt2: fp.Elt{0x1a, 0x23, 0x45, 0xa8, 0x6f, 0x4e, 0xa7, 0x4a, 0x0c, 0xeb, 0xb0, 0x43, 0xf9, 0xef, 0x99, 0x60, 0x5b, 0xdb, 0x66, 0xc0, 0x86, 0x71, 0x43, 0xb1, 0x22, 0x7b, 0x1c, 0xe7, 0x8d, 0x09, 0x1d, 0x83, 0x76, 0x9c, 0xd3, 0x5a, 0xdd, 0x42, 0xd9, 0x2f, 0x2d, 0xba, 0x7a, 0xc2, 0xd9, 0x6b, 0xd4, 0x7a, 0xf1, 0xd5, 0x5f, 0x6b, 0x85, 0xbf, 0x0b, 0xf1},
+ },
+ { /* 47P*/
+ addYX: fp.Elt{0xb2, 0x83, 0xfa, 0x1f, 0xd2, 0xce, 0xb6, 0xf2, 0x2d, 0xea, 0x1b, 0xe5, 0x29, 0xa5, 0x72, 0xf9, 0x25, 0x48, 0x4e, 0xf2, 0x50, 0x1b, 0x39, 0xda, 0x34, 0xc5, 0x16, 0x13, 0xb4, 0x0c, 0xa1, 0x00, 0x79, 0x7a, 0xf5, 0x8b, 0xf3, 0x70, 0x14, 0xb6, 0xfc, 0x9a, 0x47, 0x68, 0x1e, 0x42, 0x70, 0x64, 0x2a, 0x84, 0x3e, 0x3d, 0x20, 0x58, 0xf9, 0x6a},
+ subYX: fp.Elt{0xd9, 0xee, 0xc0, 0xc4, 0xf5, 0xc2, 0x86, 0xaf, 0x45, 0xd2, 0xd2, 0x87, 0x1b, 0x64, 0xd5, 0xe0, 0x8c, 0x44, 0x00, 0x4f, 0x43, 0x89, 0x04, 0x48, 0x4a, 0x0b, 0xca, 0x94, 0x06, 0x2f, 0x23, 0x5b, 0x6c, 0x8d, 0x44, 0x66, 0x53, 0xf5, 0x5a, 0x20, 0x72, 0x28, 0x58, 0x84, 0xcc, 0x73, 0x22, 0x5e, 0xd1, 0x0b, 0x56, 0x5e, 0x6a, 0xa3, 0x11, 0x91},
+ dt2: fp.Elt{0x6e, 0x9f, 0x88, 0xa8, 0x68, 0x2f, 0x12, 0x37, 0x88, 0xfc, 0x92, 0x8f, 0x24, 0xeb, 0x5b, 0x2a, 0x2a, 0xd0, 0x14, 0x40, 0x4c, 0xa9, 0xa4, 0x03, 0x0c, 0x45, 0x48, 0x13, 0xe8, 0xa6, 0x37, 0xab, 0xc0, 0x06, 0x38, 0x6c, 0x96, 0x73, 0x40, 0x6c, 0xc6, 0xea, 0x56, 0xc6, 0xe9, 0x1a, 0x69, 0xeb, 0x7a, 0xd1, 0x33, 0x69, 0x58, 0x2b, 0xea, 0x2f},
+ },
+ { /* 49P*/
+ addYX: fp.Elt{0x58, 0xa8, 0x05, 0x41, 0x00, 0x9d, 0xaa, 0xd9, 0x98, 0xcf, 0xb9, 0x41, 0xb5, 0x4a, 0x8d, 0xe2, 0xe7, 0xc0, 0x72, 0xef, 0xc8, 0x28, 0x6b, 0x68, 0x9d, 0xc9, 0xdf, 0x05, 0x8b, 0xd0, 0x04, 0x74, 0x79, 0x45, 0x52, 0x05, 0xa3, 0x6e, 0x35, 0x3a, 0xe3, 0xef, 0xb2, 0xdc, 0x08, 0x6f, 0x4e, 0x76, 0x85, 0x67, 0xba, 0x23, 0x8f, 0xdd, 0xaf, 0x09},
+ subYX: fp.Elt{0xb4, 0x38, 0xc8, 0xff, 0x4f, 0x65, 0x2a, 0x7e, 0xad, 0xb1, 0xc6, 0xb9, 0x3d, 0xd6, 0xf7, 0x14, 0xcf, 0xf6, 0x98, 0x75, 0xbb, 0x47, 0x83, 0x90, 0xe7, 0xe1, 0xf6, 0x14, 0x99, 0x7e, 0xfa, 0xe4, 0x77, 0x24, 0xe3, 0xe7, 0xf0, 0x1e, 0xdb, 0x27, 0x4e, 0x16, 0x04, 0xf2, 0x08, 0x52, 0xfc, 0xec, 0x55, 0xdb, 0x2e, 0x67, 0xe1, 0x94, 0x32, 0x89},
+ dt2: fp.Elt{0x00, 0xad, 0x03, 0x35, 0x1a, 0xb1, 0x88, 0xf0, 0xc9, 0x11, 0xe4, 0x12, 0x52, 0x61, 0xfd, 0x8a, 0x1b, 0x6a, 0x0a, 0x4c, 0x42, 0x46, 0x22, 0x0e, 0xa5, 0xf9, 0xe2, 0x50, 0xf2, 0xb2, 0x1f, 0x20, 0x78, 0x10, 0xf6, 0xbf, 0x7f, 0x0c, 0x9c, 0xad, 0x40, 0x8b, 0x82, 0xd4, 0xba, 0x69, 0x09, 0xac, 0x4b, 0x6d, 0xc4, 0x49, 0x17, 0x81, 0x57, 0x3b},
+ },
+ { /* 51P*/
+ addYX: fp.Elt{0x0d, 0xfe, 0xb4, 0x35, 0x11, 0xbd, 0x1d, 0x6b, 0xc2, 0xc5, 0x3b, 0xd2, 0x23, 0x2c, 0x72, 0xe3, 0x48, 0xb1, 0x48, 0x73, 0xfb, 0xa3, 0x21, 0x6e, 0xc0, 0x09, 0x69, 0xac, 0xe1, 0x60, 0xbc, 0x24, 0x03, 0x99, 0x63, 0x0a, 0x00, 0xf0, 0x75, 0xf6, 0x92, 0xc5, 0xd6, 0xdb, 0x51, 0xd4, 0x7d, 0xe6, 0xf4, 0x11, 0x79, 0xd7, 0xc3, 0xaf, 0x48, 0xd0},
+ subYX: fp.Elt{0xf4, 0x4f, 0xaf, 0x31, 0xe3, 0x10, 0x89, 0x95, 0xf0, 0x8a, 0xf6, 0x31, 0x9f, 0x48, 0x02, 0xba, 0x42, 0x2b, 0x3c, 0x22, 0x8b, 0xcc, 0x12, 0x98, 0x6e, 0x7a, 0x64, 0x3a, 0xc4, 0xca, 0x32, 0x2a, 0x72, 0xf8, 0x2c, 0xcf, 0x78, 0x5e, 0x7a, 0x75, 0x6e, 0x72, 0x46, 0x48, 0x62, 0x28, 0xac, 0x58, 0x1a, 0xc6, 0x59, 0x88, 0x2a, 0x44, 0x9e, 0x83},
+ dt2: fp.Elt{0xb3, 0xde, 0x36, 0xfd, 0xeb, 0x1b, 0xd4, 0x24, 0x1b, 0x08, 0x8c, 0xfe, 0xa9, 0x41, 0xa1, 0x64, 0xf2, 0x6d, 0xdb, 0xf9, 0x94, 0xae, 0x86, 0x71, 0xab, 0x10, 0xbf, 0xa3, 0xb2, 0xa0, 0xdf, 0x10, 0x8c, 0x74, 0xce, 0xb3, 0xfc, 0xdb, 0xba, 0x15, 0xf6, 0x91, 0x7a, 0x9c, 0x36, 0x1e, 0x45, 0x07, 0x3c, 0xec, 0x1a, 0x61, 0x26, 0x93, 0xe3, 0x50},
+ },
+ { /* 53P*/
+ addYX: fp.Elt{0xc5, 0x50, 0xc5, 0x83, 0xb0, 0xbd, 0xd9, 0xf6, 0x6d, 0x15, 0x5e, 0xc1, 0x1a, 0x33, 0xa0, 0xce, 0x13, 0x70, 0x3b, 0xe1, 0x31, 0xc6, 0xc4, 0x02, 0xec, 0x8c, 0xd5, 0x9c, 0x97, 0xd3, 0x12, 0xc4, 0xa2, 0xf9, 0xd5, 0xfb, 0x22, 0x69, 0x94, 0x09, 0x2f, 0x59, 0xce, 0xdb, 0xf2, 0xf2, 0x00, 0xe0, 0xa9, 0x08, 0x44, 0x2e, 0x8b, 0x6b, 0xf5, 0xb3},
+ subYX: fp.Elt{0x90, 0xdd, 0xec, 0xa2, 0x65, 0xb7, 0x61, 0xbc, 0xaa, 0x70, 0xa2, 0x15, 0xd8, 0xb0, 0xf8, 0x8e, 0x23, 0x3d, 0x9f, 0x46, 0xa3, 0x29, 0x20, 0xd1, 0xa1, 0x15, 0x81, 0xc6, 0xb6, 0xde, 0xbe, 0x60, 0x63, 0x24, 0xac, 0x15, 0xfb, 0xeb, 0xd3, 0xea, 0x57, 0x13, 0x86, 0x38, 0x1e, 0x22, 0xf4, 0x8c, 0x5d, 0xaf, 0x1b, 0x27, 0x21, 0x4f, 0xa3, 0x63},
+ dt2: fp.Elt{0x07, 0x15, 0x87, 0xc4, 0xfd, 0xa1, 0x97, 0x7a, 0x07, 0x1f, 0x56, 0xcc, 0xe3, 0x6a, 0x01, 0x90, 0xce, 0xf9, 0xfa, 0x50, 0xb2, 0xe0, 0x87, 0x8b, 0x6c, 0x63, 0x6c, 0xf6, 0x2a, 0x09, 0xef, 0xef, 0xd2, 0x31, 0x40, 0x25, 0xf6, 0x84, 0xcb, 0xe0, 0xc4, 0x23, 0xc1, 0xcb, 0xe2, 0x02, 0x83, 0x2d, 0xed, 0x74, 0x74, 0x8b, 0xf8, 0x7c, 0x81, 0x18},
+ },
+ { /* 55P*/
+ addYX: fp.Elt{0x9e, 0xe5, 0x59, 0x95, 0x63, 0x2e, 0xac, 0x8b, 0x03, 0x3c, 0xc1, 0x8e, 0xe1, 0x5b, 0x56, 0x3c, 0x16, 0x41, 0xe4, 0xc2, 0x60, 0x0c, 0x6d, 0x65, 0x9f, 0xfc, 0x27, 0x68, 0x43, 0x44, 0x05, 0x12, 0x6c, 0xda, 0x04, 0xef, 0xcf, 0xcf, 0xdc, 0x0a, 0x1a, 0x7f, 0x12, 0xd3, 0xeb, 0x02, 0xb6, 0x04, 0xca, 0xd6, 0xcb, 0xf0, 0x22, 0xba, 0x35, 0x6d},
+ subYX: fp.Elt{0x09, 0x6d, 0xf9, 0x64, 0x4c, 0xe6, 0x41, 0xff, 0x01, 0x4d, 0xce, 0x1e, 0xfa, 0x38, 0xa2, 0x25, 0x62, 0xff, 0x03, 0x39, 0x18, 0x91, 0xbb, 0x9d, 0xce, 0x02, 0xf0, 0xf1, 0x3c, 0x55, 0x18, 0xa9, 0xab, 0x4d, 0xd2, 0x35, 0xfd, 0x8d, 0xa9, 0xb2, 0xad, 0xb7, 0x06, 0x6e, 0xc6, 0x69, 0x49, 0xd6, 0x98, 0x98, 0x0b, 0x22, 0x81, 0x6b, 0xbd, 0xa0},
+ dt2: fp.Elt{0x22, 0xf4, 0x85, 0x5d, 0x2b, 0xf1, 0x55, 0xa5, 0xd6, 0x27, 0x86, 0x57, 0x12, 0x1f, 0x16, 0x0a, 0x5a, 0x9b, 0xf2, 0x38, 0xb6, 0x28, 0xd8, 0x99, 0x0c, 0x89, 0x1d, 0x7f, 0xca, 0x21, 0x17, 0x1a, 0x0b, 0x02, 0x5f, 0x77, 0x2f, 0x73, 0x30, 0x7c, 0xc8, 0xd7, 0x2b, 0xcc, 0xe7, 0xf3, 0x21, 0xac, 0x53, 0xa7, 0x11, 0x5d, 0xd8, 0x1d, 0x9b, 0xf5},
+ },
+ { /* 57P*/
+ addYX: fp.Elt{0x94, 0x63, 0x5d, 0xef, 0xfd, 0x6d, 0x25, 0x4e, 0x6d, 0x29, 0x03, 0xed, 0x24, 0x28, 0x27, 0x57, 0x47, 0x3e, 0x6a, 0x1a, 0xfe, 0x37, 0xee, 0x5f, 0x83, 0x29, 0x14, 0xfd, 0x78, 0x25, 0x8a, 0xe1, 0x02, 0x38, 0xd8, 0xca, 0x65, 0x55, 0x40, 0x7d, 0x48, 0x2c, 0x7c, 0x7e, 0x60, 0xb6, 0x0c, 0x6d, 0xf7, 0xe8, 0xb3, 0x62, 0x53, 0xd6, 0x9c, 0x2b},
+ subYX: fp.Elt{0x47, 0x25, 0x70, 0x62, 0xf5, 0x65, 0x93, 0x62, 0x08, 0xac, 0x59, 0x66, 0xdb, 0x08, 0xd9, 0x1a, 0x19, 0xaf, 0xf4, 0xef, 0x02, 0xa2, 0x78, 0xa9, 0x55, 0x1c, 0xfa, 0x08, 0x11, 0xcb, 0xa3, 0x71, 0x74, 0xb1, 0x62, 0xe7, 0xc7, 0xf3, 0x5a, 0xb5, 0x8b, 0xd4, 0xf6, 0x10, 0x57, 0x79, 0x72, 0x2f, 0x13, 0x86, 0x7b, 0x44, 0x5f, 0x48, 0xfd, 0x88},
+ dt2: fp.Elt{0x10, 0x02, 0xcd, 0x05, 0x9a, 0xc3, 0x32, 0x6d, 0x10, 0x3a, 0x74, 0xba, 0x06, 0xc4, 0x3b, 0x34, 0xbc, 0x36, 0xed, 0xa3, 0xba, 0x9a, 0xdb, 0x6d, 0xd4, 0x69, 0x99, 0x97, 0xd0, 0xe4, 0xdd, 0xf5, 0xd4, 0x7c, 0xd3, 0x4e, 0xab, 0xd1, 0x3b, 0xbb, 0xe9, 0xc7, 0x6a, 0x94, 0x25, 0x61, 0xf0, 0x06, 0xc5, 0x12, 0xa8, 0x86, 0xe5, 0x35, 0x46, 0xeb},
+ },
+ { /* 59P*/
+ addYX: fp.Elt{0x9e, 0x95, 0x11, 0xc6, 0xc7, 0xe8, 0xee, 0x5a, 0x26, 0xa0, 0x72, 0x72, 0x59, 0x91, 0x59, 0x16, 0x49, 0x99, 0x7e, 0xbb, 0xd7, 0x15, 0xb4, 0xf2, 0x40, 0xf9, 0x5a, 0x4d, 0xc8, 0xa0, 0xe2, 0x34, 0x7b, 0x34, 0xf3, 0x99, 0xbf, 0xa9, 0xf3, 0x79, 0xc1, 0x1a, 0x0c, 0xf4, 0x86, 0x74, 0x4e, 0xcb, 0xbc, 0x90, 0xad, 0xb6, 0x51, 0x6d, 0xaa, 0x33},
+ subYX: fp.Elt{0x9f, 0xd1, 0xc5, 0xa2, 0x6c, 0x24, 0x88, 0x15, 0x71, 0x68, 0xf6, 0x07, 0x45, 0x02, 0xc4, 0x73, 0x7e, 0x75, 0x87, 0xca, 0x7c, 0xf0, 0x92, 0x00, 0x75, 0xd6, 0x5a, 0xdd, 0xe0, 0x64, 0x16, 0x9d, 0x62, 0x80, 0x33, 0x9f, 0xf4, 0x8e, 0x1a, 0x15, 0x1c, 0xd3, 0x0f, 0x4d, 0x4f, 0x62, 0x2d, 0xd7, 0xa5, 0x77, 0xe3, 0xea, 0xf0, 0xfb, 0x1a, 0xdb},
+ dt2: fp.Elt{0x6a, 0xa2, 0xb1, 0xaa, 0xfb, 0x5a, 0x32, 0x4e, 0xff, 0x47, 0x06, 0xd5, 0x9a, 0x4f, 0xce, 0x83, 0x5b, 0x82, 0x34, 0x3e, 0x47, 0xb8, 0xf8, 0xe9, 0x7c, 0x67, 0x69, 0x8d, 0x9c, 0xb7, 0xde, 0x57, 0xf4, 0x88, 0x41, 0x56, 0x0c, 0x87, 0x1e, 0xc9, 0x2f, 0x54, 0xbf, 0x5c, 0x68, 0x2c, 0xd9, 0xc4, 0xef, 0x53, 0x73, 0x1e, 0xa6, 0x38, 0x02, 0x10},
+ },
+ { /* 61P*/
+ addYX: fp.Elt{0x08, 0x80, 0x4a, 0xc9, 0xb7, 0xa8, 0x88, 0xd9, 0xfc, 0x6a, 0xc0, 0x3e, 0xc2, 0x33, 0x4d, 0x2b, 0x2a, 0xa3, 0x6d, 0x72, 0x3e, 0xdc, 0x34, 0x68, 0x08, 0xbf, 0x27, 0xef, 0xf4, 0xff, 0xe2, 0x0c, 0x31, 0x0c, 0xa2, 0x0a, 0x1f, 0x65, 0xc1, 0x4c, 0x61, 0xd3, 0x1b, 0xbc, 0x25, 0xb1, 0xd0, 0xd4, 0x89, 0xb2, 0x53, 0xfb, 0x43, 0xa5, 0xaf, 0x04},
+ subYX: fp.Elt{0xe3, 0xe1, 0x37, 0xad, 0x58, 0xa9, 0x55, 0x81, 0xee, 0x64, 0x21, 0xb9, 0xf5, 0x4c, 0x35, 0xea, 0x4a, 0xd3, 0x26, 0xaa, 0x90, 0xd4, 0x60, 0x46, 0x09, 0x4b, 0x4a, 0x62, 0xf9, 0xcd, 0xe1, 0xee, 0xbb, 0xc2, 0x09, 0x0b, 0xb0, 0x96, 0x8e, 0x43, 0x77, 0xaf, 0x25, 0x20, 0x5e, 0x47, 0xe4, 0x1d, 0x50, 0x69, 0x74, 0x08, 0xd7, 0xb9, 0x90, 0x13},
+ dt2: fp.Elt{0x51, 0x91, 0x95, 0x64, 0x03, 0x16, 0xfd, 0x6e, 0x26, 0x94, 0x6b, 0x61, 0xe7, 0xd9, 0xe0, 0x4a, 0x6d, 0x7c, 0xfa, 0xc0, 0xe2, 0x43, 0x23, 0x53, 0x70, 0xf5, 0x6f, 0x73, 0x8b, 0x81, 0xb0, 0x0c, 0xee, 0x2e, 0x46, 0xf2, 0x8d, 0xa6, 0xfb, 0xb5, 0x1c, 0x33, 0xbf, 0x90, 0x59, 0xc9, 0x7c, 0xb8, 0x6f, 0xad, 0x75, 0x02, 0x90, 0x8e, 0x59, 0x75},
+ },
+ { /* 63P*/
+ addYX: fp.Elt{0x36, 0x4d, 0x77, 0x04, 0xb8, 0x7d, 0x4a, 0xd1, 0xc5, 0xbb, 0x7b, 0x50, 0x5f, 0x8d, 0x9d, 0x62, 0x0f, 0x66, 0x71, 0xec, 0x87, 0xc5, 0x80, 0x82, 0xc8, 0xf4, 0x6a, 0x94, 0x92, 0x5b, 0xb0, 0x16, 0x9b, 0xb2, 0xc9, 0x6f, 0x2b, 0x2d, 0xee, 0x95, 0x73, 0x2e, 0xc2, 0x1b, 0xc5, 0x55, 0x36, 0x86, 0x24, 0xf8, 0x20, 0x05, 0x0d, 0x93, 0xd7, 0x76},
+ subYX: fp.Elt{0x7f, 0x01, 0xeb, 0x2e, 0x48, 0x4d, 0x1d, 0xf1, 0x06, 0x7e, 0x7c, 0x2a, 0x43, 0xbf, 0x28, 0xac, 0xe9, 0x58, 0x13, 0xc8, 0xbf, 0x8e, 0xc0, 0xef, 0xe8, 0x4f, 0x46, 0x8a, 0xe7, 0xc0, 0xf6, 0x0f, 0x0a, 0x03, 0x48, 0x91, 0x55, 0x39, 0x2a, 0xe3, 0xdc, 0xf6, 0x22, 0x9d, 0x4d, 0x71, 0x55, 0x68, 0x25, 0x6e, 0x95, 0x52, 0xee, 0x4c, 0xd9, 0x01},
+ dt2: fp.Elt{0xac, 0x33, 0x3f, 0x7c, 0x27, 0x35, 0x15, 0x91, 0x33, 0x8d, 0xf9, 0xc4, 0xf4, 0xf3, 0x90, 0x09, 0x75, 0x69, 0x62, 0x9f, 0x61, 0x35, 0x83, 0x92, 0x04, 0xef, 0x96, 0x38, 0x80, 0x9e, 0x88, 0xb3, 0x67, 0x95, 0xbe, 0x79, 0x3c, 0x35, 0xd8, 0xdc, 0xb2, 0x3e, 0x2d, 0xe6, 0x46, 0xbe, 0x81, 0xf3, 0x32, 0x0e, 0x37, 0x23, 0x75, 0x2a, 0x3d, 0xa0},
+ },
+}
diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go
new file mode 100644
index 0000000000..f6ac5edbbb
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go
@@ -0,0 +1,62 @@
+package goldilocks
+
+import (
+ "crypto/subtle"
+
+ mlsb "github.com/cloudflare/circl/math/mlsbset"
+)
+
+const (
+ // MLSBRecoding parameters
+ fxT = 448
+ fxV = 2
+ fxW = 3
+ fx2w1 = 1 << (uint(fxW) - 1)
+)
+
+// ScalarBaseMult returns kG where G is the generator point.
+func (e twistCurve) ScalarBaseMult(k *Scalar) *twistPoint {
+ m, err := mlsb.New(fxT, fxV, fxW)
+ if err != nil {
+ panic(err)
+ }
+ if m.IsExtended() {
+ panic("not extended")
+ }
+
+ var isZero int
+ if k.IsZero() {
+ isZero = 1
+ }
+ subtle.ConstantTimeCopy(isZero, k[:], order[:])
+
+ minusK := *k
+ isEven := 1 - int(k[0]&0x1)
+ minusK.Neg()
+ subtle.ConstantTimeCopy(isEven, k[:], minusK[:])
+ c, err := m.Encode(k[:])
+ if err != nil {
+ panic(err)
+ }
+
+ gP := c.Exp(groupMLSB{})
+ P := gP.(*twistPoint)
+ P.cneg(uint(isEven))
+ return P
+}
+
+type groupMLSB struct{}
+
+func (e groupMLSB) ExtendedEltP() mlsb.EltP { return nil }
+func (e groupMLSB) Sqr(x mlsb.EltG) { x.(*twistPoint).Double() }
+func (e groupMLSB) Mul(x mlsb.EltG, y mlsb.EltP) { x.(*twistPoint).mixAddZ1(y.(*preTwistPointAffine)) }
+func (e groupMLSB) Identity() mlsb.EltG { return twistCurve{}.Identity() }
+func (e groupMLSB) NewEltP() mlsb.EltP { return &preTwistPointAffine{} }
+func (e groupMLSB) Lookup(a mlsb.EltP, v uint, s, u int32) {
+ Tabj := &tabFixMult[v]
+ P := a.(*preTwistPointAffine)
+ for k := range Tabj {
+ P.cmov(&Tabj[k], uint(subtle.ConstantTimeEq(int32(k), u)))
+ }
+ P.cneg(int(s >> 31))
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/conv/conv.go b/vendor/github.com/cloudflare/circl/internal/conv/conv.go
new file mode 100644
index 0000000000..3fd0df496f
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/conv/conv.go
@@ -0,0 +1,173 @@
+package conv
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math/big"
+ "strings"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// BytesLe2Hex returns an hexadecimal string of a number stored in a
+// little-endian order slice x.
+func BytesLe2Hex(x []byte) string {
+ b := &strings.Builder{}
+ b.Grow(2*len(x) + 2)
+ fmt.Fprint(b, "0x")
+ if len(x) == 0 {
+ fmt.Fprint(b, "00")
+ }
+ for i := len(x) - 1; i >= 0; i-- {
+ fmt.Fprintf(b, "%02x", x[i])
+ }
+ return b.String()
+}
+
+// BytesLe2BigInt converts a little-endian slice x into a big-endian
+// math/big.Int.
+func BytesLe2BigInt(x []byte) *big.Int {
+ n := len(x)
+ b := new(big.Int)
+ if len(x) > 0 {
+ y := make([]byte, n)
+ for i := 0; i < n; i++ {
+ y[n-1-i] = x[i]
+ }
+ b.SetBytes(y)
+ }
+ return b
+}
+
+// BytesBe2Uint64Le converts a big-endian slice x to a little-endian slice of uint64.
+func BytesBe2Uint64Le(x []byte) []uint64 {
+ l := len(x)
+ z := make([]uint64, (l+7)/8)
+ blocks := l / 8
+ for i := 0; i < blocks; i++ {
+ z[i] = binary.BigEndian.Uint64(x[l-8*(i+1):])
+ }
+ remBytes := l % 8
+ for i := 0; i < remBytes; i++ {
+ z[blocks] |= uint64(x[l-1-8*blocks-i]) << uint(8*i)
+ }
+ return z
+}
+
+// BigInt2BytesLe stores a positive big.Int number x into a little-endian slice z.
+// The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros).
+// If x does not fit in the slice or is negative, z is not modified.
+func BigInt2BytesLe(z []byte, x *big.Int) {
+ xLen := (x.BitLen() + 7) >> 3
+ zLen := len(z)
+ if zLen >= xLen && x.Sign() >= 0 {
+ y := x.Bytes()
+ for i := 0; i < xLen; i++ {
+ z[i] = y[xLen-1-i]
+ }
+ for i := xLen; i < zLen; i++ {
+ z[i] = 0
+ }
+ }
+}
+
+// Uint64Le2BigInt converts a little-endian slice x into a big number.
+func Uint64Le2BigInt(x []uint64) *big.Int {
+ n := len(x)
+ b := new(big.Int)
+ var bi big.Int
+ for i := n - 1; i >= 0; i-- {
+ bi.SetUint64(x[i])
+ b.Lsh(b, 64)
+ b.Add(b, &bi)
+ }
+ return b
+}
+
+// Uint64Le2BytesLe converts a little-endian slice x to a little-endian slice of bytes.
+func Uint64Le2BytesLe(x []uint64) []byte {
+ b := make([]byte, 8*len(x))
+ n := len(x)
+ for i := 0; i < n; i++ {
+ binary.LittleEndian.PutUint64(b[i*8:], x[i])
+ }
+ return b
+}
+
+// Uint64Le2BytesBe converts a little-endian slice x to a big-endian slice of bytes.
+func Uint64Le2BytesBe(x []uint64) []byte {
+ b := make([]byte, 8*len(x))
+ n := len(x)
+ for i := 0; i < n; i++ {
+ binary.BigEndian.PutUint64(b[i*8:], x[n-1-i])
+ }
+ return b
+}
+
+// Uint64Le2Hex returns an hexadecimal string of a number stored in a
+// little-endian order slice x.
+func Uint64Le2Hex(x []uint64) string {
+ b := new(strings.Builder)
+ b.Grow(16*len(x) + 2)
+ fmt.Fprint(b, "0x")
+ if len(x) == 0 {
+ fmt.Fprint(b, "00")
+ }
+ for i := len(x) - 1; i >= 0; i-- {
+ fmt.Fprintf(b, "%016x", x[i])
+ }
+ return b.String()
+}
+
+// BigInt2Uint64Le stores a positive big.Int number x into a little-endian slice z.
+// The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros).
+// If x does not fit in the slice or is negative, z is not modified.
+func BigInt2Uint64Le(z []uint64, x *big.Int) {
+ xLen := (x.BitLen() + 63) >> 6 // number of 64-bit words
+ zLen := len(z)
+ if zLen >= xLen && x.Sign() > 0 {
+ var y, yi big.Int
+ y.Set(x)
+ two64 := big.NewInt(1)
+ two64.Lsh(two64, 64).Sub(two64, big.NewInt(1))
+ for i := 0; i < xLen; i++ {
+ yi.And(&y, two64)
+ z[i] = yi.Uint64()
+ y.Rsh(&y, 64)
+ }
+ }
+ for i := xLen; i < zLen; i++ {
+ z[i] = 0
+ }
+}
+
+// MarshalBinary encodes a value into a byte array in a format readable by UnmarshalBinary.
+func MarshalBinary(v cryptobyte.MarshalingValue) ([]byte, error) {
+ const DefaultSize = 32
+ b := cryptobyte.NewBuilder(make([]byte, 0, DefaultSize))
+ b.AddValue(v)
+ return b.Bytes()
+}
+
+// MarshalBinaryLen encodes a value into an array of n bytes in a format readable by UnmarshalBinary.
+func MarshalBinaryLen(v cryptobyte.MarshalingValue, length uint) ([]byte, error) {
+ b := cryptobyte.NewFixedBuilder(make([]byte, 0, length))
+ b.AddValue(v)
+ return b.Bytes()
+}
+
+// A UnmarshalingValue decodes itself from a cryptobyte.String and advances the pointer.
+// It reports whether the read was successful.
+type UnmarshalingValue interface {
+ Unmarshal(*cryptobyte.String) bool
+}
+
+// UnmarshalBinary recovers a value from a byte array.
+// It returns an error if the read was unsuccessful.
+func UnmarshalBinary(v UnmarshalingValue, data []byte) (err error) {
+ s := cryptobyte.String(data)
+ if data == nil || !v.Unmarshal(&s) || !s.Empty() {
+ err = fmt.Errorf("cannot read %T from input string", v)
+ }
+ return
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/doc.go b/vendor/github.com/cloudflare/circl/internal/sha3/doc.go
new file mode 100644
index 0000000000..7e02309070
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/doc.go
@@ -0,0 +1,62 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha3 implements the SHA-3 fixed-output-length hash functions and
+// the SHAKE variable-output-length hash functions defined by FIPS-202.
+//
+// Both types of hash function use the "sponge" construction and the Keccak
+// permutation. For a detailed specification see http://keccak.noekeon.org/
+//
+// # Guidance
+//
+// If you aren't sure what function you need, use SHAKE256 with at least 64
+// bytes of output. The SHAKE instances are faster than the SHA3 instances;
+// the latter have to allocate memory to conform to the hash.Hash interface.
+//
+// If you need a secret-key MAC (message authentication code), prepend the
+// secret key to the input, hash with SHAKE256 and read at least 32 bytes of
+// output.
+//
+// # Security strengths
+//
+// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
+// strength against preimage attacks of x bits. Since they only produce "x"
+// bits of output, their collision-resistance is only "x/2" bits.
+//
+// The SHAKE-256 and -128 functions have a generic security strength of 256 and
+// 128 bits against all attacks, provided that at least 2x bits of their output
+// is used. Requesting more than 64 or 32 bytes of output, respectively, does
+// not increase the collision-resistance of the SHAKE functions.
+//
+// # The sponge construction
+//
+// A sponge builds a pseudo-random function from a public pseudo-random
+// permutation, by applying the permutation to a state of "rate + capacity"
+// bytes, but hiding "capacity" of the bytes.
+//
+// A sponge starts out with a zero state. To hash an input using a sponge, up
+// to "rate" bytes of the input are XORed into the sponge's state. The sponge
+// is then "full" and the permutation is applied to "empty" it. This process is
+// repeated until all the input has been "absorbed". The input is then padded.
+// The digest is "squeezed" from the sponge in the same way, except that output
+// is copied out instead of input being XORed in.
+//
+// A sponge is parameterized by its generic security strength, which is equal
+// to half its capacity; capacity + rate is equal to the permutation's width.
+// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
+// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
+//
+// # Recommendations
+//
+// The SHAKE functions are recommended for most new uses. They can produce
+// output of arbitrary length. SHAKE256, with an output length of at least
+// 64 bytes, provides 256-bit security against all attacks. The Keccak team
+// recommends it for most applications upgrading from SHA2-512. (NIST chose a
+// much stronger, but much slower, sponge instance for SHA3-512.)
+//
+// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
+// They produce output of the same length, with the same security strengths
+// against all attacks. This means, in particular, that SHA3-256 only has
+// 128-bit collision resistance, because its output length is 32 bytes.
+package sha3
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/hashes.go b/vendor/github.com/cloudflare/circl/internal/sha3/hashes.go
new file mode 100644
index 0000000000..7d2365a76e
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/hashes.go
@@ -0,0 +1,69 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// This file provides functions for creating instances of the SHA-3
+// and SHAKE hash functions, as well as utility functions for hashing
+// bytes.
+
+// New224 creates a new SHA3-224 hash.
+// Its generic security strength is 224 bits against preimage attacks,
+// and 112 bits against collision attacks.
+func New224() State {
+ return State{rate: 144, outputLen: 28, dsbyte: 0x06}
+}
+
+// New256 creates a new SHA3-256 hash.
+// Its generic security strength is 256 bits against preimage attacks,
+// and 128 bits against collision attacks.
+func New256() State {
+ return State{rate: 136, outputLen: 32, dsbyte: 0x06}
+}
+
+// New384 creates a new SHA3-384 hash.
+// Its generic security strength is 384 bits against preimage attacks,
+// and 192 bits against collision attacks.
+func New384() State {
+ return State{rate: 104, outputLen: 48, dsbyte: 0x06}
+}
+
+// New512 creates a new SHA3-512 hash.
+// Its generic security strength is 512 bits against preimage attacks,
+// and 256 bits against collision attacks.
+func New512() State {
+ return State{rate: 72, outputLen: 64, dsbyte: 0x06}
+}
+
+// Sum224 returns the SHA3-224 digest of the data.
+func Sum224(data []byte) (digest [28]byte) {
+ h := New224()
+ _, _ = h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
+
+// Sum256 returns the SHA3-256 digest of the data.
+func Sum256(data []byte) (digest [32]byte) {
+ h := New256()
+ _, _ = h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
+
+// Sum384 returns the SHA3-384 digest of the data.
+func Sum384(data []byte) (digest [48]byte) {
+ h := New384()
+ _, _ = h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
+
+// Sum512 returns the SHA3-512 digest of the data.
+func Sum512(data []byte) (digest [64]byte) {
+ h := New512()
+ _, _ = h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go b/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go
new file mode 100644
index 0000000000..1755fd1e6d
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go
@@ -0,0 +1,391 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// KeccakF1600 applies the Keccak permutation to a 1600b-wide
+// state represented as a slice of 25 uint64s.
+// If turbo is true, applies the 12-round variant instead of the
+// regular 24-round variant.
+// nolint:funlen
+func KeccakF1600(a *[25]uint64, turbo bool) {
+ // Implementation translated from Keccak-inplace.c
+ // in the keccak reference code.
+ var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
+
+ i := 0
+
+ if turbo {
+ i = 12
+ }
+
+ for ; i < 24; i += 4 {
+ // Combines the 5 steps in each round into 2 steps.
+ // Unrolls 4 rounds per loop and spreads some steps across rounds.
+
+ // Round 1
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[6] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[12] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[18] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[24] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i]
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[16] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[22] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[3] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[1] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[7] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[19] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[11] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[23] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[4] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[2] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[8] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[14] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 2
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[16] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[7] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[23] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[14] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i+1]
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[11] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[2] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[18] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[6] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[22] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[4] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[1] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[8] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[24] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[12] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[3] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[19] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 3
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[11] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[22] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[8] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[19] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i+2]
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[1] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[12] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[23] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[16] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[2] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[24] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[6] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[3] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[14] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[7] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[18] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[4] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 4
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[1] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[2] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[3] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[4] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i+3]
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[6] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[7] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[8] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[11] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[12] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[14] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[16] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[18] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[19] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[22] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[23] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[24] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+ }
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/rc.go b/vendor/github.com/cloudflare/circl/internal/sha3/rc.go
new file mode 100644
index 0000000000..6a3df42f30
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/rc.go
@@ -0,0 +1,29 @@
+package sha3
+
+// RC stores the round constants for use in the ι step.
+var RC = [24]uint64{
+ 0x0000000000000001,
+ 0x0000000000008082,
+ 0x800000000000808A,
+ 0x8000000080008000,
+ 0x000000000000808B,
+ 0x0000000080000001,
+ 0x8000000080008081,
+ 0x8000000000008009,
+ 0x000000000000008A,
+ 0x0000000000000088,
+ 0x0000000080008009,
+ 0x000000008000000A,
+ 0x000000008000808B,
+ 0x800000000000008B,
+ 0x8000000000008089,
+ 0x8000000000008003,
+ 0x8000000000008002,
+ 0x8000000000000080,
+ 0x000000000000800A,
+ 0x800000008000000A,
+ 0x8000000080008081,
+ 0x8000000000008080,
+ 0x0000000080000001,
+ 0x8000000080008008,
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go b/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go
new file mode 100644
index 0000000000..a0df5aa6c5
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go
@@ -0,0 +1,200 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// spongeDirection indicates the direction bytes are flowing through the sponge.
+type spongeDirection int
+
+const (
+ // spongeAbsorbing indicates that the sponge is absorbing input.
+ spongeAbsorbing spongeDirection = iota
+ // spongeSqueezing indicates that the sponge is being squeezed.
+ spongeSqueezing
+)
+
+const (
+ // maxRate is the maximum size of the internal buffer. SHAKE-256
+ // currently needs the largest buffer.
+ maxRate = 168
+)
+
+func (d *State) buf() []byte {
+ return d.storage.asBytes()[d.bufo:d.bufe]
+}
+
+type State struct {
+ // Generic sponge components.
+ a [25]uint64 // main state of the hash
+ rate int // the number of bytes of state to use
+
+ bufo int // offset of buffer in storage
+ bufe int // end of buffer in storage
+
+ // dsbyte contains the "domain separation" bits and the first bit of
+ // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
+ // SHA-3 and SHAKE functions by appending bitstrings to the message.
+ // Using a little-endian bit-ordering convention, these are "01" for SHA-3
+ // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
+ // padding rule from section 5.1 is applied to pad the message to a multiple
+ // of the rate, which involves adding a "1" bit, zero or more "0" bits, and
+ // a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
+ // giving 00000110b (0x06) and 00011111b (0x1f).
+ // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
+ // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
+ // Extendable-Output Functions (May 2014)"
+ dsbyte byte
+
+ storage storageBuf
+
+ // Specific to SHA-3 and SHAKE.
+ outputLen int // the default output size in bytes
+ state spongeDirection // whether the sponge is absorbing or squeezing
+ turbo bool // Whether we're using 12 rounds instead of 24
+}
+
+// BlockSize returns the rate of sponge underlying this hash function.
+func (d *State) BlockSize() int { return d.rate }
+
+// Size returns the output size of the hash function in bytes.
+func (d *State) Size() int { return d.outputLen }
+
+// Reset clears the internal state by zeroing the sponge state and
+// the byte buffer, and setting Sponge.state to absorbing.
+func (d *State) Reset() {
+ // Zero the permutation's state.
+ for i := range d.a {
+ d.a[i] = 0
+ }
+ d.state = spongeAbsorbing
+ d.bufo = 0
+ d.bufe = 0
+}
+
+func (d *State) clone() *State {
+ ret := *d
+ return &ret
+}
+
+// permute applies the KeccakF-1600 permutation. It handles
+// any input-output buffering.
+func (d *State) permute() {
+ switch d.state {
+ case spongeAbsorbing:
+ // If we're absorbing, we need to xor the input into the state
+ // before applying the permutation.
+ xorIn(d, d.buf())
+ d.bufe = 0
+ d.bufo = 0
+ KeccakF1600(&d.a, d.turbo)
+ case spongeSqueezing:
+ // If we're squeezing, we need to apply the permutation before
+ // copying more output.
+ KeccakF1600(&d.a, d.turbo)
+ d.bufe = d.rate
+ d.bufo = 0
+ copyOut(d, d.buf())
+ }
+}
+
+// pads appends the domain separation bits in dsbyte, applies
+// the multi-bitrate 10..1 padding rule, and permutes the state.
+func (d *State) padAndPermute(dsbyte byte) {
+ // Pad with this instance's domain-separator bits. We know that there's
+ // at least one byte of space in d.buf() because, if it were full,
+ // permute would have been called to empty it. dsbyte also contains the
+ // first one bit for the padding. See the comment in the state struct.
+ zerosStart := d.bufe + 1
+ d.bufe = d.rate
+ buf := d.buf()
+ buf[zerosStart-1] = dsbyte
+ for i := zerosStart; i < d.rate; i++ {
+ buf[i] = 0
+ }
+ // This adds the final one bit for the padding. Because of the way that
+ // bits are numbered from the LSB upwards, the final bit is the MSB of
+ // the last byte.
+ buf[d.rate-1] ^= 0x80
+ // Apply the permutation
+ d.permute()
+ d.state = spongeSqueezing
+ d.bufe = d.rate
+ copyOut(d, buf)
+}
+
+// Write absorbs more data into the hash's state. It produces an error
+// if more data is written to the ShakeHash after writing
+func (d *State) Write(p []byte) (written int, err error) {
+ if d.state != spongeAbsorbing {
+ panic("sha3: write to sponge after read")
+ }
+ written = len(p)
+
+ for len(p) > 0 {
+ bufl := d.bufe - d.bufo
+ if bufl == 0 && len(p) >= d.rate {
+ // The fast path; absorb a full "rate" bytes of input and apply the permutation.
+ xorIn(d, p[:d.rate])
+ p = p[d.rate:]
+ KeccakF1600(&d.a, d.turbo)
+ } else {
+ // The slow path; buffer the input until we can fill the sponge, and then xor it in.
+ todo := d.rate - bufl
+ if todo > len(p) {
+ todo = len(p)
+ }
+ d.bufe += todo
+ buf := d.buf()
+ copy(buf[bufl:], p[:todo])
+ p = p[todo:]
+
+ // If the sponge is full, apply the permutation.
+ if d.bufe == d.rate {
+ d.permute()
+ }
+ }
+ }
+
+ return written, nil
+}
+
+// Read squeezes an arbitrary number of bytes from the sponge.
+func (d *State) Read(out []byte) (n int, err error) {
+ // If we're still absorbing, pad and apply the permutation.
+ if d.state == spongeAbsorbing {
+ d.padAndPermute(d.dsbyte)
+ }
+
+ n = len(out)
+
+ // Now, do the squeezing.
+ for len(out) > 0 {
+ buf := d.buf()
+ n := copy(out, buf)
+ d.bufo += n
+ out = out[n:]
+
+ // Apply the permutation if we've squeezed the sponge dry.
+ if d.bufo == d.bufe {
+ d.permute()
+ }
+ }
+
+ return
+}
+
+// Sum applies padding to the hash state and then squeezes out the desired
+// number of output bytes.
+func (d *State) Sum(in []byte) []byte {
+ // Make a copy of the original hash so that caller can keep writing
+ // and summing.
+ dup := d.clone()
+ hash := make([]byte, dup.outputLen)
+ _, _ = dup.Read(hash)
+ return append(in, hash...)
+}
+
+func (d *State) IsAbsorbing() bool {
+ return d.state == spongeAbsorbing
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s b/vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s
new file mode 100644
index 0000000000..8a4458f63f
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s
@@ -0,0 +1,33 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo,!appengine
+
+#include "textflag.h"
+
+// func kimd(function code, chain *[200]byte, src []byte)
+TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40
+ MOVD function+0(FP), R0
+ MOVD chain+8(FP), R1
+ LMG src+16(FP), R2, R3 // R2=base, R3=len
+
+continue:
+ WORD $0xB93E0002 // KIMD --, R2
+ BVS continue // continue if interrupted
+ MOVD $0, R0 // reset R0 for pre-go1.8 compilers
+ RET
+
+// func klmd(function code, chain *[200]byte, dst, src []byte)
+TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64
+ // TODO: SHAKE support
+ MOVD function+0(FP), R0
+ MOVD chain+8(FP), R1
+ LMG dst+16(FP), R2, R3 // R2=base, R3=len
+ LMG src+40(FP), R4, R5 // R4=base, R5=len
+
+continue:
+ WORD $0xB93F0024 // KLMD R2, R4
+ BVS continue // continue if interrupted
+ MOVD $0, R0 // reset R0 for pre-go1.8 compilers
+ RET
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/shake.go b/vendor/github.com/cloudflare/circl/internal/sha3/shake.go
new file mode 100644
index 0000000000..77817f758c
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/shake.go
@@ -0,0 +1,119 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// This file defines the ShakeHash interface, and provides
+// functions for creating SHAKE and cSHAKE instances, as well as utility
+// functions for hashing bytes to arbitrary-length output.
+//
+//
+// SHAKE implementation is based on FIPS PUB 202 [1]
+// cSHAKE implementations is based on NIST SP 800-185 [2]
+//
+// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
+// [2] https://doi.org/10.6028/NIST.SP.800-185
+
+import (
+ "io"
+)
+
+// ShakeHash defines the interface to hash functions that
+// support arbitrary-length output.
+type ShakeHash interface {
+ // Write absorbs more data into the hash's state. It panics if input is
+ // written to it after output has been read from it.
+ io.Writer
+
+ // Read reads more output from the hash; reading affects the hash's
+ // state. (ShakeHash.Read is thus very different from Hash.Sum)
+ // It never returns an error.
+ io.Reader
+
+ // Clone returns a copy of the ShakeHash in its current state.
+ Clone() ShakeHash
+
+ // Reset resets the ShakeHash to its initial state.
+ Reset()
+}
+
+// Consts for configuring initial SHA-3 state
+const (
+ dsbyteShake = 0x1f
+ rate128 = 168
+ rate256 = 136
+)
+
+// Clone returns copy of SHAKE context within its current state.
+func (d *State) Clone() ShakeHash {
+ return d.clone()
+}
+
+// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
+// Its generic security strength is 128 bits against all attacks if at
+// least 32 bytes of its output are used.
+func NewShake128() State {
+ return State{rate: rate128, dsbyte: dsbyteShake}
+}
+
+// NewTurboShake128 creates a new TurboSHAKE128 variable-output-length ShakeHash.
+// Its generic security strength is 128 bits against all attacks if at
+// least 32 bytes of its output are used.
+// D is the domain separation byte and must be between 0x01 and 0x7f inclusive.
+func NewTurboShake128(D byte) State {
+ if D == 0 || D > 0x7f {
+ panic("turboshake: D out of range")
+ }
+ return State{rate: rate128, dsbyte: D, turbo: true}
+}
+
+// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
+// Its generic security strength is 256 bits against all attacks if
+// at least 64 bytes of its output are used.
+func NewShake256() State {
+ return State{rate: rate256, dsbyte: dsbyteShake}
+}
+
+// NewTurboShake256 creates a new TurboSHAKE256 variable-output-length ShakeHash.
+// Its generic security strength is 256 bits against all attacks if
+// at least 64 bytes of its output are used.
+// D is the domain separation byte and must be between 0x01 and 0x7f inclusive.
+func NewTurboShake256(D byte) State {
+ if D == 0 || D > 0x7f {
+ panic("turboshake: D out of range")
+ }
+ return State{rate: rate256, dsbyte: D, turbo: true}
+}
+
+// ShakeSum128 writes an arbitrary-length digest of data into hash.
+func ShakeSum128(hash, data []byte) {
+ h := NewShake128()
+ _, _ = h.Write(data)
+ _, _ = h.Read(hash)
+}
+
+// ShakeSum256 writes an arbitrary-length digest of data into hash.
+func ShakeSum256(hash, data []byte) {
+ h := NewShake256()
+ _, _ = h.Write(data)
+ _, _ = h.Read(hash)
+}
+
+// TurboShakeSum128 writes an arbitrary-length digest of data into hash.
+func TurboShakeSum128(hash, data []byte, D byte) {
+ h := NewTurboShake128(D)
+ _, _ = h.Write(data)
+ _, _ = h.Read(hash)
+}
+
+// TurboShakeSum256 writes an arbitrary-length digest of data into hash.
+func TurboShakeSum256(hash, data []byte, D byte) {
+ h := NewTurboShake256(D)
+ _, _ = h.Write(data)
+ _, _ = h.Read(hash)
+}
+
+func (d *State) SwitchDS(D byte) {
+ d.dsbyte = D
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/xor.go b/vendor/github.com/cloudflare/circl/internal/sha3/xor.go
new file mode 100644
index 0000000000..1e21337454
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/xor.go
@@ -0,0 +1,15 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (!amd64 && !386 && !ppc64le) || appengine
+// +build !amd64,!386,!ppc64le appengine
+
+package sha3
+
+// A storageBuf is an aligned array of maxRate bytes.
+type storageBuf [maxRate]byte
+
+func (b *storageBuf) asBytes() *[maxRate]byte {
+ return (*[maxRate]byte)(b)
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go b/vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go
new file mode 100644
index 0000000000..2b0c661790
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go
@@ -0,0 +1,33 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (!amd64 || appengine) && (!386 || appengine) && (!ppc64le || appengine)
+// +build !amd64 appengine
+// +build !386 appengine
+// +build !ppc64le appengine
+
+package sha3
+
+import "encoding/binary"
+
+// xorIn xors the bytes in buf into the state; it
+// makes no non-portable assumptions about memory layout
+// or alignment.
+func xorIn(d *State, buf []byte) {
+ n := len(buf) / 8
+
+ for i := 0; i < n; i++ {
+ a := binary.LittleEndian.Uint64(buf)
+ d.a[i] ^= a
+ buf = buf[8:]
+ }
+}
+
+// copyOut copies ulint64s to a byte buffer.
+func copyOut(d *State, b []byte) {
+ for i := 0; len(b) >= 8; i++ {
+ binary.LittleEndian.PutUint64(b, d.a[i])
+ b = b[8:]
+ }
+}
diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go b/vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go
new file mode 100644
index 0000000000..0910613465
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go
@@ -0,0 +1,61 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (amd64 || 386 || ppc64le) && !appengine
+// +build amd64 386 ppc64le
+// +build !appengine
+
+package sha3
+
+import "unsafe"
+
+// A storageBuf is an aligned array of maxRate bytes.
+type storageBuf [maxRate / 8]uint64
+
+func (b *storageBuf) asBytes() *[maxRate]byte {
+ return (*[maxRate]byte)(unsafe.Pointer(b)) //nolint:gosec
+}
+
+// xorInuses unaligned reads and writes to update d.a to contain d.a
+// XOR buf.
+func xorIn(d *State, buf []byte) {
+ n := len(buf)
+ bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8] //nolint:gosec
+ if n >= 72 {
+ d.a[0] ^= bw[0]
+ d.a[1] ^= bw[1]
+ d.a[2] ^= bw[2]
+ d.a[3] ^= bw[3]
+ d.a[4] ^= bw[4]
+ d.a[5] ^= bw[5]
+ d.a[6] ^= bw[6]
+ d.a[7] ^= bw[7]
+ d.a[8] ^= bw[8]
+ }
+ if n >= 104 {
+ d.a[9] ^= bw[9]
+ d.a[10] ^= bw[10]
+ d.a[11] ^= bw[11]
+ d.a[12] ^= bw[12]
+ }
+ if n >= 136 {
+ d.a[13] ^= bw[13]
+ d.a[14] ^= bw[14]
+ d.a[15] ^= bw[15]
+ d.a[16] ^= bw[16]
+ }
+ if n >= 144 {
+ d.a[17] ^= bw[17]
+ }
+ if n >= 168 {
+ d.a[18] ^= bw[18]
+ d.a[19] ^= bw[19]
+ d.a[20] ^= bw[20]
+ }
+}
+
+func copyOut(d *State, buf []byte) {
+ ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0])) //nolint:gosec
+ copy(buf, ab[:])
+}
diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp.go b/vendor/github.com/cloudflare/circl/math/fp25519/fp.go
new file mode 100644
index 0000000000..57a50ff5e9
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp.go
@@ -0,0 +1,205 @@
+// Package fp25519 provides prime field arithmetic over GF(2^255-19).
+package fp25519
+
+import (
+ "errors"
+
+ "github.com/cloudflare/circl/internal/conv"
+)
+
+// Size in bytes of an element.
+const Size = 32
+
+// Elt is a prime field element.
+type Elt [Size]byte
+
+func (e Elt) String() string { return conv.BytesLe2Hex(e[:]) }
+
+// p is the prime modulus 2^255-19.
+var p = Elt{
+ 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+}
+
+// P returns the prime modulus 2^255-19.
+func P() Elt { return p }
+
+// ToBytes stores in b the little-endian byte representation of x.
+func ToBytes(b []byte, x *Elt) error {
+ if len(b) != Size {
+ return errors.New("wrong size")
+ }
+ Modp(x)
+ copy(b, x[:])
+ return nil
+}
+
+// IsZero returns true if x is equal to 0.
+func IsZero(x *Elt) bool { Modp(x); return *x == Elt{} }
+
+// SetOne assigns x=1.
+func SetOne(x *Elt) { *x = Elt{}; x[0] = 1 }
+
+// Neg calculates z = -x.
+func Neg(z, x *Elt) { Sub(z, &p, x) }
+
+// InvSqrt calculates z = sqrt(x/y) iff x/y is a quadratic-residue, which is
+// indicated by returning isQR = true. Otherwise, when x/y is a quadratic
+// non-residue, z will have an undetermined value and isQR = false.
+func InvSqrt(z, x, y *Elt) (isQR bool) {
+ sqrtMinusOne := &Elt{
+ 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4,
+ 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f,
+ 0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b,
+ 0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b,
+ }
+ t0, t1, t2, t3 := &Elt{}, &Elt{}, &Elt{}, &Elt{}
+
+ Mul(t0, x, y) // t0 = u*v
+ Sqr(t1, y) // t1 = v^2
+ Mul(t2, t0, t1) // t2 = u*v^3
+ Sqr(t0, t1) // t0 = v^4
+ Mul(t1, t0, t2) // t1 = u*v^7
+
+ var Tab [4]*Elt
+ Tab[0] = &Elt{}
+ Tab[1] = &Elt{}
+ Tab[2] = t3
+ Tab[3] = t1
+
+ *Tab[0] = *t1
+ Sqr(Tab[0], Tab[0])
+ Sqr(Tab[1], Tab[0])
+ Sqr(Tab[1], Tab[1])
+ Mul(Tab[1], Tab[1], Tab[3])
+ Mul(Tab[0], Tab[0], Tab[1])
+ Sqr(Tab[0], Tab[0])
+ Mul(Tab[0], Tab[0], Tab[1])
+ Sqr(Tab[1], Tab[0])
+ for i := 0; i < 4; i++ {
+ Sqr(Tab[1], Tab[1])
+ }
+ Mul(Tab[1], Tab[1], Tab[0])
+ Sqr(Tab[2], Tab[1])
+ for i := 0; i < 4; i++ {
+ Sqr(Tab[2], Tab[2])
+ }
+ Mul(Tab[2], Tab[2], Tab[0])
+ Sqr(Tab[1], Tab[2])
+ for i := 0; i < 14; i++ {
+ Sqr(Tab[1], Tab[1])
+ }
+ Mul(Tab[1], Tab[1], Tab[2])
+ Sqr(Tab[2], Tab[1])
+ for i := 0; i < 29; i++ {
+ Sqr(Tab[2], Tab[2])
+ }
+ Mul(Tab[2], Tab[2], Tab[1])
+ Sqr(Tab[1], Tab[2])
+ for i := 0; i < 59; i++ {
+ Sqr(Tab[1], Tab[1])
+ }
+ Mul(Tab[1], Tab[1], Tab[2])
+ for i := 0; i < 5; i++ {
+ Sqr(Tab[1], Tab[1])
+ }
+ Mul(Tab[1], Tab[1], Tab[0])
+ Sqr(Tab[2], Tab[1])
+ for i := 0; i < 124; i++ {
+ Sqr(Tab[2], Tab[2])
+ }
+ Mul(Tab[2], Tab[2], Tab[1])
+ Sqr(Tab[2], Tab[2])
+ Sqr(Tab[2], Tab[2])
+ Mul(Tab[2], Tab[2], Tab[3])
+
+ Mul(z, t3, t2) // z = xy^(p+3)/8 = xy^3*(xy^7)^(p-5)/8
+ // Checking whether y z^2 == x
+ Sqr(t0, z) // t0 = z^2
+ Mul(t0, t0, y) // t0 = yz^2
+ Sub(t1, t0, x) // t1 = t0-u
+ Add(t2, t0, x) // t2 = t0+u
+ if IsZero(t1) {
+ return true
+ } else if IsZero(t2) {
+ Mul(z, z, sqrtMinusOne) // z = z*sqrt(-1)
+ return true
+ } else {
+ return false
+ }
+}
+
+// Inv calculates z = 1/x mod p.
+func Inv(z, x *Elt) {
+ x0, x1, x2 := &Elt{}, &Elt{}, &Elt{}
+ Sqr(x1, x)
+ Sqr(x0, x1)
+ Sqr(x0, x0)
+ Mul(x0, x0, x)
+ Mul(z, x0, x1)
+ Sqr(x1, z)
+ Mul(x0, x0, x1)
+ Sqr(x1, x0)
+ for i := 0; i < 4; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(x0, x0, x1)
+ Sqr(x1, x0)
+ for i := 0; i < 9; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(x1, x1, x0)
+ Sqr(x2, x1)
+ for i := 0; i < 19; i++ {
+ Sqr(x2, x2)
+ }
+ Mul(x2, x2, x1)
+ for i := 0; i < 10; i++ {
+ Sqr(x2, x2)
+ }
+ Mul(x2, x2, x0)
+ Sqr(x0, x2)
+ for i := 0; i < 49; i++ {
+ Sqr(x0, x0)
+ }
+ Mul(x0, x0, x2)
+ Sqr(x1, x0)
+ for i := 0; i < 99; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(x1, x1, x0)
+ for i := 0; i < 50; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(x1, x1, x2)
+ for i := 0; i < 5; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(z, z, x1)
+}
+
+// Cmov assigns y to x if n is 1.
+func Cmov(x, y *Elt, n uint) { cmov(x, y, n) }
+
+// Cswap interchanges x and y if n is 1.
+func Cswap(x, y *Elt, n uint) { cswap(x, y, n) }
+
+// Add calculates z = x+y mod p.
+func Add(z, x, y *Elt) { add(z, x, y) }
+
+// Sub calculates z = x-y mod p.
+func Sub(z, x, y *Elt) { sub(z, x, y) }
+
+// AddSub calculates (x,y) = (x+y mod p, x-y mod p).
+func AddSub(x, y *Elt) { addsub(x, y) }
+
+// Mul calculates z = x*y mod p.
+func Mul(z, x, y *Elt) { mul(z, x, y) }
+
+// Sqr calculates z = x^2 mod p.
+func Sqr(z, x *Elt) { sqr(z, x) }
+
+// Modp ensures that z is between [0,p-1].
+func Modp(z *Elt) { modp(z) }
diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go
new file mode 100644
index 0000000000..057f0d2803
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go
@@ -0,0 +1,45 @@
+//go:build amd64 && !purego
+// +build amd64,!purego
+
+package fp25519
+
+import (
+ "golang.org/x/sys/cpu"
+)
+
+var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX
+
+var _ = hasBmi2Adx
+
+func cmov(x, y *Elt, n uint) { cmovAmd64(x, y, n) }
+func cswap(x, y *Elt, n uint) { cswapAmd64(x, y, n) }
+func add(z, x, y *Elt) { addAmd64(z, x, y) }
+func sub(z, x, y *Elt) { subAmd64(z, x, y) }
+func addsub(x, y *Elt) { addsubAmd64(x, y) }
+func mul(z, x, y *Elt) { mulAmd64(z, x, y) }
+func sqr(z, x *Elt) { sqrAmd64(z, x) }
+func modp(z *Elt) { modpAmd64(z) }
+
+//go:noescape
+func cmovAmd64(x, y *Elt, n uint)
+
+//go:noescape
+func cswapAmd64(x, y *Elt, n uint)
+
+//go:noescape
+func addAmd64(z, x, y *Elt)
+
+//go:noescape
+func subAmd64(z, x, y *Elt)
+
+//go:noescape
+func addsubAmd64(x, y *Elt)
+
+//go:noescape
+func mulAmd64(z, x, y *Elt)
+
+//go:noescape
+func sqrAmd64(z, x *Elt)
+
+//go:noescape
+func modpAmd64(z *Elt)
diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h
new file mode 100644
index 0000000000..b884b584ab
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h
@@ -0,0 +1,351 @@
+// This code was imported from https://github.com/armfazh/rfc7748_precomputed
+
+// CHECK_BMI2ADX triggers bmi2adx if supported,
+// otherwise it fallbacks to legacy code.
+#define CHECK_BMI2ADX(label, legacy, bmi2adx) \
+ CMPB ·hasBmi2Adx(SB), $0 \
+ JE label \
+ bmi2adx \
+ RET \
+ label: \
+ legacy \
+ RET
+
+// cselect is a conditional move
+// if b=1: it copies y into x;
+// if b=0: x remains with the same value;
+// if b<> 0,1: undefined.
+// Uses: AX, DX, FLAGS
+// Instr: x86_64, cmov
+#define cselect(x,y,b) \
+ TESTQ b, b \
+ MOVQ 0+x, AX; MOVQ 0+y, DX; CMOVQNE DX, AX; MOVQ AX, 0+x; \
+ MOVQ 8+x, AX; MOVQ 8+y, DX; CMOVQNE DX, AX; MOVQ AX, 8+x; \
+ MOVQ 16+x, AX; MOVQ 16+y, DX; CMOVQNE DX, AX; MOVQ AX, 16+x; \
+ MOVQ 24+x, AX; MOVQ 24+y, DX; CMOVQNE DX, AX; MOVQ AX, 24+x;
+
+// cswap is a conditional swap
+// if b=1: x,y <- y,x;
+// if b=0: x,y remain with the same values;
+// if b<> 0,1: undefined.
+// Uses: AX, DX, R8, FLAGS
+// Instr: x86_64, cmov
+#define cswap(x,y,b) \
+ TESTQ b, b \
+ MOVQ 0+x, AX; MOVQ AX, R8; MOVQ 0+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 0+x; MOVQ DX, 0+y; \
+ MOVQ 8+x, AX; MOVQ AX, R8; MOVQ 8+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 8+x; MOVQ DX, 8+y; \
+ MOVQ 16+x, AX; MOVQ AX, R8; MOVQ 16+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 16+x; MOVQ DX, 16+y; \
+ MOVQ 24+x, AX; MOVQ AX, R8; MOVQ 24+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 24+x; MOVQ DX, 24+y;
+
+// additionLeg adds x and y and stores in z
+// Uses: AX, DX, R8-R11, FLAGS
+// Instr: x86_64, cmov
+#define additionLeg(z,x,y) \
+ MOVL $38, AX; \
+ MOVL $0, DX; \
+ MOVQ 0+x, R8; ADDQ 0+y, R8; \
+ MOVQ 8+x, R9; ADCQ 8+y, R9; \
+ MOVQ 16+x, R10; ADCQ 16+y, R10; \
+ MOVQ 24+x, R11; ADCQ 24+y, R11; \
+ CMOVQCS AX, DX; \
+ ADDQ DX, R8; \
+ ADCQ $0, R9; MOVQ R9, 8+z; \
+ ADCQ $0, R10; MOVQ R10, 16+z; \
+ ADCQ $0, R11; MOVQ R11, 24+z; \
+ MOVL $0, DX; \
+ CMOVQCS AX, DX; \
+ ADDQ DX, R8; MOVQ R8, 0+z;
+
+// additionAdx adds x and y and stores in z
+// Uses: AX, DX, R8-R11, FLAGS
+// Instr: x86_64, cmov, adx
+#define additionAdx(z,x,y) \
+ MOVL $38, AX; \
+ XORL DX, DX; \
+ MOVQ 0+x, R8; ADCXQ 0+y, R8; \
+ MOVQ 8+x, R9; ADCXQ 8+y, R9; \
+ MOVQ 16+x, R10; ADCXQ 16+y, R10; \
+ MOVQ 24+x, R11; ADCXQ 24+y, R11; \
+ CMOVQCS AX, DX ; \
+ XORL AX, AX; \
+ ADCXQ DX, R8; \
+ ADCXQ AX, R9; MOVQ R9, 8+z; \
+ ADCXQ AX, R10; MOVQ R10, 16+z; \
+ ADCXQ AX, R11; MOVQ R11, 24+z; \
+ MOVL $38, DX; \
+ CMOVQCS DX, AX; \
+ ADDQ AX, R8; MOVQ R8, 0+z;
+
+// subtraction subtracts y from x and stores in z
+// Uses: AX, DX, R8-R11, FLAGS
+// Instr: x86_64, cmov
+#define subtraction(z,x,y) \
+ MOVL $38, AX; \
+ MOVQ 0+x, R8; SUBQ 0+y, R8; \
+ MOVQ 8+x, R9; SBBQ 8+y, R9; \
+ MOVQ 16+x, R10; SBBQ 16+y, R10; \
+ MOVQ 24+x, R11; SBBQ 24+y, R11; \
+ MOVL $0, DX; \
+ CMOVQCS AX, DX; \
+ SUBQ DX, R8; \
+ SBBQ $0, R9; MOVQ R9, 8+z; \
+ SBBQ $0, R10; MOVQ R10, 16+z; \
+ SBBQ $0, R11; MOVQ R11, 24+z; \
+ MOVL $0, DX; \
+ CMOVQCS AX, DX; \
+ SUBQ DX, R8; MOVQ R8, 0+z;
+
+// integerMulAdx multiplies x and y and stores in z
+// Uses: AX, DX, R8-R15, FLAGS
+// Instr: x86_64, bmi2, adx
+#define integerMulAdx(z,x,y) \
+ MOVL $0,R15; \
+ MOVQ 0+y, DX; XORL AX, AX; \
+ MULXQ 0+x, AX, R8; MOVQ AX, 0+z; \
+ MULXQ 8+x, AX, R9; ADCXQ AX, R8; \
+ MULXQ 16+x, AX, R10; ADCXQ AX, R9; \
+ MULXQ 24+x, AX, R11; ADCXQ AX, R10; \
+ MOVL $0, AX;;;;;;;;; ADCXQ AX, R11; \
+ MOVQ 8+y, DX; XORL AX, AX; \
+ MULXQ 0+x, AX, R12; ADCXQ R8, AX; MOVQ AX, 8+z; \
+ MULXQ 8+x, AX, R13; ADCXQ R9, R12; ADOXQ AX, R12; \
+ MULXQ 16+x, AX, R14; ADCXQ R10, R13; ADOXQ AX, R13; \
+ MULXQ 24+x, AX, R15; ADCXQ R11, R14; ADOXQ AX, R14; \
+ MOVL $0, AX;;;;;;;;; ADCXQ AX, R15; ADOXQ AX, R15; \
+ MOVQ 16+y, DX; XORL AX, AX; \
+ MULXQ 0+x, AX, R8; ADCXQ R12, AX; MOVQ AX, 16+z; \
+ MULXQ 8+x, AX, R9; ADCXQ R13, R8; ADOXQ AX, R8; \
+ MULXQ 16+x, AX, R10; ADCXQ R14, R9; ADOXQ AX, R9; \
+ MULXQ 24+x, AX, R11; ADCXQ R15, R10; ADOXQ AX, R10; \
+ MOVL $0, AX;;;;;;;;; ADCXQ AX, R11; ADOXQ AX, R11; \
+ MOVQ 24+y, DX; XORL AX, AX; \
+ MULXQ 0+x, AX, R12; ADCXQ R8, AX; MOVQ AX, 24+z; \
+ MULXQ 8+x, AX, R13; ADCXQ R9, R12; ADOXQ AX, R12; MOVQ R12, 32+z; \
+ MULXQ 16+x, AX, R14; ADCXQ R10, R13; ADOXQ AX, R13; MOVQ R13, 40+z; \
+ MULXQ 24+x, AX, R15; ADCXQ R11, R14; ADOXQ AX, R14; MOVQ R14, 48+z; \
+ MOVL $0, AX;;;;;;;;; ADCXQ AX, R15; ADOXQ AX, R15; MOVQ R15, 56+z;
+
+// integerMulLeg multiplies x and y and stores in z
+// Uses: AX, DX, R8-R15, FLAGS
+// Instr: x86_64
+#define integerMulLeg(z,x,y) \
+ MOVQ 0+y, R8; \
+ MOVQ 0+x, AX; MULQ R8; MOVQ AX, 0+z; MOVQ DX, R15; \
+ MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \
+ MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \
+ MOVQ 24+x, AX; MULQ R8; \
+ ADDQ R13, R15; \
+ ADCQ R14, R10; MOVQ R10, 16+z; \
+ ADCQ AX, R11; MOVQ R11, 24+z; \
+ ADCQ $0, DX; MOVQ DX, 32+z; \
+ MOVQ 8+y, R8; \
+ MOVQ 0+x, AX; MULQ R8; MOVQ AX, R12; MOVQ DX, R9; \
+ MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \
+ MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \
+ MOVQ 24+x, AX; MULQ R8; \
+ ADDQ R12, R15; MOVQ R15, 8+z; \
+ ADCQ R13, R9; \
+ ADCQ R14, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, DX; \
+ ADCQ 16+z, R9; MOVQ R9, R15; \
+ ADCQ 24+z, R10; MOVQ R10, 24+z; \
+ ADCQ 32+z, R11; MOVQ R11, 32+z; \
+ ADCQ $0, DX; MOVQ DX, 40+z; \
+ MOVQ 16+y, R8; \
+ MOVQ 0+x, AX; MULQ R8; MOVQ AX, R12; MOVQ DX, R9; \
+ MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \
+ MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \
+ MOVQ 24+x, AX; MULQ R8; \
+ ADDQ R12, R15; MOVQ R15, 16+z; \
+ ADCQ R13, R9; \
+ ADCQ R14, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, DX; \
+ ADCQ 24+z, R9; MOVQ R9, R15; \
+ ADCQ 32+z, R10; MOVQ R10, 32+z; \
+ ADCQ 40+z, R11; MOVQ R11, 40+z; \
+ ADCQ $0, DX; MOVQ DX, 48+z; \
+ MOVQ 24+y, R8; \
+ MOVQ 0+x, AX; MULQ R8; MOVQ AX, R12; MOVQ DX, R9; \
+ MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \
+ MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \
+ MOVQ 24+x, AX; MULQ R8; \
+ ADDQ R12, R15; MOVQ R15, 24+z; \
+ ADCQ R13, R9; \
+ ADCQ R14, R10; \
+ ADCQ AX, R11; \
+ ADCQ $0, DX; \
+ ADCQ 32+z, R9; MOVQ R9, 32+z; \
+ ADCQ 40+z, R10; MOVQ R10, 40+z; \
+ ADCQ 48+z, R11; MOVQ R11, 48+z; \
+ ADCQ $0, DX; MOVQ DX, 56+z;
+
+// integerSqrLeg squares x and stores in z
+// Uses: AX, CX, DX, R8-R15, FLAGS
+// Instr: x86_64
+#define integerSqrLeg(z,x) \
+ MOVQ 0+x, R8; \
+ MOVQ 8+x, AX; MULQ R8; MOVQ AX, R9; MOVQ DX, R10; /* A[0]*A[1] */ \
+ MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; /* A[0]*A[2] */ \
+ MOVQ 24+x, AX; MULQ R8; MOVQ AX, R15; MOVQ DX, R12; /* A[0]*A[3] */ \
+ MOVQ 24+x, R8; \
+ MOVQ 8+x, AX; MULQ R8; MOVQ AX, CX; MOVQ DX, R13; /* A[3]*A[1] */ \
+ MOVQ 16+x, AX; MULQ R8; /* A[3]*A[2] */ \
+ \
+ ADDQ R14, R10;\
+ ADCQ R15, R11; MOVL $0, R15;\
+ ADCQ CX, R12;\
+ ADCQ AX, R13;\
+ ADCQ $0, DX; MOVQ DX, R14;\
+ MOVQ 8+x, AX; MULQ 16+x;\
+ \
+ ADDQ AX, R11;\
+ ADCQ DX, R12;\
+ ADCQ $0, R13;\
+ ADCQ $0, R14;\
+ ADCQ $0, R15;\
+ \
+ SHLQ $1, R14, R15; MOVQ R15, 56+z;\
+ SHLQ $1, R13, R14; MOVQ R14, 48+z;\
+ SHLQ $1, R12, R13; MOVQ R13, 40+z;\
+ SHLQ $1, R11, R12; MOVQ R12, 32+z;\
+ SHLQ $1, R10, R11; MOVQ R11, 24+z;\
+ SHLQ $1, R9, R10; MOVQ R10, 16+z;\
+ SHLQ $1, R9; MOVQ R9, 8+z;\
+ \
+ MOVQ 0+x,AX; MULQ AX; MOVQ AX, 0+z; MOVQ DX, R9;\
+ MOVQ 8+x,AX; MULQ AX; MOVQ AX, R10; MOVQ DX, R11;\
+ MOVQ 16+x,AX; MULQ AX; MOVQ AX, R12; MOVQ DX, R13;\
+ MOVQ 24+x,AX; MULQ AX; MOVQ AX, R14; MOVQ DX, R15;\
+ \
+ ADDQ 8+z, R9; MOVQ R9, 8+z;\
+ ADCQ 16+z, R10; MOVQ R10, 16+z;\
+ ADCQ 24+z, R11; MOVQ R11, 24+z;\
+ ADCQ 32+z, R12; MOVQ R12, 32+z;\
+ ADCQ 40+z, R13; MOVQ R13, 40+z;\
+ ADCQ 48+z, R14; MOVQ R14, 48+z;\
+ ADCQ 56+z, R15; MOVQ R15, 56+z;
+
+// integerSqrAdx squares x and stores in z
+// Uses: AX, CX, DX, R8-R15, FLAGS
+// Instr: x86_64, bmi2, adx
+#define integerSqrAdx(z,x) \
+ MOVQ 0+x, DX; /* A[0] */ \
+ MULXQ 8+x, R8, R14; /* A[1]*A[0] */ XORL R15, R15; \
+ MULXQ 16+x, R9, R10; /* A[2]*A[0] */ ADCXQ R14, R9; \
+ MULXQ 24+x, AX, CX; /* A[3]*A[0] */ ADCXQ AX, R10; \
+ MOVQ 24+x, DX; /* A[3] */ \
+ MULXQ 8+x, R11, R12; /* A[1]*A[3] */ ADCXQ CX, R11; \
+ MULXQ 16+x, AX, R13; /* A[2]*A[3] */ ADCXQ AX, R12; \
+ MOVQ 8+x, DX; /* A[1] */ ADCXQ R15, R13; \
+ MULXQ 16+x, AX, CX; /* A[2]*A[1] */ MOVL $0, R14; \
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ADCXQ R15, R14; \
+ XORL R15, R15; \
+ ADOXQ AX, R10; ADCXQ R8, R8; \
+ ADOXQ CX, R11; ADCXQ R9, R9; \
+ ADOXQ R15, R12; ADCXQ R10, R10; \
+ ADOXQ R15, R13; ADCXQ R11, R11; \
+ ADOXQ R15, R14; ADCXQ R12, R12; \
+ ;;;;;;;;;;;;;;; ADCXQ R13, R13; \
+ ;;;;;;;;;;;;;;; ADCXQ R14, R14; \
+ MOVQ 0+x, DX; MULXQ DX, AX, CX; /* A[0]^2 */ \
+ ;;;;;;;;;;;;;;; MOVQ AX, 0+z; \
+ ADDQ CX, R8; MOVQ R8, 8+z; \
+ MOVQ 8+x, DX; MULXQ DX, AX, CX; /* A[1]^2 */ \
+ ADCQ AX, R9; MOVQ R9, 16+z; \
+ ADCQ CX, R10; MOVQ R10, 24+z; \
+ MOVQ 16+x, DX; MULXQ DX, AX, CX; /* A[2]^2 */ \
+ ADCQ AX, R11; MOVQ R11, 32+z; \
+ ADCQ CX, R12; MOVQ R12, 40+z; \
+ MOVQ 24+x, DX; MULXQ DX, AX, CX; /* A[3]^2 */ \
+ ADCQ AX, R13; MOVQ R13, 48+z; \
+ ADCQ CX, R14; MOVQ R14, 56+z;
+
+// reduceFromDouble finds z congruent to x modulo p such that 0> 63)
+ // PUT BIT 255 IN CARRY FLAG AND CLEAR
+ x3 &^= 1 << 63
+
+ x0, c0 := bits.Add64(x0, cx, 0)
+ x1, c1 := bits.Add64(x1, 0, c0)
+ x2, c2 := bits.Add64(x2, 0, c1)
+ x3, _ = bits.Add64(x3, 0, c2)
+
+ // TEST FOR BIT 255 AGAIN; ONLY TRIGGERED ON OVERFLOW MODULO 2^255-19
+ // cx = C[255] ? 0 : 19
+ cx = uint64(19) &^ (-(x3 >> 63))
+ // CLEAR BIT 255
+ x3 &^= 1 << 63
+
+ x0, c0 = bits.Sub64(x0, cx, 0)
+ x1, c1 = bits.Sub64(x1, 0, c0)
+ x2, c2 = bits.Sub64(x2, 0, c1)
+ x3, _ = bits.Sub64(x3, 0, c2)
+
+ binary.LittleEndian.PutUint64(x[0*8:1*8], x0)
+ binary.LittleEndian.PutUint64(x[1*8:2*8], x1)
+ binary.LittleEndian.PutUint64(x[2*8:3*8], x2)
+ binary.LittleEndian.PutUint64(x[3*8:4*8], x3)
+}
+
+func red64(z *Elt, x0, x1, x2, x3, x4, x5, x6, x7 uint64) {
+ h0, l0 := bits.Mul64(x4, 38)
+ h1, l1 := bits.Mul64(x5, 38)
+ h2, l2 := bits.Mul64(x6, 38)
+ h3, l3 := bits.Mul64(x7, 38)
+
+ l1, c0 := bits.Add64(h0, l1, 0)
+ l2, c1 := bits.Add64(h1, l2, c0)
+ l3, c2 := bits.Add64(h2, l3, c1)
+ l4, _ := bits.Add64(h3, 0, c2)
+
+ l0, c0 = bits.Add64(l0, x0, 0)
+ l1, c1 = bits.Add64(l1, x1, c0)
+ l2, c2 = bits.Add64(l2, x2, c1)
+ l3, c3 := bits.Add64(l3, x3, c2)
+ l4, _ = bits.Add64(l4, 0, c3)
+
+ _, l4 = bits.Mul64(l4, 38)
+ l0, c0 = bits.Add64(l0, l4, 0)
+ z1, c1 := bits.Add64(l1, 0, c0)
+ z2, c2 := bits.Add64(l2, 0, c1)
+ z3, c3 := bits.Add64(l3, 0, c2)
+ z0, _ := bits.Add64(l0, (-c3)&38, 0)
+
+ binary.LittleEndian.PutUint64(z[0*8:1*8], z0)
+ binary.LittleEndian.PutUint64(z[1*8:2*8], z1)
+ binary.LittleEndian.PutUint64(z[2*8:3*8], z2)
+ binary.LittleEndian.PutUint64(z[3*8:4*8], z3)
+}
diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go b/vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go
new file mode 100644
index 0000000000..26ca4d01b7
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go
@@ -0,0 +1,13 @@
+//go:build !amd64 || purego
+// +build !amd64 purego
+
+package fp25519
+
+func cmov(x, y *Elt, n uint) { cmovGeneric(x, y, n) }
+func cswap(x, y *Elt, n uint) { cswapGeneric(x, y, n) }
+func add(z, x, y *Elt) { addGeneric(z, x, y) }
+func sub(z, x, y *Elt) { subGeneric(z, x, y) }
+func addsub(x, y *Elt) { addsubGeneric(x, y) }
+func mul(z, x, y *Elt) { mulGeneric(z, x, y) }
+func sqr(z, x *Elt) { sqrGeneric(z, x) }
+func modp(z *Elt) { modpGeneric(z) }
diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp.go b/vendor/github.com/cloudflare/circl/math/fp448/fp.go
new file mode 100644
index 0000000000..a5e36600bb
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp448/fp.go
@@ -0,0 +1,164 @@
+// Package fp448 provides prime field arithmetic over GF(2^448-2^224-1).
+package fp448
+
+import (
+ "errors"
+
+ "github.com/cloudflare/circl/internal/conv"
+)
+
+// Size in bytes of an element.
+const Size = 56
+
+// Elt is a prime field element.
+type Elt [Size]byte
+
+func (e Elt) String() string { return conv.BytesLe2Hex(e[:]) }
+
+// p is the prime modulus 2^448-2^224-1.
+var p = Elt{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+}
+
+// P returns the prime modulus 2^448-2^224-1.
+func P() Elt { return p }
+
+// ToBytes stores in b the little-endian byte representation of x.
+func ToBytes(b []byte, x *Elt) error {
+ if len(b) != Size {
+ return errors.New("wrong size")
+ }
+ Modp(x)
+ copy(b, x[:])
+ return nil
+}
+
+// IsZero returns true if x is equal to 0.
+func IsZero(x *Elt) bool { Modp(x); return *x == Elt{} }
+
+// IsOne returns true if x is equal to 1.
+func IsOne(x *Elt) bool { Modp(x); return *x == Elt{1} }
+
+// SetOne assigns x=1.
+func SetOne(x *Elt) { *x = Elt{1} }
+
+// One returns the 1 element.
+func One() (x Elt) { x = Elt{1}; return }
+
+// Neg calculates z = -x.
+func Neg(z, x *Elt) { Sub(z, &p, x) }
+
+// Modp ensures that z is between [0,p-1].
+func Modp(z *Elt) { Sub(z, z, &p) }
+
+// InvSqrt calculates z = sqrt(x/y) iff x/y is a quadratic-residue. If so,
+// isQR = true; otherwise, isQR = false, since x/y is a quadratic non-residue,
+// and z = sqrt(-x/y).
+func InvSqrt(z, x, y *Elt) (isQR bool) {
+ // First note that x^(2(k+1)) = x^(p-1)/2 * x = legendre(x) * x
+ // so that's x if x is a quadratic residue and -x otherwise.
+ // Next, y^(6k+3) = y^(4k+2) * y^(2k+1) = y^(p-1) * y^((p-1)/2) = legendre(y).
+ // So the z we compute satisfies z^2 y = x^(2(k+1)) y^(6k+3) = legendre(x)*legendre(y).
+ // Thus if x and y are quadratic residues, then z is indeed sqrt(x/y).
+ t0, t1 := &Elt{}, &Elt{}
+ Mul(t0, x, y) // x*y
+ Sqr(t1, y) // y^2
+ Mul(t1, t0, t1) // x*y^3
+ powPminus3div4(z, t1) // (x*y^3)^k
+ Mul(z, z, t0) // z = x*y*(x*y^3)^k = x^(k+1) * y^(3k+1)
+
+ // Check if x/y is a quadratic residue
+ Sqr(t0, z) // z^2
+ Mul(t0, t0, y) // y*z^2
+ Sub(t0, t0, x) // y*z^2-x
+ return IsZero(t0)
+}
+
+// Inv calculates z = 1/x mod p.
+func Inv(z, x *Elt) {
+ // Calculates z = x^(4k+1) = x^(p-3+1) = x^(p-2) = x^-1, where k = (p-3)/4.
+ t := &Elt{}
+ powPminus3div4(t, x) // t = x^k
+ Sqr(t, t) // t = x^2k
+ Sqr(t, t) // t = x^4k
+ Mul(z, t, x) // z = x^(4k+1)
+}
+
+// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
+func powPminus3div4(z, x *Elt) {
+ x0, x1 := &Elt{}, &Elt{}
+ Sqr(z, x)
+ Mul(z, z, x)
+ Sqr(x0, z)
+ Mul(x0, x0, x)
+ Sqr(z, x0)
+ Sqr(z, z)
+ Sqr(z, z)
+ Mul(z, z, x0)
+ Sqr(x1, z)
+ for i := 0; i < 5; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(x1, x1, z)
+ Sqr(z, x1)
+ for i := 0; i < 11; i++ {
+ Sqr(z, z)
+ }
+ Mul(z, z, x1)
+ Sqr(z, z)
+ Sqr(z, z)
+ Sqr(z, z)
+ Mul(z, z, x0)
+ Sqr(x1, z)
+ for i := 0; i < 26; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(x1, x1, z)
+ Sqr(z, x1)
+ for i := 0; i < 53; i++ {
+ Sqr(z, z)
+ }
+ Mul(z, z, x1)
+ Sqr(z, z)
+ Sqr(z, z)
+ Sqr(z, z)
+ Mul(z, z, x0)
+ Sqr(x1, z)
+ for i := 0; i < 110; i++ {
+ Sqr(x1, x1)
+ }
+ Mul(x1, x1, z)
+ Sqr(z, x1)
+ Mul(z, z, x)
+ for i := 0; i < 223; i++ {
+ Sqr(z, z)
+ }
+ Mul(z, z, x1)
+}
+
+// Cmov assigns y to x if n is 1.
+func Cmov(x, y *Elt, n uint) { cmov(x, y, n) }
+
+// Cswap interchanges x and y if n is 1.
+func Cswap(x, y *Elt, n uint) { cswap(x, y, n) }
+
+// Add calculates z = x+y mod p.
+func Add(z, x, y *Elt) { add(z, x, y) }
+
+// Sub calculates z = x-y mod p.
+func Sub(z, x, y *Elt) { sub(z, x, y) }
+
+// AddSub calculates (x,y) = (x+y mod p, x-y mod p).
+func AddSub(x, y *Elt) { addsub(x, y) }
+
+// Mul calculates z = x*y mod p.
+func Mul(z, x, y *Elt) { mul(z, x, y) }
+
+// Sqr calculates z = x^2 mod p.
+func Sqr(z, x *Elt) { sqr(z, x) }
diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go
new file mode 100644
index 0000000000..6a12209a70
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go
@@ -0,0 +1,43 @@
+//go:build amd64 && !purego
+// +build amd64,!purego
+
+package fp448
+
+import (
+ "golang.org/x/sys/cpu"
+)
+
+var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX
+
+var _ = hasBmi2Adx
+
+func cmov(x, y *Elt, n uint) { cmovAmd64(x, y, n) }
+func cswap(x, y *Elt, n uint) { cswapAmd64(x, y, n) }
+func add(z, x, y *Elt) { addAmd64(z, x, y) }
+func sub(z, x, y *Elt) { subAmd64(z, x, y) }
+func addsub(x, y *Elt) { addsubAmd64(x, y) }
+func mul(z, x, y *Elt) { mulAmd64(z, x, y) }
+func sqr(z, x *Elt) { sqrAmd64(z, x) }
+
+/* Functions defined in fp_amd64.s */
+
+//go:noescape
+func cmovAmd64(x, y *Elt, n uint)
+
+//go:noescape
+func cswapAmd64(x, y *Elt, n uint)
+
+//go:noescape
+func addAmd64(z, x, y *Elt)
+
+//go:noescape
+func subAmd64(z, x, y *Elt)
+
+//go:noescape
+func addsubAmd64(x, y *Elt)
+
+//go:noescape
+func mulAmd64(z, x, y *Elt)
+
+//go:noescape
+func sqrAmd64(z, x *Elt)
diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h
new file mode 100644
index 0000000000..536fe5bdfe
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h
@@ -0,0 +1,591 @@
+// This code was imported from https://github.com/armfazh/rfc7748_precomputed
+
+// CHECK_BMI2ADX triggers bmi2adx if supported,
+// otherwise it fallbacks to legacy code.
+#define CHECK_BMI2ADX(label, legacy, bmi2adx) \
+ CMPB ·hasBmi2Adx(SB), $0 \
+ JE label \
+ bmi2adx \
+ RET \
+ label: \
+ legacy \
+ RET
+
+// cselect is a conditional move
+// if b=1: it copies y into x;
+// if b=0: x remains with the same value;
+// if b<> 0,1: undefined.
+// Uses: AX, DX, FLAGS
+// Instr: x86_64, cmov
+#define cselect(x,y,b) \
+ TESTQ b, b \
+ MOVQ 0+x, AX; MOVQ 0+y, DX; CMOVQNE DX, AX; MOVQ AX, 0+x; \
+ MOVQ 8+x, AX; MOVQ 8+y, DX; CMOVQNE DX, AX; MOVQ AX, 8+x; \
+ MOVQ 16+x, AX; MOVQ 16+y, DX; CMOVQNE DX, AX; MOVQ AX, 16+x; \
+ MOVQ 24+x, AX; MOVQ 24+y, DX; CMOVQNE DX, AX; MOVQ AX, 24+x; \
+ MOVQ 32+x, AX; MOVQ 32+y, DX; CMOVQNE DX, AX; MOVQ AX, 32+x; \
+ MOVQ 40+x, AX; MOVQ 40+y, DX; CMOVQNE DX, AX; MOVQ AX, 40+x; \
+ MOVQ 48+x, AX; MOVQ 48+y, DX; CMOVQNE DX, AX; MOVQ AX, 48+x;
+
+// cswap is a conditional swap
+// if b=1: x,y <- y,x;
+// if b=0: x,y remain with the same values;
+// if b<> 0,1: undefined.
+// Uses: AX, DX, R8, FLAGS
+// Instr: x86_64, cmov
+#define cswap(x,y,b) \
+ TESTQ b, b \
+ MOVQ 0+x, AX; MOVQ AX, R8; MOVQ 0+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 0+x; MOVQ DX, 0+y; \
+ MOVQ 8+x, AX; MOVQ AX, R8; MOVQ 8+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 8+x; MOVQ DX, 8+y; \
+ MOVQ 16+x, AX; MOVQ AX, R8; MOVQ 16+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 16+x; MOVQ DX, 16+y; \
+ MOVQ 24+x, AX; MOVQ AX, R8; MOVQ 24+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 24+x; MOVQ DX, 24+y; \
+ MOVQ 32+x, AX; MOVQ AX, R8; MOVQ 32+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 32+x; MOVQ DX, 32+y; \
+ MOVQ 40+x, AX; MOVQ AX, R8; MOVQ 40+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 40+x; MOVQ DX, 40+y; \
+ MOVQ 48+x, AX; MOVQ AX, R8; MOVQ 48+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 48+x; MOVQ DX, 48+y;
+
+// additionLeg adds x and y and stores in z
+// Uses: AX, DX, R8-R14, FLAGS
+// Instr: x86_64
+#define additionLeg(z,x,y) \
+ MOVQ 0+x, R8; ADDQ 0+y, R8; \
+ MOVQ 8+x, R9; ADCQ 8+y, R9; \
+ MOVQ 16+x, R10; ADCQ 16+y, R10; \
+ MOVQ 24+x, R11; ADCQ 24+y, R11; \
+ MOVQ 32+x, R12; ADCQ 32+y, R12; \
+ MOVQ 40+x, R13; ADCQ 40+y, R13; \
+ MOVQ 48+x, R14; ADCQ 48+y, R14; \
+ MOVQ $0, AX; ADCQ $0, AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ ADDQ AX, R8; MOVQ $0, AX; \
+ ADCQ $0, R9; \
+ ADCQ $0, R10; \
+ ADCQ DX, R11; \
+ ADCQ $0, R12; \
+ ADCQ $0, R13; \
+ ADCQ $0, R14; \
+ ADCQ $0, AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ ADDQ AX, R8; MOVQ R8, 0+z; \
+ ADCQ $0, R9; MOVQ R9, 8+z; \
+ ADCQ $0, R10; MOVQ R10, 16+z; \
+ ADCQ DX, R11; MOVQ R11, 24+z; \
+ ADCQ $0, R12; MOVQ R12, 32+z; \
+ ADCQ $0, R13; MOVQ R13, 40+z; \
+ ADCQ $0, R14; MOVQ R14, 48+z;
+
+
+// additionAdx adds x and y and stores in z
+// Uses: AX, DX, R8-R15, FLAGS
+// Instr: x86_64, adx
+#define additionAdx(z,x,y) \
+ MOVL $32, R15; \
+ XORL DX, DX; \
+ MOVQ 0+x, R8; ADCXQ 0+y, R8; \
+ MOVQ 8+x, R9; ADCXQ 8+y, R9; \
+ MOVQ 16+x, R10; ADCXQ 16+y, R10; \
+ MOVQ 24+x, R11; ADCXQ 24+y, R11; \
+ MOVQ 32+x, R12; ADCXQ 32+y, R12; \
+ MOVQ 40+x, R13; ADCXQ 40+y, R13; \
+ MOVQ 48+x, R14; ADCXQ 48+y, R14; \
+ ;;;;;;;;;;;;;;; ADCXQ DX, DX; \
+ XORL AX, AX; \
+ ADCXQ DX, R8; SHLXQ R15, DX, DX; \
+ ADCXQ AX, R9; \
+ ADCXQ AX, R10; \
+ ADCXQ DX, R11; \
+ ADCXQ AX, R12; \
+ ADCXQ AX, R13; \
+ ADCXQ AX, R14; \
+ ADCXQ AX, AX; \
+ XORL DX, DX; \
+ ADCXQ AX, R8; MOVQ R8, 0+z; SHLXQ R15, AX, AX; \
+ ADCXQ DX, R9; MOVQ R9, 8+z; \
+ ADCXQ DX, R10; MOVQ R10, 16+z; \
+ ADCXQ AX, R11; MOVQ R11, 24+z; \
+ ADCXQ DX, R12; MOVQ R12, 32+z; \
+ ADCXQ DX, R13; MOVQ R13, 40+z; \
+ ADCXQ DX, R14; MOVQ R14, 48+z;
+
+// subtraction subtracts y from x and stores in z
+// Uses: AX, DX, R8-R14, FLAGS
+// Instr: x86_64
+#define subtraction(z,x,y) \
+ MOVQ 0+x, R8; SUBQ 0+y, R8; \
+ MOVQ 8+x, R9; SBBQ 8+y, R9; \
+ MOVQ 16+x, R10; SBBQ 16+y, R10; \
+ MOVQ 24+x, R11; SBBQ 24+y, R11; \
+ MOVQ 32+x, R12; SBBQ 32+y, R12; \
+ MOVQ 40+x, R13; SBBQ 40+y, R13; \
+ MOVQ 48+x, R14; SBBQ 48+y, R14; \
+ MOVQ $0, AX; SETCS AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ SUBQ AX, R8; MOVQ $0, AX; \
+ SBBQ $0, R9; \
+ SBBQ $0, R10; \
+ SBBQ DX, R11; \
+ SBBQ $0, R12; \
+ SBBQ $0, R13; \
+ SBBQ $0, R14; \
+ SETCS AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ SUBQ AX, R8; MOVQ R8, 0+z; \
+ SBBQ $0, R9; MOVQ R9, 8+z; \
+ SBBQ $0, R10; MOVQ R10, 16+z; \
+ SBBQ DX, R11; MOVQ R11, 24+z; \
+ SBBQ $0, R12; MOVQ R12, 32+z; \
+ SBBQ $0, R13; MOVQ R13, 40+z; \
+ SBBQ $0, R14; MOVQ R14, 48+z;
+
+// maddBmi2Adx multiplies x and y and accumulates in z
+// Uses: AX, DX, R15, FLAGS
+// Instr: x86_64, bmi2, adx
+#define maddBmi2Adx(z,x,y,i,r0,r1,r2,r3,r4,r5,r6) \
+ MOVQ i+y, DX; XORL AX, AX; \
+ MULXQ 0+x, AX, R8; ADOXQ AX, r0; ADCXQ R8, r1; MOVQ r0,i+z; \
+ MULXQ 8+x, AX, r0; ADOXQ AX, r1; ADCXQ r0, r2; MOVQ $0, R8; \
+ MULXQ 16+x, AX, r0; ADOXQ AX, r2; ADCXQ r0, r3; \
+ MULXQ 24+x, AX, r0; ADOXQ AX, r3; ADCXQ r0, r4; \
+ MULXQ 32+x, AX, r0; ADOXQ AX, r4; ADCXQ r0, r5; \
+ MULXQ 40+x, AX, r0; ADOXQ AX, r5; ADCXQ r0, r6; \
+ MULXQ 48+x, AX, r0; ADOXQ AX, r6; ADCXQ R8, r0; \
+ ;;;;;;;;;;;;;;;;;;; ADOXQ R8, r0;
+
+// integerMulAdx multiplies x and y and stores in z
+// Uses: AX, DX, R8-R15, FLAGS
+// Instr: x86_64, bmi2, adx
+#define integerMulAdx(z,x,y) \
+ MOVL $0,R15; \
+ MOVQ 0+y, DX; XORL AX, AX; MOVQ $0, R8; \
+ MULXQ 0+x, AX, R9; MOVQ AX, 0+z; \
+ MULXQ 8+x, AX, R10; ADCXQ AX, R9; \
+ MULXQ 16+x, AX, R11; ADCXQ AX, R10; \
+ MULXQ 24+x, AX, R12; ADCXQ AX, R11; \
+ MULXQ 32+x, AX, R13; ADCXQ AX, R12; \
+ MULXQ 40+x, AX, R14; ADCXQ AX, R13; \
+ MULXQ 48+x, AX, R15; ADCXQ AX, R14; \
+ ;;;;;;;;;;;;;;;;;;;; ADCXQ R8, R15; \
+ maddBmi2Adx(z,x,y, 8, R9,R10,R11,R12,R13,R14,R15) \
+ maddBmi2Adx(z,x,y,16,R10,R11,R12,R13,R14,R15, R9) \
+ maddBmi2Adx(z,x,y,24,R11,R12,R13,R14,R15, R9,R10) \
+ maddBmi2Adx(z,x,y,32,R12,R13,R14,R15, R9,R10,R11) \
+ maddBmi2Adx(z,x,y,40,R13,R14,R15, R9,R10,R11,R12) \
+ maddBmi2Adx(z,x,y,48,R14,R15, R9,R10,R11,R12,R13) \
+ MOVQ R15, 56+z; \
+ MOVQ R9, 64+z; \
+ MOVQ R10, 72+z; \
+ MOVQ R11, 80+z; \
+ MOVQ R12, 88+z; \
+ MOVQ R13, 96+z; \
+ MOVQ R14, 104+z;
+
+// maddLegacy multiplies x and y and accumulates in z
+// Uses: AX, DX, R15, FLAGS
+// Instr: x86_64
+#define maddLegacy(z,x,y,i) \
+ MOVQ i+y, R15; \
+ MOVQ 0+x, AX; MULQ R15; MOVQ AX, R8; ;;;;;;;;;;;; MOVQ DX, R9; \
+ MOVQ 8+x, AX; MULQ R15; ADDQ AX, R9; ADCQ $0, DX; MOVQ DX, R10; \
+ MOVQ 16+x, AX; MULQ R15; ADDQ AX, R10; ADCQ $0, DX; MOVQ DX, R11; \
+ MOVQ 24+x, AX; MULQ R15; ADDQ AX, R11; ADCQ $0, DX; MOVQ DX, R12; \
+ MOVQ 32+x, AX; MULQ R15; ADDQ AX, R12; ADCQ $0, DX; MOVQ DX, R13; \
+ MOVQ 40+x, AX; MULQ R15; ADDQ AX, R13; ADCQ $0, DX; MOVQ DX, R14; \
+ MOVQ 48+x, AX; MULQ R15; ADDQ AX, R14; ADCQ $0, DX; \
+ ADDQ 0+i+z, R8; MOVQ R8, 0+i+z; \
+ ADCQ 8+i+z, R9; MOVQ R9, 8+i+z; \
+ ADCQ 16+i+z, R10; MOVQ R10, 16+i+z; \
+ ADCQ 24+i+z, R11; MOVQ R11, 24+i+z; \
+ ADCQ 32+i+z, R12; MOVQ R12, 32+i+z; \
+ ADCQ 40+i+z, R13; MOVQ R13, 40+i+z; \
+ ADCQ 48+i+z, R14; MOVQ R14, 48+i+z; \
+ ADCQ $0, DX; MOVQ DX, 56+i+z;
+
+// integerMulLeg multiplies x and y and stores in z
+// Uses: AX, DX, R8-R15, FLAGS
+// Instr: x86_64
+#define integerMulLeg(z,x,y) \
+ MOVQ 0+y, R15; \
+ MOVQ 0+x, AX; MULQ R15; MOVQ AX, 0+z; ;;;;;;;;;;;; MOVQ DX, R8; \
+ MOVQ 8+x, AX; MULQ R15; ADDQ AX, R8; ADCQ $0, DX; MOVQ DX, R9; MOVQ R8, 8+z; \
+ MOVQ 16+x, AX; MULQ R15; ADDQ AX, R9; ADCQ $0, DX; MOVQ DX, R10; MOVQ R9, 16+z; \
+ MOVQ 24+x, AX; MULQ R15; ADDQ AX, R10; ADCQ $0, DX; MOVQ DX, R11; MOVQ R10, 24+z; \
+ MOVQ 32+x, AX; MULQ R15; ADDQ AX, R11; ADCQ $0, DX; MOVQ DX, R12; MOVQ R11, 32+z; \
+ MOVQ 40+x, AX; MULQ R15; ADDQ AX, R12; ADCQ $0, DX; MOVQ DX, R13; MOVQ R12, 40+z; \
+ MOVQ 48+x, AX; MULQ R15; ADDQ AX, R13; ADCQ $0, DX; MOVQ DX,56+z; MOVQ R13, 48+z; \
+ maddLegacy(z,x,y, 8) \
+ maddLegacy(z,x,y,16) \
+ maddLegacy(z,x,y,24) \
+ maddLegacy(z,x,y,32) \
+ maddLegacy(z,x,y,40) \
+ maddLegacy(z,x,y,48)
+
+// integerSqrLeg squares x and stores in z
+// Uses: AX, CX, DX, R8-R15, FLAGS
+// Instr: x86_64
+#define integerSqrLeg(z,x) \
+ XORL R15, R15; \
+ MOVQ 0+x, CX; \
+ MOVQ CX, AX; MULQ CX; MOVQ AX, 0+z; MOVQ DX, R8; \
+ ADDQ CX, CX; ADCQ $0, R15; \
+ MOVQ 8+x, AX; MULQ CX; ADDQ AX, R8; ADCQ $0, DX; MOVQ DX, R9; MOVQ R8, 8+z; \
+ MOVQ 16+x, AX; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; MOVQ DX, R10; \
+ MOVQ 24+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; MOVQ DX, R11; \
+ MOVQ 32+x, AX; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; MOVQ DX, R12; \
+ MOVQ 40+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; MOVQ DX, R13; \
+ MOVQ 48+x, AX; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; MOVQ DX, R14; \
+ \
+ MOVQ 8+x, CX; \
+ MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \
+ ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; MOVQ R9,16+z; \
+ MOVQ R15, AX; NEGQ AX; ANDQ 8+x, AX; ADDQ AX, DX; ADCQ $0, R11; MOVQ DX, R8; \
+ ADDQ 8+x, CX; ADCQ $0, R15; \
+ MOVQ 16+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; ADDQ R8, R10; ADCQ $0, DX; MOVQ DX, R8; MOVQ R10, 24+z; \
+ MOVQ 24+x, AX; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; ADDQ R8, R11; ADCQ $0, DX; MOVQ DX, R8; \
+ MOVQ 32+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; ADDQ R8, R12; ADCQ $0, DX; MOVQ DX, R8; \
+ MOVQ 40+x, AX; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; ADDQ R8, R13; ADCQ $0, DX; MOVQ DX, R8; \
+ MOVQ 48+x, AX; MULQ CX; ADDQ AX, R14; ADCQ $0, DX; ADDQ R8, R14; ADCQ $0, DX; MOVQ DX, R9; \
+ \
+ MOVQ 16+x, CX; \
+ MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \
+ ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; MOVQ R11, 32+z; \
+ MOVQ R15, AX; NEGQ AX; ANDQ 16+x,AX; ADDQ AX, DX; ADCQ $0, R13; MOVQ DX, R8; \
+ ADDQ 16+x, CX; ADCQ $0, R15; \
+ MOVQ 24+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; ADDQ R8, R12; ADCQ $0, DX; MOVQ DX, R8; MOVQ R12, 40+z; \
+ MOVQ 32+x, AX; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; ADDQ R8, R13; ADCQ $0, DX; MOVQ DX, R8; \
+ MOVQ 40+x, AX; MULQ CX; ADDQ AX, R14; ADCQ $0, DX; ADDQ R8, R14; ADCQ $0, DX; MOVQ DX, R8; \
+ MOVQ 48+x, AX; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; ADDQ R8, R9; ADCQ $0, DX; MOVQ DX,R10; \
+ \
+ MOVQ 24+x, CX; \
+ MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \
+ ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; MOVQ R13, 48+z; \
+ MOVQ R15, AX; NEGQ AX; ANDQ 24+x,AX; ADDQ AX, DX; ADCQ $0, R9; MOVQ DX, R8; \
+ ADDQ 24+x, CX; ADCQ $0, R15; \
+ MOVQ 32+x, AX; MULQ CX; ADDQ AX, R14; ADCQ $0, DX; ADDQ R8, R14; ADCQ $0, DX; MOVQ DX, R8; MOVQ R14, 56+z; \
+ MOVQ 40+x, AX; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; ADDQ R8, R9; ADCQ $0, DX; MOVQ DX, R8; \
+ MOVQ 48+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; ADDQ R8, R10; ADCQ $0, DX; MOVQ DX,R11; \
+ \
+ MOVQ 32+x, CX; \
+ MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \
+ ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; MOVQ R9, 64+z; \
+ MOVQ R15, AX; NEGQ AX; ANDQ 32+x,AX; ADDQ AX, DX; ADCQ $0, R11; MOVQ DX, R8; \
+ ADDQ 32+x, CX; ADCQ $0, R15; \
+ MOVQ 40+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; ADDQ R8, R10; ADCQ $0, DX; MOVQ DX, R8; MOVQ R10, 72+z; \
+ MOVQ 48+x, AX; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; ADDQ R8, R11; ADCQ $0, DX; MOVQ DX,R12; \
+ \
+ XORL R13, R13; \
+ XORL R14, R14; \
+ MOVQ 40+x, CX; \
+ MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \
+ ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; MOVQ R11, 80+z; \
+ MOVQ R15, AX; NEGQ AX; ANDQ 40+x,AX; ADDQ AX, DX; ADCQ $0, R13; MOVQ DX, R8; \
+ ADDQ 40+x, CX; ADCQ $0, R15; \
+ MOVQ 48+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; ADDQ R8, R12; ADCQ $0, DX; MOVQ DX, R8; MOVQ R12, 88+z; \
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ADDQ R8, R13; ADCQ $0,R14; \
+ \
+ XORL R9, R9; \
+ MOVQ 48+x, CX; \
+ MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \
+ ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; MOVQ R13, 96+z; \
+ MOVQ R15, AX; NEGQ AX; ANDQ 48+x,AX; ADDQ AX, DX; ADCQ $0, R9; MOVQ DX, R8; \
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ADDQ R8,R14; ADCQ $0, R9; MOVQ R14, 104+z;
+
+
+// integerSqrAdx squares x and stores in z
+// Uses: AX, CX, DX, R8-R15, FLAGS
+// Instr: x86_64, bmi2, adx
+#define integerSqrAdx(z,x) \
+ XORL R15, R15; \
+ MOVQ 0+x, DX; \
+ ;;;;;;;;;;;;;; MULXQ DX, AX, R8; MOVQ AX, 0+z; \
+ ADDQ DX, DX; ADCQ $0, R15; CLC; \
+ MULXQ 8+x, AX, R9; ADCXQ AX, R8; MOVQ R8, 8+z; \
+ MULXQ 16+x, AX, R10; ADCXQ AX, R9; MOVQ $0, R8;\
+ MULXQ 24+x, AX, R11; ADCXQ AX, R10; \
+ MULXQ 32+x, AX, R12; ADCXQ AX, R11; \
+ MULXQ 40+x, AX, R13; ADCXQ AX, R12; \
+ MULXQ 48+x, AX, R14; ADCXQ AX, R13; \
+ ;;;;;;;;;;;;;;;;;;;; ADCXQ R8, R14; \
+ \
+ MOVQ 8+x, DX; \
+ MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \
+ MULXQ AX, AX, CX; \
+ MOVQ R15, R8; NEGQ R8; ANDQ 8+x, R8; \
+ ADDQ AX, R9; MOVQ R9, 16+z; \
+ ADCQ CX, R8; \
+ ADCQ $0, R11; \
+ ADDQ 8+x, DX; \
+ ADCQ $0, R15; \
+ XORL R9, R9; ;;;;;;;;;;;;;;;;;;;;; ADOXQ R8, R10; \
+ MULXQ 16+x, AX, CX; ADCXQ AX, R10; ADOXQ CX, R11; MOVQ R10, 24+z; \
+ MULXQ 24+x, AX, CX; ADCXQ AX, R11; ADOXQ CX, R12; MOVQ $0, R10; \
+ MULXQ 32+x, AX, CX; ADCXQ AX, R12; ADOXQ CX, R13; \
+ MULXQ 40+x, AX, CX; ADCXQ AX, R13; ADOXQ CX, R14; \
+ MULXQ 48+x, AX, CX; ADCXQ AX, R14; ADOXQ CX, R9; \
+ ;;;;;;;;;;;;;;;;;;; ADCXQ R10, R9; \
+ \
+ MOVQ 16+x, DX; \
+ MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \
+ MULXQ AX, AX, CX; \
+ MOVQ R15, R8; NEGQ R8; ANDQ 16+x, R8; \
+ ADDQ AX, R11; MOVQ R11, 32+z; \
+ ADCQ CX, R8; \
+ ADCQ $0, R13; \
+ ADDQ 16+x, DX; \
+ ADCQ $0, R15; \
+ XORL R11, R11; ;;;;;;;;;;;;;;;;;;; ADOXQ R8, R12; \
+ MULXQ 24+x, AX, CX; ADCXQ AX, R12; ADOXQ CX, R13; MOVQ R12, 40+z; \
+ MULXQ 32+x, AX, CX; ADCXQ AX, R13; ADOXQ CX, R14; MOVQ $0, R12; \
+ MULXQ 40+x, AX, CX; ADCXQ AX, R14; ADOXQ CX, R9; \
+ MULXQ 48+x, AX, CX; ADCXQ AX, R9; ADOXQ CX, R10; \
+ ;;;;;;;;;;;;;;;;;;; ADCXQ R11,R10; \
+ \
+ MOVQ 24+x, DX; \
+ MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \
+ MULXQ AX, AX, CX; \
+ MOVQ R15, R8; NEGQ R8; ANDQ 24+x, R8; \
+ ADDQ AX, R13; MOVQ R13, 48+z; \
+ ADCQ CX, R8; \
+ ADCQ $0, R9; \
+ ADDQ 24+x, DX; \
+ ADCQ $0, R15; \
+ XORL R13, R13; ;;;;;;;;;;;;;;;;;;; ADOXQ R8, R14; \
+ MULXQ 32+x, AX, CX; ADCXQ AX, R14; ADOXQ CX, R9; MOVQ R14, 56+z; \
+ MULXQ 40+x, AX, CX; ADCXQ AX, R9; ADOXQ CX, R10; MOVQ $0, R14; \
+ MULXQ 48+x, AX, CX; ADCXQ AX, R10; ADOXQ CX, R11; \
+ ;;;;;;;;;;;;;;;;;;; ADCXQ R12,R11; \
+ \
+ MOVQ 32+x, DX; \
+ MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \
+ MULXQ AX, AX, CX; \
+ MOVQ R15, R8; NEGQ R8; ANDQ 32+x, R8; \
+ ADDQ AX, R9; MOVQ R9, 64+z; \
+ ADCQ CX, R8; \
+ ADCQ $0, R11; \
+ ADDQ 32+x, DX; \
+ ADCQ $0, R15; \
+ XORL R9, R9; ;;;;;;;;;;;;;;;;;;;;; ADOXQ R8, R10; \
+ MULXQ 40+x, AX, CX; ADCXQ AX, R10; ADOXQ CX, R11; MOVQ R10, 72+z; \
+ MULXQ 48+x, AX, CX; ADCXQ AX, R11; ADOXQ CX, R12; \
+ ;;;;;;;;;;;;;;;;;;; ADCXQ R13,R12; \
+ \
+ MOVQ 40+x, DX; \
+ MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \
+ MULXQ AX, AX, CX; \
+ MOVQ R15, R8; NEGQ R8; ANDQ 40+x, R8; \
+ ADDQ AX, R11; MOVQ R11, 80+z; \
+ ADCQ CX, R8; \
+ ADCQ $0, R13; \
+ ADDQ 40+x, DX; \
+ ADCQ $0, R15; \
+ XORL R11, R11; ;;;;;;;;;;;;;;;;;;; ADOXQ R8, R12; \
+ MULXQ 48+x, AX, CX; ADCXQ AX, R12; ADOXQ CX, R13; MOVQ R12, 88+z; \
+ ;;;;;;;;;;;;;;;;;;; ADCXQ R14,R13; \
+ \
+ MOVQ 48+x, DX; \
+ MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \
+ MULXQ AX, AX, CX; \
+ MOVQ R15, R8; NEGQ R8; ANDQ 48+x, R8; \
+ XORL R10, R10; ;;;;;;;;;;;;;; ADOXQ CX, R14; \
+ ;;;;;;;;;;;;;; ADCXQ AX, R13; ;;;;;;;;;;;;;; MOVQ R13, 96+z; \
+ ;;;;;;;;;;;;;; ADCXQ R8, R14; MOVQ R14, 104+z;
+
+// reduceFromDoubleLeg finds a z=x modulo p such that z<2^448 and stores in z
+// Uses: AX, R8-R15, FLAGS
+// Instr: x86_64
+#define reduceFromDoubleLeg(z,x) \
+ /* ( ,2C13,2C12,2C11,2C10|C10,C9,C8, C7) + (C6,...,C0) */ \
+ /* (r14, r13, r12, r11, r10,r9,r8,r15) */ \
+ MOVQ 80+x,AX; MOVQ AX,R10; \
+ MOVQ $0xFFFFFFFF00000000, R8; \
+ ANDQ R8,R10; \
+ \
+ MOVQ $0,R14; \
+ MOVQ 104+x,R13; SHLQ $1,R13,R14; \
+ MOVQ 96+x,R12; SHLQ $1,R12,R13; \
+ MOVQ 88+x,R11; SHLQ $1,R11,R12; \
+ MOVQ 72+x, R9; SHLQ $1,R10,R11; \
+ MOVQ 64+x, R8; SHLQ $1,R10; \
+ MOVQ $0xFFFFFFFF,R15; ANDQ R15,AX; ORQ AX,R10; \
+ MOVQ 56+x,R15; \
+ \
+ ADDQ 0+x,R15; MOVQ R15, 0+z; MOVQ 56+x,R15; \
+ ADCQ 8+x, R8; MOVQ R8, 8+z; MOVQ 64+x, R8; \
+ ADCQ 16+x, R9; MOVQ R9,16+z; MOVQ 72+x, R9; \
+ ADCQ 24+x,R10; MOVQ R10,24+z; MOVQ 80+x,R10; \
+ ADCQ 32+x,R11; MOVQ R11,32+z; MOVQ 88+x,R11; \
+ ADCQ 40+x,R12; MOVQ R12,40+z; MOVQ 96+x,R12; \
+ ADCQ 48+x,R13; MOVQ R13,48+z; MOVQ 104+x,R13; \
+ ADCQ $0,R14; \
+ /* (c10c9,c9c8,c8c7,c7c13,c13c12,c12c11,c11c10) + (c6,...,c0) */ \
+ /* ( r9, r8, r15, r13, r12, r11, r10) */ \
+ MOVQ R10, AX; \
+ SHRQ $32,R11,R10; \
+ SHRQ $32,R12,R11; \
+ SHRQ $32,R13,R12; \
+ SHRQ $32,R15,R13; \
+ SHRQ $32, R8,R15; \
+ SHRQ $32, R9, R8; \
+ SHRQ $32, AX, R9; \
+ \
+ ADDQ 0+z,R10; \
+ ADCQ 8+z,R11; \
+ ADCQ 16+z,R12; \
+ ADCQ 24+z,R13; \
+ ADCQ 32+z,R15; \
+ ADCQ 40+z, R8; \
+ ADCQ 48+z, R9; \
+ ADCQ $0,R14; \
+ /* ( c7) + (c6,...,c0) */ \
+ /* (r14) */ \
+ MOVQ R14, AX; SHLQ $32, AX; \
+ ADDQ R14,R10; MOVQ $0,R14; \
+ ADCQ $0,R11; \
+ ADCQ $0,R12; \
+ ADCQ AX,R13; \
+ ADCQ $0,R15; \
+ ADCQ $0, R8; \
+ ADCQ $0, R9; \
+ ADCQ $0,R14; \
+ /* ( c7) + (c6,...,c0) */ \
+ /* (r14) */ \
+ MOVQ R14, AX; SHLQ $32,AX; \
+ ADDQ R14,R10; MOVQ R10, 0+z; \
+ ADCQ $0,R11; MOVQ R11, 8+z; \
+ ADCQ $0,R12; MOVQ R12,16+z; \
+ ADCQ AX,R13; MOVQ R13,24+z; \
+ ADCQ $0,R15; MOVQ R15,32+z; \
+ ADCQ $0, R8; MOVQ R8,40+z; \
+ ADCQ $0, R9; MOVQ R9,48+z;
+
+// reduceFromDoubleAdx finds a z=x modulo p such that z<2^448 and stores in z
+// Uses: AX, R8-R15, FLAGS
+// Instr: x86_64, adx
+#define reduceFromDoubleAdx(z,x) \
+ /* ( ,2C13,2C12,2C11,2C10|C10,C9,C8, C7) + (C6,...,C0) */ \
+ /* (r14, r13, r12, r11, r10,r9,r8,r15) */ \
+ MOVQ 80+x,AX; MOVQ AX,R10; \
+ MOVQ $0xFFFFFFFF00000000, R8; \
+ ANDQ R8,R10; \
+ \
+ MOVQ $0,R14; \
+ MOVQ 104+x,R13; SHLQ $1,R13,R14; \
+ MOVQ 96+x,R12; SHLQ $1,R12,R13; \
+ MOVQ 88+x,R11; SHLQ $1,R11,R12; \
+ MOVQ 72+x, R9; SHLQ $1,R10,R11; \
+ MOVQ 64+x, R8; SHLQ $1,R10; \
+ MOVQ $0xFFFFFFFF,R15; ANDQ R15,AX; ORQ AX,R10; \
+ MOVQ 56+x,R15; \
+ \
+ XORL AX,AX; \
+ ADCXQ 0+x,R15; MOVQ R15, 0+z; MOVQ 56+x,R15; \
+ ADCXQ 8+x, R8; MOVQ R8, 8+z; MOVQ 64+x, R8; \
+ ADCXQ 16+x, R9; MOVQ R9,16+z; MOVQ 72+x, R9; \
+ ADCXQ 24+x,R10; MOVQ R10,24+z; MOVQ 80+x,R10; \
+ ADCXQ 32+x,R11; MOVQ R11,32+z; MOVQ 88+x,R11; \
+ ADCXQ 40+x,R12; MOVQ R12,40+z; MOVQ 96+x,R12; \
+ ADCXQ 48+x,R13; MOVQ R13,48+z; MOVQ 104+x,R13; \
+ ADCXQ AX,R14; \
+ /* (c10c9,c9c8,c8c7,c7c13,c13c12,c12c11,c11c10) + (c6,...,c0) */ \
+ /* ( r9, r8, r15, r13, r12, r11, r10) */ \
+ MOVQ R10, AX; \
+ SHRQ $32,R11,R10; \
+ SHRQ $32,R12,R11; \
+ SHRQ $32,R13,R12; \
+ SHRQ $32,R15,R13; \
+ SHRQ $32, R8,R15; \
+ SHRQ $32, R9, R8; \
+ SHRQ $32, AX, R9; \
+ \
+ XORL AX,AX; \
+ ADCXQ 0+z,R10; \
+ ADCXQ 8+z,R11; \
+ ADCXQ 16+z,R12; \
+ ADCXQ 24+z,R13; \
+ ADCXQ 32+z,R15; \
+ ADCXQ 40+z, R8; \
+ ADCXQ 48+z, R9; \
+ ADCXQ AX,R14; \
+ /* ( c7) + (c6,...,c0) */ \
+ /* (r14) */ \
+ MOVQ R14, AX; SHLQ $32, AX; \
+ CLC; \
+ ADCXQ R14,R10; MOVQ $0,R14; \
+ ADCXQ R14,R11; \
+ ADCXQ R14,R12; \
+ ADCXQ AX,R13; \
+ ADCXQ R14,R15; \
+ ADCXQ R14, R8; \
+ ADCXQ R14, R9; \
+ ADCXQ R14,R14; \
+ /* ( c7) + (c6,...,c0) */ \
+ /* (r14) */ \
+ MOVQ R14, AX; SHLQ $32, AX; \
+ CLC; \
+ ADCXQ R14,R10; MOVQ R10, 0+z; MOVQ $0,R14; \
+ ADCXQ R14,R11; MOVQ R11, 8+z; \
+ ADCXQ R14,R12; MOVQ R12,16+z; \
+ ADCXQ AX,R13; MOVQ R13,24+z; \
+ ADCXQ R14,R15; MOVQ R15,32+z; \
+ ADCXQ R14, R8; MOVQ R8,40+z; \
+ ADCXQ R14, R9; MOVQ R9,48+z;
+
+// addSub calculates two operations: x,y = x+y,x-y
+// Uses: AX, DX, R8-R15, FLAGS
+#define addSub(x,y) \
+ MOVQ 0+x, R8; ADDQ 0+y, R8; \
+ MOVQ 8+x, R9; ADCQ 8+y, R9; \
+ MOVQ 16+x, R10; ADCQ 16+y, R10; \
+ MOVQ 24+x, R11; ADCQ 24+y, R11; \
+ MOVQ 32+x, R12; ADCQ 32+y, R12; \
+ MOVQ 40+x, R13; ADCQ 40+y, R13; \
+ MOVQ 48+x, R14; ADCQ 48+y, R14; \
+ MOVQ $0, AX; ADCQ $0, AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ ADDQ AX, R8; MOVQ $0, AX; \
+ ADCQ $0, R9; \
+ ADCQ $0, R10; \
+ ADCQ DX, R11; \
+ ADCQ $0, R12; \
+ ADCQ $0, R13; \
+ ADCQ $0, R14; \
+ ADCQ $0, AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ ADDQ AX, R8; MOVQ 0+x,AX; MOVQ R8, 0+x; MOVQ AX, R8; \
+ ADCQ $0, R9; MOVQ 8+x,AX; MOVQ R9, 8+x; MOVQ AX, R9; \
+ ADCQ $0, R10; MOVQ 16+x,AX; MOVQ R10, 16+x; MOVQ AX, R10; \
+ ADCQ DX, R11; MOVQ 24+x,AX; MOVQ R11, 24+x; MOVQ AX, R11; \
+ ADCQ $0, R12; MOVQ 32+x,AX; MOVQ R12, 32+x; MOVQ AX, R12; \
+ ADCQ $0, R13; MOVQ 40+x,AX; MOVQ R13, 40+x; MOVQ AX, R13; \
+ ADCQ $0, R14; MOVQ 48+x,AX; MOVQ R14, 48+x; MOVQ AX, R14; \
+ SUBQ 0+y, R8; \
+ SBBQ 8+y, R9; \
+ SBBQ 16+y, R10; \
+ SBBQ 24+y, R11; \
+ SBBQ 32+y, R12; \
+ SBBQ 40+y, R13; \
+ SBBQ 48+y, R14; \
+ MOVQ $0, AX; SETCS AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ SUBQ AX, R8; MOVQ $0, AX; \
+ SBBQ $0, R9; \
+ SBBQ $0, R10; \
+ SBBQ DX, R11; \
+ SBBQ $0, R12; \
+ SBBQ $0, R13; \
+ SBBQ $0, R14; \
+ SETCS AX; \
+ MOVQ AX, DX; \
+ SHLQ $32, DX; \
+ SUBQ AX, R8; MOVQ R8, 0+y; \
+ SBBQ $0, R9; MOVQ R9, 8+y; \
+ SBBQ $0, R10; MOVQ R10, 16+y; \
+ SBBQ DX, R11; MOVQ R11, 24+y; \
+ SBBQ $0, R12; MOVQ R12, 32+y; \
+ SBBQ $0, R13; MOVQ R13, 40+y; \
+ SBBQ $0, R14; MOVQ R14, 48+y;
diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s
new file mode 100644
index 0000000000..3f1f07c986
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s
@@ -0,0 +1,75 @@
+//go:build amd64 && !purego
+// +build amd64,!purego
+
+#include "textflag.h"
+#include "fp_amd64.h"
+
+// func cmovAmd64(x, y *Elt, n uint)
+TEXT ·cmovAmd64(SB),NOSPLIT,$0-24
+ MOVQ x+0(FP), DI
+ MOVQ y+8(FP), SI
+ MOVQ n+16(FP), BX
+ cselect(0(DI),0(SI),BX)
+ RET
+
+// func cswapAmd64(x, y *Elt, n uint)
+TEXT ·cswapAmd64(SB),NOSPLIT,$0-24
+ MOVQ x+0(FP), DI
+ MOVQ y+8(FP), SI
+ MOVQ n+16(FP), BX
+ cswap(0(DI),0(SI),BX)
+ RET
+
+// func subAmd64(z, x, y *Elt)
+TEXT ·subAmd64(SB),NOSPLIT,$0-24
+ MOVQ z+0(FP), DI
+ MOVQ x+8(FP), SI
+ MOVQ y+16(FP), BX
+ subtraction(0(DI),0(SI),0(BX))
+ RET
+
+// func addsubAmd64(x, y *Elt)
+TEXT ·addsubAmd64(SB),NOSPLIT,$0-16
+ MOVQ x+0(FP), DI
+ MOVQ y+8(FP), SI
+ addSub(0(DI),0(SI))
+ RET
+
+#define addLegacy \
+ additionLeg(0(DI),0(SI),0(BX))
+#define addBmi2Adx \
+ additionAdx(0(DI),0(SI),0(BX))
+
+#define mulLegacy \
+ integerMulLeg(0(SP),0(SI),0(BX)) \
+ reduceFromDoubleLeg(0(DI),0(SP))
+#define mulBmi2Adx \
+ integerMulAdx(0(SP),0(SI),0(BX)) \
+ reduceFromDoubleAdx(0(DI),0(SP))
+
+#define sqrLegacy \
+ integerSqrLeg(0(SP),0(SI)) \
+ reduceFromDoubleLeg(0(DI),0(SP))
+#define sqrBmi2Adx \
+ integerSqrAdx(0(SP),0(SI)) \
+ reduceFromDoubleAdx(0(DI),0(SP))
+
+// func addAmd64(z, x, y *Elt)
+TEXT ·addAmd64(SB),NOSPLIT,$0-24
+ MOVQ z+0(FP), DI
+ MOVQ x+8(FP), SI
+ MOVQ y+16(FP), BX
+ CHECK_BMI2ADX(LADD, addLegacy, addBmi2Adx)
+
+// func mulAmd64(z, x, y *Elt)
+TEXT ·mulAmd64(SB),NOSPLIT,$112-24
+ MOVQ z+0(FP), DI
+ MOVQ x+8(FP), SI
+ MOVQ y+16(FP), BX
+ CHECK_BMI2ADX(LMUL, mulLegacy, mulBmi2Adx)
+
+// func sqrAmd64(z, x *Elt)
+TEXT ·sqrAmd64(SB),NOSPLIT,$112-16
+ MOVQ z+0(FP), DI
+ MOVQ x+8(FP), SI
+ CHECK_BMI2ADX(LSQR, sqrLegacy, sqrBmi2Adx)
diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go b/vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go
new file mode 100644
index 0000000000..47a0b63205
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go
@@ -0,0 +1,339 @@
+package fp448
+
+import (
+ "encoding/binary"
+ "math/bits"
+)
+
+func cmovGeneric(x, y *Elt, n uint) {
+ m := -uint64(n & 0x1)
+ x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8])
+ x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8])
+ x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8])
+ x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8])
+ x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8])
+ x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8])
+ x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8])
+
+ y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8])
+ y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8])
+ y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8])
+ y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8])
+ y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8])
+ y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8])
+ y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8])
+
+ x0 = (x0 &^ m) | (y0 & m)
+ x1 = (x1 &^ m) | (y1 & m)
+ x2 = (x2 &^ m) | (y2 & m)
+ x3 = (x3 &^ m) | (y3 & m)
+ x4 = (x4 &^ m) | (y4 & m)
+ x5 = (x5 &^ m) | (y5 & m)
+ x6 = (x6 &^ m) | (y6 & m)
+
+ binary.LittleEndian.PutUint64(x[0*8:1*8], x0)
+ binary.LittleEndian.PutUint64(x[1*8:2*8], x1)
+ binary.LittleEndian.PutUint64(x[2*8:3*8], x2)
+ binary.LittleEndian.PutUint64(x[3*8:4*8], x3)
+ binary.LittleEndian.PutUint64(x[4*8:5*8], x4)
+ binary.LittleEndian.PutUint64(x[5*8:6*8], x5)
+ binary.LittleEndian.PutUint64(x[6*8:7*8], x6)
+}
+
+func cswapGeneric(x, y *Elt, n uint) {
+ m := -uint64(n & 0x1)
+ x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8])
+ x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8])
+ x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8])
+ x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8])
+ x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8])
+ x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8])
+ x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8])
+
+ y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8])
+ y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8])
+ y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8])
+ y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8])
+ y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8])
+ y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8])
+ y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8])
+
+ t0 := m & (x0 ^ y0)
+ t1 := m & (x1 ^ y1)
+ t2 := m & (x2 ^ y2)
+ t3 := m & (x3 ^ y3)
+ t4 := m & (x4 ^ y4)
+ t5 := m & (x5 ^ y5)
+ t6 := m & (x6 ^ y6)
+ x0 ^= t0
+ x1 ^= t1
+ x2 ^= t2
+ x3 ^= t3
+ x4 ^= t4
+ x5 ^= t5
+ x6 ^= t6
+ y0 ^= t0
+ y1 ^= t1
+ y2 ^= t2
+ y3 ^= t3
+ y4 ^= t4
+ y5 ^= t5
+ y6 ^= t6
+
+ binary.LittleEndian.PutUint64(x[0*8:1*8], x0)
+ binary.LittleEndian.PutUint64(x[1*8:2*8], x1)
+ binary.LittleEndian.PutUint64(x[2*8:3*8], x2)
+ binary.LittleEndian.PutUint64(x[3*8:4*8], x3)
+ binary.LittleEndian.PutUint64(x[4*8:5*8], x4)
+ binary.LittleEndian.PutUint64(x[5*8:6*8], x5)
+ binary.LittleEndian.PutUint64(x[6*8:7*8], x6)
+
+ binary.LittleEndian.PutUint64(y[0*8:1*8], y0)
+ binary.LittleEndian.PutUint64(y[1*8:2*8], y1)
+ binary.LittleEndian.PutUint64(y[2*8:3*8], y2)
+ binary.LittleEndian.PutUint64(y[3*8:4*8], y3)
+ binary.LittleEndian.PutUint64(y[4*8:5*8], y4)
+ binary.LittleEndian.PutUint64(y[5*8:6*8], y5)
+ binary.LittleEndian.PutUint64(y[6*8:7*8], y6)
+}
+
+func addGeneric(z, x, y *Elt) {
+ x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8])
+ x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8])
+ x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8])
+ x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8])
+ x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8])
+ x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8])
+ x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8])
+
+ y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8])
+ y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8])
+ y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8])
+ y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8])
+ y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8])
+ y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8])
+ y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8])
+
+ z0, c0 := bits.Add64(x0, y0, 0)
+ z1, c1 := bits.Add64(x1, y1, c0)
+ z2, c2 := bits.Add64(x2, y2, c1)
+ z3, c3 := bits.Add64(x3, y3, c2)
+ z4, c4 := bits.Add64(x4, y4, c3)
+ z5, c5 := bits.Add64(x5, y5, c4)
+ z6, z7 := bits.Add64(x6, y6, c5)
+
+ z0, c0 = bits.Add64(z0, z7, 0)
+ z1, c1 = bits.Add64(z1, 0, c0)
+ z2, c2 = bits.Add64(z2, 0, c1)
+ z3, c3 = bits.Add64(z3, z7<<32, c2)
+ z4, c4 = bits.Add64(z4, 0, c3)
+ z5, c5 = bits.Add64(z5, 0, c4)
+ z6, z7 = bits.Add64(z6, 0, c5)
+
+ z0, c0 = bits.Add64(z0, z7, 0)
+ z1, c1 = bits.Add64(z1, 0, c0)
+ z2, c2 = bits.Add64(z2, 0, c1)
+ z3, c3 = bits.Add64(z3, z7<<32, c2)
+ z4, c4 = bits.Add64(z4, 0, c3)
+ z5, c5 = bits.Add64(z5, 0, c4)
+ z6, _ = bits.Add64(z6, 0, c5)
+
+ binary.LittleEndian.PutUint64(z[0*8:1*8], z0)
+ binary.LittleEndian.PutUint64(z[1*8:2*8], z1)
+ binary.LittleEndian.PutUint64(z[2*8:3*8], z2)
+ binary.LittleEndian.PutUint64(z[3*8:4*8], z3)
+ binary.LittleEndian.PutUint64(z[4*8:5*8], z4)
+ binary.LittleEndian.PutUint64(z[5*8:6*8], z5)
+ binary.LittleEndian.PutUint64(z[6*8:7*8], z6)
+}
+
+func subGeneric(z, x, y *Elt) {
+ x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8])
+ x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8])
+ x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8])
+ x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8])
+ x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8])
+ x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8])
+ x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8])
+
+ y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8])
+ y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8])
+ y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8])
+ y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8])
+ y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8])
+ y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8])
+ y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8])
+
+ z0, c0 := bits.Sub64(x0, y0, 0)
+ z1, c1 := bits.Sub64(x1, y1, c0)
+ z2, c2 := bits.Sub64(x2, y2, c1)
+ z3, c3 := bits.Sub64(x3, y3, c2)
+ z4, c4 := bits.Sub64(x4, y4, c3)
+ z5, c5 := bits.Sub64(x5, y5, c4)
+ z6, z7 := bits.Sub64(x6, y6, c5)
+
+ z0, c0 = bits.Sub64(z0, z7, 0)
+ z1, c1 = bits.Sub64(z1, 0, c0)
+ z2, c2 = bits.Sub64(z2, 0, c1)
+ z3, c3 = bits.Sub64(z3, z7<<32, c2)
+ z4, c4 = bits.Sub64(z4, 0, c3)
+ z5, c5 = bits.Sub64(z5, 0, c4)
+ z6, z7 = bits.Sub64(z6, 0, c5)
+
+ z0, c0 = bits.Sub64(z0, z7, 0)
+ z1, c1 = bits.Sub64(z1, 0, c0)
+ z2, c2 = bits.Sub64(z2, 0, c1)
+ z3, c3 = bits.Sub64(z3, z7<<32, c2)
+ z4, c4 = bits.Sub64(z4, 0, c3)
+ z5, c5 = bits.Sub64(z5, 0, c4)
+ z6, _ = bits.Sub64(z6, 0, c5)
+
+ binary.LittleEndian.PutUint64(z[0*8:1*8], z0)
+ binary.LittleEndian.PutUint64(z[1*8:2*8], z1)
+ binary.LittleEndian.PutUint64(z[2*8:3*8], z2)
+ binary.LittleEndian.PutUint64(z[3*8:4*8], z3)
+ binary.LittleEndian.PutUint64(z[4*8:5*8], z4)
+ binary.LittleEndian.PutUint64(z[5*8:6*8], z5)
+ binary.LittleEndian.PutUint64(z[6*8:7*8], z6)
+}
+
+func addsubGeneric(x, y *Elt) {
+ z := &Elt{}
+ addGeneric(z, x, y)
+ subGeneric(y, x, y)
+ *x = *z
+}
+
+func mulGeneric(z, x, y *Elt) {
+ x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8])
+ x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8])
+ x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8])
+ x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8])
+ x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8])
+ x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8])
+ x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8])
+
+ y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8])
+ y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8])
+ y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8])
+ y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8])
+ y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8])
+ y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8])
+ y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8])
+
+ yy := [7]uint64{y0, y1, y2, y3, y4, y5, y6}
+ zz := [7]uint64{}
+
+ yi := yy[0]
+ h0, l0 := bits.Mul64(x0, yi)
+ h1, l1 := bits.Mul64(x1, yi)
+ h2, l2 := bits.Mul64(x2, yi)
+ h3, l3 := bits.Mul64(x3, yi)
+ h4, l4 := bits.Mul64(x4, yi)
+ h5, l5 := bits.Mul64(x5, yi)
+ h6, l6 := bits.Mul64(x6, yi)
+
+ zz[0] = l0
+ a0, c0 := bits.Add64(h0, l1, 0)
+ a1, c1 := bits.Add64(h1, l2, c0)
+ a2, c2 := bits.Add64(h2, l3, c1)
+ a3, c3 := bits.Add64(h3, l4, c2)
+ a4, c4 := bits.Add64(h4, l5, c3)
+ a5, c5 := bits.Add64(h5, l6, c4)
+ a6, _ := bits.Add64(h6, 0, c5)
+
+ for i := 1; i < 7; i++ {
+ yi = yy[i]
+ h0, l0 = bits.Mul64(x0, yi)
+ h1, l1 = bits.Mul64(x1, yi)
+ h2, l2 = bits.Mul64(x2, yi)
+ h3, l3 = bits.Mul64(x3, yi)
+ h4, l4 = bits.Mul64(x4, yi)
+ h5, l5 = bits.Mul64(x5, yi)
+ h6, l6 = bits.Mul64(x6, yi)
+
+ zz[i], c0 = bits.Add64(a0, l0, 0)
+ a0, c1 = bits.Add64(a1, l1, c0)
+ a1, c2 = bits.Add64(a2, l2, c1)
+ a2, c3 = bits.Add64(a3, l3, c2)
+ a3, c4 = bits.Add64(a4, l4, c3)
+ a4, c5 = bits.Add64(a5, l5, c4)
+ a5, a6 = bits.Add64(a6, l6, c5)
+
+ a0, c0 = bits.Add64(a0, h0, 0)
+ a1, c1 = bits.Add64(a1, h1, c0)
+ a2, c2 = bits.Add64(a2, h2, c1)
+ a3, c3 = bits.Add64(a3, h3, c2)
+ a4, c4 = bits.Add64(a4, h4, c3)
+ a5, c5 = bits.Add64(a5, h5, c4)
+ a6, _ = bits.Add64(a6, h6, c5)
+ }
+ red64(z, &zz, &[7]uint64{a0, a1, a2, a3, a4, a5, a6})
+}
+
+func sqrGeneric(z, x *Elt) { mulGeneric(z, x, x) }
+
+func red64(z *Elt, l, h *[7]uint64) {
+ /* (2C13, 2C12, 2C11, 2C10|C10, C9, C8, C7) + (C6,...,C0) */
+ h0 := h[0]
+ h1 := h[1]
+ h2 := h[2]
+ h3 := ((h[3] & (0xFFFFFFFF << 32)) << 1) | (h[3] & 0xFFFFFFFF)
+ h4 := (h[3] >> 63) | (h[4] << 1)
+ h5 := (h[4] >> 63) | (h[5] << 1)
+ h6 := (h[5] >> 63) | (h[6] << 1)
+ h7 := (h[6] >> 63)
+
+ l0, c0 := bits.Add64(h0, l[0], 0)
+ l1, c1 := bits.Add64(h1, l[1], c0)
+ l2, c2 := bits.Add64(h2, l[2], c1)
+ l3, c3 := bits.Add64(h3, l[3], c2)
+ l4, c4 := bits.Add64(h4, l[4], c3)
+ l5, c5 := bits.Add64(h5, l[5], c4)
+ l6, c6 := bits.Add64(h6, l[6], c5)
+ l7, _ := bits.Add64(h7, 0, c6)
+
+ /* (C10C9, C9C8,C8C7,C7C13,C13C12,C12C11,C11C10) + (C6,...,C0) */
+ h0 = (h[3] >> 32) | (h[4] << 32)
+ h1 = (h[4] >> 32) | (h[5] << 32)
+ h2 = (h[5] >> 32) | (h[6] << 32)
+ h3 = (h[6] >> 32) | (h[0] << 32)
+ h4 = (h[0] >> 32) | (h[1] << 32)
+ h5 = (h[1] >> 32) | (h[2] << 32)
+ h6 = (h[2] >> 32) | (h[3] << 32)
+
+ l0, c0 = bits.Add64(l0, h0, 0)
+ l1, c1 = bits.Add64(l1, h1, c0)
+ l2, c2 = bits.Add64(l2, h2, c1)
+ l3, c3 = bits.Add64(l3, h3, c2)
+ l4, c4 = bits.Add64(l4, h4, c3)
+ l5, c5 = bits.Add64(l5, h5, c4)
+ l6, c6 = bits.Add64(l6, h6, c5)
+ l7, _ = bits.Add64(l7, 0, c6)
+
+ /* (C7) + (C6,...,C0) */
+ l0, c0 = bits.Add64(l0, l7, 0)
+ l1, c1 = bits.Add64(l1, 0, c0)
+ l2, c2 = bits.Add64(l2, 0, c1)
+ l3, c3 = bits.Add64(l3, l7<<32, c2)
+ l4, c4 = bits.Add64(l4, 0, c3)
+ l5, c5 = bits.Add64(l5, 0, c4)
+ l6, l7 = bits.Add64(l6, 0, c5)
+
+ /* (C7) + (C6,...,C0) */
+ l0, c0 = bits.Add64(l0, l7, 0)
+ l1, c1 = bits.Add64(l1, 0, c0)
+ l2, c2 = bits.Add64(l2, 0, c1)
+ l3, c3 = bits.Add64(l3, l7<<32, c2)
+ l4, c4 = bits.Add64(l4, 0, c3)
+ l5, c5 = bits.Add64(l5, 0, c4)
+ l6, _ = bits.Add64(l6, 0, c5)
+
+ binary.LittleEndian.PutUint64(z[0*8:1*8], l0)
+ binary.LittleEndian.PutUint64(z[1*8:2*8], l1)
+ binary.LittleEndian.PutUint64(z[2*8:3*8], l2)
+ binary.LittleEndian.PutUint64(z[3*8:4*8], l3)
+ binary.LittleEndian.PutUint64(z[4*8:5*8], l4)
+ binary.LittleEndian.PutUint64(z[5*8:6*8], l5)
+ binary.LittleEndian.PutUint64(z[6*8:7*8], l6)
+}
diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go b/vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go
new file mode 100644
index 0000000000..a62225d296
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go
@@ -0,0 +1,12 @@
+//go:build !amd64 || purego
+// +build !amd64 purego
+
+package fp448
+
+func cmov(x, y *Elt, n uint) { cmovGeneric(x, y, n) }
+func cswap(x, y *Elt, n uint) { cswapGeneric(x, y, n) }
+func add(z, x, y *Elt) { addGeneric(z, x, y) }
+func sub(z, x, y *Elt) { subGeneric(z, x, y) }
+func addsub(x, y *Elt) { addsubGeneric(x, y) }
+func mul(z, x, y *Elt) { mulGeneric(z, x, y) }
+func sqr(z, x *Elt) { sqrGeneric(z, x) }
diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go b/vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go
new file mode 100644
index 0000000000..2d7afc8059
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go
@@ -0,0 +1,75 @@
+//go:build gofuzz
+// +build gofuzz
+
+// How to run the fuzzer:
+//
+// $ go get -u github.com/dvyukov/go-fuzz/go-fuzz
+// $ go get -u github.com/dvyukov/go-fuzz/go-fuzz-build
+// $ go-fuzz-build -libfuzzer -func FuzzReduction -o lib.a
+// $ clang -fsanitize=fuzzer lib.a -o fu.exe
+// $ ./fu.exe
+package fp448
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math/big"
+
+ "github.com/cloudflare/circl/internal/conv"
+)
+
+// FuzzReduction is a fuzzer target for red64 function, which reduces t
+// (112 bits) to a number t' (56 bits) congruent modulo p448.
+func FuzzReduction(data []byte) int {
+ if len(data) != 2*Size {
+ return -1
+ }
+ var got, want Elt
+ var lo, hi [7]uint64
+ a := data[:Size]
+ b := data[Size:]
+ lo[0] = binary.LittleEndian.Uint64(a[0*8 : 1*8])
+ lo[1] = binary.LittleEndian.Uint64(a[1*8 : 2*8])
+ lo[2] = binary.LittleEndian.Uint64(a[2*8 : 3*8])
+ lo[3] = binary.LittleEndian.Uint64(a[3*8 : 4*8])
+ lo[4] = binary.LittleEndian.Uint64(a[4*8 : 5*8])
+ lo[5] = binary.LittleEndian.Uint64(a[5*8 : 6*8])
+ lo[6] = binary.LittleEndian.Uint64(a[6*8 : 7*8])
+
+ hi[0] = binary.LittleEndian.Uint64(b[0*8 : 1*8])
+ hi[1] = binary.LittleEndian.Uint64(b[1*8 : 2*8])
+ hi[2] = binary.LittleEndian.Uint64(b[2*8 : 3*8])
+ hi[3] = binary.LittleEndian.Uint64(b[3*8 : 4*8])
+ hi[4] = binary.LittleEndian.Uint64(b[4*8 : 5*8])
+ hi[5] = binary.LittleEndian.Uint64(b[5*8 : 6*8])
+ hi[6] = binary.LittleEndian.Uint64(b[6*8 : 7*8])
+
+ red64(&got, &lo, &hi)
+
+ t := conv.BytesLe2BigInt(data[:2*Size])
+
+ two448 := big.NewInt(1)
+ two448.Lsh(two448, 448) // 2^448
+ mask448 := big.NewInt(1)
+ mask448.Sub(two448, mask448) // 2^448-1
+ two224plus1 := big.NewInt(1)
+ two224plus1.Lsh(two224plus1, 224)
+ two224plus1.Add(two224plus1, big.NewInt(1)) // 2^224+1
+
+ var loBig, hiBig big.Int
+ for t.Cmp(two448) >= 0 {
+ loBig.And(t, mask448)
+ hiBig.Rsh(t, 448)
+ t.Mul(&hiBig, two224plus1)
+ t.Add(t, &loBig)
+ }
+ conv.BigInt2BytesLe(want[:], t)
+
+ if got != want {
+ fmt.Printf("in: %v\n", conv.BytesLe2BigInt(data[:2*Size]))
+ fmt.Printf("got: %v\n", got)
+ fmt.Printf("want: %v\n", want)
+ panic("error found")
+ }
+ return 1
+}
diff --git a/vendor/github.com/cloudflare/circl/math/integer.go b/vendor/github.com/cloudflare/circl/math/integer.go
new file mode 100644
index 0000000000..9c80c23b59
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/integer.go
@@ -0,0 +1,16 @@
+package math
+
+import "math/bits"
+
+// NextPow2 finds the next power of two (N=2^k, k>=0) greater than n.
+// If n is already a power of two, then this function returns n, and log2(n).
+func NextPow2(n uint) (N uint, k uint) {
+ if bits.OnesCount(n) == 1 {
+ k = uint(bits.TrailingZeros(n))
+ N = n
+ } else {
+ k = uint(bits.Len(n))
+ N = uint(1) << k
+ }
+ return
+}
diff --git a/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go b/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go
new file mode 100644
index 0000000000..a43851b8bb
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go
@@ -0,0 +1,122 @@
+// Package mlsbset provides a constant-time exponentiation method with precomputation.
+//
+// References: "Efficient and secure algorithms for GLV-based scalar
+// multiplication and their implementation on GLV–GLS curves" by (Faz-Hernandez et al.)
+// - https://doi.org/10.1007/s13389-014-0085-7
+// - https://eprint.iacr.org/2013/158
+package mlsbset
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/cloudflare/circl/internal/conv"
+)
+
+// EltG is a group element.
+type EltG interface{}
+
+// EltP is a precomputed group element.
+type EltP interface{}
+
+// Group defines the operations required by MLSBSet exponentiation method.
+type Group interface {
+ Identity() EltG // Returns the identity of the group.
+ Sqr(x EltG) // Calculates x = x^2.
+ Mul(x EltG, y EltP) // Calculates x = x*y.
+ NewEltP() EltP // Returns an arbitrary precomputed element.
+ ExtendedEltP() EltP // Returns the precomputed element x^(2^(w*d)).
+ Lookup(a EltP, v uint, s, u int32) // Sets a = s*T[v][u].
+}
+
+// Params contains the parameters of the encoding.
+type Params struct {
+ T uint // T is the maximum size (in bits) of exponents.
+ V uint // V is the number of tables.
+ W uint // W is the window size.
+ E uint // E is the number of digits per table.
+ D uint // D is the number of digits in total.
+ L uint // L is the length of the code.
+}
+
+// Encoder allows to convert integers into valid powers.
+type Encoder struct{ p Params }
+
+// New produces an encoder of the MLSBSet algorithm.
+func New(t, v, w uint) (Encoder, error) {
+ if !(t > 1 && v >= 1 && w >= 2) {
+ return Encoder{}, errors.New("t>1, v>=1, w>=2")
+ }
+ e := (t + w*v - 1) / (w * v)
+ d := e * v
+ l := d * w
+ return Encoder{Params{t, v, w, e, d, l}}, nil
+}
+
+// Encode converts an odd integer k into a valid power for exponentiation.
+func (m Encoder) Encode(k []byte) (*Power, error) {
+ if len(k) == 0 {
+ return nil, errors.New("empty slice")
+ }
+ if !(len(k) <= int(m.p.L+7)>>3) {
+ return nil, errors.New("k too big")
+ }
+ if k[0]%2 == 0 {
+ return nil, errors.New("k must be odd")
+ }
+ ap := int((m.p.L+7)/8) - len(k)
+ k = append(k, make([]byte, ap)...)
+ s := m.signs(k)
+ b := make([]int32, m.p.L-m.p.D)
+ c := conv.BytesLe2BigInt(k)
+ c.Rsh(c, m.p.D)
+ var bi big.Int
+ for i := m.p.D; i < m.p.L; i++ {
+ c0 := int32(c.Bit(0))
+ b[i-m.p.D] = s[i%m.p.D] * c0
+ bi.SetInt64(int64(b[i-m.p.D] >> 1))
+ c.Rsh(c, 1)
+ c.Sub(c, &bi)
+ }
+ carry := int(c.Int64())
+ return &Power{m, s, b, carry}, nil
+}
+
+// signs calculates the set of signs.
+func (m Encoder) signs(k []byte) []int32 {
+ s := make([]int32, m.p.D)
+ s[m.p.D-1] = 1
+ for i := uint(1); i < m.p.D; i++ {
+ ki := int32((k[i>>3] >> (i & 0x7)) & 0x1)
+ s[i-1] = 2*ki - 1
+ }
+ return s
+}
+
+// GetParams returns the complementary parameters of the encoding.
+func (m Encoder) GetParams() Params { return m.p }
+
+// tableSize returns the size of each table.
+func (m Encoder) tableSize() uint { return 1 << (m.p.W - 1) }
+
+// Elts returns the total number of elements that must be precomputed.
+func (m Encoder) Elts() uint { return m.p.V * m.tableSize() }
+
+// IsExtended returns true if the element x^(2^(wd)) must be calculated.
+func (m Encoder) IsExtended() bool { q := m.p.T / (m.p.V * m.p.W); return m.p.T == q*m.p.V*m.p.W }
+
+// Ops returns the number of squares and multiplications executed during an exponentiation.
+func (m Encoder) Ops() (S uint, M uint) {
+ S = m.p.E
+ M = m.p.E * m.p.V
+ if m.IsExtended() {
+ M++
+ }
+ return
+}
+
+func (m Encoder) String() string {
+ return fmt.Sprintf("T: %v W: %v V: %v e: %v d: %v l: %v wv|t: %v",
+ m.p.T, m.p.W, m.p.V, m.p.E, m.p.D, m.p.L, m.IsExtended())
+}
diff --git a/vendor/github.com/cloudflare/circl/math/mlsbset/power.go b/vendor/github.com/cloudflare/circl/math/mlsbset/power.go
new file mode 100644
index 0000000000..3f214c3046
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/mlsbset/power.go
@@ -0,0 +1,64 @@
+package mlsbset
+
+import "fmt"
+
+// Power is a valid exponent produced by the MLSBSet encoding algorithm.
+type Power struct {
+ set Encoder // parameters of code.
+ s []int32 // set of signs.
+ b []int32 // set of digits.
+ c int // carry is {0,1}.
+}
+
+// Exp is calculates x^k, where x is a predetermined element of a group G.
+func (p *Power) Exp(G Group) EltG {
+ a, b := G.Identity(), G.NewEltP()
+ for e := int(p.set.p.E - 1); e >= 0; e-- {
+ G.Sqr(a)
+ for v := uint(0); v < p.set.p.V; v++ {
+ sgnElt, idElt := p.Digit(v, uint(e))
+ G.Lookup(b, v, sgnElt, idElt)
+ G.Mul(a, b)
+ }
+ }
+ if p.set.IsExtended() && p.c == 1 {
+ G.Mul(a, G.ExtendedEltP())
+ }
+ return a
+}
+
+// Digit returns the (v,e)-th digit and its sign.
+func (p *Power) Digit(v, e uint) (sgn, dig int32) {
+ sgn = p.bit(0, v, e)
+ dig = 0
+ for i := p.set.p.W - 1; i > 0; i-- {
+ dig = 2*dig + p.bit(i, v, e)
+ }
+ mask := dig >> 31
+ dig = (dig + mask) ^ mask
+ return sgn, dig
+}
+
+// bit returns the (w,v,e)-th bit of the code.
+func (p *Power) bit(w, v, e uint) int32 {
+ if !(w < p.set.p.W &&
+ v < p.set.p.V &&
+ e < p.set.p.E) {
+ panic(fmt.Errorf("indexes outside (%v,%v,%v)", w, v, e))
+ }
+ if w == 0 {
+ return p.s[p.set.p.E*v+e]
+ }
+ return p.b[p.set.p.D*(w-1)+p.set.p.E*v+e]
+}
+
+func (p *Power) String() string {
+ dig := ""
+ for j := uint(0); j < p.set.p.V; j++ {
+ for i := uint(0); i < p.set.p.E; i++ {
+ s, d := p.Digit(j, i)
+ dig += fmt.Sprintf("(%2v,%2v) = %+2v %+2v\n", j, i, s, d)
+ }
+ }
+ return fmt.Sprintf("len: %v\ncarry: %v\ndigits:\n%v", len(p.b)+len(p.s), p.c, dig)
+}
diff --git a/vendor/github.com/cloudflare/circl/math/primes.go b/vendor/github.com/cloudflare/circl/math/primes.go
new file mode 100644
index 0000000000..158fd83a7a
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/primes.go
@@ -0,0 +1,34 @@
+package math
+
+import (
+ "crypto/rand"
+ "io"
+ "math/big"
+)
+
+// IsSafePrime reports whether p is (probably) a safe prime.
+// The prime p=2*q+1 is safe prime if both p and q are primes.
+// Note that ProbablyPrime is not suitable for judging primes
+// that an adversary may have crafted to fool the test.
+func IsSafePrime(p *big.Int) bool {
+ pdiv2 := new(big.Int).Rsh(p, 1)
+ return p.ProbablyPrime(20) && pdiv2.ProbablyPrime(20)
+}
+
+// SafePrime returns a number of the given bit length that is a safe prime with high probability.
+// The number returned p=2*q+1 is a safe prime if both p and q are primes.
+// SafePrime will return error for any error returned by rand.Read or if bits < 2.
+func SafePrime(random io.Reader, bits int) (*big.Int, error) {
+ one := big.NewInt(1)
+ p := new(big.Int)
+ for {
+ q, err := rand.Prime(random, bits-1)
+ if err != nil {
+ return nil, err
+ }
+ p.Lsh(q, 1).Add(p, one)
+ if p.ProbablyPrime(20) {
+ return p, nil
+ }
+ }
+}
diff --git a/vendor/github.com/cloudflare/circl/math/wnaf.go b/vendor/github.com/cloudflare/circl/math/wnaf.go
new file mode 100644
index 0000000000..94a1ec5042
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/math/wnaf.go
@@ -0,0 +1,84 @@
+// Package math provides some utility functions for big integers.
+package math
+
+import "math/big"
+
+// SignedDigit obtains the signed-digit recoding of n and returns a list L of
+// digits such that n = sum( L[i]*2^(i*(w-1)) ), and each L[i] is an odd number
+// in the set {±1, ±3, ..., ±2^(w-1)-1}. The third parameter ensures that the
+// output has ceil(l/(w-1)) digits.
+//
+// Restrictions:
+// - n is odd and n > 0.
+// - 1 < w < 32.
+// - l >= bit length of n.
+//
+// References:
+// - Alg.6 in "Exponent Recoding and Regular Exponentiation Algorithms"
+// by Joye-Tunstall. http://doi.org/10.1007/978-3-642-02384-2_21
+// - Alg.6 in "Selecting Elliptic Curves for Cryptography: An Efficiency and
+// Security Analysis" by Bos et al. http://doi.org/10.1007/s13389-015-0097-y
+func SignedDigit(n *big.Int, w, l uint) []int32 {
+ if n.Sign() <= 0 || n.Bit(0) == 0 {
+ panic("n must be non-zero, odd, and positive")
+ }
+ if w <= 1 || w >= 32 {
+ panic("Verify that 1 < w < 32")
+ }
+ if uint(n.BitLen()) > l {
+ panic("n is too big to fit in l digits")
+ }
+ lenN := (l + (w - 1) - 1) / (w - 1) // ceil(l/(w-1))
+ L := make([]int32, lenN+1)
+ var k, v big.Int
+ k.Set(n)
+
+ var i uint
+ for i = 0; i < lenN; i++ {
+ words := k.Bits()
+ value := int32(words[0] & ((1 << w) - 1))
+ value -= int32(1) << (w - 1)
+ L[i] = value
+ v.SetInt64(int64(value))
+ k.Sub(&k, &v)
+ k.Rsh(&k, w-1)
+ }
+ L[i] = int32(k.Int64())
+ return L
+}
+
+// OmegaNAF obtains the window-w Non-Adjacent Form of a positive number n and
+// 1 < w < 32. The returned slice L holds n = sum( L[i]*2^i ).
+//
+// Reference:
+// - Alg.9 "Efficient arithmetic on Koblitz curves" by Solinas.
+// http://doi.org/10.1023/A:1008306223194
+func OmegaNAF(n *big.Int, w uint) (L []int32) {
+ if n.Sign() < 0 {
+ panic("n must be positive")
+ }
+ if w <= 1 || w >= 32 {
+ panic("Verify that 1 < w < 32")
+ }
+
+ L = make([]int32, n.BitLen()+1)
+ var k, v big.Int
+ k.Set(n)
+
+ i := 0
+ for ; k.Sign() > 0; i++ {
+ value := int32(0)
+ if k.Bit(0) == 1 {
+ words := k.Bits()
+ value = int32(words[0] & ((1 << w) - 1))
+ if value >= (int32(1) << (w - 1)) {
+ value -= int32(1) << w
+ }
+ v.SetInt64(int64(value))
+ k.Sub(&k, &v)
+ }
+ L[i] = value
+ k.Rsh(&k, 1)
+ }
+ return L[:i]
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go
new file mode 100644
index 0000000000..2c73c26fb1
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go
@@ -0,0 +1,453 @@
+// Package ed25519 implements Ed25519 signature scheme as described in RFC-8032.
+//
+// This package provides optimized implementations of the three signature
+// variants and maintaining closer compatibility with crypto/ed25519.
+//
+// | Scheme Name | Sign Function | Verification | Context |
+// |-------------|-------------------|---------------|-------------------|
+// | Ed25519 | Sign | Verify | None |
+// | Ed25519Ph | SignPh | VerifyPh | Yes, can be empty |
+// | Ed25519Ctx | SignWithCtx | VerifyWithCtx | Yes, non-empty |
+// | All above | (PrivateKey).Sign | VerifyAny | As above |
+//
+// Specific functions for sign and verify are defined. A generic signing
+// function for all schemes is available through the crypto.Signer interface,
+// which is implemented by the PrivateKey type. A correspond all-in-one
+// verification method is provided by the VerifyAny function.
+//
+// Signing with Ed25519Ph or Ed25519Ctx requires a context string for domain
+// separation. This parameter is passed using a SignerOptions struct defined
+// in this package. While Ed25519Ph accepts an empty context, Ed25519Ctx
+// enforces non-empty context strings.
+//
+// # Compatibility with crypto.ed25519
+//
+// These functions are compatible with the “Ed25519” function defined in
+// RFC-8032. However, unlike RFC 8032's formulation, this package's private
+// key representation includes a public key suffix to make multiple signing
+// operations with the same key more efficient. This package refers to the
+// RFC-8032 private key as the “seed”.
+//
+// References
+//
+// - RFC-8032: https://rfc-editor.org/rfc/rfc8032.txt
+// - Ed25519: https://ed25519.cr.yp.to/
+// - EdDSA: High-speed high-security signatures. https://doi.org/10.1007/s13389-012-0027-1
+package ed25519
+
+import (
+ "bytes"
+ "crypto"
+ cryptoRand "crypto/rand"
+ "crypto/sha512"
+ "crypto/subtle"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+
+ "github.com/cloudflare/circl/sign"
+)
+
+const (
+ // ContextMaxSize is the maximum length (in bytes) allowed for context.
+ ContextMaxSize = 255
+ // PublicKeySize is the size, in bytes, of public keys as used in this package.
+ PublicKeySize = 32
+ // PrivateKeySize is the size, in bytes, of private keys as used in this package.
+ PrivateKeySize = 64
+ // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
+ SignatureSize = 64
+ // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
+ SeedSize = 32
+)
+
+const (
+ paramB = 256 / 8 // Size of keys in bytes.
+)
+
+// SignerOptions implements crypto.SignerOpts and augments with parameters
+// that are specific to the Ed25519 signature schemes.
+type SignerOptions struct {
+ // Hash must be crypto.Hash(0) for Ed25519/Ed25519ctx, or crypto.SHA512
+ // for Ed25519ph.
+ crypto.Hash
+
+ // Context is an optional domain separation string for Ed25519ph and a
+ // must for Ed25519ctx. Its length must be less or equal than 255 bytes.
+ Context string
+
+ // Scheme is an identifier for choosing a signature scheme. The zero value
+ // is ED25519.
+ Scheme SchemeID
+}
+
+// SchemeID is an identifier for each signature scheme.
+type SchemeID uint
+
+const (
+ ED25519 SchemeID = iota
+ ED25519Ph
+ ED25519Ctx
+)
+
+// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
+type PrivateKey []byte
+
+// Equal reports whether priv and x have the same value.
+func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(PrivateKey)
+ return ok && subtle.ConstantTimeCompare(priv, xx) == 1
+}
+
+// Public returns the PublicKey corresponding to priv.
+func (priv PrivateKey) Public() crypto.PublicKey {
+ publicKey := make(PublicKey, PublicKeySize)
+ copy(publicKey, priv[SeedSize:])
+ return publicKey
+}
+
+// Seed returns the private key seed corresponding to priv. It is provided for
+// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
+// in this package.
+func (priv PrivateKey) Seed() []byte {
+ seed := make([]byte, SeedSize)
+ copy(seed, priv[:SeedSize])
+ return seed
+}
+
+func (priv PrivateKey) Scheme() sign.Scheme { return sch }
+
+func (pub PublicKey) Scheme() sign.Scheme { return sch }
+
+func (priv PrivateKey) MarshalBinary() (data []byte, err error) {
+ privateKey := make(PrivateKey, PrivateKeySize)
+ copy(privateKey, priv)
+ return privateKey, nil
+}
+
+func (pub PublicKey) MarshalBinary() (data []byte, err error) {
+ publicKey := make(PublicKey, PublicKeySize)
+ copy(publicKey, pub)
+ return publicKey, nil
+}
+
+// Equal reports whether pub and x have the same value.
+func (pub PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(PublicKey)
+ return ok && bytes.Equal(pub, xx)
+}
+
+// Sign creates a signature of a message with priv key.
+// This function is compatible with crypto.ed25519 and also supports the
+// three signature variants defined in RFC-8032, namely Ed25519 (or pure
+// EdDSA), Ed25519Ph, and Ed25519Ctx.
+// The opts.HashFunc() must return zero to specify either Ed25519 or Ed25519Ctx
+// variant. This can be achieved by passing crypto.Hash(0) as the value for
+// opts.
+// The opts.HashFunc() must return SHA512 to specify the Ed25519Ph variant.
+// This can be achieved by passing crypto.SHA512 as the value for opts.
+// Use a SignerOptions struct (defined in this package) to pass a context
+// string for signing.
+func (priv PrivateKey) Sign(
+ rand io.Reader,
+ message []byte,
+ opts crypto.SignerOpts,
+) (signature []byte, err error) {
+ var ctx string
+ var scheme SchemeID
+ if o, ok := opts.(SignerOptions); ok {
+ ctx = o.Context
+ scheme = o.Scheme
+ }
+
+ switch true {
+ case scheme == ED25519 && opts.HashFunc() == crypto.Hash(0):
+ return Sign(priv, message), nil
+ case scheme == ED25519Ph && opts.HashFunc() == crypto.SHA512:
+ return SignPh(priv, message, ctx), nil
+ case scheme == ED25519Ctx && opts.HashFunc() == crypto.Hash(0) && len(ctx) > 0:
+ return SignWithCtx(priv, message, ctx), nil
+ default:
+ return nil, errors.New("ed25519: bad hash algorithm")
+ }
+}
+
+// GenerateKey generates a public/private key pair using entropy from rand.
+// If rand is nil, crypto/rand.Reader will be used.
+func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
+ if rand == nil {
+ rand = cryptoRand.Reader
+ }
+
+ seed := make([]byte, SeedSize)
+ if _, err := io.ReadFull(rand, seed); err != nil {
+ return nil, nil, err
+ }
+
+ privateKey := NewKeyFromSeed(seed)
+ publicKey := make(PublicKey, PublicKeySize)
+ copy(publicKey, privateKey[SeedSize:])
+
+ return publicKey, privateKey, nil
+}
+
+// NewKeyFromSeed calculates a private key from a seed. It will panic if
+// len(seed) is not SeedSize. This function is provided for interoperability
+// with RFC 8032. RFC 8032's private keys correspond to seeds in this
+// package.
+func NewKeyFromSeed(seed []byte) PrivateKey {
+ privateKey := make(PrivateKey, PrivateKeySize)
+ newKeyFromSeed(privateKey, seed)
+ return privateKey
+}
+
+func newKeyFromSeed(privateKey, seed []byte) {
+ if l := len(seed); l != SeedSize {
+ panic("ed25519: bad seed length: " + strconv.Itoa(l))
+ }
+ var P pointR1
+ k := sha512.Sum512(seed)
+ clamp(k[:])
+ reduceModOrder(k[:paramB], false)
+ P.fixedMult(k[:paramB])
+ copy(privateKey[:SeedSize], seed)
+ _ = P.ToBytes(privateKey[SeedSize:])
+}
+
+func signAll(signature []byte, privateKey PrivateKey, message, ctx []byte, preHash bool) {
+ if l := len(privateKey); l != PrivateKeySize {
+ panic("ed25519: bad private key length: " + strconv.Itoa(l))
+ }
+
+ H := sha512.New()
+ var PHM []byte
+
+ if preHash {
+ _, _ = H.Write(message)
+ PHM = H.Sum(nil)
+ H.Reset()
+ } else {
+ PHM = message
+ }
+
+ // 1. Hash the 32-byte private key using SHA-512.
+ _, _ = H.Write(privateKey[:SeedSize])
+ h := H.Sum(nil)
+ clamp(h[:])
+ prefix, s := h[paramB:], h[:paramB]
+
+ // 2. Compute SHA-512(dom2(F, C) || prefix || PH(M))
+ H.Reset()
+
+ writeDom(H, ctx, preHash)
+
+ _, _ = H.Write(prefix)
+ _, _ = H.Write(PHM)
+ r := H.Sum(nil)
+ reduceModOrder(r[:], true)
+
+ // 3. Compute the point [r]B.
+ var P pointR1
+ P.fixedMult(r[:paramB])
+ R := (&[paramB]byte{})[:]
+ if err := P.ToBytes(R); err != nil {
+ panic(err)
+ }
+
+ // 4. Compute SHA512(dom2(F, C) || R || A || PH(M)).
+ H.Reset()
+
+ writeDom(H, ctx, preHash)
+
+ _, _ = H.Write(R)
+ _, _ = H.Write(privateKey[SeedSize:])
+ _, _ = H.Write(PHM)
+ hRAM := H.Sum(nil)
+
+ reduceModOrder(hRAM[:], true)
+
+ // 5. Compute S = (r + k * s) mod order.
+ S := (&[paramB]byte{})[:]
+ calculateS(S, r[:paramB], hRAM[:paramB], s)
+
+ // 6. The signature is the concatenation of R and S.
+ copy(signature[:paramB], R[:])
+ copy(signature[paramB:], S[:])
+}
+
+// Sign signs the message with privateKey and returns a signature.
+// This function supports the signature variant defined in RFC-8032: Ed25519,
+// also known as the pure version of EdDSA.
+// It will panic if len(privateKey) is not PrivateKeySize.
+func Sign(privateKey PrivateKey, message []byte) []byte {
+ signature := make([]byte, SignatureSize)
+ signAll(signature, privateKey, message, []byte(""), false)
+ return signature
+}
+
+// SignPh creates a signature of a message with private key and context.
+// This function supports the signature variant defined in RFC-8032: Ed25519ph,
+// meaning it internally hashes the message using SHA-512, and optionally
+// accepts a context string.
+// It will panic if len(privateKey) is not PrivateKeySize.
+// Context could be passed to this function, which length should be no more than
+// ContextMaxSize=255. It can be empty.
+func SignPh(privateKey PrivateKey, message []byte, ctx string) []byte {
+ if len(ctx) > ContextMaxSize {
+ panic(fmt.Errorf("ed25519: bad context length: %v", len(ctx)))
+ }
+
+ signature := make([]byte, SignatureSize)
+ signAll(signature, privateKey, message, []byte(ctx), true)
+ return signature
+}
+
+// SignWithCtx creates a signature of a message with private key and context.
+// This function supports the signature variant defined in RFC-8032: Ed25519ctx,
+// meaning it accepts a non-empty context string.
+// It will panic if len(privateKey) is not PrivateKeySize.
+// Context must be passed to this function, which length should be no more than
+// ContextMaxSize=255 and cannot be empty.
+func SignWithCtx(privateKey PrivateKey, message []byte, ctx string) []byte {
+ if len(ctx) == 0 || len(ctx) > ContextMaxSize {
+ panic(fmt.Errorf("ed25519: bad context length: %v > %v", len(ctx), ContextMaxSize))
+ }
+
+ signature := make([]byte, SignatureSize)
+ signAll(signature, privateKey, message, []byte(ctx), false)
+ return signature
+}
+
+func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool {
+ if len(public) != PublicKeySize ||
+ len(signature) != SignatureSize ||
+ !isLessThanOrder(signature[paramB:]) {
+ return false
+ }
+
+ var P pointR1
+ if ok := P.FromBytes(public); !ok {
+ return false
+ }
+
+ H := sha512.New()
+ var PHM []byte
+
+ if preHash {
+ _, _ = H.Write(message)
+ PHM = H.Sum(nil)
+ H.Reset()
+ } else {
+ PHM = message
+ }
+
+ R := signature[:paramB]
+
+ writeDom(H, ctx, preHash)
+
+ _, _ = H.Write(R)
+ _, _ = H.Write(public)
+ _, _ = H.Write(PHM)
+ hRAM := H.Sum(nil)
+ reduceModOrder(hRAM[:], true)
+
+ var Q pointR1
+ encR := (&[paramB]byte{})[:]
+ P.neg()
+ Q.doubleMult(&P, signature[paramB:], hRAM[:paramB])
+ _ = Q.ToBytes(encR)
+ return bytes.Equal(R, encR)
+}
+
+// VerifyAny returns true if the signature is valid. Failure cases are invalid
+// signature, or when the public key cannot be decoded.
+// This function supports all the three signature variants defined in RFC-8032,
+// namely Ed25519 (or pure EdDSA), Ed25519Ph, and Ed25519Ctx.
+// The opts.HashFunc() must return zero to specify either Ed25519 or Ed25519Ctx
+// variant. This can be achieved by passing crypto.Hash(0) as the value for opts.
+// The opts.HashFunc() must return SHA512 to specify the Ed25519Ph variant.
+// This can be achieved by passing crypto.SHA512 as the value for opts.
+// Use a SignerOptions struct to pass a context string for signing.
+func VerifyAny(public PublicKey, message, signature []byte, opts crypto.SignerOpts) bool {
+ var ctx string
+ var scheme SchemeID
+ if o, ok := opts.(SignerOptions); ok {
+ ctx = o.Context
+ scheme = o.Scheme
+ }
+
+ switch true {
+ case scheme == ED25519 && opts.HashFunc() == crypto.Hash(0):
+ return Verify(public, message, signature)
+ case scheme == ED25519Ph && opts.HashFunc() == crypto.SHA512:
+ return VerifyPh(public, message, signature, ctx)
+ case scheme == ED25519Ctx && opts.HashFunc() == crypto.Hash(0) && len(ctx) > 0:
+ return VerifyWithCtx(public, message, signature, ctx)
+ default:
+ return false
+ }
+}
+
+// Verify returns true if the signature is valid. Failure cases are invalid
+// signature, or when the public key cannot be decoded.
+// This function supports the signature variant defined in RFC-8032: Ed25519,
+// also known as the pure version of EdDSA.
+func Verify(public PublicKey, message, signature []byte) bool {
+ return verify(public, message, signature, []byte(""), false)
+}
+
+// VerifyPh returns true if the signature is valid. Failure cases are invalid
+// signature, or when the public key cannot be decoded.
+// This function supports the signature variant defined in RFC-8032: Ed25519ph,
+// meaning it internally hashes the message using SHA-512.
+// Context could be passed to this function, which length should be no more than
+// 255. It can be empty.
+func VerifyPh(public PublicKey, message, signature []byte, ctx string) bool {
+ return verify(public, message, signature, []byte(ctx), true)
+}
+
+// VerifyWithCtx returns true if the signature is valid. Failure cases are invalid
+// signature, or when the public key cannot be decoded, or when context is
+// not provided.
+// This function supports the signature variant defined in RFC-8032: Ed25519ctx,
+// meaning it does not handle prehashed messages. Non-empty context string must be
+// provided, and must not be more than 255 of length.
+func VerifyWithCtx(public PublicKey, message, signature []byte, ctx string) bool {
+ if len(ctx) == 0 || len(ctx) > ContextMaxSize {
+ return false
+ }
+
+ return verify(public, message, signature, []byte(ctx), false)
+}
+
+func clamp(k []byte) {
+ k[0] &= 248
+ k[paramB-1] = (k[paramB-1] & 127) | 64
+}
+
+// isLessThanOrder returns true if 0 <= x < order.
+func isLessThanOrder(x []byte) bool {
+ i := len(order) - 1
+ for i > 0 && x[i] == order[i] {
+ i--
+ }
+ return x[i] < order[i]
+}
+
+func writeDom(h io.Writer, ctx []byte, preHash bool) {
+ dom2 := "SigEd25519 no Ed25519 collisions"
+
+ if len(ctx) > 0 {
+ _, _ = h.Write([]byte(dom2))
+ if preHash {
+ _, _ = h.Write([]byte{byte(0x01), byte(len(ctx))})
+ } else {
+ _, _ = h.Write([]byte{byte(0x00), byte(len(ctx))})
+ }
+ _, _ = h.Write(ctx)
+ } else if preHash {
+ _, _ = h.Write([]byte(dom2))
+ _, _ = h.Write([]byte{0x01, 0x00})
+ }
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/modular.go b/vendor/github.com/cloudflare/circl/sign/ed25519/modular.go
new file mode 100644
index 0000000000..10efafdcaf
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/modular.go
@@ -0,0 +1,175 @@
+package ed25519
+
+import (
+ "encoding/binary"
+ "math/bits"
+)
+
+var order = [paramB]byte{
+ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+ 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+}
+
+// isLessThan returns true if 0 <= x < y, and assumes that slices have the same length.
+func isLessThan(x, y []byte) bool {
+ i := len(x) - 1
+ for i > 0 && x[i] == y[i] {
+ i--
+ }
+ return x[i] < y[i]
+}
+
+// reduceModOrder calculates k = k mod order of the curve.
+func reduceModOrder(k []byte, is512Bit bool) {
+ var X [((2 * paramB) * 8) / 64]uint64
+ numWords := len(k) >> 3
+ for i := 0; i < numWords; i++ {
+ X[i] = binary.LittleEndian.Uint64(k[i*8 : (i+1)*8])
+ }
+ red512(&X, is512Bit)
+ for i := 0; i < numWords; i++ {
+ binary.LittleEndian.PutUint64(k[i*8:(i+1)*8], X[i])
+ }
+}
+
+// red512 calculates x = x mod Order of the curve.
+func red512(x *[8]uint64, full bool) {
+ // Implementation of Algs.(14.47)+(14.52) of Handbook of Applied
+ // Cryptography, by A. Menezes, P. van Oorschot, and S. Vanstone.
+ const (
+ ell0 = uint64(0x5812631a5cf5d3ed)
+ ell1 = uint64(0x14def9dea2f79cd6)
+ ell160 = uint64(0x812631a5cf5d3ed0)
+ ell161 = uint64(0x4def9dea2f79cd65)
+ ell162 = uint64(0x0000000000000001)
+ )
+
+ var c0, c1, c2, c3 uint64
+ r0, r1, r2, r3, r4 := x[0], x[1], x[2], x[3], uint64(0)
+
+ if full {
+ q0, q1, q2, q3 := x[4], x[5], x[6], x[7]
+
+ for i := 0; i < 3; i++ {
+ h0, s0 := bits.Mul64(q0, ell160)
+ h1, s1 := bits.Mul64(q1, ell160)
+ h2, s2 := bits.Mul64(q2, ell160)
+ h3, s3 := bits.Mul64(q3, ell160)
+
+ s1, c0 = bits.Add64(h0, s1, 0)
+ s2, c1 = bits.Add64(h1, s2, c0)
+ s3, c2 = bits.Add64(h2, s3, c1)
+ s4, _ := bits.Add64(h3, 0, c2)
+
+ h0, l0 := bits.Mul64(q0, ell161)
+ h1, l1 := bits.Mul64(q1, ell161)
+ h2, l2 := bits.Mul64(q2, ell161)
+ h3, l3 := bits.Mul64(q3, ell161)
+
+ l1, c0 = bits.Add64(h0, l1, 0)
+ l2, c1 = bits.Add64(h1, l2, c0)
+ l3, c2 = bits.Add64(h2, l3, c1)
+ l4, _ := bits.Add64(h3, 0, c2)
+
+ s1, c0 = bits.Add64(s1, l0, 0)
+ s2, c1 = bits.Add64(s2, l1, c0)
+ s3, c2 = bits.Add64(s3, l2, c1)
+ s4, c3 = bits.Add64(s4, l3, c2)
+ s5, s6 := bits.Add64(l4, 0, c3)
+
+ s2, c0 = bits.Add64(s2, q0, 0)
+ s3, c1 = bits.Add64(s3, q1, c0)
+ s4, c2 = bits.Add64(s4, q2, c1)
+ s5, c3 = bits.Add64(s5, q3, c2)
+ s6, s7 := bits.Add64(s6, 0, c3)
+
+ q := q0 | q1 | q2 | q3
+ m := -((q | -q) >> 63) // if q=0 then m=0...0 else m=1..1
+ s0 &= m
+ s1 &= m
+ s2 &= m
+ s3 &= m
+ q0, q1, q2, q3 = s4, s5, s6, s7
+
+ if (i+1)%2 == 0 {
+ r0, c0 = bits.Add64(r0, s0, 0)
+ r1, c1 = bits.Add64(r1, s1, c0)
+ r2, c2 = bits.Add64(r2, s2, c1)
+ r3, c3 = bits.Add64(r3, s3, c2)
+ r4, _ = bits.Add64(r4, 0, c3)
+ } else {
+ r0, c0 = bits.Sub64(r0, s0, 0)
+ r1, c1 = bits.Sub64(r1, s1, c0)
+ r2, c2 = bits.Sub64(r2, s2, c1)
+ r3, c3 = bits.Sub64(r3, s3, c2)
+ r4, _ = bits.Sub64(r4, 0, c3)
+ }
+ }
+
+ m := -(r4 >> 63)
+ r0, c0 = bits.Add64(r0, m&ell160, 0)
+ r1, c1 = bits.Add64(r1, m&ell161, c0)
+ r2, c2 = bits.Add64(r2, m&ell162, c1)
+ r3, c3 = bits.Add64(r3, 0, c2)
+ r4, _ = bits.Add64(r4, m&1, c3)
+ x[4], x[5], x[6], x[7] = 0, 0, 0, 0
+ }
+
+ q0 := (r4 << 4) | (r3 >> 60)
+ r3 &= (uint64(1) << 60) - 1
+
+ h0, s0 := bits.Mul64(ell0, q0)
+ h1, s1 := bits.Mul64(ell1, q0)
+ s1, c0 = bits.Add64(h0, s1, 0)
+ s2, _ := bits.Add64(h1, 0, c0)
+
+ r0, c0 = bits.Sub64(r0, s0, 0)
+ r1, c1 = bits.Sub64(r1, s1, c0)
+ r2, c2 = bits.Sub64(r2, s2, c1)
+ r3, _ = bits.Sub64(r3, 0, c2)
+
+ x[0], x[1], x[2], x[3] = r0, r1, r2, r3
+}
+
+// calculateS performs s = r+k*a mod Order of the curve.
+func calculateS(s, r, k, a []byte) {
+ K := [4]uint64{
+ binary.LittleEndian.Uint64(k[0*8 : 1*8]),
+ binary.LittleEndian.Uint64(k[1*8 : 2*8]),
+ binary.LittleEndian.Uint64(k[2*8 : 3*8]),
+ binary.LittleEndian.Uint64(k[3*8 : 4*8]),
+ }
+ S := [8]uint64{
+ binary.LittleEndian.Uint64(r[0*8 : 1*8]),
+ binary.LittleEndian.Uint64(r[1*8 : 2*8]),
+ binary.LittleEndian.Uint64(r[2*8 : 3*8]),
+ binary.LittleEndian.Uint64(r[3*8 : 4*8]),
+ }
+ var c3 uint64
+ for i := range K {
+ ai := binary.LittleEndian.Uint64(a[i*8 : (i+1)*8])
+
+ h0, l0 := bits.Mul64(K[0], ai)
+ h1, l1 := bits.Mul64(K[1], ai)
+ h2, l2 := bits.Mul64(K[2], ai)
+ h3, l3 := bits.Mul64(K[3], ai)
+
+ l1, c0 := bits.Add64(h0, l1, 0)
+ l2, c1 := bits.Add64(h1, l2, c0)
+ l3, c2 := bits.Add64(h2, l3, c1)
+ l4, _ := bits.Add64(h3, 0, c2)
+
+ S[i+0], c0 = bits.Add64(S[i+0], l0, 0)
+ S[i+1], c1 = bits.Add64(S[i+1], l1, c0)
+ S[i+2], c2 = bits.Add64(S[i+2], l2, c1)
+ S[i+3], c3 = bits.Add64(S[i+3], l3, c2)
+ S[i+4], _ = bits.Add64(S[i+4], l4, c3)
+ }
+ red512(&S, true)
+ binary.LittleEndian.PutUint64(s[0*8:1*8], S[0])
+ binary.LittleEndian.PutUint64(s[1*8:2*8], S[1])
+ binary.LittleEndian.PutUint64(s[2*8:3*8], S[2])
+ binary.LittleEndian.PutUint64(s[3*8:4*8], S[3])
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/mult.go b/vendor/github.com/cloudflare/circl/sign/ed25519/mult.go
new file mode 100644
index 0000000000..3216aae303
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/mult.go
@@ -0,0 +1,180 @@
+package ed25519
+
+import (
+ "crypto/subtle"
+ "encoding/binary"
+ "math/bits"
+
+ "github.com/cloudflare/circl/internal/conv"
+ "github.com/cloudflare/circl/math"
+ fp "github.com/cloudflare/circl/math/fp25519"
+)
+
+var paramD = fp.Elt{
+ 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
+ 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
+ 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
+ 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52,
+}
+
+// mLSBRecoding parameters.
+const (
+ fxT = 257
+ fxV = 2
+ fxW = 3
+ fx2w1 = 1 << (uint(fxW) - 1)
+ numWords64 = (paramB * 8 / 64)
+)
+
+// mLSBRecoding is the odd-only modified LSB-set.
+//
+// Reference:
+//
+// "Efficient and secure algorithms for GLV-based scalar multiplication and
+// their implementation on GLV–GLS curves" by (Faz-Hernandez et al.)
+// http://doi.org/10.1007/s13389-014-0085-7.
+func mLSBRecoding(L []int8, k []byte) {
+ const ee = (fxT + fxW*fxV - 1) / (fxW * fxV)
+ const dd = ee * fxV
+ const ll = dd * fxW
+ if len(L) == (ll + 1) {
+ var m [numWords64 + 1]uint64
+ for i := 0; i < numWords64; i++ {
+ m[i] = binary.LittleEndian.Uint64(k[8*i : 8*i+8])
+ }
+ condAddOrderN(&m)
+ L[dd-1] = 1
+ for i := 0; i < dd-1; i++ {
+ kip1 := (m[(i+1)/64] >> (uint(i+1) % 64)) & 0x1
+ L[i] = int8(kip1<<1) - 1
+ }
+ { // right-shift by d
+ right := uint(dd % 64)
+ left := uint(64) - right
+ lim := ((numWords64+1)*64 - dd) / 64
+ j := dd / 64
+ for i := 0; i < lim; i++ {
+ m[i] = (m[i+j] >> right) | (m[i+j+1] << left)
+ }
+ m[lim] = m[lim+j] >> right
+ }
+ for i := dd; i < ll; i++ {
+ L[i] = L[i%dd] * int8(m[0]&0x1)
+ div2subY(m[:], int64(L[i]>>1), numWords64)
+ }
+ L[ll] = int8(m[0])
+ }
+}
+
+// absolute returns always a positive value.
+func absolute(x int32) int32 {
+ mask := x >> 31
+ return (x + mask) ^ mask
+}
+
+// condAddOrderN updates x = x+order if x is even, otherwise x remains unchanged.
+func condAddOrderN(x *[numWords64 + 1]uint64) {
+ isOdd := (x[0] & 0x1) - 1
+ c := uint64(0)
+ for i := 0; i < numWords64; i++ {
+ orderWord := binary.LittleEndian.Uint64(order[8*i : 8*i+8])
+ o := isOdd & orderWord
+ x0, c0 := bits.Add64(x[i], o, c)
+ x[i] = x0
+ c = c0
+ }
+ x[numWords64], _ = bits.Add64(x[numWords64], 0, c)
+}
+
+// div2subY update x = (x/2) - y.
+func div2subY(x []uint64, y int64, l int) {
+ s := uint64(y >> 63)
+ for i := 0; i < l-1; i++ {
+ x[i] = (x[i] >> 1) | (x[i+1] << 63)
+ }
+ x[l-1] = (x[l-1] >> 1)
+
+ b := uint64(0)
+ x0, b0 := bits.Sub64(x[0], uint64(y), b)
+ x[0] = x0
+ b = b0
+ for i := 1; i < l-1; i++ {
+ x0, b0 := bits.Sub64(x[i], s, b)
+ x[i] = x0
+ b = b0
+ }
+ x[l-1], _ = bits.Sub64(x[l-1], s, b)
+}
+
+func (P *pointR1) fixedMult(scalar []byte) {
+ if len(scalar) != paramB {
+ panic("wrong scalar size")
+ }
+ const ee = (fxT + fxW*fxV - 1) / (fxW * fxV)
+ const dd = ee * fxV
+ const ll = dd * fxW
+
+ L := make([]int8, ll+1)
+ mLSBRecoding(L[:], scalar)
+ S := &pointR3{}
+ P.SetIdentity()
+ for ii := ee - 1; ii >= 0; ii-- {
+ P.double()
+ for j := 0; j < fxV; j++ {
+ dig := L[fxW*dd-j*ee+ii-ee]
+ for i := (fxW-1)*dd - j*ee + ii - ee; i >= (2*dd - j*ee + ii - ee); i = i - dd {
+ dig = 2*dig + L[i]
+ }
+ idx := absolute(int32(dig))
+ sig := L[dd-j*ee+ii-ee]
+ Tabj := &tabSign[fxV-j-1]
+ for k := 0; k < fx2w1; k++ {
+ S.cmov(&Tabj[k], subtle.ConstantTimeEq(int32(k), idx))
+ }
+ S.cneg(subtle.ConstantTimeEq(int32(sig), -1))
+ P.mixAdd(S)
+ }
+ }
+}
+
+const (
+ omegaFix = 7
+ omegaVar = 5
+)
+
+// doubleMult returns P=mG+nQ.
+func (P *pointR1) doubleMult(Q *pointR1, m, n []byte) {
+ nafFix := math.OmegaNAF(conv.BytesLe2BigInt(m), omegaFix)
+ nafVar := math.OmegaNAF(conv.BytesLe2BigInt(n), omegaVar)
+
+ if len(nafFix) > len(nafVar) {
+ nafVar = append(nafVar, make([]int32, len(nafFix)-len(nafVar))...)
+ } else if len(nafFix) < len(nafVar) {
+ nafFix = append(nafFix, make([]int32, len(nafVar)-len(nafFix))...)
+ }
+
+ var TabQ [1 << (omegaVar - 2)]pointR2
+ Q.oddMultiples(TabQ[:])
+ P.SetIdentity()
+ for i := len(nafFix) - 1; i >= 0; i-- {
+ P.double()
+ // Generator point
+ if nafFix[i] != 0 {
+ idxM := absolute(nafFix[i]) >> 1
+ R := tabVerif[idxM]
+ if nafFix[i] < 0 {
+ R.neg()
+ }
+ P.mixAdd(&R)
+ }
+ // Variable input point
+ if nafVar[i] != 0 {
+ idxN := absolute(nafVar[i]) >> 1
+ S := TabQ[idxN]
+ if nafVar[i] < 0 {
+ S.neg()
+ }
+ P.add(&S)
+ }
+ }
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/point.go b/vendor/github.com/cloudflare/circl/sign/ed25519/point.go
new file mode 100644
index 0000000000..d1c3b146b7
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/point.go
@@ -0,0 +1,195 @@
+package ed25519
+
+import fp "github.com/cloudflare/circl/math/fp25519"
+
+type (
+ pointR1 struct{ x, y, z, ta, tb fp.Elt }
+ pointR2 struct {
+ pointR3
+ z2 fp.Elt
+ }
+)
+type pointR3 struct{ addYX, subYX, dt2 fp.Elt }
+
+func (P *pointR1) neg() {
+ fp.Neg(&P.x, &P.x)
+ fp.Neg(&P.ta, &P.ta)
+}
+
+func (P *pointR1) SetIdentity() {
+ P.x = fp.Elt{}
+ fp.SetOne(&P.y)
+ fp.SetOne(&P.z)
+ P.ta = fp.Elt{}
+ P.tb = fp.Elt{}
+}
+
+func (P *pointR1) toAffine() {
+ fp.Inv(&P.z, &P.z)
+ fp.Mul(&P.x, &P.x, &P.z)
+ fp.Mul(&P.y, &P.y, &P.z)
+ fp.Modp(&P.x)
+ fp.Modp(&P.y)
+ fp.SetOne(&P.z)
+ P.ta = P.x
+ P.tb = P.y
+}
+
+func (P *pointR1) ToBytes(k []byte) error {
+ P.toAffine()
+ var x [fp.Size]byte
+ err := fp.ToBytes(k[:fp.Size], &P.y)
+ if err != nil {
+ return err
+ }
+ err = fp.ToBytes(x[:], &P.x)
+ if err != nil {
+ return err
+ }
+ b := x[0] & 1
+ k[paramB-1] = k[paramB-1] | (b << 7)
+ return nil
+}
+
+func (P *pointR1) FromBytes(k []byte) bool {
+ if len(k) != paramB {
+ panic("wrong size")
+ }
+ signX := k[paramB-1] >> 7
+ copy(P.y[:], k[:fp.Size])
+ P.y[fp.Size-1] &= 0x7F
+ p := fp.P()
+ if !isLessThan(P.y[:], p[:]) {
+ return false
+ }
+
+ one, u, v := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
+ fp.SetOne(one)
+ fp.Sqr(u, &P.y) // u = y^2
+ fp.Mul(v, u, ¶mD) // v = dy^2
+ fp.Sub(u, u, one) // u = y^2-1
+ fp.Add(v, v, one) // v = dy^2+1
+ isQR := fp.InvSqrt(&P.x, u, v) // x = sqrt(u/v)
+ if !isQR {
+ return false
+ }
+ fp.Modp(&P.x) // x = x mod p
+ if fp.IsZero(&P.x) && signX == 1 {
+ return false
+ }
+ if signX != (P.x[0] & 1) {
+ fp.Neg(&P.x, &P.x)
+ }
+ P.ta = P.x
+ P.tb = P.y
+ fp.SetOne(&P.z)
+ return true
+}
+
+// double calculates 2P for curves with A=-1.
+func (P *pointR1) double() {
+ Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb
+ a, b, c, e, f, g, h := Px, Py, Pz, Pta, Px, Py, Ptb
+ fp.Add(e, Px, Py) // x+y
+ fp.Sqr(a, Px) // A = x^2
+ fp.Sqr(b, Py) // B = y^2
+ fp.Sqr(c, Pz) // z^2
+ fp.Add(c, c, c) // C = 2*z^2
+ fp.Add(h, a, b) // H = A+B
+ fp.Sqr(e, e) // (x+y)^2
+ fp.Sub(e, e, h) // E = (x+y)^2-A-B
+ fp.Sub(g, b, a) // G = B-A
+ fp.Sub(f, c, g) // F = C-G
+ fp.Mul(Pz, f, g) // Z = F * G
+ fp.Mul(Px, e, f) // X = E * F
+ fp.Mul(Py, g, h) // Y = G * H, T = E * H
+}
+
+func (P *pointR1) mixAdd(Q *pointR3) {
+ fp.Add(&P.z, &P.z, &P.z) // D = 2*z1
+ P.coreAddition(Q)
+}
+
+func (P *pointR1) add(Q *pointR2) {
+ fp.Mul(&P.z, &P.z, &Q.z2) // D = 2*z1*z2
+ P.coreAddition(&Q.pointR3)
+}
+
+// coreAddition calculates P=P+Q for curves with A=-1.
+func (P *pointR1) coreAddition(Q *pointR3) {
+ Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb
+ addYX2, subYX2, dt2 := &Q.addYX, &Q.subYX, &Q.dt2
+ a, b, c, d, e, f, g, h := Px, Py, &fp.Elt{}, Pz, Pta, Px, Py, Ptb
+ fp.Mul(c, Pta, Ptb) // t1 = ta*tb
+ fp.Sub(h, Py, Px) // y1-x1
+ fp.Add(b, Py, Px) // y1+x1
+ fp.Mul(a, h, subYX2) // A = (y1-x1)*(y2-x2)
+ fp.Mul(b, b, addYX2) // B = (y1+x1)*(y2+x2)
+ fp.Mul(c, c, dt2) // C = 2*D*t1*t2
+ fp.Sub(e, b, a) // E = B-A
+ fp.Add(h, b, a) // H = B+A
+ fp.Sub(f, d, c) // F = D-C
+ fp.Add(g, d, c) // G = D+C
+ fp.Mul(Pz, f, g) // Z = F * G
+ fp.Mul(Px, e, f) // X = E * F
+ fp.Mul(Py, g, h) // Y = G * H, T = E * H
+}
+
+func (P *pointR1) oddMultiples(T []pointR2) {
+ var R pointR2
+ n := len(T)
+ T[0].fromR1(P)
+ _2P := *P
+ _2P.double()
+ R.fromR1(&_2P)
+ for i := 1; i < n; i++ {
+ P.add(&R)
+ T[i].fromR1(P)
+ }
+}
+
+func (P *pointR1) isEqual(Q *pointR1) bool {
+ l, r := &fp.Elt{}, &fp.Elt{}
+ fp.Mul(l, &P.x, &Q.z)
+ fp.Mul(r, &Q.x, &P.z)
+ fp.Sub(l, l, r)
+ b := fp.IsZero(l)
+ fp.Mul(l, &P.y, &Q.z)
+ fp.Mul(r, &Q.y, &P.z)
+ fp.Sub(l, l, r)
+ b = b && fp.IsZero(l)
+ fp.Mul(l, &P.ta, &P.tb)
+ fp.Mul(l, l, &Q.z)
+ fp.Mul(r, &Q.ta, &Q.tb)
+ fp.Mul(r, r, &P.z)
+ fp.Sub(l, l, r)
+ b = b && fp.IsZero(l)
+ return b && !fp.IsZero(&P.z) && !fp.IsZero(&Q.z)
+}
+
+func (P *pointR3) neg() {
+ P.addYX, P.subYX = P.subYX, P.addYX
+ fp.Neg(&P.dt2, &P.dt2)
+}
+
+func (P *pointR2) fromR1(Q *pointR1) {
+ fp.Add(&P.addYX, &Q.y, &Q.x)
+ fp.Sub(&P.subYX, &Q.y, &Q.x)
+ fp.Mul(&P.dt2, &Q.ta, &Q.tb)
+ fp.Mul(&P.dt2, &P.dt2, ¶mD)
+ fp.Add(&P.dt2, &P.dt2, &P.dt2)
+ fp.Add(&P.z2, &Q.z, &Q.z)
+}
+
+func (P *pointR3) cneg(b int) {
+ t := &fp.Elt{}
+ fp.Cswap(&P.addYX, &P.subYX, uint(b))
+ fp.Neg(t, &P.dt2)
+ fp.Cmov(&P.dt2, t, uint(b))
+}
+
+func (P *pointR3) cmov(Q *pointR3, b int) {
+ fp.Cmov(&P.addYX, &Q.addYX, uint(b))
+ fp.Cmov(&P.subYX, &Q.subYX, uint(b))
+ fp.Cmov(&P.dt2, &Q.dt2, uint(b))
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go
new file mode 100644
index 0000000000..c3505b67ac
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go
@@ -0,0 +1,9 @@
+//go:build go1.13
+// +build go1.13
+
+package ed25519
+
+import cryptoEd25519 "crypto/ed25519"
+
+// PublicKey is the type of Ed25519 public keys.
+type PublicKey cryptoEd25519.PublicKey
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go
new file mode 100644
index 0000000000..d57d86eff0
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go
@@ -0,0 +1,7 @@
+//go:build !go1.13
+// +build !go1.13
+
+package ed25519
+
+// PublicKey is the type of Ed25519 public keys.
+type PublicKey []byte
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go b/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go
new file mode 100644
index 0000000000..e4520f5203
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go
@@ -0,0 +1,87 @@
+package ed25519
+
+import (
+ "crypto/rand"
+ "encoding/asn1"
+
+ "github.com/cloudflare/circl/sign"
+)
+
+var sch sign.Scheme = &scheme{}
+
+// Scheme returns a signature interface.
+func Scheme() sign.Scheme { return sch }
+
+type scheme struct{}
+
+func (*scheme) Name() string { return "Ed25519" }
+func (*scheme) PublicKeySize() int { return PublicKeySize }
+func (*scheme) PrivateKeySize() int { return PrivateKeySize }
+func (*scheme) SignatureSize() int { return SignatureSize }
+func (*scheme) SeedSize() int { return SeedSize }
+func (*scheme) TLSIdentifier() uint { return 0x0807 }
+func (*scheme) SupportsContext() bool { return false }
+func (*scheme) Oid() asn1.ObjectIdentifier {
+ return asn1.ObjectIdentifier{1, 3, 101, 112}
+}
+
+func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) {
+ return GenerateKey(rand.Reader)
+}
+
+func (*scheme) Sign(
+ sk sign.PrivateKey,
+ message []byte,
+ opts *sign.SignatureOpts,
+) []byte {
+ priv, ok := sk.(PrivateKey)
+ if !ok {
+ panic(sign.ErrTypeMismatch)
+ }
+ if opts != nil && opts.Context != "" {
+ panic(sign.ErrContextNotSupported)
+ }
+ return Sign(priv, message)
+}
+
+func (*scheme) Verify(
+ pk sign.PublicKey,
+ message, signature []byte,
+ opts *sign.SignatureOpts,
+) bool {
+ pub, ok := pk.(PublicKey)
+ if !ok {
+ panic(sign.ErrTypeMismatch)
+ }
+ if opts != nil {
+ if opts.Context != "" {
+ panic(sign.ErrContextNotSupported)
+ }
+ }
+ return Verify(pub, message, signature)
+}
+
+func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) {
+ privateKey := NewKeyFromSeed(seed)
+ publicKey := make(PublicKey, PublicKeySize)
+ copy(publicKey, privateKey[SeedSize:])
+ return publicKey, privateKey
+}
+
+func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) {
+ if len(buf) < PublicKeySize {
+ return nil, sign.ErrPubKeySize
+ }
+ pub := make(PublicKey, PublicKeySize)
+ copy(pub, buf[:PublicKeySize])
+ return pub, nil
+}
+
+func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) {
+ if len(buf) < PrivateKeySize {
+ return nil, sign.ErrPrivKeySize
+ }
+ priv := make(PrivateKey, PrivateKeySize)
+ copy(priv, buf[:PrivateKeySize])
+ return priv, nil
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/tables.go b/vendor/github.com/cloudflare/circl/sign/ed25519/tables.go
new file mode 100644
index 0000000000..8763b426fc
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed25519/tables.go
@@ -0,0 +1,213 @@
+package ed25519
+
+import fp "github.com/cloudflare/circl/math/fp25519"
+
+var tabSign = [fxV][fx2w1]pointR3{
+ {
+ pointR3{
+ addYX: fp.Elt{0x85, 0x3b, 0x8c, 0xf5, 0xc6, 0x93, 0xbc, 0x2f, 0x19, 0x0e, 0x8c, 0xfb, 0xc6, 0x2d, 0x93, 0xcf, 0xc2, 0x42, 0x3d, 0x64, 0x98, 0x48, 0x0b, 0x27, 0x65, 0xba, 0xd4, 0x33, 0x3a, 0x9d, 0xcf, 0x07},
+ subYX: fp.Elt{0x3e, 0x91, 0x40, 0xd7, 0x05, 0x39, 0x10, 0x9d, 0xb3, 0xbe, 0x40, 0xd1, 0x05, 0x9f, 0x39, 0xfd, 0x09, 0x8a, 0x8f, 0x68, 0x34, 0x84, 0xc1, 0xa5, 0x67, 0x12, 0xf8, 0x98, 0x92, 0x2f, 0xfd, 0x44},
+ dt2: fp.Elt{0x68, 0xaa, 0x7a, 0x87, 0x05, 0x12, 0xc9, 0xab, 0x9e, 0xc4, 0xaa, 0xcc, 0x23, 0xe8, 0xd9, 0x26, 0x8c, 0x59, 0x43, 0xdd, 0xcb, 0x7d, 0x1b, 0x5a, 0xa8, 0x65, 0x0c, 0x9f, 0x68, 0x7b, 0x11, 0x6f},
+ },
+ {
+ addYX: fp.Elt{0x7c, 0xb0, 0x9e, 0xe6, 0xc5, 0xbf, 0xfa, 0x13, 0x8e, 0x0d, 0x22, 0xde, 0xc8, 0xd1, 0xce, 0x52, 0x02, 0xd5, 0x62, 0x31, 0x71, 0x0e, 0x8e, 0x9d, 0xb0, 0xd6, 0x00, 0xa5, 0x5a, 0x0e, 0xce, 0x72},
+ subYX: fp.Elt{0x1a, 0x8e, 0x5c, 0xdc, 0xa4, 0xb3, 0x6c, 0x51, 0x18, 0xa0, 0x09, 0x80, 0x9a, 0x46, 0x33, 0xd5, 0xe0, 0x3c, 0x4d, 0x3b, 0xfc, 0x49, 0xa2, 0x43, 0x29, 0xe1, 0x29, 0xa9, 0x93, 0xea, 0x7c, 0x35},
+ dt2: fp.Elt{0x08, 0x46, 0x6f, 0x68, 0x7f, 0x0b, 0x7c, 0x9e, 0xad, 0xba, 0x07, 0x61, 0x74, 0x83, 0x2f, 0xfc, 0x26, 0xd6, 0x09, 0xb9, 0x00, 0x34, 0x36, 0x4f, 0x01, 0xf3, 0x48, 0xdb, 0x43, 0xba, 0x04, 0x44},
+ },
+ {
+ addYX: fp.Elt{0x4c, 0xda, 0x0d, 0x13, 0x66, 0xfd, 0x82, 0x84, 0x9f, 0x75, 0x5b, 0xa2, 0x17, 0xfe, 0x34, 0xbf, 0x1f, 0xcb, 0xba, 0x90, 0x55, 0x80, 0x83, 0xfd, 0x63, 0xb9, 0x18, 0xf8, 0x5b, 0x5d, 0x94, 0x1e},
+ subYX: fp.Elt{0xb9, 0xdb, 0x6c, 0x04, 0x88, 0x22, 0xd8, 0x79, 0x83, 0x2f, 0x8d, 0x65, 0x6b, 0xd2, 0xab, 0x1b, 0xdd, 0x65, 0xe5, 0x93, 0x63, 0xf8, 0xa2, 0xd8, 0x3c, 0xf1, 0x4b, 0xc5, 0x99, 0xd1, 0xf2, 0x12},
+ dt2: fp.Elt{0x05, 0x4c, 0xb8, 0x3b, 0xfe, 0xf5, 0x9f, 0x2e, 0xd1, 0xb2, 0xb8, 0xff, 0xfe, 0x6d, 0xd9, 0x37, 0xe0, 0xae, 0xb4, 0x5a, 0x51, 0x80, 0x7e, 0x9b, 0x1d, 0xd1, 0x8d, 0x8c, 0x56, 0xb1, 0x84, 0x35},
+ },
+ {
+ addYX: fp.Elt{0x39, 0x71, 0x43, 0x34, 0xe3, 0x42, 0x45, 0xa1, 0xf2, 0x68, 0x71, 0xa7, 0xe8, 0x23, 0xfd, 0x9f, 0x86, 0x48, 0xff, 0xe5, 0x96, 0x74, 0xcf, 0x05, 0x49, 0xe2, 0xb3, 0x6c, 0x17, 0x77, 0x2f, 0x6d},
+ subYX: fp.Elt{0x73, 0x3f, 0xc1, 0xc7, 0x6a, 0x66, 0xa1, 0x20, 0xdd, 0x11, 0xfb, 0x7a, 0x6e, 0xa8, 0x51, 0xb8, 0x3f, 0x9d, 0xa2, 0x97, 0x84, 0xb5, 0xc7, 0x90, 0x7c, 0xab, 0x48, 0xd6, 0x84, 0xa3, 0xd5, 0x1a},
+ dt2: fp.Elt{0x63, 0x27, 0x3c, 0x49, 0x4b, 0xfc, 0x22, 0xf2, 0x0b, 0x50, 0xc2, 0x0f, 0xb4, 0x1f, 0x31, 0x0c, 0x2f, 0x53, 0xab, 0xaa, 0x75, 0x6f, 0xe0, 0x69, 0x39, 0x56, 0xe0, 0x3b, 0xb7, 0xa8, 0xbf, 0x45},
+ },
+ },
+ {
+ {
+ addYX: fp.Elt{0x00, 0x45, 0xd9, 0x0d, 0x58, 0x03, 0xfc, 0x29, 0x93, 0xec, 0xbb, 0x6f, 0xa4, 0x7a, 0xd2, 0xec, 0xf8, 0xa7, 0xe2, 0xc2, 0x5f, 0x15, 0x0a, 0x13, 0xd5, 0xa1, 0x06, 0xb7, 0x1a, 0x15, 0x6b, 0x41},
+ subYX: fp.Elt{0x85, 0x8c, 0xb2, 0x17, 0xd6, 0x3b, 0x0a, 0xd3, 0xea, 0x3b, 0x77, 0x39, 0xb7, 0x77, 0xd3, 0xc5, 0xbf, 0x5c, 0x6a, 0x1e, 0x8c, 0xe7, 0xc6, 0xc6, 0xc4, 0xb7, 0x2a, 0x8b, 0xf7, 0xb8, 0x61, 0x0d},
+ dt2: fp.Elt{0xb0, 0x36, 0xc1, 0xe9, 0xef, 0xd7, 0xa8, 0x56, 0x20, 0x4b, 0xe4, 0x58, 0xcd, 0xe5, 0x07, 0xbd, 0xab, 0xe0, 0x57, 0x1b, 0xda, 0x2f, 0xe6, 0xaf, 0xd2, 0xe8, 0x77, 0x42, 0xf7, 0x2a, 0x1a, 0x19},
+ },
+ {
+ addYX: fp.Elt{0x6a, 0x6d, 0x6d, 0xd1, 0xfa, 0xf5, 0x03, 0x30, 0xbd, 0x6d, 0xc2, 0xc8, 0xf5, 0x38, 0x80, 0x4f, 0xb2, 0xbe, 0xa1, 0x76, 0x50, 0x1a, 0x73, 0xf2, 0x78, 0x2b, 0x8e, 0x3a, 0x1e, 0x34, 0x47, 0x7b},
+ subYX: fp.Elt{0xc3, 0x2c, 0x36, 0xdc, 0xc5, 0x45, 0xbc, 0xef, 0x1b, 0x64, 0xd6, 0x65, 0x28, 0xe9, 0xda, 0x84, 0x13, 0xbe, 0x27, 0x8e, 0x3f, 0x98, 0x2a, 0x37, 0xee, 0x78, 0x97, 0xd6, 0xc0, 0x6f, 0xb4, 0x53},
+ dt2: fp.Elt{0x58, 0x5d, 0xa7, 0xa3, 0x68, 0xbb, 0x20, 0x30, 0x2e, 0x03, 0xe9, 0xb1, 0xd4, 0x90, 0x72, 0xe3, 0x71, 0xb2, 0x36, 0x3e, 0x73, 0xa0, 0x2e, 0x3d, 0xd1, 0x85, 0x33, 0x62, 0x4e, 0xa7, 0x7b, 0x31},
+ },
+ {
+ addYX: fp.Elt{0xbf, 0xc4, 0x38, 0x53, 0xfb, 0x68, 0xa9, 0x77, 0xce, 0x55, 0xf9, 0x05, 0xcb, 0xeb, 0xfb, 0x8c, 0x46, 0xc2, 0x32, 0x7c, 0xf0, 0xdb, 0xd7, 0x2c, 0x62, 0x8e, 0xdd, 0x54, 0x75, 0xcf, 0x3f, 0x33},
+ subYX: fp.Elt{0x49, 0x50, 0x1f, 0x4e, 0x6e, 0x55, 0x55, 0xde, 0x8c, 0x4e, 0x77, 0x96, 0x38, 0x3b, 0xfe, 0xb6, 0x43, 0x3c, 0x86, 0x69, 0xc2, 0x72, 0x66, 0x1f, 0x6b, 0xf9, 0x87, 0xbc, 0x4f, 0x37, 0x3e, 0x3c},
+ dt2: fp.Elt{0xd2, 0x2f, 0x06, 0x6b, 0x08, 0x07, 0x69, 0x77, 0xc0, 0x94, 0xcc, 0xae, 0x43, 0x00, 0x59, 0x6e, 0xa3, 0x63, 0xa8, 0xdd, 0xfa, 0x24, 0x18, 0xd0, 0x35, 0xc7, 0x78, 0xf7, 0x0d, 0xd4, 0x5a, 0x1e},
+ },
+ {
+ addYX: fp.Elt{0x45, 0xc1, 0x17, 0x51, 0xf8, 0xed, 0x7e, 0xc7, 0xa9, 0x1a, 0x11, 0x6e, 0x2d, 0xef, 0x0b, 0xd5, 0x3f, 0x98, 0xb0, 0xa3, 0x9d, 0x65, 0xf1, 0xcd, 0x53, 0x4a, 0x8a, 0x18, 0x70, 0x0a, 0x7f, 0x23},
+ subYX: fp.Elt{0xdd, 0xef, 0xbe, 0x3a, 0x31, 0xe0, 0xbc, 0xbe, 0x6d, 0x5d, 0x79, 0x87, 0xd6, 0xbe, 0x68, 0xe3, 0x59, 0x76, 0x8c, 0x86, 0x0e, 0x7a, 0x92, 0x13, 0x14, 0x8f, 0x67, 0xb3, 0xcb, 0x1a, 0x76, 0x76},
+ dt2: fp.Elt{0x56, 0x7a, 0x1c, 0x9d, 0xca, 0x96, 0xf9, 0xf9, 0x03, 0x21, 0xd4, 0xe8, 0xb3, 0xd5, 0xe9, 0x52, 0xc8, 0x54, 0x1e, 0x1b, 0x13, 0xb6, 0xfd, 0x47, 0x7d, 0x02, 0x32, 0x33, 0x27, 0xe2, 0x1f, 0x19},
+ },
+ },
+}
+
+var tabVerif = [1 << (omegaFix - 2)]pointR3{
+ { /* 1P */
+ addYX: fp.Elt{0x85, 0x3b, 0x8c, 0xf5, 0xc6, 0x93, 0xbc, 0x2f, 0x19, 0x0e, 0x8c, 0xfb, 0xc6, 0x2d, 0x93, 0xcf, 0xc2, 0x42, 0x3d, 0x64, 0x98, 0x48, 0x0b, 0x27, 0x65, 0xba, 0xd4, 0x33, 0x3a, 0x9d, 0xcf, 0x07},
+ subYX: fp.Elt{0x3e, 0x91, 0x40, 0xd7, 0x05, 0x39, 0x10, 0x9d, 0xb3, 0xbe, 0x40, 0xd1, 0x05, 0x9f, 0x39, 0xfd, 0x09, 0x8a, 0x8f, 0x68, 0x34, 0x84, 0xc1, 0xa5, 0x67, 0x12, 0xf8, 0x98, 0x92, 0x2f, 0xfd, 0x44},
+ dt2: fp.Elt{0x68, 0xaa, 0x7a, 0x87, 0x05, 0x12, 0xc9, 0xab, 0x9e, 0xc4, 0xaa, 0xcc, 0x23, 0xe8, 0xd9, 0x26, 0x8c, 0x59, 0x43, 0xdd, 0xcb, 0x7d, 0x1b, 0x5a, 0xa8, 0x65, 0x0c, 0x9f, 0x68, 0x7b, 0x11, 0x6f},
+ },
+ { /* 3P */
+ addYX: fp.Elt{0x30, 0x97, 0xee, 0x4c, 0xa8, 0xb0, 0x25, 0xaf, 0x8a, 0x4b, 0x86, 0xe8, 0x30, 0x84, 0x5a, 0x02, 0x32, 0x67, 0x01, 0x9f, 0x02, 0x50, 0x1b, 0xc1, 0xf4, 0xf8, 0x80, 0x9a, 0x1b, 0x4e, 0x16, 0x7a},
+ subYX: fp.Elt{0x65, 0xd2, 0xfc, 0xa4, 0xe8, 0x1f, 0x61, 0x56, 0x7d, 0xba, 0xc1, 0xe5, 0xfd, 0x53, 0xd3, 0x3b, 0xbd, 0xd6, 0x4b, 0x21, 0x1a, 0xf3, 0x31, 0x81, 0x62, 0xda, 0x5b, 0x55, 0x87, 0x15, 0xb9, 0x2a},
+ dt2: fp.Elt{0x89, 0xd8, 0xd0, 0x0d, 0x3f, 0x93, 0xae, 0x14, 0x62, 0xda, 0x35, 0x1c, 0x22, 0x23, 0x94, 0x58, 0x4c, 0xdb, 0xf2, 0x8c, 0x45, 0xe5, 0x70, 0xd1, 0xc6, 0xb4, 0xb9, 0x12, 0xaf, 0x26, 0x28, 0x5a},
+ },
+ { /* 5P */
+ addYX: fp.Elt{0x33, 0xbb, 0xa5, 0x08, 0x44, 0xbc, 0x12, 0xa2, 0x02, 0xed, 0x5e, 0xc7, 0xc3, 0x48, 0x50, 0x8d, 0x44, 0xec, 0xbf, 0x5a, 0x0c, 0xeb, 0x1b, 0xdd, 0xeb, 0x06, 0xe2, 0x46, 0xf1, 0xcc, 0x45, 0x29},
+ subYX: fp.Elt{0xba, 0xd6, 0x47, 0xa4, 0xc3, 0x82, 0x91, 0x7f, 0xb7, 0x29, 0x27, 0x4b, 0xd1, 0x14, 0x00, 0xd5, 0x87, 0xa0, 0x64, 0xb8, 0x1c, 0xf1, 0x3c, 0xe3, 0xf3, 0x55, 0x1b, 0xeb, 0x73, 0x7e, 0x4a, 0x15},
+ dt2: fp.Elt{0x85, 0x82, 0x2a, 0x81, 0xf1, 0xdb, 0xbb, 0xbc, 0xfc, 0xd1, 0xbd, 0xd0, 0x07, 0x08, 0x0e, 0x27, 0x2d, 0xa7, 0xbd, 0x1b, 0x0b, 0x67, 0x1b, 0xb4, 0x9a, 0xb6, 0x3b, 0x6b, 0x69, 0xbe, 0xaa, 0x43},
+ },
+ { /* 7P */
+ addYX: fp.Elt{0xbf, 0xa3, 0x4e, 0x94, 0xd0, 0x5c, 0x1a, 0x6b, 0xd2, 0xc0, 0x9d, 0xb3, 0x3a, 0x35, 0x70, 0x74, 0x49, 0x2e, 0x54, 0x28, 0x82, 0x52, 0xb2, 0x71, 0x7e, 0x92, 0x3c, 0x28, 0x69, 0xea, 0x1b, 0x46},
+ subYX: fp.Elt{0xb1, 0x21, 0x32, 0xaa, 0x9a, 0x2c, 0x6f, 0xba, 0xa7, 0x23, 0xba, 0x3b, 0x53, 0x21, 0xa0, 0x6c, 0x3a, 0x2c, 0x19, 0x92, 0x4f, 0x76, 0xea, 0x9d, 0xe0, 0x17, 0x53, 0x2e, 0x5d, 0xdd, 0x6e, 0x1d},
+ dt2: fp.Elt{0xa2, 0xb3, 0xb8, 0x01, 0xc8, 0x6d, 0x83, 0xf1, 0x9a, 0xa4, 0x3e, 0x05, 0x47, 0x5f, 0x03, 0xb3, 0xf3, 0xad, 0x77, 0x58, 0xba, 0x41, 0x9c, 0x52, 0xa7, 0x90, 0x0f, 0x6a, 0x1c, 0xbb, 0x9f, 0x7a},
+ },
+ { /* 9P */
+ addYX: fp.Elt{0x2f, 0x63, 0xa8, 0xa6, 0x8a, 0x67, 0x2e, 0x9b, 0xc5, 0x46, 0xbc, 0x51, 0x6f, 0x9e, 0x50, 0xa6, 0xb5, 0xf5, 0x86, 0xc6, 0xc9, 0x33, 0xb2, 0xce, 0x59, 0x7f, 0xdd, 0x8a, 0x33, 0xed, 0xb9, 0x34},
+ subYX: fp.Elt{0x64, 0x80, 0x9d, 0x03, 0x7e, 0x21, 0x6e, 0xf3, 0x9b, 0x41, 0x20, 0xf5, 0xb6, 0x81, 0xa0, 0x98, 0x44, 0xb0, 0x5e, 0xe7, 0x08, 0xc6, 0xcb, 0x96, 0x8f, 0x9c, 0xdc, 0xfa, 0x51, 0x5a, 0xc0, 0x49},
+ dt2: fp.Elt{0x1b, 0xaf, 0x45, 0x90, 0xbf, 0xe8, 0xb4, 0x06, 0x2f, 0xd2, 0x19, 0xa7, 0xe8, 0x83, 0xff, 0xe2, 0x16, 0xcf, 0xd4, 0x93, 0x29, 0xfc, 0xf6, 0xaa, 0x06, 0x8b, 0x00, 0x1b, 0x02, 0x72, 0xc1, 0x73},
+ },
+ { /* 11P */
+ addYX: fp.Elt{0xde, 0x2a, 0x80, 0x8a, 0x84, 0x00, 0xbf, 0x2f, 0x27, 0x2e, 0x30, 0x02, 0xcf, 0xfe, 0xd9, 0xe5, 0x06, 0x34, 0x70, 0x17, 0x71, 0x84, 0x3e, 0x11, 0xaf, 0x8f, 0x6d, 0x54, 0xe2, 0xaa, 0x75, 0x42},
+ subYX: fp.Elt{0x48, 0x43, 0x86, 0x49, 0x02, 0x5b, 0x5f, 0x31, 0x81, 0x83, 0x08, 0x77, 0x69, 0xb3, 0xd6, 0x3e, 0x95, 0xeb, 0x8d, 0x6a, 0x55, 0x75, 0xa0, 0xa3, 0x7f, 0xc7, 0xd5, 0x29, 0x80, 0x59, 0xab, 0x18},
+ dt2: fp.Elt{0xe9, 0x89, 0x60, 0xfd, 0xc5, 0x2c, 0x2b, 0xd8, 0xa4, 0xe4, 0x82, 0x32, 0xa1, 0xb4, 0x1e, 0x03, 0x22, 0x86, 0x1a, 0xb5, 0x99, 0x11, 0x31, 0x44, 0x48, 0xf9, 0x3d, 0xb5, 0x22, 0x55, 0xc6, 0x3d},
+ },
+ { /* 13P */
+ addYX: fp.Elt{0x6d, 0x7f, 0x00, 0xa2, 0x22, 0xc2, 0x70, 0xbf, 0xdb, 0xde, 0xbc, 0xb5, 0x9a, 0xb3, 0x84, 0xbf, 0x07, 0xba, 0x07, 0xfb, 0x12, 0x0e, 0x7a, 0x53, 0x41, 0xf2, 0x46, 0xc3, 0xee, 0xd7, 0x4f, 0x23},
+ subYX: fp.Elt{0x93, 0xbf, 0x7f, 0x32, 0x3b, 0x01, 0x6f, 0x50, 0x6b, 0x6f, 0x77, 0x9b, 0xc9, 0xeb, 0xfc, 0xae, 0x68, 0x59, 0xad, 0xaa, 0x32, 0xb2, 0x12, 0x9d, 0xa7, 0x24, 0x60, 0x17, 0x2d, 0x88, 0x67, 0x02},
+ dt2: fp.Elt{0x78, 0xa3, 0x2e, 0x73, 0x19, 0xa1, 0x60, 0x53, 0x71, 0xd4, 0x8d, 0xdf, 0xb1, 0xe6, 0x37, 0x24, 0x33, 0xe5, 0xa7, 0x91, 0xf8, 0x37, 0xef, 0xa2, 0x63, 0x78, 0x09, 0xaa, 0xfd, 0xa6, 0x7b, 0x49},
+ },
+ { /* 15P */
+ addYX: fp.Elt{0xa0, 0xea, 0xcf, 0x13, 0x03, 0xcc, 0xce, 0x24, 0x6d, 0x24, 0x9c, 0x18, 0x8d, 0xc2, 0x48, 0x86, 0xd0, 0xd4, 0xf2, 0xc1, 0xfa, 0xbd, 0xbd, 0x2d, 0x2b, 0xe7, 0x2d, 0xf1, 0x17, 0x29, 0xe2, 0x61},
+ subYX: fp.Elt{0x0b, 0xcf, 0x8c, 0x46, 0x86, 0xcd, 0x0b, 0x04, 0xd6, 0x10, 0x99, 0x2a, 0xa4, 0x9b, 0x82, 0xd3, 0x92, 0x51, 0xb2, 0x07, 0x08, 0x30, 0x08, 0x75, 0xbf, 0x5e, 0xd0, 0x18, 0x42, 0xcd, 0xb5, 0x43},
+ dt2: fp.Elt{0x16, 0xb5, 0xd0, 0x9b, 0x2f, 0x76, 0x9a, 0x5d, 0xee, 0xde, 0x3f, 0x37, 0x4e, 0xaf, 0x38, 0xeb, 0x70, 0x42, 0xd6, 0x93, 0x7d, 0x5a, 0x2e, 0x03, 0x42, 0xd8, 0xe4, 0x0a, 0x21, 0x61, 0x1d, 0x51},
+ },
+ { /* 17P */
+ addYX: fp.Elt{0x81, 0x9d, 0x0e, 0x95, 0xef, 0x76, 0xc6, 0x92, 0x4f, 0x04, 0xd7, 0xc0, 0xcd, 0x20, 0x46, 0xa5, 0x48, 0x12, 0x8f, 0x6f, 0x64, 0x36, 0x9b, 0xaa, 0xe3, 0x55, 0xb8, 0xdd, 0x24, 0x59, 0x32, 0x6d},
+ subYX: fp.Elt{0x87, 0xde, 0x20, 0x44, 0x48, 0x86, 0x13, 0x08, 0xb4, 0xed, 0x92, 0xb5, 0x16, 0xf0, 0x1c, 0x8a, 0x25, 0x2d, 0x94, 0x29, 0x27, 0x4e, 0xfa, 0x39, 0x10, 0x28, 0x48, 0xe2, 0x6f, 0xfe, 0xa7, 0x71},
+ dt2: fp.Elt{0x54, 0xc8, 0xc8, 0xa5, 0xb8, 0x82, 0x71, 0x6c, 0x03, 0x2a, 0x5f, 0xfe, 0x79, 0x14, 0xfd, 0x33, 0x0c, 0x8d, 0x77, 0x83, 0x18, 0x59, 0xcf, 0x72, 0xa9, 0xea, 0x9e, 0x55, 0xb6, 0xc4, 0x46, 0x47},
+ },
+ { /* 19P */
+ addYX: fp.Elt{0x2b, 0x9a, 0xc6, 0x6d, 0x3c, 0x7b, 0x77, 0xd3, 0x17, 0xf6, 0x89, 0x6f, 0x27, 0xb2, 0xfa, 0xde, 0xb5, 0x16, 0x3a, 0xb5, 0xf7, 0x1c, 0x65, 0x45, 0xb7, 0x9f, 0xfe, 0x34, 0xde, 0x51, 0x9a, 0x5c},
+ subYX: fp.Elt{0x47, 0x11, 0x74, 0x64, 0xc8, 0x46, 0x85, 0x34, 0x49, 0xc8, 0xfc, 0x0e, 0xdd, 0xae, 0x35, 0x7d, 0x32, 0xa3, 0x72, 0x06, 0x76, 0x9a, 0x93, 0xff, 0xd6, 0xe6, 0xb5, 0x7d, 0x49, 0x63, 0x96, 0x21},
+ dt2: fp.Elt{0x67, 0x0e, 0xf1, 0x79, 0xcf, 0xf1, 0x10, 0xf5, 0x5b, 0x51, 0x58, 0xe6, 0xa1, 0xda, 0xdd, 0xff, 0x77, 0x22, 0x14, 0x10, 0x17, 0xa7, 0xc3, 0x09, 0xbb, 0x23, 0x82, 0x60, 0x3c, 0x50, 0x04, 0x48},
+ },
+ { /* 21P */
+ addYX: fp.Elt{0xc7, 0x7f, 0xa3, 0x2c, 0xd0, 0x9e, 0x24, 0xc4, 0xab, 0xac, 0x15, 0xa6, 0xe3, 0xa0, 0x59, 0xa0, 0x23, 0x0e, 0x6e, 0xc9, 0xd7, 0x6e, 0xa9, 0x88, 0x6d, 0x69, 0x50, 0x16, 0xa5, 0x98, 0x33, 0x55},
+ subYX: fp.Elt{0x75, 0xd1, 0x36, 0x3a, 0xd2, 0x21, 0x68, 0x3b, 0x32, 0x9e, 0x9b, 0xe9, 0xa7, 0x0a, 0xb4, 0xbb, 0x47, 0x8a, 0x83, 0x20, 0xe4, 0x5c, 0x9e, 0x5d, 0x5e, 0x4c, 0xde, 0x58, 0x88, 0x09, 0x1e, 0x77},
+ dt2: fp.Elt{0xdf, 0x1e, 0x45, 0x78, 0xd2, 0xf5, 0x12, 0x9a, 0xcb, 0x9c, 0x89, 0x85, 0x79, 0x5d, 0xda, 0x3a, 0x08, 0x95, 0xa5, 0x9f, 0x2d, 0x4a, 0x7f, 0x47, 0x11, 0xa6, 0xf5, 0x8f, 0xd6, 0xd1, 0x5e, 0x5a},
+ },
+ { /* 23P */
+ addYX: fp.Elt{0x83, 0x0e, 0x15, 0xfe, 0x2a, 0x12, 0x95, 0x11, 0xd8, 0x35, 0x4b, 0x7e, 0x25, 0x9a, 0x20, 0xcf, 0x20, 0x1e, 0x71, 0x1e, 0x29, 0xf8, 0x87, 0x73, 0xf0, 0x92, 0xbf, 0xd8, 0x97, 0xb8, 0xac, 0x44},
+ subYX: fp.Elt{0x59, 0x73, 0x52, 0x58, 0xc5, 0xe0, 0xe5, 0xba, 0x7e, 0x9d, 0xdb, 0xca, 0x19, 0x5c, 0x2e, 0x39, 0xe9, 0xab, 0x1c, 0xda, 0x1e, 0x3c, 0x65, 0x28, 0x44, 0xdc, 0xef, 0x5f, 0x13, 0x60, 0x9b, 0x01},
+ dt2: fp.Elt{0x83, 0x4b, 0x13, 0x5e, 0x14, 0x68, 0x60, 0x1e, 0x16, 0x4c, 0x30, 0x24, 0x4f, 0xe6, 0xf5, 0xc4, 0xd7, 0x3e, 0x1a, 0xfc, 0xa8, 0x88, 0x6e, 0x50, 0x92, 0x2f, 0xad, 0xe6, 0xfd, 0x49, 0x0c, 0x15},
+ },
+ { /* 25P */
+ addYX: fp.Elt{0x38, 0x11, 0x47, 0x09, 0x95, 0xf2, 0x7b, 0x8e, 0x51, 0xa6, 0x75, 0x4f, 0x39, 0xef, 0x6f, 0x5d, 0xad, 0x08, 0xa7, 0x25, 0xc4, 0x79, 0xaf, 0x10, 0x22, 0x99, 0xb9, 0x5b, 0x07, 0x5a, 0x2b, 0x6b},
+ subYX: fp.Elt{0x68, 0xa8, 0xdc, 0x9c, 0x3c, 0x86, 0x49, 0xb8, 0xd0, 0x4a, 0x71, 0xb8, 0xdb, 0x44, 0x3f, 0xc8, 0x8d, 0x16, 0x36, 0x0c, 0x56, 0xe3, 0x3e, 0xfe, 0xc1, 0xfb, 0x05, 0x1e, 0x79, 0xd7, 0xa6, 0x78},
+ dt2: fp.Elt{0x76, 0xb9, 0xa0, 0x47, 0x4b, 0x70, 0xbf, 0x58, 0xd5, 0x48, 0x17, 0x74, 0x55, 0xb3, 0x01, 0xa6, 0x90, 0xf5, 0x42, 0xd5, 0xb1, 0x1f, 0x2b, 0xaa, 0x00, 0x5d, 0xd5, 0x4a, 0xfc, 0x7f, 0x5c, 0x72},
+ },
+ { /* 27P */
+ addYX: fp.Elt{0xb2, 0x99, 0xcf, 0xd1, 0x15, 0x67, 0x42, 0xe4, 0x34, 0x0d, 0xa2, 0x02, 0x11, 0xd5, 0x52, 0x73, 0x9f, 0x10, 0x12, 0x8b, 0x7b, 0x15, 0xd1, 0x23, 0xa3, 0xf3, 0xb1, 0x7c, 0x27, 0xc9, 0x4c, 0x79},
+ subYX: fp.Elt{0xc0, 0x98, 0xd0, 0x1c, 0xf7, 0x2b, 0x80, 0x91, 0x66, 0x63, 0x5e, 0xed, 0xa4, 0x6c, 0x41, 0xfe, 0x4c, 0x99, 0x02, 0x49, 0x71, 0x5d, 0x58, 0xdf, 0xe7, 0xfa, 0x55, 0xf8, 0x25, 0x46, 0xd5, 0x4c},
+ dt2: fp.Elt{0x53, 0x50, 0xac, 0xc2, 0x26, 0xc4, 0xf6, 0x4a, 0x58, 0x72, 0xf6, 0x32, 0xad, 0xed, 0x9a, 0xbc, 0x21, 0x10, 0x31, 0x0a, 0xf1, 0x32, 0xd0, 0x2a, 0x85, 0x8e, 0xcc, 0x6f, 0x7b, 0x35, 0x08, 0x70},
+ },
+ { /* 29P */
+ addYX: fp.Elt{0x01, 0x3f, 0x77, 0x38, 0x27, 0x67, 0x88, 0x0b, 0xfb, 0xcc, 0xfb, 0x95, 0xfa, 0xc8, 0xcc, 0xb8, 0xb6, 0x29, 0xad, 0xb9, 0xa3, 0xd5, 0x2d, 0x8d, 0x6a, 0x0f, 0xad, 0x51, 0x98, 0x7e, 0xef, 0x06},
+ subYX: fp.Elt{0x34, 0x4a, 0x58, 0x82, 0xbb, 0x9f, 0x1b, 0xd0, 0x2b, 0x79, 0xb4, 0xd2, 0x63, 0x64, 0xab, 0x47, 0x02, 0x62, 0x53, 0x48, 0x9c, 0x63, 0x31, 0xb6, 0x28, 0xd4, 0xd6, 0x69, 0x36, 0x2a, 0xa9, 0x13},
+ dt2: fp.Elt{0xe5, 0x7d, 0x57, 0xc0, 0x1c, 0x77, 0x93, 0xca, 0x5c, 0xdc, 0x35, 0x50, 0x1e, 0xe4, 0x40, 0x75, 0x71, 0xe0, 0x02, 0xd8, 0x01, 0x0f, 0x68, 0x24, 0x6a, 0xf8, 0x2a, 0x8a, 0xdf, 0x6d, 0x29, 0x3c},
+ },
+ { /* 31P */
+ addYX: fp.Elt{0x13, 0xa7, 0x14, 0xd9, 0xf9, 0x15, 0xad, 0xae, 0x12, 0xf9, 0x8f, 0x8c, 0xf9, 0x7b, 0x2f, 0xa9, 0x30, 0xd7, 0x53, 0x9f, 0x17, 0x23, 0xf8, 0xaf, 0xba, 0x77, 0x0c, 0x49, 0x93, 0xd3, 0x99, 0x7a},
+ subYX: fp.Elt{0x41, 0x25, 0x1f, 0xbb, 0x2e, 0x4d, 0xeb, 0xfc, 0x1f, 0xb9, 0xad, 0x40, 0xc7, 0x10, 0x95, 0xb8, 0x05, 0xad, 0xa1, 0xd0, 0x7d, 0xa3, 0x71, 0xfc, 0x7b, 0x71, 0x47, 0x07, 0x70, 0x2c, 0x89, 0x0a},
+ dt2: fp.Elt{0xe8, 0xa3, 0xbd, 0x36, 0x24, 0xed, 0x52, 0x8f, 0x94, 0x07, 0xe8, 0x57, 0x41, 0xc8, 0xa8, 0x77, 0xe0, 0x9c, 0x2f, 0x26, 0x63, 0x65, 0xa9, 0xa5, 0xd2, 0xf7, 0x02, 0x83, 0xd2, 0x62, 0x67, 0x28},
+ },
+ { /* 33P */
+ addYX: fp.Elt{0x25, 0x5b, 0xe3, 0x3c, 0x09, 0x36, 0x78, 0x4e, 0x97, 0xaa, 0x6b, 0xb2, 0x1d, 0x18, 0xe1, 0x82, 0x3f, 0xb8, 0xc7, 0xcb, 0xd3, 0x92, 0xc1, 0x0c, 0x3a, 0x9d, 0x9d, 0x6a, 0x04, 0xda, 0xf1, 0x32},
+ subYX: fp.Elt{0xbd, 0xf5, 0x2e, 0xce, 0x2b, 0x8e, 0x55, 0x7c, 0x63, 0xbc, 0x47, 0x67, 0xb4, 0x6c, 0x98, 0xe4, 0xb8, 0x89, 0xbb, 0x3b, 0x9f, 0x17, 0x4a, 0x15, 0x7a, 0x76, 0xf1, 0xd6, 0xa3, 0xf2, 0x86, 0x76},
+ dt2: fp.Elt{0x6a, 0x7c, 0x59, 0x6d, 0xa6, 0x12, 0x8d, 0xaa, 0x2b, 0x85, 0xd3, 0x04, 0x03, 0x93, 0x11, 0x8f, 0x22, 0xb0, 0x09, 0xc2, 0x73, 0xdc, 0x91, 0x3f, 0xa6, 0x28, 0xad, 0xa9, 0xf8, 0x05, 0x13, 0x56},
+ },
+ { /* 35P */
+ addYX: fp.Elt{0xd1, 0xae, 0x92, 0xec, 0x8d, 0x97, 0x0c, 0x10, 0xe5, 0x73, 0x6d, 0x4d, 0x43, 0xd5, 0x43, 0xca, 0x48, 0xba, 0x47, 0xd8, 0x22, 0x1b, 0x13, 0x83, 0x2c, 0x4d, 0x5d, 0xe3, 0x53, 0xec, 0xaa},
+ subYX: fp.Elt{0xd5, 0xc0, 0xb0, 0xe7, 0x28, 0xcc, 0x22, 0x67, 0x53, 0x5c, 0x07, 0xdb, 0xbb, 0xe9, 0x9d, 0x70, 0x61, 0x0a, 0x01, 0xd7, 0xa7, 0x8d, 0xf6, 0xca, 0x6c, 0xcc, 0x57, 0x2c, 0xef, 0x1a, 0x0a, 0x03},
+ dt2: fp.Elt{0xaa, 0xd2, 0x3a, 0x00, 0x73, 0xf7, 0xb1, 0x7b, 0x08, 0x66, 0x21, 0x2b, 0x80, 0x29, 0x3f, 0x0b, 0x3e, 0xd2, 0x0e, 0x52, 0x86, 0xdc, 0x21, 0x78, 0x80, 0x54, 0x06, 0x24, 0x1c, 0x9c, 0xbe, 0x20},
+ },
+ { /* 37P */
+ addYX: fp.Elt{0xa6, 0x73, 0x96, 0x24, 0xd8, 0x87, 0x53, 0xe1, 0x93, 0xe4, 0x46, 0xf5, 0x2d, 0xbc, 0x43, 0x59, 0xb5, 0x63, 0x6f, 0xc3, 0x81, 0x9a, 0x7f, 0x1c, 0xde, 0xc1, 0x0a, 0x1f, 0x36, 0xb3, 0x0a, 0x75},
+ subYX: fp.Elt{0x60, 0x5e, 0x02, 0xe2, 0x4a, 0xe4, 0xe0, 0x20, 0x38, 0xb9, 0xdc, 0xcb, 0x2f, 0x3b, 0x3b, 0xb0, 0x1c, 0x0d, 0x5a, 0xf9, 0x9c, 0x63, 0x5d, 0x10, 0x11, 0xe3, 0x67, 0x50, 0x54, 0x4c, 0x76, 0x69},
+ dt2: fp.Elt{0x37, 0x10, 0xf8, 0xa2, 0x83, 0x32, 0x8a, 0x1e, 0xf1, 0xcb, 0x7f, 0xbd, 0x23, 0xda, 0x2e, 0x6f, 0x63, 0x25, 0x2e, 0xac, 0x5b, 0xd1, 0x2f, 0xb7, 0x40, 0x50, 0x07, 0xb7, 0x3f, 0x6b, 0xf9, 0x54},
+ },
+ { /* 39P */
+ addYX: fp.Elt{0x79, 0x92, 0x66, 0x29, 0x04, 0xf2, 0xad, 0x0f, 0x4a, 0x72, 0x7d, 0x7d, 0x04, 0xa2, 0xdd, 0x3a, 0xf1, 0x60, 0x57, 0x8c, 0x82, 0x94, 0x3d, 0x6f, 0x9e, 0x53, 0xb7, 0x2b, 0xc5, 0xe9, 0x7f, 0x3d},
+ subYX: fp.Elt{0xcd, 0x1e, 0xb1, 0x16, 0xc6, 0xaf, 0x7d, 0x17, 0x79, 0x64, 0x57, 0xfa, 0x9c, 0x4b, 0x76, 0x89, 0x85, 0xe7, 0xec, 0xe6, 0x10, 0xa1, 0xa8, 0xb7, 0xf0, 0xdb, 0x85, 0xbe, 0x9f, 0x83, 0xe6, 0x78},
+ dt2: fp.Elt{0x6b, 0x85, 0xb8, 0x37, 0xf7, 0x2d, 0x33, 0x70, 0x8a, 0x17, 0x1a, 0x04, 0x43, 0x5d, 0xd0, 0x75, 0x22, 0x9e, 0xe5, 0xa0, 0x4a, 0xf7, 0x0f, 0x32, 0x42, 0x82, 0x08, 0x50, 0xf3, 0x68, 0xf2, 0x70},
+ },
+ { /* 41P */
+ addYX: fp.Elt{0x47, 0x5f, 0x80, 0xb1, 0x83, 0x45, 0x86, 0x66, 0x19, 0x7c, 0xdd, 0x60, 0xd1, 0xc5, 0x35, 0xf5, 0x06, 0xb0, 0x4c, 0x1e, 0xb7, 0x4e, 0x87, 0xe9, 0xd9, 0x89, 0xd8, 0xfa, 0x5c, 0x34, 0x0d, 0x7c},
+ subYX: fp.Elt{0x55, 0xf3, 0xdc, 0x70, 0x20, 0x11, 0x24, 0x23, 0x17, 0xe1, 0xfc, 0xe7, 0x7e, 0xc9, 0x0c, 0x38, 0x98, 0xb6, 0x52, 0x35, 0xed, 0xde, 0x1d, 0xb3, 0xb9, 0xc4, 0xb8, 0x39, 0xc0, 0x56, 0x4e, 0x40},
+ dt2: fp.Elt{0x8a, 0x33, 0x78, 0x8c, 0x4b, 0x1f, 0x1f, 0x59, 0xe1, 0xb5, 0xe0, 0x67, 0xb1, 0x6a, 0x36, 0xa0, 0x44, 0x3d, 0x5f, 0xb4, 0x52, 0x41, 0xbc, 0x5c, 0x77, 0xc7, 0xae, 0x2a, 0x76, 0x54, 0xd7, 0x20},
+ },
+ { /* 43P */
+ addYX: fp.Elt{0x58, 0xb7, 0x3b, 0xc7, 0x6f, 0xc3, 0x8f, 0x5e, 0x9a, 0xbb, 0x3c, 0x36, 0xa5, 0x43, 0xe5, 0xac, 0x22, 0xc9, 0x3b, 0x90, 0x7d, 0x4a, 0x93, 0xa9, 0x62, 0xec, 0xce, 0xf3, 0x46, 0x1e, 0x8f, 0x2b},
+ subYX: fp.Elt{0x43, 0xf5, 0xb9, 0x35, 0xb1, 0xfe, 0x74, 0x9d, 0x6c, 0x95, 0x8c, 0xde, 0xf1, 0x7d, 0xb3, 0x84, 0xa9, 0x8b, 0x13, 0x57, 0x07, 0x2b, 0x32, 0xe9, 0xe1, 0x4c, 0x0b, 0x79, 0xa8, 0xad, 0xb8, 0x38},
+ dt2: fp.Elt{0x5d, 0xf9, 0x51, 0xdf, 0x9c, 0x4a, 0xc0, 0xb5, 0xac, 0xde, 0x1f, 0xcb, 0xae, 0x52, 0x39, 0x2b, 0xda, 0x66, 0x8b, 0x32, 0x8b, 0x6d, 0x10, 0x1d, 0x53, 0x19, 0xba, 0xce, 0x32, 0xeb, 0x9a, 0x04},
+ },
+ { /* 45P */
+ addYX: fp.Elt{0x31, 0x79, 0xfc, 0x75, 0x0b, 0x7d, 0x50, 0xaa, 0xd3, 0x25, 0x67, 0x7a, 0x4b, 0x92, 0xef, 0x0f, 0x30, 0x39, 0x6b, 0x39, 0x2b, 0x54, 0x82, 0x1d, 0xfc, 0x74, 0xf6, 0x30, 0x75, 0xe1, 0x5e, 0x79},
+ subYX: fp.Elt{0x7e, 0xfe, 0xdc, 0x63, 0x3c, 0x7d, 0x76, 0xd7, 0x40, 0x6e, 0x85, 0x97, 0x48, 0x59, 0x9c, 0x20, 0x13, 0x7c, 0x4f, 0xe1, 0x61, 0x68, 0x67, 0xb6, 0xfc, 0x25, 0xd6, 0xc8, 0xe0, 0x65, 0xc6, 0x51},
+ dt2: fp.Elt{0x81, 0xbd, 0xec, 0x52, 0x0a, 0x5b, 0x4a, 0x25, 0xe7, 0xaf, 0x34, 0xe0, 0x6e, 0x1f, 0x41, 0x5d, 0x31, 0x4a, 0xee, 0xca, 0x0d, 0x4d, 0xa2, 0xe6, 0x77, 0x44, 0xc5, 0x9d, 0xf4, 0x9b, 0xd1, 0x6c},
+ },
+ { /* 47P */
+ addYX: fp.Elt{0x86, 0xc3, 0xaf, 0x65, 0x21, 0x61, 0xfe, 0x1f, 0x10, 0x1b, 0xd5, 0xb8, 0x88, 0x2a, 0x2a, 0x08, 0xaa, 0x0b, 0x99, 0x20, 0x7e, 0x62, 0xf6, 0x76, 0xe7, 0x43, 0x9e, 0x42, 0xa7, 0xb3, 0x01, 0x5e},
+ subYX: fp.Elt{0xa3, 0x9c, 0x17, 0x52, 0x90, 0x61, 0x87, 0x7e, 0x85, 0x9f, 0x2c, 0x0b, 0x06, 0x0a, 0x1d, 0x57, 0x1e, 0x71, 0x99, 0x84, 0xa8, 0xba, 0xa2, 0x80, 0x38, 0xe6, 0xb2, 0x40, 0xdb, 0xf3, 0x20, 0x75},
+ dt2: fp.Elt{0xa1, 0x57, 0x93, 0xd3, 0xe3, 0x0b, 0xb5, 0x3d, 0xa5, 0x94, 0x9e, 0x59, 0xdd, 0x6c, 0x7b, 0x96, 0x6e, 0x1e, 0x31, 0xdf, 0x64, 0x9a, 0x30, 0x1a, 0x86, 0xc9, 0xf3, 0xce, 0x9c, 0x2c, 0x09, 0x71},
+ },
+ { /* 49P */
+ addYX: fp.Elt{0xcf, 0x1d, 0x05, 0x74, 0xac, 0xd8, 0x6b, 0x85, 0x1e, 0xaa, 0xb7, 0x55, 0x08, 0xa4, 0xf6, 0x03, 0xeb, 0x3c, 0x74, 0xc9, 0xcb, 0xe7, 0x4a, 0x3a, 0xde, 0xab, 0x37, 0x71, 0xbb, 0xa5, 0x73, 0x41},
+ subYX: fp.Elt{0x8c, 0x91, 0x64, 0x03, 0x3f, 0x52, 0xd8, 0x53, 0x1c, 0x6b, 0xab, 0x3f, 0xf4, 0x04, 0xb4, 0xa2, 0xa4, 0xe5, 0x81, 0x66, 0x9e, 0x4a, 0x0b, 0x08, 0xa7, 0x7b, 0x25, 0xd0, 0x03, 0x5b, 0xa1, 0x0e},
+ dt2: fp.Elt{0x8a, 0x21, 0xf9, 0xf0, 0x31, 0x6e, 0xc5, 0x17, 0x08, 0x47, 0xfc, 0x1a, 0x2b, 0x6e, 0x69, 0x5a, 0x76, 0xf1, 0xb2, 0xf4, 0x68, 0x16, 0x93, 0xf7, 0x67, 0x3a, 0x4e, 0x4a, 0x61, 0x65, 0xc5, 0x5f},
+ },
+ { /* 51P */
+ addYX: fp.Elt{0x8e, 0x98, 0x90, 0x77, 0xe6, 0xe1, 0x92, 0x48, 0x22, 0xd7, 0x5c, 0x1c, 0x0f, 0x95, 0xd5, 0x01, 0xed, 0x3e, 0x92, 0xe5, 0x9a, 0x81, 0xb0, 0xe3, 0x1b, 0x65, 0x46, 0x9d, 0x40, 0xc7, 0x14, 0x32},
+ subYX: fp.Elt{0xe5, 0x7a, 0x6d, 0xc4, 0x0d, 0x57, 0x6e, 0x13, 0x8f, 0xdc, 0xf8, 0x54, 0xcc, 0xaa, 0xd0, 0x0f, 0x86, 0xad, 0x0d, 0x31, 0x03, 0x9f, 0x54, 0x59, 0xa1, 0x4a, 0x45, 0x4c, 0x41, 0x1c, 0x71, 0x62},
+ dt2: fp.Elt{0x70, 0x17, 0x65, 0x06, 0x74, 0x82, 0x29, 0x13, 0x36, 0x94, 0x27, 0x8a, 0x66, 0xa0, 0xa4, 0x3b, 0x3c, 0x22, 0x5d, 0x18, 0xec, 0xb8, 0xb6, 0xd9, 0x3c, 0x83, 0xcb, 0x3e, 0x07, 0x94, 0xea, 0x5b},
+ },
+ { /* 53P */
+ addYX: fp.Elt{0xf8, 0xd2, 0x43, 0xf3, 0x63, 0xce, 0x70, 0xb4, 0xf1, 0xe8, 0x43, 0x05, 0x8f, 0xba, 0x67, 0x00, 0x6f, 0x7b, 0x11, 0xa2, 0xa1, 0x51, 0xda, 0x35, 0x2f, 0xbd, 0xf1, 0x44, 0x59, 0x78, 0xd0, 0x4a},
+ subYX: fp.Elt{0xe4, 0x9b, 0xc8, 0x12, 0x09, 0xbf, 0x1d, 0x64, 0x9c, 0x57, 0x6e, 0x7d, 0x31, 0x8b, 0xf3, 0xac, 0x65, 0xb0, 0x97, 0xf6, 0x02, 0x9e, 0xfe, 0xab, 0xec, 0x1e, 0xf6, 0x48, 0xc1, 0xd5, 0xac, 0x3a},
+ dt2: fp.Elt{0x01, 0x83, 0x31, 0xc3, 0x34, 0x3b, 0x8e, 0x85, 0x26, 0x68, 0x31, 0x07, 0x47, 0xc0, 0x99, 0xdc, 0x8c, 0xa8, 0x9d, 0xd3, 0x2e, 0x5b, 0x08, 0x34, 0x3d, 0x85, 0x02, 0xd9, 0xb1, 0x0c, 0xff, 0x3a},
+ },
+ { /* 55P */
+ addYX: fp.Elt{0x05, 0x35, 0xc5, 0xf4, 0x0b, 0x43, 0x26, 0x92, 0x83, 0x22, 0x1f, 0x26, 0x13, 0x9c, 0xe4, 0x68, 0xc6, 0x27, 0xd3, 0x8f, 0x78, 0x33, 0xef, 0x09, 0x7f, 0x9e, 0xd9, 0x2b, 0x73, 0x9f, 0xcf, 0x2c},
+ subYX: fp.Elt{0x5e, 0x40, 0x20, 0x3a, 0xeb, 0xc7, 0xc5, 0x87, 0xc9, 0x56, 0xad, 0xed, 0xef, 0x11, 0xe3, 0x8e, 0xf9, 0xd5, 0x29, 0xad, 0x48, 0x2e, 0x25, 0x29, 0x1d, 0x25, 0xcd, 0xf4, 0x86, 0x7e, 0x0e, 0x11},
+ dt2: fp.Elt{0xe4, 0xf5, 0x03, 0xd6, 0x9e, 0xd8, 0xc0, 0x57, 0x0c, 0x20, 0xb0, 0xf0, 0x28, 0x86, 0x88, 0x12, 0xb7, 0x3b, 0x2e, 0xa0, 0x09, 0x27, 0x17, 0x53, 0x37, 0x3a, 0x69, 0xb9, 0xe0, 0x57, 0xc5, 0x05},
+ },
+ { /* 57P */
+ addYX: fp.Elt{0xb0, 0x0e, 0xc2, 0x89, 0xb0, 0xbb, 0x76, 0xf7, 0x5c, 0xd8, 0x0f, 0xfa, 0xf6, 0x5b, 0xf8, 0x61, 0xfb, 0x21, 0x44, 0x63, 0x4e, 0x3f, 0xb9, 0xb6, 0x05, 0x12, 0x86, 0x41, 0x08, 0xef, 0x9f, 0x28},
+ subYX: fp.Elt{0x6f, 0x7e, 0xc9, 0x1f, 0x31, 0xce, 0xf9, 0xd8, 0xae, 0xfd, 0xf9, 0x11, 0x30, 0x26, 0x3f, 0x7a, 0xdd, 0x25, 0xed, 0x8b, 0xa0, 0x7e, 0x5b, 0xe1, 0x5a, 0x87, 0xe9, 0x8f, 0x17, 0x4c, 0x15, 0x6e},
+ dt2: fp.Elt{0xbf, 0x9a, 0xd6, 0xfe, 0x36, 0x63, 0x61, 0xcf, 0x4f, 0xc9, 0x35, 0x83, 0xe7, 0xe4, 0x16, 0x9b, 0xe7, 0x7f, 0x3a, 0x75, 0x65, 0x97, 0x78, 0x13, 0x19, 0xa3, 0x5c, 0xa9, 0x42, 0xf6, 0xfb, 0x6a},
+ },
+ { /* 59P */
+ addYX: fp.Elt{0xcc, 0xa8, 0x13, 0xf9, 0x70, 0x50, 0xe5, 0x5d, 0x61, 0xf5, 0x0c, 0x2b, 0x7b, 0x16, 0x1d, 0x7d, 0x89, 0xd4, 0xea, 0x90, 0xb6, 0x56, 0x29, 0xda, 0xd9, 0x1e, 0x80, 0xdb, 0xce, 0x93, 0xc0, 0x12},
+ subYX: fp.Elt{0xc1, 0xd2, 0xf5, 0x62, 0x0c, 0xde, 0xa8, 0x7d, 0x9a, 0x7b, 0x0e, 0xb0, 0xa4, 0x3d, 0xfc, 0x98, 0xe0, 0x70, 0xad, 0x0d, 0xda, 0x6a, 0xeb, 0x7d, 0xc4, 0x38, 0x50, 0xb9, 0x51, 0xb8, 0xb4, 0x0d},
+ dt2: fp.Elt{0x0f, 0x19, 0xb8, 0x08, 0x93, 0x7f, 0x14, 0xfc, 0x10, 0xe3, 0x1a, 0xa1, 0xa0, 0x9d, 0x96, 0x06, 0xfd, 0xd7, 0xc7, 0xda, 0x72, 0x55, 0xe7, 0xce, 0xe6, 0x5c, 0x63, 0xc6, 0x99, 0x87, 0xaa, 0x33},
+ },
+ { /* 61P */
+ addYX: fp.Elt{0xb1, 0x6c, 0x15, 0xfc, 0x88, 0xf5, 0x48, 0x83, 0x27, 0x6d, 0x0a, 0x1a, 0x9b, 0xba, 0xa2, 0x6d, 0xb6, 0x5a, 0xca, 0x87, 0x5c, 0x2d, 0x26, 0xe2, 0xa6, 0x89, 0xd5, 0xc8, 0xc1, 0xd0, 0x2c, 0x21},
+ subYX: fp.Elt{0xf2, 0x5c, 0x08, 0xbd, 0x1e, 0xf5, 0x0f, 0xaf, 0x1f, 0x3f, 0xd3, 0x67, 0x89, 0x1a, 0xf5, 0x78, 0x3c, 0x03, 0x60, 0x50, 0xe1, 0xbf, 0xc2, 0x6e, 0x86, 0x1a, 0xe2, 0xe8, 0x29, 0x6f, 0x3c, 0x23},
+ dt2: fp.Elt{0x81, 0xc7, 0x18, 0x7f, 0x10, 0xd5, 0xf4, 0xd2, 0x28, 0x9d, 0x7e, 0x52, 0xf2, 0xcd, 0x2e, 0x12, 0x41, 0x33, 0x3d, 0x3d, 0x2a, 0x86, 0x0a, 0xa7, 0xe3, 0x4c, 0x91, 0x11, 0x89, 0x77, 0xb7, 0x1d},
+ },
+ { /* 63P */
+ addYX: fp.Elt{0xb6, 0x1a, 0x70, 0xdd, 0x69, 0x47, 0x39, 0xb3, 0xa5, 0x8d, 0xcf, 0x19, 0xd4, 0xde, 0xb8, 0xe2, 0x52, 0xc8, 0x2a, 0xfd, 0x61, 0x41, 0xdf, 0x15, 0xbe, 0x24, 0x7d, 0x01, 0x8a, 0xca, 0xe2, 0x7a},
+ subYX: fp.Elt{0x6f, 0xc2, 0x6b, 0x7c, 0x39, 0x52, 0xf3, 0xdd, 0x13, 0x01, 0xd5, 0x53, 0xcc, 0xe2, 0x97, 0x7a, 0x30, 0xa3, 0x79, 0xbf, 0x3a, 0xf4, 0x74, 0x7c, 0xfc, 0xad, 0xe2, 0x26, 0xad, 0x97, 0xad, 0x31},
+ dt2: fp.Elt{0x62, 0xb9, 0x20, 0x09, 0xed, 0x17, 0xe8, 0xb7, 0x9d, 0xda, 0x19, 0x3f, 0xcc, 0x18, 0x85, 0x1e, 0x64, 0x0a, 0x56, 0x25, 0x4f, 0xc1, 0x91, 0xe4, 0x83, 0x2c, 0x62, 0xa6, 0x53, 0xfc, 0xd1, 0x1e},
+ },
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go b/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go
new file mode 100644
index 0000000000..c368b181b4
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go
@@ -0,0 +1,411 @@
+// Package ed448 implements Ed448 signature scheme as described in RFC-8032.
+//
+// This package implements two signature variants.
+//
+// | Scheme Name | Sign Function | Verification | Context |
+// |-------------|-------------------|---------------|-------------------|
+// | Ed448 | Sign | Verify | Yes, can be empty |
+// | Ed448Ph | SignPh | VerifyPh | Yes, can be empty |
+// | All above | (PrivateKey).Sign | VerifyAny | As above |
+//
+// Specific functions for sign and verify are defined. A generic signing
+// function for all schemes is available through the crypto.Signer interface,
+// which is implemented by the PrivateKey type. A correspond all-in-one
+// verification method is provided by the VerifyAny function.
+//
+// Both schemes require a context string for domain separation. This parameter
+// is passed using a SignerOptions struct defined in this package.
+//
+// References:
+//
+// - RFC8032: https://rfc-editor.org/rfc/rfc8032.txt
+// - EdDSA for more curves: https://eprint.iacr.org/2015/677
+// - High-speed high-security signatures: https://doi.org/10.1007/s13389-012-0027-1
+package ed448
+
+import (
+ "bytes"
+ "crypto"
+ cryptoRand "crypto/rand"
+ "crypto/subtle"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+
+ "github.com/cloudflare/circl/ecc/goldilocks"
+ "github.com/cloudflare/circl/internal/sha3"
+ "github.com/cloudflare/circl/sign"
+)
+
+const (
+ // ContextMaxSize is the maximum length (in bytes) allowed for context.
+ ContextMaxSize = 255
+ // PublicKeySize is the length in bytes of Ed448 public keys.
+ PublicKeySize = 57
+ // PrivateKeySize is the length in bytes of Ed448 private keys.
+ PrivateKeySize = 114
+ // SignatureSize is the length in bytes of signatures.
+ SignatureSize = 114
+ // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
+ SeedSize = 57
+)
+
+const (
+ paramB = 456 / 8 // Size of keys in bytes.
+ hashSize = 2 * paramB // Size of the hash function's output.
+)
+
+// SignerOptions implements crypto.SignerOpts and augments with parameters
+// that are specific to the Ed448 signature schemes.
+type SignerOptions struct {
+ // Hash must be crypto.Hash(0) for both Ed448 and Ed448Ph.
+ crypto.Hash
+
+ // Context is an optional domain separation string for signing.
+ // Its length must be less or equal than 255 bytes.
+ Context string
+
+ // Scheme is an identifier for choosing a signature scheme.
+ Scheme SchemeID
+}
+
+// SchemeID is an identifier for each signature scheme.
+type SchemeID uint
+
+const (
+ ED448 SchemeID = iota
+ ED448Ph
+)
+
+// PublicKey is the type of Ed448 public keys.
+type PublicKey []byte
+
+// Equal reports whether pub and x have the same value.
+func (pub PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(PublicKey)
+ return ok && bytes.Equal(pub, xx)
+}
+
+// PrivateKey is the type of Ed448 private keys. It implements crypto.Signer.
+type PrivateKey []byte
+
+// Equal reports whether priv and x have the same value.
+func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(PrivateKey)
+ return ok && subtle.ConstantTimeCompare(priv, xx) == 1
+}
+
+// Public returns the PublicKey corresponding to priv.
+func (priv PrivateKey) Public() crypto.PublicKey {
+ publicKey := make([]byte, PublicKeySize)
+ copy(publicKey, priv[SeedSize:])
+ return PublicKey(publicKey)
+}
+
+// Seed returns the private key seed corresponding to priv. It is provided for
+// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
+// in this package.
+func (priv PrivateKey) Seed() []byte {
+ seed := make([]byte, SeedSize)
+ copy(seed, priv[:SeedSize])
+ return seed
+}
+
+func (priv PrivateKey) Scheme() sign.Scheme { return sch }
+
+func (pub PublicKey) Scheme() sign.Scheme { return sch }
+
+func (priv PrivateKey) MarshalBinary() (data []byte, err error) {
+ privateKey := make(PrivateKey, PrivateKeySize)
+ copy(privateKey, priv)
+ return privateKey, nil
+}
+
+func (pub PublicKey) MarshalBinary() (data []byte, err error) {
+ publicKey := make(PublicKey, PublicKeySize)
+ copy(publicKey, pub)
+ return publicKey, nil
+}
+
+// Sign creates a signature of a message given a key pair.
+// This function supports all the two signature variants defined in RFC-8032,
+// namely Ed448 (or pure EdDSA) and Ed448Ph.
+// The opts.HashFunc() must return zero to the specify Ed448 variant. This can
+// be achieved by passing crypto.Hash(0) as the value for opts.
+// Use an Options struct to pass a bool indicating that the ed448Ph variant
+// should be used.
+// The struct can also be optionally used to pass a context string for signing.
+func (priv PrivateKey) Sign(
+ rand io.Reader,
+ message []byte,
+ opts crypto.SignerOpts,
+) (signature []byte, err error) {
+ var ctx string
+ var scheme SchemeID
+
+ if o, ok := opts.(SignerOptions); ok {
+ ctx = o.Context
+ scheme = o.Scheme
+ }
+
+ switch true {
+ case scheme == ED448 && opts.HashFunc() == crypto.Hash(0):
+ return Sign(priv, message, ctx), nil
+ case scheme == ED448Ph && opts.HashFunc() == crypto.Hash(0):
+ return SignPh(priv, message, ctx), nil
+ default:
+ return nil, errors.New("ed448: bad hash algorithm")
+ }
+}
+
+// GenerateKey generates a public/private key pair using entropy from rand.
+// If rand is nil, crypto/rand.Reader will be used.
+func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
+ if rand == nil {
+ rand = cryptoRand.Reader
+ }
+
+ seed := make(PrivateKey, SeedSize)
+ if _, err := io.ReadFull(rand, seed); err != nil {
+ return nil, nil, err
+ }
+
+ privateKey := NewKeyFromSeed(seed)
+ publicKey := make([]byte, PublicKeySize)
+ copy(publicKey, privateKey[SeedSize:])
+
+ return publicKey, privateKey, nil
+}
+
+// NewKeyFromSeed calculates a private key from a seed. It will panic if
+// len(seed) is not SeedSize. This function is provided for interoperability
+// with RFC 8032. RFC 8032's private keys correspond to seeds in this
+// package.
+func NewKeyFromSeed(seed []byte) PrivateKey {
+ privateKey := make([]byte, PrivateKeySize)
+ newKeyFromSeed(privateKey, seed)
+ return privateKey
+}
+
+func newKeyFromSeed(privateKey, seed []byte) {
+ if l := len(seed); l != SeedSize {
+ panic("ed448: bad seed length: " + strconv.Itoa(l))
+ }
+
+ var h [hashSize]byte
+ H := sha3.NewShake256()
+ _, _ = H.Write(seed)
+ _, _ = H.Read(h[:])
+ s := &goldilocks.Scalar{}
+ deriveSecretScalar(s, h[:paramB])
+
+ copy(privateKey[:SeedSize], seed)
+ _ = goldilocks.Curve{}.ScalarBaseMult(s).ToBytes(privateKey[SeedSize:])
+}
+
+func signAll(signature []byte, privateKey PrivateKey, message, ctx []byte, preHash bool) {
+ if len(ctx) > ContextMaxSize {
+ panic(fmt.Errorf("ed448: bad context length: %v", len(ctx)))
+ }
+
+ H := sha3.NewShake256()
+ var PHM []byte
+
+ if preHash {
+ var h [64]byte
+ _, _ = H.Write(message)
+ _, _ = H.Read(h[:])
+ PHM = h[:]
+ H.Reset()
+ } else {
+ PHM = message
+ }
+
+ // 1. Hash the 57-byte private key using SHAKE256(x, 114).
+ var h [hashSize]byte
+ _, _ = H.Write(privateKey[:SeedSize])
+ _, _ = H.Read(h[:])
+ s := &goldilocks.Scalar{}
+ deriveSecretScalar(s, h[:paramB])
+ prefix := h[paramB:]
+
+ // 2. Compute SHAKE256(dom4(F, C) || prefix || PH(M), 114).
+ var rPM [hashSize]byte
+ H.Reset()
+
+ writeDom(&H, ctx, preHash)
+
+ _, _ = H.Write(prefix)
+ _, _ = H.Write(PHM)
+ _, _ = H.Read(rPM[:])
+
+ // 3. Compute the point [r]B.
+ r := &goldilocks.Scalar{}
+ r.FromBytes(rPM[:])
+ R := (&[paramB]byte{})[:]
+ if err := (goldilocks.Curve{}.ScalarBaseMult(r).ToBytes(R)); err != nil {
+ panic(err)
+ }
+ // 4. Compute SHAKE256(dom4(F, C) || R || A || PH(M), 114)
+ var hRAM [hashSize]byte
+ H.Reset()
+
+ writeDom(&H, ctx, preHash)
+
+ _, _ = H.Write(R)
+ _, _ = H.Write(privateKey[SeedSize:])
+ _, _ = H.Write(PHM)
+ _, _ = H.Read(hRAM[:])
+
+ // 5. Compute S = (r + k * s) mod order.
+ k := &goldilocks.Scalar{}
+ k.FromBytes(hRAM[:])
+ S := &goldilocks.Scalar{}
+ S.Mul(k, s)
+ S.Add(S, r)
+
+ // 6. The signature is the concatenation of R and S.
+ copy(signature[:paramB], R[:])
+ copy(signature[paramB:], S[:])
+}
+
+// Sign signs the message with privateKey and returns a signature.
+// This function supports the signature variant defined in RFC-8032: Ed448,
+// also known as the pure version of EdDSA.
+// It will panic if len(privateKey) is not PrivateKeySize.
+func Sign(priv PrivateKey, message []byte, ctx string) []byte {
+ signature := make([]byte, SignatureSize)
+ signAll(signature, priv, message, []byte(ctx), false)
+ return signature
+}
+
+// SignPh creates a signature of a message given a keypair.
+// This function supports the signature variant defined in RFC-8032: Ed448ph,
+// meaning it internally hashes the message using SHAKE-256.
+// Context could be passed to this function, which length should be no more than
+// 255. It can be empty.
+func SignPh(priv PrivateKey, message []byte, ctx string) []byte {
+ signature := make([]byte, SignatureSize)
+ signAll(signature, priv, message, []byte(ctx), true)
+ return signature
+}
+
+func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool {
+ if len(public) != PublicKeySize ||
+ len(signature) != SignatureSize ||
+ len(ctx) > ContextMaxSize ||
+ !isLessThanOrder(signature[paramB:]) {
+ return false
+ }
+
+ P, err := goldilocks.FromBytes(public)
+ if err != nil {
+ return false
+ }
+
+ H := sha3.NewShake256()
+ var PHM []byte
+
+ if preHash {
+ var h [64]byte
+ _, _ = H.Write(message)
+ _, _ = H.Read(h[:])
+ PHM = h[:]
+ H.Reset()
+ } else {
+ PHM = message
+ }
+
+ var hRAM [hashSize]byte
+ R := signature[:paramB]
+
+ writeDom(&H, ctx, preHash)
+
+ _, _ = H.Write(R)
+ _, _ = H.Write(public)
+ _, _ = H.Write(PHM)
+ _, _ = H.Read(hRAM[:])
+
+ k := &goldilocks.Scalar{}
+ k.FromBytes(hRAM[:])
+ S := &goldilocks.Scalar{}
+ S.FromBytes(signature[paramB:])
+
+ encR := (&[paramB]byte{})[:]
+ P.Neg()
+ _ = goldilocks.Curve{}.CombinedMult(S, k, P).ToBytes(encR)
+ return bytes.Equal(R, encR)
+}
+
+// VerifyAny returns true if the signature is valid. Failure cases are invalid
+// signature, or when the public key cannot be decoded.
+// This function supports all the two signature variants defined in RFC-8032,
+// namely Ed448 (or pure EdDSA) and Ed448Ph.
+// The opts.HashFunc() must return zero, this can be achieved by passing
+// crypto.Hash(0) as the value for opts.
+// Use a SignerOptions struct to pass a context string for signing.
+func VerifyAny(public PublicKey, message, signature []byte, opts crypto.SignerOpts) bool {
+ var ctx string
+ var scheme SchemeID
+ if o, ok := opts.(SignerOptions); ok {
+ ctx = o.Context
+ scheme = o.Scheme
+ }
+
+ switch true {
+ case scheme == ED448 && opts.HashFunc() == crypto.Hash(0):
+ return Verify(public, message, signature, ctx)
+ case scheme == ED448Ph && opts.HashFunc() == crypto.Hash(0):
+ return VerifyPh(public, message, signature, ctx)
+ default:
+ return false
+ }
+}
+
+// Verify returns true if the signature is valid. Failure cases are invalid
+// signature, or when the public key cannot be decoded.
+// This function supports the signature variant defined in RFC-8032: Ed448,
+// also known as the pure version of EdDSA.
+func Verify(public PublicKey, message, signature []byte, ctx string) bool {
+ return verify(public, message, signature, []byte(ctx), false)
+}
+
+// VerifyPh returns true if the signature is valid. Failure cases are invalid
+// signature, or when the public key cannot be decoded.
+// This function supports the signature variant defined in RFC-8032: Ed448ph,
+// meaning it internally hashes the message using SHAKE-256.
+// Context could be passed to this function, which length should be no more than
+// 255. It can be empty.
+func VerifyPh(public PublicKey, message, signature []byte, ctx string) bool {
+ return verify(public, message, signature, []byte(ctx), true)
+}
+
+func deriveSecretScalar(s *goldilocks.Scalar, h []byte) {
+ h[0] &= 0xFC // The two least significant bits of the first octet are cleared,
+ h[paramB-1] = 0x00 // all eight bits the last octet are cleared, and
+ h[paramB-2] |= 0x80 // the highest bit of the second to last octet is set.
+ s.FromBytes(h[:paramB])
+}
+
+// isLessThanOrder returns true if 0 <= x < order and if the last byte of x is zero.
+func isLessThanOrder(x []byte) bool {
+ order := goldilocks.Curve{}.Order()
+ i := len(order) - 1
+ for i > 0 && x[i] == order[i] {
+ i--
+ }
+ return x[paramB-1] == 0 && x[i] < order[i]
+}
+
+func writeDom(h io.Writer, ctx []byte, preHash bool) {
+ dom4 := "SigEd448"
+ _, _ = h.Write([]byte(dom4))
+
+ if preHash {
+ _, _ = h.Write([]byte{byte(0x01), byte(len(ctx))})
+ } else {
+ _, _ = h.Write([]byte{byte(0x00), byte(len(ctx))})
+ }
+ _, _ = h.Write(ctx)
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go b/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go
new file mode 100644
index 0000000000..22da8bc0a5
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go
@@ -0,0 +1,87 @@
+package ed448
+
+import (
+ "crypto/rand"
+ "encoding/asn1"
+
+ "github.com/cloudflare/circl/sign"
+)
+
+var sch sign.Scheme = &scheme{}
+
+// Scheme returns a signature interface.
+func Scheme() sign.Scheme { return sch }
+
+type scheme struct{}
+
+func (*scheme) Name() string { return "Ed448" }
+func (*scheme) PublicKeySize() int { return PublicKeySize }
+func (*scheme) PrivateKeySize() int { return PrivateKeySize }
+func (*scheme) SignatureSize() int { return SignatureSize }
+func (*scheme) SeedSize() int { return SeedSize }
+func (*scheme) TLSIdentifier() uint { return 0x0808 }
+func (*scheme) SupportsContext() bool { return true }
+func (*scheme) Oid() asn1.ObjectIdentifier {
+ return asn1.ObjectIdentifier{1, 3, 101, 113}
+}
+
+func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) {
+ return GenerateKey(rand.Reader)
+}
+
+func (*scheme) Sign(
+ sk sign.PrivateKey,
+ message []byte,
+ opts *sign.SignatureOpts,
+) []byte {
+ priv, ok := sk.(PrivateKey)
+ if !ok {
+ panic(sign.ErrTypeMismatch)
+ }
+ ctx := ""
+ if opts != nil {
+ ctx = opts.Context
+ }
+ return Sign(priv, message, ctx)
+}
+
+func (*scheme) Verify(
+ pk sign.PublicKey,
+ message, signature []byte,
+ opts *sign.SignatureOpts,
+) bool {
+ pub, ok := pk.(PublicKey)
+ if !ok {
+ panic(sign.ErrTypeMismatch)
+ }
+ ctx := ""
+ if opts != nil {
+ ctx = opts.Context
+ }
+ return Verify(pub, message, signature, ctx)
+}
+
+func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) {
+ privateKey := NewKeyFromSeed(seed)
+ publicKey := make(PublicKey, PublicKeySize)
+ copy(publicKey, privateKey[SeedSize:])
+ return publicKey, privateKey
+}
+
+func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) {
+ if len(buf) < PublicKeySize {
+ return nil, sign.ErrPubKeySize
+ }
+ pub := make(PublicKey, PublicKeySize)
+ copy(pub, buf[:PublicKeySize])
+ return pub, nil
+}
+
+func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) {
+ if len(buf) < PrivateKeySize {
+ return nil, sign.ErrPrivKeySize
+ }
+ priv := make(PrivateKey, PrivateKeySize)
+ copy(priv, buf[:PrivateKeySize])
+ return priv, nil
+}
diff --git a/vendor/github.com/cloudflare/circl/sign/sign.go b/vendor/github.com/cloudflare/circl/sign/sign.go
new file mode 100644
index 0000000000..1247f1b626
--- /dev/null
+++ b/vendor/github.com/cloudflare/circl/sign/sign.go
@@ -0,0 +1,119 @@
+// Package sign provides unified interfaces for signature schemes.
+//
+// A register of schemes is available in the package
+//
+// github.com/cloudflare/circl/sign/schemes
+package sign
+
+import (
+ "crypto"
+ "encoding"
+ "errors"
+)
+
+type SignatureOpts struct {
+ // If non-empty, includes the given context in the signature if supported
+ // and will cause an error during signing otherwise.
+ Context string
+}
+
+// A public key is used to verify a signature set by the corresponding private
+// key.
+type PublicKey interface {
+ // Returns the signature scheme for this public key.
+ Scheme() Scheme
+ Equal(crypto.PublicKey) bool
+ encoding.BinaryMarshaler
+ crypto.PublicKey
+}
+
+// A private key allows one to create signatures.
+type PrivateKey interface {
+ // Returns the signature scheme for this private key.
+ Scheme() Scheme
+ Equal(crypto.PrivateKey) bool
+ // For compatibility with Go standard library
+ crypto.Signer
+ crypto.PrivateKey
+ encoding.BinaryMarshaler
+}
+
+// A private key that retains the seed with which it was generated.
+type Seeded interface {
+ // returns the seed if retained, otherwise nil
+ Seed() []byte
+}
+
+// A Scheme represents a specific instance of a signature scheme.
+type Scheme interface {
+ // Name of the scheme.
+ Name() string
+
+ // GenerateKey creates a new key-pair.
+ GenerateKey() (PublicKey, PrivateKey, error)
+
+ // Creates a signature using the PrivateKey on the given message and
+ // returns the signature. opts are additional options which can be nil.
+ //
+ // Panics if key is nil or wrong type or opts context is not supported.
+ Sign(sk PrivateKey, message []byte, opts *SignatureOpts) []byte
+
+ // Checks whether the given signature is a valid signature set by
+ // the private key corresponding to the given public key on the
+ // given message. opts are additional options which can be nil.
+ //
+ // Panics if key is nil or wrong type or opts context is not supported.
+ Verify(pk PublicKey, message []byte, signature []byte, opts *SignatureOpts) bool
+
+ // Deterministically derives a keypair from a seed. If you're unsure,
+ // you're better off using GenerateKey().
+ //
+ // Panics if seed is not of length SeedSize().
+ DeriveKey(seed []byte) (PublicKey, PrivateKey)
+
+ // Unmarshals a PublicKey from the provided buffer.
+ UnmarshalBinaryPublicKey([]byte) (PublicKey, error)
+
+ // Unmarshals a PublicKey from the provided buffer.
+ UnmarshalBinaryPrivateKey([]byte) (PrivateKey, error)
+
+ // Size of binary marshalled public keys.
+ PublicKeySize() int
+
+ // Size of binary marshalled public keys.
+ PrivateKeySize() int
+
+ // Size of signatures.
+ SignatureSize() int
+
+ // Size of seeds.
+ SeedSize() int
+
+ // Returns whether contexts are supported.
+ SupportsContext() bool
+}
+
+var (
+ // ErrTypeMismatch is the error used if types of, for instance, private
+ // and public keys don't match.
+ ErrTypeMismatch = errors.New("types mismatch")
+
+ // ErrSeedSize is the error used if the provided seed is of the wrong
+ // size.
+ ErrSeedSize = errors.New("wrong seed size")
+
+ // ErrPubKeySize is the error used if the provided public key is of
+ // the wrong size.
+ ErrPubKeySize = errors.New("wrong size for public key")
+
+ // ErrPrivKeySize is the error used if the provided private key is of
+ // the wrong size.
+ ErrPrivKeySize = errors.New("wrong size for private key")
+
+ // ErrContextNotSupported is the error used if a context is not
+ // supported.
+ ErrContextNotSupported = errors.New("context not supported")
+
+ // ErrContextTooLong is the error used if the context string is too long.
+ ErrContextTooLong = errors.New("context string too long")
+)
diff --git a/vendor/github.com/compose-spec/compose-go/LICENSE b/vendor/github.com/compose-spec/compose-go/LICENSE
deleted file mode 100644
index 9c8e20ab85..0000000000
--- a/vendor/github.com/compose-spec/compose-go/LICENSE
+++ /dev/null
@@ -1,191 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- https://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- Copyright 2013-2017 Docker, Inc.
-
- 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
-
- https://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.
diff --git a/vendor/github.com/compose-spec/compose-go/consts/consts.go b/vendor/github.com/compose-spec/compose-go/consts/consts.go
deleted file mode 100644
index bf5cc9f1b1..0000000000
--- a/vendor/github.com/compose-spec/compose-go/consts/consts.go
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package consts
-
-const (
- ComposeProjectName = "COMPOSE_PROJECT_NAME"
- ComposePathSeparator = "COMPOSE_PATH_SEPARATOR"
- ComposeFilePath = "COMPOSE_FILE"
-)
diff --git a/vendor/github.com/compose-spec/compose-go/dotenv/godotenv.go b/vendor/github.com/compose-spec/compose-go/dotenv/godotenv.go
deleted file mode 100644
index 479831aac8..0000000000
--- a/vendor/github.com/compose-spec/compose-go/dotenv/godotenv.go
+++ /dev/null
@@ -1,375 +0,0 @@
-// Package dotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
-//
-// Examples/readme can be found on the github page at https://github.com/joho/godotenv
-//
-// The TL;DR is that you make a .env file that looks something like
-//
-// SOME_ENV_VAR=somevalue
-//
-// and then in your go code you can call
-//
-// godotenv.Load()
-//
-// and all the env vars declared in .env will be available through os.Getenv("SOME_ENV_VAR")
-package dotenv
-
-import (
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "regexp"
- "sort"
- "strconv"
- "strings"
-)
-
-const doubleQuoteSpecialChars = "\\\n\r\"!$`"
-
-// LookupFn represents a lookup function to resolve variables from
-type LookupFn func(string) (string, bool)
-
-var noLookupFn = func(s string) (string, bool) {
- return "", false
-}
-
-// Parse reads an env file from io.Reader, returning a map of keys and values.
-func Parse(r io.Reader) (map[string]string, error) {
- return ParseWithLookup(r, nil)
-}
-
-// ParseWithLookup reads an env file from io.Reader, returning a map of keys and values.
-func ParseWithLookup(r io.Reader, lookupFn LookupFn) (map[string]string, error) {
- data, err := ioutil.ReadAll(r)
- if err != nil {
- return nil, err
- }
-
- return UnmarshalBytesWithLookup(data, lookupFn)
-}
-
-// Load will read your env file(s) and load them into ENV for this process.
-//
-// Call this function as close as possible to the start of your program (ideally in main)
-//
-// If you call Load without any args it will default to loading .env in the current path
-//
-// You can otherwise tell it which files to load (there can be more than one) like
-//
-// godotenv.Load("fileone", "filetwo")
-//
-// It's important to note that it WILL NOT OVERRIDE an env variable that already exists - consider the .env file to set dev vars or sensible defaults
-func Load(filenames ...string) (err error) {
- return load(false, filenames...)
-}
-
-// Overload will read your env file(s) and load them into ENV for this process.
-//
-// Call this function as close as possible to the start of your program (ideally in main)
-//
-// If you call Overload without any args it will default to loading .env in the current path
-//
-// You can otherwise tell it which files to load (there can be more than one) like
-//
-// godotenv.Overload("fileone", "filetwo")
-//
-// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
-func Overload(filenames ...string) (err error) {
- return load(true, filenames...)
-}
-
-func load(overload bool, filenames ...string) (err error) {
- filenames = filenamesOrDefault(filenames)
-
- for _, filename := range filenames {
- err = loadFile(filename, overload)
- if err != nil {
- return // return early on a spazout
- }
- }
- return
-}
-
-// ReadWithLookup gets all env vars from the files and/or lookup function and return values as
-// a map rather than automatically writing values into env
-func ReadWithLookup(lookupFn LookupFn, filenames ...string) (envMap map[string]string, err error) {
- filenames = filenamesOrDefault(filenames)
- envMap = make(map[string]string)
-
- for _, filename := range filenames {
- individualEnvMap, individualErr := readFile(filename, lookupFn)
-
- if individualErr != nil {
- err = individualErr
- return // return early on a spazout
- }
-
- for key, value := range individualEnvMap {
- envMap[key] = value
- }
- }
-
- return
-}
-
-// Read all env (with same file loading semantics as Load) but return values as
-// a map rather than automatically writing values into env
-func Read(filenames ...string) (envMap map[string]string, err error) {
- return ReadWithLookup(nil, filenames...)
-}
-
-// Unmarshal reads an env file from a string, returning a map of keys and values.
-func Unmarshal(str string) (envMap map[string]string, err error) {
- return UnmarshalBytes([]byte(str))
-}
-
-// UnmarshalBytes parses env file from byte slice of chars, returning a map of keys and values.
-func UnmarshalBytes(src []byte) (map[string]string, error) {
- return UnmarshalBytesWithLookup(src, nil)
-}
-
-// UnmarshalBytesWithLookup parses env file from byte slice of chars, returning a map of keys and values.
-func UnmarshalBytesWithLookup(src []byte, lookupFn LookupFn) (map[string]string, error) {
- out := make(map[string]string)
- err := parseBytes(src, out, lookupFn)
- return out, err
-}
-
-// Exec loads env vars from the specified filenames (empty map falls back to default)
-// then executes the cmd specified.
-//
-// Simply hooks up os.Stdin/err/out to the command and calls Run()
-//
-// If you want more fine grained control over your command it's recommended
-// that you use `Load()` or `Read()` and the `os/exec` package yourself.
-func Exec(filenames []string, cmd string, cmdArgs []string) error {
- if err := Load(filenames...); err != nil {
- return err
- }
-
- command := exec.Command(cmd, cmdArgs...)
- command.Stdin = os.Stdin
- command.Stdout = os.Stdout
- command.Stderr = os.Stderr
- return command.Run()
-}
-
-// Write serializes the given environment and writes it to a file
-func Write(envMap map[string]string, filename string) error {
- content, err := Marshal(envMap)
- if err != nil {
- return err
- }
- file, err := os.Create(filename)
- if err != nil {
- return err
- }
- defer file.Close()
- _, err = file.WriteString(content + "\n")
- if err != nil {
- return err
- }
- return file.Sync()
-}
-
-// Marshal outputs the given environment as a dotenv-formatted environment file.
-// Each line is in the format: KEY="VALUE" where VALUE is backslash-escaped.
-func Marshal(envMap map[string]string) (string, error) {
- lines := make([]string, 0, len(envMap))
- for k, v := range envMap {
- if d, err := strconv.Atoi(v); err == nil {
- lines = append(lines, fmt.Sprintf(`%s=%d`, k, d))
- } else {
- lines = append(lines, fmt.Sprintf(`%s="%s"`, k, doubleQuoteEscape(v)))
- }
- }
- sort.Strings(lines)
- return strings.Join(lines, "\n"), nil
-}
-
-func filenamesOrDefault(filenames []string) []string {
- if len(filenames) == 0 {
- return []string{".env"}
- }
- return filenames
-}
-
-func loadFile(filename string, overload bool) error {
- envMap, err := readFile(filename, nil)
- if err != nil {
- return err
- }
-
- currentEnv := map[string]bool{}
- rawEnv := os.Environ()
- for _, rawEnvLine := range rawEnv {
- key := strings.Split(rawEnvLine, "=")[0]
- currentEnv[key] = true
- }
-
- for key, value := range envMap {
- if !currentEnv[key] || overload {
- _ = os.Setenv(key, value)
- }
- }
-
- return nil
-}
-
-func readFile(filename string, lookupFn LookupFn) (envMap map[string]string, err error) {
- file, err := os.Open(filename)
- if err != nil {
- return
- }
- defer file.Close()
-
- return ParseWithLookup(file, lookupFn)
-}
-
-var exportRegex = regexp.MustCompile(`^\s*(?:export\s+)?(.*?)\s*$`)
-
-func parseLine(line string, envMap map[string]string) (key string, value string, err error) {
- return parseLineWithLookup(line, envMap, nil)
-}
-func parseLineWithLookup(line string, envMap map[string]string, lookupFn LookupFn) (key string, value string, err error) {
- if len(line) == 0 {
- err = errors.New("zero length string")
- return
- }
-
- // ditch the comments (but keep quoted hashes)
- if strings.Contains(line, "#") {
- segmentsBetweenHashes := strings.Split(line, "#")
- quotesAreOpen := false
- var segmentsToKeep []string
- for _, segment := range segmentsBetweenHashes {
- if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
- if quotesAreOpen {
- quotesAreOpen = false
- segmentsToKeep = append(segmentsToKeep, segment)
- } else {
- quotesAreOpen = true
- }
- }
-
- if len(segmentsToKeep) == 0 || quotesAreOpen {
- segmentsToKeep = append(segmentsToKeep, segment)
- }
- }
-
- line = strings.Join(segmentsToKeep, "#")
- }
-
- firstEquals := strings.Index(line, "=")
- firstColon := strings.Index(line, ":")
- splitString := strings.SplitN(line, "=", 2)
- if firstColon != -1 && (firstColon < firstEquals || firstEquals == -1) {
- // This is a yaml-style line
- splitString = strings.SplitN(line, ":", 2)
- }
-
- if len(splitString) != 2 {
- err = errors.New("can't separate key from value")
- return
- }
- key = exportRegex.ReplaceAllString(splitString[0], "$1")
-
- // Parse the value
- value = parseValue(splitString[1], envMap, lookupFn)
- return
-}
-
-var (
- singleQuotesRegex = regexp.MustCompile(`\A'(.*)'\z`)
- doubleQuotesRegex = regexp.MustCompile(`\A"(.*)"\z`)
- escapeRegex = regexp.MustCompile(`\\.`)
- unescapeCharsRegex = regexp.MustCompile(`\\([^$])`)
-)
-
-func parseValue(value string, envMap map[string]string, lookupFn LookupFn) string {
-
- // trim
- value = strings.Trim(value, " ")
-
- // check if we've got quoted values or possible escapes
- if len(value) > 1 {
- singleQuotes := singleQuotesRegex.FindStringSubmatch(value)
-
- doubleQuotes := doubleQuotesRegex.FindStringSubmatch(value)
-
- if singleQuotes != nil || doubleQuotes != nil {
- // pull the quotes off the edges
- value = value[1 : len(value)-1]
- }
-
- if doubleQuotes != nil {
- // expand newlines
- value = escapeRegex.ReplaceAllStringFunc(value, func(match string) string {
- c := strings.TrimPrefix(match, `\`)
- switch c {
- case "n":
- return "\n"
- case "r":
- return "\r"
- default:
- return match
- }
- })
- // unescape characters
- value = unescapeCharsRegex.ReplaceAllString(value, "$1")
- }
-
- if singleQuotes == nil {
- value = expandVariables(value, envMap, lookupFn)
- }
- }
-
- return value
-}
-
-var expandVarRegex = regexp.MustCompile(`(\\)?(\$)(\()?\{?([A-Z0-9_]+)?\}?`)
-
-func expandVariables(v string, envMap map[string]string, lookupFn LookupFn) string {
- return expandVarRegex.ReplaceAllStringFunc(v, func(s string) string {
- submatch := expandVarRegex.FindStringSubmatch(s)
-
- if submatch == nil {
- return s
- }
- if submatch[1] == "\\" || submatch[2] == "(" {
- return submatch[0][1:]
- } else if submatch[4] != "" {
- // first check if we have defined this already earlier
- if envMap[submatch[4]] != "" {
- return envMap[submatch[4]]
- }
- if lookupFn == nil {
- return ""
- }
- // if we have not defined it, check the lookup function provided
- // by the user
- s2, ok := lookupFn(submatch[4])
- if ok {
- return s2
- }
- return ""
- }
- return s
- })
-}
-
-func doubleQuoteEscape(line string) string {
- for _, c := range doubleQuoteSpecialChars {
- toReplace := "\\" + string(c)
- if c == '\n' {
- toReplace = `\n`
- }
- if c == '\r' {
- toReplace = `\r`
- }
- line = strings.Replace(line, string(c), toReplace, -1)
- }
- return line
-}
diff --git a/vendor/github.com/compose-spec/compose-go/dotenv/parser.go b/vendor/github.com/compose-spec/compose-go/dotenv/parser.go
deleted file mode 100644
index 85ed2c0088..0000000000
--- a/vendor/github.com/compose-spec/compose-go/dotenv/parser.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package dotenv
-
-import (
- "bytes"
- "errors"
- "fmt"
- "strings"
- "unicode"
-)
-
-const (
- charComment = '#'
- prefixSingleQuote = '\''
- prefixDoubleQuote = '"'
-
- exportPrefix = "export"
-)
-
-func parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error {
- cutset := src
- for {
- cutset = getStatementStart(cutset)
- if cutset == nil {
- // reached end of file
- break
- }
-
- key, left, inherited, err := locateKeyName(cutset)
- if err != nil {
- return err
- }
- if strings.Contains(key, " ") {
- return errors.New("key cannot contain a space")
- }
-
- if inherited {
- if lookupFn == nil {
- lookupFn = noLookupFn
- }
-
- value, ok := lookupFn(key)
- if ok {
- out[key] = value
- }
- cutset = left
- continue
- }
-
- value, left, err := extractVarValue(left, out, lookupFn)
- if err != nil {
- return err
- }
-
- out[key] = value
- cutset = left
- }
-
- return nil
-}
-
-// getStatementPosition returns position of statement begin.
-//
-// It skips any comment line or non-whitespace character.
-func getStatementStart(src []byte) []byte {
- pos := indexOfNonSpaceChar(src)
- if pos == -1 {
- return nil
- }
-
- src = src[pos:]
- if src[0] != charComment {
- return src
- }
-
- // skip comment section
- pos = bytes.IndexFunc(src, isCharFunc('\n'))
- if pos == -1 {
- return nil
- }
-
- return getStatementStart(src[pos:])
-}
-
-// locateKeyName locates and parses key name and returns rest of slice
-func locateKeyName(src []byte) (key string, cutset []byte, inherited bool, err error) {
- // trim "export" and space at beginning
- src = bytes.TrimLeftFunc(bytes.TrimPrefix(src, []byte(exportPrefix)), isSpace)
-
- // locate key name end and validate it in single loop
- offset := 0
-loop:
- for i, char := range src {
- rchar := rune(char)
- if isSpace(rchar) {
- continue
- }
-
- switch char {
- case '=', ':', '\n':
- // library also supports yaml-style value declaration
- key = string(src[0:i])
- offset = i + 1
- inherited = char == '\n'
- break loop
- case '_':
- default:
- // variable name should match [A-Za-z0-9_]
- if unicode.IsLetter(rchar) || unicode.IsNumber(rchar) {
- continue
- }
-
- return "", nil, inherited, fmt.Errorf(
- `unexpected character %q in variable name near %q`,
- string(char), string(src))
- }
- }
-
- if len(src) == 0 {
- return "", nil, inherited, errors.New("zero length string")
- }
-
- // trim whitespace
- key = strings.TrimRightFunc(key, unicode.IsSpace)
- cutset = bytes.TrimLeftFunc(src[offset:], isSpace)
- return key, cutset, inherited, nil
-}
-
-// extractVarValue extracts variable value and returns rest of slice
-func extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (value string, rest []byte, err error) {
- quote, isQuoted := hasQuotePrefix(src)
- if !isQuoted {
- // unquoted value - read until new line
- end := bytes.IndexFunc(src, isNewLine)
- var rest []byte
- if end < 0 {
- value := strings.Split(string(src), "#")[0] // Remove inline comments on unquoted lines
- value = strings.TrimRightFunc(value, unicode.IsSpace)
- return expandVariables(value, envMap, lookupFn), nil, nil
- }
-
- value := strings.Split(string(src[0:end]), "#")[0]
- value = strings.TrimRightFunc(value, unicode.IsSpace)
- rest = src[end:]
- return expandVariables(value, envMap, lookupFn), rest, nil
- }
-
- // lookup quoted string terminator
- for i := 1; i < len(src); i++ {
- if char := src[i]; char != quote {
- continue
- }
-
- // skip escaped quote symbol (\" or \', depends on quote)
- if prevChar := src[i-1]; prevChar == '\\' {
- continue
- }
-
- // trim quotes
- trimFunc := isCharFunc(rune(quote))
- value = string(bytes.TrimLeftFunc(bytes.TrimRightFunc(src[0:i], trimFunc), trimFunc))
- if quote == prefixDoubleQuote {
- // unescape newlines for double quote (this is compat feature)
- // and expand environment variables
- value = expandVariables(expandEscapes(value), envMap, lookupFn)
- }
-
- return value, src[i+1:], nil
- }
-
- // return formatted error if quoted string is not terminated
- valEndIndex := bytes.IndexFunc(src, isCharFunc('\n'))
- if valEndIndex == -1 {
- valEndIndex = len(src)
- }
-
- return "", nil, fmt.Errorf("unterminated quoted value %s", src[:valEndIndex])
-}
-
-func expandEscapes(str string) string {
- out := escapeRegex.ReplaceAllStringFunc(str, func(match string) string {
- c := strings.TrimPrefix(match, `\`)
- switch c {
- case "n":
- return "\n"
- case "r":
- return "\r"
- default:
- return match
- }
- })
- return unescapeCharsRegex.ReplaceAllString(out, "$1")
-}
-
-func indexOfNonSpaceChar(src []byte) int {
- return bytes.IndexFunc(src, func(r rune) bool {
- return !unicode.IsSpace(r)
- })
-}
-
-// hasQuotePrefix reports whether charset starts with single or double quote and returns quote character
-func hasQuotePrefix(src []byte) (quote byte, isQuoted bool) {
- if len(src) == 0 {
- return 0, false
- }
-
- switch prefix := src[0]; prefix {
- case prefixDoubleQuote, prefixSingleQuote:
- return prefix, true
- default:
- return 0, false
- }
-}
-
-func isCharFunc(char rune) func(rune) bool {
- return func(v rune) bool {
- return v == char
- }
-}
-
-// isSpace reports whether the rune is a space character but not line break character
-//
-// this differs from unicode.IsSpace, which also applies line break as space
-func isSpace(r rune) bool {
- switch r {
- case '\t', '\v', '\f', '\r', ' ', 0x85, 0xA0:
- return true
- }
- return false
-}
-
-// isNewLine reports whether the rune is a new line character
-func isNewLine(r rune) bool {
- return r == '\n'
-}
diff --git a/vendor/github.com/compose-spec/compose-go/errdefs/errors.go b/vendor/github.com/compose-spec/compose-go/errdefs/errors.go
deleted file mode 100644
index a54407007e..0000000000
--- a/vendor/github.com/compose-spec/compose-go/errdefs/errors.go
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package errdefs
-
-import "errors"
-
-var (
- // ErrNotFound is returned when an object is not found
- ErrNotFound = errors.New("not found")
-
- // ErrInvalid is returned when a compose project is invalid
- ErrInvalid = errors.New("invalid compose project")
-
- // ErrUnsupported is returned when a compose project uses an unsupported attribute
- ErrUnsupported = errors.New("unsupported attribute")
-
- // ErrIncompatible is returned when a compose project uses an incompatible attribute
- ErrIncompatible = errors.New("incompatible attribute")
-)
-
-// IsNotFoundError returns true if the unwrapped error is ErrNotFound
-func IsNotFoundError(err error) bool {
- return errors.Is(err, ErrNotFound)
-}
-
-// IsInvalidError returns true if the unwrapped error is ErrInvalid
-func IsInvalidError(err error) bool {
- return errors.Is(err, ErrInvalid)
-}
-
-// IsUnsupportedError returns true if the unwrapped error is ErrUnsupported
-func IsUnsupportedError(err error) bool {
- return errors.Is(err, ErrUnsupported)
-}
-
-// IsUnsupportedError returns true if the unwrapped error is ErrIncompatible
-func IsIncompatibleError(err error) bool {
- return errors.Is(err, ErrIncompatible)
-}
diff --git a/vendor/github.com/compose-spec/compose-go/interpolation/interpolation.go b/vendor/github.com/compose-spec/compose-go/interpolation/interpolation.go
deleted file mode 100644
index 9c36e6d8b1..0000000000
--- a/vendor/github.com/compose-spec/compose-go/interpolation/interpolation.go
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package interpolation
-
-import (
- "os"
- "strings"
-
- "github.com/compose-spec/compose-go/template"
- "github.com/pkg/errors"
-)
-
-// Options supported by Interpolate
-type Options struct {
- // LookupValue from a key
- LookupValue LookupValue
- // TypeCastMapping maps key paths to functions to cast to a type
- TypeCastMapping map[Path]Cast
- // Substitution function to use
- Substitute func(string, template.Mapping) (string, error)
-}
-
-// LookupValue is a function which maps from variable names to values.
-// Returns the value as a string and a bool indicating whether
-// the value is present, to distinguish between an empty string
-// and the absence of a value.
-type LookupValue func(key string) (string, bool)
-
-// Cast a value to a new type, or return an error if the value can't be cast
-type Cast func(value string) (interface{}, error)
-
-// Interpolate replaces variables in a string with the values from a mapping
-func Interpolate(config map[string]interface{}, opts Options) (map[string]interface{}, error) {
- if opts.LookupValue == nil {
- opts.LookupValue = os.LookupEnv
- }
- if opts.TypeCastMapping == nil {
- opts.TypeCastMapping = make(map[Path]Cast)
- }
- if opts.Substitute == nil {
- opts.Substitute = template.Substitute
- }
-
- out := map[string]interface{}{}
-
- for key, value := range config {
- interpolatedValue, err := recursiveInterpolate(value, NewPath(key), opts)
- if err != nil {
- return out, err
- }
- out[key] = interpolatedValue
- }
-
- return out, nil
-}
-
-func recursiveInterpolate(value interface{}, path Path, opts Options) (interface{}, error) {
- switch value := value.(type) {
- case string:
- newValue, err := opts.Substitute(value, template.Mapping(opts.LookupValue))
- if err != nil || newValue == value {
- return value, newPathError(path, err)
- }
- caster, ok := opts.getCasterForPath(path)
- if !ok {
- return newValue, nil
- }
- casted, err := caster(newValue)
- return casted, newPathError(path, errors.Wrap(err, "failed to cast to expected type"))
-
- case map[string]interface{}:
- out := map[string]interface{}{}
- for key, elem := range value {
- interpolatedElem, err := recursiveInterpolate(elem, path.Next(key), opts)
- if err != nil {
- return nil, err
- }
- out[key] = interpolatedElem
- }
- return out, nil
-
- case []interface{}:
- out := make([]interface{}, len(value))
- for i, elem := range value {
- interpolatedElem, err := recursiveInterpolate(elem, path.Next(PathMatchList), opts)
- if err != nil {
- return nil, err
- }
- out[i] = interpolatedElem
- }
- return out, nil
-
- default:
- return value, nil
- }
-}
-
-func newPathError(path Path, err error) error {
- switch err := err.(type) {
- case nil:
- return nil
- case *template.InvalidTemplateError:
- return errors.Errorf(
- "invalid interpolation format for %s: %#v. You may need to escape any $ with another $",
- path, err.Template)
- default:
- return errors.Wrapf(err, "error while interpolating %s", path)
- }
-}
-
-const pathSeparator = "."
-
-// PathMatchAll is a token used as part of a Path to match any key at that level
-// in the nested structure
-const PathMatchAll = "*"
-
-// PathMatchList is a token used as part of a Path to match items in a list
-const PathMatchList = "[]"
-
-// Path is a dotted path of keys to a value in a nested mapping structure. A *
-// section in a path will match any key in the mapping structure.
-type Path string
-
-// NewPath returns a new Path
-func NewPath(items ...string) Path {
- return Path(strings.Join(items, pathSeparator))
-}
-
-// Next returns a new path by append part to the current path
-func (p Path) Next(part string) Path {
- return Path(string(p) + pathSeparator + part)
-}
-
-func (p Path) parts() []string {
- return strings.Split(string(p), pathSeparator)
-}
-
-func (p Path) matches(pattern Path) bool {
- patternParts := pattern.parts()
- parts := p.parts()
-
- if len(patternParts) != len(parts) {
- return false
- }
- for index, part := range parts {
- switch patternParts[index] {
- case PathMatchAll, part:
- continue
- default:
- return false
- }
- }
- return true
-}
-
-func (o Options) getCasterForPath(path Path) (Cast, bool) {
- for pattern, caster := range o.TypeCastMapping {
- if path.matches(pattern) {
- return caster, true
- }
- }
- return nil, false
-}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/full-example.yml b/vendor/github.com/compose-spec/compose-go/loader/full-example.yml
deleted file mode 100644
index 4f17450ef7..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/full-example.yml
+++ /dev/null
@@ -1,419 +0,0 @@
-name: Full_Example_project_name
-services:
- foo:
-
- build:
- context: ./dir
- dockerfile: Dockerfile
- args:
- foo: bar
- ssh:
- - default
- target: foo
- network: foo
- cache_from:
- - foo
- - bar
- labels: [FOO=BAR]
-
-
- cap_add:
- - ALL
-
- cap_drop:
- - NET_ADMIN
- - SYS_ADMIN
-
- cgroup_parent: m-executor-abcd
-
- # String or list
- command: bundle exec thin -p 3000
- # command: ["bundle", "exec", "thin", "-p", "3000"]
-
- configs:
- - config1
- - source: config2
- target: /my_config
- uid: '103'
- gid: '103'
- mode: 0440
-
- container_name: my-web-container
-
- depends_on:
- - db
- - redis
-
- deploy:
- mode: replicated
- replicas: 6
- labels: [FOO=BAR]
- rollback_config:
- parallelism: 3
- delay: 10s
- failure_action: continue
- monitor: 60s
- max_failure_ratio: 0.3
- order: start-first
- update_config:
- parallelism: 3
- delay: 10s
- failure_action: continue
- monitor: 60s
- max_failure_ratio: 0.3
- order: start-first
- resources:
- limits:
- cpus: '0.001'
- memory: 50M
- reservations:
- cpus: '0.0001'
- memory: 20M
- generic_resources:
- - discrete_resource_spec:
- kind: 'gpu'
- value: 2
- - discrete_resource_spec:
- kind: 'ssd'
- value: 1
- restart_policy:
- condition: on-failure
- delay: 5s
- max_attempts: 3
- window: 120s
- placement:
- constraints: [node=foo]
- max_replicas_per_node: 5
- preferences:
- - spread: node.labels.az
- endpoint_mode: dnsrr
-
- device_cgroup_rules:
- - "c 1:3 mr"
- - "a 7:* rmw"
-
- devices:
- - "/dev/ttyUSB0:/dev/ttyUSB0"
-
- # String or list
- # dns: 8.8.8.8
- dns:
- - 8.8.8.8
- - 9.9.9.9
-
- # String or list
- # dns_search: example.com
- dns_search:
- - dc1.example.com
- - dc2.example.com
-
- domainname: foo.com
-
- # String or list
- # entrypoint: /code/entrypoint.sh -p 3000
- entrypoint: ["/code/entrypoint.sh", "-p", "3000"]
-
- # String or list
- # env_file: .env
- env_file:
- - ./example1.env
- - ./example2.env
-
- # Mapping or list
- # Mapping values can be strings, numbers or null
- # Booleans are not allowed - must be quoted
- environment:
- BAZ: baz_from_service_def
- QUX:
- # environment:
- # - RACK_ENV=development
- # - SHOW=true
- # - SESSION_SECRET
-
- # Items can be strings or numbers
- expose:
- - "3000"
- - 8000
-
- external_links:
- - redis_1
- - project_db_1:mysql
- - project_db_1:postgresql
-
- # Mapping or list
- # Mapping values must be strings
- # extra_hosts:
- # somehost: "162.242.195.82"
- # otherhost: "50.31.209.229"
- extra_hosts:
- - "somehost:162.242.195.82"
- - "otherhost:50.31.209.229"
-
- hostname: foo
-
- healthcheck:
- test: echo "hello world"
- interval: 10s
- timeout: 1s
- retries: 5
- start_period: 15s
-
- # Any valid image reference - repo, tag, id, sha
- image: redis
- # image: ubuntu:14.04
- # image: tutum/influxdb
- # image: example-registry.com:4000/postgresql
- # image: a4bc65fd
- # image: busybox@sha256:38a203e1986cf79639cfb9b2e1d6e773de84002feea2d4eb006b52004ee8502d
-
- ipc: host
-
- # Mapping or list
- # Mapping values can be strings, numbers or null
- labels:
- com.example.description: "Accounting webapp"
- com.example.number: 42
- com.example.empty-label:
- # labels:
- # - "com.example.description=Accounting webapp"
- # - "com.example.number=42"
- # - "com.example.empty-label"
-
- links:
- - db
- - db:database
- - redis
-
- logging:
- driver: syslog
- options:
- syslog-address: "tcp://192.168.0.42:123"
-
- mac_address: 02:42:ac:11:65:43
-
- # network_mode: "bridge"
- # network_mode: "host"
- # network_mode: "none"
- # Use the network mode of an arbitrary container from another service
- # network_mode: "service:db"
- # Use the network mode of another container, specified by name or id
- # network_mode: "container:some-container"
- network_mode: "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b"
-
- networks:
- some-network:
- aliases:
- - alias1
- - alias3
- other-network:
- ipv4_address: 172.16.238.10
- ipv6_address: 2001:3984:3989::10
- other-other-network:
-
- pid: "host"
-
- ports:
- - 3000
- - "3001-3005"
- - "8000:8000"
- - "9090-9091:8080-8081"
- - "49100:22"
- - "127.0.0.1:8001:8001"
- - "127.0.0.1:5000-5010:5000-5010"
-
- privileged: true
-
- read_only: true
-
- restart: always
-
- secrets:
- - secret1
- - source: secret2
- target: my_secret
- uid: '103'
- gid: '103'
- mode: 0440
-
- security_opt:
- - label=level:s0:c100,c200
- - label=type:svirt_apache_t
-
- stdin_open: true
-
- stop_grace_period: 20s
-
- stop_signal: SIGUSR1
-
- sysctls:
- net.core.somaxconn: 1024
- net.ipv4.tcp_syncookies: 0
-
- # String or list
- # tmpfs: /run
- tmpfs:
- - /run
- - /tmp
-
- tty: true
-
- ulimits:
- # Single number or mapping with soft + hard limits
- nproc: 65535
- nofile:
- soft: 20000
- hard: 40000
-
- user: someone
-
- volumes:
- # Just specify a path and let the Engine create a volume
- - /var/lib/mysql
- # Specify an absolute path mapping
- - /opt/data:/var/lib/mysql
- # Path on the host, relative to the Compose file
- - .:/code
- - ./static:/var/www/html
- # User-relative path
- - ~/configs:/etc/configs:ro
- # Named volume
- - datavolume:/var/lib/mysql
- - type: bind
- source: ./opt
- target: /opt
- consistency: cached
- - type: tmpfs
- target: /opt
- tmpfs:
- size: 10000
-
- working_dir: /code
- x-bar: baz
- x-foo: bar
-
-networks:
- # Entries can be null, which specifies simply that a network
- # called "{project name}_some-network" should be created and
- # use the default driver
- some-network:
-
- other-network:
- driver: overlay
-
- driver_opts:
- # Values can be strings or numbers
- foo: "bar"
- baz: 1
-
- ipam:
- driver: overlay
- # driver_opts:
- # # Values can be strings or numbers
- # com.docker.network.enable_ipv6: "true"
- # com.docker.network.numeric_value: 1
- config:
- - subnet: 172.28.0.0/16
- ip_range: 172.28.5.0/24
- gateway: 172.28.5.254
- aux_addresses:
- host1: 172.28.1.5
- host2: 172.28.1.6
- host3: 172.28.1.7
- - subnet: 2001:3984:3989::/64
- gateway: 2001:3984:3989::1
-
- labels:
- foo: bar
-
- external-network:
- # Specifies that a pre-existing network called "external-network"
- # can be referred to within this file as "external-network"
- external: true
-
- other-external-network:
- # Specifies that a pre-existing network called "my-cool-network"
- # can be referred to within this file as "other-external-network"
- external:
- name: my-cool-network
- x-bar: baz
- x-foo: bar
-
-volumes:
- # Entries can be null, which specifies simply that a volume
- # called "{project name}_some-volume" should be created and
- # use the default driver
- some-volume:
-
- other-volume:
- driver: flocker
-
- driver_opts:
- # Values can be strings or numbers
- foo: "bar"
- baz: 1
- labels:
- foo: bar
-
- another-volume:
- name: "user_specified_name"
- driver: vsphere
-
- driver_opts:
- # Values can be strings or numbers
- foo: "bar"
- baz: 1
-
- external-volume:
- # Specifies that a pre-existing volume called "external-volume"
- # can be referred to within this file as "external-volume"
- external: true
-
- other-external-volume:
- # Specifies that a pre-existing volume called "my-cool-volume"
- # can be referred to within this file as "other-external-volume"
- # This example uses the deprecated "volume.external.name" (replaced by "volume.name")
- external:
- name: my-cool-volume
-
- external-volume3:
- # Specifies that a pre-existing volume called "this-is-volume3"
- # can be referred to within this file as "external-volume3"
- name: this-is-volume3
- external: true
- x-bar: baz
- x-foo: bar
-
-configs:
- config1:
- file: ./config_data
- labels:
- foo: bar
- config2:
- external:
- name: my_config
- config3:
- external: true
- config4:
- name: foo
- x-bar: baz
- x-foo: bar
-
-secrets:
- secret1:
- file: ./secret_data
- labels:
- foo: bar
- secret2:
- external:
- name: my_secret
- secret3:
- external: true
- secret4:
- name: bar
- x-bar: baz
- x-foo: bar
-x-bar: baz
-x-foo: bar
-x-nested:
- bar: baz
- foo: bar
diff --git a/vendor/github.com/compose-spec/compose-go/loader/interpolate.go b/vendor/github.com/compose-spec/compose-go/loader/interpolate.go
deleted file mode 100644
index 97a19f5dd8..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/interpolate.go
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package loader
-
-import (
- "strconv"
- "strings"
-
- interp "github.com/compose-spec/compose-go/interpolation"
- "github.com/pkg/errors"
-)
-
-var interpolateTypeCastMapping = map[interp.Path]interp.Cast{
- servicePath("configs", interp.PathMatchList, "mode"): toInt,
- servicePath("cpu_count"): toInt64,
- servicePath("cpu_percent"): toFloat,
- servicePath("cpu_period"): toInt64,
- servicePath("cpu_quota"): toInt64,
- servicePath("cpu_rt_period"): toInt64,
- servicePath("cpu_rt_runtime"): toInt64,
- servicePath("cpus"): toFloat32,
- servicePath("cpu_shares"): toInt64,
- servicePath("init"): toBoolean,
- servicePath("deploy", "replicas"): toInt,
- servicePath("deploy", "update_config", "parallelism"): toInt,
- servicePath("deploy", "update_config", "max_failure_ratio"): toFloat,
- servicePath("deploy", "rollback_config", "parallelism"): toInt,
- servicePath("deploy", "rollback_config", "max_failure_ratio"): toFloat,
- servicePath("deploy", "restart_policy", "max_attempts"): toInt,
- servicePath("deploy", "placement", "max_replicas_per_node"): toInt,
- servicePath("healthcheck", "retries"): toInt,
- servicePath("healthcheck", "disable"): toBoolean,
- servicePath("mem_limit"): toUnitBytes,
- servicePath("mem_reservation"): toUnitBytes,
- servicePath("memswap_limit"): toUnitBytes,
- servicePath("mem_swappiness"): toUnitBytes,
- servicePath("oom_kill_disable"): toBoolean,
- servicePath("oom_score_adj"): toInt64,
- servicePath("pids_limit"): toInt64,
- servicePath("ports", interp.PathMatchList, "target"): toInt,
- servicePath("privileged"): toBoolean,
- servicePath("read_only"): toBoolean,
- servicePath("scale"): toInt,
- servicePath("secrets", interp.PathMatchList, "mode"): toInt,
- servicePath("shm_size"): toUnitBytes,
- servicePath("stdin_open"): toBoolean,
- servicePath("stop_grace_period"): toDuration,
- servicePath("tty"): toBoolean,
- servicePath("ulimits", interp.PathMatchAll): toInt,
- servicePath("ulimits", interp.PathMatchAll, "hard"): toInt,
- servicePath("ulimits", interp.PathMatchAll, "soft"): toInt,
- servicePath("volumes", interp.PathMatchList, "read_only"): toBoolean,
- servicePath("volumes", interp.PathMatchList, "volume", "nocopy"): toBoolean,
- servicePath("volumes", interp.PathMatchList, "tmpfs", "size"): toUnitBytes,
- iPath("networks", interp.PathMatchAll, "external"): toBoolean,
- iPath("networks", interp.PathMatchAll, "internal"): toBoolean,
- iPath("networks", interp.PathMatchAll, "attachable"): toBoolean,
- iPath("networks", interp.PathMatchAll, "enable_ipv6"): toBoolean,
- iPath("volumes", interp.PathMatchAll, "external"): toBoolean,
- iPath("secrets", interp.PathMatchAll, "external"): toBoolean,
- iPath("configs", interp.PathMatchAll, "external"): toBoolean,
-}
-
-func iPath(parts ...string) interp.Path {
- return interp.NewPath(parts...)
-}
-
-func servicePath(parts ...string) interp.Path {
- return iPath(append([]string{"services", interp.PathMatchAll}, parts...)...)
-}
-
-func toInt(value string) (interface{}, error) {
- return strconv.Atoi(value)
-}
-
-func toInt64(value string) (interface{}, error) {
- return strconv.ParseInt(value, 10, 64)
-}
-
-func toUnitBytes(value string) (interface{}, error) {
- return transformSize(value)
-}
-
-func toDuration(value string) (interface{}, error) {
- return transformStringToDuration(value)
-}
-
-func toFloat(value string) (interface{}, error) {
- return strconv.ParseFloat(value, 64)
-}
-
-func toFloat32(value string) (interface{}, error) {
- f, err := strconv.ParseFloat(value, 32)
- if err != nil {
- return nil, err
- }
- return float32(f), nil
-}
-
-// should match http://yaml.org/type/bool.html
-func toBoolean(value string) (interface{}, error) {
- switch strings.ToLower(value) {
- case "y", "yes", "true", "on":
- return true, nil
- case "n", "no", "false", "off":
- return false, nil
- default:
- return nil, errors.Errorf("invalid boolean: %s", value)
- }
-}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/loader.go b/vendor/github.com/compose-spec/compose-go/loader/loader.go
deleted file mode 100644
index 895bdb2609..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/loader.go
+++ /dev/null
@@ -1,1182 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package loader
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path"
- "path/filepath"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "time"
-
- "github.com/compose-spec/compose-go/consts"
- "github.com/compose-spec/compose-go/dotenv"
- interp "github.com/compose-spec/compose-go/interpolation"
- "github.com/compose-spec/compose-go/schema"
- "github.com/compose-spec/compose-go/template"
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/go-units"
- "github.com/mattn/go-shellwords"
- "github.com/mitchellh/mapstructure"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "gopkg.in/yaml.v2"
-)
-
-// Options supported by Load
-type Options struct {
- // Skip schema validation
- SkipValidation bool
- // Skip interpolation
- SkipInterpolation bool
- // Skip normalization
- SkipNormalization bool
- // Resolve paths
- ResolvePaths bool
- // Convert Windows paths
- ConvertWindowsPaths bool
- // Skip consistency check
- SkipConsistencyCheck bool
- // Skip extends
- SkipExtends bool
- // Interpolation options
- Interpolate *interp.Options
- // Discard 'env_file' entries after resolving to 'environment' section
- discardEnvFiles bool
- // Set project projectName
- projectName string
- // Indicates when the projectName was imperatively set or guessed from path
- projectNameImperativelySet bool
-}
-
-func (o *Options) SetProjectName(name string, imperativelySet bool) {
- o.projectName = normalizeProjectName(name)
- o.projectNameImperativelySet = imperativelySet
-}
-
-func (o Options) GetProjectName() (string, bool) {
- return o.projectName, o.projectNameImperativelySet
-}
-
-// serviceRef identifies a reference to a service. It's used to detect cyclic
-// references in "extends".
-type serviceRef struct {
- filename string
- service string
-}
-
-type cycleTracker struct {
- loaded []serviceRef
-}
-
-func (ct *cycleTracker) Add(filename, service string) error {
- toAdd := serviceRef{filename: filename, service: service}
- for _, loaded := range ct.loaded {
- if toAdd == loaded {
- // Create an error message of the form:
- // Circular reference:
- // service-a in docker-compose.yml
- // extends service-b in docker-compose.yml
- // extends service-a in docker-compose.yml
- errLines := []string{
- "Circular reference:",
- fmt.Sprintf(" %s in %s", ct.loaded[0].service, ct.loaded[0].filename),
- }
- for _, service := range append(ct.loaded[1:], toAdd) {
- errLines = append(errLines, fmt.Sprintf(" extends %s in %s", service.service, service.filename))
- }
-
- return errors.New(strings.Join(errLines, "\n"))
- }
- }
-
- ct.loaded = append(ct.loaded, toAdd)
- return nil
-}
-
-// WithDiscardEnvFiles sets the Options to discard the `env_file` section after resolving to
-// the `environment` section
-func WithDiscardEnvFiles(opts *Options) {
- opts.discardEnvFiles = true
-}
-
-// WithSkipValidation sets the Options to skip validation when loading sections
-func WithSkipValidation(opts *Options) {
- opts.SkipValidation = true
-}
-
-// ParseYAML reads the bytes from a file, parses the bytes into a mapping
-// structure, and returns it.
-func ParseYAML(source []byte) (map[string]interface{}, error) {
- var cfg interface{}
- if err := yaml.Unmarshal(source, &cfg); err != nil {
- return nil, err
- }
- cfgMap, ok := cfg.(map[interface{}]interface{})
- if !ok {
- return nil, errors.Errorf("Top-level object must be a mapping")
- }
- converted, err := convertToStringKeysRecursive(cfgMap, "")
- if err != nil {
- return nil, err
- }
- return converted.(map[string]interface{}), nil
-}
-
-// Load reads a ConfigDetails and returns a fully loaded configuration
-func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.Project, error) {
- if len(configDetails.ConfigFiles) < 1 {
- return nil, errors.Errorf("No files specified")
- }
-
- opts := &Options{
- Interpolate: &interp.Options{
- Substitute: template.Substitute,
- LookupValue: configDetails.LookupEnv,
- TypeCastMapping: interpolateTypeCastMapping,
- },
- }
-
- for _, op := range options {
- op(opts)
- }
-
- var configs []*types.Config
- for i, file := range configDetails.ConfigFiles {
- configDict := file.Config
- if configDict == nil {
- dict, err := parseConfig(file.Content, opts)
- if err != nil {
- return nil, err
- }
- configDict = dict
- file.Config = dict
- configDetails.ConfigFiles[i] = file
- }
-
- if !opts.SkipValidation {
- if err := schema.Validate(configDict); err != nil {
- return nil, err
- }
- }
-
- configDict = groupXFieldsIntoExtensions(configDict)
-
- cfg, err := loadSections(file.Filename, configDict, configDetails, opts)
- if err != nil {
- return nil, err
- }
- if opts.discardEnvFiles {
- for i := range cfg.Services {
- cfg.Services[i].EnvFile = nil
- }
- }
-
- configs = append(configs, cfg)
- }
-
- model, err := merge(configs)
- if err != nil {
- return nil, err
- }
-
- for _, s := range model.Services {
- var newEnvFiles types.StringList
- for _, ef := range s.EnvFile {
- newEnvFiles = append(newEnvFiles, absPath(configDetails.WorkingDir, ef))
- }
- s.EnvFile = newEnvFiles
- }
-
- projectName, projectNameImperativelySet := opts.GetProjectName()
- model.Name = normalizeProjectName(model.Name)
- if !projectNameImperativelySet && model.Name != "" {
- projectName = model.Name
- }
-
- if projectName != "" {
- configDetails.Environment[consts.ComposeProjectName] = projectName
- }
- project := &types.Project{
- Name: projectName,
- WorkingDir: configDetails.WorkingDir,
- Services: model.Services,
- Networks: model.Networks,
- Volumes: model.Volumes,
- Secrets: model.Secrets,
- Configs: model.Configs,
- Environment: configDetails.Environment,
- Extensions: model.Extensions,
- }
-
- if !opts.SkipNormalization {
- err = normalize(project, opts.ResolvePaths)
- if err != nil {
- return nil, err
- }
- }
-
- if !opts.SkipConsistencyCheck {
- err = checkConsistency(project)
- if err != nil {
- return nil, err
- }
- }
-
- return project, nil
-}
-
-func normalizeProjectName(s string) string {
- r := regexp.MustCompile("[a-z0-9_-]")
- s = strings.ToLower(s)
- s = strings.Join(r.FindAllString(s, -1), "")
- return strings.TrimLeft(s, "_-")
-}
-
-func parseConfig(b []byte, opts *Options) (map[string]interface{}, error) {
- yml, err := ParseYAML(b)
- if err != nil {
- return nil, err
- }
- if !opts.SkipInterpolation {
- return interp.Interpolate(yml, *opts.Interpolate)
- }
- return yml, err
-}
-
-func groupXFieldsIntoExtensions(dict map[string]interface{}) map[string]interface{} {
- extras := map[string]interface{}{}
- for key, value := range dict {
- if strings.HasPrefix(key, "x-") {
- extras[key] = value
- delete(dict, key)
- }
- if d, ok := value.(map[string]interface{}); ok {
- dict[key] = groupXFieldsIntoExtensions(d)
- }
- }
- if len(extras) > 0 {
- dict["extensions"] = extras
- }
- return dict
-}
-
-func loadSections(filename string, config map[string]interface{}, configDetails types.ConfigDetails, opts *Options) (*types.Config, error) {
- var err error
- cfg := types.Config{
- Filename: filename,
- }
- name := ""
- if n, ok := config["name"]; ok {
- name, ok = n.(string)
- if !ok {
- return nil, errors.New("project name must be a string")
- }
- }
- cfg.Name = name
- cfg.Services, err = LoadServices(filename, getSection(config, "services"), configDetails.WorkingDir, configDetails.LookupEnv, opts)
- if err != nil {
- return nil, err
- }
-
- cfg.Networks, err = LoadNetworks(getSection(config, "networks"))
- if err != nil {
- return nil, err
- }
- cfg.Volumes, err = LoadVolumes(getSection(config, "volumes"))
- if err != nil {
- return nil, err
- }
- cfg.Secrets, err = LoadSecrets(getSection(config, "secrets"), configDetails, opts.ResolvePaths)
- if err != nil {
- return nil, err
- }
- cfg.Configs, err = LoadConfigObjs(getSection(config, "configs"), configDetails, opts.ResolvePaths)
- if err != nil {
- return nil, err
- }
- extensions := getSection(config, "extensions")
- if len(extensions) > 0 {
- cfg.Extensions = extensions
- }
- return &cfg, nil
-}
-
-func getSection(config map[string]interface{}, key string) map[string]interface{} {
- section, ok := config[key]
- if !ok {
- return make(map[string]interface{})
- }
- return section.(map[string]interface{})
-}
-
-// ForbiddenPropertiesError is returned when there are properties in the Compose
-// file that are forbidden.
-type ForbiddenPropertiesError struct {
- Properties map[string]string
-}
-
-func (e *ForbiddenPropertiesError) Error() string {
- return "Configuration contains forbidden properties"
-}
-
-// Transform converts the source into the target struct with compose types transformer
-// and the specified transformers if any.
-func Transform(source interface{}, target interface{}, additionalTransformers ...Transformer) error {
- data := mapstructure.Metadata{}
- config := &mapstructure.DecoderConfig{
- DecodeHook: mapstructure.ComposeDecodeHookFunc(
- createTransformHook(additionalTransformers...),
- mapstructure.StringToTimeDurationHookFunc()),
- Result: target,
- Metadata: &data,
- }
- decoder, err := mapstructure.NewDecoder(config)
- if err != nil {
- return err
- }
- return decoder.Decode(source)
-}
-
-// TransformerFunc defines a function to perform the actual transformation
-type TransformerFunc func(interface{}) (interface{}, error)
-
-// Transformer defines a map to type transformer
-type Transformer struct {
- TypeOf reflect.Type
- Func TransformerFunc
-}
-
-func createTransformHook(additionalTransformers ...Transformer) mapstructure.DecodeHookFuncType {
- transforms := map[reflect.Type]func(interface{}) (interface{}, error){
- reflect.TypeOf(types.External{}): transformExternal,
- reflect.TypeOf(types.HealthCheckTest{}): transformHealthCheckTest,
- reflect.TypeOf(types.ShellCommand{}): transformShellCommand,
- reflect.TypeOf(types.StringList{}): transformStringList,
- reflect.TypeOf(map[string]string{}): transformMapStringString,
- reflect.TypeOf(types.UlimitsConfig{}): transformUlimits,
- reflect.TypeOf(types.UnitBytes(0)): transformSize,
- reflect.TypeOf([]types.ServicePortConfig{}): transformServicePort,
- reflect.TypeOf(types.ServiceSecretConfig{}): transformFileReferenceConfig,
- reflect.TypeOf(types.ServiceConfigObjConfig{}): transformFileReferenceConfig,
- reflect.TypeOf(types.StringOrNumberList{}): transformStringOrNumberList,
- reflect.TypeOf(map[string]*types.ServiceNetworkConfig{}): transformServiceNetworkMap,
- reflect.TypeOf(types.Mapping{}): transformMappingOrListFunc("=", false),
- reflect.TypeOf(types.MappingWithEquals{}): transformMappingOrListFunc("=", true),
- reflect.TypeOf(types.Labels{}): transformMappingOrListFunc("=", false),
- reflect.TypeOf(types.MappingWithColon{}): transformMappingOrListFunc(":", false),
- reflect.TypeOf(types.HostsList{}): transformListOrMappingFunc(":", false),
- reflect.TypeOf(types.ServiceVolumeConfig{}): transformServiceVolumeConfig,
- reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
- reflect.TypeOf(types.Duration(0)): transformStringToDuration,
- reflect.TypeOf(types.DependsOnConfig{}): transformDependsOnConfig,
- reflect.TypeOf(types.ExtendsConfig{}): transformExtendsConfig,
- reflect.TypeOf(types.DeviceRequest{}): transformServiceDeviceRequest,
- reflect.TypeOf(types.SSHConfig{}): transformSSHConfig,
- }
-
- for _, transformer := range additionalTransformers {
- transforms[transformer.TypeOf] = transformer.Func
- }
-
- return func(_ reflect.Type, target reflect.Type, data interface{}) (interface{}, error) {
- transform, ok := transforms[target]
- if !ok {
- return data, nil
- }
- return transform(data)
- }
-}
-
-// keys need to be converted to strings for jsonschema
-func convertToStringKeysRecursive(value interface{}, keyPrefix string) (interface{}, error) {
- if mapping, ok := value.(map[interface{}]interface{}); ok {
- dict := make(map[string]interface{})
- for key, entry := range mapping {
- str, ok := key.(string)
- if !ok {
- return nil, formatInvalidKeyError(keyPrefix, key)
- }
- var newKeyPrefix string
- if keyPrefix == "" {
- newKeyPrefix = str
- } else {
- newKeyPrefix = fmt.Sprintf("%s.%s", keyPrefix, str)
- }
- convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix)
- if err != nil {
- return nil, err
- }
- dict[str] = convertedEntry
- }
- return dict, nil
- }
- if list, ok := value.([]interface{}); ok {
- var convertedList []interface{}
- for index, entry := range list {
- newKeyPrefix := fmt.Sprintf("%s[%d]", keyPrefix, index)
- convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix)
- if err != nil {
- return nil, err
- }
- convertedList = append(convertedList, convertedEntry)
- }
- return convertedList, nil
- }
- return value, nil
-}
-
-func formatInvalidKeyError(keyPrefix string, key interface{}) error {
- var location string
- if keyPrefix == "" {
- location = "at top level"
- } else {
- location = fmt.Sprintf("in %s", keyPrefix)
- }
- return errors.Errorf("Non-string key %s: %#v", location, key)
-}
-
-// LoadServices produces a ServiceConfig map from a compose file Dict
-// the servicesDict is not validated if directly used. Use Load() to enable validation
-func LoadServices(filename string, servicesDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, opts *Options) ([]types.ServiceConfig, error) {
- var services []types.ServiceConfig
-
- x, ok := servicesDict["extensions"]
- if ok {
- // as a top-level attribute, "services" doesn't support extensions, and a service can be named `x-foo`
- for k, v := range x.(map[string]interface{}) {
- servicesDict[k] = v
- }
- }
-
- for name := range servicesDict {
- serviceConfig, err := loadServiceWithExtends(filename, name, servicesDict, workingDir, lookupEnv, opts, &cycleTracker{})
- if err != nil {
- return nil, err
- }
-
- services = append(services, *serviceConfig)
- }
-
- return services, nil
-}
-
-func loadServiceWithExtends(filename, name string, servicesDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, opts *Options, ct *cycleTracker) (*types.ServiceConfig, error) {
- if err := ct.Add(filename, name); err != nil {
- return nil, err
- }
-
- target, ok := servicesDict[name]
- if !ok {
- return nil, fmt.Errorf("cannot extend service %q in %s: service not found", name, filename)
- }
-
- serviceConfig, err := LoadService(name, target.(map[string]interface{}), workingDir, lookupEnv, opts.ResolvePaths, opts.ConvertWindowsPaths)
- if err != nil {
- return nil, err
- }
-
- if serviceConfig.Extends != nil && !opts.SkipExtends {
- baseServiceName := *serviceConfig.Extends["service"]
- var baseService *types.ServiceConfig
- if file := serviceConfig.Extends["file"]; file == nil {
- baseService, err = loadServiceWithExtends(filename, baseServiceName, servicesDict, workingDir, lookupEnv, opts, ct)
- if err != nil {
- return nil, err
- }
- } else {
- // Resolve the path to the imported file, and load it.
- baseFilePath := absPath(workingDir, *file)
-
- bytes, err := ioutil.ReadFile(baseFilePath)
- if err != nil {
- return nil, err
- }
-
- baseFile, err := parseConfig(bytes, opts)
- if err != nil {
- return nil, err
- }
-
- baseFileServices := getSection(baseFile, "services")
- baseService, err = loadServiceWithExtends(baseFilePath, baseServiceName, baseFileServices, filepath.Dir(baseFilePath), lookupEnv, opts, ct)
- if err != nil {
- return nil, err
- }
-
- // Make paths relative to the importing Compose file. Note that we
- // make the paths relative to `*file` rather than `baseFilePath` so
- // that the resulting paths won't be absolute if `*file` isn't an
- // absolute path.
- baseFileParent := filepath.Dir(*file)
- if baseService.Build != nil {
- // Note that the Dockerfile is always defined relative to the
- // build context, so there's no need to update the Dockerfile field.
- baseService.Build.Context = absPath(baseFileParent, baseService.Build.Context)
- }
-
- for i, vol := range baseService.Volumes {
- if vol.Type != types.VolumeTypeBind {
- continue
- }
- baseService.Volumes[i].Source = absPath(baseFileParent, vol.Source)
- }
- }
-
- serviceConfig, err = _merge(baseService, serviceConfig)
- if err != nil {
- return nil, err
- }
- }
-
- return serviceConfig, nil
-}
-
-// LoadService produces a single ServiceConfig from a compose file Dict
-// the serviceDict is not validated if directly used. Use Load() to enable validation
-func LoadService(name string, serviceDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, resolvePaths bool, convertPaths bool) (*types.ServiceConfig, error) {
- serviceConfig := &types.ServiceConfig{
- Scale: 1,
- }
- if err := Transform(serviceDict, serviceConfig); err != nil {
- return nil, err
- }
- serviceConfig.Name = name
-
- if err := resolveEnvironment(serviceConfig, workingDir, lookupEnv); err != nil {
- return nil, err
- }
-
- for i, volume := range serviceConfig.Volumes {
- if volume.Type != types.VolumeTypeBind {
- continue
- }
-
- if volume.Source == "" {
- return nil, errors.New(`invalid mount config for type "bind": field Source must not be empty`)
- }
-
- if resolvePaths {
- serviceConfig.Volumes[i] = resolveVolumePath(volume, workingDir, lookupEnv)
- }
-
- if convertPaths {
- serviceConfig.Volumes[i] = convertVolumePath(volume)
- }
- }
-
- return serviceConfig, nil
-}
-
-// Windows paths, c:\\my\\path\\shiny, need to be changed to be compatible with
-// the Engine. Volume paths are expected to be linux style /c/my/path/shiny/
-func convertVolumePath(volume types.ServiceVolumeConfig) types.ServiceVolumeConfig {
- volumeName := strings.ToLower(filepath.VolumeName(volume.Source))
- if len(volumeName) != 2 {
- return volume
- }
-
- convertedSource := fmt.Sprintf("/%c%s", volumeName[0], volume.Source[len(volumeName):])
- convertedSource = strings.ReplaceAll(convertedSource, "\\", "/")
-
- volume.Source = convertedSource
- return volume
-}
-
-func resolveEnvironment(serviceConfig *types.ServiceConfig, workingDir string, lookupEnv template.Mapping) error {
- environment := types.MappingWithEquals{}
-
- if len(serviceConfig.EnvFile) > 0 {
- for _, envFile := range serviceConfig.EnvFile {
- filePath := absPath(workingDir, envFile)
- file, err := os.Open(filePath)
- if err != nil {
- return err
- }
- defer file.Close()
- fileVars, err := dotenv.ParseWithLookup(file, dotenv.LookupFn(lookupEnv))
- if err != nil {
- return err
- }
- env := types.MappingWithEquals{}
- for k, v := range fileVars {
- v := v
- env[k] = &v
- }
- environment.OverrideBy(env.Resolve(lookupEnv).RemoveEmpty())
- }
- }
-
- environment.OverrideBy(serviceConfig.Environment.Resolve(lookupEnv))
- serviceConfig.Environment = environment
- return nil
-}
-
-func resolveVolumePath(volume types.ServiceVolumeConfig, workingDir string, lookupEnv template.Mapping) types.ServiceVolumeConfig {
- filePath := expandUser(volume.Source, lookupEnv)
- // Check if source is an absolute path (either Unix or Windows), to
- // handle a Windows client with a Unix daemon or vice-versa.
- //
- // Note that this is not required for Docker for Windows when specifying
- // a local Windows path, because Docker for Windows translates the Windows
- // path into a valid path within the VM.
- if !path.IsAbs(filePath) && !isAbs(filePath) {
- filePath = absPath(workingDir, filePath)
- }
- volume.Source = filePath
- return volume
-}
-
-// TODO: make this more robust
-func expandUser(path string, lookupEnv template.Mapping) string {
- if strings.HasPrefix(path, "~") {
- home, err := os.UserHomeDir()
- if err != nil {
- logrus.Warn("cannot expand '~', because the environment lacks HOME")
- return path
- }
- return filepath.Join(home, path[1:])
- }
- return path
-}
-
-func transformUlimits(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case int:
- return types.UlimitsConfig{Single: value}, nil
- case map[string]interface{}:
- ulimit := types.UlimitsConfig{}
- if v, ok := value["soft"]; ok {
- ulimit.Soft = v.(int)
- }
- if v, ok := value["hard"]; ok {
- ulimit.Hard = v.(int)
- }
- return ulimit, nil
- default:
- return data, errors.Errorf("invalid type %T for ulimits", value)
- }
-}
-
-// LoadNetworks produces a NetworkConfig map from a compose file Dict
-// the source Dict is not validated if directly used. Use Load() to enable validation
-func LoadNetworks(source map[string]interface{}) (map[string]types.NetworkConfig, error) {
- networks := make(map[string]types.NetworkConfig)
- err := Transform(source, &networks)
- if err != nil {
- return networks, err
- }
- for name, network := range networks {
- if !network.External.External {
- continue
- }
- switch {
- case network.External.Name != "":
- if network.Name != "" {
- return nil, errors.Errorf("network %s: network.external.name and network.name conflict; only use network.name", name)
- }
- logrus.Warnf("network %s: network.external.name is deprecated in favor of network.name", name)
- network.Name = network.External.Name
- network.External.Name = ""
- case network.Name == "":
- network.Name = name
- }
- networks[name] = network
- }
- return networks, nil
-}
-
-func externalVolumeError(volume, key string) error {
- return errors.Errorf(
- "conflicting parameters \"external\" and %q specified for volume %q",
- key, volume)
-}
-
-// LoadVolumes produces a VolumeConfig map from a compose file Dict
-// the source Dict is not validated if directly used. Use Load() to enable validation
-func LoadVolumes(source map[string]interface{}) (map[string]types.VolumeConfig, error) {
- volumes := make(map[string]types.VolumeConfig)
- if err := Transform(source, &volumes); err != nil {
- return volumes, err
- }
-
- for name, volume := range volumes {
- if !volume.External.External {
- continue
- }
- switch {
- case volume.Driver != "":
- return nil, externalVolumeError(name, "driver")
- case len(volume.DriverOpts) > 0:
- return nil, externalVolumeError(name, "driver_opts")
- case len(volume.Labels) > 0:
- return nil, externalVolumeError(name, "labels")
- case volume.External.Name != "":
- if volume.Name != "" {
- return nil, errors.Errorf("volume %s: volume.external.name and volume.name conflict; only use volume.name", name)
- }
- logrus.Warnf("volume %s: volume.external.name is deprecated in favor of volume.name", name)
- volume.Name = volume.External.Name
- volume.External.Name = ""
- case volume.Name == "":
- volume.Name = name
- }
- volumes[name] = volume
- }
- return volumes, nil
-}
-
-// LoadSecrets produces a SecretConfig map from a compose file Dict
-// the source Dict is not validated if directly used. Use Load() to enable validation
-func LoadSecrets(source map[string]interface{}, details types.ConfigDetails, resolvePaths bool) (map[string]types.SecretConfig, error) {
- secrets := make(map[string]types.SecretConfig)
- if err := Transform(source, &secrets); err != nil {
- return secrets, err
- }
- for name, secret := range secrets {
- obj, err := loadFileObjectConfig(name, "secret", types.FileObjectConfig(secret), details, resolvePaths)
- if err != nil {
- return nil, err
- }
- secretConfig := types.SecretConfig(obj)
- secrets[name] = secretConfig
- }
- return secrets, nil
-}
-
-// LoadConfigObjs produces a ConfigObjConfig map from a compose file Dict
-// the source Dict is not validated if directly used. Use Load() to enable validation
-func LoadConfigObjs(source map[string]interface{}, details types.ConfigDetails, resolvePaths bool) (map[string]types.ConfigObjConfig, error) {
- configs := make(map[string]types.ConfigObjConfig)
- if err := Transform(source, &configs); err != nil {
- return configs, err
- }
- for name, config := range configs {
- obj, err := loadFileObjectConfig(name, "config", types.FileObjectConfig(config), details, resolvePaths)
- if err != nil {
- return nil, err
- }
- configConfig := types.ConfigObjConfig(obj)
- configs[name] = configConfig
- }
- return configs, nil
-}
-
-func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails, resolvePaths bool) (types.FileObjectConfig, error) {
- // if "external: true"
- switch {
- case obj.External.External:
- // handle deprecated external.name
- if obj.External.Name != "" {
- if obj.Name != "" {
- return obj, errors.Errorf("%[1]s %[2]s: %[1]s.external.name and %[1]s.name conflict; only use %[1]s.name", objType, name)
- }
- logrus.Warnf("%[1]s %[2]s: %[1]s.external.name is deprecated in favor of %[1]s.name", objType, name)
- obj.Name = obj.External.Name
- obj.External.Name = ""
- } else {
- if obj.Name == "" {
- obj.Name = name
- }
- }
- // if not "external: true"
- case obj.Driver != "":
- if obj.File != "" {
- return obj, errors.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name)
- }
- default:
- if resolvePaths {
- obj.File = absPath(details.WorkingDir, obj.File)
- }
- }
-
- return obj, nil
-}
-
-func absPath(workingDir string, filePath string) string {
- if strings.HasPrefix(filePath, "~") {
- home, _ := os.UserHomeDir()
- return filepath.Join(home, filePath[1:])
- }
- if filepath.IsAbs(filePath) {
- return filePath
- }
- return filepath.Join(workingDir, filePath)
-}
-
-var transformMapStringString TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case map[string]interface{}:
- return toMapStringString(value, false), nil
- case map[string]string:
- return value, nil
- default:
- return data, errors.Errorf("invalid type %T for map[string]string", value)
- }
-}
-
-var transformExternal TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case bool:
- return map[string]interface{}{"external": value}, nil
- case map[string]interface{}:
- return map[string]interface{}{"external": true, "name": value["name"]}, nil
- default:
- return data, errors.Errorf("invalid type %T for external", value)
- }
-}
-
-var transformServicePort TransformerFunc = func(data interface{}) (interface{}, error) {
- switch entries := data.(type) {
- case []interface{}:
- // We process the list instead of individual items here.
- // The reason is that one entry might be mapped to multiple ServicePortConfig.
- // Therefore we take an input of a list and return an output of a list.
- var ports []interface{}
- for _, entry := range entries {
- switch value := entry.(type) {
- case int:
- parsed, err := types.ParsePortConfig(fmt.Sprint(value))
- if err != nil {
- return data, err
- }
- for _, v := range parsed {
- ports = append(ports, v)
- }
- case string:
- parsed, err := types.ParsePortConfig(value)
- if err != nil {
- return data, err
- }
- for _, v := range parsed {
- ports = append(ports, v)
- }
- case map[string]interface{}:
- published := value["published"]
- if v, ok := published.(int); ok {
- value["published"] = strconv.Itoa(v)
- }
- ports = append(ports, groupXFieldsIntoExtensions(value))
- default:
- return data, errors.Errorf("invalid type %T for port", value)
- }
- }
- return ports, nil
- default:
- return data, errors.Errorf("invalid type %T for port", entries)
- }
-}
-
-var transformServiceDeviceRequest TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case map[string]interface{}:
- count, ok := value["count"]
- if ok {
- switch val := count.(type) {
- case int:
- return value, nil
- case string:
- if strings.ToLower(val) == "all" {
- value["count"] = -1
- return value, nil
- }
- return data, errors.Errorf("invalid string value for 'count' (the only value allowed is 'all')")
- default:
- return data, errors.Errorf("invalid type %T for device count", val)
- }
- }
- return data, nil
- default:
- return data, errors.Errorf("invalid type %T for resource reservation", value)
- }
-}
-
-var transformFileReferenceConfig TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case string:
- return map[string]interface{}{"source": value}, nil
- case map[string]interface{}:
- if target, ok := value["target"]; ok {
- value["target"] = cleanTarget(target.(string))
- }
- return groupXFieldsIntoExtensions(value), nil
- default:
- return data, errors.Errorf("invalid type %T for secret", value)
- }
-}
-
-func cleanTarget(target string) string {
- if target == "" {
- return ""
- }
- return path.Clean(target)
-}
-
-var transformBuildConfig TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case string:
- return map[string]interface{}{"context": value}, nil
- case map[string]interface{}:
- return groupXFieldsIntoExtensions(data.(map[string]interface{})), nil
- default:
- return data, errors.Errorf("invalid type %T for service build", value)
- }
-}
-
-var transformDependsOnConfig TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case []interface{}:
- transformed := map[string]interface{}{}
- for _, serviceIntf := range value {
- service, ok := serviceIntf.(string)
- if !ok {
- return data, errors.Errorf("invalid type %T for service depends_on elementn, expected string", value)
- }
- transformed[service] = map[string]interface{}{"condition": types.ServiceConditionStarted}
- }
- return transformed, nil
- case map[string]interface{}:
- return groupXFieldsIntoExtensions(data.(map[string]interface{})), nil
- default:
- return data, errors.Errorf("invalid type %T for service depends_on", value)
- }
-}
-
-var transformExtendsConfig TransformerFunc = func(data interface{}) (interface{}, error) {
- switch data.(type) {
- case string:
- data = map[string]interface{}{
- "service": data,
- }
- }
- return transformMappingOrListFunc("=", true)(data)
-}
-
-var transformServiceVolumeConfig TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case string:
- volume, err := ParseVolume(value)
- volume.Target = cleanTarget(volume.Target)
- return volume, err
- case map[string]interface{}:
- data := groupXFieldsIntoExtensions(data.(map[string]interface{}))
- if target, ok := data["target"]; ok {
- data["target"] = cleanTarget(target.(string))
- }
- return data, nil
- default:
- return data, errors.Errorf("invalid type %T for service volume", value)
- }
-}
-
-var transformServiceNetworkMap TransformerFunc = func(value interface{}) (interface{}, error) {
- if list, ok := value.([]interface{}); ok {
- mapValue := map[interface{}]interface{}{}
- for _, name := range list {
- mapValue[name] = nil
- }
- return mapValue, nil
- }
- return value, nil
-}
-
-var transformSSHConfig TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case map[string]interface{}:
- var result []types.SSHKey
- for key, val := range value {
- if val == nil {
- val = ""
- }
- result = append(result, types.SSHKey{ID: key, Path: val.(string)})
- }
- return result, nil
- case []interface{}:
- var result []types.SSHKey
- for _, v := range value {
- key, val := transformValueToMapEntry(v.(string), "=", false)
- result = append(result, types.SSHKey{ID: key, Path: val.(string)})
- }
- return result, nil
- case string:
- return ParseShortSSHSyntax(value)
- }
- return nil, errors.Errorf("expected a sting, map or a list, got %T: %#v", data, data)
-}
-
-// ParseShortSSHSyntax parse short syntax for SSH authentications
-func ParseShortSSHSyntax(value string) ([]types.SSHKey, error) {
- if value == "" {
- value = "default"
- }
- key, val := transformValueToMapEntry(value, "=", false)
- result := []types.SSHKey{{ID: key, Path: val.(string)}}
- return result, nil
-}
-
-var transformStringOrNumberList TransformerFunc = func(value interface{}) (interface{}, error) {
- list := value.([]interface{})
- result := make([]string, len(list))
- for i, item := range list {
- result[i] = fmt.Sprint(item)
- }
- return result, nil
-}
-
-var transformStringList TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case string:
- return []string{value}, nil
- case []interface{}:
- return value, nil
- default:
- return data, errors.Errorf("invalid type %T for string list", value)
- }
-}
-
-func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc {
- return func(data interface{}) (interface{}, error) {
- return transformMappingOrList(data, sep, allowNil)
- }
-}
-
-func transformListOrMappingFunc(sep string, allowNil bool) TransformerFunc {
- return func(data interface{}) (interface{}, error) {
- return transformListOrMapping(data, sep, allowNil)
- }
-}
-
-func transformListOrMapping(listOrMapping interface{}, sep string, allowNil bool) (interface{}, error) {
- switch value := listOrMapping.(type) {
- case map[string]interface{}:
- return toStringList(value, sep, allowNil), nil
- case []interface{}:
- return listOrMapping, nil
- }
- return nil, errors.Errorf("expected a map or a list, got %T: %#v", listOrMapping, listOrMapping)
-}
-
-func transformMappingOrList(mappingOrList interface{}, sep string, allowNil bool) (interface{}, error) {
- switch value := mappingOrList.(type) {
- case map[string]interface{}:
- return toMapStringString(value, allowNil), nil
- case []interface{}:
- result := make(map[string]interface{})
- for _, value := range value {
- key, val := transformValueToMapEntry(value.(string), sep, allowNil)
- result[key] = val
- }
- return result, nil
- }
- return nil, errors.Errorf("expected a map or a list, got %T: %#v", mappingOrList, mappingOrList)
-}
-
-func transformValueToMapEntry(value string, separator string, allowNil bool) (string, interface{}) {
- parts := strings.SplitN(value, separator, 2)
- key := parts[0]
- switch {
- case len(parts) == 1 && allowNil:
- return key, nil
- case len(parts) == 1 && !allowNil:
- return key, ""
- default:
- return key, parts[1]
- }
-}
-
-var transformShellCommand TransformerFunc = func(value interface{}) (interface{}, error) {
- if str, ok := value.(string); ok {
- return shellwords.Parse(str)
- }
- return value, nil
-}
-
-var transformHealthCheckTest TransformerFunc = func(data interface{}) (interface{}, error) {
- switch value := data.(type) {
- case string:
- return append([]string{"CMD-SHELL"}, value), nil
- case []interface{}:
- return value, nil
- default:
- return value, errors.Errorf("invalid type %T for healthcheck.test", value)
- }
-}
-
-var transformSize TransformerFunc = func(value interface{}) (interface{}, error) {
- switch value := value.(type) {
- case int:
- return int64(value), nil
- case int64, types.UnitBytes:
- return value, nil
- case string:
- return units.RAMInBytes(value)
- default:
- return value, errors.Errorf("invalid type for size %T", value)
- }
-}
-
-var transformStringToDuration TransformerFunc = func(value interface{}) (interface{}, error) {
- switch value := value.(type) {
- case string:
- d, err := time.ParseDuration(value)
- if err != nil {
- return value, err
- }
- return types.Duration(d), nil
- case types.Duration:
- return value, nil
- default:
- return value, errors.Errorf("invalid type %T for duration", value)
- }
-}
-
-func toMapStringString(value map[string]interface{}, allowNil bool) map[string]interface{} {
- output := make(map[string]interface{})
- for key, value := range value {
- output[key] = toString(value, allowNil)
- }
- return output
-}
-
-func toString(value interface{}, allowNil bool) interface{} {
- switch {
- case value != nil:
- return fmt.Sprint(value)
- case allowNil:
- return nil
- default:
- return ""
- }
-}
-
-func toStringList(value map[string]interface{}, separator string, allowNil bool) []string {
- var output []string
- for key, value := range value {
- if value == nil && !allowNil {
- continue
- }
- output = append(output, fmt.Sprintf("%s%s%s", key, separator, value))
- }
- sort.Strings(output)
- return output
-}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/merge.go b/vendor/github.com/compose-spec/compose-go/loader/merge.go
deleted file mode 100644
index f6138ca292..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/merge.go
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package loader
-
-import (
- "reflect"
- "sort"
-
- "github.com/compose-spec/compose-go/types"
- "github.com/imdario/mergo"
- "github.com/pkg/errors"
-)
-
-type specials struct {
- m map[reflect.Type]func(dst, src reflect.Value) error
-}
-
-var serviceSpecials = &specials{
- m: map[reflect.Type]func(dst, src reflect.Value) error{
- reflect.TypeOf(&types.LoggingConfig{}): safelyMerge(mergeLoggingConfig),
- reflect.TypeOf(&types.UlimitsConfig{}): safelyMerge(mergeUlimitsConfig),
- reflect.TypeOf([]types.ServiceVolumeConfig{}): mergeSlice(toServiceVolumeConfigsMap, toServiceVolumeConfigsSlice),
- reflect.TypeOf([]types.ServicePortConfig{}): mergeSlice(toServicePortConfigsMap, toServicePortConfigsSlice),
- reflect.TypeOf([]types.ServiceSecretConfig{}): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
- reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
- reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig,
- reflect.TypeOf(&types.ServiceNetworkConfig{}): mergeServiceNetworkConfig,
- },
-}
-
-func (s *specials) Transformer(t reflect.Type) func(dst, src reflect.Value) error {
- if fn, ok := s.m[t]; ok {
- return fn
- }
- return nil
-}
-
-func merge(configs []*types.Config) (*types.Config, error) {
- base := configs[0]
- for _, override := range configs[1:] {
- var err error
- base.Name = mergeNames(base.Name, override.Name)
- base.Services, err = mergeServices(base.Services, override.Services)
- if err != nil {
- return base, errors.Wrapf(err, "cannot merge services from %s", override.Filename)
- }
- base.Volumes, err = mergeVolumes(base.Volumes, override.Volumes)
- if err != nil {
- return base, errors.Wrapf(err, "cannot merge volumes from %s", override.Filename)
- }
- base.Networks, err = mergeNetworks(base.Networks, override.Networks)
- if err != nil {
- return base, errors.Wrapf(err, "cannot merge networks from %s", override.Filename)
- }
- base.Secrets, err = mergeSecrets(base.Secrets, override.Secrets)
- if err != nil {
- return base, errors.Wrapf(err, "cannot merge secrets from %s", override.Filename)
- }
- base.Configs, err = mergeConfigs(base.Configs, override.Configs)
- if err != nil {
- return base, errors.Wrapf(err, "cannot merge configs from %s", override.Filename)
- }
- base.Extensions, err = mergeExtensions(base.Extensions, override.Extensions)
- if err != nil {
- return base, errors.Wrapf(err, "cannot merge extensions from %s", override.Filename)
- }
- }
- return base, nil
-}
-
-func mergeNames(base, override string) string {
- if override != "" {
- return override
- }
- return base
-}
-
-func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig, error) {
- baseServices := mapByName(base)
- overrideServices := mapByName(override)
- for name, overrideService := range overrideServices {
- overrideService := overrideService
- if baseService, ok := baseServices[name]; ok {
- merged, err := _merge(&baseService, &overrideService)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot merge service %s", name)
- }
- baseServices[name] = *merged
- continue
- }
- baseServices[name] = overrideService
- }
- services := []types.ServiceConfig{}
- for _, baseService := range baseServices {
- services = append(services, baseService)
- }
- sort.Slice(services, func(i, j int) bool { return services[i].Name < services[j].Name })
- return services, nil
-}
-
-func _merge(baseService *types.ServiceConfig, overrideService *types.ServiceConfig) (*types.ServiceConfig, error) {
- if err := mergo.Merge(baseService, overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(serviceSpecials)); err != nil {
- return nil, err
- }
- if overrideService.Command != nil {
- baseService.Command = overrideService.Command
- }
- if overrideService.Entrypoint != nil {
- baseService.Entrypoint = overrideService.Entrypoint
- }
- if baseService.Environment != nil {
- baseService.Environment.OverrideBy(overrideService.Environment)
- } else {
- baseService.Environment = overrideService.Environment
- }
- return baseService, nil
-}
-
-func toServiceSecretConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
- secrets, ok := s.([]types.ServiceSecretConfig)
- if !ok {
- return nil, errors.Errorf("not a serviceSecretConfig: %v", s)
- }
- m := map[interface{}]interface{}{}
- for _, secret := range secrets {
- m[secret.Source] = secret
- }
- return m, nil
-}
-
-func toServiceConfigObjConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
- secrets, ok := s.([]types.ServiceConfigObjConfig)
- if !ok {
- return nil, errors.Errorf("not a serviceSecretConfig: %v", s)
- }
- m := map[interface{}]interface{}{}
- for _, secret := range secrets {
- m[secret.Source] = secret
- }
- return m, nil
-}
-
-func toServicePortConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
- ports, ok := s.([]types.ServicePortConfig)
- if !ok {
- return nil, errors.Errorf("not a servicePortConfig slice: %v", s)
- }
- m := map[interface{}]interface{}{}
- type port struct {
- target uint32
- published string
- ip string
- protocol string
- }
-
- for _, p := range ports {
- mergeKey := port{
- target: p.Target,
- published: p.Published,
- ip: p.HostIP,
- protocol: p.Protocol,
- }
- m[mergeKey] = p
- }
- return m, nil
-}
-
-func toServiceVolumeConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
- volumes, ok := s.([]types.ServiceVolumeConfig)
- if !ok {
- return nil, errors.Errorf("not a ServiceVolumeConfig slice: %v", s)
- }
- m := map[interface{}]interface{}{}
- for _, v := range volumes {
- m[v.Target] = v
- }
- return m, nil
-}
-
-func toServiceSecretConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
- var s []types.ServiceSecretConfig
- for _, v := range m {
- s = append(s, v.(types.ServiceSecretConfig))
- }
- sort.Slice(s, func(i, j int) bool { return s[i].Source < s[j].Source })
- dst.Set(reflect.ValueOf(s))
- return nil
-}
-
-func toSServiceConfigObjConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
- var s []types.ServiceConfigObjConfig
- for _, v := range m {
- s = append(s, v.(types.ServiceConfigObjConfig))
- }
- sort.Slice(s, func(i, j int) bool { return s[i].Source < s[j].Source })
- dst.Set(reflect.ValueOf(s))
- return nil
-}
-
-func toServicePortConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
- var s []types.ServicePortConfig
- for _, v := range m {
- s = append(s, v.(types.ServicePortConfig))
- }
- sort.Slice(s, func(i, j int) bool {
- if s[i].Target != s[j].Target {
- return s[i].Target < s[j].Target
- }
- if s[i].Published != s[j].Published {
- return s[i].Published < s[j].Published
- }
- if s[i].HostIP != s[j].HostIP {
- return s[i].HostIP < s[j].HostIP
- }
- return s[i].Protocol < s[j].Protocol
- })
- dst.Set(reflect.ValueOf(s))
- return nil
-}
-
-func toServiceVolumeConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
- var s []types.ServiceVolumeConfig
- for _, v := range m {
- s = append(s, v.(types.ServiceVolumeConfig))
- }
- sort.Slice(s, func(i, j int) bool { return s[i].Target < s[j].Target })
- dst.Set(reflect.ValueOf(s))
- return nil
-}
-
-type toMapFn func(s interface{}) (map[interface{}]interface{}, error)
-type writeValueFromMapFn func(reflect.Value, map[interface{}]interface{}) error
-
-func safelyMerge(mergeFn func(dst, src reflect.Value) error) func(dst, src reflect.Value) error {
- return func(dst, src reflect.Value) error {
- if src.IsNil() {
- return nil
- }
- if dst.IsNil() {
- dst.Set(src)
- return nil
- }
- return mergeFn(dst, src)
- }
-}
-
-func mergeSlice(toMap toMapFn, writeValue writeValueFromMapFn) func(dst, src reflect.Value) error {
- return func(dst, src reflect.Value) error {
- dstMap, err := sliceToMap(toMap, dst)
- if err != nil {
- return err
- }
- srcMap, err := sliceToMap(toMap, src)
- if err != nil {
- return err
- }
- if err := mergo.Map(&dstMap, srcMap, mergo.WithOverride); err != nil {
- return err
- }
- return writeValue(dst, dstMap)
- }
-}
-
-func sliceToMap(toMap toMapFn, v reflect.Value) (map[interface{}]interface{}, error) {
- // check if valid
- if !v.IsValid() {
- return nil, errors.Errorf("invalid value : %+v", v)
- }
- return toMap(v.Interface())
-}
-
-func mergeLoggingConfig(dst, src reflect.Value) error {
- // Same driver, merging options
- if getLoggingDriver(dst.Elem()) == getLoggingDriver(src.Elem()) ||
- getLoggingDriver(dst.Elem()) == "" || getLoggingDriver(src.Elem()) == "" {
- if getLoggingDriver(dst.Elem()) == "" {
- dst.Elem().FieldByName("Driver").SetString(getLoggingDriver(src.Elem()))
- }
- dstOptions := dst.Elem().FieldByName("Options").Interface().(map[string]string)
- srcOptions := src.Elem().FieldByName("Options").Interface().(map[string]string)
- return mergo.Merge(&dstOptions, srcOptions, mergo.WithOverride)
- }
- // Different driver, override with src
- dst.Set(src)
- return nil
-}
-
-// nolint: unparam
-func mergeUlimitsConfig(dst, src reflect.Value) error {
- if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
- dst.Elem().Set(src.Elem())
- }
- return nil
-}
-
-// nolint: unparam
-func mergeServiceNetworkConfig(dst, src reflect.Value) error {
- if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
- dst.Elem().FieldByName("Aliases").Set(src.Elem().FieldByName("Aliases"))
- if ipv4 := src.Elem().FieldByName("Ipv4Address").Interface().(string); ipv4 != "" {
- dst.Elem().FieldByName("Ipv4Address").SetString(ipv4)
- }
- if ipv6 := src.Elem().FieldByName("Ipv6Address").Interface().(string); ipv6 != "" {
- dst.Elem().FieldByName("Ipv6Address").SetString(ipv6)
- }
- }
- return nil
-}
-
-func getLoggingDriver(v reflect.Value) string {
- return v.FieldByName("Driver").String()
-}
-
-func mapByName(services []types.ServiceConfig) map[string]types.ServiceConfig {
- m := map[string]types.ServiceConfig{}
- for _, service := range services {
- m[service.Name] = service
- }
- return m
-}
-
-func mergeVolumes(base, override map[string]types.VolumeConfig) (map[string]types.VolumeConfig, error) {
- err := mergo.Map(&base, &override, mergo.WithOverride)
- return base, err
-}
-
-func mergeNetworks(base, override map[string]types.NetworkConfig) (map[string]types.NetworkConfig, error) {
- err := mergo.Map(&base, &override, mergo.WithOverride)
- return base, err
-}
-
-func mergeSecrets(base, override map[string]types.SecretConfig) (map[string]types.SecretConfig, error) {
- err := mergo.Map(&base, &override, mergo.WithOverride)
- return base, err
-}
-
-func mergeConfigs(base, override map[string]types.ConfigObjConfig) (map[string]types.ConfigObjConfig, error) {
- err := mergo.Map(&base, &override, mergo.WithOverride)
- return base, err
-}
-
-func mergeExtensions(base, override map[string]interface{}) (map[string]interface{}, error) {
- if base == nil {
- base = map[string]interface{}{}
- }
- err := mergo.Map(&base, &override, mergo.WithOverride)
- return base, err
-}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/normalize.go b/vendor/github.com/compose-spec/compose-go/loader/normalize.go
deleted file mode 100644
index 4b98d624a7..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/normalize.go
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package loader
-
-import (
- "fmt"
- "os"
- "path/filepath"
-
- "github.com/compose-spec/compose-go/errdefs"
- "github.com/compose-spec/compose-go/types"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// normalize compose project by moving deprecated attributes to their canonical position and injecting implicit defaults
-func normalize(project *types.Project, resolvePaths bool) error {
- absWorkingDir, err := filepath.Abs(project.WorkingDir)
- if err != nil {
- return err
- }
- project.WorkingDir = absWorkingDir
-
- absComposeFiles, err := absComposeFiles(project.ComposeFiles)
- if err != nil {
- return err
- }
- project.ComposeFiles = absComposeFiles
-
- if project.Networks == nil {
- project.Networks = make(map[string]types.NetworkConfig)
- }
-
- // If not declared explicitly, Compose model involves an implicit "default" network
- if _, ok := project.Networks["default"]; !ok {
- project.Networks["default"] = types.NetworkConfig{}
- }
-
- err = relocateExternalName(project)
- if err != nil {
- return err
- }
-
- for i, s := range project.Services {
- if len(s.Networks) == 0 && s.NetworkMode == "" {
- // Service without explicit network attachment are implicitly exposed on default network
- s.Networks = map[string]*types.ServiceNetworkConfig{"default": nil}
- }
-
- if s.PullPolicy == types.PullPolicyIfNotPresent {
- s.PullPolicy = types.PullPolicyMissing
- }
-
- fn := func(s string) (string, bool) {
- v, ok := project.Environment[s]
- return v, ok
- }
-
- if s.Build != nil {
- if s.Build.Dockerfile == "" {
- s.Build.Dockerfile = "Dockerfile"
- }
- localContext := absPath(project.WorkingDir, s.Build.Context)
- if _, err := os.Stat(localContext); err == nil {
- if resolvePaths {
- s.Build.Context = localContext
- }
- // } else {
- // might be a remote http/git context. Unfortunately supported "remote" syntax is highly ambiguous
- // in moby/moby and not defined by compose-spec, so let's assume runtime will check
- }
- s.Build.Args = s.Build.Args.Resolve(fn)
- }
- s.Environment = s.Environment.Resolve(fn)
-
- err := relocateLogDriver(&s)
- if err != nil {
- return err
- }
-
- err = relocateLogOpt(&s)
- if err != nil {
- return err
- }
-
- err = relocateDockerfile(&s)
- if err != nil {
- return err
- }
-
- err = relocateScale(&s)
- if err != nil {
- return err
- }
-
- project.Services[i] = s
- }
-
- setNameFromKey(project)
-
- return nil
-}
-
-func relocateScale(s *types.ServiceConfig) error {
- scale := uint64(s.Scale)
- if scale != 1 {
- logrus.Warn("`scale` is deprecated. Use the `deploy.replicas` element")
- if s.Deploy == nil {
- s.Deploy = &types.DeployConfig{}
- }
- if s.Deploy.Replicas != nil && *s.Deploy.Replicas != scale {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'scale' (deprecated) and 'deploy.replicas'")
- }
- s.Deploy.Replicas = &scale
- }
- return nil
-}
-
-func absComposeFiles(composeFiles []string) ([]string, error) {
- absComposeFiles := make([]string, len(composeFiles))
- for i, composeFile := range composeFiles {
- absComposefile, err := filepath.Abs(composeFile)
- if err != nil {
- return nil, err
- }
- absComposeFiles[i] = absComposefile
- }
- return absComposeFiles, nil
-}
-
-// Resources with no explicit name are actually named by their key in map
-func setNameFromKey(project *types.Project) {
- for i, n := range project.Networks {
- if n.Name == "" {
- n.Name = fmt.Sprintf("%s_%s", project.Name, i)
- project.Networks[i] = n
- }
- }
-
- for i, v := range project.Volumes {
- if v.Name == "" {
- v.Name = fmt.Sprintf("%s_%s", project.Name, i)
- project.Volumes[i] = v
- }
- }
-
- for i, c := range project.Configs {
- if c.Name == "" {
- c.Name = fmt.Sprintf("%s_%s", project.Name, i)
- project.Configs[i] = c
- }
- }
-
- for i, s := range project.Secrets {
- if s.Name == "" {
- s.Name = fmt.Sprintf("%s_%s", project.Name, i)
- project.Secrets[i] = s
- }
- }
-}
-
-func relocateExternalName(project *types.Project) error {
- for i, n := range project.Networks {
- if n.External.Name != "" {
- if n.Name != "" {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'networks.external.name' (deprecated) and 'networks.name'")
- }
- n.Name = n.External.Name
- }
- project.Networks[i] = n
- }
-
- for i, v := range project.Volumes {
- if v.External.Name != "" {
- if v.Name != "" {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'volumes.external.name' (deprecated) and 'volumes.name'")
- }
- v.Name = v.External.Name
- }
- project.Volumes[i] = v
- }
-
- for i, s := range project.Secrets {
- if s.External.Name != "" {
- if s.Name != "" {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'secrets.external.name' (deprecated) and 'secrets.name'")
- }
- s.Name = s.External.Name
- }
- project.Secrets[i] = s
- }
-
- for i, c := range project.Configs {
- if c.External.Name != "" {
- if c.Name != "" {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'configs.external.name' (deprecated) and 'configs.name'")
- }
- c.Name = c.External.Name
- }
- project.Configs[i] = c
- }
- return nil
-}
-
-func relocateLogOpt(s *types.ServiceConfig) error {
- if len(s.LogOpt) != 0 {
- logrus.Warn("`log_opts` is deprecated. Use the `logging` element")
- if s.Logging == nil {
- s.Logging = &types.LoggingConfig{}
- }
- for k, v := range s.LogOpt {
- if _, ok := s.Logging.Options[k]; !ok {
- s.Logging.Options[k] = v
- } else {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'log_opt' (deprecated) and 'logging.options'")
- }
- }
- }
- return nil
-}
-
-func relocateLogDriver(s *types.ServiceConfig) error {
- if s.LogDriver != "" {
- logrus.Warn("`log_driver` is deprecated. Use the `logging` element")
- if s.Logging == nil {
- s.Logging = &types.LoggingConfig{}
- }
- if s.Logging.Driver == "" {
- s.Logging.Driver = s.LogDriver
- } else {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'log_driver' (deprecated) and 'logging.driver'")
- }
- }
- return nil
-}
-
-func relocateDockerfile(s *types.ServiceConfig) error {
- if s.Dockerfile != "" {
- logrus.Warn("`dockerfile` is deprecated. Use the `build` element")
- if s.Build == nil {
- s.Build = &types.BuildConfig{}
- }
- if s.Dockerfile == "" {
- s.Build.Dockerfile = s.Dockerfile
- } else {
- return errors.Wrap(errdefs.ErrInvalid, "can't use both 'dockerfile' (deprecated) and 'build.dockerfile'")
- }
- }
- return nil
-}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/validate.go b/vendor/github.com/compose-spec/compose-go/loader/validate.go
deleted file mode 100644
index 4493c051da..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/validate.go
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package loader
-
-import (
- "fmt"
- "strings"
-
- "github.com/compose-spec/compose-go/errdefs"
- "github.com/compose-spec/compose-go/types"
- "github.com/pkg/errors"
-)
-
-// checkConsistency validate a compose model is consistent
-func checkConsistency(project *types.Project) error {
- for _, s := range project.Services {
- if s.Build == nil && s.Image == "" {
- return errors.Wrapf(errdefs.ErrInvalid, "service %q has neither an image nor a build context specified", s.Name)
- }
-
- for network := range s.Networks {
- if _, ok := project.Networks[network]; !ok {
- return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q refers to undefined network %s", s.Name, network))
- }
- }
-
- if strings.HasPrefix(s.NetworkMode, types.ServicePrefix) {
- serviceName := s.NetworkMode[len(types.ServicePrefix):]
- if _, err := project.GetServices(serviceName); err != nil {
- return fmt.Errorf("service %q not found for network_mode 'service:%s'", serviceName, serviceName)
- }
- }
-
- for _, volume := range s.Volumes {
- switch volume.Type {
- case types.VolumeTypeVolume:
- if volume.Source != "" { // non anonymous volumes
- if _, ok := project.Volumes[volume.Source]; !ok {
- return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q refers to undefined volume %s", s.Name, volume.Source))
- }
- }
- }
- }
- for _, secret := range s.Secrets {
- if _, ok := project.Secrets[secret.Source]; !ok {
- return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q refers to undefined secret %s", s.Name, secret.Source))
- }
- }
- for _, config := range s.Configs {
- if _, ok := project.Configs[config.Source]; !ok {
- return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q refers to undefined config %s", s.Name, config.Source))
- }
- }
- }
- return nil
-}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/volume.go b/vendor/github.com/compose-spec/compose-go/loader/volume.go
deleted file mode 100644
index f1e66cde83..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/volume.go
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package loader
-
-import (
- "strings"
- "unicode"
- "unicode/utf8"
-
- "github.com/compose-spec/compose-go/types"
- "github.com/pkg/errors"
-)
-
-const endOfSpec = rune(0)
-
-// ParseVolume parses a volume spec without any knowledge of the target platform
-func ParseVolume(spec string) (types.ServiceVolumeConfig, error) {
- volume := types.ServiceVolumeConfig{}
-
- switch len(spec) {
- case 0:
- return volume, errors.New("invalid empty volume spec")
- case 1, 2:
- volume.Target = spec
- volume.Type = types.VolumeTypeVolume
- return volume, nil
- }
-
- var buffer []rune
- for _, char := range spec + string(endOfSpec) {
- switch {
- case isWindowsDrive(buffer, char):
- buffer = append(buffer, char)
- case char == ':' || char == endOfSpec:
- if err := populateFieldFromBuffer(char, buffer, &volume); err != nil {
- populateType(&volume)
- return volume, errors.Wrapf(err, "invalid spec: %s", spec)
- }
- buffer = nil
- default:
- buffer = append(buffer, char)
- }
- }
-
- populateType(&volume)
- return volume, nil
-}
-
-func isWindowsDrive(buffer []rune, char rune) bool {
- return char == ':' && len(buffer) == 1 && unicode.IsLetter(buffer[0])
-}
-
-func populateFieldFromBuffer(char rune, buffer []rune, volume *types.ServiceVolumeConfig) error {
- strBuffer := string(buffer)
- switch {
- case len(buffer) == 0:
- return errors.New("empty section between colons")
- // Anonymous volume
- case volume.Source == "" && char == endOfSpec:
- volume.Target = strBuffer
- return nil
- case volume.Source == "":
- volume.Source = strBuffer
- return nil
- case volume.Target == "":
- volume.Target = strBuffer
- return nil
- case char == ':':
- return errors.New("too many colons")
- }
- for _, option := range strings.Split(strBuffer, ",") {
- switch option {
- case "ro":
- volume.ReadOnly = true
- case "rw":
- volume.ReadOnly = false
- case "nocopy":
- volume.Volume = &types.ServiceVolumeVolume{NoCopy: true}
- default:
- if isBindOption(option) {
- setBindOption(volume, option)
- }
- // ignore unknown options
- }
- }
- return nil
-}
-
-var Propagations = []string{
- types.PropagationRPrivate,
- types.PropagationPrivate,
- types.PropagationRShared,
- types.PropagationShared,
- types.PropagationRSlave,
- types.PropagationSlave,
-}
-
-type setBindOptionFunc func(bind *types.ServiceVolumeBind, option string)
-
-var bindOptions = map[string]setBindOptionFunc{
- types.PropagationRPrivate: setBindPropagation,
- types.PropagationPrivate: setBindPropagation,
- types.PropagationRShared: setBindPropagation,
- types.PropagationShared: setBindPropagation,
- types.PropagationRSlave: setBindPropagation,
- types.PropagationSlave: setBindPropagation,
- types.SELinuxShared: setBindSELinux,
- types.SELinuxPrivate: setBindSELinux,
-}
-
-func setBindPropagation(bind *types.ServiceVolumeBind, option string) {
- bind.Propagation = option
-}
-
-func setBindSELinux(bind *types.ServiceVolumeBind, option string) {
- bind.SELinux = option
-}
-
-func isBindOption(option string) bool {
- _, ok := bindOptions[option]
-
- return ok
-}
-
-func setBindOption(volume *types.ServiceVolumeConfig, option string) {
- if volume.Bind == nil {
- volume.Bind = &types.ServiceVolumeBind{}
- }
-
- bindOptions[option](volume.Bind, option)
-}
-
-func populateType(volume *types.ServiceVolumeConfig) {
- if isFilePath(volume.Source) {
- volume.Type = types.VolumeTypeBind
- if volume.Bind == nil {
- volume.Bind = &types.ServiceVolumeBind{}
- }
- // For backward compatibility with docker-compose legacy, using short notation involves
- // bind will create missing host path
- volume.Bind.CreateHostPath = true
- } else {
- volume.Type = types.VolumeTypeVolume
- if volume.Volume == nil {
- volume.Volume = &types.ServiceVolumeVolume{}
- }
- }
-}
-
-func isFilePath(source string) bool {
- if source == "" {
- return false
- }
- switch source[0] {
- case '.', '/', '~':
- return true
- }
-
- // windows named pipes
- if strings.HasPrefix(source, `\\`) {
- return true
- }
-
- first, nextIndex := utf8.DecodeRuneInString(source)
- return isWindowsDrive([]rune{first}, rune(source[nextIndex]))
-}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/windows_path.go b/vendor/github.com/compose-spec/compose-go/loader/windows_path.go
deleted file mode 100644
index 5094f5b576..0000000000
--- a/vendor/github.com/compose-spec/compose-go/loader/windows_path.go
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package loader
-
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-// https://github.com/golang/go/blob/master/LICENSE
-
-// This file contains utilities to check for Windows absolute paths on Linux.
-// The code in this file was largely copied from the Golang filepath package
-// https://github.com/golang/go/blob/1d0e94b1e13d5e8a323a63cd1cc1ef95290c9c36/src/path/filepath/path_windows.go#L12-L65
-
-func isSlash(c uint8) bool {
- return c == '\\' || c == '/'
-}
-
-// isAbs reports whether the path is a Windows absolute path.
-func isAbs(path string) (b bool) {
- l := volumeNameLen(path)
- if l == 0 {
- return false
- }
- path = path[l:]
- if path == "" {
- return false
- }
- return isSlash(path[0])
-}
-
-// volumeNameLen returns length of the leading volume name on Windows.
-// It returns 0 elsewhere.
-// nolint: gocyclo
-func volumeNameLen(path string) int {
- if len(path) < 2 {
- return 0
- }
- // with drive letter
- c := path[0]
- if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
- return 2
- }
- // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
- if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
- !isSlash(path[2]) && path[2] != '.' {
- // first, leading `\\` and next shouldn't be `\`. its server name.
- for n := 3; n < l-1; n++ {
- // second, next '\' shouldn't be repeated.
- if isSlash(path[n]) {
- n++
- // third, following something characters. its share name.
- if !isSlash(path[n]) {
- if path[n] == '.' {
- break
- }
- for ; n < l; n++ {
- if isSlash(path[n]) {
- break
- }
- }
- return n
- }
- break
- }
- }
- }
- return 0
-}
diff --git a/vendor/github.com/compose-spec/compose-go/schema/compose-spec.json b/vendor/github.com/compose-spec/compose-go/schema/compose-spec.json
deleted file mode 100644
index b2088998b9..0000000000
--- a/vendor/github.com/compose-spec/compose-go/schema/compose-spec.json
+++ /dev/null
@@ -1,827 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft/2019-09/schema#",
- "id": "compose_spec.json",
- "type": "object",
- "title": "Compose Specification",
- "description": "The Compose file is a YAML file defining a multi-containers based application.",
-
- "properties": {
- "version": {
- "type": "string",
- "description": "declared for backward compatibility, ignored."
- },
-
- "name": {
- "type": "string",
- "description": "define the Compose project name, until user defines one explicitly."
- },
-
- "services": {
- "id": "#/properties/services",
- "type": "object",
- "patternProperties": {
- "^[a-zA-Z0-9._-]+$": {
- "$ref": "#/definitions/service"
- }
- },
- "additionalProperties": false
- },
-
- "networks": {
- "id": "#/properties/networks",
- "type": "object",
- "patternProperties": {
- "^[a-zA-Z0-9._-]+$": {
- "$ref": "#/definitions/network"
- }
- }
- },
-
- "volumes": {
- "id": "#/properties/volumes",
- "type": "object",
- "patternProperties": {
- "^[a-zA-Z0-9._-]+$": {
- "$ref": "#/definitions/volume"
- }
- },
- "additionalProperties": false
- },
-
- "secrets": {
- "id": "#/properties/secrets",
- "type": "object",
- "patternProperties": {
- "^[a-zA-Z0-9._-]+$": {
- "$ref": "#/definitions/secret"
- }
- },
- "additionalProperties": false
- },
-
- "configs": {
- "id": "#/properties/configs",
- "type": "object",
- "patternProperties": {
- "^[a-zA-Z0-9._-]+$": {
- "$ref": "#/definitions/config"
- }
- },
- "additionalProperties": false
- }
- },
-
- "patternProperties": {"^x-": {}},
- "additionalProperties": false,
-
- "definitions": {
-
- "service": {
- "id": "#/definitions/service",
- "type": "object",
-
- "properties": {
- "deploy": {"$ref": "#/definitions/deployment"},
- "build": {
- "oneOf": [
- {"type": "string"},
- {
- "type": "object",
- "properties": {
- "context": {"type": "string"},
- "dockerfile": {"type": "string"},
- "args": {"$ref": "#/definitions/list_or_dict"},
- "ssh": {"$ref": "#/definitions/list_or_dict"},
- "labels": {"$ref": "#/definitions/list_or_dict"},
- "cache_from": {"type": "array", "items": {"type": "string"}},
- "cache_to": {"type": "array", "items": {"type": "string"}},
- "no_cache": {"type": "boolean"},
- "network": {"type": "string"},
- "pull": {"type": "boolean"},
- "target": {"type": "string"},
- "shm_size": {"type": ["integer", "string"]},
- "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
- "isolation": {"type": "string"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- ]
- },
- "blkio_config": {
- "type": "object",
- "properties": {
- "device_read_bps": {
- "type": "array",
- "items": {"$ref": "#/definitions/blkio_limit"}
- },
- "device_read_iops": {
- "type": "array",
- "items": {"$ref": "#/definitions/blkio_limit"}
- },
- "device_write_bps": {
- "type": "array",
- "items": {"$ref": "#/definitions/blkio_limit"}
- },
- "device_write_iops": {
- "type": "array",
- "items": {"$ref": "#/definitions/blkio_limit"}
- },
- "weight": {"type": "integer"},
- "weight_device": {
- "type": "array",
- "items": {"$ref": "#/definitions/blkio_weight"}
- }
- },
- "additionalProperties": false
- },
- "cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
- "cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
- "cgroup_parent": {"type": "string"},
- "command": {
- "oneOf": [
- {"type": "string"},
- {"type": "array", "items": {"type": "string"}}
- ]
- },
- "configs": {
- "type": "array",
- "items": {
- "oneOf": [
- {"type": "string"},
- {
- "type": "object",
- "properties": {
- "source": {"type": "string"},
- "target": {"type": "string"},
- "uid": {"type": "string"},
- "gid": {"type": "string"},
- "mode": {"type": "number"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- ]
- }
- },
- "container_name": {"type": "string"},
- "cpu_count": {"type": "integer", "minimum": 0},
- "cpu_percent": {"type": "integer", "minimum": 0, "maximum": 100},
- "cpu_shares": {"type": ["number", "string"]},
- "cpu_quota": {"type": ["number", "string"]},
- "cpu_period": {"type": ["number", "string"]},
- "cpu_rt_period": {"type": ["number", "string"]},
- "cpu_rt_runtime": {"type": ["number", "string"]},
- "cpus": {"type": ["number", "string"]},
- "cpuset": {"type": "string"},
- "credential_spec": {
- "type": "object",
- "properties": {
- "config": {"type": "string"},
- "file": {"type": "string"},
- "registry": {"type": "string"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "depends_on": {
- "oneOf": [
- {"$ref": "#/definitions/list_of_strings"},
- {
- "type": "object",
- "additionalProperties": false,
- "patternProperties": {
- "^[a-zA-Z0-9._-]+$": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "condition": {
- "type": "string",
- "enum": ["service_started", "service_healthy", "service_completed_successfully"]
- }
- },
- "required": ["condition"]
- }
- }
- }
- ]
- },
- "device_cgroup_rules": {"$ref": "#/definitions/list_of_strings"},
- "devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
- "dns": {"$ref": "#/definitions/string_or_list"},
- "dns_opt": {"type": "array","items": {"type": "string"}, "uniqueItems": true},
- "dns_search": {"$ref": "#/definitions/string_or_list"},
- "domainname": {"type": "string"},
- "entrypoint": {
- "oneOf": [
- {"type": "string"},
- {"type": "array", "items": {"type": "string"}}
- ]
- },
- "env_file": {"$ref": "#/definitions/string_or_list"},
- "environment": {"$ref": "#/definitions/list_or_dict"},
-
- "expose": {
- "type": "array",
- "items": {
- "type": ["string", "number"],
- "format": "expose"
- },
- "uniqueItems": true
- },
- "extends": {
- "oneOf": [
- {"type": "string"},
- {
- "type": "object",
-
- "properties": {
- "service": {"type": "string"},
- "file": {"type": "string"}
- },
- "required": ["service"],
- "additionalProperties": false
- }
- ]
- },
- "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
- "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
- "group_add": {
- "type": "array",
- "items": {
- "type": ["string", "number"]
- },
- "uniqueItems": true
- },
- "healthcheck": {"$ref": "#/definitions/healthcheck"},
- "hostname": {"type": "string"},
- "image": {"type": "string"},
- "init": {"type": "boolean"},
- "ipc": {"type": "string"},
- "isolation": {"type": "string"},
- "labels": {"$ref": "#/definitions/list_or_dict"},
- "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
- "logging": {
- "type": "object",
-
- "properties": {
- "driver": {"type": "string"},
- "options": {
- "type": "object",
- "patternProperties": {
- "^.+$": {"type": ["string", "number", "null"]}
- }
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "mac_address": {"type": "string"},
- "mem_limit": {"type": ["number", "string"]},
- "mem_reservation": {"type": ["string", "integer"]},
- "mem_swappiness": {"type": "integer"},
- "memswap_limit": {"type": ["number", "string"]},
- "network_mode": {"type": "string"},
- "networks": {
- "oneOf": [
- {"$ref": "#/definitions/list_of_strings"},
- {
- "type": "object",
- "patternProperties": {
- "^[a-zA-Z0-9._-]+$": {
- "oneOf": [
- {
- "type": "object",
- "properties": {
- "aliases": {"$ref": "#/definitions/list_of_strings"},
- "ipv4_address": {"type": "string"},
- "ipv6_address": {"type": "string"},
- "link_local_ips": {"$ref": "#/definitions/list_of_strings"},
- "priority": {"type": "number"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- {"type": "null"}
- ]
- }
- },
- "additionalProperties": false
- }
- ]
- },
- "oom_kill_disable": {"type": "boolean"},
- "oom_score_adj": {"type": "integer", "minimum": -1000, "maximum": 1000},
- "pid": {"type": ["string", "null"]},
- "pids_limit": {"type": ["number", "string"]},
- "platform": {"type": "string"},
- "ports": {
- "type": "array",
- "items": {
- "oneOf": [
- {"type": "number", "format": "ports"},
- {"type": "string", "format": "ports"},
- {
- "type": "object",
- "properties": {
- "mode": {"type": "string"},
- "host_ip": {"type": "string"},
- "target": {"type": "integer"},
- "published": {"type": ["string", "integer"]},
- "protocol": {"type": "string"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- ]
- },
- "uniqueItems": true
- },
- "privileged": {"type": "boolean"},
- "profiles": {"$ref": "#/definitions/list_of_strings"},
- "pull_policy": {"type": "string", "enum": [
- "always", "never", "if_not_present", "build", "missing"
- ]},
- "read_only": {"type": "boolean"},
- "restart": {"type": "string"},
- "runtime": {
- "type": "string"
- },
- "scale": {
- "type": "integer"
- },
- "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
- "shm_size": {"type": ["number", "string"]},
- "secrets": {
- "type": "array",
- "items": {
- "oneOf": [
- {"type": "string"},
- {
- "type": "object",
- "properties": {
- "source": {"type": "string"},
- "target": {"type": "string"},
- "uid": {"type": "string"},
- "gid": {"type": "string"},
- "mode": {"type": "number"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- ]
- }
- },
- "sysctls": {"$ref": "#/definitions/list_or_dict"},
- "stdin_open": {"type": "boolean"},
- "stop_grace_period": {"type": "string", "format": "duration"},
- "stop_signal": {"type": "string"},
- "storage_opt": {"type": "object"},
- "tmpfs": {"$ref": "#/definitions/string_or_list"},
- "tty": {"type": "boolean"},
- "ulimits": {
- "type": "object",
- "patternProperties": {
- "^[a-z]+$": {
- "oneOf": [
- {"type": "integer"},
- {
- "type": "object",
- "properties": {
- "hard": {"type": "integer"},
- "soft": {"type": "integer"}
- },
- "required": ["soft", "hard"],
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- ]
- }
- }
- },
- "user": {"type": "string"},
- "userns_mode": {"type": "string"},
- "volumes": {
- "type": "array",
- "items": {
- "oneOf": [
- {"type": "string"},
- {
- "type": "object",
- "required": ["type"],
- "properties": {
- "type": {"type": "string"},
- "source": {"type": "string"},
- "target": {"type": "string"},
- "read_only": {"type": "boolean"},
- "consistency": {"type": "string"},
- "bind": {
- "type": "object",
- "properties": {
- "propagation": {"type": "string"},
- "create_host_path": {"type": "boolean"},
- "selinux": {"type": "string", "enum": ["z", "Z"]}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "volume": {
- "type": "object",
- "properties": {
- "nocopy": {"type": "boolean"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "tmpfs": {
- "type": "object",
- "properties": {
- "size": {
- "oneOf": [
- {"type": "integer", "minimum": 0},
- {"type": "string"}
- ]
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- ]
- },
- "uniqueItems": true
- },
- "volumes_from": {
- "type": "array",
- "items": {"type": "string"},
- "uniqueItems": true
- },
- "working_dir": {"type": "string"}
- },
- "patternProperties": {"^x-": {}},
- "additionalProperties": false
- },
-
- "healthcheck": {
- "id": "#/definitions/healthcheck",
- "type": "object",
- "properties": {
- "disable": {"type": "boolean"},
- "interval": {"type": "string", "format": "duration"},
- "retries": {"type": "number"},
- "test": {
- "oneOf": [
- {"type": "string"},
- {"type": "array", "items": {"type": "string"}}
- ]
- },
- "timeout": {"type": "string", "format": "duration"},
- "start_period": {"type": "string", "format": "duration"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "deployment": {
- "id": "#/definitions/deployment",
- "type": ["object", "null"],
- "properties": {
- "mode": {"type": "string"},
- "endpoint_mode": {"type": "string"},
- "replicas": {"type": "integer"},
- "labels": {"$ref": "#/definitions/list_or_dict"},
- "rollback_config": {
- "type": "object",
- "properties": {
- "parallelism": {"type": "integer"},
- "delay": {"type": "string", "format": "duration"},
- "failure_action": {"type": "string"},
- "monitor": {"type": "string", "format": "duration"},
- "max_failure_ratio": {"type": "number"},
- "order": {"type": "string", "enum": [
- "start-first", "stop-first"
- ]}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "update_config": {
- "type": "object",
- "properties": {
- "parallelism": {"type": "integer"},
- "delay": {"type": "string", "format": "duration"},
- "failure_action": {"type": "string"},
- "monitor": {"type": "string", "format": "duration"},
- "max_failure_ratio": {"type": "number"},
- "order": {"type": "string", "enum": [
- "start-first", "stop-first"
- ]}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "resources": {
- "type": "object",
- "properties": {
- "limits": {
- "type": "object",
- "properties": {
- "cpus": {"type": ["number", "string"]},
- "memory": {"type": "string"},
- "pids": {"type": "integer"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "reservations": {
- "type": "object",
- "properties": {
- "cpus": {"type": ["number", "string"]},
- "memory": {"type": "string"},
- "generic_resources": {"$ref": "#/definitions/generic_resources"},
- "devices": {"$ref": "#/definitions/devices"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "restart_policy": {
- "type": "object",
- "properties": {
- "condition": {"type": "string"},
- "delay": {"type": "string", "format": "duration"},
- "max_attempts": {"type": "integer"},
- "window": {"type": "string", "format": "duration"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "placement": {
- "type": "object",
- "properties": {
- "constraints": {"type": "array", "items": {"type": "string"}},
- "preferences": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "spread": {"type": "string"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
- "max_replicas_per_node": {"type": "integer"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
-
- "generic_resources": {
- "id": "#/definitions/generic_resources",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "discrete_resource_spec": {
- "type": "object",
- "properties": {
- "kind": {"type": "string"},
- "value": {"type": "number"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
-
- "devices": {
- "id": "#/definitions/devices",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "capabilities": {"$ref": "#/definitions/list_of_strings"},
- "count": {"type": ["string", "integer"]},
- "device_ids": {"$ref": "#/definitions/list_of_strings"},
- "driver":{"type": "string"},
- "options":{"$ref": "#/definitions/list_or_dict"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
-
- "network": {
- "id": "#/definitions/network",
- "type": ["object", "null"],
- "properties": {
- "name": {"type": "string"},
- "driver": {"type": "string"},
- "driver_opts": {
- "type": "object",
- "patternProperties": {
- "^.+$": {"type": ["string", "number"]}
- }
- },
- "ipam": {
- "type": "object",
- "properties": {
- "driver": {"type": "string"},
- "config": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "subnet": {"type": "string", "format": "subnet_ip_address"},
- "ip_range": {"type": "string"},
- "gateway": {"type": "string"},
- "aux_addresses": {
- "type": "object",
- "additionalProperties": false,
- "patternProperties": {"^.+$": {"type": "string"}}
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- }
- },
- "options": {
- "type": "object",
- "additionalProperties": false,
- "patternProperties": {"^.+$": {"type": "string"}}
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "external": {
- "type": ["boolean", "object"],
- "properties": {
- "name": {
- "deprecated": true,
- "type": "string"
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "internal": {"type": "boolean"},
- "enable_ipv6": {"type": "boolean"},
- "attachable": {"type": "boolean"},
- "labels": {"$ref": "#/definitions/list_or_dict"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
-
- "volume": {
- "id": "#/definitions/volume",
- "type": ["object", "null"],
- "properties": {
- "name": {"type": "string"},
- "driver": {"type": "string"},
- "driver_opts": {
- "type": "object",
- "patternProperties": {
- "^.+$": {"type": ["string", "number"]}
- }
- },
- "external": {
- "type": ["boolean", "object"],
- "properties": {
- "name": {
- "deprecated": true,
- "type": "string"
- }
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
- "labels": {"$ref": "#/definitions/list_or_dict"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
-
- "secret": {
- "id": "#/definitions/secret",
- "type": "object",
- "properties": {
- "name": {"type": "string"},
- "file": {"type": "string"},
- "external": {
- "type": ["boolean", "object"],
- "properties": {
- "name": {"type": "string"}
- }
- },
- "labels": {"$ref": "#/definitions/list_or_dict"},
- "driver": {"type": "string"},
- "driver_opts": {
- "type": "object",
- "patternProperties": {
- "^.+$": {"type": ["string", "number"]}
- }
- },
- "template_driver": {"type": "string"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
-
- "config": {
- "id": "#/definitions/config",
- "type": "object",
- "properties": {
- "name": {"type": "string"},
- "file": {"type": "string"},
- "external": {
- "type": ["boolean", "object"],
- "properties": {
- "name": {
- "deprecated": true,
- "type": "string"
- }
- }
- },
- "labels": {"$ref": "#/definitions/list_or_dict"},
- "template_driver": {"type": "string"}
- },
- "additionalProperties": false,
- "patternProperties": {"^x-": {}}
- },
-
- "string_or_list": {
- "oneOf": [
- {"type": "string"},
- {"$ref": "#/definitions/list_of_strings"}
- ]
- },
-
- "list_of_strings": {
- "type": "array",
- "items": {"type": "string"},
- "uniqueItems": true
- },
-
- "list_or_dict": {
- "oneOf": [
- {
- "type": "object",
- "patternProperties": {
- ".+": {
- "type": ["string", "number", "boolean", "null"]
- }
- },
- "additionalProperties": false
- },
- {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
- ]
- },
-
- "blkio_limit": {
- "type": "object",
- "properties": {
- "path": {"type": "string"},
- "rate": {"type": ["integer", "string"]}
- },
- "additionalProperties": false
- },
- "blkio_weight": {
- "type": "object",
- "properties": {
- "path": {"type": "string"},
- "weight": {"type": "integer"}
- },
- "additionalProperties": false
- },
-
- "constraints": {
- "service": {
- "id": "#/definitions/constraints/service",
- "anyOf": [
- {"required": ["build"]},
- {"required": ["image"]}
- ],
- "properties": {
- "build": {
- "required": ["context"]
- }
- }
- }
- }
- }
-}
diff --git a/vendor/github.com/compose-spec/compose-go/schema/schema.go b/vendor/github.com/compose-spec/compose-go/schema/schema.go
deleted file mode 100644
index af3cb0a3be..0000000000
--- a/vendor/github.com/compose-spec/compose-go/schema/schema.go
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package schema
-
-import (
- "fmt"
- "strings"
- "time"
-
- "github.com/xeipuuv/gojsonschema"
-
- // Enable support for embedded static resources
- _ "embed"
-)
-
-type portsFormatChecker struct{}
-
-func (checker portsFormatChecker) IsFormat(input interface{}) bool {
- // TODO: implement this
- return true
-}
-
-type durationFormatChecker struct{}
-
-func (checker durationFormatChecker) IsFormat(input interface{}) bool {
- value, ok := input.(string)
- if !ok {
- return false
- }
- _, err := time.ParseDuration(value)
- return err == nil
-}
-
-func init() {
- gojsonschema.FormatCheckers.Add("expose", portsFormatChecker{})
- gojsonschema.FormatCheckers.Add("ports", portsFormatChecker{})
- gojsonschema.FormatCheckers.Add("duration", durationFormatChecker{})
-}
-
-// Schema is the compose-spec JSON schema
-//go:embed compose-spec.json
-var Schema string
-
-// Validate uses the jsonschema to validate the configuration
-func Validate(config map[string]interface{}) error {
- schemaLoader := gojsonschema.NewStringLoader(Schema)
- dataLoader := gojsonschema.NewGoLoader(config)
-
- result, err := gojsonschema.Validate(schemaLoader, dataLoader)
- if err != nil {
- return err
- }
-
- if !result.Valid() {
- return toError(result)
- }
-
- return nil
-}
-
-func toError(result *gojsonschema.Result) error {
- err := getMostSpecificError(result.Errors())
- return err
-}
-
-const (
- jsonschemaOneOf = "number_one_of"
- jsonschemaAnyOf = "number_any_of"
-)
-
-func getDescription(err validationError) string {
- switch err.parent.Type() {
- case "invalid_type":
- if expectedType, ok := err.parent.Details()["expected"].(string); ok {
- return fmt.Sprintf("must be a %s", humanReadableType(expectedType))
- }
- case jsonschemaOneOf, jsonschemaAnyOf:
- if err.child == nil {
- return err.parent.Description()
- }
- return err.child.Description()
- }
- return err.parent.Description()
-}
-
-func humanReadableType(definition string) string {
- if definition[0:1] == "[" {
- allTypes := strings.Split(definition[1:len(definition)-1], ",")
- for i, t := range allTypes {
- allTypes[i] = humanReadableType(t)
- }
- return fmt.Sprintf(
- "%s or %s",
- strings.Join(allTypes[0:len(allTypes)-1], ", "),
- allTypes[len(allTypes)-1],
- )
- }
- if definition == "object" {
- return "mapping"
- }
- if definition == "array" {
- return "list"
- }
- return definition
-}
-
-type validationError struct {
- parent gojsonschema.ResultError
- child gojsonschema.ResultError
-}
-
-func (err validationError) Error() string {
- description := getDescription(err)
- return fmt.Sprintf("%s %s", err.parent.Field(), description)
-}
-
-func getMostSpecificError(errors []gojsonschema.ResultError) validationError {
- mostSpecificError := 0
- for i, err := range errors {
- if specificity(err) > specificity(errors[mostSpecificError]) {
- mostSpecificError = i
- continue
- }
-
- if specificity(err) == specificity(errors[mostSpecificError]) {
- // Invalid type errors win in a tie-breaker for most specific field name
- if err.Type() == "invalid_type" && errors[mostSpecificError].Type() != "invalid_type" {
- mostSpecificError = i
- }
- }
- }
-
- if mostSpecificError+1 == len(errors) {
- return validationError{parent: errors[mostSpecificError]}
- }
-
- switch errors[mostSpecificError].Type() {
- case "number_one_of", "number_any_of":
- return validationError{
- parent: errors[mostSpecificError],
- child: errors[mostSpecificError+1],
- }
- default:
- return validationError{parent: errors[mostSpecificError]}
- }
-}
-
-func specificity(err gojsonschema.ResultError) int {
- return len(strings.Split(err.Field(), "."))
-}
diff --git a/vendor/github.com/compose-spec/compose-go/template/template.go b/vendor/github.com/compose-spec/compose-go/template/template.go
deleted file mode 100644
index 22e4e95ada..0000000000
--- a/vendor/github.com/compose-spec/compose-go/template/template.go
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package template
-
-import (
- "fmt"
- "regexp"
- "strings"
-
- "github.com/sirupsen/logrus"
-)
-
-var delimiter = "\\$"
-var substitutionNamed = "[_a-z][_a-z0-9]*"
-
-var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-?](.*}|[^}]*))?"
-
-var patternString = fmt.Sprintf(
- "%s(?i:(?P%s)|(?P%s)|{(?P%s)}|(?P))",
- delimiter, delimiter, substitutionNamed, substitutionBraced,
-)
-
-var defaultPattern = regexp.MustCompile(patternString)
-
-// InvalidTemplateError is returned when a variable template is not in a valid
-// format
-type InvalidTemplateError struct {
- Template string
-}
-
-func (e InvalidTemplateError) Error() string {
- return fmt.Sprintf("Invalid template: %#v", e.Template)
-}
-
-// Mapping is a user-supplied function which maps from variable names to values.
-// Returns the value as a string and a bool indicating whether
-// the value is present, to distinguish between an empty string
-// and the absence of a value.
-type Mapping func(string) (string, bool)
-
-// SubstituteFunc is a user-supplied function that apply substitution.
-// Returns the value as a string, a bool indicating if the function could apply
-// the substitution and an error.
-type SubstituteFunc func(string, Mapping) (string, bool, error)
-
-// SubstituteWith substitute variables in the string with their values.
-// It accepts additional substitute function.
-func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, subsFuncs ...SubstituteFunc) (string, error) {
- if len(subsFuncs) == 0 {
- subsFuncs = getDefaultSortedSubstitutionFunctions(template)
- }
- var err error
- result := pattern.ReplaceAllStringFunc(template, func(substring string) string {
- closingBraceIndex := getFirstBraceClosingIndex(substring)
- rest := ""
- if closingBraceIndex > -1 {
- rest = substring[closingBraceIndex+1:]
- substring = substring[0 : closingBraceIndex+1]
- }
-
- matches := pattern.FindStringSubmatch(substring)
- groups := matchGroups(matches, pattern)
- if escaped := groups["escaped"]; escaped != "" {
- return escaped
- }
-
- braced := false
- substitution := groups["named"]
- if substitution == "" {
- substitution = groups["braced"]
- braced = true
- }
-
- if substitution == "" {
- err = &InvalidTemplateError{Template: template}
- return ""
- }
-
- if braced {
- for _, f := range subsFuncs {
- var (
- value string
- applied bool
- )
- value, applied, err = f(substitution, mapping)
- if err != nil {
- return ""
- }
- if !applied {
- continue
- }
- interpolatedNested, err := SubstituteWith(rest, mapping, pattern, subsFuncs...)
- if err != nil {
- return ""
- }
- return value + interpolatedNested
- }
- }
-
- value, ok := mapping(substitution)
- if !ok {
- logrus.Warnf("The %q variable is not set. Defaulting to a blank string.", substitution)
- }
- return value
- })
-
- return result, err
-}
-
-func getDefaultSortedSubstitutionFunctions(template string, fns ...SubstituteFunc) []SubstituteFunc {
- hyphenIndex := strings.IndexByte(template, '-')
- questionIndex := strings.IndexByte(template, '?')
- if hyphenIndex < 0 || hyphenIndex > questionIndex {
- return []SubstituteFunc{
- requiredNonEmpty,
- required,
- softDefault,
- hardDefault,
- }
- }
- return []SubstituteFunc{
- softDefault,
- hardDefault,
- requiredNonEmpty,
- required,
- }
-}
-
-func getFirstBraceClosingIndex(s string) int {
- openVariableBraces := 0
- for i := 0; i < len(s); i++ {
- if s[i] == '}' {
- openVariableBraces--
- if openVariableBraces == 0 {
- return i
- }
- }
- if strings.HasPrefix(s[i:], "${") {
- openVariableBraces++
- i++
- }
- }
- return -1
-}
-
-// Substitute variables in the string with their values
-func Substitute(template string, mapping Mapping) (string, error) {
- return SubstituteWith(template, mapping, defaultPattern)
-}
-
-// ExtractVariables returns a map of all the variables defined in the specified
-// composefile (dict representation) and their default value if any.
-func ExtractVariables(configDict map[string]interface{}, pattern *regexp.Regexp) map[string]Variable {
- if pattern == nil {
- pattern = defaultPattern
- }
- return recurseExtract(configDict, pattern)
-}
-
-func recurseExtract(value interface{}, pattern *regexp.Regexp) map[string]Variable {
- m := map[string]Variable{}
-
- switch value := value.(type) {
- case string:
- if values, is := extractVariable(value, pattern); is {
- for _, v := range values {
- m[v.Name] = v
- }
- }
- case map[string]interface{}:
- for _, elem := range value {
- submap := recurseExtract(elem, pattern)
- for key, value := range submap {
- m[key] = value
- }
- }
-
- case []interface{}:
- for _, elem := range value {
- if values, is := extractVariable(elem, pattern); is {
- for _, v := range values {
- m[v.Name] = v
- }
- }
- }
- }
-
- return m
-}
-
-type Variable struct {
- Name string
- DefaultValue string
- Required bool
-}
-
-func extractVariable(value interface{}, pattern *regexp.Regexp) ([]Variable, bool) {
- sValue, ok := value.(string)
- if !ok {
- return []Variable{}, false
- }
- matches := pattern.FindAllStringSubmatch(sValue, -1)
- if len(matches) == 0 {
- return []Variable{}, false
- }
- values := []Variable{}
- for _, match := range matches {
- groups := matchGroups(match, pattern)
- if escaped := groups["escaped"]; escaped != "" {
- continue
- }
- val := groups["named"]
- if val == "" {
- val = groups["braced"]
- }
- name := val
- var defaultValue string
- var required bool
- switch {
- case strings.Contains(val, ":?"):
- name, _ = partition(val, ":?")
- required = true
- case strings.Contains(val, "?"):
- name, _ = partition(val, "?")
- required = true
- case strings.Contains(val, ":-"):
- name, defaultValue = partition(val, ":-")
- case strings.Contains(val, "-"):
- name, defaultValue = partition(val, "-")
- }
- values = append(values, Variable{
- Name: name,
- DefaultValue: defaultValue,
- Required: required,
- })
- }
- return values, len(values) > 0
-}
-
-// Soft default (fall back if unset or empty)
-func softDefault(substitution string, mapping Mapping) (string, bool, error) {
- sep := ":-"
- if !strings.Contains(substitution, sep) {
- return "", false, nil
- }
- name, defaultValue := partition(substitution, sep)
- defaultValue, err := Substitute(defaultValue, mapping)
- if err != nil {
- return "", false, err
- }
- value, ok := mapping(name)
- if !ok || value == "" {
- return defaultValue, true, nil
- }
- return value, true, nil
-}
-
-// Hard default (fall back if-and-only-if empty)
-func hardDefault(substitution string, mapping Mapping) (string, bool, error) {
- sep := "-"
- if !strings.Contains(substitution, sep) {
- return "", false, nil
- }
- name, defaultValue := partition(substitution, sep)
- defaultValue, err := Substitute(defaultValue, mapping)
- if err != nil {
- return "", false, err
- }
- value, ok := mapping(name)
- if !ok {
- return defaultValue, true, nil
- }
- return value, true, nil
-}
-
-func requiredNonEmpty(substitution string, mapping Mapping) (string, bool, error) {
- return withRequired(substitution, mapping, ":?", func(v string) bool { return v != "" })
-}
-
-func required(substitution string, mapping Mapping) (string, bool, error) {
- return withRequired(substitution, mapping, "?", func(_ string) bool { return true })
-}
-
-func withRequired(substitution string, mapping Mapping, sep string, valid func(string) bool) (string, bool, error) {
- if !strings.Contains(substitution, sep) {
- return "", false, nil
- }
- name, errorMessage := partition(substitution, sep)
- errorMessage, err := Substitute(errorMessage, mapping)
- if err != nil {
- return "", false, err
- }
- value, ok := mapping(name)
- if !ok || !valid(value) {
- return "", true, &InvalidTemplateError{
- Template: fmt.Sprintf("required variable %s is missing a value: %s", name, errorMessage),
- }
- }
- return value, true, nil
-}
-
-func matchGroups(matches []string, pattern *regexp.Regexp) map[string]string {
- groups := make(map[string]string)
- for i, name := range pattern.SubexpNames()[1:] {
- groups[name] = matches[i+1]
- }
- return groups
-}
-
-// Split the string at the first occurrence of sep, and return the part before the separator,
-// and the part after the separator.
-//
-// If the separator is not found, return the string itself, followed by an empty string.
-func partition(s, sep string) (string, string) {
- if strings.Contains(s, sep) {
- parts := strings.SplitN(s, sep, 2)
- return parts[0], parts[1]
- }
- return s, ""
-}
diff --git a/vendor/github.com/compose-spec/compose-go/types/config.go b/vendor/github.com/compose-spec/compose-go/types/config.go
deleted file mode 100644
index b395363bd3..0000000000
--- a/vendor/github.com/compose-spec/compose-go/types/config.go
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package types
-
-import (
- "encoding/json"
-
- "github.com/mitchellh/mapstructure"
-)
-
-// ConfigDetails are the details about a group of ConfigFiles
-type ConfigDetails struct {
- Version string
- WorkingDir string
- ConfigFiles []ConfigFile
- Environment map[string]string
-}
-
-// LookupEnv provides a lookup function for environment variables
-func (cd ConfigDetails) LookupEnv(key string) (string, bool) {
- v, ok := cd.Environment[key]
- return v, ok
-}
-
-// ConfigFile is a filename and the contents of the file as a Dict
-type ConfigFile struct {
- // Filename is the name of the yaml configuration file
- Filename string
- // Content is the raw yaml content. Will be loaded from Filename if not set
- Content []byte
- // Config if the yaml tree for this config file. Will be parsed from Content if not set
- Config map[string]interface{}
-}
-
-// Config is a full compose file configuration and model
-type Config struct {
- Filename string `yaml:"-" json:"-"`
- Name string `yaml:",omitempty" json:"name,omitempty"`
- Services Services `json:"services"`
- Networks Networks `yaml:",omitempty" json:"networks,omitempty"`
- Volumes Volumes `yaml:",omitempty" json:"volumes,omitempty"`
- Secrets Secrets `yaml:",omitempty" json:"secrets,omitempty"`
- Configs Configs `yaml:",omitempty" json:"configs,omitempty"`
- Extensions Extensions `yaml:",inline" json:"-"`
-}
-
-// Volumes is a map of VolumeConfig
-type Volumes map[string]VolumeConfig
-
-// Networks is a map of NetworkConfig
-type Networks map[string]NetworkConfig
-
-// Secrets is a map of SecretConfig
-type Secrets map[string]SecretConfig
-
-// Configs is a map of ConfigObjConfig
-type Configs map[string]ConfigObjConfig
-
-// Extensions is a map of custom extension
-type Extensions map[string]interface{}
-
-// MarshalJSON makes Config implement json.Marshaler
-func (c Config) MarshalJSON() ([]byte, error) {
- m := map[string]interface{}{
- "services": c.Services,
- }
-
- if len(c.Networks) > 0 {
- m["networks"] = c.Networks
- }
- if len(c.Volumes) > 0 {
- m["volumes"] = c.Volumes
- }
- if len(c.Secrets) > 0 {
- m["secrets"] = c.Secrets
- }
- if len(c.Configs) > 0 {
- m["configs"] = c.Configs
- }
- for k, v := range c.Extensions {
- m[k] = v
- }
- return json.Marshal(m)
-}
-
-func (e Extensions) Get(name string, target interface{}) (bool, error) {
- if v, ok := e[name]; ok {
- err := mapstructure.Decode(v, target)
- return true, err
- }
- return false, nil
-}
diff --git a/vendor/github.com/compose-spec/compose-go/types/project.go b/vendor/github.com/compose-spec/compose-go/types/project.go
deleted file mode 100644
index dc208ed587..0000000000
--- a/vendor/github.com/compose-spec/compose-go/types/project.go
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package types
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "sort"
-
- "github.com/distribution/distribution/v3/reference"
- "github.com/opencontainers/go-digest"
- "golang.org/x/sync/errgroup"
-)
-
-// Project is the result of loading a set of compose files
-type Project struct {
- Name string `yaml:"name,omitempty" json:"name,omitempty"`
- WorkingDir string `yaml:"-" json:"-"`
- Services Services `json:"services"`
- Networks Networks `yaml:",omitempty" json:"networks,omitempty"`
- Volumes Volumes `yaml:",omitempty" json:"volumes,omitempty"`
- Secrets Secrets `yaml:",omitempty" json:"secrets,omitempty"`
- Configs Configs `yaml:",omitempty" json:"configs,omitempty"`
- Extensions Extensions `yaml:",inline" json:"-"` // https://github.com/golang/go/issues/6213
- ComposeFiles []string `yaml:"-" json:"-"`
- Environment map[string]string `yaml:"-" json:"-"`
-
- // DisabledServices track services which have been disable as profile is not active
- DisabledServices Services `yaml:"-" json:"-"`
-}
-
-// ServiceNames return names for all services in this Compose config
-func (p Project) ServiceNames() []string {
- var names []string
- for _, s := range p.Services {
- names = append(names, s.Name)
- }
- sort.Strings(names)
- return names
-}
-
-// VolumeNames return names for all volumes in this Compose config
-func (p Project) VolumeNames() []string {
- var names []string
- for k := range p.Volumes {
- names = append(names, k)
- }
- sort.Strings(names)
- return names
-}
-
-// NetworkNames return names for all volumes in this Compose config
-func (p Project) NetworkNames() []string {
- var names []string
- for k := range p.Networks {
- names = append(names, k)
- }
- sort.Strings(names)
- return names
-}
-
-// SecretNames return names for all secrets in this Compose config
-func (p Project) SecretNames() []string {
- var names []string
- for k := range p.Secrets {
- names = append(names, k)
- }
- sort.Strings(names)
- return names
-}
-
-// ConfigNames return names for all configs in this Compose config
-func (p Project) ConfigNames() []string {
- var names []string
- for k := range p.Configs {
- names = append(names, k)
- }
- sort.Strings(names)
- return names
-}
-
-// GetServices retrieve services by names, or return all services if no name specified
-func (p Project) GetServices(names ...string) (Services, error) {
- if len(names) == 0 {
- return p.Services, nil
- }
- services := Services{}
- for _, name := range names {
- var serviceConfig *ServiceConfig
- for _, s := range p.Services {
- if s.Name == name {
- serviceConfig = &s
- break
- }
- }
- if serviceConfig == nil {
- return services, fmt.Errorf("no such service: %s", name)
- }
- services = append(services, *serviceConfig)
- }
- return services, nil
-}
-
-// GetService retrieve a specific service by name
-func (p Project) GetService(name string) (ServiceConfig, error) {
- services, err := p.GetServices(name)
- if err != nil {
- return ServiceConfig{}, err
- }
- if len(services) == 0 {
- return ServiceConfig{}, fmt.Errorf("no such service: %s", name)
- }
- return services[0], nil
-}
-
-func (p Project) AllServices() Services {
- var all Services
- all = append(all, p.Services...)
- all = append(all, p.DisabledServices...)
- return all
-}
-
-type ServiceFunc func(service ServiceConfig) error
-
-// WithServices run ServiceFunc on each service and dependencies in dependency order
-func (p Project) WithServices(names []string, fn ServiceFunc) error {
- return p.withServices(names, fn, map[string]bool{})
-}
-
-func (p Project) withServices(names []string, fn ServiceFunc, done map[string]bool) error {
- services, err := p.GetServices(names...)
- if err != nil {
- return err
- }
- for _, service := range services {
- if done[service.Name] {
- continue
- }
- dependencies := service.GetDependencies()
- if len(dependencies) > 0 {
- err := p.withServices(dependencies, fn, done)
- if err != nil {
- return err
- }
- }
- if err := fn(service); err != nil {
- return err
- }
- done[service.Name] = true
- }
- return nil
-}
-
-// RelativePath resolve a relative path based project's working directory
-func (p *Project) RelativePath(path string) string {
- if path[0] == '~' {
- home, _ := os.UserHomeDir()
- path = filepath.Join(home, path[1:])
- }
- if filepath.IsAbs(path) {
- return path
- }
- return filepath.Join(p.WorkingDir, path)
-}
-
-// HasProfile return true if service has no profile declared or has at least one profile matching
-func (s ServiceConfig) HasProfile(profiles []string) bool {
- if len(s.Profiles) == 0 {
- return true
- }
- for _, p := range profiles {
- for _, sp := range s.Profiles {
- if sp == p {
- return true
- }
- }
- }
- return false
-}
-
-// GetProfiles retrieve the profiles implicitly enabled by explicitly targeting selected services
-func (s Services) GetProfiles() []string {
- set := map[string]struct{}{}
- for _, service := range s {
- for _, p := range service.Profiles {
- set[p] = struct{}{}
- }
- }
- var profiles []string
- for k := range set {
- profiles = append(profiles, k)
- }
- return profiles
-}
-
-// ApplyProfiles disables service which don't match selected profiles
-func (p *Project) ApplyProfiles(profiles []string) {
- for _, p := range profiles {
- if p == "*" {
- return
- }
- }
- var enabled, disabled Services
- for _, service := range p.Services {
- if service.HasProfile(profiles) {
- enabled = append(enabled, service)
- } else {
- disabled = append(disabled, service)
- }
- }
- p.Services = enabled
- p.DisabledServices = disabled
-}
-
-// WithoutUnnecessaryResources drops networks/volumes/secrets/configs that are not referenced by active services
-func (p *Project) WithoutUnnecessaryResources() {
- requiredNetworks := map[string]struct{}{}
- requiredVolumes := map[string]struct{}{}
- requiredSecrets := map[string]struct{}{}
- requiredConfigs := map[string]struct{}{}
- for _, s := range p.Services {
- for k := range s.Networks {
- requiredNetworks[k] = struct{}{}
- }
- for _, v := range s.Volumes {
- if v.Type != VolumeTypeVolume || v.Source == "" {
- continue
- }
- requiredVolumes[v.Source] = struct{}{}
- }
- for _, v := range s.Secrets {
- requiredSecrets[v.Source] = struct{}{}
- }
- for _, v := range s.Configs {
- requiredConfigs[v.Source] = struct{}{}
- }
- }
-
- networks := Networks{}
- for k := range requiredNetworks {
- networks[k] = p.Networks[k]
- }
- p.Networks = networks
-
- volumes := Volumes{}
- for k := range requiredVolumes {
- volumes[k] = p.Volumes[k]
- }
- p.Volumes = volumes
-
- secrets := Secrets{}
- for k := range requiredSecrets {
- secrets[k] = p.Secrets[k]
- }
- p.Secrets = secrets
-
- configs := Configs{}
- for k := range requiredConfigs {
- configs[k] = p.Configs[k]
- }
- p.Configs = configs
-}
-
-// ForServices restrict the project model to a subset of services
-func (p *Project) ForServices(names []string) error {
- if len(names) == 0 {
- // All services
- return nil
- }
-
- set := map[string]struct{}{}
- err := p.WithServices(names, func(service ServiceConfig) error {
- set[service.Name] = struct{}{}
- return nil
- })
- if err != nil {
- return err
- }
-
- // Disable all services which are not explicit target or dependencies
- var enabled Services
- for _, s := range p.Services {
- if _, ok := set[s.Name]; ok {
- enabled = append(enabled, s)
- } else {
- p.DisabledServices = append(p.DisabledServices, s)
- }
- }
- p.Services = enabled
- return nil
-}
-
-// ResolveImages updates services images to include digest computed by a resolver function
-func (p *Project) ResolveImages(resolver func(named reference.Named) (digest.Digest, error)) error {
- eg := errgroup.Group{}
- for i, s := range p.Services {
- idx := i
- service := s
-
- if service.Image == "" {
- continue
- }
- eg.Go(func() error {
- named, err := reference.ParseDockerRef(service.Image)
- if err != nil {
- return err
- }
-
- if _, ok := named.(reference.Canonical); !ok {
- // image is named but not digested reference
- digest, err := resolver(named)
- if err != nil {
- return err
- }
- named, err = reference.WithDigest(named, digest)
- if err != nil {
- return err
- }
- }
-
- service.Image = named.String()
- p.Services[idx] = service
- return nil
- })
- }
- return eg.Wait()
-}
diff --git a/vendor/github.com/compose-spec/compose-go/types/types.go b/vendor/github.com/compose-spec/compose-go/types/types.go
deleted file mode 100644
index ec4b0bc73f..0000000000
--- a/vendor/github.com/compose-spec/compose-go/types/types.go
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- Copyright 2020 The Compose Specification Authors.
-
- 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.
-*/
-
-package types
-
-import (
- "encoding/json"
- "fmt"
- "sort"
- "strings"
- "time"
-
- "github.com/docker/go-connections/nat"
-)
-
-// Duration is a thin wrapper around time.Duration with improved JSON marshalling
-type Duration time.Duration
-
-func (d Duration) String() string {
- return time.Duration(d).String()
-}
-
-// ConvertDurationPtr converts a type defined Duration pointer to a time.Duration pointer with the same value.
-func ConvertDurationPtr(d *Duration) *time.Duration {
- if d == nil {
- return nil
- }
- res := time.Duration(*d)
- return &res
-}
-
-// MarshalJSON makes Duration implement json.Marshaler
-func (d Duration) MarshalJSON() ([]byte, error) {
- return json.Marshal(d.String())
-}
-
-// MarshalYAML makes Duration implement yaml.Marshaler
-func (d Duration) MarshalYAML() (interface{}, error) {
- return d.String(), nil
-}
-
-func (d *Duration) UnmarshalJSON(b []byte) error {
- s := strings.Trim(string(b), "\"")
- timeDuration, err := time.ParseDuration(s)
- if err != nil {
- return err
- }
- *d = Duration(timeDuration)
- return nil
-}
-
-// Services is a list of ServiceConfig
-type Services []ServiceConfig
-
-// MarshalYAML makes Services implement yaml.Marshaller
-func (s Services) MarshalYAML() (interface{}, error) {
- services := map[string]ServiceConfig{}
- for _, service := range s {
- services[service.Name] = service
- }
- return services, nil
-}
-
-// MarshalJSON makes Services implement json.Marshaler
-func (s Services) MarshalJSON() ([]byte, error) {
- data, err := s.MarshalYAML()
- if err != nil {
- return nil, err
- }
- return json.MarshalIndent(data, "", " ")
-}
-
-// ServiceConfig is the configuration of one service
-type ServiceConfig struct {
- Name string `yaml:"-" json:"-"`
- Profiles []string `mapstructure:"profiles" yaml:"profiles,omitempty" json:"profiles,omitempty"`
-
- Build *BuildConfig `yaml:",omitempty" json:"build,omitempty"`
- BlkioConfig *BlkioConfig `mapstructure:"blkio_config" yaml:",omitempty" json:"blkio_config,omitempty"`
- CapAdd []string `mapstructure:"cap_add" yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
- CapDrop []string `mapstructure:"cap_drop" yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"`
- CgroupParent string `mapstructure:"cgroup_parent" yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"`
- CPUCount int64 `mapstructure:"cpu_count" yaml:"cpu_count,omitempty" json:"cpu_count,omitempty"`
- CPUPercent float32 `mapstructure:"cpu_percent" yaml:"cpu_percent,omitempty" json:"cpu_percent,omitempty"`
- CPUPeriod int64 `mapstructure:"cpu_period" yaml:"cpu_period,omitempty" json:"cpu_period,omitempty"`
- CPUQuota int64 `mapstructure:"cpu_quota" yaml:"cpu_quota,omitempty" json:"cpu_quota,omitempty"`
- CPURTPeriod int64 `mapstructure:"cpu_rt_period" yaml:"cpu_rt_period,omitempty" json:"cpu_rt_period,omitempty"`
- CPURTRuntime int64 `mapstructure:"cpu_rt_runtime" yaml:"cpu_rt_runtime,omitempty" json:"cpu_rt_runtime,omitempty"`
- CPUS float32 `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
- CPUSet string `mapstructure:"cpuset" yaml:"cpuset,omitempty" json:"cpuset,omitempty"`
- CPUShares int64 `mapstructure:"cpu_shares" yaml:"cpu_shares,omitempty" json:"cpu_shares,omitempty"`
- Command ShellCommand `yaml:",omitempty" json:"command,omitempty"`
- Configs []ServiceConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`
- ContainerName string `mapstructure:"container_name" yaml:"container_name,omitempty" json:"container_name,omitempty"`
- CredentialSpec *CredentialSpecConfig `mapstructure:"credential_spec" yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
- DependsOn DependsOnConfig `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
- Deploy *DeployConfig `yaml:",omitempty" json:"deploy,omitempty"`
- DeviceCgroupRules []string `mapstructure:"device_cgroup_rules" yaml:"device_cgroup_rules,omitempty" json:"device_cgroup_rules,omitempty"`
- Devices []string `yaml:",omitempty" json:"devices,omitempty"`
- DNS StringList `yaml:",omitempty" json:"dns,omitempty"`
- DNSOpts []string `mapstructure:"dns_opt" yaml:"dns_opt,omitempty" json:"dns_opt,omitempty"`
- DNSSearch StringList `mapstructure:"dns_search" yaml:"dns_search,omitempty" json:"dns_search,omitempty"`
- Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
- DomainName string `mapstructure:"domainname" yaml:"domainname,omitempty" json:"domainname,omitempty"`
- Entrypoint ShellCommand `yaml:",omitempty" json:"entrypoint,omitempty"`
- Environment MappingWithEquals `yaml:",omitempty" json:"environment,omitempty"`
- EnvFile StringList `mapstructure:"env_file" yaml:"env_file,omitempty" json:"env_file,omitempty"`
- Expose StringOrNumberList `yaml:",omitempty" json:"expose,omitempty"`
- Extends ExtendsConfig `yaml:"extends,omitempty" json:"extends,omitempty"`
- ExternalLinks []string `mapstructure:"external_links" yaml:"external_links,omitempty" json:"external_links,omitempty"`
- ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
- GroupAdd []string `mapstructure:"group_add" yaml:"group_add,omitempty" json:"group_add,omitempty"`
- Hostname string `yaml:",omitempty" json:"hostname,omitempty"`
- HealthCheck *HealthCheckConfig `yaml:",omitempty" json:"healthcheck,omitempty"`
- Image string `yaml:",omitempty" json:"image,omitempty"`
- Init *bool `yaml:",omitempty" json:"init,omitempty"`
- Ipc string `yaml:",omitempty" json:"ipc,omitempty"`
- Isolation string `mapstructure:"isolation" yaml:"isolation,omitempty" json:"isolation,omitempty"`
- Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
- CustomLabels Labels `yaml:"-" json:"-"`
- Links []string `yaml:",omitempty" json:"links,omitempty"`
- Logging *LoggingConfig `yaml:",omitempty" json:"logging,omitempty"`
- LogDriver string `mapstructure:"log_driver" yaml:"log_driver,omitempty" json:"log_driver,omitempty"`
- LogOpt map[string]string `mapstructure:"log_opt" yaml:"log_opt,omitempty" json:"log_opt,omitempty"`
- MemLimit UnitBytes `mapstructure:"mem_limit" yaml:"mem_limit,omitempty" json:"mem_limit,omitempty"`
- MemReservation UnitBytes `mapstructure:"mem_reservation" yaml:"mem_reservation,omitempty" json:"mem_reservation,omitempty"`
- MemSwapLimit UnitBytes `mapstructure:"memswap_limit" yaml:"memswap_limit,omitempty" json:"memswap_limit,omitempty"`
- MemSwappiness UnitBytes `mapstructure:"mem_swappiness" yaml:"mem_swappiness,omitempty" json:"mem_swappiness,omitempty"`
- MacAddress string `mapstructure:"mac_address" yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
- Net string `yaml:"net,omitempty" json:"net,omitempty"`
- NetworkMode string `mapstructure:"network_mode" yaml:"network_mode,omitempty" json:"network_mode,omitempty"`
- Networks map[string]*ServiceNetworkConfig `yaml:",omitempty" json:"networks,omitempty"`
- OomKillDisable bool `mapstructure:"oom_kill_disable" yaml:"oom_kill_disable,omitempty" json:"oom_kill_disable,omitempty"`
- OomScoreAdj int64 `mapstructure:"oom_score_adj" yaml:"oom_score_adj,omitempty" json:"oom_score_adj,omitempty"`
- Pid string `yaml:",omitempty" json:"pid,omitempty"`
- PidsLimit int64 `mapstructure:"pids_limit" yaml:"pids_limit,omitempty" json:"pids_limit,omitempty"`
- Platform string `yaml:",omitempty" json:"platform,omitempty"`
- Ports []ServicePortConfig `yaml:",omitempty" json:"ports,omitempty"`
- Privileged bool `yaml:",omitempty" json:"privileged,omitempty"`
- PullPolicy string `mapstructure:"pull_policy" yaml:"pull_policy,omitempty" json:"pull_policy,omitempty"`
- ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
- Restart string `yaml:",omitempty" json:"restart,omitempty"`
- Runtime string `yaml:",omitempty" json:"runtime,omitempty"`
- Scale int `yaml:"-" json:"-"`
- Secrets []ServiceSecretConfig `yaml:",omitempty" json:"secrets,omitempty"`
- SecurityOpt []string `mapstructure:"security_opt" yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
- ShmSize UnitBytes `mapstructure:"shm_size" yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
- StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
- StopGracePeriod *Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
- StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
- Sysctls Mapping `yaml:",omitempty" json:"sysctls,omitempty"`
- Tmpfs StringList `yaml:",omitempty" json:"tmpfs,omitempty"`
- Tty bool `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"`
- Ulimits map[string]*UlimitsConfig `yaml:",omitempty" json:"ulimits,omitempty"`
- User string `yaml:",omitempty" json:"user,omitempty"`
- UserNSMode string `mapstructure:"userns_mode" yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"`
- Uts string `yaml:"uts,omitempty" json:"uts,omitempty"`
- VolumeDriver string `mapstructure:"volume_driver" yaml:"volume_driver,omitempty" json:"volume_driver,omitempty"`
- Volumes []ServiceVolumeConfig `yaml:",omitempty" json:"volumes,omitempty"`
- VolumesFrom []string `mapstructure:"volumes_from" yaml:"volumes_from,omitempty" json:"volumes_from,omitempty"`
- WorkingDir string `mapstructure:"working_dir" yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// NetworksByPriority return the service networks IDs sorted according to Priority
-func (s *ServiceConfig) NetworksByPriority() []string {
- type key struct {
- name string
- priority int
- }
- var keys []key
- for k, v := range s.Networks {
- priority := 0
- if v != nil {
- priority = v.Priority
- }
- keys = append(keys, key{
- name: k,
- priority: priority,
- })
- }
- sort.Slice(keys, func(i, j int) bool {
- return keys[i].priority > keys[j].priority
- })
- var sorted []string
- for _, k := range keys {
- sorted = append(sorted, k.name)
- }
- return sorted
-}
-
-const (
- //PullPolicyAlways always pull images
- PullPolicyAlways = "always"
- //PullPolicyNever never pull images
- PullPolicyNever = "never"
- //PullPolicyIfNotPresent pull missing images
- PullPolicyIfNotPresent = "if_not_present"
- //PullPolicyMissing pull missing images
- PullPolicyMissing = "missing"
- //PullPolicyBuild force building images
- PullPolicyBuild = "build"
-)
-
-const (
- //RestartPolicyAlways always restart the container if it stops
- RestartPolicyAlways = "always"
- //RestartPolicyOnFailure restart the container if it exits due to an error
- RestartPolicyOnFailure = "on-failure"
- //RestartPolicyNo do not automatically restart the container
- RestartPolicyNo = "no"
- //RestartPolicyUnlessStopped always restart the container unless the container is stopped (manually or otherwise)
- RestartPolicyUnlessStopped = "unless-stopped"
-)
-
-const (
- // ServicePrefix is the prefix for references pointing to a service
- ServicePrefix = "service:"
- // ContainerPrefix is the prefix for references pointing to a container
- ContainerPrefix = "container:"
-
- // NetworkModeServicePrefix is the prefix for network_mode pointing to a service
- // Deprecated prefer ServicePrefix
- NetworkModeServicePrefix = ServicePrefix
- // NetworkModeContainerPrefix is the prefix for network_mode pointing to a container
- // Deprecated prefer ContainerPrefix
- NetworkModeContainerPrefix = ContainerPrefix
-)
-
-// GetDependencies retrieve all services this service depends on
-func (s ServiceConfig) GetDependencies() []string {
- dependencies := make(set)
- for dependency := range s.DependsOn {
- dependencies.append(dependency)
- }
- for _, link := range s.Links {
- parts := strings.Split(link, ":")
- if len(parts) == 2 {
- dependencies.append(parts[0])
- } else {
- dependencies.append(link)
- }
- }
- if strings.HasPrefix(s.NetworkMode, ServicePrefix) {
- dependencies.append(s.NetworkMode[len(ServicePrefix):])
- }
- if strings.HasPrefix(s.Ipc, ServicePrefix) {
- dependencies.append(s.Ipc[len(ServicePrefix):])
- }
- if strings.HasPrefix(s.Pid, ServicePrefix) {
- dependencies.append(s.Pid[len(ServicePrefix):])
- }
- for _, vol := range s.VolumesFrom {
- if !strings.HasPrefix(s.Pid, ContainerPrefix) {
- dependencies.append(vol)
- }
- }
-
- return dependencies.toSlice()
-}
-
-type set map[string]struct{}
-
-func (s set) append(strings ...string) {
- for _, str := range strings {
- s[str] = struct{}{}
- }
-}
-
-func (s set) toSlice() []string {
- slice := make([]string, 0, len(s))
- for v := range s {
- slice = append(slice, v)
- }
- return slice
-}
-
-// BuildConfig is a type for build
-type BuildConfig struct {
- Context string `yaml:",omitempty" json:"context,omitempty"`
- Dockerfile string `yaml:",omitempty" json:"dockerfile,omitempty"`
- Args MappingWithEquals `yaml:",omitempty" json:"args,omitempty"`
- SSH SSHConfig `yaml:"ssh,omitempty" json:"ssh,omitempty"`
- Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
- CacheFrom StringList `mapstructure:"cache_from" yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
- CacheTo StringList `mapstructure:"cache_to" yaml:"cache_to,omitempty" json:"cache_to,omitempty"`
- NoCache bool `mapstructure:"no_cache" yaml:"no_cache,omitempty" json:"no_cache,omitempty"`
- Pull bool `mapstructure:"pull" yaml:"pull,omitempty" json:"pull,omitempty"`
- ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
- Isolation string `yaml:",omitempty" json:"isolation,omitempty"`
- Network string `yaml:",omitempty" json:"network,omitempty"`
- Target string `yaml:",omitempty" json:"target,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// BlkioConfig define blkio config
-type BlkioConfig struct {
- Weight uint16 `yaml:",omitempty" json:"weight,omitempty"`
- WeightDevice []WeightDevice `mapstructure:"weight_device" yaml:",omitempty" json:"weight_device,omitempty"`
- DeviceReadBps []ThrottleDevice `mapstructure:"device_read_bps" yaml:",omitempty" json:"device_read_bps,omitempty"`
- DeviceReadIOps []ThrottleDevice `mapstructure:"device_read_iops" yaml:",omitempty" json:"device_read_iops,omitempty"`
- DeviceWriteBps []ThrottleDevice `mapstructure:"device_write_bps" yaml:",omitempty" json:"device_write_bps,omitempty"`
- DeviceWriteIOps []ThrottleDevice `mapstructure:"device_write_iops" yaml:",omitempty" json:"device_write_iops,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// WeightDevice is a structure that holds device:weight pair
-type WeightDevice struct {
- Path string
- Weight uint16
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// ThrottleDevice is a structure that holds device:rate_per_second pair
-type ThrottleDevice struct {
- Path string
- Rate uint64
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// ShellCommand is a string or list of string args
-type ShellCommand []string
-
-// StringList is a type for fields that can be a string or list of strings
-type StringList []string
-
-// StringOrNumberList is a type for fields that can be a list of strings or
-// numbers
-type StringOrNumberList []string
-
-// MappingWithEquals is a mapping type that can be converted from a list of
-// key[=value] strings.
-// For the key with an empty value (`key=`), the mapped value is set to a pointer to `""`.
-// For the key without value (`key`), the mapped value is set to nil.
-type MappingWithEquals map[string]*string
-
-// NewMappingWithEquals build a new Mapping from a set of KEY=VALUE strings
-func NewMappingWithEquals(values []string) MappingWithEquals {
- mapping := MappingWithEquals{}
- for _, env := range values {
- tokens := strings.SplitN(env, "=", 2)
- if len(tokens) > 1 {
- mapping[tokens[0]] = &tokens[1]
- } else {
- mapping[env] = nil
- }
- }
- return mapping
-}
-
-// OverrideBy update MappingWithEquals with values from another MappingWithEquals
-func (e MappingWithEquals) OverrideBy(other MappingWithEquals) MappingWithEquals {
- for k, v := range other {
- e[k] = v
- }
- return e
-}
-
-// Resolve update a MappingWithEquals for keys without value (`key`, but not `key=`)
-func (e MappingWithEquals) Resolve(lookupFn func(string) (string, bool)) MappingWithEquals {
- for k, v := range e {
- if v == nil {
- if value, ok := lookupFn(k); ok {
- e[k] = &value
- }
- }
- }
- return e
-}
-
-// RemoveEmpty excludes keys that are not associated with a value
-func (e MappingWithEquals) RemoveEmpty() MappingWithEquals {
- for k, v := range e {
- if v == nil {
- delete(e, k)
- }
- }
- return e
-}
-
-// Mapping is a mapping type that can be converted from a list of
-// key[=value] strings.
-// For the key with an empty value (`key=`), or key without value (`key`), the
-// mapped value is set to an empty string `""`.
-type Mapping map[string]string
-
-// NewMapping build a new Mapping from a set of KEY=VALUE strings
-func NewMapping(values []string) Mapping {
- mapping := Mapping{}
- for _, value := range values {
- parts := strings.SplitN(value, "=", 2)
- key := parts[0]
- switch {
- case len(parts) == 1:
- mapping[key] = ""
- default:
- mapping[key] = parts[1]
- }
- }
- return mapping
-}
-
-// Labels is a mapping type for labels
-type Labels map[string]string
-
-func (l Labels) Add(key, value string) Labels {
- if l == nil {
- l = Labels{}
- }
- l[key] = value
- return l
-}
-
-type SSHKey struct {
- ID string
- Path string
-}
-
-// SSHConfig is a mapping type for SSH build config
-type SSHConfig []SSHKey
-
-func (s SSHConfig) Get(id string) (string, error) {
- for _, sshKey := range s {
- if sshKey.ID == id {
- return sshKey.Path, nil
- }
- }
- return "", fmt.Errorf("ID %s not found in SSH keys", id)
-}
-
-// MarshalYAML makes SSHKey implement yaml.Marshaller
-func (s SSHKey) MarshalYAML() (interface{}, error) {
- if s.Path == "" {
- return s.ID, nil
- }
- return fmt.Sprintf("%s: %s", s.ID, s.Path), nil
-}
-
-// MarshalJSON makes SSHKey implement json.Marshaller
-func (s SSHKey) MarshalJSON() ([]byte, error) {
- if s.Path == "" {
- return []byte(fmt.Sprintf(`"%s"`, s.ID)), nil
- }
- return []byte(fmt.Sprintf(`"%s": %s`, s.ID, s.Path)), nil
-}
-
-// MappingWithColon is a mapping type that can be converted from a list of
-// 'key: value' strings
-type MappingWithColon map[string]string
-
-// HostsList is a list of colon-separated host-ip mappings
-type HostsList []string
-
-// LoggingConfig the logging configuration for a service
-type LoggingConfig struct {
- Driver string `yaml:",omitempty" json:"driver,omitempty"`
- Options map[string]string `yaml:",omitempty" json:"options,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// DeployConfig the deployment configuration for a service
-type DeployConfig struct {
- Mode string `yaml:",omitempty" json:"mode,omitempty"`
- Replicas *uint64 `yaml:",omitempty" json:"replicas,omitempty"`
- Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
- UpdateConfig *UpdateConfig `mapstructure:"update_config" yaml:"update_config,omitempty" json:"update_config,omitempty"`
- RollbackConfig *UpdateConfig `mapstructure:"rollback_config" yaml:"rollback_config,omitempty" json:"rollback_config,omitempty"`
- Resources Resources `yaml:",omitempty" json:"resources,omitempty"`
- RestartPolicy *RestartPolicy `mapstructure:"restart_policy" yaml:"restart_policy,omitempty" json:"restart_policy,omitempty"`
- Placement Placement `yaml:",omitempty" json:"placement,omitempty"`
- EndpointMode string `mapstructure:"endpoint_mode" yaml:"endpoint_mode,omitempty" json:"endpoint_mode,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// HealthCheckConfig the healthcheck configuration for a service
-type HealthCheckConfig struct {
- Test HealthCheckTest `yaml:",omitempty" json:"test,omitempty"`
- Timeout *Duration `yaml:",omitempty" json:"timeout,omitempty"`
- Interval *Duration `yaml:",omitempty" json:"interval,omitempty"`
- Retries *uint64 `yaml:",omitempty" json:"retries,omitempty"`
- StartPeriod *Duration `mapstructure:"start_period" yaml:"start_period,omitempty" json:"start_period,omitempty"`
- Disable bool `yaml:",omitempty" json:"disable,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// HealthCheckTest is the command run to test the health of a service
-type HealthCheckTest []string
-
-// UpdateConfig the service update configuration
-type UpdateConfig struct {
- Parallelism *uint64 `yaml:",omitempty" json:"parallelism,omitempty"`
- Delay Duration `yaml:",omitempty" json:"delay,omitempty"`
- FailureAction string `mapstructure:"failure_action" yaml:"failure_action,omitempty" json:"failure_action,omitempty"`
- Monitor Duration `yaml:",omitempty" json:"monitor,omitempty"`
- MaxFailureRatio float32 `mapstructure:"max_failure_ratio" yaml:"max_failure_ratio,omitempty" json:"max_failure_ratio,omitempty"`
- Order string `yaml:",omitempty" json:"order,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// Resources the resource limits and reservations
-type Resources struct {
- Limits *Resource `yaml:",omitempty" json:"limits,omitempty"`
- Reservations *Resource `yaml:",omitempty" json:"reservations,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// Resource is a resource to be limited or reserved
-type Resource struct {
- // TODO: types to convert from units and ratios
- NanoCPUs string `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
- MemoryBytes UnitBytes `mapstructure:"memory" yaml:"memory,omitempty" json:"memory,omitempty"`
- PIds int64 `mapstructure:"pids" yaml:"pids,omitempty" json:"pids,omitempty"`
- Devices []DeviceRequest `mapstructure:"devices" yaml:"devices,omitempty" json:"devices,omitempty"`
- GenericResources []GenericResource `mapstructure:"generic_resources" yaml:"generic_resources,omitempty" json:"generic_resources,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-type DeviceRequest struct {
- Capabilities []string `mapstructure:"capabilities" yaml:"capabilities,omitempty" json:"capabilities,omitempty"`
- Driver string `mapstructure:"driver" yaml:"driver,omitempty" json:"driver,omitempty"`
- Count int64 `mapstructure:"count" yaml:"count,omitempty" json:"count,omitempty"`
- IDs []string `mapstructure:"device_ids" yaml:"device_ids,omitempty" json:"device_ids,omitempty"`
-}
-
-// GenericResource represents a "user defined" resource which can
-// only be an integer (e.g: SSD=3) for a service
-type GenericResource struct {
- DiscreteResourceSpec *DiscreteGenericResource `mapstructure:"discrete_resource_spec" yaml:"discrete_resource_spec,omitempty" json:"discrete_resource_spec,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// DiscreteGenericResource represents a "user defined" resource which is defined
-// as an integer
-// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
-// Value is used to count the resource (SSD=5, HDD=3, ...)
-type DiscreteGenericResource struct {
- Kind string `json:"kind"`
- Value int64 `json:"value"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// UnitBytes is the bytes type
-type UnitBytes int64
-
-// MarshalYAML makes UnitBytes implement yaml.Marshaller
-func (u UnitBytes) MarshalYAML() (interface{}, error) {
- return fmt.Sprintf("%d", u), nil
-}
-
-// MarshalJSON makes UnitBytes implement json.Marshaler
-func (u UnitBytes) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf(`"%d"`, u)), nil
-}
-
-// RestartPolicy the service restart policy
-type RestartPolicy struct {
- Condition string `yaml:",omitempty" json:"condition,omitempty"`
- Delay *Duration `yaml:",omitempty" json:"delay,omitempty"`
- MaxAttempts *uint64 `mapstructure:"max_attempts" yaml:"max_attempts,omitempty" json:"max_attempts,omitempty"`
- Window *Duration `yaml:",omitempty" json:"window,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// Placement constraints for the service
-type Placement struct {
- Constraints []string `yaml:",omitempty" json:"constraints,omitempty"`
- Preferences []PlacementPreferences `yaml:",omitempty" json:"preferences,omitempty"`
- MaxReplicas uint64 `mapstructure:"max_replicas_per_node" yaml:"max_replicas_per_node,omitempty" json:"max_replicas_per_node,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// PlacementPreferences is the preferences for a service placement
-type PlacementPreferences struct {
- Spread string `yaml:",omitempty" json:"spread,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// ServiceNetworkConfig is the network configuration for a service
-type ServiceNetworkConfig struct {
- Priority int `yaml:",omitempty" json:"priotirt,omitempty"`
- Aliases []string `yaml:",omitempty" json:"aliases,omitempty"`
- Ipv4Address string `mapstructure:"ipv4_address" yaml:"ipv4_address,omitempty" json:"ipv4_address,omitempty"`
- Ipv6Address string `mapstructure:"ipv6_address" yaml:"ipv6_address,omitempty" json:"ipv6_address,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// ServicePortConfig is the port configuration for a service
-type ServicePortConfig struct {
- Mode string `yaml:",omitempty" json:"mode,omitempty"`
- HostIP string `mapstructure:"host_ip" yaml:"host_ip,omitempty" json:"host_ip,omitempty"`
- Target uint32 `yaml:",omitempty" json:"target,omitempty"`
- Published string `yaml:",omitempty" json:"published,omitempty"`
- Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// ParsePortConfig parse short syntax for service port configuration
-func ParsePortConfig(value string) ([]ServicePortConfig, error) {
- var portConfigs []ServicePortConfig
- ports, portBindings, err := nat.ParsePortSpecs([]string{value})
- if err != nil {
- return nil, err
- }
- // We need to sort the key of the ports to make sure it is consistent
- keys := []string{}
- for port := range ports {
- keys = append(keys, string(port))
- }
- sort.Strings(keys)
-
- for _, key := range keys {
- port := nat.Port(key)
- converted, err := convertPortToPortConfig(port, portBindings)
- if err != nil {
- return nil, err
- }
- portConfigs = append(portConfigs, converted...)
- }
- return portConfigs, nil
-}
-
-func convertPortToPortConfig(port nat.Port, portBindings map[nat.Port][]nat.PortBinding) ([]ServicePortConfig, error) {
- var portConfigs []ServicePortConfig
- for _, binding := range portBindings[port] {
- portConfigs = append(portConfigs, ServicePortConfig{
- HostIP: binding.HostIP,
- Protocol: strings.ToLower(port.Proto()),
- Target: uint32(port.Int()),
- Published: binding.HostPort,
- Mode: "ingress",
- })
- }
- return portConfigs, nil
-}
-
-// ServiceVolumeConfig are references to a volume used by a service
-type ServiceVolumeConfig struct {
- Type string `yaml:",omitempty" json:"type,omitempty"`
- Source string `yaml:",omitempty" json:"source,omitempty"`
- Target string `yaml:",omitempty" json:"target,omitempty"`
- ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
- Consistency string `yaml:",omitempty" json:"consistency,omitempty"`
- Bind *ServiceVolumeBind `yaml:",omitempty" json:"bind,omitempty"`
- Volume *ServiceVolumeVolume `yaml:",omitempty" json:"volume,omitempty"`
- Tmpfs *ServiceVolumeTmpfs `yaml:",omitempty" json:"tmpfs,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-const (
- // VolumeTypeBind is the type for mounting host dir
- VolumeTypeBind = "bind"
- // VolumeTypeVolume is the type for remote storage volumes
- VolumeTypeVolume = "volume"
- // VolumeTypeTmpfs is the type for mounting tmpfs
- VolumeTypeTmpfs = "tmpfs"
- // VolumeTypeNamedPipe is the type for mounting Windows named pipes
- VolumeTypeNamedPipe = "npipe"
-
- // SElinuxShared share the volume content
- SElinuxShared = "z"
- // SElinuxUnshared label content as private unshared
- SElinuxUnshared = "Z"
-)
-
-// ServiceVolumeBind are options for a service volume of type bind
-type ServiceVolumeBind struct {
- SELinux string `mapstructure:"selinux" yaml:",omitempty" json:"selinux,omitempty"`
- Propagation string `yaml:",omitempty" json:"propagation,omitempty"`
- CreateHostPath bool `mapstructure:"create_host_path" yaml:"create_host_path,omitempty" json:"create_host_path,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// SELinux represents the SELinux re-labeling options.
-const (
- // SELinuxShared option indicates that the bind mount content is shared among multiple containers
- SELinuxShared string = "z"
- // SELinuxPrivate option indicates that the bind mount content is private and unshared
- SELinuxPrivate string = "Z"
-)
-
-// Propagation represents the propagation of a mount.
-const (
- // PropagationRPrivate RPRIVATE
- PropagationRPrivate string = "rprivate"
- // PropagationPrivate PRIVATE
- PropagationPrivate string = "private"
- // PropagationRShared RSHARED
- PropagationRShared string = "rshared"
- // PropagationShared SHARED
- PropagationShared string = "shared"
- // PropagationRSlave RSLAVE
- PropagationRSlave string = "rslave"
- // PropagationSlave SLAVE
- PropagationSlave string = "slave"
-)
-
-// ServiceVolumeVolume are options for a service volume of type volume
-type ServiceVolumeVolume struct {
- NoCopy bool `mapstructure:"nocopy" yaml:"nocopy,omitempty" json:"nocopy,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// ServiceVolumeTmpfs are options for a service volume of type tmpfs
-type ServiceVolumeTmpfs struct {
- Size UnitBytes `yaml:",omitempty" json:"size,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// FileReferenceConfig for a reference to a swarm file object
-type FileReferenceConfig struct {
- Source string `yaml:",omitempty" json:"source,omitempty"`
- Target string `yaml:",omitempty" json:"target,omitempty"`
- UID string `yaml:",omitempty" json:"uid,omitempty"`
- GID string `yaml:",omitempty" json:"gid,omitempty"`
- Mode *uint32 `yaml:",omitempty" json:"mode,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// ServiceConfigObjConfig is the config obj configuration for a service
-type ServiceConfigObjConfig FileReferenceConfig
-
-// ServiceSecretConfig is the secret configuration for a service
-type ServiceSecretConfig FileReferenceConfig
-
-// UlimitsConfig the ulimit configuration
-type UlimitsConfig struct {
- Single int `yaml:",omitempty" json:"single,omitempty"`
- Soft int `yaml:",omitempty" json:"soft,omitempty"`
- Hard int `yaml:",omitempty" json:"hard,omitempty"`
-
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// MarshalYAML makes UlimitsConfig implement yaml.Marshaller
-func (u *UlimitsConfig) MarshalYAML() (interface{}, error) {
- if u.Single != 0 {
- return u.Single, nil
- }
- return u, nil
-}
-
-// MarshalJSON makes UlimitsConfig implement json.Marshaller
-func (u *UlimitsConfig) MarshalJSON() ([]byte, error) {
- if u.Single != 0 {
- return json.Marshal(u.Single)
- }
- // Pass as a value to avoid re-entering this method and use the default implementation
- return json.Marshal(*u)
-}
-
-// NetworkConfig for a network
-type NetworkConfig struct {
- Name string `yaml:",omitempty" json:"name,omitempty"`
- Driver string `yaml:",omitempty" json:"driver,omitempty"`
- DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
- Ipam IPAMConfig `yaml:",omitempty" json:"ipam,omitempty"`
- External External `yaml:",omitempty" json:"external,omitempty"`
- Internal bool `yaml:",omitempty" json:"internal,omitempty"`
- Attachable bool `yaml:",omitempty" json:"attachable,omitempty"`
- Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
- EnableIPv6 bool `mapstructure:"enable_ipv6" yaml:"enable_ipv6,omitempty" json:"enable_ipv6,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// IPAMConfig for a network
-type IPAMConfig struct {
- Driver string `yaml:",omitempty" json:"driver,omitempty"`
- Config []*IPAMPool `yaml:",omitempty" json:"config,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// IPAMPool for a network
-type IPAMPool struct {
- Subnet string `yaml:",omitempty" json:"subnet,omitempty"`
- Gateway string `yaml:",omitempty" json:"gateway,omitempty"`
- IPRange string `mapstructure:"ip_range" yaml:"ip_range,omitempty" json:"ip_range,omitempty"`
- AuxiliaryAddresses map[string]string `mapstructure:"aux_addresses" yaml:"aux_addresses,omitempty" json:"aux_addresses,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// VolumeConfig for a volume
-type VolumeConfig struct {
- Name string `yaml:",omitempty" json:"name,omitempty"`
- Driver string `yaml:",omitempty" json:"driver,omitempty"`
- DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
- External External `yaml:",omitempty" json:"external,omitempty"`
- Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// External identifies a Volume or Network as a reference to a resource that is
-// not managed, and should already exist.
-// External.name is deprecated and replaced by Volume.name
-type External struct {
- Name string `yaml:",omitempty" json:"name,omitempty"`
- External bool `yaml:",omitempty" json:"external,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// MarshalYAML makes External implement yaml.Marshaller
-func (e External) MarshalYAML() (interface{}, error) {
- if e.Name == "" {
- return e.External, nil
- }
- return External{Name: e.Name}, nil
-}
-
-// MarshalJSON makes External implement json.Marshaller
-func (e External) MarshalJSON() ([]byte, error) {
- if e.Name == "" {
- return []byte(fmt.Sprintf("%v", e.External)), nil
- }
- return []byte(fmt.Sprintf(`{"name": %q}`, e.Name)), nil
-}
-
-// CredentialSpecConfig for credential spec on Windows
-type CredentialSpecConfig struct {
- Config string `yaml:",omitempty" json:"config,omitempty"` // Config was added in API v1.40
- File string `yaml:",omitempty" json:"file,omitempty"`
- Registry string `yaml:",omitempty" json:"registry,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-// FileObjectConfig is a config type for a file used by a service
-type FileObjectConfig struct {
- Name string `yaml:",omitempty" json:"name,omitempty"`
- File string `yaml:",omitempty" json:"file,omitempty"`
- External External `yaml:",omitempty" json:"external,omitempty"`
- Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
- Driver string `yaml:",omitempty" json:"driver,omitempty"`
- DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
- TemplateDriver string `mapstructure:"template_driver" yaml:"template_driver,omitempty" json:"template_driver,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-const (
- // ServiceConditionCompletedSuccessfully is the type for waiting until a service has completed successfully (exit code 0).
- ServiceConditionCompletedSuccessfully = "service_completed_successfully"
-
- // ServiceConditionHealthy is the type for waiting until a service is healthy.
- ServiceConditionHealthy = "service_healthy"
-
- // ServiceConditionStarted is the type for waiting until a service has started (default).
- ServiceConditionStarted = "service_started"
-)
-
-type DependsOnConfig map[string]ServiceDependency
-
-type ServiceDependency struct {
- Condition string `yaml:",omitempty" json:"condition,omitempty"`
- Extensions map[string]interface{} `yaml:",inline" json:"-"`
-}
-
-type ExtendsConfig MappingWithEquals
-
-// SecretConfig for a secret
-type SecretConfig FileObjectConfig
-
-// ConfigObjConfig is the config for the swarm "Config" object
-type ConfigObjConfig FileObjectConfig
diff --git a/vendor/github.com/compose-spec/compose-go/v2/LICENSE b/vendor/github.com/compose-spec/compose-go/v2/LICENSE
new file mode 100644
index 0000000000..1d97deaf40
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2020 The Compose Specification Authors
+
+ 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
+
+ https://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.
diff --git a/vendor/github.com/compose-spec/compose-go/NOTICE b/vendor/github.com/compose-spec/compose-go/v2/NOTICE
similarity index 100%
rename from vendor/github.com/compose-spec/compose-go/NOTICE
rename to vendor/github.com/compose-spec/compose-go/v2/NOTICE
diff --git a/vendor/github.com/compose-spec/compose-go/v2/consts/consts.go b/vendor/github.com/compose-spec/compose-go/v2/consts/consts.go
new file mode 100644
index 0000000000..592e6f067d
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/consts/consts.go
@@ -0,0 +1,29 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package consts
+
+const (
+ ComposeProjectName = "COMPOSE_PROJECT_NAME"
+ ComposePathSeparator = "COMPOSE_PATH_SEPARATOR"
+ ComposeFilePath = "COMPOSE_FILE"
+ ComposeDisableDefaultEnvFile = "COMPOSE_DISABLE_ENV_FILE"
+ ComposeProfiles = "COMPOSE_PROFILES"
+)
+
+const Extensions = "#extensions" // Using # prefix, we prevent risk to conflict with an actual yaml key
+
+type ComposeFileKey struct{}
diff --git a/vendor/github.com/compose-spec/compose-go/dotenv/LICENSE b/vendor/github.com/compose-spec/compose-go/v2/dotenv/LICENSE
similarity index 100%
rename from vendor/github.com/compose-spec/compose-go/dotenv/LICENSE
rename to vendor/github.com/compose-spec/compose-go/v2/dotenv/LICENSE
diff --git a/vendor/github.com/compose-spec/compose-go/v2/dotenv/env.go b/vendor/github.com/compose-spec/compose-go/v2/dotenv/env.go
new file mode 100644
index 0000000000..fe8ce85236
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/dotenv/env.go
@@ -0,0 +1,73 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package dotenv
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "path/filepath"
+)
+
+func GetEnvFromFile(currentEnv map[string]string, filenames []string) (map[string]string, error) {
+ envMap := make(map[string]string)
+
+ for _, dotEnvFile := range filenames {
+ abs, err := filepath.Abs(dotEnvFile)
+ if err != nil {
+ return envMap, err
+ }
+ dotEnvFile = abs
+
+ s, err := os.Stat(dotEnvFile)
+ if os.IsNotExist(err) {
+ return envMap, fmt.Errorf("couldn't find env file: %s", dotEnvFile)
+ }
+ if err != nil {
+ return envMap, err
+ }
+
+ if s.IsDir() {
+ if len(filenames) == 0 {
+ return envMap, nil
+ }
+ return envMap, fmt.Errorf("%s is a directory", dotEnvFile)
+ }
+
+ b, err := os.ReadFile(dotEnvFile)
+ if os.IsNotExist(err) {
+ return nil, fmt.Errorf("couldn't read env file: %s", dotEnvFile)
+ }
+ if err != nil {
+ return envMap, err
+ }
+
+ err = parseWithLookup(bytes.NewReader(b), envMap, func(k string) (string, bool) {
+ v, ok := currentEnv[k]
+ if ok {
+ return v, true
+ }
+ v, ok = envMap[k]
+ return v, ok
+ })
+ if err != nil {
+ return envMap, fmt.Errorf("failed to read %s: %w", dotEnvFile, err)
+ }
+ }
+
+ return envMap, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/dotenv/format.go b/vendor/github.com/compose-spec/compose-go/v2/dotenv/format.go
new file mode 100644
index 0000000000..0234716c87
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/dotenv/format.go
@@ -0,0 +1,51 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package dotenv
+
+import (
+ "fmt"
+ "io"
+)
+
+const DotEnv = ".env"
+
+var formats = map[string]Parser{
+ DotEnv: func(r io.Reader, filename string, vars map[string]string, lookup func(key string) (string, bool)) error {
+ err := parseWithLookup(r, vars, lookup)
+ if err != nil {
+ return fmt.Errorf("failed to read %s: %w", filename, err)
+ }
+ return nil
+ },
+}
+
+type Parser func(r io.Reader, filename string, vars map[string]string, lookup func(key string) (string, bool)) error
+
+func RegisterFormat(format string, p Parser) {
+ formats[format] = p
+}
+
+func ParseWithFormat(r io.Reader, filename string, vars map[string]string, resolve LookupFn, format string) error {
+ if format == "" {
+ format = DotEnv
+ }
+ fn, ok := formats[format]
+ if !ok {
+ return fmt.Errorf("unsupported env_file format %q", format)
+ }
+ return fn(r, filename, vars, resolve)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/dotenv/godotenv.go b/vendor/github.com/compose-spec/compose-go/v2/dotenv/godotenv.go
new file mode 100644
index 0000000000..8f4fdf6a03
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/dotenv/godotenv.go
@@ -0,0 +1,182 @@
+// Package dotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
+//
+// Examples/readme can be found on the github page at https://github.com/joho/godotenv
+//
+// The TL;DR is that you make a .env file that looks something like
+//
+// SOME_ENV_VAR=somevalue
+//
+// and then in your go code you can call
+//
+// godotenv.Load()
+//
+// and all the env vars declared in .env will be available through os.Getenv("SOME_ENV_VAR")
+package dotenv
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/template"
+)
+
+var utf8BOM = []byte("\uFEFF")
+
+var startsWithDigitRegex = regexp.MustCompile(`^\s*\d.*`) // Keys starting with numbers are ignored
+
+// LookupFn represents a lookup function to resolve variables from
+type LookupFn func(string) (string, bool)
+
+var noLookupFn = func(_ string) (string, bool) {
+ return "", false
+}
+
+// Parse reads an env file from io.Reader, returning a map of keys and values.
+func Parse(r io.Reader) (map[string]string, error) {
+ return ParseWithLookup(r, nil)
+}
+
+// ParseWithLookup reads an env file from io.Reader, returning a map of keys and values.
+func ParseWithLookup(r io.Reader, lookupFn LookupFn) (map[string]string, error) {
+ vars := map[string]string{}
+ err := parseWithLookup(r, vars, lookupFn)
+ return vars, err
+}
+
+// ParseWithLookup reads an env file from io.Reader, returning a map of keys and values.
+func parseWithLookup(r io.Reader, vars map[string]string, lookupFn LookupFn) error {
+ data, err := io.ReadAll(r)
+ if err != nil {
+ return err
+ }
+
+ // seek past the UTF-8 BOM if it exists (particularly on Windows, some
+ // editors tend to add it, and it'll cause parsing to fail)
+ data = bytes.TrimPrefix(data, utf8BOM)
+
+ return newParser().parse(string(data), vars, lookupFn)
+}
+
+// Load will read your env file(s) and load them into ENV for this process.
+//
+// Call this function as close as possible to the start of your program (ideally in main).
+//
+// If you call Load without any args it will default to loading .env in the current path.
+//
+// You can otherwise tell it which files to load (there can be more than one) like:
+//
+// godotenv.Load("fileone", "filetwo")
+//
+// It's important to note that it WILL NOT OVERRIDE an env variable that already exists - consider the .env file to set dev vars or sensible defaults
+func Load(filenames ...string) error {
+ return load(false, filenames...)
+}
+
+func load(overload bool, filenames ...string) error {
+ filenames = filenamesOrDefault(filenames)
+ for _, filename := range filenames {
+ err := loadFile(filename, overload)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ReadWithLookup gets all env vars from the files and/or lookup function and return values as
+// a map rather than automatically writing values into env
+func ReadWithLookup(lookupFn LookupFn, filenames ...string) (map[string]string, error) {
+ filenames = filenamesOrDefault(filenames)
+ envMap := make(map[string]string)
+
+ for _, filename := range filenames {
+ individualEnvMap, individualErr := ReadFile(filename, lookupFn)
+
+ if individualErr != nil {
+ return envMap, individualErr
+ }
+
+ for key, value := range individualEnvMap {
+ if startsWithDigitRegex.MatchString(key) {
+ continue
+ }
+ envMap[key] = value
+ }
+ }
+
+ return envMap, nil
+}
+
+// Read all env (with same file loading semantics as Load) but return values as
+// a map rather than automatically writing values into env
+func Read(filenames ...string) (map[string]string, error) {
+ return ReadWithLookup(nil, filenames...)
+}
+
+// UnmarshalBytesWithLookup parses env file from byte slice of chars, returning a map of keys and values.
+func UnmarshalBytesWithLookup(src []byte, lookupFn LookupFn) (map[string]string, error) {
+ return UnmarshalWithLookup(string(src), lookupFn)
+}
+
+// UnmarshalWithLookup parses env file from string, returning a map of keys and values.
+func UnmarshalWithLookup(src string, lookupFn LookupFn) (map[string]string, error) {
+ out := make(map[string]string)
+ err := newParser().parse(src, out, lookupFn)
+ return out, err
+}
+
+func filenamesOrDefault(filenames []string) []string {
+ if len(filenames) == 0 {
+ return []string{".env"}
+ }
+ return filenames
+}
+
+func loadFile(filename string, overload bool) error {
+ envMap, err := ReadFile(filename, nil)
+ if err != nil {
+ return err
+ }
+
+ currentEnv := map[string]bool{}
+ rawEnv := os.Environ()
+ for _, rawEnvLine := range rawEnv {
+ key := strings.Split(rawEnvLine, "=")[0]
+ currentEnv[key] = true
+ }
+
+ for key, value := range envMap {
+ if !currentEnv[key] || overload {
+ _ = os.Setenv(key, value)
+ }
+ }
+
+ return nil
+}
+
+func ReadFile(filename string, lookupFn LookupFn) (map[string]string, error) {
+ file, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ return ParseWithLookup(file, lookupFn)
+}
+
+func expandVariables(value string, envMap map[string]string, lookupFn LookupFn) (string, error) {
+ retVal, err := template.Substitute(value, func(k string) (string, bool) {
+ if v, ok := lookupFn(k); ok {
+ return v, true
+ }
+ v, ok := envMap[k]
+ return v, ok
+ })
+ if err != nil {
+ return value, err
+ }
+ return retVal, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/dotenv/parser.go b/vendor/github.com/compose-spec/compose-go/v2/dotenv/parser.go
new file mode 100644
index 0000000000..2db7b90724
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/dotenv/parser.go
@@ -0,0 +1,286 @@
+package dotenv
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+const (
+ charComment = '#'
+ prefixSingleQuote = '\''
+ prefixDoubleQuote = '"'
+)
+
+var (
+ escapeSeqRegex = regexp.MustCompile(`(\\(?:[abcfnrtv$"\\]|0\d{0,3}))`)
+ exportRegex = regexp.MustCompile(`^export\s+`)
+)
+
+type parser struct {
+ line int
+}
+
+func newParser() *parser {
+ return &parser{
+ line: 1,
+ }
+}
+
+func (p *parser) parse(src string, out map[string]string, lookupFn LookupFn) error {
+ cutset := src
+ if lookupFn == nil {
+ lookupFn = noLookupFn
+ }
+ for {
+ cutset = p.getStatementStart(cutset)
+ if cutset == "" {
+ // reached end of file
+ break
+ }
+
+ key, left, inherited, err := p.locateKeyName(cutset)
+ if err != nil {
+ return err
+ }
+ if strings.Contains(key, " ") {
+ return fmt.Errorf("line %d: key cannot contain a space", p.line)
+ }
+
+ if inherited {
+ value, ok := lookupFn(key)
+ if ok {
+ out[key] = value
+ }
+ cutset = left
+ continue
+ }
+
+ value, left, err := p.extractVarValue(left, out, lookupFn)
+ if err != nil {
+ return err
+ }
+
+ out[key] = value
+ cutset = left
+ }
+
+ return nil
+}
+
+// getStatementPosition returns position of statement begin.
+//
+// It skips any comment line or non-whitespace character.
+func (p *parser) getStatementStart(src string) string {
+ pos := p.indexOfNonSpaceChar(src)
+ if pos == -1 {
+ return ""
+ }
+
+ src = src[pos:]
+ if src[0] != charComment {
+ return src
+ }
+
+ // skip comment section
+ pos = strings.IndexFunc(src, isCharFunc('\n'))
+ if pos == -1 {
+ return ""
+ }
+ return p.getStatementStart(src[pos:])
+}
+
+// locateKeyName locates and parses key name and returns rest of slice
+func (p *parser) locateKeyName(src string) (string, string, bool, error) {
+ var key string
+ var inherited bool
+ // trim "export" and space at beginning
+ if exportRegex.MatchString(src) {
+ // we use a `strings.trim` to preserve the pointer to the same underlying memory.
+ // a regexp replace would copy the string.
+ src = strings.TrimLeftFunc(strings.TrimPrefix(src, "export"), isSpace)
+ }
+
+ // locate key name end and validate it in single loop
+ offset := 0
+loop:
+ for i, rune := range src {
+ if isSpace(rune) {
+ continue
+ }
+
+ switch rune {
+ case '=', ':', '\n':
+ // library also supports yaml-style value declaration
+ key = src[0:i]
+ offset = i + 1
+ inherited = rune == '\n'
+ break loop
+ case '_', '.', '-', '[', ']':
+ default:
+ // variable name should match [A-Za-z0-9_.-]
+ if unicode.IsLetter(rune) || unicode.IsNumber(rune) {
+ continue
+ }
+
+ return "", "", inherited, fmt.Errorf(
+ `line %d: unexpected character %q in variable name %q`,
+ p.line, string(rune), strings.Split(src, "\n")[0])
+ }
+ }
+
+ if src == "" {
+ return "", "", inherited, errors.New("zero length string")
+ }
+
+ if inherited && strings.IndexByte(key, ' ') == -1 {
+ p.line++
+ }
+
+ // trim whitespace
+ key = strings.TrimRightFunc(key, unicode.IsSpace)
+ cutset := strings.TrimLeftFunc(src[offset:], isSpace)
+ return key, cutset, inherited, nil
+}
+
+// extractVarValue extracts variable value and returns rest of slice
+func (p *parser) extractVarValue(src string, envMap map[string]string, lookupFn LookupFn) (string, string, error) {
+ quote, isQuoted := hasQuotePrefix(src)
+ if !isQuoted {
+ // unquoted value - read until new line
+ value, rest, _ := strings.Cut(src, "\n")
+ p.line++
+
+ // Remove inline comments on unquoted lines
+ value, _, _ = strings.Cut(value, " #")
+ value = strings.TrimRightFunc(value, unicode.IsSpace)
+ retVal, err := expandVariables(value, envMap, lookupFn)
+ return retVal, rest, err
+ }
+
+ previousCharIsEscape := false
+ // lookup quoted string terminator
+ var chars []byte
+ for i := 1; i < len(src); i++ {
+ char := src[i]
+ if char == '\n' {
+ p.line++
+ }
+ if char != quote {
+ if !previousCharIsEscape && char == '\\' {
+ previousCharIsEscape = true
+ continue
+ }
+ if previousCharIsEscape {
+ previousCharIsEscape = false
+ chars = append(chars, '\\')
+ }
+ chars = append(chars, char)
+ continue
+ }
+
+ // skip escaped quote symbol (\" or \', depends on quote)
+ if previousCharIsEscape {
+ previousCharIsEscape = false
+ chars = append(chars, char)
+ continue
+ }
+
+ // trim quotes
+ value := string(chars)
+ if quote == prefixDoubleQuote {
+ // expand standard shell escape sequences & then interpolate
+ // variables on the result
+ retVal, err := expandVariables(expandEscapes(value), envMap, lookupFn)
+ if err != nil {
+ return "", "", err
+ }
+ value = retVal
+ }
+
+ return value, src[i+1:], nil
+ }
+
+ // return formatted error if quoted string is not terminated
+ valEndIndex := strings.IndexFunc(src, isCharFunc('\n'))
+ if valEndIndex == -1 {
+ valEndIndex = len(src)
+ }
+
+ return "", "", fmt.Errorf("line %d: unterminated quoted value %s", p.line, src[:valEndIndex])
+}
+
+func expandEscapes(str string) string {
+ out := escapeSeqRegex.ReplaceAllStringFunc(str, func(match string) string {
+ if match == `\$` {
+ // `\$` is not a Go escape sequence, the expansion parser uses
+ // the special `$$` syntax
+ // both `FOO=\$bar` and `FOO=$$bar` are valid in an env file and
+ // will result in FOO w/ literal value of "$bar" (no interpolation)
+ return "$$"
+ }
+
+ if strings.HasPrefix(match, `\0`) {
+ // octal escape sequences in Go are not prefixed with `\0`, so
+ // rewrite the prefix, e.g. `\0123` -> `\123` -> literal value "S"
+ match = strings.Replace(match, `\0`, `\`, 1)
+ }
+
+ // use Go to unquote (unescape) the literal
+ // see https://go.dev/ref/spec#Rune_literals
+ //
+ // NOTE: Go supports ADDITIONAL escapes like `\x` & `\u` & `\U`!
+ // These are NOT supported, which is why we use a regex to find
+ // only matches we support and then use `UnquoteChar` instead of a
+ // `Unquote` on the entire value
+ v, _, _, err := strconv.UnquoteChar(match, '"')
+ if err != nil {
+ return match
+ }
+ return string(v)
+ })
+ return out
+}
+
+func (p *parser) indexOfNonSpaceChar(src string) int {
+ return strings.IndexFunc(src, func(r rune) bool {
+ if r == '\n' {
+ p.line++
+ }
+ return !unicode.IsSpace(r)
+ })
+}
+
+// hasQuotePrefix reports whether charset starts with single or double quote and returns quote character
+func hasQuotePrefix(src string) (byte, bool) {
+ if src == "" {
+ return 0, false
+ }
+
+ switch quote := src[0]; quote {
+ case prefixDoubleQuote, prefixSingleQuote:
+ return quote, true // isQuoted
+ default:
+ return 0, false
+ }
+}
+
+func isCharFunc(char rune) func(rune) bool {
+ return func(v rune) bool {
+ return v == char
+ }
+}
+
+// isSpace reports whether the rune is a space character but not line break character
+//
+// this differs from unicode.IsSpace, which also applies line break as space
+func isSpace(r rune) bool {
+ switch r {
+ case '\t', '\v', '\f', '\r', ' ', 0x85, 0xA0:
+ return true
+ }
+ return false
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/errdefs/errors.go b/vendor/github.com/compose-spec/compose-go/v2/errdefs/errors.go
new file mode 100644
index 0000000000..1990ddd25f
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/errdefs/errors.go
@@ -0,0 +1,56 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package errdefs
+
+import "errors"
+
+var (
+ // ErrNotFound is returned when an object is not found
+ ErrNotFound = errors.New("not found")
+
+ // ErrInvalid is returned when a compose project is invalid
+ ErrInvalid = errors.New("invalid compose project")
+
+ // ErrUnsupported is returned when a compose project uses an unsupported attribute
+ ErrUnsupported = errors.New("unsupported attribute")
+
+ // ErrIncompatible is returned when a compose project uses an incompatible attribute
+ ErrIncompatible = errors.New("incompatible attribute")
+
+ // ErrDisabled is returned when a resource was found in model but is disabled
+ ErrDisabled = errors.New("disabled")
+)
+
+// IsNotFoundError returns true if the unwrapped error is ErrNotFound
+func IsNotFoundError(err error) bool {
+ return errors.Is(err, ErrNotFound)
+}
+
+// IsInvalidError returns true if the unwrapped error is ErrInvalid
+func IsInvalidError(err error) bool {
+ return errors.Is(err, ErrInvalid)
+}
+
+// IsUnsupportedError returns true if the unwrapped error is ErrUnsupported
+func IsUnsupportedError(err error) bool {
+ return errors.Is(err, ErrUnsupported)
+}
+
+// IsUnsupportedError returns true if the unwrapped error is ErrIncompatible
+func IsIncompatibleError(err error) bool {
+ return errors.Is(err, ErrIncompatible)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/format/volume.go b/vendor/github.com/compose-spec/compose-go/v2/format/volume.go
new file mode 100644
index 0000000000..b696af3235
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/format/volume.go
@@ -0,0 +1,199 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package format
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+const endOfSpec = rune(0)
+
+// ParseVolume parses a volume spec without any knowledge of the target platform
+func ParseVolume(spec string) (types.ServiceVolumeConfig, error) {
+ volume := types.ServiceVolumeConfig{}
+
+ switch len(spec) {
+ case 0:
+ return volume, errors.New("invalid empty volume spec")
+ case 1, 2:
+ volume.Target = spec
+ volume.Type = types.VolumeTypeVolume
+ return volume, nil
+ }
+
+ var buffer []rune
+ var inVarSubstitution int // Track nesting depth of ${...}
+ for i, char := range spec + string(endOfSpec) {
+ // Check if we're entering a variable substitution
+ if char == '$' && i+1 < len(spec) && rune(spec[i+1]) == '{' {
+ inVarSubstitution++
+ buffer = append(buffer, char)
+ continue
+ }
+
+ // Check if we're exiting a variable substitution
+ if char == '}' && inVarSubstitution > 0 {
+ inVarSubstitution--
+ buffer = append(buffer, char)
+ continue
+ }
+
+ switch {
+ case isWindowsDrive(buffer, char):
+ buffer = append(buffer, char)
+ case (char == ':' || char == endOfSpec) && inVarSubstitution == 0:
+ if err := populateFieldFromBuffer(char, buffer, &volume); err != nil {
+ populateType(&volume)
+ return volume, fmt.Errorf("invalid spec: %s: %w", spec, err)
+ }
+ buffer = nil
+ default:
+ buffer = append(buffer, char)
+ }
+ }
+
+ populateType(&volume)
+ return volume, nil
+}
+
+func isWindowsDrive(buffer []rune, char rune) bool {
+ return char == ':' && len(buffer) == 1 && unicode.IsLetter(buffer[0])
+}
+
+func populateFieldFromBuffer(char rune, buffer []rune, volume *types.ServiceVolumeConfig) error {
+ strBuffer := string(buffer)
+ switch {
+ case len(buffer) == 0:
+ return errors.New("empty section between colons")
+ // Anonymous volume
+ case volume.Source == "" && char == endOfSpec:
+ volume.Target = strBuffer
+ return nil
+ case volume.Source == "":
+ volume.Source = strBuffer
+ return nil
+ case volume.Target == "":
+ volume.Target = strBuffer
+ return nil
+ case char == ':':
+ return errors.New("too many colons")
+ }
+ for _, option := range strings.Split(strBuffer, ",") {
+ switch option {
+ case "ro":
+ volume.ReadOnly = true
+ case "rw":
+ volume.ReadOnly = false
+ case "nocopy":
+ volume.Volume = &types.ServiceVolumeVolume{NoCopy: true}
+ default:
+ if isBindOption(option) {
+ setBindOption(volume, option)
+ }
+ // ignore unknown options FIXME why not report an error here?
+ }
+ }
+ return nil
+}
+
+var Propagations = []string{
+ types.PropagationRPrivate,
+ types.PropagationPrivate,
+ types.PropagationRShared,
+ types.PropagationShared,
+ types.PropagationRSlave,
+ types.PropagationSlave,
+}
+
+type setBindOptionFunc func(bind *types.ServiceVolumeBind, option string)
+
+var bindOptions = map[string]setBindOptionFunc{
+ types.PropagationRPrivate: setBindPropagation,
+ types.PropagationPrivate: setBindPropagation,
+ types.PropagationRShared: setBindPropagation,
+ types.PropagationShared: setBindPropagation,
+ types.PropagationRSlave: setBindPropagation,
+ types.PropagationSlave: setBindPropagation,
+ types.SELinuxShared: setBindSELinux,
+ types.SELinuxPrivate: setBindSELinux,
+}
+
+func setBindPropagation(bind *types.ServiceVolumeBind, option string) {
+ bind.Propagation = option
+}
+
+func setBindSELinux(bind *types.ServiceVolumeBind, option string) {
+ bind.SELinux = option
+}
+
+func isBindOption(option string) bool {
+ _, ok := bindOptions[option]
+
+ return ok
+}
+
+func setBindOption(volume *types.ServiceVolumeConfig, option string) {
+ if volume.Bind == nil {
+ volume.Bind = &types.ServiceVolumeBind{}
+ }
+
+ bindOptions[option](volume.Bind, option)
+}
+
+func populateType(volume *types.ServiceVolumeConfig) {
+ if isFilePath(volume.Source) {
+ volume.Type = types.VolumeTypeBind
+ if volume.Bind == nil {
+ volume.Bind = &types.ServiceVolumeBind{}
+ }
+ // For backward compatibility with docker-compose legacy, using short notation involves
+ // bind will create missing host path
+ volume.Bind.CreateHostPath = true
+ } else {
+ volume.Type = types.VolumeTypeVolume
+ if volume.Volume == nil {
+ volume.Volume = &types.ServiceVolumeVolume{}
+ }
+ }
+}
+
+func isFilePath(source string) bool {
+ if source == "" {
+ return false
+ }
+ switch source[0] {
+ case '.', '/', '~':
+ return true
+ }
+
+ // windows named pipes
+ if strings.HasPrefix(source, `\\`) {
+ return true
+ }
+
+ first, nextIndex := utf8.DecodeRuneInString(source)
+ if len(source) <= nextIndex {
+ return false
+ }
+ return isWindowsDrive([]rune{first}, rune(source[nextIndex]))
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/graph/cycle.go b/vendor/github.com/compose-spec/compose-go/v2/graph/cycle.go
new file mode 100644
index 0000000000..58130ad659
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/graph/cycle.go
@@ -0,0 +1,63 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package graph
+
+import (
+ "fmt"
+ "slices"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/types"
+ "github.com/compose-spec/compose-go/v2/utils"
+)
+
+// CheckCycle analyze project's depends_on relation and report an error on cycle detection
+func CheckCycle(project *types.Project) error {
+ g, err := newGraph(project)
+ if err != nil {
+ return err
+ }
+ return g.checkCycle()
+}
+
+func (g *graph[T]) checkCycle() error {
+ // iterate on vertices in a name-order to render a predicable error message
+ // this is required by tests and enforce command reproducibility by user, which otherwise could be confusing
+ names := utils.MapKeys(g.vertices)
+ for _, name := range names {
+ err := searchCycle([]string{name}, g.vertices[name])
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func searchCycle[T any](path []string, v *vertex[T]) error {
+ names := utils.MapKeys(v.children)
+ for _, name := range names {
+ if i := slices.Index(path, name); i >= 0 {
+ return fmt.Errorf("dependency cycle detected: %s -> %s", strings.Join(path[i:], " -> "), name)
+ }
+ ch := v.children[name]
+ err := searchCycle(append(path, name), ch)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/graph/graph.go b/vendor/github.com/compose-spec/compose-go/v2/graph/graph.go
new file mode 100644
index 0000000000..de4e9e1073
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/graph/graph.go
@@ -0,0 +1,75 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package graph
+
+// graph represents project as service dependencies
+type graph[T any] struct {
+ vertices map[string]*vertex[T]
+}
+
+// vertex represents a service in the dependencies structure
+type vertex[T any] struct {
+ key string
+ service *T
+ children map[string]*vertex[T]
+ parents map[string]*vertex[T]
+}
+
+func (g *graph[T]) addVertex(name string, service T) {
+ g.vertices[name] = &vertex[T]{
+ key: name,
+ service: &service,
+ parents: map[string]*vertex[T]{},
+ children: map[string]*vertex[T]{},
+ }
+}
+
+func (g *graph[T]) addEdge(src, dest string) {
+ g.vertices[src].children[dest] = g.vertices[dest]
+ g.vertices[dest].parents[src] = g.vertices[src]
+}
+
+func (g *graph[T]) roots() []*vertex[T] {
+ var res []*vertex[T]
+ for _, v := range g.vertices {
+ if len(v.parents) == 0 {
+ res = append(res, v)
+ }
+ }
+ return res
+}
+
+func (g *graph[T]) leaves() []*vertex[T] {
+ var res []*vertex[T]
+ for _, v := range g.vertices {
+ if len(v.children) == 0 {
+ res = append(res, v)
+ }
+ }
+
+ return res
+}
+
+// descendents return all descendents for a vertex, might contain duplicates
+func (v *vertex[T]) descendents() []string {
+ var vx []string
+ for _, n := range v.children {
+ vx = append(vx, n.key)
+ vx = append(vx, n.descendents()...)
+ }
+ return vx
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/graph/services.go b/vendor/github.com/compose-spec/compose-go/v2/graph/services.go
new file mode 100644
index 0000000000..44b36a3f31
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/graph/services.go
@@ -0,0 +1,80 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package graph
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+// InDependencyOrder walk the service graph an invoke VisitorFn in respect to dependency order
+func InDependencyOrder(ctx context.Context, project *types.Project, fn VisitorFn[types.ServiceConfig], options ...func(*Options)) error {
+ _, err := CollectInDependencyOrder[any](ctx, project, func(ctx context.Context, s string, config types.ServiceConfig) (any, error) {
+ return nil, fn(ctx, s, config)
+ }, options...)
+ return err
+}
+
+// CollectInDependencyOrder walk the service graph an invoke CollectorFn in respect to dependency order, then return result for each call
+func CollectInDependencyOrder[T any](ctx context.Context, project *types.Project, fn CollectorFn[types.ServiceConfig, T], options ...func(*Options)) (map[string]T, error) {
+ graph, err := newGraph(project)
+ if err != nil {
+ return nil, err
+ }
+ t := newTraversal(fn)
+ for _, option := range options {
+ option(t.Options)
+ }
+ err = walk(ctx, graph, t)
+ return t.results, err
+}
+
+// newGraph creates a service graph from project
+func newGraph(project *types.Project) (*graph[types.ServiceConfig], error) {
+ g := &graph[types.ServiceConfig]{
+ vertices: map[string]*vertex[types.ServiceConfig]{},
+ }
+
+ for name, s := range project.Services {
+ g.addVertex(name, s)
+ }
+
+ for name, s := range project.Services {
+ src := g.vertices[name]
+ for dep, condition := range s.DependsOn {
+ dest, ok := g.vertices[dep]
+ if !ok {
+ if condition.Required {
+ if ds, exists := project.DisabledServices[dep]; exists {
+ return nil, fmt.Errorf("service %q is required by %q but is disabled. Can be enabled by profiles %s", dep, name, ds.Profiles)
+ }
+ return nil, fmt.Errorf("service %q depends on unknown service %q", name, dep)
+ }
+ delete(s.DependsOn, name)
+ project.Services[name] = s
+ continue
+ }
+ src.children[dep] = dest
+ dest.parents[name] = src
+ }
+ }
+
+ err := g.checkCycle()
+ return g, err
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/graph/traversal.go b/vendor/github.com/compose-spec/compose-go/v2/graph/traversal.go
new file mode 100644
index 0000000000..99ab4a4b1d
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/graph/traversal.go
@@ -0,0 +1,211 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package graph
+
+import (
+ "context"
+ "slices"
+ "sync"
+
+ "golang.org/x/sync/errgroup"
+)
+
+// CollectorFn executes on each graph vertex based on visit order and return associated value
+type CollectorFn[S any, T any] func(context.Context, string, S) (T, error)
+
+// VisitorFn executes on each graph nodes based on visit order
+type VisitorFn[S any] func(context.Context, string, S) error
+
+type traversal[S any, T any] struct {
+ *Options
+ visitor CollectorFn[S, T]
+
+ mu sync.Mutex
+ status map[string]int
+ results map[string]T
+}
+
+type Options struct {
+ // inverse reverse the traversal direction
+ inverse bool
+ // maxConcurrency limit the concurrent execution of visitorFn while walking the graph
+ maxConcurrency int
+ // after marks a set of node as starting points walking the graph
+ after []string
+}
+
+const (
+ vertexEntered = iota
+ vertexVisited
+)
+
+func newTraversal[S, T any](fn CollectorFn[S, T]) *traversal[S, T] {
+ return &traversal[S, T]{
+ Options: &Options{},
+ status: map[string]int{},
+ results: map[string]T{},
+ visitor: fn,
+ }
+}
+
+// WithMaxConcurrency configure traversal to limit concurrency walking graph nodes
+func WithMaxConcurrency(concurrency int) func(*Options) {
+ return func(o *Options) {
+ o.maxConcurrency = concurrency
+ }
+}
+
+// InReverseOrder configure traversal to walk the graph in reverse dependency order
+func InReverseOrder(o *Options) {
+ o.inverse = true
+}
+
+// WithRootNodesAndDown creates a graphTraversal to start from selected nodes
+func WithRootNodesAndDown(nodes []string) func(*Options) {
+ return func(o *Options) {
+ o.after = nodes
+ }
+}
+
+func walk[S, T any](ctx context.Context, g *graph[S], t *traversal[S, T]) error {
+ expect := len(g.vertices)
+ if expect == 0 {
+ return nil
+ }
+ // nodeCh need to allow n=expect writers while reader goroutine could have returned after ctx.Done
+ nodeCh := make(chan *vertex[S], expect)
+ defer close(nodeCh)
+
+ eg, ctx := errgroup.WithContext(ctx)
+ if t.maxConcurrency > 0 {
+ eg.SetLimit(t.maxConcurrency + 1)
+ }
+
+ eg.Go(func() error {
+ for {
+ select {
+ case <-ctx.Done():
+ return nil
+ case node := <-nodeCh:
+ expect--
+ if expect == 0 {
+ return nil
+ }
+
+ for _, adj := range t.adjacentNodes(node) {
+ t.visit(ctx, eg, adj, nodeCh)
+ }
+ }
+ }
+ })
+
+ // select nodes to start walking the graph based on traversal.direction
+ for _, node := range t.extremityNodes(g) {
+ t.visit(ctx, eg, node, nodeCh)
+ }
+
+ return eg.Wait()
+}
+
+func (t *traversal[S, T]) visit(ctx context.Context, eg *errgroup.Group, node *vertex[S], nodeCh chan *vertex[S]) {
+ if !t.ready(node) {
+ // don't visit this service yet as dependencies haven't been visited
+ return
+ }
+ if !t.enter(node) {
+ // another worker already acquired this node
+ return
+ }
+ eg.Go(func() error {
+ var (
+ err error
+ result T
+ )
+ if !t.skip(node) {
+ result, err = t.visitor(ctx, node.key, *node.service)
+ }
+ t.done(node, result)
+ nodeCh <- node
+ return err
+ })
+}
+
+func (t *traversal[S, T]) extremityNodes(g *graph[S]) []*vertex[S] {
+ if t.inverse {
+ return g.roots()
+ }
+ return g.leaves()
+}
+
+func (t *traversal[S, T]) adjacentNodes(v *vertex[S]) map[string]*vertex[S] {
+ if t.inverse {
+ return v.children
+ }
+ return v.parents
+}
+
+func (t *traversal[S, T]) ready(v *vertex[S]) bool {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+
+ depends := v.children
+ if t.inverse {
+ depends = v.parents
+ }
+ for name := range depends {
+ if t.status[name] != vertexVisited {
+ return false
+ }
+ }
+ return true
+}
+
+func (t *traversal[S, T]) enter(v *vertex[S]) bool {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+
+ if _, ok := t.status[v.key]; ok {
+ return false
+ }
+ t.status[v.key] = vertexEntered
+ return true
+}
+
+func (t *traversal[S, T]) done(v *vertex[S], result T) {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ t.status[v.key] = vertexVisited
+ t.results[v.key] = result
+}
+
+func (t *traversal[S, T]) skip(node *vertex[S]) bool {
+ if len(t.after) == 0 {
+ return false
+ }
+ if slices.Contains(t.after, node.key) {
+ return false
+ }
+
+ // is none of our starting node is a descendent, skip visit
+ ancestors := node.descendents()
+ for _, name := range t.after {
+ if slices.Contains(ancestors, name) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/interpolation/interpolation.go b/vendor/github.com/compose-spec/compose-go/v2/interpolation/interpolation.go
new file mode 100644
index 0000000000..181ccf2897
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/interpolation/interpolation.go
@@ -0,0 +1,197 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package interpolation
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "slices"
+
+ "github.com/compose-spec/compose-go/v2/template"
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// Options supported by Interpolate
+type Options struct {
+ // LookupValue from a key
+ LookupValue LookupValue
+ // TypeCastMapping maps key paths to functions to cast to a type
+ TypeCastMapping map[tree.Path]Cast
+ // Substitution function to use
+ Substitute func(string, template.Mapping) (string, error)
+}
+
+// LookupValue is a function which maps from variable names to values.
+// Returns the value as a string and a bool indicating whether
+// the value is present, to distinguish between an empty string
+// and the absence of a value.
+type LookupValue func(key string) (string, bool)
+
+// Cast a value to a new type, or return an error if the value can't be cast
+type Cast func(value string) (interface{}, error)
+
+// Interpolate replaces variables in a string with the values from a mapping.
+// Every failure is collected into a single joined error, sorted by config
+// path, rather than returning the first one. There is one error per failing
+// config value: if a value holds several failing variable references, only
+// the first one is reported. The walk continues past failures, so
+// LookupValue, Substitute and Cast may run on values dropped from the result.
+func Interpolate(config map[string]interface{}, opts Options) (map[string]interface{}, error) {
+ if opts.LookupValue == nil {
+ opts.LookupValue = os.LookupEnv
+ }
+ if opts.TypeCastMapping == nil {
+ opts.TypeCastMapping = make(map[tree.Path]Cast)
+ }
+ if opts.Substitute == nil {
+ opts.Substitute = template.Substitute
+ }
+
+ out := map[string]interface{}{}
+ var errs []error
+ for key, value := range config {
+ interpolatedValue, err := recursiveInterpolate(value, tree.NewPath(key), opts)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ out[key] = interpolatedValue
+ }
+
+ return out, joinErrors(errs)
+}
+
+func recursiveInterpolate(value interface{}, path tree.Path, opts Options) (interface{}, error) {
+ switch value := value.(type) {
+ case string:
+ newValue, err := opts.Substitute(value, template.Mapping(opts.LookupValue))
+ if err != nil {
+ return value, newPathError(path, err)
+ }
+ caster, ok := opts.getCasterForPath(path)
+ if !ok {
+ return newValue, nil
+ }
+ casted, err := caster(newValue)
+ if err != nil {
+ return casted, newPathError(path, fmt.Errorf("failed to cast to expected type: %w", err))
+ }
+ return casted, nil
+
+ case map[string]interface{}:
+ out := map[string]interface{}{}
+ var errs []error
+ for key, elem := range value {
+ interpolatedElem, err := recursiveInterpolate(elem, path.Next(key), opts)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ out[key] = interpolatedElem
+ }
+ return out, joinErrors(errs)
+
+ case []interface{}:
+ out := make([]interface{}, len(value))
+ var errs []error
+ for i, elem := range value {
+ interpolatedElem, err := recursiveInterpolate(elem, path.Next(tree.PathMatchList), opts)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ out[i] = interpolatedElem
+ }
+ // Index order is already deterministic, no need to sort.
+ return out, errors.Join(errs...)
+
+ default:
+ return value, nil
+ }
+}
+
+// joinErrors joins errors collected while ranging over a map, sorted by the
+// config path they carry, so that the random map iteration order does not
+// leak into the reported error. Only called on the error path: successful
+// interpolation pays no sorting cost.
+func joinErrors(errs []error) error {
+ if len(errs) == 0 {
+ return nil
+ }
+ slices.SortStableFunc(errs, func(a, b error) int {
+ return slices.Compare(errorPath(a), errorPath(b))
+ })
+ return errors.Join(errs...)
+}
+
+// errorPath returns the config path an error is sorted by, as path segments
+// so that keys compare whole (a raw string compare would order "service-1"
+// before "service"). For an already-joined subtree, errors.As finds whichever
+// pathError comes first; any of them does, as they all share the subtree
+// prefix that orders it among its siblings. An error carrying no path falls
+// back to its message, so the order stays deterministic whatever is
+// collected.
+func errorPath(err error) []string {
+ var pe pathError
+ if errors.As(err, &pe) {
+ return pe.path.Parts()
+ }
+ return []string{err.Error()}
+}
+
+// pathError is an interpolation error carrying the config path where it
+// occurred, so collected errors can be sorted by path.
+type pathError struct {
+ path tree.Path
+ err error
+ msg string
+}
+
+func (e pathError) Error() string { return e.msg }
+func (e pathError) Unwrap() error { return e.err }
+
+func newPathError(path tree.Path, err error) error {
+ var ite *template.InvalidTemplateError
+ switch {
+ case err == nil:
+ return nil
+ case errors.As(err, &ite):
+ return pathError{
+ path: path,
+ err: err,
+ msg: fmt.Sprintf(
+ "invalid interpolation format for %s.\nYou may need to escape any $ with another $.\n%s",
+ path, ite.Template),
+ }
+ default:
+ return pathError{
+ path: path,
+ err: err,
+ msg: fmt.Sprintf("error while interpolating %s: %s", path, err),
+ }
+ }
+}
+
+func (o Options) getCasterForPath(path tree.Path) (Cast, bool) {
+ for pattern, caster := range o.TypeCastMapping {
+ if path.Matches(pattern) {
+ return caster, true
+ }
+ }
+ return nil, false
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/aliases.go b/vendor/github.com/compose-spec/compose-go/v2/loader/aliases.go
new file mode 100644
index 0000000000..f600f74a16
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/aliases.go
@@ -0,0 +1,121 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "strconv"
+
+ "github.com/compose-spec/compose-go/v2/override"
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// extensionAlias declares that the specification attribute `to` was used as
+// the x-* extension `from` before being adopted.
+type extensionAlias struct {
+ // parent is the path of the mapping holding the attribute.
+ parent tree.Path
+ from string
+ to string
+}
+
+// extensionAliases is ordered from the outermost to the innermost attribute.
+var extensionAliases = []extensionAlias{
+ {parent: "services.*", from: "x-develop", to: "develop"},
+ {parent: "services.*.develop.watch.[]", from: "x-initialSync", to: "initial_sync"},
+}
+
+var aliasParents = func() *tree.Matcher {
+ parents := make([]tree.Path, len(extensionAliases))
+ for i, alias := range extensionAliases {
+ parents[i] = alias.parent
+ }
+ return tree.NewMatcher(parents...)
+}()
+
+// promoteAliases renames in place the extensions declared in extensionAliases
+// to the attribute they stand for. When the mapping already sets a value for
+// the attribute, the extension is merged under it, so that the attribute wins.
+func promoteAliases(value any, p tree.Path) error {
+ switch v := value.(type) {
+ case map[string]any:
+ for _, alias := range extensionAliases {
+ if !p.Matches(alias.parent) {
+ continue
+ }
+ ext, ok := v[alias.from]
+ if !ok {
+ continue
+ }
+ delete(v, alias.from)
+ if v[alias.to] == nil {
+ v[alias.to] = ext
+ continue
+ }
+ merged, err := override.MergeYaml(deepClone(ext), v[alias.to], p.Next(alias.to))
+ if err != nil {
+ return err
+ }
+ v[alias.to] = merged
+ }
+ for key, e := range v {
+ next := p.Next(key)
+ if aliasParents.Matches(next) || aliasParents.MayContain(next) {
+ if err := promoteAliases(e, next); err != nil {
+ return err
+ }
+ }
+ }
+ case []any:
+ next := p.Next(tree.PathMatchList)
+ if aliasParents.Matches(next) || aliasParents.MayContain(next) {
+ for _, e := range v {
+ if err := promoteAliases(e, next); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// resolveAliasPath returns path with each extension declared in
+// extensionAliases replaced by the attribute it stands for. List indexes in
+// path match the tree.PathMatchList component of alias parents.
+func resolveAliasPath(path tree.Path) tree.Path {
+ parts := path.Parts()
+ for _, alias := range extensionAliases {
+ depth := len(alias.parent.Parts())
+ if len(parts) <= depth || parts[depth] != alias.from {
+ continue
+ }
+ if tree.NewPath(withListItems(parts[:depth])...).Matches(alias.parent) {
+ parts[depth] = alias.to
+ }
+ }
+ return tree.NewPath(parts...)
+}
+
+func withListItems(parts []string) []string {
+ normalized := make([]string, len(parts))
+ for i, part := range parts {
+ normalized[i] = part
+ if _, err := strconv.Atoi(part); err == nil {
+ normalized[i] = tree.PathMatchList
+ }
+ }
+ return normalized
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/environment.go b/vendor/github.com/compose-spec/compose-go/v2/loader/environment.go
new file mode 100644
index 0000000000..6360c61077
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/environment.go
@@ -0,0 +1,115 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+// ResolveEnvironment update the environment variables for the format {- VAR} (without interpolation)
+func ResolveEnvironment(dict map[string]any, environment types.Mapping) {
+ resolveServicesEnvironment(dict, environment)
+ resolveContainerEnvironment(dict, "jobs", environment)
+ resolveSecretsEnvironment(dict, environment)
+ resolveConfigsEnvironment(dict, environment)
+}
+
+func resolveServicesEnvironment(dict map[string]any, environment types.Mapping) {
+ resolveContainerEnvironment(dict, "services", environment)
+}
+
+func resolveContainerEnvironment(dict map[string]any, key string, environment types.Mapping) {
+ containers, ok := dict[key].(map[string]any)
+ if !ok {
+ return
+ }
+
+ for name, cfg := range containers {
+ config, ok := cfg.(map[string]any)
+ if !ok {
+ continue
+ }
+ envList, ok := config["environment"].([]any)
+ if !ok {
+ continue
+ }
+ envs := []any{}
+ for _, env := range envList {
+ varEnv, ok := env.(string)
+ if !ok {
+ continue
+ }
+ if found, ok := environment[varEnv]; ok {
+ envs = append(envs, fmt.Sprintf("%s=%s", varEnv, found))
+ } else {
+ // either does not exist or it was already resolved in interpolation
+ envs = append(envs, varEnv)
+ }
+ }
+ config["environment"] = envs
+ containers[name] = config
+ }
+ dict[key] = containers
+}
+
+func resolveSecretsEnvironment(dict map[string]any, environment types.Mapping) {
+ secrets, ok := dict["secrets"].(map[string]any)
+ if !ok {
+ return
+ }
+
+ for name, cfg := range secrets {
+ secret, ok := cfg.(map[string]any)
+ if !ok {
+ continue
+ }
+ env, ok := secret["environment"].(string)
+ if !ok {
+ continue
+ }
+ if found, ok := environment[env]; ok {
+ secret[types.SecretConfigXValue] = found
+ }
+ secrets[name] = secret
+ }
+ dict["secrets"] = secrets
+}
+
+func resolveConfigsEnvironment(dict map[string]any, environment types.Mapping) {
+ configs, ok := dict["configs"].(map[string]any)
+ if !ok {
+ return
+ }
+
+ for name, cfg := range configs {
+ config, ok := cfg.(map[string]any)
+ if !ok {
+ continue
+ }
+ env, ok := config["environment"].(string)
+ if !ok {
+ continue
+ }
+ if found, ok := environment[env]; ok {
+ config["content"] = found
+ }
+ configs[name] = config
+ }
+ dict["configs"] = configs
+}
diff --git a/vendor/github.com/compose-spec/compose-go/loader/example1.env b/vendor/github.com/compose-spec/compose-go/v2/loader/example1.env
similarity index 79%
rename from vendor/github.com/compose-spec/compose-go/loader/example1.env
rename to vendor/github.com/compose-spec/compose-go/v2/loader/example1.env
index f19ec0df4e..61716e93b5 100644
--- a/vendor/github.com/compose-spec/compose-go/loader/example1.env
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/example1.env
@@ -1,5 +1,7 @@
# passed through
FOO=foo_from_env_file
+ENV.WITH.DOT=ok
+ENV_WITH_UNDERSCORE=ok
# overridden in example2.env
BAR=bar_from_env_file
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/example1.label b/vendor/github.com/compose-spec/compose-go/v2/loader/example1.label
new file mode 100644
index 0000000000..27d43cffac
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/example1.label
@@ -0,0 +1,10 @@
+# passed through
+FOO=foo_from_label_file
+LABEL.WITH.DOT=ok
+LABEL_WITH_UNDERSCORE=ok
+
+# overridden in example2.label
+BAR=bar_from_label_file
+
+# overridden in full-example.yml
+BAZ=baz_from_label_file
diff --git a/vendor/github.com/compose-spec/compose-go/loader/example2.env b/vendor/github.com/compose-spec/compose-go/v2/loader/example2.env
similarity index 100%
rename from vendor/github.com/compose-spec/compose-go/loader/example2.env
rename to vendor/github.com/compose-spec/compose-go/v2/loader/example2.env
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/example2.label b/vendor/github.com/compose-spec/compose-go/v2/loader/example2.label
new file mode 100644
index 0000000000..aa667c3047
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/example2.label
@@ -0,0 +1,4 @@
+BAR=bar_from_label_file_2
+
+# overridden in configDetails.Labels
+QUX=quz_from_label_file_2
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/extends.go b/vendor/github.com/compose-spec/compose-go/v2/loader/extends.go
new file mode 100644
index 0000000000..18174c0408
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/extends.go
@@ -0,0 +1,277 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "context"
+ "fmt"
+ "path/filepath"
+
+ "github.com/compose-spec/compose-go/v2/consts"
+ "github.com/compose-spec/compose-go/v2/override"
+ "github.com/compose-spec/compose-go/v2/paths"
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+func ApplyExtends(ctx context.Context, dict map[string]any, opts *Options, tracker *cycleTracker, post PostProcessor) error {
+ for _, key := range []string{"services", "jobs"} {
+ a, ok := dict[key]
+ if !ok {
+ continue
+ }
+ entries, ok := a.(map[string]any)
+ if !ok {
+ return fmt.Errorf("%s must be a mapping", key)
+ }
+ for name := range entries {
+ merged, err := applyServiceExtends(ctx, name, entries, opts, tracker, post)
+ if err != nil {
+ return err
+ }
+ entries[name] = merged
+ }
+ dict[key] = entries
+ }
+ return nil
+}
+
+func applyServiceExtends(ctx context.Context, name string, services map[string]any, opts *Options, tracker *cycleTracker, post PostProcessor) (any, error) {
+ s := services[name]
+ if s == nil {
+ return nil, nil
+ }
+ service, ok := s.(map[string]any)
+ if !ok {
+ return nil, fmt.Errorf("services.%s must be a mapping", name)
+ }
+ extends, ok := service["extends"]
+ if !ok {
+ return s, nil
+ }
+ filename := ctx.Value(consts.ComposeFileKey{}).(string)
+ var (
+ err error
+ ref string
+ file any
+ )
+ switch v := extends.(type) {
+ case map[string]any:
+ ref, ok = v["service"].(string)
+ if !ok {
+ return nil, fmt.Errorf("extends.%s.service is required", name)
+ }
+ file = v["file"]
+ opts.ProcessEvent("extends", v)
+ case string:
+ ref = v
+ opts.ProcessEvent("extends", map[string]any{"service": ref})
+ }
+
+ var (
+ base any
+ processor = post
+ )
+
+ if file != nil {
+ refFilename := file.(string)
+ services, processor, err = getExtendsBaseFromFile(ctx, name, ref, filename, refFilename, opts, tracker)
+ if err != nil {
+ return nil, err
+ }
+ filename = refFilename
+ // extends declared in the referenced file are not part of the config
+ // files passed to the loader: don't report events for them
+ if len(opts.Listeners) > 0 {
+ opts = opts.clone()
+ opts.Listeners = nil
+ }
+ } else {
+ _, ok := services[ref]
+ if !ok {
+ return nil, fmt.Errorf("cannot extend service %q in %s: service %q not found", name, filename, ref)
+ }
+ }
+
+ tracker, err = tracker.Add(filename, name)
+ if err != nil {
+ return nil, err
+ }
+
+ // recursively apply `extends`
+ base, err = applyServiceExtends(ctx, ref, services, opts, tracker, processor)
+ if err != nil {
+ return nil, err
+ }
+
+ if base == nil {
+ return service, nil
+ }
+ source := deepClone(base).(map[string]any)
+
+ err = post.Apply(map[string]any{
+ "services": map[string]any{
+ name: source,
+ },
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ merged, err := override.ExtendService(source, service)
+ if err != nil {
+ return nil, err
+ }
+
+ delete(merged, "extends")
+ services[name] = merged
+ return merged, nil
+}
+
+type extendsCacheKey struct{}
+
+// extendsRef identifies an extends.file base within an extends cache scope.
+type extendsRef struct {
+ path string
+ workingDir string
+}
+
+type extendsBase struct {
+ services map[string]any
+ processor PostProcessor
+}
+
+// withExtendsCache attaches a fresh extends.file cache to ctx. The cache is
+// scoped to a single loadYamlModel call: within that scope interpolation
+// options and environment are fixed, so the resolved path and working
+// directory fully identify the loaded file.
+func withExtendsCache(ctx context.Context) context.Context {
+ return context.WithValue(ctx, extendsCacheKey{}, map[extendsRef]extendsBase{})
+}
+
+func extendsCache(ctx context.Context) map[extendsRef]extendsBase {
+ cache, _ := ctx.Value(extendsCacheKey{}).(map[extendsRef]extendsBase)
+ return cache
+}
+
+func getExtendsBaseFromFile(
+ ctx context.Context,
+ name, ref string,
+ path, refPath string,
+ opts *Options,
+ ct *cycleTracker,
+) (map[string]any, PostProcessor, error) {
+ for _, loader := range opts.ResourceLoaders {
+ if !loader.Accept(refPath) {
+ continue
+ }
+ local, err := loader.Load(ctx, refPath)
+ if err != nil {
+ return nil, nil, err
+ }
+ relworkingdir := loader.Dir(refPath)
+
+ cache := extendsCache(ctx)
+ cacheKey := extendsRef{path: local, workingDir: relworkingdir}
+ base, hit := cache[cacheKey]
+ if hit {
+ // hand out a copy: resolving an extends chain writes merged
+ // services back into this map (see applyServiceExtends)
+ base.services = deepClone(base.services).(map[string]any)
+ } else {
+ base, err = loadExtendsBase(ctx, name, local, relworkingdir, opts, ct)
+ if err != nil {
+ return nil, nil, err
+ }
+ if cache != nil {
+ cache[cacheKey] = extendsBase{
+ services: deepClone(base.services).(map[string]any),
+ processor: base.processor,
+ }
+ }
+ }
+
+ if _, ok := base.services[ref]; !ok {
+ return nil, nil, fmt.Errorf(
+ "cannot extend service %q in %s: service %q not found in %s",
+ name,
+ path,
+ ref,
+ refPath,
+ )
+ }
+ return base.services, base.processor, nil
+ }
+ return nil, nil, fmt.Errorf("cannot read %s", refPath)
+}
+
+func loadExtendsBase(ctx context.Context, name, local, relworkingdir string, opts *Options, ct *cycleTracker) (extendsBase, error) {
+ extendsOpts := opts.clone()
+ // replace localResourceLoader with a new flavour, using extended file base path
+ extendsOpts.ResourceLoaders = append(opts.RemoteResourceLoaders(), localResourceLoader{
+ WorkingDir: filepath.Dir(local),
+ })
+ extendsOpts.ResolvePaths = false // we do relative path resolution after file has been loaded
+ extendsOpts.SkipNormalization = true
+ extendsOpts.SkipConsistencyCheck = true
+ extendsOpts.SkipInclude = true
+ extendsOpts.SkipExtends = true // we manage extends recursively based on raw service definition
+ extendsOpts.SkipValidation = true // we validate the merge result
+ extendsOpts.SkipDefaultValues = true
+ source, processor, err := loadYamlFile(ctx, types.ConfigFile{Filename: local},
+ extendsOpts, relworkingdir, nil, ct, map[string]any{}, nil)
+ if err != nil {
+ return extendsBase{}, err
+ }
+ m, ok := source["services"]
+ if !ok {
+ return extendsBase{}, fmt.Errorf("cannot extend service %q in %s: no services section", name, local)
+ }
+ services, ok := m.(map[string]any)
+ if !ok {
+ return extendsBase{}, fmt.Errorf("cannot extend service %q in %s: services must be a mapping", name, local)
+ }
+
+ var remotes []paths.RemoteResource
+ for _, loader := range opts.RemoteResourceLoaders() {
+ remotes = append(remotes, loader.Accept)
+ }
+ err = paths.ResolveRelativePaths(source, relworkingdir, remotes)
+ if err != nil {
+ return extendsBase{}, err
+ }
+
+ return extendsBase{services: services, processor: processor}, nil
+}
+
+func deepClone(value any) any {
+ switch v := value.(type) {
+ case []any:
+ cp := make([]any, len(v))
+ for i, e := range v {
+ cp[i] = deepClone(e)
+ }
+ return cp
+ case map[string]any:
+ cp := make(map[string]any, len(v))
+ for k, e := range v {
+ cp[k] = deepClone(e)
+ }
+ return cp
+ default:
+ return value
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/fix.go b/vendor/github.com/compose-spec/compose-go/v2/loader/fix.go
new file mode 100644
index 0000000000..7a6e88d817
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/fix.go
@@ -0,0 +1,36 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+// fixEmptyNotNull is a workaround for https://github.com/xeipuuv/gojsonschema/issues/141
+// as go-yaml `[]` will load as a `[]any(nil)`, which is not the same as an empty array
+func fixEmptyNotNull(value any) interface{} {
+ switch v := value.(type) {
+ case []any:
+ if v == nil {
+ return []any{}
+ }
+ for i, e := range v {
+ v[i] = fixEmptyNotNull(e)
+ }
+ case map[string]any:
+ for k, e := range v {
+ v[k] = fixEmptyNotNull(e)
+ }
+ }
+ return value
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/include.go b/vendor/github.com/compose-spec/compose-go/v2/loader/include.go
new file mode 100644
index 0000000000..a7e8c2ac3c
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/include.go
@@ -0,0 +1,277 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+ "maps"
+ "os"
+ "path/filepath"
+ "reflect"
+ "slices"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/dotenv"
+ interp "github.com/compose-spec/compose-go/v2/interpolation"
+ "github.com/compose-spec/compose-go/v2/override"
+ "github.com/compose-spec/compose-go/v2/tree"
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+type includeCacheKey struct{}
+
+// withIncludeCache attaches a fresh include cache to ctx. The cache is scoped
+// to a single load so a file reachable through several include paths (a
+// "diamond" include graph) is parsed and expanded only once per distinct
+// (paths, directories, environment) tuple.
+func withIncludeCache(ctx context.Context) context.Context {
+ return context.WithValue(ctx, includeCacheKey{}, map[string]map[string]any{})
+}
+
+func includeCache(ctx context.Context) map[string]map[string]any {
+ cache, _ := ctx.Value(includeCacheKey{}).(map[string]map[string]any)
+ return cache
+}
+
+// includeModelKey covers every input that determines the model loaded for an
+// include: resolved paths, working directory, project directory and effective
+// environment. Interpolate.Substitute and TypeCastMapping are intentionally
+// excluded: they are invariant across includes within a single load. If a
+// future option allows them to vary per include, they must be folded into the
+// key. Fields are length-prefixed and collections count-prefixed so the byte
+// stream is uniquely decodable.
+func includeModelKey(paths types.StringList, workingDir, projectDir string, env types.Mapping) string {
+ h := sha256.New()
+ write := func(s string) {
+ fmt.Fprintf(h, "%d:%s", len(s), s)
+ }
+ fmt.Fprintf(h, "%d;", len(paths))
+ for _, p := range paths {
+ write(p)
+ }
+ write(workingDir)
+ write(projectDir)
+ fmt.Fprintf(h, "%d;", len(env))
+ for _, k := range slices.Sorted(maps.Keys(env)) {
+ write(k)
+ write(env[k])
+ }
+ return string(h.Sum(nil))
+}
+
+// loadIncludeConfig parse the required config from raw yaml
+func loadIncludeConfig(source any) ([]types.IncludeConfig, error) {
+ if source == nil {
+ return nil, nil
+ }
+ configs, ok := source.([]any)
+ if !ok {
+ return nil, fmt.Errorf("`include` must be a list, got %s", source)
+ }
+ for i, config := range configs {
+ if v, ok := config.(string); ok {
+ configs[i] = map[string]any{
+ "path": v,
+ }
+ }
+ }
+ var requires []types.IncludeConfig
+ err := Transform(source, &requires)
+ return requires, err
+}
+
+func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapping, model map[string]any, options *Options, included []string, processor PostProcessor) error {
+ includeConfig, err := loadIncludeConfig(model["include"])
+ if err != nil {
+ return err
+ }
+
+ for _, r := range includeConfig {
+ for _, listener := range options.Listeners {
+ listener("include", map[string]any{
+ "path": r.Path,
+ "workingdir": workingDir,
+ })
+ }
+
+ var relworkingdir string
+ for i, p := range r.Path {
+ for _, loader := range options.ResourceLoaders {
+ if !loader.Accept(p) {
+ continue
+ }
+ path, err := loader.Load(ctx, p)
+ if err != nil {
+ return err
+ }
+ p = path
+
+ if i == 0 { // This is the "main" file, used to define project-directory. Others are overrides
+
+ switch {
+ case r.ProjectDirectory == "":
+ relworkingdir = loader.Dir(path)
+ r.ProjectDirectory = filepath.Dir(path)
+ case !filepath.IsAbs(r.ProjectDirectory):
+ relworkingdir = loader.Dir(r.ProjectDirectory)
+ r.ProjectDirectory = filepath.Join(workingDir, r.ProjectDirectory)
+
+ default:
+ relworkingdir = r.ProjectDirectory
+
+ }
+ for _, f := range included {
+ if f == path {
+ included = append(included, path)
+ return fmt.Errorf("include cycle detected:\n%s\n include %s", included[0], strings.Join(included[1:], "\n include "))
+ }
+ }
+ }
+ }
+ r.Path[i] = p
+ }
+
+ loadOptions := options.clone()
+ loadOptions.ResolvePaths = true
+ loadOptions.SkipNormalization = true
+ loadOptions.SkipConsistencyCheck = true
+ // include and extends events are only reported for declarations in the
+ // config files passed to the loader, not for those in included files
+ loadOptions.Listeners = nil
+ loadOptions.ResourceLoaders = append(loadOptions.RemoteResourceLoaders(), localResourceLoader{
+ WorkingDir: r.ProjectDirectory,
+ })
+
+ if len(r.EnvFile) == 0 {
+ f := filepath.Join(r.ProjectDirectory, ".env")
+ if s, err := os.Stat(f); err == nil && !s.IsDir() {
+ r.EnvFile = types.StringList{f}
+ }
+ } else {
+ envFile := []string{}
+ for _, f := range r.EnvFile {
+ if f == "/dev/null" {
+ continue
+ }
+ if !filepath.IsAbs(f) {
+ f = filepath.Join(workingDir, f)
+ s, err := os.Stat(f)
+ if err != nil {
+ return err
+ }
+ if s.IsDir() {
+ return fmt.Errorf("%s is not a file", f)
+ }
+ }
+ envFile = append(envFile, f)
+ }
+ r.EnvFile = envFile
+ }
+
+ envFromFile, err := dotenv.GetEnvFromFile(environment, r.EnvFile)
+ if err != nil {
+ return err
+ }
+
+ config := types.ConfigDetails{
+ WorkingDir: relworkingdir,
+ ConfigFiles: types.ToConfigFiles(r.Path),
+ Environment: environment.Clone().Merge(envFromFile),
+ }
+ loadOptions.Interpolate = &interp.Options{
+ Substitute: options.Interpolate.Substitute,
+ LookupValue: config.LookupEnv,
+ TypeCastMapping: options.Interpolate.TypeCastMapping,
+ }
+ cache := includeCache(ctx)
+ cacheKey := includeModelKey(r.Path, relworkingdir, r.ProjectDirectory, config.Environment)
+ imported, hit := cache[cacheKey]
+ if hit {
+ // hand out a copy, the cached model must stay pristine
+ imported = deepClone(imported).(map[string]any)
+ } else {
+ imported, err = loadYamlModel(ctx, config, loadOptions, &cycleTracker{}, included)
+ if err != nil {
+ return err
+ }
+ if cache != nil {
+ // store a pristine copy: the model returned to the caller is
+ // merged into the parent and mutated by later loading phases
+ cache[cacheKey] = deepClone(imported).(map[string]any)
+ }
+ }
+ err = importResources(imported, model, processor)
+ if err != nil {
+ return err
+ }
+ }
+ delete(model, "include")
+ return nil
+}
+
+// importResources import into model all resources defined by imported, and report error on conflict
+func importResources(source map[string]any, target map[string]any, processor PostProcessor) error {
+ for _, key := range []string{"services", "jobs", "volumes", "networks", "secrets", "configs", "models"} {
+ if err := importResource(source, target, key, processor); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func importResource(source map[string]any, target map[string]any, key string, processor PostProcessor) error {
+ from := source[key]
+ if from != nil {
+ var to map[string]any
+ if v, ok := target[key]; ok {
+ to = v.(map[string]any)
+ } else {
+ to = map[string]any{}
+ }
+ for name, a := range from.(map[string]any) {
+ conflict, ok := to[name]
+ if !ok {
+ to[name] = a
+ continue
+ }
+ if reflect.DeepEqual(a, conflict) {
+ // Same resource reached through multiple include paths (a
+ // diamond); re-merging identical definitions would append
+ // duplicate entries to list-valued fields.
+ continue
+ }
+ err := processor.Apply(map[string]any{
+ key: map[string]any{
+ name: a,
+ },
+ })
+ if err != nil {
+ return err
+ }
+
+ merged, err := override.MergeYaml(a, conflict, tree.NewPath(key, name))
+ if err != nil {
+ return err
+ }
+ to[name] = merged
+ }
+ target[key] = to
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/interpolate.go b/vendor/github.com/compose-spec/compose-go/v2/loader/interpolate.go
new file mode 100644
index 0000000000..ac263fe53c
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/interpolate.go
@@ -0,0 +1,148 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ interp "github.com/compose-spec/compose-go/v2/interpolation"
+ "github.com/compose-spec/compose-go/v2/tree"
+ "github.com/sirupsen/logrus"
+)
+
+var interpolateTypeCastMapping = buildInterpolateTypeCastMapping()
+
+// buildInterpolateTypeCastMapping registers numeric/boolean casts per layer of
+// the specification: container_spec attributes apply wherever a container is
+// declared (services, jobs, pre_start init containers), workload_spec
+// attributes to services and jobs, service-only attributes to services.
+func buildInterpolateTypeCastMapping() map[tree.Path]interp.Cast {
+ casts := map[tree.Path]interp.Cast{
+ iPath("networks", tree.PathMatchAll, "external"): toBoolean,
+ iPath("networks", tree.PathMatchAll, "internal"): toBoolean,
+ iPath("networks", tree.PathMatchAll, "attachable"): toBoolean,
+ iPath("networks", tree.PathMatchAll, "enable_ipv4"): toBoolean,
+ iPath("networks", tree.PathMatchAll, "enable_ipv6"): toBoolean,
+ iPath("volumes", tree.PathMatchAll, "external"): toBoolean,
+ iPath("secrets", tree.PathMatchAll, "external"): toBoolean,
+ iPath("configs", tree.PathMatchAll, "external"): toBoolean,
+ }
+ containerSpec := []tree.Path{
+ iPath("services", tree.PathMatchAll),
+ iPath("jobs", tree.PathMatchAll),
+ iPath("services", tree.PathMatchAll, "pre_start", tree.PathMatchAll),
+ }
+ workloadSpec := []tree.Path{
+ iPath("services", tree.PathMatchAll),
+ iPath("jobs", tree.PathMatchAll),
+ }
+ serviceOnly := []tree.Path{
+ iPath("services", tree.PathMatchAll),
+ }
+ add := func(prefixes []tree.Path, cast interp.Cast, parts ...string) {
+ for _, prefix := range prefixes {
+ p := prefix
+ for _, part := range parts {
+ p = p.Next(part)
+ }
+ casts[p] = cast
+ }
+ }
+
+ add(containerSpec, toInt64, "cpu_count")
+ add(containerSpec, toFloat, "cpu_percent")
+ add(containerSpec, toInt64, "cpu_period")
+ add(containerSpec, toInt64, "cpu_quota")
+ add(containerSpec, toInt64, "cpu_rt_period")
+ add(containerSpec, toInt64, "cpu_rt_runtime")
+ add(containerSpec, toFloat32, "cpus")
+ add(containerSpec, toInt64, "cpu_shares")
+ add(containerSpec, toBoolean, "init")
+ add(containerSpec, toBoolean, "oom_kill_disable")
+ add(containerSpec, toInt64, "oom_score_adj")
+ add(containerSpec, toInt64, "pids_limit")
+ add(containerSpec, toBoolean, "privileged")
+ add(containerSpec, toBoolean, "read_only")
+ add(containerSpec, toInt, "ulimits", tree.PathMatchAll)
+ add(containerSpec, toInt, "ulimits", tree.PathMatchAll, "hard")
+ add(containerSpec, toInt, "ulimits", tree.PathMatchAll, "soft")
+ add(containerSpec, toBoolean, "volumes", tree.PathMatchList, "read_only")
+ add(containerSpec, toBoolean, "volumes", tree.PathMatchList, "volume", "nocopy")
+
+ add(workloadSpec, toBoolean, "depends_on", tree.PathMatchAll, "required")
+ add(workloadSpec, toBoolean, "depends_on", tree.PathMatchAll, "restart")
+ add(workloadSpec, toInt, "healthcheck", "retries")
+ add(workloadSpec, toBoolean, "healthcheck", "disable")
+ add(workloadSpec, toInt, "ports", tree.PathMatchList, "target")
+ add(workloadSpec, toBoolean, "stdin_open")
+ add(workloadSpec, toBoolean, "tty")
+
+ add(serviceOnly, toInt, "deploy", "replicas")
+ add(serviceOnly, toInt, "deploy", "update_config", "parallelism")
+ add(serviceOnly, toFloat, "deploy", "update_config", "max_failure_ratio")
+ add(serviceOnly, toInt, "deploy", "rollback_config", "parallelism")
+ add(serviceOnly, toFloat, "deploy", "rollback_config", "max_failure_ratio")
+ add(serviceOnly, toInt, "deploy", "restart_policy", "max_attempts")
+ add(serviceOnly, toInt, "deploy", "placement", "max_replicas_per_node")
+ add(serviceOnly, toInt, "scale")
+
+ return casts
+}
+
+func iPath(parts ...string) tree.Path {
+ return tree.NewPath(parts...)
+}
+
+func toInt(value string) (interface{}, error) {
+ return strconv.Atoi(value)
+}
+
+func toInt64(value string) (interface{}, error) {
+ return strconv.ParseInt(value, 10, 64)
+}
+
+func toFloat(value string) (interface{}, error) {
+ return strconv.ParseFloat(value, 64)
+}
+
+func toFloat32(value string) (interface{}, error) {
+ f, err := strconv.ParseFloat(value, 32)
+ if err != nil {
+ return nil, err
+ }
+ return float32(f), nil
+}
+
+// should match http://yaml.org/type/bool.html
+func toBoolean(value string) (interface{}, error) {
+ switch strings.ToLower(value) {
+ case "true":
+ return true, nil
+ case "false":
+ return false, nil
+ case "y", "yes", "on":
+ logrus.Warnf("%q for boolean is not supported by YAML 1.2, please use `true`", value)
+ return true, nil
+ case "n", "no", "off":
+ logrus.Warnf("%q for boolean is not supported by YAML 1.2, please use `false`", value)
+ return false, nil
+ default:
+ return nil, fmt.Errorf("invalid boolean: %s", value)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/loader.go b/vendor/github.com/compose-spec/compose-go/v2/loader/loader.go
new file mode 100644
index 0000000000..0094a7b9d4
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/loader.go
@@ -0,0 +1,1000 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/compose-spec/compose-go/v2/consts"
+ "github.com/compose-spec/compose-go/v2/errdefs"
+ interp "github.com/compose-spec/compose-go/v2/interpolation"
+ "github.com/compose-spec/compose-go/v2/override"
+ "github.com/compose-spec/compose-go/v2/paths"
+ "github.com/compose-spec/compose-go/v2/schema"
+ "github.com/compose-spec/compose-go/v2/template"
+ "github.com/compose-spec/compose-go/v2/transform"
+ "github.com/compose-spec/compose-go/v2/tree"
+ "github.com/compose-spec/compose-go/v2/types"
+ "github.com/compose-spec/compose-go/v2/utils"
+ "github.com/compose-spec/compose-go/v2/validation"
+ "github.com/go-viper/mapstructure/v2"
+ "github.com/sirupsen/logrus"
+ "go.yaml.in/yaml/v4"
+)
+
+// Options supported by Load
+type Options struct {
+ // Skip schema validation
+ SkipValidation bool
+ // Skip interpolation
+ SkipInterpolation bool
+ // Skip normalization
+ SkipNormalization bool
+ // Resolve path
+ ResolvePaths bool
+ // Convert Windows path
+ ConvertWindowsPaths bool
+ // Skip consistency check
+ SkipConsistencyCheck bool
+ // Skip extends
+ SkipExtends bool
+ // SkipInclude will ignore `include` and only load model from file(s) set by ConfigDetails
+ SkipInclude bool
+ // SkipResolveEnvironment will ignore computing `environment` for services
+ SkipResolveEnvironment bool
+ // SkipResolveLabels will ignore resolving `label_file` into `labels` for services.
+ // When set, service `labels` may be incomplete: `label_file` entries are left unresolved,
+ // so callers must not treat `labels` as authoritative.
+ SkipResolveLabels bool
+ // SkipDefaultValues will ignore missing required attributes
+ SkipDefaultValues bool
+ // Interpolation options
+ Interpolate *interp.Options
+ // Discard 'env_file' entries after resolving to 'environment' section
+ discardEnvFiles bool
+ // Set project projectName
+ projectName string
+ // Indicates when the projectName was explicitly set or guessed from path
+ projectNameExplicit bool
+ // Indicates the working dir passed to LoadConfigFiles was explicitly
+ // requested (e.g. --project-directory) rather than defaulted (e.g. the
+ // current directory), so a remote resource loader (git, oci) must not
+ // override it with the downloaded copy's own directory
+ workingDirExplicit bool
+ // Profiles set profiles to enable
+ Profiles []string
+ // SelectedServices restricts the project model to these services (and their dependencies)
+ // after parsing. An empty slice means "all services". When set, services not in the list
+ // are dropped from the project before environment resolution, so their env_file / label_file
+ // entries are not loaded.
+ SelectedServices []string
+ // PruneUnnecessaryResources drops networks/volumes/secrets/configs/models that are not
+ // referenced by active services after service selection.
+ PruneUnnecessaryResources bool
+ // ResourceLoaders manages support for remote resources
+ ResourceLoaders []ResourceLoader
+ // KnownExtensions manages x-* attribute we know and the corresponding go structs
+ KnownExtensions map[string]any
+ // Metada for telemetry
+ Listeners []Listener
+ // MaxNodeVisits caps total YAML node visits during reset/override resolution.
+ // Zero means use the default. Useful for very large compose files that exceed the default cap.
+ MaxNodeVisits int
+ // UnsupportedAttributesCheck detects caller-supplied patterns identifying
+ // compose-file attributes not honored by the caller's runtime. See
+ // WithUnsupportedAttributesCheck.
+ UnsupportedAttributesCheck *UnsupportedAttributesCheck
+}
+
+var (
+ versionWarning = utils.NewSet[string]()
+ versionWarningMu sync.Mutex
+)
+
+// warnObsoleteVersion warns once per file for the process lifetime (kept global so repeated LoadProject calls, e.g. compose watch, don't re-warn).
+func (o *Options) warnObsoleteVersion(file string) {
+ versionWarningMu.Lock()
+ defer versionWarningMu.Unlock()
+ if !versionWarning.Has(file) {
+ logrus.Warning(fmt.Sprintf("%s: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion", file))
+ versionWarning.Add(file)
+ }
+}
+
+type Listener = func(event string, metadata map[string]any)
+
+// Invoke all listeners for an event
+func (o *Options) ProcessEvent(event string, metadata map[string]any) {
+ for _, l := range o.Listeners {
+ l(event, metadata)
+ }
+}
+
+// ResourceLoader is a plugable remote resource resolver
+type ResourceLoader interface {
+ // Accept returns `true` is the resource reference matches ResourceLoader supported protocol(s)
+ Accept(path string) bool
+ // Load returns the path to a local copy of remote resource identified by `path`.
+ Load(ctx context.Context, path string) (string, error)
+ // Dir computes path to resource"s parent folder, made relative if possible
+ Dir(path string) string
+}
+
+// RemoteResourceLoaders excludes localResourceLoader from ResourceLoaders
+func (o Options) RemoteResourceLoaders() []ResourceLoader {
+ var loaders []ResourceLoader
+ for i, loader := range o.ResourceLoaders {
+ if _, ok := loader.(localResourceLoader); ok {
+ if i != len(o.ResourceLoaders)-1 {
+ logrus.Warning("misconfiguration of ResourceLoaders: localResourceLoader should be last")
+ }
+ continue
+ }
+ loaders = append(loaders, loader)
+ }
+ return loaders
+}
+
+type localResourceLoader struct {
+ WorkingDir string
+}
+
+func (l localResourceLoader) abs(p string) string {
+ if filepath.IsAbs(p) {
+ return p
+ }
+ return filepath.Join(l.WorkingDir, p)
+}
+
+func (l localResourceLoader) Accept(_ string) bool {
+ // LocalResourceLoader is the last loader tested so it always should accept the config and try to get the content.
+ return true
+}
+
+func (l localResourceLoader) Load(_ context.Context, p string) (string, error) {
+ return l.abs(p), nil
+}
+
+func (l localResourceLoader) Dir(originalPath string) string {
+ path := l.abs(originalPath)
+ if !l.isDir(path) {
+ path = l.abs(filepath.Dir(originalPath))
+ }
+ rel, err := filepath.Rel(l.WorkingDir, path)
+ if err != nil {
+ return path
+ }
+ return rel
+}
+
+func (l localResourceLoader) isDir(path string) bool {
+ fileInfo, err := os.Stat(path)
+ if err != nil {
+ return false
+ }
+ return fileInfo.IsDir()
+}
+
+func (o *Options) clone() *Options {
+ return &Options{
+ SkipValidation: o.SkipValidation,
+ SkipInterpolation: o.SkipInterpolation,
+ SkipNormalization: o.SkipNormalization,
+ ResolvePaths: o.ResolvePaths,
+ ConvertWindowsPaths: o.ConvertWindowsPaths,
+ SkipConsistencyCheck: o.SkipConsistencyCheck,
+ SkipExtends: o.SkipExtends,
+ SkipInclude: o.SkipInclude,
+ Interpolate: o.Interpolate,
+ discardEnvFiles: o.discardEnvFiles,
+ projectName: o.projectName,
+ projectNameExplicit: o.projectNameExplicit,
+ workingDirExplicit: o.workingDirExplicit,
+ Profiles: o.Profiles,
+ SelectedServices: o.SelectedServices,
+ PruneUnnecessaryResources: o.PruneUnnecessaryResources,
+ ResourceLoaders: o.ResourceLoaders,
+ KnownExtensions: o.KnownExtensions,
+ Listeners: o.Listeners,
+ UnsupportedAttributesCheck: o.UnsupportedAttributesCheck,
+ }
+}
+
+func (o *Options) SetProjectName(name string, explicit bool) {
+ o.projectName = name
+ o.projectNameExplicit = explicit
+}
+
+func (o Options) GetProjectName() (string, bool) {
+ return o.projectName, o.projectNameExplicit
+}
+
+// SetWorkingDirExplicit records whether the working dir passed to
+// LoadConfigFiles was explicitly requested by the caller (e.g.
+// --project-directory) rather than defaulted (e.g. the current directory).
+// A remote resource loader (git, oci) must not override an explicit working
+// dir with the directory of its downloaded copy.
+func (o *Options) SetWorkingDirExplicit(explicit bool) {
+ o.workingDirExplicit = explicit
+}
+
+// serviceRef identifies a reference to a service. It's used to detect cyclic
+// references in "extends".
+type serviceRef struct {
+ filename string
+ service string
+}
+
+type cycleTracker struct {
+ loaded []serviceRef
+}
+
+func (ct *cycleTracker) Add(filename, service string) (*cycleTracker, error) {
+ toAdd := serviceRef{filename: filename, service: service}
+ for _, loaded := range ct.loaded {
+ if toAdd == loaded {
+ // Create an error message of the form:
+ // Circular reference:
+ // service-a in docker-compose.yml
+ // extends service-b in docker-compose.yml
+ // extends service-a in docker-compose.yml
+ errLines := []string{
+ "Circular reference:",
+ fmt.Sprintf(" %s in %s", ct.loaded[0].service, ct.loaded[0].filename),
+ }
+ for _, service := range append(ct.loaded[1:], toAdd) {
+ errLines = append(errLines, fmt.Sprintf(" extends %s in %s", service.service, service.filename))
+ }
+
+ return nil, errors.New(strings.Join(errLines, "\n"))
+ }
+ }
+
+ var branch []serviceRef
+ branch = append(branch, ct.loaded...)
+ branch = append(branch, toAdd)
+ return &cycleTracker{
+ loaded: branch,
+ }, nil
+}
+
+// WithDiscardEnvFiles sets the Options to discard the `env_file` section after resolving to
+// the `environment` section
+func WithDiscardEnvFiles(opts *Options) {
+ opts.discardEnvFiles = true
+}
+
+// WithSkipValidation sets the Options to skip validation when loading sections
+func WithSkipValidation(opts *Options) {
+ opts.SkipValidation = true
+}
+
+// WithProfiles sets profiles to be activated
+func WithProfiles(profiles []string) func(*Options) {
+ return func(opts *Options) {
+ opts.Profiles = profiles
+ }
+}
+
+// WithSelectedServices restricts the loaded project to the given services and their
+// dependencies. An empty slice means "all services". When set, services not in the
+// list are dropped from the project before environment resolution: their `env_file`
+// and `label_file` entries will not be loaded from disk.
+func WithSelectedServices(services []string) func(*Options) {
+ return func(opts *Options) {
+ opts.SelectedServices = services
+ }
+}
+
+// WithoutUnnecessaryResources drops networks/volumes/secrets/configs/models that
+// are not referenced by services remaining after selection.
+func WithoutUnnecessaryResources(opts *Options) {
+ opts.PruneUnnecessaryResources = true
+}
+
+// PostProcessor is used to tweak compose model based on metadata extracted during yaml Unmarshal phase
+// that hardly can be implemented using go-yaml and mapstructure
+type PostProcessor interface {
+ // Apply changes to compose model based on recorder metadata
+ Apply(interface{}) error
+}
+
+type NoopPostProcessor struct{}
+
+func (NoopPostProcessor) Apply(interface{}) error { return nil }
+
+// LoadConfigFiles ingests config files with ResourceLoader and returns config details with paths to local copies
+func LoadConfigFiles(ctx context.Context, configFiles []string, workingDir string, options ...func(*Options)) (*types.ConfigDetails, error) {
+ if len(configFiles) < 1 {
+ return &types.ConfigDetails{}, fmt.Errorf("no configuration file provided: %w", errdefs.ErrNotFound)
+ }
+
+ opts := &Options{}
+ config := &types.ConfigDetails{
+ ConfigFiles: make([]types.ConfigFile, len(configFiles)),
+ }
+
+ for _, op := range options {
+ op(opts)
+ }
+ opts.ResourceLoaders = append(opts.ResourceLoaders, localResourceLoader{})
+
+ for i, p := range configFiles {
+ if p == "-" {
+ config.ConfigFiles[i] = types.ConfigFile{
+ Filename: p,
+ }
+ continue
+ }
+
+ for _, loader := range opts.ResourceLoaders {
+ _, isLocalResourceLoader := loader.(localResourceLoader)
+ if !loader.Accept(p) {
+ continue
+ }
+ local, err := loader.Load(ctx, p)
+ if err != nil {
+ return nil, err
+ }
+ if config.WorkingDir == "" && !isLocalResourceLoader && !opts.workingDirExplicit {
+ config.WorkingDir = filepath.Dir(local)
+ }
+ abs, err := filepath.Abs(local)
+ if err != nil {
+ abs = local
+ }
+ config.ConfigFiles[i] = types.ConfigFile{
+ Filename: abs,
+ }
+ break
+ }
+ }
+ if config.WorkingDir == "" {
+ config.WorkingDir = workingDir
+ }
+ return config, nil
+}
+
+// LoadWithContext reads a ConfigDetails and returns a fully loaded configuration as a compose-go Project
+func LoadWithContext(ctx context.Context, configDetails types.ConfigDetails, options ...func(*Options)) (*types.Project, error) {
+ opts := ToOptions(&configDetails, options)
+ dict, err := loadModelWithContext(ctx, &configDetails, opts)
+ if err != nil {
+ return nil, err
+ }
+ return ModelToProject(dict, opts, configDetails)
+}
+
+// LoadModelWithContext reads a ConfigDetails and returns a fully loaded configuration as a yaml dictionary
+func LoadModelWithContext(ctx context.Context, configDetails types.ConfigDetails, options ...func(*Options)) (map[string]any, error) {
+ opts := ToOptions(&configDetails, options)
+ return loadModelWithContext(ctx, &configDetails, opts)
+}
+
+// LoadModelWithContext reads a ConfigDetails and returns a fully loaded configuration as a yaml dictionary
+func loadModelWithContext(ctx context.Context, configDetails *types.ConfigDetails, opts *Options) (map[string]any, error) {
+ if len(configDetails.ConfigFiles) < 1 {
+ return nil, errors.New("no compose file specified")
+ }
+
+ err := projectName(configDetails, opts)
+ if err != nil {
+ return nil, err
+ }
+
+ return load(ctx, *configDetails, opts, nil)
+}
+
+func ToOptions(configDetails *types.ConfigDetails, options []func(*Options)) *Options {
+ opts := &Options{
+ Interpolate: &interp.Options{
+ Substitute: template.Substitute,
+ LookupValue: configDetails.LookupEnv,
+ TypeCastMapping: interpolateTypeCastMapping,
+ },
+ ResolvePaths: true,
+ }
+
+ for _, op := range options {
+ op(opts)
+ }
+ opts.ResourceLoaders = append(opts.ResourceLoaders, localResourceLoader{configDetails.WorkingDir})
+ return opts
+}
+
+func loadYamlModel(ctx context.Context, config types.ConfigDetails, opts *Options, ct *cycleTracker, included []string) (map[string]interface{}, error) {
+ var (
+ dict = map[string]interface{}{}
+ err error
+ )
+ workingDir, environment := config.WorkingDir, config.Environment
+
+ // interpolation options and environment are fixed within this call, so
+ // extends.file bases can be shared by every service loaded from it
+ ctx = withExtendsCache(ctx)
+
+ for _, file := range config.ConfigFiles {
+ dict, _, err = loadYamlFile(ctx, file, opts, workingDir, environment, ct, dict, included)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if !opts.SkipDefaultValues {
+ dict, err = transform.SetDefaultValues(dict)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if !opts.SkipValidation {
+ if err := validation.Validate(dict); err != nil {
+ return nil, err
+ }
+ }
+
+ if opts.ResolvePaths {
+ var remotes []paths.RemoteResource
+ for _, loader := range opts.RemoteResourceLoaders() {
+ remotes = append(remotes, loader.Accept)
+ }
+ err = paths.ResolveRelativePaths(dict, config.WorkingDir, remotes)
+ if err != nil {
+ return nil, err
+ }
+ }
+ ResolveEnvironment(dict, config.Environment)
+
+ return dict, nil
+}
+
+func loadYamlFile(ctx context.Context,
+ file types.ConfigFile,
+ opts *Options,
+ workingDir string,
+ environment types.Mapping,
+ ct *cycleTracker,
+ dict map[string]interface{},
+ included []string,
+) (map[string]interface{}, PostProcessor, error) {
+ ctx = context.WithValue(ctx, consts.ComposeFileKey{}, file.Filename)
+ if file.Content == nil && file.Config == nil {
+ content, err := os.ReadFile(file.Filename)
+ if err != nil {
+ return nil, nil, err
+ }
+ file.Content = content
+ }
+
+ processRawYaml := func(raw interface{}, processor PostProcessor) error {
+ converted, err := convertToStringKeysRecursive(raw, "")
+ if err != nil {
+ return err
+ }
+ cfg, ok := converted.(map[string]interface{})
+ if !ok {
+ return errors.New("top-level object must be a mapping")
+ }
+
+ if opts.Interpolate != nil && !opts.SkipInterpolation {
+ cfg, err = interp.Interpolate(cfg, *opts.Interpolate)
+ if err != nil {
+ return err
+ }
+ }
+
+ fixEmptyNotNull(cfg)
+
+ if err := promoteAliases(cfg, tree.NewPath()); err != nil {
+ return err
+ }
+
+ // Process includes first so that extended services have all merged attributes
+ if !opts.SkipInclude {
+ included = append(included, file.Filename)
+ err = ApplyInclude(ctx, workingDir, environment, cfg, opts, included, processor)
+ if err != nil {
+ return err
+ }
+ }
+
+ if err := processor.Apply(dict); err != nil {
+ return err
+ }
+
+ // Process extends after includes so base services are fully merged
+ if !opts.SkipExtends {
+ err = ApplyExtends(ctx, cfg, opts, ct, processor)
+ if err != nil {
+ return err
+ }
+
+ }
+
+ dict, err = override.Merge(dict, cfg)
+ if err != nil {
+ return err
+ }
+
+ dict, err = override.EnforceUnicity(dict)
+ if err != nil {
+ return err
+ }
+
+ if !opts.SkipValidation {
+ if err := schema.Validate(dict); err != nil {
+ return fmt.Errorf("validating %s: %w", file.Filename, err)
+ }
+ if _, ok := dict["version"]; ok {
+ opts.warnObsoleteVersion(file.Filename)
+ delete(dict, "version")
+ }
+ }
+
+ dict, err = transform.Canonical(dict, opts.SkipInterpolation)
+ if err != nil {
+ return err
+ }
+
+ dict = OmitEmpty(dict)
+
+ // Canonical transformation can reveal duplicates, typically as ports can be a range and conflict with an override
+ dict, err = override.EnforceUnicity(dict)
+ return err
+ }
+
+ var processor PostProcessor
+ if file.Config == nil {
+ r := bytes.NewReader(file.Content)
+ decoder := yaml.NewDecoder(r)
+ for {
+ var raw interface{}
+ reset := &ResetProcessor{target: &raw, maxNodeVisits: opts.MaxNodeVisits}
+ err := decoder.Decode(reset)
+ if err != nil && errors.Is(err, io.EOF) {
+ break
+ }
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to parse %s: %w", file.Filename, err)
+ }
+ processor = reset
+ if err := processRawYaml(raw, processor); err != nil {
+ return nil, nil, err
+ }
+ }
+ } else {
+ if err := processRawYaml(file.Config, NoopPostProcessor{}); err != nil {
+ return nil, nil, err
+ }
+ }
+ return dict, processor, nil
+}
+
+func load(ctx context.Context, configDetails types.ConfigDetails, opts *Options, loaded []string) (map[string]interface{}, error) {
+ mainFile := configDetails.ConfigFiles[0].Filename
+ for _, f := range loaded {
+ if f == mainFile {
+ loaded = append(loaded, mainFile)
+ return nil, fmt.Errorf("include cycle detected:\n%s\n include %s", loaded[0], strings.Join(loaded[1:], "\n include "))
+ }
+ }
+
+ dict, err := loadYamlModel(withIncludeCache(ctx), configDetails, opts, &cycleTracker{}, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(dict) == 0 {
+ return nil, errors.New("empty compose file")
+ }
+
+ if !opts.SkipValidation && opts.projectName == "" {
+ return nil, errors.New("project name must not be empty")
+ }
+
+ // runs here, once, on the fully merged model (loadYamlModel recurses once
+ // per `include:`d file): unlike validation.Validate, this is a batch scan
+ // with no per-file/fail-fast need, so it must not ride along on
+ // loadYamlModel's recursive call site or it fires once per included file.
+ if check := opts.UnsupportedAttributesCheck; check != nil && check.Report != nil {
+ check.Report(detectUnsupportedAttributes(dict, check))
+ }
+
+ if !opts.SkipNormalization {
+ dict["name"] = opts.projectName
+ dict, err = Normalize(dict, configDetails.Environment)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return dict, nil
+}
+
+// ModelToProject binds a canonical yaml dict into compose-go structs
+func ModelToProject(dict map[string]interface{}, opts *Options, configDetails types.ConfigDetails) (*types.Project, error) {
+ project := &types.Project{
+ Name: opts.projectName,
+ WorkingDir: configDetails.WorkingDir,
+ Environment: configDetails.Environment,
+ }
+ delete(dict, "name") // project name set by yaml must be identified by caller as opts.projectName
+
+ var err error
+ dict, err = processExtensions(dict, tree.NewPath(), opts.KnownExtensions)
+ if err != nil {
+ return nil, err
+ }
+
+ err = Transform(dict, project)
+ if err != nil {
+ return nil, err
+ }
+
+ if opts.ConvertWindowsPaths {
+ for i, service := range project.Services {
+ for j, volume := range service.Volumes {
+ service.Volumes[j] = convertVolumePath(volume)
+ }
+ project.Services[i] = service
+ }
+ }
+
+ if project, err = project.WithProfiles(opts.Profiles); err != nil {
+ return nil, err
+ }
+
+ if !opts.SkipConsistencyCheck {
+ err := checkConsistency(project)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if len(opts.SelectedServices) > 0 {
+ // WithServicesEnabled must precede WithSelectedServices: the latter walks
+ // only active services, so any selected service currently sitting in
+ // DisabledServices (e.g. gated by a profile) would otherwise be invisible.
+ project, err = project.WithServicesEnabled(opts.SelectedServices...)
+ if err != nil {
+ return nil, err
+ }
+ project, err = project.WithSelectedServices(opts.SelectedServices)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if opts.PruneUnnecessaryResources {
+ project = project.WithoutUnnecessaryResources()
+ }
+
+ if !opts.SkipResolveEnvironment {
+ project, err = project.WithServicesEnvironmentResolved(opts.discardEnvFiles)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if !opts.SkipResolveLabels {
+ // discardEnvFiles only applies to `env_file`: `label_file` entries are never discarded
+ project, err = project.WithServicesLabelsResolved(false)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return project, nil
+}
+
+func InvalidProjectNameErr(v string) error {
+ return fmt.Errorf(
+ "invalid project name %q: must consist only of lowercase alphanumeric characters, hyphens, and underscores as well as start with a letter or number",
+ v,
+ )
+}
+
+// projectName determines the canonical name to use for the project considering
+// the loader Options as well as `name` fields in Compose YAML fields (which
+// also support interpolation).
+func projectName(details *types.ConfigDetails, opts *Options) error {
+ defer func() {
+ if details.Environment == nil {
+ details.Environment = map[string]string{}
+ }
+ details.Environment[consts.ComposeProjectName] = opts.projectName
+ }()
+
+ if opts.projectNameExplicit {
+ if NormalizeProjectName(opts.projectName) != opts.projectName {
+ return InvalidProjectNameErr(opts.projectName)
+ }
+ return nil
+ }
+
+ type named struct {
+ Name string `yaml:"name"`
+ }
+
+ // if user did NOT provide a name explicitly, then see if one is defined
+ // in any of the config files
+ var pjNameFromConfigFile string
+ for _, configFile := range details.ConfigFiles {
+ content := configFile.Content
+ if content == nil {
+ // This can be hit when Filename is set but Content is not. One
+ // example is when using ToConfigFiles().
+ d, err := os.ReadFile(configFile.Filename)
+ if err != nil {
+ return fmt.Errorf("failed to read file %q: %w", configFile.Filename, err)
+ }
+ content = d
+ configFile.Content = d
+ }
+ var n named
+ r := bytes.NewReader(content)
+ decoder := yaml.NewDecoder(r)
+ for {
+ err := decoder.Decode(&n)
+ if err != nil && errors.Is(err, io.EOF) {
+ break
+ }
+ if err != nil {
+ // HACK: the way that loading is currently structured, this is
+ // a duplicative parse just for the `name`. if it fails, we
+ // give up but don't return the error, knowing that it'll get
+ // caught downstream for us
+ break
+ }
+ if n.Name != "" {
+ pjNameFromConfigFile = n.Name
+ }
+ }
+ }
+ if !opts.SkipInterpolation {
+ interpolated, err := interp.Interpolate(
+ map[string]interface{}{"name": pjNameFromConfigFile},
+ *opts.Interpolate,
+ )
+ if err != nil {
+ return err
+ }
+ pjNameFromConfigFile = interpolated["name"].(string)
+ }
+
+ if !opts.SkipNormalization {
+ pjNameFromConfigFile = NormalizeProjectName(pjNameFromConfigFile)
+ }
+ if pjNameFromConfigFile != "" {
+ opts.projectName = pjNameFromConfigFile
+ }
+ return nil
+}
+
+func NormalizeProjectName(s string) string {
+ r := regexp.MustCompile("[a-z0-9_-]")
+ s = strings.ToLower(s)
+ s = strings.Join(r.FindAllString(s, -1), "")
+ return strings.TrimLeft(s, "_-")
+}
+
+var userDefinedKeys = []tree.Path{
+ "services",
+ "services.*.depends_on",
+ "volumes",
+ "networks",
+ "secrets",
+ "configs",
+}
+
+func processExtensions(dict map[string]any, p tree.Path, extensions map[string]any) (map[string]interface{}, error) {
+ extras := map[string]any{}
+ var err error
+ for key, value := range dict {
+ skip := false
+ for _, uk := range userDefinedKeys {
+ if p.Matches(uk) {
+ skip = true
+ break
+ }
+ }
+ if !skip && strings.HasPrefix(key, "x-") {
+ extras[key] = value
+ delete(dict, key)
+ continue
+ }
+ switch v := value.(type) {
+ case map[string]interface{}:
+ dict[key], err = processExtensions(v, p.Next(key), extensions)
+ if err != nil {
+ return nil, err
+ }
+ case []interface{}:
+ for i, e := range v {
+ if m, ok := e.(map[string]interface{}); ok {
+ v[i], err = processExtensions(m, p.Next(strconv.Itoa(i)), extensions)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+ }
+ for name, val := range extras {
+ if typ, ok := extensions[name]; ok {
+ target := reflect.New(reflect.TypeOf(typ)).Elem().Interface()
+ err = Transform(val, &target)
+ if err != nil {
+ return nil, err
+ }
+ extras[name] = target
+ }
+ }
+ if len(extras) > 0 {
+ dict[consts.Extensions] = extras
+ }
+ return dict, nil
+}
+
+// Transform converts the source into the target struct with compose types transformer
+// and the specified transformers if any.
+func Transform(source interface{}, target interface{}) error {
+ data := mapstructure.Metadata{}
+ config := &mapstructure.DecoderConfig{
+ DecodeHook: mapstructure.ComposeDecodeHookFunc(
+ nameServices,
+ decoderHook,
+ cast,
+ secretConfigDecoderHook,
+ ),
+ Result: target,
+ TagName: "yaml",
+ Squash: true,
+ Metadata: &data,
+ }
+ decoder, err := mapstructure.NewDecoder(config)
+ if err != nil {
+ return err
+ }
+ return decoder.Decode(source)
+}
+
+// nameServices create implicit `name` key for convenience accessing service or job
+func nameServices(from reflect.Value, to reflect.Value) (interface{}, error) {
+ if to.Type() == reflect.TypeOf(types.Services{}) || to.Type() == reflect.TypeOf(types.Jobs{}) {
+ nameK := reflect.ValueOf("name")
+ iter := from.MapRange()
+ for iter.Next() {
+ name := iter.Key()
+ elem := iter.Value()
+ elem.Elem().SetMapIndex(nameK, name)
+ }
+ }
+ return from.Interface(), nil
+}
+
+func secretConfigDecoderHook(from, to reflect.Type, data interface{}) (interface{}, error) {
+ // Check if the input is a map and we're decoding into a SecretConfig
+ if from.Kind() == reflect.Map && to == reflect.TypeOf(types.SecretConfig{}) {
+ if v, ok := data.(map[string]interface{}); ok {
+ if ext, ok := v[consts.Extensions].(map[string]interface{}); ok {
+ if val, ok := ext[types.SecretConfigXValue].(string); ok {
+ // Return a map with the Content field populated
+ v["Content"] = val
+ delete(ext, types.SecretConfigXValue)
+
+ if len(ext) == 0 {
+ delete(v, consts.Extensions)
+ }
+ }
+ }
+ }
+ }
+
+ // Return the original data so the rest is handled by default mapstructure logic
+ return data, nil
+}
+
+// keys need to be converted to strings for jsonschema
+func convertToStringKeysRecursive(value interface{}, keyPrefix string) (interface{}, error) {
+ if mapping, ok := value.(map[string]interface{}); ok {
+ for key, entry := range mapping {
+ var newKeyPrefix string
+ if keyPrefix == "" {
+ newKeyPrefix = key
+ } else {
+ newKeyPrefix = fmt.Sprintf("%s.%s", keyPrefix, key)
+ }
+ convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix)
+ if err != nil {
+ return nil, err
+ }
+ mapping[key] = convertedEntry
+ }
+ return mapping, nil
+ }
+ if mapping, ok := value.(map[interface{}]interface{}); ok {
+ dict := make(map[string]interface{})
+ for key, entry := range mapping {
+ str, ok := key.(string)
+ if !ok {
+ return nil, formatInvalidKeyError(keyPrefix, key)
+ }
+ var newKeyPrefix string
+ if keyPrefix == "" {
+ newKeyPrefix = str
+ } else {
+ newKeyPrefix = fmt.Sprintf("%s.%s", keyPrefix, str)
+ }
+ convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix)
+ if err != nil {
+ return nil, err
+ }
+ dict[str] = convertedEntry
+ }
+ return dict, nil
+ }
+ if list, ok := value.([]interface{}); ok {
+ var convertedList []interface{}
+ for index, entry := range list {
+ newKeyPrefix := fmt.Sprintf("%s[%d]", keyPrefix, index)
+ convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix)
+ if err != nil {
+ return nil, err
+ }
+ convertedList = append(convertedList, convertedEntry)
+ }
+ return convertedList, nil
+ }
+ return value, nil
+}
+
+func formatInvalidKeyError(keyPrefix string, key interface{}) error {
+ var location string
+ if keyPrefix == "" {
+ location = "at top level"
+ } else {
+ location = fmt.Sprintf("in %s", keyPrefix)
+ }
+ return fmt.Errorf("non-string key %s: %#v", location, key)
+}
+
+// Windows path, c:\\my\\path\\shiny, need to be changed to be compatible with
+// the Engine. Volume path are expected to be linux style /c/my/path/shiny/
+func convertVolumePath(volume types.ServiceVolumeConfig) types.ServiceVolumeConfig {
+ volumeName := strings.ToLower(filepath.VolumeName(volume.Source))
+ if len(volumeName) != 2 {
+ return volume
+ }
+
+ convertedSource := fmt.Sprintf("/%c%s", volumeName[0], volume.Source[len(volumeName):])
+ convertedSource = strings.ReplaceAll(convertedSource, "\\", "/")
+
+ volume.Source = convertedSource
+ return volume
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/mapstructure.go b/vendor/github.com/compose-spec/compose-go/v2/loader/mapstructure.go
new file mode 100644
index 0000000000..3082bd2ea0
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/mapstructure.go
@@ -0,0 +1,79 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "reflect"
+ "strconv"
+)
+
+// comparable to yaml.Unmarshaler, decoder allow a type to define it's own custom logic to convert value
+// see https://github.com/mitchellh/mapstructure/pull/294
+type decoder interface {
+ DecodeMapstructure(interface{}) error
+}
+
+// see https://github.com/mitchellh/mapstructure/issues/115#issuecomment-735287466
+// adapted to support types derived from built-in types, as DecodeMapstructure would not be able to mutate internal
+// value, so need to invoke DecodeMapstructure defined by pointer to type
+func decoderHook(from reflect.Value, to reflect.Value) (interface{}, error) {
+ // If the destination implements the decoder interface
+ u, ok := to.Interface().(decoder)
+ if !ok {
+ // for non-struct types we need to invoke func (*type) DecodeMapstructure()
+ if to.CanAddr() {
+ pto := to.Addr()
+ u, ok = pto.Interface().(decoder)
+ }
+ if !ok {
+ return from.Interface(), nil
+ }
+ }
+ // If it is nil and a pointer, create and assign the target value first
+ if to.Type().Kind() == reflect.Pointer && to.IsNil() {
+ to.Set(reflect.New(to.Type().Elem()))
+ u = to.Interface().(decoder)
+ }
+ // Call the custom DecodeMapstructure method
+ if err := u.DecodeMapstructure(from.Interface()); err != nil {
+ return to.Interface(), err
+ }
+ return to.Interface(), nil
+}
+
+func cast(from reflect.Value, to reflect.Value) (interface{}, error) {
+ switch from.Type().Kind() {
+ case reflect.String:
+ switch to.Kind() {
+ case reflect.Bool:
+ return toBoolean(from.String())
+ case reflect.Int:
+ return toInt(from.String())
+ case reflect.Int64:
+ return toInt64(from.String())
+ case reflect.Float32:
+ return toFloat32(from.String())
+ case reflect.Float64:
+ return toFloat(from.String())
+ }
+ case reflect.Int:
+ if to.Kind() == reflect.String {
+ return strconv.FormatInt(from.Int(), 10), nil
+ }
+ }
+ return from.Interface(), nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/normalize.go b/vendor/github.com/compose-spec/compose-go/v2/loader/normalize.go
new file mode 100644
index 0000000000..ecc589aece
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/normalize.go
@@ -0,0 +1,337 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "fmt"
+ "path"
+ "strconv"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/override"
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+// Normalize compose project by moving deprecated attributes to their canonical position and injecting implicit defaults
+func Normalize(dict map[string]any, env types.Mapping) (map[string]any, error) {
+ normalizeNetworks(dict)
+
+ for _, key := range []string{"services", "jobs"} {
+ d, ok := dict[key]
+ if !ok {
+ continue
+ }
+ containers := d.(map[string]any)
+ for name, s := range containers {
+ container := s.(map[string]any)
+
+ if container["pull_policy"] == types.PullPolicyIfNotPresent {
+ container["pull_policy"] = types.PullPolicyMissing
+ }
+
+ fn := func(s string) (string, bool) {
+ v, ok := env[s]
+ return v, ok
+ }
+
+ if b, ok := container["build"]; ok {
+ build := b.(map[string]any)
+ if build["context"] == nil {
+ build["context"] = "."
+ }
+ if build["dockerfile"] == nil && build["dockerfile_inline"] == nil {
+ build["dockerfile"] = "Dockerfile"
+ }
+
+ if a, ok := build["args"]; ok {
+ build["args"], _ = resolve(a, fn, false)
+ }
+
+ container["build"] = build
+ }
+
+ if e, ok := container["environment"]; ok {
+ container["environment"], _ = resolve(e, fn, true)
+ }
+
+ var dependsOn map[string]any
+ if d, ok := container["depends_on"]; ok {
+ dependsOn = d.(map[string]any)
+ } else {
+ dependsOn = map[string]any{}
+ }
+ if l, ok := container["links"]; ok {
+ links := l.([]any)
+ for _, e := range links {
+ link := e.(string)
+ parts := strings.Split(link, ":")
+ if len(parts) == 2 {
+ link = parts[0]
+ }
+ if _, ok := dependsOn[link]; !ok {
+ dependsOn[link] = map[string]any{
+ "condition": types.ServiceConditionStarted,
+ "restart": true,
+ "required": true,
+ }
+ }
+ }
+ }
+
+ for _, namespace := range []string{"network_mode", "ipc", "pid", "uts", "cgroup"} {
+ if n, ok := container[namespace]; ok {
+ ref := n.(string)
+ if strings.HasPrefix(ref, types.ServicePrefix) {
+ shared := ref[len(types.ServicePrefix):]
+ if _, ok := dependsOn[shared]; !ok {
+ dependsOn[shared] = map[string]any{
+ "condition": types.ServiceConditionStarted,
+ "restart": true,
+ "required": true,
+ }
+ }
+ }
+ }
+ }
+
+ if v, ok := container["volumes"]; ok {
+ volumes := v.([]any)
+ for i, volume := range volumes {
+ vol := volume.(map[string]any)
+ target := vol["target"].(string)
+ vol["target"] = path.Clean(target)
+ volumes[i] = vol
+ }
+ container["volumes"] = volumes
+ }
+
+ if n, ok := container["volumes_from"]; ok {
+ volumesFrom := n.([]any)
+ for _, v := range volumesFrom {
+ vol := v.(string)
+ if !strings.HasPrefix(vol, types.ContainerPrefix) {
+ spec := strings.Split(vol, ":")
+ if _, ok := dependsOn[spec[0]]; !ok {
+ dependsOn[spec[0]] = map[string]any{
+ "condition": types.ServiceConditionStarted,
+ "restart": false,
+ "required": true,
+ }
+ }
+ }
+ }
+ }
+ if len(dependsOn) > 0 {
+ container["depends_on"] = dependsOn
+ }
+
+ if err := resolvePreStartHooks(container); err != nil {
+ return nil, err
+ }
+
+ containers[name] = container
+ }
+
+ dict[key] = containers
+ }
+ setNameFromKey(dict)
+
+ return dict, nil
+}
+
+// resolvePreStartHooks materializes pre_start inheritance at load time: each
+// hook's container specification is completed with the service's own
+// container-spec attributes, per the compose merge rules — the hook's
+// declarations win on conflicts, and accumulated entries strictly identical
+// to an inherited one are not duplicated, which keeps this resolution
+// idempotent when an already-resolved model (a `config` output) is loaded
+// again. This subsumes the image inheritance of compose-spec#647.
+//
+// Volumes are deliberately not inherited: mounts inherit at runtime through
+// volumes_from, the only mechanism able to share the parent's anonymous and
+// image volumes; the hook keeps only its own volume declarations.
+func resolvePreStartHooks(service map[string]any) error {
+ hooks, ok := service["pre_start"].([]any)
+ if !ok || len(hooks) == 0 {
+ return nil
+ }
+ base := map[string]any{}
+ for k, v := range service {
+ if k == "volumes" || !containerSpecKeys[k] {
+ continue
+ }
+ base[k] = v
+ }
+ for i, h := range hooks {
+ hook, ok := h.(map[string]any)
+ if !ok {
+ continue
+ }
+ // wrapped as a service entry so the per-attribute merge rules
+ // registered under services.* apply to the hook's specification
+ merged, err := override.Merge(
+ map[string]any{"services": map[string]any{"hook": deepClone(base)}},
+ map[string]any{"services": map[string]any{"hook": hook}},
+ )
+ if err != nil {
+ return fmt.Errorf("resolving pre_start hook specification: %w", err)
+ }
+ hooks[i] = merged["services"].(map[string]any)["hook"]
+ }
+ return nil
+}
+
+// containerSpecKeys indexes types.ContainerSpecAttributes (generated at
+// build time from the ContainerSpec type, so the boundary cannot drift from
+// the model). The filter matters for the dict form of the model
+// (LoadModel/ToModel consumers): schema validation runs before normalization
+// and the typed decode drops unknown keys, so nothing else prevents workload
+// or service-only attributes (ports, build, depends_on, x-*) from leaking
+// into the rendered hooks.
+var containerSpecKeys = func() map[string]bool {
+ keys := make(map[string]bool, len(types.ContainerSpecAttributes))
+ for _, k := range types.ContainerSpecAttributes {
+ keys[k] = true
+ }
+ return keys
+}()
+
+func normalizeNetworks(dict map[string]any) {
+ var networks map[string]any
+ if n, ok := dict["networks"]; ok {
+ networks = n.(map[string]any)
+ } else {
+ networks = map[string]any{}
+ }
+
+ // implicit `default` network must be introduced only if actually used by some service
+ usesDefaultNetwork := false
+
+ for _, key := range []string{"services", "jobs"} {
+ s, ok := dict[key]
+ if !ok {
+ continue
+ }
+ containers := s.(map[string]any)
+ for name, se := range containers {
+ container := se.(map[string]any)
+ if _, ok := container["provider"]; ok {
+ continue
+ }
+ if _, ok := container["network_mode"]; ok {
+ continue
+ }
+ if n, ok := container["networks"]; !ok {
+ // If none explicitly declared, container is connected to default network
+ container["networks"] = map[string]any{"default": nil}
+ usesDefaultNetwork = true
+ } else {
+ net := n.(map[string]any)
+ if len(net) == 0 {
+ // networks section declared but empty (corner case)
+ container["networks"] = map[string]any{"default": nil}
+ usesDefaultNetwork = true
+ } else if _, ok := net["default"]; ok {
+ usesDefaultNetwork = true
+ }
+ }
+ containers[name] = container
+ }
+ dict[key] = containers
+ }
+
+ if _, ok := networks["default"]; !ok && usesDefaultNetwork {
+ // If not declared explicitly, Compose model involves an implicit "default" network
+ networks["default"] = nil
+ }
+
+ if len(networks) > 0 {
+ dict["networks"] = networks
+ }
+}
+
+func resolve(a any, fn func(s string) (string, bool), keepEmpty bool) (any, bool) {
+ switch v := a.(type) {
+ case []any:
+ var resolved []any
+ for _, val := range v {
+ if r, ok := resolve(val, fn, keepEmpty); ok {
+ resolved = append(resolved, r)
+ }
+ }
+ return resolved, true
+ case map[string]any:
+ resolved := map[string]any{}
+ for key, val := range v {
+ if val != nil {
+ resolved[key] = val
+ continue
+ }
+ if s, ok := fn(key); ok {
+ resolved[key] = s
+ } else if keepEmpty {
+ resolved[key] = nil
+ }
+ }
+ return resolved, true
+ case string:
+ if !strings.Contains(v, "=") {
+ if val, ok := fn(v); ok {
+ return fmt.Sprintf("%s=%s", v, val), true
+ }
+ if keepEmpty {
+ return v, true
+ }
+ return "", false
+ }
+ return v, true
+ default:
+ return v, false
+ }
+}
+
+// Resources with no explicit name are actually named by their key in map
+func setNameFromKey(dict map[string]any) {
+ for _, r := range []string{"networks", "volumes", "configs", "secrets"} {
+ a, ok := dict[r]
+ if !ok {
+ continue
+ }
+ toplevel := a.(map[string]any)
+ for key, r := range toplevel {
+ var resource map[string]any
+ if r != nil {
+ resource = r.(map[string]any)
+ } else {
+ resource = map[string]any{}
+ }
+ if resource["name"] == nil {
+ if x, ok := resource["external"]; ok && isTrue(x) {
+ resource["name"] = key
+ } else {
+ resource["name"] = fmt.Sprintf("%s_%s", dict["name"], key)
+ }
+ }
+ toplevel[key] = resource
+ }
+ }
+}
+
+func isTrue(x any) bool {
+ parseBool, _ := strconv.ParseBool(fmt.Sprint(x))
+ return parseBool
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/omitEmpty.go b/vendor/github.com/compose-spec/compose-go/v2/loader/omitEmpty.go
new file mode 100644
index 0000000000..8f004664d2
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/omitEmpty.go
@@ -0,0 +1,76 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import "github.com/compose-spec/compose-go/v2/tree"
+
+var omitempty = []tree.Path{
+ "services.*.dns",
+ "jobs.*.dns",
+}
+
+// OmitEmpty removes empty attributes which are irrelevant when unset
+func OmitEmpty(yaml map[string]any) map[string]any {
+ cleaned := omitEmpty(yaml, tree.NewPath())
+ return cleaned.(map[string]any)
+}
+
+func omitEmpty(data any, p tree.Path) any {
+ switch v := data.(type) {
+ case map[string]any:
+ for k, e := range v {
+ if isEmpty(e) && mustOmit(p) {
+ delete(v, k)
+ continue
+ }
+
+ v[k] = omitEmpty(e, p.Next(k))
+ }
+ return v
+ case []any:
+ c := make([]any, 0, len(v))
+ for _, e := range v {
+ if isEmpty(e) && mustOmit(p) {
+ continue
+ }
+
+ c = append(c, omitEmpty(e, p.Next("[]")))
+ }
+ return c
+ default:
+ return data
+ }
+}
+
+func mustOmit(p tree.Path) bool {
+ for _, pattern := range omitempty {
+ if p.Matches(pattern) {
+ return true
+ }
+ }
+ return false
+}
+
+func isEmpty(e any) bool {
+ if e == nil {
+ return true
+ }
+ if v, ok := e.(string); ok && v == "" {
+ return true
+ }
+ return false
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/paths.go b/vendor/github.com/compose-spec/compose-go/v2/loader/paths.go
new file mode 100644
index 0000000000..c03126a83a
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/paths.go
@@ -0,0 +1,50 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "path/filepath"
+
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+// ResolveRelativePaths resolves relative paths based on project WorkingDirectory
+func ResolveRelativePaths(project *types.Project) error {
+ absWorkingDir, err := filepath.Abs(project.WorkingDir)
+ if err != nil {
+ return err
+ }
+ project.WorkingDir = absWorkingDir
+
+ absComposeFiles, err := absComposeFiles(project.ComposeFiles)
+ if err != nil {
+ return err
+ }
+ project.ComposeFiles = absComposeFiles
+ return nil
+}
+
+func absComposeFiles(composeFiles []string) ([]string, error) {
+ for i, composeFile := range composeFiles {
+ absComposefile, err := filepath.Abs(composeFile)
+ if err != nil {
+ return nil, err
+ }
+ composeFiles[i] = absComposefile
+ }
+ return composeFiles, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/reset.go b/vendor/github.com/compose-spec/compose-go/v2/loader/reset.go
new file mode 100644
index 0000000000..43d155051e
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/reset.go
@@ -0,0 +1,340 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+ "go.yaml.in/yaml/v4"
+)
+
+// defaultMaxNodeVisits caps total resolveReset calls per document.
+// Sized to accommodate large real-world compose files while rejecting documents that would
+// cause unbounded traversal. Callers can override this via Options.MaxNodeVisits.
+const defaultMaxNodeVisits = 100_000
+
+// nodeCache stores a resolved node and the relative sub-paths within its subtree that
+// carried !reset/!override tags, so cache hits at different call sites can replay them.
+type nodeCache struct {
+ node *yaml.Node
+ relativePaths []tree.Path
+}
+
+type ResetProcessor struct {
+ target any
+ paths []tree.Path
+ visitedNodes map[*yaml.Node][]tree.Path
+ resolvedNodes map[*yaml.Node]nodeCache
+ visitCount int
+ // maxNodeVisits is the per-document cap; when zero, defaultMaxNodeVisits is used.
+ maxNodeVisits int
+}
+
+// UnmarshalYAML implement yaml.Unmarshaler
+func (p *ResetProcessor) UnmarshalYAML(value *yaml.Node) error {
+ p.visitedNodes = make(map[*yaml.Node][]tree.Path)
+ p.resolvedNodes = make(map[*yaml.Node]nodeCache)
+ p.visitCount = 0
+ defer func() {
+ p.visitedNodes = nil
+ p.resolvedNodes = nil
+ }()
+ resolved, err := p.resolveReset(value, tree.NewPath())
+ if err != nil {
+ return err
+ }
+ p.addAliasPaths()
+ return resolved.Decode(p.target)
+}
+
+// addAliasPaths records, next to each path going through an extension declared
+// in extensionAliases, the path of the attribute it stands for: earlier files
+// hold that attribute under its own name once their extensions are promoted.
+func (p *ResetProcessor) addAliasPaths() {
+ for _, path := range p.paths {
+ if resolved := resolveAliasPath(path); resolved != path {
+ p.paths = append(p.paths, resolved)
+ }
+ }
+}
+
+// resolveReset detects `!reset` tag being set on yaml nodes and record position in the yaml tree
+func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
+ p.visitCount++
+ limit := p.maxNodeVisits
+ if limit <= 0 {
+ limit = defaultMaxNodeVisits
+ }
+ if p.visitCount > limit {
+ return nil, fmt.Errorf("compose file exceeds maximum node visit limit (%d)", limit)
+ }
+
+ pathStr := path.String()
+ // If the path contains "<<", removing the "<<" element and merging the path
+ if strings.Contains(pathStr, ".<<") {
+ path = tree.NewPath(strings.Replace(pathStr, ".<<", "", 1))
+ }
+
+ if node.Tag == "!reset" {
+ p.paths = append(p.paths, path)
+ return nil, nil
+ }
+ if node.Tag == "!override" {
+ p.paths = append(p.paths, path)
+ return node, nil
+ }
+
+ // If the node is an alias, process the alias target via the cache so each anchor is
+ // processed at most once.
+ if node.Kind == yaml.AliasNode {
+ if err := p.checkForCycle(node.Alias, path); err != nil {
+ return nil, err
+ }
+ // Handle !reset/!override on the alias target before delegating to the cache,
+ // keeping all tag-handling logic in resolveReset rather than split across functions.
+ target := node.Alias
+ if target.Tag == "!reset" {
+ p.paths = append(p.paths, path)
+ return nil, nil
+ }
+ if target.Tag == "!override" {
+ p.paths = append(p.paths, path)
+ return target, nil
+ }
+ return p.cachedResolve(target, path)
+ }
+
+ // Container nodes are resolved through the cache, ensuring resolved containers are
+ // not re-traversed.
+ if node.Kind == yaml.SequenceNode || node.Kind == yaml.MappingNode {
+ return p.cachedResolve(node, path)
+ }
+
+ return node, nil
+}
+
+// cachedResolve resolves node (a container without !reset/!override), serving from cache on
+// repeat visits to prevent re-traversal. It is only called after tag checks are done in
+// resolveReset, so it never receives !reset/!override-tagged nodes.
+func (p *ResetProcessor) cachedResolve(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
+ if cached, ok := p.resolvedNodes[node]; ok {
+ for _, rel := range cached.relativePaths {
+ p.paths = append(p.paths, joinPath(path, rel))
+ }
+ return cached.node, nil
+ }
+
+ startIdx := len(p.paths)
+ resolved, err := p.resolveContainer(node, path)
+ if err != nil {
+ return nil, err
+ }
+
+ var relPaths []tree.Path
+ for _, addedPath := range p.paths[startIdx:] {
+ rel, err := subPath(addedPath, path)
+ if err != nil {
+ return nil, err
+ }
+ relPaths = append(relPaths, rel)
+ }
+ p.resolvedNodes[node] = nodeCache{node: resolved, relativePaths: relPaths}
+ return resolved, nil
+}
+
+// resolveContainer processes the children of a Sequence or Mapping node.
+// AliasNodes must be kept as-is in the output Content; the resolved value is used only
+// for tag inspection. Changing this will affect how the YAML library handles the document
+// during decoding.
+func (p *ResetProcessor) resolveContainer(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
+ switch node.Kind {
+ case yaml.SequenceNode:
+ var nodes []*yaml.Node
+ for idx, v := range node.Content {
+ next := path.Next(strconv.Itoa(idx))
+ resolved, err := p.resolveReset(v, next)
+ if err != nil {
+ return nil, err
+ }
+ if resolved == nil {
+ continue
+ }
+ if v.Kind == yaml.AliasNode {
+ nodes = append(nodes, v)
+ } else {
+ nodes = append(nodes, resolved)
+ }
+ }
+ node.Content = nodes
+ case yaml.MappingNode:
+ keys := map[string]int{}
+ var key string
+ var nodes []*yaml.Node
+ for idx, v := range node.Content {
+ if idx%2 == 0 {
+ key = v.Value
+ if line, seen := keys[key]; seen {
+ return nil, fmt.Errorf("line %d: mapping key %#v already defined at line %d", v.Line, key, line)
+ }
+ keys[key] = v.Line
+ } else {
+ resolved, err := p.resolveReset(v, path.Next(key))
+ if err != nil {
+ return nil, err
+ }
+ if resolved == nil {
+ continue
+ }
+ // Under the merge key `<<`, the YAML library only accepts an
+ // AliasNode value when its target is a MappingNode. An alias to a
+ // SequenceNode (the spec-allowed "sequence of mappings" form via an
+ // anchor) is rejected. Substitute the resolved target so the YAML
+ // library sees the underlying node directly for merge keys.
+ if v.Kind == yaml.AliasNode && key != "<<" {
+ nodes = append(nodes, node.Content[idx-1], v)
+ } else {
+ nodes = append(nodes, node.Content[idx-1], resolved)
+ }
+ }
+ }
+ node.Content = nodes
+ }
+ return node, nil
+}
+
+// subPath strips base from full to produce a relative path for cache storage.
+// Returns "" when full == base (the !reset/!override tag is on the node root itself).
+// Returns an error when full is not rooted at base, which would indicate a logic error
+// in resolveReset/cachedResolve.
+func subPath(full, base tree.Path) (tree.Path, error) {
+ if base == "" {
+ return full, nil
+ }
+ fullStr := string(full)
+ baseStr := string(base)
+ if fullStr == baseStr {
+ return "", nil
+ }
+ prefix := baseStr + "."
+ if strings.HasPrefix(fullStr, prefix) {
+ return tree.Path(fullStr[len(prefix):]), nil
+ }
+ return "", fmt.Errorf("internal error: path %q is not a sub-path of %q", fullStr, baseStr)
+}
+
+// joinPath reconstructs an absolute path from a call-site base and a cached relative path.
+// A relative path of "" means the tag was on the node root, so base is returned unchanged.
+func joinPath(base, rel tree.Path) tree.Path {
+ if rel == "" {
+ return base
+ }
+ if base == "" {
+ return rel
+ }
+ return tree.Path(string(base) + "." + string(rel))
+}
+
+// Apply finds the go attributes matching recorded paths and reset them to zero value
+func (p *ResetProcessor) Apply(target any) error {
+ return p.applyNullOverrides(target, tree.NewPath())
+}
+
+// applyNullOverrides set val to Zero if it matches any of the recorded paths
+func (p *ResetProcessor) applyNullOverrides(target any, path tree.Path) error {
+ switch v := target.(type) {
+ case map[string]any:
+ KEYS:
+ for k, e := range v {
+ next := path.Next(k)
+ for _, pattern := range p.paths {
+ if next.Matches(pattern) {
+ delete(v, k)
+ continue KEYS
+ }
+ }
+ err := p.applyNullOverrides(e, next)
+ if err != nil {
+ return err
+ }
+ }
+ case []any:
+ ITER:
+ for i, e := range v {
+ next := path.Next(fmt.Sprintf("[%d]", i))
+ for _, pattern := range p.paths {
+ if next.Matches(pattern) {
+ continue ITER
+ // TODO(ndeloof) support removal from sequence
+ }
+ }
+ err := p.applyNullOverrides(e, next)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (p *ResetProcessor) checkForCycle(node *yaml.Node, path tree.Path) error {
+ paths := p.visitedNodes[node]
+
+ for _, prevPath := range paths {
+ // If we're visiting the exact same path, it's not a cycle
+ if path == prevPath {
+ continue
+ }
+
+ // Compare on the raw form so dots inside escaped segment names (e.g.
+ // service names containing ".") aren't conflated with path separators.
+ pathStr := string(path)
+ prevStr := string(prevPath)
+
+ // If either path is using a merge key, it's legitimate YAML merging
+ if strings.Contains(prevStr, "<<") || strings.Contains(pathStr, "<<") {
+ continue
+ }
+
+ // Only consider it a cycle if one path is contained within the other
+ // and they're not in different service definitions
+ if (strings.HasPrefix(pathStr, prevStr+".") ||
+ strings.HasPrefix(prevStr, pathStr+".")) &&
+ !areInDifferentServices(path, prevPath) {
+ return fmt.Errorf("cycle detected: node at path %s references node at path %s",
+ path.String(), prevPath.String())
+ }
+ }
+
+ p.visitedNodes[node] = append(paths, path)
+ return nil
+}
+
+// areInDifferentServices checks if two paths are in different service definitions
+func areInDifferentServices(path1, path2 tree.Path) bool {
+ parts1 := path1.Parts()
+ parts2 := path2.Parts()
+ for i := 0; i < len(parts1) && i < len(parts2); i++ {
+ if parts1[i] == "services" && i+1 < len(parts1) &&
+ parts2[i] == "services" && i+1 < len(parts2) {
+ return parts1[i+1] != parts2[i+1]
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/unsupported_attributes.go b/vendor/github.com/compose-spec/compose-go/v2/loader/unsupported_attributes.go
new file mode 100644
index 0000000000..1c2daa29dc
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/unsupported_attributes.go
@@ -0,0 +1,172 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "cmp"
+ "slices"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// UnsupportedAttribute is a single instance of a caller-supplied
+// UnsupportedAttributePattern matching the loaded compose model.
+type UnsupportedAttribute struct {
+ // Path locates the match in the loaded model, e.g. "services.web.deploy.mode".
+ Path tree.Path
+ // Value is whatever Path resolved to: a scalar, a map, or a list item,
+ // depending on the depth the matching pattern targeted.
+ Value any
+}
+
+// UnsupportedAttributePattern identifies a compose-file attribute that is
+// schema-valid but not honored by the caller's runtime. compose-go does not
+// know what any given runtime supports: the list of patterns is supplied by
+// the caller.
+type UnsupportedAttributePattern struct {
+ // Path is a tree.Path pattern (may use tree.PathMatchAll) identifying
+ // the node to inspect.
+ Path tree.Path
+ // Detect reports whether the value found at Path is unsupported. Nil
+ // means presence alone is unsupported. Detect may target an
+ // intermediate map node (not just a scalar leaf) to inspect sibling
+ // fields, e.g. matching a whole `ports` entry to flag only `mode: host`.
+ //
+ // Once any pattern's Path matches a node, the walk stops descending into
+ // that node's children regardless of what Detect returns: a pattern
+ // targeting a child of an already-matched node will never be evaluated
+ // for that occurrence.
+ Detect func(value any) bool
+}
+
+// UnsupportedAttributesCheck bundles the detection rules with the callback
+// invoked once, after loading, with every match found (possibly empty).
+//
+// Detection combines two complementary rule sets over one walk:
+//
+// - Patterns is a denylist: attributes the caller knows it does not honor,
+// with optional value predicates for cases like `ports[].mode: host`.
+// - Supported is an allowlist: when non-empty, every attribute matching
+// none of its paths is reported too. It makes the screening fail-closed —
+// an attribute the specification gains later is reported until the
+// runtime deliberately declares it. schema.AttributePaths returns the
+// full specification inventory to build it from (remove what the runtime
+// does not implement); extension keys (x-*) are never reported by this
+// rule set.
+type UnsupportedAttributesCheck struct {
+ Patterns []UnsupportedAttributePattern
+ Supported []tree.Path
+ Report func([]UnsupportedAttribute)
+}
+
+// WithUnsupportedAttributesCheck registers a set of UnsupportedAttributePattern
+// to be evaluated against the loaded model. report is invoked once, after
+// loading, with every match found (possibly empty). Composable with
+// WithSupportedAttributes: both feed the same walk and report.
+func WithUnsupportedAttributesCheck(patterns []UnsupportedAttributePattern, report func([]UnsupportedAttribute)) func(*Options) {
+ return func(opts *Options) {
+ if opts.UnsupportedAttributesCheck == nil {
+ opts.UnsupportedAttributesCheck = &UnsupportedAttributesCheck{}
+ }
+ opts.UnsupportedAttributesCheck.Patterns = patterns
+ opts.UnsupportedAttributesCheck.Report = report
+ }
+}
+
+// WithSupportedAttributes declares the attribute paths the caller's runtime
+// implements: every attribute of the loaded model matching none of them is
+// reported, alongside any WithUnsupportedAttributesCheck findings, through
+// the same report callback (report may be nil when the other option already
+// set one). Extension keys (x-*) are never reported.
+//
+// This is the fail-closed side of the check: built by removing the
+// unimplemented paths from schema.AttributePaths, it keeps reporting every
+// newly-specified attribute until the runtime deliberately wires it in.
+func WithSupportedAttributes(supported []tree.Path, report func([]UnsupportedAttribute)) func(*Options) {
+ return func(opts *Options) {
+ if opts.UnsupportedAttributesCheck == nil {
+ opts.UnsupportedAttributesCheck = &UnsupportedAttributesCheck{}
+ }
+ opts.UnsupportedAttributesCheck.Supported = supported
+ if report != nil {
+ opts.UnsupportedAttributesCheck.Report = report
+ }
+ }
+}
+
+// detectUnsupportedAttributes walks dict once and returns every finding from
+// both rule sets, ordered by Path. The walk itself visits map keys in Go's
+// randomized order, so results are sorted here for deterministic output.
+func detectUnsupportedAttributes(dict map[string]any, check *UnsupportedAttributesCheck) []UnsupportedAttribute {
+ var supported *tree.Matcher
+ if len(check.Supported) > 0 {
+ supported = tree.NewMatcher(check.Supported...)
+ }
+ findings := walkUnsupportedAttributes(dict, tree.NewPath(), check.Patterns, supported)
+ slices.SortFunc(findings, func(a, b UnsupportedAttribute) int {
+ return cmp.Compare(a.Path, b.Path)
+ })
+ return findings
+}
+
+func walkUnsupportedAttributes(value any, p tree.Path, patterns []UnsupportedAttributePattern, supported *tree.Matcher) []UnsupportedAttribute {
+ matched := false
+ for _, pattern := range patterns {
+ if !p.Matches(pattern.Path) {
+ continue
+ }
+ matched = true
+ if pattern.Detect == nil || pattern.Detect(value) {
+ return []UnsupportedAttribute{{Path: p, Value: value}}
+ }
+ }
+ if matched {
+ // one or more patterns targeted this exact node but none flagged it:
+ // don't descend any further into a node the caller already inspected
+ // as a whole.
+ return nil
+ }
+ var findings []UnsupportedAttribute
+ switch v := value.(type) {
+ case map[string]any:
+ for k, e := range v {
+ next := p.Next(k)
+ // Extension keys are specification-blessed escape hatches: the
+ // allowlist never reports them nor anything underneath (deny
+ // patterns still apply below, so the walk continues without the
+ // matcher).
+ if strings.HasPrefix(k, "x-") {
+ findings = append(findings, walkUnsupportedAttributes(e, next, patterns, nil)...)
+ continue
+ }
+ // allowlist screening: an attribute neither declared (exact
+ // match) nor holding declared attributes deeper (MayContain) is
+ // reported once, undescended
+ if supported != nil && !supported.Matches(next) && !supported.MayContain(next) {
+ findings = append(findings, UnsupportedAttribute{Path: next, Value: e})
+ continue
+ }
+ findings = append(findings, walkUnsupportedAttributes(e, next, patterns, supported)...)
+ }
+ case []any:
+ for _, e := range v {
+ findings = append(findings, walkUnsupportedAttributes(e, p.Next(tree.PathMatchList), patterns, supported)...)
+ }
+ }
+ return findings
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/loader/validate.go b/vendor/github.com/compose-spec/compose-go/v2/loader/validate.go
new file mode 100644
index 0000000000..a04a067f42
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/loader/validate.go
@@ -0,0 +1,252 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package loader
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/errdefs"
+ "github.com/compose-spec/compose-go/v2/graph"
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+// checkConsistency validate a compose model is consistent
+func checkConsistency(project *types.Project) error { //nolint:gocyclo
+ for name, s := range project.Services {
+ if s.Build == nil && s.Image == "" && s.Provider == nil {
+ return fmt.Errorf("service %q has neither an image nor a build context specified: %w", s.Name, errdefs.ErrInvalid)
+ }
+
+ if s.Build != nil {
+ if s.Build.DockerfileInline != "" && s.Build.Dockerfile != "" {
+ return fmt.Errorf("service %q declares mutualy exclusive dockerfile and dockerfile_inline: %w", s.Name, errdefs.ErrInvalid)
+ }
+
+ for add, c := range s.Build.AdditionalContexts {
+ if target, ok := strings.CutPrefix(c, types.ServicePrefix); ok {
+ t, err := project.GetService(target)
+ if errors.Is(err, errdefs.ErrDisabled) {
+ t = project.DisabledServices[target]
+ err = nil
+ }
+ if err != nil {
+ return fmt.Errorf("service %q declares unknown service %q as additional contexts %s", name, target, add)
+ }
+ if t.Build == nil {
+ return fmt.Errorf("service %q declares non-buildable service %q as additional contexts %s", name, target, add)
+ }
+ }
+ }
+
+ if len(s.Build.Platforms) > 0 && s.Platform != "" {
+ var found bool
+ for _, platform := range s.Build.Platforms {
+ if platform == s.Platform {
+ found = true
+ break
+ }
+ }
+ if !found {
+ return fmt.Errorf("service.build.platforms MUST include service.platform %q: %w", s.Platform, errdefs.ErrInvalid)
+ }
+ }
+ }
+
+ if s.NetworkMode != "" && len(s.Networks) > 0 {
+ return fmt.Errorf("service %s declares mutually exclusive `network_mode` and `networks`: %w", s.Name, errdefs.ErrInvalid)
+ }
+ for network := range s.Networks {
+ if _, ok := project.Networks[network]; !ok {
+ return fmt.Errorf("service %q refers to undefined network %s: %w", s.Name, network, errdefs.ErrInvalid)
+ }
+ }
+
+ if s.HealthCheck != nil && len(s.HealthCheck.Test) > 0 {
+ switch s.HealthCheck.Test[0] {
+ case "CMD", "CMD-SHELL", "NONE":
+ default:
+ return errors.New(`healthcheck.test must start either by "CMD", "CMD-SHELL" or "NONE"`)
+ }
+ }
+
+ for dependedService, cfg := range s.DependsOn {
+ if _, err := project.GetService(dependedService); err != nil {
+ if errors.Is(err, errdefs.ErrDisabled) && !cfg.Required {
+ continue
+ }
+ if _, isJob := project.Jobs[dependedService]; isJob {
+ return fmt.Errorf("service %q cannot depend on job %q: services can only depend on other services: %w", s.Name, dependedService, errdefs.ErrInvalid)
+ }
+ return fmt.Errorf("service %q depends on undefined service %q: %w", s.Name, dependedService, errdefs.ErrInvalid)
+ }
+ }
+
+ if strings.HasPrefix(s.NetworkMode, types.ServicePrefix) {
+ serviceName := s.NetworkMode[len(types.ServicePrefix):]
+ if _, err := project.GetServices(serviceName); err != nil {
+ return fmt.Errorf("service %q not found for network_mode 'service:%s'", serviceName, serviceName)
+ }
+ }
+
+ for _, volume := range s.Volumes {
+ if volume.Type == types.VolumeTypeVolume && volume.Source != "" { // non anonymous volumes
+ if _, ok := project.Volumes[volume.Source]; !ok {
+ return fmt.Errorf("service %q refers to undefined volume %s: %w", s.Name, volume.Source, errdefs.ErrInvalid)
+ }
+ }
+ }
+ if s.Build != nil {
+ for _, secret := range s.Build.Secrets {
+ if _, ok := project.Secrets[secret.Source]; !ok {
+ return fmt.Errorf("service %q refers to undefined build secret %s: %w", s.Name, secret.Source, errdefs.ErrInvalid)
+ }
+ }
+ }
+ for _, config := range s.Configs {
+ if _, ok := project.Configs[config.Source]; !ok {
+ return fmt.Errorf("service %q refers to undefined config %s: %w", s.Name, config.Source, errdefs.ErrInvalid)
+ }
+ }
+
+ for model := range s.Models {
+ if _, ok := project.Models[model]; !ok {
+ return fmt.Errorf("service %q refers to undefined model %s: %w", s.Name, model, errdefs.ErrInvalid)
+ }
+ }
+
+ for _, secret := range s.Secrets {
+ if _, ok := project.Secrets[secret.Source]; !ok {
+ return fmt.Errorf("service %q refers to undefined secret %s: %w", s.Name, secret.Source, errdefs.ErrInvalid)
+ }
+ }
+
+ if s.Scale != nil && s.Deploy != nil {
+ if s.Deploy.Replicas != nil && *s.Scale != *s.Deploy.Replicas {
+ return fmt.Errorf("services.%s: can't set distinct values on 'scale' and 'deploy.replicas': %w",
+ s.Name, errdefs.ErrInvalid)
+ }
+ s.Deploy.Replicas = s.Scale
+ }
+
+ if s.Scale != nil && *s.Scale < 0 {
+ return fmt.Errorf("services.%s.scale: must be greater than or equal to 0", s.Name)
+ }
+ if s.Deploy != nil && s.Deploy.Replicas != nil && *s.Deploy.Replicas < 0 {
+ return fmt.Errorf("services.%s.deploy.replicas: must be greater than or equal to 0", s.Name)
+ }
+
+ if s.CPUS != 0 && s.Deploy != nil {
+ if s.Deploy.Resources.Limits != nil && s.Deploy.Resources.Limits.NanoCPUs.Value() != s.CPUS {
+ return fmt.Errorf("services.%s: can't set distinct values on 'cpus' and 'deploy.resources.limits.cpus': %w",
+ s.Name, errdefs.ErrInvalid)
+ }
+ }
+ if s.MemLimit != 0 && s.Deploy != nil {
+ if s.Deploy.Resources.Limits != nil && s.Deploy.Resources.Limits.MemoryBytes != s.MemLimit {
+ return fmt.Errorf("services.%s: can't set distinct values on 'mem_limit' and 'deploy.resources.limits.memory': %w",
+ s.Name, errdefs.ErrInvalid)
+ }
+ }
+ if s.MemReservation != 0 && s.Deploy != nil {
+ if s.Deploy.Resources.Reservations != nil && s.Deploy.Resources.Reservations.MemoryBytes != s.MemReservation {
+ return fmt.Errorf("services.%s: can't set distinct values on 'mem_reservation' and 'deploy.resources.reservations.memory': %w",
+ s.Name, errdefs.ErrInvalid)
+ }
+ }
+ if s.PidsLimit != 0 && s.Deploy != nil {
+ if s.Deploy.Resources.Limits != nil && s.Deploy.Resources.Limits.Pids != s.PidsLimit {
+ return fmt.Errorf("services.%s: can't set distinct values on 'pids_limit' and 'deploy.resources.limits.pids': %w",
+ s.Name, errdefs.ErrInvalid)
+ }
+ }
+
+ if s.GetScale() > 1 && s.ContainerName != "" {
+ attr := "scale"
+ if s.Scale == nil {
+ attr = "deploy.replicas"
+ }
+ return fmt.Errorf("services.%s: can't set container_name and %s as container name must be unique: %w", attr,
+ s.Name, errdefs.ErrInvalid)
+ }
+
+ if s.Develop != nil && s.Develop.Watch != nil {
+ for _, watch := range s.Develop.Watch {
+ if watch.Target == "" && watch.Action != types.WatchActionRebuild && watch.Action != types.WatchActionRestart {
+ return fmt.Errorf("services.%s.develop.watch: target is required for non-rebuild actions: %w", s.Name, errdefs.ErrInvalid)
+ }
+ }
+ }
+
+ mounts := map[string]string{}
+ for i, tmpfs := range s.Tmpfs {
+ loc := fmt.Sprintf("services.%s.tmpfs[%d]", s.Name, i)
+ path, _, _ := strings.Cut(tmpfs, ":")
+ if p, ok := mounts[path]; ok {
+ return fmt.Errorf("%s: target %s already mounted as %s", loc, path, p)
+ }
+ mounts[path] = loc
+ }
+ for i, volume := range s.Volumes {
+ loc := fmt.Sprintf("services.%s.volumes[%d]", s.Name, i)
+ if p, ok := mounts[volume.Target]; ok {
+ return fmt.Errorf("%s: target %s already mounted as %s", loc, volume.Target, p)
+ }
+ mounts[volume.Target] = loc
+ }
+
+ }
+
+ // names must be unique across services and jobs so a name always
+ // resolves to exactly one of them (e.g. `docker compose run `),
+ // including profile-disabled ones which may be enabled later
+ for name := range project.AllJobs() {
+ if _, ok := project.Services[name]; ok {
+ return fmt.Errorf("%q is declared both as a service and a job: service and job names must be unique: %w", name, errdefs.ErrInvalid)
+ }
+ if _, ok := project.DisabledServices[name]; ok {
+ return fmt.Errorf("%q is declared both as a service and a job: service and job names must be unique: %w", name, errdefs.ErrInvalid)
+ }
+ }
+
+ for name, j := range project.Jobs {
+ // a job can depend on services and on other jobs
+ for depended, cfg := range j.DependsOn {
+ if _, isJob := project.Jobs[depended]; isJob {
+ continue
+ }
+ if _, err := project.GetService(depended); err != nil {
+ if errors.Is(err, errdefs.ErrDisabled) && !cfg.Required {
+ continue
+ }
+ return fmt.Errorf("job %q depends on undefined service or job %q: %w", name, depended, errdefs.ErrInvalid)
+ }
+ }
+ }
+
+ for name, secret := range project.Secrets {
+ if secret.External {
+ continue
+ }
+ if secret.File == "" && secret.Environment == "" {
+ return fmt.Errorf("secret %q must declare either `file` or `environment`: %w", name, errdefs.ErrInvalid)
+ }
+ }
+
+ return graph.CheckCycle(project)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/override/extends.go b/vendor/github.com/compose-spec/compose-go/v2/override/extends.go
new file mode 100644
index 0000000000..de92fd29e7
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/override/extends.go
@@ -0,0 +1,27 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package override
+
+import "github.com/compose-spec/compose-go/v2/tree"
+
+func ExtendService(base, override map[string]any) (map[string]any, error) {
+ yaml, err := MergeYaml(base, override, tree.NewPath("services.x"))
+ if err != nil {
+ return nil, err
+ }
+ return yaml.(map[string]any), nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/override/merge.go b/vendor/github.com/compose-spec/compose-go/v2/override/merge.go
new file mode 100644
index 0000000000..60806b3e8c
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/override/merge.go
@@ -0,0 +1,357 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package override
+
+import (
+ "cmp"
+ "fmt"
+ "reflect"
+ "slices"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// Merge applies overrides to a config model
+func Merge(right, left map[string]any) (map[string]any, error) {
+ merged, err := MergeYaml(right, left, tree.NewPath())
+ if err != nil {
+ return nil, err
+ }
+ return merged.(map[string]any), nil
+}
+
+type merger func(any, any, tree.Path) (any, error)
+
+// mergeSpecials defines the custom rules applied by compose when merging yaml trees
+var mergeSpecials = map[tree.Path]merger{}
+
+func init() {
+ mergeSpecials["networks.*.ipam.config"] = mergeIPAMConfig
+ mergeSpecials["networks.*.labels"] = mergeKeyValueSequence
+ mergeSpecials["volumes.*.labels"] = mergeKeyValueSequence
+ mergeSpecials["secrets.*.labels"] = mergeKeyValueSequence
+ mergeSpecials["configs.*.labels"] = mergeKeyValueSequence
+ for _, prefix := range []tree.Path{"services", "jobs"} {
+ mergeSpecials[prefix+".*.annotations"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.build"] = mergeBuild
+ mergeSpecials[prefix+".*.build.args"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.build.additional_contexts"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.build.extra_hosts"] = mergeToSequence
+ mergeSpecials[prefix+".*.build.labels"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.command"] = override
+ mergeSpecials[prefix+".*.depends_on"] = mergeDependsOn
+ mergeSpecials[prefix+".*.dns"] = mergeToSequence
+ mergeSpecials[prefix+".*.dns_opt"] = mergeToSequence
+ mergeSpecials[prefix+".*.dns_search"] = mergeToSequence
+ mergeSpecials[prefix+".*.entrypoint"] = override
+ mergeSpecials[prefix+".*.env_file"] = mergeToSequence
+ mergeSpecials[prefix+".*.label_file"] = mergeToSequence
+ mergeSpecials[prefix+".*.environment"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.extra_hosts"] = mergeToSequence
+ mergeSpecials[prefix+".*.healthcheck.test"] = override
+ mergeSpecials[prefix+".*.labels"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.volumes.*.volume.labels"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.logging"] = mergeLogging
+ mergeSpecials[prefix+".*.models"] = mergeModels
+ mergeSpecials[prefix+".*.networks"] = mergeNetworks
+ mergeSpecials[prefix+".*.sysctls"] = mergeKeyValueSequence
+ mergeSpecials[prefix+".*.tmpfs"] = mergeToSequence
+ mergeSpecials[prefix+".*.ulimits.*"] = mergeUlimit
+ }
+ mergeSpecials["services.*.deploy.labels"] = mergeKeyValueSequence
+}
+
+// MergeYaml merges map[string]any yaml trees handling special rules
+func MergeYaml(e any, o any, p tree.Path) (any, error) {
+ for pattern, merger := range mergeSpecials {
+ if p.Matches(pattern) {
+ merged, err := merger(e, o, p)
+ if err != nil {
+ return nil, err
+ }
+ return merged, nil
+ }
+ }
+ if o == nil {
+ return e, nil
+ }
+ switch value := e.(type) {
+ case map[string]any:
+ other, ok := o.(map[string]any)
+ if !ok {
+ return nil, fmt.Errorf("cannot override %s", p)
+ }
+ return mergeMappings(value, other, p)
+ case []any:
+ other, ok := o.([]any)
+ if !ok {
+ return nil, fmt.Errorf("cannot override %s", p)
+ }
+ return appendWithoutDuplicates(value, other), nil
+ default:
+ return o, nil
+ }
+}
+
+func mergeMappings(mapping map[string]any, other map[string]any, p tree.Path) (map[string]any, error) {
+ for k, v := range other {
+ e, ok := mapping[k]
+ if !ok {
+ mapping[k] = v
+ continue
+ }
+ next := p.Next(k)
+ merged, err := MergeYaml(e, v, next)
+ if err != nil {
+ return nil, err
+ }
+ mapping[k] = merged
+ }
+ return mapping, nil
+}
+
+// logging driver options are merged only when both compose file define the same driver
+func mergeLogging(config any, other any, p tree.Path) (any, error) {
+ base, ok := config.(map[string]any)
+ if !ok {
+ return nil, fmt.Errorf("%s: cannot merge logging: expected a mapping, got %T", p, config)
+ }
+ override, ok := other.(map[string]any)
+ if !ok {
+ return nil, fmt.Errorf("%s: cannot merge logging: expected a mapping, got %T", p, other)
+ }
+ // we override logging config if source and override have the same driver set, or none
+ d, ok1 := override["driver"]
+ baseDriver, ok2 := base["driver"]
+ if d == baseDriver || !ok1 || !ok2 {
+ return mergeMappings(base, override, p)
+ }
+ return override, nil
+}
+
+func mergeBuild(config any, other any, path tree.Path) (any, error) {
+ toBuild := func(c any) map[string]any {
+ switch v := c.(type) {
+ case string:
+ return map[string]any{
+ "context": v,
+ }
+ case map[string]any:
+ return v
+ }
+ return nil
+ }
+ return mergeMappings(toBuild(config), toBuild(other), path)
+}
+
+func mergeDependsOn(config any, other any, path tree.Path) (any, error) {
+ return mergeAsMapping(config, other, map[string]any{
+ "condition": "service_started",
+ "required": true,
+ }, path)
+}
+
+func mergeModels(config any, other any, path tree.Path) (any, error) {
+ return mergeAsMapping(config, other, nil, path)
+}
+
+func mergeNetworks(config any, other any, path tree.Path) (any, error) {
+ return mergeAsMapping(config, other, nil, path)
+}
+
+func mergeAsMapping(config, other any, defaults map[string]any, path tree.Path) (any, error) {
+ right, err := convertIntoMapping(nullAsEmpty(config), defaults, path)
+ if err != nil {
+ return nil, err
+ }
+ left, err := convertIntoMapping(nullAsEmpty(other), defaults, path)
+ if err != nil {
+ return nil, err
+ }
+ return mergeMappings(right, left, path)
+}
+
+func mergeToSequence(config any, other any, _ tree.Path) (any, error) {
+ right := convertIntoSequence(config)
+ left := convertIntoSequence(other)
+ return appendWithoutDuplicates(right, left), nil
+}
+
+// appendWithoutDuplicates appends override entries to the base sequence,
+// ignoring entries strictly identical (deep equality) to one already
+// present. Two identical entries never carry more meaning than one, while
+// they routinely break things — the same env_file applied twice, a
+// duplicate mount rejected by the engine — and dropping them makes merging
+// a value over an already-merged result idempotent. Entries that differ in
+// form (short vs long syntax of the same thing) are not equal and are kept:
+// the rule is strict identity, not equivalence.
+func appendWithoutDuplicates(base []any, override []any) []any {
+ merged := base
+ for _, v := range override {
+ if !slices.ContainsFunc(merged, func(existing any) bool { return reflect.DeepEqual(existing, v) }) {
+ merged = append(merged, v)
+ }
+ }
+ return merged
+}
+
+// mergeKeyValueSequence merges KEY=VALUE lists by key: an override entry
+// replaces the base entry of the same key in place, new keys are appended. The
+// last entry for a key takes effect, so an override repeating a base entry
+// after another value for the same key (`[MODE=debug, MODE=release]` over
+// `[MODE=release]`) must end on the repeated one, not drop it as a duplicate.
+// Keys repeated in the base collapse the same way, so that the override never
+// leaves two identical entries behind.
+func mergeKeyValueSequence(config any, other any, path tree.Path) (any, error) {
+ return uniqueEntries(slices.Concat(convertIntoSequence(config), convertIntoSequence(other)), keyValueIndexer, path)
+}
+
+func convertIntoSequence(value any) []any {
+ switch v := value.(type) {
+ case map[string]any:
+ var seq []any
+ for k, val := range v {
+ if val == nil {
+ seq = append(seq, k)
+ } else {
+ switch vl := val.(type) {
+ // if val is an array we need to add the key with each value one by one
+ case []any:
+ for _, vlv := range vl {
+ seq = append(seq, fmt.Sprintf("%s=%v", k, vlv))
+ }
+ default:
+ seq = append(seq, fmt.Sprintf("%s=%v", k, val))
+ }
+ }
+ }
+ slices.SortFunc(seq, func(a, b any) int {
+ return cmp.Compare(a.(string), b.(string))
+ })
+ return seq
+ case []any:
+ return v
+ case string:
+ return []any{v}
+ }
+ return nil
+}
+
+func mergeUlimit(config any, other any, path tree.Path) (any, error) {
+ over, ismapping := other.(map[string]any)
+ if base, ok := config.(map[string]any); ok && ismapping {
+ return mergeMappings(base, over, path)
+ }
+ return other, nil
+}
+
+func mergeIPAMConfig(config any, other any, path tree.Path) (any, error) {
+ var ipamConfigs []any
+ configs, ok := config.([]any)
+ if !ok {
+ return other, fmt.Errorf("%s: unexpected type %T", path, config)
+ }
+ overrides, ok := other.([]any)
+ if !ok {
+ return other, fmt.Errorf("%s: unexpected type %T", path, other)
+ }
+ for _, original := range configs {
+ right, err := convertIntoMapping(original, nil, path)
+ if err != nil {
+ return nil, err
+ }
+ for _, override := range overrides {
+ left, err := convertIntoMapping(override, nil, path)
+ if err != nil {
+ return nil, err
+ }
+ if left["subnet"] != right["subnet"] {
+ // check if left is already in ipamConfigs, add it if not and continue with the next config
+ if !slices.ContainsFunc(ipamConfigs, func(a any) bool {
+ return a.(map[string]any)["subnet"] == left["subnet"]
+ }) {
+ ipamConfigs = append(ipamConfigs, left)
+ continue
+ }
+ }
+ merged, err := mergeMappings(right, left, path)
+ if err != nil {
+ return nil, err
+ }
+ // find index of potential previous config with the same subnet in ipamConfigs
+ indexIfExist := slices.IndexFunc(ipamConfigs, func(a any) bool {
+ return a.(map[string]any)["subnet"] == merged["subnet"]
+ })
+ // if a previous config is already in ipamConfigs, replace it
+ if indexIfExist >= 0 {
+ ipamConfigs[indexIfExist] = merged
+ } else {
+ // or add the new config to ipamConfigs
+ ipamConfigs = append(ipamConfigs, merged)
+ }
+ }
+ }
+ return ipamConfigs, nil
+}
+
+// nullAsEmpty reads a null value as an empty mapping. An empty one rather than
+// nil, as merging into a nil map panics.
+func nullAsEmpty(value any) any {
+ if value == nil {
+ return map[string]any{}
+ }
+ return value
+}
+
+func convertIntoMapping(a any, defaultValue map[string]any, path tree.Path) (map[string]any, error) {
+ switch v := a.(type) {
+ case map[string]any:
+ return v, nil
+ case string:
+ if defaultValue == nil {
+ return map[string]any{v: nil}, nil
+ }
+ return map[string]any{v: copyMap(defaultValue)}, nil
+ case []any:
+ converted := map[string]any{}
+ for _, s := range v {
+ key, ok := s.(string)
+ if !ok {
+ return nil, fmt.Errorf("%s: cannot use %T as a mapping key", path, s)
+ }
+ if defaultValue == nil {
+ converted[key] = nil
+ } else {
+ converted[key] = copyMap(defaultValue)
+ }
+ }
+ return converted, nil
+ }
+ return nil, fmt.Errorf("%s: cannot convert %T into a mapping", path, a)
+}
+
+func copyMap(m map[string]any) map[string]any {
+ c := make(map[string]any, len(m))
+ for k, v := range m {
+ c[k] = v
+ }
+ return c
+}
+
+func override(_ any, other any, _ tree.Path) (any, error) {
+ return other, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/override/uncity.go b/vendor/github.com/compose-spec/compose-go/v2/override/uncity.go
new file mode 100644
index 0000000000..b71c9e95da
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/override/uncity.go
@@ -0,0 +1,235 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package override
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/format"
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+type indexer func(any, tree.Path) (string, error)
+
+// mergeSpecials defines the custom rules applied by compose when merging yaml trees
+var unique = map[tree.Path]indexer{}
+
+func init() {
+ unique["networks.*.labels"] = keyValueIndexer
+ unique["networks.*.ipam.options"] = keyValueIndexer
+ unique["services.*.annotations"] = keyValueIndexer
+ unique["services.*.build.args"] = keyValueIndexer
+ unique["services.*.build.additional_contexts"] = keyValueIndexer
+ unique["services.*.build.platform"] = keyValueIndexer
+ unique["services.*.build.tags"] = keyValueIndexer
+ unique["services.*.build.labels"] = keyValueIndexer
+ unique["services.*.cap_add"] = keyValueIndexer
+ unique["services.*.cap_drop"] = keyValueIndexer
+ unique["services.*.devices"] = volumeIndexer
+ unique["services.*.configs"] = mountIndexer("")
+ unique["services.*.deploy.labels"] = keyValueIndexer
+ unique["services.*.dns"] = keyValueIndexer
+ unique["services.*.dns_opt"] = keyValueIndexer
+ unique["services.*.dns_search"] = keyValueIndexer
+ unique["services.*.environment"] = keyValueIndexer
+ unique["services.*.env_file"] = envFileIndexer
+ unique["services.*.expose"] = exposeIndexer
+ unique["services.*.labels"] = keyValueIndexer
+ unique["services.*.links"] = keyValueIndexer
+ unique["services.*.networks.*.aliases"] = keyValueIndexer
+ unique["services.*.networks.*.link_local_ips"] = keyValueIndexer
+ unique["services.*.ports"] = portIndexer
+ unique["services.*.profiles"] = keyValueIndexer
+ unique["services.*.secrets"] = mountIndexer("/run/secrets")
+ unique["services.*.sysctls"] = keyValueIndexer
+ unique["services.*.tmpfs"] = keyValueIndexer
+ unique["services.*.volumes"] = volumeIndexer
+ unique["services.*.devices"] = deviceMappingIndexer
+}
+
+// EnforceUnicity removes redefinition of elements declared in a sequence
+func EnforceUnicity(value map[string]any) (map[string]any, error) {
+ uniq, err := enforceUnicity(value, tree.NewPath())
+ if err != nil {
+ return nil, err
+ }
+ return uniq.(map[string]any), nil
+}
+
+func enforceUnicity(value any, p tree.Path) (any, error) {
+ switch v := value.(type) {
+ case map[string]any:
+ for k, e := range v {
+ u, err := enforceUnicity(e, p.Next(k))
+ if err != nil {
+ return nil, err
+ }
+ v[k] = u
+ }
+ return v, nil
+ case []any:
+ for pattern, indexer := range unique {
+ if p.Matches(pattern) {
+ return uniqueEntries(v, indexer, p)
+ }
+ }
+ }
+ return value, nil
+}
+
+// uniqueEntries keeps one entry per key: the last entry for a key takes effect,
+// at the position of the first one.
+func uniqueEntries(entries []any, indexer indexer, p tree.Path) ([]any, error) {
+ seq := []any{}
+ keys := map[string]int{}
+ for i, entry := range entries {
+ key, err := indexer(entry, p.Next(fmt.Sprintf("[%d]", i)))
+ if err != nil {
+ return nil, err
+ }
+ if j, ok := keys[key]; ok {
+ seq[j] = entry
+ } else {
+ seq = append(seq, entry)
+ keys[key] = len(seq) - 1
+ }
+ }
+ return seq, nil
+}
+
+func keyValueIndexer(v any, p tree.Path) (string, error) {
+ switch value := v.(type) {
+ case string:
+ key, _, found := strings.Cut(value, "=")
+ if found {
+ return key, nil
+ }
+ return value, nil
+ default:
+ return "", fmt.Errorf("%s: unexpected type %T", p, v)
+ }
+}
+
+func volumeIndexer(y any, p tree.Path) (string, error) {
+ switch value := y.(type) {
+ case map[string]any:
+ target, ok := value["target"].(string)
+ if !ok {
+ return "", fmt.Errorf("service volume %s is missing a mount target", p)
+ }
+ return target, nil
+ case string:
+ volume, err := format.ParseVolume(value)
+ if err != nil {
+ return "", err
+ }
+ return volume.Target, nil
+ }
+ return "", nil
+}
+
+func deviceMappingIndexer(y any, p tree.Path) (string, error) {
+ switch value := y.(type) {
+ case map[string]any:
+ target, ok := value["target"].(string)
+ if !ok {
+ return "", fmt.Errorf("service device %s is missing a mount target", p)
+ }
+ return target, nil
+ case string:
+ arr := strings.Split(value, ":")
+ if len(arr) == 1 {
+ return arr[0], nil
+ }
+ return arr[1], nil
+ }
+ return "", nil
+}
+
+func exposeIndexer(a any, path tree.Path) (string, error) {
+ switch v := a.(type) {
+ case string:
+ return v, nil
+ case int:
+ return strconv.Itoa(v), nil
+ default:
+ return "", fmt.Errorf("%s: unsupported expose value %s", path, a)
+ }
+}
+
+func mountIndexer(defaultPath string) indexer {
+ return func(a any, path tree.Path) (string, error) {
+ switch v := a.(type) {
+ case string:
+ return fmt.Sprintf("%s/%s", defaultPath, v), nil
+ case map[string]any:
+ t, ok := v["target"]
+ if ok {
+ return t.(string), nil
+ }
+ return fmt.Sprintf("%s/%s", defaultPath, v["source"]), nil
+ default:
+ return "", fmt.Errorf("%s: unsupported expose value %s", path, a)
+ }
+ }
+}
+
+func portIndexer(y any, p tree.Path) (string, error) {
+ switch value := y.(type) {
+ case int:
+ return strconv.Itoa(value), nil
+ case map[string]any:
+ target, ok := value["target"]
+ if !ok {
+ return "", fmt.Errorf("service ports %s is missing a target port", p)
+ }
+ published, ok := value["published"]
+ if !ok {
+ // try to parse it as an int
+ if pub, ok := value["published"]; ok {
+ published = fmt.Sprintf("%d", pub)
+ }
+ }
+ host, ok := value["host_ip"]
+ if !ok {
+ host = "0.0.0.0"
+ }
+ protocol, ok := value["protocol"]
+ if !ok {
+ protocol = "tcp"
+ }
+ return fmt.Sprintf("%s:%s:%d/%s", host, published, target, protocol), nil
+ case string:
+ return value, nil
+ }
+ return "", nil
+}
+
+func envFileIndexer(y any, p tree.Path) (string, error) {
+ switch value := y.(type) {
+ case string:
+ return value, nil
+ case map[string]any:
+ if pathValue, ok := value["path"]; ok {
+ return pathValue.(string), nil
+ }
+ return "", fmt.Errorf("environment path attribute %s is missing", p)
+ }
+ return "", nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/paths/context.go b/vendor/github.com/compose-spec/compose-go/v2/paths/context.go
new file mode 100644
index 0000000000..ceab7d6787
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/paths/context.go
@@ -0,0 +1,51 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package paths
+
+import (
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+func (r *relativePathsResolver) absContextPath(value any) (any, error) {
+ v := value.(string)
+ if strings.Contains(v, "://") { // `docker-image://` or any builder specific context type
+ return v, nil
+ }
+ if strings.HasPrefix(v, types.ServicePrefix) { // `docker-image://` or any builder specific context type
+ return v, nil
+ }
+ if isRemoteContext(v) {
+ return v, nil
+ }
+ return r.absPath(v)
+}
+
+// isRemoteContext returns true if the value is a Git reference or HTTP(S) URL.
+//
+// Any other value is assumed to be a local filesystem path and returns false.
+//
+// See: https://github.com/moby/buildkit/blob/18fc875d9bfd6e065cd8211abc639434ba65aa56/frontend/dockerui/context.go#L76-L79
+func isRemoteContext(maybeURL string) bool {
+ for _, prefix := range []string{"https://", "http://", "git://", "ssh://", "github.com/", "git@"} {
+ if strings.HasPrefix(maybeURL, prefix) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/paths/extends.go b/vendor/github.com/compose-spec/compose-go/v2/paths/extends.go
new file mode 100644
index 0000000000..aa61a9f9aa
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/paths/extends.go
@@ -0,0 +1,25 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package paths
+
+func (r *relativePathsResolver) absExtendsPath(value any) (any, error) {
+ v := value.(string)
+ if r.isRemoteResource(v) {
+ return v, nil
+ }
+ return r.absPath(v)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/paths/home.go b/vendor/github.com/compose-spec/compose-go/v2/paths/home.go
new file mode 100644
index 0000000000..a5579262be
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/paths/home.go
@@ -0,0 +1,37 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package paths
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/sirupsen/logrus"
+)
+
+func ExpandUser(p string) string {
+ if strings.HasPrefix(p, "~") {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ logrus.Warn("cannot expand '~', because the environment lacks HOME")
+ return p
+ }
+ return filepath.Join(home, p[1:])
+ }
+ return p
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/paths/resolve.go b/vendor/github.com/compose-spec/compose-go/v2/paths/resolve.go
new file mode 100644
index 0000000000..34a198001e
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/paths/resolve.go
@@ -0,0 +1,180 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package paths
+
+import (
+ "errors"
+ "fmt"
+ "path/filepath"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+ "github.com/compose-spec/compose-go/v2/types"
+)
+
+type resolver func(any) (any, error)
+
+// ResolveRelativePaths make relative paths absolute
+func ResolveRelativePaths(project map[string]any, base string, remotes []RemoteResource) error {
+ r := relativePathsResolver{
+ workingDir: base,
+ remotes: remotes,
+ }
+ r.resolvers = map[tree.Path]resolver{
+ "services.*.build.context": r.absContextPath,
+ "services.*.build.additional_contexts.*": r.absContextPath,
+ "services.*.build.ssh.*": r.maybeUnixPath,
+ "services.*.env_file.*.path": r.absPath,
+ "services.*.label_file.*": r.absPath,
+ "services.*.extends.file": r.absExtendsPath,
+ "services.*.develop.watch.*.path": r.absSymbolicLink,
+ "services.*.volumes.*": r.absVolumeMount,
+ "jobs.*.build.context": r.absContextPath,
+ "jobs.*.build.additional_contexts.*": r.absContextPath,
+ "jobs.*.build.ssh.*": r.maybeUnixPath,
+ "jobs.*.env_file.*.path": r.absPath,
+ "jobs.*.label_file.*": r.absPath,
+ "jobs.*.extends.file": r.absExtendsPath,
+ "jobs.*.volumes.*": r.absVolumeMount,
+ // pre_start hooks are full container specifications (compose-spec#656)
+ "services.*.pre_start.*.env_file.*.path": r.absPath,
+ "services.*.pre_start.*.label_file.*": r.absPath,
+ "services.*.pre_start.*.volumes.*": r.absVolumeMount,
+ "configs.*.file": r.maybeUnixPath,
+ "secrets.*.file": r.maybeUnixPath,
+ "include.path": r.absPath,
+ "include.project_directory": r.absPath,
+ "include.env_file": r.absPath,
+ "volumes.*": r.volumeDriverOpts,
+ }
+ _, err := r.resolveRelativePaths(project, tree.NewPath())
+ return err
+}
+
+type RemoteResource func(path string) bool
+
+type relativePathsResolver struct {
+ workingDir string
+ remotes []RemoteResource
+ resolvers map[tree.Path]resolver
+}
+
+func (r *relativePathsResolver) isRemoteResource(path string) bool {
+ for _, remote := range r.remotes {
+ if remote(path) {
+ return true
+ }
+ }
+ return false
+}
+
+func (r *relativePathsResolver) resolveRelativePaths(value any, p tree.Path) (any, error) {
+ for pattern, resolver := range r.resolvers {
+ if p.Matches(pattern) {
+ return resolver(value)
+ }
+ }
+ switch v := value.(type) {
+ case map[string]any:
+ for k, e := range v {
+ resolved, err := r.resolveRelativePaths(e, p.Next(k))
+ if err != nil {
+ return nil, err
+ }
+ v[k] = resolved
+ }
+ case []any:
+ for i, e := range v {
+ resolved, err := r.resolveRelativePaths(e, p.Next("[]"))
+ if err != nil {
+ return nil, err
+ }
+ v[i] = resolved
+ }
+ }
+ return value, nil
+}
+
+func (r *relativePathsResolver) absPath(value any) (any, error) {
+ switch v := value.(type) {
+ case []any:
+ for i, s := range v {
+ abs, err := r.absPath(s)
+ if err != nil {
+ return nil, err
+ }
+ v[i] = abs
+ }
+ return v, nil
+ case string:
+ v = ExpandUser(v)
+ if filepath.IsAbs(v) {
+ return v, nil
+ }
+ if v != "" {
+ return filepath.Join(r.workingDir, v), nil
+ }
+ return v, nil
+ }
+
+ return nil, fmt.Errorf("unexpected type %T", value)
+}
+
+func (r *relativePathsResolver) absVolumeMount(a any) (any, error) {
+ switch vol := a.(type) {
+ case map[string]any:
+ if vol["type"] != types.VolumeTypeBind {
+ return vol, nil
+ }
+ src, ok := vol["source"]
+ if !ok {
+ return nil, errors.New(`invalid mount config for type "bind": field Source must not be empty`)
+ }
+ abs, err := r.maybeUnixPath(src.(string))
+ if err != nil {
+ return nil, err
+ }
+ vol["source"] = abs
+ return vol, nil
+ default:
+ // not using canonical format, skip
+ return a, nil
+ }
+}
+
+func (r *relativePathsResolver) volumeDriverOpts(a any) (any, error) {
+ if a == nil {
+ return nil, nil
+ }
+ vol := a.(map[string]any)
+ if vol["driver"] != "local" {
+ return vol, nil
+ }
+ do, ok := vol["driver_opts"]
+ if !ok {
+ return vol, nil
+ }
+ opts := do.(map[string]any)
+ if dev, ok := opts["device"]; opts["o"] == "bind" && ok {
+ // This is actually a bind mount
+ path, err := r.maybeUnixPath(dev)
+ if err != nil {
+ return nil, err
+ }
+ opts["device"] = path
+ }
+ return vol, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/paths/unix.go b/vendor/github.com/compose-spec/compose-go/v2/paths/unix.go
new file mode 100644
index 0000000000..ccfe9fae8d
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/paths/unix.go
@@ -0,0 +1,57 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package paths
+
+import (
+ "path"
+ "path/filepath"
+
+ "github.com/compose-spec/compose-go/v2/utils"
+)
+
+func (r *relativePathsResolver) maybeUnixPath(a any) (any, error) {
+ p, ok := a.(string)
+ if !ok {
+ return a, nil
+ }
+ p = ExpandUser(p)
+ // Check if source is an absolute path (either Unix or Windows), to
+ // handle a Windows client with a Unix daemon or vice-versa.
+ //
+ // Note that this is not required for Docker for Windows when specifying
+ // a local Windows path, because Docker for Windows translates the Windows
+ // path into a valid path within the VM.
+ if !path.IsAbs(p) && !IsWindowsAbs(p) {
+ if filepath.IsAbs(p) {
+ return p, nil
+ }
+ return filepath.Join(r.workingDir, p), nil
+ }
+ return p, nil
+}
+
+func (r *relativePathsResolver) absSymbolicLink(value any) (any, error) {
+ abs, err := r.absPath(value)
+ if err != nil {
+ return nil, err
+ }
+ str, ok := abs.(string)
+ if !ok {
+ return abs, nil
+ }
+ return utils.ResolveSymbolicLink(str)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/paths/windows_path.go b/vendor/github.com/compose-spec/compose-go/v2/paths/windows_path.go
new file mode 100644
index 0000000000..c296f5996e
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/paths/windows_path.go
@@ -0,0 +1,233 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package paths
+
+// This file contains utilities to check for Windows absolute paths on Linux.
+// The code in this file was largely copied from the Golang filepath package
+// https://github.com/golang/go/blob/master/src/internal/filepathlite/path_windows.go
+
+import "slices"
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// https://github.com/golang/go/blob/master/LICENSE
+
+func IsPathSeparator(c uint8) bool {
+ return c == '\\' || c == '/'
+}
+
+// IsWindowsAbs reports whether the path is absolute.
+// copied from IsAbs(path string) (b bool) from internal.filetpathlite
+func IsWindowsAbs(path string) (b bool) {
+ l := volumeNameLen(path)
+ if l == 0 {
+ return false
+ }
+ // If the volume name starts with a double slash, this is an absolute path.
+ if IsPathSeparator(path[0]) && IsPathSeparator(path[1]) {
+ return true
+ }
+ path = path[l:]
+ if path == "" {
+ return false
+ }
+ return IsPathSeparator(path[0])
+}
+
+// volumeNameLen returns length of the leading volume name on Windows.
+// It returns 0 elsewhere.
+//
+// See:
+// https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
+// https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
+func volumeNameLen(path string) int {
+ switch {
+ case len(path) >= 2 && path[1] == ':':
+ // Path starts with a drive letter.
+ //
+ // Not all Windows functions necessarily enforce the requirement that
+ // drive letters be in the set A-Z, and we don't try to here.
+ //
+ // We don't handle the case of a path starting with a non-ASCII character,
+ // in which case the "drive letter" might be multiple bytes long.
+ return 2
+
+ case len(path) == 0 || !IsPathSeparator(path[0]):
+ // Path does not have a volume component.
+ return 0
+
+ case pathHasPrefixFold(path, `\\.\UNC`):
+ // We're going to treat the UNC host and share as part of the volume
+ // prefix for historical reasons, but this isn't really principled;
+ // Windows's own GetFullPathName will happily remove the first
+ // component of the path in this space, converting
+ // \\.\unc\a\b\..\c into \\.\unc\a\c.
+ return uncLen(path, len(`\\.\UNC\`))
+
+ case pathHasPrefixFold(path, `\\.`) ||
+ pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`):
+ // Path starts with \\.\, and is a Local Device path; or
+ // path starts with \\?\ or \??\ and is a Root Local Device path.
+ //
+ // We treat the next component after the \\.\ prefix as
+ // part of the volume name, which means Clean(`\\?\c:\`)
+ // won't remove the trailing \. (See #64028.)
+ if len(path) == 3 {
+ return 3 // exactly \\.
+ }
+ _, rest, ok := cutPath(path[4:])
+ if !ok {
+ return len(path)
+ }
+ return len(path) - len(rest) - 1
+
+ case len(path) >= 2 && IsPathSeparator(path[1]):
+ // Path starts with \\, and is a UNC path.
+ return uncLen(path, 2)
+ }
+ return 0
+}
+
+// pathHasPrefixFold tests whether the path s begins with prefix,
+// ignoring case and treating all path separators as equivalent.
+// If s is longer than prefix, then s[len(prefix)] must be a path separator.
+func pathHasPrefixFold(s, prefix string) bool {
+ if len(s) < len(prefix) {
+ return false
+ }
+ for i := 0; i < len(prefix); i++ {
+ if IsPathSeparator(prefix[i]) {
+ if !IsPathSeparator(s[i]) {
+ return false
+ }
+ } else if toUpper(prefix[i]) != toUpper(s[i]) {
+ return false
+ }
+ }
+ if len(s) > len(prefix) && !IsPathSeparator(s[len(prefix)]) {
+ return false
+ }
+ return true
+}
+
+// uncLen returns the length of the volume prefix of a UNC path.
+// prefixLen is the prefix prior to the start of the UNC host;
+// for example, for "//host/share", the prefixLen is len("//")==2.
+func uncLen(path string, prefixLen int) int {
+ count := 0
+ for i := prefixLen; i < len(path); i++ {
+ if IsPathSeparator(path[i]) {
+ count++
+ if count == 2 {
+ return i
+ }
+ }
+ }
+ return len(path)
+}
+
+// cutPath slices path around the first path separator.
+func cutPath(path string) (before, after string, found bool) {
+ for i := range path {
+ if IsPathSeparator(path[i]) {
+ return path[:i], path[i+1:], true
+ }
+ }
+ return path, "", false
+}
+
+// postClean adjusts the results of Clean to avoid turning a relative path
+// into an absolute or rooted one.
+func postClean(out *lazybuf) {
+ if out.volLen != 0 || out.buf == nil {
+ return
+ }
+ // If a ':' appears in the path element at the start of a path,
+ // insert a .\ at the beginning to avoid converting relative paths
+ // like a/../c: into c:.
+ for _, c := range out.buf {
+ if IsPathSeparator(c) {
+ break
+ }
+ if c == ':' {
+ out.prepend('.', Separator)
+ return
+ }
+ }
+ // If a path begins with \??\, insert a \. at the beginning
+ // to avoid converting paths like \a\..\??\c:\x into \??\c:\x
+ // (equivalent to c:\x).
+ if len(out.buf) >= 3 && IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' {
+ out.prepend(Separator, '.')
+ }
+}
+
+func toUpper(c byte) byte {
+ if 'a' <= c && c <= 'z' {
+ return c - ('a' - 'A')
+ }
+ return c
+}
+
+const (
+ Separator = '\\' // OS-specific path separator
+)
+
+// A lazybuf is a lazily constructed path buffer.
+// It supports append, reading previously appended bytes,
+// and retrieving the final string. It does not allocate a buffer
+// to hold the output until that output diverges from s.
+type lazybuf struct {
+ path string
+ buf []byte
+ w int
+ volAndPath string
+ volLen int
+}
+
+func (b *lazybuf) index(i int) byte {
+ if b.buf != nil {
+ return b.buf[i]
+ }
+ return b.path[i]
+}
+
+func (b *lazybuf) append(c byte) {
+ if b.buf == nil {
+ if b.w < len(b.path) && b.path[b.w] == c {
+ b.w++
+ return
+ }
+ b.buf = make([]byte, len(b.path))
+ copy(b.buf, b.path[:b.w])
+ }
+ b.buf[b.w] = c
+ b.w++
+}
+
+func (b *lazybuf) prepend(prefix ...byte) {
+ b.buf = slices.Insert(b.buf, 0, prefix...)
+ b.w += len(prefix)
+}
+
+func (b *lazybuf) string() string {
+ if b.buf == nil {
+ return b.volAndPath[:b.volLen+b.w]
+ }
+ return b.volAndPath[:b.volLen] + string(b.buf[:b.w])
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/schema/compose-spec.json b/vendor/github.com/compose-spec/compose-go/v2/schema/compose-spec.json
new file mode 100644
index 0000000000..e4e473bbca
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/schema/compose-spec.json
@@ -0,0 +1,2647 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "compose_spec.json",
+ "type": "object",
+ "title": "Compose Specification",
+ "description": "The Compose file is a YAML file defining a multi-containers based application.",
+ "properties": {
+ "version": {
+ "type": "string",
+ "deprecated": true,
+ "description": "declared for backward compatibility, ignored. Please remove it."
+ },
+ "name": {
+ "type": "string",
+ "description": "define the Compose project name, until user defines one explicitly."
+ },
+ "include": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/include"
+ },
+ "description": "compose sub-projects to be included."
+ },
+ "services": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/$defs/service"
+ }
+ },
+ "additionalProperties": false,
+ "description": "The services that will be used by your application."
+ },
+ "models": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/$defs/model"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Language models that will be used by your application."
+ },
+ "networks": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/$defs/network"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Networks that are shared among multiple services."
+ },
+ "volumes": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/$defs/volume"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Named volumes that are shared among multiple services."
+ },
+ "secrets": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/$defs/secret"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Secrets that are shared among multiple services."
+ },
+ "configs": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/$defs/config"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Configurations that are shared among multiple services."
+ },
+ "jobs": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/$defs/job"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Jobs are containers that run to completion."
+ }
+ },
+ "patternProperties": {
+ "^x-": {}
+ },
+ "additionalProperties": false,
+ "$defs": {
+ "container_spec": {
+ "type": "object",
+ "description": "Attributes of a container specification shared by anything that runs a container: services, jobs, and run-to-completion init containers (pre_start hooks).",
+ "properties": {
+ "annotations": {
+ "$ref": "#/$defs/list_or_dict"
+ },
+ "blkio_config": {
+ "type": "object",
+ "description": "Block IO configuration for the service.",
+ "properties": {
+ "device_read_bps": {
+ "type": "array",
+ "description": "Limit read rate (bytes per second) from a device.",
+ "items": {
+ "$ref": "#/$defs/blkio_limit"
+ }
+ },
+ "device_read_iops": {
+ "type": "array",
+ "description": "Limit read rate (IO per second) from a device.",
+ "items": {
+ "$ref": "#/$defs/blkio_limit"
+ }
+ },
+ "device_write_bps": {
+ "type": "array",
+ "description": "Limit write rate (bytes per second) to a device.",
+ "items": {
+ "$ref": "#/$defs/blkio_limit"
+ }
+ },
+ "device_write_iops": {
+ "type": "array",
+ "description": "Limit write rate (IO per second) to a device.",
+ "items": {
+ "$ref": "#/$defs/blkio_limit"
+ }
+ },
+ "weight": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Block IO weight (relative weight) for the service, between 10 and 1000."
+ },
+ "weight_device": {
+ "type": "array",
+ "description": "Block IO weight (relative weight) for specific devices.",
+ "items": {
+ "$ref": "#/$defs/blkio_weight"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "cap_add": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "description": "Add Linux capabilities. For example, 'CAP_SYS_ADMIN', 'SYS_ADMIN', or 'NET_ADMIN'."
+ },
+ "cap_drop": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "description": "Drop Linux capabilities. For example, 'CAP_SYS_ADMIN', 'SYS_ADMIN', or 'NET_ADMIN'."
+ },
+ "cgroup": {
+ "type": "string",
+ "enum": [
+ "host",
+ "private"
+ ],
+ "description": "Specify the cgroup namespace to join. Use 'host' to use the host's cgroup namespace, or 'private' to use a private cgroup namespace."
+ },
+ "cgroup_parent": {
+ "type": "string",
+ "description": "Specify an optional parent cgroup for the container."
+ },
+ "command": {
+ "$ref": "#/$defs/command",
+ "description": "Override the default command declared by the container image, for example 'CMD' in Dockerfile."
+ },
+ "configs": {
+ "$ref": "#/$defs/service_config_or_secret",
+ "description": "Grant access to Configs on a per-service basis."
+ },
+ "cpu_count": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "integer",
+ "minimum": 0
+ }
+ ],
+ "description": "Number of usable CPUs."
+ },
+ "cpu_percent": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 100
+ }
+ ],
+ "description": "Percentage of CPU resources to use."
+ },
+ "cpu_shares": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "CPU shares (relative weight) for the container."
+ },
+ "cpu_quota": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Limit the CPU CFS (Completely Fair Scheduler) quota."
+ },
+ "cpu_period": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Limit the CPU CFS (Completely Fair Scheduler) period."
+ },
+ "cpu_rt_period": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Limit the CPU real-time period in microseconds or a duration."
+ },
+ "cpu_rt_runtime": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Limit the CPU real-time runtime in microseconds or a duration."
+ },
+ "cpus": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Number of CPUs to use. A floating-point value is supported to request partial CPUs."
+ },
+ "cpuset": {
+ "type": "string",
+ "description": "CPUs in which to allow execution (0-3, 0,1)."
+ },
+ "credential_spec": {
+ "type": "object",
+ "description": "Configure the credential spec for managed service account.",
+ "properties": {
+ "config": {
+ "type": "string",
+ "description": "The name of the credential spec Config to use."
+ },
+ "file": {
+ "type": "string",
+ "description": "Path to a credential spec file."
+ },
+ "registry": {
+ "type": "string",
+ "description": "Path to a credential spec in the Windows registry."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "device_cgroup_rules": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "Add rules to the cgroup allowed devices list."
+ },
+ "devices": {
+ "type": "array",
+ "description": "List of device mappings for the container.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "required": [
+ "source"
+ ],
+ "properties": {
+ "source": {
+ "type": "string",
+ "description": "Path on the host to the device."
+ },
+ "target": {
+ "type": "string",
+ "description": "Path in the container where the device will be mapped."
+ },
+ "permissions": {
+ "type": "string",
+ "description": "Cgroup permissions for the device (rwm)."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ ]
+ }
+ },
+ "dns": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Custom DNS servers to set for the service container."
+ },
+ "dns_opt": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "description": "Custom DNS options to be passed to the container's DNS resolver."
+ },
+ "dns_search": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Custom DNS search domains to set on the service container."
+ },
+ "domainname": {
+ "type": "string",
+ "description": "Custom domain name to use for the service container."
+ },
+ "entrypoint": {
+ "$ref": "#/$defs/command",
+ "description": "Override the default entrypoint declared by the container image, for example 'ENTRYPOINT' in Dockerfile."
+ },
+ "env_file": {
+ "$ref": "#/$defs/env_file",
+ "description": "Add environment variables from a file or multiple files. Can be a single file path or a list of file paths."
+ },
+ "label_file": {
+ "$ref": "#/$defs/label_file",
+ "description": "Add metadata to containers using files containing Docker labels."
+ },
+ "environment": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Add environment variables. You can use either an array or a list of KEY=VAL pairs."
+ },
+ "extra_hosts": {
+ "$ref": "#/$defs/extra_hosts",
+ "description": "Add hostname mappings to the container network interface configuration."
+ },
+ "gpus": {
+ "$ref": "#/$defs/gpus",
+ "description": "Define GPU devices to use. Can be set to 'all' to use all GPUs, or a list of specific GPU devices."
+ },
+ "group_add": {
+ "type": "array",
+ "items": {
+ "type": [
+ "string",
+ "number"
+ ]
+ },
+ "uniqueItems": true,
+ "description": "Add additional groups which user inside the container should be member of."
+ },
+ "hostname": {
+ "type": "string",
+ "description": "Define a custom hostname for the service container."
+ },
+ "image": {
+ "type": "string",
+ "description": "Specify the image to start the container from. Can be a repository/tag, a digest, or a local image ID."
+ },
+ "init": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Run as an init process inside the container that forwards signals and reaps processes."
+ },
+ "ipc": {
+ "type": "string",
+ "description": "IPC sharing mode for the service container. Use 'host' to share the host's IPC namespace, 'service:[service_name]' to share with another service, or 'shareable' to allow other services to share this service's IPC namespace."
+ },
+ "isolation": {
+ "type": "string",
+ "description": "Container isolation technology to use. Supported values are platform-specific."
+ },
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Add metadata to containers using Docker labels. You can use either an array or a list."
+ },
+ "logging": {
+ "type": "object",
+ "description": "Logging configuration for the service.",
+ "properties": {
+ "driver": {
+ "type": "string",
+ "description": "Logging driver to use, such as 'json-file', 'syslog', 'journald', etc."
+ },
+ "options": {
+ "type": "object",
+ "description": "Options for the logging driver.",
+ "patternProperties": {
+ "^.+$": {
+ "type": [
+ "string",
+ "number",
+ "null"
+ ]
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "mac_address": {
+ "type": "string",
+ "description": "Container MAC address to set."
+ },
+ "mem_limit": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Memory limit for the container. A string value can use suffix like '2g' for 2 gigabytes."
+ },
+ "mem_reservation": {
+ "type": [
+ "string",
+ "integer"
+ ],
+ "description": "Memory reservation for the container."
+ },
+ "mem_swappiness": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Container memory swappiness as percentage (0 to 100)."
+ },
+ "memswap_limit": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Amount of memory the container is allowed to swap to disk. Set to -1 to enable unlimited swap."
+ },
+ "network_mode": {
+ "type": "string",
+ "description": "Network mode. Values can be 'bridge', 'host', 'none', 'service:[service name]', or 'container:[container name]'."
+ },
+ "models": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/list_of_strings"
+ },
+ {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "endpoint_var": {
+ "type": "string",
+ "description": "Environment variable set to AI model endpoint."
+ },
+ "model_var": {
+ "type": "string",
+ "description": "Environment variable set to AI model name."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "description": "AI Models to use, referencing entries under the top-level models key."
+ },
+ "networks": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/list_of_strings"
+ },
+ {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "aliases": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "Alternative hostnames for this service on the network."
+ },
+ "interface_name": {
+ "type": "string",
+ "description": "Interface network name used to connect to network"
+ },
+ "ipv4_address": {
+ "type": "string",
+ "description": "Specify a static IPv4 address for this service on this network."
+ },
+ "ipv6_address": {
+ "type": "string",
+ "description": "Specify a static IPv6 address for this service on this network."
+ },
+ "link_local_ips": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "List of link-local IPs."
+ },
+ "mac_address": {
+ "type": "string",
+ "description": "Specify a MAC address for this service on this network."
+ },
+ "driver_opts": {
+ "type": "object",
+ "description": "Driver options for this network.",
+ "patternProperties": {
+ "^.+$": {
+ "type": [
+ "string",
+ "number"
+ ]
+ }
+ }
+ },
+ "priority": {
+ "type": "number",
+ "description": "Specify the priority for the network connection."
+ },
+ "gw_priority": {
+ "type": "number",
+ "description": "Specify the gateway priority for the network connection."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ ],
+ "description": "Networks to join, referencing entries under the top-level networks key. Can be a list of network names or a mapping of network name to network configuration."
+ },
+ "oom_kill_disable": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Disable OOM Killer for the container."
+ },
+ "oom_score_adj": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "integer",
+ "minimum": -1000,
+ "maximum": 1000
+ }
+ ],
+ "description": "Tune host's OOM preferences for the container (accepts -1000 to 1000)."
+ },
+ "pid": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "PID mode for container."
+ },
+ "pids_limit": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Tune a container's PIDs limit. Set to -1 for unlimited PIDs."
+ },
+ "platform": {
+ "type": "string",
+ "description": "Target platform to run on, e.g., 'linux/amd64', 'linux/arm64', or 'windows/amd64'."
+ },
+ "privileged": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Give extended privileges to the service container."
+ },
+ "pull_policy": {
+ "type": "string",
+ "pattern": "^(always|never|build|if_not_present|missing|refresh|daily|weekly|every_([0-9]+[wdhms])+)$",
+ "description": "Policy for pulling images. Options include: 'always', 'never', 'if_not_present', 'missing', 'build', or time-based refresh policies."
+ },
+ "pull_refresh_after": {
+ "type": "string",
+ "description": "Time after which to refresh the image. Used with pull_policy=refresh."
+ },
+ "read_only": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Mount the container's filesystem as read only."
+ },
+ "runtime": {
+ "type": "string",
+ "description": "Runtime to use for this container, e.g., 'runc'."
+ },
+ "security_opt": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "description": "Override the default labeling scheme for each container."
+ },
+ "shm_size": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Size of /dev/shm. A string value can use suffix like '2g' for 2 gigabytes."
+ },
+ "secrets": {
+ "$ref": "#/$defs/service_config_or_secret",
+ "description": "Grant access to Secrets on a per-service basis."
+ },
+ "sysctls": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Kernel parameters to set in the container. You can use either an array or a list."
+ },
+ "stop_grace_period": {
+ "type": "string",
+ "description": "Time to wait for the container to stop gracefully before sending SIGKILL (e.g., '1s', '1m30s')."
+ },
+ "stop_signal": {
+ "type": "string",
+ "description": "Signal to stop the container (e.g., 'SIGTERM', 'SIGINT')."
+ },
+ "storage_opt": {
+ "type": "object",
+ "description": "Storage driver options for the container."
+ },
+ "tmpfs": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Mount a temporary filesystem (tmpfs) into the container. Can be a single value or a list."
+ },
+ "ulimits": {
+ "$ref": "#/$defs/ulimits",
+ "description": "Override the default ulimits for a container."
+ },
+ "use_api_socket": {
+ "type": "boolean",
+ "description": "Bind mount Docker API socket and required auth."
+ },
+ "user": {
+ "type": "string",
+ "description": "Username or UID to run the container process as."
+ },
+ "uts": {
+ "type": "string",
+ "description": "UTS namespace to use. 'host' shares the host's UTS namespace."
+ },
+ "userns_mode": {
+ "type": "string",
+ "description": "User namespace to use. 'host' shares the host's user namespace."
+ },
+ "volumes": {
+ "type": "array",
+ "description": "Mount host paths or named volumes accessible to the container. Short syntax (VOLUME:CONTAINER_PATH[:MODE])",
+ "items": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "bind",
+ "volume",
+ "tmpfs",
+ "cluster",
+ "npipe",
+ "image"
+ ],
+ "description": "The mount type: bind for mounting host directories, volume for named volumes, tmpfs for temporary filesystems, cluster for cluster volumes, npipe for named pipes, or image for mounting from an image."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the mount, a path on the host for a bind mount, a docker image reference for an image mount, or the name of a volume defined in the top-level volumes key. Not applicable for a tmpfs mount."
+ },
+ "target": {
+ "type": "string",
+ "description": "The path in the container where the volume is mounted."
+ },
+ "read_only": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Flag to set the volume as read-only."
+ },
+ "consistency": {
+ "type": "string",
+ "description": "The consistency requirements for the mount. Available values are platform specific."
+ },
+ "bind": {
+ "type": "object",
+ "description": "Configuration specific to bind mounts.",
+ "properties": {
+ "propagation": {
+ "type": "string",
+ "description": "The propagation mode for the bind mount: 'shared', 'slave', 'private', 'rshared', 'rslave', or 'rprivate'."
+ },
+ "create_host_path": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Create the host path if it doesn't exist."
+ },
+ "recursive": {
+ "type": "string",
+ "enum": [
+ "enabled",
+ "disabled",
+ "writable",
+ "readonly"
+ ],
+ "description": "Recursively mount the source directory."
+ },
+ "selinux": {
+ "type": "string",
+ "enum": [
+ "z",
+ "Z"
+ ],
+ "description": "SELinux relabeling options: 'z' for shared content, 'Z' for private unshared content."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "volume": {
+ "type": "object",
+ "description": "Configuration specific to volume mounts.",
+ "properties": {
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Labels to apply to the volume."
+ },
+ "nocopy": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Flag to disable copying of data from a container when a volume is created."
+ },
+ "subpath": {
+ "type": "string",
+ "description": "Path within the volume to mount instead of the volume root."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "tmpfs": {
+ "type": "object",
+ "description": "Configuration specific to tmpfs mounts.",
+ "properties": {
+ "size": {
+ "oneOf": [
+ {
+ "type": "integer",
+ "minimum": 0
+ },
+ {
+ "type": "string"
+ }
+ ],
+ "description": "Size of the tmpfs mount in bytes."
+ },
+ "mode": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "File mode of the tmpfs in octal."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "image": {
+ "type": "object",
+ "description": "Configuration specific to image mounts.",
+ "properties": {
+ "subpath": {
+ "type": "string",
+ "description": "Path within the image to mount instead of the image root."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "volumes_from": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "description": "Mount volumes from another service or container. Optionally specify read-only access (ro) or read-write (rw)."
+ },
+ "working_dir": {
+ "type": "string",
+ "description": "The working directory in which the entrypoint or command will be run"
+ }
+ },
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "service": {
+ "description": "Configuration for a service.",
+ "allOf": [
+ {
+ "$ref": "#/$defs/container_spec"
+ },
+ {
+ "$ref": "#/$defs/workload_spec"
+ }
+ ],
+ "properties": {
+ "deploy": {
+ "$ref": "#/$defs/deployment"
+ },
+ "develop": {
+ "$ref": "#/$defs/development"
+ },
+ "profiles": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "List of profiles for this service. When profiles are specified, services are only started when the profile is activated."
+ },
+ "restart": {
+ "type": "string",
+ "description": "Restart policy for the service container. Options include: 'no', 'always', 'on-failure', and 'unless-stopped'."
+ },
+ "scale": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Number of containers to deploy for this service."
+ },
+ "attach": {
+ "type": [
+ "boolean",
+ "string"
+ ]
+ },
+ "container_name": {
+ "type": "string",
+ "description": "Specify a custom container name, rather than a generated default name.",
+ "pattern": "[a-zA-Z0-9][a-zA-Z0-9_.-]+"
+ },
+ "provider": {
+ "type": "object",
+ "description": "Specify a service which will not be manage by Compose directly, and delegate its management to an external provider.",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "External component used by Compose to manage setup and teardown lifecycle of the service."
+ },
+ "options": {
+ "type": "object",
+ "description": "Provider-specific options.",
+ "patternProperties": {
+ "^.+$": {
+ "oneOf": [
+ {
+ "type": [
+ "string",
+ "number",
+ "boolean"
+ ]
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": [
+ "string",
+ "number",
+ "boolean"
+ ]
+ }
+ }
+ ]
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "extends": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "service": {
+ "type": "string",
+ "description": "The name of the service to extend."
+ },
+ "file": {
+ "type": "string",
+ "description": "The file path where the service to extend is defined."
+ }
+ },
+ "required": [
+ "service"
+ ],
+ "additionalProperties": false
+ }
+ ],
+ "description": "Extend another service, in the current file or another file."
+ },
+ "links": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "description": "Link to containers in another service. Either specify both the service name and a link alias (SERVICE:ALIAS), or just the service name."
+ },
+ "external_links": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "description": "Link to services started outside this Compose application. Specify services as :."
+ },
+ "pre_start": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/pre_start_hook"
+ },
+ "description": "Init containers to run to completion before the service container is started. Each step runs in its own ephemeral container, in declared order; a non-zero exit fails the bring-up of the service and its dependents."
+ },
+ "post_start": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/service_hook"
+ },
+ "description": "Commands to run after the container starts. If any command fails, the container stops."
+ },
+ "pre_stop": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/service_hook"
+ },
+ "description": "Commands to run before the container stops. If any command fails, the container stop is aborted."
+ }
+ },
+ "unevaluatedProperties": false
+ },
+ "job": {
+ "description": "Configuration for a job. Jobs are containers that run to completion.",
+ "allOf": [
+ {
+ "$ref": "#/$defs/container_spec"
+ },
+ {
+ "$ref": "#/$defs/workload_spec"
+ }
+ ],
+ "required": [
+ "triggers"
+ ],
+ "properties": {
+ "profiles": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "List of profiles for this job. When profiles are specified, the job is only active when the profile is activated."
+ },
+ "triggers": {
+ "type": "object",
+ "description": "Trigger conditions for the job. At least one trigger attribute must be declared. Setting manual to false forbids manual execution by an explicit run command.",
+ "properties": {
+ "manual": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Whether the job can be triggered manually by an explicit run command. Defaults to true; an explicit false forbids manual execution."
+ },
+ "schedule": {
+ "type": "array",
+ "description": "List of schedules for the job.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Crontab expression to schedule the job (e.g. '0 * * * *' for every hour)."
+ },
+ {
+ "$ref": "#/$defs/schedule"
+ }
+ ]
+ }
+ }
+ },
+ "anyOf": [
+ {
+ "required": [
+ "manual"
+ ]
+ },
+ {
+ "required": [
+ "schedule"
+ ]
+ }
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "unevaluatedProperties": false
+ },
+ "schedule": {
+ "type": "object",
+ "description": "Schedule configuration for a job trigger.",
+ "required": [
+ "cron"
+ ],
+ "properties": {
+ "cron": {
+ "type": "string",
+ "description": "Crontab expression to schedule the job (e.g. '0 * * * *' for every hour)."
+ },
+ "timezone": {
+ "type": "string",
+ "description": "Timezone used to evaluate the cron expression (e.g. 'Europe/Paris'). Defaults to the platform's local timezone."
+ },
+ "concurrency": {
+ "type": "string",
+ "enum": [
+ "forbid",
+ "queue"
+ ],
+ "description": "Policy applied when the schedule fires while a previous run is still in progress: prevent the new run ('forbid', the default) or queue it ('queue')."
+ },
+ "missed_fires": {
+ "type": "string",
+ "enum": [
+ "one",
+ "skip"
+ ],
+ "description": "Policy applied to fires missed while the platform was unavailable: run a single catch-up ('one', the default) or skip them ('skip')."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "healthcheck": {
+ "type": "object",
+ "description": "Configuration options to determine whether the container is healthy.",
+ "properties": {
+ "disable": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Disable any container-specified healthcheck. Set to true to disable."
+ },
+ "interval": {
+ "type": "string",
+ "description": "Time between running the check (e.g., '1s', '1m30s'). Default: 30s."
+ },
+ "retries": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Number of consecutive failures needed to consider the container as unhealthy. Default: 3."
+ },
+ "test": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ],
+ "description": "The test to perform to check container health. Can be a string or a list. The first item is either NONE, CMD, or CMD-SHELL. If it's CMD, the rest of the command is exec'd. If it's CMD-SHELL, the rest is run in the shell."
+ },
+ "timeout": {
+ "type": "string",
+ "description": "Maximum time to allow one check to run (e.g., '1s', '1m30s'). Default: 30s."
+ },
+ "start_period": {
+ "type": "string",
+ "description": "Start period for the container to initialize before starting health-retries countdown (e.g., '1s', '1m30s'). Default: 0s."
+ },
+ "start_interval": {
+ "type": "string",
+ "description": "Time between running the check during the start period (e.g., '1s', '1m30s'). Default: interval value."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "development": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "description": "Development configuration for the service, used for development workflows.",
+ "properties": {
+ "watch": {
+ "type": "array",
+ "description": "Configure watch mode for the service, which monitors file changes and performs actions in response.",
+ "items": {
+ "type": "object",
+ "required": [
+ "path",
+ "action"
+ ],
+ "properties": {
+ "ignore": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Patterns to exclude from watching."
+ },
+ "include": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Patterns to include in watching."
+ },
+ "path": {
+ "type": "string",
+ "description": "Path to watch for changes."
+ },
+ "action": {
+ "type": "string",
+ "enum": [
+ "rebuild",
+ "sync",
+ "restart",
+ "sync+restart",
+ "sync+exec"
+ ],
+ "description": "Action to take when a change is detected: rebuild the container, sync files, restart the container, sync and restart, or sync and execute a command."
+ },
+ "target": {
+ "type": "string",
+ "description": "Target path in the container for sync operations."
+ },
+ "exec": {
+ "$ref": "#/$defs/service_hook",
+ "description": "Command to execute when a change is detected and action is sync+exec."
+ },
+ "initial_sync": {
+ "type": "boolean",
+ "description": "Ensure that an initial synchronization is done before starting watch mode for sync+x triggers"
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "deployment": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "description": "Deployment configuration for the service.",
+ "properties": {
+ "mode": {
+ "type": "string",
+ "description": "Deployment mode for the service: 'replicated' (default) or 'global'."
+ },
+ "endpoint_mode": {
+ "type": "string",
+ "description": "Endpoint mode for the service: 'vip' (default) or 'dnsrr'."
+ },
+ "replicas": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Number of replicas of the service container to run."
+ },
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Labels to apply to the service."
+ },
+ "rollback_config": {
+ "type": "object",
+ "description": "Configuration for rolling back a service update.",
+ "properties": {
+ "parallelism": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "The number of containers to rollback at a time. If set to 0, all containers rollback simultaneously."
+ },
+ "delay": {
+ "type": "string",
+ "description": "The time to wait between each container group's rollback (e.g., '1s', '1m30s')."
+ },
+ "failure_action": {
+ "type": "string",
+ "description": "Action to take if a rollback fails: 'continue', 'pause'."
+ },
+ "monitor": {
+ "type": "string",
+ "description": "Duration to monitor each task for failures after it is created (e.g., '1s', '1m30s')."
+ },
+ "max_failure_ratio": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Failure rate to tolerate during a rollback."
+ },
+ "order": {
+ "type": "string",
+ "enum": [
+ "start-first",
+ "stop-first"
+ ],
+ "description": "Order of operations during rollbacks: 'stop-first' (default) or 'start-first'."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "update_config": {
+ "type": "object",
+ "description": "Configuration for updating a service.",
+ "properties": {
+ "parallelism": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "The number of containers to update at a time."
+ },
+ "delay": {
+ "type": "string",
+ "description": "The time to wait between updating a group of containers (e.g., '1s', '1m30s')."
+ },
+ "failure_action": {
+ "type": "string",
+ "description": "Action to take if an update fails: 'continue', 'pause', 'rollback'."
+ },
+ "monitor": {
+ "type": "string",
+ "description": "Duration to monitor each updated task for failures after it is created (e.g., '1s', '1m30s')."
+ },
+ "max_failure_ratio": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Failure rate to tolerate during an update (0 to 1)."
+ },
+ "order": {
+ "type": "string",
+ "enum": [
+ "start-first",
+ "stop-first"
+ ],
+ "description": "Order of operations during updates: 'stop-first' (default) or 'start-first'."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "resources": {
+ "type": "object",
+ "description": "Resource constraints and reservations for the service.",
+ "properties": {
+ "limits": {
+ "type": "object",
+ "description": "Resource limits for the service containers.",
+ "properties": {
+ "cpus": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Limit for how much of the available CPU resources, as number of cores, a container can use."
+ },
+ "memory": {
+ "type": "string",
+ "description": "Limit on the amount of memory a container can allocate (e.g., '1g', '1024m')."
+ },
+ "pids": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Maximum number of PIDs available to the container."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "reservations": {
+ "type": "object",
+ "description": "Resource reservations for the service containers.",
+ "properties": {
+ "cpus": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Reservation for how much of the available CPU resources, as number of cores, a container can use."
+ },
+ "memory": {
+ "type": "string",
+ "description": "Reservation on the amount of memory a container can allocate (e.g., '1g', '1024m')."
+ },
+ "generic_resources": {
+ "$ref": "#/$defs/generic_resources",
+ "description": "User-defined resources to reserve."
+ },
+ "devices": {
+ "$ref": "#/$defs/devices",
+ "description": "Device reservations for the container."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "restart_policy": {
+ "type": "object",
+ "description": "Restart policy for the service containers.",
+ "properties": {
+ "condition": {
+ "type": "string",
+ "description": "Condition for restarting the container: 'none', 'on-failure', 'any'."
+ },
+ "delay": {
+ "type": "string",
+ "description": "Delay between restart attempts (e.g., '1s', '1m30s')."
+ },
+ "max_attempts": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Maximum number of restart attempts before giving up."
+ },
+ "window": {
+ "type": "string",
+ "description": "Time window used to evaluate the restart policy (e.g., '1s', '1m30s')."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "placement": {
+ "type": "object",
+ "description": "Constraints and preferences for the platform to select a physical node to run service containers",
+ "properties": {
+ "constraints": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Placement constraints for the service (e.g., 'node.role==manager')."
+ },
+ "preferences": {
+ "type": "array",
+ "description": "Placement preferences for the service.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "spread": {
+ "type": "string",
+ "description": "Spread tasks evenly across values of the specified node label."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "max_replicas_per_node": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Maximum number of replicas of the service."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "generic_resources": {
+ "type": "array",
+ "description": "User-defined resources for services, allowing services to reserve specialized hardware resources.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "discrete_resource_spec": {
+ "type": "object",
+ "description": "Specification for discrete (countable) resources.",
+ "properties": {
+ "kind": {
+ "type": "string",
+ "description": "Type of resource (e.g., 'GPU', 'FPGA', 'SSD')."
+ },
+ "value": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Number of resources of this kind to reserve."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "devices": {
+ "type": "array",
+ "description": "Device reservations for containers, allowing services to access specific hardware devices.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "capabilities": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "List of capabilities the device needs to have (e.g., 'gpu', 'compute', 'utility')."
+ },
+ "count": {
+ "type": [
+ "string",
+ "integer"
+ ],
+ "description": "Number of devices of this type to reserve."
+ },
+ "device_ids": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "List of specific device IDs to reserve."
+ },
+ "driver": {
+ "type": "string",
+ "description": "Device driver to use (e.g., 'nvidia')."
+ },
+ "options": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Driver-specific options for the device."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ },
+ "required": [
+ "capabilities"
+ ]
+ }
+ },
+ "gpus": {
+ "oneOf": [
+ {
+ "type": "string",
+ "enum": [
+ "all"
+ ],
+ "description": "Use all available GPUs."
+ },
+ {
+ "type": "array",
+ "description": "List of specific GPU devices to use.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "capabilities": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "List of capabilities the GPU needs to have (e.g., 'compute', 'utility')."
+ },
+ "count": {
+ "type": [
+ "string",
+ "integer"
+ ],
+ "description": "Number of GPUs to use."
+ },
+ "device_ids": {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "List of specific GPU device IDs to use."
+ },
+ "driver": {
+ "type": "string",
+ "description": "GPU driver to use (e.g., 'nvidia')."
+ },
+ "options": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Driver-specific options for the GPU."
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ ]
+ },
+ "include": {
+ "description": "Compose application or sub-projects to be included.",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "path": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Path to the Compose application or sub-project files to include."
+ },
+ "env_file": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Path to the environment files to use to define default values when interpolating variables in the Compose files being parsed."
+ },
+ "project_directory": {
+ "type": "string",
+ "description": "Path to resolve relative paths set in the Compose file"
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "network": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "description": "Network configuration for the Compose application.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Custom name for this network."
+ },
+ "driver": {
+ "type": "string",
+ "description": "Specify which driver should be used for this network. Default is 'bridge'."
+ },
+ "driver_opts": {
+ "type": "object",
+ "description": "Specify driver-specific options defined as key/value pairs.",
+ "patternProperties": {
+ "^.+$": {
+ "type": [
+ "string",
+ "number"
+ ]
+ }
+ }
+ },
+ "ipam": {
+ "type": "object",
+ "description": "Custom IP Address Management configuration for this network.",
+ "properties": {
+ "driver": {
+ "type": "string",
+ "description": "Custom IPAM driver, instead of the default."
+ },
+ "config": {
+ "type": "array",
+ "description": "List of IPAM configuration blocks.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "subnet": {
+ "type": "string",
+ "description": "Subnet in CIDR format that represents a network segment."
+ },
+ "ip_range": {
+ "type": "string",
+ "description": "Range of IPs from which to allocate container IPs."
+ },
+ "gateway": {
+ "type": "string",
+ "description": "IPv4 or IPv6 gateway for the subnet."
+ },
+ "aux_addresses": {
+ "type": "object",
+ "description": "Auxiliary IPv4 or IPv6 addresses used by Network driver.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^.+$": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ },
+ "options": {
+ "type": "object",
+ "description": "Driver-specific options for the IPAM driver.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^.+$": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "external": {
+ "type": [
+ "boolean",
+ "string",
+ "object"
+ ],
+ "description": "Specifies that this network already exists and was created outside of Compose.",
+ "properties": {
+ "name": {
+ "deprecated": true,
+ "type": "string",
+ "description": "Specifies the name of the external network. Deprecated: use the 'name' property instead."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "internal": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Create an externally isolated network."
+ },
+ "enable_ipv4": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Enable IPv4 networking."
+ },
+ "enable_ipv6": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Enable IPv6 networking."
+ },
+ "attachable": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "If true, standalone containers can attach to this network."
+ },
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Add metadata to the network using labels."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "volume": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "description": "Volume configuration for the Compose application.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Custom name for this volume."
+ },
+ "driver": {
+ "type": "string",
+ "description": "Specify which volume driver should be used for this volume."
+ },
+ "driver_opts": {
+ "type": "object",
+ "description": "Specify driver-specific options.",
+ "patternProperties": {
+ "^.+$": {
+ "type": [
+ "string",
+ "number"
+ ]
+ }
+ }
+ },
+ "external": {
+ "type": [
+ "boolean",
+ "string",
+ "object"
+ ],
+ "description": "Specifies that this volume already exists and was created outside of Compose.",
+ "properties": {
+ "name": {
+ "deprecated": true,
+ "type": "string",
+ "description": "Specifies the name of the external volume. Deprecated: use the 'name' property instead."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Add metadata to the volume using labels."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "secret": {
+ "type": "object",
+ "description": "Secret configuration for the Compose application.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Custom name for this secret."
+ },
+ "environment": {
+ "type": "string",
+ "description": "Name of an environment variable from which to get the secret value."
+ },
+ "file": {
+ "type": "string",
+ "description": "Path to a file containing the secret value."
+ },
+ "external": {
+ "type": [
+ "boolean",
+ "string",
+ "object"
+ ],
+ "description": "Specifies that this secret already exists and was created outside of Compose.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Specifies the name of the external secret."
+ }
+ }
+ },
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Add metadata to the secret using labels."
+ },
+ "driver": {
+ "type": "string",
+ "description": "Specify which secret driver should be used for this secret."
+ },
+ "driver_opts": {
+ "type": "object",
+ "description": "Specify driver-specific options.",
+ "patternProperties": {
+ "^.+$": {
+ "type": [
+ "string",
+ "number"
+ ]
+ }
+ }
+ },
+ "template_driver": {
+ "type": "string",
+ "description": "Driver to use for templating the secret's value."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "config": {
+ "type": "object",
+ "description": "Config configuration for the Compose application.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Custom name for this config."
+ },
+ "content": {
+ "type": "string",
+ "description": "Inline content of the config."
+ },
+ "environment": {
+ "type": "string",
+ "description": "Name of an environment variable from which to get the config value."
+ },
+ "file": {
+ "type": "string",
+ "description": "Path to a file containing the config value."
+ },
+ "external": {
+ "type": [
+ "boolean",
+ "string",
+ "object"
+ ],
+ "description": "Specifies that this config already exists and was created outside of Compose.",
+ "properties": {
+ "name": {
+ "deprecated": true,
+ "type": "string",
+ "description": "Specifies the name of the external config. Deprecated: use the 'name' property instead."
+ }
+ }
+ },
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Add metadata to the config using labels."
+ },
+ "template_driver": {
+ "type": "string",
+ "description": "Driver to use for templating the config's value."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "model": {
+ "type": "object",
+ "description": "Language Model for the Compose application.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Custom name for this model."
+ },
+ "model": {
+ "type": "string",
+ "description": "Language Model to run."
+ },
+ "context_size": {
+ "type": "integer"
+ },
+ "runtime_flags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Raw runtime flags to pass to the inference engine."
+ }
+ },
+ "required": [
+ "model"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ },
+ "command": {
+ "oneOf": [
+ {
+ "type": "null",
+ "description": "No command specified, use the container's default command."
+ },
+ {
+ "type": "string",
+ "description": "Command as a string, which will be executed in a shell (e.g., '/bin/sh -c')."
+ },
+ {
+ "type": "array",
+ "description": "Command as an array of strings, which will be executed directly without a shell.",
+ "items": {
+ "type": "string",
+ "description": "Part of the command (executable or argument)."
+ }
+ }
+ ],
+ "description": "Command to run in the container, which can be specified as a string (shell form) or array (exec form)."
+ },
+ "service_hook": {
+ "type": "object",
+ "description": "Configuration for service lifecycle hooks, which are commands executed at specific points in a container's lifecycle.",
+ "properties": {
+ "command": {
+ "$ref": "#/$defs/command",
+ "description": "Command to execute as part of the hook."
+ },
+ "user": {
+ "type": "string",
+ "description": "User to run the command as."
+ },
+ "privileged": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Whether to run the command with extended privileges."
+ },
+ "working_dir": {
+ "type": "string",
+ "description": "Working directory for the command."
+ },
+ "environment": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Environment variables for the command."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ },
+ "required": [
+ "command"
+ ]
+ },
+ "pre_start_hook": {
+ "type": "object",
+ "description": "Configuration for a pre_start init container, run to completion before the service container starts. Accepts the full container specification; per #656, attributes not set explicitly are inherited from the service: collection attributes are completed by the hook's declarations (which win on conflicts), scalar attributes are replaced.",
+ "allOf": [
+ {
+ "$ref": "#/$defs/container_spec"
+ }
+ ],
+ "unevaluatedProperties": false,
+ "properties": {
+ "per_replica": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "When true, the hook runs once per service replica instead of once per service."
+ }
+ }
+ },
+ "env_file": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Path to a file containing environment variables."
+ },
+ {
+ "type": "array",
+ "description": "List of paths to files containing environment variables.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Path to a file containing environment variables."
+ },
+ {
+ "type": "object",
+ "description": "Detailed configuration for an environment file.",
+ "additionalProperties": false,
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to the environment file."
+ },
+ "format": {
+ "type": "string",
+ "description": "Format attribute lets you to use an alternative file formats for env_file. When not set, env_file is parsed according to Compose rules."
+ },
+ "required": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "default": true,
+ "description": "Whether the file is required. If true and the file doesn't exist, an error will be raised."
+ }
+ },
+ "required": [
+ "path"
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "label_file": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Path to a file containing Docker labels."
+ },
+ {
+ "type": "array",
+ "description": "List of paths to files containing Docker labels.",
+ "items": {
+ "type": "string",
+ "description": "Path to a file containing Docker labels."
+ }
+ }
+ ]
+ },
+ "string_or_list": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "A single string value."
+ },
+ {
+ "$ref": "#/$defs/list_of_strings",
+ "description": "A list of string values."
+ }
+ ],
+ "description": "Either a single string or a list of strings."
+ },
+ "list_of_strings": {
+ "type": "array",
+ "description": "A list of unique string values.",
+ "items": {
+ "type": "string",
+ "description": "A string value in the list."
+ },
+ "uniqueItems": true
+ },
+ "list_or_dict": {
+ "oneOf": [
+ {
+ "type": "object",
+ "description": "A dictionary mapping keys to values.",
+ "patternProperties": {
+ ".+": {
+ "type": [
+ "string",
+ "number",
+ "boolean",
+ "null"
+ ],
+ "description": "Value for the key, which can be a string, number, boolean, or null."
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "array",
+ "description": "A list of unique string values.",
+ "items": {
+ "type": "string",
+ "description": "A string value in the list."
+ },
+ "uniqueItems": true
+ }
+ ],
+ "description": "Either a dictionary mapping keys to values, or a list of strings."
+ },
+ "extra_hosts": {
+ "oneOf": [
+ {
+ "type": "object",
+ "description": "list mapping hostnames to IP addresses.",
+ "patternProperties": {
+ ".+": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "IP address for the hostname."
+ },
+ {
+ "type": "array",
+ "description": "List of IP addresses for the hostname.",
+ "items": {
+ "type": "string",
+ "description": "IP address for the hostname."
+ },
+ "uniqueItems": false
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "array",
+ "description": "List of host:IP mappings in the format 'hostname:IP'.",
+ "items": {
+ "type": "string",
+ "description": "Host:IP mapping in the format 'hostname:IP'."
+ },
+ "uniqueItems": true
+ }
+ ],
+ "description": "Additional hostnames to be defined in the container's /etc/hosts file."
+ },
+ "blkio_limit": {
+ "type": "object",
+ "description": "Block IO limit for a specific device.",
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to the device (e.g., '/dev/sda')."
+ },
+ "rate": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Rate limit in bytes per second or IO operations per second."
+ }
+ },
+ "additionalProperties": false
+ },
+ "blkio_weight": {
+ "type": "object",
+ "description": "Block IO weight for a specific device.",
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to the device (e.g., '/dev/sda')."
+ },
+ "weight": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Relative weight for the device, between 10 and 1000."
+ }
+ },
+ "additionalProperties": false
+ },
+ "service_config_or_secret": {
+ "type": "array",
+ "description": "Configuration for service configs or secrets, defining how they are mounted in the container.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Name of the config or secret to grant access to."
+ },
+ {
+ "type": "object",
+ "description": "Detailed configuration for a config or secret.",
+ "properties": {
+ "source": {
+ "type": "string",
+ "description": "Name of the config or secret as defined in the top-level configs or secrets section."
+ },
+ "target": {
+ "type": "string",
+ "description": "Path in the container where the config or secret will be mounted. Defaults to / for configs and /run/secrets/ for secrets."
+ },
+ "uid": {
+ "type": "string",
+ "description": "UID of the file in the container. Default is 0 (root)."
+ },
+ "gid": {
+ "type": "string",
+ "description": "GID of the file in the container. Default is 0 (root)."
+ },
+ "mode": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "File permission mode inside the container, in octal. Default is 0444 for configs and 0400 for secrets."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ ]
+ }
+ },
+ "ulimits": {
+ "type": "object",
+ "description": "Container ulimit options, controlling resource limits for processes inside the container.",
+ "patternProperties": {
+ "^[a-z]+$": {
+ "oneOf": [
+ {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Single value for both soft and hard limits."
+ },
+ {
+ "type": "object",
+ "description": "Separate soft and hard limits.",
+ "properties": {
+ "hard": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Hard limit for the ulimit type. This is the maximum allowed value."
+ },
+ "soft": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Soft limit for the ulimit type. This is the value that's actually enforced."
+ }
+ },
+ "required": [
+ "soft",
+ "hard"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ ]
+ }
+ }
+ },
+ "workload_spec": {
+ "type": "object",
+ "description": "Container attributes meaningful for orchestrated workloads (services and jobs) but not for run-to-completion init containers: build, dependency ordering, health reporting, port exposure and interactivity.",
+ "properties": {
+ "build": {
+ "description": "Configuration options for building the service's image.",
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Path to the build context. Can be a relative path or a URL."
+ },
+ {
+ "type": "object",
+ "properties": {
+ "context": {
+ "type": "string",
+ "description": "Path to the build context. Can be a relative path or a URL."
+ },
+ "dockerfile": {
+ "type": "string",
+ "description": "Name of the Dockerfile to use for building the image."
+ },
+ "dockerfile_inline": {
+ "type": "string",
+ "description": "Inline Dockerfile content to use instead of a Dockerfile from the build context."
+ },
+ "entitlements": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of extra privileged entitlements to grant to the build process."
+ },
+ "args": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Build-time variables, specified as a map or a list of KEY=VAL pairs."
+ },
+ "ssh": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "SSH agent socket or keys to expose to the build. Format is either a string or a list of 'default|[=|[,]]'."
+ },
+ "labels": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Labels to apply to the built image."
+ },
+ "cache_from": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of sources the image builder should use for cache resolution"
+ },
+ "cache_to": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Cache destinations for the build cache."
+ },
+ "no_cache": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Do not use cache when building the image."
+ },
+ "no_cache_filter": {
+ "$ref": "#/$defs/string_or_list",
+ "description": "Do not use build cache for the specified stages."
+ },
+ "additional_contexts": {
+ "$ref": "#/$defs/list_or_dict",
+ "description": "Additional build contexts to use, specified as a map of name to context path or URL."
+ },
+ "network": {
+ "type": "string",
+ "description": "Network mode to use for the build. Options include 'default', 'none', 'host', or a network name."
+ },
+ "provenance": {
+ "type": [
+ "string",
+ "boolean"
+ ],
+ "description": "Add a provenance attestation"
+ },
+ "sbom": {
+ "type": [
+ "string",
+ "boolean"
+ ],
+ "description": "Add a SBOM attestation"
+ },
+ "pull": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Always attempt to pull a newer version of the image."
+ },
+ "target": {
+ "type": "string",
+ "description": "Build stage to target in a multi-stage Dockerfile."
+ },
+ "shm_size": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Size of /dev/shm for the build container. A string value can use suffix like '2g' for 2 gigabytes."
+ },
+ "extra_hosts": {
+ "$ref": "#/$defs/extra_hosts",
+ "description": "Add hostname mappings for the build container."
+ },
+ "isolation": {
+ "type": "string",
+ "description": "Container isolation technology to use for the build process."
+ },
+ "privileged": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Give extended privileges to the build container."
+ },
+ "secrets": {
+ "$ref": "#/$defs/service_config_or_secret",
+ "description": "Secrets to expose to the build. These are accessible at build-time."
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Additional tags to apply to the built image."
+ },
+ "ulimits": {
+ "$ref": "#/$defs/ulimits",
+ "description": "Override the default ulimits for the build container."
+ },
+ "platforms": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Platforms to build for, e.g., 'linux/amd64', 'linux/arm64', or 'windows/amd64'."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ ]
+ },
+ "depends_on": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/list_of_strings"
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ },
+ "properties": {
+ "restart": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Whether to restart dependent services when this service is restarted."
+ },
+ "required": {
+ "type": "boolean",
+ "default": true,
+ "description": "Whether the dependency is required for the dependent service to start."
+ },
+ "condition": {
+ "type": "string",
+ "enum": [
+ "service_started",
+ "service_healthy",
+ "service_completed_successfully"
+ ],
+ "description": "Condition to wait for. 'service_started' waits until the service has started, 'service_healthy' waits until the service is healthy (as defined by its healthcheck), 'service_completed_successfully' waits until the service has completed successfully."
+ }
+ },
+ "required": [
+ "condition"
+ ]
+ }
+ }
+ }
+ ],
+ "description": "Express dependency between services. Service dependencies cause services to be started in dependency order. The dependent service will wait for the dependency to be ready before starting."
+ },
+ "healthcheck": {
+ "$ref": "#/$defs/healthcheck",
+ "description": "Configure a health check for the container to monitor its health status."
+ },
+ "ports": {
+ "type": "array",
+ "description": "Expose container ports. Short format ([HOST:]CONTAINER[/PROTOCOL]).",
+ "items": {
+ "oneOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "A human-readable name for this port mapping."
+ },
+ "mode": {
+ "type": "string",
+ "description": "The port binding mode, either 'host' for publishing a host port or 'ingress' for load balancing."
+ },
+ "host_ip": {
+ "type": "string",
+ "description": "The host IP to bind to."
+ },
+ "target": {
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "The port inside the container."
+ },
+ "published": {
+ "type": [
+ "string",
+ "integer"
+ ],
+ "description": "The publicly exposed port."
+ },
+ "protocol": {
+ "type": "string",
+ "description": "The port protocol (tcp or udp)."
+ },
+ "app_protocol": {
+ "type": "string",
+ "description": "Application protocol to use with the port (e.g., http, https, mysql)."
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "expose": {
+ "type": "array",
+ "items": {
+ "type": [
+ "string",
+ "number"
+ ]
+ },
+ "uniqueItems": true,
+ "description": "Expose ports without publishing them to the host machine - they'll only be accessible to linked services."
+ },
+ "stdin_open": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Keep STDIN open even if not attached."
+ },
+ "tty": {
+ "type": [
+ "boolean",
+ "string"
+ ],
+ "description": "Allocate a pseudo-TTY to service container."
+ }
+ },
+ "patternProperties": {
+ "^x-": {}
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/vendor/github.com/compose-spec/compose-go/v2/schema/paths.go b/vendor/github.com/compose-spec/compose-go/v2/schema/paths.go
new file mode 100644
index 0000000000..8c508ec01c
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/schema/paths.go
@@ -0,0 +1,145 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package schema
+
+import (
+ "encoding/json"
+ "slices"
+ "strings"
+ "sync"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// AttributePaths returns the attribute paths ([tree.Path] patterns) the
+// Compose Specification JSON schema declares, one per mapping attribute:
+// pattern-keyed mappings (services, networks, per-key mounts…) contribute a
+// [tree.PathMatchAll] component and sequence items a [tree.PathMatchList]
+// component, matching the convention used across compose-go.
+//
+// It gives a runtime the complete spec-level inventory to build its
+// "supported attributes" declaration from (see loader.Options
+// SupportedAttributes): start from the full specification and remove the
+// paths the runtime does not implement, so every newly-specified attribute is
+// reported as unsupported until it is deliberately wired in.
+//
+// The result is sorted and stable for a given schema; the slice is shared,
+// callers must not mutate it (clone before editing).
+func AttributePaths() []tree.Path {
+ attributePathsOnce.Do(func() {
+ attributePaths = collectAttributePaths()
+ })
+ return attributePaths
+}
+
+var (
+ attributePathsOnce sync.Once
+ attributePaths []tree.Path
+)
+
+func collectAttributePaths() []tree.Path {
+ var root map[string]any
+ // the embedded schema is validated by tests; a broken schema would fail
+ // Validate long before this point
+ if err := json.Unmarshal([]byte(Schema), &root); err != nil {
+ panic(err)
+ }
+ defs, _ := root["$defs"].(map[string]any)
+ c := &pathCollector{defs: defs}
+ c.walk(root, tree.NewPath(), map[string]bool{})
+
+ paths := make([]tree.Path, 0, len(c.paths))
+ for path := range c.paths {
+ paths = append(paths, tree.Path(path))
+ }
+ slices.Sort(paths)
+ return paths
+}
+
+type pathCollector struct {
+ defs map[string]any
+ paths map[string]bool
+}
+
+// walk visits a schema node and records the attribute paths its object
+// properties declare. active tracks the $refs on the current branch so
+// self-referencing definitions (include, service.develop…) terminate.
+func (c *pathCollector) walk(node map[string]any, path tree.Path, active map[string]bool) {
+ if c.paths == nil {
+ c.paths = map[string]bool{}
+ }
+ if ref, ok := node["$ref"].(string); ok {
+ name := strings.TrimPrefix(ref, "#/$defs/")
+ if active[name] {
+ return
+ }
+ if def, ok := c.defs[name].(map[string]any); ok {
+ active[name] = true
+ c.walk(def, path, active)
+ delete(active, name)
+ }
+ return
+ }
+ for _, combinator := range []string{"oneOf", "anyOf", "allOf"} {
+ if alternatives, ok := node[combinator].([]any); ok {
+ for _, alternative := range alternatives {
+ if sub, ok := alternative.(map[string]any); ok {
+ c.walk(sub, path, active)
+ }
+ }
+ }
+ }
+ if properties, ok := node["properties"].(map[string]any); ok {
+ for name, sub := range properties {
+ next := path.Next(name)
+ c.paths[string(next)] = true
+ if subSchema, ok := sub.(map[string]any); ok {
+ c.walk(subSchema, next, active)
+ }
+ }
+ }
+ // pattern-keyed mappings (services, networks, x-* extension points…)
+ // and typed additionalProperties both accept arbitrary keys: a single
+ // PathMatchAll component stands for them
+ for _, keyed := range []string{"patternProperties", "additionalProperties"} {
+ v, ok := node[keyed].(map[string]any)
+ if ok {
+ if keyed == "patternProperties" {
+ for patternKey, sub := range v {
+ // extension escape hatches ("^x-") are not attributes of
+ // the specification: recording them as a wildcard would
+ // blanket-accept every sibling key
+ if strings.Contains(patternKey, "x-") {
+ continue
+ }
+ if subSchema, ok := sub.(map[string]any); ok {
+ next := path.Next(tree.PathMatchAll)
+ c.paths[string(next)] = true
+ c.walk(subSchema, next, active)
+ }
+ }
+ } else {
+ next := path.Next(tree.PathMatchAll)
+ c.paths[string(next)] = true
+ c.walk(v, next, active)
+ }
+ }
+ }
+ if items, ok := node["items"].(map[string]any); ok {
+ c.walk(items, path.Next(tree.PathMatchList), active)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/schema/schema.go b/vendor/github.com/compose-spec/compose-go/v2/schema/schema.go
new file mode 100644
index 0000000000..a765e3378c
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/schema/schema.go
@@ -0,0 +1,173 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package schema
+
+import (
+ // Enable support for embedded static resources
+ _ "embed"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "slices"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/santhosh-tekuri/jsonschema/v6"
+ "github.com/santhosh-tekuri/jsonschema/v6/kind"
+ "golang.org/x/text/language"
+ "golang.org/x/text/message"
+)
+
+func durationFormatChecker(input any) error {
+ value, ok := input.(string)
+ if !ok {
+ return fmt.Errorf("expected string")
+ }
+ _, err := time.ParseDuration(value)
+ return err
+}
+
+// Schema is the compose-spec JSON schema
+//
+//go:embed compose-spec.json
+var Schema string
+
+// compiledSchema is the compose-spec schema compiled once and reused across
+// every Validate call. Compiling the schema (which loads and resolves the
+// draft 2020-12 meta-schema) is expensive and was previously redone on every
+// call; doing it once behind a sync.Once keeps Validate cheap and makes it
+// safe to call from several goroutines without sharing any mutable compiler
+// state. see https://github.com/docker/compose/issues/13866
+var (
+ compiledSchema *jsonschema.Schema
+ compiledSchemaErr error
+ compiledSchemaOnce sync.Once
+)
+
+func compileSchema() (*jsonschema.Schema, error) {
+ compiledSchemaOnce.Do(func() {
+ compiler := jsonschema.NewCompiler()
+ shema, err := jsonschema.UnmarshalJSON(strings.NewReader(Schema))
+ if err != nil {
+ compiledSchemaErr = err
+ return
+ }
+ if err := compiler.AddResource("compose-spec.json", shema); err != nil {
+ compiledSchemaErr = err
+ return
+ }
+ compiler.RegisterFormat(&jsonschema.Format{
+ Name: "duration",
+ Validate: durationFormatChecker,
+ })
+ compiledSchema, compiledSchemaErr = compiler.Compile("compose-spec.json")
+ })
+ return compiledSchema, compiledSchemaErr
+}
+
+// Validate uses the jsonschema to validate the configuration
+func Validate(config map[string]interface{}) error {
+ schema, err := compileSchema()
+ if err != nil {
+ return err
+ }
+
+ // santhosh-tekuri doesn't allow derived types
+ // see https://github.com/santhosh-tekuri/jsonschema/pull/240
+ marshaled, err := json.Marshal(config)
+ if err != nil {
+ return err
+ }
+
+ var raw map[string]interface{}
+ err = json.Unmarshal(marshaled, &raw)
+ if err != nil {
+ return err
+ }
+
+ err = schema.Validate(raw)
+ var verr *jsonschema.ValidationError
+ if ok := errors.As(err, &verr); ok {
+ return validationError{getMostSpecificError(verr)}
+ }
+ return err
+}
+
+type validationError struct {
+ err *jsonschema.ValidationError
+}
+
+func (e validationError) Error() string {
+ path := strings.Join(e.err.InstanceLocation, ".")
+ p := message.NewPrinter(language.English)
+ switch k := e.err.ErrorKind.(type) {
+ case *kind.Type:
+ return fmt.Sprintf("%s must be a %s", path, humanReadableType(k.Want...))
+ case *kind.Minimum:
+ return fmt.Sprintf("%s must be greater than or equal to %s", path, k.Want.Num())
+ case *kind.Maximum:
+ return fmt.Sprintf("%s must be less than or equal to %s", path, k.Want.Num())
+ }
+ return fmt.Sprintf("%s %s", path, e.err.ErrorKind.LocalizedString(p))
+}
+
+func humanReadableType(want ...string) string {
+ if len(want) == 1 {
+ switch want[0] {
+ case "object":
+ return "mapping"
+ default:
+ return want[0]
+ }
+ }
+
+ for i, s := range want {
+ want[i] = humanReadableType(s)
+ }
+
+ slices.Sort(want)
+ return fmt.Sprintf(
+ "%s or %s",
+ strings.Join(want[0:len(want)-1], ", "),
+ want[len(want)-1],
+ )
+}
+
+func getMostSpecificError(err *jsonschema.ValidationError) *jsonschema.ValidationError {
+ var mostSpecificError *jsonschema.ValidationError
+ if len(err.Causes) == 0 {
+ return err
+ }
+ for _, cause := range err.Causes {
+ cause = getMostSpecificError(cause)
+ if specificity(cause) > specificity(mostSpecificError) {
+ mostSpecificError = cause
+ }
+ }
+ return mostSpecificError
+}
+
+func specificity(err *jsonschema.ValidationError) int {
+ if err == nil {
+ return -1
+ }
+ if _, ok := err.ErrorKind.(*kind.AdditionalProperties); ok {
+ return len(err.InstanceLocation) + 1
+ }
+ return len(err.InstanceLocation)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/schema/using-variables.yaml b/vendor/github.com/compose-spec/compose-go/v2/schema/using-variables.yaml
new file mode 100644
index 0000000000..3f302cd6ef
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/schema/using-variables.yaml
@@ -0,0 +1,123 @@
+name: ${VARIABLE}
+services:
+ foo:
+ deploy:
+ mode: ${VARIABLE}
+ replicas: ${VARIABLE}
+ rollback_config:
+ parallelism: ${VARIABLE}
+ delay: ${VARIABLE}
+ failure_action: ${VARIABLE}
+ monitor: ${VARIABLE}
+ max_failure_ratio: ${VARIABLE}
+ update_config:
+ parallelism: ${VARIABLE}
+ delay: ${VARIABLE}
+ failure_action: ${VARIABLE}
+ monitor: ${VARIABLE}
+ max_failure_ratio: ${VARIABLE}
+ resources:
+ limits:
+ memory: ${VARIABLE}
+ reservations:
+ memory: ${VARIABLE}
+ generic_resources:
+ - discrete_resource_spec:
+ kind: ${VARIABLE}
+ value: ${VARIABLE}
+ - discrete_resource_spec:
+ kind: ${VARIABLE}
+ value: ${VARIABLE}
+ restart_policy:
+ condition: ${VARIABLE}
+ delay: ${VARIABLE}
+ max_attempts: ${VARIABLE}
+ window: ${VARIABLE}
+ placement:
+ max_replicas_per_node: ${VARIABLE}
+ preferences:
+ - spread: ${VARIABLE}
+ endpoint_mode: ${VARIABLE}
+ expose:
+ - ${VARIABLE}
+ external_links:
+ - ${VARIABLE}
+ extra_hosts:
+ - ${VARIABLE}
+ hostname: ${VARIABLE}
+
+ healthcheck:
+ test: ${VARIABLE}
+ interval: ${VARIABLE}
+ timeout: ${VARIABLE}
+ retries: ${VARIABLE}
+ start_period: ${VARIABLE}
+ start_interval: ${VARIABLE}
+ image: ${VARIABLE}
+ mac_address: ${VARIABLE}
+ networks:
+ some-network:
+ aliases:
+ - ${VARIABLE}
+ other-network:
+ ipv4_address: ${VARIABLE}
+ ipv6_address: ${VARIABLE}
+ mac_address: ${VARIABLE}
+ ports:
+ - ${VARIABLE}
+ privileged: ${VARIABLE}
+ read_only: ${VARIABLE}
+ restart: ${VARIABLE}
+ secrets:
+ - source: ${VARIABLE}
+ target: ${VARIABLE}
+ uid: ${VARIABLE}
+ gid: ${VARIABLE}
+ mode: ${VARIABLE}
+ stdin_open: ${VARIABLE}
+ stop_grace_period: ${VARIABLE}
+ stop_signal: ${VARIABLE}
+ storage_opt:
+ size: ${VARIABLE}
+ sysctls:
+ net.core.somaxconn: ${VARIABLE}
+ tmpfs:
+ - ${VARIABLE}
+ tty: ${VARIABLE}
+ ulimits:
+ nproc: ${VARIABLE}
+ nofile:
+ soft: ${VARIABLE}
+ hard: ${VARIABLE}
+ user: ${VARIABLE}
+ volumes:
+ - ${VARIABLE}:${VARIABLE}
+ - type: tmpfs
+ target: ${VARIABLE}
+ tmpfs:
+ size: ${VARIABLE}
+
+networks:
+ network:
+ ipam:
+ driver: ${VARIABLE}
+ config:
+ - subnet: ${VARIABLE}
+ ip_range: ${VARIABLE}
+ gateway: ${VARIABLE}
+ aux_addresses:
+ host1: ${VARIABLE}
+ external-network:
+ external: ${VARIABLE}
+
+volumes:
+ external-volume:
+ external: ${VARIABLE}
+
+configs:
+ config1:
+ external: ${VARIABLE}
+
+secrets:
+ secret1:
+ external: ${VARIABLE}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/template/template.go b/vendor/github.com/compose-spec/compose-go/v2/template/template.go
new file mode 100644
index 0000000000..beb61ed803
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/template/template.go
@@ -0,0 +1,380 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package template
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "sort"
+ "strings"
+
+ "github.com/sirupsen/logrus"
+)
+
+const (
+ delimiter = "\\$"
+ substitutionNamed = "[_a-z][_a-z0-9]*"
+ substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-+?](.*))?"
+ groupEscaped = "escaped"
+ groupNamed = "named"
+ groupBraced = "braced"
+ groupInvalid = "invalid"
+)
+
+var (
+ patternString = fmt.Sprintf(
+ "%s(?i:(?P<%s>%s)|(?P<%s>%s)|{(?:(?P<%s>%s)}|(?P<%s>)))",
+ delimiter,
+ groupEscaped, delimiter,
+ groupNamed, substitutionNamed,
+ groupBraced, substitutionBraced,
+ groupInvalid,
+ )
+
+ DefaultPattern = regexp.MustCompile(patternString)
+)
+
+// InvalidTemplateError is returned when a variable template is not in a valid
+// format
+type InvalidTemplateError struct {
+ Template string
+}
+
+func (e InvalidTemplateError) Error() string {
+ return fmt.Sprintf("Invalid template: %#v", e.Template)
+}
+
+// MissingRequiredError is returned when a variable template is missing
+type MissingRequiredError struct {
+ Variable string
+ Reason string
+}
+
+func (e MissingRequiredError) Error() string {
+ if e.Reason != "" {
+ return fmt.Sprintf("required variable %s is missing a value: %s", e.Variable, e.Reason)
+ }
+ return fmt.Sprintf("required variable %s is missing a value", e.Variable)
+}
+
+// Mapping is a user-supplied function which maps from variable names to values.
+// Returns the value as a string and a bool indicating whether
+// the value is present, to distinguish between an empty string
+// and the absence of a value.
+type Mapping func(string) (string, bool)
+
+// SubstituteFunc is a user-supplied function that apply substitution.
+// Returns the value as a string, a bool indicating if the function could apply
+// the substitution and an error.
+type SubstituteFunc func(string, Mapping) (string, bool, error)
+
+// ReplacementFunc is a user-supplied function that is apply to the matching
+// substring. Returns the value as a string and an error.
+type ReplacementFunc func(string, Mapping, *Config) (string, error)
+
+type Config struct {
+ pattern *regexp.Regexp
+ substituteFunc SubstituteFunc
+ replacementFunc ReplacementFunc
+ logging bool
+}
+
+type Option func(*Config)
+
+func WithPattern(pattern *regexp.Regexp) Option {
+ return func(cfg *Config) {
+ cfg.pattern = pattern
+ }
+}
+
+func WithSubstitutionFunction(subsFunc SubstituteFunc) Option {
+ return func(cfg *Config) {
+ cfg.substituteFunc = subsFunc
+ }
+}
+
+func WithReplacementFunction(replacementFunc ReplacementFunc) Option {
+ return func(cfg *Config) {
+ cfg.replacementFunc = replacementFunc
+ }
+}
+
+func WithoutLogging(cfg *Config) {
+ cfg.logging = false
+}
+
+// SubstituteWithOptions substitute variables in the string with their values.
+// It accepts additional options such as a custom function or pattern.
+func SubstituteWithOptions(template string, mapping Mapping, options ...Option) (string, error) {
+ var returnErr error
+
+ cfg := &Config{
+ pattern: DefaultPattern,
+ replacementFunc: DefaultReplacementFunc,
+ logging: true,
+ }
+ for _, o := range options {
+ o(cfg)
+ }
+
+ result := cfg.pattern.ReplaceAllStringFunc(template, func(substring string) string {
+ replacement, err := cfg.replacementFunc(substring, mapping, cfg)
+ if err != nil {
+ // Add the template for template errors
+ var tmplErr *InvalidTemplateError
+ if errors.As(err, &tmplErr) {
+ if tmplErr.Template == "" {
+ tmplErr.Template = template
+ }
+ }
+ // Save the first error to be returned
+ if returnErr == nil {
+ returnErr = err
+ }
+
+ }
+ return replacement
+ })
+
+ return result, returnErr
+}
+
+func DefaultReplacementFunc(substring string, mapping Mapping, cfg *Config) (string, error) {
+ value, _, err := DefaultReplacementAppliedFunc(substring, mapping, cfg)
+ return value, err
+}
+
+func DefaultReplacementAppliedFunc(substring string, mapping Mapping, cfg *Config) (string, bool, error) {
+ pattern := cfg.pattern
+ subsFunc := cfg.substituteFunc
+ if subsFunc == nil {
+ _, subsFunc = getSubstitutionFunctionForTemplate(substring)
+ }
+
+ closingBraceIndex := getFirstBraceClosingIndex(substring)
+ rest := ""
+ if closingBraceIndex > -1 {
+ rest = substring[closingBraceIndex+1:]
+ substring = substring[0 : closingBraceIndex+1]
+ }
+
+ matches := pattern.FindStringSubmatch(substring)
+ groups := matchGroups(matches, pattern)
+ if escaped := groups[groupEscaped]; escaped != "" {
+ return escaped, true, nil
+ }
+
+ braced := false
+ substitution := groups[groupNamed]
+ if substitution == "" {
+ substitution = groups[groupBraced]
+ braced = true
+ }
+
+ if substitution == "" {
+ return "", false, &InvalidTemplateError{}
+ }
+
+ if braced {
+ value, applied, err := subsFunc(substitution, mapping)
+ if err != nil {
+ return "", false, err
+ }
+ if applied {
+ interpolatedNested, err := SubstituteWith(rest, mapping, pattern)
+ if err != nil {
+ return "", false, err
+ }
+ return value + interpolatedNested, true, nil
+ }
+ }
+
+ value, ok := mapping(substitution)
+ if !ok && cfg.logging {
+ logrus.Warnf("The %q variable is not set. Defaulting to a blank string.", substitution)
+ }
+
+ return value, ok, nil
+}
+
+// SubstituteWith substitute variables in the string with their values.
+// It accepts additional substitute function.
+func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, subsFuncs ...SubstituteFunc) (string, error) {
+ options := []Option{
+ WithPattern(pattern),
+ }
+ if len(subsFuncs) > 0 {
+ options = append(options, WithSubstitutionFunction(subsFuncs[0]))
+ }
+
+ return SubstituteWithOptions(template, mapping, options...)
+}
+
+func getSubstitutionFunctionForTemplate(template string) (string, SubstituteFunc) {
+ interpolationMapping := []struct {
+ string
+ SubstituteFunc
+ }{
+ {":?", requiredErrorWhenEmptyOrUnset},
+ {"?", requiredErrorWhenUnset},
+ {":-", defaultWhenEmptyOrUnset},
+ {"-", defaultWhenUnset},
+ {":+", defaultWhenNotEmpty},
+ {"+", defaultWhenSet},
+ }
+ sort.Slice(interpolationMapping, func(i, j int) bool {
+ idxI := strings.Index(template, interpolationMapping[i].string)
+ idxJ := strings.Index(template, interpolationMapping[j].string)
+ if idxI < 0 {
+ return false
+ }
+ if idxJ < 0 {
+ return true
+ }
+ return idxI < idxJ
+ })
+
+ return interpolationMapping[0].string, interpolationMapping[0].SubstituteFunc
+}
+
+func getFirstBraceClosingIndex(s string) int {
+ openVariableBraces := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '}' {
+ openVariableBraces--
+ if openVariableBraces == 0 {
+ return i
+ }
+ }
+ if s[i] == '{' {
+ openVariableBraces++
+ i++
+ }
+ }
+ return -1
+}
+
+// Substitute variables in the string with their values
+func Substitute(template string, mapping Mapping) (string, error) {
+ return SubstituteWith(template, mapping, DefaultPattern)
+}
+
+// Soft default (fall back if unset or empty)
+func defaultWhenEmptyOrUnset(substitution string, mapping Mapping) (string, bool, error) {
+ return withDefaultWhenAbsence(substitution, mapping, true)
+}
+
+// Hard default (fall back if-and-only-if empty)
+func defaultWhenUnset(substitution string, mapping Mapping) (string, bool, error) {
+ return withDefaultWhenAbsence(substitution, mapping, false)
+}
+
+func defaultWhenNotEmpty(substitution string, mapping Mapping) (string, bool, error) {
+ return withDefaultWhenPresence(substitution, mapping, true)
+}
+
+func defaultWhenSet(substitution string, mapping Mapping) (string, bool, error) {
+ return withDefaultWhenPresence(substitution, mapping, false)
+}
+
+func requiredErrorWhenEmptyOrUnset(substitution string, mapping Mapping) (string, bool, error) {
+ return withRequired(substitution, mapping, ":?", func(v string) bool { return v != "" })
+}
+
+func requiredErrorWhenUnset(substitution string, mapping Mapping) (string, bool, error) {
+ return withRequired(substitution, mapping, "?", func(_ string) bool { return true })
+}
+
+func withDefaultWhenPresence(substitution string, mapping Mapping, notEmpty bool) (string, bool, error) {
+ sep := "+"
+ if notEmpty {
+ sep = ":+"
+ }
+ if !strings.Contains(substitution, sep) {
+ return "", false, nil
+ }
+ name, defaultValue := partition(substitution, sep)
+ value, ok := mapping(name)
+ if ok && (!notEmpty || (notEmpty && value != "")) {
+ defaultValue, err := Substitute(defaultValue, mapping)
+ if err != nil {
+ return "", false, err
+ }
+ return defaultValue, true, nil
+ }
+ return value, true, nil
+}
+
+func withDefaultWhenAbsence(substitution string, mapping Mapping, emptyOrUnset bool) (string, bool, error) {
+ sep := "-"
+ if emptyOrUnset {
+ sep = ":-"
+ }
+ if !strings.Contains(substitution, sep) {
+ return "", false, nil
+ }
+ name, defaultValue := partition(substitution, sep)
+ value, ok := mapping(name)
+ if !ok || (emptyOrUnset && value == "") {
+ defaultValue, err := Substitute(defaultValue, mapping)
+ if err != nil {
+ return "", false, err
+ }
+ return defaultValue, true, nil
+ }
+ return value, true, nil
+}
+
+func withRequired(substitution string, mapping Mapping, sep string, valid func(string) bool) (string, bool, error) {
+ if !strings.Contains(substitution, sep) {
+ return "", false, nil
+ }
+ name, errorMessage := partition(substitution, sep)
+ value, ok := mapping(name)
+ if !ok || !valid(value) {
+ errorMessage, err := Substitute(errorMessage, mapping)
+ if err != nil {
+ return "", false, err
+ }
+ return "", true, &MissingRequiredError{
+ Reason: errorMessage,
+ Variable: name,
+ }
+ }
+ return value, true, nil
+}
+
+func matchGroups(matches []string, pattern *regexp.Regexp) map[string]string {
+ groups := make(map[string]string)
+ for i, name := range pattern.SubexpNames()[1:] {
+ groups[name] = matches[i+1]
+ }
+ return groups
+}
+
+// Split the string at the first occurrence of sep, and return the part before the separator,
+// and the part after the separator.
+//
+// If the separator is not found, return the string itself, followed by an empty string.
+func partition(s, sep string) (string, string) {
+ if strings.Contains(s, sep) {
+ parts := strings.SplitN(s, sep, 2)
+ return parts[0], parts[1]
+ }
+ return s, ""
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/template/variables.go b/vendor/github.com/compose-spec/compose-go/v2/template/variables.go
new file mode 100644
index 0000000000..d293fa5063
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/template/variables.go
@@ -0,0 +1,180 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package template
+
+import (
+ "regexp"
+ "strings"
+)
+
+type Variable struct {
+ Name string
+ DefaultValue string
+ PresenceValue string
+ Required bool
+}
+
+// ExtractVariables returns a map of all the variables defined in the specified
+// compose file (dict representation) and their default value if any.
+func ExtractVariables(configDict map[string]interface{}, pattern *regexp.Regexp) map[string]Variable {
+ if pattern == nil {
+ pattern = DefaultPattern
+ }
+ return recurseExtract(configDict, pattern)
+}
+
+func recurseExtract(value interface{}, pattern *regexp.Regexp) map[string]Variable {
+ m := map[string]Variable{}
+
+ switch value := value.(type) {
+ case string:
+ if values, is := extractVariable(value, pattern); is {
+ for _, v := range values {
+ combineVariable(m, v)
+ }
+ }
+ case map[string]interface{}:
+ for _, elem := range value {
+ submap := recurseExtract(elem, pattern)
+ for _, value := range submap {
+ combineVariable(m, value)
+ }
+ }
+
+ case []interface{}:
+ for _, elem := range value {
+ submap := recurseExtract(elem, pattern)
+ for _, value := range submap {
+ combineVariable(m, value)
+ }
+ }
+ }
+
+ return m
+}
+
+// combineVariable merges a new occurrence of a variable into m: a variable
+// used several times in the configuration is required as soon as one of its
+// occurrences is (interpolation of that occurrence fails when the variable is
+// unset, whatever the other occurrences declare), and keeps the default and
+// presence values of the first occurrence defining one, so a plain `${VAR}`
+// occurrence doesn't erase the attributes of a `${VAR:?}` or `${VAR:-value}`
+// one.
+func combineVariable(m map[string]Variable, v Variable) {
+ existing, ok := m[v.Name]
+ if !ok {
+ m[v.Name] = v
+ return
+ }
+ existing.Required = existing.Required || v.Required
+ if existing.DefaultValue == "" {
+ existing.DefaultValue = v.DefaultValue
+ }
+ if existing.PresenceValue == "" {
+ existing.PresenceValue = v.PresenceValue
+ }
+ m[v.Name] = existing
+}
+
+func extractVariable(value interface{}, pattern *regexp.Regexp) ([]Variable, bool) {
+ sValue, ok := value.(string)
+ if !ok {
+ return []Variable{}, false
+ }
+ matches := pattern.FindAllStringSubmatch(sValue, -1)
+ if len(matches) == 0 {
+ return []Variable{}, false
+ }
+ values := []Variable{}
+ for _, match := range matches {
+ groups := matchGroups(match, pattern)
+ if escaped := groups[groupEscaped]; escaped != "" {
+ continue
+ }
+ val := groups[groupNamed]
+ if val == "" {
+ val = groups[groupBraced]
+ s := match[0]
+ i := getFirstBraceClosingIndex(s)
+ if i > 0 {
+ val = s[2:i]
+ if len(s) > i {
+ if v, b := extractVariable(s[i+1:], pattern); b {
+ values = append(values, v...)
+ }
+ }
+ }
+ }
+ name := val
+ var defaultValue string
+ var presenceValue string
+ var required bool
+ i := strings.IndexFunc(val, func(r rune) bool {
+ if r >= 'a' && r <= 'z' {
+ return false
+ }
+ if r >= 'A' && r <= 'Z' {
+ return false
+ }
+ if r >= '0' && r <= '9' {
+ return false
+ }
+ if r == '_' {
+ return false
+ }
+ return true
+ })
+
+ if i > 0 {
+ name = val[:i]
+ rest := val[i:]
+ switch {
+ case strings.HasPrefix(rest, ":?"):
+ required = true
+ case strings.HasPrefix(rest, "?"):
+ required = true
+ case strings.HasPrefix(rest, ":-"):
+ defaultValue = rest[2:]
+ case strings.HasPrefix(rest, "-"):
+ defaultValue = rest[1:]
+ case strings.HasPrefix(rest, ":+"):
+ presenceValue = rest[2:]
+ case strings.HasPrefix(rest, "+"):
+ presenceValue = rest[1:]
+ }
+ }
+
+ values = append(values, Variable{
+ Name: name,
+ DefaultValue: defaultValue,
+ PresenceValue: presenceValue,
+ Required: required,
+ })
+
+ if defaultValue != "" {
+ if v, b := extractVariable(defaultValue, pattern); b {
+ values = append(values, v...)
+ }
+ }
+ if presenceValue != "" {
+ if v, b := extractVariable(presenceValue, pattern); b {
+ values = append(values, v...)
+ }
+ }
+ }
+ return values, len(values) > 0
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/build.go b/vendor/github.com/compose-spec/compose-go/v2/transform/build.go
new file mode 100644
index 0000000000..90a996ccd6
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/build.go
@@ -0,0 +1,48 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformBuild(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return transformMapping(v, p, ignoreParseError)
+ case string:
+ return map[string]any{
+ "context": v,
+ }, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for build", p, v)
+ }
+}
+
+func defaultBuildContext(data any, _ tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ if _, ok := v["context"]; !ok {
+ v["context"] = "."
+ }
+ return v, nil
+ default:
+ return data, nil
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/canonical.go b/vendor/github.com/compose-spec/compose-go/v2/transform/canonical.go
new file mode 100644
index 0000000000..65f59f9d95
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/canonical.go
@@ -0,0 +1,145 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// Func is a function that can transform data at a specific path
+type Func func(data any, p tree.Path, ignoreParseError bool) (any, error)
+
+var transformers = map[tree.Path]Func{}
+
+func init() {
+ // container_spec-level canonicalizations: shared by anything declaring a
+ // container — services, jobs, and pre_start init containers
+ for _, prefix := range []tree.Path{"services.*", "jobs.*", "services.*.pre_start.*"} {
+ transformers[prefix+".env_file"] = transformEnvFile
+ transformers[prefix+".label_file"] = transformStringOrList
+ transformers[prefix+".gpus"] = transformGpus
+ transformers[prefix+".networks"] = transformStringSliceToMap
+ transformers[prefix+".models"] = transformStringSliceToMap
+ transformers[prefix+".volumes.*"] = transformVolumeMount
+ transformers[prefix+".dns"] = transformStringOrList
+ transformers[prefix+".devices.*"] = transformDeviceMapping
+ transformers[prefix+".secrets.*"] = transformFileMount
+ transformers[prefix+".configs.*"] = transformFileMount
+ transformers[prefix+".ulimits.*"] = transformUlimits
+ }
+ // workload_spec and service-level canonicalizations
+ for _, prefix := range []tree.Path{"services", "jobs"} {
+ transformers[prefix+".*"] = transformService
+ transformers[prefix+".*.build.secrets.*"] = transformFileMount
+ transformers[prefix+".*.build.provenance"] = transformStringOrX
+ transformers[prefix+".*.build.sbom"] = transformStringOrX
+ transformers[prefix+".*.build.additional_contexts"] = transformKeyValue
+ transformers[prefix+".*.depends_on"] = transformDependsOn
+ transformers[prefix+".*.extends"] = transformExtends
+ transformers[prefix+".*.ports"] = transformPorts
+ transformers[prefix+".*.build"] = transformBuild
+ transformers[prefix+".*.build.ssh"] = transformSSH
+ transformers[prefix+".*.build.ulimits.*"] = transformUlimits
+ }
+ transformers["jobs.*.triggers.schedule.*"] = transformSchedule
+ transformers["services.*.develop.watch.*.ignore"] = transformStringOrList
+ transformers["services.*.develop.watch.*.include"] = transformStringOrList
+ transformers["volumes.*"] = transformMaybeExternal
+ transformers["networks.*"] = transformMaybeExternal
+ transformers["secrets.*"] = transformMaybeExternal
+ transformers["configs.*"] = transformMaybeExternal
+ transformers["include.*"] = transformInclude
+}
+
+func transformStringOrList(data any, _ tree.Path, _ bool) (any, error) {
+ switch t := data.(type) {
+ case string:
+ return []any{t}, nil
+ default:
+ return data, nil
+ }
+}
+
+// Canonical transforms a compose model into canonical syntax
+func Canonical(yaml map[string]any, ignoreParseError bool) (map[string]any, error) {
+ canonical, err := transform(yaml, tree.NewPath(), ignoreParseError)
+ if err != nil {
+ return nil, err
+ }
+ return canonical.(map[string]any), nil
+}
+
+func transform(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ for pattern, transformer := range transformers {
+ if p.Matches(pattern) {
+ t, err := transformer(data, p, ignoreParseError)
+ if err != nil {
+ return nil, err
+ }
+ return t, nil
+ }
+ }
+ switch v := data.(type) {
+ case map[string]any:
+ a, err := transformMapping(v, p, ignoreParseError)
+ if err != nil {
+ return a, err
+ }
+ return v, nil
+ case []any:
+ a, err := transformSequence(v, p, ignoreParseError)
+ if err != nil {
+ return a, err
+ }
+ return v, nil
+ default:
+ return data, nil
+ }
+}
+
+func transformSequence(v []any, p tree.Path, ignoreParseError bool) ([]any, error) {
+ for i, e := range v {
+ t, err := transform(e, p.Next("[]"), ignoreParseError)
+ if err != nil {
+ return nil, err
+ }
+ v[i] = t
+ }
+ return v, nil
+}
+
+func transformMapping(v map[string]any, p tree.Path, ignoreParseError bool) (map[string]any, error) {
+ for k, e := range v {
+ t, err := transform(e, p.Next(k), ignoreParseError)
+ if err != nil {
+ return nil, err
+ }
+ v[k] = t
+ }
+ return v, nil
+}
+
+func transformStringOrX(data any, _ tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case string:
+ return v, nil
+ default:
+ return fmt.Sprint(v), nil
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/defaults.go b/vendor/github.com/compose-spec/compose-go/v2/transform/defaults.go
new file mode 100644
index 0000000000..f8de3ff8ba
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/defaults.go
@@ -0,0 +1,101 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// DefaultValues contains the default value transformers for compose fields
+var DefaultValues = map[tree.Path]Func{}
+
+func init() {
+ // container_spec-level defaults, applied wherever a container is declared
+ for _, prefix := range []tree.Path{"services", "jobs"} {
+ DefaultValues[prefix+".*.build"] = defaultBuildContext
+ DefaultValues[prefix+".*.secrets.*"] = defaultSecretMount
+ DefaultValues[prefix+".*.ports.*"] = portDefaults
+ DefaultValues[prefix+".*.gpus.*"] = deviceRequestDefaults
+ DefaultValues[prefix+".*.volumes.*.bind"] = defaultVolumeBind
+ }
+ // deploy is service-only
+ DefaultValues["services.*.deploy.resources.reservations.devices.*"] = deviceRequestDefaults
+}
+
+// RegisterDefaultValue registers a custom transformer for the given path pattern
+func RegisterDefaultValue(path string, transformer Func) {
+ DefaultValues[tree.Path(path)] = transformer
+}
+
+// SetDefaultValues transforms a compose model to set default values to missing attributes
+func SetDefaultValues(yaml map[string]any) (map[string]any, error) {
+ result, err := setDefaults(yaml, tree.NewPath())
+ if err != nil {
+ return nil, err
+ }
+ return result.(map[string]any), nil
+}
+
+func setDefaults(data any, p tree.Path) (any, error) {
+ for pattern, transformer := range DefaultValues {
+ if p.Matches(pattern) {
+ t, err := transformer(data, p, false)
+ if err != nil {
+ return nil, err
+ }
+ return t, nil
+ }
+ }
+ switch v := data.(type) {
+ case map[string]any:
+ a, err := setDefaultsMapping(v, p)
+ if err != nil {
+ return a, err
+ }
+ return v, nil
+ case []any:
+ a, err := setDefaultsSequence(v, p)
+ if err != nil {
+ return a, err
+ }
+ return v, nil
+ default:
+ return data, nil
+ }
+}
+
+func setDefaultsSequence(v []any, p tree.Path) ([]any, error) {
+ for i, e := range v {
+ t, err := setDefaults(e, p.Next("[]"))
+ if err != nil {
+ return nil, err
+ }
+ v[i] = t
+ }
+ return v, nil
+}
+
+func setDefaultsMapping(v map[string]any, p tree.Path) (map[string]any, error) {
+ for k, e := range v {
+ t, err := setDefaults(e, p.Next(k))
+ if err != nil {
+ return nil, err
+ }
+ v[k] = t
+ }
+ return v, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/dependson.go b/vendor/github.com/compose-spec/compose-go/v2/transform/dependson.go
new file mode 100644
index 0000000000..0a72ffa412
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/dependson.go
@@ -0,0 +1,53 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformDependsOn(data any, p tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ for i, e := range v {
+ d, ok := e.(map[string]any)
+ if !ok {
+ return nil, fmt.Errorf("%s.%s: unsupported value %s", p, i, v)
+ }
+ if _, ok := d["condition"]; !ok {
+ d["condition"] = "service_started"
+ }
+ if _, ok := d["required"]; !ok {
+ d["required"] = true
+ }
+ }
+ return v, nil
+ case []any:
+ d := map[string]any{}
+ for _, k := range v {
+ d[k.(string)] = map[string]any{
+ "condition": "service_started",
+ "required": true,
+ }
+ }
+ return d, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for depend_on", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/device.go b/vendor/github.com/compose-spec/compose-go/v2/transform/device.go
new file mode 100644
index 0000000000..351d81513f
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/device.go
@@ -0,0 +1,60 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformDeviceMapping(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return v, nil
+ case string:
+ src := ""
+ dst := ""
+ permissions := "rwm"
+ arr := strings.Split(v, ":")
+ switch len(arr) {
+ case 3:
+ permissions = arr[2]
+ fallthrough
+ case 2:
+ dst = arr[1]
+ fallthrough
+ case 1:
+ src = arr[0]
+ default:
+ if !ignoreParseError {
+ return nil, fmt.Errorf("confusing device mapping, please use long syntax: %s", v)
+ }
+ }
+ if dst == "" {
+ dst = src
+ }
+ return map[string]any{
+ "source": src,
+ "target": dst,
+ "permissions": permissions,
+ }, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for service volume mount", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/devices.go b/vendor/github.com/compose-spec/compose-go/v2/transform/devices.go
new file mode 100644
index 0000000000..5de0613c74
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/devices.go
@@ -0,0 +1,36 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func deviceRequestDefaults(data any, p tree.Path, _ bool) (any, error) {
+ v, ok := data.(map[string]any)
+ if !ok {
+ return data, fmt.Errorf("%s: invalid type %T for device request", p, v)
+ }
+ _, hasCount := v["count"]
+ _, hasIDs := v["device_ids"]
+ if !hasCount && !hasIDs {
+ v["count"] = "all"
+ }
+ return v, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/envfile.go b/vendor/github.com/compose-spec/compose-go/v2/transform/envfile.go
new file mode 100644
index 0000000000..e51005309c
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/envfile.go
@@ -0,0 +1,55 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformEnvFile(data any, p tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case string:
+ return []any{
+ transformEnvFileValue(v),
+ }, nil
+ case []any:
+ for i, e := range v {
+ v[i] = transformEnvFileValue(e)
+ }
+ return v, nil
+ default:
+ return nil, fmt.Errorf("%s: invalid type %T for env_file", p, v)
+ }
+}
+
+func transformEnvFileValue(data any) any {
+ switch v := data.(type) {
+ case string:
+ return map[string]any{
+ "path": v,
+ "required": true,
+ }
+ case map[string]any:
+ if _, ok := v["required"]; !ok {
+ v["required"] = true
+ }
+ return v
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/extends.go b/vendor/github.com/compose-spec/compose-go/v2/transform/extends.go
new file mode 100644
index 0000000000..e0f9be2d14
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/extends.go
@@ -0,0 +1,36 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformExtends(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return transformMapping(v, p, ignoreParseError)
+ case string:
+ return map[string]any{
+ "service": v,
+ }, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for extends", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/external.go b/vendor/github.com/compose-spec/compose-go/v2/transform/external.go
new file mode 100644
index 0000000000..025deaa299
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/external.go
@@ -0,0 +1,58 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+ "github.com/sirupsen/logrus"
+)
+
+func transformMaybeExternal(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ if data == nil {
+ return nil, nil
+ }
+ m, ok := data.(map[string]any)
+ if !ok {
+ return nil, fmt.Errorf("%s: must be a mapping", p)
+ }
+ resource, err := transformMapping(m, p, ignoreParseError)
+ if err != nil {
+ return nil, err
+ }
+
+ if ext, ok := resource["external"]; ok {
+ name, named := resource["name"]
+ if external, ok := ext.(map[string]any); ok {
+ resource["external"] = true
+ if extname, extNamed := external["name"]; extNamed {
+ logrus.Warnf("%s: external.name is deprecated. Please set name and external: true", p)
+ if named && extname != name {
+ return nil, fmt.Errorf("%s: name and external.name conflict; only use name", p)
+ }
+ if !named {
+ // adopt (deprecated) external.name if set
+ resource["name"] = extname
+ return resource, nil
+ }
+ }
+ }
+ }
+
+ return resource, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/gpus.go b/vendor/github.com/compose-spec/compose-go/v2/transform/gpus.go
new file mode 100644
index 0000000000..3c91b63bd0
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/gpus.go
@@ -0,0 +1,38 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformGpus(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case []any:
+ return transformSequence(v, p, ignoreParseError)
+ case string:
+ return []any{
+ map[string]any{
+ "count": "all",
+ },
+ }, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for gpus", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/include.go b/vendor/github.com/compose-spec/compose-go/v2/transform/include.go
new file mode 100644
index 0000000000..8a80439e4a
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/include.go
@@ -0,0 +1,36 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformInclude(data any, p tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return v, nil
+ case string:
+ return map[string]any{
+ "path": v,
+ }, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for external", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/mapping.go b/vendor/github.com/compose-spec/compose-go/v2/transform/mapping.go
new file mode 100644
index 0000000000..007aa9ed56
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/mapping.go
@@ -0,0 +1,46 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformKeyValue(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return v, nil
+ case []any:
+ mapping := map[string]any{}
+ for _, e := range v {
+ before, after, found := strings.Cut(e.(string), "=")
+ if !found {
+ if ignoreParseError {
+ return data, nil
+ }
+ return nil, fmt.Errorf("%s: invalid value %s, expected key=value", p, e)
+ }
+ mapping[before] = after
+ }
+ return mapping, nil
+ default:
+ return nil, fmt.Errorf("%s: invalid type %T", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/ports.go b/vendor/github.com/compose-spec/compose-go/v2/transform/ports.go
new file mode 100644
index 0000000000..68e26f3d4e
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/ports.go
@@ -0,0 +1,104 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+ "github.com/compose-spec/compose-go/v2/types"
+ "github.com/go-viper/mapstructure/v2"
+)
+
+func transformPorts(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch entries := data.(type) {
+ case []any:
+ // We process the list instead of individual items here.
+ // The reason is that one entry might be mapped to multiple ServicePortConfig.
+ // Therefore we take an input of a list and return an output of a list.
+ var ports []any
+ for _, entry := range entries {
+ switch value := entry.(type) {
+ case int:
+ parsed, err := types.ParsePortConfig(fmt.Sprint(value))
+ if err != nil {
+ return data, err
+ }
+ for _, v := range parsed {
+ m, err := encode(v)
+ if err != nil {
+ return nil, err
+ }
+ ports = append(ports, m)
+ }
+ case string:
+ parsed, err := types.ParsePortConfig(value)
+ if err != nil {
+ if ignoreParseError {
+ return data, nil
+ }
+ return nil, err
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, v := range parsed {
+ m, err := encode(v)
+ if err != nil {
+ return nil, err
+ }
+ ports = append(ports, m)
+ }
+ case map[string]any:
+ ports = append(ports, value)
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for port", p, value)
+ }
+ }
+ return ports, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for port", p, entries)
+ }
+}
+
+func encode(v any) (map[string]any, error) {
+ m := map[string]any{}
+ decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
+ Result: &m,
+ TagName: "yaml",
+ })
+ if err != nil {
+ return nil, err
+ }
+ err = decoder.Decode(v)
+ return m, err
+}
+
+func portDefaults(data any, _ tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ if _, ok := v["protocol"]; !ok {
+ v["protocol"] = "tcp"
+ }
+ if _, ok := v["mode"]; !ok {
+ v["mode"] = "ingress"
+ }
+ return v, nil
+ default:
+ return data, nil
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/schedule.go b/vendor/github.com/compose-spec/compose-go/v2/transform/schedule.go
new file mode 100644
index 0000000000..dde1e84d84
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/schedule.go
@@ -0,0 +1,39 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+// transformSchedule canonicalizes a job trigger schedule entry: a plain
+// crontab expression (short syntax) becomes a schedule object declaring only
+// `cron`, following the same short/long syntax model as `volumes`.
+func transformSchedule(data any, p tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case string:
+ return map[string]any{
+ "cron": v,
+ }, nil
+ case map[string]any:
+ return v, nil
+ default:
+ return nil, fmt.Errorf("%s: invalid type %T for schedule entry", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/secrets.go b/vendor/github.com/compose-spec/compose-go/v2/transform/secrets.go
new file mode 100644
index 0000000000..c2db135238
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/secrets.go
@@ -0,0 +1,49 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformFileMount(data any, p tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return data, nil
+ case string:
+ return map[string]any{
+ "source": v,
+ }, nil
+ default:
+ return nil, fmt.Errorf("%s: unsupported type %T", p, data)
+ }
+}
+
+func defaultSecretMount(data any, p tree.Path, _ bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ source := v["source"]
+ if _, ok := v["target"]; !ok {
+ v["target"] = fmt.Sprintf("/run/secrets/%s", source)
+ }
+ return v, nil
+ default:
+ return nil, fmt.Errorf("%s: unsupported type %T", p, data)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/services.go b/vendor/github.com/compose-spec/compose-go/v2/transform/services.go
new file mode 100644
index 0000000000..d9df42c8a5
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/services.go
@@ -0,0 +1,41 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformService(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch value := data.(type) {
+ case map[string]any:
+ return transformMapping(value, p, ignoreParseError)
+ default:
+ return value, nil
+ }
+}
+
+func transformStringSliceToMap(data any, _ tree.Path, _ bool) (any, error) {
+ if slice, ok := data.([]any); ok {
+ mapping := make(map[string]any, len(slice))
+ for _, net := range slice {
+ mapping[net.(string)] = nil
+ }
+ return mapping, nil
+ }
+ return data, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/ssh.go b/vendor/github.com/compose-spec/compose-go/v2/transform/ssh.go
new file mode 100644
index 0000000000..84a83684d8
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/ssh.go
@@ -0,0 +1,54 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformSSH(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return v, nil
+ case []any:
+ result := make(map[string]any, len(v))
+ for _, e := range v {
+ s, ok := e.(string)
+ if !ok {
+ return nil, fmt.Errorf("invalid ssh key type %T", e)
+ }
+ id, path, ok := strings.Cut(s, "=")
+ if !ok {
+ if id != "default" {
+ if ignoreParseError {
+ return data, nil
+ }
+ return nil, fmt.Errorf("invalid ssh key %q", s)
+ }
+ result[id] = nil
+ continue
+ }
+ result[id] = path
+ }
+ return result, nil
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for ssh", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/ulimits.go b/vendor/github.com/compose-spec/compose-go/v2/transform/ulimits.go
new file mode 100644
index 0000000000..9a9962bd84
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/ulimits.go
@@ -0,0 +1,39 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformUlimits(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return v, nil
+ case int:
+ return v, nil
+ case string:
+ if ignoreParseError {
+ return v, nil
+ }
+ return data, fmt.Errorf("%s: invalid type %T for ulimits", p, v)
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for ulimits", p, v)
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/transform/volume.go b/vendor/github.com/compose-spec/compose-go/v2/transform/volume.go
new file mode 100644
index 0000000000..6aa59cf15b
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/transform/volume.go
@@ -0,0 +1,63 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package transform
+
+import (
+ "fmt"
+ "path"
+
+ "github.com/compose-spec/compose-go/v2/format"
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func transformVolumeMount(data any, p tree.Path, ignoreParseError bool) (any, error) {
+ switch v := data.(type) {
+ case map[string]any:
+ return v, nil
+ case string:
+ volume, err := format.ParseVolume(v) // TODO(ndeloof) ParseVolume should not rely on types and return map[string]
+ if err != nil {
+ if ignoreParseError {
+ return v, nil
+ }
+ return nil, err
+ }
+ volume.Target = cleanTarget(volume.Target)
+
+ return encode(volume)
+ default:
+ return data, fmt.Errorf("%s: invalid type %T for service volume mount", p, v)
+ }
+}
+
+func cleanTarget(target string) string {
+ if target == "" {
+ return ""
+ }
+ return path.Clean(target)
+}
+
+func defaultVolumeBind(data any, p tree.Path, _ bool) (any, error) {
+ bind, ok := data.(map[string]any)
+ if !ok {
+ return data, fmt.Errorf("%s: invalid type %T for service volume bind", p, data)
+ }
+ if _, ok := bind["create_host_path"]; !ok {
+ bind["create_host_path"] = true
+ }
+ return bind, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/tree/matcher.go b/vendor/github.com/compose-spec/compose-go/v2/tree/matcher.go
new file mode 100644
index 0000000000..bb8d01a91b
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/tree/matcher.go
@@ -0,0 +1,74 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package tree
+
+// Matcher matches concrete attribute paths against a set of declared path
+// patterns. Patterns use the same tokens as [Path.Matches]: [PathMatchAll]
+// for any mapping key and [PathMatchList] for sequence items.
+//
+// Matching is exact by construction — declaring a path accepts that node
+// only, not its subtree — so removing one leaf from a declared set reliably
+// surfaces it. [Matcher.MayContain] tells a caller walking a nested
+// structure when descending can still reach a declared node.
+type Matcher struct {
+ patterns [][]string
+}
+
+// NewMatcher returns a Matcher for the given path patterns.
+func NewMatcher(patterns ...Path) *Matcher {
+ m := &Matcher{patterns: make([][]string, 0, len(patterns))}
+ for _, pattern := range patterns {
+ m.patterns = append(m.patterns, pattern.Parts())
+ }
+ return m
+}
+
+// Matches reports whether path matches one of the declared patterns.
+func (m *Matcher) Matches(path Path) bool {
+ parts := path.Parts()
+ for _, pattern := range m.patterns {
+ if len(pattern) == len(parts) && matchParts(pattern, parts) {
+ return true
+ }
+ }
+ return false
+}
+
+// MayContain reports whether path is a strict ancestor of at least one
+// pattern: even when the node itself is not declared, a declared attribute
+// lives somewhere underneath it.
+func (m *Matcher) MayContain(path Path) bool {
+ parts := path.Parts()
+ for _, pattern := range m.patterns {
+ if len(pattern) > len(parts) && matchParts(pattern[:len(parts)], parts) {
+ return true
+ }
+ }
+ return false
+}
+
+func matchParts(pattern, parts []string) bool {
+ for i, part := range parts {
+ switch pattern[i] {
+ case PathMatchAll, part:
+ continue
+ default:
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/tree/path.go b/vendor/github.com/compose-spec/compose-go/v2/tree/path.go
new file mode 100644
index 0000000000..f8a8d9a64a
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/tree/path.go
@@ -0,0 +1,87 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package tree
+
+import (
+ "strings"
+)
+
+const pathSeparator = "."
+
+// PathMatchAll is a token used as part of a Path to match any key at that level
+// in the nested structure
+const PathMatchAll = "*"
+
+// PathMatchList is a token used as part of a Path to match items in a list
+const PathMatchList = "[]"
+
+// Path is a dotted path of keys to a value in a nested mapping structure. A *
+// section in a path will match any key in the mapping structure.
+type Path string
+
+// NewPath returns a new Path
+func NewPath(items ...string) Path {
+ return Path(strings.Join(items, pathSeparator))
+}
+
+// Next returns a new path by append part to the current path
+func (p Path) Next(part string) Path {
+ if p == "" {
+ return Path(part)
+ }
+ part = strings.ReplaceAll(part, pathSeparator, "👻")
+ return Path(string(p) + pathSeparator + part)
+}
+
+func (p Path) Parts() []string {
+ return strings.Split(string(p), pathSeparator)
+}
+
+func (p Path) Matches(pattern Path) bool {
+ patternParts := pattern.Parts()
+ parts := p.Parts()
+
+ if len(patternParts) != len(parts) {
+ return false
+ }
+ for index, part := range parts {
+ switch patternParts[index] {
+ case PathMatchAll, part:
+ continue
+ default:
+ return false
+ }
+ }
+ return true
+}
+
+func (p Path) Last() string {
+ parts := p.Parts()
+ return parts[len(parts)-1]
+}
+
+func (p Path) Parent() Path {
+ index := strings.LastIndex(string(p), pathSeparator)
+ if index > 0 {
+ return p[0:index]
+ }
+ return ""
+}
+
+func (p Path) String() string {
+ return strings.ReplaceAll(string(p), "👻", pathSeparator)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/build.go b/vendor/github.com/compose-spec/compose-go/v2/types/build.go
new file mode 100644
index 0000000000..9893140075
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/build.go
@@ -0,0 +1,48 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+// BuildConfig is a type for build
+type BuildConfig struct {
+ Context string `yaml:"context,omitempty" json:"context,omitempty"`
+ Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
+ DockerfileInline string `yaml:"dockerfile_inline,omitempty" json:"dockerfile_inline,omitempty"`
+ Entitlements []string `yaml:"entitlements,omitempty" json:"entitlements,omitempty"`
+ Args MappingWithEquals `yaml:"args,omitempty" json:"args,omitempty"`
+ Provenance string `yaml:"provenance,omitempty" json:"provenance,omitempty"`
+ SBOM string `yaml:"sbom,omitempty" json:"sbom,omitempty"`
+ SSH SSHConfig `yaml:"ssh,omitempty" json:"ssh,omitempty"`
+ Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
+ CacheFrom StringList `yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
+ CacheTo StringList `yaml:"cache_to,omitempty" json:"cache_to,omitempty"`
+ NoCache bool `yaml:"no_cache,omitempty" json:"no_cache,omitempty"`
+ NoCacheFilter StringList `yaml:"no_cache_filter,omitempty" json:"no_cache_filter,omitempty"`
+ AdditionalContexts Mapping `yaml:"additional_contexts,omitempty" json:"additional_contexts,omitempty"`
+ Pull bool `yaml:"pull,omitempty" json:"pull,omitempty"`
+ ExtraHosts HostsList `yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
+ Isolation string `yaml:"isolation,omitempty" json:"isolation,omitempty"`
+ Network string `yaml:"network,omitempty" json:"network,omitempty"`
+ Target string `yaml:"target,omitempty" json:"target,omitempty"`
+ Secrets []ServiceSecretConfig `yaml:"secrets,omitempty" json:"secrets,omitempty"`
+ ShmSize UnitBytes `yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
+ Tags StringList `yaml:"tags,omitempty" json:"tags,omitempty"`
+ Ulimits map[string]*UlimitsConfig `yaml:"ulimits,omitempty" json:"ulimits,omitempty"`
+ Platforms StringList `yaml:"platforms,omitempty" json:"platforms,omitempty"`
+ Privileged bool `yaml:"privileged,omitempty" json:"privileged,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/bytes.go b/vendor/github.com/compose-spec/compose-go/v2/types/bytes.go
new file mode 100644
index 0000000000..0f039ab767
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/bytes.go
@@ -0,0 +1,90 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "encoding/json"
+ "fmt"
+ "strconv"
+
+ "github.com/docker/go-units"
+ "go.yaml.in/yaml/v4"
+)
+
+// UnitBytes is the bytes type
+type UnitBytes int64
+
+// MarshalYAML makes UnitBytes implement yaml.Marshaller
+func (u UnitBytes) MarshalYAML() (interface{}, error) {
+ return fmt.Sprintf("%d", u), nil
+}
+
+// MarshalJSON makes UnitBytes implement json.Marshaler
+func (u UnitBytes) MarshalJSON() ([]byte, error) {
+ return []byte(fmt.Sprintf(`"%d"`, u)), nil
+}
+
+// parseString parses a string into a UnitBytes value, supporting plain
+// integers, negative values (e.g., "-1"), and human-readable byte units
+// (e.g., "1g", "512m").
+func (u *UnitBytes) parseString(s string) error {
+ if n, err := strconv.ParseInt(s, 10, 64); err == nil {
+ *u = UnitBytes(n)
+ return nil
+ }
+ b, err := units.RAMInBytes(s)
+ *u = UnitBytes(b)
+ return err
+}
+
+// UnmarshalJSON makes UnitBytes implement json.Unmarshaler
+func (u *UnitBytes) UnmarshalJSON(data []byte) error {
+ var v int64
+ if err := json.Unmarshal(data, &v); err == nil {
+ *u = UnitBytes(v)
+ return nil
+ }
+ var s string
+ if err := json.Unmarshal(data, &s); err != nil {
+ return err
+ }
+ return u.parseString(s)
+}
+
+// UnmarshalYAML makes UnitBytes implement yaml.Unmarshaler
+func (u *UnitBytes) UnmarshalYAML(value *yaml.Node) error {
+ var v int64
+ if err := value.Decode(&v); err == nil {
+ *u = UnitBytes(v)
+ return nil
+ }
+ var s string
+ if err := value.Decode(&s); err != nil {
+ return err
+ }
+ return u.parseString(s)
+}
+
+func (u *UnitBytes) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case int:
+ *u = UnitBytes(v)
+ case string:
+ return u.parseString(v)
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/command.go b/vendor/github.com/compose-spec/compose-go/v2/types/command.go
new file mode 100644
index 0000000000..559dc3050d
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/command.go
@@ -0,0 +1,86 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import "github.com/mattn/go-shellwords"
+
+// ShellCommand is a string or list of string args.
+//
+// When marshaled to YAML, nil command fields will be omitted if `omitempty`
+// is specified as a struct tag. Explicitly empty commands (i.e. `[]` or
+// empty string will serialize to an empty array (`[]`).
+//
+// When marshaled to JSON, the `omitempty` struct must NOT be specified.
+// If the command field is nil, it will be serialized as `null`.
+// Explicitly empty commands (i.e. `[]` or empty string) will serialize to
+// an empty array (`[]`).
+//
+// The distinction between nil and explicitly empty is important to distinguish
+// between an unset value and a provided, but empty, value, which should be
+// preserved so that it can override any base value (e.g. container entrypoint).
+//
+// The different semantics between YAML and JSON are due to limitations with
+// JSON marshaling + `omitempty` in the Go stdlib, while go.yaml.in/yaml/v4 gives
+// us more flexibility via the yaml.IsZeroer interface.
+//
+// In the future, it might make sense to make fields of this type be
+// `*ShellCommand` to avoid this situation, but that would constitute a
+// breaking change.
+type ShellCommand []string
+
+// IsZero returns true if the slice is nil.
+//
+// Empty (but non-nil) slices are NOT considered zero values.
+func (s ShellCommand) IsZero() bool {
+ // we do NOT want len(s) == 0, ONLY explicitly nil
+ return s == nil
+}
+
+// MarshalYAML returns nil (which will be serialized as `null`) for nil slices
+// and delegates to the standard marshaller behavior otherwise.
+//
+// NOTE: Typically the nil case here is not hit because IsZero has already
+// short-circuited marshalling, but this ensures that the type serializes
+// accurately if the `omitempty` struct tag is omitted/forgotten.
+//
+// A similar MarshalJSON() implementation is not needed because the Go stdlib
+// already serializes nil slices to `null`, whereas go.yaml.in/yaml/v4 by default
+// serializes nil slices to `[]`.
+func (s ShellCommand) MarshalYAML() (interface{}, error) {
+ if s == nil {
+ return nil, nil
+ }
+ return []string(s), nil
+}
+
+func (s *ShellCommand) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case string:
+ cmd, err := shellwords.Parse(v)
+ if err != nil {
+ return err
+ }
+ *s = cmd
+ case []interface{}:
+ cmd := make([]string, len(v))
+ for i, s := range v {
+ cmd[i] = s.(string)
+ }
+ *s = cmd
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/config.go b/vendor/github.com/compose-spec/compose-go/v2/types/config.go
new file mode 100644
index 0000000000..9a0fdaf272
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/config.go
@@ -0,0 +1,145 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "encoding/json"
+ "runtime"
+ "strings"
+
+ "github.com/go-viper/mapstructure/v2"
+)
+
+// isCaseInsensitiveEnvVars is true on platforms where environment variable names are treated case-insensitively.
+var isCaseInsensitiveEnvVars = (runtime.GOOS == "windows")
+
+// ConfigDetails are the details about a group of ConfigFiles
+type ConfigDetails struct {
+ Version string
+ WorkingDir string
+ ConfigFiles []ConfigFile
+ Environment Mapping
+}
+
+// LookupEnv provides a lookup function for environment variables
+func (cd *ConfigDetails) LookupEnv(key string) (string, bool) {
+ v, ok := cd.Environment[key]
+ if !isCaseInsensitiveEnvVars || ok {
+ return v, ok
+ }
+ // variable names must be treated case-insensitively on some platforms (that is, Windows).
+ // Resolves in this way:
+ // * Return the value if its name matches with the passed name case-sensitively.
+ // * Otherwise, return the value if its lower-cased name matches lower-cased passed name.
+ // * The value is indefinite if multiple variables match.
+ lowerKey := strings.ToLower(key)
+ for k, v := range cd.Environment {
+ if strings.ToLower(k) == lowerKey {
+ return v, true
+ }
+ }
+ return "", false
+}
+
+// ConfigFile is a filename and the contents of the file as a Dict
+type ConfigFile struct {
+ // Filename is the name of the yaml configuration file
+ Filename string
+ // Content is the raw yaml content. Will be loaded from Filename if not set
+ Content []byte
+ // Config if the yaml tree for this config file. Will be parsed from Content if not set
+ Config map[string]interface{}
+}
+
+func (cf ConfigFile) IsStdin() bool {
+ return cf.Filename == "-"
+}
+
+func ToConfigFiles(path []string) (f []ConfigFile) {
+ for _, p := range path {
+ f = append(f, ConfigFile{Filename: p})
+ }
+ return
+}
+
+// Config is a full compose file configuration and model
+type Config struct {
+ Filename string `yaml:"-" json:"-"`
+ Name string `yaml:"name,omitempty" json:"name,omitempty"`
+ Services Services `yaml:"services" json:"services"`
+ Networks Networks `yaml:"networks,omitempty" json:"networks,omitempty"`
+ Volumes Volumes `yaml:"volumes,omitempty" json:"volumes,omitempty"`
+ Secrets Secrets `yaml:"secrets,omitempty" json:"secrets,omitempty"`
+ Configs Configs `yaml:"configs,omitempty" json:"configs,omitempty"`
+ Extensions Extensions `yaml:",inline" json:"-"`
+ Include []IncludeConfig `yaml:"include,omitempty" json:"include,omitempty"`
+}
+
+// Volumes is a map of VolumeConfig
+type Volumes map[string]VolumeConfig
+
+// Networks is a map of NetworkConfig
+type Networks map[string]NetworkConfig
+
+// Secrets is a map of SecretConfig
+type Secrets map[string]SecretConfig
+
+// Configs is a map of ConfigObjConfig
+type Configs map[string]ConfigObjConfig
+
+type Models map[string]ModelConfig
+
+// Extensions is a map of custom extension
+type Extensions map[string]any
+
+func (e Extensions) DeepCopy(t Extensions) {
+ for k, v := range e {
+ t[k] = v
+ }
+}
+
+// MarshalJSON makes Config implement json.Marshaler
+func (c Config) MarshalJSON() ([]byte, error) {
+ m := map[string]interface{}{
+ "services": c.Services,
+ }
+
+ if len(c.Networks) > 0 {
+ m["networks"] = c.Networks
+ }
+ if len(c.Volumes) > 0 {
+ m["volumes"] = c.Volumes
+ }
+ if len(c.Secrets) > 0 {
+ m["secrets"] = c.Secrets
+ }
+ if len(c.Configs) > 0 {
+ m["configs"] = c.Configs
+ }
+ for k, v := range c.Extensions {
+ m[k] = v
+ }
+ return json.Marshal(m)
+}
+
+func (e Extensions) Get(name string, target interface{}) (bool, error) {
+ if v, ok := e[name]; ok {
+ err := mapstructure.Decode(v, target)
+ return true, err
+ }
+ return false, nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/container_spec_attributes.gen.go b/vendor/github.com/compose-spec/compose-go/v2/types/container_spec_attributes.gen.go
new file mode 100644
index 0000000000..189fe9994b
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/container_spec_attributes.gen.go
@@ -0,0 +1,85 @@
+// Code generated by internal/generate/containerspec. DO NOT EDIT.
+
+package types
+
+// ContainerSpecAttributes lists the yaml attributes of ContainerSpec —
+// the boundary between the container specification and workload or
+// service-only attributes, as consumed by the pre_start inheritance
+// resolution.
+var ContainerSpecAttributes = []string{
+ "annotations",
+ "blkio_config",
+ "cap_add",
+ "cap_drop",
+ "cgroup",
+ "cgroup_parent",
+ "command",
+ "configs",
+ "cpu_count",
+ "cpu_percent",
+ "cpu_period",
+ "cpu_quota",
+ "cpu_rt_period",
+ "cpu_rt_runtime",
+ "cpu_shares",
+ "cpus",
+ "cpuset",
+ "credential_spec",
+ "device_cgroup_rules",
+ "devices",
+ "dns",
+ "dns_opt",
+ "dns_search",
+ "domainname",
+ "entrypoint",
+ "env_file",
+ "environment",
+ "extra_hosts",
+ "gpus",
+ "group_add",
+ "hostname",
+ "image",
+ "init",
+ "ipc",
+ "isolation",
+ "label_file",
+ "labels",
+ "log_driver",
+ "log_opt",
+ "logging",
+ "mac_address",
+ "mem_limit",
+ "mem_reservation",
+ "mem_swappiness",
+ "memswap_limit",
+ "models",
+ "network_mode",
+ "networks",
+ "oom_kill_disable",
+ "oom_score_adj",
+ "pid",
+ "pids_limit",
+ "platform",
+ "privileged",
+ "pull_policy",
+ "pull_refresh_after",
+ "read_only",
+ "runtime",
+ "secrets",
+ "security_opt",
+ "shm_size",
+ "stop_grace_period",
+ "stop_signal",
+ "storage_opt",
+ "sysctls",
+ "tmpfs",
+ "ulimits",
+ "use_api_socket",
+ "user",
+ "userns_mode",
+ "uts",
+ "volume_driver",
+ "volumes",
+ "volumes_from",
+ "working_dir",
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/cpus.go b/vendor/github.com/compose-spec/compose-go/v2/types/cpus.go
new file mode 100644
index 0000000000..f32c6e6212
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/cpus.go
@@ -0,0 +1,48 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "fmt"
+ "strconv"
+)
+
+type NanoCPUs float32
+
+func (n *NanoCPUs) DecodeMapstructure(a any) error {
+ switch v := a.(type) {
+ case string:
+ f, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ return err
+ }
+ *n = NanoCPUs(f)
+ case int:
+ *n = NanoCPUs(v)
+ case float32:
+ *n = NanoCPUs(v)
+ case float64:
+ *n = NanoCPUs(v)
+ default:
+ return fmt.Errorf("unexpected value type %T for cpus", v)
+ }
+ return nil
+}
+
+func (n *NanoCPUs) Value() float32 {
+ return float32(*n)
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/derived.gen.go b/vendor/github.com/compose-spec/compose-go/v2/types/derived.gen.go
new file mode 100644
index 0000000000..6b1d3aa374
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/derived.gen.go
@@ -0,0 +1,2620 @@
+// Code generated by goderive DO NOT EDIT.
+
+package types
+
+// deriveDeepCopyProject recursively copies the contents of src into dst.
+func deriveDeepCopyProject(dst, src *Project) {
+ dst.Name = src.Name
+ dst.WorkingDir = src.WorkingDir
+ if src.Services != nil {
+ dst.Services = make(map[string]ServiceConfig, len(src.Services))
+ deriveDeepCopy(dst.Services, src.Services)
+ } else {
+ dst.Services = nil
+ }
+ if src.Jobs != nil {
+ dst.Jobs = make(map[string]JobConfig, len(src.Jobs))
+ deriveDeepCopy_(dst.Jobs, src.Jobs)
+ } else {
+ dst.Jobs = nil
+ }
+ if src.Networks != nil {
+ dst.Networks = make(map[string]NetworkConfig, len(src.Networks))
+ deriveDeepCopy_1(dst.Networks, src.Networks)
+ } else {
+ dst.Networks = nil
+ }
+ if src.Volumes != nil {
+ dst.Volumes = make(map[string]VolumeConfig, len(src.Volumes))
+ deriveDeepCopy_2(dst.Volumes, src.Volumes)
+ } else {
+ dst.Volumes = nil
+ }
+ if src.Secrets != nil {
+ dst.Secrets = make(map[string]SecretConfig, len(src.Secrets))
+ deriveDeepCopy_3(dst.Secrets, src.Secrets)
+ } else {
+ dst.Secrets = nil
+ }
+ if src.Configs != nil {
+ dst.Configs = make(map[string]ConfigObjConfig, len(src.Configs))
+ deriveDeepCopy_4(dst.Configs, src.Configs)
+ } else {
+ dst.Configs = nil
+ }
+ if src.Models != nil {
+ dst.Models = make(map[string]ModelConfig, len(src.Models))
+ deriveDeepCopy_5(dst.Models, src.Models)
+ } else {
+ dst.Models = nil
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+ if src.ComposeFiles == nil {
+ dst.ComposeFiles = nil
+ } else {
+ if dst.ComposeFiles != nil {
+ if len(src.ComposeFiles) > len(dst.ComposeFiles) {
+ if cap(dst.ComposeFiles) >= len(src.ComposeFiles) {
+ dst.ComposeFiles = (dst.ComposeFiles)[:len(src.ComposeFiles)]
+ } else {
+ dst.ComposeFiles = make([]string, len(src.ComposeFiles))
+ }
+ } else if len(src.ComposeFiles) < len(dst.ComposeFiles) {
+ dst.ComposeFiles = (dst.ComposeFiles)[:len(src.ComposeFiles)]
+ }
+ } else {
+ dst.ComposeFiles = make([]string, len(src.ComposeFiles))
+ }
+ copy(dst.ComposeFiles, src.ComposeFiles)
+ }
+ if src.Environment != nil {
+ dst.Environment = make(map[string]string, len(src.Environment))
+ deriveDeepCopy_6(dst.Environment, src.Environment)
+ } else {
+ dst.Environment = nil
+ }
+ if src.DisabledServices != nil {
+ dst.DisabledServices = make(map[string]ServiceConfig, len(src.DisabledServices))
+ deriveDeepCopy(dst.DisabledServices, src.DisabledServices)
+ } else {
+ dst.DisabledServices = nil
+ }
+ if src.DisabledJobs != nil {
+ dst.DisabledJobs = make(map[string]JobConfig, len(src.DisabledJobs))
+ deriveDeepCopy_(dst.DisabledJobs, src.DisabledJobs)
+ } else {
+ dst.DisabledJobs = nil
+ }
+ if src.Profiles == nil {
+ dst.Profiles = nil
+ } else {
+ if dst.Profiles != nil {
+ if len(src.Profiles) > len(dst.Profiles) {
+ if cap(dst.Profiles) >= len(src.Profiles) {
+ dst.Profiles = (dst.Profiles)[:len(src.Profiles)]
+ } else {
+ dst.Profiles = make([]string, len(src.Profiles))
+ }
+ } else if len(src.Profiles) < len(dst.Profiles) {
+ dst.Profiles = (dst.Profiles)[:len(src.Profiles)]
+ }
+ } else {
+ dst.Profiles = make([]string, len(src.Profiles))
+ }
+ copy(dst.Profiles, src.Profiles)
+ }
+}
+
+// deriveDeepCopyService recursively copies the contents of src into dst.
+func deriveDeepCopyService(dst, src *ServiceConfig) {
+ dst.Name = src.Name
+ if src.Profiles == nil {
+ dst.Profiles = nil
+ } else {
+ if dst.Profiles != nil {
+ if len(src.Profiles) > len(dst.Profiles) {
+ if cap(dst.Profiles) >= len(src.Profiles) {
+ dst.Profiles = (dst.Profiles)[:len(src.Profiles)]
+ } else {
+ dst.Profiles = make([]string, len(src.Profiles))
+ }
+ } else if len(src.Profiles) < len(dst.Profiles) {
+ dst.Profiles = (dst.Profiles)[:len(src.Profiles)]
+ }
+ } else {
+ dst.Profiles = make([]string, len(src.Profiles))
+ }
+ copy(dst.Profiles, src.Profiles)
+ }
+ if src.Deploy == nil {
+ dst.Deploy = nil
+ } else {
+ dst.Deploy = new(DeployConfig)
+ deriveDeepCopy_7(dst.Deploy, src.Deploy)
+ }
+ if src.Develop == nil {
+ dst.Develop = nil
+ } else {
+ dst.Develop = new(DevelopConfig)
+ deriveDeepCopy_8(dst.Develop, src.Develop)
+ }
+ dst.Restart = src.Restart
+ if src.Scale == nil {
+ dst.Scale = nil
+ } else {
+ dst.Scale = new(int)
+ *dst.Scale = *src.Scale
+ }
+ if src.Attach == nil {
+ dst.Attach = nil
+ } else {
+ dst.Attach = new(bool)
+ *dst.Attach = *src.Attach
+ }
+ dst.ContainerName = src.ContainerName
+ if src.Provider == nil {
+ dst.Provider = nil
+ } else {
+ dst.Provider = new(ServiceProviderConfig)
+ deriveDeepCopy_9(dst.Provider, src.Provider)
+ }
+ if src.Extends == nil {
+ dst.Extends = nil
+ } else {
+ dst.Extends = new(ExtendsConfig)
+ *dst.Extends = *src.Extends
+ }
+ if src.ExternalLinks == nil {
+ dst.ExternalLinks = nil
+ } else {
+ if dst.ExternalLinks != nil {
+ if len(src.ExternalLinks) > len(dst.ExternalLinks) {
+ if cap(dst.ExternalLinks) >= len(src.ExternalLinks) {
+ dst.ExternalLinks = (dst.ExternalLinks)[:len(src.ExternalLinks)]
+ } else {
+ dst.ExternalLinks = make([]string, len(src.ExternalLinks))
+ }
+ } else if len(src.ExternalLinks) < len(dst.ExternalLinks) {
+ dst.ExternalLinks = (dst.ExternalLinks)[:len(src.ExternalLinks)]
+ }
+ } else {
+ dst.ExternalLinks = make([]string, len(src.ExternalLinks))
+ }
+ copy(dst.ExternalLinks, src.ExternalLinks)
+ }
+ if src.Links == nil {
+ dst.Links = nil
+ } else {
+ if dst.Links != nil {
+ if len(src.Links) > len(dst.Links) {
+ if cap(dst.Links) >= len(src.Links) {
+ dst.Links = (dst.Links)[:len(src.Links)]
+ } else {
+ dst.Links = make([]string, len(src.Links))
+ }
+ } else if len(src.Links) < len(dst.Links) {
+ dst.Links = (dst.Links)[:len(src.Links)]
+ }
+ } else {
+ dst.Links = make([]string, len(src.Links))
+ }
+ copy(dst.Links, src.Links)
+ }
+ dst.Net = src.Net
+ if src.PreStart == nil {
+ dst.PreStart = nil
+ } else {
+ if dst.PreStart != nil {
+ if len(src.PreStart) > len(dst.PreStart) {
+ if cap(dst.PreStart) >= len(src.PreStart) {
+ dst.PreStart = (dst.PreStart)[:len(src.PreStart)]
+ } else {
+ dst.PreStart = make([]PreStartHook, len(src.PreStart))
+ }
+ } else if len(src.PreStart) < len(dst.PreStart) {
+ dst.PreStart = (dst.PreStart)[:len(src.PreStart)]
+ }
+ } else {
+ dst.PreStart = make([]PreStartHook, len(src.PreStart))
+ }
+ deriveDeepCopy_10(dst.PreStart, src.PreStart)
+ }
+ if src.PostStart == nil {
+ dst.PostStart = nil
+ } else {
+ if dst.PostStart != nil {
+ if len(src.PostStart) > len(dst.PostStart) {
+ if cap(dst.PostStart) >= len(src.PostStart) {
+ dst.PostStart = (dst.PostStart)[:len(src.PostStart)]
+ } else {
+ dst.PostStart = make([]ServiceHook, len(src.PostStart))
+ }
+ } else if len(src.PostStart) < len(dst.PostStart) {
+ dst.PostStart = (dst.PostStart)[:len(src.PostStart)]
+ }
+ } else {
+ dst.PostStart = make([]ServiceHook, len(src.PostStart))
+ }
+ deriveDeepCopy_11(dst.PostStart, src.PostStart)
+ }
+ if src.PreStop == nil {
+ dst.PreStop = nil
+ } else {
+ if dst.PreStop != nil {
+ if len(src.PreStop) > len(dst.PreStop) {
+ if cap(dst.PreStop) >= len(src.PreStop) {
+ dst.PreStop = (dst.PreStop)[:len(src.PreStop)]
+ } else {
+ dst.PreStop = make([]ServiceHook, len(src.PreStop))
+ }
+ } else if len(src.PreStop) < len(dst.PreStop) {
+ dst.PreStop = (dst.PreStop)[:len(src.PreStop)]
+ }
+ } else {
+ dst.PreStop = make([]ServiceHook, len(src.PreStop))
+ }
+ deriveDeepCopy_11(dst.PreStop, src.PreStop)
+ }
+ func() {
+ field := new(ContainerSpec)
+ deriveDeepCopy_12(field, &src.ContainerSpec)
+ dst.ContainerSpec = *field
+ }()
+ func() {
+ field := new(WorkloadSpec)
+ deriveDeepCopy_13(field, &src.WorkloadSpec)
+ dst.WorkloadSpec = *field
+ }()
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy recursively copies the contents of src into dst.
+func deriveDeepCopy(dst, src map[string]ServiceConfig) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(ServiceConfig)
+ deriveDeepCopyService(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_ recursively copies the contents of src into dst.
+func deriveDeepCopy_(dst, src map[string]JobConfig) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(JobConfig)
+ deriveDeepCopy_14(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_1 recursively copies the contents of src into dst.
+func deriveDeepCopy_1(dst, src map[string]NetworkConfig) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(NetworkConfig)
+ deriveDeepCopy_15(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_2 recursively copies the contents of src into dst.
+func deriveDeepCopy_2(dst, src map[string]VolumeConfig) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(VolumeConfig)
+ deriveDeepCopy_16(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_3 recursively copies the contents of src into dst.
+func deriveDeepCopy_3(dst, src map[string]SecretConfig) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(SecretConfig)
+ deriveDeepCopy_17(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_4 recursively copies the contents of src into dst.
+func deriveDeepCopy_4(dst, src map[string]ConfigObjConfig) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(ConfigObjConfig)
+ deriveDeepCopy_18(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_5 recursively copies the contents of src into dst.
+func deriveDeepCopy_5(dst, src map[string]ModelConfig) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(ModelConfig)
+ deriveDeepCopy_19(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_6 recursively copies the contents of src into dst.
+func deriveDeepCopy_6(dst, src map[string]string) {
+ for src_key, src_value := range src {
+ dst[src_key] = src_value
+ }
+}
+
+// deriveDeepCopy_7 recursively copies the contents of src into dst.
+func deriveDeepCopy_7(dst, src *DeployConfig) {
+ dst.Mode = src.Mode
+ if src.Replicas == nil {
+ dst.Replicas = nil
+ } else {
+ dst.Replicas = new(int)
+ *dst.Replicas = *src.Replicas
+ }
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ if src.UpdateConfig == nil {
+ dst.UpdateConfig = nil
+ } else {
+ dst.UpdateConfig = new(UpdateConfig)
+ deriveDeepCopy_20(dst.UpdateConfig, src.UpdateConfig)
+ }
+ if src.RollbackConfig == nil {
+ dst.RollbackConfig = nil
+ } else {
+ dst.RollbackConfig = new(UpdateConfig)
+ deriveDeepCopy_20(dst.RollbackConfig, src.RollbackConfig)
+ }
+ func() {
+ field := new(Resources)
+ deriveDeepCopy_21(field, &src.Resources)
+ dst.Resources = *field
+ }()
+ if src.RestartPolicy == nil {
+ dst.RestartPolicy = nil
+ } else {
+ dst.RestartPolicy = new(RestartPolicy)
+ deriveDeepCopy_22(dst.RestartPolicy, src.RestartPolicy)
+ }
+ func() {
+ field := new(Placement)
+ deriveDeepCopy_23(field, &src.Placement)
+ dst.Placement = *field
+ }()
+ dst.EndpointMode = src.EndpointMode
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_8 recursively copies the contents of src into dst.
+func deriveDeepCopy_8(dst, src *DevelopConfig) {
+ if src.Watch == nil {
+ dst.Watch = nil
+ } else {
+ if dst.Watch != nil {
+ if len(src.Watch) > len(dst.Watch) {
+ if cap(dst.Watch) >= len(src.Watch) {
+ dst.Watch = (dst.Watch)[:len(src.Watch)]
+ } else {
+ dst.Watch = make([]Trigger, len(src.Watch))
+ }
+ } else if len(src.Watch) < len(dst.Watch) {
+ dst.Watch = (dst.Watch)[:len(src.Watch)]
+ }
+ } else {
+ dst.Watch = make([]Trigger, len(src.Watch))
+ }
+ deriveDeepCopy_24(dst.Watch, src.Watch)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_9 recursively copies the contents of src into dst.
+func deriveDeepCopy_9(dst, src *ServiceProviderConfig) {
+ dst.Type = src.Type
+ if src.Options != nil {
+ dst.Options = make(map[string][]string, len(src.Options))
+ deriveDeepCopy_25(dst.Options, src.Options)
+ } else {
+ dst.Options = nil
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_10 recursively copies the contents of src into dst.
+func deriveDeepCopy_10(dst, src []PreStartHook) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(PreStartHook)
+ deriveDeepCopy_26(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_11 recursively copies the contents of src into dst.
+func deriveDeepCopy_11(dst, src []ServiceHook) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(ServiceHook)
+ deriveDeepCopy_27(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_12 recursively copies the contents of src into dst.
+func deriveDeepCopy_12(dst, src *ContainerSpec) {
+ if src.Annotations != nil {
+ dst.Annotations = make(map[string]string, len(src.Annotations))
+ deriveDeepCopy_6(dst.Annotations, src.Annotations)
+ } else {
+ dst.Annotations = nil
+ }
+ if src.BlkioConfig == nil {
+ dst.BlkioConfig = nil
+ } else {
+ dst.BlkioConfig = new(BlkioConfig)
+ deriveDeepCopy_28(dst.BlkioConfig, src.BlkioConfig)
+ }
+ if src.CapAdd == nil {
+ dst.CapAdd = nil
+ } else {
+ if dst.CapAdd != nil {
+ if len(src.CapAdd) > len(dst.CapAdd) {
+ if cap(dst.CapAdd) >= len(src.CapAdd) {
+ dst.CapAdd = (dst.CapAdd)[:len(src.CapAdd)]
+ } else {
+ dst.CapAdd = make([]string, len(src.CapAdd))
+ }
+ } else if len(src.CapAdd) < len(dst.CapAdd) {
+ dst.CapAdd = (dst.CapAdd)[:len(src.CapAdd)]
+ }
+ } else {
+ dst.CapAdd = make([]string, len(src.CapAdd))
+ }
+ copy(dst.CapAdd, src.CapAdd)
+ }
+ if src.CapDrop == nil {
+ dst.CapDrop = nil
+ } else {
+ if dst.CapDrop != nil {
+ if len(src.CapDrop) > len(dst.CapDrop) {
+ if cap(dst.CapDrop) >= len(src.CapDrop) {
+ dst.CapDrop = (dst.CapDrop)[:len(src.CapDrop)]
+ } else {
+ dst.CapDrop = make([]string, len(src.CapDrop))
+ }
+ } else if len(src.CapDrop) < len(dst.CapDrop) {
+ dst.CapDrop = (dst.CapDrop)[:len(src.CapDrop)]
+ }
+ } else {
+ dst.CapDrop = make([]string, len(src.CapDrop))
+ }
+ copy(dst.CapDrop, src.CapDrop)
+ }
+ dst.CgroupParent = src.CgroupParent
+ dst.Cgroup = src.Cgroup
+ dst.CPUCount = src.CPUCount
+ dst.CPUPercent = src.CPUPercent
+ dst.CPUPeriod = src.CPUPeriod
+ dst.CPUQuota = src.CPUQuota
+ dst.CPURTPeriod = src.CPURTPeriod
+ dst.CPURTRuntime = src.CPURTRuntime
+ dst.CPUS = src.CPUS
+ dst.CPUSet = src.CPUSet
+ dst.CPUShares = src.CPUShares
+ if src.Command == nil {
+ dst.Command = nil
+ } else {
+ if dst.Command != nil {
+ if len(src.Command) > len(dst.Command) {
+ if cap(dst.Command) >= len(src.Command) {
+ dst.Command = (dst.Command)[:len(src.Command)]
+ } else {
+ dst.Command = make([]string, len(src.Command))
+ }
+ } else if len(src.Command) < len(dst.Command) {
+ dst.Command = (dst.Command)[:len(src.Command)]
+ }
+ } else {
+ dst.Command = make([]string, len(src.Command))
+ }
+ copy(dst.Command, src.Command)
+ }
+ if src.Configs == nil {
+ dst.Configs = nil
+ } else {
+ if dst.Configs != nil {
+ if len(src.Configs) > len(dst.Configs) {
+ if cap(dst.Configs) >= len(src.Configs) {
+ dst.Configs = (dst.Configs)[:len(src.Configs)]
+ } else {
+ dst.Configs = make([]ServiceConfigObjConfig, len(src.Configs))
+ }
+ } else if len(src.Configs) < len(dst.Configs) {
+ dst.Configs = (dst.Configs)[:len(src.Configs)]
+ }
+ } else {
+ dst.Configs = make([]ServiceConfigObjConfig, len(src.Configs))
+ }
+ deriveDeepCopy_29(dst.Configs, src.Configs)
+ }
+ if src.CredentialSpec == nil {
+ dst.CredentialSpec = nil
+ } else {
+ dst.CredentialSpec = new(CredentialSpecConfig)
+ deriveDeepCopy_30(dst.CredentialSpec, src.CredentialSpec)
+ }
+ if src.DeviceCgroupRules == nil {
+ dst.DeviceCgroupRules = nil
+ } else {
+ if dst.DeviceCgroupRules != nil {
+ if len(src.DeviceCgroupRules) > len(dst.DeviceCgroupRules) {
+ if cap(dst.DeviceCgroupRules) >= len(src.DeviceCgroupRules) {
+ dst.DeviceCgroupRules = (dst.DeviceCgroupRules)[:len(src.DeviceCgroupRules)]
+ } else {
+ dst.DeviceCgroupRules = make([]string, len(src.DeviceCgroupRules))
+ }
+ } else if len(src.DeviceCgroupRules) < len(dst.DeviceCgroupRules) {
+ dst.DeviceCgroupRules = (dst.DeviceCgroupRules)[:len(src.DeviceCgroupRules)]
+ }
+ } else {
+ dst.DeviceCgroupRules = make([]string, len(src.DeviceCgroupRules))
+ }
+ copy(dst.DeviceCgroupRules, src.DeviceCgroupRules)
+ }
+ if src.Devices == nil {
+ dst.Devices = nil
+ } else {
+ if dst.Devices != nil {
+ if len(src.Devices) > len(dst.Devices) {
+ if cap(dst.Devices) >= len(src.Devices) {
+ dst.Devices = (dst.Devices)[:len(src.Devices)]
+ } else {
+ dst.Devices = make([]DeviceMapping, len(src.Devices))
+ }
+ } else if len(src.Devices) < len(dst.Devices) {
+ dst.Devices = (dst.Devices)[:len(src.Devices)]
+ }
+ } else {
+ dst.Devices = make([]DeviceMapping, len(src.Devices))
+ }
+ deriveDeepCopy_31(dst.Devices, src.Devices)
+ }
+ if src.DNS == nil {
+ dst.DNS = nil
+ } else {
+ if dst.DNS != nil {
+ if len(src.DNS) > len(dst.DNS) {
+ if cap(dst.DNS) >= len(src.DNS) {
+ dst.DNS = (dst.DNS)[:len(src.DNS)]
+ } else {
+ dst.DNS = make([]string, len(src.DNS))
+ }
+ } else if len(src.DNS) < len(dst.DNS) {
+ dst.DNS = (dst.DNS)[:len(src.DNS)]
+ }
+ } else {
+ dst.DNS = make([]string, len(src.DNS))
+ }
+ copy(dst.DNS, src.DNS)
+ }
+ if src.DNSOpts == nil {
+ dst.DNSOpts = nil
+ } else {
+ if dst.DNSOpts != nil {
+ if len(src.DNSOpts) > len(dst.DNSOpts) {
+ if cap(dst.DNSOpts) >= len(src.DNSOpts) {
+ dst.DNSOpts = (dst.DNSOpts)[:len(src.DNSOpts)]
+ } else {
+ dst.DNSOpts = make([]string, len(src.DNSOpts))
+ }
+ } else if len(src.DNSOpts) < len(dst.DNSOpts) {
+ dst.DNSOpts = (dst.DNSOpts)[:len(src.DNSOpts)]
+ }
+ } else {
+ dst.DNSOpts = make([]string, len(src.DNSOpts))
+ }
+ copy(dst.DNSOpts, src.DNSOpts)
+ }
+ if src.DNSSearch == nil {
+ dst.DNSSearch = nil
+ } else {
+ if dst.DNSSearch != nil {
+ if len(src.DNSSearch) > len(dst.DNSSearch) {
+ if cap(dst.DNSSearch) >= len(src.DNSSearch) {
+ dst.DNSSearch = (dst.DNSSearch)[:len(src.DNSSearch)]
+ } else {
+ dst.DNSSearch = make([]string, len(src.DNSSearch))
+ }
+ } else if len(src.DNSSearch) < len(dst.DNSSearch) {
+ dst.DNSSearch = (dst.DNSSearch)[:len(src.DNSSearch)]
+ }
+ } else {
+ dst.DNSSearch = make([]string, len(src.DNSSearch))
+ }
+ copy(dst.DNSSearch, src.DNSSearch)
+ }
+ dst.DomainName = src.DomainName
+ if src.Entrypoint == nil {
+ dst.Entrypoint = nil
+ } else {
+ if dst.Entrypoint != nil {
+ if len(src.Entrypoint) > len(dst.Entrypoint) {
+ if cap(dst.Entrypoint) >= len(src.Entrypoint) {
+ dst.Entrypoint = (dst.Entrypoint)[:len(src.Entrypoint)]
+ } else {
+ dst.Entrypoint = make([]string, len(src.Entrypoint))
+ }
+ } else if len(src.Entrypoint) < len(dst.Entrypoint) {
+ dst.Entrypoint = (dst.Entrypoint)[:len(src.Entrypoint)]
+ }
+ } else {
+ dst.Entrypoint = make([]string, len(src.Entrypoint))
+ }
+ copy(dst.Entrypoint, src.Entrypoint)
+ }
+ if src.Environment != nil {
+ dst.Environment = make(map[string]*string, len(src.Environment))
+ deriveDeepCopy_32(dst.Environment, src.Environment)
+ } else {
+ dst.Environment = nil
+ }
+ if src.EnvFiles == nil {
+ dst.EnvFiles = nil
+ } else {
+ if dst.EnvFiles != nil {
+ if len(src.EnvFiles) > len(dst.EnvFiles) {
+ if cap(dst.EnvFiles) >= len(src.EnvFiles) {
+ dst.EnvFiles = (dst.EnvFiles)[:len(src.EnvFiles)]
+ } else {
+ dst.EnvFiles = make([]EnvFile, len(src.EnvFiles))
+ }
+ } else if len(src.EnvFiles) < len(dst.EnvFiles) {
+ dst.EnvFiles = (dst.EnvFiles)[:len(src.EnvFiles)]
+ }
+ } else {
+ dst.EnvFiles = make([]EnvFile, len(src.EnvFiles))
+ }
+ copy(dst.EnvFiles, src.EnvFiles)
+ }
+ if src.ExtraHosts != nil {
+ dst.ExtraHosts = make(map[string][]string, len(src.ExtraHosts))
+ deriveDeepCopy_25(dst.ExtraHosts, src.ExtraHosts)
+ } else {
+ dst.ExtraHosts = nil
+ }
+ if src.GroupAdd == nil {
+ dst.GroupAdd = nil
+ } else {
+ if dst.GroupAdd != nil {
+ if len(src.GroupAdd) > len(dst.GroupAdd) {
+ if cap(dst.GroupAdd) >= len(src.GroupAdd) {
+ dst.GroupAdd = (dst.GroupAdd)[:len(src.GroupAdd)]
+ } else {
+ dst.GroupAdd = make([]string, len(src.GroupAdd))
+ }
+ } else if len(src.GroupAdd) < len(dst.GroupAdd) {
+ dst.GroupAdd = (dst.GroupAdd)[:len(src.GroupAdd)]
+ }
+ } else {
+ dst.GroupAdd = make([]string, len(src.GroupAdd))
+ }
+ copy(dst.GroupAdd, src.GroupAdd)
+ }
+ if src.Gpus == nil {
+ dst.Gpus = nil
+ } else {
+ if dst.Gpus != nil {
+ if len(src.Gpus) > len(dst.Gpus) {
+ if cap(dst.Gpus) >= len(src.Gpus) {
+ dst.Gpus = (dst.Gpus)[:len(src.Gpus)]
+ } else {
+ dst.Gpus = make([]DeviceRequest, len(src.Gpus))
+ }
+ } else if len(src.Gpus) < len(dst.Gpus) {
+ dst.Gpus = (dst.Gpus)[:len(src.Gpus)]
+ }
+ } else {
+ dst.Gpus = make([]DeviceRequest, len(src.Gpus))
+ }
+ deriveDeepCopy_33(dst.Gpus, src.Gpus)
+ }
+ dst.Hostname = src.Hostname
+ dst.Image = src.Image
+ if src.Init == nil {
+ dst.Init = nil
+ } else {
+ dst.Init = new(bool)
+ *dst.Init = *src.Init
+ }
+ dst.Ipc = src.Ipc
+ dst.Isolation = src.Isolation
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ if src.LabelFiles == nil {
+ dst.LabelFiles = nil
+ } else {
+ if dst.LabelFiles != nil {
+ if len(src.LabelFiles) > len(dst.LabelFiles) {
+ if cap(dst.LabelFiles) >= len(src.LabelFiles) {
+ dst.LabelFiles = (dst.LabelFiles)[:len(src.LabelFiles)]
+ } else {
+ dst.LabelFiles = make([]string, len(src.LabelFiles))
+ }
+ } else if len(src.LabelFiles) < len(dst.LabelFiles) {
+ dst.LabelFiles = (dst.LabelFiles)[:len(src.LabelFiles)]
+ }
+ } else {
+ dst.LabelFiles = make([]string, len(src.LabelFiles))
+ }
+ copy(dst.LabelFiles, src.LabelFiles)
+ }
+ if src.CustomLabels != nil {
+ dst.CustomLabels = make(map[string]string, len(src.CustomLabels))
+ deriveDeepCopy_6(dst.CustomLabels, src.CustomLabels)
+ } else {
+ dst.CustomLabels = nil
+ }
+ if src.Logging == nil {
+ dst.Logging = nil
+ } else {
+ dst.Logging = new(LoggingConfig)
+ deriveDeepCopy_34(dst.Logging, src.Logging)
+ }
+ dst.LogDriver = src.LogDriver
+ if src.LogOpt != nil {
+ dst.LogOpt = make(map[string]string, len(src.LogOpt))
+ deriveDeepCopy_6(dst.LogOpt, src.LogOpt)
+ } else {
+ dst.LogOpt = nil
+ }
+ dst.MemLimit = src.MemLimit
+ dst.MemReservation = src.MemReservation
+ dst.MemSwapLimit = src.MemSwapLimit
+ dst.MemSwappiness = src.MemSwappiness
+ dst.MacAddress = src.MacAddress
+ if src.Models != nil {
+ dst.Models = make(map[string]*ServiceModelConfig, len(src.Models))
+ deriveDeepCopy_35(dst.Models, src.Models)
+ } else {
+ dst.Models = nil
+ }
+ dst.NetworkMode = src.NetworkMode
+ if src.Networks != nil {
+ dst.Networks = make(map[string]*ServiceNetworkConfig, len(src.Networks))
+ deriveDeepCopy_36(dst.Networks, src.Networks)
+ } else {
+ dst.Networks = nil
+ }
+ dst.OomKillDisable = src.OomKillDisable
+ dst.OomScoreAdj = src.OomScoreAdj
+ dst.Pid = src.Pid
+ dst.PidsLimit = src.PidsLimit
+ dst.Platform = src.Platform
+ dst.Privileged = src.Privileged
+ dst.PullPolicy = src.PullPolicy
+ dst.PullRefreshAfter = src.PullRefreshAfter
+ dst.ReadOnly = src.ReadOnly
+ dst.Runtime = src.Runtime
+ if src.Secrets == nil {
+ dst.Secrets = nil
+ } else {
+ if dst.Secrets != nil {
+ if len(src.Secrets) > len(dst.Secrets) {
+ if cap(dst.Secrets) >= len(src.Secrets) {
+ dst.Secrets = (dst.Secrets)[:len(src.Secrets)]
+ } else {
+ dst.Secrets = make([]ServiceSecretConfig, len(src.Secrets))
+ }
+ } else if len(src.Secrets) < len(dst.Secrets) {
+ dst.Secrets = (dst.Secrets)[:len(src.Secrets)]
+ }
+ } else {
+ dst.Secrets = make([]ServiceSecretConfig, len(src.Secrets))
+ }
+ deriveDeepCopy_37(dst.Secrets, src.Secrets)
+ }
+ if src.SecurityOpt == nil {
+ dst.SecurityOpt = nil
+ } else {
+ if dst.SecurityOpt != nil {
+ if len(src.SecurityOpt) > len(dst.SecurityOpt) {
+ if cap(dst.SecurityOpt) >= len(src.SecurityOpt) {
+ dst.SecurityOpt = (dst.SecurityOpt)[:len(src.SecurityOpt)]
+ } else {
+ dst.SecurityOpt = make([]string, len(src.SecurityOpt))
+ }
+ } else if len(src.SecurityOpt) < len(dst.SecurityOpt) {
+ dst.SecurityOpt = (dst.SecurityOpt)[:len(src.SecurityOpt)]
+ }
+ } else {
+ dst.SecurityOpt = make([]string, len(src.SecurityOpt))
+ }
+ copy(dst.SecurityOpt, src.SecurityOpt)
+ }
+ dst.ShmSize = src.ShmSize
+ if src.StopGracePeriod == nil {
+ dst.StopGracePeriod = nil
+ } else {
+ dst.StopGracePeriod = new(Duration)
+ *dst.StopGracePeriod = *src.StopGracePeriod
+ }
+ dst.StopSignal = src.StopSignal
+ if src.StorageOpt != nil {
+ dst.StorageOpt = make(map[string]string, len(src.StorageOpt))
+ deriveDeepCopy_6(dst.StorageOpt, src.StorageOpt)
+ } else {
+ dst.StorageOpt = nil
+ }
+ if src.Sysctls != nil {
+ dst.Sysctls = make(map[string]string, len(src.Sysctls))
+ deriveDeepCopy_6(dst.Sysctls, src.Sysctls)
+ } else {
+ dst.Sysctls = nil
+ }
+ if src.Tmpfs == nil {
+ dst.Tmpfs = nil
+ } else {
+ if dst.Tmpfs != nil {
+ if len(src.Tmpfs) > len(dst.Tmpfs) {
+ if cap(dst.Tmpfs) >= len(src.Tmpfs) {
+ dst.Tmpfs = (dst.Tmpfs)[:len(src.Tmpfs)]
+ } else {
+ dst.Tmpfs = make([]string, len(src.Tmpfs))
+ }
+ } else if len(src.Tmpfs) < len(dst.Tmpfs) {
+ dst.Tmpfs = (dst.Tmpfs)[:len(src.Tmpfs)]
+ }
+ } else {
+ dst.Tmpfs = make([]string, len(src.Tmpfs))
+ }
+ copy(dst.Tmpfs, src.Tmpfs)
+ }
+ if src.Ulimits != nil {
+ dst.Ulimits = make(map[string]*UlimitsConfig, len(src.Ulimits))
+ deriveDeepCopy_38(dst.Ulimits, src.Ulimits)
+ } else {
+ dst.Ulimits = nil
+ }
+ dst.UseAPISocket = src.UseAPISocket
+ dst.User = src.User
+ dst.UserNSMode = src.UserNSMode
+ dst.Uts = src.Uts
+ dst.VolumeDriver = src.VolumeDriver
+ if src.Volumes == nil {
+ dst.Volumes = nil
+ } else {
+ if dst.Volumes != nil {
+ if len(src.Volumes) > len(dst.Volumes) {
+ if cap(dst.Volumes) >= len(src.Volumes) {
+ dst.Volumes = (dst.Volumes)[:len(src.Volumes)]
+ } else {
+ dst.Volumes = make([]ServiceVolumeConfig, len(src.Volumes))
+ }
+ } else if len(src.Volumes) < len(dst.Volumes) {
+ dst.Volumes = (dst.Volumes)[:len(src.Volumes)]
+ }
+ } else {
+ dst.Volumes = make([]ServiceVolumeConfig, len(src.Volumes))
+ }
+ deriveDeepCopy_39(dst.Volumes, src.Volumes)
+ }
+ if src.VolumesFrom == nil {
+ dst.VolumesFrom = nil
+ } else {
+ if dst.VolumesFrom != nil {
+ if len(src.VolumesFrom) > len(dst.VolumesFrom) {
+ if cap(dst.VolumesFrom) >= len(src.VolumesFrom) {
+ dst.VolumesFrom = (dst.VolumesFrom)[:len(src.VolumesFrom)]
+ } else {
+ dst.VolumesFrom = make([]string, len(src.VolumesFrom))
+ }
+ } else if len(src.VolumesFrom) < len(dst.VolumesFrom) {
+ dst.VolumesFrom = (dst.VolumesFrom)[:len(src.VolumesFrom)]
+ }
+ } else {
+ dst.VolumesFrom = make([]string, len(src.VolumesFrom))
+ }
+ copy(dst.VolumesFrom, src.VolumesFrom)
+ }
+ dst.WorkingDir = src.WorkingDir
+}
+
+// deriveDeepCopy_13 recursively copies the contents of src into dst.
+func deriveDeepCopy_13(dst, src *WorkloadSpec) {
+ if src.Build == nil {
+ dst.Build = nil
+ } else {
+ dst.Build = new(BuildConfig)
+ deriveDeepCopy_40(dst.Build, src.Build)
+ }
+ if src.DependsOn != nil {
+ dst.DependsOn = make(map[string]ServiceDependency, len(src.DependsOn))
+ deriveDeepCopy_41(dst.DependsOn, src.DependsOn)
+ } else {
+ dst.DependsOn = nil
+ }
+ dst.Dockerfile = src.Dockerfile
+ if src.Expose == nil {
+ dst.Expose = nil
+ } else {
+ if dst.Expose != nil {
+ if len(src.Expose) > len(dst.Expose) {
+ if cap(dst.Expose) >= len(src.Expose) {
+ dst.Expose = (dst.Expose)[:len(src.Expose)]
+ } else {
+ dst.Expose = make([]string, len(src.Expose))
+ }
+ } else if len(src.Expose) < len(dst.Expose) {
+ dst.Expose = (dst.Expose)[:len(src.Expose)]
+ }
+ } else {
+ dst.Expose = make([]string, len(src.Expose))
+ }
+ copy(dst.Expose, src.Expose)
+ }
+ if src.HealthCheck == nil {
+ dst.HealthCheck = nil
+ } else {
+ dst.HealthCheck = new(HealthCheckConfig)
+ deriveDeepCopy_42(dst.HealthCheck, src.HealthCheck)
+ }
+ if src.Ports == nil {
+ dst.Ports = nil
+ } else {
+ if dst.Ports != nil {
+ if len(src.Ports) > len(dst.Ports) {
+ if cap(dst.Ports) >= len(src.Ports) {
+ dst.Ports = (dst.Ports)[:len(src.Ports)]
+ } else {
+ dst.Ports = make([]ServicePortConfig, len(src.Ports))
+ }
+ } else if len(src.Ports) < len(dst.Ports) {
+ dst.Ports = (dst.Ports)[:len(src.Ports)]
+ }
+ } else {
+ dst.Ports = make([]ServicePortConfig, len(src.Ports))
+ }
+ deriveDeepCopy_43(dst.Ports, src.Ports)
+ }
+ dst.StdinOpen = src.StdinOpen
+ dst.Tty = src.Tty
+}
+
+// deriveDeepCopy_14 recursively copies the contents of src into dst.
+func deriveDeepCopy_14(dst, src *JobConfig) {
+ dst.Name = src.Name
+ if src.Profiles == nil {
+ dst.Profiles = nil
+ } else {
+ if dst.Profiles != nil {
+ if len(src.Profiles) > len(dst.Profiles) {
+ if cap(dst.Profiles) >= len(src.Profiles) {
+ dst.Profiles = (dst.Profiles)[:len(src.Profiles)]
+ } else {
+ dst.Profiles = make([]string, len(src.Profiles))
+ }
+ } else if len(src.Profiles) < len(dst.Profiles) {
+ dst.Profiles = (dst.Profiles)[:len(src.Profiles)]
+ }
+ } else {
+ dst.Profiles = make([]string, len(src.Profiles))
+ }
+ copy(dst.Profiles, src.Profiles)
+ }
+ if src.Triggers == nil {
+ dst.Triggers = nil
+ } else {
+ dst.Triggers = new(TriggerConfig)
+ deriveDeepCopy_44(dst.Triggers, src.Triggers)
+ }
+ func() {
+ field := new(ContainerSpec)
+ deriveDeepCopy_12(field, &src.ContainerSpec)
+ dst.ContainerSpec = *field
+ }()
+ func() {
+ field := new(WorkloadSpec)
+ deriveDeepCopy_13(field, &src.WorkloadSpec)
+ dst.WorkloadSpec = *field
+ }()
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_15 recursively copies the contents of src into dst.
+func deriveDeepCopy_15(dst, src *NetworkConfig) {
+ dst.Name = src.Name
+ dst.Driver = src.Driver
+ if src.DriverOpts != nil {
+ dst.DriverOpts = make(map[string]string, len(src.DriverOpts))
+ deriveDeepCopy_6(dst.DriverOpts, src.DriverOpts)
+ } else {
+ dst.DriverOpts = nil
+ }
+ func() {
+ field := new(IPAMConfig)
+ deriveDeepCopy_45(field, &src.Ipam)
+ dst.Ipam = *field
+ }()
+ dst.External = src.External
+ dst.Internal = src.Internal
+ dst.Attachable = src.Attachable
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ if src.CustomLabels != nil {
+ dst.CustomLabels = make(map[string]string, len(src.CustomLabels))
+ deriveDeepCopy_6(dst.CustomLabels, src.CustomLabels)
+ } else {
+ dst.CustomLabels = nil
+ }
+ if src.EnableIPv4 == nil {
+ dst.EnableIPv4 = nil
+ } else {
+ dst.EnableIPv4 = new(bool)
+ *dst.EnableIPv4 = *src.EnableIPv4
+ }
+ if src.EnableIPv6 == nil {
+ dst.EnableIPv6 = nil
+ } else {
+ dst.EnableIPv6 = new(bool)
+ *dst.EnableIPv6 = *src.EnableIPv6
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_16 recursively copies the contents of src into dst.
+func deriveDeepCopy_16(dst, src *VolumeConfig) {
+ dst.Name = src.Name
+ dst.Driver = src.Driver
+ if src.DriverOpts != nil {
+ dst.DriverOpts = make(map[string]string, len(src.DriverOpts))
+ deriveDeepCopy_6(dst.DriverOpts, src.DriverOpts)
+ } else {
+ dst.DriverOpts = nil
+ }
+ dst.External = src.External
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ if src.CustomLabels != nil {
+ dst.CustomLabels = make(map[string]string, len(src.CustomLabels))
+ deriveDeepCopy_6(dst.CustomLabels, src.CustomLabels)
+ } else {
+ dst.CustomLabels = nil
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_17 recursively copies the contents of src into dst.
+func deriveDeepCopy_17(dst, src *SecretConfig) {
+ dst.Name = src.Name
+ dst.File = src.File
+ dst.Environment = src.Environment
+ dst.Content = src.Content
+ dst.marshallContent = src.marshallContent
+ dst.External = src.External
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ dst.Driver = src.Driver
+ if src.DriverOpts != nil {
+ dst.DriverOpts = make(map[string]string, len(src.DriverOpts))
+ deriveDeepCopy_6(dst.DriverOpts, src.DriverOpts)
+ } else {
+ dst.DriverOpts = nil
+ }
+ dst.TemplateDriver = src.TemplateDriver
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_18 recursively copies the contents of src into dst.
+func deriveDeepCopy_18(dst, src *ConfigObjConfig) {
+ dst.Name = src.Name
+ dst.File = src.File
+ dst.Environment = src.Environment
+ dst.Content = src.Content
+ dst.marshallContent = src.marshallContent
+ dst.External = src.External
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ dst.Driver = src.Driver
+ if src.DriverOpts != nil {
+ dst.DriverOpts = make(map[string]string, len(src.DriverOpts))
+ deriveDeepCopy_6(dst.DriverOpts, src.DriverOpts)
+ } else {
+ dst.DriverOpts = nil
+ }
+ dst.TemplateDriver = src.TemplateDriver
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_19 recursively copies the contents of src into dst.
+func deriveDeepCopy_19(dst, src *ModelConfig) {
+ dst.Name = src.Name
+ dst.Model = src.Model
+ dst.ContextSize = src.ContextSize
+ if src.RuntimeFlags == nil {
+ dst.RuntimeFlags = nil
+ } else {
+ if dst.RuntimeFlags != nil {
+ if len(src.RuntimeFlags) > len(dst.RuntimeFlags) {
+ if cap(dst.RuntimeFlags) >= len(src.RuntimeFlags) {
+ dst.RuntimeFlags = (dst.RuntimeFlags)[:len(src.RuntimeFlags)]
+ } else {
+ dst.RuntimeFlags = make([]string, len(src.RuntimeFlags))
+ }
+ } else if len(src.RuntimeFlags) < len(dst.RuntimeFlags) {
+ dst.RuntimeFlags = (dst.RuntimeFlags)[:len(src.RuntimeFlags)]
+ }
+ } else {
+ dst.RuntimeFlags = make([]string, len(src.RuntimeFlags))
+ }
+ copy(dst.RuntimeFlags, src.RuntimeFlags)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_20 recursively copies the contents of src into dst.
+func deriveDeepCopy_20(dst, src *UpdateConfig) {
+ if src.Parallelism == nil {
+ dst.Parallelism = nil
+ } else {
+ dst.Parallelism = new(uint64)
+ *dst.Parallelism = *src.Parallelism
+ }
+ dst.Delay = src.Delay
+ dst.FailureAction = src.FailureAction
+ dst.Monitor = src.Monitor
+ dst.MaxFailureRatio = src.MaxFailureRatio
+ dst.Order = src.Order
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_21 recursively copies the contents of src into dst.
+func deriveDeepCopy_21(dst, src *Resources) {
+ if src.Limits == nil {
+ dst.Limits = nil
+ } else {
+ dst.Limits = new(Resource)
+ deriveDeepCopy_46(dst.Limits, src.Limits)
+ }
+ if src.Reservations == nil {
+ dst.Reservations = nil
+ } else {
+ dst.Reservations = new(Resource)
+ deriveDeepCopy_46(dst.Reservations, src.Reservations)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_22 recursively copies the contents of src into dst.
+func deriveDeepCopy_22(dst, src *RestartPolicy) {
+ dst.Condition = src.Condition
+ if src.Delay == nil {
+ dst.Delay = nil
+ } else {
+ dst.Delay = new(Duration)
+ *dst.Delay = *src.Delay
+ }
+ if src.MaxAttempts == nil {
+ dst.MaxAttempts = nil
+ } else {
+ dst.MaxAttempts = new(uint64)
+ *dst.MaxAttempts = *src.MaxAttempts
+ }
+ if src.Window == nil {
+ dst.Window = nil
+ } else {
+ dst.Window = new(Duration)
+ *dst.Window = *src.Window
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_23 recursively copies the contents of src into dst.
+func deriveDeepCopy_23(dst, src *Placement) {
+ if src.Constraints == nil {
+ dst.Constraints = nil
+ } else {
+ if dst.Constraints != nil {
+ if len(src.Constraints) > len(dst.Constraints) {
+ if cap(dst.Constraints) >= len(src.Constraints) {
+ dst.Constraints = (dst.Constraints)[:len(src.Constraints)]
+ } else {
+ dst.Constraints = make([]string, len(src.Constraints))
+ }
+ } else if len(src.Constraints) < len(dst.Constraints) {
+ dst.Constraints = (dst.Constraints)[:len(src.Constraints)]
+ }
+ } else {
+ dst.Constraints = make([]string, len(src.Constraints))
+ }
+ copy(dst.Constraints, src.Constraints)
+ }
+ if src.Preferences == nil {
+ dst.Preferences = nil
+ } else {
+ if dst.Preferences != nil {
+ if len(src.Preferences) > len(dst.Preferences) {
+ if cap(dst.Preferences) >= len(src.Preferences) {
+ dst.Preferences = (dst.Preferences)[:len(src.Preferences)]
+ } else {
+ dst.Preferences = make([]PlacementPreferences, len(src.Preferences))
+ }
+ } else if len(src.Preferences) < len(dst.Preferences) {
+ dst.Preferences = (dst.Preferences)[:len(src.Preferences)]
+ }
+ } else {
+ dst.Preferences = make([]PlacementPreferences, len(src.Preferences))
+ }
+ deriveDeepCopy_47(dst.Preferences, src.Preferences)
+ }
+ dst.MaxReplicas = src.MaxReplicas
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_24 recursively copies the contents of src into dst.
+func deriveDeepCopy_24(dst, src []Trigger) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(Trigger)
+ deriveDeepCopy_48(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_25 recursively copies the contents of src into dst.
+func deriveDeepCopy_25(dst, src map[string][]string) {
+ for src_key, src_value := range src {
+ if src_value == nil {
+ dst[src_key] = nil
+ }
+ if src_value == nil {
+ dst[src_key] = nil
+ } else {
+ if dst[src_key] != nil {
+ if len(src_value) > len(dst[src_key]) {
+ if cap(dst[src_key]) >= len(src_value) {
+ dst[src_key] = (dst[src_key])[:len(src_value)]
+ } else {
+ dst[src_key] = make([]string, len(src_value))
+ }
+ } else if len(src_value) < len(dst[src_key]) {
+ dst[src_key] = (dst[src_key])[:len(src_value)]
+ }
+ } else {
+ dst[src_key] = make([]string, len(src_value))
+ }
+ copy(dst[src_key], src_value)
+ }
+ }
+}
+
+// deriveDeepCopy_26 recursively copies the contents of src into dst.
+func deriveDeepCopy_26(dst, src *PreStartHook) {
+ func() {
+ field := new(ContainerSpec)
+ deriveDeepCopy_12(field, &src.ContainerSpec)
+ dst.ContainerSpec = *field
+ }()
+ dst.PerReplica = src.PerReplica
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_27 recursively copies the contents of src into dst.
+func deriveDeepCopy_27(dst, src *ServiceHook) {
+ if src.Command == nil {
+ dst.Command = nil
+ } else {
+ if dst.Command != nil {
+ if len(src.Command) > len(dst.Command) {
+ if cap(dst.Command) >= len(src.Command) {
+ dst.Command = (dst.Command)[:len(src.Command)]
+ } else {
+ dst.Command = make([]string, len(src.Command))
+ }
+ } else if len(src.Command) < len(dst.Command) {
+ dst.Command = (dst.Command)[:len(src.Command)]
+ }
+ } else {
+ dst.Command = make([]string, len(src.Command))
+ }
+ copy(dst.Command, src.Command)
+ }
+ dst.User = src.User
+ dst.Privileged = src.Privileged
+ dst.WorkingDir = src.WorkingDir
+ if src.Environment != nil {
+ dst.Environment = make(map[string]*string, len(src.Environment))
+ deriveDeepCopy_32(dst.Environment, src.Environment)
+ } else {
+ dst.Environment = nil
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_28 recursively copies the contents of src into dst.
+func deriveDeepCopy_28(dst, src *BlkioConfig) {
+ dst.Weight = src.Weight
+ if src.WeightDevice == nil {
+ dst.WeightDevice = nil
+ } else {
+ if dst.WeightDevice != nil {
+ if len(src.WeightDevice) > len(dst.WeightDevice) {
+ if cap(dst.WeightDevice) >= len(src.WeightDevice) {
+ dst.WeightDevice = (dst.WeightDevice)[:len(src.WeightDevice)]
+ } else {
+ dst.WeightDevice = make([]WeightDevice, len(src.WeightDevice))
+ }
+ } else if len(src.WeightDevice) < len(dst.WeightDevice) {
+ dst.WeightDevice = (dst.WeightDevice)[:len(src.WeightDevice)]
+ }
+ } else {
+ dst.WeightDevice = make([]WeightDevice, len(src.WeightDevice))
+ }
+ deriveDeepCopy_49(dst.WeightDevice, src.WeightDevice)
+ }
+ if src.DeviceReadBps == nil {
+ dst.DeviceReadBps = nil
+ } else {
+ if dst.DeviceReadBps != nil {
+ if len(src.DeviceReadBps) > len(dst.DeviceReadBps) {
+ if cap(dst.DeviceReadBps) >= len(src.DeviceReadBps) {
+ dst.DeviceReadBps = (dst.DeviceReadBps)[:len(src.DeviceReadBps)]
+ } else {
+ dst.DeviceReadBps = make([]ThrottleDevice, len(src.DeviceReadBps))
+ }
+ } else if len(src.DeviceReadBps) < len(dst.DeviceReadBps) {
+ dst.DeviceReadBps = (dst.DeviceReadBps)[:len(src.DeviceReadBps)]
+ }
+ } else {
+ dst.DeviceReadBps = make([]ThrottleDevice, len(src.DeviceReadBps))
+ }
+ deriveDeepCopy_50(dst.DeviceReadBps, src.DeviceReadBps)
+ }
+ if src.DeviceReadIOps == nil {
+ dst.DeviceReadIOps = nil
+ } else {
+ if dst.DeviceReadIOps != nil {
+ if len(src.DeviceReadIOps) > len(dst.DeviceReadIOps) {
+ if cap(dst.DeviceReadIOps) >= len(src.DeviceReadIOps) {
+ dst.DeviceReadIOps = (dst.DeviceReadIOps)[:len(src.DeviceReadIOps)]
+ } else {
+ dst.DeviceReadIOps = make([]ThrottleDevice, len(src.DeviceReadIOps))
+ }
+ } else if len(src.DeviceReadIOps) < len(dst.DeviceReadIOps) {
+ dst.DeviceReadIOps = (dst.DeviceReadIOps)[:len(src.DeviceReadIOps)]
+ }
+ } else {
+ dst.DeviceReadIOps = make([]ThrottleDevice, len(src.DeviceReadIOps))
+ }
+ deriveDeepCopy_50(dst.DeviceReadIOps, src.DeviceReadIOps)
+ }
+ if src.DeviceWriteBps == nil {
+ dst.DeviceWriteBps = nil
+ } else {
+ if dst.DeviceWriteBps != nil {
+ if len(src.DeviceWriteBps) > len(dst.DeviceWriteBps) {
+ if cap(dst.DeviceWriteBps) >= len(src.DeviceWriteBps) {
+ dst.DeviceWriteBps = (dst.DeviceWriteBps)[:len(src.DeviceWriteBps)]
+ } else {
+ dst.DeviceWriteBps = make([]ThrottleDevice, len(src.DeviceWriteBps))
+ }
+ } else if len(src.DeviceWriteBps) < len(dst.DeviceWriteBps) {
+ dst.DeviceWriteBps = (dst.DeviceWriteBps)[:len(src.DeviceWriteBps)]
+ }
+ } else {
+ dst.DeviceWriteBps = make([]ThrottleDevice, len(src.DeviceWriteBps))
+ }
+ deriveDeepCopy_50(dst.DeviceWriteBps, src.DeviceWriteBps)
+ }
+ if src.DeviceWriteIOps == nil {
+ dst.DeviceWriteIOps = nil
+ } else {
+ if dst.DeviceWriteIOps != nil {
+ if len(src.DeviceWriteIOps) > len(dst.DeviceWriteIOps) {
+ if cap(dst.DeviceWriteIOps) >= len(src.DeviceWriteIOps) {
+ dst.DeviceWriteIOps = (dst.DeviceWriteIOps)[:len(src.DeviceWriteIOps)]
+ } else {
+ dst.DeviceWriteIOps = make([]ThrottleDevice, len(src.DeviceWriteIOps))
+ }
+ } else if len(src.DeviceWriteIOps) < len(dst.DeviceWriteIOps) {
+ dst.DeviceWriteIOps = (dst.DeviceWriteIOps)[:len(src.DeviceWriteIOps)]
+ }
+ } else {
+ dst.DeviceWriteIOps = make([]ThrottleDevice, len(src.DeviceWriteIOps))
+ }
+ deriveDeepCopy_50(dst.DeviceWriteIOps, src.DeviceWriteIOps)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_29 recursively copies the contents of src into dst.
+func deriveDeepCopy_29(dst, src []ServiceConfigObjConfig) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(ServiceConfigObjConfig)
+ deriveDeepCopy_51(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_30 recursively copies the contents of src into dst.
+func deriveDeepCopy_30(dst, src *CredentialSpecConfig) {
+ dst.Config = src.Config
+ dst.File = src.File
+ dst.Registry = src.Registry
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_31 recursively copies the contents of src into dst.
+func deriveDeepCopy_31(dst, src []DeviceMapping) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(DeviceMapping)
+ deriveDeepCopy_52(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_32 recursively copies the contents of src into dst.
+func deriveDeepCopy_32(dst, src map[string]*string) {
+ for src_key, src_value := range src {
+ if src_value == nil {
+ dst[src_key] = nil
+ }
+ if src_value == nil {
+ dst[src_key] = nil
+ } else {
+ dst[src_key] = new(string)
+ *dst[src_key] = *src_value
+ }
+ }
+}
+
+// deriveDeepCopy_33 recursively copies the contents of src into dst.
+func deriveDeepCopy_33(dst, src []DeviceRequest) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(DeviceRequest)
+ deriveDeepCopy_53(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_34 recursively copies the contents of src into dst.
+func deriveDeepCopy_34(dst, src *LoggingConfig) {
+ dst.Driver = src.Driver
+ if src.Options != nil {
+ dst.Options = make(map[string]string, len(src.Options))
+ deriveDeepCopy_6(dst.Options, src.Options)
+ } else {
+ dst.Options = nil
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_35 recursively copies the contents of src into dst.
+func deriveDeepCopy_35(dst, src map[string]*ServiceModelConfig) {
+ for src_key, src_value := range src {
+ if src_value == nil {
+ dst[src_key] = nil
+ }
+ if src_value == nil {
+ dst[src_key] = nil
+ } else {
+ dst[src_key] = new(ServiceModelConfig)
+ deriveDeepCopy_54(dst[src_key], src_value)
+ }
+ }
+}
+
+// deriveDeepCopy_36 recursively copies the contents of src into dst.
+func deriveDeepCopy_36(dst, src map[string]*ServiceNetworkConfig) {
+ for src_key, src_value := range src {
+ if src_value == nil {
+ dst[src_key] = nil
+ }
+ if src_value == nil {
+ dst[src_key] = nil
+ } else {
+ dst[src_key] = new(ServiceNetworkConfig)
+ deriveDeepCopy_55(dst[src_key], src_value)
+ }
+ }
+}
+
+// deriveDeepCopy_37 recursively copies the contents of src into dst.
+func deriveDeepCopy_37(dst, src []ServiceSecretConfig) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(ServiceSecretConfig)
+ deriveDeepCopy_56(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_38 recursively copies the contents of src into dst.
+func deriveDeepCopy_38(dst, src map[string]*UlimitsConfig) {
+ for src_key, src_value := range src {
+ if src_value == nil {
+ dst[src_key] = nil
+ }
+ if src_value == nil {
+ dst[src_key] = nil
+ } else {
+ dst[src_key] = new(UlimitsConfig)
+ deriveDeepCopy_57(dst[src_key], src_value)
+ }
+ }
+}
+
+// deriveDeepCopy_39 recursively copies the contents of src into dst.
+func deriveDeepCopy_39(dst, src []ServiceVolumeConfig) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(ServiceVolumeConfig)
+ deriveDeepCopy_58(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_40 recursively copies the contents of src into dst.
+func deriveDeepCopy_40(dst, src *BuildConfig) {
+ dst.Context = src.Context
+ dst.Dockerfile = src.Dockerfile
+ dst.DockerfileInline = src.DockerfileInline
+ if src.Entitlements == nil {
+ dst.Entitlements = nil
+ } else {
+ if dst.Entitlements != nil {
+ if len(src.Entitlements) > len(dst.Entitlements) {
+ if cap(dst.Entitlements) >= len(src.Entitlements) {
+ dst.Entitlements = (dst.Entitlements)[:len(src.Entitlements)]
+ } else {
+ dst.Entitlements = make([]string, len(src.Entitlements))
+ }
+ } else if len(src.Entitlements) < len(dst.Entitlements) {
+ dst.Entitlements = (dst.Entitlements)[:len(src.Entitlements)]
+ }
+ } else {
+ dst.Entitlements = make([]string, len(src.Entitlements))
+ }
+ copy(dst.Entitlements, src.Entitlements)
+ }
+ if src.Args != nil {
+ dst.Args = make(map[string]*string, len(src.Args))
+ deriveDeepCopy_32(dst.Args, src.Args)
+ } else {
+ dst.Args = nil
+ }
+ dst.Provenance = src.Provenance
+ dst.SBOM = src.SBOM
+ if src.SSH == nil {
+ dst.SSH = nil
+ } else {
+ if dst.SSH != nil {
+ if len(src.SSH) > len(dst.SSH) {
+ if cap(dst.SSH) >= len(src.SSH) {
+ dst.SSH = (dst.SSH)[:len(src.SSH)]
+ } else {
+ dst.SSH = make([]SSHKey, len(src.SSH))
+ }
+ } else if len(src.SSH) < len(dst.SSH) {
+ dst.SSH = (dst.SSH)[:len(src.SSH)]
+ }
+ } else {
+ dst.SSH = make([]SSHKey, len(src.SSH))
+ }
+ copy(dst.SSH, src.SSH)
+ }
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ if src.CacheFrom == nil {
+ dst.CacheFrom = nil
+ } else {
+ if dst.CacheFrom != nil {
+ if len(src.CacheFrom) > len(dst.CacheFrom) {
+ if cap(dst.CacheFrom) >= len(src.CacheFrom) {
+ dst.CacheFrom = (dst.CacheFrom)[:len(src.CacheFrom)]
+ } else {
+ dst.CacheFrom = make([]string, len(src.CacheFrom))
+ }
+ } else if len(src.CacheFrom) < len(dst.CacheFrom) {
+ dst.CacheFrom = (dst.CacheFrom)[:len(src.CacheFrom)]
+ }
+ } else {
+ dst.CacheFrom = make([]string, len(src.CacheFrom))
+ }
+ copy(dst.CacheFrom, src.CacheFrom)
+ }
+ if src.CacheTo == nil {
+ dst.CacheTo = nil
+ } else {
+ if dst.CacheTo != nil {
+ if len(src.CacheTo) > len(dst.CacheTo) {
+ if cap(dst.CacheTo) >= len(src.CacheTo) {
+ dst.CacheTo = (dst.CacheTo)[:len(src.CacheTo)]
+ } else {
+ dst.CacheTo = make([]string, len(src.CacheTo))
+ }
+ } else if len(src.CacheTo) < len(dst.CacheTo) {
+ dst.CacheTo = (dst.CacheTo)[:len(src.CacheTo)]
+ }
+ } else {
+ dst.CacheTo = make([]string, len(src.CacheTo))
+ }
+ copy(dst.CacheTo, src.CacheTo)
+ }
+ dst.NoCache = src.NoCache
+ if src.NoCacheFilter == nil {
+ dst.NoCacheFilter = nil
+ } else {
+ if dst.NoCacheFilter != nil {
+ if len(src.NoCacheFilter) > len(dst.NoCacheFilter) {
+ if cap(dst.NoCacheFilter) >= len(src.NoCacheFilter) {
+ dst.NoCacheFilter = (dst.NoCacheFilter)[:len(src.NoCacheFilter)]
+ } else {
+ dst.NoCacheFilter = make([]string, len(src.NoCacheFilter))
+ }
+ } else if len(src.NoCacheFilter) < len(dst.NoCacheFilter) {
+ dst.NoCacheFilter = (dst.NoCacheFilter)[:len(src.NoCacheFilter)]
+ }
+ } else {
+ dst.NoCacheFilter = make([]string, len(src.NoCacheFilter))
+ }
+ copy(dst.NoCacheFilter, src.NoCacheFilter)
+ }
+ if src.AdditionalContexts != nil {
+ dst.AdditionalContexts = make(map[string]string, len(src.AdditionalContexts))
+ deriveDeepCopy_6(dst.AdditionalContexts, src.AdditionalContexts)
+ } else {
+ dst.AdditionalContexts = nil
+ }
+ dst.Pull = src.Pull
+ if src.ExtraHosts != nil {
+ dst.ExtraHosts = make(map[string][]string, len(src.ExtraHosts))
+ deriveDeepCopy_25(dst.ExtraHosts, src.ExtraHosts)
+ } else {
+ dst.ExtraHosts = nil
+ }
+ dst.Isolation = src.Isolation
+ dst.Network = src.Network
+ dst.Target = src.Target
+ if src.Secrets == nil {
+ dst.Secrets = nil
+ } else {
+ if dst.Secrets != nil {
+ if len(src.Secrets) > len(dst.Secrets) {
+ if cap(dst.Secrets) >= len(src.Secrets) {
+ dst.Secrets = (dst.Secrets)[:len(src.Secrets)]
+ } else {
+ dst.Secrets = make([]ServiceSecretConfig, len(src.Secrets))
+ }
+ } else if len(src.Secrets) < len(dst.Secrets) {
+ dst.Secrets = (dst.Secrets)[:len(src.Secrets)]
+ }
+ } else {
+ dst.Secrets = make([]ServiceSecretConfig, len(src.Secrets))
+ }
+ deriveDeepCopy_37(dst.Secrets, src.Secrets)
+ }
+ dst.ShmSize = src.ShmSize
+ if src.Tags == nil {
+ dst.Tags = nil
+ } else {
+ if dst.Tags != nil {
+ if len(src.Tags) > len(dst.Tags) {
+ if cap(dst.Tags) >= len(src.Tags) {
+ dst.Tags = (dst.Tags)[:len(src.Tags)]
+ } else {
+ dst.Tags = make([]string, len(src.Tags))
+ }
+ } else if len(src.Tags) < len(dst.Tags) {
+ dst.Tags = (dst.Tags)[:len(src.Tags)]
+ }
+ } else {
+ dst.Tags = make([]string, len(src.Tags))
+ }
+ copy(dst.Tags, src.Tags)
+ }
+ if src.Ulimits != nil {
+ dst.Ulimits = make(map[string]*UlimitsConfig, len(src.Ulimits))
+ deriveDeepCopy_38(dst.Ulimits, src.Ulimits)
+ } else {
+ dst.Ulimits = nil
+ }
+ if src.Platforms == nil {
+ dst.Platforms = nil
+ } else {
+ if dst.Platforms != nil {
+ if len(src.Platforms) > len(dst.Platforms) {
+ if cap(dst.Platforms) >= len(src.Platforms) {
+ dst.Platforms = (dst.Platforms)[:len(src.Platforms)]
+ } else {
+ dst.Platforms = make([]string, len(src.Platforms))
+ }
+ } else if len(src.Platforms) < len(dst.Platforms) {
+ dst.Platforms = (dst.Platforms)[:len(src.Platforms)]
+ }
+ } else {
+ dst.Platforms = make([]string, len(src.Platforms))
+ }
+ copy(dst.Platforms, src.Platforms)
+ }
+ dst.Privileged = src.Privileged
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_41 recursively copies the contents of src into dst.
+func deriveDeepCopy_41(dst, src map[string]ServiceDependency) {
+ for src_key, src_value := range src {
+ func() {
+ field := new(ServiceDependency)
+ deriveDeepCopy_59(field, &src_value)
+ dst[src_key] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_42 recursively copies the contents of src into dst.
+func deriveDeepCopy_42(dst, src *HealthCheckConfig) {
+ if src.Test == nil {
+ dst.Test = nil
+ } else {
+ if dst.Test != nil {
+ if len(src.Test) > len(dst.Test) {
+ if cap(dst.Test) >= len(src.Test) {
+ dst.Test = (dst.Test)[:len(src.Test)]
+ } else {
+ dst.Test = make([]string, len(src.Test))
+ }
+ } else if len(src.Test) < len(dst.Test) {
+ dst.Test = (dst.Test)[:len(src.Test)]
+ }
+ } else {
+ dst.Test = make([]string, len(src.Test))
+ }
+ copy(dst.Test, src.Test)
+ }
+ if src.Timeout == nil {
+ dst.Timeout = nil
+ } else {
+ dst.Timeout = new(Duration)
+ *dst.Timeout = *src.Timeout
+ }
+ if src.Interval == nil {
+ dst.Interval = nil
+ } else {
+ dst.Interval = new(Duration)
+ *dst.Interval = *src.Interval
+ }
+ if src.Retries == nil {
+ dst.Retries = nil
+ } else {
+ dst.Retries = new(uint64)
+ *dst.Retries = *src.Retries
+ }
+ if src.StartPeriod == nil {
+ dst.StartPeriod = nil
+ } else {
+ dst.StartPeriod = new(Duration)
+ *dst.StartPeriod = *src.StartPeriod
+ }
+ if src.StartInterval == nil {
+ dst.StartInterval = nil
+ } else {
+ dst.StartInterval = new(Duration)
+ *dst.StartInterval = *src.StartInterval
+ }
+ dst.Disable = src.Disable
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_43 recursively copies the contents of src into dst.
+func deriveDeepCopy_43(dst, src []ServicePortConfig) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(ServicePortConfig)
+ deriveDeepCopy_60(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_44 recursively copies the contents of src into dst.
+func deriveDeepCopy_44(dst, src *TriggerConfig) {
+ if src.Manual == nil {
+ dst.Manual = nil
+ } else {
+ dst.Manual = new(bool)
+ *dst.Manual = *src.Manual
+ }
+ if src.Schedule == nil {
+ dst.Schedule = nil
+ } else {
+ if dst.Schedule != nil {
+ if len(src.Schedule) > len(dst.Schedule) {
+ if cap(dst.Schedule) >= len(src.Schedule) {
+ dst.Schedule = (dst.Schedule)[:len(src.Schedule)]
+ } else {
+ dst.Schedule = make([]ScheduleConfig, len(src.Schedule))
+ }
+ } else if len(src.Schedule) < len(dst.Schedule) {
+ dst.Schedule = (dst.Schedule)[:len(src.Schedule)]
+ }
+ } else {
+ dst.Schedule = make([]ScheduleConfig, len(src.Schedule))
+ }
+ deriveDeepCopy_61(dst.Schedule, src.Schedule)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_45 recursively copies the contents of src into dst.
+func deriveDeepCopy_45(dst, src *IPAMConfig) {
+ dst.Driver = src.Driver
+ if src.Config == nil {
+ dst.Config = nil
+ } else {
+ if dst.Config != nil {
+ if len(src.Config) > len(dst.Config) {
+ if cap(dst.Config) >= len(src.Config) {
+ dst.Config = (dst.Config)[:len(src.Config)]
+ } else {
+ dst.Config = make([]*IPAMPool, len(src.Config))
+ }
+ } else if len(src.Config) < len(dst.Config) {
+ dst.Config = (dst.Config)[:len(src.Config)]
+ }
+ } else {
+ dst.Config = make([]*IPAMPool, len(src.Config))
+ }
+ deriveDeepCopy_62(dst.Config, src.Config)
+ }
+ if src.Options != nil {
+ dst.Options = make(map[string]string, len(src.Options))
+ deriveDeepCopy_6(dst.Options, src.Options)
+ } else {
+ dst.Options = nil
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_46 recursively copies the contents of src into dst.
+func deriveDeepCopy_46(dst, src *Resource) {
+ dst.NanoCPUs = src.NanoCPUs
+ dst.MemoryBytes = src.MemoryBytes
+ dst.Pids = src.Pids
+ if src.Devices == nil {
+ dst.Devices = nil
+ } else {
+ if dst.Devices != nil {
+ if len(src.Devices) > len(dst.Devices) {
+ if cap(dst.Devices) >= len(src.Devices) {
+ dst.Devices = (dst.Devices)[:len(src.Devices)]
+ } else {
+ dst.Devices = make([]DeviceRequest, len(src.Devices))
+ }
+ } else if len(src.Devices) < len(dst.Devices) {
+ dst.Devices = (dst.Devices)[:len(src.Devices)]
+ }
+ } else {
+ dst.Devices = make([]DeviceRequest, len(src.Devices))
+ }
+ deriveDeepCopy_33(dst.Devices, src.Devices)
+ }
+ if src.GenericResources == nil {
+ dst.GenericResources = nil
+ } else {
+ if dst.GenericResources != nil {
+ if len(src.GenericResources) > len(dst.GenericResources) {
+ if cap(dst.GenericResources) >= len(src.GenericResources) {
+ dst.GenericResources = (dst.GenericResources)[:len(src.GenericResources)]
+ } else {
+ dst.GenericResources = make([]GenericResource, len(src.GenericResources))
+ }
+ } else if len(src.GenericResources) < len(dst.GenericResources) {
+ dst.GenericResources = (dst.GenericResources)[:len(src.GenericResources)]
+ }
+ } else {
+ dst.GenericResources = make([]GenericResource, len(src.GenericResources))
+ }
+ deriveDeepCopy_63(dst.GenericResources, src.GenericResources)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_47 recursively copies the contents of src into dst.
+func deriveDeepCopy_47(dst, src []PlacementPreferences) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(PlacementPreferences)
+ deriveDeepCopy_64(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_48 recursively copies the contents of src into dst.
+func deriveDeepCopy_48(dst, src *Trigger) {
+ dst.Path = src.Path
+ dst.Action = src.Action
+ dst.Target = src.Target
+ func() {
+ field := new(ServiceHook)
+ deriveDeepCopy_27(field, &src.Exec)
+ dst.Exec = *field
+ }()
+ if src.Include == nil {
+ dst.Include = nil
+ } else {
+ if dst.Include != nil {
+ if len(src.Include) > len(dst.Include) {
+ if cap(dst.Include) >= len(src.Include) {
+ dst.Include = (dst.Include)[:len(src.Include)]
+ } else {
+ dst.Include = make([]string, len(src.Include))
+ }
+ } else if len(src.Include) < len(dst.Include) {
+ dst.Include = (dst.Include)[:len(src.Include)]
+ }
+ } else {
+ dst.Include = make([]string, len(src.Include))
+ }
+ copy(dst.Include, src.Include)
+ }
+ if src.Ignore == nil {
+ dst.Ignore = nil
+ } else {
+ if dst.Ignore != nil {
+ if len(src.Ignore) > len(dst.Ignore) {
+ if cap(dst.Ignore) >= len(src.Ignore) {
+ dst.Ignore = (dst.Ignore)[:len(src.Ignore)]
+ } else {
+ dst.Ignore = make([]string, len(src.Ignore))
+ }
+ } else if len(src.Ignore) < len(dst.Ignore) {
+ dst.Ignore = (dst.Ignore)[:len(src.Ignore)]
+ }
+ } else {
+ dst.Ignore = make([]string, len(src.Ignore))
+ }
+ copy(dst.Ignore, src.Ignore)
+ }
+ dst.InitialSync = src.InitialSync
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_49 recursively copies the contents of src into dst.
+func deriveDeepCopy_49(dst, src []WeightDevice) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(WeightDevice)
+ deriveDeepCopy_65(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_50 recursively copies the contents of src into dst.
+func deriveDeepCopy_50(dst, src []ThrottleDevice) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(ThrottleDevice)
+ deriveDeepCopy_66(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_51 recursively copies the contents of src into dst.
+func deriveDeepCopy_51(dst, src *ServiceConfigObjConfig) {
+ dst.Source = src.Source
+ dst.Target = src.Target
+ dst.UID = src.UID
+ dst.GID = src.GID
+ if src.Mode == nil {
+ dst.Mode = nil
+ } else {
+ dst.Mode = new(FileMode)
+ *dst.Mode = *src.Mode
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_52 recursively copies the contents of src into dst.
+func deriveDeepCopy_52(dst, src *DeviceMapping) {
+ dst.Source = src.Source
+ dst.Target = src.Target
+ dst.Permissions = src.Permissions
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_53 recursively copies the contents of src into dst.
+func deriveDeepCopy_53(dst, src *DeviceRequest) {
+ if src.Capabilities == nil {
+ dst.Capabilities = nil
+ } else {
+ if dst.Capabilities != nil {
+ if len(src.Capabilities) > len(dst.Capabilities) {
+ if cap(dst.Capabilities) >= len(src.Capabilities) {
+ dst.Capabilities = (dst.Capabilities)[:len(src.Capabilities)]
+ } else {
+ dst.Capabilities = make([]string, len(src.Capabilities))
+ }
+ } else if len(src.Capabilities) < len(dst.Capabilities) {
+ dst.Capabilities = (dst.Capabilities)[:len(src.Capabilities)]
+ }
+ } else {
+ dst.Capabilities = make([]string, len(src.Capabilities))
+ }
+ copy(dst.Capabilities, src.Capabilities)
+ }
+ dst.Driver = src.Driver
+ dst.Count = src.Count
+ if src.IDs == nil {
+ dst.IDs = nil
+ } else {
+ if dst.IDs != nil {
+ if len(src.IDs) > len(dst.IDs) {
+ if cap(dst.IDs) >= len(src.IDs) {
+ dst.IDs = (dst.IDs)[:len(src.IDs)]
+ } else {
+ dst.IDs = make([]string, len(src.IDs))
+ }
+ } else if len(src.IDs) < len(dst.IDs) {
+ dst.IDs = (dst.IDs)[:len(src.IDs)]
+ }
+ } else {
+ dst.IDs = make([]string, len(src.IDs))
+ }
+ copy(dst.IDs, src.IDs)
+ }
+ if src.Options != nil {
+ dst.Options = make(map[string]string, len(src.Options))
+ deriveDeepCopy_6(dst.Options, src.Options)
+ } else {
+ dst.Options = nil
+ }
+}
+
+// deriveDeepCopy_54 recursively copies the contents of src into dst.
+func deriveDeepCopy_54(dst, src *ServiceModelConfig) {
+ dst.EndpointVariable = src.EndpointVariable
+ dst.ModelVariable = src.ModelVariable
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_55 recursively copies the contents of src into dst.
+func deriveDeepCopy_55(dst, src *ServiceNetworkConfig) {
+ if src.Aliases == nil {
+ dst.Aliases = nil
+ } else {
+ if dst.Aliases != nil {
+ if len(src.Aliases) > len(dst.Aliases) {
+ if cap(dst.Aliases) >= len(src.Aliases) {
+ dst.Aliases = (dst.Aliases)[:len(src.Aliases)]
+ } else {
+ dst.Aliases = make([]string, len(src.Aliases))
+ }
+ } else if len(src.Aliases) < len(dst.Aliases) {
+ dst.Aliases = (dst.Aliases)[:len(src.Aliases)]
+ }
+ } else {
+ dst.Aliases = make([]string, len(src.Aliases))
+ }
+ copy(dst.Aliases, src.Aliases)
+ }
+ if src.DriverOpts != nil {
+ dst.DriverOpts = make(map[string]string, len(src.DriverOpts))
+ deriveDeepCopy_6(dst.DriverOpts, src.DriverOpts)
+ } else {
+ dst.DriverOpts = nil
+ }
+ dst.GatewayPriority = src.GatewayPriority
+ dst.InterfaceName = src.InterfaceName
+ dst.Ipv4Address = src.Ipv4Address
+ dst.Ipv6Address = src.Ipv6Address
+ if src.LinkLocalIPs == nil {
+ dst.LinkLocalIPs = nil
+ } else {
+ if dst.LinkLocalIPs != nil {
+ if len(src.LinkLocalIPs) > len(dst.LinkLocalIPs) {
+ if cap(dst.LinkLocalIPs) >= len(src.LinkLocalIPs) {
+ dst.LinkLocalIPs = (dst.LinkLocalIPs)[:len(src.LinkLocalIPs)]
+ } else {
+ dst.LinkLocalIPs = make([]string, len(src.LinkLocalIPs))
+ }
+ } else if len(src.LinkLocalIPs) < len(dst.LinkLocalIPs) {
+ dst.LinkLocalIPs = (dst.LinkLocalIPs)[:len(src.LinkLocalIPs)]
+ }
+ } else {
+ dst.LinkLocalIPs = make([]string, len(src.LinkLocalIPs))
+ }
+ copy(dst.LinkLocalIPs, src.LinkLocalIPs)
+ }
+ dst.MacAddress = src.MacAddress
+ dst.Priority = src.Priority
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_56 recursively copies the contents of src into dst.
+func deriveDeepCopy_56(dst, src *ServiceSecretConfig) {
+ dst.Source = src.Source
+ dst.Target = src.Target
+ dst.UID = src.UID
+ dst.GID = src.GID
+ if src.Mode == nil {
+ dst.Mode = nil
+ } else {
+ dst.Mode = new(FileMode)
+ *dst.Mode = *src.Mode
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_57 recursively copies the contents of src into dst.
+func deriveDeepCopy_57(dst, src *UlimitsConfig) {
+ dst.Single = src.Single
+ dst.Soft = src.Soft
+ dst.Hard = src.Hard
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_58 recursively copies the contents of src into dst.
+func deriveDeepCopy_58(dst, src *ServiceVolumeConfig) {
+ dst.Type = src.Type
+ dst.Source = src.Source
+ dst.Target = src.Target
+ dst.ReadOnly = src.ReadOnly
+ dst.Consistency = src.Consistency
+ if src.Bind == nil {
+ dst.Bind = nil
+ } else {
+ dst.Bind = new(ServiceVolumeBind)
+ deriveDeepCopy_67(dst.Bind, src.Bind)
+ }
+ if src.Volume == nil {
+ dst.Volume = nil
+ } else {
+ dst.Volume = new(ServiceVolumeVolume)
+ deriveDeepCopy_68(dst.Volume, src.Volume)
+ }
+ if src.Tmpfs == nil {
+ dst.Tmpfs = nil
+ } else {
+ dst.Tmpfs = new(ServiceVolumeTmpfs)
+ deriveDeepCopy_69(dst.Tmpfs, src.Tmpfs)
+ }
+ if src.Image == nil {
+ dst.Image = nil
+ } else {
+ dst.Image = new(ServiceVolumeImage)
+ deriveDeepCopy_70(dst.Image, src.Image)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_59 recursively copies the contents of src into dst.
+func deriveDeepCopy_59(dst, src *ServiceDependency) {
+ dst.Condition = src.Condition
+ dst.Restart = src.Restart
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+ dst.Required = src.Required
+}
+
+// deriveDeepCopy_60 recursively copies the contents of src into dst.
+func deriveDeepCopy_60(dst, src *ServicePortConfig) {
+ dst.Name = src.Name
+ dst.Mode = src.Mode
+ dst.HostIP = src.HostIP
+ dst.Target = src.Target
+ dst.Published = src.Published
+ dst.Protocol = src.Protocol
+ dst.AppProtocol = src.AppProtocol
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_61 recursively copies the contents of src into dst.
+func deriveDeepCopy_61(dst, src []ScheduleConfig) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(ScheduleConfig)
+ deriveDeepCopy_71(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_62 recursively copies the contents of src into dst.
+func deriveDeepCopy_62(dst, src []*IPAMPool) {
+ for src_i, src_value := range src {
+ if src_value == nil {
+ dst[src_i] = nil
+ } else {
+ dst[src_i] = new(IPAMPool)
+ deriveDeepCopy_72(dst[src_i], src_value)
+ }
+ }
+}
+
+// deriveDeepCopy_63 recursively copies the contents of src into dst.
+func deriveDeepCopy_63(dst, src []GenericResource) {
+ for src_i, src_value := range src {
+ func() {
+ field := new(GenericResource)
+ deriveDeepCopy_73(field, &src_value)
+ dst[src_i] = *field
+ }()
+ }
+}
+
+// deriveDeepCopy_64 recursively copies the contents of src into dst.
+func deriveDeepCopy_64(dst, src *PlacementPreferences) {
+ dst.Spread = src.Spread
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_65 recursively copies the contents of src into dst.
+func deriveDeepCopy_65(dst, src *WeightDevice) {
+ dst.Path = src.Path
+ dst.Weight = src.Weight
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_66 recursively copies the contents of src into dst.
+func deriveDeepCopy_66(dst, src *ThrottleDevice) {
+ dst.Path = src.Path
+ dst.Rate = src.Rate
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_67 recursively copies the contents of src into dst.
+func deriveDeepCopy_67(dst, src *ServiceVolumeBind) {
+ dst.SELinux = src.SELinux
+ dst.Propagation = src.Propagation
+ dst.CreateHostPath = src.CreateHostPath
+ dst.Recursive = src.Recursive
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_68 recursively copies the contents of src into dst.
+func deriveDeepCopy_68(dst, src *ServiceVolumeVolume) {
+ if src.Labels != nil {
+ dst.Labels = make(map[string]string, len(src.Labels))
+ deriveDeepCopy_6(dst.Labels, src.Labels)
+ } else {
+ dst.Labels = nil
+ }
+ dst.NoCopy = src.NoCopy
+ dst.Subpath = src.Subpath
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_69 recursively copies the contents of src into dst.
+func deriveDeepCopy_69(dst, src *ServiceVolumeTmpfs) {
+ dst.Size = src.Size
+ dst.Mode = src.Mode
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_70 recursively copies the contents of src into dst.
+func deriveDeepCopy_70(dst, src *ServiceVolumeImage) {
+ dst.SubPath = src.SubPath
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_71 recursively copies the contents of src into dst.
+func deriveDeepCopy_71(dst, src *ScheduleConfig) {
+ dst.Cron = src.Cron
+ dst.Timezone = src.Timezone
+ dst.Concurrency = src.Concurrency
+ dst.MissedFires = src.MissedFires
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_72 recursively copies the contents of src into dst.
+func deriveDeepCopy_72(dst, src *IPAMPool) {
+ dst.Subnet = src.Subnet
+ dst.Gateway = src.Gateway
+ dst.IPRange = src.IPRange
+ if src.AuxiliaryAddresses != nil {
+ dst.AuxiliaryAddresses = make(map[string]string, len(src.AuxiliaryAddresses))
+ deriveDeepCopy_6(dst.AuxiliaryAddresses, src.AuxiliaryAddresses)
+ } else {
+ dst.AuxiliaryAddresses = nil
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_73 recursively copies the contents of src into dst.
+func deriveDeepCopy_73(dst, src *GenericResource) {
+ if src.DiscreteResourceSpec == nil {
+ dst.DiscreteResourceSpec = nil
+ } else {
+ dst.DiscreteResourceSpec = new(DiscreteGenericResource)
+ deriveDeepCopy_74(dst.DiscreteResourceSpec, src.DiscreteResourceSpec)
+ }
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
+
+// deriveDeepCopy_74 recursively copies the contents of src into dst.
+func deriveDeepCopy_74(dst, src *DiscreteGenericResource) {
+ dst.Kind = src.Kind
+ dst.Value = src.Value
+ if src.Extensions != nil {
+ dst.Extensions = make(map[string]any, len(src.Extensions))
+ src.Extensions.DeepCopy(dst.Extensions)
+ } else {
+ dst.Extensions = nil
+ }
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/develop.go b/vendor/github.com/compose-spec/compose-go/v2/types/develop.go
new file mode 100644
index 0000000000..d468a8c071
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/develop.go
@@ -0,0 +1,44 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+type DevelopConfig struct {
+ Watch []Trigger `yaml:"watch,omitempty" json:"watch,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+type WatchAction string
+
+const (
+ WatchActionSync WatchAction = "sync"
+ WatchActionRebuild WatchAction = "rebuild"
+ WatchActionRestart WatchAction = "restart"
+ WatchActionSyncRestart WatchAction = "sync+restart"
+ WatchActionSyncExec WatchAction = "sync+exec"
+)
+
+type Trigger struct {
+ Path string `yaml:"path" json:"path"`
+ Action WatchAction `yaml:"action" json:"action"`
+ Target string `yaml:"target,omitempty" json:"target,omitempty"`
+ Exec ServiceHook `yaml:"exec,omitempty" json:"exec,omitempty"`
+ Include []string `yaml:"include,omitempty" json:"include,omitempty"`
+ Ignore []string `yaml:"ignore,omitempty" json:"ignore,omitempty"`
+ InitialSync bool `yaml:"initial_sync,omitempty" json:"initial_sync,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/device.go b/vendor/github.com/compose-spec/compose-go/v2/types/device.go
new file mode 100644
index 0000000000..5b30cc0ca2
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/device.go
@@ -0,0 +1,53 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type DeviceRequest struct {
+ Capabilities []string `yaml:"capabilities,omitempty" json:"capabilities,omitempty"`
+ Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
+ Count DeviceCount `yaml:"count,omitempty" json:"count,omitempty"`
+ IDs []string `yaml:"device_ids,omitempty" json:"device_ids,omitempty"`
+ Options Mapping `yaml:"options,omitempty" json:"options,omitempty"`
+}
+
+type DeviceCount int64
+
+func (c *DeviceCount) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case int:
+ *c = DeviceCount(v)
+ case string:
+ if strings.ToLower(v) == "all" {
+ *c = -1
+ return nil
+ }
+ i, err := strconv.ParseInt(v, 10, 64)
+ if err != nil {
+ return fmt.Errorf("invalid value %q, the only value allowed is 'all' or a number", v)
+ }
+ *c = DeviceCount(i)
+ default:
+ return fmt.Errorf("invalid type %T for device count", v)
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/duration.go b/vendor/github.com/compose-spec/compose-go/v2/types/duration.go
new file mode 100644
index 0000000000..c1c39730dd
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/duration.go
@@ -0,0 +1,62 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/xhit/go-str2duration/v2"
+)
+
+// Duration is a thin wrapper around time.Duration with improved JSON marshalling
+type Duration time.Duration
+
+func (d Duration) String() string {
+ return time.Duration(d).String()
+}
+
+func (d *Duration) DecodeMapstructure(value interface{}) error {
+ v, err := str2duration.ParseDuration(fmt.Sprint(value))
+ if err != nil {
+ return err
+ }
+ *d = Duration(v)
+ return nil
+}
+
+// MarshalJSON makes Duration implement json.Marshaler
+func (d Duration) MarshalJSON() ([]byte, error) {
+ return json.Marshal(d.String())
+}
+
+// MarshalYAML makes Duration implement yaml.Marshaler
+func (d Duration) MarshalYAML() (interface{}, error) {
+ return d.String(), nil
+}
+
+func (d *Duration) UnmarshalJSON(b []byte) error {
+ s := strings.Trim(string(b), "\"")
+ timeDuration, err := time.ParseDuration(s)
+ if err != nil {
+ return err
+ }
+ *d = Duration(timeDuration)
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/envfile.go b/vendor/github.com/compose-spec/compose-go/v2/types/envfile.go
new file mode 100644
index 0000000000..a7d239ee8b
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/envfile.go
@@ -0,0 +1,23 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+type EnvFile struct {
+ Path string `yaml:"path,omitempty" json:"path,omitempty"`
+ Required OptOut `yaml:"required,omitempty" json:"required,omitzero"`
+ Format string `yaml:"format,omitempty" json:"format,omitempty"`
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/healthcheck.go b/vendor/github.com/compose-spec/compose-go/v2/types/healthcheck.go
new file mode 100644
index 0000000000..c6c3b37e0d
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/healthcheck.go
@@ -0,0 +1,53 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "fmt"
+)
+
+// HealthCheckConfig the healthcheck configuration for a service
+type HealthCheckConfig struct {
+ Test HealthCheckTest `yaml:"test,omitempty" json:"test,omitempty"`
+ Timeout *Duration `yaml:"timeout,omitempty" json:"timeout,omitempty"`
+ Interval *Duration `yaml:"interval,omitempty" json:"interval,omitempty"`
+ Retries *uint64 `yaml:"retries,omitempty" json:"retries,omitempty"`
+ StartPeriod *Duration `yaml:"start_period,omitempty" json:"start_period,omitempty"`
+ StartInterval *Duration `yaml:"start_interval,omitempty" json:"start_interval,omitempty"`
+ Disable bool `yaml:"disable,omitempty" json:"disable,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// HealthCheckTest is the command run to test the health of a service
+type HealthCheckTest []string
+
+func (l *HealthCheckTest) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case string:
+ *l = []string{"CMD-SHELL", v}
+ case []interface{}:
+ seq := make([]string, len(v))
+ for i, e := range v {
+ seq[i] = e.(string)
+ }
+ *l = seq
+ default:
+ return fmt.Errorf("unexpected value type %T for healthcheck.test", value)
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/hooks.go b/vendor/github.com/compose-spec/compose-go/v2/types/hooks.go
new file mode 100644
index 0000000000..5ca5d3f581
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/hooks.go
@@ -0,0 +1,45 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+// ServiceHook is a command exec'd inside the service container at a lifecycle
+// event (post_start, pre_stop).
+type ServiceHook struct {
+ Command ShellCommand `yaml:"command,omitempty" json:"command"`
+ User string `yaml:"user,omitempty" json:"user,omitempty"`
+ Privileged bool `yaml:"privileged,omitempty" json:"privileged,omitempty"`
+ WorkingDir string `yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
+ Environment MappingWithEquals `yaml:"environment,omitempty" json:"environment,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// PreStartHook is an init container run to completion before the service
+// starts. It accepts the full container specification, inheriting from the
+// service in the spirit of the yaml merge rules: collection attributes
+// complete the inherited value with the hook's declarations winning on
+// conflicts, scalar attributes replace it (image is inherited via
+// normalization when undeclared).
+type PreStartHook struct {
+ ContainerSpec `yaml:",inline" mapstructure:",squash"`
+
+ // PerReplica runs the hook once per service replica instead of once per
+ // service.
+ PerReplica bool `yaml:"per_replica,omitempty" json:"per_replica,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/hostList.go b/vendor/github.com/compose-spec/compose-go/v2/types/hostList.go
new file mode 100644
index 0000000000..9bc0fbc5d8
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/hostList.go
@@ -0,0 +1,144 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "encoding/json"
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// HostsList is a list of colon-separated host-ip mappings
+type HostsList map[string][]string
+
+// NewHostsList creates a HostsList from a list of `host=ip` strings
+func NewHostsList(hosts []string) (HostsList, error) {
+ list := HostsList{}
+ for _, s := range hosts {
+ var found bool
+ for _, sep := range hostListSerapators {
+ host, ip, ok := strings.Cut(s, sep)
+ if ok {
+ // Mapping found with this separator, stop here.
+ if ips, ok := list[host]; ok {
+ list[host] = append(ips, strings.Split(ip, ",")...)
+ } else {
+ list[host] = strings.Split(ip, ",")
+ }
+ found = true
+ break
+ }
+ }
+ if !found {
+ return nil, fmt.Errorf("invalid additional host, missing IP: %s", s)
+ }
+ }
+ err := list.cleanup()
+ return list, err
+}
+
+// AsList returns host-ip mappings as a list of strings, using the given
+// separator. The Docker Engine API expects ':' separators, the original format
+// for '--add-hosts'. But an '=' separator is used in YAML/JSON renderings to
+// make IPv6 addresses more readable (for example "my-host=::1" instead of
+// "my-host:::1").
+func (h HostsList) AsList(sep string) []string {
+ l := make([]string, 0, len(h))
+ for k, v := range h {
+ for _, ip := range v {
+ l = append(l, fmt.Sprintf("%s%s%s", k, sep, ip))
+ }
+ }
+ return l
+}
+
+func (h HostsList) MarshalYAML() (interface{}, error) {
+ list := h.AsList("=")
+ sort.Strings(list)
+ return list, nil
+}
+
+func (h HostsList) MarshalJSON() ([]byte, error) {
+ list := h.AsList("=")
+ sort.Strings(list)
+ return json.Marshal(list)
+}
+
+var hostListSerapators = []string{"=", ":"}
+
+func (h *HostsList) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case map[string]interface{}:
+ list := make(HostsList, len(v))
+ for i, e := range v {
+ if e == nil {
+ e = ""
+ }
+ switch t := e.(type) {
+ case string:
+ list[i] = []string{t}
+ case []any:
+ hosts := make([]string, len(t))
+ for j, h := range t {
+ hosts[j] = fmt.Sprint(h)
+ }
+ list[i] = hosts
+ default:
+ return fmt.Errorf("unexpected value type %T for extra_hosts entry", value)
+ }
+ }
+ err := list.cleanup()
+ if err != nil {
+ return err
+ }
+ *h = list
+ return nil
+ case []interface{}:
+ s := make([]string, len(v))
+ for i, e := range v {
+ s[i] = fmt.Sprint(e)
+ }
+ list, err := NewHostsList(s)
+ if err != nil {
+ return err
+ }
+ *h = list
+ return nil
+ default:
+ return fmt.Errorf("unexpected value type %T for extra_hosts", value)
+ }
+}
+
+func (h HostsList) cleanup() error {
+ for host, ips := range h {
+ // Check that there is a hostname and that it doesn't contain either
+ // of the allowed separators, to generate a clearer error than the
+ // engine would do if it splits the string differently.
+ if host == "" || strings.ContainsAny(host, ":=") {
+ return fmt.Errorf("bad host name '%s'", host)
+ }
+ for i, ip := range ips {
+ // Remove brackets from IP addresses (for example "[::1]" -> "::1").
+ if len(ip) > 2 && ip[0] == '[' && ip[len(ip)-1] == ']' {
+ ips[i] = ip[1 : len(ip)-1]
+ }
+ }
+ h[host] = ips
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/jobs.go b/vendor/github.com/compose-spec/compose-go/v2/types/jobs.go
new file mode 100644
index 0000000000..1634442336
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/jobs.go
@@ -0,0 +1,53 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+// JobConfig is the configuration of one job
+type JobConfig struct {
+ Name string `yaml:"name,omitempty" json:"-"`
+ Profiles []string `yaml:"profiles,omitempty" json:"profiles,omitempty"`
+ Triggers *TriggerConfig `yaml:"triggers,omitempty" json:"triggers,omitempty"`
+
+ ContainerSpec `yaml:",inline" mapstructure:",squash"`
+ WorkloadSpec `yaml:",inline" mapstructure:",squash"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// TriggerConfig defines trigger conditions for a job.
+// Manual is tri-state: nil (unset) leaves manual execution allowed — any job
+// can be triggered by an explicit run command; an explicit false forbids it;
+// an explicit true declares the job as manual-only intent.
+type TriggerConfig struct {
+ Manual *bool `yaml:"manual,omitempty" json:"manual,omitempty"`
+ Schedule []ScheduleConfig `yaml:"schedule,omitempty" json:"schedule,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// ScheduleConfig defines a schedule for a job trigger.
+// A plain crontab expression in yaml is canonicalized into a ScheduleConfig
+// with only Cron set.
+type ScheduleConfig struct {
+ Cron string `yaml:"cron,omitempty" json:"cron,omitempty"`
+ Timezone string `yaml:"timezone,omitempty" json:"timezone,omitempty"`
+ Concurrency string `yaml:"concurrency,omitempty" json:"concurrency,omitempty"`
+ MissedFires string `yaml:"missed_fires,omitempty" json:"missed_fires,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// Jobs is a mapping of job names to job configurations
+type Jobs map[string]JobConfig
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/labels.go b/vendor/github.com/compose-spec/compose-go/v2/types/labels.go
new file mode 100644
index 0000000000..7ea5edc410
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/labels.go
@@ -0,0 +1,95 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Labels is a mapping type for labels
+type Labels map[string]string
+
+func NewLabelsFromMappingWithEquals(mapping MappingWithEquals) Labels {
+ labels := Labels{}
+ for k, v := range mapping {
+ if v != nil {
+ labels[k] = *v
+ }
+ }
+ return labels
+}
+
+func (l Labels) Add(key, value string) Labels {
+ if l == nil {
+ l = Labels{}
+ }
+ l[key] = value
+ return l
+}
+
+func (l Labels) AsList() []string {
+ s := make([]string, len(l))
+ i := 0
+ for k, v := range l {
+ s[i] = fmt.Sprintf("%s=%s", k, v)
+ i++
+ }
+ return s
+}
+
+func (l Labels) ToMappingWithEquals() MappingWithEquals {
+ mapping := MappingWithEquals{}
+ for k, v := range l {
+ mapping[k] = &v
+ }
+ return mapping
+}
+
+// label value can be a string | number | boolean | null (empty)
+func labelValue(e interface{}) string {
+ if e == nil {
+ return ""
+ }
+ switch v := e.(type) {
+ case string:
+ return v
+ default:
+ return fmt.Sprint(v)
+ }
+}
+
+func (l *Labels) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case map[string]interface{}:
+ labels := make(map[string]string, len(v))
+ for k, e := range v {
+ labels[k] = labelValue(e)
+ }
+ *l = labels
+ case []interface{}:
+ labels := make(map[string]string, len(v))
+ for _, s := range v {
+ k, e, _ := strings.Cut(fmt.Sprint(s), "=")
+ labels[k] = labelValue(e)
+ }
+ *l = labels
+ default:
+ return fmt.Errorf("unexpected value type %T for labels", value)
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/mapping.go b/vendor/github.com/compose-spec/compose-go/v2/types/mapping.go
new file mode 100644
index 0000000000..fb14974f95
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/mapping.go
@@ -0,0 +1,230 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+ "unicode"
+)
+
+// MappingWithEquals is a mapping type that can be converted from a list of
+// key[=value] strings.
+// For the key with an empty value (`key=`), the mapped value is set to a pointer to `""`.
+// For the key without value (`key`), the mapped value is set to nil.
+type MappingWithEquals map[string]*string
+
+// NewMappingWithEquals build a new Mapping from a set of KEY=VALUE strings
+func NewMappingWithEquals(values []string) MappingWithEquals {
+ mapping := MappingWithEquals{}
+ for _, env := range values {
+ tokens := strings.SplitN(env, "=", 2)
+ if len(tokens) > 1 {
+ mapping[tokens[0]] = &tokens[1]
+ } else {
+ mapping[env] = nil
+ }
+ }
+ return mapping
+}
+
+// OverrideBy update MappingWithEquals with values from another MappingWithEquals
+func (m MappingWithEquals) OverrideBy(other MappingWithEquals) MappingWithEquals {
+ for k, v := range other {
+ m[k] = v
+ }
+ return m
+}
+
+// Resolve update a MappingWithEquals for keys without value (`key`, but not `key=`)
+func (m MappingWithEquals) Resolve(lookupFn func(string) (string, bool)) MappingWithEquals {
+ for k, v := range m {
+ if v == nil {
+ if value, ok := lookupFn(k); ok {
+ m[k] = &value
+ }
+ }
+ }
+ return m
+}
+
+// RemoveEmpty excludes keys that are not associated with a value
+func (m MappingWithEquals) RemoveEmpty() MappingWithEquals {
+ for k, v := range m {
+ if v == nil {
+ delete(m, k)
+ }
+ }
+ return m
+}
+
+func (m MappingWithEquals) ToMapping() Mapping {
+ o := Mapping{}
+ for k, v := range m {
+ if v != nil {
+ o[k] = *v
+ }
+ }
+ return o
+}
+
+func (m *MappingWithEquals) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case map[string]interface{}:
+ mapping := make(MappingWithEquals, len(v))
+ for k, e := range v {
+ mapping[k] = mappingValue(e)
+ }
+ *m = mapping
+ case []interface{}:
+ mapping := make(MappingWithEquals, len(v))
+ for _, s := range v {
+ k, e, ok := strings.Cut(fmt.Sprint(s), "=")
+ if k != "" && unicode.IsSpace(rune(k[len(k)-1])) {
+ return fmt.Errorf("environment variable %s is declared with a trailing space", k)
+ }
+ if !ok {
+ mapping[k] = nil
+ } else {
+ mapping[k] = mappingValue(e)
+ }
+ }
+ *m = mapping
+ default:
+ return fmt.Errorf("unexpected value type %T for mapping", value)
+ }
+ return nil
+}
+
+// label value can be a string | number | boolean | null
+func mappingValue(e interface{}) *string {
+ if e == nil {
+ return nil
+ }
+ switch v := e.(type) {
+ case string:
+ return &v
+ default:
+ s := fmt.Sprint(v)
+ return &s
+ }
+}
+
+// Mapping is a mapping type that can be converted from a list of
+// key[=value] strings.
+// For the key with an empty value (`key=`), or key without value (`key`), the
+// mapped value is set to an empty string `""`.
+type Mapping map[string]string
+
+// NewMapping build a new Mapping from a set of KEY=VALUE strings
+func NewMapping(values []string) Mapping {
+ mapping := Mapping{}
+ for _, value := range values {
+ parts := strings.SplitN(value, "=", 2)
+ key := parts[0]
+ switch {
+ case len(parts) == 1:
+ mapping[key] = ""
+ default:
+ mapping[key] = parts[1]
+ }
+ }
+ return mapping
+}
+
+// convert values into a set of KEY=VALUE strings
+func (m Mapping) Values() []string {
+ values := make([]string, 0, len(m))
+ for k, v := range m {
+ values = append(values, fmt.Sprintf("%s=%s", k, v))
+ }
+ sort.Strings(values)
+ return values
+}
+
+// ToMappingWithEquals converts Mapping into a MappingWithEquals with pointer references
+func (m Mapping) ToMappingWithEquals() MappingWithEquals {
+ mapping := MappingWithEquals{}
+ for k, v := range m {
+ mapping[k] = &v
+ }
+ return mapping
+}
+
+func (m Mapping) Resolve(s string) (string, bool) {
+ v, ok := m[s]
+ return v, ok
+}
+
+func (m Mapping) Clone() Mapping {
+ clone := Mapping{}
+ for k, v := range m {
+ clone[k] = v
+ }
+ return clone
+}
+
+// Merge adds all values from second mapping which are not already defined
+func (m Mapping) Merge(o Mapping) Mapping {
+ for k, v := range o {
+ if _, set := m[k]; !set {
+ m[k] = v
+ }
+ }
+ return m
+}
+
+func (m *Mapping) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case map[string]interface{}:
+ mapping := make(Mapping, len(v))
+ for k, e := range v {
+ if e == nil {
+ e = ""
+ }
+ mapping[k] = fmt.Sprint(e)
+ }
+ *m = mapping
+ case []interface{}:
+ *m = decodeMapping(v, "=")
+ default:
+ return fmt.Errorf("unexpected value type %T for mapping", value)
+ }
+ return nil
+}
+
+// Generate a mapping by splitting strings at any of seps, which will be tried
+// in-order for each input string. (For example, to allow the preferred 'host=ip'
+// in 'extra_hosts', as well as 'host:ip' for backwards compatibility.)
+func decodeMapping(v []interface{}, seps ...string) map[string]string {
+ mapping := make(Mapping, len(v))
+ for _, s := range v {
+ for i, sep := range seps {
+ k, e, ok := strings.Cut(fmt.Sprint(s), sep)
+ if ok {
+ // Mapping found with this separator, stop here.
+ mapping[k] = e
+ break
+ } else if i == len(seps)-1 {
+ // No more separators to try, map to empty string.
+ mapping[k] = ""
+ }
+ }
+ }
+ return mapping
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/models.go b/vendor/github.com/compose-spec/compose-go/v2/types/models.go
new file mode 100644
index 0000000000..4f144c0a40
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/models.go
@@ -0,0 +1,31 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+type ModelConfig struct {
+ Name string `yaml:"name,omitempty" json:"name,omitempty"`
+ Model string `yaml:"model,omitempty" json:"model,omitempty"`
+ ContextSize int `yaml:"context_size,omitempty" json:"context_size,omitempty"`
+ RuntimeFlags []string `yaml:"runtime_flags,omitempty" json:"runtime_flags,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+type ServiceModelConfig struct {
+ EndpointVariable string `yaml:"endpoint_var,omitempty" json:"endpoint_var,omitempty"`
+ ModelVariable string `yaml:"model_var,omitempty" json:"model_var,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/options.go b/vendor/github.com/compose-spec/compose-go/v2/types/options.go
new file mode 100644
index 0000000000..9aadb89ca0
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/options.go
@@ -0,0 +1,66 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import "fmt"
+
+// Options is a mapping type for options we pass as-is to container runtime
+type Options map[string]string
+
+func (d *Options) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case map[string]interface{}:
+ m := make(map[string]string)
+ for key, e := range v {
+ if e == nil {
+ m[key] = ""
+ } else {
+ m[key] = fmt.Sprint(e)
+ }
+ }
+ *d = m
+ case map[string]string:
+ *d = v
+ default:
+ return fmt.Errorf("invalid type %T for options", value)
+ }
+ return nil
+}
+
+// MultiOptions allow option to be repeated
+type MultiOptions map[string][]string
+
+func (d *MultiOptions) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case map[string]interface{}:
+ m := make(map[string][]string)
+ for key, e := range v {
+ switch e := e.(type) {
+ case []interface{}:
+ for _, v := range e {
+ m[key] = append(m[key], fmt.Sprint(v))
+ }
+ default:
+ m[key] = append(m[key], fmt.Sprint(e))
+ }
+ }
+ *d = m
+ default:
+ return fmt.Errorf("invalid type %T for options", value)
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/project.go b/vendor/github.com/compose-spec/compose-go/v2/types/project.go
new file mode 100644
index 0000000000..852361bed8
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/project.go
@@ -0,0 +1,1033 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "maps"
+ "os"
+ "path/filepath"
+ "slices"
+ "sort"
+ "sync"
+
+ "github.com/compose-spec/compose-go/v2/dotenv"
+ "github.com/compose-spec/compose-go/v2/errdefs"
+ "github.com/compose-spec/compose-go/v2/utils"
+ "github.com/distribution/reference"
+ godigest "github.com/opencontainers/go-digest"
+ "go.yaml.in/yaml/v4"
+ "golang.org/x/sync/errgroup"
+ "golang.org/x/sync/singleflight"
+)
+
+// Project is the result of loading a set of compose files
+// Since v2, Project are managed as immutable objects.
+// Each public functions which mutate Project state now return a copy of the original Project with the expected changes.
+type Project struct {
+ Name string `yaml:"name,omitempty" json:"name,omitempty"`
+ WorkingDir string `yaml:"-" json:"-"`
+ Services Services `yaml:"services" json:"services"`
+ Jobs Jobs `yaml:"jobs,omitempty" json:"jobs,omitempty"`
+ Networks Networks `yaml:"networks,omitempty" json:"networks,omitempty"`
+ Volumes Volumes `yaml:"volumes,omitempty" json:"volumes,omitempty"`
+ Secrets Secrets `yaml:"secrets,omitempty" json:"secrets,omitempty"`
+ Configs Configs `yaml:"configs,omitempty" json:"configs,omitempty"`
+ Models Models `yaml:"models,omitempty" json:"models,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"` // https://github.com/golang/go/issues/6213
+
+ ComposeFiles []string `yaml:"-" json:"-"`
+ Environment Mapping `yaml:"-" json:"-"`
+
+ // DisabledServices track services which have been disable as profile is not active
+ DisabledServices Services `yaml:"-" json:"-"`
+ // DisabledJobs track jobs which have been disabled as profile is not active
+ DisabledJobs Jobs `yaml:"-" json:"-"`
+ Profiles []string `yaml:"-" json:"-"`
+}
+
+// ServiceNames return names for all services in this Compose config
+func (p *Project) ServiceNames() []string {
+ var names []string
+ for k := range p.Services {
+ names = append(names, k)
+ }
+ sort.Strings(names)
+ return names
+}
+
+// DisabledServiceNames return names for all disabled services in this Compose config
+func (p *Project) DisabledServiceNames() []string {
+ var names []string
+ for k := range p.DisabledServices {
+ names = append(names, k)
+ }
+ sort.Strings(names)
+ return names
+}
+
+// VolumeNames return names for all volumes in this Compose config
+func (p *Project) VolumeNames() []string {
+ var names []string
+ for k := range p.Volumes {
+ names = append(names, k)
+ }
+ sort.Strings(names)
+ return names
+}
+
+// NetworkNames return names for all volumes in this Compose config
+func (p *Project) NetworkNames() []string {
+ var names []string
+ for k := range p.Networks {
+ names = append(names, k)
+ }
+ sort.Strings(names)
+ return names
+}
+
+// SecretNames return names for all secrets in this Compose config
+func (p *Project) SecretNames() []string {
+ var names []string
+ for k := range p.Secrets {
+ names = append(names, k)
+ }
+ sort.Strings(names)
+ return names
+}
+
+// ConfigNames return names for all configs in this Compose config
+func (p *Project) ConfigNames() []string {
+ var names []string
+ for k := range p.Configs {
+ names = append(names, k)
+ }
+ sort.Strings(names)
+ return names
+}
+
+// ModelNames return names for all models in this Compose config
+func (p *Project) ModelNames() []string {
+ var names []string
+ for k := range p.Models {
+ names = append(names, k)
+ }
+ sort.Strings(names)
+ return names
+}
+
+func (p *Project) ServicesWithBuild() []string {
+ servicesBuild := p.Services.Filter(func(s ServiceConfig) bool {
+ return s.Build != nil && s.Build.Context != ""
+ })
+ return slices.Collect(maps.Keys(servicesBuild))
+}
+
+func (p *Project) ServicesWithExtends() []string {
+ servicesExtends := p.Services.Filter(func(s ServiceConfig) bool {
+ return s.Extends != nil && *s.Extends != (ExtendsConfig{})
+ })
+ return slices.Collect(maps.Keys(servicesExtends))
+}
+
+func (p *Project) ServicesWithDependsOn() []string {
+ servicesDependsOn := p.Services.Filter(func(s ServiceConfig) bool {
+ return len(s.DependsOn) > 0
+ })
+ return slices.Collect(maps.Keys(servicesDependsOn))
+}
+
+func (p *Project) ServicesWithModels() []string {
+ servicesModels := p.Services.Filter(func(s ServiceConfig) bool { return len(s.Models) > 0 })
+ return slices.Collect(maps.Keys(servicesModels))
+}
+
+func (p *Project) ServicesWithCapabilities() ([]string, []string, []string) {
+ capabilities := []string{}
+ gpu := []string{}
+ tpu := []string{}
+ for _, service := range p.Services {
+ deploy := service.Deploy
+ if deploy == nil {
+ continue
+ }
+ reservation := deploy.Resources.Reservations
+ if reservation == nil {
+ continue
+ }
+ devices := reservation.Devices
+ for _, d := range devices {
+ if len(d.Capabilities) > 0 {
+ capabilities = append(capabilities, service.Name)
+ }
+ for _, c := range d.Capabilities {
+ switch c {
+ case "gpu":
+ gpu = append(gpu, service.Name)
+ case "tpu":
+ tpu = append(tpu, service.Name)
+ }
+ }
+ }
+ }
+
+ return utils.RemoveDuplicates(capabilities), utils.RemoveDuplicates(gpu), utils.RemoveDuplicates(tpu)
+}
+
+// GetServices retrieve services by names, or return all services if no name specified
+func (p *Project) GetServices(names ...string) (Services, error) {
+ if len(names) == 0 {
+ return p.Services, nil
+ }
+ services := Services{}
+ for _, name := range names {
+ service, err := p.GetService(name)
+ if err != nil {
+ return nil, err
+ }
+ services[name] = service
+ }
+ return services, nil
+}
+
+func (p *Project) getServicesByNames(names ...string) (Services, []string) {
+ if len(names) == 0 {
+ return p.Services, nil
+ }
+
+ services := Services{}
+ var servicesNotFound []string
+ for _, name := range names {
+ matched := false
+
+ for serviceName, service := range p.Services {
+ match, _ := filepath.Match(name, serviceName)
+ if match {
+ services[serviceName] = service
+ matched = true
+ }
+ }
+
+ if !matched {
+ servicesNotFound = append(servicesNotFound, name)
+ }
+ }
+
+ return services, servicesNotFound
+}
+
+// GetDisabledService retrieve disabled service by name
+func (p Project) GetDisabledService(name string) (ServiceConfig, error) {
+ service, ok := p.DisabledServices[name]
+ if !ok {
+ return ServiceConfig{}, fmt.Errorf("no such service: %s", name)
+ }
+ return service, nil
+}
+
+// GetService retrieve a specific service by name
+func (p *Project) GetService(name string) (ServiceConfig, error) {
+ service, ok := p.Services[name]
+ if !ok {
+ _, ok := p.DisabledServices[name]
+ if ok {
+ return ServiceConfig{}, fmt.Errorf("no such service: %s: %w", name, errdefs.ErrDisabled)
+ }
+ return ServiceConfig{}, fmt.Errorf("no such service: %s: %w", name, errdefs.ErrNotFound)
+ }
+ return service, nil
+}
+
+func (p *Project) AllServices() Services {
+ all := Services{}
+ for name, service := range p.Services {
+ all[name] = service
+ }
+ for name, service := range p.DisabledServices {
+ all[name] = service
+ }
+ return all
+}
+
+// AllJobs returns all the project jobs, enabled or not
+func (p *Project) AllJobs() Jobs {
+ all := Jobs{}
+ for name, job := range p.Jobs {
+ all[name] = job
+ }
+ for name, job := range p.DisabledJobs {
+ all[name] = job
+ }
+ return all
+}
+
+type ServiceFunc func(name string, service *ServiceConfig) error
+
+// ForEachService runs ServiceFunc on each service and dependencies according to DependencyPolicy
+func (p *Project) ForEachService(names []string, fn ServiceFunc, options ...DependencyOption) error {
+ if len(options) == 0 {
+ // backward compatibility
+ options = []DependencyOption{IncludeDependencies}
+ }
+ return p.withServices(names, fn, map[string]bool{}, options, map[string]ServiceDependency{})
+}
+
+type withServicesOptions struct {
+ dependencyPolicy int
+}
+
+const (
+ includeDependencies = iota
+ includeDependents
+ ignoreDependencies
+)
+
+func (p *Project) withServices(names []string, fn ServiceFunc, seen map[string]bool, options []DependencyOption, dependencies map[string]ServiceDependency) error {
+ services, servicesNotFound := p.getServicesByNames(names...)
+ if len(servicesNotFound) > 0 {
+ for _, serviceNotFound := range servicesNotFound {
+ if dependency, ok := dependencies[serviceNotFound]; !ok || dependency.Required {
+ return fmt.Errorf("no such service: %s", serviceNotFound)
+ }
+ }
+ }
+ opts := withServicesOptions{
+ dependencyPolicy: includeDependencies,
+ }
+ for _, option := range options {
+ option(&opts)
+ }
+
+ for name, service := range services {
+ if seen[name] {
+ continue
+ }
+ seen[name] = true
+ var dependencies map[string]ServiceDependency
+ switch opts.dependencyPolicy {
+ case includeDependents:
+ dependencies = utils.MapsAppend(dependencies, p.dependentsForService(service))
+ case includeDependencies:
+ dependencies = utils.MapsAppend(dependencies, service.DependsOn)
+ case ignoreDependencies:
+ // Noop
+ }
+ if len(dependencies) > 0 {
+ err := p.withServices(utils.MapKeys(dependencies), fn, seen, options, dependencies)
+ if err != nil {
+ return err
+ }
+ }
+ if err := fn(name, service.deepCopy()); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p *Project) GetDependentsForService(s ServiceConfig, filter ...func(ServiceDependency) bool) []string {
+ return utils.MapKeys(p.dependentsForService(s, filter...))
+}
+
+func (p *Project) dependentsForService(s ServiceConfig, filter ...func(ServiceDependency) bool) map[string]ServiceDependency {
+ dependent := make(map[string]ServiceDependency)
+ for _, service := range p.Services {
+ for name, dependency := range service.DependsOn {
+ if name == s.Name {
+ depends := true
+ for _, f := range filter {
+ if !f(dependency) {
+ depends = false
+ break
+ }
+ }
+ if depends {
+ dependent[service.Name] = dependency
+ }
+ }
+ }
+ }
+ return dependent
+}
+
+// RelativePath resolve a relative path based project's working directory
+func (p *Project) RelativePath(path string) string {
+ if path[0] == '~' {
+ home, _ := os.UserHomeDir()
+ path = filepath.Join(home, path[1:])
+ }
+ if filepath.IsAbs(path) {
+ return path
+ }
+ return filepath.Join(p.WorkingDir, path)
+}
+
+// HasProfile return true if service has no profile declared or has at least one profile matching
+func (s ServiceConfig) HasProfile(profiles []string) bool {
+ return matchesProfiles(s.Profiles, profiles)
+}
+
+// HasProfile return true if job has no profile declared or has at least one profile matching
+func (j JobConfig) HasProfile(profiles []string) bool {
+ return matchesProfiles(j.Profiles, profiles)
+}
+
+func matchesProfiles(declared, active []string) bool {
+ if len(declared) == 0 {
+ return true
+ }
+ for _, p := range active {
+ if p == "*" {
+ return true
+ }
+ for _, sp := range declared {
+ if sp == p {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// WithProfiles disables services which don't match selected profiles
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p *Project) WithProfiles(profiles []string) (*Project, error) {
+ newProject := p.deepCopy()
+ enabled := Services{}
+ disabled := Services{}
+ for name, service := range newProject.AllServices() {
+ if service.HasProfile(profiles) {
+ enabled[name] = service
+ } else {
+ disabled[name] = service
+ }
+ }
+ newProject.Services = enabled
+ newProject.DisabledServices = disabled
+
+ if newProject.Jobs != nil || newProject.DisabledJobs != nil {
+ enabledJobs := Jobs{}
+ disabledJobs := Jobs{}
+ for name, job := range newProject.AllJobs() {
+ if job.HasProfile(profiles) {
+ enabledJobs[name] = job
+ } else {
+ disabledJobs[name] = job
+ }
+ }
+ newProject.Jobs = enabledJobs
+ newProject.DisabledJobs = disabledJobs
+ }
+
+ newProject.Profiles = profiles
+ return newProject, nil
+}
+
+// WithServicesEnabled ensures services are enabled and activate profiles accordingly
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p *Project) WithServicesEnabled(names ...string) (*Project, error) {
+ newProject := p.deepCopy()
+ if len(names) == 0 {
+ return newProject, nil
+ }
+
+ profiles := append([]string{}, p.Profiles...)
+ for _, name := range names {
+ if _, ok := newProject.Services[name]; ok {
+ // already enabled
+ continue
+ }
+ service := p.DisabledServices[name]
+ profiles = append(profiles, service.Profiles...)
+ }
+ return newProject.WithProfiles(profiles)
+}
+
+// WithoutUnnecessaryResources drops networks/volumes/secrets/configs that are not referenced by active services
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p *Project) WithoutUnnecessaryResources() *Project {
+ newProject := p.deepCopy()
+ requiredNetworks := map[string]struct{}{}
+ requiredVolumes := map[string]struct{}{}
+ requiredSecrets := map[string]struct{}{}
+ requiredConfigs := map[string]struct{}{}
+ requiredModels := map[string]struct{}{}
+ for _, s := range newProject.Services {
+ for k := range s.Networks {
+ requiredNetworks[k] = struct{}{}
+ }
+ for _, v := range s.Volumes {
+ if v.Type != VolumeTypeVolume || v.Source == "" {
+ continue
+ }
+ requiredVolumes[v.Source] = struct{}{}
+ }
+ for _, v := range s.Secrets {
+ requiredSecrets[v.Source] = struct{}{}
+ }
+ if s.Build != nil {
+ for _, v := range s.Build.Secrets {
+ requiredSecrets[v.Source] = struct{}{}
+ }
+ }
+ for _, v := range s.Configs {
+ requiredConfigs[v.Source] = struct{}{}
+ }
+ for m := range s.Models {
+ requiredModels[m] = struct{}{}
+ }
+ }
+
+ networks := Networks{}
+ for k := range requiredNetworks {
+ if value, ok := p.Networks[k]; ok {
+ networks[k] = value
+ }
+ }
+ newProject.Networks = networks
+
+ volumes := Volumes{}
+ for k := range requiredVolumes {
+ if value, ok := p.Volumes[k]; ok {
+ volumes[k] = value
+ }
+ }
+ newProject.Volumes = volumes
+
+ secrets := Secrets{}
+ for k := range requiredSecrets {
+ if value, ok := p.Secrets[k]; ok {
+ secrets[k] = value
+ }
+ }
+ newProject.Secrets = secrets
+
+ configs := Configs{}
+ for k := range requiredConfigs {
+ if value, ok := p.Configs[k]; ok {
+ configs[k] = value
+ }
+ }
+ newProject.Configs = configs
+
+ models := Models{}
+ for k := range requiredModels {
+ if value, ok := p.Models[k]; ok {
+ models[k] = value
+ }
+ }
+ newProject.Models = models
+ return newProject
+}
+
+type DependencyOption func(options *withServicesOptions)
+
+func IncludeDependencies(options *withServicesOptions) {
+ options.dependencyPolicy = includeDependencies
+}
+
+func IncludeDependents(options *withServicesOptions) {
+ options.dependencyPolicy = includeDependents
+}
+
+func IgnoreDependencies(options *withServicesOptions) {
+ options.dependencyPolicy = ignoreDependencies
+}
+
+// WithSelectedServices restricts the project model to selected services and dependencies
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p *Project) WithSelectedServices(names []string, options ...DependencyOption) (*Project, error) {
+ newProject := p.deepCopy()
+ if len(names) == 0 {
+ // All services
+ return newProject, nil
+ }
+
+ set := utils.NewSet[string]()
+ err := p.ForEachService(names, func(name string, _ *ServiceConfig) error {
+ set.Add(name)
+ return nil
+ }, options...)
+ if err != nil {
+ return nil, err
+ }
+
+ // Disable all services which are not explicit target or dependencies
+ enabled := Services{}
+ for name, s := range newProject.Services {
+ if _, ok := set[name]; ok {
+ // remove all dependencies but those implied by explicitly selected services
+ dependencies := s.DependsOn
+ for d := range dependencies {
+ if _, ok := set[d]; !ok {
+ delete(dependencies, d)
+ }
+ }
+ s.DependsOn = dependencies
+ enabled[name] = s
+ } else {
+ newProject = newProject.WithServicesDisabled(name)
+ }
+ }
+ newProject.Services = enabled
+ return newProject, nil
+}
+
+// WithoutUnresolvedOptionalDependencies removes from services any optional (required: false)
+// depends_on reference to a service absent from the model — typically disabled by an inactive
+// profile or dropped by service selection. Required references are deliberately kept, so
+// consumers can detect them and report a meaningful error.
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p *Project) WithoutUnresolvedOptionalDependencies() *Project {
+ newProject := p.deepCopy()
+ for name, s := range newProject.Services {
+ for dep, cfg := range s.DependsOn {
+ if _, ok := newProject.Services[dep]; !ok && !cfg.Required {
+ delete(s.DependsOn, dep)
+ }
+ }
+ newProject.Services[name] = s
+ }
+ return newProject
+}
+
+// WithSelectedJob returns a new Project containing only the services required
+// by the named job's DependsOn. The job itself is NOT added to Services.
+func (p *Project) WithSelectedJob(name string, options ...DependencyOption) (*Project, error) {
+ job, ok := p.Jobs[name]
+ if !ok {
+ if disabled, exists := p.DisabledJobs[name]; exists {
+ // a profile-disabled job is enabled when explicitly selected,
+ // and its profiles are added to the set of active profiles
+ enabled, err := p.WithProfiles(append(append([]string{}, p.Profiles...), disabled.Profiles...))
+ if err != nil {
+ return nil, err
+ }
+ return enabled.WithSelectedJob(name, options...)
+ }
+ return nil, fmt.Errorf("no such job: %s", name)
+ }
+
+ // a job may depend on another job: walk depends_on transitively to
+ // collect the actual services required to run the selected job. Jobs are
+ // looked up enabled or not — a profile-disabled dependency is still a
+ // job, and treating its name as a service would fail the selection.
+ deps := resolveJobServiceDeps(p.AllJobs(), job, map[string]bool{name: true})
+ sort.Strings(deps)
+
+ if len(deps) == 0 {
+ // Job has no service dependencies: return project with all services disabled
+ newProject := p.deepCopy()
+ for name := range newProject.Services {
+ newProject = newProject.WithServicesDisabled(name)
+ }
+ return newProject, nil
+ }
+
+ return p.WithSelectedServices(deps, options...)
+}
+
+// resolveJobServiceDeps walks a job's DependsOn, following job-typed
+// dependencies transitively, and returns the names of the actual services
+// required to run it. jobs is the full job set (see AllJobs), so a
+// profile-disabled job in the chain is followed like an enabled one. A
+// dependency name matching a job takes precedence over a same-named service
+// — jobs and services share the depends_on namespace, and a job reference is
+// resolved first. seen guards against dependency cycles between jobs and
+// must contain the starting job's name.
+func resolveJobServiceDeps(jobs Jobs, job JobConfig, seen map[string]bool) []string {
+ var services []string
+ for dep := range job.DependsOn {
+ if seen[dep] {
+ continue
+ }
+ seen[dep] = true
+ if depJob, ok := jobs[dep]; ok {
+ services = append(services, resolveJobServiceDeps(jobs, depJob, seen)...)
+ continue
+ }
+ services = append(services, dep)
+ }
+ return services
+}
+
+// WithServicesDisabled removes from the project model the given services and their references in all dependencies
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p *Project) WithServicesDisabled(names ...string) *Project {
+ newProject := p.deepCopy()
+ if len(names) == 0 {
+ return newProject
+ }
+ if newProject.DisabledServices == nil {
+ newProject.DisabledServices = Services{}
+ }
+ for _, name := range names {
+ // We should remove all dependencies which reference the disabled service
+ for i, s := range newProject.Services {
+ if _, ok := s.DependsOn[name]; ok {
+ delete(s.DependsOn, name)
+ newProject.Services[i] = s
+ }
+ }
+ if service, ok := newProject.Services[name]; ok {
+ newProject.DisabledServices[name] = service
+ delete(newProject.Services, name)
+ }
+ }
+ return newProject
+}
+
+// WithImagesResolved updates services images to include digest computed by a resolver function
+// It returns a new Project instance with the changes and keep the original Project unchanged.
+// Besides the service image, this also resolves the images services depend on:
+// - pre_start hook images, which run as ephemeral init containers with their own image
+// - `type: image` volume sources — source is always a docker image reference, not
+// a reference to another service (there is no such thing in the Compose Spec)
+func (p *Project) WithImagesResolved(resolver func(named reference.Named) (godigest.Digest, error)) (*Project, error) {
+ // Deduplicate resolutions per raw image string across the whole call, on two axes:
+ // - cache (sync.Map) memoizes results for the whole call, so images resolved at
+ // different times — e.g. a hook or volume source equal to service.Image, resolved
+ // sequentially within the same service — are resolved once.
+ // - singleflight collapses concurrent resolutions of the same image (transforms run
+ // one goroutine per service) into a single call before it reaches the cache.
+ // Neither alone suffices: the cache lets a concurrent burst miss simultaneously and
+ // all resolve, while singleflight forgets a key as soon as its call returns.
+ var (
+ cache sync.Map // map[string]string
+ group singleflight.Group
+ )
+ resolve := func(image string) (string, error) {
+ if r, ok := cache.Load(image); ok {
+ return r.(string), nil
+ }
+ r, err, _ := group.Do(image, func() (any, error) {
+ if r, ok := cache.Load(image); ok {
+ return r, nil
+ }
+ r, err := resolveImageDigest(image, resolver)
+ if err != nil {
+ return image, err
+ }
+ cache.Store(image, r)
+ return r, nil
+ })
+ if err != nil {
+ return image, err
+ }
+ return r.(string), nil
+ }
+ return p.WithServicesTransform(func(_ string, service ServiceConfig) (ServiceConfig, error) {
+ image, err := resolve(service.Image)
+ if err != nil {
+ return service, err
+ }
+ service.Image = image
+
+ for i, hook := range service.PreStart {
+ image, err := resolve(hook.Image)
+ if err != nil {
+ return service, err
+ }
+ service.PreStart[i].Image = image
+ }
+
+ for i, vol := range service.Volumes {
+ if vol.Type != VolumeTypeImage {
+ continue
+ }
+ image, err := resolve(vol.Source)
+ if err != nil {
+ return service, err
+ }
+ service.Volumes[i].Source = image
+ }
+ return service, nil
+ })
+}
+
+// resolveImageDigest returns image with its digest resolved by resolver, unless
+// it is empty or already a canonical (digested) reference, in which case it is
+// returned unchanged.
+func resolveImageDigest(image string, resolver func(named reference.Named) (godigest.Digest, error)) (string, error) {
+ if image == "" {
+ return image, nil
+ }
+ named, err := reference.ParseDockerRef(image)
+ if err != nil {
+ return image, err
+ }
+
+ if _, ok := named.(reference.Canonical); !ok {
+ // image is named but not digested reference
+ digest, err := resolver(named)
+ if err != nil {
+ return image, err
+ }
+ named, err = reference.WithDigest(named, digest)
+ if err != nil {
+ return image, err
+ }
+ }
+ return named.String(), nil
+}
+
+type marshallOptions struct {
+ secretsContent bool
+}
+
+func WithSecretContent(o *marshallOptions) {
+ o.secretsContent = true
+}
+
+func (opt *marshallOptions) apply(p *Project) *Project {
+ if opt.secretsContent {
+ p = p.deepCopy()
+ for name, config := range p.Secrets {
+ config.marshallContent = true
+ p.Secrets[name] = config
+ }
+ }
+ return p
+}
+
+func applyMarshallOptions(p *Project, options ...func(*marshallOptions)) *Project {
+ opts := &marshallOptions{}
+ for _, option := range options {
+ option(opts)
+ }
+ p = opts.apply(p)
+ return p
+}
+
+// MarshalYAML marshal Project into a yaml tree
+func (p *Project) MarshalYAML(options ...func(*marshallOptions)) ([]byte, error) {
+ buf := bytes.NewBuffer([]byte{})
+ encoder := yaml.NewEncoder(buf)
+ encoder.SetIndent(2)
+ // encoder.CompactSeqIndent() FIXME https://github.com/go-yaml/yaml/pull/753
+ src := applyMarshallOptions(p, options...)
+ err := encoder.Encode(src)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalJSON marshal Project into a json document
+func (p *Project) MarshalJSON(options ...func(*marshallOptions)) ([]byte, error) {
+ src := applyMarshallOptions(p, options...)
+ m := map[string]interface{}{
+ "name": src.Name,
+ "services": src.Services,
+ }
+
+ if len(src.Networks) > 0 {
+ m["networks"] = src.Networks
+ }
+ if len(src.Volumes) > 0 {
+ m["volumes"] = src.Volumes
+ }
+ if len(src.Secrets) > 0 {
+ m["secrets"] = src.Secrets
+ }
+ if len(src.Configs) > 0 {
+ m["configs"] = src.Configs
+ }
+ if len(src.Jobs) > 0 {
+ m["jobs"] = src.Jobs
+ }
+ for k, v := range src.Extensions {
+ m[k] = v
+ }
+ return json.MarshalIndent(m, "", " ")
+}
+
+// WithServicesEnvironmentResolved parses env_files set for services to resolve the actual environment map for services
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p Project) WithServicesEnvironmentResolved(discardEnvFiles bool) (*Project, error) {
+ newProject := p.deepCopy()
+ for i, service := range newProject.Services {
+ service.Environment = service.Environment.Resolve(newProject.Environment.Resolve)
+
+ environment := service.Environment.ToMapping()
+ for _, envFile := range service.EnvFiles {
+ err := loadEnvFile(envFile, environment, func(k string) (string, bool) {
+ // project.env has precedence doing interpolation
+ if resolve, ok := p.Environment.Resolve(k); ok {
+ return resolve, true
+ }
+ // then service.environment
+ if s, ok := service.Environment[k]; ok && s != nil {
+ return *s, true
+ }
+ return "", false
+ })
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ service.Environment = environment.ToMappingWithEquals().OverrideBy(service.Environment)
+
+ if discardEnvFiles {
+ service.EnvFiles = nil
+ }
+ newProject.Services[i] = service
+ }
+ return newProject, nil
+}
+
+// WithServicesLabelsResolved parses label_files set for services to resolve the actual label map for services
+// It returns a new Project instance with the changes and keep the original Project unchanged
+func (p Project) WithServicesLabelsResolved(discardLabelFiles bool) (*Project, error) {
+ newProject := p.deepCopy()
+ for i, service := range newProject.Services {
+ labels := MappingWithEquals{}
+ // resolve variables based on other files we already parsed
+ var resolve dotenv.LookupFn = func(s string) (string, bool) {
+ v, ok := labels[s]
+ if ok && v != nil {
+ return *v, ok
+ }
+ return "", false
+ }
+
+ for _, labelFile := range service.LabelFiles {
+ vars, err := loadLabelFile(labelFile, resolve)
+ if err != nil {
+ return nil, err
+ }
+ labels.OverrideBy(vars.ToMappingWithEquals())
+ }
+
+ labels = labels.OverrideBy(service.Labels.ToMappingWithEquals())
+ if len(labels) == 0 {
+ labels = nil
+ } else {
+ service.Labels = NewLabelsFromMappingWithEquals(labels)
+ }
+
+ if discardLabelFiles {
+ service.LabelFiles = nil
+ }
+ newProject.Services[i] = service
+ }
+ return newProject, nil
+}
+
+func loadEnvFile(envFile EnvFile, environment Mapping, resolve dotenv.LookupFn) error {
+ if _, err := os.Stat(envFile.Path); os.IsNotExist(err) {
+ if envFile.Required {
+ return fmt.Errorf("env file %s not found: %w", envFile.Path, err)
+ }
+ return nil
+ }
+
+ err := loadMappingFile(envFile.Path, envFile.Format, environment, resolve)
+ return err
+}
+
+func loadLabelFile(labelFile string, resolve dotenv.LookupFn) (Mapping, error) {
+ if _, err := os.Stat(labelFile); os.IsNotExist(err) {
+ return nil, fmt.Errorf("label file %s not found: %w", labelFile, err)
+ }
+
+ labels := Mapping{}
+ err := loadMappingFile(labelFile, "", labels, resolve)
+ return labels, err
+}
+
+func loadMappingFile(path string, format string, vars Mapping, resolve dotenv.LookupFn) error {
+ file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ return dotenv.ParseWithFormat(file, path, vars, resolve, format)
+}
+
+func (p *Project) deepCopy() *Project {
+ if p == nil {
+ return nil
+ }
+ n := &Project{}
+ deriveDeepCopyProject(n, p)
+ return n
+}
+
+// WithServicesTransform applies a transformation to project services and return a new project with transformation results
+func (p *Project) WithServicesTransform(fn func(name string, s ServiceConfig) (ServiceConfig, error)) (*Project, error) {
+ type result struct {
+ name string
+ service ServiceConfig
+ }
+ expect := len(p.Services)
+ resultCh := make(chan result, expect)
+ newProject := p.deepCopy()
+ services := newProject.Services
+
+ eg, ctx := errgroup.WithContext(context.Background())
+ eg.Go(func() error {
+ s := Services{}
+ for expect > 0 {
+ select {
+ case <-ctx.Done():
+ // interrupted as some goroutine returned an error
+ return nil
+ case r := <-resultCh:
+ s[r.name] = r.service
+ expect--
+ }
+ }
+ newProject.Services = s
+ return nil
+ })
+ for n, s := range services {
+ name := n
+ service := s
+ eg.Go(func() error {
+ updated, err := fn(name, service)
+ if err != nil {
+ return err
+ }
+ resultCh <- result{
+ name: name,
+ service: updated,
+ }
+ return nil
+ })
+ }
+ return newProject, eg.Wait()
+}
+
+// CheckContainerNameUnicity validate project doesn't have services declaring the same container_name
+func (p *Project) CheckContainerNameUnicity() error {
+ names := utils.Set[string]{}
+ for name, s := range p.Services {
+ if s.ContainerName != "" {
+ if existing, ok := names[s.ContainerName]; ok {
+ return fmt.Errorf(`services.%s: container name %q is already in use by service %s"`, name, s.ContainerName, existing)
+ }
+ names.Add(s.ContainerName)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/services.go b/vendor/github.com/compose-spec/compose-go/v2/types/services.go
new file mode 100644
index 0000000000..0efc4b9fab
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/services.go
@@ -0,0 +1,45 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+// Services is a map of ServiceConfig
+type Services map[string]ServiceConfig
+
+// GetProfiles retrieve the profiles implicitly enabled by explicitly targeting selected services
+func (s Services) GetProfiles() []string {
+ set := map[string]struct{}{}
+ for _, service := range s {
+ for _, p := range service.Profiles {
+ set[p] = struct{}{}
+ }
+ }
+ var profiles []string
+ for k := range set {
+ profiles = append(profiles, k)
+ }
+ return profiles
+}
+
+func (s Services) Filter(predicate func(ServiceConfig) bool) Services {
+ services := Services{}
+ for name, service := range s {
+ if predicate(service) {
+ services[name] = service
+ }
+ }
+ return services
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/ssh.go b/vendor/github.com/compose-spec/compose-go/v2/types/ssh.go
new file mode 100644
index 0000000000..6d0edb6956
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/ssh.go
@@ -0,0 +1,73 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "fmt"
+)
+
+type SSHKey struct {
+ ID string `yaml:"id,omitempty" json:"id,omitempty"`
+ Path string `path:"path,omitempty" json:"path,omitempty"`
+}
+
+// SSHConfig is a mapping type for SSH build config
+type SSHConfig []SSHKey
+
+func (s SSHConfig) Get(id string) (string, error) {
+ for _, sshKey := range s {
+ if sshKey.ID == id {
+ return sshKey.Path, nil
+ }
+ }
+ return "", fmt.Errorf("ID %s not found in SSH keys", id)
+}
+
+// MarshalYAML makes SSHKey implement yaml.Marshaller
+func (s SSHKey) MarshalYAML() (interface{}, error) {
+ if s.Path == "" {
+ return s.ID, nil
+ }
+ return fmt.Sprintf("%s: %s", s.ID, s.Path), nil
+}
+
+// MarshalJSON makes SSHKey implement json.Marshaller
+func (s SSHKey) MarshalJSON() ([]byte, error) {
+ if s.Path == "" {
+ return []byte(fmt.Sprintf(`%q`, s.ID)), nil
+ }
+ return []byte(fmt.Sprintf(`%q: %s`, s.ID, s.Path)), nil
+}
+
+func (s *SSHConfig) DecodeMapstructure(value interface{}) error {
+ v, ok := value.(map[string]any)
+ if !ok {
+ return fmt.Errorf("invalid ssh config type %T", value)
+ }
+ result := make(SSHConfig, len(v))
+ i := 0
+ for id, path := range v {
+ key := SSHKey{ID: id}
+ if path != nil {
+ key.Path = fmt.Sprint(path)
+ }
+ result[i] = key
+ i++
+ }
+ *s = result
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/stringOrList.go b/vendor/github.com/compose-spec/compose-go/v2/types/stringOrList.go
new file mode 100644
index 0000000000..a6720df088
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/stringOrList.go
@@ -0,0 +1,61 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import "fmt"
+
+// StringList is a type for fields that can be a string or list of strings
+type StringList []string
+
+func (l *StringList) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case string:
+ *l = []string{v}
+ case []interface{}:
+ list := make([]string, len(v))
+ for i, e := range v {
+ val, ok := e.(string)
+ if !ok {
+ return fmt.Errorf("invalid type %T for string list", value)
+ }
+ list[i] = val
+ }
+ *l = list
+ default:
+ return fmt.Errorf("invalid type %T for string list", value)
+ }
+ return nil
+}
+
+// StringOrNumberList is a type for fields that can be a list of strings or numbers
+type StringOrNumberList []string
+
+func (l *StringOrNumberList) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case string:
+ *l = []string{v}
+ case []interface{}:
+ list := make([]string, len(v))
+ for i, e := range v {
+ list[i] = fmt.Sprint(e)
+ }
+ *l = list
+ default:
+ return fmt.Errorf("invalid type %T for string list", value)
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/types/types.go b/vendor/github.com/compose-spec/compose-go/v2/types/types.go
new file mode 100644
index 0000000000..bab138cd62
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/types.go
@@ -0,0 +1,900 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package types
+
+import (
+ "encoding/json"
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/docker/go-connections/nat"
+ "github.com/xhit/go-str2duration/v2"
+)
+
+// ContainerSpec defines the runtime configuration for a container.
+// It is the common set of attributes shared by services, jobs, and other container-based elements.
+// ContainerSpec holds the attributes shared by anything that runs a container:
+// services, jobs, and run-to-completion init containers (pre_start hooks).
+type ContainerSpec struct {
+ Annotations Mapping `yaml:"annotations,omitempty" json:"annotations,omitempty"`
+ BlkioConfig *BlkioConfig `yaml:"blkio_config,omitempty" json:"blkio_config,omitempty"`
+ CapAdd []string `yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
+ CapDrop []string `yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"`
+ CgroupParent string `yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"`
+ Cgroup string `yaml:"cgroup,omitempty" json:"cgroup,omitempty"`
+ CPUCount int64 `yaml:"cpu_count,omitempty" json:"cpu_count,omitempty"`
+ CPUPercent float32 `yaml:"cpu_percent,omitempty" json:"cpu_percent,omitempty"`
+ CPUPeriod int64 `yaml:"cpu_period,omitempty" json:"cpu_period,omitempty"`
+ CPUQuota int64 `yaml:"cpu_quota,omitempty" json:"cpu_quota,omitempty"`
+ CPURTPeriod int64 `yaml:"cpu_rt_period,omitempty" json:"cpu_rt_period,omitempty"`
+ CPURTRuntime int64 `yaml:"cpu_rt_runtime,omitempty" json:"cpu_rt_runtime,omitempty"`
+ CPUS float32 `yaml:"cpus,omitempty" json:"cpus,omitempty"`
+ CPUSet string `yaml:"cpuset,omitempty" json:"cpuset,omitempty"`
+ CPUShares int64 `yaml:"cpu_shares,omitempty" json:"cpu_shares,omitempty"`
+
+ // Command for the service containers.
+ // If set, overrides COMMAND from the image.
+ //
+ // Set to `[]` or an empty string to clear the command from the image.
+ Command ShellCommand `yaml:"command,omitempty" json:"command"` // NOTE: we can NOT omitempty for JSON! see ShellCommand type for details.
+
+ Configs []ServiceConfigObjConfig `yaml:"configs,omitempty" json:"configs,omitempty"`
+ CredentialSpec *CredentialSpecConfig `yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
+ DeviceCgroupRules []string `yaml:"device_cgroup_rules,omitempty" json:"device_cgroup_rules,omitempty"`
+ Devices []DeviceMapping `yaml:"devices,omitempty" json:"devices,omitempty"`
+ DNS StringList `yaml:"dns,omitempty" json:"dns,omitempty"`
+ DNSOpts []string `yaml:"dns_opt,omitempty" json:"dns_opt,omitempty"`
+ DNSSearch StringList `yaml:"dns_search,omitempty" json:"dns_search,omitempty"`
+ DomainName string `yaml:"domainname,omitempty" json:"domainname,omitempty"`
+
+ // Entrypoint for the service containers.
+ // If set, overrides ENTRYPOINT from the image.
+ //
+ // Set to `[]` or an empty string to clear the entrypoint from the image.
+ Entrypoint ShellCommand `yaml:"entrypoint,omitempty" json:"entrypoint"` // NOTE: we can NOT omitempty for JSON! see ShellCommand type for details.
+ Environment MappingWithEquals `yaml:"environment,omitempty" json:"environment,omitempty"`
+ EnvFiles []EnvFile `yaml:"env_file,omitempty" json:"env_file,omitempty"`
+ ExtraHosts HostsList `yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
+ GroupAdd []string `yaml:"group_add,omitempty" json:"group_add,omitempty"`
+ Gpus []DeviceRequest `yaml:"gpus,omitempty" json:"gpus,omitempty"`
+ Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
+ Image string `yaml:"image,omitempty" json:"image,omitempty"`
+ Init *bool `yaml:"init,omitempty" json:"init,omitempty"`
+ Ipc string `yaml:"ipc,omitempty" json:"ipc,omitempty"`
+ Isolation string `yaml:"isolation,omitempty" json:"isolation,omitempty"`
+ Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
+ LabelFiles []string `yaml:"label_file,omitempty" json:"label_file,omitempty"`
+ CustomLabels Labels `yaml:"-" json:"-"`
+ Logging *LoggingConfig `yaml:"logging,omitempty" json:"logging,omitempty"`
+ LogDriver string `yaml:"log_driver,omitempty" json:"log_driver,omitempty"`
+ LogOpt map[string]string `yaml:"log_opt,omitempty" json:"log_opt,omitempty"`
+ MemLimit UnitBytes `yaml:"mem_limit,omitempty" json:"mem_limit,omitempty"`
+ MemReservation UnitBytes `yaml:"mem_reservation,omitempty" json:"mem_reservation,omitempty"`
+ MemSwapLimit UnitBytes `yaml:"memswap_limit,omitempty" json:"memswap_limit,omitempty"`
+ MemSwappiness UnitBytes `yaml:"mem_swappiness,omitempty" json:"mem_swappiness,omitempty"`
+ MacAddress string `yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
+ Models map[string]*ServiceModelConfig `yaml:"models,omitempty" json:"models,omitempty"`
+ NetworkMode string `yaml:"network_mode,omitempty" json:"network_mode,omitempty"`
+ Networks map[string]*ServiceNetworkConfig `yaml:"networks,omitempty" json:"networks,omitempty"`
+ OomKillDisable bool `yaml:"oom_kill_disable,omitempty" json:"oom_kill_disable,omitempty"`
+ OomScoreAdj int64 `yaml:"oom_score_adj,omitempty" json:"oom_score_adj,omitempty"`
+ Pid string `yaml:"pid,omitempty" json:"pid,omitempty"`
+ PidsLimit int64 `yaml:"pids_limit,omitempty" json:"pids_limit,omitempty"`
+ Platform string `yaml:"platform,omitempty" json:"platform,omitempty"`
+ Privileged bool `yaml:"privileged,omitempty" json:"privileged,omitempty"`
+ PullPolicy string `yaml:"pull_policy,omitempty" json:"pull_policy,omitempty"`
+ PullRefreshAfter string `yaml:"pull_refresh_after,omitempty" json:"pull_refresh_after,omitempty"`
+ ReadOnly bool `yaml:"read_only,omitempty" json:"read_only,omitempty"`
+ Runtime string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
+ Secrets []ServiceSecretConfig `yaml:"secrets,omitempty" json:"secrets,omitempty"`
+ SecurityOpt []string `yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
+ ShmSize UnitBytes `yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
+ StopGracePeriod *Duration `yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
+ StopSignal string `yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
+ StorageOpt map[string]string `yaml:"storage_opt,omitempty" json:"storage_opt,omitempty"`
+ Sysctls Mapping `yaml:"sysctls,omitempty" json:"sysctls,omitempty"`
+ Tmpfs StringList `yaml:"tmpfs,omitempty" json:"tmpfs,omitempty"`
+ Ulimits map[string]*UlimitsConfig `yaml:"ulimits,omitempty" json:"ulimits,omitempty"`
+ UseAPISocket bool `yaml:"use_api_socket,omitempty" json:"use_api_socket,omitempty"`
+ User string `yaml:"user,omitempty" json:"user,omitempty"`
+ UserNSMode string `yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"`
+ Uts string `yaml:"uts,omitempty" json:"uts,omitempty"`
+ VolumeDriver string `yaml:"volume_driver,omitempty" json:"volume_driver,omitempty"`
+ Volumes []ServiceVolumeConfig `yaml:"volumes,omitempty" json:"volumes,omitempty"`
+ VolumesFrom []string `yaml:"volumes_from,omitempty" json:"volumes_from,omitempty"`
+ WorkingDir string `yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
+}
+
+// WorkloadSpec holds container attributes meaningful for orchestrated
+// workloads (services and jobs) but not for run-to-completion init
+// containers: build, dependency ordering, health reporting, port exposure
+// and interactivity.
+type WorkloadSpec struct {
+ Build *BuildConfig `yaml:"build,omitempty" json:"build,omitempty"`
+ DependsOn DependsOnConfig `yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
+ Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
+ Expose StringOrNumberList `yaml:"expose,omitempty" json:"expose,omitempty"`
+ HealthCheck *HealthCheckConfig `yaml:"healthcheck,omitempty" json:"healthcheck,omitempty"`
+ Ports []ServicePortConfig `yaml:"ports,omitempty" json:"ports,omitempty"`
+ StdinOpen bool `yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
+ Tty bool `yaml:"tty,omitempty" json:"tty,omitempty"`
+}
+
+// ServiceConfig is the configuration of one service
+type ServiceConfig struct {
+ Name string `yaml:"name,omitempty" json:"-"`
+ Profiles []string `yaml:"profiles,omitempty" json:"profiles,omitempty"`
+ Deploy *DeployConfig `yaml:"deploy,omitempty" json:"deploy,omitempty"`
+ Develop *DevelopConfig `yaml:"develop,omitempty" json:"develop,omitempty"`
+ Restart string `yaml:"restart,omitempty" json:"restart,omitempty"`
+ Scale *int `yaml:"scale,omitempty" json:"scale,omitempty"`
+
+ Attach *bool `yaml:"attach,omitempty" json:"attach,omitempty"`
+ ContainerName string `yaml:"container_name,omitempty" json:"container_name,omitempty"`
+ Provider *ServiceProviderConfig `yaml:"provider,omitempty" json:"provider,omitempty"`
+ Extends *ExtendsConfig `yaml:"extends,omitempty" json:"extends,omitempty"`
+ ExternalLinks []string `yaml:"external_links,omitempty" json:"external_links,omitempty"`
+ Links []string `yaml:"links,omitempty" json:"links,omitempty"`
+ Net string `yaml:"net,omitempty" json:"net,omitempty"`
+ PreStart []PreStartHook `yaml:"pre_start,omitempty" json:"pre_start,omitempty"`
+ PostStart []ServiceHook `yaml:"post_start,omitempty" json:"post_start,omitempty"`
+ PreStop []ServiceHook `yaml:"pre_stop,omitempty" json:"pre_stop,omitempty"`
+
+ ContainerSpec `yaml:",inline" mapstructure:",squash"`
+ WorkloadSpec `yaml:",inline" mapstructure:",squash"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+type ServiceProviderConfig struct {
+ Type string `yaml:"type,omitempty" json:"type,omitempty"`
+ Options MultiOptions `yaml:"options,omitempty" json:"options,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// MarshalYAML makes ServiceConfig implement yaml.Marshaller
+func (s ServiceConfig) MarshalYAML() (interface{}, error) {
+ type t ServiceConfig
+ value := t(s)
+ value.Name = "" // set during map to slice conversion, not part of the yaml representation
+ return value, nil
+}
+
+// NetworksByPriority return the service networks IDs sorted according to Priority
+func (s *ContainerSpec) NetworksByPriority() []string {
+ type key struct {
+ name string
+ priority int
+ }
+ var keys []key
+ for k, v := range s.Networks {
+ priority := 0
+ if v != nil {
+ priority = v.Priority
+ }
+ keys = append(keys, key{
+ name: k,
+ priority: priority,
+ })
+ }
+ sort.Slice(keys, func(i, j int) bool {
+ if keys[i].priority == keys[j].priority {
+ return keys[i].name < keys[j].name
+ }
+ return keys[i].priority > keys[j].priority
+ })
+ var sorted []string
+ for _, k := range keys {
+ sorted = append(sorted, k.name)
+ }
+ return sorted
+}
+
+func (s *ServiceConfig) GetScale() int {
+ if s.Scale != nil {
+ return *s.Scale
+ }
+ if s.Deploy != nil && s.Deploy.Replicas != nil {
+ // this should not be required as compose-go enforce consistency between scale anr replicas
+ return *s.Deploy.Replicas
+ }
+ return 1
+}
+
+func (s *ServiceConfig) SetScale(scale int) {
+ s.Scale = &scale
+ if s.Deploy != nil {
+ s.Deploy.Replicas = &scale
+ }
+}
+
+func (s *ServiceConfig) deepCopy() *ServiceConfig {
+ if s == nil {
+ return nil
+ }
+ n := &ServiceConfig{}
+ deriveDeepCopyService(n, s)
+ return n
+}
+
+const (
+ // PullPolicyAlways always pull images
+ PullPolicyAlways = "always"
+ // PullPolicyNever never pull images
+ PullPolicyNever = "never"
+ // PullPolicyIfNotPresent pull missing images
+ PullPolicyIfNotPresent = "if_not_present"
+ // PullPolicyMissing pull missing images
+ PullPolicyMissing = "missing"
+ // PullPolicyBuild force building images
+ PullPolicyBuild = "build"
+ // PullPolicyRefresh checks if image needs to be updated
+ PullPolicyRefresh = "refresh"
+)
+
+const (
+ // RestartPolicyAlways always restart the container if it stops
+ RestartPolicyAlways = "always"
+ // RestartPolicyOnFailure restart the container if it exits due to an error
+ RestartPolicyOnFailure = "on-failure"
+ // RestartPolicyNo do not automatically restart the container
+ RestartPolicyNo = "no"
+ // RestartPolicyUnlessStopped always restart the container unless the container is stopped (manually or otherwise)
+ RestartPolicyUnlessStopped = "unless-stopped"
+)
+
+const (
+ // ServicePrefix is the prefix for references pointing to a service
+ ServicePrefix = "service:"
+ // ContainerPrefix is the prefix for references pointing to a container
+ ContainerPrefix = "container:"
+
+ // NetworkModeServicePrefix is the prefix for network_mode pointing to a service
+ // Deprecated prefer ServicePrefix
+ NetworkModeServicePrefix = ServicePrefix
+ // NetworkModeContainerPrefix is the prefix for network_mode pointing to a container
+ // Deprecated prefer ContainerPrefix
+ NetworkModeContainerPrefix = ContainerPrefix
+)
+
+const (
+ SecretConfigXValue = "x-#value"
+)
+
+// GetDependencies retrieves all services this service depends on
+func (s ServiceConfig) GetDependencies() []string {
+ var dependencies []string
+ for service := range s.DependsOn {
+ dependencies = append(dependencies, service)
+ }
+ return dependencies
+}
+
+// GetDependents retrieves all services which depend on this service
+func (s ServiceConfig) GetDependents(p *Project) []string {
+ var dependent []string
+ for _, service := range p.Services {
+ for name := range service.DependsOn {
+ if name == s.Name {
+ dependent = append(dependent, service.Name)
+ }
+ }
+ }
+ return dependent
+}
+
+func (s ServiceConfig) GetPullPolicy() (string, time.Duration, error) {
+ switch s.PullPolicy {
+ case "":
+ return PullPolicyMissing, 0, nil
+ case PullPolicyAlways, PullPolicyNever, PullPolicyIfNotPresent, PullPolicyMissing, PullPolicyBuild, PullPolicyRefresh:
+ return s.PullPolicy, 0, nil
+ case "daily":
+ return PullPolicyRefresh, 24 * time.Hour, nil
+ case "weekly":
+ return PullPolicyRefresh, 7 * 24 * time.Hour, nil
+ default:
+ if strings.HasPrefix(s.PullPolicy, "every_") {
+ delay := s.PullPolicy[6:]
+ duration, err := str2duration.ParseDuration(delay)
+ if err != nil {
+ return "", 0, err
+ }
+ return PullPolicyRefresh, duration, nil
+ }
+ return "", 0, fmt.Errorf("invalid pull_policy %q", s.PullPolicy)
+ }
+}
+
+// BlkioConfig define blkio config
+type BlkioConfig struct {
+ Weight uint16 `yaml:"weight,omitempty" json:"weight,omitempty"`
+ WeightDevice []WeightDevice `yaml:"weight_device,omitempty" json:"weight_device,omitempty"`
+ DeviceReadBps []ThrottleDevice `yaml:"device_read_bps,omitempty" json:"device_read_bps,omitempty"`
+ DeviceReadIOps []ThrottleDevice `yaml:"device_read_iops,omitempty" json:"device_read_iops,omitempty"`
+ DeviceWriteBps []ThrottleDevice `yaml:"device_write_bps,omitempty" json:"device_write_bps,omitempty"`
+ DeviceWriteIOps []ThrottleDevice `yaml:"device_write_iops,omitempty" json:"device_write_iops,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+type DeviceMapping struct {
+ Source string `yaml:"source,omitempty" json:"source,omitempty"`
+ Target string `yaml:"target,omitempty" json:"target,omitempty"`
+ Permissions string `yaml:"permissions,omitempty" json:"permissions,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// WeightDevice is a structure that holds device:weight pair
+type WeightDevice struct {
+ Path string
+ Weight uint16
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// ThrottleDevice is a structure that holds device:rate_per_second pair
+type ThrottleDevice struct {
+ Path string
+ Rate UnitBytes
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// MappingWithColon is a mapping type that can be converted from a list of
+// 'key: value' strings
+type MappingWithColon map[string]string
+
+// LoggingConfig the logging configuration for a service
+type LoggingConfig struct {
+ Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
+ Options Options `yaml:"options,omitempty" json:"options,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// DeployConfig the deployment configuration for a service
+type DeployConfig struct {
+ Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
+ Replicas *int `yaml:"replicas,omitempty" json:"replicas,omitempty"`
+ Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
+ UpdateConfig *UpdateConfig `yaml:"update_config,omitempty" json:"update_config,omitempty"`
+ RollbackConfig *UpdateConfig `yaml:"rollback_config,omitempty" json:"rollback_config,omitempty"`
+ Resources Resources `yaml:"resources,omitempty" json:"resources,omitempty"`
+ RestartPolicy *RestartPolicy `yaml:"restart_policy,omitempty" json:"restart_policy,omitempty"`
+ Placement Placement `yaml:"placement,omitempty" json:"placement,omitempty"`
+ EndpointMode string `yaml:"endpoint_mode,omitempty" json:"endpoint_mode,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// UpdateConfig the service update configuration
+type UpdateConfig struct {
+ Parallelism *uint64 `yaml:"parallelism,omitempty" json:"parallelism,omitempty"`
+ Delay Duration `yaml:"delay,omitempty" json:"delay,omitempty"`
+ FailureAction string `yaml:"failure_action,omitempty" json:"failure_action,omitempty"`
+ Monitor Duration `yaml:"monitor,omitempty" json:"monitor,omitempty"`
+ MaxFailureRatio float32 `yaml:"max_failure_ratio,omitempty" json:"max_failure_ratio,omitempty"`
+ Order string `yaml:"order,omitempty" json:"order,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// Resources the resource limits and reservations
+type Resources struct {
+ Limits *Resource `yaml:"limits,omitempty" json:"limits,omitempty"`
+ Reservations *Resource `yaml:"reservations,omitempty" json:"reservations,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// Resource is a resource to be limited or reserved
+type Resource struct {
+ // TODO: types to convert from units and ratios
+ NanoCPUs NanoCPUs `yaml:"cpus,omitempty" json:"cpus,omitempty"`
+ MemoryBytes UnitBytes `yaml:"memory,omitempty" json:"memory,omitempty"`
+ Pids int64 `yaml:"pids,omitempty" json:"pids,omitempty"`
+ Devices []DeviceRequest `yaml:"devices,omitempty" json:"devices,omitempty"`
+ GenericResources []GenericResource `yaml:"generic_resources,omitempty" json:"generic_resources,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// GenericResource represents a "user defined" resource which can
+// only be an integer (e.g: SSD=3) for a service
+type GenericResource struct {
+ DiscreteResourceSpec *DiscreteGenericResource `yaml:"discrete_resource_spec,omitempty" json:"discrete_resource_spec,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// DiscreteGenericResource represents a "user defined" resource which is defined
+// as an integer
+// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
+// Value is used to count the resource (SSD=5, HDD=3, ...)
+type DiscreteGenericResource struct {
+ Kind string `json:"kind"`
+ Value int64 `json:"value"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// RestartPolicy the service restart policy
+type RestartPolicy struct {
+ Condition string `yaml:"condition,omitempty" json:"condition,omitempty"`
+ Delay *Duration `yaml:"delay,omitempty" json:"delay,omitempty"`
+ MaxAttempts *uint64 `yaml:"max_attempts,omitempty" json:"max_attempts,omitempty"`
+ Window *Duration `yaml:"window,omitempty" json:"window,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// Placement constraints for the service
+type Placement struct {
+ Constraints []string `yaml:"constraints,omitempty" json:"constraints,omitempty"`
+ Preferences []PlacementPreferences `yaml:"preferences,omitempty" json:"preferences,omitempty"`
+ MaxReplicas uint64 `yaml:"max_replicas_per_node,omitempty" json:"max_replicas_per_node,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// PlacementPreferences is the preferences for a service placement
+type PlacementPreferences struct {
+ Spread string `yaml:"spread,omitempty" json:"spread,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// ServiceNetworkConfig is the network configuration for a service
+type ServiceNetworkConfig struct {
+ Aliases []string `yaml:"aliases,omitempty" json:"aliases,omitempty"`
+ DriverOpts Options `yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
+ GatewayPriority int `yaml:"gw_priority,omitempty" json:"gw_priority,omitempty"`
+ InterfaceName string `yaml:"interface_name,omitempty" json:"interface_name,omitempty"`
+ Ipv4Address string `yaml:"ipv4_address,omitempty" json:"ipv4_address,omitempty"`
+ Ipv6Address string `yaml:"ipv6_address,omitempty" json:"ipv6_address,omitempty"`
+ LinkLocalIPs []string `yaml:"link_local_ips,omitempty" json:"link_local_ips,omitempty"`
+ MacAddress string `yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
+ Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// ServicePortConfig is the port configuration for a service
+type ServicePortConfig struct {
+ Name string `yaml:"name,omitempty" json:"name,omitempty"`
+ Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
+ HostIP string `yaml:"host_ip,omitempty" json:"host_ip,omitempty"`
+ Target uint32 `yaml:"target,omitempty" json:"target,omitempty"`
+ Published string `yaml:"published,omitempty" json:"published,omitempty"`
+ Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
+ AppProtocol string `yaml:"app_protocol,omitempty" json:"app_protocol,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// ParsePortConfig parse short syntax for service port configuration
+func ParsePortConfig(value string) ([]ServicePortConfig, error) {
+ var portConfigs []ServicePortConfig
+ ports, portBindings, err := nat.ParsePortSpecs([]string{value})
+ if err != nil {
+ return nil, err
+ }
+ // We need to sort the key of the ports to make sure it is consistent
+ keys := []string{}
+ for port := range ports {
+ keys = append(keys, string(port))
+ }
+ sort.Strings(keys)
+
+ for _, key := range keys {
+ port := nat.Port(key)
+ converted := convertPortToPortConfig(port, portBindings)
+ portConfigs = append(portConfigs, converted...)
+ }
+ return portConfigs, nil
+}
+
+func convertPortToPortConfig(port nat.Port, portBindings map[nat.Port][]nat.PortBinding) []ServicePortConfig {
+ var portConfigs []ServicePortConfig
+ for _, binding := range portBindings[port] {
+ portConfigs = append(portConfigs, ServicePortConfig{
+ HostIP: binding.HostIP,
+ Protocol: strings.ToLower(port.Proto()),
+ Target: uint32(port.Int()),
+ Published: binding.HostPort,
+ Mode: "ingress",
+ })
+ }
+ return portConfigs
+}
+
+// ServiceVolumeConfig are references to a volume used by a service
+type ServiceVolumeConfig struct {
+ Type string `yaml:"type,omitempty" json:"type,omitempty"`
+ Source string `yaml:"source,omitempty" json:"source,omitempty"`
+ Target string `yaml:"target,omitempty" json:"target,omitempty"`
+ ReadOnly bool `yaml:"read_only,omitempty" json:"read_only,omitempty"`
+ Consistency string `yaml:"consistency,omitempty" json:"consistency,omitempty"`
+ Bind *ServiceVolumeBind `yaml:"bind,omitempty" json:"bind,omitempty"`
+ Volume *ServiceVolumeVolume `yaml:"volume,omitempty" json:"volume,omitempty"`
+ Tmpfs *ServiceVolumeTmpfs `yaml:"tmpfs,omitempty" json:"tmpfs,omitempty"`
+ Image *ServiceVolumeImage `yaml:"image,omitempty" json:"image,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// String render ServiceVolumeConfig as a volume string, one can parse back using loader.ParseVolume
+func (s ServiceVolumeConfig) String() string {
+ access := "rw"
+ if s.ReadOnly {
+ access = "ro"
+ }
+ options := []string{access}
+ if s.Bind != nil && s.Bind.SELinux != "" {
+ options = append(options, s.Bind.SELinux)
+ }
+ if s.Bind != nil && s.Bind.Propagation != "" {
+ options = append(options, s.Bind.Propagation)
+ }
+ if s.Volume != nil && s.Volume.NoCopy {
+ options = append(options, "nocopy")
+ }
+ return fmt.Sprintf("%s:%s:%s", s.Source, s.Target, strings.Join(options, ","))
+}
+
+const (
+ // VolumeTypeBind is the type for mounting host dir
+ VolumeTypeBind = "bind"
+ // VolumeTypeVolume is the type for remote storage volumes
+ VolumeTypeVolume = "volume"
+ // VolumeTypeTmpfs is the type for mounting tmpfs
+ VolumeTypeTmpfs = "tmpfs"
+ // VolumeTypeNamedPipe is the type for mounting Windows named pipes
+ VolumeTypeNamedPipe = "npipe"
+ // VolumeTypeCluster is the type for mounting container storage interface (CSI) volumes
+ VolumeTypeCluster = "cluster"
+ // VolumeTypeImage is the tpe for mounting an image
+ VolumeTypeImage = "image"
+
+ // SElinuxShared share the volume content
+ SElinuxShared = "z"
+ // SElinuxUnshared label content as private unshared
+ SElinuxUnshared = "Z"
+)
+
+// ServiceVolumeBind are options for a service volume of type bind
+type ServiceVolumeBind struct {
+ SELinux string `yaml:"selinux,omitempty" json:"selinux,omitempty"`
+ Propagation string `yaml:"propagation,omitempty" json:"propagation,omitempty"`
+ CreateHostPath OptOut `yaml:"create_host_path,omitempty" json:"create_host_path,omitzero"`
+ Recursive string `yaml:"recursive,omitempty" json:"recursive,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// OptOut is a boolean which default value is 'true'
+type OptOut bool
+
+func (o OptOut) IsZero() bool {
+ // Attribute can be omitted if value is true
+ return bool(o)
+}
+
+// SELinux represents the SELinux re-labeling options.
+const (
+ // SELinuxShared option indicates that the bind mount content is shared among multiple containers
+ SELinuxShared string = "z"
+ // SELinuxPrivate option indicates that the bind mount content is private and unshared
+ SELinuxPrivate string = "Z"
+)
+
+// Propagation represents the propagation of a mount.
+const (
+ // PropagationRPrivate RPRIVATE
+ PropagationRPrivate string = "rprivate"
+ // PropagationPrivate PRIVATE
+ PropagationPrivate string = "private"
+ // PropagationRShared RSHARED
+ PropagationRShared string = "rshared"
+ // PropagationShared SHARED
+ PropagationShared string = "shared"
+ // PropagationRSlave RSLAVE
+ PropagationRSlave string = "rslave"
+ // PropagationSlave SLAVE
+ PropagationSlave string = "slave"
+)
+
+// ServiceVolumeVolume are options for a service volume of type volume
+type ServiceVolumeVolume struct {
+ Labels Mapping `yaml:"labels,omitempty" json:"labels,omitempty"`
+ NoCopy bool `yaml:"nocopy,omitempty" json:"nocopy,omitempty"`
+ Subpath string `yaml:"subpath,omitempty" json:"subpath,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// ServiceVolumeTmpfs are options for a service volume of type tmpfs
+type ServiceVolumeTmpfs struct {
+ Size UnitBytes `yaml:"size,omitempty" json:"size,omitempty"`
+
+ Mode uint32 `yaml:"mode,omitempty" json:"mode,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+type ServiceVolumeImage struct {
+ SubPath string `yaml:"subpath,omitempty" json:"subpath,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+type FileMode int64
+
+// FileReferenceConfig for a reference to a swarm file object
+type FileReferenceConfig struct {
+ Source string `yaml:"source,omitempty" json:"source,omitempty"`
+ Target string `yaml:"target,omitempty" json:"target,omitempty"`
+ UID string `yaml:"uid,omitempty" json:"uid,omitempty"`
+ GID string `yaml:"gid,omitempty" json:"gid,omitempty"`
+ Mode *FileMode `yaml:"mode,omitempty" json:"mode,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+func (f *FileMode) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case *FileMode:
+ return nil
+ case string:
+ i, err := strconv.ParseInt(v, 8, 64)
+ if err != nil {
+ return err
+ }
+ *f = FileMode(i)
+ case int:
+ *f = FileMode(v)
+ default:
+ return fmt.Errorf("unexpected value type %T for mode", value)
+ }
+ return nil
+}
+
+// MarshalYAML makes FileMode implement yaml.Marshaller
+func (f *FileMode) MarshalYAML() (interface{}, error) {
+ return f.String(), nil
+}
+
+// MarshalJSON makes FileMode implement json.Marshaller
+func (f *FileMode) MarshalJSON() ([]byte, error) {
+ return []byte("\"" + f.String() + "\""), nil
+}
+
+func (f *FileMode) String() string {
+ return fmt.Sprintf("0%o", int64(*f))
+}
+
+// ServiceConfigObjConfig is the config obj configuration for a service
+type ServiceConfigObjConfig FileReferenceConfig
+
+// ServiceSecretConfig is the secret configuration for a service
+type ServiceSecretConfig FileReferenceConfig
+
+// UlimitsConfig the ulimit configuration
+type UlimitsConfig struct {
+ Single int `yaml:"single,omitempty" json:"single,omitempty"`
+ Soft int `yaml:"soft,omitempty" json:"soft,omitempty"`
+ Hard int `yaml:"hard,omitempty" json:"hard,omitempty"`
+
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+func (u *UlimitsConfig) DecodeMapstructure(value interface{}) error {
+ switch v := value.(type) {
+ case *UlimitsConfig:
+ // this call to DecodeMapstructure is triggered after initial value conversion as we use a map[string]*UlimitsConfig
+ return nil
+ case int:
+ u.Single = v
+ u.Soft = 0
+ u.Hard = 0
+ case map[string]any:
+ u.Single = 0
+ soft, ok := v["soft"]
+ if ok {
+ u.Soft = soft.(int)
+ }
+ hard, ok := v["hard"]
+ if ok {
+ u.Hard = hard.(int)
+ }
+ default:
+ return fmt.Errorf("unexpected value type %T for ulimit", value)
+ }
+ return nil
+}
+
+// MarshalYAML makes UlimitsConfig implement yaml.Marshaller
+func (u *UlimitsConfig) MarshalYAML() (interface{}, error) {
+ if u.Single != 0 {
+ return u.Single, nil
+ }
+ return struct {
+ Soft int
+ Hard int
+ }{
+ Soft: u.Soft,
+ Hard: u.Hard,
+ }, nil
+}
+
+// MarshalJSON makes UlimitsConfig implement json.Marshaller
+func (u *UlimitsConfig) MarshalJSON() ([]byte, error) {
+ if u.Single != 0 {
+ return json.Marshal(u.Single)
+ }
+ // Pass as a value to avoid re-entering this method and use the default implementation
+ return json.Marshal(*u)
+}
+
+// NetworkConfig for a network
+type NetworkConfig struct {
+ Name string `yaml:"name,omitempty" json:"name,omitempty"`
+ Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
+ DriverOpts Options `yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
+ Ipam IPAMConfig `yaml:"ipam,omitempty" json:"ipam,omitempty"`
+ External External `yaml:"external,omitempty" json:"external,omitempty"`
+ Internal bool `yaml:"internal,omitempty" json:"internal,omitempty"`
+ Attachable bool `yaml:"attachable,omitempty" json:"attachable,omitempty"`
+ Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
+ CustomLabels Labels `yaml:"-" json:"-"`
+ EnableIPv4 *bool `yaml:"enable_ipv4,omitempty" json:"enable_ipv4,omitempty"`
+ EnableIPv6 *bool `yaml:"enable_ipv6,omitempty" json:"enable_ipv6,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// IPAMConfig for a network
+type IPAMConfig struct {
+ Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
+ Config []*IPAMPool `yaml:"config,omitempty" json:"config,omitempty"`
+ Options Options `yaml:"options,omitempty" json:"options,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// IPAMPool for a network
+type IPAMPool struct {
+ Subnet string `yaml:"subnet,omitempty" json:"subnet,omitempty"`
+ Gateway string `yaml:"gateway,omitempty" json:"gateway,omitempty"`
+ IPRange string `yaml:"ip_range,omitempty" json:"ip_range,omitempty"`
+ AuxiliaryAddresses Mapping `yaml:"aux_addresses,omitempty" json:"aux_addresses,omitempty"`
+ Extensions Extensions `yaml:",inline" json:"-"`
+}
+
+// VolumeConfig for a volume
+type VolumeConfig struct {
+ Name string `yaml:"name,omitempty" json:"name,omitempty"`
+ Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
+ DriverOpts Options `yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
+ External External `yaml:"external,omitempty" json:"external,omitempty"`
+ Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
+ CustomLabels Labels `yaml:"-" json:"-"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// External identifies a Volume or Network as a reference to a resource that is
+// not managed, and should already exist.
+type External bool
+
+// CredentialSpecConfig for credential spec on Windows
+type CredentialSpecConfig struct {
+ Config string `yaml:"config,omitempty" json:"config,omitempty"` // Config was added in API v1.40
+ File string `yaml:"file,omitempty" json:"file,omitempty"`
+ Registry string `yaml:"registry,omitempty" json:"registry,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+// FileObjectConfig is a config type for a file used by a service
+type FileObjectConfig struct {
+ Name string `yaml:"name,omitempty" json:"name,omitempty"`
+ File string `yaml:"file,omitempty" json:"file,omitempty"`
+ Environment string `yaml:"environment,omitempty" json:"environment,omitempty"`
+ Content string `yaml:"content,omitempty" json:"content,omitempty"`
+ // configure marshalling to include Content - excluded by default to prevent sensitive data leaks
+ marshallContent bool
+ External External `yaml:"external,omitempty" json:"external,omitempty"`
+ Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
+ Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
+ DriverOpts map[string]string `yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
+ TemplateDriver string `yaml:"template_driver,omitempty" json:"template_driver,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+}
+
+const (
+ // ServiceConditionCompletedSuccessfully is the type for waiting until a service has completed successfully (exit code 0).
+ ServiceConditionCompletedSuccessfully = "service_completed_successfully"
+
+ // ServiceConditionHealthy is the type for waiting until a service is healthy.
+ ServiceConditionHealthy = "service_healthy"
+
+ // ServiceConditionStarted is the type for waiting until a service has started (default).
+ ServiceConditionStarted = "service_started"
+)
+
+type DependsOnConfig map[string]ServiceDependency
+
+type ServiceDependency struct {
+ Condition string `yaml:"condition,omitempty" json:"condition,omitempty"`
+ Restart bool `yaml:"restart,omitempty" json:"restart,omitempty"`
+ Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
+ Required bool `yaml:"required" json:"required"`
+}
+
+type ExtendsConfig struct {
+ File string `yaml:"file,omitempty" json:"file,omitempty"`
+ Service string `yaml:"service,omitempty" json:"service,omitempty"`
+}
+
+// SecretConfig for a secret
+type SecretConfig FileObjectConfig
+
+// MarshalYAML makes SecretConfig implement yaml.Marshaller
+func (s SecretConfig) MarshalYAML() (interface{}, error) {
+ // secret content is set while loading model. Never marshall it
+ if !s.marshallContent {
+ s.Content = ""
+ }
+ return FileObjectConfig(s), nil
+}
+
+// MarshalJSON makes SecretConfig implement json.Marshaller
+func (s SecretConfig) MarshalJSON() ([]byte, error) {
+ // secret content is set while loading model. Never marshall it
+ if !s.marshallContent {
+ s.Content = ""
+ }
+ return json.Marshal(FileObjectConfig(s))
+}
+
+// ConfigObjConfig is the config for the swarm "Config" object
+type ConfigObjConfig FileObjectConfig
+
+// MarshalYAML makes ConfigObjConfig implement yaml.Marshaller
+func (s ConfigObjConfig) MarshalYAML() (interface{}, error) {
+ // config content may have been set from environment while loading model. Marshall actual source
+ if s.Environment != "" {
+ s.Content = ""
+ }
+ return FileObjectConfig(s), nil
+}
+
+// MarshalJSON makes ConfigObjConfig implement json.Marshaller
+func (s ConfigObjConfig) MarshalJSON() ([]byte, error) {
+ // config content may have been set from environment while loading model. Marshall actual source
+ if s.Environment != "" {
+ s.Content = ""
+ }
+ return json.Marshal(FileObjectConfig(s))
+}
+
+type IncludeConfig struct {
+ Path StringList `yaml:"path,omitempty" json:"path,omitempty"`
+ ProjectDirectory string `yaml:"project_directory,omitempty" json:"project_directory,omitempty"`
+ EnvFile StringList `yaml:"env_file,omitempty" json:"env_file,omitempty"`
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/utils/collectionutils.go b/vendor/github.com/compose-spec/compose-go/v2/utils/collectionutils.go
new file mode 100644
index 0000000000..ed815f0f3a
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/utils/collectionutils.go
@@ -0,0 +1,66 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package utils
+
+import (
+ "cmp"
+ "maps"
+ "slices"
+)
+
+func MapKeys[T cmp.Ordered, U any](theMap map[T]U) []T {
+ return slices.Sorted(maps.Keys(theMap))
+}
+
+func MapsAppend[T comparable, U any](target map[T]U, source map[T]U) map[T]U {
+ if target == nil {
+ return source
+ }
+ if source == nil {
+ return target
+ }
+ for key, value := range source {
+ if _, ok := target[key]; !ok {
+ target[key] = value
+ }
+ }
+ return target
+}
+
+func ArrayContains[T comparable](source []T, toCheck []T) bool {
+ for _, value := range toCheck {
+ if !slices.Contains(source, value) {
+ return false
+ }
+ }
+ return true
+}
+
+func RemoveDuplicates[T comparable](slice []T) []T {
+ // Create a map to store unique elements
+ seen := make(map[T]bool)
+ result := []T{}
+
+ // Loop through the slice, adding elements to the map if they haven't been seen before
+ for _, val := range slice {
+ if _, ok := seen[val]; !ok {
+ seen[val] = true
+ result = append(result, val)
+ }
+ }
+ return result
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/utils/pathutils.go b/vendor/github.com/compose-spec/compose-go/v2/utils/pathutils.go
new file mode 100644
index 0000000000..211e299935
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/utils/pathutils.go
@@ -0,0 +1,91 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package utils
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// ResolveSymbolicLink converts the section of an absolute path if it is a
+// symbolic link
+//
+// Parameters:
+// - path: an absolute path
+//
+// Returns:
+// - converted path if it has a symbolic link or the same path if there is
+// no symbolic link
+func ResolveSymbolicLink(path string) (string, error) {
+ sym, part, err := getSymbolinkLink(path)
+ if err != nil {
+ return "", err
+ }
+ if sym == "" && part == "" {
+ // no symbolic link detected
+ return path, nil
+ }
+ return strings.Replace(path, part, sym, 1), nil
+}
+
+// getSymbolinkLink parses all parts of the path and returns the
+// the symbolic link part as well as the correspondent original part
+// Parameters:
+// - path: an absolute path
+//
+// Returns:
+// - string section of the path that is a symbolic link
+// - string correspondent path section of the symbolic link
+// - An error
+func getSymbolinkLink(path string) (string, string, error) {
+ parts := strings.Split(path, string(os.PathSeparator))
+
+ // Reconstruct the path step by step, checking each component
+ var currentPath string
+ if filepath.IsAbs(path) {
+ currentPath = string(os.PathSeparator)
+ }
+
+ for _, part := range parts {
+ if part == "" {
+ continue
+ }
+ currentPath = filepath.Join(currentPath, part)
+
+ if isSymLink := isSymbolicLink(currentPath); isSymLink {
+ // return symbolic link, and correspondent part
+ target, err := filepath.EvalSymlinks(currentPath)
+ if err != nil {
+ return "", "", err
+ }
+ return target, currentPath, nil
+ }
+ }
+ return "", "", nil // no symbolic link
+}
+
+// isSymbolicLink validates if the path is a symbolic link
+func isSymbolicLink(path string) bool {
+ info, err := os.Lstat(path)
+ if err != nil {
+ return false
+ }
+
+ // Check if the file mode indicates a symbolic link
+ return info.Mode()&os.ModeSymlink != 0
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/utils/set.go b/vendor/github.com/compose-spec/compose-go/v2/utils/set.go
new file mode 100644
index 0000000000..bbbeaa966d
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/utils/set.go
@@ -0,0 +1,95 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package utils
+
+type Set[T comparable] map[T]struct{}
+
+func NewSet[T comparable](v ...T) Set[T] {
+ if len(v) == 0 {
+ return make(Set[T])
+ }
+
+ out := make(Set[T], len(v))
+ for i := range v {
+ out.Add(v[i])
+ }
+ return out
+}
+
+func (s Set[T]) Has(v T) bool {
+ _, ok := s[v]
+ return ok
+}
+
+func (s Set[T]) Add(v T) {
+ s[v] = struct{}{}
+}
+
+func (s Set[T]) AddAll(v ...T) {
+ for _, e := range v {
+ s[e] = struct{}{}
+ }
+}
+
+func (s Set[T]) Remove(v T) bool {
+ _, ok := s[v]
+ if ok {
+ delete(s, v)
+ }
+ return ok
+}
+
+func (s Set[T]) Clear() {
+ for v := range s {
+ delete(s, v)
+ }
+}
+
+func (s Set[T]) Elements() []T {
+ elements := make([]T, 0, len(s))
+ for v := range s {
+ elements = append(elements, v)
+ }
+ return elements
+}
+
+func (s Set[T]) RemoveAll(elements ...T) {
+ for _, e := range elements {
+ s.Remove(e)
+ }
+}
+
+func (s Set[T]) Diff(other Set[T]) Set[T] {
+ out := make(Set[T])
+ for k := range s {
+ if _, ok := other[k]; !ok {
+ out[k] = struct{}{}
+ }
+ }
+ return out
+}
+
+func (s Set[T]) Union(other Set[T]) Set[T] {
+ out := make(Set[T])
+ for k := range s {
+ out[k] = struct{}{}
+ }
+ for k := range other {
+ out[k] = struct{}{}
+ }
+ return out
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/utils/stringutils.go b/vendor/github.com/compose-spec/compose-go/v2/utils/stringutils.go
new file mode 100644
index 0000000000..fc6b2035f5
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/utils/stringutils.go
@@ -0,0 +1,50 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package utils
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// StringToBool converts a string to a boolean ignoring errors
+func StringToBool(s string) bool {
+ b, _ := strconv.ParseBool(strings.ToLower(strings.TrimSpace(s)))
+ return b
+}
+
+// GetAsEqualsMap split key=value formatted strings into a key : value map
+func GetAsEqualsMap(em []string) map[string]string {
+ m := make(map[string]string)
+ for _, v := range em {
+ key, val, found := strings.Cut(v, "=")
+ if found {
+ m[key] = val
+ }
+ }
+ return m
+}
+
+// GetAsEqualsMap format a key : value map into key=value strings
+func GetAsStringList(em map[string]string) []string {
+ m := make([]string, 0, len(em))
+ for k, v := range em {
+ m = append(m, fmt.Sprintf("%s=%s", k, v))
+ }
+ return m
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/validation/external.go b/vendor/github.com/compose-spec/compose-go/v2/validation/external.go
new file mode 100644
index 0000000000..b74d551a02
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/validation/external.go
@@ -0,0 +1,49 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package validation
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/consts"
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func checkExternal(v map[string]any, p tree.Path) error {
+ b, ok := v["external"]
+ if !ok {
+ return nil
+ }
+ if !b.(bool) {
+ return nil
+ }
+
+ for k := range v {
+ switch k {
+ case "name", "external", consts.Extensions:
+ continue
+ default:
+ if strings.HasPrefix(k, "x-") {
+ // custom extension, ignored
+ continue
+ }
+ return fmt.Errorf("%s: conflicting parameters \"external\" and %q specified", p, k)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/validation/validation.go b/vendor/github.com/compose-spec/compose-go/v2/validation/validation.go
new file mode 100644
index 0000000000..28cad44c21
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/validation/validation.go
@@ -0,0 +1,119 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package validation
+
+import (
+ "fmt"
+ "net"
+ "strings"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+type checkerFunc func(value any, p tree.Path) error
+
+var checks = map[tree.Path]checkerFunc{
+ "volumes.*": checkVolume,
+ "configs.*": checkFileObject("file", "environment", "content"),
+ "secrets.*": checkFileObject("file", "environment"),
+ "services.*.ports.*": checkIPAddress,
+ "services.*.develop.watch.*.path": checkPath,
+ "services.*.deploy.resources.reservations.devices.*": checkDeviceRequest,
+ "services.*.gpus.*": checkDeviceRequest,
+}
+
+func Validate(dict map[string]any) error {
+ return check(dict, tree.NewPath())
+}
+
+func check(value any, p tree.Path) error {
+ for pattern, fn := range checks {
+ if p.Matches(pattern) {
+ return fn(value, p)
+ }
+ }
+ switch v := value.(type) {
+ case map[string]any:
+ for k, v := range v {
+ err := check(v, p.Next(k))
+ if err != nil {
+ return err
+ }
+ }
+ case []any:
+ for _, e := range v {
+ err := check(e, p.Next("[]"))
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func checkFileObject(keys ...string) checkerFunc {
+ return func(value any, p tree.Path) error {
+ v := value.(map[string]any)
+ count := 0
+ for _, s := range keys {
+ if _, ok := v[s]; ok {
+ count++
+ }
+ }
+ if count > 1 {
+ return fmt.Errorf("%s: %s attributes are mutually exclusive", p, strings.Join(keys, "|"))
+ }
+ if count == 0 {
+ if _, ok := v["driver"]; ok {
+ // User specified a custom driver, which might have it's own way to set content
+ return nil
+ }
+ if _, ok := v["external"]; !ok {
+ return fmt.Errorf("%s: one of %s must be set", p, strings.Join(keys, "|"))
+ }
+ }
+ return nil
+ }
+}
+
+func checkPath(value any, p tree.Path) error {
+ v := value.(string)
+ if v == "" {
+ return fmt.Errorf("%s: value can't be blank", p)
+ }
+ return nil
+}
+
+func checkDeviceRequest(value any, p tree.Path) error {
+ v := value.(map[string]any)
+ _, hasCount := v["count"]
+ _, hasIDs := v["device_ids"]
+ if hasCount && hasIDs {
+ return fmt.Errorf(`%s: "count" and "device_ids" attributes are exclusive`, p)
+ }
+ return nil
+}
+
+func checkIPAddress(value any, p tree.Path) error {
+ if v, ok := value.(map[string]any); ok {
+ ip, ok := v["host_ip"]
+ if ok && net.ParseIP(ip.(string)) == nil {
+ return fmt.Errorf("%s: invalid ip address: %s", p, ip)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/compose-spec/compose-go/v2/validation/volume.go b/vendor/github.com/compose-spec/compose-go/v2/validation/volume.go
new file mode 100644
index 0000000000..5b40068116
--- /dev/null
+++ b/vendor/github.com/compose-spec/compose-go/v2/validation/volume.go
@@ -0,0 +1,39 @@
+/*
+ Copyright 2020 The Compose Specification Authors.
+
+ 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.
+*/
+
+package validation
+
+import (
+ "fmt"
+
+ "github.com/compose-spec/compose-go/v2/tree"
+)
+
+func checkVolume(value any, p tree.Path) error {
+ if value == nil {
+ return nil
+ }
+ v, ok := value.(map[string]any)
+ if !ok {
+ return fmt.Errorf("expected volume, got %s", value)
+ }
+
+ err := checkExternal(v, p)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/console/.golangci.yml b/vendor/github.com/containerd/console/.golangci.yml
index fcba5e885f..abe3d84bb1 100644
--- a/vendor/github.com/containerd/console/.golangci.yml
+++ b/vendor/github.com/containerd/console/.golangci.yml
@@ -1,16 +1,16 @@
linters:
enable:
- - structcheck
- - varcheck
- - staticcheck
- - unconvert
- gofmt
- goimports
- - golint
- ineffassign
- - vet
- - unused
- misspell
+ - revive
+ - staticcheck
+ - structcheck
+ - unconvert
+ - unused
+ - varcheck
+ - vet
disable:
- errcheck
diff --git a/vendor/github.com/containerd/console/README.md b/vendor/github.com/containerd/console/README.md
index 580b461a73..a849a728f1 100644
--- a/vendor/github.com/containerd/console/README.md
+++ b/vendor/github.com/containerd/console/README.md
@@ -22,8 +22,8 @@ current.Resize(ws)
console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
As a containerd sub-project, you will find the:
- * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
- * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
- * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/console/console.go b/vendor/github.com/containerd/console/console.go
index f989d28a41..dd587d88e0 100644
--- a/vendor/github.com/containerd/console/console.go
+++ b/vendor/github.com/containerd/console/console.go
@@ -22,7 +22,10 @@ import (
"os"
)
-var ErrNotAConsole = errors.New("provided file is not a console")
+var (
+ ErrNotAConsole = errors.New("provided file is not a console")
+ ErrNotImplemented = errors.New("not implemented")
+)
type File interface {
io.ReadWriteCloser
@@ -45,7 +48,7 @@ type Console interface {
SetRaw() error
// DisableEcho disables echo on the console
DisableEcho() error
- // Reset restores the console to its orignal state
+ // Reset restores the console to its original state
Reset() error
// Size returns the window size of the console
Size() (WinSize, error)
@@ -78,7 +81,7 @@ func Current() (c Console) {
}
// ConsoleFromFile returns a console using the provided file
-// nolint:golint
+// nolint:revive
func ConsoleFromFile(f File) (Console, error) {
if err := checkConsole(f); err != nil {
return nil, err
diff --git a/vendor/github.com/containerd/console/console_linux.go b/vendor/github.com/containerd/console/console_linux.go
index c1c839ee3a..28b77b7a38 100644
--- a/vendor/github.com/containerd/console/console_linux.go
+++ b/vendor/github.com/containerd/console/console_linux.go
@@ -1,3 +1,4 @@
+//go:build linux
// +build linux
/*
diff --git a/vendor/github.com/containerd/console/console_other.go b/vendor/github.com/containerd/console/console_other.go
new file mode 100644
index 0000000000..968c5771c8
--- /dev/null
+++ b/vendor/github.com/containerd/console/console_other.go
@@ -0,0 +1,36 @@
+//go:build !darwin && !freebsd && !linux && !netbsd && !openbsd && !windows && !zos
+// +build !darwin,!freebsd,!linux,!netbsd,!openbsd,!windows,!zos
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package console
+
+// NewPty creates a new pty pair
+// The master is returned as the first console and a string
+// with the path to the pty slave is returned as the second
+func NewPty() (Console, string, error) {
+ return nil, "", ErrNotImplemented
+}
+
+// checkConsole checks if the provided file is a console
+func checkConsole(f File) error {
+ return ErrNotAConsole
+}
+
+func newMaster(f File) (Console, error) {
+ return nil, ErrNotImplemented
+}
diff --git a/vendor/github.com/containerd/console/console_unix.go b/vendor/github.com/containerd/console/console_unix.go
index a08117695e..aa4c696234 100644
--- a/vendor/github.com/containerd/console/console_unix.go
+++ b/vendor/github.com/containerd/console/console_unix.go
@@ -1,4 +1,5 @@
-// +build darwin freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || netbsd || openbsd || zos
+// +build darwin freebsd linux netbsd openbsd zos
/*
Copyright The containerd Authors.
@@ -30,6 +31,15 @@ func NewPty() (Console, string, error) {
if err != nil {
return nil, "", err
}
+ return NewPtyFromFile(f)
+}
+
+// NewPtyFromFile creates a new pty pair, just like [NewPty] except that the
+// provided [os.File] is used as the master rather than automatically creating
+// a new master from /dev/ptmx. The ownership of [os.File] is passed to the
+// returned [Console], so the caller must be careful to not call Close on the
+// underlying file.
+func NewPtyFromFile(f File) (Console, string, error) {
slave, err := ptsname(f)
if err != nil {
return nil, "", err
diff --git a/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/containerd/console/console_windows.go
index 787c11fe56..6896db1825 100644
--- a/vendor/github.com/containerd/console/console_windows.go
+++ b/vendor/github.com/containerd/console/console_windows.go
@@ -24,12 +24,13 @@ import (
"golang.org/x/sys/windows"
)
-var (
- vtInputSupported bool
- ErrNotImplemented = errors.New("not implemented")
-)
+var vtInputSupported bool
func (m *master) initStdios() {
+ // Note: We discard console mode warnings, because in/out can be redirected.
+ //
+ // TODO: Investigate opening CONOUT$/CONIN$ to handle this correctly
+
m.in = windows.Handle(os.Stdin.Fd())
if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil {
// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
@@ -39,8 +40,6 @@ func (m *master) initStdios() {
// Unconditionally set the console mode back even on failure because SetConsoleMode
// remembers invalid bits on input handles.
windows.SetConsoleMode(m.in, m.inMode)
- } else {
- fmt.Printf("failed to get console mode for stdin: %v\n", err)
}
m.out = windows.Handle(os.Stdout.Fd())
@@ -50,8 +49,6 @@ func (m *master) initStdios() {
} else {
windows.SetConsoleMode(m.out, m.outMode)
}
- } else {
- fmt.Printf("failed to get console mode for stdout: %v\n", err)
}
m.err = windows.Handle(os.Stderr.Fd())
@@ -61,8 +58,6 @@ func (m *master) initStdios() {
} else {
windows.SetConsoleMode(m.err, m.errMode)
}
- } else {
- fmt.Printf("failed to get console mode for stderr: %v\n", err)
}
}
@@ -94,6 +89,8 @@ func (m *master) SetRaw() error {
}
func (m *master) Reset() error {
+ var errs []error
+
for _, s := range []struct {
fd windows.Handle
mode uint32
@@ -103,10 +100,16 @@ func (m *master) Reset() error {
{m.err, m.errMode},
} {
if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
- return fmt.Errorf("unable to restore console mode: %w", err)
+ // we can't just abort on the first error, otherwise we might leave
+ // the console in an unexpected state.
+ errs = append(errs, fmt.Errorf("unable to restore console mode: %w", err))
}
}
+ if len(errs) > 0 {
+ return errs[0]
+ }
+
return nil
}
diff --git a/vendor/github.com/containerd/console/console_zos.go b/vendor/github.com/containerd/console/console_zos.go
deleted file mode 100644
index b348a839a0..0000000000
--- a/vendor/github.com/containerd/console/console_zos.go
+++ /dev/null
@@ -1,163 +0,0 @@
-// +build zos
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package console
-
-import (
- "fmt"
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-// NewPty creates a new pty pair
-// The master is returned as the first console and a string
-// with the path to the pty slave is returned as the second
-func NewPty() (Console, string, error) {
- var f File
- var err error
- var slave string
- for i := 0;; i++ {
- ptyp := fmt.Sprintf("/dev/ptyp%04d", i)
- f, err = os.OpenFile(ptyp, os.O_RDWR, 0600)
- if err == nil {
- slave = fmt.Sprintf("/dev/ttyp%04d", i)
- break
- }
- if os.IsNotExist(err) {
- return nil, "", err
- }
- // else probably Resource Busy
- }
- m, err := newMaster(f)
- if err != nil {
- return nil, "", err
- }
- return m, slave, nil
-}
-
-type master struct {
- f File
- original *unix.Termios
-}
-
-func (m *master) Read(b []byte) (int, error) {
- return m.f.Read(b)
-}
-
-func (m *master) Write(b []byte) (int, error) {
- return m.f.Write(b)
-}
-
-func (m *master) Close() error {
- return m.f.Close()
-}
-
-func (m *master) Resize(ws WinSize) error {
- return tcswinsz(m.f.Fd(), ws)
-}
-
-func (m *master) ResizeFrom(c Console) error {
- ws, err := c.Size()
- if err != nil {
- return err
- }
- return m.Resize(ws)
-}
-
-func (m *master) Reset() error {
- if m.original == nil {
- return nil
- }
- return tcset(m.f.Fd(), m.original)
-}
-
-func (m *master) getCurrent() (unix.Termios, error) {
- var termios unix.Termios
- if err := tcget(m.f.Fd(), &termios); err != nil {
- return unix.Termios{}, err
- }
- return termios, nil
-}
-
-func (m *master) SetRaw() error {
- rawState, err := m.getCurrent()
- if err != nil {
- return err
- }
- rawState = cfmakeraw(rawState)
- rawState.Oflag = rawState.Oflag | unix.OPOST
- return tcset(m.f.Fd(), &rawState)
-}
-
-func (m *master) DisableEcho() error {
- rawState, err := m.getCurrent()
- if err != nil {
- return err
- }
- rawState.Lflag = rawState.Lflag &^ unix.ECHO
- return tcset(m.f.Fd(), &rawState)
-}
-
-func (m *master) Size() (WinSize, error) {
- return tcgwinsz(m.f.Fd())
-}
-
-func (m *master) Fd() uintptr {
- return m.f.Fd()
-}
-
-func (m *master) Name() string {
- return m.f.Name()
-}
-
-// checkConsole checks if the provided file is a console
-func checkConsole(f File) error {
- var termios unix.Termios
- if tcget(f.Fd(), &termios) != nil {
- return ErrNotAConsole
- }
- return nil
-}
-
-func newMaster(f File) (Console, error) {
- m := &master{
- f: f,
- }
- t, err := m.getCurrent()
- if err != nil {
- return nil, err
- }
- m.original = &t
- return m, nil
-}
-
-// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
-// created by us acts normally. In particular, a not-very-well-known default of
-// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
-// problem for terminal emulators, because we relay data from the terminal we
-// also relay that funky line discipline.
-func ClearONLCR(fd uintptr) error {
- return setONLCR(fd, false)
-}
-
-// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
-// created by us acts as intended for a terminal emulator.
-func SetONLCR(fd uintptr) error {
- return setONLCR(fd, true)
-}
diff --git a/vendor/github.com/containerd/console/pty_freebsd_cgo.go b/vendor/github.com/containerd/console/pty_freebsd_cgo.go
index cbd3cd7ea4..22368623aa 100644
--- a/vendor/github.com/containerd/console/pty_freebsd_cgo.go
+++ b/vendor/github.com/containerd/console/pty_freebsd_cgo.go
@@ -1,3 +1,4 @@
+//go:build freebsd && cgo
// +build freebsd,cgo
/*
diff --git a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
index b5e43181d4..ceb90a47b8 100644
--- a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
+++ b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
@@ -1,3 +1,4 @@
+//go:build freebsd && !cgo
// +build freebsd,!cgo
/*
diff --git a/vendor/github.com/containerd/console/pty_unix.go b/vendor/github.com/containerd/console/pty_unix.go
index d5a6bd8ca2..f5a5b8058c 100644
--- a/vendor/github.com/containerd/console/pty_unix.go
+++ b/vendor/github.com/containerd/console/pty_unix.go
@@ -1,4 +1,5 @@
-// +build darwin linux netbsd openbsd solaris
+//go:build darwin || linux || netbsd || openbsd
+// +build darwin linux netbsd openbsd
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/console/pty_zos.go b/vendor/github.com/containerd/console/pty_zos.go
new file mode 100644
index 0000000000..58f59aba58
--- /dev/null
+++ b/vendor/github.com/containerd/console/pty_zos.go
@@ -0,0 +1,43 @@
+//go:build zos
+// +build zos
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package console
+
+import (
+ "fmt"
+ "os"
+)
+
+// openpt allocates a new pseudo-terminal by opening the first available /dev/ptypXX device
+func openpt() (*os.File, error) {
+ var f *os.File
+ var err error
+ for i := 0; ; i++ {
+ ptyp := fmt.Sprintf("/dev/ptyp%04d", i)
+ f, err = os.OpenFile(ptyp, os.O_RDWR, 0600)
+ if err == nil {
+ break
+ }
+ if os.IsNotExist(err) {
+ return nil, err
+ }
+ // else probably Resource Busy
+ }
+ return f, nil
+}
diff --git a/vendor/github.com/containerd/console/tc_darwin.go b/vendor/github.com/containerd/console/tc_darwin.go
index 787154580f..77c695a40f 100644
--- a/vendor/github.com/containerd/console/tc_darwin.go
+++ b/vendor/github.com/containerd/console/tc_darwin.go
@@ -18,7 +18,6 @@ package console
import (
"fmt"
- "os"
"golang.org/x/sys/unix"
)
@@ -30,12 +29,12 @@ const (
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
+func unlockpt(f File) error {
return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0)
}
// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
+func ptsname(f File) (string, error) {
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME)
if err != nil {
return "", err
diff --git a/vendor/github.com/containerd/console/tc_freebsd_cgo.go b/vendor/github.com/containerd/console/tc_freebsd_cgo.go
index 0f3d272730..627f7d55a9 100644
--- a/vendor/github.com/containerd/console/tc_freebsd_cgo.go
+++ b/vendor/github.com/containerd/console/tc_freebsd_cgo.go
@@ -1,3 +1,4 @@
+//go:build freebsd && cgo
// +build freebsd,cgo
/*
@@ -20,7 +21,6 @@ package console
import (
"fmt"
- "os"
"golang.org/x/sys/unix"
)
@@ -38,7 +38,7 @@ const (
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
+func unlockpt(f File) error {
fd := C.int(f.Fd())
if _, err := C.unlockpt(fd); err != nil {
C.close(fd)
@@ -48,7 +48,7 @@ func unlockpt(f *os.File) error {
}
// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
+func ptsname(f File) (string, error) {
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
if err != nil {
return "", err
diff --git a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
index 087fc158a1..434ba46efc 100644
--- a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
+++ b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
@@ -1,3 +1,4 @@
+//go:build freebsd && !cgo
// +build freebsd,!cgo
/*
@@ -20,7 +21,6 @@ package console
import (
"fmt"
- "os"
"golang.org/x/sys/unix"
)
@@ -41,12 +41,12 @@ const (
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
+func unlockpt(f File) error {
panic("unlockpt() support requires cgo.")
}
// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
+func ptsname(f File) (string, error) {
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
if err != nil {
return "", err
diff --git a/vendor/github.com/containerd/console/tc_linux.go b/vendor/github.com/containerd/console/tc_linux.go
index 7d552ea4ba..e98dc022dc 100644
--- a/vendor/github.com/containerd/console/tc_linux.go
+++ b/vendor/github.com/containerd/console/tc_linux.go
@@ -18,7 +18,6 @@ package console
import (
"fmt"
- "os"
"unsafe"
"golang.org/x/sys/unix"
@@ -31,7 +30,7 @@ const (
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
+func unlockpt(f File) error {
var u int32
// XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81.
if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 {
@@ -41,7 +40,7 @@ func unlockpt(f *os.File) error {
}
// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
+func ptsname(f File) (string, error) {
var u uint32
// XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81.
if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 {
diff --git a/vendor/github.com/containerd/console/tc_netbsd.go b/vendor/github.com/containerd/console/tc_netbsd.go
index 71227aefdf..73cf439777 100644
--- a/vendor/github.com/containerd/console/tc_netbsd.go
+++ b/vendor/github.com/containerd/console/tc_netbsd.go
@@ -18,7 +18,6 @@ package console
import (
"bytes"
- "os"
"golang.org/x/sys/unix"
)
@@ -31,12 +30,12 @@ const (
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
// This does not exist on NetBSD, it does not allocate controlling terminals on open
-func unlockpt(f *os.File) error {
+func unlockpt(f File) error {
return nil
}
// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
+func ptsname(f File) (string, error) {
ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME)
if err != nil {
return "", err
diff --git a/vendor/github.com/containerd/console/tc_openbsd_cgo.go b/vendor/github.com/containerd/console/tc_openbsd_cgo.go
index f0cec06a72..46f4250c4d 100644
--- a/vendor/github.com/containerd/console/tc_openbsd_cgo.go
+++ b/vendor/github.com/containerd/console/tc_openbsd_cgo.go
@@ -1,3 +1,4 @@
+//go:build openbsd && cgo
// +build openbsd,cgo
/*
@@ -19,8 +20,6 @@
package console
import (
- "os"
-
"golang.org/x/sys/unix"
)
@@ -33,7 +32,7 @@ const (
)
// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
+func ptsname(f File) (string, error) {
ptspath, err := C.ptsname(C.int(f.Fd()))
if err != nil {
return "", err
@@ -43,7 +42,7 @@ func ptsname(f *os.File) (string, error) {
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
+func unlockpt(f File) error {
if _, err := C.grantpt(C.int(f.Fd())); err != nil {
return err
}
diff --git a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go
index daccce2058..a8f9f6c25c 100644
--- a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go
+++ b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go
@@ -1,3 +1,4 @@
+//go:build openbsd && !cgo
// +build openbsd,!cgo
/*
@@ -28,8 +29,6 @@
package console
import (
- "os"
-
"golang.org/x/sys/unix"
)
@@ -38,10 +37,10 @@ const (
cmdTcSet = unix.TIOCSETA
)
-func ptsname(f *os.File) (string, error) {
+func ptsname(f File) (string, error) {
panic("ptsname() support requires cgo.")
}
-func unlockpt(f *os.File) error {
+func unlockpt(f File) error {
panic("unlockpt() support requires cgo.")
}
diff --git a/vendor/github.com/containerd/console/tc_solaris_cgo.go b/vendor/github.com/containerd/console/tc_solaris_cgo.go
deleted file mode 100644
index e36a68edd1..0000000000
--- a/vendor/github.com/containerd/console/tc_solaris_cgo.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// +build solaris,cgo
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package console
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-//#include
-import "C"
-
-const (
- cmdTcGet = unix.TCGETS
- cmdTcSet = unix.TCSETS
-)
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- ptspath, err := C.ptsname(C.int(f.Fd()))
- if err != nil {
- return "", err
- }
- return C.GoString(ptspath), nil
-}
-
-// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
-// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
- if _, err := C.grantpt(C.int(f.Fd())); err != nil {
- return err
- }
- return nil
-}
diff --git a/vendor/github.com/containerd/console/tc_solaris_nocgo.go b/vendor/github.com/containerd/console/tc_solaris_nocgo.go
deleted file mode 100644
index eb0bd2c36b..0000000000
--- a/vendor/github.com/containerd/console/tc_solaris_nocgo.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// +build solaris,!cgo
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-//
-// Implementing the functions below requires cgo support. Non-cgo stubs
-// versions are defined below to enable cross-compilation of source code
-// that depends on these functions, but the resultant cross-compiled
-// binaries cannot actually be used. If the stub function(s) below are
-// actually invoked they will display an error message and cause the
-// calling process to exit.
-//
-
-package console
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- cmdTcGet = unix.TCGETS
- cmdTcSet = unix.TCSETS
-)
-
-func ptsname(f *os.File) (string, error) {
- panic("ptsname() support requires cgo.")
-}
-
-func unlockpt(f *os.File) error {
- panic("unlockpt() support requires cgo.")
-}
diff --git a/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/containerd/console/tc_unix.go
index a6bf01e8d1..2ecf188fca 100644
--- a/vendor/github.com/containerd/console/tc_unix.go
+++ b/vendor/github.com/containerd/console/tc_unix.go
@@ -1,4 +1,5 @@
-// +build darwin freebsd linux netbsd openbsd solaris zos
+//go:build darwin || freebsd || linux || netbsd || openbsd || zos
+// +build darwin freebsd linux netbsd openbsd zos
/*
Copyright The containerd Authors.
@@ -83,7 +84,7 @@ func cfmakeraw(t unix.Termios) unix.Termios {
t.Oflag &^= unix.OPOST
t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
t.Cflag &^= (unix.CSIZE | unix.PARENB)
- t.Cflag &^= unix.CS8
+ t.Cflag |= unix.CS8
t.Cc[unix.VMIN] = 1
t.Cc[unix.VTIME] = 0
diff --git a/vendor/github.com/containerd/console/tc_zos.go b/vendor/github.com/containerd/console/tc_zos.go
index 4262eaf4cc..23b0bd2820 100644
--- a/vendor/github.com/containerd/console/tc_zos.go
+++ b/vendor/github.com/containerd/console/tc_zos.go
@@ -17,6 +17,8 @@
package console
import (
+ "strings"
+
"golang.org/x/sys/unix"
)
@@ -24,3 +26,13 @@ const (
cmdTcGet = unix.TCGETS
cmdTcSet = unix.TCSETS
)
+
+// unlockpt is a no-op on zos.
+func unlockpt(File) error {
+ return nil
+}
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f File) (string, error) {
+ return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil
+}
diff --git a/vendor/github.com/containerd/containerd/LICENSE b/vendor/github.com/containerd/containerd/api/LICENSE
similarity index 100%
rename from vendor/github.com/containerd/containerd/LICENSE
rename to vendor/github.com/containerd/containerd/api/LICENSE
diff --git a/vendor/github.com/containerd/containerd/api/services/content/v1/content.pb.go b/vendor/github.com/containerd/containerd/api/services/content/v1/content.pb.go
index df272237cc..2836646628 100644
--- a/vendor/github.com/containerd/containerd/api/services/content/v1/content.pb.go
+++ b/vendor/github.com/containerd/containerd/api/services/content/v1/content.pb.go
@@ -1,38 +1,42 @@
-// Code generated by protoc-gen-gogo. DO NOT EDIT.
+//
+//Copyright The containerd Authors.
+//
+//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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.28.1
+// protoc v3.20.1
// source: github.com/containerd/containerd/api/services/content/v1/content.proto
package content
import (
- context "context"
- fmt "fmt"
- proto "github.com/gogo/protobuf/proto"
- github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
- github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
- types "github.com/gogo/protobuf/types"
- github_com_opencontainers_go_digest "github.com/opencontainers/go-digest"
- grpc "google.golang.org/grpc"
- codes "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
- io "io"
- math "math"
- math_bits "math/bits"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+ fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
- strings "strings"
- time "time"
+ sync "sync"
)
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-var _ = time.Kitchen
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
// WriteAction defines the behavior of a WriteRequest.
type WriteAction int32
@@ -40,14 +44,14 @@ type WriteAction int32
const (
// WriteActionStat instructs the writer to return the current status while
// holding the lock on the write.
- WriteActionStat WriteAction = 0
+ WriteAction_STAT WriteAction = 0
// WriteActionWrite sets the action for the write request to write data.
//
// Any data included will be written at the provided offset. The
// transaction will be left open for further writes.
//
// This is the default.
- WriteActionWrite WriteAction = 1
+ WriteAction_WRITE WriteAction = 1
// WriteActionCommit will write any outstanding data in the message and
// commit the write, storing it under the digest.
//
@@ -55,243 +59,343 @@ const (
// commit it.
//
// This action will always terminate the write.
- WriteActionCommit WriteAction = 2
+ WriteAction_COMMIT WriteAction = 2
)
-var WriteAction_name = map[int32]string{
- 0: "STAT",
- 1: "WRITE",
- 2: "COMMIT",
-}
+// Enum value maps for WriteAction.
+var (
+ WriteAction_name = map[int32]string{
+ 0: "STAT",
+ 1: "WRITE",
+ 2: "COMMIT",
+ }
+ WriteAction_value = map[string]int32{
+ "STAT": 0,
+ "WRITE": 1,
+ "COMMIT": 2,
+ }
+)
-var WriteAction_value = map[string]int32{
- "STAT": 0,
- "WRITE": 1,
- "COMMIT": 2,
+func (x WriteAction) Enum() *WriteAction {
+ p := new(WriteAction)
+ *p = x
+ return p
}
func (x WriteAction) String() string {
- return proto.EnumName(WriteAction_name, int32(x))
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (WriteAction) Descriptor() protoreflect.EnumDescriptor {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_enumTypes[0].Descriptor()
+}
+
+func (WriteAction) Type() protoreflect.EnumType {
+ return &file_github_com_containerd_containerd_api_services_content_v1_content_proto_enumTypes[0]
}
+func (x WriteAction) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use WriteAction.Descriptor instead.
func (WriteAction) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{0}
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{0}
}
type Info struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
// Digest is the hash identity of the blob.
- Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
+ Digest string `protobuf:"bytes,1,opt,name=digest,proto3" json:"digest,omitempty"`
// Size is the total number of bytes in the blob.
- Size_ int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
+ Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
// CreatedAt provides the time at which the blob was committed.
- CreatedAt time.Time `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"`
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
// UpdatedAt provides the time the info was last updated.
- UpdatedAt time.Time `protobuf:"bytes,4,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"`
+ UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
// Labels are arbitrary data on snapshots.
//
// The combined size of a key/value pair cannot exceed 4096 bytes.
- Labels map[string]string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ Labels map[string]string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *Info) Reset() {
+ *x = Info{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Info) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *Info) Reset() { *m = Info{} }
func (*Info) ProtoMessage() {}
-func (*Info) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{0}
-}
-func (m *Info) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *Info) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_Info.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *Info) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Info.ProtoReflect.Descriptor instead.
+func (*Info) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Info) GetDigest() string {
+ if x != nil {
+ return x.Digest
}
+ return ""
}
-func (m *Info) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Info.Merge(m, src)
+
+func (x *Info) GetSize() int64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
}
-func (m *Info) XXX_Size() int {
- return m.Size()
+
+func (x *Info) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
}
-func (m *Info) XXX_DiscardUnknown() {
- xxx_messageInfo_Info.DiscardUnknown(m)
+
+func (x *Info) GetUpdatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.UpdatedAt
+ }
+ return nil
}
-var xxx_messageInfo_Info proto.InternalMessageInfo
+func (x *Info) GetLabels() map[string]string {
+ if x != nil {
+ return x.Labels
+ }
+ return nil
+}
type InfoRequest struct {
- Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Digest string `protobuf:"bytes,1,opt,name=digest,proto3" json:"digest,omitempty"`
+}
+
+func (x *InfoRequest) Reset() {
+ *x = InfoRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InfoRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *InfoRequest) Reset() { *m = InfoRequest{} }
func (*InfoRequest) ProtoMessage() {}
-func (*InfoRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{1}
-}
-func (m *InfoRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *InfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_InfoRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *InfoRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *InfoRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_InfoRequest.Merge(m, src)
+
+// Deprecated: Use InfoRequest.ProtoReflect.Descriptor instead.
+func (*InfoRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{1}
}
-func (m *InfoRequest) XXX_Size() int {
- return m.Size()
+
+func (x *InfoRequest) GetDigest() string {
+ if x != nil {
+ return x.Digest
+ }
+ return ""
}
-func (m *InfoRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_InfoRequest.DiscardUnknown(m)
+
+type InfoResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Info *Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
}
-var xxx_messageInfo_InfoRequest proto.InternalMessageInfo
+func (x *InfoResponse) Reset() {
+ *x = InfoResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
-type InfoResponse struct {
- Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+func (x *InfoResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *InfoResponse) Reset() { *m = InfoResponse{} }
func (*InfoResponse) ProtoMessage() {}
-func (*InfoResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{2}
-}
-func (m *InfoResponse) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *InfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_InfoResponse.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *InfoResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *InfoResponse) XXX_Merge(src proto.Message) {
- xxx_messageInfo_InfoResponse.Merge(m, src)
-}
-func (m *InfoResponse) XXX_Size() int {
- return m.Size()
-}
-func (m *InfoResponse) XXX_DiscardUnknown() {
- xxx_messageInfo_InfoResponse.DiscardUnknown(m)
+
+// Deprecated: Use InfoResponse.ProtoReflect.Descriptor instead.
+func (*InfoResponse) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{2}
}
-var xxx_messageInfo_InfoResponse proto.InternalMessageInfo
+func (x *InfoResponse) GetInfo() *Info {
+ if x != nil {
+ return x.Info
+ }
+ return nil
+}
type UpdateRequest struct {
- Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"`
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Info *Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
// UpdateMask specifies which fields to perform the update on. If empty,
// the operation applies to all fields.
//
// In info, Digest, Size, and CreatedAt are immutable,
// other field may be updated using this mask.
// If no mask is provided, all mutable field are updated.
- UpdateMask *types.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
+}
+
+func (x *UpdateRequest) Reset() {
+ *x = UpdateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *UpdateRequest) Reset() { *m = UpdateRequest{} }
func (*UpdateRequest) ProtoMessage() {}
-func (*UpdateRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{3}
-}
-func (m *UpdateRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *UpdateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_UpdateRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *UpdateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *UpdateRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_UpdateRequest.Merge(m, src)
-}
-func (m *UpdateRequest) XXX_Size() int {
- return m.Size()
+
+// Deprecated: Use UpdateRequest.ProtoReflect.Descriptor instead.
+func (*UpdateRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{3}
}
-func (m *UpdateRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_UpdateRequest.DiscardUnknown(m)
+
+func (x *UpdateRequest) GetInfo() *Info {
+ if x != nil {
+ return x.Info
+ }
+ return nil
}
-var xxx_messageInfo_UpdateRequest proto.InternalMessageInfo
+func (x *UpdateRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
+ if x != nil {
+ return x.UpdateMask
+ }
+ return nil
+}
type UpdateResponse struct {
- Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Info *Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
}
-func (m *UpdateResponse) Reset() { *m = UpdateResponse{} }
-func (*UpdateResponse) ProtoMessage() {}
-func (*UpdateResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{4}
-}
-func (m *UpdateResponse) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *UpdateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_UpdateResponse.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
+func (x *UpdateResponse) Reset() {
+ *x = UpdateResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
}
-func (m *UpdateResponse) XXX_Merge(src proto.Message) {
- xxx_messageInfo_UpdateResponse.Merge(m, src)
+
+func (x *UpdateResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *UpdateResponse) XXX_Size() int {
- return m.Size()
+
+func (*UpdateResponse) ProtoMessage() {}
+
+func (x *UpdateResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
}
-func (m *UpdateResponse) XXX_DiscardUnknown() {
- xxx_messageInfo_UpdateResponse.DiscardUnknown(m)
+
+// Deprecated: Use UpdateResponse.ProtoReflect.Descriptor instead.
+func (*UpdateResponse) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{4}
}
-var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo
+func (x *UpdateResponse) GetInfo() *Info {
+ if x != nil {
+ return x.Info
+ }
+ return nil
+}
type ListContentRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
// Filters contains one or more filters using the syntax defined in the
// containerd filter package.
//
@@ -302,415 +406,551 @@ type ListContentRequest struct {
// filters[0] or filters[1] or ... or filters[n-1] or filters[n]
//
// If filters is zero-length or nil, all items will be returned.
- Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"`
+}
+
+func (x *ListContentRequest) Reset() {
+ *x = ListContentRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListContentRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *ListContentRequest) Reset() { *m = ListContentRequest{} }
func (*ListContentRequest) ProtoMessage() {}
-func (*ListContentRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{5}
-}
-func (m *ListContentRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *ListContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_ListContentRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *ListContentRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *ListContentRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_ListContentRequest.Merge(m, src)
+
+// Deprecated: Use ListContentRequest.ProtoReflect.Descriptor instead.
+func (*ListContentRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{5}
}
-func (m *ListContentRequest) XXX_Size() int {
- return m.Size()
+
+func (x *ListContentRequest) GetFilters() []string {
+ if x != nil {
+ return x.Filters
+ }
+ return nil
}
-func (m *ListContentRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_ListContentRequest.DiscardUnknown(m)
+
+type ListContentResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Info []*Info `protobuf:"bytes,1,rep,name=info,proto3" json:"info,omitempty"`
}
-var xxx_messageInfo_ListContentRequest proto.InternalMessageInfo
+func (x *ListContentResponse) Reset() {
+ *x = ListContentResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
-type ListContentResponse struct {
- Info []Info `protobuf:"bytes,1,rep,name=info,proto3" json:"info"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+func (x *ListContentResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *ListContentResponse) Reset() { *m = ListContentResponse{} }
func (*ListContentResponse) ProtoMessage() {}
-func (*ListContentResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{6}
-}
-func (m *ListContentResponse) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *ListContentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_ListContentResponse.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *ListContentResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *ListContentResponse) XXX_Merge(src proto.Message) {
- xxx_messageInfo_ListContentResponse.Merge(m, src)
-}
-func (m *ListContentResponse) XXX_Size() int {
- return m.Size()
-}
-func (m *ListContentResponse) XXX_DiscardUnknown() {
- xxx_messageInfo_ListContentResponse.DiscardUnknown(m)
+
+// Deprecated: Use ListContentResponse.ProtoReflect.Descriptor instead.
+func (*ListContentResponse) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{6}
}
-var xxx_messageInfo_ListContentResponse proto.InternalMessageInfo
+func (x *ListContentResponse) GetInfo() []*Info {
+ if x != nil {
+ return x.Info
+ }
+ return nil
+}
type DeleteContentRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
// Digest specifies which content to delete.
- Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ Digest string `protobuf:"bytes,1,opt,name=digest,proto3" json:"digest,omitempty"`
}
-func (m *DeleteContentRequest) Reset() { *m = DeleteContentRequest{} }
-func (*DeleteContentRequest) ProtoMessage() {}
-func (*DeleteContentRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{7}
-}
-func (m *DeleteContentRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *DeleteContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_DeleteContentRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
+func (x *DeleteContentRequest) Reset() {
+ *x = DeleteContentRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
}
-func (m *DeleteContentRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_DeleteContentRequest.Merge(m, src)
+
+func (x *DeleteContentRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *DeleteContentRequest) XXX_Size() int {
- return m.Size()
+
+func (*DeleteContentRequest) ProtoMessage() {}
+
+func (x *DeleteContentRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
}
-func (m *DeleteContentRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_DeleteContentRequest.DiscardUnknown(m)
+
+// Deprecated: Use DeleteContentRequest.ProtoReflect.Descriptor instead.
+func (*DeleteContentRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{7}
}
-var xxx_messageInfo_DeleteContentRequest proto.InternalMessageInfo
+func (x *DeleteContentRequest) GetDigest() string {
+ if x != nil {
+ return x.Digest
+ }
+ return ""
+}
// ReadContentRequest defines the fields that make up a request to read a portion of
// data from a stored object.
type ReadContentRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
// Digest is the hash identity to read.
- Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
+ Digest string `protobuf:"bytes,1,opt,name=digest,proto3" json:"digest,omitempty"`
// Offset specifies the number of bytes from the start at which to begin
// the read. If zero or less, the read will be from the start. This uses
// standard zero-indexed semantics.
Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
// size is the total size of the read. If zero, the entire blob will be
// returned by the service.
- Size_ int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
+}
+
+func (x *ReadContentRequest) Reset() {
+ *x = ReadContentRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReadContentRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *ReadContentRequest) Reset() { *m = ReadContentRequest{} }
func (*ReadContentRequest) ProtoMessage() {}
-func (*ReadContentRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{8}
-}
-func (m *ReadContentRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *ReadContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_ReadContentRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *ReadContentRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *ReadContentRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_ReadContentRequest.Merge(m, src)
+
+// Deprecated: Use ReadContentRequest.ProtoReflect.Descriptor instead.
+func (*ReadContentRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{8}
}
-func (m *ReadContentRequest) XXX_Size() int {
- return m.Size()
+
+func (x *ReadContentRequest) GetDigest() string {
+ if x != nil {
+ return x.Digest
+ }
+ return ""
}
-func (m *ReadContentRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_ReadContentRequest.DiscardUnknown(m)
+
+func (x *ReadContentRequest) GetOffset() int64 {
+ if x != nil {
+ return x.Offset
+ }
+ return 0
}
-var xxx_messageInfo_ReadContentRequest proto.InternalMessageInfo
+func (x *ReadContentRequest) GetSize() int64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
// ReadContentResponse carries byte data for a read request.
type ReadContentResponse struct {
- Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"`
- Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` // offset of the returned data
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` // actual data
+}
+
+func (x *ReadContentResponse) Reset() {
+ *x = ReadContentResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReadContentResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *ReadContentResponse) Reset() { *m = ReadContentResponse{} }
func (*ReadContentResponse) ProtoMessage() {}
-func (*ReadContentResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{9}
-}
-func (m *ReadContentResponse) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *ReadContentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_ReadContentResponse.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *ReadContentResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *ReadContentResponse) XXX_Merge(src proto.Message) {
- xxx_messageInfo_ReadContentResponse.Merge(m, src)
-}
-func (m *ReadContentResponse) XXX_Size() int {
- return m.Size()
+
+// Deprecated: Use ReadContentResponse.ProtoReflect.Descriptor instead.
+func (*ReadContentResponse) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{9}
}
-func (m *ReadContentResponse) XXX_DiscardUnknown() {
- xxx_messageInfo_ReadContentResponse.DiscardUnknown(m)
+
+func (x *ReadContentResponse) GetOffset() int64 {
+ if x != nil {
+ return x.Offset
+ }
+ return 0
}
-var xxx_messageInfo_ReadContentResponse proto.InternalMessageInfo
+func (x *ReadContentResponse) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
type Status struct {
- StartedAt time.Time `protobuf:"bytes,1,opt,name=started_at,json=startedAt,proto3,stdtime" json:"started_at"`
- UpdatedAt time.Time `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"`
- Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"`
- Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
- Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"`
- Expected github_com_opencontainers_go_digest.Digest `protobuf:"bytes,6,opt,name=expected,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"expected"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *Status) Reset() { *m = Status{} }
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ StartedAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
+ UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
+ Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"`
+ Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
+ Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"`
+ Expected string `protobuf:"bytes,6,opt,name=expected,proto3" json:"expected,omitempty"`
+}
+
+func (x *Status) Reset() {
+ *x = Status{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Status) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
func (*Status) ProtoMessage() {}
-func (*Status) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{10}
-}
-func (m *Status) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *Status) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_Status.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *Status) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Status.ProtoReflect.Descriptor instead.
+func (*Status) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *Status) GetStartedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.StartedAt
}
+ return nil
+}
+
+func (x *Status) GetUpdatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.UpdatedAt
+ }
+ return nil
}
-func (m *Status) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status.Merge(m, src)
+
+func (x *Status) GetRef() string {
+ if x != nil {
+ return x.Ref
+ }
+ return ""
}
-func (m *Status) XXX_Size() int {
- return m.Size()
+
+func (x *Status) GetOffset() int64 {
+ if x != nil {
+ return x.Offset
+ }
+ return 0
}
-func (m *Status) XXX_DiscardUnknown() {
- xxx_messageInfo_Status.DiscardUnknown(m)
+
+func (x *Status) GetTotal() int64 {
+ if x != nil {
+ return x.Total
+ }
+ return 0
}
-var xxx_messageInfo_Status proto.InternalMessageInfo
+func (x *Status) GetExpected() string {
+ if x != nil {
+ return x.Expected
+ }
+ return ""
+}
type StatusRequest struct {
- Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
+}
+
+func (x *StatusRequest) Reset() {
+ *x = StatusRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StatusRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *StatusRequest) Reset() { *m = StatusRequest{} }
func (*StatusRequest) ProtoMessage() {}
-func (*StatusRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{11}
-}
-func (m *StatusRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *StatusRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_StatusRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *StatusRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *StatusRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_StatusRequest.Merge(m, src)
+
+// Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead.
+func (*StatusRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{11}
}
-func (m *StatusRequest) XXX_Size() int {
- return m.Size()
+
+func (x *StatusRequest) GetRef() string {
+ if x != nil {
+ return x.Ref
+ }
+ return ""
}
-func (m *StatusRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_StatusRequest.DiscardUnknown(m)
+
+type StatusResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
}
-var xxx_messageInfo_StatusRequest proto.InternalMessageInfo
+func (x *StatusResponse) Reset() {
+ *x = StatusResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
-type StatusResponse struct {
- Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+func (x *StatusResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *StatusResponse) Reset() { *m = StatusResponse{} }
func (*StatusResponse) ProtoMessage() {}
-func (*StatusResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{12}
-}
-func (m *StatusResponse) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *StatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_StatusResponse.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *StatusResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *StatusResponse) XXX_Merge(src proto.Message) {
- xxx_messageInfo_StatusResponse.Merge(m, src)
+
+// Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead.
+func (*StatusResponse) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{12}
}
-func (m *StatusResponse) XXX_Size() int {
- return m.Size()
+
+func (x *StatusResponse) GetStatus() *Status {
+ if x != nil {
+ return x.Status
+ }
+ return nil
}
-func (m *StatusResponse) XXX_DiscardUnknown() {
- xxx_messageInfo_StatusResponse.DiscardUnknown(m)
+
+type ListStatusesRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"`
}
-var xxx_messageInfo_StatusResponse proto.InternalMessageInfo
+func (x *ListStatusesRequest) Reset() {
+ *x = ListStatusesRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
-type ListStatusesRequest struct {
- Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+func (x *ListStatusesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *ListStatusesRequest) Reset() { *m = ListStatusesRequest{} }
func (*ListStatusesRequest) ProtoMessage() {}
-func (*ListStatusesRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{13}
-}
-func (m *ListStatusesRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *ListStatusesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_ListStatusesRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *ListStatusesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
+ return mi.MessageOf(x)
}
-func (m *ListStatusesRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_ListStatusesRequest.Merge(m, src)
+
+// Deprecated: Use ListStatusesRequest.ProtoReflect.Descriptor instead.
+func (*ListStatusesRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{13}
}
-func (m *ListStatusesRequest) XXX_Size() int {
- return m.Size()
+
+func (x *ListStatusesRequest) GetFilters() []string {
+ if x != nil {
+ return x.Filters
+ }
+ return nil
}
-func (m *ListStatusesRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_ListStatusesRequest.DiscardUnknown(m)
+
+type ListStatusesResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Statuses []*Status `protobuf:"bytes,1,rep,name=statuses,proto3" json:"statuses,omitempty"`
}
-var xxx_messageInfo_ListStatusesRequest proto.InternalMessageInfo
+func (x *ListStatusesResponse) Reset() {
+ *x = ListStatusesResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
-type ListStatusesResponse struct {
- Statuses []Status `protobuf:"bytes,1,rep,name=statuses,proto3" json:"statuses"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+func (x *ListStatusesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *ListStatusesResponse) Reset() { *m = ListStatusesResponse{} }
func (*ListStatusesResponse) ProtoMessage() {}
-func (*ListStatusesResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{14}
-}
-func (m *ListStatusesResponse) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *ListStatusesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_ListStatusesResponse.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+
+func (x *ListStatusesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
+ return ms
}
-}
-func (m *ListStatusesResponse) XXX_Merge(src proto.Message) {
- xxx_messageInfo_ListStatusesResponse.Merge(m, src)
-}
-func (m *ListStatusesResponse) XXX_Size() int {
- return m.Size()
-}
-func (m *ListStatusesResponse) XXX_DiscardUnknown() {
- xxx_messageInfo_ListStatusesResponse.DiscardUnknown(m)
+ return mi.MessageOf(x)
}
-var xxx_messageInfo_ListStatusesResponse proto.InternalMessageInfo
+// Deprecated: Use ListStatusesResponse.ProtoReflect.Descriptor instead.
+func (*ListStatusesResponse) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *ListStatusesResponse) GetStatuses() []*Status {
+ if x != nil {
+ return x.Statuses
+ }
+ return nil
+}
// WriteContentRequest writes data to the request ref at offset.
type WriteContentRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
// Action sets the behavior of the write.
//
// When this is a write and the ref is not yet allocated, the ref will be
@@ -744,7 +984,7 @@ type WriteContentRequest struct {
// Only the latest version will be used to check the content against the
// digest. It is only required to include it on a single message, before or
// with the commit action message.
- Expected github_com_opencontainers_go_digest.Digest `protobuf:"bytes,4,opt,name=expected,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"expected"`
+ Expected string `protobuf:"bytes,4,opt,name=expected,proto3" json:"expected,omitempty"`
// Offset specifies the number of bytes from the start at which to begin
// the write. For most implementations, this means from the start of the
// file. This uses standard, zero-indexed semantics.
@@ -763,4663 +1003,786 @@ type WriteContentRequest struct {
// Labels are arbitrary data on snapshots.
//
// The combined size of a key/value pair cannot exceed 4096 bytes.
- Labels map[string]string `protobuf:"bytes,7,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ Labels map[string]string `protobuf:"bytes,7,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
-func (m *WriteContentRequest) Reset() { *m = WriteContentRequest{} }
-func (*WriteContentRequest) ProtoMessage() {}
-func (*WriteContentRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{15}
-}
-func (m *WriteContentRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *WriteContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_WriteContentRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
+func (x *WriteContentRequest) Reset() {
+ *x = WriteContentRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
}
-func (m *WriteContentRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_WriteContentRequest.Merge(m, src)
-}
-func (m *WriteContentRequest) XXX_Size() int {
- return m.Size()
-}
-func (m *WriteContentRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_WriteContentRequest.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_WriteContentRequest proto.InternalMessageInfo
-
-// WriteContentResponse is returned on the culmination of a write call.
-type WriteContentResponse struct {
- // Action contains the action for the final message of the stream. A writer
- // should confirm that they match the intended result.
- Action WriteAction `protobuf:"varint,1,opt,name=action,proto3,enum=containerd.services.content.v1.WriteAction" json:"action,omitempty"`
- // StartedAt provides the time at which the write began.
- //
- // This must be set for stat and commit write actions. All other write
- // actions may omit this.
- StartedAt time.Time `protobuf:"bytes,2,opt,name=started_at,json=startedAt,proto3,stdtime" json:"started_at"`
- // UpdatedAt provides the last time of a successful write.
- //
- // This must be set for stat and commit write actions. All other write
- // actions may omit this.
- UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"`
- // Offset is the current committed size for the write.
- Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
- // Total provides the current, expected total size of the write.
- //
- // We include this to provide consistency with the Status structure on the
- // client writer.
- //
- // This is only valid on the Stat and Commit response.
- Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"`
- // Digest, if present, includes the digest up to the currently committed
- // bytes. If action is commit, this field will be set. It is implementation
- // defined if this is set for other actions.
- Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,6,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-func (m *WriteContentResponse) Reset() { *m = WriteContentResponse{} }
-func (*WriteContentResponse) ProtoMessage() {}
-func (*WriteContentResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{16}
-}
-func (m *WriteContentResponse) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *WriteContentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_WriteContentResponse.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *WriteContentResponse) XXX_Merge(src proto.Message) {
- xxx_messageInfo_WriteContentResponse.Merge(m, src)
-}
-func (m *WriteContentResponse) XXX_Size() int {
- return m.Size()
-}
-func (m *WriteContentResponse) XXX_DiscardUnknown() {
- xxx_messageInfo_WriteContentResponse.DiscardUnknown(m)
+func (x *WriteContentRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-var xxx_messageInfo_WriteContentResponse proto.InternalMessageInfo
-
-type AbortRequest struct {
- Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
+func (*WriteContentRequest) ProtoMessage() {}
-func (m *AbortRequest) Reset() { *m = AbortRequest{} }
-func (*AbortRequest) ProtoMessage() {}
-func (*AbortRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_468430ba3e400391, []int{17}
-}
-func (m *AbortRequest) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *AbortRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_AbortRequest.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
+func (x *WriteContentRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[15]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- return b[:n], nil
- }
-}
-func (m *AbortRequest) XXX_Merge(src proto.Message) {
- xxx_messageInfo_AbortRequest.Merge(m, src)
-}
-func (m *AbortRequest) XXX_Size() int {
- return m.Size()
-}
-func (m *AbortRequest) XXX_DiscardUnknown() {
- xxx_messageInfo_AbortRequest.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_AbortRequest proto.InternalMessageInfo
-
-func init() {
- proto.RegisterEnum("containerd.services.content.v1.WriteAction", WriteAction_name, WriteAction_value)
- proto.RegisterType((*Info)(nil), "containerd.services.content.v1.Info")
- proto.RegisterMapType((map[string]string)(nil), "containerd.services.content.v1.Info.LabelsEntry")
- proto.RegisterType((*InfoRequest)(nil), "containerd.services.content.v1.InfoRequest")
- proto.RegisterType((*InfoResponse)(nil), "containerd.services.content.v1.InfoResponse")
- proto.RegisterType((*UpdateRequest)(nil), "containerd.services.content.v1.UpdateRequest")
- proto.RegisterType((*UpdateResponse)(nil), "containerd.services.content.v1.UpdateResponse")
- proto.RegisterType((*ListContentRequest)(nil), "containerd.services.content.v1.ListContentRequest")
- proto.RegisterType((*ListContentResponse)(nil), "containerd.services.content.v1.ListContentResponse")
- proto.RegisterType((*DeleteContentRequest)(nil), "containerd.services.content.v1.DeleteContentRequest")
- proto.RegisterType((*ReadContentRequest)(nil), "containerd.services.content.v1.ReadContentRequest")
- proto.RegisterType((*ReadContentResponse)(nil), "containerd.services.content.v1.ReadContentResponse")
- proto.RegisterType((*Status)(nil), "containerd.services.content.v1.Status")
- proto.RegisterType((*StatusRequest)(nil), "containerd.services.content.v1.StatusRequest")
- proto.RegisterType((*StatusResponse)(nil), "containerd.services.content.v1.StatusResponse")
- proto.RegisterType((*ListStatusesRequest)(nil), "containerd.services.content.v1.ListStatusesRequest")
- proto.RegisterType((*ListStatusesResponse)(nil), "containerd.services.content.v1.ListStatusesResponse")
- proto.RegisterType((*WriteContentRequest)(nil), "containerd.services.content.v1.WriteContentRequest")
- proto.RegisterMapType((map[string]string)(nil), "containerd.services.content.v1.WriteContentRequest.LabelsEntry")
- proto.RegisterType((*WriteContentResponse)(nil), "containerd.services.content.v1.WriteContentResponse")
- proto.RegisterType((*AbortRequest)(nil), "containerd.services.content.v1.AbortRequest")
-}
-
-func init() {
- proto.RegisterFile("github.com/containerd/containerd/api/services/content/v1/content.proto", fileDescriptor_468430ba3e400391)
-}
-
-var fileDescriptor_468430ba3e400391 = []byte{
- // 1081 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6f, 0x1b, 0x45,
- 0x14, 0xf7, 0x78, 0xed, 0x4d, 0xf2, 0x9c, 0x16, 0x33, 0x31, 0x95, 0xb5, 0x08, 0x67, 0xbb, 0x42,
- 0xc8, 0x6a, 0xc9, 0x3a, 0x75, 0x7a, 0x00, 0x2a, 0x01, 0x8e, 0x9b, 0xaa, 0x41, 0x4d, 0x41, 0x5b,
- 0x97, 0x40, 0x2f, 0x65, 0x6d, 0x8f, 0xcd, 0x2a, 0xb6, 0xd7, 0xdd, 0x19, 0x5b, 0x84, 0x13, 0x17,
- 0x24, 0x14, 0xf5, 0x80, 0xb8, 0xe7, 0x02, 0xfc, 0x15, 0x1c, 0x38, 0xe7, 0xc8, 0x11, 0x71, 0x68,
- 0x69, 0xfe, 0x07, 0xee, 0x68, 0x66, 0x67, 0xed, 0xf5, 0x47, 0x58, 0xdb, 0x31, 0x27, 0xbf, 0x99,
- 0x7d, 0xbf, 0xf7, 0xfd, 0x31, 0x86, 0x7b, 0x4d, 0x87, 0x7d, 0xdd, 0xab, 0x9a, 0x35, 0xb7, 0x5d,
- 0xa8, 0xb9, 0x1d, 0x66, 0x3b, 0x1d, 0xe2, 0xd5, 0xc3, 0xa4, 0xdd, 0x75, 0x0a, 0x94, 0x78, 0x7d,
- 0xa7, 0x46, 0xa8, 0xb8, 0x27, 0x1d, 0x56, 0xe8, 0xdf, 0x0a, 0x48, 0xb3, 0xeb, 0xb9, 0xcc, 0xc5,
- 0xb9, 0x21, 0xc2, 0x0c, 0xb8, 0xcd, 0x80, 0xa5, 0x7f, 0x4b, 0xcb, 0x34, 0xdd, 0xa6, 0x2b, 0x58,
- 0x0b, 0x9c, 0xf2, 0x51, 0x9a, 0xde, 0x74, 0xdd, 0x66, 0x8b, 0x14, 0xc4, 0xa9, 0xda, 0x6b, 0x14,
- 0x1a, 0x0e, 0x69, 0xd5, 0x9f, 0xb6, 0x6d, 0x7a, 0x24, 0x39, 0x36, 0xc7, 0x39, 0x98, 0xd3, 0x26,
- 0x94, 0xd9, 0xed, 0xae, 0x64, 0x78, 0x73, 0x9c, 0x81, 0xb4, 0xbb, 0xec, 0xd8, 0xff, 0x68, 0xfc,
- 0x13, 0x87, 0xc4, 0x7e, 0xa7, 0xe1, 0xe2, 0x4f, 0x40, 0xad, 0x3b, 0x4d, 0x42, 0x59, 0x16, 0xe9,
- 0x28, 0xbf, 0xb6, 0x5b, 0x3c, 0x7b, 0xb1, 0x19, 0xfb, 0xeb, 0xc5, 0xe6, 0x8d, 0x90, 0xfb, 0x6e,
- 0x97, 0x74, 0x06, 0x5e, 0xd0, 0x42, 0xd3, 0xdd, 0xf2, 0x21, 0xe6, 0x5d, 0xf1, 0x63, 0x49, 0x09,
- 0x18, 0x43, 0x82, 0x3a, 0xdf, 0x92, 0x6c, 0x5c, 0x47, 0x79, 0xc5, 0x12, 0x34, 0x2e, 0x03, 0xd4,
- 0x3c, 0x62, 0x33, 0x52, 0x7f, 0x6a, 0xb3, 0xac, 0xa2, 0xa3, 0x7c, 0xaa, 0xa8, 0x99, 0xbe, 0x69,
- 0x66, 0x60, 0x9a, 0x59, 0x09, 0x6c, 0xdf, 0x5d, 0xe5, 0xfa, 0x7f, 0x7c, 0xb9, 0x89, 0xac, 0x35,
- 0x89, 0x2b, 0x31, 0x2e, 0xa4, 0xd7, 0xad, 0x07, 0x42, 0x12, 0xf3, 0x08, 0x91, 0xb8, 0x12, 0xc3,
- 0xf7, 0x41, 0x6d, 0xd9, 0x55, 0xd2, 0xa2, 0xd9, 0xa4, 0xae, 0xe4, 0x53, 0xc5, 0x6d, 0xf3, 0xbf,
- 0x33, 0x63, 0xf2, 0xf8, 0x98, 0x0f, 0x04, 0x64, 0xaf, 0xc3, 0xbc, 0x63, 0x4b, 0xe2, 0xb5, 0xf7,
- 0x21, 0x15, 0xba, 0xc6, 0x69, 0x50, 0x8e, 0xc8, 0xb1, 0x1f, 0x3f, 0x8b, 0x93, 0x38, 0x03, 0xc9,
- 0xbe, 0xdd, 0xea, 0xf9, 0x91, 0x58, 0xb3, 0xfc, 0xc3, 0x07, 0xf1, 0xf7, 0x90, 0xf1, 0x25, 0xa4,
- 0xb8, 0x58, 0x8b, 0x3c, 0xeb, 0xf1, 0x88, 0x2d, 0x31, 0xfa, 0xc6, 0x43, 0x58, 0xf7, 0x45, 0xd3,
- 0xae, 0xdb, 0xa1, 0x04, 0x7f, 0x08, 0x09, 0xa7, 0xd3, 0x70, 0x85, 0xe4, 0x54, 0xf1, 0xed, 0x59,
- 0xbc, 0xdd, 0x4d, 0x70, 0xfd, 0x96, 0xc0, 0x19, 0xcf, 0x11, 0x5c, 0x79, 0x2c, 0xa2, 0x17, 0x58,
- 0x7b, 0x49, 0x89, 0xf8, 0x0e, 0xa4, 0xfc, 0x74, 0x88, 0x3a, 0x16, 0xc1, 0x99, 0x96, 0xc7, 0x7b,
- 0xbc, 0xd4, 0x0f, 0x6c, 0x7a, 0x64, 0xc9, 0xac, 0x73, 0xda, 0xf8, 0x0c, 0xae, 0x06, 0xd6, 0x2c,
- 0xc9, 0x41, 0x13, 0xf0, 0x03, 0x87, 0xb2, 0xb2, 0xcf, 0x12, 0x38, 0x99, 0x85, 0x95, 0x86, 0xd3,
- 0x62, 0xc4, 0xa3, 0x59, 0xa4, 0x2b, 0xf9, 0x35, 0x2b, 0x38, 0x1a, 0x8f, 0x61, 0x63, 0x84, 0x7f,
- 0xc2, 0x0c, 0x65, 0x21, 0x33, 0xaa, 0x90, 0xb9, 0x4b, 0x5a, 0x84, 0x91, 0x31, 0x43, 0x96, 0x59,
- 0x1b, 0xcf, 0x11, 0x60, 0x8b, 0xd8, 0xf5, 0xff, 0x4f, 0x05, 0xbe, 0x06, 0xaa, 0xdb, 0x68, 0x50,
- 0xc2, 0x64, 0xfb, 0xcb, 0xd3, 0x60, 0x28, 0x28, 0xc3, 0xa1, 0x60, 0x94, 0x60, 0x63, 0xc4, 0x1a,
- 0x19, 0xc9, 0xa1, 0x08, 0x34, 0x2e, 0xa2, 0x6e, 0x33, 0x5b, 0x08, 0x5e, 0xb7, 0x04, 0x6d, 0xfc,
- 0x1c, 0x07, 0xf5, 0x11, 0xb3, 0x59, 0x8f, 0xf2, 0xe9, 0x40, 0x99, 0xed, 0xc9, 0xe9, 0x80, 0xe6,
- 0x99, 0x0e, 0x12, 0x37, 0x31, 0x62, 0xe2, 0x8b, 0x8d, 0x98, 0x34, 0x28, 0x1e, 0x69, 0x08, 0x57,
- 0xd7, 0x2c, 0x4e, 0x86, 0x5c, 0x4a, 0x8c, 0xb8, 0x94, 0x81, 0x24, 0x73, 0x99, 0xdd, 0xca, 0x26,
- 0xc5, 0xb5, 0x7f, 0xc0, 0x0f, 0x61, 0x95, 0x7c, 0xd3, 0x25, 0x35, 0x46, 0xea, 0x59, 0x75, 0xe1,
- 0x8c, 0x0c, 0x64, 0x18, 0xd7, 0xe1, 0x8a, 0x1f, 0xa3, 0x20, 0xe1, 0xd2, 0x40, 0x34, 0x30, 0x90,
- 0xb7, 0x55, 0xc0, 0x32, 0xa8, 0x67, 0x95, 0x8a, 0x1b, 0x19, 0xca, 0x77, 0xa2, 0x2a, 0x5a, 0xe2,
- 0x25, 0xca, 0x28, 0xf8, 0x6d, 0xe2, 0xdf, 0x12, 0x1a, 0xdd, 0x57, 0x5f, 0x41, 0x66, 0x14, 0x20,
- 0x0d, 0xb9, 0x0f, 0xab, 0x54, 0xde, 0xc9, 0xe6, 0x9a, 0xd1, 0x14, 0xd9, 0x5e, 0x03, 0xb4, 0xf1,
- 0x93, 0x02, 0x1b, 0x87, 0x9e, 0x33, 0xd1, 0x62, 0x65, 0x50, 0xed, 0x1a, 0x73, 0xdc, 0x8e, 0x70,
- 0xf5, 0x6a, 0xf1, 0x66, 0x94, 0x7c, 0x21, 0xa4, 0x24, 0x20, 0x96, 0x84, 0x06, 0x31, 0x8d, 0x0f,
- 0x93, 0x3e, 0x48, 0xae, 0x72, 0x51, 0x72, 0x13, 0x97, 0x4f, 0x6e, 0xa8, 0xb4, 0x92, 0x53, 0xbb,
- 0x45, 0x1d, 0x76, 0x0b, 0x3e, 0x1c, 0xec, 0xbe, 0x15, 0x11, 0xc8, 0x8f, 0x66, 0x72, 0x74, 0x34,
- 0x5a, 0xcb, 0x5e, 0x85, 0x2f, 0xe3, 0x90, 0x19, 0x55, 0x23, 0xf3, 0xbe, 0x94, 0xac, 0x8c, 0x0e,
- 0x85, 0xf8, 0x32, 0x86, 0x82, 0xb2, 0xd8, 0x50, 0x98, 0x6f, 0x04, 0x0c, 0x47, 0xb2, 0x7a, 0xe9,
- 0xa9, 0xaf, 0xc3, 0x7a, 0xa9, 0xea, 0x7a, 0xec, 0xc2, 0xee, 0xbf, 0xf1, 0x3d, 0x82, 0x54, 0x28,
- 0x7a, 0xf8, 0x2d, 0x48, 0x3c, 0xaa, 0x94, 0x2a, 0xe9, 0x98, 0xb6, 0x71, 0x72, 0xaa, 0xbf, 0x16,
- 0xfa, 0xc4, 0x3b, 0x0b, 0x6f, 0x42, 0xf2, 0xd0, 0xda, 0xaf, 0xec, 0xa5, 0x91, 0x96, 0x39, 0x39,
- 0xd5, 0xd3, 0xa1, 0xef, 0x82, 0xc4, 0xd7, 0x41, 0x2d, 0x7f, 0x7a, 0x70, 0xb0, 0x5f, 0x49, 0xc7,
- 0xb5, 0x37, 0x4e, 0x4e, 0xf5, 0xd7, 0x43, 0x1c, 0x65, 0xb7, 0xdd, 0x76, 0x98, 0xb6, 0xf1, 0xc3,
- 0x2f, 0xb9, 0xd8, 0x6f, 0xbf, 0xe6, 0xc2, 0x7a, 0x8b, 0xbf, 0xaf, 0xc0, 0x8a, 0x2c, 0x03, 0x6c,
- 0xcb, 0x97, 0xe9, 0xcd, 0x59, 0x36, 0xa9, 0x74, 0x4d, 0x7b, 0x77, 0x36, 0x66, 0x59, 0x61, 0x4d,
- 0x50, 0xfd, 0xb7, 0x04, 0xde, 0x8a, 0xc2, 0x8d, 0xbc, 0x80, 0x34, 0x73, 0x56, 0x76, 0xa9, 0xe8,
- 0x19, 0x24, 0xf8, 0x68, 0xc3, 0xc5, 0x28, 0xdc, 0xe4, 0x43, 0x44, 0xdb, 0x99, 0x0b, 0xe3, 0x2b,
- 0xdc, 0x46, 0xf8, 0x73, 0x50, 0xfd, 0xe7, 0x04, 0xbe, 0x1d, 0x25, 0x60, 0xda, 0xb3, 0x43, 0xbb,
- 0x36, 0x51, 0xdf, 0x7b, 0xfc, 0x7f, 0x03, 0x77, 0x85, 0xef, 0xec, 0x68, 0x57, 0x26, 0xdf, 0x19,
- 0xd1, 0xae, 0x4c, 0x79, 0x0d, 0x6c, 0x23, 0x9e, 0x26, 0xb9, 0xe2, 0xb7, 0x66, 0xdc, 0x41, 0xb3,
- 0xa6, 0x69, 0x6c, 0xe5, 0x1d, 0xc3, 0x7a, 0x78, 0x03, 0xe1, 0x99, 0x42, 0x3f, 0xb6, 0xe0, 0xb4,
- 0xdb, 0xf3, 0x81, 0xa4, 0xea, 0x3e, 0x24, 0xfd, 0xd6, 0xd9, 0x59, 0x60, 0x24, 0x47, 0xeb, 0x9c,
- 0x36, 0x60, 0xf3, 0x68, 0x1b, 0xe1, 0x03, 0x48, 0x8a, 0xd9, 0x80, 0x23, 0x3b, 0x27, 0x3c, 0x42,
- 0x2e, 0xaa, 0x8e, 0xdd, 0x27, 0x67, 0xaf, 0x72, 0xb1, 0x3f, 0x5f, 0xe5, 0x62, 0xdf, 0x9d, 0xe7,
- 0xd0, 0xd9, 0x79, 0x0e, 0xfd, 0x71, 0x9e, 0x43, 0x7f, 0x9f, 0xe7, 0xd0, 0x93, 0x8f, 0x17, 0xfd,
- 0x1f, 0x7d, 0x47, 0x92, 0x5f, 0xc4, 0xaa, 0xaa, 0xd0, 0xb6, 0xf3, 0x6f, 0x00, 0x00, 0x00, 0xff,
- 0xff, 0xc0, 0xc2, 0x35, 0xb1, 0x94, 0x0f, 0x00, 0x00,
-}
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConn
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion4
-
-// ContentClient is the client API for Content service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type ContentClient interface {
- // Info returns information about a committed object.
- //
- // This call can be used for getting the size of content and checking for
- // existence.
- Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error)
- // Update updates content metadata.
- //
- // This call can be used to manage the mutable content labels. The
- // immutable metadata such as digest, size, and committed at cannot
- // be updated.
- Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*UpdateResponse, error)
- // List streams the entire set of content as Info objects and closes the
- // stream.
- //
- // Typically, this will yield a large response, chunked into messages.
- // Clients should make provisions to ensure they can handle the entire data
- // set.
- List(ctx context.Context, in *ListContentRequest, opts ...grpc.CallOption) (Content_ListClient, error)
- // Delete will delete the referenced object.
- Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*types.Empty, error)
- // Read allows one to read an object based on the offset into the content.
- //
- // The requested data may be returned in one or more messages.
- Read(ctx context.Context, in *ReadContentRequest, opts ...grpc.CallOption) (Content_ReadClient, error)
- // Status returns the status for a single reference.
- Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
- // ListStatuses returns the status of ongoing object ingestions, started via
- // Write.
- //
- // Only those matching the regular expression will be provided in the
- // response. If the provided regular expression is empty, all ingestions
- // will be provided.
- ListStatuses(ctx context.Context, in *ListStatusesRequest, opts ...grpc.CallOption) (*ListStatusesResponse, error)
- // Write begins or resumes writes to a resource identified by a unique ref.
- // Only one active stream may exist at a time for each ref.
- //
- // Once a write stream has started, it may only write to a single ref, thus
- // once a stream is started, the ref may be omitted on subsequent writes.
- //
- // For any write transaction represented by a ref, only a single write may
- // be made to a given offset. If overlapping writes occur, it is an error.
- // Writes should be sequential and implementations may throw an error if
- // this is required.
- //
- // If expected_digest is set and already part of the content store, the
- // write will fail.
- //
- // When completed, the commit flag should be set to true. If expected size
- // or digest is set, the content will be validated against those values.
- Write(ctx context.Context, opts ...grpc.CallOption) (Content_WriteClient, error)
- // Abort cancels the ongoing write named in the request. Any resources
- // associated with the write will be collected.
- Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*types.Empty, error)
-}
-
-type contentClient struct {
- cc *grpc.ClientConn
-}
-
-func NewContentClient(cc *grpc.ClientConn) ContentClient {
- return &contentClient{cc}
-}
-
-func (c *contentClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) {
- out := new(InfoResponse)
- err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Info", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-func (c *contentClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*UpdateResponse, error) {
- out := new(UpdateResponse)
- err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Update", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-func (c *contentClient) List(ctx context.Context, in *ListContentRequest, opts ...grpc.CallOption) (Content_ListClient, error) {
- stream, err := c.cc.NewStream(ctx, &_Content_serviceDesc.Streams[0], "/containerd.services.content.v1.Content/List", opts...)
- if err != nil {
- return nil, err
+ return ms
}
- x := &contentListClient{stream}
- if err := x.ClientStream.SendMsg(in); err != nil {
- return nil, err
- }
- if err := x.ClientStream.CloseSend(); err != nil {
- return nil, err
- }
- return x, nil
-}
-
-type Content_ListClient interface {
- Recv() (*ListContentResponse, error)
- grpc.ClientStream
+ return mi.MessageOf(x)
}
-type contentListClient struct {
- grpc.ClientStream
-}
-
-func (x *contentListClient) Recv() (*ListContentResponse, error) {
- m := new(ListContentResponse)
- if err := x.ClientStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
+// Deprecated: Use WriteContentRequest.ProtoReflect.Descriptor instead.
+func (*WriteContentRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{15}
}
-func (c *contentClient) Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*types.Empty, error) {
- out := new(types.Empty)
- err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Delete", in, out, opts...)
- if err != nil {
- return nil, err
+func (x *WriteContentRequest) GetAction() WriteAction {
+ if x != nil {
+ return x.Action
}
- return out, nil
+ return WriteAction_STAT
}
-func (c *contentClient) Read(ctx context.Context, in *ReadContentRequest, opts ...grpc.CallOption) (Content_ReadClient, error) {
- stream, err := c.cc.NewStream(ctx, &_Content_serviceDesc.Streams[1], "/containerd.services.content.v1.Content/Read", opts...)
- if err != nil {
- return nil, err
+func (x *WriteContentRequest) GetRef() string {
+ if x != nil {
+ return x.Ref
}
- x := &contentReadClient{stream}
- if err := x.ClientStream.SendMsg(in); err != nil {
- return nil, err
- }
- if err := x.ClientStream.CloseSend(); err != nil {
- return nil, err
- }
- return x, nil
-}
-
-type Content_ReadClient interface {
- Recv() (*ReadContentResponse, error)
- grpc.ClientStream
+ return ""
}
-type contentReadClient struct {
- grpc.ClientStream
-}
-
-func (x *contentReadClient) Recv() (*ReadContentResponse, error) {
- m := new(ReadContentResponse)
- if err := x.ClientStream.RecvMsg(m); err != nil {
- return nil, err
+func (x *WriteContentRequest) GetTotal() int64 {
+ if x != nil {
+ return x.Total
}
- return m, nil
+ return 0
}
-func (c *contentClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) {
- out := new(StatusResponse)
- err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Status", in, out, opts...)
- if err != nil {
- return nil, err
+func (x *WriteContentRequest) GetExpected() string {
+ if x != nil {
+ return x.Expected
}
- return out, nil
+ return ""
}
-func (c *contentClient) ListStatuses(ctx context.Context, in *ListStatusesRequest, opts ...grpc.CallOption) (*ListStatusesResponse, error) {
- out := new(ListStatusesResponse)
- err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/ListStatuses", in, out, opts...)
- if err != nil {
- return nil, err
+func (x *WriteContentRequest) GetOffset() int64 {
+ if x != nil {
+ return x.Offset
}
- return out, nil
+ return 0
}
-func (c *contentClient) Write(ctx context.Context, opts ...grpc.CallOption) (Content_WriteClient, error) {
- stream, err := c.cc.NewStream(ctx, &_Content_serviceDesc.Streams[2], "/containerd.services.content.v1.Content/Write", opts...)
- if err != nil {
- return nil, err
+func (x *WriteContentRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
}
- x := &contentWriteClient{stream}
- return x, nil
-}
-
-type Content_WriteClient interface {
- Send(*WriteContentRequest) error
- Recv() (*WriteContentResponse, error)
- grpc.ClientStream
-}
-
-type contentWriteClient struct {
- grpc.ClientStream
-}
-
-func (x *contentWriteClient) Send(m *WriteContentRequest) error {
- return x.ClientStream.SendMsg(m)
+ return nil
}
-func (x *contentWriteClient) Recv() (*WriteContentResponse, error) {
- m := new(WriteContentResponse)
- if err := x.ClientStream.RecvMsg(m); err != nil {
- return nil, err
+func (x *WriteContentRequest) GetLabels() map[string]string {
+ if x != nil {
+ return x.Labels
}
- return m, nil
+ return nil
}
-func (c *contentClient) Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*types.Empty, error) {
- out := new(types.Empty)
- err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Abort", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
+// WriteContentResponse is returned on the culmination of a write call.
+type WriteContentResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
-// ContentServer is the server API for Content service.
-type ContentServer interface {
- // Info returns information about a committed object.
- //
- // This call can be used for getting the size of content and checking for
- // existence.
- Info(context.Context, *InfoRequest) (*InfoResponse, error)
- // Update updates content metadata.
- //
- // This call can be used to manage the mutable content labels. The
- // immutable metadata such as digest, size, and committed at cannot
- // be updated.
- Update(context.Context, *UpdateRequest) (*UpdateResponse, error)
- // List streams the entire set of content as Info objects and closes the
- // stream.
- //
- // Typically, this will yield a large response, chunked into messages.
- // Clients should make provisions to ensure they can handle the entire data
- // set.
- List(*ListContentRequest, Content_ListServer) error
- // Delete will delete the referenced object.
- Delete(context.Context, *DeleteContentRequest) (*types.Empty, error)
- // Read allows one to read an object based on the offset into the content.
- //
- // The requested data may be returned in one or more messages.
- Read(*ReadContentRequest, Content_ReadServer) error
- // Status returns the status for a single reference.
- Status(context.Context, *StatusRequest) (*StatusResponse, error)
- // ListStatuses returns the status of ongoing object ingestions, started via
- // Write.
- //
- // Only those matching the regular expression will be provided in the
- // response. If the provided regular expression is empty, all ingestions
- // will be provided.
- ListStatuses(context.Context, *ListStatusesRequest) (*ListStatusesResponse, error)
- // Write begins or resumes writes to a resource identified by a unique ref.
- // Only one active stream may exist at a time for each ref.
+ // Action contains the action for the final message of the stream. A writer
+ // should confirm that they match the intended result.
+ Action WriteAction `protobuf:"varint,1,opt,name=action,proto3,enum=containerd.services.content.v1.WriteAction" json:"action,omitempty"`
+ // StartedAt provides the time at which the write began.
//
- // Once a write stream has started, it may only write to a single ref, thus
- // once a stream is started, the ref may be omitted on subsequent writes.
+ // This must be set for stat and commit write actions. All other write
+ // actions may omit this.
+ StartedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
+ // UpdatedAt provides the last time of a successful write.
//
- // For any write transaction represented by a ref, only a single write may
- // be made to a given offset. If overlapping writes occur, it is an error.
- // Writes should be sequential and implementations may throw an error if
- // this is required.
+ // This must be set for stat and commit write actions. All other write
+ // actions may omit this.
+ UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
+ // Offset is the current committed size for the write.
+ Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
+ // Total provides the current, expected total size of the write.
//
- // If expected_digest is set and already part of the content store, the
- // write will fail.
+ // We include this to provide consistency with the Status structure on the
+ // client writer.
//
- // When completed, the commit flag should be set to true. If expected size
- // or digest is set, the content will be validated against those values.
- Write(Content_WriteServer) error
- // Abort cancels the ongoing write named in the request. Any resources
- // associated with the write will be collected.
- Abort(context.Context, *AbortRequest) (*types.Empty, error)
-}
-
-// UnimplementedContentServer can be embedded to have forward compatible implementations.
-type UnimplementedContentServer struct {
-}
-
-func (*UnimplementedContentServer) Info(ctx context.Context, req *InfoRequest) (*InfoResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method Info not implemented")
-}
-func (*UnimplementedContentServer) Update(ctx context.Context, req *UpdateRequest) (*UpdateResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method Update not implemented")
-}
-func (*UnimplementedContentServer) List(req *ListContentRequest, srv Content_ListServer) error {
- return status.Errorf(codes.Unimplemented, "method List not implemented")
-}
-func (*UnimplementedContentServer) Delete(ctx context.Context, req *DeleteContentRequest) (*types.Empty, error) {
- return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
-}
-func (*UnimplementedContentServer) Read(req *ReadContentRequest, srv Content_ReadServer) error {
- return status.Errorf(codes.Unimplemented, "method Read not implemented")
-}
-func (*UnimplementedContentServer) Status(ctx context.Context, req *StatusRequest) (*StatusResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method Status not implemented")
-}
-func (*UnimplementedContentServer) ListStatuses(ctx context.Context, req *ListStatusesRequest) (*ListStatusesResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method ListStatuses not implemented")
-}
-func (*UnimplementedContentServer) Write(srv Content_WriteServer) error {
- return status.Errorf(codes.Unimplemented, "method Write not implemented")
-}
-func (*UnimplementedContentServer) Abort(ctx context.Context, req *AbortRequest) (*types.Empty, error) {
- return nil, status.Errorf(codes.Unimplemented, "method Abort not implemented")
-}
-
-func RegisterContentServer(s *grpc.Server, srv ContentServer) {
- s.RegisterService(&_Content_serviceDesc, srv)
-}
-
-func _Content_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(InfoRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ContentServer).Info(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/containerd.services.content.v1.Content/Info",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ContentServer).Info(ctx, req.(*InfoRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _Content_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(UpdateRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ContentServer).Update(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/containerd.services.content.v1.Content/Update",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ContentServer).Update(ctx, req.(*UpdateRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _Content_List_Handler(srv interface{}, stream grpc.ServerStream) error {
- m := new(ListContentRequest)
- if err := stream.RecvMsg(m); err != nil {
- return err
- }
- return srv.(ContentServer).List(m, &contentListServer{stream})
-}
-
-type Content_ListServer interface {
- Send(*ListContentResponse) error
- grpc.ServerStream
-}
-
-type contentListServer struct {
- grpc.ServerStream
-}
-
-func (x *contentListServer) Send(m *ListContentResponse) error {
- return x.ServerStream.SendMsg(m)
-}
-
-func _Content_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(DeleteContentRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ContentServer).Delete(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/containerd.services.content.v1.Content/Delete",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ContentServer).Delete(ctx, req.(*DeleteContentRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _Content_Read_Handler(srv interface{}, stream grpc.ServerStream) error {
- m := new(ReadContentRequest)
- if err := stream.RecvMsg(m); err != nil {
- return err
- }
- return srv.(ContentServer).Read(m, &contentReadServer{stream})
-}
-
-type Content_ReadServer interface {
- Send(*ReadContentResponse) error
- grpc.ServerStream
-}
-
-type contentReadServer struct {
- grpc.ServerStream
-}
-
-func (x *contentReadServer) Send(m *ReadContentResponse) error {
- return x.ServerStream.SendMsg(m)
-}
-
-func _Content_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(StatusRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ContentServer).Status(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/containerd.services.content.v1.Content/Status",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ContentServer).Status(ctx, req.(*StatusRequest))
- }
- return interceptor(ctx, in, info, handler)
+ // This is only valid on the Stat and Commit response.
+ Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"`
+ // Digest, if present, includes the digest up to the currently committed
+ // bytes. If action is commit, this field will be set. It is implementation
+ // defined if this is set for other actions.
+ Digest string `protobuf:"bytes,6,opt,name=digest,proto3" json:"digest,omitempty"`
}
-func _Content_ListStatuses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(ListStatusesRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ContentServer).ListStatuses(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/containerd.services.content.v1.Content/ListStatuses",
+func (x *WriteContentResponse) Reset() {
+ *x = WriteContentResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ContentServer).ListStatuses(ctx, req.(*ListStatusesRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _Content_Write_Handler(srv interface{}, stream grpc.ServerStream) error {
- return srv.(ContentServer).Write(&contentWriteServer{stream})
-}
-
-type Content_WriteServer interface {
- Send(*WriteContentResponse) error
- Recv() (*WriteContentRequest, error)
- grpc.ServerStream
-}
-
-type contentWriteServer struct {
- grpc.ServerStream
}
-func (x *contentWriteServer) Send(m *WriteContentResponse) error {
- return x.ServerStream.SendMsg(m)
+func (x *WriteContentResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (x *contentWriteServer) Recv() (*WriteContentRequest, error) {
- m := new(WriteContentRequest)
- if err := x.ServerStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
-}
+func (*WriteContentResponse) ProtoMessage() {}
-func _Content_Abort_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(AbortRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ContentServer).Abort(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/containerd.services.content.v1.Content/Abort",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ContentServer).Abort(ctx, req.(*AbortRequest))
+func (x *WriteContentResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[16]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
}
- return interceptor(ctx, in, info, handler)
+ return mi.MessageOf(x)
}
-var _Content_serviceDesc = grpc.ServiceDesc{
- ServiceName: "containerd.services.content.v1.Content",
- HandlerType: (*ContentServer)(nil),
- Methods: []grpc.MethodDesc{
- {
- MethodName: "Info",
- Handler: _Content_Info_Handler,
- },
- {
- MethodName: "Update",
- Handler: _Content_Update_Handler,
- },
- {
- MethodName: "Delete",
- Handler: _Content_Delete_Handler,
- },
- {
- MethodName: "Status",
- Handler: _Content_Status_Handler,
- },
- {
- MethodName: "ListStatuses",
- Handler: _Content_ListStatuses_Handler,
- },
- {
- MethodName: "Abort",
- Handler: _Content_Abort_Handler,
- },
- },
- Streams: []grpc.StreamDesc{
- {
- StreamName: "List",
- Handler: _Content_List_Handler,
- ServerStreams: true,
- },
- {
- StreamName: "Read",
- Handler: _Content_Read_Handler,
- ServerStreams: true,
- },
- {
- StreamName: "Write",
- Handler: _Content_Write_Handler,
- ServerStreams: true,
- ClientStreams: true,
- },
- },
- Metadata: "github.com/containerd/containerd/api/services/content/v1/content.proto",
+// Deprecated: Use WriteContentResponse.ProtoReflect.Descriptor instead.
+func (*WriteContentResponse) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{16}
}
-func (m *Info) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
+func (x *WriteContentResponse) GetAction() WriteAction {
+ if x != nil {
+ return x.Action
}
- return dAtA[:n], nil
+ return WriteAction_STAT
}
-func (m *Info) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *Info) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Labels) > 0 {
- for k := range m.Labels {
- v := m.Labels[k]
- baseI := i
- i -= len(v)
- copy(dAtA[i:], v)
- i = encodeVarintContent(dAtA, i, uint64(len(v)))
- i--
- dAtA[i] = 0x12
- i -= len(k)
- copy(dAtA[i:], k)
- i = encodeVarintContent(dAtA, i, uint64(len(k)))
- i--
- dAtA[i] = 0xa
- i = encodeVarintContent(dAtA, i, uint64(baseI-i))
- i--
- dAtA[i] = 0x2a
- }
- }
- n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):])
- if err1 != nil {
- return 0, err1
- }
- i -= n1
- i = encodeVarintContent(dAtA, i, uint64(n1))
- i--
- dAtA[i] = 0x22
- n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):])
- if err2 != nil {
- return 0, err2
- }
- i -= n2
- i = encodeVarintContent(dAtA, i, uint64(n2))
- i--
- dAtA[i] = 0x1a
- if m.Size_ != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Size_))
- i--
- dAtA[i] = 0x10
- }
- if len(m.Digest) > 0 {
- i -= len(m.Digest)
- copy(dAtA[i:], m.Digest)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Digest)))
- i--
- dAtA[i] = 0xa
+func (x *WriteContentResponse) GetStartedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.StartedAt
}
- return len(dAtA) - i, nil
+ return nil
}
-func (m *InfoRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
+func (x *WriteContentResponse) GetUpdatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.UpdatedAt
}
- return dAtA[:n], nil
-}
-
-func (m *InfoRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
+ return nil
}
-func (m *InfoRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
+func (x *WriteContentResponse) GetOffset() int64 {
+ if x != nil {
+ return x.Offset
}
- if len(m.Digest) > 0 {
- i -= len(m.Digest)
- copy(dAtA[i:], m.Digest)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Digest)))
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
+ return 0
}
-func (m *InfoResponse) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
+func (x *WriteContentResponse) GetTotal() int64 {
+ if x != nil {
+ return x.Total
}
- return dAtA[:n], nil
-}
-
-func (m *InfoResponse) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
+ return 0
}
-func (m *InfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- {
- size, err := m.Info.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintContent(dAtA, i, uint64(size))
+func (x *WriteContentResponse) GetDigest() string {
+ if x != nil {
+ return x.Digest
}
- i--
- dAtA[i] = 0xa
- return len(dAtA) - i, nil
+ return ""
}
-func (m *UpdateRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
+type AbortRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
-func (m *UpdateRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
+ Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
}
-func (m *UpdateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if m.UpdateMask != nil {
- {
- size, err := m.UpdateMask.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintContent(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0x12
- }
- {
- size, err := m.Info.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintContent(dAtA, i, uint64(size))
+func (x *AbortRequest) Reset() {
+ *x = AbortRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
- i--
- dAtA[i] = 0xa
- return len(dAtA) - i, nil
}
-func (m *UpdateResponse) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
+func (x *AbortRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
}
-func (m *UpdateResponse) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
+func (*AbortRequest) ProtoMessage() {}
-func (m *UpdateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- {
- size, err := m.Info.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
+func (x *AbortRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[17]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
}
- i -= size
- i = encodeVarintContent(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0xa
- return len(dAtA) - i, nil
-}
-
-func (m *ListContentRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
+ return ms
}
- return dAtA[:n], nil
+ return mi.MessageOf(x)
}
-func (m *ListContentRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *ListContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Filters) > 0 {
- for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- {
- i -= len(m.Filters[iNdEx])
- copy(dAtA[i:], m.Filters[iNdEx])
- i = encodeVarintContent(dAtA, i, uint64(len(m.Filters[iNdEx])))
- i--
- dAtA[i] = 0xa
- }
- }
- return len(dAtA) - i, nil
+// Deprecated: Use AbortRequest.ProtoReflect.Descriptor instead.
+func (*AbortRequest) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *AbortRequest) GetRef() string {
+ if x != nil {
+ return x.Ref
+ }
+ return ""
+}
+
+var File_github_com_containerd_containerd_api_services_content_v1_content_proto protoreflect.FileDescriptor
+
+var file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDesc = []byte{
+ 0x0a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e,
+ 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+ 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f,
+ 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65,
+ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70,
+ 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xad, 0x02, 0x0a, 0x04, 0x49, 0x6e, 0x66,
+ 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x39, 0x0a,
+ 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
+ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+ 0x64, 0x41, 0x74, 0x12, 0x48, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64,
+ 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a,
+ 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+ 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x25, 0x0a, 0x0b, 0x49, 0x6e, 0x66, 0x6f,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73,
+ 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22,
+ 0x48, 0x0a, 0x0c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x38, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e,
+ 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
+ 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49,
+ 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x86, 0x01, 0x0a, 0x0d, 0x55, 0x70,
+ 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x69,
+ 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+ 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f,
+ 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65,
+ 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61,
+ 0x73, 0x6b, 0x22, 0x4a, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e,
+ 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x2e,
+ 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x4f,
+ 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64,
+ 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22,
+ 0x2e, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73,
+ 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22,
+ 0x58, 0x0a, 0x12, 0x52, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a,
+ 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f,
+ 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x41, 0x0a, 0x13, 0x52, 0x65, 0x61,
+ 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xda, 0x01, 0x0a,
+ 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74,
+ 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
+ 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64,
+ 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+ 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a,
+ 0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12,
+ 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
+ 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1a, 0x0a,
+ 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x21, 0x0a, 0x0d, 0x53, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65,
+ 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x22, 0x50, 0x0a, 0x0e,
+ 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e,
+ 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26,
+ 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e,
+ 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x2f,
+ 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73,
+ 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22,
+ 0x5a, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x22, 0xde, 0x02, 0x0a, 0x13,
+ 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64,
+ 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f,
+ 0x74, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c,
+ 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06,
+ 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66,
+ 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x57, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65,
+ 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61,
+ 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c,
+ 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+ 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x97, 0x02, 0x0a,
+ 0x14, 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x41, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74,
+ 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72,
+ 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
+ 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
+ 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61,
+ 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x16,
+ 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+ 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x20, 0x0a, 0x0c, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x2a, 0x2e, 0x0a, 0x0b, 0x57, 0x72, 0x69, 0x74,
+ 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x41, 0x54, 0x10,
+ 0x00, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x52, 0x49, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06,
+ 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x02, 0x32, 0xbe, 0x07, 0x0a, 0x07, 0x43, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x12, 0x61, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x63,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e,
+ 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e,
+ 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76,
+ 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x12, 0x71, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
+ 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x34, 0x2e,
+ 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
+ 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44,
+ 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x71, 0x0a, 0x04, 0x52,
+ 0x65, 0x61, 0x64, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64,
+ 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x67,
+ 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
+ 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x76, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x33, 0x2e, 0x63, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69,
+ 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x76,
+ 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x05, 0x41, 0x62,
+ 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64,
+ 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74,
+ 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70,
+ 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+ 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
-func (m *ListContentResponse) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
+var (
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescOnce sync.Once
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescData = file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDesc
+)
-func (m *ListContentResponse) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
+func file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescGZIP() []byte {
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescOnce.Do(func() {
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescData)
+ })
+ return file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDescData
+}
+
+var file_github_com_containerd_containerd_api_services_content_v1_content_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
+var file_github_com_containerd_containerd_api_services_content_v1_content_proto_goTypes = []interface{}{
+ (WriteAction)(0), // 0: containerd.services.content.v1.WriteAction
+ (*Info)(nil), // 1: containerd.services.content.v1.Info
+ (*InfoRequest)(nil), // 2: containerd.services.content.v1.InfoRequest
+ (*InfoResponse)(nil), // 3: containerd.services.content.v1.InfoResponse
+ (*UpdateRequest)(nil), // 4: containerd.services.content.v1.UpdateRequest
+ (*UpdateResponse)(nil), // 5: containerd.services.content.v1.UpdateResponse
+ (*ListContentRequest)(nil), // 6: containerd.services.content.v1.ListContentRequest
+ (*ListContentResponse)(nil), // 7: containerd.services.content.v1.ListContentResponse
+ (*DeleteContentRequest)(nil), // 8: containerd.services.content.v1.DeleteContentRequest
+ (*ReadContentRequest)(nil), // 9: containerd.services.content.v1.ReadContentRequest
+ (*ReadContentResponse)(nil), // 10: containerd.services.content.v1.ReadContentResponse
+ (*Status)(nil), // 11: containerd.services.content.v1.Status
+ (*StatusRequest)(nil), // 12: containerd.services.content.v1.StatusRequest
+ (*StatusResponse)(nil), // 13: containerd.services.content.v1.StatusResponse
+ (*ListStatusesRequest)(nil), // 14: containerd.services.content.v1.ListStatusesRequest
+ (*ListStatusesResponse)(nil), // 15: containerd.services.content.v1.ListStatusesResponse
+ (*WriteContentRequest)(nil), // 16: containerd.services.content.v1.WriteContentRequest
+ (*WriteContentResponse)(nil), // 17: containerd.services.content.v1.WriteContentResponse
+ (*AbortRequest)(nil), // 18: containerd.services.content.v1.AbortRequest
+ nil, // 19: containerd.services.content.v1.Info.LabelsEntry
+ nil, // 20: containerd.services.content.v1.WriteContentRequest.LabelsEntry
+ (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp
+ (*fieldmaskpb.FieldMask)(nil), // 22: google.protobuf.FieldMask
+ (*emptypb.Empty)(nil), // 23: google.protobuf.Empty
+}
+var file_github_com_containerd_containerd_api_services_content_v1_content_proto_depIdxs = []int32{
+ 21, // 0: containerd.services.content.v1.Info.created_at:type_name -> google.protobuf.Timestamp
+ 21, // 1: containerd.services.content.v1.Info.updated_at:type_name -> google.protobuf.Timestamp
+ 19, // 2: containerd.services.content.v1.Info.labels:type_name -> containerd.services.content.v1.Info.LabelsEntry
+ 1, // 3: containerd.services.content.v1.InfoResponse.info:type_name -> containerd.services.content.v1.Info
+ 1, // 4: containerd.services.content.v1.UpdateRequest.info:type_name -> containerd.services.content.v1.Info
+ 22, // 5: containerd.services.content.v1.UpdateRequest.update_mask:type_name -> google.protobuf.FieldMask
+ 1, // 6: containerd.services.content.v1.UpdateResponse.info:type_name -> containerd.services.content.v1.Info
+ 1, // 7: containerd.services.content.v1.ListContentResponse.info:type_name -> containerd.services.content.v1.Info
+ 21, // 8: containerd.services.content.v1.Status.started_at:type_name -> google.protobuf.Timestamp
+ 21, // 9: containerd.services.content.v1.Status.updated_at:type_name -> google.protobuf.Timestamp
+ 11, // 10: containerd.services.content.v1.StatusResponse.status:type_name -> containerd.services.content.v1.Status
+ 11, // 11: containerd.services.content.v1.ListStatusesResponse.statuses:type_name -> containerd.services.content.v1.Status
+ 0, // 12: containerd.services.content.v1.WriteContentRequest.action:type_name -> containerd.services.content.v1.WriteAction
+ 20, // 13: containerd.services.content.v1.WriteContentRequest.labels:type_name -> containerd.services.content.v1.WriteContentRequest.LabelsEntry
+ 0, // 14: containerd.services.content.v1.WriteContentResponse.action:type_name -> containerd.services.content.v1.WriteAction
+ 21, // 15: containerd.services.content.v1.WriteContentResponse.started_at:type_name -> google.protobuf.Timestamp
+ 21, // 16: containerd.services.content.v1.WriteContentResponse.updated_at:type_name -> google.protobuf.Timestamp
+ 2, // 17: containerd.services.content.v1.Content.Info:input_type -> containerd.services.content.v1.InfoRequest
+ 4, // 18: containerd.services.content.v1.Content.Update:input_type -> containerd.services.content.v1.UpdateRequest
+ 6, // 19: containerd.services.content.v1.Content.List:input_type -> containerd.services.content.v1.ListContentRequest
+ 8, // 20: containerd.services.content.v1.Content.Delete:input_type -> containerd.services.content.v1.DeleteContentRequest
+ 9, // 21: containerd.services.content.v1.Content.Read:input_type -> containerd.services.content.v1.ReadContentRequest
+ 12, // 22: containerd.services.content.v1.Content.Status:input_type -> containerd.services.content.v1.StatusRequest
+ 14, // 23: containerd.services.content.v1.Content.ListStatuses:input_type -> containerd.services.content.v1.ListStatusesRequest
+ 16, // 24: containerd.services.content.v1.Content.Write:input_type -> containerd.services.content.v1.WriteContentRequest
+ 18, // 25: containerd.services.content.v1.Content.Abort:input_type -> containerd.services.content.v1.AbortRequest
+ 3, // 26: containerd.services.content.v1.Content.Info:output_type -> containerd.services.content.v1.InfoResponse
+ 5, // 27: containerd.services.content.v1.Content.Update:output_type -> containerd.services.content.v1.UpdateResponse
+ 7, // 28: containerd.services.content.v1.Content.List:output_type -> containerd.services.content.v1.ListContentResponse
+ 23, // 29: containerd.services.content.v1.Content.Delete:output_type -> google.protobuf.Empty
+ 10, // 30: containerd.services.content.v1.Content.Read:output_type -> containerd.services.content.v1.ReadContentResponse
+ 13, // 31: containerd.services.content.v1.Content.Status:output_type -> containerd.services.content.v1.StatusResponse
+ 15, // 32: containerd.services.content.v1.Content.ListStatuses:output_type -> containerd.services.content.v1.ListStatusesResponse
+ 17, // 33: containerd.services.content.v1.Content.Write:output_type -> containerd.services.content.v1.WriteContentResponse
+ 23, // 34: containerd.services.content.v1.Content.Abort:output_type -> google.protobuf.Empty
+ 26, // [26:35] is the sub-list for method output_type
+ 17, // [17:26] is the sub-list for method input_type
+ 17, // [17:17] is the sub-list for extension type_name
+ 17, // [17:17] is the sub-list for extension extendee
+ 0, // [0:17] is the sub-list for field type_name
+}
+
+func init() { file_github_com_containerd_containerd_api_services_content_v1_content_proto_init() }
+func file_github_com_containerd_containerd_api_services_content_v1_content_proto_init() {
+ if File_github_com_containerd_containerd_api_services_content_v1_content_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Info); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InfoRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InfoResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UpdateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UpdateResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListContentRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListContentResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DeleteContentRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ReadContentRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ReadContentResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Status); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StatusRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StatusResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListStatusesRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListStatusesResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*WriteContentRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*WriteContentResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*AbortRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDesc,
+ NumEnums: 1,
+ NumMessages: 20,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_github_com_containerd_containerd_api_services_content_v1_content_proto_goTypes,
+ DependencyIndexes: file_github_com_containerd_containerd_api_services_content_v1_content_proto_depIdxs,
+ EnumInfos: file_github_com_containerd_containerd_api_services_content_v1_content_proto_enumTypes,
+ MessageInfos: file_github_com_containerd_containerd_api_services_content_v1_content_proto_msgTypes,
+ }.Build()
+ File_github_com_containerd_containerd_api_services_content_v1_content_proto = out.File
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_rawDesc = nil
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_goTypes = nil
+ file_github_com_containerd_containerd_api_services_content_v1_content_proto_depIdxs = nil
}
-
-func (m *ListContentResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Info) > 0 {
- for iNdEx := len(m.Info) - 1; iNdEx >= 0; iNdEx-- {
- {
- size, err := m.Info[iNdEx].MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintContent(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0xa
- }
- }
- return len(dAtA) - i, nil
-}
-
-func (m *DeleteContentRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *DeleteContentRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *DeleteContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Digest) > 0 {
- i -= len(m.Digest)
- copy(dAtA[i:], m.Digest)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Digest)))
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
-}
-
-func (m *ReadContentRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *ReadContentRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *ReadContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if m.Size_ != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Size_))
- i--
- dAtA[i] = 0x18
- }
- if m.Offset != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Offset))
- i--
- dAtA[i] = 0x10
- }
- if len(m.Digest) > 0 {
- i -= len(m.Digest)
- copy(dAtA[i:], m.Digest)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Digest)))
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
-}
-
-func (m *ReadContentResponse) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *ReadContentResponse) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *ReadContentResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Data) > 0 {
- i -= len(m.Data)
- copy(dAtA[i:], m.Data)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Data)))
- i--
- dAtA[i] = 0x12
- }
- if m.Offset != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Offset))
- i--
- dAtA[i] = 0x8
- }
- return len(dAtA) - i, nil
-}
-
-func (m *Status) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *Status) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *Status) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Expected) > 0 {
- i -= len(m.Expected)
- copy(dAtA[i:], m.Expected)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Expected)))
- i--
- dAtA[i] = 0x32
- }
- if m.Total != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Total))
- i--
- dAtA[i] = 0x28
- }
- if m.Offset != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Offset))
- i--
- dAtA[i] = 0x20
- }
- if len(m.Ref) > 0 {
- i -= len(m.Ref)
- copy(dAtA[i:], m.Ref)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Ref)))
- i--
- dAtA[i] = 0x1a
- }
- n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):])
- if err7 != nil {
- return 0, err7
- }
- i -= n7
- i = encodeVarintContent(dAtA, i, uint64(n7))
- i--
- dAtA[i] = 0x12
- n8, err8 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt):])
- if err8 != nil {
- return 0, err8
- }
- i -= n8
- i = encodeVarintContent(dAtA, i, uint64(n8))
- i--
- dAtA[i] = 0xa
- return len(dAtA) - i, nil
-}
-
-func (m *StatusRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *StatusRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *StatusRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Ref) > 0 {
- i -= len(m.Ref)
- copy(dAtA[i:], m.Ref)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Ref)))
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
-}
-
-func (m *StatusResponse) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *StatusResponse) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *StatusResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if m.Status != nil {
- {
- size, err := m.Status.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintContent(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
-}
-
-func (m *ListStatusesRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *ListStatusesRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *ListStatusesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Filters) > 0 {
- for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- {
- i -= len(m.Filters[iNdEx])
- copy(dAtA[i:], m.Filters[iNdEx])
- i = encodeVarintContent(dAtA, i, uint64(len(m.Filters[iNdEx])))
- i--
- dAtA[i] = 0xa
- }
- }
- return len(dAtA) - i, nil
-}
-
-func (m *ListStatusesResponse) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *ListStatusesResponse) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *ListStatusesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Statuses) > 0 {
- for iNdEx := len(m.Statuses) - 1; iNdEx >= 0; iNdEx-- {
- {
- size, err := m.Statuses[iNdEx].MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintContent(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0xa
- }
- }
- return len(dAtA) - i, nil
-}
-
-func (m *WriteContentRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *WriteContentRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *WriteContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Labels) > 0 {
- for k := range m.Labels {
- v := m.Labels[k]
- baseI := i
- i -= len(v)
- copy(dAtA[i:], v)
- i = encodeVarintContent(dAtA, i, uint64(len(v)))
- i--
- dAtA[i] = 0x12
- i -= len(k)
- copy(dAtA[i:], k)
- i = encodeVarintContent(dAtA, i, uint64(len(k)))
- i--
- dAtA[i] = 0xa
- i = encodeVarintContent(dAtA, i, uint64(baseI-i))
- i--
- dAtA[i] = 0x3a
- }
- }
- if len(m.Data) > 0 {
- i -= len(m.Data)
- copy(dAtA[i:], m.Data)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Data)))
- i--
- dAtA[i] = 0x32
- }
- if m.Offset != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Offset))
- i--
- dAtA[i] = 0x28
- }
- if len(m.Expected) > 0 {
- i -= len(m.Expected)
- copy(dAtA[i:], m.Expected)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Expected)))
- i--
- dAtA[i] = 0x22
- }
- if m.Total != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Total))
- i--
- dAtA[i] = 0x18
- }
- if len(m.Ref) > 0 {
- i -= len(m.Ref)
- copy(dAtA[i:], m.Ref)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Ref)))
- i--
- dAtA[i] = 0x12
- }
- if m.Action != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Action))
- i--
- dAtA[i] = 0x8
- }
- return len(dAtA) - i, nil
-}
-
-func (m *WriteContentResponse) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *WriteContentResponse) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *WriteContentResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Digest) > 0 {
- i -= len(m.Digest)
- copy(dAtA[i:], m.Digest)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Digest)))
- i--
- dAtA[i] = 0x32
- }
- if m.Total != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Total))
- i--
- dAtA[i] = 0x28
- }
- if m.Offset != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Offset))
- i--
- dAtA[i] = 0x20
- }
- n10, err10 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):])
- if err10 != nil {
- return 0, err10
- }
- i -= n10
- i = encodeVarintContent(dAtA, i, uint64(n10))
- i--
- dAtA[i] = 0x1a
- n11, err11 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt):])
- if err11 != nil {
- return 0, err11
- }
- i -= n11
- i = encodeVarintContent(dAtA, i, uint64(n11))
- i--
- dAtA[i] = 0x12
- if m.Action != 0 {
- i = encodeVarintContent(dAtA, i, uint64(m.Action))
- i--
- dAtA[i] = 0x8
- }
- return len(dAtA) - i, nil
-}
-
-func (m *AbortRequest) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *AbortRequest) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *AbortRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if len(m.Ref) > 0 {
- i -= len(m.Ref)
- copy(dAtA[i:], m.Ref)
- i = encodeVarintContent(dAtA, i, uint64(len(m.Ref)))
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
-}
-
-func encodeVarintContent(dAtA []byte, offset int, v uint64) int {
- offset -= sovContent(v)
- base := offset
- for v >= 1<<7 {
- dAtA[offset] = uint8(v&0x7f | 0x80)
- v >>= 7
- offset++
- }
- dAtA[offset] = uint8(v)
- return base
-}
-func (m *Info) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = len(m.Digest)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.Size_ != 0 {
- n += 1 + sovContent(uint64(m.Size_))
- }
- l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
- n += 1 + l + sovContent(uint64(l))
- l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
- n += 1 + l + sovContent(uint64(l))
- if len(m.Labels) > 0 {
- for k, v := range m.Labels {
- _ = k
- _ = v
- mapEntrySize := 1 + len(k) + sovContent(uint64(len(k))) + 1 + len(v) + sovContent(uint64(len(v)))
- n += mapEntrySize + 1 + sovContent(uint64(mapEntrySize))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *InfoRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = len(m.Digest)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *InfoResponse) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = m.Info.Size()
- n += 1 + l + sovContent(uint64(l))
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *UpdateRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = m.Info.Size()
- n += 1 + l + sovContent(uint64(l))
- if m.UpdateMask != nil {
- l = m.UpdateMask.Size()
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *UpdateResponse) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = m.Info.Size()
- n += 1 + l + sovContent(uint64(l))
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *ListContentRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if len(m.Filters) > 0 {
- for _, s := range m.Filters {
- l = len(s)
- n += 1 + l + sovContent(uint64(l))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *ListContentResponse) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if len(m.Info) > 0 {
- for _, e := range m.Info {
- l = e.Size()
- n += 1 + l + sovContent(uint64(l))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *DeleteContentRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = len(m.Digest)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *ReadContentRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = len(m.Digest)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.Offset != 0 {
- n += 1 + sovContent(uint64(m.Offset))
- }
- if m.Size_ != 0 {
- n += 1 + sovContent(uint64(m.Size_))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *ReadContentResponse) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.Offset != 0 {
- n += 1 + sovContent(uint64(m.Offset))
- }
- l = len(m.Data)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *Status) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
- n += 1 + l + sovContent(uint64(l))
- l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
- n += 1 + l + sovContent(uint64(l))
- l = len(m.Ref)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.Offset != 0 {
- n += 1 + sovContent(uint64(m.Offset))
- }
- if m.Total != 0 {
- n += 1 + sovContent(uint64(m.Total))
- }
- l = len(m.Expected)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *StatusRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = len(m.Ref)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *StatusResponse) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.Status != nil {
- l = m.Status.Size()
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *ListStatusesRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if len(m.Filters) > 0 {
- for _, s := range m.Filters {
- l = len(s)
- n += 1 + l + sovContent(uint64(l))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *ListStatusesResponse) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if len(m.Statuses) > 0 {
- for _, e := range m.Statuses {
- l = e.Size()
- n += 1 + l + sovContent(uint64(l))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *WriteContentRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.Action != 0 {
- n += 1 + sovContent(uint64(m.Action))
- }
- l = len(m.Ref)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.Total != 0 {
- n += 1 + sovContent(uint64(m.Total))
- }
- l = len(m.Expected)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.Offset != 0 {
- n += 1 + sovContent(uint64(m.Offset))
- }
- l = len(m.Data)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if len(m.Labels) > 0 {
- for k, v := range m.Labels {
- _ = k
- _ = v
- mapEntrySize := 1 + len(k) + sovContent(uint64(len(k))) + 1 + len(v) + sovContent(uint64(len(v)))
- n += mapEntrySize + 1 + sovContent(uint64(mapEntrySize))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *WriteContentResponse) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.Action != 0 {
- n += 1 + sovContent(uint64(m.Action))
- }
- l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
- n += 1 + l + sovContent(uint64(l))
- l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
- n += 1 + l + sovContent(uint64(l))
- if m.Offset != 0 {
- n += 1 + sovContent(uint64(m.Offset))
- }
- if m.Total != 0 {
- n += 1 + sovContent(uint64(m.Total))
- }
- l = len(m.Digest)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *AbortRequest) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- l = len(m.Ref)
- if l > 0 {
- n += 1 + l + sovContent(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func sovContent(x uint64) (n int) {
- return (math_bits.Len64(x|1) + 6) / 7
-}
-func sozContent(x uint64) (n int) {
- return sovContent(uint64((x << 1) ^ uint64((int64(x) >> 63))))
-}
-func (this *Info) String() string {
- if this == nil {
- return "nil"
- }
- keysForLabels := make([]string, 0, len(this.Labels))
- for k, _ := range this.Labels {
- keysForLabels = append(keysForLabels, k)
- }
- github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
- mapStringForLabels := "map[string]string{"
- for _, k := range keysForLabels {
- mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
- }
- mapStringForLabels += "}"
- s := strings.Join([]string{`&Info{`,
- `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`,
- `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`,
- `CreatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CreatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`,
- `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`,
- `Labels:` + mapStringForLabels + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *InfoRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&InfoRequest{`,
- `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *InfoResponse) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&InfoResponse{`,
- `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *UpdateRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&UpdateRequest{`,
- `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`,
- `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "types.FieldMask", 1) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *UpdateResponse) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&UpdateResponse{`,
- `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *ListContentRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&ListContentRequest{`,
- `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *ListContentResponse) String() string {
- if this == nil {
- return "nil"
- }
- repeatedStringForInfo := "[]Info{"
- for _, f := range this.Info {
- repeatedStringForInfo += strings.Replace(strings.Replace(f.String(), "Info", "Info", 1), `&`, ``, 1) + ","
- }
- repeatedStringForInfo += "}"
- s := strings.Join([]string{`&ListContentResponse{`,
- `Info:` + repeatedStringForInfo + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *DeleteContentRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&DeleteContentRequest{`,
- `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *ReadContentRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&ReadContentRequest{`,
- `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`,
- `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
- `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *ReadContentResponse) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&ReadContentResponse{`,
- `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
- `Data:` + fmt.Sprintf("%v", this.Data) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *Status) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&Status{`,
- `StartedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.StartedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`,
- `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`,
- `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
- `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
- `Total:` + fmt.Sprintf("%v", this.Total) + `,`,
- `Expected:` + fmt.Sprintf("%v", this.Expected) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *StatusRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&StatusRequest{`,
- `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *StatusResponse) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&StatusResponse{`,
- `Status:` + strings.Replace(this.Status.String(), "Status", "Status", 1) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *ListStatusesRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&ListStatusesRequest{`,
- `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *ListStatusesResponse) String() string {
- if this == nil {
- return "nil"
- }
- repeatedStringForStatuses := "[]Status{"
- for _, f := range this.Statuses {
- repeatedStringForStatuses += strings.Replace(strings.Replace(f.String(), "Status", "Status", 1), `&`, ``, 1) + ","
- }
- repeatedStringForStatuses += "}"
- s := strings.Join([]string{`&ListStatusesResponse{`,
- `Statuses:` + repeatedStringForStatuses + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *WriteContentRequest) String() string {
- if this == nil {
- return "nil"
- }
- keysForLabels := make([]string, 0, len(this.Labels))
- for k, _ := range this.Labels {
- keysForLabels = append(keysForLabels, k)
- }
- github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
- mapStringForLabels := "map[string]string{"
- for _, k := range keysForLabels {
- mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
- }
- mapStringForLabels += "}"
- s := strings.Join([]string{`&WriteContentRequest{`,
- `Action:` + fmt.Sprintf("%v", this.Action) + `,`,
- `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
- `Total:` + fmt.Sprintf("%v", this.Total) + `,`,
- `Expected:` + fmt.Sprintf("%v", this.Expected) + `,`,
- `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
- `Data:` + fmt.Sprintf("%v", this.Data) + `,`,
- `Labels:` + mapStringForLabels + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *WriteContentResponse) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&WriteContentResponse{`,
- `Action:` + fmt.Sprintf("%v", this.Action) + `,`,
- `StartedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.StartedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`,
- `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`,
- `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
- `Total:` + fmt.Sprintf("%v", this.Total) + `,`,
- `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func (this *AbortRequest) String() string {
- if this == nil {
- return "nil"
- }
- s := strings.Join([]string{`&AbortRequest{`,
- `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
- `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
- `}`,
- }, "")
- return s
-}
-func valueToStringContent(v interface{}) string {
- rv := reflect.ValueOf(v)
- if rv.IsNil() {
- return "nil"
- }
- pv := reflect.Indirect(rv).Interface()
- return fmt.Sprintf("*%v", pv)
-}
-func (m *Info) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Info: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Info: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- case 2:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType)
- }
- m.Size_ = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Size_ |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 3:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 4:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 5:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Labels == nil {
- m.Labels = make(map[string]string)
- }
- var mapkey string
- var mapvalue string
- for iNdEx < postIndex {
- entryPreIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- if fieldNum == 1 {
- var stringLenmapkey uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLenmapkey |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLenmapkey := int(stringLenmapkey)
- if intStringLenmapkey < 0 {
- return ErrInvalidLengthContent
- }
- postStringIndexmapkey := iNdEx + intStringLenmapkey
- if postStringIndexmapkey < 0 {
- return ErrInvalidLengthContent
- }
- if postStringIndexmapkey > l {
- return io.ErrUnexpectedEOF
- }
- mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
- iNdEx = postStringIndexmapkey
- } else if fieldNum == 2 {
- var stringLenmapvalue uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLenmapvalue |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLenmapvalue := int(stringLenmapvalue)
- if intStringLenmapvalue < 0 {
- return ErrInvalidLengthContent
- }
- postStringIndexmapvalue := iNdEx + intStringLenmapvalue
- if postStringIndexmapvalue < 0 {
- return ErrInvalidLengthContent
- }
- if postStringIndexmapvalue > l {
- return io.ErrUnexpectedEOF
- }
- mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
- iNdEx = postStringIndexmapvalue
- } else {
- iNdEx = entryPreIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > postIndex {
- return io.ErrUnexpectedEOF
- }
- iNdEx += skippy
- }
- }
- m.Labels[mapkey] = mapvalue
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *InfoRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: InfoRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: InfoRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *InfoResponse) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: InfoResponse: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: InfoResponse: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *UpdateRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: UpdateRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: UpdateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 2:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field UpdateMask", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.UpdateMask == nil {
- m.UpdateMask = &types.FieldMask{}
- }
- if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *UpdateResponse) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: UpdateResponse: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: UpdateResponse: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *ListContentRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: ListContentRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: ListContentRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex]))
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *ListContentResponse) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: ListContentResponse: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: ListContentResponse: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Info = append(m.Info, Info{})
- if err := m.Info[len(m.Info)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *DeleteContentRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: DeleteContentRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: DeleteContentRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *ReadContentRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: ReadContentRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: ReadContentRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- case 2:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
- }
- m.Offset = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Offset |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 3:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType)
- }
- m.Size_ = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Size_ |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *ReadContentResponse) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: ReadContentResponse: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: ReadContentResponse: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
- }
- m.Offset = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Offset |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 2:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
- }
- var byteLen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- byteLen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if byteLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + byteLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
- if m.Data == nil {
- m.Data = []byte{}
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *Status) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Status: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Status: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 2:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 3:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Ref = string(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- case 4:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
- }
- m.Offset = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Offset |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 5:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType)
- }
- m.Total = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Total |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 6:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Expected", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Expected = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *StatusRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: StatusRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: StatusRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Ref = string(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *StatusResponse) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: StatusResponse: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: StatusResponse: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Status == nil {
- m.Status = &Status{}
- }
- if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *ListStatusesRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: ListStatusesRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: ListStatusesRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex]))
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *ListStatusesResponse) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: ListStatusesResponse: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: ListStatusesResponse: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Statuses", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Statuses = append(m.Statuses, Status{})
- if err := m.Statuses[len(m.Statuses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *WriteContentRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: WriteContentRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: WriteContentRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType)
- }
- m.Action = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Action |= WriteAction(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 2:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Ref = string(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- case 3:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType)
- }
- m.Total = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Total |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 4:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Expected", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Expected = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- case 5:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
- }
- m.Offset = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Offset |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 6:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
- }
- var byteLen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- byteLen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if byteLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + byteLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
- if m.Data == nil {
- m.Data = []byte{}
- }
- iNdEx = postIndex
- case 7:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Labels == nil {
- m.Labels = make(map[string]string)
- }
- var mapkey string
- var mapvalue string
- for iNdEx < postIndex {
- entryPreIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- if fieldNum == 1 {
- var stringLenmapkey uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLenmapkey |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLenmapkey := int(stringLenmapkey)
- if intStringLenmapkey < 0 {
- return ErrInvalidLengthContent
- }
- postStringIndexmapkey := iNdEx + intStringLenmapkey
- if postStringIndexmapkey < 0 {
- return ErrInvalidLengthContent
- }
- if postStringIndexmapkey > l {
- return io.ErrUnexpectedEOF
- }
- mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
- iNdEx = postStringIndexmapkey
- } else if fieldNum == 2 {
- var stringLenmapvalue uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLenmapvalue |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLenmapvalue := int(stringLenmapvalue)
- if intStringLenmapvalue < 0 {
- return ErrInvalidLengthContent
- }
- postStringIndexmapvalue := iNdEx + intStringLenmapvalue
- if postStringIndexmapvalue < 0 {
- return ErrInvalidLengthContent
- }
- if postStringIndexmapvalue > l {
- return io.ErrUnexpectedEOF
- }
- mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
- iNdEx = postStringIndexmapvalue
- } else {
- iNdEx = entryPreIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > postIndex {
- return io.ErrUnexpectedEOF
- }
- iNdEx += skippy
- }
- }
- m.Labels[mapkey] = mapvalue
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *WriteContentResponse) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: WriteContentResponse: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: WriteContentResponse: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType)
- }
- m.Action = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Action |= WriteAction(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 2:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 3:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 4:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
- }
- m.Offset = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Offset |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 5:
- if wireType != 0 {
- return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType)
- }
- m.Total = 0
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- m.Total |= int64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- case 6:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *AbortRequest) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: AbortRequest: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: AbortRequest: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
- }
- var stringLen uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowContent
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- stringLen |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- intStringLen := int(stringLen)
- if intStringLen < 0 {
- return ErrInvalidLengthContent
- }
- postIndex := iNdEx + intStringLen
- if postIndex < 0 {
- return ErrInvalidLengthContent
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.Ref = string(dAtA[iNdEx:postIndex])
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipContent(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthContent
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func skipContent(dAtA []byte) (n int, err error) {
- l := len(dAtA)
- iNdEx := 0
- depth := 0
- for iNdEx < l {
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return 0, ErrIntOverflowContent
- }
- if iNdEx >= l {
- return 0, io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= (uint64(b) & 0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- wireType := int(wire & 0x7)
- switch wireType {
- case 0:
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return 0, ErrIntOverflowContent
- }
- if iNdEx >= l {
- return 0, io.ErrUnexpectedEOF
- }
- iNdEx++
- if dAtA[iNdEx-1] < 0x80 {
- break
- }
- }
- case 1:
- iNdEx += 8
- case 2:
- var length int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return 0, ErrIntOverflowContent
- }
- if iNdEx >= l {
- return 0, io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- length |= (int(b) & 0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if length < 0 {
- return 0, ErrInvalidLengthContent
- }
- iNdEx += length
- case 3:
- depth++
- case 4:
- if depth == 0 {
- return 0, ErrUnexpectedEndOfGroupContent
- }
- depth--
- case 5:
- iNdEx += 4
- default:
- return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
- }
- if iNdEx < 0 {
- return 0, ErrInvalidLengthContent
- }
- if depth == 0 {
- return iNdEx, nil
- }
- }
- return 0, io.ErrUnexpectedEOF
-}
-
-var (
- ErrInvalidLengthContent = fmt.Errorf("proto: negative length found during unmarshaling")
- ErrIntOverflowContent = fmt.Errorf("proto: integer overflow")
- ErrUnexpectedEndOfGroupContent = fmt.Errorf("proto: unexpected end of group")
-)
diff --git a/vendor/github.com/containerd/containerd/api/services/content/v1/content.proto b/vendor/github.com/containerd/containerd/api/services/content/v1/content.proto
index b33ea5b2e8..8aea0636b8 100644
--- a/vendor/github.com/containerd/containerd/api/services/content/v1/content.proto
+++ b/vendor/github.com/containerd/containerd/api/services/content/v1/content.proto
@@ -18,7 +18,6 @@ syntax = "proto3";
package containerd.services.content.v1;
-import weak "gogoproto/gogo.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
@@ -92,16 +91,16 @@ service Content {
message Info {
// Digest is the hash identity of the blob.
- string digest = 1 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
+ string digest = 1;
// Size is the total number of bytes in the blob.
int64 size = 2;
// CreatedAt provides the time at which the blob was committed.
- google.protobuf.Timestamp created_at = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+ google.protobuf.Timestamp created_at = 3;
// UpdatedAt provides the time the info was last updated.
- google.protobuf.Timestamp updated_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+ google.protobuf.Timestamp updated_at = 4;
// Labels are arbitrary data on snapshots.
//
@@ -110,15 +109,15 @@ message Info {
}
message InfoRequest {
- string digest = 1 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
+ string digest = 1;
}
message InfoResponse {
- Info info = 1 [(gogoproto.nullable) = false];
+ Info info = 1;
}
message UpdateRequest {
- Info info = 1 [(gogoproto.nullable) = false];
+ Info info = 1;
// UpdateMask specifies which fields to perform the update on. If empty,
// the operation applies to all fields.
@@ -130,7 +129,7 @@ message UpdateRequest {
}
message UpdateResponse {
- Info info = 1 [(gogoproto.nullable) = false];
+ Info info = 1;
}
message ListContentRequest {
@@ -141,26 +140,26 @@ message ListContentRequest {
// filters. Expanded, containers that match the following will be
// returned:
//
- // filters[0] or filters[1] or ... or filters[n-1] or filters[n]
+ // filters[0] or filters[1] or ... or filters[n-1] or filters[n]
//
// If filters is zero-length or nil, all items will be returned.
repeated string filters = 1;
}
message ListContentResponse {
- repeated Info info = 1 [(gogoproto.nullable) = false];
+ repeated Info info = 1;
}
message DeleteContentRequest {
// Digest specifies which content to delete.
- string digest = 1 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
+ string digest = 1;
}
// ReadContentRequest defines the fields that make up a request to read a portion of
// data from a stored object.
message ReadContentRequest {
// Digest is the hash identity to read.
- string digest = 1 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
+ string digest = 1;
// Offset specifies the number of bytes from the start at which to begin
// the read. If zero or less, the read will be from the start. This uses
@@ -179,12 +178,12 @@ message ReadContentResponse {
}
message Status {
- google.protobuf.Timestamp started_at = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
- google.protobuf.Timestamp updated_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+ google.protobuf.Timestamp started_at = 1;
+ google.protobuf.Timestamp updated_at = 2;
string ref = 3;
int64 offset = 4;
int64 total = 5;
- string expected = 6 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
+ string expected = 6;
}
@@ -201,17 +200,14 @@ message ListStatusesRequest {
}
message ListStatusesResponse {
- repeated Status statuses = 1 [(gogoproto.nullable) = false];
+ repeated Status statuses = 1;
}
// WriteAction defines the behavior of a WriteRequest.
enum WriteAction {
- option (gogoproto.goproto_enum_prefix) = false;
- option (gogoproto.enum_customname) = "WriteAction";
-
// WriteActionStat instructs the writer to return the current status while
// holding the lock on the write.
- STAT = 0 [(gogoproto.enumvalue_customname) = "WriteActionStat"];
+ STAT = 0;
// WriteActionWrite sets the action for the write request to write data.
//
@@ -219,7 +215,7 @@ enum WriteAction {
// transaction will be left open for further writes.
//
// This is the default.
- WRITE = 1 [(gogoproto.enumvalue_customname) = "WriteActionWrite"];
+ WRITE = 1;
// WriteActionCommit will write any outstanding data in the message and
// commit the write, storing it under the digest.
@@ -228,7 +224,7 @@ enum WriteAction {
// commit it.
//
// This action will always terminate the write.
- COMMIT = 2 [(gogoproto.enumvalue_customname) = "WriteActionCommit"];
+ COMMIT = 2;
}
// WriteContentRequest writes data to the request ref at offset.
@@ -269,7 +265,7 @@ message WriteContentRequest {
// Only the latest version will be used to check the content against the
// digest. It is only required to include it on a single message, before or
// with the commit action message.
- string expected = 4 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
+ string expected = 4;
// Offset specifies the number of bytes from the start at which to begin
// the write. For most implementations, this means from the start of the
@@ -304,13 +300,13 @@ message WriteContentResponse {
//
// This must be set for stat and commit write actions. All other write
// actions may omit this.
- google.protobuf.Timestamp started_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+ google.protobuf.Timestamp started_at = 2;
// UpdatedAt provides the last time of a successful write.
//
// This must be set for stat and commit write actions. All other write
// actions may omit this.
- google.protobuf.Timestamp updated_at = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+ google.protobuf.Timestamp updated_at = 3;
// Offset is the current committed size for the write.
int64 offset = 4;
@@ -326,7 +322,7 @@ message WriteContentResponse {
// Digest, if present, includes the digest up to the currently committed
// bytes. If action is commit, this field will be set. It is implementation
// defined if this is set for other actions.
- string digest = 6 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
+ string digest = 6;
}
message AbortRequest {
diff --git a/vendor/github.com/containerd/containerd/api/services/content/v1/content_grpc.pb.go b/vendor/github.com/containerd/containerd/api/services/content/v1/content_grpc.pb.go
new file mode 100644
index 0000000000..68efff90e1
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/api/services/content/v1/content_grpc.pb.go
@@ -0,0 +1,571 @@
+//go:build !no_grpc
+
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc v3.20.1
+// source: github.com/containerd/containerd/api/services/content/v1/content.proto
+
+package content
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// ContentClient is the client API for Content service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type ContentClient interface {
+ // Info returns information about a committed object.
+ //
+ // This call can be used for getting the size of content and checking for
+ // existence.
+ Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error)
+ // Update updates content metadata.
+ //
+ // This call can be used to manage the mutable content labels. The
+ // immutable metadata such as digest, size, and committed at cannot
+ // be updated.
+ Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*UpdateResponse, error)
+ // List streams the entire set of content as Info objects and closes the
+ // stream.
+ //
+ // Typically, this will yield a large response, chunked into messages.
+ // Clients should make provisions to ensure they can handle the entire data
+ // set.
+ List(ctx context.Context, in *ListContentRequest, opts ...grpc.CallOption) (Content_ListClient, error)
+ // Delete will delete the referenced object.
+ Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Read allows one to read an object based on the offset into the content.
+ //
+ // The requested data may be returned in one or more messages.
+ Read(ctx context.Context, in *ReadContentRequest, opts ...grpc.CallOption) (Content_ReadClient, error)
+ // Status returns the status for a single reference.
+ Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
+ // ListStatuses returns the status of ongoing object ingestions, started via
+ // Write.
+ //
+ // Only those matching the regular expression will be provided in the
+ // response. If the provided regular expression is empty, all ingestions
+ // will be provided.
+ ListStatuses(ctx context.Context, in *ListStatusesRequest, opts ...grpc.CallOption) (*ListStatusesResponse, error)
+ // Write begins or resumes writes to a resource identified by a unique ref.
+ // Only one active stream may exist at a time for each ref.
+ //
+ // Once a write stream has started, it may only write to a single ref, thus
+ // once a stream is started, the ref may be omitted on subsequent writes.
+ //
+ // For any write transaction represented by a ref, only a single write may
+ // be made to a given offset. If overlapping writes occur, it is an error.
+ // Writes should be sequential and implementations may throw an error if
+ // this is required.
+ //
+ // If expected_digest is set and already part of the content store, the
+ // write will fail.
+ //
+ // When completed, the commit flag should be set to true. If expected size
+ // or digest is set, the content will be validated against those values.
+ Write(ctx context.Context, opts ...grpc.CallOption) (Content_WriteClient, error)
+ // Abort cancels the ongoing write named in the request. Any resources
+ // associated with the write will be collected.
+ Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+}
+
+type contentClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewContentClient(cc grpc.ClientConnInterface) ContentClient {
+ return &contentClient{cc}
+}
+
+func (c *contentClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) {
+ out := new(InfoResponse)
+ err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Info", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *contentClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*UpdateResponse, error) {
+ out := new(UpdateResponse)
+ err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Update", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *contentClient) List(ctx context.Context, in *ListContentRequest, opts ...grpc.CallOption) (Content_ListClient, error) {
+ stream, err := c.cc.NewStream(ctx, &Content_ServiceDesc.Streams[0], "/containerd.services.content.v1.Content/List", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &contentListClient{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil {
+ return nil, err
+ }
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ return x, nil
+}
+
+type Content_ListClient interface {
+ Recv() (*ListContentResponse, error)
+ grpc.ClientStream
+}
+
+type contentListClient struct {
+ grpc.ClientStream
+}
+
+func (x *contentListClient) Recv() (*ListContentResponse, error) {
+ m := new(ListContentResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *contentClient) Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Delete", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *contentClient) Read(ctx context.Context, in *ReadContentRequest, opts ...grpc.CallOption) (Content_ReadClient, error) {
+ stream, err := c.cc.NewStream(ctx, &Content_ServiceDesc.Streams[1], "/containerd.services.content.v1.Content/Read", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &contentReadClient{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil {
+ return nil, err
+ }
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ return x, nil
+}
+
+type Content_ReadClient interface {
+ Recv() (*ReadContentResponse, error)
+ grpc.ClientStream
+}
+
+type contentReadClient struct {
+ grpc.ClientStream
+}
+
+func (x *contentReadClient) Recv() (*ReadContentResponse, error) {
+ m := new(ReadContentResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *contentClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) {
+ out := new(StatusResponse)
+ err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Status", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *contentClient) ListStatuses(ctx context.Context, in *ListStatusesRequest, opts ...grpc.CallOption) (*ListStatusesResponse, error) {
+ out := new(ListStatusesResponse)
+ err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/ListStatuses", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *contentClient) Write(ctx context.Context, opts ...grpc.CallOption) (Content_WriteClient, error) {
+ stream, err := c.cc.NewStream(ctx, &Content_ServiceDesc.Streams[2], "/containerd.services.content.v1.Content/Write", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &contentWriteClient{stream}
+ return x, nil
+}
+
+type Content_WriteClient interface {
+ Send(*WriteContentRequest) error
+ Recv() (*WriteContentResponse, error)
+ grpc.ClientStream
+}
+
+type contentWriteClient struct {
+ grpc.ClientStream
+}
+
+func (x *contentWriteClient) Send(m *WriteContentRequest) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *contentWriteClient) Recv() (*WriteContentResponse, error) {
+ m := new(WriteContentResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *contentClient) Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Abort", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// ContentServer is the server API for Content service.
+// All implementations must embed UnimplementedContentServer
+// for forward compatibility
+type ContentServer interface {
+ // Info returns information about a committed object.
+ //
+ // This call can be used for getting the size of content and checking for
+ // existence.
+ Info(context.Context, *InfoRequest) (*InfoResponse, error)
+ // Update updates content metadata.
+ //
+ // This call can be used to manage the mutable content labels. The
+ // immutable metadata such as digest, size, and committed at cannot
+ // be updated.
+ Update(context.Context, *UpdateRequest) (*UpdateResponse, error)
+ // List streams the entire set of content as Info objects and closes the
+ // stream.
+ //
+ // Typically, this will yield a large response, chunked into messages.
+ // Clients should make provisions to ensure they can handle the entire data
+ // set.
+ List(*ListContentRequest, Content_ListServer) error
+ // Delete will delete the referenced object.
+ Delete(context.Context, *DeleteContentRequest) (*emptypb.Empty, error)
+ // Read allows one to read an object based on the offset into the content.
+ //
+ // The requested data may be returned in one or more messages.
+ Read(*ReadContentRequest, Content_ReadServer) error
+ // Status returns the status for a single reference.
+ Status(context.Context, *StatusRequest) (*StatusResponse, error)
+ // ListStatuses returns the status of ongoing object ingestions, started via
+ // Write.
+ //
+ // Only those matching the regular expression will be provided in the
+ // response. If the provided regular expression is empty, all ingestions
+ // will be provided.
+ ListStatuses(context.Context, *ListStatusesRequest) (*ListStatusesResponse, error)
+ // Write begins or resumes writes to a resource identified by a unique ref.
+ // Only one active stream may exist at a time for each ref.
+ //
+ // Once a write stream has started, it may only write to a single ref, thus
+ // once a stream is started, the ref may be omitted on subsequent writes.
+ //
+ // For any write transaction represented by a ref, only a single write may
+ // be made to a given offset. If overlapping writes occur, it is an error.
+ // Writes should be sequential and implementations may throw an error if
+ // this is required.
+ //
+ // If expected_digest is set and already part of the content store, the
+ // write will fail.
+ //
+ // When completed, the commit flag should be set to true. If expected size
+ // or digest is set, the content will be validated against those values.
+ Write(Content_WriteServer) error
+ // Abort cancels the ongoing write named in the request. Any resources
+ // associated with the write will be collected.
+ Abort(context.Context, *AbortRequest) (*emptypb.Empty, error)
+ mustEmbedUnimplementedContentServer()
+}
+
+// UnimplementedContentServer must be embedded to have forward compatible implementations.
+type UnimplementedContentServer struct {
+}
+
+func (UnimplementedContentServer) Info(context.Context, *InfoRequest) (*InfoResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Info not implemented")
+}
+func (UnimplementedContentServer) Update(context.Context, *UpdateRequest) (*UpdateResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Update not implemented")
+}
+func (UnimplementedContentServer) List(*ListContentRequest, Content_ListServer) error {
+ return status.Errorf(codes.Unimplemented, "method List not implemented")
+}
+func (UnimplementedContentServer) Delete(context.Context, *DeleteContentRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
+}
+func (UnimplementedContentServer) Read(*ReadContentRequest, Content_ReadServer) error {
+ return status.Errorf(codes.Unimplemented, "method Read not implemented")
+}
+func (UnimplementedContentServer) Status(context.Context, *StatusRequest) (*StatusResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Status not implemented")
+}
+func (UnimplementedContentServer) ListStatuses(context.Context, *ListStatusesRequest) (*ListStatusesResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ListStatuses not implemented")
+}
+func (UnimplementedContentServer) Write(Content_WriteServer) error {
+ return status.Errorf(codes.Unimplemented, "method Write not implemented")
+}
+func (UnimplementedContentServer) Abort(context.Context, *AbortRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Abort not implemented")
+}
+func (UnimplementedContentServer) mustEmbedUnimplementedContentServer() {}
+
+// UnsafeContentServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to ContentServer will
+// result in compilation errors.
+type UnsafeContentServer interface {
+ mustEmbedUnimplementedContentServer()
+}
+
+func RegisterContentServer(s grpc.ServiceRegistrar, srv ContentServer) {
+ s.RegisterService(&Content_ServiceDesc, srv)
+}
+
+func _Content_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InfoRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ContentServer).Info(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/containerd.services.content.v1.Content/Info",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ContentServer).Info(ctx, req.(*InfoRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Content_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ContentServer).Update(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/containerd.services.content.v1.Content/Update",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ContentServer).Update(ctx, req.(*UpdateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Content_List_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(ListContentRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(ContentServer).List(m, &contentListServer{stream})
+}
+
+type Content_ListServer interface {
+ Send(*ListContentResponse) error
+ grpc.ServerStream
+}
+
+type contentListServer struct {
+ grpc.ServerStream
+}
+
+func (x *contentListServer) Send(m *ListContentResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func _Content_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteContentRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ContentServer).Delete(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/containerd.services.content.v1.Content/Delete",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ContentServer).Delete(ctx, req.(*DeleteContentRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Content_Read_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(ReadContentRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(ContentServer).Read(m, &contentReadServer{stream})
+}
+
+type Content_ReadServer interface {
+ Send(*ReadContentResponse) error
+ grpc.ServerStream
+}
+
+type contentReadServer struct {
+ grpc.ServerStream
+}
+
+func (x *contentReadServer) Send(m *ReadContentResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func _Content_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(StatusRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ContentServer).Status(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/containerd.services.content.v1.Content/Status",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ContentServer).Status(ctx, req.(*StatusRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Content_ListStatuses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListStatusesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ContentServer).ListStatuses(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/containerd.services.content.v1.Content/ListStatuses",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ContentServer).ListStatuses(ctx, req.(*ListStatusesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Content_Write_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(ContentServer).Write(&contentWriteServer{stream})
+}
+
+type Content_WriteServer interface {
+ Send(*WriteContentResponse) error
+ Recv() (*WriteContentRequest, error)
+ grpc.ServerStream
+}
+
+type contentWriteServer struct {
+ grpc.ServerStream
+}
+
+func (x *contentWriteServer) Send(m *WriteContentResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *contentWriteServer) Recv() (*WriteContentRequest, error) {
+ m := new(WriteContentRequest)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func _Content_Abort_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(AbortRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(ContentServer).Abort(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/containerd.services.content.v1.Content/Abort",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(ContentServer).Abort(ctx, req.(*AbortRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// Content_ServiceDesc is the grpc.ServiceDesc for Content service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Content_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "containerd.services.content.v1.Content",
+ HandlerType: (*ContentServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Info",
+ Handler: _Content_Info_Handler,
+ },
+ {
+ MethodName: "Update",
+ Handler: _Content_Update_Handler,
+ },
+ {
+ MethodName: "Delete",
+ Handler: _Content_Delete_Handler,
+ },
+ {
+ MethodName: "Status",
+ Handler: _Content_Status_Handler,
+ },
+ {
+ MethodName: "ListStatuses",
+ Handler: _Content_ListStatuses_Handler,
+ },
+ {
+ MethodName: "Abort",
+ Handler: _Content_Abort_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "List",
+ Handler: _Content_List_Handler,
+ ServerStreams: true,
+ },
+ {
+ StreamName: "Read",
+ Handler: _Content_Read_Handler,
+ ServerStreams: true,
+ },
+ {
+ StreamName: "Write",
+ Handler: _Content_Write_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ },
+ Metadata: "github.com/containerd/containerd/api/services/content/v1/content.proto",
+}
diff --git a/vendor/github.com/containerd/containerd/api/services/content/v1/content_ttrpc.pb.go b/vendor/github.com/containerd/containerd/api/services/content/v1/content_ttrpc.pb.go
new file mode 100644
index 0000000000..efa241a2b2
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/api/services/content/v1/content_ttrpc.pb.go
@@ -0,0 +1,311 @@
+// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT.
+// source: github.com/containerd/containerd/api/services/content/v1/content.proto
+package content
+
+import (
+ context "context"
+ ttrpc "github.com/containerd/ttrpc"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+type TTRPCContentService interface {
+ Info(context.Context, *InfoRequest) (*InfoResponse, error)
+ Update(context.Context, *UpdateRequest) (*UpdateResponse, error)
+ List(context.Context, *ListContentRequest, TTRPCContent_ListServer) error
+ Delete(context.Context, *DeleteContentRequest) (*emptypb.Empty, error)
+ Read(context.Context, *ReadContentRequest, TTRPCContent_ReadServer) error
+ Status(context.Context, *StatusRequest) (*StatusResponse, error)
+ ListStatuses(context.Context, *ListStatusesRequest) (*ListStatusesResponse, error)
+ Write(context.Context, TTRPCContent_WriteServer) error
+ Abort(context.Context, *AbortRequest) (*emptypb.Empty, error)
+}
+
+type TTRPCContent_ListServer interface {
+ Send(*ListContentResponse) error
+ ttrpc.StreamServer
+}
+
+type ttrpccontentListServer struct {
+ ttrpc.StreamServer
+}
+
+func (x *ttrpccontentListServer) Send(m *ListContentResponse) error {
+ return x.StreamServer.SendMsg(m)
+}
+
+type TTRPCContent_ReadServer interface {
+ Send(*ReadContentResponse) error
+ ttrpc.StreamServer
+}
+
+type ttrpccontentReadServer struct {
+ ttrpc.StreamServer
+}
+
+func (x *ttrpccontentReadServer) Send(m *ReadContentResponse) error {
+ return x.StreamServer.SendMsg(m)
+}
+
+type TTRPCContent_WriteServer interface {
+ Send(*WriteContentResponse) error
+ Recv() (*WriteContentRequest, error)
+ ttrpc.StreamServer
+}
+
+type ttrpccontentWriteServer struct {
+ ttrpc.StreamServer
+}
+
+func (x *ttrpccontentWriteServer) Send(m *WriteContentResponse) error {
+ return x.StreamServer.SendMsg(m)
+}
+
+func (x *ttrpccontentWriteServer) Recv() (*WriteContentRequest, error) {
+ m := new(WriteContentRequest)
+ if err := x.StreamServer.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func RegisterTTRPCContentService(srv *ttrpc.Server, svc TTRPCContentService) {
+ srv.RegisterService("containerd.services.content.v1.Content", &ttrpc.ServiceDesc{
+ Methods: map[string]ttrpc.Method{
+ "Info": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
+ var req InfoRequest
+ if err := unmarshal(&req); err != nil {
+ return nil, err
+ }
+ return svc.Info(ctx, &req)
+ },
+ "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
+ var req UpdateRequest
+ if err := unmarshal(&req); err != nil {
+ return nil, err
+ }
+ return svc.Update(ctx, &req)
+ },
+ "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
+ var req DeleteContentRequest
+ if err := unmarshal(&req); err != nil {
+ return nil, err
+ }
+ return svc.Delete(ctx, &req)
+ },
+ "Status": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
+ var req StatusRequest
+ if err := unmarshal(&req); err != nil {
+ return nil, err
+ }
+ return svc.Status(ctx, &req)
+ },
+ "ListStatuses": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
+ var req ListStatusesRequest
+ if err := unmarshal(&req); err != nil {
+ return nil, err
+ }
+ return svc.ListStatuses(ctx, &req)
+ },
+ "Abort": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
+ var req AbortRequest
+ if err := unmarshal(&req); err != nil {
+ return nil, err
+ }
+ return svc.Abort(ctx, &req)
+ },
+ },
+ Streams: map[string]ttrpc.Stream{
+ "List": {
+ Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) {
+ m := new(ListContentRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return nil, svc.List(ctx, m, &ttrpccontentListServer{stream})
+ },
+ StreamingClient: false,
+ StreamingServer: true,
+ },
+ "Read": {
+ Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) {
+ m := new(ReadContentRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return nil, svc.Read(ctx, m, &ttrpccontentReadServer{stream})
+ },
+ StreamingClient: false,
+ StreamingServer: true,
+ },
+ "Write": {
+ Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) {
+ return nil, svc.Write(ctx, &ttrpccontentWriteServer{stream})
+ },
+ StreamingClient: true,
+ StreamingServer: true,
+ },
+ },
+ })
+}
+
+type TTRPCContentClient interface {
+ Info(context.Context, *InfoRequest) (*InfoResponse, error)
+ Update(context.Context, *UpdateRequest) (*UpdateResponse, error)
+ List(context.Context, *ListContentRequest) (TTRPCContent_ListClient, error)
+ Delete(context.Context, *DeleteContentRequest) (*emptypb.Empty, error)
+ Read(context.Context, *ReadContentRequest) (TTRPCContent_ReadClient, error)
+ Status(context.Context, *StatusRequest) (*StatusResponse, error)
+ ListStatuses(context.Context, *ListStatusesRequest) (*ListStatusesResponse, error)
+ Write(context.Context) (TTRPCContent_WriteClient, error)
+ Abort(context.Context, *AbortRequest) (*emptypb.Empty, error)
+}
+
+type ttrpccontentClient struct {
+ client *ttrpc.Client
+}
+
+func NewTTRPCContentClient(client *ttrpc.Client) TTRPCContentClient {
+ return &ttrpccontentClient{
+ client: client,
+ }
+}
+
+func (c *ttrpccontentClient) Info(ctx context.Context, req *InfoRequest) (*InfoResponse, error) {
+ var resp InfoResponse
+ if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Info", req, &resp); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+func (c *ttrpccontentClient) Update(ctx context.Context, req *UpdateRequest) (*UpdateResponse, error) {
+ var resp UpdateResponse
+ if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Update", req, &resp); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+func (c *ttrpccontentClient) List(ctx context.Context, req *ListContentRequest) (TTRPCContent_ListClient, error) {
+ stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{
+ StreamingClient: false,
+ StreamingServer: true,
+ }, "containerd.services.content.v1.Content", "List", req)
+ if err != nil {
+ return nil, err
+ }
+ x := &ttrpccontentListClient{stream}
+ return x, nil
+}
+
+type TTRPCContent_ListClient interface {
+ Recv() (*ListContentResponse, error)
+ ttrpc.ClientStream
+}
+
+type ttrpccontentListClient struct {
+ ttrpc.ClientStream
+}
+
+func (x *ttrpccontentListClient) Recv() (*ListContentResponse, error) {
+ m := new(ListContentResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *ttrpccontentClient) Delete(ctx context.Context, req *DeleteContentRequest) (*emptypb.Empty, error) {
+ var resp emptypb.Empty
+ if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Delete", req, &resp); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+func (c *ttrpccontentClient) Read(ctx context.Context, req *ReadContentRequest) (TTRPCContent_ReadClient, error) {
+ stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{
+ StreamingClient: false,
+ StreamingServer: true,
+ }, "containerd.services.content.v1.Content", "Read", req)
+ if err != nil {
+ return nil, err
+ }
+ x := &ttrpccontentReadClient{stream}
+ return x, nil
+}
+
+type TTRPCContent_ReadClient interface {
+ Recv() (*ReadContentResponse, error)
+ ttrpc.ClientStream
+}
+
+type ttrpccontentReadClient struct {
+ ttrpc.ClientStream
+}
+
+func (x *ttrpccontentReadClient) Recv() (*ReadContentResponse, error) {
+ m := new(ReadContentResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *ttrpccontentClient) Status(ctx context.Context, req *StatusRequest) (*StatusResponse, error) {
+ var resp StatusResponse
+ if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Status", req, &resp); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+func (c *ttrpccontentClient) ListStatuses(ctx context.Context, req *ListStatusesRequest) (*ListStatusesResponse, error) {
+ var resp ListStatusesResponse
+ if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "ListStatuses", req, &resp); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+func (c *ttrpccontentClient) Write(ctx context.Context) (TTRPCContent_WriteClient, error) {
+ stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{
+ StreamingClient: true,
+ StreamingServer: true,
+ }, "containerd.services.content.v1.Content", "Write", nil)
+ if err != nil {
+ return nil, err
+ }
+ x := &ttrpccontentWriteClient{stream}
+ return x, nil
+}
+
+type TTRPCContent_WriteClient interface {
+ Send(*WriteContentRequest) error
+ Recv() (*WriteContentResponse, error)
+ ttrpc.ClientStream
+}
+
+type ttrpccontentWriteClient struct {
+ ttrpc.ClientStream
+}
+
+func (x *ttrpccontentWriteClient) Send(m *WriteContentRequest) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *ttrpccontentWriteClient) Recv() (*WriteContentResponse, error) {
+ m := new(WriteContentResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *ttrpccontentClient) Abort(ctx context.Context, req *AbortRequest) (*emptypb.Empty, error) {
+ var resp emptypb.Empty
+ if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Abort", req, &resp); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
diff --git a/vendor/github.com/containerd/containerd/content/content.go b/vendor/github.com/containerd/containerd/content/content.go
deleted file mode 100644
index ff17a8417b..0000000000
--- a/vendor/github.com/containerd/containerd/content/content.go
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package content
-
-import (
- "context"
- "io"
- "time"
-
- "github.com/opencontainers/go-digest"
- ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-// ReaderAt extends the standard io.ReaderAt interface with reporting of Size and io.Closer
-type ReaderAt interface {
- io.ReaderAt
- io.Closer
- Size() int64
-}
-
-// Provider provides a reader interface for specific content
-type Provider interface {
- // ReaderAt only requires desc.Digest to be set.
- // Other fields in the descriptor may be used internally for resolving
- // the location of the actual data.
- ReaderAt(ctx context.Context, desc ocispec.Descriptor) (ReaderAt, error)
-}
-
-// Ingester writes content
-type Ingester interface {
- // Some implementations require WithRef to be included in opts.
- Writer(ctx context.Context, opts ...WriterOpt) (Writer, error)
-}
-
-// Info holds content specific information
-//
-// TODO(stevvooe): Consider a very different name for this struct. Info is way
-// to general. It also reads very weird in certain context, like pluralization.
-type Info struct {
- Digest digest.Digest
- Size int64
- CreatedAt time.Time
- UpdatedAt time.Time
- Labels map[string]string
-}
-
-// Status of a content operation
-type Status struct {
- Ref string
- Offset int64
- Total int64
- Expected digest.Digest
- StartedAt time.Time
- UpdatedAt time.Time
-}
-
-// WalkFunc defines the callback for a blob walk.
-type WalkFunc func(Info) error
-
-// Manager provides methods for inspecting, listing and removing content.
-type Manager interface {
- // Info will return metadata about content available in the content store.
- //
- // If the content is not present, ErrNotFound will be returned.
- Info(ctx context.Context, dgst digest.Digest) (Info, error)
-
- // Update updates mutable information related to content.
- // If one or more fieldpaths are provided, only those
- // fields will be updated.
- // Mutable fields:
- // labels.*
- Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error)
-
- // Walk will call fn for each item in the content store which
- // match the provided filters. If no filters are given all
- // items will be walked.
- Walk(ctx context.Context, fn WalkFunc, filters ...string) error
-
- // Delete removes the content from the store.
- Delete(ctx context.Context, dgst digest.Digest) error
-}
-
-// IngestManager provides methods for managing ingests.
-type IngestManager interface {
- // Status returns the status of the provided ref.
- Status(ctx context.Context, ref string) (Status, error)
-
- // ListStatuses returns the status of any active ingestions whose ref match the
- // provided regular expression. If empty, all active ingestions will be
- // returned.
- ListStatuses(ctx context.Context, filters ...string) ([]Status, error)
-
- // Abort completely cancels the ingest operation targeted by ref.
- Abort(ctx context.Context, ref string) error
-}
-
-// Writer handles the write of content into a content store
-type Writer interface {
- // Close closes the writer, if the writer has not been
- // committed this allows resuming or aborting.
- // Calling Close on a closed writer will not error.
- io.WriteCloser
-
- // Digest may return empty digest or panics until committed.
- Digest() digest.Digest
-
- // Commit commits the blob (but no roll-back is guaranteed on an error).
- // size and expected can be zero-value when unknown.
- // Commit always closes the writer, even on error.
- // ErrAlreadyExists aborts the writer.
- Commit(ctx context.Context, size int64, expected digest.Digest, opts ...Opt) error
-
- // Status returns the current state of write
- Status() (Status, error)
-
- // Truncate updates the size of the target blob
- Truncate(size int64) error
-}
-
-// Store combines the methods of content-oriented interfaces into a set that
-// are commonly provided by complete implementations.
-type Store interface {
- Manager
- Provider
- IngestManager
- Ingester
-}
-
-// Opt is used to alter the mutable properties of content
-type Opt func(*Info) error
-
-// WithLabels allows labels to be set on content
-func WithLabels(labels map[string]string) Opt {
- return func(info *Info) error {
- info.Labels = labels
- return nil
- }
-}
-
-// WriterOpts is internally used by WriterOpt.
-type WriterOpts struct {
- Ref string
- Desc ocispec.Descriptor
-}
-
-// WriterOpt is used for passing options to Ingester.Writer.
-type WriterOpt func(*WriterOpts) error
-
-// WithDescriptor specifies an OCI descriptor.
-// Writer may optionally use the descriptor internally for resolving
-// the location of the actual data.
-// Write does not require any field of desc to be set.
-// If the data size is unknown, desc.Size should be set to 0.
-// Some implementations may also accept negative values as "unknown".
-func WithDescriptor(desc ocispec.Descriptor) WriterOpt {
- return func(opts *WriterOpts) error {
- opts.Desc = desc
- return nil
- }
-}
-
-// WithRef specifies a ref string.
-func WithRef(ref string) WriterOpt {
- return func(opts *WriterOpts) error {
- opts.Ref = ref
- return nil
- }
-}
diff --git a/vendor/github.com/containerd/containerd/content/helpers.go b/vendor/github.com/containerd/containerd/content/helpers.go
deleted file mode 100644
index 723c313917..0000000000
--- a/vendor/github.com/containerd/containerd/content/helpers.go
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package content
-
-import (
- "context"
- "errors"
- "fmt"
- "io"
- "math/rand"
- "sync"
- "time"
-
- "github.com/containerd/containerd/errdefs"
- "github.com/containerd/containerd/log"
- "github.com/opencontainers/go-digest"
- ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-// maxResets is the no.of times the Copy() method can tolerate a reset of the body
-const maxResets = 5
-
-var ErrReset = errors.New("writer has been reset")
-
-var bufPool = sync.Pool{
- New: func() interface{} {
- buffer := make([]byte, 1<<20)
- return &buffer
- },
-}
-
-// NewReader returns a io.Reader from a ReaderAt
-func NewReader(ra ReaderAt) io.Reader {
- rd := io.NewSectionReader(ra, 0, ra.Size())
- return rd
-}
-
-// ReadBlob retrieves the entire contents of the blob from the provider.
-//
-// Avoid using this for large blobs, such as layers.
-func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) ([]byte, error) {
- ra, err := provider.ReaderAt(ctx, desc)
- if err != nil {
- return nil, err
- }
- defer ra.Close()
-
- p := make([]byte, ra.Size())
-
- n, err := ra.ReadAt(p, 0)
- if err == io.EOF {
- if int64(n) != ra.Size() {
- err = io.ErrUnexpectedEOF
- } else {
- err = nil
- }
- }
- return p, err
-}
-
-// WriteBlob writes data with the expected digest into the content store. If
-// expected already exists, the method returns immediately and the reader will
-// not be consumed.
-//
-// This is useful when the digest and size are known beforehand.
-//
-// Copy is buffered, so no need to wrap reader in buffered io.
-func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, desc ocispec.Descriptor, opts ...Opt) error {
- cw, err := OpenWriter(ctx, cs, WithRef(ref), WithDescriptor(desc))
- if err != nil {
- if !errdefs.IsAlreadyExists(err) {
- return fmt.Errorf("failed to open writer: %w", err)
- }
-
- return nil // already present
- }
- defer cw.Close()
-
- return Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
-}
-
-// OpenWriter opens a new writer for the given reference, retrying if the writer
-// is locked until the reference is available or returns an error.
-func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, error) {
- var (
- cw Writer
- err error
- retry = 16
- )
- for {
- cw, err = cs.Writer(ctx, opts...)
- if err != nil {
- if !errdefs.IsUnavailable(err) {
- return nil, err
- }
-
- // TODO: Check status to determine if the writer is active,
- // continue waiting while active, otherwise return lock
- // error or abort. Requires asserting for an ingest manager
-
- select {
- case <-time.After(time.Millisecond * time.Duration(rand.Intn(retry))):
- if retry < 2048 {
- retry = retry << 1
- }
- continue
- case <-ctx.Done():
- // Propagate lock error
- return nil, err
- }
-
- }
- break
- }
-
- return cw, err
-}
-
-// Copy copies data with the expected digest from the reader into the
-// provided content store writer. This copy commits the writer.
-//
-// This is useful when the digest and size are known beforehand. When
-// the size or digest is unknown, these values may be empty.
-//
-// Copy is buffered, so no need to wrap reader in buffered io.
-func Copy(ctx context.Context, cw Writer, or io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
- ws, err := cw.Status()
- if err != nil {
- return fmt.Errorf("failed to get status: %w", err)
- }
- r := or
- if ws.Offset > 0 {
- r, err = seekReader(or, ws.Offset, size)
- if err != nil {
- return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
- }
- }
-
- for i := 0; i < maxResets; i++ {
- if i >= 1 {
- log.G(ctx).WithField("digest", expected).Debugf("retrying copy due to reset")
- }
- copied, err := copyWithBuffer(cw, r)
- if errors.Is(err, ErrReset) {
- ws, err := cw.Status()
- if err != nil {
- return fmt.Errorf("failed to get status: %w", err)
- }
- r, err = seekReader(or, ws.Offset, size)
- if err != nil {
- return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
- }
- continue
- }
- if err != nil {
- return fmt.Errorf("failed to copy: %w", err)
- }
- if size != 0 && copied < size-ws.Offset {
- // Short writes would return its own error, this indicates a read failure
- return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF)
- }
- if err := cw.Commit(ctx, size, expected, opts...); err != nil {
- if errors.Is(err, ErrReset) {
- ws, err := cw.Status()
- if err != nil {
- return fmt.Errorf("failed to get status: %w", err)
- }
- r, err = seekReader(or, ws.Offset, size)
- if err != nil {
- return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
- }
- continue
- }
- if !errdefs.IsAlreadyExists(err) {
- return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err)
- }
- }
- return nil
- }
-
- log.G(ctx).WithField("digest", expected).Errorf("failed to copy after %d retries", maxResets)
- return fmt.Errorf("failed to copy after %d retries", maxResets)
-}
-
-// CopyReaderAt copies to a writer from a given reader at for the given
-// number of bytes. This copy does not commit the writer.
-func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
- ws, err := cw.Status()
- if err != nil {
- return err
- }
-
- copied, err := copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n))
- if err != nil {
- return fmt.Errorf("failed to copy: %w", err)
- }
- if copied < n {
- // Short writes would return its own error, this indicates a read failure
- return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF)
- }
- return nil
-}
-
-// CopyReader copies to a writer from a given reader, returning
-// the number of bytes copied.
-// Note: if the writer has a non-zero offset, the total number
-// of bytes read may be greater than those copied if the reader
-// is not an io.Seeker.
-// This copy does not commit the writer.
-func CopyReader(cw Writer, r io.Reader) (int64, error) {
- ws, err := cw.Status()
- if err != nil {
- return 0, fmt.Errorf("failed to get status: %w", err)
- }
-
- if ws.Offset > 0 {
- r, err = seekReader(r, ws.Offset, 0)
- if err != nil {
- return 0, fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
- }
- }
-
- return copyWithBuffer(cw, r)
-}
-
-// seekReader attempts to seek the reader to the given offset, either by
-// resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding
-// up to the given offset.
-func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
- // attempt to resolve r as a seeker and setup the offset.
- seeker, ok := r.(io.Seeker)
- if ok {
- nn, err := seeker.Seek(offset, io.SeekStart)
- if nn != offset {
- if err == nil {
- err = fmt.Errorf("unexpected seek location without seek error")
- }
- return nil, fmt.Errorf("failed to seek to offset %v: %w", offset, err)
- }
-
- if err != nil {
- return nil, err
- }
-
- return r, nil
- }
-
- // ok, let's try io.ReaderAt!
- readerAt, ok := r.(io.ReaderAt)
- if ok && size > offset {
- sr := io.NewSectionReader(readerAt, offset, size)
- return sr, nil
- }
-
- // well then, let's just discard up to the offset
- n, err := copyWithBuffer(io.Discard, io.LimitReader(r, offset))
- if err != nil {
- return nil, fmt.Errorf("failed to discard to offset: %w", err)
- }
- if n != offset {
- return nil, errors.New("unable to discard to offset")
- }
-
- return r, nil
-}
-
-// copyWithBuffer is very similar to io.CopyBuffer https://golang.org/pkg/io/#CopyBuffer
-// but instead of using Read to read from the src, we use ReadAtLeast to make sure we have
-// a full buffer before we do a write operation to dst to reduce overheads associated
-// with the write operations of small buffers.
-func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
- // If the reader has a WriteTo method, use it to do the copy.
- // Avoids an allocation and a copy.
- if wt, ok := src.(io.WriterTo); ok {
- return wt.WriteTo(dst)
- }
- // Similarly, if the writer has a ReadFrom method, use it to do the copy.
- if rt, ok := dst.(io.ReaderFrom); ok {
- return rt.ReadFrom(src)
- }
- bufRef := bufPool.Get().(*[]byte)
- defer bufPool.Put(bufRef)
- buf := *bufRef
- for {
- nr, er := io.ReadAtLeast(src, buf, len(buf))
- if nr > 0 {
- nw, ew := dst.Write(buf[0:nr])
- if nw > 0 {
- written += int64(nw)
- }
- if ew != nil {
- err = ew
- break
- }
- if nr != nw {
- err = io.ErrShortWrite
- break
- }
- }
- if er != nil {
- // If an EOF happens after reading fewer than the requested bytes,
- // ReadAtLeast returns ErrUnexpectedEOF.
- if er != io.EOF && er != io.ErrUnexpectedEOF {
- err = er
- }
- break
- }
- }
- return
-}
diff --git a/vendor/github.com/containerd/containerd/content/local/locks.go b/vendor/github.com/containerd/containerd/content/local/locks.go
deleted file mode 100644
index 1e59f39b30..0000000000
--- a/vendor/github.com/containerd/containerd/content/local/locks.go
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package local
-
-import (
- "fmt"
- "sync"
- "time"
-
- "github.com/containerd/containerd/errdefs"
-)
-
-// Handles locking references
-
-type lock struct {
- since time.Time
-}
-
-var (
- // locks lets us lock in process
- locks = make(map[string]*lock)
- locksMu sync.Mutex
-)
-
-func tryLock(ref string) error {
- locksMu.Lock()
- defer locksMu.Unlock()
-
- if v, ok := locks[ref]; ok {
- // Returning the duration may help developers distinguish dead locks (long duration) from
- // lock contentions (short duration).
- now := time.Now()
- return fmt.Errorf(
- "ref %s locked for %s (since %s): %w", ref, now.Sub(v.since), v.since,
- errdefs.ErrUnavailable,
- )
- }
-
- locks[ref] = &lock{time.Now()}
- return nil
-}
-
-func unlock(ref string) {
- locksMu.Lock()
- defer locksMu.Unlock()
-
- delete(locks, ref)
-}
diff --git a/vendor/github.com/containerd/containerd/content/local/store.go b/vendor/github.com/containerd/containerd/content/local/store.go
deleted file mode 100644
index f41a92d04a..0000000000
--- a/vendor/github.com/containerd/containerd/content/local/store.go
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package local
-
-import (
- "context"
- "fmt"
- "io"
- "math/rand"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/containerd/containerd/content"
- "github.com/containerd/containerd/errdefs"
- "github.com/containerd/containerd/filters"
- "github.com/containerd/containerd/log"
- "github.com/sirupsen/logrus"
-
- digest "github.com/opencontainers/go-digest"
- ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-var bufPool = sync.Pool{
- New: func() interface{} {
- buffer := make([]byte, 1<<20)
- return &buffer
- },
-}
-
-// LabelStore is used to store mutable labels for digests
-type LabelStore interface {
- // Get returns all the labels for the given digest
- Get(digest.Digest) (map[string]string, error)
-
- // Set sets all the labels for a given digest
- Set(digest.Digest, map[string]string) error
-
- // Update replaces the given labels for a digest,
- // a key with an empty value removes a label.
- Update(digest.Digest, map[string]string) (map[string]string, error)
-}
-
-// Store is digest-keyed store for content. All data written into the store is
-// stored under a verifiable digest.
-//
-// Store can generally support multi-reader, single-writer ingest of data,
-// including resumable ingest.
-type store struct {
- root string
- ls LabelStore
-}
-
-// NewStore returns a local content store
-func NewStore(root string) (content.Store, error) {
- return NewLabeledStore(root, nil)
-}
-
-// NewLabeledStore returns a new content store using the provided label store
-//
-// Note: content stores which are used underneath a metadata store may not
-// require labels and should use `NewStore`. `NewLabeledStore` is primarily
-// useful for tests or standalone implementations.
-func NewLabeledStore(root string, ls LabelStore) (content.Store, error) {
- if err := os.MkdirAll(filepath.Join(root, "ingest"), 0777); err != nil {
- return nil, err
- }
-
- return &store{
- root: root,
- ls: ls,
- }, nil
-}
-
-func (s *store) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
- p, err := s.blobPath(dgst)
- if err != nil {
- return content.Info{}, fmt.Errorf("calculating blob info path: %w", err)
- }
-
- fi, err := os.Stat(p)
- if err != nil {
- if os.IsNotExist(err) {
- err = fmt.Errorf("content %v: %w", dgst, errdefs.ErrNotFound)
- }
-
- return content.Info{}, err
- }
- var labels map[string]string
- if s.ls != nil {
- labels, err = s.ls.Get(dgst)
- if err != nil {
- return content.Info{}, err
- }
- }
- return s.info(dgst, fi, labels), nil
-}
-
-func (s *store) info(dgst digest.Digest, fi os.FileInfo, labels map[string]string) content.Info {
- return content.Info{
- Digest: dgst,
- Size: fi.Size(),
- CreatedAt: fi.ModTime(),
- UpdatedAt: getATime(fi),
- Labels: labels,
- }
-}
-
-// ReaderAt returns an io.ReaderAt for the blob.
-func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
- p, err := s.blobPath(desc.Digest)
- if err != nil {
- return nil, fmt.Errorf("calculating blob path for ReaderAt: %w", err)
- }
-
- reader, err := OpenReader(p)
- if err != nil {
- return nil, fmt.Errorf("blob %s expected at %s: %w", desc.Digest, p, err)
- }
-
- return reader, nil
-}
-
-// Delete removes a blob by its digest.
-//
-// While this is safe to do concurrently, safe exist-removal logic must hold
-// some global lock on the store.
-func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
- bp, err := s.blobPath(dgst)
- if err != nil {
- return fmt.Errorf("calculating blob path for delete: %w", err)
- }
-
- if err := os.RemoveAll(bp); err != nil {
- if !os.IsNotExist(err) {
- return err
- }
-
- return fmt.Errorf("content %v: %w", dgst, errdefs.ErrNotFound)
- }
-
- return nil
-}
-
-func (s *store) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
- if s.ls == nil {
- return content.Info{}, fmt.Errorf("update not supported on immutable content store: %w", errdefs.ErrFailedPrecondition)
- }
-
- p, err := s.blobPath(info.Digest)
- if err != nil {
- return content.Info{}, fmt.Errorf("calculating blob path for update: %w", err)
- }
-
- fi, err := os.Stat(p)
- if err != nil {
- if os.IsNotExist(err) {
- err = fmt.Errorf("content %v: %w", info.Digest, errdefs.ErrNotFound)
- }
-
- return content.Info{}, err
- }
-
- var (
- all bool
- labels map[string]string
- )
- if len(fieldpaths) > 0 {
- for _, path := range fieldpaths {
- if strings.HasPrefix(path, "labels.") {
- if labels == nil {
- labels = map[string]string{}
- }
-
- key := strings.TrimPrefix(path, "labels.")
- labels[key] = info.Labels[key]
- continue
- }
-
- switch path {
- case "labels":
- all = true
- labels = info.Labels
- default:
- return content.Info{}, fmt.Errorf("cannot update %q field on content info %q: %w", path, info.Digest, errdefs.ErrInvalidArgument)
- }
- }
- } else {
- all = true
- labels = info.Labels
- }
-
- if all {
- err = s.ls.Set(info.Digest, labels)
- } else {
- labels, err = s.ls.Update(info.Digest, labels)
- }
- if err != nil {
- return content.Info{}, err
- }
-
- info = s.info(info.Digest, fi, labels)
- info.UpdatedAt = time.Now()
-
- if err := os.Chtimes(p, info.UpdatedAt, info.CreatedAt); err != nil {
- log.G(ctx).WithError(err).Warnf("could not change access time for %s", info.Digest)
- }
-
- return info, nil
-}
-
-func (s *store) Walk(ctx context.Context, fn content.WalkFunc, fs ...string) error {
- root := filepath.Join(s.root, "blobs")
-
- filter, err := filters.ParseAll(fs...)
- if err != nil {
- return err
- }
-
- var alg digest.Algorithm
- return filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if !fi.IsDir() && !alg.Available() {
- return nil
- }
-
- // TODO(stevvooe): There are few more cases with subdirs that should be
- // handled in case the layout gets corrupted. This isn't strict enough
- // and may spew bad data.
-
- if path == root {
- return nil
- }
- if filepath.Dir(path) == root {
- alg = digest.Algorithm(filepath.Base(path))
-
- if !alg.Available() {
- alg = ""
- return filepath.SkipDir
- }
-
- // descending into a hash directory
- return nil
- }
-
- dgst := digest.NewDigestFromHex(alg.String(), filepath.Base(path))
- if err := dgst.Validate(); err != nil {
- // log error but don't report
- log.L.WithError(err).WithField("path", path).Error("invalid digest for blob path")
- // if we see this, it could mean some sort of corruption of the
- // store or extra paths not expected previously.
- }
-
- var labels map[string]string
- if s.ls != nil {
- labels, err = s.ls.Get(dgst)
- if err != nil {
- return err
- }
- }
-
- info := s.info(dgst, fi, labels)
- if !filter.Match(content.AdaptInfo(info)) {
- return nil
- }
- return fn(info)
- })
-}
-
-func (s *store) Status(ctx context.Context, ref string) (content.Status, error) {
- return s.status(s.ingestRoot(ref))
-}
-
-func (s *store) ListStatuses(ctx context.Context, fs ...string) ([]content.Status, error) {
- fp, err := os.Open(filepath.Join(s.root, "ingest"))
- if err != nil {
- return nil, err
- }
-
- defer fp.Close()
-
- fis, err := fp.Readdir(-1)
- if err != nil {
- return nil, err
- }
-
- filter, err := filters.ParseAll(fs...)
- if err != nil {
- return nil, err
- }
-
- var active []content.Status
- for _, fi := range fis {
- p := filepath.Join(s.root, "ingest", fi.Name())
- stat, err := s.status(p)
- if err != nil {
- if !os.IsNotExist(err) {
- return nil, err
- }
-
- // TODO(stevvooe): This is a common error if uploads are being
- // completed while making this listing. Need to consider taking a
- // lock on the whole store to coordinate this aspect.
- //
- // Another option is to cleanup downloads asynchronously and
- // coordinate this method with the cleanup process.
- //
- // For now, we just skip them, as they really don't exist.
- continue
- }
-
- if filter.Match(adaptStatus(stat)) {
- active = append(active, stat)
- }
- }
-
- return active, nil
-}
-
-// WalkStatusRefs is used to walk all status references
-// Failed status reads will be logged and ignored, if
-// this function is called while references are being altered,
-// these error messages may be produced.
-func (s *store) WalkStatusRefs(ctx context.Context, fn func(string) error) error {
- fp, err := os.Open(filepath.Join(s.root, "ingest"))
- if err != nil {
- return err
- }
-
- defer fp.Close()
-
- fis, err := fp.Readdir(-1)
- if err != nil {
- return err
- }
-
- for _, fi := range fis {
- rf := filepath.Join(s.root, "ingest", fi.Name(), "ref")
-
- ref, err := readFileString(rf)
- if err != nil {
- log.G(ctx).WithError(err).WithField("path", rf).Error("failed to read ingest ref")
- continue
- }
-
- if err := fn(ref); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// status works like stat above except uses the path to the ingest.
-func (s *store) status(ingestPath string) (content.Status, error) {
- dp := filepath.Join(ingestPath, "data")
- fi, err := os.Stat(dp)
- if err != nil {
- if os.IsNotExist(err) {
- err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
- }
- return content.Status{}, err
- }
-
- ref, err := readFileString(filepath.Join(ingestPath, "ref"))
- if err != nil {
- if os.IsNotExist(err) {
- err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
- }
- return content.Status{}, err
- }
-
- startedAt, err := readFileTimestamp(filepath.Join(ingestPath, "startedat"))
- if err != nil {
- return content.Status{}, fmt.Errorf("could not read startedat: %w", err)
- }
-
- updatedAt, err := readFileTimestamp(filepath.Join(ingestPath, "updatedat"))
- if err != nil {
- return content.Status{}, fmt.Errorf("could not read updatedat: %w", err)
- }
-
- // because we don't write updatedat on every write, the mod time may
- // actually be more up to date.
- if fi.ModTime().After(updatedAt) {
- updatedAt = fi.ModTime()
- }
-
- return content.Status{
- Ref: ref,
- Offset: fi.Size(),
- Total: s.total(ingestPath),
- UpdatedAt: updatedAt,
- StartedAt: startedAt,
- }, nil
-}
-
-func adaptStatus(status content.Status) filters.Adaptor {
- return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
- if len(fieldpath) == 0 {
- return "", false
- }
- switch fieldpath[0] {
- case "ref":
- return status.Ref, true
- }
-
- return "", false
- })
-}
-
-// total attempts to resolve the total expected size for the write.
-func (s *store) total(ingestPath string) int64 {
- totalS, err := readFileString(filepath.Join(ingestPath, "total"))
- if err != nil {
- return 0
- }
-
- total, err := strconv.ParseInt(totalS, 10, 64)
- if err != nil {
- // represents a corrupted file, should probably remove.
- return 0
- }
-
- return total
-}
-
-// Writer begins or resumes the active writer identified by ref. If the writer
-// is already in use, an error is returned. Only one writer may be in use per
-// ref at a time.
-//
-// The argument `ref` is used to uniquely identify a long-lived writer transaction.
-func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
- var wOpts content.WriterOpts
- for _, opt := range opts {
- if err := opt(&wOpts); err != nil {
- return nil, err
- }
- }
- // TODO(AkihiroSuda): we could create a random string or one calculated based on the context
- // https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
- if wOpts.Ref == "" {
- return nil, fmt.Errorf("ref must not be empty: %w", errdefs.ErrInvalidArgument)
- }
- var lockErr error
- for count := uint64(0); count < 10; count++ {
- if err := tryLock(wOpts.Ref); err != nil {
- if !errdefs.IsUnavailable(err) {
- return nil, err
- }
-
- lockErr = err
- } else {
- lockErr = nil
- break
- }
- time.Sleep(time.Millisecond * time.Duration(rand.Intn(1< 0 && status.Total > 0 && total != status.Total {
- return status, fmt.Errorf("provided total differs from status: %v != %v", total, status.Total)
- }
-
- // TODO(stevvooe): slow slow slow!!, send to goroutine or use resumable hashes
- fp, err := os.Open(data)
- if err != nil {
- return status, err
- }
-
- p := bufPool.Get().(*[]byte)
- status.Offset, err = io.CopyBuffer(digester.Hash(), fp, *p)
- bufPool.Put(p)
- fp.Close()
- return status, err
-}
-
-// writer provides the main implementation of the Writer method. The caller
-// must hold the lock correctly and release on error if there is a problem.
-func (s *store) writer(ctx context.Context, ref string, total int64, expected digest.Digest) (content.Writer, error) {
- // TODO(stevvooe): Need to actually store expected here. We have
- // code in the service that shouldn't be dealing with this.
- if expected != "" {
- p, err := s.blobPath(expected)
- if err != nil {
- return nil, fmt.Errorf("calculating expected blob path for writer: %w", err)
- }
- if _, err := os.Stat(p); err == nil {
- return nil, fmt.Errorf("content %v: %w", expected, errdefs.ErrAlreadyExists)
- }
- }
-
- path, refp, data := s.ingestPaths(ref)
-
- var (
- digester = digest.Canonical.Digester()
- offset int64
- startedAt time.Time
- updatedAt time.Time
- )
-
- foundValidIngest := false
- // ensure that the ingest path has been created.
- if err := os.Mkdir(path, 0755); err != nil {
- if !os.IsExist(err) {
- return nil, err
- }
- status, err := s.resumeStatus(ref, total, digester)
- if err == nil {
- foundValidIngest = true
- updatedAt = status.UpdatedAt
- startedAt = status.StartedAt
- total = status.Total
- offset = status.Offset
- } else {
- logrus.Infof("failed to resume the status from path %s: %s. will recreate them", path, err.Error())
- }
- }
-
- if !foundValidIngest {
- startedAt = time.Now()
- updatedAt = startedAt
-
- // the ingest is new, we need to setup the target location.
- // write the ref to a file for later use
- if err := os.WriteFile(refp, []byte(ref), 0666); err != nil {
- return nil, err
- }
-
- if err := writeTimestampFile(filepath.Join(path, "startedat"), startedAt); err != nil {
- return nil, err
- }
-
- if err := writeTimestampFile(filepath.Join(path, "updatedat"), startedAt); err != nil {
- return nil, err
- }
-
- if total > 0 {
- if err := os.WriteFile(filepath.Join(path, "total"), []byte(fmt.Sprint(total)), 0666); err != nil {
- return nil, err
- }
- }
- }
-
- fp, err := os.OpenFile(data, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- return nil, fmt.Errorf("failed to open data file: %w", err)
- }
-
- if _, err := fp.Seek(offset, io.SeekStart); err != nil {
- fp.Close()
- return nil, fmt.Errorf("could not seek to current write offset: %w", err)
- }
-
- return &writer{
- s: s,
- fp: fp,
- ref: ref,
- path: path,
- offset: offset,
- total: total,
- digester: digester,
- startedAt: startedAt,
- updatedAt: updatedAt,
- }, nil
-}
-
-// Abort an active transaction keyed by ref. If the ingest is active, it will
-// be cancelled. Any resources associated with the ingest will be cleaned.
-func (s *store) Abort(ctx context.Context, ref string) error {
- root := s.ingestRoot(ref)
- if err := os.RemoveAll(root); err != nil {
- if os.IsNotExist(err) {
- return fmt.Errorf("ingest ref %q: %w", ref, errdefs.ErrNotFound)
- }
-
- return err
- }
-
- return nil
-}
-
-func (s *store) blobPath(dgst digest.Digest) (string, error) {
- if err := dgst.Validate(); err != nil {
- return "", fmt.Errorf("cannot calculate blob path from invalid digest: %v: %w", err, errdefs.ErrInvalidArgument)
- }
-
- return filepath.Join(s.root, "blobs", dgst.Algorithm().String(), dgst.Hex()), nil
-}
-
-func (s *store) ingestRoot(ref string) string {
- // we take a digest of the ref to keep the ingest paths constant length.
- // Note that this is not the current or potential digest of incoming content.
- dgst := digest.FromString(ref)
- return filepath.Join(s.root, "ingest", dgst.Hex())
-}
-
-// ingestPaths are returned. The paths are the following:
-//
-// - root: entire ingest directory
-// - ref: name of the starting ref, must be unique
-// - data: file where data is written
-func (s *store) ingestPaths(ref string) (string, string, string) {
- var (
- fp = s.ingestRoot(ref)
- rp = filepath.Join(fp, "ref")
- dp = filepath.Join(fp, "data")
- )
-
- return fp, rp, dp
-}
-
-func readFileString(path string) (string, error) {
- p, err := os.ReadFile(path)
- return string(p), err
-}
-
-// readFileTimestamp reads a file with just a timestamp present.
-func readFileTimestamp(p string) (time.Time, error) {
- b, err := os.ReadFile(p)
- if err != nil {
- if os.IsNotExist(err) {
- err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
- }
- return time.Time{}, err
- }
-
- var t time.Time
- if err := t.UnmarshalText(b); err != nil {
- return time.Time{}, fmt.Errorf("could not parse timestamp file %v: %w", p, err)
- }
-
- return t, nil
-}
-
-func writeTimestampFile(p string, t time.Time) error {
- b, err := t.MarshalText()
- if err != nil {
- return err
- }
- return writeToCompletion(p, b, 0666)
-}
-
-func writeToCompletion(path string, data []byte, mode os.FileMode) error {
- tmp := fmt.Sprintf("%s.tmp", path)
- f, err := os.OpenFile(tmp, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, mode)
- if err != nil {
- return fmt.Errorf("create tmp file: %w", err)
- }
- _, err = f.Write(data)
- f.Close()
- if err != nil {
- return fmt.Errorf("write tmp file: %w", err)
- }
- err = os.Rename(tmp, path)
- if err != nil {
- return fmt.Errorf("rename tmp file: %w", err)
- }
- return nil
-}
diff --git a/vendor/github.com/containerd/containerd/content/local/writer.go b/vendor/github.com/containerd/containerd/content/local/writer.go
deleted file mode 100644
index b187e524cb..0000000000
--- a/vendor/github.com/containerd/containerd/content/local/writer.go
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package local
-
-import (
- "context"
- "errors"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "runtime"
- "time"
-
- "github.com/containerd/containerd/content"
- "github.com/containerd/containerd/errdefs"
- "github.com/containerd/containerd/log"
- "github.com/opencontainers/go-digest"
-)
-
-// writer represents a write transaction against the blob store.
-type writer struct {
- s *store
- fp *os.File // opened data file
- path string // path to writer dir
- ref string // ref key
- offset int64
- total int64
- digester digest.Digester
- startedAt time.Time
- updatedAt time.Time
-}
-
-func (w *writer) Status() (content.Status, error) {
- return content.Status{
- Ref: w.ref,
- Offset: w.offset,
- Total: w.total,
- StartedAt: w.startedAt,
- UpdatedAt: w.updatedAt,
- }, nil
-}
-
-// Digest returns the current digest of the content, up to the current write.
-//
-// Cannot be called concurrently with `Write`.
-func (w *writer) Digest() digest.Digest {
- return w.digester.Digest()
-}
-
-// Write p to the transaction.
-//
-// Note that writes are unbuffered to the backing file. When writing, it is
-// recommended to wrap in a bufio.Writer or, preferably, use io.CopyBuffer.
-func (w *writer) Write(p []byte) (n int, err error) {
- n, err = w.fp.Write(p)
- w.digester.Hash().Write(p[:n])
- w.offset += int64(len(p))
- w.updatedAt = time.Now()
- return n, err
-}
-
-func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
- // Ensure even on error the writer is fully closed
- defer unlock(w.ref)
-
- var base content.Info
- for _, opt := range opts {
- if err := opt(&base); err != nil {
- return err
- }
- }
-
- fp := w.fp
- w.fp = nil
-
- if fp == nil {
- return fmt.Errorf("cannot commit on closed writer: %w", errdefs.ErrFailedPrecondition)
- }
-
- if err := fp.Sync(); err != nil {
- fp.Close()
- return fmt.Errorf("sync failed: %w", err)
- }
-
- fi, err := fp.Stat()
- closeErr := fp.Close()
- if err != nil {
- return fmt.Errorf("stat on ingest file failed: %w", err)
- }
- if closeErr != nil {
- return fmt.Errorf("failed to close ingest file: %w", closeErr)
- }
-
- if size > 0 && size != fi.Size() {
- return fmt.Errorf("unexpected commit size %d, expected %d: %w", fi.Size(), size, errdefs.ErrFailedPrecondition)
- }
-
- dgst := w.digester.Digest()
- if expected != "" && expected != dgst {
- return fmt.Errorf("unexpected commit digest %s, expected %s: %w", dgst, expected, errdefs.ErrFailedPrecondition)
- }
-
- var (
- ingest = filepath.Join(w.path, "data")
- target, _ = w.s.blobPath(dgst) // ignore error because we calculated this dgst
- )
-
- // make sure parent directories of blob exist
- if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
- return err
- }
-
- if _, err := os.Stat(target); err == nil {
- // collision with the target file!
- if err := os.RemoveAll(w.path); err != nil {
- log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Error("failed to remove ingest directory")
- }
- return fmt.Errorf("content %v: %w", dgst, errdefs.ErrAlreadyExists)
- }
-
- if err := os.Rename(ingest, target); err != nil {
- return err
- }
-
- // Ingest has now been made available in the content store, attempt to complete
- // setting metadata but errors should only be logged and not returned since
- // the content store cannot be cleanly rolled back.
-
- commitTime := time.Now()
- if err := os.Chtimes(target, commitTime, commitTime); err != nil {
- log.G(ctx).WithField("digest", dgst).Error("failed to change file time to commit time")
- }
-
- // clean up!!
- if err := os.RemoveAll(w.path); err != nil {
- log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Error("failed to remove ingest directory")
- }
-
- if w.s.ls != nil && base.Labels != nil {
- if err := w.s.ls.Set(dgst, base.Labels); err != nil {
- log.G(ctx).WithField("digest", dgst).Error("failed to set labels")
- }
- }
-
- // change to readonly, more important for read, but provides _some_
- // protection from this point on. We use the existing perms with a mask
- // only allowing reads honoring the umask on creation.
- //
- // This removes write and exec, only allowing read per the creation umask.
- //
- // NOTE: Windows does not support this operation
- if runtime.GOOS != "windows" {
- if err := os.Chmod(target, (fi.Mode()&os.ModePerm)&^0333); err != nil {
- log.G(ctx).WithField("ref", w.ref).Error("failed to make readonly")
- }
- }
-
- return nil
-}
-
-// Close the writer, flushing any unwritten data and leaving the progress in
-// tact.
-//
-// If one needs to resume the transaction, a new writer can be obtained from
-// `Ingester.Writer` using the same key. The write can then be continued
-// from it was left off.
-//
-// To abandon a transaction completely, first call close then `IngestManager.Abort` to
-// clean up the associated resources.
-func (w *writer) Close() (err error) {
- if w.fp != nil {
- w.fp.Sync()
- err = w.fp.Close()
- writeTimestampFile(filepath.Join(w.path, "updatedat"), w.updatedAt)
- w.fp = nil
- unlock(w.ref)
- return
- }
-
- return nil
-}
-
-func (w *writer) Truncate(size int64) error {
- if size != 0 {
- return errors.New("Truncate: unsupported size")
- }
- w.offset = 0
- w.digester.Hash().Reset()
- if _, err := w.fp.Seek(0, io.SeekStart); err != nil {
- return err
- }
- return w.fp.Truncate(0)
-}
diff --git a/vendor/github.com/containerd/containerd/content/proxy/content_store.go b/vendor/github.com/containerd/containerd/content/proxy/content_store.go
deleted file mode 100644
index 217b746516..0000000000
--- a/vendor/github.com/containerd/containerd/content/proxy/content_store.go
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package proxy
-
-import (
- "context"
- "io"
-
- contentapi "github.com/containerd/containerd/api/services/content/v1"
- "github.com/containerd/containerd/content"
- "github.com/containerd/containerd/errdefs"
- protobuftypes "github.com/gogo/protobuf/types"
- digest "github.com/opencontainers/go-digest"
- ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-type proxyContentStore struct {
- client contentapi.ContentClient
-}
-
-// NewContentStore returns a new content store which communicates over a GRPC
-// connection using the containerd content GRPC API.
-func NewContentStore(client contentapi.ContentClient) content.Store {
- return &proxyContentStore{
- client: client,
- }
-}
-
-func (pcs *proxyContentStore) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
- resp, err := pcs.client.Info(ctx, &contentapi.InfoRequest{
- Digest: dgst,
- })
- if err != nil {
- return content.Info{}, errdefs.FromGRPC(err)
- }
-
- return infoFromGRPC(resp.Info), nil
-}
-
-func (pcs *proxyContentStore) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error {
- session, err := pcs.client.List(ctx, &contentapi.ListContentRequest{
- Filters: filters,
- })
- if err != nil {
- return errdefs.FromGRPC(err)
- }
-
- for {
- msg, err := session.Recv()
- if err != nil {
- if err != io.EOF {
- return errdefs.FromGRPC(err)
- }
-
- break
- }
-
- for _, info := range msg.Info {
- if err := fn(infoFromGRPC(info)); err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
-func (pcs *proxyContentStore) Delete(ctx context.Context, dgst digest.Digest) error {
- if _, err := pcs.client.Delete(ctx, &contentapi.DeleteContentRequest{
- Digest: dgst,
- }); err != nil {
- return errdefs.FromGRPC(err)
- }
-
- return nil
-}
-
-// ReaderAt ignores MediaType.
-func (pcs *proxyContentStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
- i, err := pcs.Info(ctx, desc.Digest)
- if err != nil {
- return nil, err
- }
-
- return &remoteReaderAt{
- ctx: ctx,
- digest: desc.Digest,
- size: i.Size,
- client: pcs.client,
- }, nil
-}
-
-func (pcs *proxyContentStore) Status(ctx context.Context, ref string) (content.Status, error) {
- resp, err := pcs.client.Status(ctx, &contentapi.StatusRequest{
- Ref: ref,
- })
- if err != nil {
- return content.Status{}, errdefs.FromGRPC(err)
- }
-
- status := resp.Status
- return content.Status{
- Ref: status.Ref,
- StartedAt: status.StartedAt,
- UpdatedAt: status.UpdatedAt,
- Offset: status.Offset,
- Total: status.Total,
- Expected: status.Expected,
- }, nil
-}
-
-func (pcs *proxyContentStore) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
- resp, err := pcs.client.Update(ctx, &contentapi.UpdateRequest{
- Info: infoToGRPC(info),
- UpdateMask: &protobuftypes.FieldMask{
- Paths: fieldpaths,
- },
- })
- if err != nil {
- return content.Info{}, errdefs.FromGRPC(err)
- }
- return infoFromGRPC(resp.Info), nil
-}
-
-func (pcs *proxyContentStore) ListStatuses(ctx context.Context, filters ...string) ([]content.Status, error) {
- resp, err := pcs.client.ListStatuses(ctx, &contentapi.ListStatusesRequest{
- Filters: filters,
- })
- if err != nil {
- return nil, errdefs.FromGRPC(err)
- }
-
- var statuses []content.Status
- for _, status := range resp.Statuses {
- statuses = append(statuses, content.Status{
- Ref: status.Ref,
- StartedAt: status.StartedAt,
- UpdatedAt: status.UpdatedAt,
- Offset: status.Offset,
- Total: status.Total,
- Expected: status.Expected,
- })
- }
-
- return statuses, nil
-}
-
-// Writer ignores MediaType.
-func (pcs *proxyContentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
- var wOpts content.WriterOpts
- for _, opt := range opts {
- if err := opt(&wOpts); err != nil {
- return nil, err
- }
- }
- wrclient, offset, err := pcs.negotiate(ctx, wOpts.Ref, wOpts.Desc.Size, wOpts.Desc.Digest)
- if err != nil {
- return nil, errdefs.FromGRPC(err)
- }
-
- return &remoteWriter{
- ref: wOpts.Ref,
- client: wrclient,
- offset: offset,
- }, nil
-}
-
-// Abort implements asynchronous abort. It starts a new write session on the ref l
-func (pcs *proxyContentStore) Abort(ctx context.Context, ref string) error {
- if _, err := pcs.client.Abort(ctx, &contentapi.AbortRequest{
- Ref: ref,
- }); err != nil {
- return errdefs.FromGRPC(err)
- }
-
- return nil
-}
-
-func (pcs *proxyContentStore) negotiate(ctx context.Context, ref string, size int64, expected digest.Digest) (contentapi.Content_WriteClient, int64, error) {
- wrclient, err := pcs.client.Write(ctx)
- if err != nil {
- return nil, 0, err
- }
-
- if err := wrclient.Send(&contentapi.WriteContentRequest{
- Action: contentapi.WriteActionStat,
- Ref: ref,
- Total: size,
- Expected: expected,
- }); err != nil {
- return nil, 0, err
- }
-
- resp, err := wrclient.Recv()
- if err != nil {
- return nil, 0, err
- }
-
- return wrclient, resp.Offset, nil
-}
-
-func infoToGRPC(info content.Info) contentapi.Info {
- return contentapi.Info{
- Digest: info.Digest,
- Size_: info.Size,
- CreatedAt: info.CreatedAt,
- UpdatedAt: info.UpdatedAt,
- Labels: info.Labels,
- }
-}
-
-func infoFromGRPC(info contentapi.Info) content.Info {
- return content.Info{
- Digest: info.Digest,
- Size: info.Size_,
- CreatedAt: info.CreatedAt,
- UpdatedAt: info.UpdatedAt,
- Labels: info.Labels,
- }
-}
diff --git a/vendor/github.com/containerd/containerd/content/proxy/content_writer.go b/vendor/github.com/containerd/containerd/content/proxy/content_writer.go
deleted file mode 100644
index ffc0f50ea1..0000000000
--- a/vendor/github.com/containerd/containerd/content/proxy/content_writer.go
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package proxy
-
-import (
- "context"
- "fmt"
- "io"
-
- contentapi "github.com/containerd/containerd/api/services/content/v1"
- "github.com/containerd/containerd/content"
- "github.com/containerd/containerd/errdefs"
- digest "github.com/opencontainers/go-digest"
-)
-
-type remoteWriter struct {
- ref string
- client contentapi.Content_WriteClient
- offset int64
- digest digest.Digest
-}
-
-// send performs a synchronous req-resp cycle on the client.
-func (rw *remoteWriter) send(req *contentapi.WriteContentRequest) (*contentapi.WriteContentResponse, error) {
- if err := rw.client.Send(req); err != nil {
- return nil, err
- }
-
- resp, err := rw.client.Recv()
-
- if err == nil {
- // try to keep these in sync
- if resp.Digest != "" {
- rw.digest = resp.Digest
- }
- }
-
- return resp, err
-}
-
-func (rw *remoteWriter) Status() (content.Status, error) {
- resp, err := rw.send(&contentapi.WriteContentRequest{
- Action: contentapi.WriteActionStat,
- })
- if err != nil {
- return content.Status{}, fmt.Errorf("error getting writer status: %w", errdefs.FromGRPC(err))
- }
-
- return content.Status{
- Ref: rw.ref,
- Offset: resp.Offset,
- Total: resp.Total,
- StartedAt: resp.StartedAt,
- UpdatedAt: resp.UpdatedAt,
- }, nil
-}
-
-func (rw *remoteWriter) Digest() digest.Digest {
- return rw.digest
-}
-
-func (rw *remoteWriter) Write(p []byte) (n int, err error) {
- offset := rw.offset
-
- resp, err := rw.send(&contentapi.WriteContentRequest{
- Action: contentapi.WriteActionWrite,
- Offset: offset,
- Data: p,
- })
- if err != nil {
- return 0, fmt.Errorf("failed to send write: %w", errdefs.FromGRPC(err))
- }
-
- n = int(resp.Offset - offset)
- if n < len(p) {
- err = io.ErrShortWrite
- }
-
- rw.offset += int64(n)
- if resp.Digest != "" {
- rw.digest = resp.Digest
- }
- return
-}
-
-func (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) (err error) {
- defer func() {
- err1 := rw.Close()
- if err == nil {
- err = err1
- }
- }()
-
- var base content.Info
- for _, opt := range opts {
- if err := opt(&base); err != nil {
- return err
- }
- }
- resp, err := rw.send(&contentapi.WriteContentRequest{
- Action: contentapi.WriteActionCommit,
- Total: size,
- Offset: rw.offset,
- Expected: expected,
- Labels: base.Labels,
- })
- if err != nil {
- return fmt.Errorf("commit failed: %w", errdefs.FromGRPC(err))
- }
-
- if size != 0 && resp.Offset != size {
- return fmt.Errorf("unexpected size: %v != %v", resp.Offset, size)
- }
-
- if expected != "" && resp.Digest != expected {
- return fmt.Errorf("unexpected digest: %v != %v", resp.Digest, expected)
- }
-
- rw.digest = resp.Digest
- rw.offset = resp.Offset
- return nil
-}
-
-func (rw *remoteWriter) Truncate(size int64) error {
- // This truncation won't actually be validated until a write is issued.
- rw.offset = size
- return nil
-}
-
-func (rw *remoteWriter) Close() error {
- return rw.client.CloseSend()
-}
diff --git a/vendor/github.com/containerd/containerd/defaults/defaults.go b/vendor/github.com/containerd/containerd/defaults/defaults.go
deleted file mode 100644
index 6f5b122ecf..0000000000
--- a/vendor/github.com/containerd/containerd/defaults/defaults.go
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package defaults
-
-const (
- // DefaultMaxRecvMsgSize defines the default maximum message size for
- // receiving protobufs passed over the GRPC API.
- DefaultMaxRecvMsgSize = 16 << 20
- // DefaultMaxSendMsgSize defines the default maximum message size for
- // sending protobufs passed over the GRPC API.
- DefaultMaxSendMsgSize = 16 << 20
- // DefaultRuntimeNSLabel defines the namespace label to check for the
- // default runtime
- DefaultRuntimeNSLabel = "containerd.io/defaults/runtime"
- // DefaultSnapshotterNSLabel defines the namespace label to check for the
- // default snapshotter
- DefaultSnapshotterNSLabel = "containerd.io/defaults/snapshotter"
-)
diff --git a/vendor/github.com/containerd/containerd/defaults/defaults_darwin.go b/vendor/github.com/containerd/containerd/defaults/defaults_darwin.go
deleted file mode 100644
index 1391884cde..0000000000
--- a/vendor/github.com/containerd/containerd/defaults/defaults_darwin.go
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package defaults
-
-const (
- // DefaultRootDir is the default location used by containerd to store
- // persistent data
- DefaultRootDir = "/var/lib/containerd"
- // DefaultStateDir is the default location used by containerd to store
- // transient data
- DefaultStateDir = "/var/run/containerd"
- // DefaultAddress is the default unix socket address
- DefaultAddress = "/var/run/containerd/containerd.sock"
- // DefaultDebugAddress is the default unix socket address for pprof data
- DefaultDebugAddress = "/var/run/containerd/debug.sock"
- // DefaultFIFODir is the default location used by client-side cio library
- // to store FIFOs.
- DefaultFIFODir = "/var/run/containerd/fifo"
- // DefaultRuntime would be a multiple of choices, thus empty
- DefaultRuntime = ""
- // DefaultConfigDir is the default location for config files.
- DefaultConfigDir = "/etc/containerd"
-)
diff --git a/vendor/github.com/containerd/containerd/defaults/defaults_unix.go b/vendor/github.com/containerd/containerd/defaults/defaults_unix.go
deleted file mode 100644
index 8e2619a381..0000000000
--- a/vendor/github.com/containerd/containerd/defaults/defaults_unix.go
+++ /dev/null
@@ -1,40 +0,0 @@
-//go:build !windows && !darwin
-// +build !windows,!darwin
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package defaults
-
-const (
- // DefaultRootDir is the default location used by containerd to store
- // persistent data
- DefaultRootDir = "/var/lib/containerd"
- // DefaultStateDir is the default location used by containerd to store
- // transient data
- DefaultStateDir = "/run/containerd"
- // DefaultAddress is the default unix socket address
- DefaultAddress = "/run/containerd/containerd.sock"
- // DefaultDebugAddress is the default unix socket address for pprof data
- DefaultDebugAddress = "/run/containerd/debug.sock"
- // DefaultFIFODir is the default location used by client-side cio library
- // to store FIFOs.
- DefaultFIFODir = "/run/containerd/fifo"
- // DefaultRuntime is the default linux runtime
- DefaultRuntime = "io.containerd.runc.v2"
- // DefaultConfigDir is the default location for config files.
- DefaultConfigDir = "/etc/containerd"
-)
diff --git a/vendor/github.com/containerd/containerd/defaults/defaults_windows.go b/vendor/github.com/containerd/containerd/defaults/defaults_windows.go
deleted file mode 100644
index 9f4bed8b07..0000000000
--- a/vendor/github.com/containerd/containerd/defaults/defaults_windows.go
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package defaults
-
-import (
- "os"
- "path/filepath"
-)
-
-var (
- // DefaultRootDir is the default location used by containerd to store
- // persistent data
- DefaultRootDir = filepath.Join(os.Getenv("ProgramData"), "containerd", "root")
- // DefaultStateDir is the default location used by containerd to store
- // transient data
- DefaultStateDir = filepath.Join(os.Getenv("ProgramData"), "containerd", "state")
-
- // DefaultConfigDir is the default location for config files.
- DefaultConfigDir = filepath.Join(os.Getenv("programfiles"), "containerd")
-)
-
-const (
- // DefaultAddress is the default winpipe address
- DefaultAddress = `\\.\pipe\containerd-containerd`
- // DefaultDebugAddress is the default winpipe address for pprof data
- DefaultDebugAddress = `\\.\pipe\containerd-debug`
- // DefaultFIFODir is the default location used by client-side cio library
- // to store FIFOs. Unused on Windows.
- DefaultFIFODir = ""
- // DefaultRuntime is the default windows runtime
- DefaultRuntime = "io.containerd.runhcs.v1"
-)
diff --git a/vendor/github.com/containerd/containerd/errdefs/errors.go b/vendor/github.com/containerd/containerd/errdefs/errors.go
deleted file mode 100644
index 8762255970..0000000000
--- a/vendor/github.com/containerd/containerd/errdefs/errors.go
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-// Package errdefs defines the common errors used throughout containerd
-// packages.
-//
-// Use with fmt.Errorf to add context to an error.
-//
-// To detect an error class, use the IsXXX functions to tell whether an error
-// is of a certain type.
-//
-// The functions ToGRPC and FromGRPC can be used to map server-side and
-// client-side errors to the correct types.
-package errdefs
-
-import (
- "context"
- "errors"
-)
-
-// Definitions of common error types used throughout containerd. All containerd
-// errors returned by most packages will map into one of these errors classes.
-// Packages should return errors of these types when they want to instruct a
-// client to take a particular action.
-//
-// For the most part, we just try to provide local grpc errors. Most conditions
-// map very well to those defined by grpc.
-var (
- ErrUnknown = errors.New("unknown") // used internally to represent a missed mapping.
- ErrInvalidArgument = errors.New("invalid argument")
- ErrNotFound = errors.New("not found")
- ErrAlreadyExists = errors.New("already exists")
- ErrFailedPrecondition = errors.New("failed precondition")
- ErrUnavailable = errors.New("unavailable")
- ErrNotImplemented = errors.New("not implemented") // represents not supported and unimplemented
-)
-
-// IsInvalidArgument returns true if the error is due to an invalid argument
-func IsInvalidArgument(err error) bool {
- return errors.Is(err, ErrInvalidArgument)
-}
-
-// IsNotFound returns true if the error is due to a missing object
-func IsNotFound(err error) bool {
- return errors.Is(err, ErrNotFound)
-}
-
-// IsAlreadyExists returns true if the error is due to an already existing
-// metadata item
-func IsAlreadyExists(err error) bool {
- return errors.Is(err, ErrAlreadyExists)
-}
-
-// IsFailedPrecondition returns true if an operation could not proceed to the
-// lack of a particular condition
-func IsFailedPrecondition(err error) bool {
- return errors.Is(err, ErrFailedPrecondition)
-}
-
-// IsUnavailable returns true if the error is due to a resource being unavailable
-func IsUnavailable(err error) bool {
- return errors.Is(err, ErrUnavailable)
-}
-
-// IsNotImplemented returns true if the error is due to not being implemented
-func IsNotImplemented(err error) bool {
- return errors.Is(err, ErrNotImplemented)
-}
-
-// IsCanceled returns true if the error is due to `context.Canceled`.
-func IsCanceled(err error) bool {
- return errors.Is(err, context.Canceled)
-}
-
-// IsDeadlineExceeded returns true if the error is due to
-// `context.DeadlineExceeded`.
-func IsDeadlineExceeded(err error) bool {
- return errors.Is(err, context.DeadlineExceeded)
-}
diff --git a/vendor/github.com/containerd/containerd/errdefs/grpc.go b/vendor/github.com/containerd/containerd/errdefs/grpc.go
deleted file mode 100644
index 7a9b33e05a..0000000000
--- a/vendor/github.com/containerd/containerd/errdefs/grpc.go
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package errdefs
-
-import (
- "context"
- "fmt"
- "strings"
-
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
-)
-
-// ToGRPC will attempt to map the backend containerd error into a grpc error,
-// using the original error message as a description.
-//
-// Further information may be extracted from certain errors depending on their
-// type.
-//
-// If the error is unmapped, the original error will be returned to be handled
-// by the regular grpc error handling stack.
-func ToGRPC(err error) error {
- if err == nil {
- return nil
- }
-
- if isGRPCError(err) {
- // error has already been mapped to grpc
- return err
- }
-
- switch {
- case IsInvalidArgument(err):
- return status.Errorf(codes.InvalidArgument, err.Error())
- case IsNotFound(err):
- return status.Errorf(codes.NotFound, err.Error())
- case IsAlreadyExists(err):
- return status.Errorf(codes.AlreadyExists, err.Error())
- case IsFailedPrecondition(err):
- return status.Errorf(codes.FailedPrecondition, err.Error())
- case IsUnavailable(err):
- return status.Errorf(codes.Unavailable, err.Error())
- case IsNotImplemented(err):
- return status.Errorf(codes.Unimplemented, err.Error())
- case IsCanceled(err):
- return status.Errorf(codes.Canceled, err.Error())
- case IsDeadlineExceeded(err):
- return status.Errorf(codes.DeadlineExceeded, err.Error())
- }
-
- return err
-}
-
-// ToGRPCf maps the error to grpc error codes, assembling the formatting string
-// and combining it with the target error string.
-//
-// This is equivalent to errdefs.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
-func ToGRPCf(err error, format string, args ...interface{}) error {
- return ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
-}
-
-// FromGRPC returns the underlying error from a grpc service based on the grpc error code
-func FromGRPC(err error) error {
- if err == nil {
- return nil
- }
-
- var cls error // divide these into error classes, becomes the cause
-
- switch code(err) {
- case codes.InvalidArgument:
- cls = ErrInvalidArgument
- case codes.AlreadyExists:
- cls = ErrAlreadyExists
- case codes.NotFound:
- cls = ErrNotFound
- case codes.Unavailable:
- cls = ErrUnavailable
- case codes.FailedPrecondition:
- cls = ErrFailedPrecondition
- case codes.Unimplemented:
- cls = ErrNotImplemented
- case codes.Canceled:
- cls = context.Canceled
- case codes.DeadlineExceeded:
- cls = context.DeadlineExceeded
- default:
- cls = ErrUnknown
- }
-
- msg := rebaseMessage(cls, err)
- if msg != "" {
- err = fmt.Errorf("%s: %w", msg, cls)
- } else {
- err = cls
- }
-
- return err
-}
-
-// rebaseMessage removes the repeats for an error at the end of an error
-// string. This will happen when taking an error over grpc then remapping it.
-//
-// Effectively, we just remove the string of cls from the end of err if it
-// appears there.
-func rebaseMessage(cls error, err error) string {
- desc := errDesc(err)
- clss := cls.Error()
- if desc == clss {
- return ""
- }
-
- return strings.TrimSuffix(desc, ": "+clss)
-}
-
-func isGRPCError(err error) bool {
- _, ok := status.FromError(err)
- return ok
-}
-
-func code(err error) codes.Code {
- if s, ok := status.FromError(err); ok {
- return s.Code()
- }
- return codes.Unknown
-}
-
-func errDesc(err error) string {
- if s, ok := status.FromError(err); ok {
- return s.Message()
- }
- return err.Error()
-}
diff --git a/vendor/github.com/containerd/containerd/filters/filter.go b/vendor/github.com/containerd/containerd/filters/filter.go
deleted file mode 100644
index e13f2625c7..0000000000
--- a/vendor/github.com/containerd/containerd/filters/filter.go
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-// Package filters defines a syntax and parser that can be used for the
-// filtration of items across the containerd API. The core is built on the
-// concept of protobuf field paths, with quoting. Several operators allow the
-// user to flexibly select items based on field presence, equality, inequality
-// and regular expressions. Flexible adaptors support working with any type.
-//
-// The syntax is fairly familiar, if you've used container ecosystem
-// projects. At the core, we base it on the concept of protobuf field
-// paths, augmenting with the ability to quote portions of the field path
-// to match arbitrary labels. These "selectors" come in the following
-// syntax:
-//
-// ```
-// []
-// ```
-//
-// A basic example is as follows:
-//
-// ```
-// name==foo
-// ```
-//
-// This would match all objects that have a field `name` with the value
-// `foo`. If we only want to test if the field is present, we can omit the
-// operator. This is most useful for matching labels in containerd. The
-// following will match objects that have the field "labels" and have the
-// label "foo" defined:
-//
-// ```
-// labels.foo
-// ```
-//
-// We also allow for quoting of parts of the field path to allow matching
-// of arbitrary items:
-//
-// ```
-// labels."very complex label"==something
-// ```
-//
-// We also define `!=` and `~=` as operators. The `!=` will match all
-// objects that don't match the value for a field and `~=` will compile the
-// target value as a regular expression and match the field value against that.
-//
-// Selectors can be combined using a comma, such that the resulting
-// selector will require all selectors are matched for the object to match.
-// The following example will match objects that are named `foo` and have
-// the label `bar`:
-//
-// ```
-// name==foo,labels.bar
-// ```
-package filters
-
-import (
- "regexp"
-
- "github.com/containerd/containerd/log"
-)
-
-// Filter matches specific resources based the provided filter
-type Filter interface {
- Match(adaptor Adaptor) bool
-}
-
-// FilterFunc is a function that handles matching with an adaptor
-type FilterFunc func(Adaptor) bool
-
-// Match matches the FilterFunc returning true if the object matches the filter
-func (fn FilterFunc) Match(adaptor Adaptor) bool {
- return fn(adaptor)
-}
-
-// Always is a filter that always returns true for any type of object
-var Always FilterFunc = func(adaptor Adaptor) bool {
- return true
-}
-
-// Any allows multiple filters to be matched against the object
-type Any []Filter
-
-// Match returns true if any of the provided filters are true
-func (m Any) Match(adaptor Adaptor) bool {
- for _, m := range m {
- if m.Match(adaptor) {
- return true
- }
- }
-
- return false
-}
-
-// All allows multiple filters to be matched against the object
-type All []Filter
-
-// Match only returns true if all filters match the object
-func (m All) Match(adaptor Adaptor) bool {
- for _, m := range m {
- if !m.Match(adaptor) {
- return false
- }
- }
-
- return true
-}
-
-type operator int
-
-const (
- operatorPresent = iota
- operatorEqual
- operatorNotEqual
- operatorMatches
-)
-
-func (op operator) String() string {
- switch op {
- case operatorPresent:
- return "?"
- case operatorEqual:
- return "=="
- case operatorNotEqual:
- return "!="
- case operatorMatches:
- return "~="
- }
-
- return "unknown"
-}
-
-type selector struct {
- fieldpath []string
- operator operator
- value string
- re *regexp.Regexp
-}
-
-func (m selector) Match(adaptor Adaptor) bool {
- value, present := adaptor.Field(m.fieldpath)
-
- switch m.operator {
- case operatorPresent:
- return present
- case operatorEqual:
- return present && value == m.value
- case operatorNotEqual:
- return value != m.value
- case operatorMatches:
- if m.re == nil {
- r, err := regexp.Compile(m.value)
- if err != nil {
- log.L.Errorf("error compiling regexp %q", m.value)
- return false
- }
-
- m.re = r
- }
-
- return m.re.MatchString(value)
- default:
- return false
- }
-}
diff --git a/vendor/github.com/containerd/containerd/filters/parser.go b/vendor/github.com/containerd/containerd/filters/parser.go
deleted file mode 100644
index 32767909b1..0000000000
--- a/vendor/github.com/containerd/containerd/filters/parser.go
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package filters
-
-import (
- "fmt"
- "io"
-
- "github.com/containerd/containerd/errdefs"
-)
-
-/*
-Parse the strings into a filter that may be used with an adaptor.
-
-The filter is made up of zero or more selectors.
-
-The format is a comma separated list of expressions, in the form of
-``, known as selectors. All selectors must match the
-target object for the filter to be true.
-
-We define the operators "==" for equality, "!=" for not equal and "~=" for a
-regular expression. If the operator and value are not present, the matcher will
-test for the presence of a value, as defined by the target object.
-
-The formal grammar is as follows:
-
-selectors := selector ("," selector)*
-selector := fieldpath (operator value)
-fieldpath := field ('.' field)*
-field := quoted | [A-Za-z] [A-Za-z0-9_]+
-operator := "==" | "!=" | "~="
-value := quoted | [^\s,]+
-quoted :=
-*/
-func Parse(s string) (Filter, error) {
- // special case empty to match all
- if s == "" {
- return Always, nil
- }
-
- p := parser{input: s}
- return p.parse()
-}
-
-// ParseAll parses each filter in ss and returns a filter that will return true
-// if any filter matches the expression.
-//
-// If no filters are provided, the filter will match anything.
-func ParseAll(ss ...string) (Filter, error) {
- if len(ss) == 0 {
- return Always, nil
- }
-
- var fs []Filter
- for _, s := range ss {
- f, err := Parse(s)
- if err != nil {
- return nil, fmt.Errorf("%s: %w", err.Error(), errdefs.ErrInvalidArgument)
- }
-
- fs = append(fs, f)
- }
-
- return Any(fs), nil
-}
-
-type parser struct {
- input string
- scanner scanner
-}
-
-func (p *parser) parse() (Filter, error) {
- p.scanner.init(p.input)
-
- ss, err := p.selectors()
- if err != nil {
- return nil, fmt.Errorf("filters: %w", err)
- }
-
- return ss, nil
-}
-
-func (p *parser) selectors() (Filter, error) {
- s, err := p.selector()
- if err != nil {
- return nil, err
- }
-
- ss := All{s}
-
-loop:
- for {
- tok := p.scanner.peek()
- switch tok {
- case ',':
- pos, tok, _ := p.scanner.scan()
- if tok != tokenSeparator {
- return nil, p.mkerr(pos, "expected a separator")
- }
-
- s, err := p.selector()
- if err != nil {
- return nil, err
- }
-
- ss = append(ss, s)
- case tokenEOF:
- break loop
- default:
- return nil, p.mkerr(p.scanner.ppos, "unexpected input: %v", string(tok))
- }
- }
-
- return ss, nil
-}
-
-func (p *parser) selector() (selector, error) {
- fieldpath, err := p.fieldpath()
- if err != nil {
- return selector{}, err
- }
-
- switch p.scanner.peek() {
- case ',', tokenSeparator, tokenEOF:
- return selector{
- fieldpath: fieldpath,
- operator: operatorPresent,
- }, nil
- }
-
- op, err := p.operator()
- if err != nil {
- return selector{}, err
- }
-
- var allowAltQuotes bool
- if op == operatorMatches {
- allowAltQuotes = true
- }
-
- value, err := p.value(allowAltQuotes)
- if err != nil {
- if err == io.EOF {
- return selector{}, io.ErrUnexpectedEOF
- }
- return selector{}, err
- }
-
- return selector{
- fieldpath: fieldpath,
- value: value,
- operator: op,
- }, nil
-}
-
-func (p *parser) fieldpath() ([]string, error) {
- f, err := p.field()
- if err != nil {
- return nil, err
- }
-
- fs := []string{f}
-loop:
- for {
- tok := p.scanner.peek() // lookahead to consume field separator
-
- switch tok {
- case '.':
- pos, tok, _ := p.scanner.scan() // consume separator
- if tok != tokenSeparator {
- return nil, p.mkerr(pos, "expected a field separator (`.`)")
- }
-
- f, err := p.field()
- if err != nil {
- return nil, err
- }
-
- fs = append(fs, f)
- default:
- // let the layer above handle the other bad cases.
- break loop
- }
- }
-
- return fs, nil
-}
-
-func (p *parser) field() (string, error) {
- pos, tok, s := p.scanner.scan()
- switch tok {
- case tokenField:
- return s, nil
- case tokenQuoted:
- return p.unquote(pos, s, false)
- case tokenIllegal:
- return "", p.mkerr(pos, p.scanner.err)
- }
-
- return "", p.mkerr(pos, "expected field or quoted")
-}
-
-func (p *parser) operator() (operator, error) {
- pos, tok, s := p.scanner.scan()
- switch tok {
- case tokenOperator:
- switch s {
- case "==":
- return operatorEqual, nil
- case "!=":
- return operatorNotEqual, nil
- case "~=":
- return operatorMatches, nil
- default:
- return 0, p.mkerr(pos, "unsupported operator %q", s)
- }
- case tokenIllegal:
- return 0, p.mkerr(pos, p.scanner.err)
- }
-
- return 0, p.mkerr(pos, `expected an operator ("=="|"!="|"~=")`)
-}
-
-func (p *parser) value(allowAltQuotes bool) (string, error) {
- pos, tok, s := p.scanner.scan()
-
- switch tok {
- case tokenValue, tokenField:
- return s, nil
- case tokenQuoted:
- return p.unquote(pos, s, allowAltQuotes)
- case tokenIllegal:
- return "", p.mkerr(pos, p.scanner.err)
- }
-
- return "", p.mkerr(pos, "expected value or quoted")
-}
-
-func (p *parser) unquote(pos int, s string, allowAlts bool) (string, error) {
- if !allowAlts && s[0] != '\'' && s[0] != '"' {
- return "", p.mkerr(pos, "invalid quote encountered")
- }
-
- uq, err := unquote(s)
- if err != nil {
- return "", p.mkerr(pos, "unquoting failed: %v", err)
- }
-
- return uq, nil
-}
-
-type parseError struct {
- input string
- pos int
- msg string
-}
-
-func (pe parseError) Error() string {
- if pe.pos < len(pe.input) {
- before := pe.input[:pe.pos]
- location := pe.input[pe.pos : pe.pos+1] // need to handle end
- after := pe.input[pe.pos+1:]
-
- return fmt.Sprintf("[%s >|%s|< %s]: %v", before, location, after, pe.msg)
- }
-
- return fmt.Sprintf("[%s]: %v", pe.input, pe.msg)
-}
-
-func (p *parser) mkerr(pos int, format string, args ...interface{}) error {
- return fmt.Errorf("parse error: %w", parseError{
- input: p.input,
- pos: pos,
- msg: fmt.Sprintf(format, args...),
- })
-}
diff --git a/vendor/github.com/containerd/containerd/log/context.go b/vendor/github.com/containerd/containerd/log/context.go
deleted file mode 100644
index 0db9562b82..0000000000
--- a/vendor/github.com/containerd/containerd/log/context.go
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package log
-
-import (
- "context"
-
- "github.com/sirupsen/logrus"
-)
-
-var (
- // G is an alias for GetLogger.
- //
- // We may want to define this locally to a package to get package tagged log
- // messages.
- G = GetLogger
-
- // L is an alias for the standard logger.
- L = logrus.NewEntry(logrus.StandardLogger())
-)
-
-type (
- loggerKey struct{}
-)
-
-const (
- // RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
- // ensure the formatted time is always the same number of characters.
- RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
-
- // TextFormat represents the text logging format
- TextFormat = "text"
-
- // JSONFormat represents the JSON logging format
- JSONFormat = "json"
-)
-
-// WithLogger returns a new context with the provided logger. Use in
-// combination with logger.WithField(s) for great effect.
-func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
- e := logger.WithContext(ctx)
- return context.WithValue(ctx, loggerKey{}, e)
-}
-
-// GetLogger retrieves the current logger from the context. If no logger is
-// available, the default logger is returned.
-func GetLogger(ctx context.Context) *logrus.Entry {
- logger := ctx.Value(loggerKey{})
-
- if logger == nil {
- return L.WithContext(ctx)
- }
-
- return logger.(*logrus.Entry)
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/compare.go b/vendor/github.com/containerd/containerd/platforms/compare.go
deleted file mode 100644
index 3913ef6637..0000000000
--- a/vendor/github.com/containerd/containerd/platforms/compare.go
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package platforms
-
-import (
- "strconv"
- "strings"
-
- specs "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-// MatchComparer is able to match and compare platforms to
-// filter and sort platforms.
-type MatchComparer interface {
- Matcher
-
- Less(specs.Platform, specs.Platform) bool
-}
-
-// platformVector returns an (ordered) vector of appropriate specs.Platform
-// objects to try matching for the given platform object (see platforms.Only).
-func platformVector(platform specs.Platform) []specs.Platform {
- vector := []specs.Platform{platform}
-
- switch platform.Architecture {
- case "amd64":
- if amd64Version, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && amd64Version > 1 {
- for amd64Version--; amd64Version >= 1; amd64Version-- {
- vector = append(vector, specs.Platform{
- Architecture: platform.Architecture,
- OS: platform.OS,
- OSVersion: platform.OSVersion,
- OSFeatures: platform.OSFeatures,
- Variant: "v" + strconv.Itoa(amd64Version),
- })
- }
- }
- vector = append(vector, specs.Platform{
- Architecture: "386",
- OS: platform.OS,
- OSVersion: platform.OSVersion,
- OSFeatures: platform.OSFeatures,
- })
- case "arm":
- if armVersion, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && armVersion > 5 {
- for armVersion--; armVersion >= 5; armVersion-- {
- vector = append(vector, specs.Platform{
- Architecture: platform.Architecture,
- OS: platform.OS,
- OSVersion: platform.OSVersion,
- OSFeatures: platform.OSFeatures,
- Variant: "v" + strconv.Itoa(armVersion),
- })
- }
- }
- case "arm64":
- variant := platform.Variant
- if variant == "" {
- variant = "v8"
- }
- vector = append(vector, platformVector(specs.Platform{
- Architecture: "arm",
- OS: platform.OS,
- OSVersion: platform.OSVersion,
- OSFeatures: platform.OSFeatures,
- Variant: variant,
- })...)
- }
-
- return vector
-}
-
-// Only returns a match comparer for a single platform
-// using default resolution logic for the platform.
-//
-// For arm/v8, will also match arm/v7, arm/v6 and arm/v5
-// For arm/v7, will also match arm/v6 and arm/v5
-// For arm/v6, will also match arm/v5
-// For amd64, will also match 386
-func Only(platform specs.Platform) MatchComparer {
- return Ordered(platformVector(Normalize(platform))...)
-}
-
-// OnlyStrict returns a match comparer for a single platform.
-//
-// Unlike Only, OnlyStrict does not match sub platforms.
-// So, "arm/vN" will not match "arm/vM" where M < N,
-// and "amd64" will not also match "386".
-//
-// OnlyStrict matches non-canonical forms.
-// So, "arm64" matches "arm/64/v8".
-func OnlyStrict(platform specs.Platform) MatchComparer {
- return Ordered(Normalize(platform))
-}
-
-// Ordered returns a platform MatchComparer which matches any of the platforms
-// but orders them in order they are provided.
-func Ordered(platforms ...specs.Platform) MatchComparer {
- matchers := make([]Matcher, len(platforms))
- for i := range platforms {
- matchers[i] = NewMatcher(platforms[i])
- }
- return orderedPlatformComparer{
- matchers: matchers,
- }
-}
-
-// Any returns a platform MatchComparer which matches any of the platforms
-// with no preference for ordering.
-func Any(platforms ...specs.Platform) MatchComparer {
- matchers := make([]Matcher, len(platforms))
- for i := range platforms {
- matchers[i] = NewMatcher(platforms[i])
- }
- return anyPlatformComparer{
- matchers: matchers,
- }
-}
-
-// All is a platform MatchComparer which matches all platforms
-// with preference for ordering.
-var All MatchComparer = allPlatformComparer{}
-
-type orderedPlatformComparer struct {
- matchers []Matcher
-}
-
-func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
- for _, m := range c.matchers {
- if m.Match(platform) {
- return true
- }
- }
- return false
-}
-
-func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
- for _, m := range c.matchers {
- p1m := m.Match(p1)
- p2m := m.Match(p2)
- if p1m && !p2m {
- return true
- }
- if p1m || p2m {
- return false
- }
- }
- return false
-}
-
-type anyPlatformComparer struct {
- matchers []Matcher
-}
-
-func (c anyPlatformComparer) Match(platform specs.Platform) bool {
- for _, m := range c.matchers {
- if m.Match(platform) {
- return true
- }
- }
- return false
-}
-
-func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
- var p1m, p2m bool
- for _, m := range c.matchers {
- if !p1m && m.Match(p1) {
- p1m = true
- }
- if !p2m && m.Match(p2) {
- p2m = true
- }
- if p1m && p2m {
- return false
- }
- }
- // If one matches, and the other does, sort match first
- return p1m && !p2m
-}
-
-type allPlatformComparer struct{}
-
-func (allPlatformComparer) Match(specs.Platform) bool {
- return true
-}
-
-func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
- return false
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/cpuinfo.go b/vendor/github.com/containerd/containerd/platforms/cpuinfo.go
deleted file mode 100644
index 046e0356d1..0000000000
--- a/vendor/github.com/containerd/containerd/platforms/cpuinfo.go
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package platforms
-
-import (
- "bufio"
- "fmt"
- "os"
- "runtime"
- "strings"
- "sync"
-
- "github.com/containerd/containerd/errdefs"
- "github.com/containerd/containerd/log"
-)
-
-// Present the ARM instruction set architecture, eg: v7, v8
-// Don't use this value directly; call cpuVariant() instead.
-var cpuVariantValue string
-
-var cpuVariantOnce sync.Once
-
-func cpuVariant() string {
- cpuVariantOnce.Do(func() {
- if isArmArch(runtime.GOARCH) {
- cpuVariantValue = getCPUVariant()
- }
- })
- return cpuVariantValue
-}
-
-// For Linux, the kernel has already detected the ABI, ISA and Features.
-// So we don't need to access the ARM registers to detect platform information
-// by ourselves. We can just parse these information from /proc/cpuinfo
-func getCPUInfo(pattern string) (info string, err error) {
- if !isLinuxOS(runtime.GOOS) {
- return "", fmt.Errorf("getCPUInfo for OS %s: %w", runtime.GOOS, errdefs.ErrNotImplemented)
- }
-
- cpuinfo, err := os.Open("/proc/cpuinfo")
- if err != nil {
- return "", err
- }
- defer cpuinfo.Close()
-
- // Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
- // the first core is enough.
- scanner := bufio.NewScanner(cpuinfo)
- for scanner.Scan() {
- newline := scanner.Text()
- list := strings.Split(newline, ":")
-
- if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
- return strings.TrimSpace(list[1]), nil
- }
- }
-
- // Check whether the scanner encountered errors
- err = scanner.Err()
- if err != nil {
- return "", err
- }
-
- return "", fmt.Errorf("getCPUInfo for pattern: %s: %w", pattern, errdefs.ErrNotFound)
-}
-
-func getCPUVariant() string {
- if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
- // Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
- // runtime.GOARCH to determine the variants
- var variant string
- switch runtime.GOARCH {
- case "arm64":
- variant = "v8"
- case "arm":
- variant = "v7"
- default:
- variant = "unknown"
- }
-
- return variant
- }
-
- variant, err := getCPUInfo("Cpu architecture")
- if err != nil {
- log.L.WithError(err).Error("failure getting variant")
- return ""
- }
-
- // handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
- // https://www.raspberrypi.org/forums/viewtopic.php?t=12614
- if runtime.GOARCH == "arm" && variant == "7" {
- model, err := getCPUInfo("model name")
- if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
- variant = "6"
- }
- }
-
- switch strings.ToLower(variant) {
- case "8", "aarch64":
- variant = "v8"
- case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
- variant = "v7"
- case "6", "6tej":
- variant = "v6"
- case "5", "5t", "5te", "5tej":
- variant = "v5"
- case "4", "4t":
- variant = "v4"
- case "3":
- variant = "v3"
- default:
- variant = "unknown"
- }
-
- return variant
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults.go b/vendor/github.com/containerd/containerd/platforms/defaults.go
deleted file mode 100644
index cfa3ff34a1..0000000000
--- a/vendor/github.com/containerd/containerd/platforms/defaults.go
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package platforms
-
-// DefaultString returns the default string specifier for the platform.
-func DefaultString() string {
- return Format(DefaultSpec())
-}
-
-// DefaultStrict returns strict form of Default.
-func DefaultStrict() MatchComparer {
- return OnlyStrict(DefaultSpec())
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults_darwin.go b/vendor/github.com/containerd/containerd/platforms/defaults_darwin.go
deleted file mode 100644
index e249fe48d3..0000000000
--- a/vendor/github.com/containerd/containerd/platforms/defaults_darwin.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build darwin
-// +build darwin
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package platforms
-
-import (
- "runtime"
-
- specs "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-// DefaultSpec returns the current platform's default platform specification.
-func DefaultSpec() specs.Platform {
- return specs.Platform{
- OS: runtime.GOOS,
- Architecture: runtime.GOARCH,
- // The Variant field will be empty if arch != ARM.
- Variant: cpuVariant(),
- }
-}
-
-// Default returns the default matcher for the platform.
-func Default() MatchComparer {
- return Ordered(DefaultSpec(), specs.Platform{
- // darwin runtime also supports Linux binary via runu/LKL
- OS: "linux",
- Architecture: runtime.GOARCH,
- })
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults_unix.go b/vendor/github.com/containerd/containerd/platforms/defaults_unix.go
deleted file mode 100644
index 49690f1b3e..0000000000
--- a/vendor/github.com/containerd/containerd/platforms/defaults_unix.go
+++ /dev/null
@@ -1,41 +0,0 @@
-//go:build !windows && !darwin
-// +build !windows,!darwin
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package platforms
-
-import (
- "runtime"
-
- specs "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-// DefaultSpec returns the current platform's default platform specification.
-func DefaultSpec() specs.Platform {
- return specs.Platform{
- OS: runtime.GOOS,
- Architecture: runtime.GOARCH,
- // The Variant field will be empty if arch != ARM.
- Variant: cpuVariant(),
- }
-}
-
-// Default returns the default matcher for the platform.
-func Default() MatchComparer {
- return Only(DefaultSpec())
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults_windows.go b/vendor/github.com/containerd/containerd/platforms/defaults_windows.go
deleted file mode 100644
index ff9771a600..0000000000
--- a/vendor/github.com/containerd/containerd/platforms/defaults_windows.go
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package platforms
-
-import (
- "fmt"
- "runtime"
- "strconv"
- "strings"
-
- imagespec "github.com/opencontainers/image-spec/specs-go/v1"
- specs "github.com/opencontainers/image-spec/specs-go/v1"
- "golang.org/x/sys/windows"
-)
-
-// DefaultSpec returns the current platform's default platform specification.
-func DefaultSpec() specs.Platform {
- major, minor, build := windows.RtlGetNtVersionNumbers()
- return specs.Platform{
- OS: runtime.GOOS,
- Architecture: runtime.GOARCH,
- OSVersion: fmt.Sprintf("%d.%d.%d", major, minor, build),
- // The Variant field will be empty if arch != ARM.
- Variant: cpuVariant(),
- }
-}
-
-type matchComparer struct {
- defaults Matcher
- osVersionPrefix string
-}
-
-// Match matches platform with the same windows major, minor
-// and build version.
-func (m matchComparer) Match(p specs.Platform) bool {
- match := m.defaults.Match(p)
-
- if match && p.OS == "windows" {
- if strings.HasPrefix(p.OSVersion, m.osVersionPrefix) {
- return true
- }
- return p.OSVersion == ""
- }
- return false
-}
-
-// Less sorts matched platforms in front of other platforms.
-// For matched platforms, it puts platforms with larger revision
-// number in front.
-func (m matchComparer) Less(p1, p2 imagespec.Platform) bool {
- m1, m2 := m.Match(p1), m.Match(p2)
- if m1 && m2 {
- r1, r2 := revision(p1.OSVersion), revision(p2.OSVersion)
- return r1 > r2
- }
- return m1 && !m2
-}
-
-func revision(v string) int {
- parts := strings.Split(v, ".")
- if len(parts) < 4 {
- return 0
- }
- r, err := strconv.Atoi(parts[3])
- if err != nil {
- return 0
- }
- return r
-}
-
-// Default returns the current platform's default platform specification.
-func Default() MatchComparer {
- major, minor, build := windows.RtlGetNtVersionNumbers()
- return matchComparer{
- defaults: Ordered(DefaultSpec(), specs.Platform{
- OS: "linux",
- Architecture: runtime.GOARCH,
- }),
- osVersionPrefix: fmt.Sprintf("%d.%d.%d", major, minor, build),
- }
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/platforms.go b/vendor/github.com/containerd/containerd/platforms/platforms.go
deleted file mode 100644
index 2343099418..0000000000
--- a/vendor/github.com/containerd/containerd/platforms/platforms.go
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-// Package platforms provides a toolkit for normalizing, matching and
-// specifying container platforms.
-//
-// Centered around OCI platform specifications, we define a string-based
-// specifier syntax that can be used for user input. With a specifier, users
-// only need to specify the parts of the platform that are relevant to their
-// context, providing an operating system or architecture or both.
-//
-// How do I use this package?
-//
-// The vast majority of use cases should simply use the match function with
-// user input. The first step is to parse a specifier into a matcher:
-//
-// m, err := Parse("linux")
-// if err != nil { ... }
-//
-// Once you have a matcher, use it to match against the platform declared by a
-// component, typically from an image or runtime. Since extracting an images
-// platform is a little more involved, we'll use an example against the
-// platform default:
-//
-// if ok := m.Match(Default()); !ok { /* doesn't match */ }
-//
-// This can be composed in loops for resolving runtimes or used as a filter for
-// fetch and select images.
-//
-// More details of the specifier syntax and platform spec follow.
-//
-// # Declaring Platform Support
-//
-// Components that have strict platform requirements should use the OCI
-// platform specification to declare their support. Typically, this will be
-// images and runtimes that should make these declaring which platform they
-// support specifically. This looks roughly as follows:
-//
-// type Platform struct {
-// Architecture string
-// OS string
-// Variant string
-// }
-//
-// Most images and runtimes should at least set Architecture and OS, according
-// to their GOARCH and GOOS values, respectively (follow the OCI image
-// specification when in doubt). ARM should set variant under certain
-// discussions, which are outlined below.
-//
-// # Platform Specifiers
-//
-// While the OCI platform specifications provide a tool for components to
-// specify structured information, user input typically doesn't need the full
-// context and much can be inferred. To solve this problem, we introduced
-// "specifiers". A specifier has the format
-// `||/[/]`. The user can provide either the
-// operating system or the architecture or both.
-//
-// An example of a common specifier is `linux/amd64`. If the host has a default
-// of runtime that matches this, the user can simply provide the component that
-// matters. For example, if a image provides amd64 and arm64 support, the
-// operating system, `linux` can be inferred, so they only have to provide
-// `arm64` or `amd64`. Similar behavior is implemented for operating systems,
-// where the architecture may be known but a runtime may support images from
-// different operating systems.
-//
-// # Normalization
-//
-// Because not all users are familiar with the way the Go runtime represents
-// platforms, several normalizations have been provided to make this package
-// easier to user.
-//
-// The following are performed for architectures:
-//
-// Value Normalized
-// aarch64 arm64
-// armhf arm
-// armel arm/v6
-// i386 386
-// x86_64 amd64
-// x86-64 amd64
-//
-// We also normalize the operating system `macos` to `darwin`.
-//
-// # ARM Support
-//
-// To qualify ARM architecture, the Variant field is used to qualify the arm
-// version. The most common arm version, v7, is represented without the variant
-// unless it is explicitly provided. This is treated as equivalent to armhf. A
-// previous architecture, armel, will be normalized to arm/v6.
-//
-// While these normalizations are provided, their support on arm platforms has
-// not yet been fully implemented and tested.
-package platforms
-
-import (
- "fmt"
- "path"
- "regexp"
- "runtime"
- "strconv"
- "strings"
-
- "github.com/containerd/containerd/errdefs"
- specs "github.com/opencontainers/image-spec/specs-go/v1"
-)
-
-var (
- specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
-)
-
-// Matcher matches platforms specifications, provided by an image or runtime.
-type Matcher interface {
- Match(platform specs.Platform) bool
-}
-
-// NewMatcher returns a simple matcher based on the provided platform
-// specification. The returned matcher only looks for equality based on os,
-// architecture and variant.
-//
-// One may implement their own matcher if this doesn't provide the required
-// functionality.
-//
-// Applications should opt to use `Match` over directly parsing specifiers.
-func NewMatcher(platform specs.Platform) Matcher {
- return &matcher{
- Platform: Normalize(platform),
- }
-}
-
-type matcher struct {
- specs.Platform
-}
-
-func (m *matcher) Match(platform specs.Platform) bool {
- normalized := Normalize(platform)
- return m.OS == normalized.OS &&
- m.Architecture == normalized.Architecture &&
- m.Variant == normalized.Variant
-}
-
-func (m *matcher) String() string {
- return Format(m.Platform)
-}
-
-// Parse parses the platform specifier syntax into a platform declaration.
-//
-// Platform specifiers are in the format `||/[/]`.
-// The minimum required information for a platform specifier is the operating
-// system or architecture. If there is only a single string (no slashes), the
-// value will be matched against the known set of operating systems, then fall
-// back to the known set of architectures. The missing component will be
-// inferred based on the local environment.
-func Parse(specifier string) (specs.Platform, error) {
- if strings.Contains(specifier, "*") {
- // TODO(stevvooe): need to work out exact wildcard handling
- return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errdefs.ErrInvalidArgument)
- }
-
- parts := strings.Split(specifier, "/")
-
- for _, part := range parts {
- if !specifierRe.MatchString(part) {
- return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errdefs.ErrInvalidArgument)
- }
- }
-
- var p specs.Platform
- switch len(parts) {
- case 1:
- // in this case, we will test that the value might be an OS, then look
- // it up. If it is not known, we'll treat it as an architecture. Since
- // we have very little information about the platform here, we are
- // going to be a little more strict if we don't know about the argument
- // value.
- p.OS = normalizeOS(parts[0])
- if isKnownOS(p.OS) {
- // picks a default architecture
- p.Architecture = runtime.GOARCH
- if p.Architecture == "arm" && cpuVariant() != "v7" {
- p.Variant = cpuVariant()
- }
-
- return p, nil
- }
-
- p.Architecture, p.Variant = normalizeArch(parts[0], "")
- if p.Architecture == "arm" && p.Variant == "v7" {
- p.Variant = ""
- }
- if isKnownArch(p.Architecture) {
- p.OS = runtime.GOOS
- return p, nil
- }
-
- return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errdefs.ErrInvalidArgument)
- case 2:
- // In this case, we treat as a regular os/arch pair. We don't care
- // about whether or not we know of the platform.
- p.OS = normalizeOS(parts[0])
- p.Architecture, p.Variant = normalizeArch(parts[1], "")
- if p.Architecture == "arm" && p.Variant == "v7" {
- p.Variant = ""
- }
-
- return p, nil
- case 3:
- // we have a fully specified variant, this is rare
- p.OS = normalizeOS(parts[0])
- p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
- if p.Architecture == "arm64" && p.Variant == "" {
- p.Variant = "v8"
- }
-
- return p, nil
- }
-
- return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errdefs.ErrInvalidArgument)
-}
-
-// MustParse is like Parses but panics if the specifier cannot be parsed.
-// Simplifies initialization of global variables.
-func MustParse(specifier string) specs.Platform {
- p, err := Parse(specifier)
- if err != nil {
- panic("platform: Parse(" + strconv.Quote(specifier) + "): " + err.Error())
- }
- return p
-}
-
-// Format returns a string specifier from the provided platform specification.
-func Format(platform specs.Platform) string {
- if platform.OS == "" {
- return "unknown"
- }
-
- return path.Join(platform.OS, platform.Architecture, platform.Variant)
-}
-
-// Normalize validates and translate the platform to the canonical value.
-//
-// For example, if "Aarch64" is encountered, we change it to "arm64" or if
-// "x86_64" is encountered, it becomes "amd64".
-func Normalize(platform specs.Platform) specs.Platform {
- platform.OS = normalizeOS(platform.OS)
- platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)
- return platform
-}
diff --git a/vendor/github.com/containerd/containerd/remotes/errors/errors.go b/vendor/github.com/containerd/containerd/remotes/errors/errors.go
deleted file mode 100644
index 67ccb23df6..0000000000
--- a/vendor/github.com/containerd/containerd/remotes/errors/errors.go
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package errors
-
-import (
- "fmt"
- "io"
- "net/http"
-)
-
-var _ error = ErrUnexpectedStatus{}
-
-// ErrUnexpectedStatus is returned if a registry API request returned with unexpected HTTP status
-type ErrUnexpectedStatus struct {
- Status string
- StatusCode int
- Body []byte
- RequestURL, RequestMethod string
-}
-
-func (e ErrUnexpectedStatus) Error() string {
- return fmt.Sprintf("unexpected status: %s", e.Status)
-}
-
-// NewUnexpectedStatusErr creates an ErrUnexpectedStatus from HTTP response
-func NewUnexpectedStatusErr(resp *http.Response) error {
- var b []byte
- if resp.Body != nil {
- b, _ = io.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB
- }
- err := ErrUnexpectedStatus{
- Body: b,
- Status: resp.Status,
- StatusCode: resp.StatusCode,
- RequestMethod: resp.Request.Method,
- }
- if resp.Request.URL != nil {
- err.RequestURL = resp.Request.URL.String()
- }
- return err
-}
diff --git a/vendor/github.com/containerd/typeurl/LICENSE b/vendor/github.com/containerd/containerd/v2/LICENSE
similarity index 100%
rename from vendor/github.com/containerd/typeurl/LICENSE
rename to vendor/github.com/containerd/containerd/v2/LICENSE
diff --git a/vendor/github.com/containerd/containerd/NOTICE b/vendor/github.com/containerd/containerd/v2/NOTICE
similarity index 100%
rename from vendor/github.com/containerd/containerd/NOTICE
rename to vendor/github.com/containerd/containerd/v2/NOTICE
diff --git a/vendor/github.com/containerd/containerd/content/adaptor.go b/vendor/github.com/containerd/containerd/v2/core/content/adaptor.go
similarity index 96%
rename from vendor/github.com/containerd/containerd/content/adaptor.go
rename to vendor/github.com/containerd/containerd/v2/core/content/adaptor.go
index 88bad2610e..4ba6cc74d3 100644
--- a/vendor/github.com/containerd/containerd/content/adaptor.go
+++ b/vendor/github.com/containerd/containerd/v2/core/content/adaptor.go
@@ -19,7 +19,7 @@ package content
import (
"strings"
- "github.com/containerd/containerd/filters"
+ "github.com/containerd/containerd/v2/pkg/filters"
)
// AdaptInfo returns `filters.Adaptor` that handles `content.Info`.
diff --git a/vendor/github.com/containerd/containerd/v2/core/content/content.go b/vendor/github.com/containerd/containerd/v2/core/content/content.go
new file mode 100644
index 0000000000..05c8883ec0
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/content/content.go
@@ -0,0 +1,217 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package content
+
+import (
+ "context"
+ "io"
+ "time"
+
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// Store combines the methods of content-oriented interfaces into a set that
+// are commonly provided by complete implementations.
+//
+// Overall content lifecycle:
+// - Ingester is used to initiate a write operation (aka ingestion)
+// - IngestManager is used to manage (e.g. list, abort) active ingestions
+// - Once an ingestion is complete (see Writer.Commit), Provider is used to
+// query a single piece of content by its digest
+// - Manager is used to manage (e.g. list, delete) previously committed content
+//
+// Note that until ingestion is complete, its content is not visible through
+// Provider or Manager. Once ingestion is complete, it is no longer exposed
+// through IngestManager.
+type Store interface {
+ Manager
+ Provider
+ IngestManager
+ Ingester
+}
+
+// ReaderAt extends the standard io.ReaderAt interface with reporting of Size and io.Closer
+type ReaderAt interface {
+ io.ReaderAt
+ io.Closer
+ Size() int64
+}
+
+// Provider provides a reader interface for specific content
+type Provider interface {
+ // ReaderAt only requires desc.Digest to be set.
+ // Other fields in the descriptor may be used internally for resolving
+ // the location of the actual data.
+ ReaderAt(ctx context.Context, desc ocispec.Descriptor) (ReaderAt, error)
+}
+
+// Ingester writes content
+type Ingester interface {
+ // Writer initiates a writing operation (aka ingestion). A single ingestion
+ // is uniquely identified by its ref, provided using a WithRef option.
+ // Writer can be called multiple times with the same ref to access the same
+ // ingestion.
+ // Once all the data is written, use Writer.Commit to complete the ingestion.
+ Writer(ctx context.Context, opts ...WriterOpt) (Writer, error)
+}
+
+// IngestManager provides methods for managing ingestions. An ingestion is a
+// not-yet-complete writing operation initiated using Ingester and identified
+// by a ref string.
+type IngestManager interface {
+ // Status returns the status of the provided ref.
+ Status(ctx context.Context, ref string) (Status, error)
+
+ // ListStatuses returns the status of any active ingestions whose ref match
+ // the provided regular expression. If empty, all active ingestions will be
+ // returned.
+ ListStatuses(ctx context.Context, filters ...string) ([]Status, error)
+
+ // Abort completely cancels the ingest operation targeted by ref.
+ Abort(ctx context.Context, ref string) error
+}
+
+// Info holds content specific information
+type Info struct {
+ Digest digest.Digest
+ Size int64
+ CreatedAt time.Time
+ UpdatedAt time.Time
+ Labels map[string]string
+}
+
+// Status of a content operation (i.e. an ingestion)
+type Status struct {
+ Ref string
+ Offset int64
+ Total int64
+ Expected digest.Digest
+ StartedAt time.Time
+ UpdatedAt time.Time
+}
+
+// WalkFunc defines the callback for a blob walk.
+type WalkFunc func(Info) error
+
+// InfoReaderProvider provides both info and reader for the specific content.
+type InfoReaderProvider interface {
+ InfoProvider
+ Provider
+}
+
+// InfoProvider provides info for content inspection.
+type InfoProvider interface {
+ // Info will return metadata about content available in the content store.
+ //
+ // If the content is not present, ErrNotFound will be returned.
+ Info(ctx context.Context, dgst digest.Digest) (Info, error)
+}
+
+// Manager provides methods for inspecting, listing and removing content.
+type Manager interface {
+ InfoProvider
+
+ // Update updates mutable information related to content.
+ // If one or more fieldpaths are provided, only those
+ // fields will be updated.
+ // Mutable fields:
+ // labels.*
+ Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error)
+
+ // Walk will call fn for each item in the content store which
+ // match the provided filters. If no filters are given all
+ // items will be walked.
+ Walk(ctx context.Context, fn WalkFunc, filters ...string) error
+
+ // Delete removes the content from the store.
+ Delete(ctx context.Context, dgst digest.Digest) error
+}
+
+// Writer handles writing of content into a content store
+type Writer interface {
+ // Close closes the writer, if the writer has not been
+ // committed this allows resuming or aborting.
+ // Calling Close on a closed writer will not error.
+ io.WriteCloser
+
+ // Digest may return empty digest or panics until committed.
+ Digest() digest.Digest
+
+ // Commit commits the blob (but no roll-back is guaranteed on an error).
+ // size and expected can be zero-value when unknown.
+ // Commit always closes the writer, even on error.
+ // ErrAlreadyExists aborts the writer.
+ Commit(ctx context.Context, size int64, expected digest.Digest, opts ...Opt) error
+
+ // Status returns the current state of write
+ Status() (Status, error)
+
+ // Truncate updates the size of the target blob
+ Truncate(size int64) error
+}
+
+type Syncer interface {
+ // Sync flushes the in-flight writes to the disk (when applicable)
+ Sync() error
+}
+
+// ReferrersProvider handles looking up additional referrer objects for a given descriptor.
+type ReferrersProvider interface {
+ Referrers(context.Context, ocispec.Descriptor) ([]ocispec.Descriptor, error)
+}
+
+// Opt is used to alter the mutable properties of content
+type Opt func(*Info) error
+
+// WithLabels allows labels to be set on content
+func WithLabels(labels map[string]string) Opt {
+ return func(info *Info) error {
+ info.Labels = labels
+ return nil
+ }
+}
+
+// WriterOpts is internally used by WriterOpt.
+type WriterOpts struct {
+ Ref string
+ Desc ocispec.Descriptor
+}
+
+// WriterOpt is used for passing options to Ingester.Writer.
+type WriterOpt func(*WriterOpts) error
+
+// WithDescriptor specifies an OCI descriptor.
+// Writer may optionally use the descriptor internally for resolving
+// the location of the actual data.
+// Write does not require any field of desc to be set.
+// If the data size is unknown, desc.Size should be set to 0.
+// Some implementations may also accept negative values as "unknown".
+func WithDescriptor(desc ocispec.Descriptor) WriterOpt {
+ return func(opts *WriterOpts) error {
+ opts.Desc = desc
+ return nil
+ }
+}
+
+// WithRef specifies a ref string.
+func WithRef(ref string) WriterOpt {
+ return func(opts *WriterOpts) error {
+ opts.Ref = ref
+ return nil
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/content/helpers.go b/vendor/github.com/containerd/containerd/v2/core/content/helpers.go
new file mode 100644
index 0000000000..749e65311e
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/content/helpers.go
@@ -0,0 +1,353 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package content
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "sync"
+ "time"
+
+ "github.com/containerd/containerd/v2/internal/randutil"
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+var ErrReset = errors.New("writer has been reset")
+
+var bufPool = sync.Pool{
+ New: func() interface{} {
+ buffer := make([]byte, 1<<20)
+ return &buffer
+ },
+}
+
+type reader interface {
+ Reader() io.Reader
+}
+
+// NewReader returns a io.Reader from a ReaderAt
+func NewReader(ra ReaderAt) io.Reader {
+ if rd, ok := ra.(reader); ok {
+ return rd.Reader()
+ }
+ return io.NewSectionReader(ra, 0, ra.Size())
+}
+
+type nopCloserBytesReader struct {
+ *bytes.Reader
+}
+
+func (*nopCloserBytesReader) Close() error { return nil }
+
+type nopCloserSectionReader struct {
+ *io.SectionReader
+}
+
+func (*nopCloserSectionReader) Close() error { return nil }
+
+// BlobReadSeeker returns a read seeker for the blob from the provider.
+func BlobReadSeeker(ctx context.Context, provider Provider, desc ocispec.Descriptor) (io.ReadSeekCloser, error) {
+ if int64(len(desc.Data)) == desc.Size && digest.FromBytes(desc.Data) == desc.Digest {
+ return &nopCloserBytesReader{bytes.NewReader(desc.Data)}, nil
+ }
+
+ ra, err := provider.ReaderAt(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+ return &nopCloserSectionReader{io.NewSectionReader(ra, 0, ra.Size())}, nil
+}
+
+// ReadBlob retrieves the entire contents of the blob from the provider.
+//
+// Avoid using this for large blobs, such as layers.
+func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) ([]byte, error) {
+ if int64(len(desc.Data)) == desc.Size && digest.FromBytes(desc.Data) == desc.Digest {
+ return desc.Data, nil
+ }
+
+ ra, err := provider.ReaderAt(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+ defer ra.Close()
+
+ p := make([]byte, ra.Size())
+
+ n, err := ra.ReadAt(p, 0)
+ if err == io.EOF {
+ if int64(n) != ra.Size() {
+ err = io.ErrUnexpectedEOF
+ } else {
+ err = nil
+ }
+ }
+ return p, err
+}
+
+// WriteBlob writes data with the expected digest into the content store. If
+// expected already exists, the method returns immediately and the reader will
+// not be consumed.
+//
+// This is useful when the digest and size are known beforehand.
+//
+// Copy is buffered, so no need to wrap reader in buffered io.
+func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, desc ocispec.Descriptor, opts ...Opt) error {
+ cw, err := OpenWriter(ctx, cs, WithRef(ref), WithDescriptor(desc))
+ if err != nil {
+ if !errdefs.IsAlreadyExists(err) {
+ return fmt.Errorf("failed to open writer: %w", err)
+ }
+
+ return nil // already present
+ }
+ defer cw.Close()
+
+ return Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
+}
+
+// OpenWriter opens a new writer for the given reference, retrying if the writer
+// is locked until the reference is available or returns an error.
+func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, error) {
+ var (
+ cw Writer
+ err error
+ retry = 16
+ )
+ for {
+ cw, err = cs.Writer(ctx, opts...)
+ if err != nil {
+ if !errdefs.IsUnavailable(err) {
+ return nil, err
+ }
+
+ // TODO: Check status to determine if the writer is active,
+ // continue waiting while active, otherwise return lock
+ // error or abort. Requires asserting for an ingest manager
+
+ select {
+ case <-time.After(time.Millisecond * time.Duration(randutil.Intn(retry))):
+ if retry < 2048 {
+ retry = retry << 1
+ }
+ continue
+ case <-ctx.Done():
+ // Propagate lock error
+ return nil, err
+ }
+
+ }
+ break
+ }
+
+ return cw, err
+}
+
+// Copy copies data with the expected digest from the reader into the
+// provided content store writer. This copy commits the writer.
+//
+// This is useful when the digest and size are known beforehand. When
+// the size or digest is unknown, these values may be empty.
+//
+// Copy is buffered, so no need to wrap reader in buffered io.
+func Copy(ctx context.Context, cw Writer, or io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
+ r := or
+ for i := 0; ; i++ {
+ if i >= 1 {
+ log.G(ctx).WithField("digest", expected).Debugf("retrying copy due to reset")
+ }
+
+ ws, err := cw.Status()
+ if err != nil {
+ return fmt.Errorf("failed to get status: %w", err)
+ }
+ // Reset the original reader if
+ // 1. there is an offset, or
+ // 2. this is a retry due to Reset error
+ if ws.Offset > 0 || i > 0 {
+ r, err = seekReader(or, ws.Offset, size)
+ if err != nil {
+ return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
+ }
+ }
+
+ copied, err := copyWithBuffer(cw, r)
+ if errors.Is(err, ErrReset) {
+ continue
+ }
+ if err != nil {
+ return fmt.Errorf("failed to copy: %w", err)
+ }
+ if size != 0 && copied < size-ws.Offset {
+ // Short writes would return its own error, this indicates a read failure
+ return fmt.Errorf("short read: expected %d bytes but got %d: %w", size-ws.Offset, copied, io.ErrUnexpectedEOF)
+ }
+ if err := cw.Commit(ctx, size, expected, opts...); err != nil {
+ if errors.Is(err, ErrReset) {
+ continue
+ }
+ if !errdefs.IsAlreadyExists(err) {
+ return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err)
+ }
+ }
+ return nil
+ }
+}
+
+// CopyReaderAt copies to a writer from a given reader at for the given
+// number of bytes. This copy does not commit the writer.
+func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
+ ws, err := cw.Status()
+ if err != nil {
+ return err
+ }
+
+ copied, err := copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n))
+ if err != nil {
+ return fmt.Errorf("failed to copy: %w", err)
+ }
+ if copied < n {
+ // Short writes would return its own error, this indicates a read failure
+ return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF)
+ }
+ return nil
+}
+
+// CopyReader copies to a writer from a given reader, returning
+// the number of bytes copied.
+// Note: if the writer has a non-zero offset, the total number
+// of bytes read may be greater than those copied if the reader
+// is not an io.Seeker.
+// This copy does not commit the writer.
+func CopyReader(cw Writer, r io.Reader) (int64, error) {
+ ws, err := cw.Status()
+ if err != nil {
+ return 0, fmt.Errorf("failed to get status: %w", err)
+ }
+
+ if ws.Offset > 0 {
+ r, err = seekReader(r, ws.Offset, 0)
+ if err != nil {
+ return 0, fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
+ }
+ }
+
+ return copyWithBuffer(cw, r)
+}
+
+// seekReader attempts to seek the reader to the given offset, either by
+// resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding
+// up to the given offset.
+func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
+ // attempt to resolve r as a seeker and setup the offset.
+ seeker, ok := r.(io.Seeker)
+ if ok {
+ nn, err := seeker.Seek(offset, io.SeekStart)
+ if nn != offset {
+ if err == nil {
+ err = fmt.Errorf("unexpected seek location without seek error")
+ }
+ return nil, fmt.Errorf("failed to seek to offset %v: %w", offset, err)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ return r, nil
+ }
+
+ // ok, let's try io.ReaderAt!
+ readerAt, ok := r.(io.ReaderAt)
+ if ok && size > offset {
+ sr := io.NewSectionReader(readerAt, offset, size)
+ return sr, nil
+ }
+
+ // well then, let's just discard up to the offset
+ n, err := copyWithBuffer(io.Discard, io.LimitReader(r, offset))
+ if err != nil {
+ return nil, fmt.Errorf("failed to discard to offset: %w", err)
+ }
+ if n != offset {
+ return nil, errors.New("unable to discard to offset")
+ }
+
+ return r, nil
+}
+
+// copyWithBuffer is very similar to io.CopyBuffer https://golang.org/pkg/io/#CopyBuffer
+// but instead of using Read to read from the src, we use ReadAtLeast to make sure we have
+// a full buffer before we do a write operation to dst to reduce overheads associated
+// with the write operations of small buffers.
+func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
+ // If the reader has a WriteTo method, use it to do the copy.
+ // Avoids an allocation and a copy.
+ if wt, ok := src.(io.WriterTo); ok {
+ return wt.WriteTo(dst)
+ }
+ // Similarly, if the writer has a ReadFrom method, use it to do the copy.
+ if rt, ok := dst.(io.ReaderFrom); ok {
+ return rt.ReadFrom(src)
+ }
+ bufRef := bufPool.Get().(*[]byte)
+ defer bufPool.Put(bufRef)
+ buf := *bufRef
+ for {
+ nr, er := io.ReadAtLeast(src, buf, len(buf))
+ if nr > 0 {
+ nw, ew := dst.Write(buf[0:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if ew != nil {
+ err = ew
+ break
+ }
+ if nr != nw {
+ err = io.ErrShortWrite
+ break
+ }
+ }
+ if er != nil {
+ // If an EOF happens after reading fewer than the requested bytes,
+ // ReadAtLeast returns ErrUnexpectedEOF.
+ if er != io.EOF && er != io.ErrUnexpectedEOF {
+ err = er
+ }
+ break
+ }
+ }
+ return
+}
+
+// Exists returns whether an attempt to access the content would not error out
+// with an ErrNotFound error. It will return an encountered error if it was
+// different than ErrNotFound.
+func Exists(ctx context.Context, provider InfoProvider, desc ocispec.Descriptor) (bool, error) {
+ _, err := provider.Info(ctx, desc.Digest)
+ if errdefs.IsNotFound(err) {
+ return false, nil
+ }
+ return err == nil, err
+}
diff --git a/vendor/github.com/containerd/containerd/content/proxy/content_reader.go b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_reader.go
similarity index 95%
rename from vendor/github.com/containerd/containerd/content/proxy/content_reader.go
rename to vendor/github.com/containerd/containerd/v2/core/content/proxy/content_reader.go
index 2947a7c821..b591a7749d 100644
--- a/vendor/github.com/containerd/containerd/content/proxy/content_reader.go
+++ b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_reader.go
@@ -27,7 +27,7 @@ type remoteReaderAt struct {
ctx context.Context
digest digest.Digest
size int64
- client contentapi.ContentClient
+ client contentapi.TTRPCContentClient
}
func (ra *remoteReaderAt) Size() int64 {
@@ -36,9 +36,9 @@ func (ra *remoteReaderAt) Size() int64 {
func (ra *remoteReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
rr := &contentapi.ReadContentRequest{
- Digest: ra.digest,
+ Digest: ra.digest.String(),
Offset: off,
- Size_: int64(len(p)),
+ Size: int64(len(p)),
}
// we need a child context with cancel, or the eventually called
// grpc.NewStream will leak the goroutine until the whole thing is cleared.
diff --git a/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_store.go b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_store.go
new file mode 100644
index 0000000000..1c1c1cfc86
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_store.go
@@ -0,0 +1,324 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package proxy
+
+import (
+ "context"
+ "fmt"
+ "io"
+
+ contentapi "github.com/containerd/containerd/api/services/content/v1"
+ "github.com/containerd/errdefs"
+ "github.com/containerd/errdefs/pkg/errgrpc"
+ "github.com/containerd/ttrpc"
+ digest "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "google.golang.org/grpc"
+ "google.golang.org/protobuf/types/known/emptypb"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/pkg/protobuf"
+ protobuftypes "github.com/containerd/containerd/v2/pkg/protobuf/types"
+)
+
+type proxyContentStore struct {
+ // client is the rpc content client
+ // NOTE: ttrpc is used because it is the smaller interface shared with grpc
+ client contentapi.TTRPCContentClient
+}
+
+// NewContentStore returns a new content store which communicates over a GRPC
+// connection using the containerd content GRPC API.
+func NewContentStore(client any) content.Store {
+ switch c := client.(type) {
+ case contentapi.ContentClient:
+ return &proxyContentStore{
+ client: convertClient{c},
+ }
+ case grpc.ClientConnInterface:
+ return &proxyContentStore{
+ client: convertClient{contentapi.NewContentClient(c)},
+ }
+ case contentapi.TTRPCContentClient:
+ return &proxyContentStore{
+ client: c,
+ }
+ case *ttrpc.Client:
+ return &proxyContentStore{
+ client: contentapi.NewTTRPCContentClient(c),
+ }
+ default:
+ panic(fmt.Errorf("unsupported content client %T: %w", client, errdefs.ErrNotImplemented))
+ }
+}
+
+func (pcs *proxyContentStore) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
+ resp, err := pcs.client.Info(ctx, &contentapi.InfoRequest{
+ Digest: dgst.String(),
+ })
+ if err != nil {
+ return content.Info{}, errgrpc.ToNative(err)
+ }
+
+ return infoFromGRPC(resp.Info), nil
+}
+
+func (pcs *proxyContentStore) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error {
+ session, err := pcs.client.List(ctx, &contentapi.ListContentRequest{
+ Filters: filters,
+ })
+ if err != nil {
+ return errgrpc.ToNative(err)
+ }
+
+ for {
+ msg, err := session.Recv()
+ if err != nil {
+ if err != io.EOF {
+ return errgrpc.ToNative(err)
+ }
+
+ break
+ }
+
+ for _, info := range msg.Info {
+ if err := fn(infoFromGRPC(info)); err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func (pcs *proxyContentStore) Delete(ctx context.Context, dgst digest.Digest) error {
+ if _, err := pcs.client.Delete(ctx, &contentapi.DeleteContentRequest{
+ Digest: dgst.String(),
+ }); err != nil {
+ return errgrpc.ToNative(err)
+ }
+
+ return nil
+}
+
+// ReaderAt ignores MediaType.
+func (pcs *proxyContentStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
+ i, err := pcs.Info(ctx, desc.Digest)
+ if err != nil {
+ return nil, err
+ }
+
+ return &remoteReaderAt{
+ ctx: ctx,
+ digest: desc.Digest,
+ size: i.Size,
+ client: pcs.client,
+ }, nil
+}
+
+func (pcs *proxyContentStore) Status(ctx context.Context, ref string) (content.Status, error) {
+ resp, err := pcs.client.Status(ctx, &contentapi.StatusRequest{
+ Ref: ref,
+ })
+ if err != nil {
+ return content.Status{}, errgrpc.ToNative(err)
+ }
+
+ status := resp.Status
+ return content.Status{
+ Ref: status.Ref,
+ StartedAt: protobuf.FromTimestamp(status.StartedAt),
+ UpdatedAt: protobuf.FromTimestamp(status.UpdatedAt),
+ Offset: status.Offset,
+ Total: status.Total,
+ Expected: digest.Digest(status.Expected),
+ }, nil
+}
+
+func (pcs *proxyContentStore) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
+ resp, err := pcs.client.Update(ctx, &contentapi.UpdateRequest{
+ Info: infoToGRPC(&info),
+ UpdateMask: &protobuftypes.FieldMask{
+ Paths: fieldpaths,
+ },
+ })
+ if err != nil {
+ return content.Info{}, errgrpc.ToNative(err)
+ }
+ return infoFromGRPC(resp.Info), nil
+}
+
+func (pcs *proxyContentStore) ListStatuses(ctx context.Context, filters ...string) ([]content.Status, error) {
+ resp, err := pcs.client.ListStatuses(ctx, &contentapi.ListStatusesRequest{
+ Filters: filters,
+ })
+ if err != nil {
+ return nil, errgrpc.ToNative(err)
+ }
+
+ var statuses []content.Status
+ for _, status := range resp.Statuses {
+ statuses = append(statuses, content.Status{
+ Ref: status.Ref,
+ StartedAt: protobuf.FromTimestamp(status.StartedAt),
+ UpdatedAt: protobuf.FromTimestamp(status.UpdatedAt),
+ Offset: status.Offset,
+ Total: status.Total,
+ Expected: digest.Digest(status.Expected),
+ })
+ }
+
+ return statuses, nil
+}
+
+// Writer ignores MediaType.
+func (pcs *proxyContentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
+ var wOpts content.WriterOpts
+ for _, opt := range opts {
+ if err := opt(&wOpts); err != nil {
+ return nil, err
+ }
+ }
+ wrclient, offset, err := pcs.negotiate(ctx, wOpts.Ref, wOpts.Desc.Size, wOpts.Desc.Digest)
+ if err != nil {
+ return nil, errgrpc.ToNative(err)
+ }
+
+ return &remoteWriter{
+ ref: wOpts.Ref,
+ client: wrclient,
+ offset: offset,
+ }, nil
+}
+
+// Abort implements asynchronous abort. It starts a new write session on the ref l
+func (pcs *proxyContentStore) Abort(ctx context.Context, ref string) error {
+ if _, err := pcs.client.Abort(ctx, &contentapi.AbortRequest{
+ Ref: ref,
+ }); err != nil {
+ return errgrpc.ToNative(err)
+ }
+
+ return nil
+}
+
+func (pcs *proxyContentStore) negotiate(ctx context.Context, ref string, size int64, expected digest.Digest) (contentapi.TTRPCContent_WriteClient, int64, error) {
+ wrclient, err := pcs.client.Write(ctx)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ if err := wrclient.Send(&contentapi.WriteContentRequest{
+ Action: contentapi.WriteAction_STAT,
+ Ref: ref,
+ Total: size,
+ Expected: expected.String(),
+ }); err != nil {
+ return nil, 0, err
+ }
+
+ resp, err := wrclient.Recv()
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return wrclient, resp.Offset, nil
+}
+
+type convertClient struct {
+ contentapi.ContentClient
+}
+
+func (c convertClient) Info(ctx context.Context, req *contentapi.InfoRequest) (*contentapi.InfoResponse, error) {
+ return c.ContentClient.Info(ctx, req)
+}
+
+func (c convertClient) Update(ctx context.Context, req *contentapi.UpdateRequest) (*contentapi.UpdateResponse, error) {
+ return c.ContentClient.Update(ctx, req)
+}
+
+type convertListClient struct {
+ contentapi.Content_ListClient
+}
+
+func (c convertClient) List(ctx context.Context, req *contentapi.ListContentRequest) (contentapi.TTRPCContent_ListClient, error) {
+ lc, err := c.ContentClient.List(ctx, req)
+ if lc == nil {
+ return nil, err
+ }
+ return convertListClient{lc}, err
+}
+
+func (c convertClient) Delete(ctx context.Context, req *contentapi.DeleteContentRequest) (*emptypb.Empty, error) {
+ return c.ContentClient.Delete(ctx, req)
+}
+
+type convertReadClient struct {
+ contentapi.Content_ReadClient
+}
+
+func (c convertClient) Read(ctx context.Context, req *contentapi.ReadContentRequest) (contentapi.TTRPCContent_ReadClient, error) {
+ rc, err := c.ContentClient.Read(ctx, req)
+ if rc == nil {
+ return nil, err
+ }
+ return convertReadClient{rc}, err
+}
+
+func (c convertClient) Status(ctx context.Context, req *contentapi.StatusRequest) (*contentapi.StatusResponse, error) {
+ return c.ContentClient.Status(ctx, req)
+}
+
+func (c convertClient) ListStatuses(ctx context.Context, req *contentapi.ListStatusesRequest) (*contentapi.ListStatusesResponse, error) {
+ return c.ContentClient.ListStatuses(ctx, req)
+}
+
+type convertWriteClient struct {
+ contentapi.Content_WriteClient
+}
+
+func (c convertClient) Write(ctx context.Context) (contentapi.TTRPCContent_WriteClient, error) {
+ wc, err := c.ContentClient.Write(ctx)
+ if wc == nil {
+ return nil, err
+ }
+ return convertWriteClient{wc}, err
+}
+
+func (c convertClient) Abort(ctx context.Context, req *contentapi.AbortRequest) (*emptypb.Empty, error) {
+ return c.ContentClient.Abort(ctx, req)
+}
+
+func infoToGRPC(info *content.Info) *contentapi.Info {
+ return &contentapi.Info{
+ Digest: info.Digest.String(),
+ Size: info.Size,
+ CreatedAt: protobuf.ToTimestamp(info.CreatedAt),
+ UpdatedAt: protobuf.ToTimestamp(info.UpdatedAt),
+ Labels: info.Labels,
+ }
+}
+
+func infoFromGRPC(info *contentapi.Info) content.Info {
+ return content.Info{
+ Digest: digest.Digest(info.Digest),
+ Size: info.Size,
+ CreatedAt: protobuf.FromTimestamp(info.CreatedAt),
+ UpdatedAt: protobuf.FromTimestamp(info.UpdatedAt),
+ Labels: info.Labels,
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_writer.go b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_writer.go
new file mode 100644
index 0000000000..45718be7d8
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_writer.go
@@ -0,0 +1,155 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package proxy
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "slices"
+
+ contentapi "github.com/containerd/containerd/api/services/content/v1"
+ "github.com/containerd/errdefs/pkg/errgrpc"
+ digest "github.com/opencontainers/go-digest"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/defaults"
+ "github.com/containerd/containerd/v2/pkg/protobuf"
+)
+
+type remoteWriter struct {
+ ref string
+ client contentapi.TTRPCContent_WriteClient
+ offset int64
+ digest digest.Digest
+}
+
+// send performs a synchronous req-resp cycle on the client.
+func (rw *remoteWriter) send(req *contentapi.WriteContentRequest) (*contentapi.WriteContentResponse, error) {
+ if err := rw.client.Send(req); err != nil {
+ return nil, err
+ }
+
+ resp, err := rw.client.Recv()
+
+ if err == nil {
+ // try to keep these in sync
+ if resp.Digest != "" {
+ rw.digest = digest.Digest(resp.Digest)
+ }
+ }
+
+ return resp, err
+}
+
+func (rw *remoteWriter) Status() (content.Status, error) {
+ resp, err := rw.send(&contentapi.WriteContentRequest{
+ Action: contentapi.WriteAction_STAT,
+ })
+ if err != nil {
+ return content.Status{}, fmt.Errorf("error getting writer status: %w", errgrpc.ToNative(err))
+ }
+
+ return content.Status{
+ Ref: rw.ref,
+ Offset: resp.Offset,
+ Total: resp.Total,
+ StartedAt: protobuf.FromTimestamp(resp.StartedAt),
+ UpdatedAt: protobuf.FromTimestamp(resp.UpdatedAt),
+ }, nil
+}
+
+func (rw *remoteWriter) Digest() digest.Digest {
+ return rw.digest
+}
+
+func (rw *remoteWriter) Write(p []byte) (n int, err error) {
+ const maxBufferSize = defaults.DefaultMaxSendMsgSize >> 1
+ for data := range slices.Chunk(p, maxBufferSize) {
+ offset := rw.offset
+
+ resp, err := rw.send(&contentapi.WriteContentRequest{
+ Action: contentapi.WriteAction_WRITE,
+ Offset: offset,
+ Data: data,
+ })
+ if err != nil {
+ return 0, fmt.Errorf("failed to send write: %w", errgrpc.ToNative(err))
+ }
+
+ written := int(resp.Offset - offset)
+ rw.offset += int64(written)
+ if resp.Digest != "" {
+ rw.digest = digest.Digest(resp.Digest)
+ }
+ n += written
+
+ if written < len(data) {
+ return n, io.ErrShortWrite
+ }
+ }
+ return n, nil
+}
+
+func (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) (err error) {
+ defer func() {
+ err1 := rw.Close()
+ if err == nil {
+ err = err1
+ }
+ }()
+
+ var base content.Info
+ for _, opt := range opts {
+ if err := opt(&base); err != nil {
+ return err
+ }
+ }
+ resp, err := rw.send(&contentapi.WriteContentRequest{
+ Action: contentapi.WriteAction_COMMIT,
+ Total: size,
+ Offset: rw.offset,
+ Expected: expected.String(),
+ Labels: base.Labels,
+ })
+ if err != nil {
+ return fmt.Errorf("commit failed: %w", errgrpc.ToNative(err))
+ }
+
+ if size != 0 && resp.Offset != size {
+ return fmt.Errorf("unexpected size: %v != %v", resp.Offset, size)
+ }
+
+ actual := digest.Digest(resp.Digest)
+ if expected != "" && actual != expected {
+ return fmt.Errorf("unexpected digest: %v != %v", resp.Digest, expected)
+ }
+
+ rw.digest = actual
+ rw.offset = resp.Offset
+ return nil
+}
+
+func (rw *remoteWriter) Truncate(size int64) error {
+ // This truncation won't actually be validated until a write is issued.
+ rw.offset = size
+ return nil
+}
+
+func (rw *remoteWriter) Close() error {
+ return rw.client.CloseSend()
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/images/annotations.go b/vendor/github.com/containerd/containerd/v2/core/images/annotations.go
new file mode 100644
index 0000000000..33ae15e47d
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/images/annotations.go
@@ -0,0 +1,29 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package images
+
+const (
+ // AnnotationImageName is an annotation on a Descriptor in an index.json
+ // containing the `Name` value as used by an `Image` struct
+ AnnotationImageName = "io.containerd.image.name"
+
+ // AnnotationManifestSubject is an annotation on a Descriptor that means
+ // that current descriptor is a referrer to the subject manifest.
+ // If descriptor in image.json has this annotation, it will not create
+ // a new image.
+ AnnotationManifestSubject = "io.containerd.manifest.subject"
+)
diff --git a/vendor/github.com/containerd/containerd/v2/core/images/diffid.go b/vendor/github.com/containerd/containerd/v2/core/images/diffid.go
new file mode 100644
index 0000000000..140d2c07c6
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/images/diffid.go
@@ -0,0 +1,82 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package images
+
+import (
+ "context"
+ "io"
+
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/pkg/archive/compression"
+ "github.com/containerd/containerd/v2/pkg/labels"
+ "github.com/containerd/log"
+)
+
+// GetDiffID gets the diff ID of the layer blob descriptor.
+func GetDiffID(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (digest.Digest, error) {
+ switch desc.MediaType {
+ case
+ // If the layer is already uncompressed, we can just return its digest
+ MediaTypeDockerSchema2Layer,
+ ocispec.MediaTypeImageLayer,
+ MediaTypeDockerSchema2LayerForeign,
+ ocispec.MediaTypeImageLayerNonDistributable: //nolint:staticcheck // deprecated
+ return desc.Digest, nil
+ }
+ info, err := cs.Info(ctx, desc.Digest)
+ if err != nil {
+ return "", err
+ }
+ v, ok := info.Labels[labels.LabelUncompressed]
+ if ok {
+ // Fast path: if the image is already unpacked, we can use the label value
+ return digest.Parse(v)
+ }
+ // if the image is not unpacked, we may not have the label
+ ra, err := cs.ReaderAt(ctx, desc)
+ if err != nil {
+ return "", err
+ }
+ defer ra.Close()
+ r := content.NewReader(ra)
+ uR, err := compression.DecompressStream(r)
+ if err != nil {
+ return "", err
+ }
+ defer uR.Close()
+ digester := digest.Canonical.Digester()
+ hashW := digester.Hash()
+ if _, err := io.Copy(hashW, uR); err != nil {
+ return "", err
+ }
+ if err := ra.Close(); err != nil {
+ return "", err
+ }
+ digest := digester.Digest()
+ // memorize the computed value
+ if info.Labels == nil {
+ info.Labels = make(map[string]string)
+ }
+ info.Labels[labels.LabelUncompressed] = digest.String()
+ if _, err := cs.Update(ctx, info, "labels"); err != nil {
+ log.G(ctx).WithError(err).Warnf("failed to set %s label for %s", labels.LabelUncompressed, desc.Digest)
+ }
+ return digest, nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/images/handlers.go b/vendor/github.com/containerd/containerd/v2/core/images/handlers.go
new file mode 100644
index 0000000000..245b9ac43c
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/images/handlers.go
@@ -0,0 +1,351 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package images
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "slices"
+ "sort"
+ "strings"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/errdefs"
+ "github.com/containerd/platforms"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sync/errgroup"
+ "golang.org/x/sync/semaphore"
+)
+
+var (
+ // ErrSkipDesc is used to skip processing of a descriptor and
+ // its descendants.
+ ErrSkipDesc = errors.New("skip descriptor")
+
+ // ErrStopHandler is used to signify that the descriptor
+ // has been handled and should not be handled further.
+ // This applies only to a single descriptor in a handler
+ // chain and does not apply to descendant descriptors.
+ ErrStopHandler = errors.New("stop handler")
+
+ // ErrEmptyWalk is used when the WalkNotEmpty handlers return no
+ // children (e.g.: they were filtered out).
+ ErrEmptyWalk = errors.New("image might be filtered out")
+)
+
+// Handler handles image manifests
+type Handler interface {
+ Handle(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error)
+}
+
+// HandlerFunc function implementing the Handler interface
+type HandlerFunc func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error)
+
+// Handle image manifests
+func (fn HandlerFunc) Handle(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
+ return fn(ctx, desc)
+}
+
+// Handlers returns a handler that will run the handlers in sequence.
+//
+// A handler may return `ErrStopHandler` to stop calling additional handlers
+func Handlers(handlers ...Handler) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
+ var children []ocispec.Descriptor
+ for _, handler := range handlers {
+ ch, err := handler.Handle(ctx, desc)
+ if err != nil {
+ if errors.Is(err, ErrStopHandler) {
+ break
+ }
+ return nil, err
+ }
+
+ children = append(children, ch...)
+ }
+
+ return children, nil
+ }
+}
+
+// Walk the resources of an image and call the handler for each. If the handler
+// decodes the sub-resources for each image,
+//
+// This differs from dispatch in that each sibling resource is considered
+// synchronously.
+func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error {
+ for _, desc := range descs {
+
+ children, err := handler.Handle(ctx, desc)
+ if err != nil {
+ if errors.Is(err, ErrSkipDesc) {
+ continue // don't traverse the children.
+ }
+ return err
+ }
+
+ if len(children) > 0 {
+ if err := Walk(ctx, handler, children...); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// WalkNotEmpty works the same way Walk does, with the exception that it ensures that
+// some children are still found by Walking the descriptors (for example, not all of
+// them have been filtered out by one of the handlers). If there are no children,
+// then an ErrEmptyWalk error is returned.
+func WalkNotEmpty(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error {
+ isEmpty := true
+ var notEmptyHandler HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := handler.Handle(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ if len(children) > 0 {
+ isEmpty = false
+ }
+
+ return children, nil
+ }
+
+ err := Walk(ctx, notEmptyHandler, descs...)
+ if err != nil {
+ return err
+ }
+
+ if isEmpty {
+ return ErrEmptyWalk
+ }
+
+ return nil
+}
+
+// Dispatch runs the provided handler for content specified by the descriptors.
+// If the handler decode subresources, they will be visited, as well.
+//
+// Handlers for siblings are run in parallel on the provided descriptors. A
+// handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse
+// any children.
+//
+// A concurrency limiter can be passed in to limit the number of concurrent
+// handlers running. When limiter is nil, there is no limit.
+//
+// Typically, this function will be used with `FetchHandler`, often composed
+// with other handlers.
+//
+// If any handler returns an error, the dispatch session will be canceled.
+func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
+ eg, ctx2 := errgroup.WithContext(ctx)
+ for _, desc := range descs {
+ if limiter != nil {
+ if err := limiter.Acquire(ctx, 1); err != nil {
+ return err
+ }
+ }
+
+ eg.Go(func() error {
+ desc := desc
+
+ children, err := handler.Handle(ctx2, desc)
+ if limiter != nil {
+ limiter.Release(1)
+ }
+ if err != nil {
+ if errors.Is(err, ErrSkipDesc) {
+ return nil // don't traverse the children.
+ }
+ return err
+ }
+
+ if len(children) > 0 {
+ return Dispatch(ctx2, handler, limiter, children...)
+ }
+
+ return nil
+ })
+ }
+
+ return eg.Wait()
+}
+
+// ChildrenHandler decodes well-known manifest types and returns their children.
+//
+// This is useful for supporting recursive fetch and other use cases where you
+// want to do a full walk of resources.
+//
+// One can also replace this with another implementation to allow descending of
+// arbitrary types.
+func ChildrenHandler(provider content.Provider) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ return Children(ctx, provider, desc)
+ }
+}
+
+// SetReferrers is a handler wrapper which adds referrer descriptors
+// from the provided ReferrersProvider and adds them to the children
+// returned by the handler. The referrers will have a container-specific
+// annotation added to indicate the subject descriptor.
+func SetReferrers(refProvider content.ReferrersProvider, f HandlerFunc) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+ if !IsManifestType(desc.MediaType) && !IsIndexType(desc.MediaType) {
+ return children, nil
+ }
+ refs, err := refProvider.Referrers(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+ children = slices.Grow(children, len(refs))
+ for _, ref := range refs {
+ if ref.Annotations == nil {
+ ref.Annotations = map[string]string{}
+ }
+ ref.Annotations[AnnotationManifestSubject] = desc.Digest.String()
+ children = append(children, ref)
+ }
+ return children, nil
+ }
+}
+
+// SetChildrenLabels is a handler wrapper which sets labels for the content on
+// the children returned by the handler and passes through the children.
+// Must follow a handler that returns the children to be labeled.
+func SetChildrenLabels(manager content.Manager, f HandlerFunc) HandlerFunc {
+ return SetChildrenMappedLabels(manager, f, nil)
+}
+
+// SetChildrenMappedLabels is a handler wrapper which sets labels for the content on
+// the children returned by the handler and passes through the children.
+// Must follow a handler that returns the children to be labeled.
+// The label map allows the caller to control the labels per child descriptor.
+// For returned labels, the index of the child will be appended to the end
+// except for the first index when the returned label does not end with '.'.
+func SetChildrenMappedLabels(manager content.Manager, f HandlerFunc, labelMap func(ocispec.Descriptor) []string) HandlerFunc {
+ if labelMap == nil {
+ labelMap = ChildGCLabels
+ }
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ if len(children) > 0 {
+ var (
+ info = content.Info{
+ Digest: desc.Digest,
+ Labels: map[string]string{},
+ }
+ fields = []string{}
+ keys = map[string]uint{}
+ )
+ for _, ch := range children {
+ labelKeys := labelMap(ch)
+ for _, key := range labelKeys {
+ idx := keys[key]
+ keys[key] = idx + 1
+ if strings.HasSuffix(key, ".sha256.") {
+ key = fmt.Sprintf("%s%s", key, ch.Digest.Hex()[:12])
+ } else if idx > 0 || key[len(key)-1] == '.' {
+ key = fmt.Sprintf("%s%d", key, idx)
+ }
+
+ info.Labels[key] = ch.Digest.String()
+ fields = append(fields, "labels."+key)
+ }
+ }
+
+ _, err := manager.Update(ctx, info, fields...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return children, err
+ }
+}
+
+// FilterPlatforms is a handler wrapper which limits the descriptors returned
+// based on matching the specified platform matcher.
+func FilterPlatforms(f HandlerFunc, m platforms.Matcher) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ var descs []ocispec.Descriptor
+
+ if m == nil {
+ descs = children
+ } else {
+ for _, d := range children {
+ if d.Platform == nil || m.Match(*d.Platform) {
+ descs = append(descs, d)
+ }
+ }
+ }
+
+ return descs, nil
+ }
+}
+
+// LimitManifests is a handler wrapper which filters the manifest descriptors
+// returned using the provided platform.
+// The results will be ordered according to the comparison operator and
+// use the ordering in the manifests for equal matches.
+// A limit of 0 or less is considered no limit.
+// A not found error is returned if no manifest is matched.
+func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ // only limit manifests from an index
+ if IsIndexType(desc.MediaType) {
+ sort.SliceStable(children, func(i, j int) bool {
+ if children[i].Platform == nil {
+ return false
+ }
+ if children[j].Platform == nil {
+ return true
+ }
+ return m.Less(*children[i].Platform, *children[j].Platform)
+ })
+
+ if n > 0 {
+ if len(children) == 0 {
+ return children, fmt.Errorf("no match for platform in manifest: %w", errdefs.ErrNotFound)
+ }
+ if len(children) > n {
+ children = children[:n]
+ }
+ }
+ }
+ return children, nil
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/images/image.go b/vendor/github.com/containerd/containerd/v2/core/images/image.go
new file mode 100644
index 0000000000..9fcce9b4eb
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/images/image.go
@@ -0,0 +1,440 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package images
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "sort"
+ "time"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ "github.com/containerd/platforms"
+ digest "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// Image provides the model for how containerd views container images.
+type Image struct {
+ // Name of the image.
+ //
+ // To be pulled, it must be a reference compatible with resolvers.
+ //
+ // This field is required.
+ Name string
+
+ // Labels provide runtime decoration for the image record.
+ //
+ // There is no default behavior for how these labels are propagated. They
+ // only decorate the static metadata object.
+ //
+ // This field is optional.
+ Labels map[string]string
+
+ // Target describes the root content for this image. Typically, this is
+ // a manifest, index or manifest list.
+ Target ocispec.Descriptor
+
+ CreatedAt, UpdatedAt time.Time
+}
+
+// DeleteOptions provide options on image delete
+type DeleteOptions struct {
+ Synchronous bool
+ Target *ocispec.Descriptor
+}
+
+// DeleteOpt allows configuring a delete operation
+type DeleteOpt func(context.Context, *DeleteOptions) error
+
+// SynchronousDelete is used to indicate that an image deletion and removal of
+// the image resources should occur synchronously before returning a result.
+func SynchronousDelete() DeleteOpt {
+ return func(ctx context.Context, o *DeleteOptions) error {
+ o.Synchronous = true
+ return nil
+ }
+}
+
+// DeleteTarget is used to specify the target value an image is expected
+// to have when deleting. If the image has a different target, then
+// NotFound is returned.
+func DeleteTarget(target *ocispec.Descriptor) DeleteOpt {
+ return func(ctx context.Context, o *DeleteOptions) error {
+ o.Target = target
+ return nil
+ }
+}
+
+// Store and interact with images
+type Store interface {
+ Get(ctx context.Context, name string) (Image, error)
+ List(ctx context.Context, filters ...string) ([]Image, error)
+ Create(ctx context.Context, image Image) (Image, error)
+
+ // Update will replace the data in the store with the provided image. If
+ // one or more fieldpaths are provided, only those fields will be updated.
+ Update(ctx context.Context, image Image, fieldpaths ...string) (Image, error)
+
+ Delete(ctx context.Context, name string, opts ...DeleteOpt) error
+}
+
+// TODO(stevvooe): Many of these functions make strong platform assumptions,
+// which are untrue in a lot of cases. More refactoring must be done here to
+// make this work in all cases.
+
+// Config resolves the image configuration descriptor.
+//
+// The caller can then use the descriptor to resolve and process the
+// configuration of the image.
+func (image *Image) Config(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
+ return Config(ctx, provider, image.Target, platform)
+}
+
+// RootFS returns the unpacked diffids that make up and images rootfs.
+//
+// These are used to verify that a set of layers unpacked to the expected
+// values.
+func (image *Image) RootFS(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) ([]digest.Digest, error) {
+ desc, err := image.Config(ctx, provider, platform)
+ if err != nil {
+ return nil, err
+ }
+ return RootFS(ctx, provider, desc)
+}
+
+// Size returns the total size of an image's packed resources.
+func (image *Image) Size(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (int64, error) {
+ var size int64
+ return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if desc.Size < 0 {
+ return nil, fmt.Errorf("invalid size %v in %v (%v)", desc.Size, desc.Digest, desc.MediaType)
+ }
+ size += desc.Size
+ return nil, nil
+ }), LimitManifests(FilterPlatforms(ChildrenHandler(provider), platform), platform, 1)), image.Target)
+}
+
+type platformManifest struct {
+ p *ocispec.Platform
+ m *ocispec.Manifest
+}
+
+// Manifest resolves a manifest from the image for the given platform.
+//
+// When a manifest descriptor inside of a manifest index does not have
+// a platform defined, the platform from the image config is considered.
+//
+// If the descriptor points to a non-index manifest, then the manifest is
+// unmarshalled and returned without considering the platform inside of the
+// config.
+//
+// TODO(stevvooe): This violates the current platform agnostic approach to this
+// package by returning a specific manifest type. We'll need to refactor this
+// to return a manifest descriptor or decide that we want to bring the API in
+// this direction because this abstraction is not needed.
+func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) {
+ var (
+ limit = 1
+ m []platformManifest
+ wasIndex bool
+ )
+
+ if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if IsManifestType(desc.MediaType) {
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("manifest: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ var manifest ocispec.Manifest
+ if err := json.Unmarshal(p, &manifest); err != nil {
+ return nil, err
+ }
+
+ if desc.Digest != image.Digest && platform != nil {
+ if desc.Platform != nil && !platform.Match(*desc.Platform) {
+ return nil, nil
+ }
+
+ if desc.Platform == nil {
+ imagePlatform, err := ConfigPlatform(ctx, provider, manifest.Config)
+ if err != nil {
+ return nil, err
+ }
+ if !platform.Match(imagePlatform) {
+ return nil, nil
+ }
+
+ }
+ }
+
+ m = append(m, platformManifest{
+ p: desc.Platform,
+ m: &manifest,
+ })
+
+ return nil, nil
+ } else if IsIndexType(desc.MediaType) {
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("manifest: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ var idx ocispec.Index
+ if err := json.Unmarshal(p, &idx); err != nil {
+ return nil, err
+ }
+
+ if platform == nil {
+ return idx.Manifests, nil
+ }
+
+ var descs []ocispec.Descriptor
+ for _, d := range idx.Manifests {
+ if d.Platform == nil || platform.Match(*d.Platform) {
+ descs = append(descs, d)
+ }
+ }
+
+ sort.SliceStable(descs, func(i, j int) bool {
+ if descs[i].Platform == nil {
+ return false
+ }
+ if descs[j].Platform == nil {
+ return true
+ }
+ return platform.Less(*descs[i].Platform, *descs[j].Platform)
+ })
+
+ wasIndex = true
+
+ if len(descs) > limit {
+ return descs[:limit], nil
+ }
+ return descs, nil
+ }
+ return nil, fmt.Errorf("unexpected media type %v for %v: %w", desc.MediaType, desc.Digest, errdefs.ErrNotFound)
+ }), image); err != nil {
+ return ocispec.Manifest{}, err
+ }
+
+ if len(m) == 0 {
+ err := fmt.Errorf("manifest %v: %w", image.Digest, errdefs.ErrNotFound)
+ if wasIndex {
+ err = fmt.Errorf("no match for platform in manifest %v: %w", image.Digest, errdefs.ErrNotFound)
+ }
+ return ocispec.Manifest{}, err
+ }
+ return *m[0].m, nil
+}
+
+// Config resolves the image configuration descriptor using a content provided
+// to resolve child resources on the image.
+//
+// The caller can then use the descriptor to resolve and process the
+// configuration of the image.
+func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
+ manifest, err := Manifest(ctx, provider, image, platform)
+ if err != nil {
+ return ocispec.Descriptor{}, err
+ }
+ return manifest.Config, nil
+}
+
+// Platforms returns one or more platforms supported by the image.
+func Platforms(ctx context.Context, provider content.Provider, image ocispec.Descriptor) ([]ocispec.Platform, error) {
+ var platformSpecs []ocispec.Platform
+ return platformSpecs, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if desc.Platform != nil {
+ if desc.Platform.OS == "unknown" || desc.Platform.Architecture == "unknown" {
+ return nil, ErrSkipDesc
+ }
+ platformSpecs = append(platformSpecs, *desc.Platform)
+ return nil, ErrSkipDesc
+ }
+
+ if IsConfigType(desc.MediaType) {
+ imagePlatform, err := ConfigPlatform(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+ platformSpecs = append(platformSpecs, imagePlatform)
+ }
+ return nil, nil
+ }), ChildrenHandler(provider)), image)
+}
+
+// Check returns nil if the all components of an image are available in the
+// provider for the specified platform.
+//
+// If available is true, the caller can assume that required represents the
+// complete set of content required for the image.
+//
+// missing will have the components that are part of required but not available
+// in the provider.
+//
+// If there is a problem resolving content, an error will be returned.
+func Check(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (available bool, required, present, missing []ocispec.Descriptor, err error) {
+ mfst, err := Manifest(ctx, provider, image, platform)
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ return false, []ocispec.Descriptor{image}, nil, []ocispec.Descriptor{image}, nil
+ }
+
+ return false, nil, nil, nil, fmt.Errorf("failed to check image %v: %w", image.Digest, err)
+ }
+
+ // TODO(stevvooe): It is possible that referenced components could have
+ // children, but this is rare. For now, we ignore this and only verify
+ // that manifest components are present.
+ required = append([]ocispec.Descriptor{mfst.Config}, mfst.Layers...)
+
+ for _, desc := range required {
+ ra, err := provider.ReaderAt(ctx, desc)
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ missing = append(missing, desc)
+ continue
+ } else {
+ return false, nil, nil, nil, fmt.Errorf("failed to check image %v: %w", desc.Digest, err)
+ }
+ }
+ ra.Close()
+ present = append(present, desc)
+
+ }
+
+ return true, required, present, missing, nil
+}
+
+// Children returns the immediate children of content described by the descriptor.
+func Children(ctx context.Context, provider content.Provider, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if IsManifestType(desc.MediaType) {
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("children: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ // TODO(stevvooe): We just assume oci manifest, for now. There may be
+ // subtle differences from the docker version.
+ var manifest ocispec.Manifest
+ if err := json.Unmarshal(p, &manifest); err != nil {
+ return nil, err
+ }
+
+ return append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...), nil
+ } else if IsIndexType(desc.MediaType) {
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("children: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ var index ocispec.Index
+ if err := json.Unmarshal(p, &index); err != nil {
+ return nil, err
+ }
+
+ return append([]ocispec.Descriptor{}, index.Manifests...), nil
+ } else if !IsLayerType(desc.MediaType) && !IsKnownConfig(desc.MediaType) && !IsAttestationType(desc.MediaType) {
+ // Layers, configs, and attestations are childless data types and should not be logged.
+ log.G(ctx).Debugf("encountered unknown type %v; children may not be fetched", desc.MediaType)
+ }
+ return nil, nil
+}
+
+// unknownDocument represents a manifest, manifest list, or index that has not
+// yet been validated.
+type unknownDocument struct {
+ MediaType string `json:"mediaType,omitempty"`
+ Config json.RawMessage `json:"config,omitempty"`
+ Layers json.RawMessage `json:"layers,omitempty"`
+ Manifests json.RawMessage `json:"manifests,omitempty"`
+ FSLayers json.RawMessage `json:"fsLayers,omitempty"` // schema 1
+}
+
+// validateMediaType returns an error if the byte slice is invalid JSON,
+// if the format of the blob is not supported, or if the media type
+// identifies the blob as one format, but it identifies itself as, or
+// contains elements of another format.
+func validateMediaType(b []byte, mt string) error {
+ var doc unknownDocument
+ if err := json.Unmarshal(b, &doc); err != nil {
+ return err
+ }
+ if len(doc.FSLayers) != 0 {
+ return fmt.Errorf("media-type: schema 1 not supported")
+ }
+ if IsManifestType(mt) && (len(doc.Manifests) != 0 || IsIndexType(doc.MediaType)) {
+ return fmt.Errorf("media-type: expected manifest but found index (%s)", mt)
+ } else if IsIndexType(mt) && (len(doc.Config) != 0 || len(doc.Layers) != 0 || IsManifestType(doc.MediaType)) {
+ return fmt.Errorf("media-type: expected index but found manifest (%s)", mt)
+ }
+ return nil
+}
+
+// RootFS returns the unpacked diffids that make up and images rootfs.
+//
+// These are used to verify that a set of layers unpacked to the expected
+// values.
+func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
+ p, err := content.ReadBlob(ctx, provider, configDesc)
+ if err != nil {
+ return nil, err
+ }
+
+ var config ocispec.Image
+ if err := json.Unmarshal(p, &config); err != nil {
+ return nil, err
+ }
+ return config.RootFS.DiffIDs, nil
+}
+
+// ConfigPlatform returns a normalized platform from an image manifest config.
+func ConfigPlatform(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) (ocispec.Platform, error) {
+ p, err := content.ReadBlob(ctx, provider, configDesc)
+ if err != nil {
+ return ocispec.Platform{}, err
+ }
+
+ // Technically, this should be ocispec.Image, but we only need the
+ // ocispec.Platform that is embedded in the image struct.
+ var imagePlatform ocispec.Platform
+ if err := json.Unmarshal(p, &imagePlatform); err != nil {
+ return ocispec.Platform{}, err
+ }
+ return platforms.Normalize(imagePlatform), nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/images/importexport.go b/vendor/github.com/containerd/containerd/v2/core/images/importexport.go
new file mode 100644
index 0000000000..601d545ef0
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/images/importexport.go
@@ -0,0 +1,37 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package images
+
+import (
+ "context"
+ "io"
+
+ "github.com/containerd/containerd/v2/core/content"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// Importer is the interface for image importer.
+type Importer interface {
+ // Import imports an image from a tar stream.
+ Import(ctx context.Context, store content.Store, reader io.Reader) (ocispec.Descriptor, error)
+}
+
+// Exporter is the interface for image exporter.
+type Exporter interface {
+ // Export exports an image to a tar stream.
+ Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/images/mediatypes.go b/vendor/github.com/containerd/containerd/v2/core/images/mediatypes.go
new file mode 100644
index 0000000000..b82548dd81
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/images/mediatypes.go
@@ -0,0 +1,238 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package images
+
+import (
+ "context"
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/containerd/errdefs"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// mediatype definitions for image components handled in containerd.
+//
+// oci components are generally referenced directly, although we may centralize
+// here for clarity.
+const (
+ MediaTypeDockerSchema2Layer = "application/vnd.docker.image.rootfs.diff.tar"
+ MediaTypeDockerSchema2LayerForeign = "application/vnd.docker.image.rootfs.foreign.diff.tar"
+ MediaTypeDockerSchema2LayerGzip = "application/vnd.docker.image.rootfs.diff.tar.gzip"
+ MediaTypeDockerSchema2LayerZstd = "application/vnd.docker.image.rootfs.diff.tar.zstd"
+ MediaTypeDockerSchema2LayerForeignGzip = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
+ MediaTypeDockerSchema2Config = "application/vnd.docker.container.image.v1+json"
+ MediaTypeDockerSchema2Manifest = "application/vnd.docker.distribution.manifest.v2+json"
+ MediaTypeDockerSchema2ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json"
+
+ // Checkpoint/Restore Media Types
+
+ MediaTypeContainerd1Checkpoint = "application/vnd.containerd.container.criu.checkpoint.criu.tar"
+ MediaTypeContainerd1CheckpointPreDump = "application/vnd.containerd.container.criu.checkpoint.predump.tar"
+ MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar"
+ MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar"
+ MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto"
+ MediaTypeContainerd1CheckpointOptions = "application/vnd.containerd.container.checkpoint.options.v1+proto"
+ MediaTypeContainerd1CheckpointRuntimeName = "application/vnd.containerd.container.checkpoint.runtime.name"
+ MediaTypeContainerd1CheckpointRuntimeOptions = "application/vnd.containerd.container.checkpoint.runtime.options+proto"
+
+ // MediaTypeDockerSchema1Manifest is the legacy Docker schema1 manifest
+ MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
+
+ // Encrypted media types
+
+ MediaTypeImageLayerEncrypted = ocispec.MediaTypeImageLayer + "+encrypted"
+ MediaTypeImageLayerGzipEncrypted = ocispec.MediaTypeImageLayerGzip + "+encrypted"
+
+ // In-toto attestation
+ MediaTypeInToto = "application/vnd.in-toto+json"
+)
+
+// DiffCompression returns the compression as defined by the layer diff media
+// type. For Docker media types without compression, "unknown" is returned to
+// indicate that the media type may be compressed. If the media type is not
+// recognized as a layer diff, then it returns errdefs.ErrNotImplemented
+func DiffCompression(ctx context.Context, mediaType string) (string, error) {
+ base, ext := parseMediaTypes(mediaType)
+ switch base {
+ case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerForeign:
+ if len(ext) > 0 {
+ // Type is wrapped
+ return "", nil
+ }
+ // These media types may have been compressed but failed to
+ // use the correct media type. The decompression function
+ // should detect and handle this case.
+ return "unknown", nil
+ case MediaTypeDockerSchema2LayerGzip, MediaTypeDockerSchema2LayerForeignGzip:
+ if len(ext) > 0 {
+ // Type is wrapped
+ return "", nil
+ }
+ return "gzip", nil
+ case MediaTypeDockerSchema2LayerZstd:
+ if len(ext) > 0 {
+ // Type is wrapped
+ return "", nil
+ }
+ return "zstd", nil
+ case ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerNonDistributable: //nolint:staticcheck // Non-distributable layers are deprecated
+ if len(ext) > 0 {
+ switch ext[len(ext)-1] {
+ case "gzip":
+ return "gzip", nil
+ case "zstd":
+ return "zstd", nil
+ }
+ }
+ return "", nil
+ default:
+ return "", fmt.Errorf("unrecognised mediatype %s: %w", mediaType, errdefs.ErrNotImplemented)
+ }
+}
+
+// parseMediaTypes splits the media type into the base type and
+// an array of sorted extensions
+func parseMediaTypes(mt string) (mediaType string, suffixes []string) {
+ if mt == "" {
+ return "", []string{}
+ }
+ mediaType, ext, ok := strings.Cut(mt, "+")
+ if !ok {
+ return mediaType, []string{}
+ }
+
+ // Splitting the extensions following the mediatype "(+)gzip+encrypted".
+ // We expect this to be a limited list, so add an arbitrary limit (50).
+ //
+ // Note that DiffCompression is only using the last element, so perhaps we
+ // should split on the last "+" only.
+ suffixes = strings.SplitN(ext, "+", 50)
+ sort.Strings(suffixes)
+ return mediaType, suffixes
+}
+
+// IsNonDistributable returns true if the media type is non-distributable.
+func IsNonDistributable(mt string) bool {
+ return strings.HasPrefix(mt, "application/vnd.oci.image.layer.nondistributable.") ||
+ strings.HasPrefix(mt, "application/vnd.docker.image.rootfs.foreign.")
+}
+
+// IsLayerType returns true if the media type is a layer
+func IsLayerType(mt string) bool {
+ if strings.HasPrefix(mt, "application/vnd.oci.image.layer.") {
+ return true
+ }
+
+ // Parse Docker media types, strip off any + suffixes first
+ switch base, _ := parseMediaTypes(mt); base {
+ case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip,
+ MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip, MediaTypeDockerSchema2LayerZstd:
+ return true
+ }
+ return false
+}
+
+// IsDockerType returns true if the media type has "application/vnd.docker." prefix
+func IsDockerType(mt string) bool {
+ return strings.HasPrefix(mt, "application/vnd.docker.")
+}
+
+// IsManifestType returns true if the media type is an OCI-compatible manifest.
+// No support for schema1 manifest.
+func IsManifestType(mt string) bool {
+ switch mt {
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ return true
+ default:
+ return false
+ }
+}
+
+// IsIndexType returns true if the media type is an OCI-compatible index.
+func IsIndexType(mt string) bool {
+ switch mt {
+ case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
+ return true
+ default:
+ return false
+ }
+}
+
+// IsConfigType returns true if the media type is an OCI-compatible image config.
+// No support for containerd checkpoint configs.
+func IsConfigType(mt string) bool {
+ switch mt {
+ case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
+ return true
+ default:
+ return false
+ }
+}
+
+// IsKnownConfig returns true if the media type is a known config type,
+// including containerd checkpoint configs
+func IsKnownConfig(mt string) bool {
+ switch mt {
+ case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig,
+ MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig:
+ return true
+ }
+ return false
+}
+
+// IsAttestationType returns true if the media type is an attestation type
+func IsAttestationType(mt string) bool {
+ switch mt {
+ case MediaTypeInToto:
+ return true
+ default:
+ return false
+ }
+}
+
+// ChildGCLabels returns the label for a given descriptor to reference it
+func ChildGCLabels(desc ocispec.Descriptor) []string {
+ if _, ok := desc.Annotations[AnnotationManifestSubject]; ok {
+ return []string{"containerd.io/gc.ref.content.referrer.sha256."}
+ }
+ mt := desc.MediaType
+ if IsKnownConfig(mt) {
+ return []string{"containerd.io/gc.ref.content.config"}
+ }
+
+ switch mt {
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ return []string{"containerd.io/gc.ref.content.m."}
+ }
+
+ if IsLayerType(mt) {
+ return []string{"containerd.io/gc.ref.content.l."}
+ }
+
+ return []string{"containerd.io/gc.ref.content."}
+}
+
+// ChildGCLabelsFilterLayers returns the labels for a given descriptor to
+// reference it, skipping layer media types
+func ChildGCLabelsFilterLayers(desc ocispec.Descriptor) []string {
+ if IsLayerType(desc.MediaType) {
+ return nil
+ }
+ return ChildGCLabels(desc)
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/leases/context.go b/vendor/github.com/containerd/containerd/v2/core/leases/context.go
new file mode 100644
index 0000000000..599c549d31
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/leases/context.go
@@ -0,0 +1,40 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package leases
+
+import "context"
+
+type leaseKey struct{}
+
+// WithLease sets a given lease on the context
+func WithLease(ctx context.Context, lid string) context.Context {
+ ctx = context.WithValue(ctx, leaseKey{}, lid)
+
+ // also store on the grpc headers so it gets picked up by any clients that
+ // are using this.
+ return withGRPCLeaseHeader(ctx, lid)
+}
+
+// FromContext returns the lease from the context.
+func FromContext(ctx context.Context) (string, bool) {
+ lid, ok := ctx.Value(leaseKey{}).(string)
+ if !ok {
+ return fromGRPCHeader(ctx)
+ }
+
+ return lid, ok
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/leases/grpc.go b/vendor/github.com/containerd/containerd/v2/core/leases/grpc.go
new file mode 100644
index 0000000000..22f287a8bf
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/leases/grpc.go
@@ -0,0 +1,58 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package leases
+
+import (
+ "context"
+
+ "google.golang.org/grpc/metadata"
+)
+
+const (
+ // GRPCHeader defines the header name for specifying a containerd lease.
+ GRPCHeader = "containerd-lease"
+)
+
+func withGRPCLeaseHeader(ctx context.Context, lid string) context.Context {
+ // also store on the grpc headers so it gets picked up by any clients
+ // that are using this.
+ txheader := metadata.Pairs(GRPCHeader, lid)
+ md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
+ if !ok {
+ md = txheader
+ } else {
+ // order ensures the latest is first in this list.
+ md = metadata.Join(txheader, md)
+ }
+
+ return metadata.NewOutgoingContext(ctx, md)
+}
+
+func fromGRPCHeader(ctx context.Context) (string, bool) {
+ // try to extract for use in grpc servers.
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ return "", false
+ }
+
+ values := md[GRPCHeader]
+ if len(values) == 0 {
+ return "", false
+ }
+
+ return values[0], true
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/leases/id.go b/vendor/github.com/containerd/containerd/v2/core/leases/id.go
new file mode 100644
index 0000000000..8f5dc93f34
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/leases/id.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package leases
+
+import (
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "time"
+)
+
+// WithRandomID sets the lease ID to a random unique value
+func WithRandomID() Opt {
+ return func(l *Lease) error {
+ t := time.Now()
+ var b [3]byte
+ rand.Read(b[:])
+ l.ID = fmt.Sprintf("%d-%s", t.Nanosecond(), base64.URLEncoding.EncodeToString(b[:]))
+ return nil
+ }
+}
+
+// WithID sets the ID for the lease
+func WithID(id string) Opt {
+ return func(l *Lease) error {
+ l.ID = id
+ return nil
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/leases/lease.go b/vendor/github.com/containerd/containerd/v2/core/leases/lease.go
new file mode 100644
index 0000000000..d842c4081a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/leases/lease.go
@@ -0,0 +1,104 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package leases
+
+import (
+ "context"
+ "time"
+)
+
+// Opt is used to set options on a lease
+type Opt func(*Lease) error
+
+// DeleteOpt allows configuring a delete operation
+type DeleteOpt func(context.Context, *DeleteOptions) error
+
+// Manager is used to create, list, and remove leases
+type Manager interface {
+ Create(context.Context, ...Opt) (Lease, error)
+ Delete(context.Context, Lease, ...DeleteOpt) error
+ List(context.Context, ...string) ([]Lease, error)
+ AddResource(context.Context, Lease, Resource) error
+ DeleteResource(context.Context, Lease, Resource) error
+ ListResources(context.Context, Lease) ([]Resource, error)
+}
+
+// Lease retains resources to prevent cleanup before
+// the resources can be fully referenced.
+type Lease struct {
+ ID string
+ CreatedAt time.Time
+ Labels map[string]string
+}
+
+// Resource represents low level resource of image, like content, ingest and
+// snapshotter.
+type Resource struct {
+ ID string
+ Type string
+}
+
+// DeleteOptions provide options on image delete
+type DeleteOptions struct {
+ Synchronous bool
+}
+
+// SynchronousDelete is used to indicate that a lease deletion and removal of
+// any unreferenced resources should occur synchronously before returning the
+// result.
+func SynchronousDelete(ctx context.Context, o *DeleteOptions) error {
+ o.Synchronous = true
+ return nil
+}
+
+// WithLabel sets a label on a lease, and merges it with existing labels.
+// It overwrites the existing value of the given label (if present).
+func WithLabel(label, value string) Opt {
+ return func(l *Lease) error {
+ if l.Labels == nil {
+ l.Labels = map[string]string{label: value}
+ return nil
+ }
+ l.Labels[label] = value
+ return nil
+ }
+}
+
+// WithLabels merges labels on a lease
+func WithLabels(labels map[string]string) Opt {
+ return func(l *Lease) error {
+ if l.Labels == nil {
+ l.Labels = map[string]string{}
+ }
+ for k, v := range labels {
+ l.Labels[k] = v
+ }
+ return nil
+ }
+}
+
+// WithExpiration sets an expiration on the lease
+func WithExpiration(d time.Duration) Opt {
+ return func(l *Lease) error {
+ if l.Labels == nil {
+ l.Labels = map[string]string{}
+ }
+ l.Labels["containerd.io/gc.expire"] = time.Now().Add(d).Format(time.RFC3339)
+
+ return nil
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/auth/fetch.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/auth/fetch.go
similarity index 80%
rename from vendor/github.com/containerd/containerd/remotes/docker/auth/fetch.go
rename to vendor/github.com/containerd/containerd/v2/core/remotes/docker/auth/fetch.go
index c259873d2a..f68c22ab7a 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/auth/fetch.go
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/auth/fetch.go
@@ -26,10 +26,10 @@ import (
"strings"
"time"
- "github.com/containerd/containerd/log"
- remoteserrors "github.com/containerd/containerd/remotes/errors"
- "github.com/containerd/containerd/version"
- "golang.org/x/net/context/ctxhttp"
+ remoteserrors "github.com/containerd/containerd/v2/core/remotes/errors"
+ "github.com/containerd/containerd/v2/pkg/tracing"
+ "github.com/containerd/containerd/v2/version"
+ "github.com/containerd/log"
)
var (
@@ -78,24 +78,28 @@ type TokenOptions struct {
// FetchRefreshToken enables fetching a refresh token (aka "identity token", "offline token") along with the bearer token.
//
// For HTTP GET mode (FetchToken), FetchRefreshToken sets `offline_token=true` in the request.
- // https://docs.docker.com/registry/spec/auth/token/#requesting-a-token
+ // https://distribution.github.io/distribution/spec/auth/token/#requesting-a-token
//
// For HTTP POST mode (FetchTokenWithOAuth), FetchRefreshToken sets `access_type=offline` in the request.
- // https://docs.docker.com/registry/spec/auth/oauth/#getting-a-token
+ // https://distribution.github.io/distribution/spec/auth/oauth/#getting-a-token
FetchRefreshToken bool
}
// OAuthTokenResponse is response from fetching token with a OAuth POST request
type OAuthTokenResponse struct {
- AccessToken string `json:"access_token"`
- RefreshToken string `json:"refresh_token"`
- ExpiresIn int `json:"expires_in"`
- IssuedAt time.Time `json:"issued_at"`
- Scope string `json:"scope"`
+ AccessToken string `json:"access_token"`
+ RefreshToken string `json:"refresh_token"`
+ ExpiresInSeconds int `json:"expires_in"`
+ IssuedAt time.Time `json:"issued_at"`
+ Scope string `json:"scope"`
}
// FetchTokenWithOAuth fetches a token using a POST request
func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.Header, clientID string, to TokenOptions) (*OAuthTokenResponse, error) {
+ c := *client
+ client = &c
+ tracing.UpdateHTTPClient(client, tracing.Name("remotes.docker.resolver", "FetchTokenWithOAuth"))
+
form := url.Values{}
if len(to.Scopes) > 0 {
form.Set("scope", strings.Join(to.Scopes, " "))
@@ -115,7 +119,7 @@ func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.
form.Set("access_type", "offline")
}
- req, err := http.NewRequest("POST", to.Realm, strings.NewReader(form.Encode()))
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, to.Realm, strings.NewReader(form.Encode()))
if err != nil {
return nil, err
}
@@ -127,7 +131,7 @@ func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.
req.Header.Set("User-Agent", "containerd/"+version.Version)
}
- resp, err := ctxhttp.Do(ctx, client, req)
+ resp, err := client.Do(req)
if err != nil {
return nil, err
}
@@ -153,16 +157,20 @@ func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.
// FetchTokenResponse is response from fetching token with GET request
type FetchTokenResponse struct {
- Token string `json:"token"`
- AccessToken string `json:"access_token"`
- ExpiresIn int `json:"expires_in"`
- IssuedAt time.Time `json:"issued_at"`
- RefreshToken string `json:"refresh_token"`
+ Token string `json:"token"`
+ AccessToken string `json:"access_token"`
+ ExpiresInSeconds int `json:"expires_in"`
+ IssuedAt time.Time `json:"issued_at"`
+ RefreshToken string `json:"refresh_token"`
}
// FetchToken fetches a token using a GET request
func FetchToken(ctx context.Context, client *http.Client, headers http.Header, to TokenOptions) (*FetchTokenResponse, error) {
- req, err := http.NewRequest("GET", to.Realm, nil)
+ c := *client
+ client = &c
+ tracing.UpdateHTTPClient(client, tracing.Name("remotes.docker.resolver", "FetchToken"))
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, to.Realm, nil)
if err != nil {
return nil, err
}
@@ -194,7 +202,7 @@ func FetchToken(ctx context.Context, client *http.Client, headers http.Header, t
req.URL.RawQuery = reqParams.Encode()
- resp, err := ctxhttp.Do(ctx, client, req)
+ resp, err := client.Do(req)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/auth/parse.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/auth/parse.go
similarity index 98%
rename from vendor/github.com/containerd/containerd/remotes/docker/auth/parse.go
rename to vendor/github.com/containerd/containerd/v2/core/remotes/docker/auth/parse.go
index e4529a7761..6ca935158e 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/auth/parse.go
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/auth/parse.go
@@ -49,7 +49,7 @@ type byScheme []Challenge
func (bs byScheme) Len() int { return len(bs) }
func (bs byScheme) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] }
-// Sort in priority order: token > digest > basic
+// Less sorts in priority order: token > digest > basic
func (bs byScheme) Less(i, j int) bool { return bs[i].Scheme > bs[j].Scheme }
// Octet types from RFC 2616.
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/authorizer.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/authorizer.go
new file mode 100644
index 0000000000..00d1b34114
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/authorizer.go
@@ -0,0 +1,387 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "context"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/containerd/containerd/v2/core/remotes/docker/auth"
+ remoteerrors "github.com/containerd/containerd/v2/core/remotes/errors"
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+)
+
+type dockerAuthorizer struct {
+ credentials func(string) (string, string, error)
+
+ client *http.Client
+ header http.Header
+ mu sync.RWMutex
+
+ // indexed by host name
+ handlers map[string]*authHandler
+
+ onFetchRefreshToken OnFetchRefreshToken
+}
+
+type authorizerConfig struct {
+ credentials func(string) (string, string, error)
+ client *http.Client
+ header http.Header
+ onFetchRefreshToken OnFetchRefreshToken
+}
+
+// AuthorizerOpt configures an authorizer
+type AuthorizerOpt func(*authorizerConfig)
+
+// WithAuthClient provides the HTTP client for the authorizer
+func WithAuthClient(client *http.Client) AuthorizerOpt {
+ return func(opt *authorizerConfig) {
+ opt.client = client
+ }
+}
+
+// WithAuthCreds provides a credential function to the authorizer
+func WithAuthCreds(creds func(string) (string, string, error)) AuthorizerOpt {
+ return func(opt *authorizerConfig) {
+ opt.credentials = creds
+ }
+}
+
+// WithAuthHeader provides HTTP headers for authorization
+//
+// We need to merge instead of replacing because header may be set by
+// a per-host hosts.toml or/AND by a global header config (e.g., cri.config.headers)
+func WithAuthHeader(hdr http.Header) AuthorizerOpt {
+ return func(opt *authorizerConfig) {
+ if opt.header == nil {
+ opt.header = hdr.Clone()
+ } else {
+ for k, v := range hdr {
+ opt.header[k] = append(opt.header[k], v...)
+ }
+ }
+ }
+}
+
+// OnFetchRefreshToken is called on fetching request token.
+type OnFetchRefreshToken func(ctx context.Context, refreshToken string, req *http.Request)
+
+// WithFetchRefreshToken enables fetching "refresh token" (aka "identity token", "offline token").
+func WithFetchRefreshToken(f OnFetchRefreshToken) AuthorizerOpt {
+ return func(opt *authorizerConfig) {
+ opt.onFetchRefreshToken = f
+ }
+}
+
+// NewDockerAuthorizer creates an authorizer using Docker's registry
+// authentication spec.
+// See https://distribution.github.io/distribution/spec/auth/
+func NewDockerAuthorizer(opts ...AuthorizerOpt) Authorizer {
+ var ao authorizerConfig
+ for _, opt := range opts {
+ opt(&ao)
+ }
+
+ if ao.client == nil {
+ ao.client = http.DefaultClient
+ }
+
+ return &dockerAuthorizer{
+ credentials: ao.credentials,
+ client: ao.client,
+ header: ao.header,
+ handlers: make(map[string]*authHandler),
+ onFetchRefreshToken: ao.onFetchRefreshToken,
+ }
+}
+
+// Authorize handles auth request.
+func (a *dockerAuthorizer) Authorize(ctx context.Context, req *http.Request) error {
+ // skip if there is no auth handler
+ ah := a.getAuthHandler(req.URL.Host)
+ if ah == nil {
+ return nil
+ }
+
+ auth, refreshToken, err := ah.authorize(ctx)
+ if err != nil {
+ return err
+ }
+
+ req.Header.Set("Authorization", auth)
+
+ if refreshToken != "" {
+ a.mu.RLock()
+ onFetchRefreshToken := a.onFetchRefreshToken
+ a.mu.RUnlock()
+ if onFetchRefreshToken != nil {
+ onFetchRefreshToken(ctx, refreshToken, req)
+ }
+ }
+ return nil
+}
+
+func (a *dockerAuthorizer) getAuthHandler(host string) *authHandler {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ return a.handlers[host]
+}
+
+func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.Response) error {
+ last := responses[len(responses)-1]
+ host := last.Request.URL.Host
+
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for _, c := range auth.ParseAuthHeader(last.Header) {
+ if c.Scheme == auth.BearerAuth {
+ if retry, err := invalidAuthorization(ctx, c, responses); err != nil {
+ delete(a.handlers, host)
+ return err
+ } else if retry {
+ delete(a.handlers, host)
+ }
+
+ // reuse existing handler
+ //
+ // assume that one registry will return the common
+ // challenge information, including realm and service.
+ // and the resource scope is only different part
+ // which can be provided by each request.
+ if _, ok := a.handlers[host]; ok {
+ return nil
+ }
+
+ var username, secret string
+ if a.credentials != nil {
+ var err error
+ username, secret, err = a.credentials(host)
+ if err != nil {
+ return err
+ }
+ }
+
+ common, err := auth.GenerateTokenOptions(ctx, host, username, secret, c)
+ if err != nil {
+ return err
+ }
+ common.FetchRefreshToken = a.onFetchRefreshToken != nil
+
+ a.handlers[host] = newAuthHandler(a.client, a.header, c.Scheme, common)
+ return nil
+ } else if c.Scheme == auth.BasicAuth && a.credentials != nil {
+ username, secret, err := a.credentials(host)
+ if err != nil {
+ return err
+ }
+
+ if username == "" || secret == "" {
+ return fmt.Errorf("%w: no basic auth credentials", ErrInvalidAuthorization)
+ }
+
+ a.handlers[host] = newAuthHandler(a.client, a.header, c.Scheme, auth.TokenOptions{
+ Username: username,
+ Secret: secret,
+ })
+ return nil
+ }
+ }
+ return fmt.Errorf("failed to find supported auth scheme: %w", errdefs.ErrNotImplemented)
+}
+
+// authResult is used to control limit rate.
+type authResult struct {
+ sync.WaitGroup
+ token string
+ refreshToken string
+ expirationTime *time.Time
+ err error
+}
+
+// authHandler is used to handle auth request per registry server.
+type authHandler struct {
+ sync.Mutex
+
+ header http.Header
+
+ client *http.Client
+
+ // only support basic and bearer schemes
+ scheme auth.AuthenticationScheme
+
+ // common contains common challenge answer
+ common auth.TokenOptions
+
+ // scopedTokens caches token indexed by scopes, which used in
+ // bearer auth case
+ scopedTokens map[string]*authResult
+}
+
+func newAuthHandler(client *http.Client, hdr http.Header, scheme auth.AuthenticationScheme, opts auth.TokenOptions) *authHandler {
+ return &authHandler{
+ header: hdr,
+ client: client,
+ scheme: scheme,
+ common: opts,
+ scopedTokens: map[string]*authResult{},
+ }
+}
+
+func (ah *authHandler) authorize(ctx context.Context) (string, string, error) {
+ switch ah.scheme {
+ case auth.BasicAuth:
+ return ah.doBasicAuth(ctx)
+ case auth.BearerAuth:
+ return ah.doBearerAuth(ctx)
+ default:
+ return "", "", fmt.Errorf("failed to find supported auth scheme: %s: %w", string(ah.scheme), errdefs.ErrNotImplemented)
+ }
+}
+
+func (ah *authHandler) doBasicAuth(ctx context.Context) (string, string, error) {
+ username, secret := ah.common.Username, ah.common.Secret
+
+ if username == "" || secret == "" {
+ return "", "", fmt.Errorf("failed to handle basic auth because missing username or secret")
+ }
+
+ auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + secret))
+ return fmt.Sprintf("Basic %s", auth), "", nil
+}
+
+func (ah *authHandler) doBearerAuth(ctx context.Context) (token, refreshToken string, err error) {
+ // copy common tokenOptions
+ to := ah.common
+
+ to.Scopes = GetTokenScopes(ctx, to.Scopes)
+
+ // Docs: https://distribution.github.io/distribution/spec/auth/scope/
+ scoped := strings.Join(to.Scopes, " ")
+
+ // Keep track of the expiration time of cached bearer tokens so they can be
+ // refreshed when they expire without a server roundtrip.
+ var expirationTime *time.Time
+
+ ah.Lock()
+ if r, exist := ah.scopedTokens[scoped]; exist && (r.expirationTime == nil || r.expirationTime.After(time.Now())) {
+ ah.Unlock()
+ r.Wait()
+ return r.token, r.refreshToken, r.err
+ }
+
+ // only one fetch token job
+ r := new(authResult)
+ r.Add(1)
+ ah.scopedTokens[scoped] = r
+ ah.Unlock()
+
+ defer func() {
+ token = fmt.Sprintf("Bearer %s", token)
+ r.token, r.refreshToken, r.err, r.expirationTime = token, refreshToken, err, expirationTime
+ r.Done()
+ }()
+
+ // fetch token for the resource scope
+ if to.Secret != "" {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("failed to fetch oauth token: %w", err)
+ }
+ }()
+ // credential information is provided, use oauth POST endpoint
+ // TODO: Allow setting client_id
+ resp, err := auth.FetchTokenWithOAuth(ctx, ah.client, ah.header, "containerd-client", to)
+ if err != nil {
+ var errStatus remoteerrors.ErrUnexpectedStatus
+ if errors.As(err, &errStatus) {
+ // Registries without support for POST may return 404 for POST /v2/token.
+ // As of September 2017, GCR is known to return 404.
+ // As of February 2018, JFrog Artifactory is known to return 401.
+ // As of January 2022, ACR is known to return 400.
+ if (errStatus.StatusCode == 405 && to.Username != "") || errStatus.StatusCode == 404 || errStatus.StatusCode == 401 || errStatus.StatusCode == 400 {
+ resp, err := auth.FetchToken(ctx, ah.client, ah.header, to)
+ if err != nil {
+ return "", "", err
+ }
+ expirationTime = getExpirationTime(resp.ExpiresInSeconds)
+ return resp.Token, resp.RefreshToken, nil
+ }
+ log.G(ctx).WithFields(log.Fields{
+ "status": errStatus.Status,
+ "body": string(errStatus.Body),
+ }).Debugf("token request failed")
+ }
+ return "", "", err
+ }
+ expirationTime = getExpirationTime(resp.ExpiresInSeconds)
+ return resp.AccessToken, resp.RefreshToken, nil
+ }
+ // do request anonymously
+ resp, err := auth.FetchToken(ctx, ah.client, ah.header, to)
+ if err != nil {
+ return "", "", fmt.Errorf("failed to fetch anonymous token: %w", err)
+ }
+ expirationTime = getExpirationTime(resp.ExpiresInSeconds)
+ return resp.Token, resp.RefreshToken, nil
+}
+
+func getExpirationTime(expiresInSeconds int) *time.Time {
+ if expiresInSeconds <= 0 {
+ return nil
+ }
+ expirationTime := time.Now().Add(time.Duration(expiresInSeconds) * time.Second)
+ return &expirationTime
+}
+
+func invalidAuthorization(ctx context.Context, c auth.Challenge, responses []*http.Response) (retry bool, _ error) {
+ errStr := c.Parameters["error"]
+ if errStr == "" {
+ return retry, nil
+ }
+
+ n := len(responses)
+ if n == 1 || (n > 1 && !sameRequest(responses[n-2].Request, responses[n-1].Request)) {
+ limitedErr := errStr
+ errLenghLimit := 64
+ if len(limitedErr) > errLenghLimit {
+ limitedErr = limitedErr[:errLenghLimit] + "..."
+ }
+ log.G(ctx).WithField("error", limitedErr).Debug("authorization error using bearer token, retrying")
+ return true, nil
+ }
+
+ return retry, fmt.Errorf("server message: %s: %w", errStr, ErrInvalidAuthorization)
+}
+
+func sameRequest(r1, r2 *http.Request) bool {
+ if r1.Method != r2.Method {
+ return false
+ }
+ if *r1.URL != *r2.URL {
+ return false
+ }
+ return true
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/converter.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/converter.go
new file mode 100644
index 0000000000..f21103e17f
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/converter.go
@@ -0,0 +1,85 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/core/images"
+ "github.com/containerd/containerd/v2/core/remotes"
+ "github.com/containerd/log"
+ digest "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// LegacyConfigMediaType should be replaced by OCI image spec.
+//
+// More detail: docker/distribution#1622
+const LegacyConfigMediaType = "application/octet-stream"
+
+// ConvertManifest changes application/octet-stream to schema2 config media type if need.
+//
+// NOTE:
+// 1. original manifest will be deleted by next gc round.
+// 2. don't cover manifest list.
+func ConvertManifest(ctx context.Context, store content.Store, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
+ if !images.IsManifestType(desc.MediaType) {
+ log.G(ctx).Warnf("do nothing for media type: %s", desc.MediaType)
+ return desc, nil
+ }
+
+ // read manifest data
+ mb, err := content.ReadBlob(ctx, store, desc)
+ if err != nil {
+ return ocispec.Descriptor{}, fmt.Errorf("failed to read index data: %w", err)
+ }
+
+ var manifest ocispec.Manifest
+ if err := json.Unmarshal(mb, &manifest); err != nil {
+ return ocispec.Descriptor{}, fmt.Errorf("failed to unmarshal data into manifest: %w", err)
+ }
+
+ // check config media type
+ if manifest.Config.MediaType != LegacyConfigMediaType {
+ return desc, nil
+ }
+
+ manifest.Config.MediaType = images.MediaTypeDockerSchema2Config
+ data, err := json.MarshalIndent(manifest, "", " ")
+ if err != nil {
+ return ocispec.Descriptor{}, fmt.Errorf("failed to marshal manifest: %w", err)
+ }
+
+ // update manifest with gc labels
+ desc.Digest = digest.Canonical.FromBytes(data)
+ desc.Size = int64(len(data))
+
+ labels := map[string]string{}
+ for i, c := range append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...) {
+ labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = c.Digest.String()
+ }
+
+ ref := remotes.MakeRefKey(ctx, desc)
+ if err := content.WriteBlob(ctx, store, ref, bytes.NewReader(data), desc, content.WithLabels(labels)); err != nil {
+ return ocispec.Descriptor{}, fmt.Errorf("failed to update content: %w", err)
+ }
+ return desc, nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errcode.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errcode.go
new file mode 100644
index 0000000000..8e1469d3e9
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errcode.go
@@ -0,0 +1,305 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+
+ remoteerrors "github.com/containerd/containerd/v2/core/remotes/errors"
+)
+
+// ErrorCoder is the base interface for ErrorCode and Error allowing
+// users of each to just call ErrorCode to get the real ID of each
+type ErrorCoder interface {
+ ErrorCode() ErrorCode
+}
+
+// ErrorCode represents the error type. The errors are serialized via strings
+// and the integer format may change and should *never* be exported.
+type ErrorCode int
+
+var _ error = ErrorCode(0)
+
+// ErrorCode just returns itself
+func (ec ErrorCode) ErrorCode() ErrorCode {
+ return ec
+}
+
+// Error returns the ID/Value
+func (ec ErrorCode) Error() string {
+ // NOTE(stevvooe): Cannot use message here since it may have unpopulated args.
+ return strings.ToLower(strings.ReplaceAll(ec.String(), "_", " "))
+}
+
+// Descriptor returns the descriptor for the error code.
+func (ec ErrorCode) Descriptor() ErrorDescriptor {
+ d, ok := errorCodeToDescriptors[ec]
+
+ if !ok {
+ return ErrorCodeUnknown.Descriptor()
+ }
+
+ return d
+}
+
+// String returns the canonical identifier for this error code.
+func (ec ErrorCode) String() string {
+ return ec.Descriptor().Value
+}
+
+// Message returned the human-readable error message for this error code.
+func (ec ErrorCode) Message() string {
+ return ec.Descriptor().Message
+}
+
+// MarshalText encodes the receiver into UTF-8-encoded text and returns the
+// result.
+func (ec ErrorCode) MarshalText() (text []byte, err error) {
+ return []byte(ec.String()), nil
+}
+
+// UnmarshalText decodes the form generated by MarshalText.
+func (ec *ErrorCode) UnmarshalText(text []byte) error {
+ desc, ok := idToDescriptors[string(text)]
+
+ if !ok {
+ desc = ErrorCodeUnknown.Descriptor()
+ }
+
+ *ec = desc.Code
+
+ return nil
+}
+
+// WithMessage creates a new Error struct based on the passed-in info and
+// overrides the Message property.
+func (ec ErrorCode) WithMessage(message string) Error {
+ return Error{
+ Code: ec,
+ Message: message,
+ }
+}
+
+// WithDetail creates a new Error struct based on the passed-in info and
+// set the Detail property appropriately
+func (ec ErrorCode) WithDetail(detail interface{}) Error {
+ return Error{
+ Code: ec,
+ Message: ec.Message(),
+ }.WithDetail(detail)
+}
+
+// WithArgs creates a new Error struct and sets the Args slice
+func (ec ErrorCode) WithArgs(args ...interface{}) Error {
+ return Error{
+ Code: ec,
+ Message: ec.Message(),
+ }.WithArgs(args...)
+}
+
+// Error provides a wrapper around ErrorCode with extra Details provided.
+type Error struct {
+ Code ErrorCode `json:"code"`
+ Message string `json:"message"`
+ Detail interface{} `json:"detail,omitempty"`
+
+ // TODO(duglin): See if we need an "args" property so we can do the
+ // variable substitution right before showing the message to the user
+}
+
+var _ error = Error{}
+
+// ErrorCode returns the ID/Value of this Error
+func (e Error) ErrorCode() ErrorCode {
+ return e.Code
+}
+
+// Error returns a human readable representation of the error.
+func (e Error) Error() string {
+ return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message)
+}
+
+// WithDetail will return a new Error, based on the current one, but with
+// some Detail info added
+func (e Error) WithDetail(detail interface{}) Error {
+ return Error{
+ Code: e.Code,
+ Message: e.Message,
+ Detail: detail,
+ }
+}
+
+// WithArgs uses the passed-in list of interface{} as the substitution
+// variables in the Error's Message string, but returns a new Error
+func (e Error) WithArgs(args ...interface{}) Error {
+ return Error{
+ Code: e.Code,
+ Message: fmt.Sprintf(e.Code.Message(), args...),
+ Detail: e.Detail,
+ }
+}
+
+// ErrorDescriptor provides relevant information about a given error code.
+type ErrorDescriptor struct {
+ // Code is the error code that this descriptor describes.
+ Code ErrorCode
+
+ // Value provides a unique, string key, often captilized with
+ // underscores, to identify the error code. This value is used as the
+ // keyed value when serializing api errors.
+ Value string
+
+ // Message is a short, human readable description of the error condition
+ // included in API responses.
+ Message string
+
+ // Description provides a complete account of the errors purpose, suitable
+ // for use in documentation.
+ Description string
+
+ // HTTPStatusCode provides the http status code that is associated with
+ // this error condition.
+ HTTPStatusCode int
+}
+
+// ParseErrorCode returns the value by the string error code.
+// `ErrorCodeUnknown` will be returned if the error is not known.
+func ParseErrorCode(value string) ErrorCode {
+ ed, ok := idToDescriptors[value]
+ if ok {
+ return ed.Code
+ }
+
+ return ErrorCodeUnknown
+}
+
+// Errors provides the envelope for multiple errors and a few sugar methods
+// for use within the application.
+type Errors []error
+
+var _ error = Errors{}
+
+func (errs Errors) Error() string {
+ switch len(errs) {
+ case 0:
+ return ""
+ case 1:
+ return errs[0].Error()
+ default:
+ msg := "errors:\n"
+ for _, err := range errs {
+ msg += err.Error() + "\n"
+ }
+ return msg
+ }
+}
+
+// Len returns the current number of errors.
+func (errs Errors) Len() int {
+ return len(errs)
+}
+
+// MarshalJSON converts slice of error, ErrorCode or Error into a
+// slice of Error - then serializes
+func (errs Errors) MarshalJSON() ([]byte, error) {
+ var tmpErrs struct {
+ Errors []Error `json:"errors,omitempty"`
+ }
+
+ for _, daErr := range errs {
+ var err Error
+
+ switch daErr := daErr.(type) {
+ case ErrorCode:
+ err = daErr.WithDetail(nil)
+ case Error:
+ err = daErr
+ default:
+ err = ErrorCodeUnknown.WithDetail(daErr)
+
+ }
+
+ // If the Error struct was setup and they forgot to set the
+ // Message field (meaning its "") then grab it from the ErrCode
+ msg := err.Message
+ if msg == "" {
+ msg = err.Code.Message()
+ }
+
+ tmpErrs.Errors = append(tmpErrs.Errors, Error{
+ Code: err.Code,
+ Message: msg,
+ Detail: err.Detail,
+ })
+ }
+
+ return json.Marshal(tmpErrs)
+}
+
+// UnmarshalJSON deserializes []Error and then converts it into slice of
+// Error or ErrorCode
+func (errs *Errors) UnmarshalJSON(data []byte) error {
+ var tmpErrs struct {
+ Errors []Error
+ }
+
+ if err := json.Unmarshal(data, &tmpErrs); err != nil {
+ return err
+ }
+
+ var newErrs Errors
+ for _, daErr := range tmpErrs.Errors {
+ // If Message is empty or exactly matches the Code's message string
+ // then just use the Code, no need for a full Error struct
+ if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) {
+ // Error's w/o details get converted to ErrorCode
+ newErrs = append(newErrs, daErr.Code)
+ } else {
+ // Error's w/ details are untouched
+ newErrs = append(newErrs, Error{
+ Code: daErr.Code,
+ Message: daErr.Message,
+ Detail: daErr.Detail,
+ })
+ }
+ }
+
+ *errs = newErrs
+ return nil
+}
+
+func unexpectedResponseErr(resp *http.Response) (retErr error) {
+ retErr = remoteerrors.NewUnexpectedStatusErr(resp)
+
+ // Decode registry error if provided
+ if rerr := retErr.(remoteerrors.ErrUnexpectedStatus); len(rerr.Body) > 0 {
+ var registryErr Errors
+ if err := json.Unmarshal(rerr.Body, ®istryErr); err == nil && registryErr.Len() > 0 {
+ // Join the unexpected error with the typed errors, when printed it will
+ // show the unexpected error message and the registry errors. The body
+ // is always excluded from the unexpected error message. This also allows
+ // clients to decode into either type.
+ retErr = errors.Join(rerr, registryErr)
+ }
+ }
+
+ return
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errdesc.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errdesc.go
new file mode 100644
index 0000000000..b2bd4d82bd
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/errdesc.go
@@ -0,0 +1,154 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "fmt"
+ "net/http"
+ "sort"
+ "sync"
+)
+
+var (
+ errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
+ idToDescriptors = map[string]ErrorDescriptor{}
+ groupToDescriptors = map[string][]ErrorDescriptor{}
+)
+
+var (
+ // ErrorCodeUnknown is a generic error that can be used as a last
+ // resort if there is no situation-specific error message that can be used
+ ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
+ Value: "UNKNOWN",
+ Message: "unknown error",
+ Description: `Generic error returned when the error does not have an
+ API classification.`,
+ HTTPStatusCode: http.StatusInternalServerError,
+ })
+
+ // ErrorCodeUnsupported is returned when an operation is not supported.
+ ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
+ Value: "UNSUPPORTED",
+ Message: "The operation is unsupported.",
+ Description: `The operation was unsupported due to a missing
+ implementation or invalid set of parameters.`,
+ HTTPStatusCode: http.StatusMethodNotAllowed,
+ })
+
+ // ErrorCodeUnauthorized is returned if a request requires
+ // authentication.
+ ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
+ Value: "UNAUTHORIZED",
+ Message: "authentication required",
+ Description: `The access controller was unable to authenticate
+ the client. Often this will be accompanied by a
+ Www-Authenticate HTTP response header indicating how to
+ authenticate.`,
+ HTTPStatusCode: http.StatusUnauthorized,
+ })
+
+ // ErrorCodeDenied is returned if a client does not have sufficient
+ // permission to perform an action.
+ ErrorCodeDenied = Register("errcode", ErrorDescriptor{
+ Value: "DENIED",
+ Message: "requested access to the resource is denied",
+ Description: `The access controller denied access for the
+ operation on a resource.`,
+ HTTPStatusCode: http.StatusForbidden,
+ })
+
+ // ErrorCodeUnavailable provides a common error to report unavailability
+ // of a service or endpoint.
+ ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
+ Value: "UNAVAILABLE",
+ Message: "service unavailable",
+ Description: "Returned when a service is not available",
+ HTTPStatusCode: http.StatusServiceUnavailable,
+ })
+
+ // ErrorCodeTooManyRequests is returned if a client attempts too many
+ // times to contact a service endpoint.
+ ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{
+ Value: "TOOMANYREQUESTS",
+ Message: "too many requests",
+ Description: `Returned when a client attempts to contact a
+ service too many times`,
+ HTTPStatusCode: http.StatusTooManyRequests,
+ })
+)
+
+var nextCode = 1000
+var registerLock sync.Mutex
+
+// Register will make the passed-in error known to the environment and
+// return a new ErrorCode
+func Register(group string, descriptor ErrorDescriptor) ErrorCode {
+ registerLock.Lock()
+ defer registerLock.Unlock()
+
+ descriptor.Code = ErrorCode(nextCode)
+
+ if _, ok := idToDescriptors[descriptor.Value]; ok {
+ panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
+ }
+ if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
+ panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
+ }
+
+ groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
+ errorCodeToDescriptors[descriptor.Code] = descriptor
+ idToDescriptors[descriptor.Value] = descriptor
+
+ nextCode++
+ return descriptor.Code
+}
+
+type byValue []ErrorDescriptor
+
+func (a byValue) Len() int { return len(a) }
+func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
+
+// GetGroupNames returns the list of Error group names that are registered
+func GetGroupNames() []string {
+ keys := []string{}
+
+ for k := range groupToDescriptors {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+// GetErrorCodeGroup returns the named group of error descriptors
+func GetErrorCodeGroup(name string) []ErrorDescriptor {
+ desc := groupToDescriptors[name]
+ sort.Sort(byValue(desc))
+ return desc
+}
+
+// GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are
+// registered, irrespective of what group they're in
+func GetErrorAllDescriptors() []ErrorDescriptor {
+ result := []ErrorDescriptor{}
+
+ for _, group := range GetGroupNames() {
+ result = append(result, GetErrorCodeGroup(group)...)
+ }
+ sort.Sort(byValue(result))
+ return result
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go
new file mode 100644
index 0000000000..57e13f0da6
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go
@@ -0,0 +1,627 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "bytes"
+ "compress/flate"
+ "compress/gzip"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+ "sync"
+
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ "github.com/klauspost/compress/zstd"
+ digest "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+
+ "github.com/containerd/containerd/v2/core/images"
+ "github.com/containerd/containerd/v2/core/remotes"
+)
+
+type bufferPool struct {
+ pool *sync.Pool
+}
+
+func newbufferPool(bufCap int64) *bufferPool {
+ pool := &sync.Pool{
+ New: func() any {
+ return bytes.NewBuffer(make([]byte, 0, bufCap))
+ },
+ }
+ return &bufferPool{
+ pool: pool,
+ }
+}
+
+func (p *bufferPool) Get() *bytes.Buffer {
+ buf := p.pool.Get().(*bytes.Buffer)
+ return buf
+}
+
+func (p *bufferPool) Put(buffer *bytes.Buffer) {
+ p.pool.Put(buffer)
+}
+
+var ErrClosedPipe = errors.New("bufpipe: read/write on closed pipe")
+
+// pipe implements an asynchronous buffered pipe designed for high-throughput
+// I/O with configurable initial buffer sizes and buffer reuse. It decouples
+// read/write operations, allowing writers to proceed without blocking (unless
+// the pipe is closed) and readers to wait efficiently for incoming data.
+//
+// Key Characteristics:
+// - Asynchronous Operation: Writers populate buffers independently of read
+// timing, enabling continuous data flow without reader-writer synchronization.
+// - Dynamic Buffering: Active buffer grows organically to handle large payloads, while
+// the initial capacity (bufCap) balances memory pre-allocation and growth overhead.
+// - Buffer Recycling: Retrieved from/pushed to a pool to minimize allocations, reducing
+// garbage collection pressure in sustained I/O scenarios.
+// - Error Semantics: Closes deterministically on first error (read or write), propagating
+// errors atomically to both ends while draining buffered data.
+//
+// Difference with io.Pipe:
+// - Unlike io.Pipe's strict synchronization (blocking write until read), this implementation
+// allows writers to buffer data ahead of reads, improving throughput for bursty workloads.
+//
+// Synchronization & Internals:
+// - Condition Variable (sync.Cond): Coordinates reader/writer, waking readers on new data
+// or closure. Locking is centralized via the condition's mutex.
+// - Buffer Lifecycle: Active buffer serves writes until read depletion, after which it's
+// recycled to the pool. Pooled buffers retain their capacity across uses.
+// - Error Handling: Write errors (werr) permanently fail writes; read errors (rerr) mark
+// terminal read state after buffer exhaustion.
+//
+// Future Considerations:
+// - Zero-copy reads/writes to avoid buffer copying overhead.
+// - Memory-mapped file backing for multi-gigabyte payloads.
+type pipe struct {
+ cond *sync.Cond // Coordinates read/write signaling via Lock+Wait/Signal
+ bufPool *bufferPool // Reusable buffers with initial capacity bufCap
+ buf *bytes.Buffer // Active data buffer (nil when empty/returned to pool)
+ rerr, werr error // Terminal read/write errors (sticky once set)
+}
+
+type pipeReader struct {
+ *pipe
+}
+
+type pipeWriter struct {
+ *pipe
+}
+
+func newPipeWriter(bufPool *bufferPool) (*pipeReader, *pipeWriter) {
+ p := &pipe{
+ cond: sync.NewCond(new(sync.Mutex)),
+ bufPool: bufPool,
+ buf: nil,
+ }
+ return &pipeReader{
+ pipe: p,
+ }, &pipeWriter{
+ pipe: p,
+ }
+}
+
+// Read implements the standard Read interface: it reads data from the pipe,
+// reading from the internal buffer, otherwise blocking until a writer arrives
+// or the write end is closed. If the write end is closed with an error, that
+// error is returned as err; otherwise err is io.EOF.
+func (r *pipeReader) Read(data []byte) (n int, err error) {
+ r.cond.L.Lock()
+ defer r.cond.L.Unlock()
+
+ if r.buf == nil {
+ r.buf = r.bufPool.Get()
+ }
+
+ for {
+ n, err = r.buf.Read(data)
+ // If not closed and no read, wait for writing.
+ if err == io.EOF && r.rerr == nil && n == 0 {
+ r.cond.Wait() // Wait for data to be written
+ continue
+ }
+ break
+ }
+ if err == io.EOF {
+ // Put buffer back to pool
+ r.bufPool.Put(r.buf)
+ r.buf = nil
+ return n, r.rerr
+ }
+ return n, err
+}
+
+// Close closes the reader; subsequent writes from the write half of the pipe
+// will return error ErrClosedPipe.
+func (r *pipeReader) Close() error {
+ return r.CloseWithError(nil)
+}
+
+// CloseWithError closes the reader; subsequent writes to the write half of the
+// pipe will return the error err.
+func (r *pipeReader) CloseWithError(err error) error {
+ r.cond.L.Lock()
+ defer r.cond.L.Unlock()
+
+ if err == nil {
+ err = ErrClosedPipe
+ }
+ r.werr = err
+ return nil
+}
+
+// Write implements the standard Write interface: it writes data to the internal
+// buffer. If the read end is closed with an error, that err is returned as err;
+// otherwise err is ErrClosedPipe.
+func (w *pipeWriter) Write(data []byte) (int, error) {
+ w.cond.L.Lock()
+ defer w.cond.L.Unlock()
+
+ if w.werr != nil {
+ return 0, w.werr
+ }
+
+ if w.buf == nil {
+ w.buf = w.bufPool.Get()
+ }
+
+ n, err := w.buf.Write(data)
+ w.cond.Signal()
+ return n, err
+}
+
+// Close closes the writer; subsequent reads from the read half of the pipe will
+// return io.EOF once the internal buffer get empty.
+func (w *pipeWriter) Close() error {
+ return w.CloseWithError(nil)
+}
+
+// Close closes the writer; subsequent reads from the read half of the pipe will
+// return err once the internal buffer get empty.
+func (w *pipeWriter) CloseWithError(err error) error {
+ w.cond.L.Lock()
+ defer w.cond.L.Unlock()
+
+ if err == nil {
+ err = io.EOF
+ }
+ w.rerr = err
+ w.cond.Broadcast()
+ return nil
+}
+
+type dockerFetcher struct {
+ *dockerBase
+}
+
+func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) {
+ ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", desc.Digest))
+
+ hosts := r.filterHosts(HostCapabilityPull)
+ if len(hosts) == 0 {
+ return nil, fmt.Errorf("no pull hosts: %w", errdefs.ErrNotFound)
+ }
+
+ ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false)
+ if err != nil {
+ return nil, err
+ }
+
+ return newHTTPReadSeeker(desc.Size, func(offset int64) (io.ReadCloser, error) {
+ // firstly try fetch via external urls
+ for _, us := range desc.URLs {
+ u, err := url.Parse(us)
+ if err != nil {
+ log.G(ctx).WithError(err).Debugf("failed to parse %q", us)
+ continue
+ }
+ if u.Scheme != "http" && u.Scheme != "https" {
+ log.G(ctx).Debug("non-http(s) alternative url is unsupported")
+ continue
+ }
+ ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u))
+ log.G(ctx).Info("request")
+
+ // Try this first, parse it
+ host := RegistryHost{
+ Client: http.DefaultClient,
+ Host: u.Host,
+ Scheme: u.Scheme,
+ Path: u.Path,
+ Capabilities: HostCapabilityPull,
+ }
+ req := r.request(host, http.MethodGet)
+ // Strip namespace from base
+ req.path = u.Path
+ if u.RawQuery != "" {
+ req.path = req.path + "?" + u.RawQuery
+ }
+
+ rc, _, err := r.open(ctx, req, desc.MediaType, offset, false)
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ continue // try one of the other urls.
+ }
+
+ return nil, err
+ }
+
+ return rc, nil
+ }
+
+ // Try manifests endpoints for manifests types
+ if images.IsManifestType(desc.MediaType) || images.IsIndexType(desc.MediaType) {
+
+ var firstErr error
+ for i, host := range r.hosts {
+ req := r.request(host, http.MethodGet, "manifests", desc.Digest.String())
+ if err := req.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, err
+ }
+
+ rc, _, err := r.open(ctx, req, desc.MediaType, offset, i == len(r.hosts)-1)
+ if err != nil {
+ // Store the error for referencing later
+ if firstErr == nil {
+ firstErr = err
+ }
+ continue // try another host
+ }
+
+ return rc, nil
+ }
+
+ return nil, firstErr
+ }
+
+ // Finally use blobs endpoints
+ var firstErr error
+ for i, host := range r.hosts {
+ req := r.request(host, http.MethodGet, "blobs", desc.Digest.String())
+ if err := req.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, err
+ }
+
+ rc, _, err := r.open(ctx, req, desc.MediaType, offset, i == len(r.hosts)-1)
+ if err != nil {
+ // Store the error for referencing later
+ if firstErr == nil {
+ firstErr = err
+ }
+ continue // try another host
+ }
+
+ return rc, nil
+ }
+
+ if errdefs.IsNotFound(firstErr) {
+ firstErr = fmt.Errorf("could not fetch content descriptor %v (%v) from remote: %w",
+ desc.Digest, desc.MediaType, errdefs.ErrNotFound,
+ )
+ }
+
+ return nil, firstErr
+
+ })
+}
+
+func (r dockerFetcher) createGetReq(ctx context.Context, host RegistryHost, lastHost bool, mediatype string, ps ...string) (*request, int64, error) {
+ headReq := r.request(host, http.MethodHead, ps...)
+ if err := headReq.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, 0, err
+ }
+
+ if mediatype == "" {
+ headReq.header.Set("Accept", "*/*")
+ } else {
+ headReq.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", "))
+ }
+
+ headResp, err := headReq.doWithRetries(ctx, lastHost)
+ if err != nil {
+ return nil, 0, err
+ }
+ if headResp.Body != nil {
+ headResp.Body.Close()
+ }
+ if headResp.StatusCode > 299 {
+ return nil, 0, fmt.Errorf("unexpected HEAD status code %v: %s", headReq.String(), headResp.Status)
+ }
+
+ getReq := r.request(host, http.MethodGet, ps...)
+ if err := getReq.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, 0, err
+ }
+ return getReq, headResp.ContentLength, nil
+}
+
+func (r dockerFetcher) FetchByDigest(ctx context.Context, dgst digest.Digest, opts ...remotes.FetchByDigestOpts) (io.ReadCloser, ocispec.Descriptor, error) {
+ var desc ocispec.Descriptor
+ ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", dgst))
+ var config remotes.FetchByDigestConfig
+ for _, o := range opts {
+ if err := o(ctx, &config); err != nil {
+ return nil, desc, err
+ }
+ }
+
+ hosts := r.filterHosts(HostCapabilityPull)
+ if len(hosts) == 0 {
+ return nil, desc, fmt.Errorf("no pull hosts: %w", errdefs.ErrNotFound)
+ }
+
+ ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false)
+ if err != nil {
+ return nil, desc, err
+ }
+
+ var (
+ getReq *request
+ sz int64
+ firstErr error
+ )
+
+ for i, host := range r.hosts {
+ getReq, sz, err = r.createGetReq(ctx, host, i == len(r.hosts)-1, config.Mediatype, "blobs", dgst.String())
+ if err == nil {
+ break
+ }
+ // Store the error for referencing later
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+
+ if getReq == nil {
+ // Fall back to the "manifests" endpoint
+ for i, host := range r.hosts {
+ getReq, sz, err = r.createGetReq(ctx, host, i == len(r.hosts)-1, config.Mediatype, "manifests", dgst.String())
+ if err == nil {
+ break
+ }
+ // Store the error for referencing later
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+ }
+
+ if getReq == nil {
+ if errdefs.IsNotFound(firstErr) {
+ firstErr = fmt.Errorf("could not fetch content %v from remote: %w", dgst, errdefs.ErrNotFound)
+ }
+ if firstErr == nil {
+ firstErr = fmt.Errorf("could not fetch content %v from remote: (unknown)", dgst)
+ }
+ return nil, desc, firstErr
+ }
+
+ seeker, err := newHTTPReadSeeker(sz, func(offset int64) (rc io.ReadCloser, err error) {
+ rc, _, err = r.open(ctx, getReq, config.Mediatype, offset, true)
+ return
+ })
+ if err != nil {
+ return nil, desc, err
+ }
+
+ desc = ocispec.Descriptor{
+ MediaType: "application/octet-stream",
+ Digest: dgst,
+ Size: sz,
+ }
+ if config.Mediatype != "" {
+ desc.MediaType = config.Mediatype
+ }
+ return seeker, desc, nil
+}
+
+func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64, lastHost bool) (_ io.ReadCloser, _ int64, retErr error) {
+ const minChunkSize = 512
+
+ chunkSize := int64(r.performances.ConcurrentLayerFetchBuffer)
+ parallelism := int64(r.performances.MaxConcurrentDownloads)
+ if chunkSize < minChunkSize || req.body != nil {
+ parallelism = 1
+ }
+ log.G(ctx).WithField("initial_parallelism", r.performances.MaxConcurrentDownloads).
+ WithField("parallelism", parallelism).
+ WithField("chunk_size", chunkSize).
+ WithField("offset", offset).
+ Debug("fetching layer")
+ req.setMediaType(mediatype)
+ req.header.Set("Accept-Encoding", "zstd;q=1.0, gzip;q=0.8, deflate;q=0.5")
+ if parallelism > 1 || offset > 0 {
+ req.setOffset(offset)
+ }
+
+ if err := r.Acquire(ctx, 1); err != nil {
+ return nil, 0, err
+ }
+ var remaining int64
+ resp, err := req.doWithRetries(ctx, lastHost, withErrorCheck, withOffsetCheck(offset, parallelism))
+ switch err {
+ case nil:
+ // all good
+ remaining = resp.ContentLength
+ case errContentRangeIgnored:
+ if parallelism != 1 {
+ log.G(ctx).WithError(err).Info("remote host ignored content range, forcing parallelism to 1")
+ parallelism = 1
+ }
+ remaining = resp.ContentLength - offset
+ default:
+ log.G(ctx).WithError(err).Debug("fetch failed")
+ r.Release(1)
+ return nil, 0, err
+ }
+
+ body := &fnOnClose{
+ BeforeClose: func() {
+ r.Release(1)
+ },
+ ReadCloser: resp.Body,
+ }
+ defer func() {
+ if retErr != nil {
+ body.Close()
+ }
+ }()
+
+ encoding := strings.FieldsFunc(resp.Header.Get("Content-Encoding"), func(r rune) bool {
+ return r == ' ' || r == '\t' || r == ','
+ })
+
+ if remaining <= chunkSize {
+ parallelism = 1
+ }
+
+ if parallelism > 1 {
+ // If we have a content length, we can use multiple requests to fetch
+ // the content in parallel. This will make download of bigger bodies
+ // faster, at the cost of parallelism more requests and max
+ // ~(max_parallelism * goroutine footprint) memory usage. The goroutine
+ // footprint should be: the goroutine stack + pipe buffer size
+ numChunks := remaining / chunkSize
+ if numChunks*chunkSize < remaining {
+ numChunks++
+ }
+ if numChunks < parallelism {
+ parallelism = numChunks
+ }
+ queue := make(chan int64, parallelism)
+ ctx, cancelCtx := context.WithCancel(ctx)
+ done := ctx.Done()
+ readers, writers := make([]io.Reader, numChunks), make([]*pipeWriter, numChunks)
+ bufPool := newbufferPool(chunkSize)
+ for i := range numChunks {
+ readers[i], writers[i] = newPipeWriter(bufPool)
+ }
+ // keep reference of the initial body value to ensure it is closed
+ ibody := body
+ go func() {
+ for i := range numChunks {
+ select {
+ case queue <- i:
+ case <-done:
+ if i == 0 {
+ ibody.Close()
+ }
+ return // avoid leaking a goroutine if we exit early.
+ }
+ }
+ close(queue)
+ }()
+ for range parallelism {
+ go func() {
+ for i := range queue { // first in first out
+ copy := func() error {
+ var body io.ReadCloser
+ if i == 0 {
+ body = ibody
+ } else {
+ if err := r.Acquire(ctx, 1); err != nil {
+ return err
+ }
+ defer r.Release(1)
+ reqClone := req.clone()
+ reqClone.setOffset(offset + i*chunkSize)
+ nresp, err := reqClone.doWithRetries(ctx, lastHost, withErrorCheck)
+ if err != nil {
+ _ = writers[i].CloseWithError(err)
+ select {
+ case <-done:
+ return ctx.Err()
+ default:
+ cancelCtx()
+ }
+ return err
+ }
+ body = nresp.Body
+ }
+ _, err := io.Copy(writers[i], io.LimitReader(body, chunkSize))
+ _ = body.Close()
+ _ = writers[i].CloseWithError(err)
+ if err != nil && err != io.EOF {
+ cancelCtx()
+ return err
+ }
+ return nil
+ }
+ if copy() != nil {
+ return
+ }
+ }
+ }()
+ }
+ body = &fnOnClose{
+ BeforeClose: func() {
+ cancelCtx()
+ },
+ ReadCloser: io.NopCloser(io.MultiReader(readers...)),
+ }
+ }
+
+ for i := len(encoding) - 1; i >= 0; i-- {
+ algorithm := strings.ToLower(encoding[i])
+ switch algorithm {
+ case "zstd":
+ r, err := zstd.NewReader(body.ReadCloser,
+ zstd.WithDecoderLowmem(false),
+ )
+ if err != nil {
+ return nil, 0, err
+ }
+ body.ReadCloser = r.IOReadCloser()
+ case "gzip":
+ r, err := gzip.NewReader(body.ReadCloser)
+ if err != nil {
+ return nil, 0, err
+ }
+ body.ReadCloser = r
+ case "deflate":
+ body.ReadCloser = flate.NewReader(body.ReadCloser)
+ case "identity", "":
+ // no content-encoding applied, use raw body
+ default:
+ return nil, 0, errors.New("unsupported Content-Encoding algorithm: " + algorithm)
+ }
+ }
+
+ return body, remaining, nil
+}
+
+type fnOnClose struct {
+ BeforeClose func()
+ io.ReadCloser
+}
+
+// Close calls the BeforeClose function before closing the underlying
+// ReadCloser.
+func (f *fnOnClose) Close() error {
+ f.BeforeClose()
+ return f.ReadCloser.Close()
+}
+
+var _ io.ReadCloser = &fnOnClose{}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/handler.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/handler.go
new file mode 100644
index 0000000000..615869a224
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/handler.go
@@ -0,0 +1,149 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "context"
+ "fmt"
+ "net/url"
+ "strings"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/core/images"
+ "github.com/containerd/containerd/v2/pkg/labels"
+ "github.com/containerd/containerd/v2/pkg/reference"
+ "github.com/containerd/log"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// AppendDistributionSourceLabel updates the label of blob with distribution source.
+func AppendDistributionSourceLabel(manager content.Manager, ref string) (images.HandlerFunc, error) {
+ refspec, err := reference.Parse(ref)
+ if err != nil {
+ return nil, err
+ }
+
+ u, err := url.Parse("dummy://" + refspec.Locator)
+ if err != nil {
+ return nil, err
+ }
+
+ source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/")
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ info, err := manager.Info(ctx, desc.Digest)
+ if err != nil {
+ return nil, err
+ }
+
+ key := distributionSourceLabelKey(source)
+
+ originLabel := ""
+ if info.Labels != nil {
+ originLabel = info.Labels[key]
+ }
+ value := appendDistributionSourceLabel(originLabel, repo)
+
+ // The repo name has been limited under 256 and the distribution
+ // label might hit the limitation of label size, when blob data
+ // is used as the very, very common layer.
+ if err := labels.Validate(key, value); err != nil {
+ log.G(ctx).Warnf("skip to append distribution label: %s", err)
+ return nil, nil
+ }
+
+ info = content.Info{
+ Digest: desc.Digest,
+ Labels: map[string]string{
+ key: value,
+ },
+ }
+ _, err = manager.Update(ctx, info, fmt.Sprintf("labels.%s", key))
+ return nil, err
+ }, nil
+}
+
+func appendDistributionSourceLabel(originLabel, repo string) string {
+ repos := []string{}
+ if originLabel != "" {
+ repos = strings.Split(originLabel, ",")
+ }
+ repos = append(repos, repo)
+
+ // use empty string to present duplicate items
+ for i := 1; i < len(repos); i++ {
+ tmp, j := repos[i], i-1
+ for ; j >= 0 && repos[j] >= tmp; j-- {
+ if repos[j] == tmp {
+ tmp = ""
+ }
+ repos[j+1] = repos[j]
+ }
+ repos[j+1] = tmp
+ }
+
+ i := 0
+ for ; i < len(repos) && repos[i] == ""; i++ {
+ }
+
+ return strings.Join(repos[i:], ",")
+}
+
+func distributionSourceLabelKey(source string) string {
+ return labels.LabelDistributionSource + "." + source
+}
+
+// selectRepositoryMountCandidate will select the repo which has longest
+// common prefix components as the candidate.
+func selectRepositoryMountCandidate(refspec reference.Spec, sources map[string]string) string {
+ u, err := url.Parse("dummy://" + refspec.Locator)
+ if err != nil {
+ // NOTE: basically, it won't be error here
+ return ""
+ }
+
+ source, target := u.Hostname(), strings.TrimPrefix(u.Path, "/")
+ repoLabel, ok := sources[distributionSourceLabelKey(source)]
+ if !ok || repoLabel == "" {
+ return ""
+ }
+
+ n, match := 0, ""
+ components := strings.Split(target, "/")
+ for _, repo := range strings.Split(repoLabel, ",") {
+ // the target repo is not a candidate
+ if repo == target {
+ continue
+ }
+
+ if l := commonPrefixComponents(components, repo); l >= n {
+ n, match = l, repo
+ }
+ }
+ return match
+}
+
+func commonPrefixComponents(components []string, target string) int {
+ targetComponents := strings.Split(target, "/")
+
+ i := 0
+ for ; i < len(components) && i < len(targetComponents); i++ {
+ if components[i] != targetComponents[i] {
+ break
+ }
+ }
+ return i
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/httpreadseeker.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/httpreadseeker.go
new file mode 100644
index 0000000000..fa52aea647
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/httpreadseeker.go
@@ -0,0 +1,179 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+)
+
+const maxRetry = 3
+
+type httpReadSeeker struct {
+ size int64
+ offset int64
+ rc io.ReadCloser
+ open func(offset int64) (io.ReadCloser, error)
+ closed bool
+
+ errsWithNoProgress int
+}
+
+func newHTTPReadSeeker(size int64, open func(offset int64) (io.ReadCloser, error)) (io.ReadCloser, error) {
+ return &httpReadSeeker{
+ size: size,
+ open: open,
+ }, nil
+}
+
+func (hrs *httpReadSeeker) Read(p []byte) (n int, err error) {
+ if hrs.closed {
+ return 0, io.EOF
+ }
+
+ rd, err := hrs.reader()
+ if err != nil {
+ return 0, err
+ }
+
+ n, err = rd.Read(p)
+ hrs.offset += int64(n)
+ if n > 0 || err == nil {
+ hrs.errsWithNoProgress = 0
+ }
+ switch err {
+ case io.ErrUnexpectedEOF:
+ // connection closed unexpectedly. try reconnecting.
+ if n == 0 {
+ hrs.errsWithNoProgress++
+ if hrs.errsWithNoProgress > maxRetry {
+ return // too many retries for this offset with no progress
+ }
+ }
+ if hrs.rc != nil {
+ if clsErr := hrs.rc.Close(); clsErr != nil {
+ log.L.WithError(clsErr).Error("httpReadSeeker: failed to close ReadCloser")
+ }
+ hrs.rc = nil
+ }
+ if _, err2 := hrs.reader(); err2 == nil {
+ return n, nil
+ }
+ case io.EOF:
+ // The CRI's imagePullProgressTimeout relies on responseBody.Close to
+ // update the process monitor's status. If the err is io.EOF, close
+ // the connection since there is no more available data.
+ if hrs.rc != nil {
+ if clsErr := hrs.rc.Close(); clsErr != nil {
+ log.L.WithError(clsErr).Error("httpReadSeeker: failed to close ReadCloser after io.EOF")
+ }
+ hrs.rc = nil
+ }
+ }
+ return
+}
+
+func (hrs *httpReadSeeker) Close() error {
+ if hrs.closed {
+ return nil
+ }
+ hrs.closed = true
+ if hrs.rc != nil {
+ return hrs.rc.Close()
+ }
+
+ return nil
+}
+
+func (hrs *httpReadSeeker) Seek(offset int64, whence int) (int64, error) {
+ if hrs.closed {
+ return 0, fmt.Errorf("Fetcher.Seek: closed: %w", errdefs.ErrUnavailable)
+ }
+
+ abs := hrs.offset
+ switch whence {
+ case io.SeekStart:
+ abs = offset
+ case io.SeekCurrent:
+ abs += offset
+ case io.SeekEnd:
+ if hrs.size == -1 {
+ return 0, fmt.Errorf("Fetcher.Seek: unknown size, cannot seek from end: %w", errdefs.ErrUnavailable)
+ }
+ abs = hrs.size + offset
+ default:
+ return 0, fmt.Errorf("Fetcher.Seek: invalid whence: %w", errdefs.ErrInvalidArgument)
+ }
+
+ if abs < 0 {
+ return 0, fmt.Errorf("Fetcher.Seek: negative offset: %w", errdefs.ErrInvalidArgument)
+ }
+
+ if abs != hrs.offset {
+ if hrs.rc != nil {
+ if err := hrs.rc.Close(); err != nil {
+ log.L.WithError(err).Error("Fetcher.Seek: failed to close ReadCloser")
+ }
+
+ hrs.rc = nil
+ }
+
+ hrs.offset = abs
+ }
+
+ return hrs.offset, nil
+}
+
+func (hrs *httpReadSeeker) reader() (io.Reader, error) {
+ if hrs.rc != nil {
+ return hrs.rc, nil
+ }
+
+ if hrs.size == -1 || hrs.offset < hrs.size {
+ // only try to reopen the body request if we are seeking to a value
+ // less than the actual size.
+ if hrs.open == nil {
+ return nil, fmt.Errorf("cannot open: %w", errdefs.ErrNotImplemented)
+ }
+
+ rc, err := hrs.open(hrs.offset)
+ if err != nil {
+ return nil, fmt.Errorf("httpReadSeeker: failed open: %w", err)
+ }
+
+ if hrs.rc != nil {
+ if err := hrs.rc.Close(); err != nil {
+ log.L.WithError(err).Error("httpReadSeeker: failed to close ReadCloser")
+ }
+ }
+ hrs.rc = rc
+ } else {
+ // There is an edge case here where offset == size of the content. If
+ // we seek, we will probably get an error for content that cannot be
+ // sought (?). In that case, we should err on committing the content,
+ // as the length is already satisfied but we just return the empty
+ // reader instead.
+
+ hrs.rc = io.NopCloser(bytes.NewReader([]byte{}))
+ }
+
+ return hrs.rc, nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/pusher.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/pusher.go
new file mode 100644
index 0000000000..b472d6f259
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/pusher.go
@@ -0,0 +1,570 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ digest "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/core/images"
+ "github.com/containerd/containerd/v2/core/remotes"
+)
+
+type dockerPusher struct {
+ *dockerBase
+ object string
+
+ // TODO: namespace tracker
+ tracker StatusTracker
+}
+
+// Writer implements Ingester API of content store. This allows the client
+// to receive ErrUnavailable when there is already an on-going upload.
+// Note that the tracker MUST implement StatusTrackLocker interface to avoid
+// race condition on StatusTracker.
+func (p dockerPusher) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
+ var wOpts content.WriterOpts
+ for _, opt := range opts {
+ if err := opt(&wOpts); err != nil {
+ return nil, err
+ }
+ }
+ if wOpts.Ref == "" {
+ return nil, fmt.Errorf("ref must not be empty: %w", errdefs.ErrInvalidArgument)
+ }
+ return p.push(ctx, wOpts.Desc, wOpts.Ref, true)
+}
+
+func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) {
+ return p.push(ctx, desc, remotes.MakeRefKey(ctx, desc), false)
+}
+
+func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref string, unavailableOnFail bool) (content.Writer, error) {
+ if l, ok := p.tracker.(StatusTrackLocker); ok {
+ l.Lock(ref)
+ defer l.Unlock(ref)
+ }
+ ctx, err := ContextWithRepositoryScope(ctx, p.refspec, true)
+ if err != nil {
+ return nil, err
+ }
+ status, err := p.tracker.GetStatus(ref)
+ if err == nil {
+ if status.Committed && status.Offset == status.Total {
+ return nil, fmt.Errorf("ref %v: %w", ref, errdefs.ErrAlreadyExists)
+ }
+ if unavailableOnFail && status.ErrClosed == nil {
+ // Another push of this ref is happening elsewhere. The rest of function
+ // will continue only when `errdefs.IsNotFound(err) == true` (i.e. there
+ // is no actively-tracked ref already).
+ return nil, fmt.Errorf("push is on-going: %w", errdefs.ErrUnavailable)
+ }
+ // TODO: Handle incomplete status
+ } else if !errdefs.IsNotFound(err) {
+ return nil, fmt.Errorf("failed to get status: %w", err)
+ }
+
+ hosts := p.filterHosts(HostCapabilityPush)
+ if len(hosts) == 0 {
+ return nil, fmt.Errorf("no push hosts: %w", errdefs.ErrNotFound)
+ }
+
+ var (
+ isManifest bool
+ existCheck []string
+ host = hosts[0]
+ )
+
+ if images.IsManifestType(desc.MediaType) || images.IsIndexType(desc.MediaType) {
+ isManifest = true
+ existCheck = getManifestPath(p.object, desc.Digest)
+ } else {
+ existCheck = []string{"blobs", desc.Digest.String()}
+ }
+
+ req := p.request(host, http.MethodHead, existCheck...)
+ req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*/*`}, ", "))
+
+ log.G(ctx).WithField("url", req.String()).Debugf("checking and pushing to")
+
+ resp, err := req.doWithRetries(ctx, true)
+ if err != nil {
+ if !errors.Is(err, ErrInvalidAuthorization) {
+ return nil, err
+ }
+ log.G(ctx).WithError(err).Debugf("Unable to check existence, continuing with push")
+ } else {
+ if resp.StatusCode == http.StatusOK {
+ var exists bool
+ if isManifest && existCheck[1] != desc.Digest.String() {
+ dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest"))
+ if dgstHeader == desc.Digest {
+ exists = true
+ }
+ } else {
+ exists = true
+ }
+
+ if exists {
+ p.tracker.SetStatus(ref, Status{
+ Committed: true,
+ PushStatus: PushStatus{
+ Exists: true,
+ },
+ Status: content.Status{
+ Ref: ref,
+ // TODO: Set updated time?
+ },
+ })
+ resp.Body.Close()
+ return nil, fmt.Errorf("content %v on remote: %w", desc.Digest, errdefs.ErrAlreadyExists)
+ }
+ } else if resp.StatusCode != http.StatusNotFound {
+ err := unexpectedResponseErr(resp)
+ log.G(ctx).WithError(err).Debug("unexpected response")
+ resp.Body.Close()
+ return nil, err
+ }
+ resp.Body.Close()
+ }
+
+ if isManifest {
+ putPath := getManifestPath(p.object, desc.Digest)
+ req = p.request(host, http.MethodPut, putPath...)
+ req.header.Add("Content-Type", desc.MediaType)
+ } else {
+ // Start upload request
+ req = p.request(host, http.MethodPost, "blobs", "uploads/")
+
+ mountedFrom := ""
+ var resp *http.Response
+ if fromRepo := selectRepositoryMountCandidate(p.refspec, desc.Annotations); fromRepo != "" {
+ preq := requestWithMountFrom(req, desc.Digest.String(), fromRepo)
+ pctx := ContextWithAppendPullRepositoryScope(ctx, fromRepo)
+
+ // NOTE: the fromRepo might be private repo and
+ // auth service still can grant token without error.
+ // but the post request will fail because of 401.
+ //
+ // for the private repo, we should remove mount-from
+ // query and send the request again.
+ resp, err = preq.doWithRetries(pctx, true)
+ if err != nil {
+ if !errors.Is(err, ErrInvalidAuthorization) {
+ return nil, fmt.Errorf("pushing with mount from %s: %w", fromRepo, err)
+ }
+ log.G(ctx).Debugf("failed to push with mount from repository %s: %v", fromRepo, err)
+ }
+ if resp != nil {
+ switch resp.StatusCode {
+ case http.StatusUnauthorized:
+ log.G(ctx).Debugf("failed to mount from repository %s, not authorized", fromRepo)
+
+ resp.Body.Close()
+ resp = nil
+ case http.StatusCreated:
+ mountedFrom = path.Join(p.refspec.Hostname(), fromRepo)
+ }
+ }
+ }
+
+ if resp == nil {
+ resp, err = req.doWithRetries(ctx, true)
+ if err != nil {
+ if errors.Is(err, ErrInvalidAuthorization) {
+ return nil, fmt.Errorf("push access denied, repository does not exist or may require authorization: %w", err)
+ }
+ return nil, err
+ }
+ }
+ defer resp.Body.Close()
+
+ switch resp.StatusCode {
+ case http.StatusOK, http.StatusAccepted, http.StatusNoContent:
+ case http.StatusCreated:
+ p.tracker.SetStatus(ref, Status{
+ Committed: true,
+ PushStatus: PushStatus{
+ MountedFrom: mountedFrom,
+ },
+ Status: content.Status{
+ Ref: ref,
+ Total: desc.Size,
+ Offset: desc.Size,
+ },
+ })
+ return nil, fmt.Errorf("content %v on remote: %w", desc.Digest, errdefs.ErrAlreadyExists)
+ default:
+ err := unexpectedResponseErr(resp)
+ log.G(ctx).WithError(err).Debug("unexpected response")
+ return nil, err
+ }
+
+ var (
+ location = resp.Header.Get("Location")
+ lurl *url.URL
+ lhost = host
+ )
+ // Support paths without host in location
+ if strings.HasPrefix(location, "/") {
+ lurl, err = url.Parse(lhost.Scheme + "://" + lhost.Host + location)
+ if err != nil {
+ return nil, fmt.Errorf("unable to parse location %v: %w", location, err)
+ }
+ } else {
+ if !strings.Contains(location, "://") {
+ location = lhost.Scheme + "://" + location
+ }
+ lurl, err = url.Parse(location)
+ if err != nil {
+ return nil, fmt.Errorf("unable to parse location %v: %w", location, err)
+ }
+
+ if lurl.Host != lhost.Host || lhost.Scheme != lurl.Scheme {
+ lhost.Scheme = lurl.Scheme
+ lhost.Host = lurl.Host
+
+ // Check if different than what was requested, accounting for fallback in the transport layer
+ requested := resp.Request.URL
+ if requested.Host != lhost.Host || requested.Scheme != lhost.Scheme {
+ // Strip authorizer if change to host or scheme
+ lhost.Authorizer = nil
+ log.G(ctx).WithField("host", lhost.Host).WithField("scheme", lhost.Scheme).Debug("upload changed destination, authorizer removed")
+ }
+ }
+ }
+ q := lurl.Query()
+ q.Add("digest", desc.Digest.String())
+
+ req = p.request(lhost, http.MethodPut)
+ req.header.Set("Content-Type", "application/octet-stream")
+ req.path = lurl.Path + "?" + q.Encode()
+ }
+ p.tracker.SetStatus(ref, Status{
+ Status: content.Status{
+ Ref: ref,
+ Total: desc.Size,
+ Expected: desc.Digest,
+ StartedAt: time.Now(),
+ },
+ })
+
+ // TODO: Support chunked upload
+
+ pushw := newPushWriter(p.dockerBase, ref, desc.Digest, p.tracker, isManifest)
+
+ req.body = func() (io.ReadCloser, error) {
+ pr, pw := io.Pipe()
+ pushw.setPipe(pw)
+ return pr, nil
+ }
+ req.size = desc.Size
+
+ go func() {
+ resp, err := req.doWithRetries(ctx, true)
+ if err != nil {
+ pushw.setError(err)
+ return
+ }
+
+ switch resp.StatusCode {
+ case http.StatusOK, http.StatusCreated, http.StatusNoContent:
+ default:
+ err := unexpectedResponseErr(resp)
+ log.G(ctx).WithError(err).Debug("unexpected response")
+ pushw.setError(err)
+ return
+ }
+ pushw.setResponse(resp)
+ }()
+
+ return pushw, nil
+}
+
+func getManifestPath(object string, dgst digest.Digest) []string {
+ if i := strings.IndexByte(object, '@'); i >= 0 {
+ if object[i+1:] != dgst.String() {
+ // use digest, not tag
+ object = ""
+ } else {
+ // strip @ for registry path to make tag
+ object = object[:i]
+ }
+
+ }
+
+ if object == "" {
+ return []string{"manifests", dgst.String()}
+ }
+
+ return []string{"manifests", object}
+}
+
+type pushWriter struct {
+ base *dockerBase
+ ref string
+
+ pipe *io.PipeWriter
+
+ done chan struct{}
+ closeOnce sync.Once
+
+ pipeC chan *io.PipeWriter
+ respC chan *http.Response
+ errC chan error
+
+ isManifest bool
+
+ expected digest.Digest
+ tracker StatusTracker
+}
+
+func newPushWriter(db *dockerBase, ref string, expected digest.Digest, tracker StatusTracker, isManifest bool) *pushWriter {
+ // Initialize and create response
+ return &pushWriter{
+ base: db,
+ ref: ref,
+ expected: expected,
+ tracker: tracker,
+ pipeC: make(chan *io.PipeWriter, 1),
+ respC: make(chan *http.Response, 1),
+ errC: make(chan error, 1),
+ done: make(chan struct{}),
+ isManifest: isManifest,
+ }
+}
+
+func (pw *pushWriter) setPipe(p *io.PipeWriter) {
+ select {
+ case <-pw.done:
+ case pw.pipeC <- p:
+ }
+}
+
+func (pw *pushWriter) setError(err error) {
+ select {
+ case <-pw.done:
+ case pw.errC <- err:
+ }
+}
+
+func (pw *pushWriter) setResponse(resp *http.Response) {
+ select {
+ case <-pw.done:
+ case pw.respC <- resp:
+ }
+}
+
+func (pw *pushWriter) replacePipe(p *io.PipeWriter) error {
+ if pw.pipe == nil {
+ pw.pipe = p
+ return nil
+ }
+
+ pw.pipe.CloseWithError(content.ErrReset)
+ pw.pipe = p
+
+ // If content has already been written, the bytes
+ // cannot be written again and the caller must reset
+ status, err := pw.tracker.GetStatus(pw.ref)
+ if err != nil {
+ return err
+ }
+ status.Offset = 0
+ status.UpdatedAt = time.Now()
+ pw.tracker.SetStatus(pw.ref, status)
+ return content.ErrReset
+}
+
+func (pw *pushWriter) Write(p []byte) (n int, err error) {
+ status, err := pw.tracker.GetStatus(pw.ref)
+ if err != nil {
+ return n, err
+ }
+
+ if pw.pipe == nil {
+ select {
+ case <-pw.done:
+ return 0, io.ErrClosedPipe
+ case p := <-pw.pipeC:
+ pw.replacePipe(p)
+ }
+ } else {
+ select {
+ case <-pw.done:
+ return 0, io.ErrClosedPipe
+ case p := <-pw.pipeC:
+ return 0, pw.replacePipe(p)
+ default:
+ }
+ }
+
+ n, err = pw.pipe.Write(p)
+ if errors.Is(err, io.ErrClosedPipe) {
+ // if the pipe is closed, we might have the original error on the error
+ // channel - so we should try and get it
+ select {
+ case <-pw.done:
+ case err = <-pw.errC:
+ pw.Close()
+ case p := <-pw.pipeC:
+ return 0, pw.replacePipe(p)
+ case resp := <-pw.respC:
+ pw.setResponse(resp)
+ }
+ }
+ status.Offset += int64(n)
+ status.UpdatedAt = time.Now()
+ pw.tracker.SetStatus(pw.ref, status)
+ return
+}
+
+func (pw *pushWriter) Close() error {
+ // Ensure pipeC is closed but handle `Close()` being
+ // called multiple times without panicking
+ pw.closeOnce.Do(func() {
+ close(pw.done)
+ })
+ if pw.pipe != nil {
+ status, err := pw.tracker.GetStatus(pw.ref)
+ if err == nil && !status.Committed {
+ // Closing an incomplete writer. Record this as an error so that following write can retry it.
+ status.ErrClosed = errors.New("closed incomplete writer")
+ pw.tracker.SetStatus(pw.ref, status)
+ }
+ return pw.pipe.Close()
+ }
+ return nil
+}
+
+func (pw *pushWriter) Status() (content.Status, error) {
+ status, err := pw.tracker.GetStatus(pw.ref)
+ if err != nil {
+ return content.Status{}, err
+ }
+ return status.Status, nil
+
+}
+
+func (pw *pushWriter) Digest() digest.Digest {
+ // TODO: Get rid of this function?
+ return pw.expected
+}
+
+func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
+ // Check whether read has already thrown an error
+ if pw.pipe != nil {
+ if _, err := pw.pipe.Write([]byte{}); err != nil && !errors.Is(err, io.ErrClosedPipe) {
+ return fmt.Errorf("pipe error before commit: %w", err)
+ }
+ if err := pw.pipe.Close(); err != nil {
+ return err
+ }
+ }
+
+ // TODO: timeout waiting for response
+ var resp *http.Response
+ select {
+ case <-pw.done:
+ return io.ErrClosedPipe
+ case err := <-pw.errC:
+ pw.Close()
+ return err
+ case resp = <-pw.respC:
+ defer resp.Body.Close()
+ case p := <-pw.pipeC:
+ // check whether the pipe has changed in the commit, because sometimes Write
+ // can complete successfully, but the pipe may have changed. In that case, the
+ // content needs to be reset.
+ return pw.replacePipe(p)
+ }
+
+ // 201 is specified return status, some registries return
+ // 200, 202 or 204.
+ switch resp.StatusCode {
+ case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
+ default:
+ return unexpectedResponseErr(resp)
+ }
+
+ status, err := pw.tracker.GetStatus(pw.ref)
+ if err != nil {
+ return fmt.Errorf("failed to get status: %w", err)
+ }
+
+ if size > 0 && size != status.Offset {
+ return fmt.Errorf("unexpected size %d, expected %d", status.Offset, size)
+ }
+
+ if expected == "" {
+ expected = status.Expected
+ } else if expected != status.Expected {
+ return fmt.Errorf("unexpected digest received: got %q, expected %q", status.Expected, expected)
+ }
+
+ if dgstHdr := resp.Header.Get("Docker-Content-Digest"); dgstHdr != "" {
+ actual, err := digest.Parse(dgstHdr)
+ if err != nil {
+ return fmt.Errorf("invalid content digest in response: %w", err)
+ }
+
+ if actual != expected {
+ return fmt.Errorf("got digest %s, expected %s", actual, expected)
+ }
+ } else {
+ log.G(ctx).Info("registry did not send a Docker-Content-Digest header")
+ }
+
+ status.Committed = true
+ status.UpdatedAt = time.Now()
+ pw.tracker.SetStatus(pw.ref, status)
+
+ return nil
+}
+
+func (pw *pushWriter) Truncate(size int64) error {
+ // TODO: if blob close request and start new request at offset
+ // TODO: always error on manifest
+ return errors.New("cannot truncate remote upload")
+}
+
+func requestWithMountFrom(req *request, mount, from string) *request {
+ creq := *req
+
+ sep := "?"
+ if strings.Contains(creq.path, sep) {
+ sep = "&"
+ }
+
+ creq.path = creq.path + sep + "mount=" + mount + "&from=" + from
+
+ return &creq
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/referrers.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/referrers.go
new file mode 100644
index 0000000000..503f06d72c
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/referrers.go
@@ -0,0 +1,158 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/containerd/containerd/v2/core/remotes"
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ digest "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.Digest, opts ...remotes.FetchReferrersOpt) ([]ocispec.Descriptor, error) {
+ var config remotes.FetchReferrersConfig
+ for _, opt := range opts {
+ opt(ctx, &config)
+ }
+ rc, size, err := r.openReferrers(ctx, dgst, config)
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ return []ocispec.Descriptor{}, nil
+ }
+ return nil, err
+ }
+ defer rc.Close()
+ if size < 0 {
+ size = MaxManifestSize
+ } else if size > MaxManifestSize {
+ return nil, fmt.Errorf("referrers index size %d exceeds maximum allowed %d: %w", size, MaxManifestSize, errdefs.ErrNotFound)
+ }
+
+ var index ocispec.Index
+ dec := json.NewDecoder(io.LimitReader(rc, size))
+ if err := dec.Decode(&index); err != nil {
+ return nil, fmt.Errorf("failed to decode referrers index: %w", err)
+ }
+ if _, err := dec.Token(); !errors.Is(err, io.EOF) {
+ return nil, fmt.Errorf("unexpected data after JSON object")
+ }
+
+ if len(config.ArtifactTypes) == 0 {
+ return index.Manifests, nil
+ }
+
+ var referrers []ocispec.Descriptor
+ tFilter := map[string]struct{}{}
+ for _, t := range config.ArtifactTypes {
+ tFilter[t] = struct{}{}
+ }
+ for _, desc := range index.Manifests {
+ if _, ok := tFilter[desc.ArtifactType]; ok {
+ referrers = append(referrers, desc)
+ }
+ }
+ return referrers, nil
+}
+
+func (r dockerFetcher) openReferrers(ctx context.Context, dgst digest.Digest, config remotes.FetchReferrersConfig) (io.ReadCloser, int64, error) {
+ mediaType := ocispec.MediaTypeImageIndex
+ ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", dgst))
+
+ hosts := r.filterHosts(HostCapabilityReferrers)
+ var fallbackHosts []RegistryHost
+ if len(hosts) == 0 {
+ fallbackHosts = r.filterHosts(HostCapabilityResolve)
+ if len(fallbackHosts) == 0 {
+ return nil, 0, fmt.Errorf("no referrers hosts: %w", errdefs.ErrNotFound)
+ }
+ } else {
+ // If referrers are defined, use same hosts for fallback
+ fallbackHosts = hosts
+ }
+
+ ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ var firstErr error
+ for i, host := range hosts {
+ req := r.request(host, http.MethodGet, "referrers", dgst.String())
+ for _, artifactType := range config.ArtifactTypes {
+ if err := req.addQuery("artifactType", artifactType); err != nil {
+ return nil, 0, err
+ }
+ }
+ for k, vs := range config.QueryFilters {
+ for _, v := range vs {
+ if err := req.addQuery(k, v); err != nil {
+ return nil, 0, err
+ }
+ }
+ }
+ if err := req.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, 0, err
+ }
+
+ rc, cl, err := r.open(ctx, req, mediaType, 0, i == len(hosts)-1)
+ if err != nil {
+ if !errdefs.IsNotFound(err) {
+ log.G(ctx).WithError(err).WithField("host", host.Host).Debug("error fetching referrers")
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+ } else {
+ return rc, cl, nil
+ }
+ }
+
+ for i, host := range fallbackHosts {
+ req := r.request(host, http.MethodGet, "manifests", strings.Replace(dgst.String(), ":", "-", 1))
+ if err := req.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, 0, err
+ }
+ rc, cl, err := r.open(ctx, req, mediaType, 0, i == len(fallbackHosts)-1)
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ // Equivalent to empty referrers list
+ firstErr = err
+ break
+ }
+ log.G(ctx).WithError(err).WithField("host", host.Host).Debug("error fetching referrers via fallback")
+ if firstErr == nil {
+ firstErr = err
+ }
+ } else {
+ return rc, cl, nil
+ }
+ }
+ if firstErr == nil {
+ firstErr = fmt.Errorf("could not be found at any host: %w", errdefs.ErrNotFound)
+ }
+
+ return nil, 0, firstErr
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/registry.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/registry.go
new file mode 100644
index 0000000000..9b601cb241
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/registry.go
@@ -0,0 +1,268 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "crypto/tls"
+ "errors"
+ "net"
+ "net/http"
+ "time"
+)
+
+// HostCapabilities represent the capabilities of the registry
+// host. This also represents the set of operations for which
+// the registry host may be trusted to perform.
+//
+// For example pushing is a capability which should only be
+// performed on an upstream source, not a mirror.
+// Resolving (the process of converting a name into a digest)
+// must be considered a trusted operation and only done by
+// a host which is trusted (or more preferably by secure process
+// which can prove the provenance of the mapping). A public
+// mirror should never be trusted to do a resolve action.
+//
+// | Registry Type | Pull | Resolve | Push |
+// |------------------|------|---------|------|
+// | Public Registry | yes | yes | yes |
+// | Private Registry | yes | yes | yes |
+// | Public Mirror | yes | no | no |
+// | Private Mirror | yes | yes | no |
+type HostCapabilities uint8
+
+const (
+ // HostCapabilityPull represents the capability to fetch manifests
+ // and blobs by digest
+ HostCapabilityPull HostCapabilities = 1 << iota
+
+ // HostCapabilityResolve represents the capability to fetch manifests
+ // by name
+ HostCapabilityResolve
+
+ // HostCapabilityPush represents the capability to push blobs and
+ // manifests
+ HostCapabilityPush
+
+ // HostCapabilityReferrers represents the capability to generate a
+ // list of referrers using the OCI Distribution referrers endpoint.
+ HostCapabilityReferrers
+
+ // Reserved for future capabilities (i.e. search, catalog, remove)
+)
+
+// Has checks whether the capabilities list has the provide capability
+func (c HostCapabilities) Has(t HostCapabilities) bool {
+ return c&t == t
+}
+
+// RegistryHost represents a complete configuration for a registry
+// host, representing the capabilities, authorizations, connection
+// configuration, and location.
+type RegistryHost struct {
+ Client *http.Client
+ Authorizer Authorizer
+ Host string
+ Scheme string
+ Path string
+ Capabilities HostCapabilities
+ Header http.Header
+}
+
+func (h RegistryHost) isProxy(refhost string) bool {
+ if refhost != h.Host {
+ if refhost != "docker.io" || h.Host != "registry-1.docker.io" {
+ return true
+ }
+ }
+ return false
+}
+
+// RegistryHosts fetches the registry hosts for a given namespace,
+// provided by the host component of an distribution image reference.
+type RegistryHosts func(string) ([]RegistryHost, error)
+
+// Registries joins multiple registry configuration functions, using the same
+// order as provided within the arguments. When an empty registry configuration
+// is returned with a nil error, the next function will be called.
+// NOTE: This function will not join configurations, as soon as a non-empty
+// configuration is returned from a configuration function, it will be returned
+// to the caller.
+func Registries(registries ...RegistryHosts) RegistryHosts {
+ return func(host string) ([]RegistryHost, error) {
+ for _, registry := range registries {
+ config, err := registry(host)
+ if err != nil {
+ return config, err
+ }
+ if len(config) > 0 {
+ return config, nil
+ }
+ }
+ return nil, nil
+ }
+}
+
+type registryOpts struct {
+ authorizer Authorizer
+ plainHTTP func(string) (bool, error)
+ host func(string) (string, error)
+ client *http.Client
+}
+
+// RegistryOpt defines a registry default option
+type RegistryOpt func(*registryOpts)
+
+// WithPlainHTTP configures registries to use plaintext http scheme
+// for the provided host match function.
+func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt {
+ return func(opts *registryOpts) {
+ opts.plainHTTP = f
+ }
+}
+
+// WithAuthorizer configures the default authorizer for a registry
+func WithAuthorizer(a Authorizer) RegistryOpt {
+ return func(opts *registryOpts) {
+ opts.authorizer = a
+ }
+}
+
+// WithHostTranslator defines the default translator to use for registry hosts
+func WithHostTranslator(h func(string) (string, error)) RegistryOpt {
+ return func(opts *registryOpts) {
+ opts.host = h
+ }
+}
+
+// WithClient configures the default http client for a registry
+func WithClient(c *http.Client) RegistryOpt {
+ return func(opts *registryOpts) {
+ opts.client = c
+ }
+}
+
+// ConfigureDefaultRegistries is used to create a default configuration for
+// registries. For more advanced configurations or per-domain setups,
+// the RegistryHosts interface should be used directly.
+// NOTE: This function will always return a non-empty value or error
+func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts {
+ var opts registryOpts
+ for _, opt := range ropts {
+ opt(&opts)
+ }
+
+ return func(host string) ([]RegistryHost, error) {
+ config := RegistryHost{
+ Client: opts.client,
+ Authorizer: opts.authorizer,
+ Host: host,
+ Scheme: "https",
+ Path: "/v2",
+ Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush | HostCapabilityReferrers,
+ }
+
+ if config.Client == nil {
+ config.Client = &http.Client{
+ Transport: DefaultHTTPTransport(nil),
+ }
+ }
+
+ if opts.plainHTTP != nil {
+ match, err := opts.plainHTTP(host)
+ if err != nil {
+ return nil, err
+ }
+ if match {
+ config.Scheme = "http"
+ }
+ }
+
+ if opts.host != nil {
+ var err error
+ config.Host, err = opts.host(config.Host)
+ if err != nil {
+ return nil, err
+ }
+ } else if host == "docker.io" {
+ config.Host = "registry-1.docker.io"
+ }
+
+ return []RegistryHost{config}, nil
+ }
+}
+
+// MatchAllHosts is a host match function which is always true.
+func MatchAllHosts(string) (bool, error) {
+ return true, nil
+}
+
+// MatchLocalhost is a host match function which returns true for
+// localhost.
+//
+// Note: this does not handle matching of ip addresses in octal,
+// decimal or hex form.
+func MatchLocalhost(host string) (bool, error) {
+ switch host {
+ case "::1":
+ return true, nil
+ case "[::1]":
+ return true, nil
+ }
+ h, p, err := net.SplitHostPort(host)
+
+ // addrError helps distinguish between errors of form
+ // "no colon in address" and "too many colons in address".
+ // The former is fine as the host string need not have a
+ // port. Latter needs to be handled.
+ addrError := &net.AddrError{
+ Err: "missing port in address",
+ Addr: host,
+ }
+ if err != nil {
+ if err.Error() != addrError.Error() {
+ return false, err
+ }
+ // host string without any port specified
+ h = host
+ } else if len(p) == 0 {
+ return false, errors.New("invalid host name format")
+ }
+
+ // use ipv4 dotted decimal for further checking
+ if h == "localhost" {
+ h = "127.0.0.1"
+ }
+ ip := net.ParseIP(h)
+
+ return ip.IsLoopback(), nil
+}
+
+func DefaultHTTPTransport(defaultTLSConfig *tls.Config) *http.Transport {
+ return &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
+ DialContext: (&net.Dialer{
+ Timeout: 30 * time.Second,
+ KeepAlive: 30 * time.Second,
+ FallbackDelay: 300 * time.Millisecond,
+ }).DialContext,
+ MaxIdleConns: 10,
+ IdleConnTimeout: 30 * time.Second,
+ TLSHandshakeTimeout: 10 * time.Second,
+ TLSClientConfig: defaultTLSConfig,
+ ExpectContinueTimeout: 5 * time.Second,
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver.go
new file mode 100644
index 0000000000..74a5bd08c9
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver.go
@@ -0,0 +1,923 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "path"
+ "strings"
+ "sync"
+
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sync/semaphore"
+
+ "github.com/containerd/containerd/v2/core/images"
+ "github.com/containerd/containerd/v2/core/remotes"
+ "github.com/containerd/containerd/v2/core/transfer"
+ "github.com/containerd/containerd/v2/pkg/reference"
+ "github.com/containerd/containerd/v2/pkg/tracing"
+ "github.com/containerd/containerd/v2/version"
+)
+
+var (
+ // ErrInvalidAuthorization is used when credentials are passed to a server but
+ // those credentials are rejected.
+ ErrInvalidAuthorization = errors.New("authorization failed")
+
+ // MaxManifestSize represents the largest size accepted from a registry
+ // during resolution. Larger manifests may be accepted using a
+ // resolution method other than the registry.
+ //
+ // NOTE: The max supported layers by some runtimes is 128 and individual
+ // layers will not contribute more than 256 bytes, making a
+ // reasonable limit for a large image manifests of 32K bytes.
+ // 4M bytes represents a much larger upper bound for images which may
+ // contain large annotations or be non-images. A proper manifest
+ // design puts large metadata in subobjects, as is consistent the
+ // intent of the manifest design.
+ MaxManifestSize int64 = 4 * 1048 * 1048
+)
+
+// Authorizer is used to authorize HTTP requests based on 401 HTTP responses.
+// An Authorizer is responsible for caching tokens or credentials used by
+// requests.
+type Authorizer interface {
+ // Authorize sets the appropriate `Authorization` header on the given
+ // request.
+ //
+ // If no authorization is found for the request, the request remains
+ // unmodified. It may also add an `Authorization` header as
+ // "bearer "
+ // "basic "
+ //
+ // It may return remotes/errors.ErrUnexpectedStatus, which for example,
+ // can be used by the caller to find out the status code returned by the registry.
+ Authorize(context.Context, *http.Request) error
+
+ // AddResponses adds a 401 response for the authorizer to consider when
+ // authorizing requests. The last response should be unauthorized and
+ // the previous requests are used to consider redirects and retries
+ // that may have led to the 401.
+ //
+ // If response is not handled, returns `ErrNotImplemented`
+ AddResponses(context.Context, []*http.Response) error
+}
+
+// ResolverOptions are used to configured a new Docker register resolver
+type ResolverOptions struct {
+ // Hosts returns registry host configurations for a namespace.
+ Hosts RegistryHosts
+
+ // Headers are the HTTP request header fields sent by the resolver
+ Headers http.Header
+
+ // Tracker is used to track uploads to the registry. This is used
+ // since the registry does not have upload tracking and the existing
+ // mechanism for getting blob upload status is expensive.
+ Tracker StatusTracker
+
+ // Authorizer is used to authorize registry requests
+ //
+ // Deprecated: use Hosts.
+ Authorizer Authorizer
+
+ // Credentials provides username and secret given a host.
+ // If username is empty but a secret is given, that secret
+ // is interpreted as a long lived token.
+ //
+ // Deprecated: use Hosts.
+ Credentials func(string) (string, string, error)
+
+ // Host provides the hostname given a namespace.
+ //
+ // Deprecated: use Hosts.
+ Host func(string) (string, error)
+
+ // PlainHTTP specifies to use plain http and not https
+ //
+ // Deprecated: use Hosts.
+ PlainHTTP bool
+
+ // Client is the http client to used when making registry requests
+ //
+ // Deprecated: use Hosts.
+ Client *http.Client
+}
+
+// DefaultHost is the default host function.
+func DefaultHost(ns string) (string, error) {
+ if ns == "docker.io" {
+ return "registry-1.docker.io", nil
+ }
+ return ns, nil
+}
+
+type dockerResolver struct {
+ hosts RegistryHosts
+ header http.Header
+ resolveHeader http.Header
+ tracker StatusTracker
+ config transfer.ImageResolverOptions
+}
+
+// NewResolver returns a new resolver to a Docker registry
+func NewResolver(options ResolverOptions) remotes.Resolver {
+ if options.Tracker == nil {
+ options.Tracker = NewInMemoryTracker()
+ }
+
+ if options.Headers == nil {
+ options.Headers = make(http.Header)
+ } else {
+ // make a copy of the headers to avoid race due to concurrent map write
+ options.Headers = options.Headers.Clone()
+ }
+
+ resolveHeader := http.Header{}
+ if _, ok := options.Headers["Accept"]; !ok {
+ // set headers for all the types we support for resolution.
+ resolveHeader.Set("Accept", strings.Join([]string{
+ images.MediaTypeDockerSchema2Manifest,
+ images.MediaTypeDockerSchema2ManifestList,
+ ocispec.MediaTypeImageManifest,
+ ocispec.MediaTypeImageIndex, "*/*",
+ }, ", "))
+ } else {
+ resolveHeader["Accept"] = options.Headers["Accept"]
+ delete(options.Headers, "Accept")
+ }
+
+ if options.Hosts == nil {
+ opts := []RegistryOpt{}
+ if options.Host != nil {
+ opts = append(opts, WithHostTranslator(options.Host))
+ }
+
+ if options.Authorizer == nil {
+ options.Authorizer = NewDockerAuthorizer(
+ WithAuthClient(options.Client),
+ WithAuthHeader(options.Headers),
+ WithAuthCreds(options.Credentials))
+ }
+ opts = append(opts, WithAuthorizer(options.Authorizer))
+
+ if options.Client != nil {
+ opts = append(opts, WithClient(options.Client))
+ }
+ if options.PlainHTTP {
+ opts = append(opts, WithPlainHTTP(MatchAllHosts))
+ } else {
+ opts = append(opts, WithPlainHTTP(MatchLocalhost))
+ }
+ options.Hosts = ConfigureDefaultRegistries(opts...)
+ }
+ return &dockerResolver{
+ hosts: options.Hosts,
+ header: options.Headers,
+ resolveHeader: resolveHeader,
+ tracker: options.Tracker,
+ }
+}
+
+func getManifestMediaType(resp *http.Response) string {
+ // Strip encoding data (manifests should always be ascii JSON)
+ contentType := resp.Header.Get("Content-Type")
+ if sp := strings.IndexByte(contentType, ';'); sp != -1 {
+ contentType = contentType[0:sp]
+ }
+
+ // As of Apr 30 2019 the registry.access.redhat.com registry does not specify
+ // the content type of any data but uses schema1 manifests.
+ if contentType == "text/plain" {
+ contentType = images.MediaTypeDockerSchema1Manifest
+ }
+ return contentType
+}
+
+type countingReader struct {
+ reader io.Reader
+ bytesRead int64
+}
+
+func (r *countingReader) Read(p []byte) (int, error) {
+ n, err := r.reader.Read(p)
+ r.bytesRead += int64(n)
+ return n, err
+}
+
+var _ remotes.ResolverWithOptions = &dockerResolver{}
+
+func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocispec.Descriptor, error) {
+ base, err := r.resolveDockerBase(ref)
+ if err != nil {
+ return "", ocispec.Descriptor{}, err
+ }
+ refspec := base.refspec
+ if refspec.Object == "" {
+ return "", ocispec.Descriptor{}, reference.ErrObjectRequired
+ }
+
+ var (
+ paths [][]string
+ dgst = refspec.Digest()
+ caps = HostCapabilityPull
+ )
+
+ if dgst != "" {
+ if err := dgst.Validate(); err != nil {
+ // need to fail here, since we can't actually resolve the invalid
+ // digest.
+ return "", ocispec.Descriptor{}, err
+ }
+
+ // turns out, we have a valid digest, make a url.
+ paths = append(paths, []string{"manifests", dgst.String()})
+
+ // fallback to blobs on not found.
+ paths = append(paths, []string{"blobs", dgst.String()})
+ } else {
+ // Add
+ paths = append(paths, []string{"manifests", refspec.Object})
+ caps |= HostCapabilityResolve
+ }
+
+ hosts := base.filterHosts(caps)
+ if len(hosts) == 0 {
+ return "", ocispec.Descriptor{}, fmt.Errorf("no resolve hosts: %w", errdefs.ErrNotFound)
+ }
+
+ ctx, err = ContextWithRepositoryScope(ctx, refspec, false)
+ if err != nil {
+ return "", ocispec.Descriptor{}, err
+ }
+
+ var (
+ // firstErr is the most relevant error encountered during resolution.
+ // We use this to determine the error to return, making sure that the
+ // error created furthest through the resolution process is returned.
+ firstErr error
+ firstErrPriority int
+ )
+
+ nextHostOrFail := func(i int) string {
+ if i < len(hosts)-1 {
+ return "trying next host"
+ }
+ return "fetch failed"
+ }
+
+ for _, u := range paths {
+ for i, host := range hosts {
+ ctx := log.WithLogger(ctx, log.G(ctx).WithField("host", host.Host))
+
+ req := base.request(host, http.MethodHead, u...)
+ if err := req.addNamespace(base.refspec.Hostname()); err != nil {
+ return "", ocispec.Descriptor{}, err
+ }
+
+ for key, value := range r.resolveHeader {
+ req.header[key] = append(req.header[key], value...)
+ }
+
+ log.G(ctx).Debug("resolving")
+ resp, err := req.doWithRetries(ctx, i == len(hosts)-1)
+ if err != nil {
+ if errors.Is(err, ErrInvalidAuthorization) {
+ err = fmt.Errorf("pull access denied, repository does not exist or may require authorization: %w", err)
+ }
+ if firstErrPriority < 1 {
+ firstErr = err
+ firstErrPriority = 1
+ }
+ log.G(ctx).WithError(err).Info(nextHostOrFail(i))
+ continue // try another host
+ }
+ resp.Body.Close() // don't care about body contents.
+
+ if resp.StatusCode > 299 {
+ if resp.StatusCode == http.StatusNotFound {
+ if firstErrPriority < 2 {
+ firstErr = fmt.Errorf("%s: %w", ref, errdefs.ErrNotFound)
+ firstErrPriority = 2
+ }
+ log.G(ctx).Infof("%s after status: %s", nextHostOrFail(i), resp.Status)
+ continue
+ }
+ if resp.StatusCode > 399 {
+ if firstErrPriority < 3 {
+ firstErr = unexpectedResponseErr(resp)
+ firstErrPriority = 3
+ }
+ log.G(ctx).Infof("%s after status: %s", nextHostOrFail(i), resp.Status)
+ continue // try another host
+ }
+ return "", ocispec.Descriptor{}, unexpectedResponseErr(resp)
+ }
+ size := resp.ContentLength
+ contentType := getManifestMediaType(resp)
+
+ // if no digest was provided, then only a resolve
+ // trusted registry was contacted, in this case use
+ // the digest header (or content from GET)
+ if dgst == "" {
+ // this is the only point at which we trust the registry. we use the
+ // content headers to assemble a descriptor for the name. when this becomes
+ // more robust, we mostly get this information from a secure trust store.
+ dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest"))
+
+ if dgstHeader != "" && size != -1 {
+ if err := dgstHeader.Validate(); err != nil {
+ return "", ocispec.Descriptor{}, fmt.Errorf("%q in header not a valid digest: %w", dgstHeader, err)
+ }
+ dgst = dgstHeader
+ }
+ }
+ if dgst == "" || size == -1 {
+ log.G(ctx).Debug("no Docker-Content-Digest header, fetching manifest instead")
+
+ req = base.request(host, http.MethodGet, u...)
+ if err := req.addNamespace(base.refspec.Hostname()); err != nil {
+ return "", ocispec.Descriptor{}, err
+ }
+
+ for key, value := range r.resolveHeader {
+ req.header[key] = append(req.header[key], value...)
+ }
+
+ resp, err := req.doWithRetries(ctx, true)
+ if err != nil {
+ return "", ocispec.Descriptor{}, err
+ }
+
+ bodyReader := countingReader{reader: resp.Body}
+
+ contentType = getManifestMediaType(resp)
+ err = func() error {
+ defer resp.Body.Close()
+ if dgst != "" {
+ _, err = io.Copy(io.Discard, &bodyReader)
+ return err
+ }
+
+ if contentType == images.MediaTypeDockerSchema1Manifest {
+ return fmt.Errorf("%w: media type %q is no longer supported since containerd v2.0, please rebuild the image as %q or %q",
+ errdefs.ErrNotImplemented, images.MediaTypeDockerSchema1Manifest, images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest)
+ }
+
+ dgst, err = digest.FromReader(&bodyReader)
+ return err
+ }()
+ if err != nil {
+ return "", ocispec.Descriptor{}, err
+ }
+ size = bodyReader.bytesRead
+ }
+ // Prevent resolving to excessively large manifests
+ if size > MaxManifestSize {
+ if firstErrPriority < 4 {
+ firstErr = fmt.Errorf("rejecting %d byte manifest for %s: %w", size, ref, errdefs.ErrNotFound)
+ firstErrPriority = 4
+ }
+ continue
+ }
+
+ desc := ocispec.Descriptor{
+ Digest: dgst,
+ MediaType: contentType,
+ Size: size,
+ }
+
+ log.G(ctx).WithField("desc.digest", desc.Digest).Debug("resolved")
+ return ref, desc, nil
+ }
+ }
+
+ // If above loop terminates without return or error, then no registries
+ // were provided.
+ if firstErr == nil {
+ firstErr = fmt.Errorf("%s: %w", ref, errdefs.ErrNotFound)
+ }
+
+ return "", ocispec.Descriptor{}, firstErr
+}
+
+func (r *dockerResolver) SetOptions(options ...transfer.ImageResolverOption) {
+ for _, opt := range options {
+ opt(&r.config)
+ }
+}
+
+func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
+ base, err := r.resolveDockerBase(ref)
+ if err != nil {
+ return nil, err
+ }
+
+ return dockerFetcher{
+ dockerBase: base,
+ }, nil
+}
+
+func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
+ base, err := r.resolveDockerBase(ref)
+ if err != nil {
+ return nil, err
+ }
+
+ return dockerPusher{
+ dockerBase: base,
+ object: base.refspec.Object,
+ tracker: r.tracker,
+ }, nil
+}
+
+func (r *dockerResolver) resolveDockerBase(ref string) (*dockerBase, error) {
+ refspec, err := reference.Parse(ref)
+ if err != nil {
+ return nil, err
+ }
+
+ return r.base(refspec)
+}
+
+type dockerBase struct {
+ refspec reference.Spec
+ repository string
+ hosts []RegistryHost
+ header http.Header
+ performances transfer.ImageResolverPerformanceSettings
+ limiter *semaphore.Weighted
+}
+
+func (r *dockerBase) Acquire(ctx context.Context, weight int64) error {
+ if r.limiter == nil {
+ return nil
+ }
+ return r.limiter.Acquire(ctx, weight)
+}
+
+func (r *dockerBase) Release(weight int64) {
+ if r.limiter != nil {
+ r.limiter.Release(weight)
+ }
+}
+
+func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, error) {
+ host := refspec.Hostname()
+ hosts, err := r.hosts(host)
+ if err != nil {
+ return nil, err
+ }
+ return &dockerBase{
+ refspec: refspec,
+ repository: strings.TrimPrefix(refspec.Locator, host+"/"),
+ hosts: hosts,
+ header: r.header,
+ performances: r.config.Performances,
+ limiter: r.config.DownloadLimiter,
+ }, nil
+}
+
+func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) {
+ for _, host := range r.hosts {
+ if host.Capabilities.Has(caps) {
+ hosts = append(hosts, host)
+ }
+ }
+ return
+}
+
+func (r *dockerBase) request(host RegistryHost, method string, ps ...string) *request {
+ header := r.header.Clone()
+ if header == nil {
+ header = http.Header{}
+ }
+
+ for key, value := range host.Header {
+ header[key] = append(header[key], value...)
+ }
+
+ if len(header.Get("User-Agent")) == 0 {
+ header.Set("User-Agent", "containerd/"+version.Version)
+ }
+
+ parts := append([]string{"/", host.Path, r.repository}, ps...)
+ p := path.Join(parts...)
+ // Join strips trailing slash, re-add ending "/" if included
+ if len(parts) > 0 && strings.HasSuffix(parts[len(parts)-1], "/") {
+ p = p + "/"
+ }
+ return &request{
+ method: method,
+ path: p,
+ header: header,
+ host: host,
+ }
+}
+
+func (r *request) authorize(ctx context.Context, req *http.Request) error {
+ // Check if has header for host
+ if r.host.Authorizer != nil {
+ if err := r.host.Authorizer.Authorize(ctx, req); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (r *request) addQuery(key, value string) (err error) {
+ var q url.Values
+ // Parse query
+ if p, query, ok := strings.Cut(r.path, "?"); ok {
+ q, err = url.ParseQuery(query)
+ if err != nil {
+ return
+ }
+ r.path = p + "?"
+ } else {
+ r.path = r.path + "?"
+ q = url.Values{}
+ }
+ q.Add(key, value)
+
+ r.path = r.path + q.Encode()
+
+ return
+}
+
+func (r *request) addNamespace(ns string) error {
+ if !r.host.isProxy(ns) {
+ return nil
+ }
+ return r.addQuery("ns", ns)
+}
+
+type request struct {
+ method string
+ path string
+ header http.Header
+ host RegistryHost
+ body func() (io.ReadCloser, error)
+ size int64
+}
+
+func (r *request) clone() *request {
+ res := *r
+ res.header = r.header.Clone()
+ return &res
+}
+
+func (r *request) do(ctx context.Context) (*http.Response, error) {
+ u := r.host.Scheme + "://" + r.host.Host + r.path
+ req, err := http.NewRequestWithContext(ctx, r.method, u, nil)
+ if err != nil {
+ return nil, err
+ }
+ if r.header == nil {
+ req.Header = http.Header{}
+ } else {
+ req.Header = r.header.Clone() // headers need to be copied to avoid concurrent map access
+ }
+ if r.body != nil {
+ body, err := r.body()
+ if err != nil {
+ return nil, err
+ }
+ req.Body = body
+ req.GetBody = r.body
+ if r.size > 0 {
+ req.ContentLength = r.size
+ }
+ }
+
+ ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u))
+ log.G(ctx).WithFields(requestFields(req)).Debug("do request")
+ if err := r.authorize(ctx, req); err != nil {
+ return nil, fmt.Errorf("failed to authorize: %w", err)
+ }
+
+ client := &http.Client{}
+ if r.host.Client != nil {
+ *client = *r.host.Client
+ }
+ if client.CheckRedirect == nil {
+ client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+ if len(via) >= 10 {
+ return errors.New("stopped after 10 redirects")
+ }
+ if err := r.authorize(ctx, req); err != nil {
+ return fmt.Errorf("failed to authorize redirect: %w", err)
+ }
+ return nil
+ }
+ }
+
+ tracing.UpdateHTTPClient(client, tracing.Name("remotes.docker.resolver", "HTTPRequest"))
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to do request: %w", err)
+ }
+ log.G(ctx).WithFields(responseFields(resp)).Debug("fetch response received")
+ return resp, nil
+}
+
+type doChecks func(r *request, resp *http.Response) error
+
+func withErrorCheck(r *request, resp *http.Response) error {
+ if resp.StatusCode > 299 {
+ if resp.StatusCode == http.StatusNotFound {
+ return fmt.Errorf("content at %v not found: %w", r.String(), errdefs.ErrNotFound)
+ }
+
+ return unexpectedResponseErr(resp)
+ }
+ return nil
+}
+
+var errContentRangeIgnored = errors.New("content range requests ignored")
+
+func withOffsetCheck(offset, parallelism int64) doChecks {
+ return func(r *request, resp *http.Response) error {
+ if parallelism <= 1 && offset == 0 {
+ return nil
+ }
+ if resp.StatusCode == http.StatusPartialContent {
+ return nil
+ }
+ if cr := resp.Header.Get("Content-Range"); cr != "" {
+ if !strings.HasPrefix(cr, fmt.Sprintf("bytes %d-", offset)) {
+ return fmt.Errorf("unhandled content range in response: %v", cr)
+ }
+ return nil
+ }
+
+ // Discard up to offset
+ // Could use buffer pool here but this case should be rare
+ n, err := io.Copy(io.Discard, io.LimitReader(resp.Body, offset))
+ if err != nil {
+ return fmt.Errorf("failed to discard to offset: %w", err)
+ }
+ if n != offset {
+ return errors.New("unable to discard to offset")
+ }
+
+ // content range ignored, we can't do concurrent fetches here.
+ // return an error to be caught
+ return errContentRangeIgnored
+ }
+}
+
+func (r *request) doWithRetries(ctx context.Context, lastHost bool, checks ...doChecks) (resp *http.Response, err error) {
+ resp, err = r.doWithRetriesInner(ctx, nil, lastHost)
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ if err != nil && err != errContentRangeIgnored {
+ resp.Body.Close()
+ }
+ }()
+ for _, check := range checks {
+ if err := check(r, resp); err != nil {
+ return resp, err
+ }
+ }
+
+ return resp, nil
+}
+
+func (r *request) doWithRetriesInner(ctx context.Context, responses []*http.Response, lastHost bool) (*http.Response, error) {
+ resp, err := r.do(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ responses = append(responses, resp)
+ retry, err := r.retryRequest(ctx, responses, lastHost)
+ if err != nil {
+ resp.Body.Close()
+ return nil, err
+ }
+ if retry {
+ resp.Body.Close()
+ return r.doWithRetriesInner(ctx, responses, lastHost)
+ }
+ return resp, err
+}
+
+func (r *request) retryRequest(ctx context.Context, responses []*http.Response, lastHost bool) (bool, error) {
+ if len(responses) > 5 {
+ return false, nil
+ }
+ last := responses[len(responses)-1]
+ switch last.StatusCode {
+ case http.StatusUnauthorized:
+ log.G(ctx).WithField("header", last.Header.Get("WWW-Authenticate")).Debug("Unauthorized")
+ if r.host.Authorizer != nil {
+ if err := r.host.Authorizer.AddResponses(ctx, responses); err == nil {
+ return true, nil
+ } else if !errdefs.IsNotImplemented(err) {
+ return false, err
+ }
+ }
+
+ return false, nil
+ case http.StatusMethodNotAllowed:
+ // Support registries which have not properly implemented the HEAD method for
+ // manifests endpoint
+ if r.method == http.MethodHead && strings.Contains(r.path, "/manifests/") {
+ r.method = http.MethodGet
+ return true, nil
+ }
+ case http.StatusRequestTimeout, http.StatusTooManyRequests:
+ return true, nil
+ case http.StatusServiceUnavailable, http.StatusGatewayTimeout, http.StatusInternalServerError:
+ // Do not retry if the same error was seen in the last request
+ if len(responses) > 1 && responses[len(responses)-2].StatusCode == last.StatusCode {
+ return false, nil
+ }
+ // Only retry if this is the last host that will be attempted
+ if lastHost {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
+func (r *request) String() string {
+ return r.host.Scheme + "://" + r.host.Host + r.path
+}
+
+func (r *request) setMediaType(mediatype string) {
+ if mediatype == "" {
+ r.header.Set("Accept", "*/*")
+ } else {
+ r.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", "))
+ }
+}
+
+func (r *request) setOffset(offset int64) {
+ r.header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
+}
+
+func requestFields(req *http.Request) log.Fields {
+ fields := map[string]interface{}{
+ "request.method": req.Method,
+ }
+ for k, vals := range req.Header {
+ k = strings.ToLower(k)
+ if k == "authorization" {
+ continue
+ }
+ for i, v := range vals {
+ field := "request.header." + k
+ if i > 0 {
+ field = fmt.Sprintf("%s.%d", field, i)
+ }
+ fields[field] = v
+ }
+ }
+
+ return fields
+}
+
+func responseFields(resp *http.Response) log.Fields {
+ fields := map[string]interface{}{
+ "response.status": resp.Status,
+ }
+ for k, vals := range resp.Header {
+ k = strings.ToLower(k)
+ for i, v := range vals {
+ field := "response.header." + k
+ if i > 0 {
+ field = fmt.Sprintf("%s.%d", field, i)
+ }
+ fields[field] = v
+ }
+ }
+
+ return fields
+}
+
+// IsLocalhost checks if the registry host is local.
+func IsLocalhost(host string) bool {
+ if h, _, err := net.SplitHostPort(host); err == nil {
+ host = h
+ }
+
+ if host == "localhost" {
+ return true
+ }
+
+ ip := net.ParseIP(host)
+ return ip.IsLoopback()
+}
+
+// NewHTTPFallback returns http.RoundTripper which allows fallback from https to
+// http for registry endpoints with configurations for both http and TLS,
+// such as defaulted localhost endpoints.
+func NewHTTPFallback(transport http.RoundTripper) http.RoundTripper {
+ return &httpFallback{
+ super: transport,
+ }
+}
+
+type httpFallback struct {
+ super http.RoundTripper
+ host string
+ mu sync.Mutex
+}
+
+func (f *httpFallback) RoundTrip(r *http.Request) (*http.Response, error) {
+ f.mu.Lock()
+ fallback := f.host == r.URL.Host
+ f.mu.Unlock()
+
+ // only fall back if the same host had previously fell back
+ if !fallback {
+ resp, err := f.super.RoundTrip(r)
+ if !isTLSError(err) && !isPortError(err, r.URL.Host) {
+ return resp, err
+ }
+ }
+
+ plainHTTPUrl := *r.URL
+ plainHTTPUrl.Scheme = "http"
+
+ plainHTTPRequest := *r
+ plainHTTPRequest.URL = &plainHTTPUrl
+
+ if !fallback {
+ f.mu.Lock()
+ if f.host != r.URL.Host {
+ f.host = r.URL.Host
+ }
+ f.mu.Unlock()
+
+ // update body on the second attempt
+ if r.Body != nil && r.GetBody != nil {
+ body, err := r.GetBody()
+ if err != nil {
+ return nil, err
+ }
+ plainHTTPRequest.Body = body
+ }
+ }
+
+ return f.super.RoundTrip(&plainHTTPRequest)
+}
+
+func isTLSError(err error) bool {
+ if err == nil {
+ return false
+ }
+ var tlsErr tls.RecordHeaderError
+ if errors.As(err, &tlsErr) && string(tlsErr.RecordHeader[:]) == "HTTP/" {
+ return true
+ }
+ if strings.Contains(err.Error(), "TLS handshake timeout") {
+ return true
+ }
+
+ return false
+}
+
+func isPortError(err error, host string) bool {
+ if isConnError(err) || os.IsTimeout(err) {
+ if _, port, _ := net.SplitHostPort(host); port != "" {
+ // Port is specified, will not retry on different port with scheme change
+ return false
+ }
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver_unix.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver_unix.go
new file mode 100644
index 0000000000..4ef0e0062a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver_unix.go
@@ -0,0 +1,28 @@
+//go:build !windows
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "errors"
+ "syscall"
+)
+
+func isConnError(err error) bool {
+ return errors.Is(err, syscall.ECONNREFUSED)
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver_windows.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver_windows.go
new file mode 100644
index 0000000000..9c98df04bb
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/resolver_windows.go
@@ -0,0 +1,30 @@
+//go:build windows
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "errors"
+ "syscall"
+
+ "golang.org/x/sys/windows"
+)
+
+func isConnError(err error) bool {
+ return errors.Is(err, syscall.ECONNREFUSED) || errors.Is(err, windows.WSAECONNREFUSED)
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/scope.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/scope.go
new file mode 100644
index 0000000000..ed38318631
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/scope.go
@@ -0,0 +1,101 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "context"
+ "fmt"
+ "net/url"
+ "sort"
+ "strings"
+
+ "github.com/containerd/containerd/v2/pkg/reference"
+)
+
+// RepositoryScope returns a repository scope string such as "repository:foo/bar:pull"
+// for "host/foo/bar:baz".
+// When push is true, both pull and push are added to the scope.
+func RepositoryScope(refspec reference.Spec, push bool) (string, error) {
+ u, err := url.Parse("dummy://" + refspec.Locator)
+ if err != nil {
+ return "", err
+ }
+ s := "repository:" + strings.TrimPrefix(u.Path, "/") + ":pull"
+ if push {
+ s += ",push"
+ }
+ return s, nil
+}
+
+// tokenScopesKey is used for the key for context.WithValue().
+// value: []string (e.g. {"registry:foo/bar:pull"})
+type tokenScopesKey struct{}
+
+// ContextWithRepositoryScope returns a context with tokenScopesKey{} and the repository scope value.
+func ContextWithRepositoryScope(ctx context.Context, refspec reference.Spec, push bool) (context.Context, error) {
+ s, err := RepositoryScope(refspec, push)
+ if err != nil {
+ return nil, err
+ }
+ return WithScope(ctx, s), nil
+}
+
+// WithScope appends a custom registry auth scope to the context.
+func WithScope(ctx context.Context, scope string) context.Context {
+ var scopes []string
+ if v := ctx.Value(tokenScopesKey{}); v != nil {
+ scopes = v.([]string)
+ scopes = append(scopes, scope)
+ } else {
+ scopes = []string{scope}
+ }
+ return context.WithValue(ctx, tokenScopesKey{}, scopes)
+}
+
+// ContextWithAppendPullRepositoryScope is used to append repository pull
+// scope into existing scopes indexed by the tokenScopesKey{}.
+func ContextWithAppendPullRepositoryScope(ctx context.Context, repo string) context.Context {
+ return WithScope(ctx, fmt.Sprintf("repository:%s:pull", repo))
+}
+
+// GetTokenScopes returns deduplicated and sorted scopes from ctx.Value(tokenScopesKey{}) and common scopes.
+func GetTokenScopes(ctx context.Context, common []string) []string {
+ scopes := []string{}
+ if x := ctx.Value(tokenScopesKey{}); x != nil {
+ scopes = append(scopes, x.([]string)...)
+ }
+
+ scopes = append(scopes, common...)
+ sort.Strings(scopes)
+
+ if len(scopes) == 0 {
+ return scopes
+ }
+
+ l := 0
+ for idx := 1; idx < len(scopes); idx++ {
+ // Note: this comparison is unaware of the scope grammar (https://distribution.github.io/distribution/spec/auth/scope/)
+ // So, "repository:foo/bar:pull,push" != "repository:foo/bar:push,pull", although semantically they are equal.
+ if scopes[l] == scopes[idx] {
+ continue
+ }
+
+ l++
+ scopes[l] = scopes[idx]
+ }
+ return scopes[:l+1]
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/status.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/status.go
new file mode 100644
index 0000000000..9835525ab5
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/status.go
@@ -0,0 +1,101 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package docker
+
+import (
+ "fmt"
+ "sync"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/errdefs"
+ "github.com/moby/locker"
+)
+
+// Status of a content operation
+type Status struct {
+ content.Status
+
+ Committed bool
+
+ // ErrClosed contains error encountered on close.
+ ErrClosed error
+
+ // UploadUUID is used by the Docker registry to reference blob uploads
+ UploadUUID string
+
+ // PushStatus contains status related to push.
+ PushStatus
+}
+
+type PushStatus struct {
+ // MountedFrom is the source content was cross-repo mounted from (empty if no cross-repo mount was performed).
+ MountedFrom string
+
+ // Exists indicates whether content already exists in the repository and wasn't uploaded.
+ Exists bool
+}
+
+// StatusTracker to track status of operations
+type StatusTracker interface {
+ GetStatus(string) (Status, error)
+ SetStatus(string, Status)
+}
+
+// StatusTrackLocker to track status of operations with lock
+type StatusTrackLocker interface {
+ StatusTracker
+ Lock(string)
+ Unlock(string)
+}
+
+type memoryStatusTracker struct {
+ statuses map[string]Status
+ m sync.Mutex
+ locker *locker.Locker
+}
+
+// NewInMemoryTracker returns a StatusTracker that tracks content status in-memory
+func NewInMemoryTracker() StatusTrackLocker {
+ return &memoryStatusTracker{
+ statuses: map[string]Status{},
+ locker: locker.New(),
+ }
+}
+
+func (t *memoryStatusTracker) GetStatus(ref string) (Status, error) {
+ t.m.Lock()
+ defer t.m.Unlock()
+ status, ok := t.statuses[ref]
+ if !ok {
+ return Status{}, fmt.Errorf("status for ref %v: %w", ref, errdefs.ErrNotFound)
+ }
+ return status, nil
+}
+
+func (t *memoryStatusTracker) SetStatus(ref string, status Status) {
+ t.m.Lock()
+ t.statuses[ref] = status
+ t.m.Unlock()
+}
+
+func (t *memoryStatusTracker) Lock(ref string) {
+ t.locker.Lock(ref)
+}
+
+func (t *memoryStatusTracker) Unlock(ref string) {
+ t.locker.Unlock(ref)
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/errors/errors.go b/vendor/github.com/containerd/containerd/v2/core/remotes/errors/errors.go
new file mode 100644
index 0000000000..d07d174080
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/errors/errors.go
@@ -0,0 +1,62 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package errors
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+
+ "github.com/containerd/typeurl/v2"
+)
+
+var _ error = ErrUnexpectedStatus{}
+
+func init() {
+ typeurl.Register(&ErrUnexpectedStatus{}, "github.com/containerd/containerd/v2/core/remotes/errors", "ErrUnexpectedStatus")
+}
+
+// ErrUnexpectedStatus is returned if a registry API request returned with unexpected HTTP status
+type ErrUnexpectedStatus struct {
+ Status string `json:"status"`
+ StatusCode int `json:"statusCode"`
+ Body []byte `json:"body,omitempty"`
+ RequestURL string `json:"requestURL,omitempty"`
+ RequestMethod string `json:"requestMethod,omitempty"`
+}
+
+func (e ErrUnexpectedStatus) Error() string {
+ return fmt.Sprintf("unexpected status from %s request to %s: %s", e.RequestMethod, e.RequestURL, e.Status)
+}
+
+// NewUnexpectedStatusErr creates an ErrUnexpectedStatus from HTTP response
+func NewUnexpectedStatusErr(resp *http.Response) error {
+ var b []byte
+ if resp.Body != nil {
+ b, _ = io.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB
+ }
+ err := ErrUnexpectedStatus{
+ Body: b,
+ Status: resp.Status,
+ StatusCode: resp.StatusCode,
+ RequestMethod: resp.Request.Method,
+ }
+ if resp.Request.URL != nil {
+ err.RequestURL = resp.Request.URL.String()
+ }
+ return err
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/handlers.go b/vendor/github.com/containerd/containerd/v2/core/remotes/handlers.go
new file mode 100644
index 0000000000..5adb2b39a8
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/handlers.go
@@ -0,0 +1,398 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package remotes
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "maps"
+ "strings"
+ "sync"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/core/images"
+ "github.com/containerd/containerd/v2/pkg/labels"
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ "github.com/containerd/platforms"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sync/semaphore"
+)
+
+type refKeyPrefix struct{}
+
+// WithMediaTypeKeyPrefix adds a custom key prefix for a media type which is used when storing
+// data in the content store from the FetchHandler.
+//
+// Used in `MakeRefKey` to determine what the key prefix should be.
+func WithMediaTypeKeyPrefix(ctx context.Context, mediaType, prefix string) context.Context {
+ var values map[string]string
+ if v := ctx.Value(refKeyPrefix{}); v != nil {
+ values = v.(map[string]string)
+ values = maps.Clone(values)
+ } else {
+ values = make(map[string]string)
+ }
+
+ values[mediaType] = prefix
+ return context.WithValue(ctx, refKeyPrefix{}, values)
+}
+
+// MakeRefKey returns a unique reference for the descriptor. This reference can be
+// used to lookup ongoing processes related to the descriptor. This function
+// may look to the context to namespace the reference appropriately.
+func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
+ key := desc.Digest.String()
+ if desc.Annotations != nil {
+ if name, ok := desc.Annotations[ocispec.AnnotationRefName]; ok {
+ key = fmt.Sprintf("%s@%s", name, desc.Digest.String())
+ }
+ }
+
+ if v := ctx.Value(refKeyPrefix{}); v != nil {
+ values := v.(map[string]string)
+ if prefix := values[desc.MediaType]; prefix != "" {
+ return prefix + "-" + key
+ }
+ }
+
+ switch {
+ case images.IsManifestType(desc.MediaType):
+ return "manifest-" + key
+ case images.IsIndexType(desc.MediaType):
+ return "index-" + key
+ case images.IsLayerType(desc.MediaType):
+ return "layer-" + key
+ case images.IsKnownConfig(desc.MediaType):
+ return "config-" + key
+ case images.IsAttestationType(desc.MediaType):
+ return "attestation-" + key
+ default:
+ log.G(ctx).Warnf("reference for unknown type: %s", desc.MediaType)
+ return "unknown-" + key
+ }
+}
+
+// FetchHandler returns a handler that will fetch all content into the ingester
+// discovered in a call to Dispatch. Use with ChildrenHandler to do a full
+// recursive fetch.
+func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
+ "digest": desc.Digest,
+ "mediatype": desc.MediaType,
+ "size": desc.Size,
+ }))
+
+ if desc.MediaType == images.MediaTypeDockerSchema1Manifest {
+ return nil, fmt.Errorf("%v not supported", desc.MediaType)
+ }
+ err := Fetch(ctx, ingester, fetcher, desc)
+ if errdefs.IsAlreadyExists(err) {
+ return nil, nil
+ }
+ return nil, err
+ }
+}
+
+// Fetch fetches the given digest into the provided ingester
+func Fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
+ log.G(ctx).Debug("fetch")
+
+ cw, err := content.OpenWriter(ctx, ingester, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc))
+ if err != nil {
+ return err
+ }
+ defer cw.Close()
+
+ ws, err := cw.Status()
+ if err != nil {
+ return err
+ }
+
+ if desc.Size == 0 {
+ // most likely a poorly configured registry/web front end which responded with no
+ // Content-Length header; unable (not to mention useless) to commit a 0-length entry
+ // into the content store. Error out here otherwise the error sent back is confusing
+ return fmt.Errorf("unable to fetch descriptor (%s) which reports content size of zero: %w", desc.Digest, errdefs.ErrInvalidArgument)
+ }
+ if ws.Offset == desc.Size {
+ // If writer is already complete, commit and return
+ err := cw.Commit(ctx, desc.Size, desc.Digest)
+ if err != nil && !errdefs.IsAlreadyExists(err) {
+ return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err)
+ }
+ return err
+ }
+
+ if desc.Size == int64(len(desc.Data)) {
+ return content.Copy(ctx, cw, bytes.NewReader(desc.Data), desc.Size, desc.Digest)
+ }
+
+ rc, err := fetcher.Fetch(ctx, desc)
+ if err != nil {
+ return err
+ }
+ defer rc.Close()
+
+ return content.Copy(ctx, cw, rc, desc.Size, desc.Digest)
+}
+
+// PushHandler returns a handler that will push all content from the provider
+// using a writer from the pusher.
+func PushHandler(pusher Pusher, provider content.Provider) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
+ "digest": desc.Digest,
+ "mediatype": desc.MediaType,
+ "size": desc.Size,
+ }))
+
+ err := push(ctx, provider, pusher, desc)
+ return nil, err
+ }
+}
+
+func push(ctx context.Context, provider content.Provider, pusher Pusher, desc ocispec.Descriptor) error {
+ log.G(ctx).Debug("push")
+
+ var (
+ cw content.Writer
+ err error
+ )
+ if cs, ok := pusher.(content.Ingester); ok {
+ cw, err = content.OpenWriter(ctx, cs, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc))
+ } else {
+ cw, err = pusher.Push(ctx, desc)
+ }
+ if err != nil {
+ if !errdefs.IsAlreadyExists(err) {
+ return err
+ }
+
+ return nil
+ }
+ defer cw.Close()
+
+ ra, err := provider.ReaderAt(ctx, desc)
+ if err != nil {
+ return err
+ }
+ defer ra.Close()
+
+ rd := io.NewSectionReader(ra, 0, desc.Size)
+ return content.Copy(ctx, cw, rd, desc.Size, desc.Digest)
+}
+
+// PushContent pushes content specified by the descriptor from the provider.
+//
+// Base handlers can be provided which will be called before any push specific
+// handlers.
+//
+// If the passed in content.Provider is also a content.InfoProvider (such as
+// content.Manager) then this will also annotate the distribution sources using
+// labels prefixed with "containerd.io/distribution.source".
+func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, store content.Provider, limiter *semaphore.Weighted, platform platforms.MatchComparer, wrapper func(h images.Handler) images.Handler) error {
+
+ var m sync.Mutex
+ manifests := []ocispec.Descriptor{}
+ indexStack := []ocispec.Descriptor{}
+
+ filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if images.IsManifestType(desc.MediaType) {
+ m.Lock()
+ manifests = append(manifests, desc)
+ m.Unlock()
+ return nil, images.ErrStopHandler
+ } else if images.IsIndexType(desc.MediaType) {
+ m.Lock()
+ indexStack = append(indexStack, desc)
+ m.Unlock()
+ return nil, images.ErrStopHandler
+ }
+ return nil, nil
+ })
+
+ pushHandler := PushHandler(pusher, store)
+
+ platformFilterhandler := images.FilterPlatforms(images.ChildrenHandler(store), platform)
+
+ var handler images.Handler
+ if m, ok := store.(content.InfoProvider); ok {
+ annotateHandler := annotateDistributionSourceHandler(platformFilterhandler, m)
+ handler = images.Handlers(annotateHandler, filterHandler, pushHandler)
+ } else {
+ handler = images.Handlers(platformFilterhandler, filterHandler, pushHandler)
+ }
+
+ if wrapper != nil {
+ handler = wrapper(handler)
+ }
+
+ if err := images.Dispatch(ctx, handler, limiter, desc); err != nil {
+ return err
+ }
+
+ if err := images.Dispatch(ctx, pushHandler, limiter, manifests...); err != nil {
+ return err
+ }
+
+ // Iterate in reverse order as seen, parent always uploaded after child
+ for i := len(indexStack) - 1; i >= 0; i-- {
+ err := images.Dispatch(ctx, pushHandler, limiter, indexStack[i])
+ if err != nil {
+ // TODO(estesp): until we have a more complete method for index push, we need to report
+ // missing dependencies in an index/manifest list by sensing the "400 Bad Request"
+ // as a marker for this problem
+ if errors.Unwrap(err) != nil && strings.Contains(errors.Unwrap(err).Error(), "400 Bad Request") {
+ return fmt.Errorf("manifest list/index references to blobs and/or manifests are missing in your target registry: %w", err)
+ }
+ return err
+ }
+ }
+
+ return nil
+}
+
+// SkipNonDistributableBlobs returns a handler that skips blobs that have a media type that is "non-distributeable".
+// An example of this kind of content would be a Windows base layer, which is not supposed to be redistributed.
+//
+// This is based on the media type of the content:
+// - application/vnd.oci.image.layer.nondistributable
+// - application/vnd.docker.image.rootfs.foreign
+func SkipNonDistributableBlobs(f images.HandlerFunc) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if images.IsNonDistributable(desc.MediaType) {
+ log.G(ctx).WithField("digest", desc.Digest).WithField("mediatype", desc.MediaType).Debug("Skipping non-distributable blob")
+ return nil, images.ErrSkipDesc
+ }
+
+ children, err := f(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+ if len(children) == 0 {
+ return nil, nil
+ }
+
+ out := make([]ocispec.Descriptor, 0, len(children))
+ for _, child := range children {
+ if !images.IsNonDistributable(child.MediaType) {
+ out = append(out, child)
+ } else {
+ log.G(ctx).WithField("digest", child.Digest).WithField("mediatype", child.MediaType).Debug("Skipping non-distributable blob")
+ }
+ }
+ return out, nil
+ }
+}
+
+// FilterManifestByPlatformHandler allows Handler to handle non-target
+// platform's manifest and configuration data.
+func FilterManifestByPlatformHandler(f images.HandlerFunc, m platforms.Matcher) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ // no platform information
+ if desc.Platform == nil || m == nil {
+ return children, nil
+ }
+
+ if images.IsManifestType(desc.MediaType) && !m.Match(*desc.Platform) {
+ var descs []ocispec.Descriptor
+ for _, child := range children {
+ if images.IsConfigType(child.MediaType) {
+ descs = append(descs, child)
+ }
+ }
+ return descs, nil
+ }
+ return children, nil
+ }
+}
+
+// annotateDistributionSourceHandler add distribution source label into
+// annotation of config or blob descriptor.
+func annotateDistributionSourceHandler(f images.HandlerFunc, provider content.InfoProvider) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ // Distribution source is only used for config or blob but may be inherited from
+ // a manifest or manifest list
+ if !images.IsManifestType(desc.MediaType) && !images.IsIndexType(desc.MediaType) {
+ return children, nil
+ }
+
+ parentSourceAnnotations := desc.Annotations
+ var parentLabels map[string]string
+ if pi, err := provider.Info(ctx, desc.Digest); err != nil {
+ if !errdefs.IsNotFound(err) {
+ return nil, err
+ }
+ } else {
+ parentLabels = pi.Labels
+ }
+
+ for i := range children {
+ child := children[i]
+
+ info, err := provider.Info(ctx, child.Digest)
+ if err != nil {
+ if !errdefs.IsNotFound(err) {
+ return nil, err
+ }
+ }
+ copyDistributionSourceLabels(info.Labels, &child)
+
+ // Annotate with parent labels for cross repo mount or fetch.
+ // Parent sources may apply to all children since most registries
+ // enforce that children exist before the manifests.
+ copyDistributionSourceLabels(parentSourceAnnotations, &child)
+ copyDistributionSourceLabels(parentLabels, &child)
+
+ children[i] = child
+ }
+ return children, nil
+ }
+}
+
+func copyDistributionSourceLabels(from map[string]string, to *ocispec.Descriptor) {
+ for k, v := range from {
+ if !strings.HasPrefix(k, labels.LabelDistributionSource+".") {
+ continue
+ }
+
+ if to.Annotations == nil {
+ to.Annotations = make(map[string]string)
+ } else {
+ // Only propagate the parent label if the child doesn't already have it.
+ if _, has := to.Annotations[k]; has {
+ continue
+ }
+ }
+ to.Annotations[k] = v
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/resolver.go b/vendor/github.com/containerd/containerd/v2/core/remotes/resolver.go
new file mode 100644
index 0000000000..8a226e978f
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/remotes/resolver.go
@@ -0,0 +1,152 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package remotes
+
+import (
+ "context"
+ "io"
+ "net/url"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/core/transfer"
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// Resolver provides remotes based on a locator.
+type Resolver interface {
+ // Resolve attempts to resolve the reference into a name and descriptor.
+ //
+ // The argument `ref` should be a scheme-less URI representing the remote.
+ // Structurally, it has a host and path. The "host" can be used to directly
+ // reference a specific host or be matched against a specific handler.
+ //
+ // The returned name should be used to identify the referenced entity.
+ // Depending on the remote namespace, this may be immutable or mutable.
+ // While the name may differ from ref, it should itself be a valid ref.
+ //
+ // If the resolution fails, an error will be returned.
+ Resolve(ctx context.Context, ref string) (name string, desc ocispec.Descriptor, err error)
+
+ // Fetcher returns a new fetcher for the provided reference.
+ // All content fetched from the returned fetcher will be
+ // from the namespace referred to by ref.
+ Fetcher(ctx context.Context, ref string) (Fetcher, error)
+
+ // Pusher returns a new pusher for the provided reference
+ // The returned Pusher should satisfy content.Ingester and concurrent attempts
+ // to push the same blob using the Ingester API should result in ErrUnavailable.
+ Pusher(ctx context.Context, ref string) (Pusher, error)
+}
+
+// ResolverWithOptions is a Resolver that also supports setting options.
+type ResolverWithOptions interface {
+ Resolver
+ SetOptions(options ...transfer.ImageResolverOption)
+}
+
+// Fetcher fetches content.
+// A fetcher implementation may implement the FetcherByDigest interface too.
+type Fetcher interface {
+ // Fetch the resource identified by the descriptor.
+ Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error)
+}
+
+// FetcherByDigest fetches content by the digest.
+type FetcherByDigest interface {
+ // FetchByDigest fetches the resource identified by the digest.
+ //
+ // FetcherByDigest usually returns an incomplete descriptor.
+ // Typically, the media type is always set to "application/octet-stream",
+ // and the annotations are unset.
+ FetchByDigest(ctx context.Context, dgst digest.Digest, opts ...FetchByDigestOpts) (io.ReadCloser, ocispec.Descriptor, error)
+}
+
+type ReferrersFetcher interface {
+ FetchReferrers(ctx context.Context, dgst digest.Digest, opts ...FetchReferrersOpt) ([]ocispec.Descriptor, error)
+}
+
+// Pusher pushes content
+type Pusher interface {
+ // Push returns a content writer for the given resource identified
+ // by the descriptor.
+ Push(ctx context.Context, d ocispec.Descriptor) (content.Writer, error)
+}
+
+// FetcherFunc allows package users to implement a Fetcher with just a
+// function.
+type FetcherFunc func(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error)
+
+// Fetch content
+func (fn FetcherFunc) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) {
+ return fn(ctx, desc)
+}
+
+// PusherFunc allows package users to implement a Pusher with just a
+// function.
+type PusherFunc func(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error)
+
+// Push content
+func (fn PusherFunc) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) {
+ return fn(ctx, desc)
+}
+
+// FetchByDigestConfig provides configuration for fetching content by digest
+type FetchByDigestConfig struct {
+ //Mediatype specifies mediatype header to append for fetch request
+ Mediatype string
+}
+
+// FetchByDigestOpts allows callers to set options for fetch object
+type FetchByDigestOpts func(context.Context, *FetchByDigestConfig) error
+
+// WithMediaType sets the media type header for fetch request
+func WithMediaType(mediatype string) FetchByDigestOpts {
+ return func(ctx context.Context, cfg *FetchByDigestConfig) error {
+ cfg.Mediatype = mediatype
+ return nil
+ }
+}
+
+type FetchReferrersConfig struct {
+ // ArtifactTypes specifies the artifact types to filter referrers, this can be
+ // applied to registry queries or filtering the results after fetching.
+ ArtifactTypes []string
+ // QueryFilters specifies additional filters which may get sent as query parameters
+ QueryFilters url.Values
+}
+
+type FetchReferrersOpt func(context.Context, *FetchReferrersConfig) error
+
+// WithReferrerArtifactTypes sets the artifact types to filter referrers
+func WithReferrerArtifactTypes(artifactTypes ...string) FetchReferrersOpt {
+ return func(ctx context.Context, cfg *FetchReferrersConfig) error {
+ cfg.ArtifactTypes = artifactTypes
+ return nil
+ }
+}
+
+// WithReferrerQueryFilter sets additional query filters for referrer fetching
+func WithReferrerQueryFilter(param, value string) FetchReferrersOpt {
+ return func(ctx context.Context, cfg *FetchReferrersConfig) error {
+ if cfg.QueryFilters == nil {
+ cfg.QueryFilters = url.Values{}
+ }
+ cfg.QueryFilters.Add(param, value)
+ return nil
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/core/transfer/transfer.go b/vendor/github.com/containerd/containerd/v2/core/transfer/transfer.go
new file mode 100644
index 0000000000..cd4a4963aa
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/core/transfer/transfer.go
@@ -0,0 +1,178 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package transfer
+
+import (
+ "context"
+ "io"
+
+ "golang.org/x/sync/semaphore"
+
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/core/images"
+)
+
+type Transferrer interface {
+ Transfer(ctx context.Context, source interface{}, destination interface{}, opts ...Opt) error
+}
+
+type ImageResolver interface {
+ Resolve(ctx context.Context) (name string, desc ocispec.Descriptor, err error)
+}
+
+type ImageResolverOptionSetter interface {
+ ImageResolver
+ SetResolverOptions(opts ...ImageResolverOption)
+}
+
+type ImageResolverOption func(*ImageResolverOptions)
+
+type ImageResolverOptions struct {
+ DownloadLimiter *semaphore.Weighted
+ Performances ImageResolverPerformanceSettings
+}
+
+type ImageResolverPerformanceSettings struct {
+ MaxConcurrentDownloads int
+ ConcurrentLayerFetchBuffer int
+}
+
+func WithDownloadLimiter(limiter *semaphore.Weighted) ImageResolverOption {
+ return func(opts *ImageResolverOptions) {
+ opts.DownloadLimiter = limiter
+ }
+}
+
+func WithMaxConcurrentDownloads(maxConcurrentDownloads int) ImageResolverOption {
+ return func(opts *ImageResolverOptions) {
+ opts.Performances.MaxConcurrentDownloads = maxConcurrentDownloads
+ }
+}
+
+func WithConcurrentLayerFetchBuffer(ConcurrentLayerFetchBuffer int) ImageResolverOption {
+ return func(opts *ImageResolverOptions) {
+ opts.Performances.ConcurrentLayerFetchBuffer = ConcurrentLayerFetchBuffer
+ }
+}
+
+type ImageFetcher interface {
+ ImageResolver
+
+ Fetcher(ctx context.Context, ref string) (Fetcher, error)
+}
+
+type ImagePusher interface {
+ Pusher(context.Context, ocispec.Descriptor) (Pusher, error)
+}
+
+type Fetcher interface {
+ Fetch(context.Context, ocispec.Descriptor) (io.ReadCloser, error)
+}
+
+type Pusher interface {
+ Push(context.Context, ocispec.Descriptor) (content.Writer, error)
+}
+
+// ImageFilterer is used to filter out child objects of an image
+type ImageFilterer interface {
+ ImageFilter(images.HandlerFunc, content.Store) images.HandlerFunc
+}
+
+// ImageStorer is a type which is capable of storing images for
+// the provided descriptor. The descriptor may be any type of manifest
+// including an index with multiple image references.
+type ImageStorer interface {
+ Store(context.Context, ocispec.Descriptor, images.Store) ([]images.Image, error)
+}
+
+// ImageGetter is type which returns an image from an image store
+type ImageGetter interface {
+ Get(context.Context, images.Store) (images.Image, error)
+}
+
+// ImageLookup is a type which returns images from an image store
+// based on names or prefixes
+type ImageLookup interface {
+ Lookup(context.Context, images.Store) ([]images.Image, error)
+}
+
+// ImageExporter exports images to a writer
+type ImageExporter interface {
+ Export(context.Context, content.Store, []images.Image) error
+}
+
+// ImageImporter imports an image into a content store
+type ImageImporter interface {
+ Import(context.Context, content.Store) (ocispec.Descriptor, error)
+}
+
+// ImageImportStreamer returns an import streamer based on OCI or
+// Docker image tar archives. The stream should be a raw tar stream
+// and without compression.
+type ImageImportStreamer interface {
+ ImportStream(context.Context) (io.Reader, string, error)
+}
+
+type ImageExportStreamer interface {
+ ExportStream(context.Context) (io.WriteCloser, string, error)
+}
+
+type ImageUnpacker interface {
+ UnpackPlatforms() []UnpackConfiguration
+}
+
+// ImagePlatformsGetter is type which returns configured platforms.
+type ImagePlatformsGetter interface {
+ Platforms() []ocispec.Platform
+}
+
+// UnpackConfiguration specifies the platform and snapshotter to use for resolving
+// the unpack Platform, if snapshotter is not specified the platform default will
+// be used.
+type UnpackConfiguration struct {
+ Platform ocispec.Platform
+ Snapshotter string
+}
+
+type ProgressFunc func(Progress)
+
+type Config struct {
+ Progress ProgressFunc
+}
+
+type Opt func(*Config)
+
+func WithProgress(f ProgressFunc) Opt {
+ return func(opts *Config) {
+ opts.Progress = f
+ }
+}
+
+// Progress is used to represent a particular progress event or incremental
+// update for the provided named object. The parents represent the names of
+// the objects which initiated the progress for the provided named object.
+// The name and what object it represents is determined by the implementation.
+type Progress struct {
+ Event string
+ Name string
+ Parents []string
+ Progress int64
+ Total int64
+ Desc *ocispec.Descriptor // since containerd v2.0
+}
diff --git a/vendor/github.com/containerd/containerd/v2/defaults/defaults.go b/vendor/github.com/containerd/containerd/v2/defaults/defaults.go
new file mode 100644
index 0000000000..fcf3ec60cd
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/defaults/defaults.go
@@ -0,0 +1,37 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package defaults
+
+const (
+ // DefaultMaxRecvMsgSize defines the default maximum message size for
+ // receiving protobufs passed over the GRPC API.
+ DefaultMaxRecvMsgSize = 16 << 20
+ // DefaultMaxSendMsgSize defines the default maximum message size for
+ // sending protobufs passed over the GRPC API.
+ DefaultMaxSendMsgSize = 16 << 20
+ // DefaultRuntimeNSLabel defines the namespace label to check for the
+ // default runtime
+ DefaultRuntimeNSLabel = "containerd.io/defaults/runtime"
+ // DefaultSnapshotterNSLabel defines the namespace label to check for the
+ // default snapshotter
+ DefaultSnapshotterNSLabel = "containerd.io/defaults/snapshotter"
+ // DefaultSandboxerNSLabel defines the namespace label to check for the
+ // default sandboxcr
+ DefaultSandboxerNSLabel = "containerd.io/defaults/sandboxer"
+ // DefaultSandboxer defines the default sandboxer to use for creating sandboxes.
+ DefaultSandboxer = "shim"
+)
diff --git a/vendor/github.com/containerd/containerd/v2/defaults/defaults_darwin.go b/vendor/github.com/containerd/containerd/v2/defaults/defaults_darwin.go
new file mode 100644
index 0000000000..ffc58cb968
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/defaults/defaults_darwin.go
@@ -0,0 +1,39 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package defaults
+
+const (
+ // DefaultRuntime is the default darwin runtime for running containers
+ DefaultRuntime = "io.containerd.nerdbox.v1"
+ // DefaultAddress is the default unix socket address
+ DefaultAddress = "/var/run/containerd/containerd.sock"
+ // DefaultDebugAddress is the default unix socket address for pprof data
+ DefaultDebugAddress = "/var/run/containerd/debug.sock"
+ // DefaultFIFODir is the default location used by client-side cio library
+ // to store FIFOs.
+ DefaultFIFODir = "/var/run/containerd/fifo"
+ // DefaultSnapshotter will set the default snapshotter for the platform.
+ // Since mounts are not supported on Darwin, use erofs as the default
+ // which does not require mount support.
+ DefaultSnapshotter = "erofs"
+ // DefaultStateDir is the default location used by containerd to store
+ // transient data
+ DefaultStateDir = "/var/run/containerd"
+ // DefaultDiffer will set the default differ for the platform, use the
+ // erofs differ which does not require mount support.
+ DefaultDiffer = "erofs"
+)
diff --git a/vendor/github.com/containerd/containerd/v2/defaults/defaults_freebsd.go b/vendor/github.com/containerd/containerd/v2/defaults/defaults_freebsd.go
new file mode 100644
index 0000000000..d74133012a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/defaults/defaults_freebsd.go
@@ -0,0 +1,22 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package defaults
+
+const (
+ // DefaultRuntime is the default freebsd runtime
+ DefaultRuntime = "wtf.sbk.runj.v1"
+)
diff --git a/vendor/github.com/containerd/containerd/v2/defaults/defaults_linux.go b/vendor/github.com/containerd/containerd/v2/defaults/defaults_linux.go
new file mode 100644
index 0000000000..dc1ff0909c
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/defaults/defaults_linux.go
@@ -0,0 +1,38 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package defaults
+
+const (
+ // DefaultAddress is the default unix socket address
+ DefaultAddress = "/run/containerd/containerd.sock"
+ // DefaultDebugAddress is the default unix socket address for pprof data
+ DefaultDebugAddress = "/run/containerd/debug.sock"
+ // DefaultFIFODir is the default location used by client-side cio library
+ // to store FIFOs.
+ DefaultFIFODir = "/run/containerd/fifo"
+ // DefaultRuntime is the default linux runtime
+ DefaultRuntime = "io.containerd.runc.v2"
+ // DefaultSnapshotter will set the default snapshotter for the platform.
+ // This will be based on the client compilation target, so take that into
+ // account when choosing this value.
+ DefaultSnapshotter = "overlayfs"
+ // DefaultStateDir is the default location used by containerd to store
+ // transient data
+ DefaultStateDir = "/run/containerd"
+ // DefaultDiffer will set the default differ for the platform.
+ DefaultDiffer = "walking"
+)
diff --git a/vendor/github.com/containerd/containerd/v2/defaults/defaults_unix.go b/vendor/github.com/containerd/containerd/v2/defaults/defaults_unix.go
new file mode 100644
index 0000000000..07cc441556
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/defaults/defaults_unix.go
@@ -0,0 +1,30 @@
+//go:build unix
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package defaults
+
+const (
+ // DefaultConfigDir is the default location for config files.
+ DefaultConfigDir = "/etc/containerd"
+ // DefaultRootDir is the default location used by containerd to store
+ // persistent data
+ DefaultRootDir = "/var/lib/containerd"
+
+ // DefaultConfigIncludePattern is the default location for drop-in configuration files.
+ DefaultConfigIncludePattern = "/etc/containerd/conf.d/*.toml"
+)
diff --git a/vendor/github.com/containerd/containerd/v2/defaults/defaults_unix_other.go b/vendor/github.com/containerd/containerd/v2/defaults/defaults_unix_other.go
new file mode 100644
index 0000000000..6004c20171
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/defaults/defaults_unix_other.go
@@ -0,0 +1,38 @@
+//go:build unix && !linux && !darwin
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package defaults
+
+const (
+ // DefaultAddress is the default unix socket address
+ DefaultAddress = "/var/run/containerd/containerd.sock"
+ // DefaultDebugAddress is the default unix socket address for pprof data
+ DefaultDebugAddress = "/var/run/containerd/debug.sock"
+ // DefaultFIFODir is the default location used by client-side cio library
+ // to store FIFOs.
+ DefaultFIFODir = "/var/run/containerd/fifo"
+ // DefaultSnapshotter will set the default snapshotter for the platform.
+ // This will be based on the client compilation target, so take that into
+ // account when choosing this value.
+ DefaultSnapshotter = "native"
+ // DefaultStateDir is the default location used by containerd to store
+ // transient data
+ DefaultStateDir = "/var/run/containerd"
+ // DefaultDiffer will set the default differ for the platform.
+ DefaultDiffer = "walking"
+)
diff --git a/vendor/github.com/containerd/containerd/v2/defaults/defaults_windows.go b/vendor/github.com/containerd/containerd/v2/defaults/defaults_windows.go
new file mode 100644
index 0000000000..9fa2bc732a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/defaults/defaults_windows.go
@@ -0,0 +1,56 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package defaults
+
+import (
+ "os"
+ "path/filepath"
+)
+
+var (
+ // DefaultRootDir is the default location used by containerd to store
+ // persistent data
+ DefaultRootDir = filepath.Join(os.Getenv("ProgramData"), "containerd", "root")
+ // DefaultStateDir is the default location used by containerd to store
+ // transient data
+ DefaultStateDir = filepath.Join(os.Getenv("ProgramData"), "containerd", "state")
+
+ // DefaultConfigDir is the default location for config files.
+ DefaultConfigDir = filepath.Join(os.Getenv("programfiles"), "containerd")
+
+ // DefaultConfigIncludePattern is the default location for drop-in configuration files.
+ DefaultConfigIncludePattern = filepath.Join(os.Getenv("programfiles"), "containerd\\conf.d\\*.toml")
+)
+
+const (
+ // DefaultAddress is the default winpipe address
+ DefaultAddress = `\\.\pipe\containerd-containerd`
+ // DefaultDebugAddress is the default winpipe address for pprof data
+ DefaultDebugAddress = `\\.\pipe\containerd-debug`
+ // DefaultDiffer will set the default differ for the platform.
+ // This differ should be compatible with the windows snapshotter.
+ DefaultDiffer = "windows"
+ // DefaultFIFODir is the default location used by client-side cio library
+ // to store FIFOs. Unused on Windows.
+ DefaultFIFODir = ""
+ // DefaultRuntime is the default windows runtime
+ DefaultRuntime = "io.containerd.runhcs.v1"
+ // DefaultSnapshotter will set the default snapshotter for the platform.
+ // This will be based on the client compilation target, so take that into
+ // account when choosing this value.
+ DefaultSnapshotter = "windows"
+)
diff --git a/vendor/github.com/containerd/containerd/defaults/doc.go b/vendor/github.com/containerd/containerd/v2/defaults/doc.go
similarity index 100%
rename from vendor/github.com/containerd/containerd/defaults/doc.go
rename to vendor/github.com/containerd/containerd/v2/defaults/doc.go
diff --git a/vendor/github.com/containerd/containerd/v2/internal/fsverity/fsverity_linux.go b/vendor/github.com/containerd/containerd/v2/internal/fsverity/fsverity_linux.go
new file mode 100644
index 0000000000..6b55666d82
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/internal/fsverity/fsverity_linux.go
@@ -0,0 +1,130 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package fsverity
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "syscall"
+ "unsafe"
+
+ "github.com/containerd/containerd/v2/pkg/kernelversion"
+ "golang.org/x/sys/unix"
+)
+
+type fsverityEnableArg struct {
+ version uint32
+ hashAlgorithm uint32
+ blockSize uint32
+ saltSize uint32
+ saltPtr uint64
+ sigSize uint32
+ reserved1 uint32
+ sigPtr uint64
+ reserved2 [11]uint64
+}
+
+const (
+ defaultBlockSize int = 4096
+ maxDigestSize uint16 = 64
+)
+
+func IsSupported(rootPath string) (bool, error) {
+ minKernelVersion := kernelversion.KernelVersion{Kernel: 5, Major: 4}
+ s, err := kernelversion.GreaterEqualThan(minKernelVersion)
+ if err != nil {
+ return s, err
+ }
+
+ integrityDir, err := os.MkdirTemp(rootPath, ".fsverity-check-*")
+ if err != nil {
+ return false, err
+ }
+ defer os.RemoveAll(integrityDir)
+
+ digestPath := filepath.Join(integrityDir, "supported")
+ digestFile, err := os.Create(digestPath)
+ if err != nil {
+ return false, err
+ }
+
+ digestFile.Close()
+
+ eerr := Enable(digestPath)
+ if eerr != nil {
+ return false, eerr
+ }
+
+ return true, nil
+}
+
+func IsEnabled(path string) (bool, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return false, err
+ }
+ defer f.Close()
+
+ var attr int32
+
+ _, _, flagErr := unix.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(unix.FS_IOC_GETFLAGS), uintptr(unsafe.Pointer(&attr)))
+ if flagErr != 0 {
+ return false, fmt.Errorf("error getting inode flags: %w", flagErr)
+ }
+
+ if attr&unix.FS_VERITY_FL == unix.FS_VERITY_FL {
+ return true, nil
+ }
+
+ return false, nil
+}
+
+func Enable(path string) error {
+ f, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+
+ var args = &fsverityEnableArg{}
+ args.version = 1
+ args.hashAlgorithm = 1
+
+ // fsverity block size should be the minimum between the page size
+ // and the file system block size
+ // If neither value is retrieved successfully, set fsverity block size to the default value
+ blockSize := unix.Getpagesize()
+
+ s := unix.Stat_t{}
+ serr := unix.Stat(path, &s)
+ if serr == nil && int(s.Blksize) < blockSize {
+ blockSize = int(s.Blksize)
+ }
+
+ if blockSize <= 0 {
+ blockSize = defaultBlockSize
+ }
+
+ args.blockSize = uint32(blockSize)
+
+ _, _, errno := unix.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(unix.FS_IOC_ENABLE_VERITY), uintptr(unsafe.Pointer(args)))
+ if errno != 0 {
+ return fmt.Errorf("enable fsverity failed: %w", errno)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/internal/fsverity/fsverity_other.go b/vendor/github.com/containerd/containerd/v2/internal/fsverity/fsverity_other.go
new file mode 100644
index 0000000000..f50789adab
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/internal/fsverity/fsverity_other.go
@@ -0,0 +1,33 @@
+//go:build !linux
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package fsverity
+
+import "fmt"
+
+func IsSupported(rootPath string) (bool, error) {
+ return false, fmt.Errorf("fsverity is only supported on Linux systems")
+}
+
+func IsEnabled(path string) (bool, error) {
+ return false, fmt.Errorf("fsverity is only supported on Linux systems")
+}
+
+func Enable(_ string) error {
+ return fmt.Errorf("fsverity is only supported on Linux systems")
+}
diff --git a/vendor/github.com/containerd/containerd/v2/internal/lazyregexp/lazyregexp.go b/vendor/github.com/containerd/containerd/v2/internal/lazyregexp/lazyregexp.go
new file mode 100644
index 0000000000..08d890f313
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/internal/lazyregexp/lazyregexp.go
@@ -0,0 +1,86 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code below was largely copied from golang.org/x/mod@v0.22;
+// https://github.com/golang/mod/blob/v0.22.0/internal/lazyregexp/lazyre.go
+// with some additional methods added.
+
+// Package lazyregexp is a thin wrapper over regexp, allowing the use of global
+// regexp variables without forcing them to be compiled at init.
+package lazyregexp
+
+import (
+ "os"
+ "regexp"
+ "strings"
+ "sync"
+)
+
+// Regexp is a wrapper around [regexp.Regexp], where the underlying regexp will be
+// compiled the first time it is needed.
+type Regexp struct {
+ str string
+ once sync.Once
+ rx *regexp.Regexp
+}
+
+func (re *Regexp) re() *regexp.Regexp {
+ re.once.Do(re.build)
+ return re.rx
+}
+
+func (re *Regexp) build() {
+ re.rx = regexp.MustCompile(re.str)
+ re.str = ""
+}
+
+func (re *Regexp) FindStringIndex(s string) (loc []int) {
+ return re.re().FindStringIndex(s)
+}
+
+func (re *Regexp) FindStringSubmatch(s string) []string {
+ return re.re().FindStringSubmatch(s)
+}
+
+func (re *Regexp) MatchString(s string) bool {
+ return re.re().MatchString(s)
+}
+
+func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
+ return re.re().ReplaceAll(src, repl)
+}
+
+func (re *Regexp) String() string {
+ return re.re().String()
+}
+
+var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
+
+// New creates a new lazy regexp, delaying the compiling work until it is first
+// needed. If the code is being run as part of tests, the regexp compiling will
+// happen immediately.
+func New(str string) *Regexp {
+ lr := &Regexp{str: str}
+ if inTest {
+ // In tests, always compile the regexps early.
+ lr.re()
+ }
+ return lr
+}
diff --git a/vendor/github.com/containerd/containerd/v2/internal/randutil/randutil.go b/vendor/github.com/containerd/containerd/v2/internal/randutil/randutil.go
new file mode 100644
index 0000000000..f4b657d7dd
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/internal/randutil/randutil.go
@@ -0,0 +1,48 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+// Package randutil provides utilities for [cyrpto/rand].
+package randutil
+
+import (
+ "crypto/rand"
+ "math"
+ "math/big"
+)
+
+// Int63n is similar to [math/rand.Int63n] but uses [crypto/rand.Reader] under the hood.
+func Int63n(n int64) int64 {
+ b, err := rand.Int(rand.Reader, big.NewInt(n))
+ if err != nil {
+ panic(err)
+ }
+ return b.Int64()
+}
+
+// Int63 is similar to [math/rand.Int63] but uses [crypto/rand.Reader] under the hood.
+func Int63() int64 {
+ return Int63n(math.MaxInt64)
+}
+
+// Intn is similar to [math/rand.Intn] but uses [crypto/rand.Reader] under the hood.
+func Intn(n int) int {
+ return int(Int63n(int64(n)))
+}
+
+// Int is similar to [math/rand.Int] but uses [crypto/rand.Reader] under the hood.
+func Int() int {
+ return int(Int63())
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/archive/compression/compression.go b/vendor/github.com/containerd/containerd/v2/pkg/archive/compression/compression.go
new file mode 100644
index 0000000000..de3cb07adb
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/archive/compression/compression.go
@@ -0,0 +1,332 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package compression
+
+import (
+ "bufio"
+ "bytes"
+ "compress/gzip"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "os/exec"
+ "strconv"
+ "sync"
+
+ "github.com/containerd/log"
+ "github.com/klauspost/compress/zstd"
+)
+
+type (
+ // Compression is the state represents if compressed or not.
+ Compression int
+)
+
+const (
+ // Uncompressed represents the uncompressed.
+ Uncompressed Compression = iota
+ // Gzip is gzip compression algorithm.
+ Gzip
+ // Zstd is zstd compression algorithm.
+ Zstd
+ // Unknown is used when a plugin handles the algorithm.
+ Unknown
+)
+
+const (
+ disablePigzEnv = "CONTAINERD_DISABLE_PIGZ"
+ disableIgzipEnv = "CONTAINERD_DISABLE_IGZIP"
+)
+
+var (
+ initGzip sync.Once
+ gzipPath string
+)
+
+var (
+ bufioReader32KPool = &sync.Pool{
+ New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
+ }
+)
+
+// DecompressReadCloser include the stream after decompress and the compress method detected.
+type DecompressReadCloser interface {
+ io.ReadCloser
+ // GetCompression returns the compress method which is used before decompressing
+ GetCompression() Compression
+}
+
+type readCloserWrapper struct {
+ io.Reader
+ compression Compression
+ closer func() error
+}
+
+func (r *readCloserWrapper) Close() error {
+ if r.closer != nil {
+ return r.closer()
+ }
+ return nil
+}
+
+func (r *readCloserWrapper) GetCompression() Compression {
+ return r.compression
+}
+
+type writeCloserWrapper struct {
+ io.Writer
+ closer func() error
+}
+
+func (w *writeCloserWrapper) Close() error {
+ if w.closer != nil {
+ w.closer()
+ }
+ return nil
+}
+
+type bufferedReader struct {
+ buf *bufio.Reader
+}
+
+func newBufferedReader(r io.Reader) *bufferedReader {
+ buf := bufioReader32KPool.Get().(*bufio.Reader)
+ buf.Reset(r)
+ return &bufferedReader{buf}
+}
+
+func (r *bufferedReader) Read(p []byte) (n int, err error) {
+ if r.buf == nil {
+ return 0, io.EOF
+ }
+ n, err = r.buf.Read(p)
+ if err == io.EOF {
+ r.buf.Reset(nil)
+ bufioReader32KPool.Put(r.buf)
+ r.buf = nil
+ }
+ return
+}
+
+func (r *bufferedReader) Peek(n int) ([]byte, error) {
+ if r.buf == nil {
+ return nil, io.EOF
+ }
+ return r.buf.Peek(n)
+}
+
+const (
+ zstdMagicSkippableStart = 0x184D2A50
+ zstdMagicSkippableMask = 0xFFFFFFF0
+)
+
+var (
+ gzipMagic = []byte{0x1F, 0x8B, 0x08}
+ zstdMagic = []byte{0x28, 0xb5, 0x2f, 0xfd}
+)
+
+type matcher = func([]byte) bool
+
+func magicNumberMatcher(m []byte) matcher {
+ return func(source []byte) bool {
+ return bytes.HasPrefix(source, m)
+ }
+}
+
+// zstdMatcher detects zstd compression algorithm.
+// There are two frame formats defined by Zstandard: Zstandard frames and Skippable frames.
+// See https://datatracker.ietf.org/doc/html/rfc8878#section-3 for more details.
+func zstdMatcher() matcher {
+ return func(source []byte) bool {
+ if bytes.HasPrefix(source, zstdMagic) {
+ // Zstandard frame
+ return true
+ }
+ // skippable frame
+ if len(source) < 8 {
+ return false
+ }
+ // magic number from 0x184D2A50 to 0x184D2A5F.
+ if binary.LittleEndian.Uint32(source[:4])&zstdMagicSkippableMask == zstdMagicSkippableStart {
+ return true
+ }
+ return false
+ }
+}
+
+// DetectCompression detects the compression algorithm of the source.
+func DetectCompression(source []byte) Compression {
+ for compression, fn := range map[Compression]matcher{
+ Gzip: magicNumberMatcher(gzipMagic),
+ Zstd: zstdMatcher(),
+ } {
+ if fn(source) {
+ return compression
+ }
+ }
+ return Uncompressed
+}
+
+// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive.
+func DecompressStream(archive io.Reader) (DecompressReadCloser, error) {
+ buf := newBufferedReader(archive)
+ bs, err := buf.Peek(10)
+ if err != nil && err != io.EOF {
+ // Note: we'll ignore any io.EOF error because there are some odd
+ // cases where the layer.tar file will be empty (zero bytes) and
+ // that results in an io.EOF from the Peek() call. So, in those
+ // cases we'll just treat it as a non-compressed stream and
+ // that means just create an empty layer.
+ // See Issue docker/docker#18170
+ return nil, err
+ }
+
+ switch compression := DetectCompression(bs); compression {
+ case Uncompressed:
+ return &readCloserWrapper{
+ Reader: buf,
+ compression: compression,
+ }, nil
+ case Gzip:
+ ctx, cancel := context.WithCancel(context.Background())
+ gzReader, err := gzipDecompress(ctx, buf)
+ if err != nil {
+ cancel()
+ return nil, err
+ }
+
+ return &readCloserWrapper{
+ Reader: gzReader,
+ compression: compression,
+ closer: func() error {
+ cancel()
+ return gzReader.Close()
+ },
+ }, nil
+ case Zstd:
+ zstdReader, err := zstd.NewReader(buf,
+ zstd.WithDecoderLowmem(false),
+ )
+ if err != nil {
+ return nil, err
+ }
+ return &readCloserWrapper{
+ Reader: zstdReader,
+ compression: compression,
+ closer: func() error {
+ zstdReader.Close()
+ return nil
+ },
+ }, nil
+
+ default:
+ return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
+ }
+}
+
+// CompressStream compresses the dest with specified compression algorithm.
+func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) {
+ switch compression {
+ case Uncompressed:
+ return &writeCloserWrapper{dest, nil}, nil
+ case Gzip:
+ return gzip.NewWriter(dest), nil
+ case Zstd:
+ return zstd.NewWriter(dest)
+ default:
+ return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
+ }
+}
+
+// Extension returns the extension of a file that uses the specified compression algorithm.
+func (compression *Compression) Extension() string {
+ switch *compression {
+ case Gzip:
+ return "gz"
+ case Zstd:
+ return "zst"
+ case Unknown:
+ return "unknown"
+ }
+ return ""
+}
+
+func gzipDecompress(ctx context.Context, buf io.Reader) (io.ReadCloser, error) {
+ initGzip.Do(func() {
+ if gzipPath = detectCommand("igzip", disableIgzipEnv); gzipPath != "" {
+ log.L.Debug("using igzip for decompression")
+ return
+ }
+ if gzipPath = detectCommand("unpigz", disablePigzEnv); gzipPath != "" {
+ log.L.Debug("using unpigz for decompression")
+ }
+ })
+
+ if gzipPath == "" {
+ return gzip.NewReader(buf)
+ }
+ return cmdStream(exec.CommandContext(ctx, gzipPath, "-d", "-c"), buf)
+}
+
+func cmdStream(cmd *exec.Cmd, in io.Reader) (io.ReadCloser, error) {
+ reader, writer := io.Pipe()
+
+ cmd.Stdin = in
+ cmd.Stdout = writer
+
+ var errBuf bytes.Buffer
+ cmd.Stderr = &errBuf
+
+ if err := cmd.Start(); err != nil {
+ return nil, err
+ }
+
+ go func() {
+ if err := cmd.Wait(); err != nil {
+ writer.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String()))
+ } else {
+ writer.Close()
+ }
+ }()
+
+ return reader, nil
+}
+
+func detectCommand(path, disableEnvName string) string {
+ // Check if this command is disabled via the env variable
+ value := os.Getenv(disableEnvName)
+ if value != "" {
+ disable, err := strconv.ParseBool(value)
+ if err != nil {
+ log.L.WithError(err).Warnf("could not parse %s: %s", disableEnvName, value)
+ }
+
+ if disable {
+ return ""
+ }
+ }
+
+ path, err := exec.LookPath(path)
+ if err != nil {
+ log.L.WithError(err).Debugf("%s not found", path)
+ return ""
+ }
+
+ return path
+}
diff --git a/vendor/github.com/containerd/containerd/filters/adaptor.go b/vendor/github.com/containerd/containerd/v2/pkg/filters/adaptor.go
similarity index 100%
rename from vendor/github.com/containerd/containerd/filters/adaptor.go
rename to vendor/github.com/containerd/containerd/v2/pkg/filters/adaptor.go
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/filters/filter.go b/vendor/github.com/containerd/containerd/v2/pkg/filters/filter.go
new file mode 100644
index 0000000000..dcc569a4b7
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/filters/filter.go
@@ -0,0 +1,178 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+// Package filters defines a syntax and parser that can be used for the
+// filtration of items across the containerd API. The core is built on the
+// concept of protobuf field paths, with quoting. Several operators allow the
+// user to flexibly select items based on field presence, equality, inequality
+// and regular expressions. Flexible adaptors support working with any type.
+//
+// The syntax is fairly familiar, if you've used container ecosystem
+// projects. At the core, we base it on the concept of protobuf field
+// paths, augmenting with the ability to quote portions of the field path
+// to match arbitrary labels. These "selectors" come in the following
+// syntax:
+//
+// ```
+// []
+// ```
+//
+// A basic example is as follows:
+//
+// ```
+// name==foo
+// ```
+//
+// This would match all objects that have a field `name` with the value
+// `foo`. If we only want to test if the field is present, we can omit the
+// operator. This is most useful for matching labels in containerd. The
+// following will match objects that have the field "labels" and have the
+// label "foo" defined:
+//
+// ```
+// labels.foo
+// ```
+//
+// We also allow for quoting of parts of the field path to allow matching
+// of arbitrary items:
+//
+// ```
+// labels."very complex label"==something
+// ```
+//
+// We also define `!=` and `~=` as operators. The `!=` will match all
+// objects that don't match the value for a field and `~=` will compile the
+// target value as a regular expression and match the field value against that.
+//
+// Selectors can be combined using a comma, such that the resulting
+// selector will require all selectors are matched for the object to match.
+// The following example will match objects that are named `foo` and have
+// the label `bar`:
+//
+// ```
+// name==foo,labels.bar
+// ```
+package filters
+
+import (
+ "regexp"
+
+ "github.com/containerd/log"
+)
+
+// Filter matches specific resources based the provided filter
+type Filter interface {
+ Match(adaptor Adaptor) bool
+}
+
+// FilterFunc is a function that handles matching with an adaptor
+type FilterFunc func(Adaptor) bool
+
+// Match matches the FilterFunc returning true if the object matches the filter
+func (fn FilterFunc) Match(adaptor Adaptor) bool {
+ return fn(adaptor)
+}
+
+// Always is a filter that always returns true for any type of object
+var Always FilterFunc = func(adaptor Adaptor) bool {
+ return true
+}
+
+// Any allows multiple filters to be matched against the object
+type Any []Filter
+
+// Match returns true if any of the provided filters are true
+func (m Any) Match(adaptor Adaptor) bool {
+ for _, m := range m {
+ if m.Match(adaptor) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// All allows multiple filters to be matched against the object
+type All []Filter
+
+// Match only returns true if all filters match the object
+func (m All) Match(adaptor Adaptor) bool {
+ for _, m := range m {
+ if !m.Match(adaptor) {
+ return false
+ }
+ }
+
+ return true
+}
+
+type operator int
+
+const (
+ operatorPresent = iota
+ operatorEqual
+ operatorNotEqual
+ operatorMatches
+)
+
+func (op operator) String() string {
+ switch op {
+ case operatorPresent:
+ return "?"
+ case operatorEqual:
+ return "=="
+ case operatorNotEqual:
+ return "!="
+ case operatorMatches:
+ return "~="
+ }
+
+ return "unknown"
+}
+
+type selector struct {
+ fieldpath []string
+ operator operator
+ value string
+ re *regexp.Regexp
+}
+
+func (m selector) Match(adaptor Adaptor) bool {
+ value, present := adaptor.Field(m.fieldpath)
+
+ switch m.operator {
+ case operatorPresent:
+ return present
+ case operatorEqual:
+ return present && value == m.value
+ case operatorNotEqual:
+ return value != m.value
+ case operatorMatches:
+ if m.re == nil {
+ r, err := regexp.Compile(m.value)
+ if err != nil {
+ log.L.Errorf("error compiling regexp %q", m.value)
+ return false
+ }
+
+ m.re = r
+ }
+
+ return m.re.MatchString(value)
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/filters/parser.go b/vendor/github.com/containerd/containerd/v2/pkg/filters/parser.go
new file mode 100644
index 0000000000..e86ed8eb46
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/filters/parser.go
@@ -0,0 +1,290 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package filters
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/containerd/errdefs"
+)
+
+/*
+Parse the strings into a filter that may be used with an adaptor.
+
+The filter is made up of zero or more selectors.
+
+The format is a comma separated list of expressions, in the form of
+``, known as selectors. All selectors must match the
+target object for the filter to be true.
+
+We define the operators "==" for equality, "!=" for not equal and "~=" for a
+regular expression. If the operator and value are not present, the matcher will
+test for the presence of a value, as defined by the target object.
+
+The formal grammar is as follows:
+
+selectors := selector ("," selector)*
+selector := fieldpath (operator value)
+fieldpath := field ('.' field)*
+field := quoted | [A-Za-z] [A-Za-z0-9_]+
+operator := "==" | "!=" | "~="
+value := quoted | [^\s,]+
+quoted :=
+*/
+func Parse(s string) (Filter, error) {
+ // special case empty to match all
+ if s == "" {
+ return Always, nil
+ }
+
+ p := parser{input: s}
+ return p.parse()
+}
+
+// ParseAll parses each filter in ss and returns a filter that will return true
+// if any filter matches the expression.
+//
+// If no filters are provided, the filter will match anything.
+func ParseAll(ss ...string) (Filter, error) {
+ if len(ss) == 0 {
+ return Always, nil
+ }
+
+ var fs []Filter
+ for _, s := range ss {
+ f, err := Parse(s)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", err.Error(), errdefs.ErrInvalidArgument)
+ }
+
+ fs = append(fs, f)
+ }
+
+ return Any(fs), nil
+}
+
+type parser struct {
+ input string
+ scanner scanner
+}
+
+func (p *parser) parse() (Filter, error) {
+ p.scanner.init(p.input)
+
+ ss, err := p.selectors()
+ if err != nil {
+ return nil, fmt.Errorf("filters: %w", err)
+ }
+
+ return ss, nil
+}
+
+func (p *parser) selectors() (Filter, error) {
+ s, err := p.selector()
+ if err != nil {
+ return nil, err
+ }
+
+ ss := All{s}
+
+loop:
+ for {
+ tok := p.scanner.peek()
+ switch tok {
+ case ',':
+ pos, tok, _ := p.scanner.scan()
+ if tok != tokenSeparator {
+ return nil, p.mkerr(pos, "expected a separator")
+ }
+
+ s, err := p.selector()
+ if err != nil {
+ return nil, err
+ }
+
+ ss = append(ss, s)
+ case tokenEOF:
+ break loop
+ default:
+ return nil, p.mkerr(p.scanner.ppos, "unexpected input: %v", string(tok))
+ }
+ }
+
+ return ss, nil
+}
+
+func (p *parser) selector() (selector, error) {
+ fieldpath, err := p.fieldpath()
+ if err != nil {
+ return selector{}, err
+ }
+
+ switch p.scanner.peek() {
+ case ',', tokenSeparator, tokenEOF:
+ return selector{
+ fieldpath: fieldpath,
+ operator: operatorPresent,
+ }, nil
+ }
+
+ op, err := p.operator()
+ if err != nil {
+ return selector{}, err
+ }
+
+ var allowAltQuotes bool
+ if op == operatorMatches {
+ allowAltQuotes = true
+ }
+
+ value, err := p.value(allowAltQuotes)
+ if err != nil {
+ if err == io.EOF {
+ return selector{}, io.ErrUnexpectedEOF
+ }
+ return selector{}, err
+ }
+
+ return selector{
+ fieldpath: fieldpath,
+ value: value,
+ operator: op,
+ }, nil
+}
+
+func (p *parser) fieldpath() ([]string, error) {
+ f, err := p.field()
+ if err != nil {
+ return nil, err
+ }
+
+ fs := []string{f}
+loop:
+ for {
+ tok := p.scanner.peek() // lookahead to consume field separator
+
+ switch tok {
+ case '.':
+ pos, tok, _ := p.scanner.scan() // consume separator
+ if tok != tokenSeparator {
+ return nil, p.mkerr(pos, "expected a field separator (`.`)")
+ }
+
+ f, err := p.field()
+ if err != nil {
+ return nil, err
+ }
+
+ fs = append(fs, f)
+ default:
+ // let the layer above handle the other bad cases.
+ break loop
+ }
+ }
+
+ return fs, nil
+}
+
+func (p *parser) field() (string, error) {
+ pos, tok, s := p.scanner.scan()
+ switch tok {
+ case tokenField:
+ return s, nil
+ case tokenQuoted:
+ return p.unquote(pos, s, false)
+ case tokenIllegal:
+ return "", p.mkerr(pos, "%s", p.scanner.err)
+ }
+
+ return "", p.mkerr(pos, "expected field or quoted")
+}
+
+func (p *parser) operator() (operator, error) {
+ pos, tok, s := p.scanner.scan()
+ switch tok {
+ case tokenOperator:
+ switch s {
+ case "==":
+ return operatorEqual, nil
+ case "!=":
+ return operatorNotEqual, nil
+ case "~=":
+ return operatorMatches, nil
+ default:
+ return 0, p.mkerr(pos, "unsupported operator %q", s)
+ }
+ case tokenIllegal:
+ return 0, p.mkerr(pos, "%s", p.scanner.err)
+ }
+
+ return 0, p.mkerr(pos, `expected an operator ("=="|"!="|"~=")`)
+}
+
+func (p *parser) value(allowAltQuotes bool) (string, error) {
+ pos, tok, s := p.scanner.scan()
+
+ switch tok {
+ case tokenValue, tokenField:
+ return s, nil
+ case tokenQuoted:
+ return p.unquote(pos, s, allowAltQuotes)
+ case tokenIllegal:
+ return "", p.mkerr(pos, "%s", p.scanner.err)
+ }
+
+ return "", p.mkerr(pos, "expected value or quoted")
+}
+
+func (p *parser) unquote(pos int, s string, allowAlts bool) (string, error) {
+ if !allowAlts && s[0] != '\'' && s[0] != '"' {
+ return "", p.mkerr(pos, "invalid quote encountered")
+ }
+
+ uq, err := unquote(s)
+ if err != nil {
+ return "", p.mkerr(pos, "unquoting failed: %v", err)
+ }
+
+ return uq, nil
+}
+
+type parseError struct {
+ input string
+ pos int
+ msg string
+}
+
+func (pe parseError) Error() string {
+ if pe.pos < len(pe.input) {
+ before := pe.input[:pe.pos]
+ location := pe.input[pe.pos : pe.pos+1] // need to handle end
+ after := pe.input[pe.pos+1:]
+
+ return fmt.Sprintf("[%s >|%s|< %s]: %v", before, location, after, pe.msg)
+ }
+
+ return fmt.Sprintf("[%s]: %v", pe.input, pe.msg)
+}
+
+func (p *parser) mkerr(pos int, format string, args ...interface{}) error {
+ return fmt.Errorf("parse error: %w", parseError{
+ input: p.input,
+ pos: pos,
+ msg: fmt.Sprintf(format, args...),
+ })
+}
diff --git a/vendor/github.com/containerd/containerd/filters/quote.go b/vendor/github.com/containerd/containerd/v2/pkg/filters/quote.go
similarity index 100%
rename from vendor/github.com/containerd/containerd/filters/quote.go
rename to vendor/github.com/containerd/containerd/v2/pkg/filters/quote.go
diff --git a/vendor/github.com/containerd/containerd/filters/scanner.go b/vendor/github.com/containerd/containerd/v2/pkg/filters/scanner.go
similarity index 100%
rename from vendor/github.com/containerd/containerd/filters/scanner.go
rename to vendor/github.com/containerd/containerd/v2/pkg/filters/scanner.go
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/identifiers/validate.go b/vendor/github.com/containerd/containerd/v2/pkg/identifiers/validate.go
new file mode 100644
index 0000000000..c1c7a336a4
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/identifiers/validate.go
@@ -0,0 +1,73 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+// Package identifiers provides common validation for identifiers and keys
+// across containerd.
+//
+// Identifiers in containerd must be a alphanumeric, allowing limited
+// underscores, dashes and dots.
+//
+// While the character set may be expanded in the future, identifiers
+// are guaranteed to be safely used as filesystem path components.
+package identifiers
+
+import (
+ "fmt"
+
+ "github.com/containerd/containerd/v2/internal/lazyregexp"
+ "github.com/containerd/errdefs"
+)
+
+const (
+ maxLength = 76
+ alphanum = `[A-Za-z0-9]+`
+ separators = `[._-]`
+)
+
+var (
+ // identifierRe defines the pattern for valid identifiers.
+ identifierRe = lazyregexp.New(reAnchor(alphanum + reGroup(separators+reGroup(alphanum)) + "*"))
+)
+
+// Validate returns nil if the string s is a valid identifier.
+//
+// identifiers are similar to the domain name rules according to RFC 1035, section 2.3.1. However
+// rules in this package are relaxed to allow numerals to follow period (".") and mixed case is
+// allowed.
+//
+// In general identifiers that pass this validation should be safe for use as filesystem path components.
+func Validate(s string) error {
+ if len(s) == 0 {
+ return fmt.Errorf("identifier must not be empty: %w", errdefs.ErrInvalidArgument)
+ }
+
+ if len(s) > maxLength {
+ return fmt.Errorf("identifier %q greater than maximum length (%d characters): %w", s, maxLength, errdefs.ErrInvalidArgument)
+ }
+
+ if !identifierRe.MatchString(s) {
+ return fmt.Errorf("identifier %q must match %v: %w", s, identifierRe, errdefs.ErrInvalidArgument)
+ }
+ return nil
+}
+
+func reGroup(s string) string {
+ return `(?:` + s + `)`
+}
+
+func reAnchor(s string) string {
+ return `^` + s + `$`
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/kernelversion/kernel_linux.go b/vendor/github.com/containerd/containerd/v2/pkg/kernelversion/kernel_linux.go
new file mode 100644
index 0000000000..a8cec6481f
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/kernelversion/kernel_linux.go
@@ -0,0 +1,94 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+/*
+ File copied and customized based on
+ https://github.com/moby/moby/tree/v20.10.14/profiles/seccomp/kernel_linux.go
+*/
+
+package kernelversion
+
+import (
+ "bytes"
+ "fmt"
+ "sync"
+
+ "golang.org/x/sys/unix"
+)
+
+// KernelVersion holds information about the kernel.
+type KernelVersion struct {
+ Kernel uint64 // Version of the Kernel (i.e., the "4" in "4.1.2-generic")
+ Major uint64 // Major revision of the Kernel (i.e., the "1" in "4.1.2-generic")
+}
+
+// String implements fmt.Stringer for KernelVersion
+func (k *KernelVersion) String() string {
+ if k.Kernel > 0 || k.Major > 0 {
+ return fmt.Sprintf("%d.%d", k.Kernel, k.Major)
+ }
+ return ""
+}
+
+var (
+ currentKernelVersion *KernelVersion
+ kernelVersionError error
+ once sync.Once
+)
+
+// getKernelVersion gets the current kernel version.
+func getKernelVersion() (*KernelVersion, error) {
+ once.Do(func() {
+ var uts unix.Utsname
+ if err := unix.Uname(&uts); err != nil {
+ return
+ }
+ // Remove the \x00 from the release for Atoi to parse correctly
+ currentKernelVersion, kernelVersionError = parseRelease(string(uts.Release[:bytes.IndexByte(uts.Release[:], 0)]))
+ })
+ return currentKernelVersion, kernelVersionError
+}
+
+// parseRelease parses a string and creates a KernelVersion based on it.
+func parseRelease(release string) (*KernelVersion, error) {
+ var version = KernelVersion{}
+
+ // We're only make sure we get the "kernel" and "major revision". Sometimes we have
+ // 3.12.25-gentoo, but sometimes we just have 3.12-1-amd64.
+ _, err := fmt.Sscanf(release, "%d.%d", &version.Kernel, &version.Major)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse kernel version %q: %w", release, err)
+ }
+ return &version, nil
+}
+
+// GreaterEqualThan checks if the host's kernel version is greater than, or
+// equal to the given kernel version v. Only "kernel version" and "major revision"
+// can be specified (e.g., "3.12") and will be taken into account, which means
+// that 3.12.25-gentoo and 3.12-1-amd64 are considered equal (kernel: 3, major: 12).
+func GreaterEqualThan(minVersion KernelVersion) (bool, error) {
+ kv, err := getKernelVersion()
+ if err != nil {
+ return false, err
+ }
+ if kv.Kernel > minVersion.Kernel {
+ return true, nil
+ }
+ if kv.Kernel == minVersion.Kernel && kv.Major >= minVersion.Major {
+ return true, nil
+ }
+ return false, nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/labels/labels.go b/vendor/github.com/containerd/containerd/v2/pkg/labels/labels.go
new file mode 100644
index 0000000000..0f9bab5c5d
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/labels/labels.go
@@ -0,0 +1,29 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package labels
+
+// LabelUncompressed is added to compressed layer contents.
+// The value is digest of the uncompressed content.
+const LabelUncompressed = "containerd.io/uncompressed"
+
+// LabelSharedNamespace is added to a namespace to allow that namespaces
+// contents to be shared.
+const LabelSharedNamespace = "containerd.io/namespace.shareable"
+
+// LabelDistributionSource is added to content to indicate its origin.
+// e.g., "containerd.io/distribution.source.docker.io=library/redis"
+const LabelDistributionSource = "containerd.io/distribution.source"
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/labels/validate.go b/vendor/github.com/containerd/containerd/v2/pkg/labels/validate.go
new file mode 100644
index 0000000000..6f23cdd7c6
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/labels/validate.go
@@ -0,0 +1,41 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package labels
+
+import (
+ "fmt"
+
+ "github.com/containerd/errdefs"
+)
+
+const (
+ maxSize = 4096
+ // maximum length of key portion of error message if len of key + len of value > maxSize
+ keyMaxLen = 64
+)
+
+// Validate a label's key and value are under 4096 bytes
+func Validate(k, v string) error {
+ total := len(k) + len(v)
+ if total > maxSize {
+ if len(k) > keyMaxLen {
+ k = k[:keyMaxLen]
+ }
+ return fmt.Errorf("label key and value length (%d bytes) greater than maximum size (%d bytes), key: %s: %w", total, maxSize, k, errdefs.ErrInvalidArgument)
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/namespaces/context.go b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/context.go
new file mode 100644
index 0000000000..dbbc28615d
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/context.go
@@ -0,0 +1,78 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package namespaces
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/containerd/containerd/v2/pkg/identifiers"
+ "github.com/containerd/errdefs"
+)
+
+const (
+ // NamespaceEnvVar is the environment variable key name
+ NamespaceEnvVar = "CONTAINERD_NAMESPACE"
+ // Default is the name of the default namespace
+ Default = "default"
+)
+
+type namespaceKey struct{}
+
+// WithNamespace sets a given namespace on the context
+func WithNamespace(ctx context.Context, namespace string) context.Context {
+ ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace
+ // also store on the grpc and ttrpc headers so it gets picked up by any clients that
+ // are using this.
+ return withTTRPCNamespaceHeader(withGRPCNamespaceHeader(ctx, namespace), namespace)
+}
+
+// NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or
+// default
+func NamespaceFromEnv(ctx context.Context) context.Context {
+ namespace := os.Getenv(NamespaceEnvVar)
+ if namespace == "" {
+ namespace = Default
+ }
+ return WithNamespace(ctx, namespace)
+}
+
+// Namespace returns the namespace from the context.
+//
+// The namespace is not guaranteed to be valid.
+func Namespace(ctx context.Context) (string, bool) {
+ namespace, ok := ctx.Value(namespaceKey{}).(string)
+ if !ok {
+ if namespace, ok = fromGRPCHeader(ctx); !ok {
+ return fromTTRPCHeader(ctx)
+ }
+ }
+ return namespace, ok
+}
+
+// NamespaceRequired returns the valid namespace from the context or an error.
+func NamespaceRequired(ctx context.Context) (string, error) {
+ namespace, ok := Namespace(ctx)
+ if !ok || namespace == "" {
+ return "", fmt.Errorf("namespace is required: %w", errdefs.ErrFailedPrecondition)
+ }
+ if err := identifiers.Validate(namespace); err != nil {
+ return "", fmt.Errorf("namespace validation: %w", err)
+ }
+ return namespace, nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/namespaces/grpc.go b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/grpc.go
new file mode 100644
index 0000000000..6991460da6
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/grpc.go
@@ -0,0 +1,61 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package namespaces
+
+import (
+ "context"
+
+ "google.golang.org/grpc/metadata"
+)
+
+const (
+ // GRPCHeader defines the header name for specifying a containerd namespace.
+ GRPCHeader = "containerd-namespace"
+)
+
+// NOTE(stevvooe): We can stub this file out if we don't want a grpc dependency here.
+
+func withGRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
+ // also store on the grpc headers so it gets picked up by any clients that
+ // are using this.
+ nsheader := metadata.Pairs(GRPCHeader, namespace)
+ md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
+ if !ok {
+ md = nsheader
+ } else {
+ // order ensures the latest is first in this list.
+ md = metadata.Join(nsheader, md)
+ }
+
+ return metadata.NewOutgoingContext(ctx, md)
+}
+
+func fromGRPCHeader(ctx context.Context) (string, bool) {
+ // try to extract for use in grpc servers.
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ // TODO(stevvooe): Check outgoing context?
+ return "", false
+ }
+
+ values := md[GRPCHeader]
+ if len(values) == 0 {
+ return "", false
+ }
+
+ return values[0], true
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/namespaces/store.go b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/store.go
new file mode 100644
index 0000000000..a1b2571bb1
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/store.go
@@ -0,0 +1,44 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package namespaces
+
+import "context"
+
+// Store provides introspection about namespaces.
+//
+// Note that these are slightly different than other objects, which are record
+// oriented. A namespace is really just a name and a set of labels. Objects
+// that belong to a namespace are returned when the namespace is assigned to a
+// given context.
+type Store interface {
+ Create(ctx context.Context, namespace string, labels map[string]string) error
+ Labels(ctx context.Context, namespace string) (map[string]string, error)
+ SetLabel(ctx context.Context, namespace, key, value string) error
+ List(ctx context.Context) ([]string, error)
+
+ // Delete removes the namespace. The namespace must be empty to be deleted.
+ Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error
+}
+
+// DeleteInfo specifies information for the deletion of a namespace
+type DeleteInfo struct {
+ // Name of the namespace
+ Name string
+}
+
+// DeleteOpts allows the caller to set options for namespace deletion
+type DeleteOpts func(context.Context, *DeleteInfo) error
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/namespaces/ttrpc.go b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/ttrpc.go
new file mode 100644
index 0000000000..f9b24ad69a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/namespaces/ttrpc.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package namespaces
+
+import (
+ "context"
+
+ "github.com/containerd/ttrpc"
+)
+
+const (
+ // TTRPCHeader defines the header name for specifying a containerd namespace
+ TTRPCHeader = "containerd-namespace-ttrpc"
+)
+
+func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
+ md, ok := ttrpc.GetMetadata(ctx)
+ if !ok {
+ md = ttrpc.MD{}
+ } else {
+ md = md.Clone()
+ }
+ md.Set(TTRPCHeader, namespace)
+ return ttrpc.WithMetadata(ctx, md)
+}
+
+func fromTTRPCHeader(ctx context.Context) (string, bool) {
+ return ttrpc.GetMetadataValue(ctx, TTRPCHeader)
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/protobuf/compare.go b/vendor/github.com/containerd/containerd/v2/pkg/protobuf/compare.go
new file mode 100644
index 0000000000..602a4bcac5
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/protobuf/compare.go
@@ -0,0 +1,41 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package protobuf
+
+import (
+ "github.com/google/go-cmp/cmp"
+ "google.golang.org/protobuf/proto"
+)
+
+var Compare = cmp.FilterValues(
+ func(x, y interface{}) bool {
+ _, xok := x.(proto.Message)
+ _, yok := y.(proto.Message)
+ return xok && yok
+ },
+ cmp.Comparer(func(x, y interface{}) bool {
+ vx, ok := x.(proto.Message)
+ if !ok {
+ return false
+ }
+ vy, ok := y.(proto.Message)
+ if !ok {
+ return false
+ }
+ return proto.Equal(vx, vy)
+ }),
+)
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/protobuf/timestamp.go b/vendor/github.com/containerd/containerd/v2/pkg/protobuf/timestamp.go
new file mode 100644
index 0000000000..0615f823b0
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/protobuf/timestamp.go
@@ -0,0 +1,36 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package protobuf
+
+import (
+ "time"
+
+ "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+// Once we migrate off from gogo/protobuf, we can use the function below, which don't return any errors.
+// https://github.com/protocolbuffers/protobuf-go/blob/v1.28.0/types/known/timestamppb/timestamp.pb.go#L200-L208
+
+// ToTimestamp creates protobuf's Timestamp from time.Time.
+func ToTimestamp(from time.Time) *timestamppb.Timestamp {
+ return timestamppb.New(from)
+}
+
+// FromTimestamp creates time.Time from protobuf's Timestamp.
+func FromTimestamp(from *timestamppb.Timestamp) time.Time {
+ return from.AsTime()
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/protobuf/types/types.go b/vendor/github.com/containerd/containerd/v2/pkg/protobuf/types/types.go
new file mode 100644
index 0000000000..dd0b0299b6
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/protobuf/types/types.go
@@ -0,0 +1,28 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+// Package types provides convenient aliases that make google.golang.org/protobuf migration easier.
+package types
+
+import (
+ "google.golang.org/protobuf/types/known/anypb"
+ "google.golang.org/protobuf/types/known/emptypb"
+ field_mask "google.golang.org/protobuf/types/known/fieldmaskpb"
+)
+
+type Empty = emptypb.Empty
+type Any = anypb.Any
+type FieldMask = field_mask.FieldMask
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/reference/reference.go b/vendor/github.com/containerd/containerd/v2/pkg/reference/reference.go
new file mode 100644
index 0000000000..55c7b6fb52
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/reference/reference.go
@@ -0,0 +1,156 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package reference
+
+import (
+ "errors"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/containerd/containerd/v2/internal/lazyregexp"
+ digest "github.com/opencontainers/go-digest"
+)
+
+var (
+ // ErrInvalid is returned when there is an invalid reference
+ ErrInvalid = errors.New("invalid reference")
+ // ErrObjectRequired is returned when the object is required
+ ErrObjectRequired = errors.New("object required")
+ // ErrHostnameRequired is returned when the hostname is required
+ ErrHostnameRequired = errors.New("hostname required")
+)
+
+// Spec defines the main components of a reference specification.
+//
+// A reference specification is a schema-less URI parsed into common
+// components. The two main components, locator and object, are required to be
+// supported by remotes. It represents a superset of the naming define in
+// docker's reference schema. It aims to be compatible but not prescriptive.
+//
+// While the interpretation of the components, locator and object, are up to
+// the remote, we define a few common parts, accessible via helper methods.
+//
+// The first is the hostname, which is part of the locator. This doesn't need
+// to map to a physical resource, but it must parse as a hostname. We refer to
+// this as the namespace.
+//
+// The other component made accessible by helper method is the digest. This is
+// part of the object identifier, always prefixed with an '@'. If present, the
+// remote may use the digest portion directly or resolve it against a prefix.
+// If the object does not include the `@` symbol, the return value for `Digest`
+// will be empty.
+type Spec struct {
+ // Locator is the host and path portion of the specification. The host
+ // portion may refer to an actual host or just a namespace of related
+ // images.
+ //
+ // Typically, the locator may used to resolve the remote to fetch specific
+ // resources.
+ Locator string
+
+ // Object contains the identifier for the remote resource. Classically,
+ // this is a tag but can refer to anything in a remote. By convention, any
+ // portion that may be a partial or whole digest will be preceded by an
+ // `@`. Anything preceding the `@` will be referred to as the "tag".
+ //
+ // In practice, we will see this broken down into the following formats:
+ //
+ // 1.
+ // 2. @
+ // 3. @
+ //
+ // We define the tag to be anything except '@' and ':'. may
+ // be a full valid digest or shortened version, possibly with elided
+ // algorithm.
+ Object string
+}
+
+var splitRe = lazyregexp.New(`[:@]`)
+
+// Parse parses the string into a structured ref.
+func Parse(s string) (Spec, error) {
+ if strings.Contains(s, "://") {
+ return Spec{}, ErrInvalid
+ }
+
+ u, err := url.Parse("dummy://" + s)
+ if err != nil {
+ return Spec{}, err
+ }
+
+ if u.Scheme != "dummy" {
+ return Spec{}, ErrInvalid
+ }
+
+ if u.Host == "" {
+ return Spec{}, ErrHostnameRequired
+ }
+
+ var object string
+
+ if idx := splitRe.FindStringIndex(u.Path); idx != nil {
+ // This allows us to retain the @ to signify digests or shortened digests in
+ // the object.
+ object = u.Path[idx[0]:]
+ if object[:1] == ":" {
+ object = object[1:]
+ }
+ u.Path = u.Path[:idx[0]]
+ }
+
+ return Spec{
+ Locator: path.Join(u.Host, u.Path),
+ Object: object,
+ }, nil
+}
+
+// Hostname returns the hostname portion of the locator.
+//
+// Remotes are not required to directly access the resources at this host. This
+// method is provided for convenience.
+func (r Spec) Hostname() string {
+ i := strings.Index(r.Locator, "/")
+
+ if i < 0 {
+ return r.Locator
+ }
+ return r.Locator[:i]
+}
+
+// Digest returns the digest portion of the reference spec. This may be a
+// partial or invalid digest, which may be used to lookup a complete digest.
+func (r Spec) Digest() digest.Digest {
+ i := strings.Index(r.Object, "@")
+
+ if i < 0 {
+ return ""
+ }
+ return digest.Digest(r.Object[i+1:])
+}
+
+// String returns the normalized string for the ref.
+func (r Spec) String() string {
+ if r.Object == "" {
+ return r.Locator
+ }
+ if r.Object[:1] == "@" {
+ return r.Locator + r.Object
+ }
+
+ return r.Locator + ":" + r.Object
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/tracing/helpers.go b/vendor/github.com/containerd/containerd/v2/pkg/tracing/helpers.go
new file mode 100644
index 0000000000..ab1278ef1f
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/tracing/helpers.go
@@ -0,0 +1,85 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package tracing
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "go.opentelemetry.io/otel/attribute"
+)
+
+func keyValue(k string, v any) attribute.KeyValue {
+ if v == nil {
+ return attribute.String(k, "")
+ }
+
+ switch typed := v.(type) {
+ case bool:
+ return attribute.Bool(k, typed)
+ case []bool:
+ return attribute.BoolSlice(k, typed)
+ case int:
+ return attribute.Int(k, typed)
+ case []int:
+ return attribute.IntSlice(k, typed)
+ case int8:
+ return attribute.Int(k, int(typed))
+ case []int8:
+ ls := make([]int, 0, len(typed))
+ for _, i := range typed {
+ ls = append(ls, int(i))
+ }
+ return attribute.IntSlice(k, ls)
+ case int16:
+ return attribute.Int(k, int(typed))
+ case []int16:
+ ls := make([]int, 0, len(typed))
+ for _, i := range typed {
+ ls = append(ls, int(i))
+ }
+ return attribute.IntSlice(k, ls)
+ case int32:
+ return attribute.Int64(k, int64(typed))
+ case []int32:
+ ls := make([]int64, 0, len(typed))
+ for _, i := range typed {
+ ls = append(ls, int64(i))
+ }
+ return attribute.Int64Slice(k, ls)
+ case int64:
+ return attribute.Int64(k, typed)
+ case []int64:
+ return attribute.Int64Slice(k, typed)
+ case float64:
+ return attribute.Float64(k, typed)
+ case []float64:
+ return attribute.Float64Slice(k, typed)
+ case string:
+ return attribute.String(k, typed)
+ case []string:
+ return attribute.StringSlice(k, typed)
+ }
+
+ if stringer, ok := v.(fmt.Stringer); ok {
+ return attribute.String(k, stringer.String())
+ }
+ if b, err := json.Marshal(v); b != nil && err == nil {
+ return attribute.String(k, string(b))
+ }
+ return attribute.String(k, fmt.Sprintf("%v", v))
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/tracing/log.go b/vendor/github.com/containerd/containerd/v2/pkg/tracing/log.go
new file mode 100644
index 0000000000..3af24a294a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/tracing/log.go
@@ -0,0 +1,82 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package tracing
+
+import (
+ "github.com/containerd/log"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// allLevels is the equivalent to [logrus.AllLevels].
+//
+// [logrus.AllLevels]: https://github.com/sirupsen/logrus/blob/v1.9.3/logrus.go#L80-L89
+var allLevels = []log.Level{
+ log.PanicLevel,
+ log.FatalLevel,
+ log.ErrorLevel,
+ log.WarnLevel,
+ log.InfoLevel,
+ log.DebugLevel,
+ log.TraceLevel,
+}
+
+// NewLogrusHook creates a new logrus hook
+func NewLogrusHook() *LogrusHook {
+ return &LogrusHook{}
+}
+
+// LogrusHook is a [logrus.Hook] which adds logrus events to active spans.
+// If the span is not recording or the span context is invalid, the hook
+// is a no-op.
+//
+// [logrus.Hook]: https://github.com/sirupsen/logrus/blob/v1.9.3/hooks.go#L3-L11
+type LogrusHook struct{}
+
+// Levels returns the logrus levels that this hook is interested in.
+func (h *LogrusHook) Levels() []log.Level {
+ return allLevels
+}
+
+// Fire is called when a log event occurs.
+func (h *LogrusHook) Fire(entry *log.Entry) error {
+ span := trace.SpanFromContext(entry.Context)
+ if span == nil {
+ return nil
+ }
+
+ if !span.IsRecording() || !span.SpanContext().IsValid() {
+ return nil
+ }
+
+ span.AddEvent(
+ entry.Message,
+ trace.WithAttributes(logrusDataToAttrs(entry.Data)...),
+ trace.WithAttributes(attribute.String("level", entry.Level.String())),
+ trace.WithTimestamp(entry.Time),
+ )
+
+ return nil
+}
+
+func logrusDataToAttrs(data map[string]any) []attribute.KeyValue {
+ attrs := make([]attribute.KeyValue, 0, len(data))
+ for k, v := range data {
+ attrs = append(attrs, keyValue(k, v))
+ }
+ return attrs
+}
diff --git a/vendor/github.com/containerd/containerd/v2/pkg/tracing/tracing.go b/vendor/github.com/containerd/containerd/v2/pkg/tracing/tracing.go
new file mode 100644
index 0000000000..a874b2af76
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/pkg/tracing/tracing.go
@@ -0,0 +1,134 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package tracing
+
+import (
+ "context"
+ "net/http"
+ "strings"
+
+ "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// StartConfig defines configuration for a new span object.
+type StartConfig struct {
+ spanOpts []trace.SpanStartOption
+}
+
+type SpanOpt func(config *StartConfig)
+
+// WithAttribute appends attributes to a new created span.
+func WithAttribute(k string, v interface{}) SpanOpt {
+ return func(config *StartConfig) {
+ config.spanOpts = append(config.spanOpts,
+ trace.WithAttributes(Attribute(k, v)))
+ }
+}
+
+// UpdateHTTPClient updates the http client with the necessary otel transport
+func UpdateHTTPClient(client *http.Client, name string) {
+ client.Transport = otelhttp.NewTransport(
+ client.Transport,
+ otelhttp.WithSpanNameFormatter(func(operation string, r *http.Request) string {
+ return name
+ }),
+ )
+}
+
+// StartSpan starts child span in a context.
+func StartSpan(ctx context.Context, opName string, opts ...SpanOpt) (context.Context, *Span) {
+ config := StartConfig{}
+ for _, fn := range opts {
+ fn(&config)
+ }
+ tracer := otel.Tracer("")
+ if parent := trace.SpanFromContext(ctx); parent != nil && parent.SpanContext().IsValid() {
+ tracer = parent.TracerProvider().Tracer("")
+ }
+ ctx, span := tracer.Start(ctx, opName, config.spanOpts...)
+ return ctx, &Span{otelSpan: span}
+}
+
+// SpanFromContext returns the current Span from the context.
+func SpanFromContext(ctx context.Context) *Span {
+ return &Span{
+ otelSpan: trace.SpanFromContext(ctx),
+ }
+}
+
+// Span is wrapper around otel trace.Span.
+// Span is the individual component of a trace. It represents a
+// single named and timed operation of a workflow that is traced.
+type Span struct {
+ otelSpan trace.Span
+}
+
+// End completes the span.
+func (s *Span) End() {
+ s.otelSpan.End()
+}
+
+// AddEvent adds an event with provided name and options.
+func (s *Span) AddEvent(name string, attributes ...attribute.KeyValue) {
+ s.otelSpan.AddEvent(name, trace.WithAttributes(attributes...))
+}
+
+// RecordError will record err as an exception span event for this span
+func (s *Span) RecordError(err error, options ...trace.EventOption) {
+ s.otelSpan.RecordError(err, options...)
+}
+
+// SetStatus sets the status of the current span.
+// If an error is encountered, it records the error and sets span status to Error.
+func (s *Span) SetStatus(err error) {
+ if err != nil {
+ s.otelSpan.RecordError(err)
+ s.otelSpan.SetStatus(codes.Error, err.Error())
+ } else {
+ s.otelSpan.SetStatus(codes.Ok, "")
+ }
+}
+
+// SetAttributes sets kv as attributes of the span.
+func (s *Span) SetAttributes(kv ...attribute.KeyValue) {
+ s.otelSpan.SetAttributes(kv...)
+}
+
+const spanDelimiter = "."
+
+// Name sets the span name by joining a list of strings in dot separated format.
+func Name(names ...string) string {
+ return strings.Join(names, spanDelimiter)
+}
+
+// Attribute takes a key value pair and returns attribute.KeyValue type.
+func Attribute(k string, v any) attribute.KeyValue {
+ return keyValue(k, v)
+}
+
+// HTTPStatusCodeAttributes generates HTTP response status code attributes
+// as specified by the current OpenTelemetry semantic conventions.
+func HTTPStatusCodeAttributes(code int) []attribute.KeyValue {
+ return []attribute.KeyValue{
+ attribute.Int("http.response.status_code", code),
+ attribute.Int("http.status_code", code), // Deprecated: SemConv <= v1.21
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/v2/plugins/content/local/locks.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/locks.go
new file mode 100644
index 0000000000..80795add32
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/locks.go
@@ -0,0 +1,55 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package local
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/containerd/errdefs"
+)
+
+// Handles locking references
+
+type lock struct {
+ since time.Time
+}
+
+func (s *store) tryLock(ref string) error {
+ s.locksMu.Lock()
+ defer s.locksMu.Unlock()
+
+ if v, ok := s.locks[ref]; ok {
+ // Returning the duration may help developers distinguish dead locks (long duration) from
+ // lock contentions (short duration).
+ now := time.Now()
+ return fmt.Errorf(
+ "ref %s locked for %s (since %s): %w", ref, now.Sub(v.since), v.since,
+ errdefs.ErrUnavailable,
+ )
+ }
+
+ s.locks[ref] = &lock{time.Now()}
+ return nil
+}
+
+func (s *store) unlock(ref string) {
+ s.locksMu.Lock()
+ defer s.locksMu.Unlock()
+
+ delete(s.locks, ref)
+}
diff --git a/vendor/github.com/containerd/containerd/content/local/readerat.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/readerat.go
similarity index 89%
rename from vendor/github.com/containerd/containerd/content/local/readerat.go
rename to vendor/github.com/containerd/containerd/v2/plugins/content/local/readerat.go
index a83c171bbd..59198fd6e9 100644
--- a/vendor/github.com/containerd/containerd/content/local/readerat.go
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/readerat.go
@@ -18,10 +18,11 @@ package local
import (
"fmt"
+ "io"
"os"
- "github.com/containerd/containerd/content"
- "github.com/containerd/containerd/errdefs"
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/errdefs"
)
// readerat implements io.ReaderAt in a completely stateless manner by opening
@@ -65,3 +66,7 @@ func (ra sizeReaderAt) Size() int64 {
func (ra sizeReaderAt) Close() error {
return ra.fp.Close()
}
+
+func (ra sizeReaderAt) Reader() io.Reader {
+ return io.LimitReader(ra.fp, ra.size)
+}
diff --git a/vendor/github.com/containerd/containerd/v2/plugins/content/local/store.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store.go
new file mode 100644
index 0000000000..794c82c25e
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store.go
@@ -0,0 +1,710 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package local
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/internal/fsverity"
+ "github.com/containerd/containerd/v2/pkg/filters"
+
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+var bufPool = sync.Pool{
+ New: func() interface{} {
+ buffer := make([]byte, 1<<20)
+ return &buffer
+ },
+}
+
+// LabelStore is used to store mutable labels for digests
+type LabelStore interface {
+ // Get returns all the labels for the given digest
+ Get(digest.Digest) (map[string]string, error)
+
+ // Set sets all the labels for a given digest
+ Set(digest.Digest, map[string]string) error
+
+ // Update replaces the given labels for a digest,
+ // a key with an empty value removes a label.
+ Update(digest.Digest, map[string]string) (map[string]string, error)
+}
+
+// Store is digest-keyed store for content. All data written into the store is
+// stored under a verifiable digest.
+//
+// Store can generally support multi-reader, single-writer ingest of data,
+// including resumable ingest.
+type store struct {
+ root string
+ ls LabelStore
+ integritySupported bool
+
+ locksMu sync.Mutex
+ locks map[string]*lock
+ ensureIngestRootOnce func() error
+}
+
+// NewStore returns a local content store
+func NewStore(root string) (content.Store, error) {
+ return NewLabeledStore(root, nil)
+}
+
+// NewLabeledStore returns a new content store using the provided label store
+//
+// Note: content stores which are used underneath a metadata store may not
+// require labels and should use `NewStore`. `NewLabeledStore` is primarily
+// useful for tests or standalone implementations.
+func NewLabeledStore(root string, ls LabelStore) (content.Store, error) {
+ supported, _ := fsverity.IsSupported(root)
+
+ s := &store{
+ root: root,
+ ls: ls,
+ integritySupported: supported,
+ locks: map[string]*lock{},
+ }
+ s.ensureIngestRootOnce = sync.OnceValue(s.ensureIngestRoot)
+ return s, nil
+}
+
+func (s *store) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
+ p, err := s.blobPath(dgst)
+ if err != nil {
+ return content.Info{}, fmt.Errorf("calculating blob info path: %w", err)
+ }
+
+ fi, err := os.Stat(p)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = fmt.Errorf("content %v: %w", dgst, errdefs.ErrNotFound)
+ }
+
+ return content.Info{}, err
+ }
+ var labels map[string]string
+ if s.ls != nil {
+ labels, err = s.ls.Get(dgst)
+ if err != nil {
+ return content.Info{}, err
+ }
+ }
+ return s.info(dgst, fi, labels), nil
+}
+
+func (s *store) info(dgst digest.Digest, fi os.FileInfo, labels map[string]string) content.Info {
+ return content.Info{
+ Digest: dgst,
+ Size: fi.Size(),
+ CreatedAt: fi.ModTime(),
+ UpdatedAt: getATime(fi),
+ Labels: labels,
+ }
+}
+
+// ReaderAt returns an io.ReaderAt for the blob.
+func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
+ p, err := s.blobPath(desc.Digest)
+ if err != nil {
+ return nil, fmt.Errorf("calculating blob path for ReaderAt: %w", err)
+ }
+
+ reader, err := OpenReader(p)
+ if err != nil {
+ return nil, fmt.Errorf("blob %s expected at %s: %w", desc.Digest, p, err)
+ }
+
+ return reader, nil
+}
+
+// Delete removes a blob by its digest.
+//
+// While this is safe to do concurrently, safe exist-removal logic must hold
+// some global lock on the store.
+func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
+ bp, err := s.blobPath(dgst)
+ if err != nil {
+ return fmt.Errorf("calculating blob path for delete: %w", err)
+ }
+
+ if err := os.RemoveAll(bp); err != nil {
+ if !os.IsNotExist(err) {
+ return err
+ }
+
+ return fmt.Errorf("content %v: %w", dgst, errdefs.ErrNotFound)
+ }
+
+ return nil
+}
+
+func (s *store) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
+ if s.ls == nil {
+ return content.Info{}, fmt.Errorf("update not supported on immutable content store: %w", errdefs.ErrFailedPrecondition)
+ }
+
+ p, err := s.blobPath(info.Digest)
+ if err != nil {
+ return content.Info{}, fmt.Errorf("calculating blob path for update: %w", err)
+ }
+
+ fi, err := os.Stat(p)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = fmt.Errorf("content %v: %w", info.Digest, errdefs.ErrNotFound)
+ }
+
+ return content.Info{}, err
+ }
+
+ var (
+ all bool
+ labels map[string]string
+ )
+ if len(fieldpaths) > 0 {
+ for _, path := range fieldpaths {
+ if strings.HasPrefix(path, "labels.") {
+ if labels == nil {
+ labels = map[string]string{}
+ }
+
+ key := strings.TrimPrefix(path, "labels.")
+ labels[key] = info.Labels[key]
+ continue
+ }
+
+ switch path {
+ case "labels":
+ all = true
+ labels = info.Labels
+ default:
+ return content.Info{}, fmt.Errorf("cannot update %q field on content info %q: %w", path, info.Digest, errdefs.ErrInvalidArgument)
+ }
+ }
+ } else {
+ all = true
+ labels = info.Labels
+ }
+
+ if all {
+ err = s.ls.Set(info.Digest, labels)
+ } else {
+ labels, err = s.ls.Update(info.Digest, labels)
+ }
+ if err != nil {
+ return content.Info{}, err
+ }
+
+ info = s.info(info.Digest, fi, labels)
+ info.UpdatedAt = time.Now()
+
+ if err := os.Chtimes(p, info.UpdatedAt, info.CreatedAt); err != nil {
+ log.G(ctx).WithError(err).Warnf("could not change access time for %s", info.Digest)
+ }
+
+ return info, nil
+}
+
+func (s *store) Walk(ctx context.Context, fn content.WalkFunc, fs ...string) error {
+ root := filepath.Join(s.root, "blobs")
+
+ filter, err := filters.ParseAll(fs...)
+ if err != nil {
+ return err
+ }
+
+ var alg digest.Algorithm
+ return filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if !fi.IsDir() && !alg.Available() {
+ return nil
+ }
+
+ // TODO(stevvooe): There are few more cases with subdirs that should be
+ // handled in case the layout gets corrupted. This isn't strict enough
+ // and may spew bad data.
+
+ if path == root {
+ return nil
+ }
+ if filepath.Dir(path) == root {
+ alg = digest.Algorithm(filepath.Base(path))
+
+ if !alg.Available() {
+ alg = ""
+ return filepath.SkipDir
+ }
+
+ // descending into a hash directory
+ return nil
+ }
+
+ dgst := digest.NewDigestFromEncoded(alg, filepath.Base(path))
+ if err := dgst.Validate(); err != nil {
+ // log error but don't report
+ log.L.WithError(err).WithField("path", path).Error("invalid digest for blob path")
+ // if we see this, it could mean some sort of corruption of the
+ // store or extra paths not expected previously.
+ }
+
+ var labels map[string]string
+ if s.ls != nil {
+ labels, err = s.ls.Get(dgst)
+ if err != nil {
+ return err
+ }
+ }
+
+ info := s.info(dgst, fi, labels)
+ if !filter.Match(content.AdaptInfo(info)) {
+ return nil
+ }
+ return fn(info)
+ })
+}
+
+func (s *store) Status(ctx context.Context, ref string) (content.Status, error) {
+ return s.status(s.ingestRoot(ref))
+}
+
+func (s *store) ListStatuses(ctx context.Context, fs ...string) ([]content.Status, error) {
+ fp, err := os.Open(filepath.Join(s.root, "ingest"))
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ defer fp.Close()
+
+ fis, err := fp.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+
+ filter, err := filters.ParseAll(fs...)
+ if err != nil {
+ return nil, err
+ }
+
+ var active []content.Status
+ for _, fi := range fis {
+ p := filepath.Join(s.root, "ingest", fi)
+ stat, err := s.status(p)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ return nil, err
+ }
+
+ // TODO(stevvooe): This is a common error if uploads are being
+ // completed while making this listing. Need to consider taking a
+ // lock on the whole store to coordinate this aspect.
+ //
+ // Another option is to cleanup downloads asynchronously and
+ // coordinate this method with the cleanup process.
+ //
+ // For now, we just skip them, as they really don't exist.
+ continue
+ }
+
+ if filter.Match(adaptStatus(stat)) {
+ active = append(active, stat)
+ }
+ }
+
+ return active, nil
+}
+
+// WalkStatusRefs is used to walk all status references
+// Failed status reads will be logged and ignored, if
+// this function is called while references are being altered,
+// these error messages may be produced.
+func (s *store) WalkStatusRefs(ctx context.Context, fn func(string) error) error {
+ fp, err := os.Open(filepath.Join(s.root, "ingest"))
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+ defer fp.Close()
+
+ fis, err := fp.Readdirnames(-1)
+ if err != nil {
+ return err
+ }
+
+ for _, fi := range fis {
+ rf := filepath.Join(s.root, "ingest", fi, "ref")
+
+ ref, err := readFileString(rf)
+ if err != nil {
+ log.G(ctx).WithError(err).WithField("path", rf).Error("failed to read ingest ref")
+ continue
+ }
+
+ if err := fn(ref); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// status works like stat above except uses the path to the ingest.
+func (s *store) status(ingestPath string) (content.Status, error) {
+ dp := filepath.Join(ingestPath, "data")
+ fi, err := os.Stat(dp)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
+ }
+ return content.Status{}, err
+ }
+
+ ref, err := readFileString(filepath.Join(ingestPath, "ref"))
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
+ }
+ return content.Status{}, err
+ }
+
+ startedAt, err := readFileTimestamp(filepath.Join(ingestPath, "startedat"))
+ if err != nil {
+ return content.Status{}, fmt.Errorf("could not read startedat: %w", err)
+ }
+
+ updatedAt, err := readFileTimestamp(filepath.Join(ingestPath, "updatedat"))
+ if err != nil {
+ return content.Status{}, fmt.Errorf("could not read updatedat: %w", err)
+ }
+
+ // because we don't write updatedat on every write, the mod time may
+ // actually be more up to date.
+ if fi.ModTime().After(updatedAt) {
+ updatedAt = fi.ModTime()
+ }
+
+ return content.Status{
+ Ref: ref,
+ Offset: fi.Size(),
+ Total: s.total(ingestPath),
+ UpdatedAt: updatedAt,
+ StartedAt: startedAt,
+ }, nil
+}
+
+func adaptStatus(status content.Status) filters.Adaptor {
+ return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
+ if len(fieldpath) == 0 {
+ return "", false
+ }
+ switch fieldpath[0] {
+ case "ref":
+ return status.Ref, true
+ }
+
+ return "", false
+ })
+}
+
+// total attempts to resolve the total expected size for the write.
+func (s *store) total(ingestPath string) int64 {
+ totalS, err := readFileString(filepath.Join(ingestPath, "total"))
+ if err != nil {
+ return 0
+ }
+
+ total, err := strconv.ParseInt(totalS, 10, 64)
+ if err != nil {
+ // represents a corrupted file, should probably remove.
+ return 0
+ }
+
+ return total
+}
+
+// Writer begins or resumes the active writer identified by ref. If the writer
+// is already in use, an error is returned. Only one writer may be in use per
+// ref at a time.
+//
+// The argument `ref` is used to uniquely identify a long-lived writer transaction.
+func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
+ var wOpts content.WriterOpts
+ for _, opt := range opts {
+ if err := opt(&wOpts); err != nil {
+ return nil, err
+ }
+ }
+ // TODO(AkihiroSuda): we could create a random string or one calculated based on the context
+ // https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
+ if wOpts.Ref == "" {
+ return nil, fmt.Errorf("ref must not be empty: %w", errdefs.ErrInvalidArgument)
+ }
+
+ if err := s.tryLock(wOpts.Ref); err != nil {
+ return nil, err
+ }
+
+ w, err := s.writer(ctx, wOpts.Ref, wOpts.Desc.Size, wOpts.Desc.Digest)
+ if err != nil {
+ s.unlock(wOpts.Ref)
+ return nil, err
+ }
+
+ return w, nil // lock is now held by w.
+}
+
+func (s *store) resumeStatus(ref string, total int64, digester digest.Digester) (content.Status, error) {
+ path, _, data := s.ingestPaths(ref)
+ status, err := s.status(path)
+ if err != nil {
+ return status, fmt.Errorf("failed reading status of resume write: %w", err)
+ }
+ if ref != status.Ref {
+ // NOTE(stevvooe): This is fairly catastrophic. Either we have some
+ // layout corruption or a hash collision for the ref key.
+ return status, fmt.Errorf("ref key does not match: %v != %v", ref, status.Ref)
+ }
+
+ if total > 0 && status.Total > 0 && total != status.Total {
+ return status, fmt.Errorf("provided total differs from status: %v != %v", total, status.Total)
+ }
+
+ //nolint:dupword
+ // TODO(stevvooe): slow slow slow!!, send to goroutine or use resumable hashes
+ fp, err := os.Open(data)
+ if err != nil {
+ return status, err
+ }
+
+ p := bufPool.Get().(*[]byte)
+ status.Offset, err = io.CopyBuffer(digester.Hash(), fp, *p)
+ bufPool.Put(p)
+ fp.Close()
+ return status, err
+}
+
+// writer provides the main implementation of the Writer method. The caller
+// must hold the lock correctly and release on error if there is a problem.
+func (s *store) writer(ctx context.Context, ref string, total int64, expected digest.Digest) (content.Writer, error) {
+ // TODO(stevvooe): Need to actually store expected here. We have
+ // code in the service that shouldn't be dealing with this.
+ if expected != "" {
+ p, err := s.blobPath(expected)
+ if err != nil {
+ return nil, fmt.Errorf("calculating expected blob path for writer: %w", err)
+ }
+ if _, err := os.Stat(p); err == nil {
+ return nil, fmt.Errorf("content %v: %w", expected, errdefs.ErrAlreadyExists)
+ }
+ }
+
+ path, refp, data := s.ingestPaths(ref)
+
+ var (
+ digester = digest.Canonical.Digester()
+ offset int64
+ startedAt time.Time
+ updatedAt time.Time
+ )
+
+ foundValidIngest := false
+
+ if err := s.ensureIngestRootOnce(); err != nil {
+ return nil, err
+ }
+
+ // ensure that the ingest path has been created.
+ if err := os.Mkdir(path, 0755); err != nil {
+ if !os.IsExist(err) {
+ return nil, err
+ }
+ status, err := s.resumeStatus(ref, total, digester)
+ if err == nil {
+ foundValidIngest = true
+ updatedAt = status.UpdatedAt
+ startedAt = status.StartedAt
+ total = status.Total
+ offset = status.Offset
+ } else {
+ log.G(ctx).Infof("failed to resume the status from path %s: %s. will recreate them", path, err.Error())
+ }
+ }
+
+ if !foundValidIngest {
+ startedAt = time.Now()
+ updatedAt = startedAt
+
+ // the ingest is new, we need to setup the target location.
+ // write the ref to a file for later use
+ if err := os.WriteFile(refp, []byte(ref), 0666); err != nil {
+ return nil, err
+ }
+
+ if err := writeTimestampFile(filepath.Join(path, "startedat"), startedAt); err != nil {
+ return nil, err
+ }
+
+ if err := writeTimestampFile(filepath.Join(path, "updatedat"), startedAt); err != nil {
+ return nil, err
+ }
+
+ if total > 0 {
+ if err := os.WriteFile(filepath.Join(path, "total"), []byte(fmt.Sprint(total)), 0666); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ fp, err := os.OpenFile(data, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open data file: %w", err)
+ }
+
+ if _, err := fp.Seek(offset, io.SeekStart); err != nil {
+ fp.Close()
+ return nil, fmt.Errorf("could not seek to current write offset: %w", err)
+ }
+
+ return &writer{
+ s: s,
+ fp: fp,
+ ref: ref,
+ path: path,
+ offset: offset,
+ total: total,
+ digester: digester,
+ startedAt: startedAt,
+ updatedAt: updatedAt,
+ }, nil
+}
+
+// Abort an active transaction keyed by ref. If the ingest is active, it will
+// be cancelled. Any resources associated with the ingest will be cleaned.
+func (s *store) Abort(ctx context.Context, ref string) error {
+ root := s.ingestRoot(ref)
+ if err := os.RemoveAll(root); err != nil {
+ if os.IsNotExist(err) {
+ return fmt.Errorf("ingest ref %q: %w", ref, errdefs.ErrNotFound)
+ }
+
+ return err
+ }
+
+ return nil
+}
+
+func (s *store) blobPath(dgst digest.Digest) (string, error) {
+ if err := dgst.Validate(); err != nil {
+ return "", fmt.Errorf("cannot calculate blob path from invalid digest: %v: %w", err, errdefs.ErrInvalidArgument)
+ }
+
+ return filepath.Join(s.root, "blobs", dgst.Algorithm().String(), dgst.Encoded()), nil
+}
+
+func (s *store) ingestRoot(ref string) string {
+ // we take a digest of the ref to keep the ingest paths constant length.
+ // Note that this is not the current or potential digest of incoming content.
+ dgst := digest.FromString(ref)
+ return filepath.Join(s.root, "ingest", dgst.Encoded())
+}
+
+// ingestPaths are returned. The paths are the following:
+//
+// - root: entire ingest directory
+// - ref: name of the starting ref, must be unique
+// - data: file where data is written
+func (s *store) ingestPaths(ref string) (string, string, string) {
+ var (
+ fp = s.ingestRoot(ref)
+ rp = filepath.Join(fp, "ref")
+ dp = filepath.Join(fp, "data")
+ )
+
+ return fp, rp, dp
+}
+
+func (s *store) ensureIngestRoot() error {
+ return os.MkdirAll(filepath.Join(s.root, "ingest"), 0777)
+}
+
+func readFileString(path string) (string, error) {
+ p, err := os.ReadFile(path)
+ return string(p), err
+}
+
+// readFileTimestamp reads a file with just a timestamp present.
+func readFileTimestamp(p string) (time.Time, error) {
+ b, err := os.ReadFile(p)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
+ }
+ return time.Time{}, err
+ }
+
+ var t time.Time
+ if err := t.UnmarshalText(b); err != nil {
+ return time.Time{}, fmt.Errorf("could not parse timestamp file %v: %w", p, err)
+ }
+
+ return t, nil
+}
+
+func writeTimestampFile(p string, t time.Time) error {
+ b, err := t.MarshalText()
+ if err != nil {
+ return err
+ }
+ return writeToCompletion(p, b, 0666)
+}
+
+func writeToCompletion(path string, data []byte, mode os.FileMode) error {
+ tmp := fmt.Sprintf("%s.tmp", path)
+ f, err := os.OpenFile(tmp, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, mode)
+ if err != nil {
+ return fmt.Errorf("create tmp file: %w", err)
+ }
+ _, err = f.Write(data)
+ f.Close()
+ if err != nil {
+ return fmt.Errorf("write tmp file: %w", err)
+ }
+ err = os.Rename(tmp, path)
+ if err != nil {
+ return fmt.Errorf("rename tmp file: %w", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/content/local/store_bsd.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store_bsd.go
similarity index 96%
rename from vendor/github.com/containerd/containerd/content/local/store_bsd.go
rename to vendor/github.com/containerd/containerd/v2/plugins/content/local/store_bsd.go
index 42fddd3411..7dcc192327 100644
--- a/vendor/github.com/containerd/containerd/content/local/store_bsd.go
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store_bsd.go
@@ -1,5 +1,4 @@
//go:build darwin || freebsd || netbsd
-// +build darwin freebsd netbsd
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/containerd/content/local/store_openbsd.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store_openbsd.go
similarity index 97%
rename from vendor/github.com/containerd/containerd/content/local/store_openbsd.go
rename to vendor/github.com/containerd/containerd/v2/plugins/content/local/store_openbsd.go
index 2b58b617b9..45dfa9997e 100644
--- a/vendor/github.com/containerd/containerd/content/local/store_openbsd.go
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store_openbsd.go
@@ -1,5 +1,4 @@
//go:build openbsd
-// +build openbsd
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/containerd/content/local/store_unix.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store_unix.go
similarity index 97%
rename from vendor/github.com/containerd/containerd/content/local/store_unix.go
rename to vendor/github.com/containerd/containerd/v2/plugins/content/local/store_unix.go
index efa2eb9430..cb01c91c7f 100644
--- a/vendor/github.com/containerd/containerd/content/local/store_unix.go
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store_unix.go
@@ -1,5 +1,4 @@
//go:build linux || solaris
-// +build linux solaris
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/containerd/content/local/store_windows.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/store_windows.go
similarity index 100%
rename from vendor/github.com/containerd/containerd/content/local/store_windows.go
rename to vendor/github.com/containerd/containerd/v2/plugins/content/local/store_windows.go
diff --git a/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer.go
new file mode 100644
index 0000000000..2e12233098
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer.go
@@ -0,0 +1,229 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package local
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime"
+ "time"
+
+ "github.com/containerd/errdefs"
+ "github.com/containerd/log"
+ "github.com/opencontainers/go-digest"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/internal/fsverity"
+)
+
+// writer represents a write transaction against the blob store.
+type writer struct {
+ s *store
+ fp *os.File // opened data file
+ path string // path to writer dir
+ ref string // ref key
+ offset int64
+ total int64
+ digester digest.Digester
+ startedAt time.Time
+ updatedAt time.Time
+}
+
+func (w *writer) Status() (content.Status, error) {
+ return content.Status{
+ Ref: w.ref,
+ Offset: w.offset,
+ Total: w.total,
+ StartedAt: w.startedAt,
+ UpdatedAt: w.updatedAt,
+ }, nil
+}
+
+// Digest returns the current digest of the content, up to the current write.
+//
+// Cannot be called concurrently with `Write`.
+func (w *writer) Digest() digest.Digest {
+ return w.digester.Digest()
+}
+
+// Write p to the transaction.
+//
+// Note that writes are unbuffered to the backing file. When writing, it is
+// recommended to wrap in a bufio.Writer or, preferably, use io.CopyBuffer.
+func (w *writer) Write(p []byte) (n int, err error) {
+ n, err = w.fp.Write(p)
+ w.digester.Hash().Write(p[:n])
+ w.offset += int64(len(p))
+ w.updatedAt = time.Now()
+ return n, err
+}
+
+func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
+ // Ensure even on error the writer is fully closed
+ defer w.s.unlock(w.ref)
+
+ var base content.Info
+ for _, opt := range opts {
+ if err := opt(&base); err != nil {
+ return err
+ }
+ }
+
+ fp := w.fp
+ w.fp = nil
+
+ if fp == nil {
+ return fmt.Errorf("cannot commit on closed writer: %w", errdefs.ErrFailedPrecondition)
+ }
+
+ if err := fp.Sync(); err != nil {
+ fp.Close()
+ return fmt.Errorf("sync failed: %w", err)
+ }
+
+ fi, err := fp.Stat()
+ closeErr := fp.Close()
+ if err != nil {
+ return fmt.Errorf("stat on ingest file failed: %w", err)
+ }
+ if closeErr != nil {
+ return fmt.Errorf("failed to close ingest file: %w", closeErr)
+ }
+
+ if size > 0 && size != fi.Size() {
+ return fmt.Errorf("unexpected commit size %d, expected %d: %w", fi.Size(), size, errdefs.ErrFailedPrecondition)
+ }
+
+ dgst := w.digester.Digest()
+ if expected != "" && expected != dgst {
+ return fmt.Errorf("unexpected commit digest %s, expected %s: %w", dgst, expected, errdefs.ErrFailedPrecondition)
+ }
+
+ var (
+ ingest = filepath.Join(w.path, "data")
+ target, _ = w.s.blobPath(dgst) // ignore error because we calculated this dgst
+ )
+
+ // make sure parent directories of blob exist
+ if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
+ return err
+ }
+
+ if _, err := os.Stat(target); err == nil {
+ // collision with the target file!
+ if err := os.RemoveAll(w.path); err != nil {
+ log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Error("failed to remove ingest directory")
+ }
+ return fmt.Errorf("content %v: %w", dgst, errdefs.ErrAlreadyExists)
+ }
+
+ if err := os.Rename(ingest, target); err != nil {
+ return err
+ }
+
+ if err := syncDir(filepath.Dir(target)); err != nil {
+ return err
+ }
+ // Enable content blob integrity verification if supported
+
+ if w.s.integritySupported {
+ if err := fsverity.Enable(target); err != nil {
+ log.G(ctx).Warnf("failed to enable integrity for blob %v: %s", target, err.Error())
+ }
+ }
+
+ // Ingest has now been made available in the content store, attempt to complete
+ // setting metadata but errors should only be logged and not returned since
+ // the content store cannot be cleanly rolled back.
+
+ commitTime := time.Now()
+ if err := os.Chtimes(target, commitTime, commitTime); err != nil {
+ log.G(ctx).WithField("digest", dgst).Error("failed to change file time to commit time")
+ }
+
+ // clean up!!
+ if err := os.RemoveAll(w.path); err != nil {
+ log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Error("failed to remove ingest directory")
+ }
+
+ if w.s.ls != nil && base.Labels != nil {
+ if err := w.s.ls.Set(dgst, base.Labels); err != nil {
+ log.G(ctx).WithField("digest", dgst).Error("failed to set labels")
+ }
+ }
+
+ // change to readonly, more important for read, but provides _some_
+ // protection from this point on. We use the existing perms with a mask
+ // only allowing reads honoring the umask on creation.
+ //
+ // This removes write and exec, only allowing read per the creation umask.
+ //
+ // NOTE: Windows does not support this operation
+ if runtime.GOOS != "windows" {
+ if err := os.Chmod(target, (fi.Mode()&os.ModePerm)&^0333); err != nil {
+ log.G(ctx).WithField("ref", w.ref).Error("failed to make readonly")
+ }
+ }
+
+ return nil
+}
+
+// Close the writer, flushing any unwritten data and leaving the progress in
+// tact.
+//
+// If one needs to resume the transaction, a new writer can be obtained from
+// `Ingester.Writer` using the same key. The write can then be continued
+// from it was left off.
+//
+// To abandon a transaction completely, first call close then `IngestManager.Abort` to
+// clean up the associated resources.
+func (w *writer) Close() (err error) {
+ if w.fp != nil {
+ w.fp.Sync()
+ err = w.fp.Close()
+ writeTimestampFile(filepath.Join(w.path, "updatedat"), w.updatedAt)
+ w.fp = nil
+ w.s.unlock(w.ref)
+ return
+ }
+
+ return nil
+}
+
+func (w *writer) Truncate(size int64) error {
+ if size != 0 {
+ return errors.New("Truncate: unsupported size")
+ }
+ w.offset = 0
+ w.digester.Hash().Reset()
+ if _, err := w.fp.Seek(0, io.SeekStart); err != nil {
+ return err
+ }
+ return w.fp.Truncate(0)
+}
+
+func (w *writer) Sync() error {
+ if w.fp != nil {
+ return w.fp.Sync()
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer_unix.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer_unix.go
new file mode 100644
index 0000000000..aafd294e9a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer_unix.go
@@ -0,0 +1,37 @@
+//go:build !windows
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package local
+
+import (
+ "fmt"
+ "os"
+)
+
+func syncDir(dir string) error {
+ dirF, err := os.Open(dir)
+ if err != nil {
+ return fmt.Errorf("failed to open dir %s: %w", dir, err)
+ }
+ err = dirF.Sync()
+ dirF.Close()
+ if err != nil {
+ return fmt.Errorf("failed to sync dir %s: %w", dir, err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer_windows.go b/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer_windows.go
new file mode 100644
index 0000000000..7e1ef186b7
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/plugins/content/local/writer_windows.go
@@ -0,0 +1,22 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package local
+
+// sync dir doesn't support in windows
+func syncDir(dir string) error {
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/services/content/contentserver/contentserver.go b/vendor/github.com/containerd/containerd/v2/plugins/services/content/contentserver/contentserver.go
similarity index 76%
rename from vendor/github.com/containerd/containerd/services/content/contentserver/contentserver.go
rename to vendor/github.com/containerd/containerd/v2/plugins/services/content/contentserver/contentserver.go
index eb5855a476..cfa00bf4bd 100644
--- a/vendor/github.com/containerd/containerd/services/content/contentserver/contentserver.go
+++ b/vendor/github.com/containerd/containerd/v2/plugins/services/content/contentserver/contentserver.go
@@ -23,28 +23,33 @@ import (
"sync"
api "github.com/containerd/containerd/api/services/content/v1"
- "github.com/containerd/containerd/content"
- "github.com/containerd/containerd/errdefs"
- "github.com/containerd/containerd/log"
- ptypes "github.com/gogo/protobuf/types"
+ "github.com/containerd/errdefs/pkg/errgrpc"
+ "github.com/containerd/log"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
+
+ "github.com/containerd/containerd/v2/core/content"
+ "github.com/containerd/containerd/v2/pkg/protobuf"
+ ptypes "github.com/containerd/containerd/v2/pkg/protobuf/types"
)
type service struct {
store content.Store
+ api.UnimplementedContentServer
}
-var bufPool = sync.Pool{
- New: func() interface{} {
- buffer := make([]byte, 1<<20)
- return &buffer
- },
-}
+var (
+ empty = &ptypes.Empty{}
+ bufPool = sync.Pool{
+ New: func() interface{} {
+ buffer := make([]byte, 1<<20)
+ return &buffer
+ },
+ }
+)
// New returns the content GRPC server
func New(cs content.Store) api.ContentServer {
@@ -57,13 +62,14 @@ func (s *service) Register(server *grpc.Server) error {
}
func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) {
- if err := req.Digest.Validate(); err != nil {
+ dg, err := digest.Parse(req.Digest)
+ if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest)
}
- bi, err := s.store.Info(ctx, req.Digest)
+ bi, err := s.store.Info(ctx, dg)
if err != nil {
- return nil, errdefs.ToGRPC(err)
+ return nil, errgrpc.ToGRPC(err)
}
return &api.InfoResponse{
@@ -72,13 +78,14 @@ func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResp
}
func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) {
- if err := req.Info.Digest.Validate(); err != nil {
+ _, err := digest.Parse(req.Info.Digest)
+ if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest)
}
info, err := s.store.Update(ctx, infoFromGRPC(req.Info), req.UpdateMask.GetPaths()...)
if err != nil {
- return nil, errdefs.ToGRPC(err)
+ return nil, errgrpc.ToGRPC(err)
}
return &api.UpdateResponse{
@@ -88,8 +95,8 @@ func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.Upda
func (s *service) List(req *api.ListContentRequest, session api.Content_ListServer) error {
var (
- buffer []api.Info
- sendBlock = func(block []api.Info) error {
+ buffer []*api.Info
+ sendBlock = func(block []*api.Info) error {
// send last block
return session.Send(&api.ListContentResponse{
Info: block,
@@ -98,12 +105,7 @@ func (s *service) List(req *api.ListContentRequest, session api.Content_ListServ
)
if err := s.store.Walk(session.Context(), func(info content.Info) error {
- buffer = append(buffer, api.Info{
- Digest: info.Digest,
- Size_: info.Size,
- CreatedAt: info.CreatedAt,
- Labels: info.Labels,
- })
+ buffer = append(buffer, infoToGRPC(info))
if len(buffer) >= 100 {
if err := sendBlock(buffer); err != nil {
@@ -115,7 +117,7 @@ func (s *service) List(req *api.ListContentRequest, session api.Content_ListServ
return nil
}, req.Filters...); err != nil {
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
if len(buffer) > 0 {
@@ -130,30 +132,32 @@ func (s *service) List(req *api.ListContentRequest, session api.Content_ListServ
func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*ptypes.Empty, error) {
log.G(ctx).WithField("digest", req.Digest).Debugf("delete content")
- if err := req.Digest.Validate(); err != nil {
- return nil, status.Errorf(codes.InvalidArgument, err.Error())
+ dg, err := digest.Parse(req.Digest)
+ if err != nil {
+ return nil, status.Error(codes.InvalidArgument, err.Error())
}
- if err := s.store.Delete(ctx, req.Digest); err != nil {
- return nil, errdefs.ToGRPC(err)
+ if err := s.store.Delete(ctx, dg); err != nil {
+ return nil, errgrpc.ToGRPC(err)
}
- return &ptypes.Empty{}, nil
+ return empty, nil
}
func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error {
- if err := req.Digest.Validate(); err != nil {
+ dg, err := digest.Parse(req.Digest)
+ if err != nil {
return status.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err)
}
- oi, err := s.store.Info(session.Context(), req.Digest)
+ oi, err := s.store.Info(session.Context(), dg)
if err != nil {
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
- ra, err := s.store.ReaderAt(session.Context(), ocispec.Descriptor{Digest: req.Digest})
+ ra, err := s.store.ReaderAt(session.Context(), ocispec.Descriptor{Digest: dg})
if err != nil {
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
defer ra.Close()
@@ -161,7 +165,7 @@ func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServ
offset = req.Offset
// size is read size, not the expected size of the blob (oi.Size), which the caller might not be aware of.
// offset+size can be larger than oi.Size.
- size = req.Size_
+ size = req.Size
// TODO(stevvooe): Using the global buffer pool. At 32KB, it is probably
// little inefficient for work over a fast network. We can tune this later.
@@ -184,7 +188,7 @@ func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServ
_, err = io.CopyBuffer(
&readResponseWriter{session: session},
io.NewSectionReader(ra, offset, size), *p)
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
// readResponseWriter is a writer that places the output into ReadContentRequest messages.
@@ -211,17 +215,17 @@ func (rw *readResponseWriter) Write(p []byte) (n int, err error) {
func (s *service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) {
status, err := s.store.Status(ctx, req.Ref)
if err != nil {
- return nil, errdefs.ToGRPCf(err, "could not get status for ref %q", req.Ref)
+ return nil, errgrpc.ToGRPCf(err, "could not get status for ref %q", req.Ref)
}
var resp api.StatusResponse
resp.Status = &api.Status{
- StartedAt: status.StartedAt,
- UpdatedAt: status.UpdatedAt,
+ StartedAt: protobuf.ToTimestamp(status.StartedAt),
+ UpdatedAt: protobuf.ToTimestamp(status.UpdatedAt),
Ref: status.Ref,
Offset: status.Offset,
Total: status.Total,
- Expected: status.Expected,
+ Expected: status.Expected.String(),
}
return &resp, nil
@@ -230,18 +234,18 @@ func (s *service) Status(ctx context.Context, req *api.StatusRequest) (*api.Stat
func (s *service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest) (*api.ListStatusesResponse, error) {
statuses, err := s.store.ListStatuses(ctx, req.Filters...)
if err != nil {
- return nil, errdefs.ToGRPC(err)
+ return nil, errgrpc.ToGRPC(err)
}
var resp api.ListStatusesResponse
for _, status := range statuses {
- resp.Statuses = append(resp.Statuses, api.Status{
- StartedAt: status.StartedAt,
- UpdatedAt: status.UpdatedAt,
+ resp.Statuses = append(resp.Statuses, &api.Status{
+ StartedAt: protobuf.ToTimestamp(status.StartedAt),
+ UpdatedAt: protobuf.ToTimestamp(status.UpdatedAt),
Ref: status.Ref,
Offset: status.Offset,
Total: status.Total,
- Expected: status.Expected,
+ Expected: status.Expected.String(),
})
}
@@ -289,11 +293,11 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
return status.Errorf(codes.InvalidArgument, "first message must have a reference")
}
- fields := logrus.Fields{
+ fields := log.Fields{
"ref": ref,
}
total = req.Total
- expected = req.Expected
+ expected = digest.Digest(req.Expected)
if total > 0 {
fields["total"] = total
}
@@ -310,7 +314,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
content.WithRef(ref),
content.WithDescriptor(ocispec.Descriptor{Size: total, Digest: expected}))
if err != nil {
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
defer wr.Close()
@@ -318,7 +322,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
msg.Action = req.Action
ws, err := wr.Status()
if err != nil {
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
msg.Offset = ws.Offset // always set the offset.
@@ -341,12 +345,13 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
// Supporting these two paths is quite awkward but it lets both API
// users use the same writer style for each with a minimum of overhead.
if req.Expected != "" {
- if expected != "" && expected != req.Expected {
- log.G(ctx).Debugf("commit digest differs from writer digest: %v != %v", req.Expected, expected)
+ dg := digest.Digest(req.Expected)
+ if expected != "" && expected != dg {
+ log.G(ctx).Debugf("commit digest differs from writer digest: %v != %v", dg, expected)
}
- expected = req.Expected
+ expected = dg
- if _, err := s.store.Info(session.Context(), req.Expected); err == nil {
+ if _, err := s.store.Info(session.Context(), dg); err == nil {
if err := wr.Close(); err != nil {
log.G(ctx).WithError(err).Error("failed to close writer")
}
@@ -368,12 +373,12 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
}
switch req.Action {
- case api.WriteActionStat:
- msg.Digest = wr.Digest()
- msg.StartedAt = ws.StartedAt
- msg.UpdatedAt = ws.UpdatedAt
+ case api.WriteAction_STAT:
+ msg.Digest = wr.Digest().String()
+ msg.StartedAt = protobuf.ToTimestamp(ws.StartedAt)
+ msg.UpdatedAt = protobuf.ToTimestamp(ws.UpdatedAt)
msg.Total = total
- case api.WriteActionWrite, api.WriteActionCommit:
+ case api.WriteAction_WRITE, api.WriteAction_COMMIT:
if req.Offset > 0 {
// validate the offset if provided
if req.Offset != ws.Offset {
@@ -394,7 +399,7 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
// maintain the offset as append only, we just issue the write.
n, err := wr.Write(req.Data)
if err != nil {
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
if n != len(req.Data) {
@@ -406,24 +411,24 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
msg.Offset += int64(n)
}
- if req.Action == api.WriteActionCommit {
+ if req.Action == api.WriteAction_COMMIT {
var opts []content.Opt
if req.Labels != nil {
opts = append(opts, content.WithLabels(req.Labels))
}
if err := wr.Commit(ctx, total, expected, opts...); err != nil {
- return errdefs.ToGRPC(err)
+ return errgrpc.ToGRPC(err)
}
}
- msg.Digest = wr.Digest()
+ msg.Digest = wr.Digest().String()
}
if err := session.Send(&msg); err != nil {
return err
}
- if req.Action == api.WriteActionCommit {
+ if req.Action == api.WriteAction_COMMIT {
return nil
}
@@ -440,28 +445,28 @@ func (s *service) Write(session api.Content_WriteServer) (err error) {
func (s *service) Abort(ctx context.Context, req *api.AbortRequest) (*ptypes.Empty, error) {
if err := s.store.Abort(ctx, req.Ref); err != nil {
- return nil, errdefs.ToGRPC(err)
+ return nil, errgrpc.ToGRPC(err)
}
- return &ptypes.Empty{}, nil
+ return empty, nil
}
-func infoToGRPC(info content.Info) api.Info {
- return api.Info{
- Digest: info.Digest,
- Size_: info.Size,
- CreatedAt: info.CreatedAt,
- UpdatedAt: info.UpdatedAt,
+func infoToGRPC(info content.Info) *api.Info {
+ return &api.Info{
+ Digest: info.Digest.String(),
+ Size: info.Size,
+ CreatedAt: protobuf.ToTimestamp(info.CreatedAt),
+ UpdatedAt: protobuf.ToTimestamp(info.UpdatedAt),
Labels: info.Labels,
}
}
-func infoFromGRPC(info api.Info) content.Info {
+func infoFromGRPC(info *api.Info) content.Info {
return content.Info{
- Digest: info.Digest,
- Size: info.Size_,
- CreatedAt: info.CreatedAt,
- UpdatedAt: info.UpdatedAt,
+ Digest: digest.Digest(info.Digest),
+ Size: info.Size,
+ CreatedAt: protobuf.FromTimestamp(info.CreatedAt),
+ UpdatedAt: protobuf.FromTimestamp(info.UpdatedAt),
Labels: info.Labels,
}
}
diff --git a/vendor/github.com/containerd/containerd/v2/version/version.go b/vendor/github.com/containerd/containerd/v2/version/version.go
new file mode 100644
index 0000000000..d915fb9a30
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/v2/version/version.go
@@ -0,0 +1,41 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package version
+
+import "runtime"
+
+var (
+ Name = "containerd"
+ // Package is filled at linking time
+ Package = "github.com/containerd/containerd/v2"
+
+ // Version holds the complete version number. Filled in at linking time.
+ Version = "2.2.4+unknown"
+
+ // Revision is filled with the VCS (e.g. git) revision being used to build
+ // the program at linking time.
+ Revision = ""
+
+ // GoVersion is Go tree's version.
+ GoVersion = runtime.Version()
+)
+
+// ConfigVersion is the current highest supported configuration version.
+// This version is used by the main configuration as well as all plugins.
+// Any configuration less than this version which has structural changes
+// should migrate the configuration structures used by this version.
+const ConfigVersion = 3
diff --git a/vendor/github.com/containerd/containerd/version/version.go b/vendor/github.com/containerd/containerd/version/version.go
deleted file mode 100644
index ca1b6773ab..0000000000
--- a/vendor/github.com/containerd/containerd/version/version.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package version
-
-import "runtime"
-
-var (
- // Package is filled at linking time
- Package = "github.com/containerd/containerd"
-
- // Version holds the complete version number. Filled in at linking time.
- Version = "1.6.18+unknown"
-
- // Revision is filled with the VCS (e.g. git) revision being used to build
- // the program at linking time.
- Revision = ""
-
- // GoVersion is Go tree's version.
- GoVersion = runtime.Version()
-)
diff --git a/vendor/github.com/containerd/continuity/fs/copy.go b/vendor/github.com/containerd/continuity/fs/copy.go
deleted file mode 100644
index 6982a761ba..0000000000
--- a/vendor/github.com/containerd/continuity/fs/copy.go
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "sync"
-
- "github.com/sirupsen/logrus"
-)
-
-var bufferPool = &sync.Pool{
- New: func() interface{} {
- buffer := make([]byte, 32*1024)
- return &buffer
- },
-}
-
-// XAttrErrorHandler transform a non-nil xattr error.
-// Return nil to ignore an error.
-// xattrKey can be empty for listxattr operation.
-type XAttrErrorHandler func(dst, src, xattrKey string, err error) error
-
-type copyDirOpts struct {
- xeh XAttrErrorHandler
- // xex contains a set of xattrs to exclude when copying
- xex map[string]struct{}
-}
-
-type CopyDirOpt func(*copyDirOpts) error
-
-// WithXAttrErrorHandler allows specifying XAttrErrorHandler
-// If nil XAttrErrorHandler is specified (default), CopyDir stops
-// on a non-nil xattr error.
-func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt {
- return func(o *copyDirOpts) error {
- o.xeh = xeh
- return nil
- }
-}
-
-// WithAllowXAttrErrors allows ignoring xattr errors.
-func WithAllowXAttrErrors() CopyDirOpt {
- xeh := func(dst, src, xattrKey string, err error) error {
- return nil
- }
- return WithXAttrErrorHandler(xeh)
-}
-
-// WithXAttrExclude allows for exclusion of specified xattr during CopyDir operation.
-func WithXAttrExclude(keys ...string) CopyDirOpt {
- return func(o *copyDirOpts) error {
- if o.xex == nil {
- o.xex = make(map[string]struct{}, len(keys))
- }
- for _, key := range keys {
- o.xex[key] = struct{}{}
- }
- return nil
- }
-}
-
-// CopyDir copies the directory from src to dst.
-// Most efficient copy of files is attempted.
-func CopyDir(dst, src string, opts ...CopyDirOpt) error {
- var o copyDirOpts
- for _, opt := range opts {
- if err := opt(&o); err != nil {
- return err
- }
- }
- inodes := map[uint64]string{}
- return copyDirectory(dst, src, inodes, &o)
-}
-
-func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error {
- stat, err := os.Stat(src)
- if err != nil {
- return fmt.Errorf("failed to stat %s: %w", src, err)
- }
- if !stat.IsDir() {
- return fmt.Errorf("source %s is not directory", src)
- }
-
- if st, err := os.Stat(dst); err != nil {
- if err := os.Mkdir(dst, stat.Mode()); err != nil {
- return fmt.Errorf("failed to mkdir %s: %w", dst, err)
- }
- } else if !st.IsDir() {
- return fmt.Errorf("cannot copy to non-directory: %s", dst)
- } else {
- if err := os.Chmod(dst, stat.Mode()); err != nil {
- return fmt.Errorf("failed to chmod on %s: %w", dst, err)
- }
- }
-
- fis, err := ioutil.ReadDir(src)
- if err != nil {
- return fmt.Errorf("failed to read %s: %w", src, err)
- }
-
- if err := copyFileInfo(stat, src, dst); err != nil {
- return fmt.Errorf("failed to copy file info for %s: %w", dst, err)
- }
-
- if err := copyXAttrs(dst, src, o.xex, o.xeh); err != nil {
- return fmt.Errorf("failed to copy xattrs: %w", err)
- }
-
- for _, fi := range fis {
- source := filepath.Join(src, fi.Name())
- target := filepath.Join(dst, fi.Name())
-
- switch {
- case fi.IsDir():
- if err := copyDirectory(target, source, inodes, o); err != nil {
- return err
- }
- continue
- case (fi.Mode() & os.ModeType) == 0:
- link, err := getLinkSource(target, fi, inodes)
- if err != nil {
- return fmt.Errorf("failed to get hardlink: %w", err)
- }
- if link != "" {
- if err := os.Link(link, target); err != nil {
- return fmt.Errorf("failed to create hard link: %w", err)
- }
- } else if err := CopyFile(target, source); err != nil {
- return fmt.Errorf("failed to copy files: %w", err)
- }
- case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink:
- link, err := os.Readlink(source)
- if err != nil {
- return fmt.Errorf("failed to read link: %s: %w", source, err)
- }
- if err := os.Symlink(link, target); err != nil {
- return fmt.Errorf("failed to create symlink: %s: %w", target, err)
- }
- case (fi.Mode() & os.ModeDevice) == os.ModeDevice,
- (fi.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe,
- (fi.Mode() & os.ModeSocket) == os.ModeSocket:
- if err := copyIrregular(target, fi); err != nil {
- return fmt.Errorf("failed to create irregular file: %w", err)
- }
- default:
- logrus.Warnf("unsupported mode: %s: %s", source, fi.Mode())
- continue
- }
-
- if err := copyFileInfo(fi, source, target); err != nil {
- return fmt.Errorf("failed to copy file info: %w", err)
- }
-
- if err := copyXAttrs(target, source, o.xex, o.xeh); err != nil {
- return fmt.Errorf("failed to copy xattrs: %w", err)
- }
- }
-
- return nil
-}
-
-// CopyFile copies the source file to the target.
-// The most efficient means of copying is used for the platform.
-func CopyFile(target, source string) error {
- src, err := os.Open(source)
- if err != nil {
- return fmt.Errorf("failed to open source %s: %w", source, err)
- }
- defer src.Close()
- tgt, err := os.Create(target)
- if err != nil {
- return fmt.Errorf("failed to open target %s: %w", target, err)
- }
- defer tgt.Close()
-
- return copyFileContent(tgt, src)
-}
diff --git a/vendor/github.com/containerd/continuity/fs/copy_irregular_freebsd.go b/vendor/github.com/containerd/continuity/fs/copy_irregular_freebsd.go
deleted file mode 100644
index cfe9d80204..0000000000
--- a/vendor/github.com/containerd/continuity/fs/copy_irregular_freebsd.go
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "fmt"
- "os"
- "syscall"
-)
-
-// copyIrregular covers devices, pipes, and sockets
-func copyIrregular(dst string, fi os.FileInfo) error {
- st, ok := fi.Sys().(*syscall.Stat_t) // not *unix.Stat_t
- if !ok {
- return fmt.Errorf("unsupported stat type: %s: %v", dst, fi.Mode())
- }
- var rDev uint64 // uint64 on FreeBSD, int on other unixen
- if fi.Mode()&os.ModeDevice == os.ModeDevice {
- rDev = st.Rdev
- }
- return syscall.Mknod(dst, uint32(st.Mode), rDev)
-}
diff --git a/vendor/github.com/containerd/continuity/fs/copy_irregular_unix.go b/vendor/github.com/containerd/continuity/fs/copy_irregular_unix.go
deleted file mode 100644
index 99fc8a9651..0000000000
--- a/vendor/github.com/containerd/continuity/fs/copy_irregular_unix.go
+++ /dev/null
@@ -1,40 +0,0 @@
-//go:build !windows && !freebsd
-// +build !windows,!freebsd
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "fmt"
- "os"
- "syscall"
-)
-
-// copyIrregular covers devices, pipes, and sockets
-func copyIrregular(dst string, fi os.FileInfo) error {
- st, ok := fi.Sys().(*syscall.Stat_t) // not *unix.Stat_t
- if !ok {
- return fmt.Errorf("unsupported stat type: %s: %v", dst, fi.Mode())
- }
- var rDev int
- if fi.Mode()&os.ModeDevice == os.ModeDevice {
- rDev = int(st.Rdev)
- }
- //nolint:unconvert
- return syscall.Mknod(dst, uint32(st.Mode), rDev)
-}
diff --git a/vendor/github.com/containerd/continuity/fs/copy_linux.go b/vendor/github.com/containerd/continuity/fs/copy_linux.go
deleted file mode 100644
index 1906e5e011..0000000000
--- a/vendor/github.com/containerd/continuity/fs/copy_linux.go
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "fmt"
- "io"
- "os"
- "syscall"
-
- "github.com/containerd/continuity/sysx"
- "golang.org/x/sys/unix"
-)
-
-func copyFileInfo(fi os.FileInfo, src, name string) error {
- st := fi.Sys().(*syscall.Stat_t)
- if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
- if os.IsPermission(err) {
- // Normally if uid/gid are the same this would be a no-op, but some
- // filesystems may still return EPERM... for instance NFS does this.
- // In such a case, this is not an error.
- if dstStat, err2 := os.Lstat(name); err2 == nil {
- st2 := dstStat.Sys().(*syscall.Stat_t)
- if st.Uid == st2.Uid && st.Gid == st2.Gid {
- err = nil
- }
- }
- }
- if err != nil {
- return fmt.Errorf("failed to chown %s: %w", name, err)
- }
- }
-
- if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
- if err := os.Chmod(name, fi.Mode()); err != nil {
- return fmt.Errorf("failed to chmod %s: %w", name, err)
- }
- }
-
- timespec := []unix.Timespec{
- unix.NsecToTimespec(syscall.TimespecToNsec(StatAtime(st))),
- unix.NsecToTimespec(syscall.TimespecToNsec(StatMtime(st))),
- }
- if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
- return fmt.Errorf("failed to utime %s: %w", name, err)
- }
-
- return nil
-}
-
-const maxSSizeT = int64(^uint(0) >> 1)
-
-func copyFileContent(dst, src *os.File) error {
- st, err := src.Stat()
- if err != nil {
- return fmt.Errorf("unable to stat source: %w", err)
- }
-
- size := st.Size()
- first := true
- srcFd := int(src.Fd())
- dstFd := int(dst.Fd())
-
- for size > 0 {
- // Ensure that we are never trying to copy more than SSIZE_MAX at a
- // time and at the same time avoids overflows when the file is larger
- // than 4GB on 32-bit systems.
- var copySize int
- if size > maxSSizeT {
- copySize = int(maxSSizeT)
- } else {
- copySize = int(size)
- }
- n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, copySize, 0)
- if err != nil {
- if (err != unix.ENOSYS && err != unix.EXDEV) || !first {
- return fmt.Errorf("copy file range failed: %w", err)
- }
-
- buf := bufferPool.Get().(*[]byte)
- _, err = io.CopyBuffer(dst, src, *buf)
- bufferPool.Put(buf)
- if err != nil {
- return fmt.Errorf("userspace copy failed: %w", err)
- }
- return nil
- }
-
- first = false
- size -= int64(n)
- }
-
- return nil
-}
-
-func copyXAttrs(dst, src string, excludes map[string]struct{}, errorHandler XAttrErrorHandler) error {
- xattrKeys, err := sysx.LListxattr(src)
- if err != nil {
- e := fmt.Errorf("failed to list xattrs on %s: %w", src, err)
- if errorHandler != nil {
- e = errorHandler(dst, src, "", e)
- }
- return e
- }
- for _, xattr := range xattrKeys {
- if _, exclude := excludes[xattr]; exclude {
- continue
- }
- data, err := sysx.LGetxattr(src, xattr)
- if err != nil {
- e := fmt.Errorf("failed to get xattr %q on %s: %w", xattr, src, err)
- if errorHandler != nil {
- if e = errorHandler(dst, src, xattr, e); e == nil {
- continue
- }
- }
- return e
- }
- if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
- e := fmt.Errorf("failed to set xattr %q on %s: %w", xattr, dst, err)
- if errorHandler != nil {
- if e = errorHandler(dst, src, xattr, e); e == nil {
- continue
- }
- }
- return e
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/containerd/continuity/fs/copy_unix.go b/vendor/github.com/containerd/continuity/fs/copy_unix.go
deleted file mode 100644
index 0e68ba9ec2..0000000000
--- a/vendor/github.com/containerd/continuity/fs/copy_unix.go
+++ /dev/null
@@ -1,106 +0,0 @@
-//go:build darwin || freebsd || openbsd || netbsd || solaris
-// +build darwin freebsd openbsd netbsd solaris
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "fmt"
- "io"
- "os"
- "syscall"
-
- "github.com/containerd/continuity/sysx"
-)
-
-func copyFileInfo(fi os.FileInfo, src, name string) error {
- st := fi.Sys().(*syscall.Stat_t)
- if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
- if os.IsPermission(err) {
- // Normally if uid/gid are the same this would be a no-op, but some
- // filesystems may still return EPERM... for instance NFS does this.
- // In such a case, this is not an error.
- if dstStat, err2 := os.Lstat(name); err2 == nil {
- st2 := dstStat.Sys().(*syscall.Stat_t)
- if st.Uid == st2.Uid && st.Gid == st2.Gid {
- err = nil
- }
- }
- }
- if err != nil {
- return fmt.Errorf("failed to chown %s: %w", name, err)
- }
- }
-
- if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
- if err := os.Chmod(name, fi.Mode()); err != nil {
- return fmt.Errorf("failed to chmod %s: %w", name, err)
- }
- }
-
- if err := utimesNano(name, StatAtime(st), StatMtime(st)); err != nil {
- return fmt.Errorf("failed to utime %s: %w", name, err)
- }
-
- return nil
-}
-
-func copyFileContent(dst, src *os.File) error {
- buf := bufferPool.Get().(*[]byte)
- _, err := io.CopyBuffer(dst, src, *buf)
- bufferPool.Put(buf)
-
- return err
-}
-
-func copyXAttrs(dst, src string, excludes map[string]struct{}, errorHandler XAttrErrorHandler) error {
- xattrKeys, err := sysx.LListxattr(src)
- if err != nil {
- e := fmt.Errorf("failed to list xattrs on %s: %w", src, err)
- if errorHandler != nil {
- e = errorHandler(dst, src, "", e)
- }
- return e
- }
- for _, xattr := range xattrKeys {
- if _, exclude := excludes[xattr]; exclude {
- continue
- }
- data, err := sysx.LGetxattr(src, xattr)
- if err != nil {
- e := fmt.Errorf("failed to get xattr %q on %s: %w", xattr, src, err)
- if errorHandler != nil {
- if e = errorHandler(dst, src, xattr, e); e == nil {
- continue
- }
- }
- return e
- }
- if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
- e := fmt.Errorf("failed to set xattr %q on %s: %w", xattr, dst, err)
- if errorHandler != nil {
- if e = errorHandler(dst, src, xattr, e); e == nil {
- continue
- }
- }
- return e
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/containerd/continuity/fs/copy_windows.go b/vendor/github.com/containerd/continuity/fs/copy_windows.go
deleted file mode 100644
index 4dad9441de..0000000000
--- a/vendor/github.com/containerd/continuity/fs/copy_windows.go
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "errors"
- "fmt"
- "io"
- "os"
-
- winio "github.com/Microsoft/go-winio"
- "golang.org/x/sys/windows"
-)
-
-const (
- seTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
-)
-
-func copyFileInfo(fi os.FileInfo, src, name string) error {
- if err := os.Chmod(name, fi.Mode()); err != nil {
- return fmt.Errorf("failed to chmod %s: %w", name, err)
- }
-
- // Copy file ownership and ACL
- // We need SeRestorePrivilege and SeTakeOwnershipPrivilege in order
- // to restore security info on a file, especially if we're trying to
- // apply security info which includes SIDs not necessarily present on
- // the host.
- privileges := []string{winio.SeRestorePrivilege, seTakeOwnershipPrivilege}
- if err := winio.EnableProcessPrivileges(privileges); err != nil {
- return err
- }
- defer winio.DisableProcessPrivileges(privileges)
-
- secInfo, err := windows.GetNamedSecurityInfo(
- src, windows.SE_FILE_OBJECT,
- windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION)
-
- if err != nil {
- return err
- }
-
- dacl, _, err := secInfo.DACL()
- if err != nil {
- return err
- }
-
- sid, _, err := secInfo.Owner()
- if err != nil {
- return err
- }
-
- if err := windows.SetNamedSecurityInfo(
- name, windows.SE_FILE_OBJECT,
- windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION,
- sid, nil, dacl, nil); err != nil {
-
- return err
- }
- return nil
-}
-
-func copyFileContent(dst, src *os.File) error {
- buf := bufferPool.Get().(*[]byte)
- _, err := io.CopyBuffer(dst, src, *buf)
- bufferPool.Put(buf)
- return err
-}
-
-func copyXAttrs(dst, src string, excludes map[string]struct{}, errorHandler XAttrErrorHandler) error {
- return nil
-}
-
-func copyIrregular(dst string, fi os.FileInfo) error {
- return errors.New("irregular copy not supported")
-}
diff --git a/vendor/github.com/containerd/continuity/fs/diff.go b/vendor/github.com/containerd/continuity/fs/diff.go
deleted file mode 100644
index 3cd4eee6fb..0000000000
--- a/vendor/github.com/containerd/continuity/fs/diff.go
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "context"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/sirupsen/logrus"
- "golang.org/x/sync/errgroup"
-)
-
-// ChangeKind is the type of modification that
-// a change is making.
-type ChangeKind int
-
-const (
- // ChangeKindUnmodified represents an unmodified
- // file
- ChangeKindUnmodified = iota
-
- // ChangeKindAdd represents an addition of
- // a file
- ChangeKindAdd
-
- // ChangeKindModify represents a change to
- // an existing file
- ChangeKindModify
-
- // ChangeKindDelete represents a delete of
- // a file
- ChangeKindDelete
-)
-
-func (k ChangeKind) String() string {
- switch k {
- case ChangeKindUnmodified:
- return "unmodified"
- case ChangeKindAdd:
- return "add"
- case ChangeKindModify:
- return "modify"
- case ChangeKindDelete:
- return "delete"
- default:
- return ""
- }
-}
-
-// Change represents single change between a diff and its parent.
-type Change struct {
- Kind ChangeKind
- Path string
-}
-
-// ChangeFunc is the type of function called for each change
-// computed during a directory changes calculation.
-type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error
-
-// Changes computes changes between two directories calling the
-// given change function for each computed change. The first
-// directory is intended to the base directory and second
-// directory the changed directory.
-//
-// The change callback is called by the order of path names and
-// should be appliable in that order.
-// Due to this apply ordering, the following is true
-// - Removed directory trees only create a single change for the root
-// directory removed. Remaining changes are implied.
-// - A directory which is modified to become a file will not have
-// delete entries for sub-path items, their removal is implied
-// by the removal of the parent directory.
-//
-// Opaque directories will not be treated specially and each file
-// removed from the base directory will show up as a removal.
-//
-// File content comparisons will be done on files which have timestamps
-// which may have been truncated. If either of the files being compared
-// has a zero value nanosecond value, each byte will be compared for
-// differences. If 2 files have the same seconds value but different
-// nanosecond values where one of those values is zero, the files will
-// be considered unchanged if the content is the same. This behavior
-// is to account for timestamp truncation during archiving.
-func Changes(ctx context.Context, a, b string, changeFn ChangeFunc) error {
- if a == "" {
- logrus.Debugf("Using single walk diff for %s", b)
- return addDirChanges(ctx, changeFn, b)
- } else if diffOptions := detectDirDiff(b, a); diffOptions != nil {
- logrus.Debugf("Using single walk diff for %s from %s", diffOptions.diffDir, a)
- return diffDirChanges(ctx, changeFn, a, diffOptions)
- }
-
- logrus.Debugf("Using double walk diff for %s from %s", b, a)
- return doubleWalkDiff(ctx, changeFn, a, b)
-}
-
-func addDirChanges(ctx context.Context, changeFn ChangeFunc, root string) error {
- return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- // Rebase path
- path, err = filepath.Rel(root, path)
- if err != nil {
- return err
- }
-
- path = filepath.Join(string(os.PathSeparator), path)
-
- // Skip root
- if path == string(os.PathSeparator) {
- return nil
- }
-
- return changeFn(ChangeKindAdd, path, f, nil)
- })
-}
-
-// diffDirOptions is used when the diff can be directly calculated from
-// a diff directory to its base, without walking both trees.
-type diffDirOptions struct {
- diffDir string
- skipChange func(string) (bool, error)
- deleteChange func(string, string, os.FileInfo) (string, error)
-}
-
-// diffDirChanges walks the diff directory and compares changes against the base.
-func diffDirChanges(ctx context.Context, changeFn ChangeFunc, base string, o *diffDirOptions) error {
- changedDirs := make(map[string]struct{})
- return filepath.Walk(o.diffDir, func(path string, f os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- // Rebase path
- path, err = filepath.Rel(o.diffDir, path)
- if err != nil {
- return err
- }
-
- path = filepath.Join(string(os.PathSeparator), path)
-
- // Skip root
- if path == string(os.PathSeparator) {
- return nil
- }
-
- // TODO: handle opaqueness, start new double walker at this
- // location to get deletes, and skip tree in single walker
-
- if o.skipChange != nil {
- if skip, err := o.skipChange(path); skip {
- return err
- }
- }
-
- var kind ChangeKind
-
- deletedFile, err := o.deleteChange(o.diffDir, path, f)
- if err != nil {
- return err
- }
-
- // Find out what kind of modification happened
- if deletedFile != "" {
- path = deletedFile
- kind = ChangeKindDelete
- f = nil
- } else {
- // Otherwise, the file was added
- kind = ChangeKindAdd
-
- // ...Unless it already existed in a base, in which case, it's a modification
- stat, err := os.Stat(filepath.Join(base, path))
- if err != nil && !os.IsNotExist(err) {
- return err
- }
- if err == nil {
- // The file existed in the base, so that's a modification
-
- // However, if it's a directory, maybe it wasn't actually modified.
- // If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
- if stat.IsDir() && f.IsDir() {
- if f.Size() == stat.Size() && f.Mode() == stat.Mode() && sameFsTime(f.ModTime(), stat.ModTime()) {
- // Both directories are the same, don't record the change
- return nil
- }
- }
- kind = ChangeKindModify
- }
- }
-
- // If /foo/bar/file.txt is modified, then /foo/bar must be part of the changed files.
- // This block is here to ensure the change is recorded even if the
- // modify time, mode and size of the parent directory in the rw and ro layers are all equal.
- // Check https://github.com/docker/docker/pull/13590 for details.
- if f.IsDir() {
- changedDirs[path] = struct{}{}
- }
- if kind == ChangeKindAdd || kind == ChangeKindDelete {
- parent := filepath.Dir(path)
- if _, ok := changedDirs[parent]; !ok && parent != "/" {
- pi, err := os.Stat(filepath.Join(o.diffDir, parent))
- if err := changeFn(ChangeKindModify, parent, pi, err); err != nil {
- return err
- }
- changedDirs[parent] = struct{}{}
- }
- }
-
- return changeFn(kind, path, f, nil)
- })
-}
-
-// doubleWalkDiff walks both directories to create a diff
-func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err error) {
- g, ctx := errgroup.WithContext(ctx)
-
- var (
- c1 = make(chan *currentPath)
- c2 = make(chan *currentPath)
-
- f1, f2 *currentPath
- rmdir string
- )
- g.Go(func() error {
- defer close(c1)
- return pathWalk(ctx, a, c1)
- })
- g.Go(func() error {
- defer close(c2)
- return pathWalk(ctx, b, c2)
- })
- g.Go(func() error {
- for c1 != nil || c2 != nil {
- if f1 == nil && c1 != nil {
- f1, err = nextPath(ctx, c1)
- if err != nil {
- return err
- }
- if f1 == nil {
- c1 = nil
- }
- }
-
- if f2 == nil && c2 != nil {
- f2, err = nextPath(ctx, c2)
- if err != nil {
- return err
- }
- if f2 == nil {
- c2 = nil
- }
- }
- if f1 == nil && f2 == nil {
- continue
- }
-
- var f os.FileInfo
- k, p := pathChange(f1, f2)
- switch k {
- case ChangeKindAdd:
- if rmdir != "" {
- rmdir = ""
- }
- f = f2.f
- f2 = nil
- case ChangeKindDelete:
- // Check if this file is already removed by being
- // under of a removed directory
- if rmdir != "" && strings.HasPrefix(f1.path, rmdir) {
- f1 = nil
- continue
- } else if f1.f.IsDir() {
- rmdir = f1.path + string(os.PathSeparator)
- } else if rmdir != "" {
- rmdir = ""
- }
- f1 = nil
- case ChangeKindModify:
- same, err := sameFile(f1, f2)
- if err != nil {
- return err
- }
- if f1.f.IsDir() && !f2.f.IsDir() {
- rmdir = f1.path + string(os.PathSeparator)
- } else if rmdir != "" {
- rmdir = ""
- }
- f = f2.f
- f1 = nil
- f2 = nil
- if same {
- if !isLinked(f) {
- continue
- }
- k = ChangeKindUnmodified
- }
- }
- if err := changeFn(k, p, f, nil); err != nil {
- return err
- }
- }
- return nil
- })
-
- return g.Wait()
-}
diff --git a/vendor/github.com/containerd/continuity/fs/diff_unix.go b/vendor/github.com/containerd/continuity/fs/diff_unix.go
deleted file mode 100644
index 5de9b6b48f..0000000000
--- a/vendor/github.com/containerd/continuity/fs/diff_unix.go
+++ /dev/null
@@ -1,75 +0,0 @@
-//go:build !windows
-// +build !windows
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "bytes"
- "fmt"
- "os"
- "syscall"
-
- "github.com/containerd/continuity/sysx"
-)
-
-// detectDirDiff returns diff dir options if a directory could
-// be found in the mount info for upper which is the direct
-// diff with the provided lower directory
-func detectDirDiff(upper, lower string) *diffDirOptions {
- // TODO: get mount options for upper
- // TODO: detect AUFS
- // TODO: detect overlay
- return nil
-}
-
-// compareSysStat returns whether the stats are equivalent,
-// whether the files are considered the same file, and
-// an error
-func compareSysStat(s1, s2 interface{}) (bool, error) {
- ls1, ok := s1.(*syscall.Stat_t)
- if !ok {
- return false, nil
- }
- ls2, ok := s2.(*syscall.Stat_t)
- if !ok {
- return false, nil
- }
-
- return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil
-}
-
-func compareCapabilities(p1, p2 string) (bool, error) {
- c1, err := sysx.LGetxattr(p1, "security.capability")
- if err != nil && err != sysx.ENODATA {
- return false, fmt.Errorf("failed to get xattr for %s: %w", p1, err)
- }
- c2, err := sysx.LGetxattr(p2, "security.capability")
- if err != nil && err != sysx.ENODATA {
- return false, fmt.Errorf("failed to get xattr for %s: %w", p2, err)
- }
- return bytes.Equal(c1, c2), nil
-}
-
-func isLinked(f os.FileInfo) bool {
- s, ok := f.Sys().(*syscall.Stat_t)
- if !ok {
- return false
- }
- return !f.IsDir() && s.Nlink > 1
-}
diff --git a/vendor/github.com/containerd/continuity/fs/diff_windows.go b/vendor/github.com/containerd/continuity/fs/diff_windows.go
deleted file mode 100644
index 4bfa72d3a1..0000000000
--- a/vendor/github.com/containerd/continuity/fs/diff_windows.go
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "os"
-
- "golang.org/x/sys/windows"
-)
-
-func detectDirDiff(upper, lower string) *diffDirOptions {
- return nil
-}
-
-func compareSysStat(s1, s2 interface{}) (bool, error) {
- f1, ok := s1.(windows.Win32FileAttributeData)
- if !ok {
- return false, nil
- }
- f2, ok := s2.(windows.Win32FileAttributeData)
- if !ok {
- return false, nil
- }
- return f1.FileAttributes == f2.FileAttributes, nil
-}
-
-func compareCapabilities(p1, p2 string) (bool, error) {
- // TODO: Use windows equivalent
- return true, nil
-}
-
-func isLinked(os.FileInfo) bool {
- return false
-}
diff --git a/vendor/github.com/containerd/continuity/fs/dtype_linux.go b/vendor/github.com/containerd/continuity/fs/dtype_linux.go
deleted file mode 100644
index a8eab1db8a..0000000000
--- a/vendor/github.com/containerd/continuity/fs/dtype_linux.go
+++ /dev/null
@@ -1,104 +0,0 @@
-//go:build linux
-// +build linux
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "syscall"
- "unsafe"
-)
-
-func locateDummyIfEmpty(path string) (string, error) {
- children, err := ioutil.ReadDir(path)
- if err != nil {
- return "", err
- }
- if len(children) != 0 {
- return "", nil
- }
- dummyFile, err := os.CreateTemp(path, "fsutils-dummy")
- if err != nil {
- return "", err
- }
- name := dummyFile.Name()
- err = dummyFile.Close()
- return name, err
-}
-
-// SupportsDType returns whether the filesystem mounted on path supports d_type
-func SupportsDType(path string) (bool, error) {
- // locate dummy so that we have at least one dirent
- dummy, err := locateDummyIfEmpty(path)
- if err != nil {
- return false, err
- }
- if dummy != "" {
- defer os.Remove(dummy)
- }
-
- visited := 0
- supportsDType := true
- fn := func(ent *syscall.Dirent) bool {
- visited++
- if ent.Type == syscall.DT_UNKNOWN {
- supportsDType = false
- // stop iteration
- return true
- }
- // continue iteration
- return false
- }
- if err = iterateReadDir(path, fn); err != nil {
- return false, err
- }
- if visited == 0 {
- return false, fmt.Errorf("did not hit any dirent during iteration %s", path)
- }
- return supportsDType, nil
-}
-
-func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error {
- d, err := os.Open(path)
- if err != nil {
- return err
- }
- defer d.Close()
- fd := int(d.Fd())
- buf := make([]byte, 4096)
- for {
- nbytes, err := syscall.ReadDirent(fd, buf)
- if err != nil {
- return err
- }
- if nbytes == 0 {
- break
- }
- for off := 0; off < nbytes; {
- ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off]))
- if stop := fn(ent); stop {
- return nil
- }
- off += int(ent.Reclen)
- }
- }
- return nil
-}
diff --git a/vendor/github.com/containerd/continuity/fs/du.go b/vendor/github.com/containerd/continuity/fs/du.go
deleted file mode 100644
index fccc985dc5..0000000000
--- a/vendor/github.com/containerd/continuity/fs/du.go
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import "context"
-
-// Usage of disk information
-type Usage struct {
- Inodes int64
- Size int64
-}
-
-// DiskUsage counts the number of inodes and disk usage for the resources under
-// path.
-func DiskUsage(ctx context.Context, roots ...string) (Usage, error) {
- return diskUsage(ctx, roots...)
-}
-
-// DiffUsage counts the numbers of inodes and disk usage in the
-// diff between the 2 directories. The first path is intended
-// as the base directory and the second as the changed directory.
-func DiffUsage(ctx context.Context, a, b string) (Usage, error) {
- return diffUsage(ctx, a, b)
-}
diff --git a/vendor/github.com/containerd/continuity/fs/du_unix.go b/vendor/github.com/containerd/continuity/fs/du_unix.go
deleted file mode 100644
index bf33c42d72..0000000000
--- a/vendor/github.com/containerd/continuity/fs/du_unix.go
+++ /dev/null
@@ -1,119 +0,0 @@
-//go:build !windows
-// +build !windows
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "context"
- "os"
- "path/filepath"
- "syscall"
-)
-
-// blocksUnitSize is the unit used by `st_blocks` in `stat` in bytes.
-// See https://man7.org/linux/man-pages/man2/stat.2.html
-// st_blocks
-// This field indicates the number of blocks allocated to the
-// file, in 512-byte units. (This may be smaller than
-// st_size/512 when the file has holes.)
-const blocksUnitSize = 512
-
-type inode struct {
- // TODO(stevvooe): Can probably reduce memory usage by not tracking
- // device, but we can leave this right for now.
- dev, ino uint64
-}
-
-func newInode(stat *syscall.Stat_t) inode {
- return inode{
- dev: uint64(stat.Dev), //nolint: unconvert // dev is uint32 on darwin/bsd, uint64 on linux/solaris/freebsd
- ino: uint64(stat.Ino), //nolint: unconvert // ino is uint32 on bsd, uint64 on darwin/linux/solaris/freebsd
- }
-}
-
-func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
-
- var (
- size int64
- inodes = map[inode]struct{}{} // expensive!
- )
-
- for _, root := range roots {
- if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- select {
- case <-ctx.Done():
- return ctx.Err()
- default:
- }
-
- stat := fi.Sys().(*syscall.Stat_t)
- inoKey := newInode(stat)
- if _, ok := inodes[inoKey]; !ok {
- inodes[inoKey] = struct{}{}
- size += stat.Blocks * blocksUnitSize
- }
-
- return nil
- }); err != nil {
- return Usage{}, err
- }
- }
-
- return Usage{
- Inodes: int64(len(inodes)),
- Size: size,
- }, nil
-}
-
-func diffUsage(ctx context.Context, a, b string) (Usage, error) {
- var (
- size int64
- inodes = map[inode]struct{}{} // expensive!
- )
-
- if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- if kind == ChangeKindAdd || kind == ChangeKindModify {
- stat := fi.Sys().(*syscall.Stat_t)
- inoKey := newInode(stat)
- if _, ok := inodes[inoKey]; !ok {
- inodes[inoKey] = struct{}{}
- size += stat.Blocks * blocksUnitSize
- }
-
- return nil
-
- }
- return nil
- }); err != nil {
- return Usage{}, err
- }
-
- return Usage{
- Inodes: int64(len(inodes)),
- Size: size,
- }, nil
-}
diff --git a/vendor/github.com/containerd/continuity/fs/du_windows.go b/vendor/github.com/containerd/continuity/fs/du_windows.go
deleted file mode 100644
index 08fb283336..0000000000
--- a/vendor/github.com/containerd/continuity/fs/du_windows.go
+++ /dev/null
@@ -1,83 +0,0 @@
-//go:build windows
-// +build windows
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "context"
- "os"
- "path/filepath"
-)
-
-func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
- var (
- size int64
- )
-
- // TODO(stevvooe): Support inodes (or equivalent) for windows.
-
- for _, root := range roots {
- if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- select {
- case <-ctx.Done():
- return ctx.Err()
- default:
- }
-
- size += fi.Size()
- return nil
- }); err != nil {
- return Usage{}, err
- }
- }
-
- return Usage{
- Size: size,
- }, nil
-}
-
-func diffUsage(ctx context.Context, a, b string) (Usage, error) {
- var (
- size int64
- )
-
- if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- if kind == ChangeKindAdd || kind == ChangeKindModify {
- size += fi.Size()
-
- return nil
-
- }
- return nil
- }); err != nil {
- return Usage{}, err
- }
-
- return Usage{
- Size: size,
- }, nil
-}
diff --git a/vendor/github.com/containerd/continuity/fs/hardlink.go b/vendor/github.com/containerd/continuity/fs/hardlink.go
deleted file mode 100644
index 762aa45e69..0000000000
--- a/vendor/github.com/containerd/continuity/fs/hardlink.go
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import "os"
-
-// GetLinkInfo returns an identifier representing the node a hardlink is pointing
-// to. If the file is not hard linked then 0 will be returned.
-func GetLinkInfo(fi os.FileInfo) (uint64, bool) {
- return getLinkInfo(fi)
-}
-
-// getLinkSource returns a path for the given name and
-// file info to its link source in the provided inode
-// map. If the given file name is not in the map and
-// has other links, it is added to the inode map
-// to be a source for other link locations.
-func getLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
- inode, isHardlink := getLinkInfo(fi)
- if !isHardlink {
- return "", nil
- }
-
- path, ok := inodes[inode]
- if !ok {
- inodes[inode] = name
- }
- return path, nil
-}
diff --git a/vendor/github.com/containerd/continuity/fs/hardlink_unix.go b/vendor/github.com/containerd/continuity/fs/hardlink_unix.go
deleted file mode 100644
index cce8902f3b..0000000000
--- a/vendor/github.com/containerd/continuity/fs/hardlink_unix.go
+++ /dev/null
@@ -1,34 +0,0 @@
-//go:build !windows
-// +build !windows
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "os"
- "syscall"
-)
-
-func getLinkInfo(fi os.FileInfo) (uint64, bool) {
- s, ok := fi.Sys().(*syscall.Stat_t)
- if !ok {
- return 0, false
- }
-
- return uint64(s.Ino), !fi.IsDir() && s.Nlink > 1 //nolint: unconvert // ino is uint32 on bsd, uint64 on darwin/linux/solaris
-}
diff --git a/vendor/github.com/containerd/continuity/fs/hardlink_windows.go b/vendor/github.com/containerd/continuity/fs/hardlink_windows.go
deleted file mode 100644
index 7485547147..0000000000
--- a/vendor/github.com/containerd/continuity/fs/hardlink_windows.go
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import "os"
-
-func getLinkInfo(fi os.FileInfo) (uint64, bool) {
- return 0, false
-}
diff --git a/vendor/github.com/containerd/continuity/fs/path.go b/vendor/github.com/containerd/continuity/fs/path.go
deleted file mode 100644
index 97313e2b82..0000000000
--- a/vendor/github.com/containerd/continuity/fs/path.go
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "bytes"
- "context"
- "errors"
- "io"
- "os"
- "path/filepath"
-)
-
-var (
- errTooManyLinks = errors.New("too many links")
-)
-
-type currentPath struct {
- path string
- f os.FileInfo
- fullPath string
-}
-
-func pathChange(lower, upper *currentPath) (ChangeKind, string) {
- if lower == nil {
- if upper == nil {
- panic("cannot compare nil paths")
- }
- return ChangeKindAdd, upper.path
- }
- if upper == nil {
- return ChangeKindDelete, lower.path
- }
-
- switch i := directoryCompare(lower.path, upper.path); {
- case i < 0:
- // File in lower that is not in upper
- return ChangeKindDelete, lower.path
- case i > 0:
- // File in upper that is not in lower
- return ChangeKindAdd, upper.path
- default:
- return ChangeKindModify, upper.path
- }
-}
-
-func directoryCompare(a, b string) int {
- l := len(a)
- if len(b) < l {
- l = len(b)
- }
- for i := 0; i < l; i++ {
- c1, c2 := a[i], b[i]
- if c1 == filepath.Separator {
- c1 = byte(0)
- }
- if c2 == filepath.Separator {
- c2 = byte(0)
- }
- if c1 < c2 {
- return -1
- }
- if c1 > c2 {
- return +1
- }
- }
- if len(a) < len(b) {
- return -1
- }
- if len(a) > len(b) {
- return +1
- }
- return 0
-}
-
-func sameFile(f1, f2 *currentPath) (bool, error) {
- if os.SameFile(f1.f, f2.f) {
- return true, nil
- }
-
- equalStat, err := compareSysStat(f1.f.Sys(), f2.f.Sys())
- if err != nil || !equalStat {
- return equalStat, err
- }
-
- if eq, err := compareCapabilities(f1.fullPath, f2.fullPath); err != nil || !eq {
- return eq, err
- }
-
- // If not a directory also check size, modtime, and content
- if !f1.f.IsDir() {
- if f1.f.Size() != f2.f.Size() {
- return false, nil
- }
- t1 := f1.f.ModTime()
- t2 := f2.f.ModTime()
-
- if t1.Unix() != t2.Unix() {
- return false, nil
- }
-
- // If the timestamp may have been truncated in both of the
- // files, check content of file to determine difference
- if t1.Nanosecond() == 0 && t2.Nanosecond() == 0 {
- if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink {
- return compareSymlinkTarget(f1.fullPath, f2.fullPath)
- }
- if f1.f.Size() == 0 { // if file sizes are zero length, the files are the same by definition
- return true, nil
- }
- return compareFileContent(f1.fullPath, f2.fullPath)
- } else if t1.Nanosecond() != t2.Nanosecond() {
- return false, nil
- }
- }
-
- return true, nil
-}
-
-func compareSymlinkTarget(p1, p2 string) (bool, error) {
- t1, err := os.Readlink(p1)
- if err != nil {
- return false, err
- }
- t2, err := os.Readlink(p2)
- if err != nil {
- return false, err
- }
- return t1 == t2, nil
-}
-
-const compareChuckSize = 32 * 1024
-
-// compareFileContent compares the content of 2 same sized files
-// by comparing each byte.
-func compareFileContent(p1, p2 string) (bool, error) {
- f1, err := os.Open(p1)
- if err != nil {
- return false, err
- }
- defer f1.Close()
- f2, err := os.Open(p2)
- if err != nil {
- return false, err
- }
- defer f2.Close()
-
- b1 := make([]byte, compareChuckSize)
- b2 := make([]byte, compareChuckSize)
- for {
- n1, err1 := f1.Read(b1)
- if err1 != nil && err1 != io.EOF {
- return false, err1
- }
- n2, err2 := f2.Read(b2)
- if err2 != nil && err2 != io.EOF {
- return false, err2
- }
- if n1 != n2 || !bytes.Equal(b1[:n1], b2[:n2]) {
- return false, nil
- }
- if err1 == io.EOF && err2 == io.EOF {
- return true, nil
- }
- }
-}
-
-func pathWalk(ctx context.Context, root string, pathC chan<- *currentPath) error {
- return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- // Rebase path
- path, err = filepath.Rel(root, path)
- if err != nil {
- return err
- }
-
- path = filepath.Join(string(os.PathSeparator), path)
-
- // Skip root
- if path == string(os.PathSeparator) {
- return nil
- }
-
- p := ¤tPath{
- path: path,
- f: f,
- fullPath: filepath.Join(root, path),
- }
-
- select {
- case <-ctx.Done():
- return ctx.Err()
- case pathC <- p:
- return nil
- }
- })
-}
-
-func nextPath(ctx context.Context, pathC <-chan *currentPath) (*currentPath, error) {
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- case p := <-pathC:
- return p, nil
- }
-}
-
-// RootPath joins a path with a root, evaluating and bounding any
-// symlink to the root directory.
-func RootPath(root, path string) (string, error) {
- if path == "" {
- return root, nil
- }
- var linksWalked int // to protect against cycles
- for {
- i := linksWalked
- newpath, err := walkLinks(root, path, &linksWalked)
- if err != nil {
- return "", err
- }
- path = newpath
- if i == linksWalked {
- newpath = filepath.Join("/", newpath)
- if path == newpath {
- return filepath.Join(root, newpath), nil
- }
- path = newpath
- }
- }
-}
-
-func walkLink(root, path string, linksWalked *int) (newpath string, islink bool, err error) {
- if *linksWalked > 255 {
- return "", false, errTooManyLinks
- }
-
- path = filepath.Join("/", path)
- if path == "/" {
- return path, false, nil
- }
- realPath := filepath.Join(root, path)
-
- fi, err := os.Lstat(realPath)
- if err != nil {
- // If path does not yet exist, treat as non-symlink
- if os.IsNotExist(err) {
- return path, false, nil
- }
- return "", false, err
- }
- if fi.Mode()&os.ModeSymlink == 0 {
- return path, false, nil
- }
- newpath, err = os.Readlink(realPath)
- if err != nil {
- return "", false, err
- }
- *linksWalked++
- return newpath, true, nil
-}
-
-func walkLinks(root, path string, linksWalked *int) (string, error) {
- switch dir, file := filepath.Split(path); {
- case dir == "":
- newpath, _, err := walkLink(root, file, linksWalked)
- return newpath, err
- case file == "":
- if os.IsPathSeparator(dir[len(dir)-1]) {
- if dir == "/" {
- return dir, nil
- }
- return walkLinks(root, dir[:len(dir)-1], linksWalked)
- }
- newpath, _, err := walkLink(root, dir, linksWalked)
- return newpath, err
- default:
- newdir, err := walkLinks(root, dir, linksWalked)
- if err != nil {
- return "", err
- }
- newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked)
- if err != nil {
- return "", err
- }
- if !islink {
- return newpath, nil
- }
- if filepath.IsAbs(newpath) {
- return newpath, nil
- }
- return filepath.Join(newdir, newpath), nil
- }
-}
diff --git a/vendor/github.com/containerd/continuity/fs/stat_atim.go b/vendor/github.com/containerd/continuity/fs/stat_atim.go
deleted file mode 100644
index 996b9c1ae7..0000000000
--- a/vendor/github.com/containerd/continuity/fs/stat_atim.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build linux || openbsd || solaris
-// +build linux openbsd solaris
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "syscall"
- "time"
-)
-
-// StatAtime returns the Atim
-func StatAtime(st *syscall.Stat_t) syscall.Timespec {
- return st.Atim
-}
-
-// StatCtime returns the Ctim
-func StatCtime(st *syscall.Stat_t) syscall.Timespec {
- return st.Ctim
-}
-
-// StatMtime returns the Mtim
-func StatMtime(st *syscall.Stat_t) syscall.Timespec {
- return st.Mtim
-}
-
-// StatATimeAsTime returns st.Atim as a time.Time
-func StatATimeAsTime(st *syscall.Stat_t) time.Time {
- return time.Unix(st.Atim.Unix())
-}
diff --git a/vendor/github.com/containerd/continuity/fs/stat_darwinbsd.go b/vendor/github.com/containerd/continuity/fs/stat_darwinbsd.go
deleted file mode 100644
index dbdb90ec83..0000000000
--- a/vendor/github.com/containerd/continuity/fs/stat_darwinbsd.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build darwin || freebsd || netbsd
-// +build darwin freebsd netbsd
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "syscall"
- "time"
-)
-
-// StatAtime returns the access time from a stat struct
-func StatAtime(st *syscall.Stat_t) syscall.Timespec {
- return st.Atimespec
-}
-
-// StatCtime returns the created time from a stat struct
-func StatCtime(st *syscall.Stat_t) syscall.Timespec {
- return st.Ctimespec
-}
-
-// StatMtime returns the modified time from a stat struct
-func StatMtime(st *syscall.Stat_t) syscall.Timespec {
- return st.Mtimespec
-}
-
-// StatATimeAsTime returns the access time as a time.Time
-func StatATimeAsTime(st *syscall.Stat_t) time.Time {
- return time.Unix(st.Atimespec.Unix())
-}
diff --git a/vendor/github.com/containerd/continuity/fs/time.go b/vendor/github.com/containerd/continuity/fs/time.go
deleted file mode 100644
index cde4561233..0000000000
--- a/vendor/github.com/containerd/continuity/fs/time.go
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import "time"
-
-// Gnu tar and the go tar writer don't have sub-second mtime
-// precision, which is problematic when we apply changes via tar
-// files, we handle this by comparing for exact times, *or* same
-// second count and either a or b having exactly 0 nanoseconds
-func sameFsTime(a, b time.Time) bool {
- return a == b ||
- (a.Unix() == b.Unix() &&
- (a.Nanosecond() == 0 || b.Nanosecond() == 0))
-}
diff --git a/vendor/github.com/containerd/continuity/fs/utimesnanoat.go b/vendor/github.com/containerd/continuity/fs/utimesnanoat.go
deleted file mode 100644
index 5435398d48..0000000000
--- a/vendor/github.com/containerd/continuity/fs/utimesnanoat.go
+++ /dev/null
@@ -1,33 +0,0 @@
-//go:build !(windows || linux)
-// +build !windows,!linux
-
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package fs
-
-import (
- "syscall"
-
- "golang.org/x/sys/unix"
-)
-
-func utimesNano(name string, atime, mtime syscall.Timespec) error {
- at := unix.NsecToTimespec(atime.Nano())
- mt := unix.NsecToTimespec(mtime.Nano())
- utimes := [2]unix.Timespec{at, mt}
- return unix.UtimesNanoAt(unix.AT_FDCWD, name, utimes[0:], unix.AT_SYMLINK_NOFOLLOW)
-}
diff --git a/vendor/github.com/containerd/continuity/sysx/nodata_unix.go b/vendor/github.com/containerd/continuity/sysx/nodata_unix.go
index e78f77f6a1..b5720ac92d 100644
--- a/vendor/github.com/containerd/continuity/sysx/nodata_unix.go
+++ b/vendor/github.com/containerd/continuity/sysx/nodata_unix.go
@@ -1,5 +1,4 @@
//go:build !(linux || solaris || windows)
-// +build !linux,!solaris,!windows
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/continuity/sysx/xattr.go b/vendor/github.com/containerd/continuity/sysx/xattr.go
index 1497398553..eb1bbd9850 100644
--- a/vendor/github.com/containerd/continuity/sysx/xattr.go
+++ b/vendor/github.com/containerd/continuity/sysx/xattr.go
@@ -1,5 +1,4 @@
//go:build linux || darwin
-// +build linux darwin
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go b/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
index da1e940d62..9e0963bf25 100644
--- a/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
+++ b/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
@@ -1,5 +1,4 @@
//go:build !linux && !darwin
-// +build !linux,!darwin
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/errdefs/pkg/errgrpc/grpc.go b/vendor/github.com/containerd/errdefs/pkg/errgrpc/grpc.go
new file mode 100644
index 0000000000..59577595a2
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/pkg/errgrpc/grpc.go
@@ -0,0 +1,353 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+// Package errgrpc provides utility functions for translating errors to
+// and from a gRPC context.
+//
+// The functions ToGRPC and ToNative can be used to map server-side and
+// client-side errors to the correct types.
+package errgrpc
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+
+ spb "google.golang.org/genproto/googleapis/rpc/status"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/protoadapt"
+ "google.golang.org/protobuf/types/known/anypb"
+
+ "github.com/containerd/typeurl/v2"
+
+ "github.com/containerd/errdefs"
+ "github.com/containerd/errdefs/pkg/internal/cause"
+ "github.com/containerd/errdefs/pkg/internal/types"
+)
+
+// ToGRPC will attempt to map the error into a grpc error, from the error types
+// defined in the the errdefs package and attempign to preserve the original
+// description. Any type which does not resolve to a defined error type will
+// be assigned the unknown error code.
+//
+// Further information may be extracted from certain errors depending on their
+// type. The grpc error details will be used to attempt to preserve as much of
+// the error structures and types as possible.
+//
+// Errors which can be marshaled using protobuf or typeurl will be considered
+// for including as GRPC error details.
+// Additionally, use the following interfaces in errors to preserve custom types:
+//
+// WrapError(error) error - Used to wrap the previous error
+// JoinErrors(...error) error - Used to join all previous errors
+// CollapseError() - Used for errors which carry information but
+// should not have their error message shown.
+func ToGRPC(err error) error {
+ if err == nil {
+ return nil
+ }
+
+ if _, ok := status.FromError(err); ok {
+ // error has already been mapped to grpc
+ return err
+ }
+ st := statusFromError(err)
+ if st != nil {
+ if details := errorDetails(err, false); len(details) > 0 {
+ if ds, _ := st.WithDetails(details...); ds != nil {
+ st = ds
+ }
+ }
+ err = st.Err()
+ }
+ return err
+}
+
+func statusFromError(err error) *status.Status {
+ switch errdefs.Resolve(err) {
+ case errdefs.ErrInvalidArgument:
+ return status.New(codes.InvalidArgument, err.Error())
+ case errdefs.ErrNotFound:
+ return status.New(codes.NotFound, err.Error())
+ case errdefs.ErrAlreadyExists:
+ return status.New(codes.AlreadyExists, err.Error())
+ case errdefs.ErrPermissionDenied:
+ return status.New(codes.PermissionDenied, err.Error())
+ case errdefs.ErrResourceExhausted:
+ return status.New(codes.ResourceExhausted, err.Error())
+ case errdefs.ErrFailedPrecondition, errdefs.ErrConflict, errdefs.ErrNotModified:
+ return status.New(codes.FailedPrecondition, err.Error())
+ case errdefs.ErrAborted:
+ return status.New(codes.Aborted, err.Error())
+ case errdefs.ErrOutOfRange:
+ return status.New(codes.OutOfRange, err.Error())
+ case errdefs.ErrNotImplemented:
+ return status.New(codes.Unimplemented, err.Error())
+ case errdefs.ErrInternal:
+ return status.New(codes.Internal, err.Error())
+ case errdefs.ErrUnavailable:
+ return status.New(codes.Unavailable, err.Error())
+ case errdefs.ErrDataLoss:
+ return status.New(codes.DataLoss, err.Error())
+ case errdefs.ErrUnauthenticated:
+ return status.New(codes.Unauthenticated, err.Error())
+ case context.DeadlineExceeded:
+ return status.New(codes.DeadlineExceeded, err.Error())
+ case context.Canceled:
+ return status.New(codes.Canceled, err.Error())
+ case errdefs.ErrUnknown:
+ return status.New(codes.Unknown, err.Error())
+ }
+ return nil
+}
+
+// errorDetails returns an array of errors which make up the provided error.
+// If firstIncluded is true, then all encodable errors will be used, otherwise
+// the first error in an error list will be not be used, to account for the
+// the base status error which details are added to via wrap or join.
+//
+// The errors are ordered in way that they can be applied in order by either
+// wrapping or joining the errors to recreate an error with the same structure
+// when `WrapError` and `JoinErrors` interfaces are used.
+//
+// The intent is that when re-applying the errors to create a single error, the
+// results of calls to `Error()`, `errors.Is`, `errors.As`, and "%+v" formatting
+// is the same as the original error.
+func errorDetails(err error, firstIncluded bool) []protoadapt.MessageV1 {
+ switch uerr := err.(type) {
+ case interface{ Unwrap() error }:
+ details := errorDetails(uerr.Unwrap(), firstIncluded)
+
+ // If the type is able to wrap, then include if proto
+ if _, ok := err.(interface{ WrapError(error) error }); ok {
+ // Get proto message
+ if protoErr := toProtoMessage(err); protoErr != nil {
+ details = append(details, protoErr)
+ }
+ }
+
+ return details
+ case interface{ Unwrap() []error }:
+ var details []protoadapt.MessageV1
+ for i, e := range uerr.Unwrap() {
+ details = append(details, errorDetails(e, firstIncluded || i > 0)...)
+ }
+
+ if _, ok := err.(interface{ JoinErrors(...error) error }); ok {
+ // Get proto message
+ if protoErr := toProtoMessage(err); protoErr != nil {
+ details = append(details, protoErr)
+ }
+ }
+ return details
+ }
+
+ if firstIncluded {
+ if protoErr := toProtoMessage(err); protoErr != nil {
+ return []protoadapt.MessageV1{protoErr}
+ }
+ if gs, ok := status.FromError(ToGRPC(err)); ok {
+ return []protoadapt.MessageV1{gs.Proto()}
+ }
+ // TODO: Else include unknown extra error type?
+ }
+
+ return nil
+}
+
+func toProtoMessage(err error) protoadapt.MessageV1 {
+ // Do not double encode proto messages, otherwise use Any
+ if pm, ok := err.(protoadapt.MessageV1); ok {
+ return pm
+ }
+ if pm, ok := err.(proto.Message); ok {
+ return protoadapt.MessageV1Of(pm)
+ }
+
+ if reflect.TypeOf(err).Kind() == reflect.Ptr {
+ a, aerr := typeurl.MarshalAny(err)
+ if aerr == nil {
+ return &anypb.Any{
+ TypeUrl: a.GetTypeUrl(),
+ Value: a.GetValue(),
+ }
+ }
+ }
+ return nil
+}
+
+// ToGRPCf maps the error to grpc error codes, assembling the formatting string
+// and combining it with the target error string.
+//
+// This is equivalent to grpc.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
+func ToGRPCf(err error, format string, args ...interface{}) error {
+ return ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
+}
+
+// ToNative returns the underlying error from a grpc service based on the grpc
+// error code. The grpc details are used to add wrap the error in more context
+// or support multiple errors.
+func ToNative(err error) error {
+ if err == nil {
+ return nil
+ }
+
+ s, isGRPC := status.FromError(err)
+
+ var (
+ desc string
+ code codes.Code
+ )
+
+ if isGRPC {
+ desc = s.Message()
+ code = s.Code()
+ } else {
+ desc = err.Error()
+ code = codes.Unknown
+ }
+
+ var cls error // divide these into error classes, becomes the cause
+
+ switch code {
+ case codes.InvalidArgument:
+ cls = errdefs.ErrInvalidArgument
+ case codes.AlreadyExists:
+ cls = errdefs.ErrAlreadyExists
+ case codes.NotFound:
+ cls = errdefs.ErrNotFound
+ case codes.Unavailable:
+ cls = errdefs.ErrUnavailable
+ case codes.FailedPrecondition:
+ // TODO: Has suffix is not sufficient for conflict and not modified
+ // Message should start with ": " or be at beginning of a line
+ // Message should end with ": " or be at the end of a line
+ // Compile a regex
+ if desc == errdefs.ErrConflict.Error() || strings.HasSuffix(desc, ": "+errdefs.ErrConflict.Error()) {
+ cls = errdefs.ErrConflict
+ } else if desc == errdefs.ErrNotModified.Error() || strings.HasSuffix(desc, ": "+errdefs.ErrNotModified.Error()) {
+ cls = errdefs.ErrNotModified
+ } else {
+ cls = errdefs.ErrFailedPrecondition
+ }
+ case codes.Unimplemented:
+ cls = errdefs.ErrNotImplemented
+ case codes.Canceled:
+ cls = context.Canceled
+ case codes.DeadlineExceeded:
+ cls = context.DeadlineExceeded
+ case codes.Aborted:
+ cls = errdefs.ErrAborted
+ case codes.Unauthenticated:
+ cls = errdefs.ErrUnauthenticated
+ case codes.PermissionDenied:
+ cls = errdefs.ErrPermissionDenied
+ case codes.Internal:
+ cls = errdefs.ErrInternal
+ case codes.DataLoss:
+ cls = errdefs.ErrDataLoss
+ case codes.OutOfRange:
+ cls = errdefs.ErrOutOfRange
+ case codes.ResourceExhausted:
+ cls = errdefs.ErrResourceExhausted
+ default:
+ if idx := strings.LastIndex(desc, cause.UnexpectedStatusPrefix); idx > 0 {
+ if status, uerr := strconv.Atoi(desc[idx+len(cause.UnexpectedStatusPrefix):]); uerr == nil && status >= 200 && status < 600 {
+ cls = cause.ErrUnexpectedStatus{Status: status}
+ }
+ }
+ if cls == nil {
+ cls = errdefs.ErrUnknown
+ }
+ }
+
+ msg := rebaseMessage(cls, desc)
+ if msg == "" {
+ err = cls
+ } else if msg != desc {
+ err = fmt.Errorf("%s: %w", msg, cls)
+ } else if wm, ok := cls.(interface{ WithMessage(string) error }); ok {
+ err = wm.WithMessage(msg)
+ } else {
+ err = fmt.Errorf("%s: %w", msg, cls)
+ }
+
+ if isGRPC {
+ errs := []error{err}
+ for _, a := range s.Details() {
+ var derr error
+
+ // First decode error if needed
+ if s, ok := a.(*spb.Status); ok {
+ derr = ToNative(status.ErrorProto(s))
+ } else if e, ok := a.(error); ok {
+ derr = e
+ } else if dany, ok := a.(typeurl.Any); ok {
+ i, uerr := typeurl.UnmarshalAny(dany)
+ if uerr == nil {
+ if e, ok = i.(error); ok {
+ derr = e
+ } else {
+ derr = fmt.Errorf("non-error unmarshalled detail: %v", i)
+ }
+ } else {
+ derr = fmt.Errorf("error of type %q with failure to unmarshal: %v", dany.GetTypeUrl(), uerr)
+ }
+ } else {
+ derr = fmt.Errorf("non-error detail: %v", a)
+ }
+
+ switch werr := derr.(type) {
+ case interface{ WrapError(error) error }:
+ errs[len(errs)-1] = werr.WrapError(errs[len(errs)-1])
+ case interface{ JoinErrors(...error) error }:
+ // TODO: Consider whether this should support joining a subset
+ errs[0] = werr.JoinErrors(errs...)
+ case interface{ CollapseError() }:
+ errs[len(errs)-1] = types.CollapsedError(errs[len(errs)-1], derr)
+ default:
+ errs = append(errs, derr)
+ }
+
+ }
+ if len(errs) > 1 {
+ err = errors.Join(errs...)
+ } else {
+ err = errs[0]
+ }
+ }
+
+ return err
+}
+
+// rebaseMessage removes the repeats for an error at the end of an error
+// string. This will happen when taking an error over grpc then remapping it.
+//
+// Effectively, we just remove the string of cls from the end of err if it
+// appears there.
+func rebaseMessage(cls error, desc string) string {
+ clss := cls.Error()
+ if desc == clss {
+ return ""
+ }
+
+ return strings.TrimSuffix(desc, ": "+clss)
+}
diff --git a/vendor/github.com/containerd/errdefs/pkg/internal/types/collapsible.go b/vendor/github.com/containerd/errdefs/pkg/internal/types/collapsible.go
new file mode 100644
index 0000000000..a37e7722a8
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/pkg/internal/types/collapsible.go
@@ -0,0 +1,57 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package types
+
+import "fmt"
+
+// CollapsibleError indicates the error should be collapsed
+type CollapsibleError interface {
+ CollapseError()
+}
+
+// CollapsedError returns a new error with the collapsed
+// error returned on unwrapped or when formatted with "%+v"
+func CollapsedError(err error, collapsed ...error) error {
+ return collapsedError{err, collapsed}
+}
+
+type collapsedError struct {
+ error
+ collapsed []error
+}
+
+func (c collapsedError) Unwrap() []error {
+ return append([]error{c.error}, c.collapsed...)
+}
+
+func (c collapsedError) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ if s.Flag('+') {
+ fmt.Fprintf(s, "%+v", c.error)
+ for _, err := range c.collapsed {
+ fmt.Fprintf(s, "\n%+v", err)
+ }
+ return
+ }
+ fallthrough
+ case 's':
+ fmt.Fprint(s, c.Error())
+ case 'q':
+ fmt.Fprintf(s, "%q", c.Error())
+ }
+}
diff --git a/vendor/github.com/containerd/platforms/.gitattributes b/vendor/github.com/containerd/platforms/.gitattributes
new file mode 100644
index 0000000000..a0717e4b3b
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/.gitattributes
@@ -0,0 +1 @@
+*.go text eol=lf
\ No newline at end of file
diff --git a/vendor/github.com/containerd/platforms/.golangci.yml b/vendor/github.com/containerd/platforms/.golangci.yml
new file mode 100644
index 0000000000..9320503c7b
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/.golangci.yml
@@ -0,0 +1,25 @@
+version: "2"
+linters:
+ enable:
+ - copyloopvar
+ - dupword
+ - gosec
+ - misspell
+ - nolintlint
+ - revive
+ - unconvert
+ disable:
+ - errcheck
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+formatters:
+ enable:
+ - gofmt
+ - goimports
+ exclusions:
+ generated: lax
diff --git a/vendor/github.com/containerd/platforms/LICENSE b/vendor/github.com/containerd/platforms/LICENSE
new file mode 100644
index 0000000000..584149b6ee
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd Authors
+
+ 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
+
+ https://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.
diff --git a/vendor/github.com/containerd/platforms/README.md b/vendor/github.com/containerd/platforms/README.md
new file mode 100644
index 0000000000..2059de771c
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/README.md
@@ -0,0 +1,32 @@
+# platforms
+
+A Go package for formatting, normalizing and matching container platforms.
+
+This package is based on the Open Containers Image Spec definition of a [platform](https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/descriptor.go#L52).
+
+## Platform Specifier
+
+While the OCI platform specifications provide a tool for components to
+specify structured information, user input typically doesn't need the full
+context and much can be inferred. To solve this problem, this package introduces
+"specifiers". A specifier has the format
+`||/[/]`. The user can provide either the
+operating system or the architecture or both.
+
+An example of a common specifier is `linux/amd64`. If the host has a default
+runtime that matches this, the user can simply provide the component that
+matters. For example, if an image provides `amd64` and `arm64` support, the
+operating system, `linux` can be inferred, so they only have to provide
+`arm64` or `amd64`. Similar behavior is implemented for operating systems,
+where the architecture may be known but a runtime may support images from
+different operating systems.
+
+## Project details
+
+**platforms** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
\ No newline at end of file
diff --git a/vendor/github.com/containerd/platforms/compare.go b/vendor/github.com/containerd/platforms/compare.go
new file mode 100644
index 0000000000..ea5e7aa14b
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/compare.go
@@ -0,0 +1,364 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "strconv"
+ "strings"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// MatchComparer is able to match and compare platforms to
+// filter and sort platforms.
+type MatchComparer interface {
+ Matcher
+
+ Less(specs.Platform, specs.Platform) bool
+}
+
+type platformVersions struct {
+ major []int
+ minor []int
+}
+
+var arm64variantToVersion = map[string]platformVersions{
+ "v8": {[]int{8}, []int{0}},
+ "v8.0": {[]int{8}, []int{0}},
+ "v8.1": {[]int{8}, []int{1}},
+ "v8.2": {[]int{8}, []int{2}},
+ "v8.3": {[]int{8}, []int{3}},
+ "v8.4": {[]int{8}, []int{4}},
+ "v8.5": {[]int{8}, []int{5}},
+ "v8.6": {[]int{8}, []int{6}},
+ "v8.7": {[]int{8}, []int{7}},
+ "v8.8": {[]int{8}, []int{8}},
+ "v8.9": {[]int{8}, []int{9}},
+ "v9": {[]int{9, 8}, []int{0, 5}},
+ "v9.0": {[]int{9, 8}, []int{0, 5}},
+ "v9.1": {[]int{9, 8}, []int{1, 6}},
+ "v9.2": {[]int{9, 8}, []int{2, 7}},
+ "v9.3": {[]int{9, 8}, []int{3, 8}},
+ "v9.4": {[]int{9, 8}, []int{4, 9}},
+ "v9.5": {[]int{9, 8}, []int{5, 9}},
+ "v9.6": {[]int{9, 8}, []int{6, 9}},
+ "v9.7": {[]int{9, 8}, []int{7, 9}},
+}
+
+// platformVector returns an (ordered) vector of appropriate specs.Platform
+// objects to try matching for the given platform object (see platforms.Only).
+func platformVector(platform specs.Platform) []specs.Platform {
+ vector := []specs.Platform{platform}
+
+ switch platform.Architecture {
+ case "amd64":
+ if amd64Version, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && amd64Version > 1 {
+ for amd64Version--; amd64Version >= 1; amd64Version-- {
+ vector = append(vector, specs.Platform{
+ Architecture: platform.Architecture,
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ Variant: "v" + strconv.Itoa(amd64Version),
+ })
+ }
+ }
+ vector = append(vector, specs.Platform{
+ Architecture: "386",
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ })
+ case "arm":
+ if armVersion, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && armVersion > 5 {
+ for armVersion--; armVersion >= 5; armVersion-- {
+ vector = append(vector, specs.Platform{
+ Architecture: platform.Architecture,
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ Variant: "v" + strconv.Itoa(armVersion),
+ })
+ }
+ }
+ case "arm64":
+ variant := platform.Variant
+ if variant == "" {
+ variant = "v8"
+ }
+
+ vector = []specs.Platform{} // Reset vector, the first variant will be added in loop.
+ arm64Versions, ok := arm64variantToVersion[variant]
+ if !ok {
+ break
+ }
+ for i, major := range arm64Versions.major {
+ for minor := arm64Versions.minor[i]; minor >= 0; minor-- {
+ arm64Variant := "v" + strconv.Itoa(major) + "." + strconv.Itoa(minor)
+ if minor == 0 {
+ arm64Variant = "v" + strconv.Itoa(major)
+ }
+ vector = append(vector, specs.Platform{
+ Architecture: "arm64",
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ Variant: arm64Variant,
+ })
+ }
+ }
+
+ // All arm64/v8.x and arm64/v9.x are compatible with arm/v8 (32-bits) and below.
+ // There's no arm64 v9 variant, so it's normalized to v8.
+ if strings.HasPrefix(variant, "v8") || strings.HasPrefix(variant, "v9") {
+ variant = "v8"
+ }
+ vector = append(vector, platformVector(specs.Platform{
+ Architecture: "arm",
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ Variant: variant,
+ })...)
+ }
+
+ return vector
+}
+
+// Only returns a match comparer for a single platform
+// using default resolution logic for the platform.
+//
+// For arm64/v9.x, will also match arm64/v9.{0..x-1} and arm64/v8.{0..x+5}
+// For arm64/v8.x, will also match arm64/v8.{0..x-1}
+// For arm/v8, will also match arm/v7, arm/v6 and arm/v5
+// For arm/v7, will also match arm/v6 and arm/v5
+// For arm/v6, will also match arm/v5
+// For amd64, will also match 386
+func Only(platform specs.Platform) MatchComparer {
+ return Ordered(platformVector(Normalize(platform))...)
+}
+
+// OnlyOS returns a match comparer that matches only platforms with the same
+// OS, OS version, and OS features, regardless of architecture. When comparing,
+// it always ranks the best architecture match highest using the default
+// platform resolution logic.
+func OnlyOS(platform specs.Platform) MatchComparer {
+ normalized := Normalize(platform)
+ return onlyOSComparer{
+ platform: normalized,
+ osvM: newOSVersionMatcher(normalized),
+ archOrder: orderedPlatformComparer{
+ matchers: []Matcher{NewMatcher(normalized)},
+ },
+ }
+}
+
+func newOSVersionMatcher(platform specs.Platform) osVerMatcher {
+ if platform.OS == "windows" {
+ return &windowsVersionMatcher{
+ windowsOSVersion: getWindowsOSVersion(platform.OSVersion),
+ }
+ }
+ return nil
+}
+
+type onlyOSComparer struct {
+ platform specs.Platform
+ osvM osVerMatcher
+ archOrder orderedPlatformComparer
+}
+
+func (c onlyOSComparer) matchOS(platform specs.Platform) bool {
+ normalized := Normalize(platform)
+ if c.platform.OS != normalized.OS {
+ return false
+ }
+ if c.osvM != nil {
+ if !c.osvM.Match(platform.OSVersion) {
+ return false
+ }
+ }
+ if len(normalized.OSFeatures) > 0 {
+ if len(c.platform.OSFeatures) < len(normalized.OSFeatures) {
+ return false
+ }
+ j := 0
+ for _, feature := range normalized.OSFeatures {
+ found := false
+ for ; j < len(c.platform.OSFeatures); j++ {
+ if feature == c.platform.OSFeatures[j] {
+ found = true
+ j++
+ break
+ }
+ if feature < c.platform.OSFeatures[j] {
+ return false
+ }
+ }
+ if !found {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func (c onlyOSComparer) Match(platform specs.Platform) bool {
+ return c.matchOS(platform)
+}
+
+func (c onlyOSComparer) Less(p1, p2 specs.Platform) bool {
+ p1m := c.matchOS(p1)
+ p2m := c.matchOS(p2)
+ if p1m && !p2m {
+ return true
+ }
+ if !p1m {
+ return false
+ }
+ // Both match — rank by architecture preference
+ return c.archOrder.Less(p1, p2)
+}
+
+// OnlyStrict returns a match comparer for a single platform.
+//
+// Unlike Only, OnlyStrict does not match sub platforms.
+// So, "arm/vN" will not match "arm/vM" where M < N,
+// and "amd64" will not also match "386".
+//
+// OnlyStrict matches non-canonical forms.
+// So, "arm64" matches "arm/64/v8".
+func OnlyStrict(platform specs.Platform) MatchComparer {
+ return Ordered(Normalize(platform))
+}
+
+// Ordered returns a platform MatchComparer which matches any of the platforms
+// but orders them in order they are provided.
+func Ordered(platforms ...specs.Platform) MatchComparer {
+ matchers := make([]Matcher, len(platforms))
+ for i := range platforms {
+ matchers[i] = NewMatcher(platforms[i])
+ }
+ return orderedPlatformComparer{
+ matchers: matchers,
+ }
+}
+
+// Any returns a platform MatchComparer which matches any of the platforms
+// with no preference for ordering.
+func Any(platforms ...specs.Platform) MatchComparer {
+ matchers := make([]Matcher, len(platforms))
+ for i := range platforms {
+ matchers[i] = NewMatcher(platforms[i])
+ }
+ return anyPlatformComparer{
+ matchers: matchers,
+ }
+}
+
+// All is a platform MatchComparer which matches all platforms
+// with preference for ordering.
+var All MatchComparer = allPlatformComparer{}
+
+type orderedPlatformComparer struct {
+ matchers []Matcher
+}
+
+func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
+ for _, m := range c.matchers {
+ if m.Match(platform) {
+ return true
+ }
+ }
+ return false
+}
+
+func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
+ for _, m := range c.matchers {
+ p1m := m.Match(p1)
+ p2m := m.Match(p2)
+ if p1m && !p2m {
+ return true
+ }
+ if p1m || p2m {
+ if p1m && p2m {
+ // Prefer one with most matching features
+ if len(p1.OSFeatures) != len(p2.OSFeatures) {
+ return len(p1.OSFeatures) > len(p2.OSFeatures)
+ }
+ }
+ return false
+ }
+ }
+ if len(p1.OSFeatures) > 0 || len(p2.OSFeatures) > 0 {
+ p1.OSFeatures = nil
+ p2.OSFeatures = nil
+ return c.Less(p1, p2)
+ }
+ return false
+}
+
+type anyPlatformComparer struct {
+ matchers []Matcher
+}
+
+func (c anyPlatformComparer) Match(platform specs.Platform) bool {
+ for _, m := range c.matchers {
+ if m.Match(platform) {
+ return true
+ }
+ }
+ return false
+}
+
+func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
+ var p1m, p2m bool
+ for _, m := range c.matchers {
+ if !p1m && m.Match(p1) {
+ p1m = true
+ }
+ if !p2m && m.Match(p2) {
+ p2m = true
+ }
+ if p1m && p2m {
+ if len(p1.OSFeatures) != len(p2.OSFeatures) {
+ return len(p1.OSFeatures) > len(p2.OSFeatures)
+ }
+ break
+ }
+ }
+
+ // If neither match and has features, strip features and compare
+ if !p1m && !p2m && (len(p1.OSFeatures) > 0 || len(p2.OSFeatures) > 0) {
+ p1.OSFeatures = nil
+ p2.OSFeatures = nil
+ return c.Less(p1, p2)
+ }
+
+ // If one matches, and the other does, sort match first
+ return p1m && !p2m
+}
+
+type allPlatformComparer struct{}
+
+func (allPlatformComparer) Match(specs.Platform) bool {
+ return true
+}
+
+func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
+ return false
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo.go b/vendor/github.com/containerd/platforms/cpuinfo.go
new file mode 100644
index 0000000000..91f50e8c88
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "runtime"
+ "sync"
+
+ "github.com/containerd/log"
+)
+
+// Present the ARM instruction set architecture, eg: v7, v8
+// Don't use this value directly; call cpuVariant() instead.
+var cpuVariantValue string
+
+var cpuVariantOnce sync.Once
+
+func cpuVariant() string {
+ cpuVariantOnce.Do(func() {
+ if isArmArch(runtime.GOARCH) {
+ var err error
+ cpuVariantValue, err = getCPUVariant()
+ if err != nil {
+ log.L.Errorf("Error getCPUVariant for OS %s: %v", runtime.GOOS, err)
+ }
+ }
+ })
+ return cpuVariantValue
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo_linux.go b/vendor/github.com/containerd/platforms/cpuinfo_linux.go
new file mode 100644
index 0000000000..06da8b9612
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo_linux.go
@@ -0,0 +1,158 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+
+ "golang.org/x/sys/unix"
+)
+
+// getMachineArch retrieves the machine architecture through system call
+func getMachineArch() (string, error) {
+ var uname unix.Utsname
+ err := unix.Uname(&uname)
+ if err != nil {
+ return "", err
+ }
+
+ arch := string(uname.Machine[:bytes.IndexByte(uname.Machine[:], 0)])
+
+ return arch, nil
+}
+
+// For Linux, the kernel has already detected the ABI, ISA and Features.
+// So we don't need to access the ARM registers to detect platform information
+// by ourselves. We can just parse these information from /proc/cpuinfo
+func getCPUInfo(pattern string) (info string, err error) {
+ cpuinfo, err := os.Open("/proc/cpuinfo")
+ if err != nil {
+ return "", err
+ }
+ defer cpuinfo.Close()
+
+ // Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
+ // the first core is enough.
+ scanner := bufio.NewScanner(cpuinfo)
+ for scanner.Scan() {
+ newline := scanner.Text()
+ list := strings.Split(newline, ":")
+
+ if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
+ return strings.TrimSpace(list[1]), nil
+ }
+ }
+
+ // Check whether the scanner encountered errors
+ err = scanner.Err()
+ if err != nil {
+ return "", err
+ }
+
+ return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errNotFound)
+}
+
+// getCPUVariantFromArch get CPU variant from arch through a system call
+func getCPUVariantFromArch(arch string) (string, error) {
+ var variant string
+
+ arch = strings.ToLower(arch)
+
+ if arch == "aarch64" {
+ variant = "8"
+ } else if arch[0:4] == "armv" && len(arch) >= 5 {
+ // Valid arch format is in form of armvXx
+ switch arch[3:5] {
+ case "v8":
+ variant = "8"
+ case "v7":
+ variant = "7"
+ case "v6":
+ variant = "6"
+ case "v5":
+ variant = "5"
+ case "v4":
+ variant = "4"
+ case "v3":
+ variant = "3"
+ default:
+ variant = "unknown"
+ }
+ } else {
+ return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errInvalidArgument)
+ }
+ return variant, nil
+}
+
+// getCPUVariant returns cpu variant for ARM
+// We first try reading "Cpu architecture" field from /proc/cpuinfo
+// If we can't find it, then fall back using a system call
+// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
+// was not present.
+func getCPUVariant() (string, error) {
+ variant, err := getCPUInfo("Cpu architecture")
+ if err != nil {
+ if errors.Is(err, errNotFound) {
+ // Let's try getting CPU variant from machine architecture
+ arch, err := getMachineArch()
+ if err != nil {
+ return "", fmt.Errorf("failure getting machine architecture: %v", err)
+ }
+
+ variant, err = getCPUVariantFromArch(arch)
+ if err != nil {
+ return "", fmt.Errorf("failure getting CPU variant from machine architecture: %v", err)
+ }
+ } else {
+ return "", fmt.Errorf("failure getting CPU variant: %v", err)
+ }
+ }
+
+ // handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
+ // https://www.raspberrypi.org/forums/viewtopic.php?t=12614
+ if runtime.GOARCH == "arm" && variant == "7" {
+ model, err := getCPUInfo("model name")
+ if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
+ variant = "6"
+ }
+ }
+
+ switch strings.ToLower(variant) {
+ case "8", "aarch64":
+ variant = "v8"
+ case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
+ variant = "v7"
+ case "6", "6tej":
+ variant = "v6"
+ case "5", "5t", "5te", "5tej":
+ variant = "v5"
+ case "4", "4t":
+ variant = "v4"
+ case "3":
+ variant = "v3"
+ default:
+ variant = "unknown"
+ }
+
+ return variant, nil
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo_other.go b/vendor/github.com/containerd/platforms/cpuinfo_other.go
new file mode 100644
index 0000000000..b8c7a4b226
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo_other.go
@@ -0,0 +1,55 @@
+//go:build !linux
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "fmt"
+ "runtime"
+)
+
+func getCPUVariant() (string, error) {
+ var variant string
+
+ switch runtime.GOOS {
+ case "windows", "darwin":
+ // Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
+ // runtime.GOARCH to determine the variants
+ switch runtime.GOARCH {
+ case "arm64":
+ variant = "v8"
+ case "arm":
+ variant = "v7"
+ default:
+ variant = "unknown"
+ }
+ case "freebsd":
+ // FreeBSD supports ARMv6 and ARMv7 as well as ARMv4 and ARMv5 (though deprecated)
+ // detecting those variants is currently unimplemented
+ switch runtime.GOARCH {
+ case "arm64":
+ variant = "v8"
+ default:
+ variant = "unknown"
+ }
+ default:
+ return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errNotImplemented)
+ }
+
+ return variant, nil
+}
diff --git a/vendor/github.com/containerd/containerd/platforms/database.go b/vendor/github.com/containerd/platforms/database.go
similarity index 93%
rename from vendor/github.com/containerd/containerd/platforms/database.go
rename to vendor/github.com/containerd/platforms/database.go
index dbe9957ca9..7a6f0d98cd 100644
--- a/vendor/github.com/containerd/containerd/platforms/database.go
+++ b/vendor/github.com/containerd/platforms/database.go
@@ -21,13 +21,6 @@ import (
"strings"
)
-// isLinuxOS returns true if the operating system is Linux.
-//
-// The OS value should be normalized before calling this function.
-func isLinuxOS(os string) bool {
- return os == "linux"
-}
-
// These function are generated from https://golang.org/src/go/build/syslist.go.
//
// We use switch statements because they are slightly faster than map lookups
@@ -94,8 +87,10 @@ func normalizeArch(arch, variant string) (string, string) {
case "aarch64", "arm64":
arch = "arm64"
switch variant {
- case "8", "v8":
+ case "8", "v8", "v8.0":
variant = ""
+ case "9", "9.0", "v9.0":
+ variant = "v9"
}
case "armhf":
arch = "arm"
diff --git a/vendor/github.com/containerd/platforms/defaults.go b/vendor/github.com/containerd/platforms/defaults.go
new file mode 100644
index 0000000000..9d898d60e6
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults.go
@@ -0,0 +1,29 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+// DefaultString returns the default string specifier for the platform,
+// with [PR#6](https://github.com/containerd/platforms/pull/6) the result
+// may now also include the OSVersion from the provided platform specification.
+func DefaultString() string {
+ return FormatAll(DefaultSpec())
+}
+
+// DefaultStrict returns strict form of Default.
+func DefaultStrict() MatchComparer {
+ return OnlyStrict(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_darwin.go b/vendor/github.com/containerd/platforms/defaults_darwin.go
new file mode 100644
index 0000000000..72355ca85f
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_darwin.go
@@ -0,0 +1,44 @@
+//go:build darwin
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+ return Ordered(DefaultSpec(), specs.Platform{
+ // darwin runtime also supports Linux binary via runu/LKL
+ OS: "linux",
+ Architecture: runtime.GOARCH,
+ })
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_freebsd.go b/vendor/github.com/containerd/platforms/defaults_freebsd.go
new file mode 100644
index 0000000000..d3fe89e076
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_freebsd.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+ return Ordered(DefaultSpec(), specs.Platform{
+ OS: "linux",
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ })
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_unix.go b/vendor/github.com/containerd/platforms/defaults_unix.go
new file mode 100644
index 0000000000..44acc47eb3
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_unix.go
@@ -0,0 +1,40 @@
+//go:build !windows && !darwin && !freebsd
+
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+ return Only(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_windows.go b/vendor/github.com/containerd/platforms/defaults_windows.go
new file mode 100644
index 0000000000..64e2846674
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_windows.go
@@ -0,0 +1,42 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "fmt"
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sys/windows"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ major, minor, build := windows.RtlGetNtVersionNumbers()
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ OSVersion: fmt.Sprintf("%d.%d.%d", major, minor, build),
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the current platform's default platform specification.
+func Default() MatchComparer {
+ return &windowsMatchComparer{Matcher: NewMatcher(DefaultSpec())}
+}
diff --git a/vendor/github.com/containerd/platforms/errors.go b/vendor/github.com/containerd/platforms/errors.go
new file mode 100644
index 0000000000..5ad721e779
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/errors.go
@@ -0,0 +1,30 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import "errors"
+
+// These errors mirror the errors defined in [github.com/containerd/containerd/errdefs],
+// however, they are not exported as they are not expected to be used as sentinel
+// errors by consumers of this package.
+//
+//nolint:unused // not all errors are used on all platforms.
+var (
+ errNotFound = errors.New("not found")
+ errInvalidArgument = errors.New("invalid argument")
+ errNotImplemented = errors.New("not implemented")
+)
diff --git a/vendor/github.com/containerd/platforms/platform_windows_compat.go b/vendor/github.com/containerd/platforms/platform_windows_compat.go
new file mode 100644
index 0000000000..ef21a29068
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platform_windows_compat.go
@@ -0,0 +1,176 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package platforms
+
+import (
+ "slices"
+ "strconv"
+ "strings"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// windowsOSVersion is a wrapper for Windows version information
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
+type windowsOSVersion struct {
+ Version uint32
+ MajorVersion uint8
+ MinorVersion uint8
+ Build uint16
+}
+
+// Windows Client and Server build numbers.
+//
+// See:
+// https://learn.microsoft.com/en-us/windows/release-health/release-information
+// https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info
+// https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
+const (
+ // rs5 (version 1809, codename "Redstone 5") corresponds to Windows Server
+ // 2019 (ltsc2019), and Windows 10 (October 2018 Update).
+ rs5 = 17763
+ // ltsc2019 (Windows Server 2019) is an alias for [RS5].
+ ltsc2019 = rs5
+
+ // v21H2Server corresponds to Windows Server 2022 (ltsc2022).
+ v21H2Server = 20348
+ // ltsc2022 (Windows Server 2022) is an alias for [v21H2Server]
+ ltsc2022 = v21H2Server
+
+ // v22H2Win11 corresponds to Windows 11 (2022 Update).
+ v22H2Win11 = 22621
+
+ // v23H2 is the 23H2 release in the Windows Server annual channel.
+ v23H2 = 25398
+
+ // Windows Server 2025 build 26100
+ v25H1Server = 26100
+ ltsc2025 = v25H1Server
+)
+
+// List of stable ABI compliant ltsc releases
+// Note: List must be sorted in ascending order
+var compatLTSCReleases = []uint16{
+ ltsc2022,
+ ltsc2025,
+}
+
+// CheckHostAndContainerCompat checks if given host and container
+// OS versions are compatible.
+// It includes support for stable ABI compliant versions as well.
+// Every release after WS 2022 will support the previous ltsc
+// container image. Stable ABI is in preview mode for windows 11 client.
+// Refer: https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10#windows-server-host-os-compatibility
+func checkWindowsHostAndContainerCompat(host, ctr windowsOSVersion) bool {
+ // check major minor versions of host and guest
+ if host.MajorVersion != ctr.MajorVersion ||
+ host.MinorVersion != ctr.MinorVersion {
+ return false
+ }
+
+ // If host is < WS 2022, exact version match is required
+ if host.Build < ltsc2022 {
+ return host.Build == ctr.Build
+ }
+
+ // Find the latest LTSC version that is earlier than the host version.
+ // This is the earliest version of container that the host can run.
+ //
+ // If the host version is an LTSC, then it supports compatibility with
+ // everything from the previous LTSC up to itself, so we want supportedLTSCRelease
+ // to be the previous entry.
+ //
+ // If no match is found, then we know that the host is LTSC2022 exactly,
+ // since we already checked that it's not less than LTSC2022.
+ var supportedLTSCRelease uint16 = ltsc2022
+ for i := len(compatLTSCReleases) - 1; i >= 0; i-- {
+ if host.Build > compatLTSCReleases[i] {
+ supportedLTSCRelease = compatLTSCReleases[i]
+ break
+ }
+ }
+ return supportedLTSCRelease <= ctr.Build && ctr.Build <= host.Build
+}
+
+func getWindowsOSVersion(osVersionPrefix string) windowsOSVersion {
+ if strings.Count(osVersionPrefix, ".") < 2 {
+ return windowsOSVersion{}
+ }
+
+ major, extra, _ := strings.Cut(osVersionPrefix, ".")
+ minor, extra, _ := strings.Cut(extra, ".")
+ build, _, _ := strings.Cut(extra, ".")
+
+ majorVersion, err := strconv.ParseUint(major, 10, 8)
+ if err != nil {
+ return windowsOSVersion{}
+ }
+
+ minorVersion, err := strconv.ParseUint(minor, 10, 8)
+ if err != nil {
+ return windowsOSVersion{}
+ }
+ buildNumber, err := strconv.ParseUint(build, 10, 16)
+ if err != nil {
+ return windowsOSVersion{}
+ }
+
+ return windowsOSVersion{
+ MajorVersion: uint8(majorVersion),
+ MinorVersion: uint8(minorVersion),
+ Build: uint16(buildNumber),
+ }
+}
+
+type windowsVersionMatcher struct {
+ windowsOSVersion
+}
+
+func (m windowsVersionMatcher) Match(v string) bool {
+ if m.isEmpty() || v == "" {
+ return true
+ }
+ osv := getWindowsOSVersion(v)
+ return checkWindowsHostAndContainerCompat(m.windowsOSVersion, osv)
+}
+
+func (m windowsVersionMatcher) isEmpty() bool {
+ return m.MajorVersion == 0 && m.MinorVersion == 0 && m.Build == 0
+}
+
+type windowsMatchComparer struct {
+ Matcher
+}
+
+func (c *windowsMatchComparer) Less(p1, p2 specs.Platform) bool {
+ m1, m2 := c.Match(p1), c.Match(p2)
+ if m1 && m2 {
+ return p1.OSVersion > p2.OSVersion
+ }
+ return m1 && !m2
+}
+
+type windowsStripFeaturesMatcher struct {
+ Matcher
+}
+
+func (m windowsStripFeaturesMatcher) Match(p specs.Platform) bool {
+ if i := slices.Index(p.OSFeatures, "win32k"); i >= 0 {
+ p.OSFeatures = slices.Delete(slices.Clone(p.OSFeatures), i, i+1)
+ }
+ return m.Matcher.Match(p)
+}
diff --git a/vendor/github.com/containerd/platforms/platforms.go b/vendor/github.com/containerd/platforms/platforms.go
new file mode 100644
index 0000000000..81d7ee3869
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platforms.go
@@ -0,0 +1,487 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+// Package platforms provides a toolkit for normalizing, matching and
+// specifying container platforms.
+//
+// Centered around OCI platform specifications, we define a string-based
+// specifier syntax that can be used for user input. With a specifier, users
+// only need to specify the parts of the platform that are relevant to their
+// context, providing an operating system or architecture or both.
+//
+// How do I use this package?
+//
+// The vast majority of use cases should simply use the match function with
+// user input. The first step is to parse a specifier into a matcher:
+//
+// m, err := Parse("linux")
+// if err != nil { ... }
+//
+// Once you have a matcher, use it to match against the platform declared by a
+// component, typically from an image or runtime. Since extracting an images
+// platform is a little more involved, we'll use an example against the
+// platform default:
+//
+// if ok := m.Match(Default()); !ok { /* doesn't match */ }
+//
+// This can be composed in loops for resolving runtimes or used as a filter for
+// fetch and select images.
+//
+// More details of the specifier syntax and platform spec follow.
+//
+// # Declaring Platform Support
+//
+// Components that have strict platform requirements should use the OCI
+// platform specification to declare their support. Typically, this will be
+// images and runtimes that should make these declaring which platform they
+// support specifically. This looks roughly as follows:
+//
+// type Platform struct {
+// Architecture string
+// OS string
+// Variant string
+// }
+//
+// Most images and runtimes should at least set Architecture and OS, according
+// to their GOARCH and GOOS values, respectively (follow the OCI image
+// specification when in doubt). ARM should set variant under certain
+// discussions, which are outlined below.
+//
+// # Platform Specifiers
+//
+// While the OCI platform specifications provide a tool for components to
+// specify structured information, user input typically doesn't need the full
+// context and much can be inferred. To solve this problem, we introduced
+// "specifiers". A specifier has the format
+// `||/[/]`. The user can provide either the
+// operating system or the architecture or both.
+//
+// An example of a common specifier is `linux/amd64`. If the host has a default
+// of runtime that matches this, the user can simply provide the component that
+// matters. For example, if a image provides amd64 and arm64 support, the
+// operating system, `linux` can be inferred, so they only have to provide
+// `arm64` or `amd64`. Similar behavior is implemented for operating systems,
+// where the architecture may be known but a runtime may support images from
+// different operating systems.
+//
+// # Normalization
+//
+// Because not all users are familiar with the way the Go runtime represents
+// platforms, several normalizations have been provided to make this package
+// easier to user.
+//
+// The following are performed for architectures:
+//
+// Value Normalized
+// aarch64 arm64
+// armhf arm
+// armel arm/v6
+// i386 386
+// x86_64 amd64
+// x86-64 amd64
+//
+// We also normalize the operating system `macos` to `darwin`.
+//
+// # ARM Support
+//
+// To qualify ARM architecture, the Variant field is used to qualify the arm
+// version. The most common arm version, v7, is represented without the variant
+// unless it is explicitly provided. This is treated as equivalent to armhf. A
+// previous architecture, armel, will be normalized to arm/v6.
+//
+// Similarly, the most common arm64 version v8, and most common amd64 version v1
+// are represented without the variant.
+//
+// While these normalizations are provided, their support on arm platforms has
+// not yet been fully implemented and tested.
+package platforms
+
+import (
+ "fmt"
+ "net/url"
+ "path"
+ "regexp"
+ "runtime"
+ "slices"
+ "strconv"
+ "strings"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+var (
+ specifierRe = regexp.MustCompile(`^[A-Za-z0-9_.-]+$`)
+ osRe = regexp.MustCompile(`^([A-Za-z0-9_-]+)(?:\(([A-Za-z0-9_.%-]*)((?:\+[A-Za-z0-9_.%-]+)*)\))?$`)
+)
+
+// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
+type Platform = specs.Platform
+
+// Matcher matches platforms specifications, provided by an image or runtime.
+type Matcher interface {
+ Match(platform specs.Platform) bool
+}
+
+// NewMatcher returns a simple matcher based on the provided platform
+// specification. The returned matcher only looks for equality based on os,
+// architecture and variant.
+//
+// One may implement their own matcher if this doesn't provide the required
+// functionality.
+//
+// Applications should opt to use `Match` over directly parsing specifiers.
+//
+// For OSFeatures, this matcher will match if the platform to match has
+// OSFeatures which are a subset of the OSFeatures of the platform
+// provided to NewMatcher.
+func NewMatcher(platform specs.Platform) Matcher {
+ m := &matcher{
+ Platform: Normalize(platform),
+ }
+
+ if platform.OS == "windows" {
+ m.osvM = &windowsVersionMatcher{
+ windowsOSVersion: getWindowsOSVersion(platform.OSVersion),
+ }
+
+ // In prior versions, the win32k os feature was not considered for matching,
+ // strip out the win32k feature for comparison
+ var stripped Matcher = windowsStripFeaturesMatcher{m}
+
+ // In prior versions, on windows, the returned matcher implements a
+ // MatchComprarer interface.
+ // This preserves that behavior for backwards compatibility.
+ //
+ // TODO: This isn't actually used in this package, except for a test case,
+ // which may have been an unintended side of some refactor.
+ // It was likely intended to be used in `Ordered` but it is not since
+ // `Less` that is implemented here ends up getting masked due to wrapping.
+ if runtime.GOOS == "windows" {
+ return &windowsMatchComparer{stripped}
+ }
+ return stripped
+ }
+ return m
+}
+
+type osVerMatcher interface {
+ Match(string) bool
+}
+
+type matcher struct {
+ specs.Platform
+ osvM osVerMatcher
+}
+
+func (m *matcher) Match(platform specs.Platform) bool {
+ normalized := Normalize(platform)
+ if m.OS == normalized.OS &&
+ m.Architecture == normalized.Architecture &&
+ m.Variant == normalized.Variant &&
+ m.matchOSVersion(platform) {
+ if len(normalized.OSFeatures) == 0 {
+ return true
+ }
+ if len(m.OSFeatures) >= len(normalized.OSFeatures) {
+ // Ensure that normalized.OSFeatures is a subset of
+ // m.OSFeatures
+ j := 0
+ for _, feature := range normalized.OSFeatures {
+ found := false
+ for ; j < len(m.OSFeatures); j++ {
+ if feature == m.OSFeatures[j] {
+ found = true
+ j++
+ break
+ }
+ // Since both lists are ordered, if the feature is less
+ // than what is seen, it is not in the list
+ if feature < m.OSFeatures[j] {
+ return false
+ }
+ }
+ if !found {
+ return false
+ }
+ }
+ return true
+ }
+ }
+ return false
+}
+
+func (m *matcher) matchOSVersion(platform specs.Platform) bool {
+ if m.osvM != nil {
+ return m.osvM.Match(platform.OSVersion)
+ }
+ return true
+}
+
+func (m *matcher) String() string {
+ return FormatAll(m.Platform)
+}
+
+// ParseAll parses a list of platform specifiers into a list of platform.
+func ParseAll(specifiers []string) ([]specs.Platform, error) {
+ platforms := make([]specs.Platform, len(specifiers))
+ for i, s := range specifiers {
+ p, err := Parse(s)
+ if err != nil {
+ return nil, fmt.Errorf("invalid platform %s: %w", s, err)
+ }
+ platforms[i] = p
+ }
+ return platforms, nil
+}
+
+// Parse parses the platform specifier syntax into a platform declaration.
+//
+// Platform specifiers are in the format `[()]||[()]/[/]`.
+// The minimum required information for a platform specifier is the operating
+// system or architecture. The "os options" may be OSVersion which can be part of the OS
+// like `windows(10.0.17763)`. When an OSVersion is specified, then specs.Platform.OSVersion is
+// populated with that value, and an empty string otherwise. The "os options" may also include an
+// array of OSFeatures, each feature prefixed with '+', without any other separator, and provided
+// after the OSVersion when the OSVersion is specified. An "os options" with version and features
+// is like `windows(10.0.17763+win32k)`.
+// If there is only a single string (no slashes), the
+// value will be matched against the known set of operating systems, then fall
+// back to the known set of architectures. The missing component will be
+// inferred based on the local environment.
+func Parse(specifier string) (specs.Platform, error) {
+ if strings.Contains(specifier, "*") {
+ // TODO(stevvooe): need to work out exact wildcard handling
+ return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errInvalidArgument)
+ }
+
+ // Limit to 4 elements to prevent unbounded split
+ parts := strings.SplitN(specifier, "/", 4)
+
+ var p specs.Platform
+ for i, part := range parts {
+ if i == 0 {
+ // First element is [([+]*)]
+ osOptions := osRe.FindStringSubmatch(part)
+ if osOptions == nil {
+ return specs.Platform{}, fmt.Errorf("%q is an invalid OS component of %q: OSAndVersion specifier component must match %q: %w", part, specifier, osRe.String(), errInvalidArgument)
+ }
+
+ p.OS = normalizeOS(osOptions[1])
+ osVersion, err := decodeOSOption(osOptions[2])
+ if err != nil {
+ return specs.Platform{}, fmt.Errorf("%q has an invalid OS version %q: %w", specifier, osOptions[2], err)
+ }
+ p.OSVersion = osVersion
+ if osOptions[3] != "" {
+ p.OSFeatures, err = parseOSFeatures(osOptions[3][1:])
+ if err != nil {
+ return specs.Platform{}, fmt.Errorf("%q has invalid OS features: %w", specifier, err)
+ }
+ }
+ } else {
+ if !specifierRe.MatchString(part) {
+ return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errInvalidArgument)
+ }
+ }
+ }
+
+ switch len(parts) {
+ case 1:
+ // in this case, we will test that the value might be an OS (with or
+ // without the optional OSVersion specified) and look it up.
+ // If it is not known, we'll treat it as an architecture. Since
+ // we have very little information about the platform here, we are
+ // going to be a little more strict if we don't know about the argument
+ // value.
+ if isKnownOS(p.OS) {
+ // picks a default architecture
+ p.Architecture = runtime.GOARCH
+ if p.Architecture == "arm" && cpuVariant() != "v7" {
+ p.Variant = cpuVariant()
+ }
+
+ return p, nil
+ }
+
+ p.Architecture, p.Variant = normalizeArch(parts[0], "")
+ if p.Architecture == "arm" && p.Variant == "v7" {
+ p.Variant = ""
+ }
+ if isKnownArch(p.Architecture) {
+ p.OS = runtime.GOOS
+ return p, nil
+ }
+
+ return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errInvalidArgument)
+ case 2:
+ // In this case, we treat as a regular OS[(OSVersion)]/arch pair. We don't care
+ // about whether or not we know of the platform.
+ p.Architecture, p.Variant = normalizeArch(parts[1], "")
+ if p.Architecture == "arm" && p.Variant == "v7" {
+ p.Variant = ""
+ }
+
+ return p, nil
+ case 3:
+ // we have a fully specified variant, this is rare
+ p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
+ if p.Architecture == "arm64" && p.Variant == "" {
+ p.Variant = "v8"
+ }
+
+ return p, nil
+ }
+
+ return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errInvalidArgument)
+}
+
+func parseOSFeatures(s string) ([]string, error) {
+ if s == "" {
+ return nil, nil
+ }
+
+ var features []string
+ for raw := range strings.SplitSeq(s, "+") {
+ raw = strings.TrimSpace(raw)
+ if raw == "" {
+ return nil, fmt.Errorf("empty os feature: %w", errInvalidArgument)
+ }
+ feature, err := decodeOSOption(raw)
+ if err != nil {
+ return nil, fmt.Errorf("invalid os feature %q: %w", raw, err)
+ }
+ if feature == "" {
+ continue
+ }
+ features = append(features, feature)
+ }
+
+ return features, nil
+}
+
+// MustParse is like Parses but panics if the specifier cannot be parsed.
+// Simplifies initialization of global variables.
+func MustParse(specifier string) specs.Platform {
+ p, err := Parse(specifier)
+ if err != nil {
+ panic("platform: Parse(" + strconv.Quote(specifier) + "): " + err.Error())
+ }
+ return p
+}
+
+// Format returns a string specifier from the provided platform specification.
+func Format(platform specs.Platform) string {
+ if platform.OS == "" {
+ return "unknown"
+ }
+
+ return path.Join(platform.OS, platform.Architecture, platform.Variant)
+}
+
+// FormatAll returns a string specifier that also includes the OSVersion from the
+// provided platform specification.
+func FormatAll(platform specs.Platform) string {
+ if platform.OS == "" {
+ return "unknown"
+ }
+ if platform.OSVersion == "" && len(platform.OSFeatures) == 0 {
+ return path.Join(platform.OS, platform.Architecture, platform.Variant)
+ }
+
+ var b strings.Builder
+ b.WriteString(platform.OS)
+ osv := encodeOSOption(platform.OSVersion)
+ formatted := formatOSFeatures(platform.OSFeatures)
+ if osv != "" || formatted != "" {
+ b.Grow(len(osv) + len(formatted) + 3) // parens + maybe '+'
+ b.WriteByte('(')
+ if osv != "" {
+ b.WriteString(osv)
+ }
+ if formatted != "" {
+ b.WriteByte('+')
+ b.WriteString(formatted)
+ }
+ b.WriteByte(')')
+ }
+
+ return path.Join(b.String(), platform.Architecture, platform.Variant)
+}
+
+func formatOSFeatures(features []string) string {
+ if len(features) == 0 {
+ return ""
+ }
+
+ if !slices.IsSorted(features) {
+ features = slices.Clone(features)
+ slices.Sort(features)
+ }
+ var b strings.Builder
+ var wrote bool
+ var prev string
+ for _, f := range features {
+ if f == "" || f == prev {
+ // skip empty and duplicate values
+ continue
+ }
+ prev = f
+ if wrote {
+ b.WriteByte('+')
+ }
+ b.WriteString(encodeOSOption(f))
+ wrote = true
+ }
+ return b.String()
+}
+
+// osOptionReplacer encodes characters in OS option values (version and
+// features) that are ambiguous with the format syntax. The percent sign
+// must be replaced first to avoid double-encoding.
+var osOptionReplacer = strings.NewReplacer(
+ "%", "%25",
+ "+", "%2B",
+ "(", "%28",
+ ")", "%29",
+ "/", "%2F",
+)
+
+func encodeOSOption(v string) string {
+ return osOptionReplacer.Replace(v)
+}
+
+func decodeOSOption(v string) (string, error) {
+ if strings.Contains(v, "%") {
+ return url.PathUnescape(v)
+ }
+ return v, nil
+}
+
+// Normalize validates and translate the platform to the canonical value.
+//
+// For example, if "Aarch64" is encountered, we change it to "arm64" or if
+// "x86_64" is encountered, it becomes "amd64".
+func Normalize(platform specs.Platform) specs.Platform {
+ platform.OS = normalizeOS(platform.OS)
+ platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)
+ if len(platform.OSFeatures) > 0 {
+ platform.OSFeatures = slices.Clone(platform.OSFeatures)
+ slices.Sort(platform.OSFeatures)
+ platform.OSFeatures = slices.Compact(platform.OSFeatures)
+ }
+
+ return platform
+}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go
deleted file mode 100644
index 6aba0ef1f6..0000000000
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-/*
- Copyright 2019 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file.
-*/
-
-package estargz
-
-import (
- "archive/tar"
- "bytes"
- "compress/gzip"
- "context"
- "errors"
- "fmt"
- "io"
- "os"
- "path"
- "runtime"
- "strings"
- "sync"
-
- "github.com/containerd/stargz-snapshotter/estargz/errorutil"
- "github.com/klauspost/compress/zstd"
- digest "github.com/opencontainers/go-digest"
- "golang.org/x/sync/errgroup"
-)
-
-type options struct {
- chunkSize int
- compressionLevel int
- prioritizedFiles []string
- missedPrioritizedFiles *[]string
- compression Compression
- ctx context.Context
- minChunkSize int
-}
-
-type Option func(o *options) error
-
-// WithChunkSize option specifies the chunk size of eStargz blob to build.
-func WithChunkSize(chunkSize int) Option {
- return func(o *options) error {
- o.chunkSize = chunkSize
- return nil
- }
-}
-
-// WithCompressionLevel option specifies the gzip compression level.
-// The default is gzip.BestCompression.
-// This option will be ignored if WithCompression option is used.
-// See also: https://godoc.org/compress/gzip#pkg-constants
-func WithCompressionLevel(level int) Option {
- return func(o *options) error {
- o.compressionLevel = level
- return nil
- }
-}
-
-// WithPrioritizedFiles option specifies the list of prioritized files.
-// These files must be complete paths that are absolute or relative to "/"
-// For example, all of "foo/bar", "/foo/bar", "./foo/bar" and "../foo/bar"
-// are treated as "/foo/bar".
-func WithPrioritizedFiles(files []string) Option {
- return func(o *options) error {
- o.prioritizedFiles = files
- return nil
- }
-}
-
-// WithAllowPrioritizeNotFound makes Build continue the execution even if some
-// of prioritized files specified by WithPrioritizedFiles option aren't found
-// in the input tar. Instead, this records all missed file names to the passed
-// slice.
-func WithAllowPrioritizeNotFound(missedFiles *[]string) Option {
- return func(o *options) error {
- if missedFiles == nil {
- return fmt.Errorf("WithAllowPrioritizeNotFound: slice must be passed")
- }
- o.missedPrioritizedFiles = missedFiles
- return nil
- }
-}
-
-// WithCompression specifies compression algorithm to be used.
-// Default is gzip.
-func WithCompression(compression Compression) Option {
- return func(o *options) error {
- o.compression = compression
- return nil
- }
-}
-
-// WithContext specifies a context that can be used for clean canceleration.
-func WithContext(ctx context.Context) Option {
- return func(o *options) error {
- o.ctx = ctx
- return nil
- }
-}
-
-// WithMinChunkSize option specifies the minimal number of bytes of data
-// must be written in one gzip stream.
-// By increasing this number, one gzip stream can contain multiple files
-// and it hopefully leads to smaller result blob.
-// NOTE: This adds a TOC property that old reader doesn't understand.
-func WithMinChunkSize(minChunkSize int) Option {
- return func(o *options) error {
- o.minChunkSize = minChunkSize
- return nil
- }
-}
-
-// Blob is an eStargz blob.
-type Blob struct {
- io.ReadCloser
- diffID digest.Digester
- tocDigest digest.Digest
-}
-
-// DiffID returns the digest of uncompressed blob.
-// It is only valid to call DiffID after Close.
-func (b *Blob) DiffID() digest.Digest {
- return b.diffID.Digest()
-}
-
-// TOCDigest returns the digest of uncompressed TOC JSON.
-func (b *Blob) TOCDigest() digest.Digest {
- return b.tocDigest
-}
-
-// Build builds an eStargz blob which is an extended version of stargz, from a blob (gzip, zstd
-// or plain tar) passed through the argument. If there are some prioritized files are listed in
-// the option, these files are grouped as "prioritized" and can be used for runtime optimization
-// (e.g. prefetch). This function builds a blob in parallel, with dividing that blob into several
-// (at least the number of runtime.GOMAXPROCS(0)) sub-blobs.
-func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
- var opts options
- opts.compressionLevel = gzip.BestCompression // BestCompression by default
- for _, o := range opt {
- if err := o(&opts); err != nil {
- return nil, err
- }
- }
- if opts.compression == nil {
- opts.compression = newGzipCompressionWithLevel(opts.compressionLevel)
- }
- layerFiles := newTempFiles()
- ctx := opts.ctx
- if ctx == nil {
- ctx = context.Background()
- }
- done := make(chan struct{})
- defer close(done)
- go func() {
- select {
- case <-done:
- // nop
- case <-ctx.Done():
- layerFiles.CleanupAll()
- }
- }()
- defer func() {
- if rErr != nil {
- if err := layerFiles.CleanupAll(); err != nil {
- rErr = fmt.Errorf("failed to cleanup tmp files: %v: %w", err, rErr)
- }
- }
- if cErr := ctx.Err(); cErr != nil {
- rErr = fmt.Errorf("error from context %q: %w", cErr, rErr)
- }
- }()
- tarBlob, err := decompressBlob(tarBlob, layerFiles)
- if err != nil {
- return nil, err
- }
- entries, err := sortEntries(tarBlob, opts.prioritizedFiles, opts.missedPrioritizedFiles)
- if err != nil {
- return nil, err
- }
- var tarParts [][]*entry
- if opts.minChunkSize > 0 {
- // Each entry needs to know the size of the current gzip stream so they
- // cannot be processed in parallel.
- tarParts = [][]*entry{entries}
- } else {
- tarParts = divideEntries(entries, runtime.GOMAXPROCS(0))
- }
- writers := make([]*Writer, len(tarParts))
- payloads := make([]*os.File, len(tarParts))
- var mu sync.Mutex
- var eg errgroup.Group
- for i, parts := range tarParts {
- i, parts := i, parts
- // builds verifiable stargz sub-blobs
- eg.Go(func() error {
- esgzFile, err := layerFiles.TempFile("", "esgzdata")
- if err != nil {
- return err
- }
- sw := NewWriterWithCompressor(esgzFile, opts.compression)
- sw.ChunkSize = opts.chunkSize
- sw.MinChunkSize = opts.minChunkSize
- if sw.needsOpenGzEntries == nil {
- sw.needsOpenGzEntries = make(map[string]struct{})
- }
- for _, f := range []string{PrefetchLandmark, NoPrefetchLandmark} {
- sw.needsOpenGzEntries[f] = struct{}{}
- }
- if err := sw.AppendTar(readerFromEntries(parts...)); err != nil {
- return err
- }
- mu.Lock()
- writers[i] = sw
- payloads[i] = esgzFile
- mu.Unlock()
- return nil
- })
- }
- if err := eg.Wait(); err != nil {
- rErr = err
- return nil, err
- }
- tocAndFooter, tocDgst, err := closeWithCombine(writers...)
- if err != nil {
- rErr = err
- return nil, err
- }
- var rs []io.Reader
- for _, p := range payloads {
- fs, err := fileSectionReader(p)
- if err != nil {
- return nil, err
- }
- rs = append(rs, fs)
- }
- diffID := digest.Canonical.Digester()
- pr, pw := io.Pipe()
- go func() {
- r, err := opts.compression.Reader(io.TeeReader(io.MultiReader(append(rs, tocAndFooter)...), pw))
- if err != nil {
- pw.CloseWithError(err)
- return
- }
- defer r.Close()
- if _, err := io.Copy(diffID.Hash(), r); err != nil {
- pw.CloseWithError(err)
- return
- }
- pw.Close()
- }()
- return &Blob{
- ReadCloser: readCloser{
- Reader: pr,
- closeFunc: layerFiles.CleanupAll,
- },
- tocDigest: tocDgst,
- diffID: diffID,
- }, nil
-}
-
-// closeWithCombine takes unclosed Writers and close them. This also returns the
-// toc that combined all Writers into.
-// Writers doesn't write TOC and footer to the underlying writers so they can be
-// combined into a single eStargz and tocAndFooter returned by this function can
-// be appended at the tail of that combined blob.
-func closeWithCombine(ws ...*Writer) (tocAndFooterR io.Reader, tocDgst digest.Digest, err error) {
- if len(ws) == 0 {
- return nil, "", fmt.Errorf("at least one writer must be passed")
- }
- for _, w := range ws {
- if w.closed {
- return nil, "", fmt.Errorf("writer must be unclosed")
- }
- defer func(w *Writer) { w.closed = true }(w)
- if err := w.closeGz(); err != nil {
- return nil, "", err
- }
- if err := w.bw.Flush(); err != nil {
- return nil, "", err
- }
- }
- var (
- mtoc = new(JTOC)
- currentOffset int64
- )
- mtoc.Version = ws[0].toc.Version
- for _, w := range ws {
- for _, e := range w.toc.Entries {
- // Recalculate Offset of non-empty files/chunks
- if (e.Type == "reg" && e.Size > 0) || e.Type == "chunk" {
- e.Offset += currentOffset
- }
- mtoc.Entries = append(mtoc.Entries, e)
- }
- if w.toc.Version > mtoc.Version {
- mtoc.Version = w.toc.Version
- }
- currentOffset += w.cw.n
- }
-
- return tocAndFooter(ws[0].compressor, mtoc, currentOffset)
-}
-
-func tocAndFooter(compressor Compressor, toc *JTOC, offset int64) (io.Reader, digest.Digest, error) {
- buf := new(bytes.Buffer)
- tocDigest, err := compressor.WriteTOCAndFooter(buf, offset, toc, nil)
- if err != nil {
- return nil, "", err
- }
- return buf, tocDigest, nil
-}
-
-// divideEntries divides passed entries to the parts at least the number specified by the
-// argument.
-func divideEntries(entries []*entry, minPartsNum int) (set [][]*entry) {
- var estimatedSize int64
- for _, e := range entries {
- estimatedSize += e.header.Size
- }
- unitSize := estimatedSize / int64(minPartsNum)
- var (
- nextEnd = unitSize
- offset int64
- )
- set = append(set, []*entry{})
- for _, e := range entries {
- set[len(set)-1] = append(set[len(set)-1], e)
- offset += e.header.Size
- if offset > nextEnd {
- set = append(set, []*entry{})
- nextEnd += unitSize
- }
- }
- return
-}
-
-var errNotFound = errors.New("not found")
-
-// sortEntries reads the specified tar blob and returns a list of tar entries.
-// If some of prioritized files are specified, the list starts from these
-// files with keeping the order specified by the argument.
-func sortEntries(in io.ReaderAt, prioritized []string, missedPrioritized *[]string) ([]*entry, error) {
-
- // Import tar file.
- intar, err := importTar(in)
- if err != nil {
- return nil, fmt.Errorf("failed to sort: %w", err)
- }
-
- // Sort the tar file respecting to the prioritized files list.
- sorted := &tarFile{}
- for _, l := range prioritized {
- if err := moveRec(l, intar, sorted); err != nil {
- if errors.Is(err, errNotFound) && missedPrioritized != nil {
- *missedPrioritized = append(*missedPrioritized, l)
- continue // allow not found
- }
- return nil, fmt.Errorf("failed to sort tar entries: %w", err)
- }
- }
- if len(prioritized) == 0 {
- sorted.add(&entry{
- header: &tar.Header{
- Name: NoPrefetchLandmark,
- Typeflag: tar.TypeReg,
- Size: int64(len([]byte{landmarkContents})),
- },
- payload: bytes.NewReader([]byte{landmarkContents}),
- })
- } else {
- sorted.add(&entry{
- header: &tar.Header{
- Name: PrefetchLandmark,
- Typeflag: tar.TypeReg,
- Size: int64(len([]byte{landmarkContents})),
- },
- payload: bytes.NewReader([]byte{landmarkContents}),
- })
- }
-
- // Dump all entry and concatinate them.
- return append(sorted.dump(), intar.dump()...), nil
-}
-
-// readerFromEntries returns a reader of tar archive that contains entries passed
-// through the arguments.
-func readerFromEntries(entries ...*entry) io.Reader {
- pr, pw := io.Pipe()
- go func() {
- tw := tar.NewWriter(pw)
- defer tw.Close()
- for _, entry := range entries {
- if err := tw.WriteHeader(entry.header); err != nil {
- pw.CloseWithError(fmt.Errorf("Failed to write tar header: %v", err))
- return
- }
- if _, err := io.Copy(tw, entry.payload); err != nil {
- pw.CloseWithError(fmt.Errorf("Failed to write tar payload: %v", err))
- return
- }
- }
- pw.Close()
- }()
- return pr
-}
-
-func importTar(in io.ReaderAt) (*tarFile, error) {
- tf := &tarFile{}
- pw, err := newCountReadSeeker(in)
- if err != nil {
- return nil, fmt.Errorf("failed to make position watcher: %w", err)
- }
- tr := tar.NewReader(pw)
-
- // Walk through all nodes.
- for {
- // Fetch and parse next header.
- h, err := tr.Next()
- if err != nil {
- if err == io.EOF {
- break
- }
- return nil, fmt.Errorf("failed to parse tar file, %w", err)
- }
- switch cleanEntryName(h.Name) {
- case PrefetchLandmark, NoPrefetchLandmark:
- // Ignore existing landmark
- continue
- }
-
- // Add entry. If it already exists, replace it.
- if _, ok := tf.get(h.Name); ok {
- tf.remove(h.Name)
- }
- tf.add(&entry{
- header: h,
- payload: io.NewSectionReader(in, pw.currentPos(), h.Size),
- })
- }
-
- return tf, nil
-}
-
-func moveRec(name string, in *tarFile, out *tarFile) error {
- name = cleanEntryName(name)
- if name == "" { // root directory. stop recursion.
- if e, ok := in.get(name); ok {
- // entry of the root directory exists. we should move it as well.
- // this case will occur if tar entries are prefixed with "./", "/", etc.
- out.add(e)
- in.remove(name)
- }
- return nil
- }
-
- _, okIn := in.get(name)
- _, okOut := out.get(name)
- if !okIn && !okOut {
- return fmt.Errorf("file: %q: %w", name, errNotFound)
- }
-
- parent, _ := path.Split(strings.TrimSuffix(name, "/"))
- if err := moveRec(parent, in, out); err != nil {
- return err
- }
- if e, ok := in.get(name); ok && e.header.Typeflag == tar.TypeLink {
- if err := moveRec(e.header.Linkname, in, out); err != nil {
- return err
- }
- }
- if e, ok := in.get(name); ok {
- out.add(e)
- in.remove(name)
- }
- return nil
-}
-
-type entry struct {
- header *tar.Header
- payload io.ReadSeeker
-}
-
-type tarFile struct {
- index map[string]*entry
- stream []*entry
-}
-
-func (f *tarFile) add(e *entry) {
- if f.index == nil {
- f.index = make(map[string]*entry)
- }
- f.index[cleanEntryName(e.header.Name)] = e
- f.stream = append(f.stream, e)
-}
-
-func (f *tarFile) remove(name string) {
- name = cleanEntryName(name)
- if f.index != nil {
- delete(f.index, name)
- }
- var filtered []*entry
- for _, e := range f.stream {
- if cleanEntryName(e.header.Name) == name {
- continue
- }
- filtered = append(filtered, e)
- }
- f.stream = filtered
-}
-
-func (f *tarFile) get(name string) (e *entry, ok bool) {
- if f.index == nil {
- return nil, false
- }
- e, ok = f.index[cleanEntryName(name)]
- return
-}
-
-func (f *tarFile) dump() []*entry {
- return f.stream
-}
-
-type readCloser struct {
- io.Reader
- closeFunc func() error
-}
-
-func (rc readCloser) Close() error {
- return rc.closeFunc()
-}
-
-func fileSectionReader(file *os.File) (*io.SectionReader, error) {
- info, err := file.Stat()
- if err != nil {
- return nil, err
- }
- return io.NewSectionReader(file, 0, info.Size()), nil
-}
-
-func newTempFiles() *tempFiles {
- return &tempFiles{}
-}
-
-type tempFiles struct {
- files []*os.File
- filesMu sync.Mutex
- cleanupOnce sync.Once
-}
-
-func (tf *tempFiles) TempFile(dir, pattern string) (*os.File, error) {
- f, err := os.CreateTemp(dir, pattern)
- if err != nil {
- return nil, err
- }
- tf.filesMu.Lock()
- tf.files = append(tf.files, f)
- tf.filesMu.Unlock()
- return f, nil
-}
-
-func (tf *tempFiles) CleanupAll() (err error) {
- tf.cleanupOnce.Do(func() {
- err = tf.cleanupAll()
- })
- return
-}
-
-func (tf *tempFiles) cleanupAll() error {
- tf.filesMu.Lock()
- defer tf.filesMu.Unlock()
- var allErr []error
- for _, f := range tf.files {
- if err := f.Close(); err != nil {
- allErr = append(allErr, err)
- }
- if err := os.Remove(f.Name()); err != nil {
- allErr = append(allErr, err)
- }
- }
- tf.files = nil
- return errorutil.Aggregate(allErr)
-}
-
-func newCountReadSeeker(r io.ReaderAt) (*countReadSeeker, error) {
- pos := int64(0)
- return &countReadSeeker{r: r, cPos: &pos}, nil
-}
-
-type countReadSeeker struct {
- r io.ReaderAt
- cPos *int64
-
- mu sync.Mutex
-}
-
-func (cr *countReadSeeker) Read(p []byte) (int, error) {
- cr.mu.Lock()
- defer cr.mu.Unlock()
-
- n, err := cr.r.ReadAt(p, *cr.cPos)
- if err == nil {
- *cr.cPos += int64(n)
- }
- return n, err
-}
-
-func (cr *countReadSeeker) Seek(offset int64, whence int) (int64, error) {
- cr.mu.Lock()
- defer cr.mu.Unlock()
-
- switch whence {
- default:
- return 0, fmt.Errorf("Unknown whence: %v", whence)
- case io.SeekStart:
- case io.SeekCurrent:
- offset += *cr.cPos
- case io.SeekEnd:
- return 0, fmt.Errorf("Unsupported whence: %v", whence)
- }
-
- if offset < 0 {
- return 0, fmt.Errorf("invalid offset")
- }
- *cr.cPos = offset
- return offset, nil
-}
-
-func (cr *countReadSeeker) currentPos() int64 {
- cr.mu.Lock()
- defer cr.mu.Unlock()
-
- return *cr.cPos
-}
-
-func decompressBlob(org *io.SectionReader, tmp *tempFiles) (*io.SectionReader, error) {
- if org.Size() < 4 {
- return org, nil
- }
- src := make([]byte, 4)
- if _, err := org.Read(src); err != nil && err != io.EOF {
- return nil, err
- }
- var dR io.Reader
- if bytes.Equal([]byte{0x1F, 0x8B, 0x08}, src[:3]) {
- // gzip
- dgR, err := gzip.NewReader(io.NewSectionReader(org, 0, org.Size()))
- if err != nil {
- return nil, err
- }
- defer dgR.Close()
- dR = io.Reader(dgR)
- } else if bytes.Equal([]byte{0x28, 0xb5, 0x2f, 0xfd}, src[:4]) {
- // zstd
- dzR, err := zstd.NewReader(io.NewSectionReader(org, 0, org.Size()))
- if err != nil {
- return nil, err
- }
- defer dzR.Close()
- dR = io.Reader(dzR)
- } else {
- // uncompressed
- return io.NewSectionReader(org, 0, org.Size()), nil
- }
- b, err := tmp.TempFile("", "uncompresseddata")
- if err != nil {
- return nil, err
- }
- if _, err := io.Copy(b, dR); err != nil {
- return nil, err
- }
- return fileSectionReader(b)
-}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/errorutil/errors.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/errorutil/errors.go
deleted file mode 100644
index 6de78b02dc..0000000000
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/errorutil/errors.go
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package errorutil
-
-import (
- "errors"
- "fmt"
- "strings"
-)
-
-// Aggregate combines a list of errors into a single new error.
-func Aggregate(errs []error) error {
- switch len(errs) {
- case 0:
- return nil
- case 1:
- return errs[0]
- default:
- points := make([]string, len(errs)+1)
- points[0] = fmt.Sprintf("%d error(s) occurred:", len(errs))
- for i, err := range errs {
- points[i+1] = fmt.Sprintf("* %s", err)
- }
- return errors.New(strings.Join(points, "\n\t"))
- }
-}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
deleted file mode 100644
index f4d5546558..0000000000
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
+++ /dev/null
@@ -1,1223 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-/*
- Copyright 2019 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file.
-*/
-
-package estargz
-
-import (
- "bufio"
- "bytes"
- "compress/gzip"
- "crypto/sha256"
- "errors"
- "fmt"
- "hash"
- "io"
- "os"
- "path"
- "sort"
- "strings"
- "sync"
- "time"
-
- "github.com/containerd/stargz-snapshotter/estargz/errorutil"
- digest "github.com/opencontainers/go-digest"
- "github.com/vbatts/tar-split/archive/tar"
-)
-
-// A Reader permits random access reads from a stargz file.
-type Reader struct {
- sr *io.SectionReader
- toc *JTOC
- tocDigest digest.Digest
-
- // m stores all non-chunk entries, keyed by name.
- m map[string]*TOCEntry
-
- // chunks stores all TOCEntry values for regular files that
- // are split up. For a file with a single chunk, it's only
- // stored in m.
- chunks map[string][]*TOCEntry
-
- decompressor Decompressor
-}
-
-type openOpts struct {
- tocOffset int64
- decompressors []Decompressor
- telemetry *Telemetry
-}
-
-// OpenOption is an option used during opening the layer
-type OpenOption func(o *openOpts) error
-
-// WithTOCOffset option specifies the offset of TOC
-func WithTOCOffset(tocOffset int64) OpenOption {
- return func(o *openOpts) error {
- o.tocOffset = tocOffset
- return nil
- }
-}
-
-// WithDecompressors option specifies decompressors to use.
-// Default is gzip-based decompressor.
-func WithDecompressors(decompressors ...Decompressor) OpenOption {
- return func(o *openOpts) error {
- o.decompressors = decompressors
- return nil
- }
-}
-
-// WithTelemetry option specifies the telemetry hooks
-func WithTelemetry(telemetry *Telemetry) OpenOption {
- return func(o *openOpts) error {
- o.telemetry = telemetry
- return nil
- }
-}
-
-// MeasureLatencyHook is a func which takes start time and records the diff
-type MeasureLatencyHook func(time.Time)
-
-// Telemetry is a struct which defines telemetry hooks. By implementing these hooks you should be able to record
-// the latency metrics of the respective steps of estargz open operation. To be used with estargz.OpenWithTelemetry(...)
-type Telemetry struct {
- GetFooterLatency MeasureLatencyHook // measure time to get stargz footer (in milliseconds)
- GetTocLatency MeasureLatencyHook // measure time to GET TOC JSON (in milliseconds)
- DeserializeTocLatency MeasureLatencyHook // measure time to deserialize TOC JSON (in milliseconds)
-}
-
-// Open opens a stargz file for reading.
-// The behavior is configurable using options.
-//
-// Note that each entry name is normalized as the path that is relative to root.
-func Open(sr *io.SectionReader, opt ...OpenOption) (*Reader, error) {
- var opts openOpts
- for _, o := range opt {
- if err := o(&opts); err != nil {
- return nil, err
- }
- }
-
- gzipCompressors := []Decompressor{new(GzipDecompressor), new(LegacyGzipDecompressor)}
- decompressors := append(gzipCompressors, opts.decompressors...)
-
- // Determine the size to fetch. Try to fetch as many bytes as possible.
- fetchSize := maxFooterSize(sr.Size(), decompressors...)
- if maybeTocOffset := opts.tocOffset; maybeTocOffset > fetchSize {
- if maybeTocOffset > sr.Size() {
- return nil, fmt.Errorf("blob size %d is smaller than the toc offset", sr.Size())
- }
- fetchSize = sr.Size() - maybeTocOffset
- }
-
- start := time.Now() // before getting layer footer
- footer := make([]byte, fetchSize)
- if _, err := sr.ReadAt(footer, sr.Size()-fetchSize); err != nil {
- return nil, fmt.Errorf("error reading footer: %v", err)
- }
- if opts.telemetry != nil && opts.telemetry.GetFooterLatency != nil {
- opts.telemetry.GetFooterLatency(start)
- }
-
- var allErr []error
- var found bool
- var r *Reader
- for _, d := range decompressors {
- fSize := d.FooterSize()
- fOffset := positive(int64(len(footer)) - fSize)
- maybeTocBytes := footer[:fOffset]
- _, tocOffset, tocSize, err := d.ParseFooter(footer[fOffset:])
- if err != nil {
- allErr = append(allErr, err)
- continue
- }
- if tocOffset >= 0 && tocSize <= 0 {
- tocSize = sr.Size() - tocOffset - fSize
- }
- if tocOffset >= 0 && tocSize < int64(len(maybeTocBytes)) {
- maybeTocBytes = maybeTocBytes[:tocSize]
- }
- r, err = parseTOC(d, sr, tocOffset, tocSize, maybeTocBytes, opts)
- if err == nil {
- found = true
- break
- }
- allErr = append(allErr, err)
- }
- if !found {
- return nil, errorutil.Aggregate(allErr)
- }
- if err := r.initFields(); err != nil {
- return nil, fmt.Errorf("failed to initialize fields of entries: %v", err)
- }
- return r, nil
-}
-
-// OpenFooter extracts and parses footer from the given blob.
-// only supports gzip-based eStargz.
-func OpenFooter(sr *io.SectionReader) (tocOffset int64, footerSize int64, rErr error) {
- if sr.Size() < FooterSize && sr.Size() < legacyFooterSize {
- return 0, 0, fmt.Errorf("blob size %d is smaller than the footer size", sr.Size())
- }
- var footer [FooterSize]byte
- if _, err := sr.ReadAt(footer[:], sr.Size()-FooterSize); err != nil {
- return 0, 0, fmt.Errorf("error reading footer: %v", err)
- }
- var allErr []error
- for _, d := range []Decompressor{new(GzipDecompressor), new(LegacyGzipDecompressor)} {
- fSize := d.FooterSize()
- fOffset := positive(int64(len(footer)) - fSize)
- _, tocOffset, _, err := d.ParseFooter(footer[fOffset:])
- if err == nil {
- return tocOffset, fSize, err
- }
- allErr = append(allErr, err)
- }
- return 0, 0, errorutil.Aggregate(allErr)
-}
-
-// initFields populates the Reader from r.toc after decoding it from
-// JSON.
-//
-// Unexported fields are populated and TOCEntry fields that were
-// implicit in the JSON are populated.
-func (r *Reader) initFields() error {
- r.m = make(map[string]*TOCEntry, len(r.toc.Entries))
- r.chunks = make(map[string][]*TOCEntry)
- var lastPath string
- uname := map[int]string{}
- gname := map[int]string{}
- var lastRegEnt *TOCEntry
- var chunkTopIndex int
- for i, ent := range r.toc.Entries {
- ent.Name = cleanEntryName(ent.Name)
- switch ent.Type {
- case "reg", "chunk":
- if ent.Offset != r.toc.Entries[chunkTopIndex].Offset {
- chunkTopIndex = i
- }
- ent.chunkTopIndex = chunkTopIndex
- }
- if ent.Type == "reg" {
- lastRegEnt = ent
- }
- if ent.Type == "chunk" {
- ent.Name = lastPath
- r.chunks[ent.Name] = append(r.chunks[ent.Name], ent)
- if ent.ChunkSize == 0 && lastRegEnt != nil {
- ent.ChunkSize = lastRegEnt.Size - ent.ChunkOffset
- }
- } else {
- lastPath = ent.Name
-
- if ent.Uname != "" {
- uname[ent.UID] = ent.Uname
- } else {
- ent.Uname = uname[ent.UID]
- }
- if ent.Gname != "" {
- gname[ent.GID] = ent.Gname
- } else {
- ent.Gname = uname[ent.GID]
- }
-
- ent.modTime, _ = time.Parse(time.RFC3339, ent.ModTime3339)
-
- if ent.Type == "dir" {
- ent.NumLink++ // Parent dir links to this directory
- }
- r.m[ent.Name] = ent
- }
- if ent.Type == "reg" && ent.ChunkSize > 0 && ent.ChunkSize < ent.Size {
- r.chunks[ent.Name] = make([]*TOCEntry, 0, ent.Size/ent.ChunkSize+1)
- r.chunks[ent.Name] = append(r.chunks[ent.Name], ent)
- }
- if ent.ChunkSize == 0 && ent.Size != 0 {
- ent.ChunkSize = ent.Size
- }
- }
-
- // Populate children, add implicit directories:
- for _, ent := range r.toc.Entries {
- if ent.Type == "chunk" {
- continue
- }
- // add "foo/":
- // add "foo" child to "" (creating "" if necessary)
- //
- // add "foo/bar/":
- // add "bar" child to "foo" (creating "foo" if necessary)
- //
- // add "foo/bar.txt":
- // add "bar.txt" child to "foo" (creating "foo" if necessary)
- //
- // add "a/b/c/d/e/f.txt":
- // create "a/b/c/d/e" node
- // add "f.txt" child to "e"
-
- name := ent.Name
- pdirName := parentDir(name)
- if name == pdirName {
- // This entry and its parent are the same.
- // Ignore this for avoiding infinite loop of the reference.
- // The example case where this can occur is when tar contains the root
- // directory itself (e.g. "./", "/").
- continue
- }
- pdir := r.getOrCreateDir(pdirName)
- ent.NumLink++ // at least one name(ent.Name) references this entry.
- if ent.Type == "hardlink" {
- org, err := r.getSource(ent)
- if err != nil {
- return err
- }
- org.NumLink++ // original entry is referenced by this ent.Name.
- ent = org
- }
- pdir.addChild(path.Base(name), ent)
- }
-
- lastOffset := r.sr.Size()
- for i := len(r.toc.Entries) - 1; i >= 0; i-- {
- e := r.toc.Entries[i]
- if e.isDataType() {
- e.nextOffset = lastOffset
- }
- if e.Offset != 0 && e.InnerOffset == 0 {
- lastOffset = e.Offset
- }
- }
-
- return nil
-}
-
-func (r *Reader) getSource(ent *TOCEntry) (_ *TOCEntry, err error) {
- if ent.Type == "hardlink" {
- org, ok := r.m[cleanEntryName(ent.LinkName)]
- if !ok {
- return nil, fmt.Errorf("%q is a hardlink but the linkname %q isn't found", ent.Name, ent.LinkName)
- }
- ent, err = r.getSource(org)
- if err != nil {
- return nil, err
- }
- }
- return ent, nil
-}
-
-func parentDir(p string) string {
- dir, _ := path.Split(p)
- return strings.TrimSuffix(dir, "/")
-}
-
-func (r *Reader) getOrCreateDir(d string) *TOCEntry {
- e, ok := r.m[d]
- if !ok {
- e = &TOCEntry{
- Name: d,
- Type: "dir",
- Mode: 0755,
- NumLink: 2, // The directory itself(.) and the parent link to this directory.
- }
- r.m[d] = e
- if d != "" {
- pdir := r.getOrCreateDir(parentDir(d))
- pdir.addChild(path.Base(d), e)
- }
- }
- return e
-}
-
-func (r *Reader) TOCDigest() digest.Digest {
- return r.tocDigest
-}
-
-// VerifyTOC checks that the TOC JSON in the passed blob matches the
-// passed digests and that the TOC JSON contains digests for all chunks
-// contained in the blob. If the verification succceeds, this function
-// returns TOCEntryVerifier which holds all chunk digests in the stargz blob.
-func (r *Reader) VerifyTOC(tocDigest digest.Digest) (TOCEntryVerifier, error) {
- // Verify the digest of TOC JSON
- if r.tocDigest != tocDigest {
- return nil, fmt.Errorf("invalid TOC JSON %q; want %q", r.tocDigest, tocDigest)
- }
- return r.Verifiers()
-}
-
-// Verifiers returns TOCEntryVerifier of this chunk. Use VerifyTOC instead in most cases
-// because this doesn't verify TOC.
-func (r *Reader) Verifiers() (TOCEntryVerifier, error) {
- chunkDigestMap := make(map[int64]digest.Digest) // map from chunk offset to the chunk digest
- regDigestMap := make(map[int64]digest.Digest) // map from chunk offset to the reg file digest
- var chunkDigestMapIncomplete bool
- var regDigestMapIncomplete bool
- var containsChunk bool
- for _, e := range r.toc.Entries {
- if e.Type != "reg" && e.Type != "chunk" {
- continue
- }
-
- // offset must be unique in stargz blob
- _, dOK := chunkDigestMap[e.Offset]
- _, rOK := regDigestMap[e.Offset]
- if dOK || rOK {
- return nil, fmt.Errorf("offset %d found twice", e.Offset)
- }
-
- if e.Type == "reg" {
- if e.Size == 0 {
- continue // ignores empty file
- }
-
- // record the digest of regular file payload
- if e.Digest != "" {
- d, err := digest.Parse(e.Digest)
- if err != nil {
- return nil, fmt.Errorf("failed to parse regular file digest %q: %w", e.Digest, err)
- }
- regDigestMap[e.Offset] = d
- } else {
- regDigestMapIncomplete = true
- }
- } else {
- containsChunk = true // this layer contains "chunk" entries.
- }
-
- // "reg" also can contain ChunkDigest (e.g. when "reg" is the first entry of
- // chunked file)
- if e.ChunkDigest != "" {
- d, err := digest.Parse(e.ChunkDigest)
- if err != nil {
- return nil, fmt.Errorf("failed to parse chunk digest %q: %w", e.ChunkDigest, err)
- }
- chunkDigestMap[e.Offset] = d
- } else {
- chunkDigestMapIncomplete = true
- }
- }
-
- if chunkDigestMapIncomplete {
- // Though some chunk digests are not found, if this layer doesn't contain
- // "chunk"s and all digest of "reg" files are recorded, we can use them instead.
- if !containsChunk && !regDigestMapIncomplete {
- return &verifier{digestMap: regDigestMap}, nil
- }
- return nil, fmt.Errorf("some ChunkDigest not found in TOC JSON")
- }
-
- return &verifier{digestMap: chunkDigestMap}, nil
-}
-
-// verifier is an implementation of TOCEntryVerifier which holds verifiers keyed by
-// offset of the chunk.
-type verifier struct {
- digestMap map[int64]digest.Digest
- digestMapMu sync.Mutex
-}
-
-// Verifier returns a content verifier specified by TOCEntry.
-func (v *verifier) Verifier(ce *TOCEntry) (digest.Verifier, error) {
- v.digestMapMu.Lock()
- defer v.digestMapMu.Unlock()
- d, ok := v.digestMap[ce.Offset]
- if !ok {
- return nil, fmt.Errorf("verifier for offset=%d,size=%d hasn't been registered",
- ce.Offset, ce.ChunkSize)
- }
- return d.Verifier(), nil
-}
-
-// ChunkEntryForOffset returns the TOCEntry containing the byte of the
-// named file at the given offset within the file.
-// Name must be absolute path or one that is relative to root.
-func (r *Reader) ChunkEntryForOffset(name string, offset int64) (e *TOCEntry, ok bool) {
- name = cleanEntryName(name)
- e, ok = r.Lookup(name)
- if !ok || !e.isDataType() {
- return nil, false
- }
- ents := r.chunks[name]
- if len(ents) < 2 {
- if offset >= e.ChunkSize {
- return nil, false
- }
- return e, true
- }
- i := sort.Search(len(ents), func(i int) bool {
- e := ents[i]
- return e.ChunkOffset >= offset || (offset > e.ChunkOffset && offset < e.ChunkOffset+e.ChunkSize)
- })
- if i == len(ents) {
- return nil, false
- }
- return ents[i], true
-}
-
-// Lookup returns the Table of Contents entry for the given path.
-//
-// To get the root directory, use the empty string.
-// Path must be absolute path or one that is relative to root.
-func (r *Reader) Lookup(path string) (e *TOCEntry, ok bool) {
- path = cleanEntryName(path)
- if r == nil {
- return
- }
- e, ok = r.m[path]
- if ok && e.Type == "hardlink" {
- var err error
- e, err = r.getSource(e)
- if err != nil {
- return nil, false
- }
- }
- return
-}
-
-// OpenFile returns the reader of the specified file payload.
-//
-// Name must be absolute path or one that is relative to root.
-func (r *Reader) OpenFile(name string) (*io.SectionReader, error) {
- fr, err := r.newFileReader(name)
- if err != nil {
- return nil, err
- }
- return io.NewSectionReader(fr, 0, fr.size), nil
-}
-
-func (r *Reader) newFileReader(name string) (*fileReader, error) {
- name = cleanEntryName(name)
- ent, ok := r.Lookup(name)
- if !ok {
- // TODO: come up with some error plan. This is lazy:
- return nil, &os.PathError{
- Path: name,
- Op: "OpenFile",
- Err: os.ErrNotExist,
- }
- }
- if ent.Type != "reg" {
- return nil, &os.PathError{
- Path: name,
- Op: "OpenFile",
- Err: errors.New("not a regular file"),
- }
- }
- return &fileReader{
- r: r,
- size: ent.Size,
- ents: r.getChunks(ent),
- }, nil
-}
-
-func (r *Reader) OpenFileWithPreReader(name string, preRead func(*TOCEntry, io.Reader) error) (*io.SectionReader, error) {
- fr, err := r.newFileReader(name)
- if err != nil {
- return nil, err
- }
- fr.preRead = preRead
- return io.NewSectionReader(fr, 0, fr.size), nil
-}
-
-func (r *Reader) getChunks(ent *TOCEntry) []*TOCEntry {
- if ents, ok := r.chunks[ent.Name]; ok {
- return ents
- }
- return []*TOCEntry{ent}
-}
-
-type fileReader struct {
- r *Reader
- size int64
- ents []*TOCEntry // 1 or more reg/chunk entries
- preRead func(*TOCEntry, io.Reader) error
-}
-
-func (fr *fileReader) ReadAt(p []byte, off int64) (n int, err error) {
- if off >= fr.size {
- return 0, io.EOF
- }
- if off < 0 {
- return 0, errors.New("invalid offset")
- }
- var i int
- if len(fr.ents) > 1 {
- i = sort.Search(len(fr.ents), func(i int) bool {
- return fr.ents[i].ChunkOffset >= off
- })
- if i == len(fr.ents) {
- i = len(fr.ents) - 1
- }
- }
- ent := fr.ents[i]
- if ent.ChunkOffset > off {
- if i == 0 {
- return 0, errors.New("internal error; first chunk offset is non-zero")
- }
- ent = fr.ents[i-1]
- }
-
- // If ent is a chunk of a large file, adjust the ReadAt
- // offset by the chunk's offset.
- off -= ent.ChunkOffset
-
- finalEnt := fr.ents[len(fr.ents)-1]
- compressedOff := ent.Offset
- // compressedBytesRemain is the number of compressed bytes in this
- // file remaining, over 1+ chunks.
- compressedBytesRemain := finalEnt.NextOffset() - compressedOff
-
- sr := io.NewSectionReader(fr.r.sr, compressedOff, compressedBytesRemain)
-
- const maxRead = 2 << 20
- var bufSize = maxRead
- if compressedBytesRemain < maxRead {
- bufSize = int(compressedBytesRemain)
- }
-
- br := bufio.NewReaderSize(sr, bufSize)
- if _, err := br.Peek(bufSize); err != nil {
- return 0, fmt.Errorf("fileReader.ReadAt.peek: %v", err)
- }
-
- dr, err := fr.r.decompressor.Reader(br)
- if err != nil {
- return 0, fmt.Errorf("fileReader.ReadAt.decompressor.Reader: %v", err)
- }
- defer dr.Close()
-
- if fr.preRead == nil {
- if n, err := io.CopyN(io.Discard, dr, ent.InnerOffset+off); n != ent.InnerOffset+off || err != nil {
- return 0, fmt.Errorf("discard of %d bytes != %v, %v", ent.InnerOffset+off, n, err)
- }
- return io.ReadFull(dr, p)
- }
-
- var retN int
- var retErr error
- var found bool
- var nr int64
- for _, e := range fr.r.toc.Entries[ent.chunkTopIndex:] {
- if !e.isDataType() {
- continue
- }
- if e.Offset != fr.r.toc.Entries[ent.chunkTopIndex].Offset {
- break
- }
- if in, err := io.CopyN(io.Discard, dr, e.InnerOffset-nr); err != nil || in != e.InnerOffset-nr {
- return 0, fmt.Errorf("discard of remaining %d bytes != %v, %v", e.InnerOffset-nr, in, err)
- }
- nr = e.InnerOffset
- if e == ent {
- found = true
- if n, err := io.CopyN(io.Discard, dr, off); n != off || err != nil {
- return 0, fmt.Errorf("discard of offset %d bytes != %v, %v", off, n, err)
- }
- retN, retErr = io.ReadFull(dr, p)
- nr += off + int64(retN)
- continue
- }
- cr := &countReader{r: io.LimitReader(dr, e.ChunkSize)}
- if err := fr.preRead(e, cr); err != nil {
- return 0, fmt.Errorf("failed to pre read: %w", err)
- }
- nr += cr.n
- }
- if !found {
- return 0, fmt.Errorf("fileReader.ReadAt: target entry not found")
- }
- return retN, retErr
-}
-
-// A Writer writes stargz files.
-//
-// Use NewWriter to create a new Writer.
-type Writer struct {
- bw *bufio.Writer
- cw *countWriter
- toc *JTOC
- diffHash hash.Hash // SHA-256 of uncompressed tar
-
- closed bool
- gz io.WriteCloser
- lastUsername map[int]string
- lastGroupname map[int]string
- compressor Compressor
-
- uncompressedCounter *countWriteFlusher
-
- // ChunkSize optionally controls the maximum number of bytes
- // of data of a regular file that can be written in one gzip
- // stream before a new gzip stream is started.
- // Zero means to use a default, currently 4 MiB.
- ChunkSize int
-
- // MinChunkSize optionally controls the minimum number of bytes
- // of data must be written in one gzip stream before a new gzip
- // NOTE: This adds a TOC property that stargz snapshotter < v0.13.0 doesn't understand.
- MinChunkSize int
-
- needsOpenGzEntries map[string]struct{}
-}
-
-// currentCompressionWriter writes to the current w.gz field, which can
-// change throughout writing a tar entry.
-//
-// Additionally, it updates w's SHA-256 of the uncompressed bytes
-// of the tar file.
-type currentCompressionWriter struct{ w *Writer }
-
-func (ccw currentCompressionWriter) Write(p []byte) (int, error) {
- ccw.w.diffHash.Write(p)
- if ccw.w.gz == nil {
- if err := ccw.w.condOpenGz(); err != nil {
- return 0, err
- }
- }
- return ccw.w.gz.Write(p)
-}
-
-func (w *Writer) chunkSize() int {
- if w.ChunkSize <= 0 {
- return 4 << 20
- }
- return w.ChunkSize
-}
-
-// Unpack decompresses the given estargz blob and returns a ReadCloser of the tar blob.
-// TOC JSON and footer are removed.
-func Unpack(sr *io.SectionReader, c Decompressor) (io.ReadCloser, error) {
- footerSize := c.FooterSize()
- if sr.Size() < footerSize {
- return nil, fmt.Errorf("blob is too small; %d < %d", sr.Size(), footerSize)
- }
- footerOffset := sr.Size() - footerSize
- footer := make([]byte, footerSize)
- if _, err := sr.ReadAt(footer, footerOffset); err != nil {
- return nil, err
- }
- blobPayloadSize, _, _, err := c.ParseFooter(footer)
- if err != nil {
- return nil, fmt.Errorf("failed to parse footer: %w", err)
- }
- if blobPayloadSize < 0 {
- blobPayloadSize = sr.Size()
- }
- return c.Reader(io.LimitReader(sr, blobPayloadSize))
-}
-
-// NewWriter returns a new stargz writer (gzip-based) writing to w.
-//
-// The writer must be closed to write its trailing table of contents.
-func NewWriter(w io.Writer) *Writer {
- return NewWriterLevel(w, gzip.BestCompression)
-}
-
-// NewWriterLevel returns a new stargz writer (gzip-based) writing to w.
-// The compression level is configurable.
-//
-// The writer must be closed to write its trailing table of contents.
-func NewWriterLevel(w io.Writer, compressionLevel int) *Writer {
- return NewWriterWithCompressor(w, NewGzipCompressorWithLevel(compressionLevel))
-}
-
-// NewWriterWithCompressor returns a new stargz writer writing to w.
-// The compression method is configurable.
-//
-// The writer must be closed to write its trailing table of contents.
-func NewWriterWithCompressor(w io.Writer, c Compressor) *Writer {
- bw := bufio.NewWriter(w)
- cw := &countWriter{w: bw}
- return &Writer{
- bw: bw,
- cw: cw,
- toc: &JTOC{Version: 1},
- diffHash: sha256.New(),
- compressor: c,
- uncompressedCounter: &countWriteFlusher{},
- }
-}
-
-// Close writes the stargz's table of contents and flushes all the
-// buffers, returning any error.
-func (w *Writer) Close() (digest.Digest, error) {
- if w.closed {
- return "", nil
- }
- defer func() { w.closed = true }()
-
- if err := w.closeGz(); err != nil {
- return "", err
- }
-
- // Write the TOC index and footer.
- tocDigest, err := w.compressor.WriteTOCAndFooter(w.cw, w.cw.n, w.toc, w.diffHash)
- if err != nil {
- return "", err
- }
- if err := w.bw.Flush(); err != nil {
- return "", err
- }
-
- return tocDigest, nil
-}
-
-func (w *Writer) closeGz() error {
- if w.closed {
- return errors.New("write on closed Writer")
- }
- if w.gz != nil {
- if err := w.gz.Close(); err != nil {
- return err
- }
- w.gz = nil
- }
- return nil
-}
-
-func (w *Writer) flushGz() error {
- if w.closed {
- return errors.New("flush on closed Writer")
- }
- if w.gz != nil {
- if f, ok := w.gz.(interface {
- Flush() error
- }); ok {
- return f.Flush()
- }
- }
- return nil
-}
-
-// nameIfChanged returns name, unless it was the already the value of (*mp)[id],
-// in which case it returns the empty string.
-func (w *Writer) nameIfChanged(mp *map[int]string, id int, name string) string {
- if name == "" {
- return ""
- }
- if *mp == nil {
- *mp = make(map[int]string)
- }
- if (*mp)[id] == name {
- return ""
- }
- (*mp)[id] = name
- return name
-}
-
-func (w *Writer) condOpenGz() (err error) {
- if w.gz == nil {
- w.gz, err = w.compressor.Writer(w.cw)
- if w.gz != nil {
- w.gz = w.uncompressedCounter.register(w.gz)
- }
- }
- return
-}
-
-// AppendTar reads the tar or tar.gz file from r and appends
-// each of its contents to w.
-//
-// The input r can optionally be gzip compressed but the output will
-// always be compressed by the specified compressor.
-func (w *Writer) AppendTar(r io.Reader) error {
- return w.appendTar(r, false)
-}
-
-// AppendTarLossLess reads the tar or tar.gz file from r and appends
-// each of its contents to w.
-//
-// The input r can optionally be gzip compressed but the output will
-// always be compressed by the specified compressor.
-//
-// The difference of this func with AppendTar is that this writes
-// the input tar stream into w without any modification (e.g. to header bytes).
-//
-// Note that if the input tar stream already contains TOC JSON, this returns
-// error because w cannot overwrite the TOC JSON to the one generated by w without
-// lossy modification. To avoid this error, if the input stream is known to be stargz/estargz,
-// you shoud decompress it and remove TOC JSON in advance.
-func (w *Writer) AppendTarLossLess(r io.Reader) error {
- return w.appendTar(r, true)
-}
-
-func (w *Writer) appendTar(r io.Reader, lossless bool) error {
- var src io.Reader
- br := bufio.NewReader(r)
- if isGzip(br) {
- zr, _ := gzip.NewReader(br)
- src = zr
- } else {
- src = io.Reader(br)
- }
- dst := currentCompressionWriter{w}
- var tw *tar.Writer
- if !lossless {
- tw = tar.NewWriter(dst) // use tar writer only when this isn't lossless mode.
- }
- tr := tar.NewReader(src)
- if lossless {
- tr.RawAccounting = true
- }
- prevOffset := w.cw.n
- var prevOffsetUncompressed int64
- for {
- h, err := tr.Next()
- if err == io.EOF {
- if lossless {
- if remain := tr.RawBytes(); len(remain) > 0 {
- // Collect the remaining null bytes.
- // https://github.com/vbatts/tar-split/blob/80a436fd6164c557b131f7c59ed69bd81af69761/concept/main.go#L49-L53
- if _, err := dst.Write(remain); err != nil {
- return err
- }
- }
- }
- break
- }
- if err != nil {
- return fmt.Errorf("error reading from source tar: tar.Reader.Next: %v", err)
- }
- if cleanEntryName(h.Name) == TOCTarName {
- // It is possible for a layer to be "stargzified" twice during the
- // distribution lifecycle. So we reserve "TOCTarName" here to avoid
- // duplicated entries in the resulting layer.
- if lossless {
- // We cannot handle this in lossless way.
- return fmt.Errorf("existing TOC JSON is not allowed; decompress layer before append")
- }
- continue
- }
-
- xattrs := make(map[string][]byte)
- const xattrPAXRecordsPrefix = "SCHILY.xattr."
- if h.PAXRecords != nil {
- for k, v := range h.PAXRecords {
- if strings.HasPrefix(k, xattrPAXRecordsPrefix) {
- xattrs[k[len(xattrPAXRecordsPrefix):]] = []byte(v)
- }
- }
- }
- ent := &TOCEntry{
- Name: h.Name,
- Mode: h.Mode,
- UID: h.Uid,
- GID: h.Gid,
- Uname: w.nameIfChanged(&w.lastUsername, h.Uid, h.Uname),
- Gname: w.nameIfChanged(&w.lastGroupname, h.Gid, h.Gname),
- ModTime3339: formatModtime(h.ModTime),
- Xattrs: xattrs,
- }
- if err := w.condOpenGz(); err != nil {
- return err
- }
- if tw != nil {
- if err := tw.WriteHeader(h); err != nil {
- return err
- }
- } else {
- if _, err := dst.Write(tr.RawBytes()); err != nil {
- return err
- }
- }
- switch h.Typeflag {
- case tar.TypeLink:
- ent.Type = "hardlink"
- ent.LinkName = h.Linkname
- case tar.TypeSymlink:
- ent.Type = "symlink"
- ent.LinkName = h.Linkname
- case tar.TypeDir:
- ent.Type = "dir"
- case tar.TypeReg:
- ent.Type = "reg"
- ent.Size = h.Size
- case tar.TypeChar:
- ent.Type = "char"
- ent.DevMajor = int(h.Devmajor)
- ent.DevMinor = int(h.Devminor)
- case tar.TypeBlock:
- ent.Type = "block"
- ent.DevMajor = int(h.Devmajor)
- ent.DevMinor = int(h.Devminor)
- case tar.TypeFifo:
- ent.Type = "fifo"
- default:
- return fmt.Errorf("unsupported input tar entry %q", h.Typeflag)
- }
-
- // We need to keep a reference to the TOC entry for regular files, so that we
- // can fill the digest later.
- var regFileEntry *TOCEntry
- var payloadDigest digest.Digester
- if h.Typeflag == tar.TypeReg {
- regFileEntry = ent
- payloadDigest = digest.Canonical.Digester()
- }
-
- if h.Typeflag == tar.TypeReg && ent.Size > 0 {
- var written int64
- totalSize := ent.Size // save it before we destroy ent
- tee := io.TeeReader(tr, payloadDigest.Hash())
- for written < totalSize {
- chunkSize := int64(w.chunkSize())
- remain := totalSize - written
- if remain < chunkSize {
- chunkSize = remain
- } else {
- ent.ChunkSize = chunkSize
- }
-
- // We flush the underlying compression writer here to correctly calculate "w.cw.n".
- if err := w.flushGz(); err != nil {
- return err
- }
- if w.needsOpenGz(ent) || w.cw.n-prevOffset >= int64(w.MinChunkSize) {
- if err := w.closeGz(); err != nil {
- return err
- }
- ent.Offset = w.cw.n
- prevOffset = ent.Offset
- prevOffsetUncompressed = w.uncompressedCounter.n
- } else {
- ent.Offset = prevOffset
- ent.InnerOffset = w.uncompressedCounter.n - prevOffsetUncompressed
- }
-
- ent.ChunkOffset = written
- chunkDigest := digest.Canonical.Digester()
-
- if err := w.condOpenGz(); err != nil {
- return err
- }
-
- teeChunk := io.TeeReader(tee, chunkDigest.Hash())
- var out io.Writer
- if tw != nil {
- out = tw
- } else {
- out = dst
- }
- if _, err := io.CopyN(out, teeChunk, chunkSize); err != nil {
- return fmt.Errorf("error copying %q: %v", h.Name, err)
- }
- ent.ChunkDigest = chunkDigest.Digest().String()
- w.toc.Entries = append(w.toc.Entries, ent)
- written += chunkSize
- ent = &TOCEntry{
- Name: h.Name,
- Type: "chunk",
- }
- }
- } else {
- w.toc.Entries = append(w.toc.Entries, ent)
- }
- if payloadDigest != nil {
- regFileEntry.Digest = payloadDigest.Digest().String()
- }
- if tw != nil {
- if err := tw.Flush(); err != nil {
- return err
- }
- }
- }
- remainDest := io.Discard
- if lossless {
- remainDest = dst // Preserve the remaining bytes in lossless mode
- }
- _, err := io.Copy(remainDest, src)
- return err
-}
-
-func (w *Writer) needsOpenGz(ent *TOCEntry) bool {
- if ent.Type != "reg" {
- return false
- }
- if w.needsOpenGzEntries == nil {
- return false
- }
- _, ok := w.needsOpenGzEntries[ent.Name]
- return ok
-}
-
-// DiffID returns the SHA-256 of the uncompressed tar bytes.
-// It is only valid to call DiffID after Close.
-func (w *Writer) DiffID() string {
- return fmt.Sprintf("sha256:%x", w.diffHash.Sum(nil))
-}
-
-func maxFooterSize(blobSize int64, decompressors ...Decompressor) (res int64) {
- for _, d := range decompressors {
- if s := d.FooterSize(); res < s && s <= blobSize {
- res = s
- }
- }
- return
-}
-
-func parseTOC(d Decompressor, sr *io.SectionReader, tocOff, tocSize int64, tocBytes []byte, opts openOpts) (*Reader, error) {
- if tocOff < 0 {
- // This means that TOC isn't contained in the blob.
- // We pass nil reader to ParseTOC and expect that ParseTOC acquire TOC from
- // the external location.
- start := time.Now()
- toc, tocDgst, err := d.ParseTOC(nil)
- if err != nil {
- return nil, err
- }
- if opts.telemetry != nil && opts.telemetry.GetTocLatency != nil {
- opts.telemetry.GetTocLatency(start)
- }
- if opts.telemetry != nil && opts.telemetry.DeserializeTocLatency != nil {
- opts.telemetry.DeserializeTocLatency(start)
- }
- return &Reader{
- sr: sr,
- toc: toc,
- tocDigest: tocDgst,
- decompressor: d,
- }, nil
- }
- if len(tocBytes) > 0 {
- start := time.Now()
- toc, tocDgst, err := d.ParseTOC(bytes.NewReader(tocBytes))
- if err == nil {
- if opts.telemetry != nil && opts.telemetry.DeserializeTocLatency != nil {
- opts.telemetry.DeserializeTocLatency(start)
- }
- return &Reader{
- sr: sr,
- toc: toc,
- tocDigest: tocDgst,
- decompressor: d,
- }, nil
- }
- }
-
- start := time.Now()
- tocBytes = make([]byte, tocSize)
- if _, err := sr.ReadAt(tocBytes, tocOff); err != nil {
- return nil, fmt.Errorf("error reading %d byte TOC targz: %v", len(tocBytes), err)
- }
- if opts.telemetry != nil && opts.telemetry.GetTocLatency != nil {
- opts.telemetry.GetTocLatency(start)
- }
- start = time.Now()
- toc, tocDgst, err := d.ParseTOC(bytes.NewReader(tocBytes))
- if err != nil {
- return nil, err
- }
- if opts.telemetry != nil && opts.telemetry.DeserializeTocLatency != nil {
- opts.telemetry.DeserializeTocLatency(start)
- }
- return &Reader{
- sr: sr,
- toc: toc,
- tocDigest: tocDgst,
- decompressor: d,
- }, nil
-}
-
-func formatModtime(t time.Time) string {
- if t.IsZero() || t.Unix() == 0 {
- return ""
- }
- return t.UTC().Round(time.Second).Format(time.RFC3339)
-}
-
-func cleanEntryName(name string) string {
- // Use path.Clean to consistently deal with path separators across platforms.
- return strings.TrimPrefix(path.Clean("/"+name), "/")
-}
-
-// countWriter counts how many bytes have been written to its wrapped
-// io.Writer.
-type countWriter struct {
- w io.Writer
- n int64
-}
-
-func (cw *countWriter) Write(p []byte) (n int, err error) {
- n, err = cw.w.Write(p)
- cw.n += int64(n)
- return
-}
-
-type countWriteFlusher struct {
- io.WriteCloser
- n int64
-}
-
-func (wc *countWriteFlusher) register(w io.WriteCloser) io.WriteCloser {
- wc.WriteCloser = w
- return wc
-}
-
-func (wc *countWriteFlusher) Write(p []byte) (n int, err error) {
- n, err = wc.WriteCloser.Write(p)
- wc.n += int64(n)
- return
-}
-
-func (wc *countWriteFlusher) Flush() error {
- if f, ok := wc.WriteCloser.(interface {
- Flush() error
- }); ok {
- return f.Flush()
- }
- return nil
-}
-
-func (wc *countWriteFlusher) Close() error {
- err := wc.WriteCloser.Close()
- wc.WriteCloser = nil
- return err
-}
-
-// isGzip reports whether br is positioned right before an upcoming gzip stream.
-// It does not consume any bytes from br.
-func isGzip(br *bufio.Reader) bool {
- const (
- gzipID1 = 0x1f
- gzipID2 = 0x8b
- gzipDeflate = 8
- )
- peek, _ := br.Peek(3)
- return len(peek) >= 3 && peek[0] == gzipID1 && peek[1] == gzipID2 && peek[2] == gzipDeflate
-}
-
-func positive(n int64) int64 {
- if n < 0 {
- return 0
- }
- return n
-}
-
-type countReader struct {
- r io.Reader
- n int64
-}
-
-func (cr *countReader) Read(p []byte) (n int, err error) {
- n, err = cr.r.Read(p)
- cr.n += int64(n)
- return
-}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
deleted file mode 100644
index f24afe32f4..0000000000
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-/*
- Copyright 2019 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file.
-*/
-
-package estargz
-
-import (
- "archive/tar"
- "bytes"
- "compress/gzip"
- "encoding/binary"
- "encoding/json"
- "fmt"
- "hash"
- "io"
- "strconv"
-
- digest "github.com/opencontainers/go-digest"
-)
-
-type gzipCompression struct {
- *GzipCompressor
- *GzipDecompressor
-}
-
-func newGzipCompressionWithLevel(level int) Compression {
- return &gzipCompression{
- &GzipCompressor{level},
- &GzipDecompressor{},
- }
-}
-
-func NewGzipCompressor() *GzipCompressor {
- return &GzipCompressor{gzip.BestCompression}
-}
-
-func NewGzipCompressorWithLevel(level int) *GzipCompressor {
- return &GzipCompressor{level}
-}
-
-type GzipCompressor struct {
- compressionLevel int
-}
-
-func (gc *GzipCompressor) Writer(w io.Writer) (WriteFlushCloser, error) {
- return gzip.NewWriterLevel(w, gc.compressionLevel)
-}
-
-func (gc *GzipCompressor) WriteTOCAndFooter(w io.Writer, off int64, toc *JTOC, diffHash hash.Hash) (digest.Digest, error) {
- tocJSON, err := json.MarshalIndent(toc, "", "\t")
- if err != nil {
- return "", err
- }
- gz, _ := gzip.NewWriterLevel(w, gc.compressionLevel)
- gw := io.Writer(gz)
- if diffHash != nil {
- gw = io.MultiWriter(gz, diffHash)
- }
- tw := tar.NewWriter(gw)
- if err := tw.WriteHeader(&tar.Header{
- Typeflag: tar.TypeReg,
- Name: TOCTarName,
- Size: int64(len(tocJSON)),
- }); err != nil {
- return "", err
- }
- if _, err := tw.Write(tocJSON); err != nil {
- return "", err
- }
-
- if err := tw.Close(); err != nil {
- return "", err
- }
- if err := gz.Close(); err != nil {
- return "", err
- }
- if _, err := w.Write(gzipFooterBytes(off)); err != nil {
- return "", err
- }
- return digest.FromBytes(tocJSON), nil
-}
-
-// gzipFooterBytes returns the 51 bytes footer.
-func gzipFooterBytes(tocOff int64) []byte {
- buf := bytes.NewBuffer(make([]byte, 0, FooterSize))
- gz, _ := gzip.NewWriterLevel(buf, gzip.NoCompression) // MUST be NoCompression to keep 51 bytes
-
- // Extra header indicating the offset of TOCJSON
- // https://tools.ietf.org/html/rfc1952#section-2.3.1.1
- header := make([]byte, 4)
- header[0], header[1] = 'S', 'G'
- subfield := fmt.Sprintf("%016xSTARGZ", tocOff)
- binary.LittleEndian.PutUint16(header[2:4], uint16(len(subfield))) // little-endian per RFC1952
- gz.Header.Extra = append(header, []byte(subfield)...)
- gz.Close()
- if buf.Len() != FooterSize {
- panic(fmt.Sprintf("footer buffer = %d, not %d", buf.Len(), FooterSize))
- }
- return buf.Bytes()
-}
-
-type GzipDecompressor struct{}
-
-func (gz *GzipDecompressor) Reader(r io.Reader) (io.ReadCloser, error) {
- return gzip.NewReader(r)
-}
-
-func (gz *GzipDecompressor) ParseTOC(r io.Reader) (toc *JTOC, tocDgst digest.Digest, err error) {
- return parseTOCEStargz(r)
-}
-
-func (gz *GzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOffset, tocSize int64, err error) {
- if len(p) != FooterSize {
- return 0, 0, 0, fmt.Errorf("invalid length %d cannot be parsed", len(p))
- }
- zr, err := gzip.NewReader(bytes.NewReader(p))
- if err != nil {
- return 0, 0, 0, err
- }
- defer zr.Close()
- extra := zr.Header.Extra
- si1, si2, subfieldlen, subfield := extra[0], extra[1], extra[2:4], extra[4:]
- if si1 != 'S' || si2 != 'G' {
- return 0, 0, 0, fmt.Errorf("invalid subfield IDs: %q, %q; want E, S", si1, si2)
- }
- if slen := binary.LittleEndian.Uint16(subfieldlen); slen != uint16(16+len("STARGZ")) {
- return 0, 0, 0, fmt.Errorf("invalid length of subfield %d; want %d", slen, 16+len("STARGZ"))
- }
- if string(subfield[16:]) != "STARGZ" {
- return 0, 0, 0, fmt.Errorf("STARGZ magic string must be included in the footer subfield")
- }
- tocOffset, err = strconv.ParseInt(string(subfield[:16]), 16, 64)
- if err != nil {
- return 0, 0, 0, fmt.Errorf("legacy: failed to parse toc offset: %w", err)
- }
- return tocOffset, tocOffset, 0, nil
-}
-
-func (gz *GzipDecompressor) FooterSize() int64 {
- return FooterSize
-}
-
-func (gz *GzipDecompressor) DecompressTOC(r io.Reader) (tocJSON io.ReadCloser, err error) {
- return decompressTOCEStargz(r)
-}
-
-type LegacyGzipDecompressor struct{}
-
-func (gz *LegacyGzipDecompressor) Reader(r io.Reader) (io.ReadCloser, error) {
- return gzip.NewReader(r)
-}
-
-func (gz *LegacyGzipDecompressor) ParseTOC(r io.Reader) (toc *JTOC, tocDgst digest.Digest, err error) {
- return parseTOCEStargz(r)
-}
-
-func (gz *LegacyGzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOffset, tocSize int64, err error) {
- if len(p) != legacyFooterSize {
- return 0, 0, 0, fmt.Errorf("legacy: invalid length %d cannot be parsed", len(p))
- }
- zr, err := gzip.NewReader(bytes.NewReader(p))
- if err != nil {
- return 0, 0, 0, fmt.Errorf("legacy: failed to get footer gzip reader: %w", err)
- }
- defer zr.Close()
- extra := zr.Header.Extra
- if len(extra) != 16+len("STARGZ") {
- return 0, 0, 0, fmt.Errorf("legacy: invalid stargz's extra field size")
- }
- if string(extra[16:]) != "STARGZ" {
- return 0, 0, 0, fmt.Errorf("legacy: magic string STARGZ not found")
- }
- tocOffset, err = strconv.ParseInt(string(extra[:16]), 16, 64)
- if err != nil {
- return 0, 0, 0, fmt.Errorf("legacy: failed to parse toc offset: %w", err)
- }
- return tocOffset, tocOffset, 0, nil
-}
-
-func (gz *LegacyGzipDecompressor) FooterSize() int64 {
- return legacyFooterSize
-}
-
-func (gz *LegacyGzipDecompressor) DecompressTOC(r io.Reader) (tocJSON io.ReadCloser, err error) {
- return decompressTOCEStargz(r)
-}
-
-func parseTOCEStargz(r io.Reader) (toc *JTOC, tocDgst digest.Digest, err error) {
- tr, err := decompressTOCEStargz(r)
- if err != nil {
- return nil, "", err
- }
- dgstr := digest.Canonical.Digester()
- toc = new(JTOC)
- if err := json.NewDecoder(io.TeeReader(tr, dgstr.Hash())).Decode(&toc); err != nil {
- return nil, "", fmt.Errorf("error decoding TOC JSON: %v", err)
- }
- if err := tr.Close(); err != nil {
- return nil, "", err
- }
- return toc, dgstr.Digest(), nil
-}
-
-func decompressTOCEStargz(r io.Reader) (tocJSON io.ReadCloser, err error) {
- zr, err := gzip.NewReader(r)
- if err != nil {
- return nil, fmt.Errorf("malformed TOC gzip header: %v", err)
- }
- zr.Multistream(false)
- tr := tar.NewReader(zr)
- h, err := tr.Next()
- if err != nil {
- return nil, fmt.Errorf("failed to find tar header in TOC gzip stream: %v", err)
- }
- if h.Name != TOCTarName {
- return nil, fmt.Errorf("TOC tar entry had name %q; expected %q", h.Name, TOCTarName)
- }
- return readCloser{tr, zr.Close}, nil
-}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
deleted file mode 100644
index ba650b4d1d..0000000000
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
+++ /dev/null
@@ -1,2369 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-/*
- Copyright 2019 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file.
-*/
-
-package estargz
-
-import (
- "archive/tar"
- "bytes"
- "compress/gzip"
- "crypto/rand"
- "crypto/sha256"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "math/big"
- "os"
- "path/filepath"
- "reflect"
- "sort"
- "strings"
- "testing"
- "time"
-
- "github.com/containerd/stargz-snapshotter/estargz/errorutil"
- "github.com/klauspost/compress/zstd"
- digest "github.com/opencontainers/go-digest"
-)
-
-// TestingController is Compression with some helper methods necessary for testing.
-type TestingController interface {
- Compression
- TestStreams(t *testing.T, b []byte, streams []int64)
- DiffIDOf(*testing.T, []byte) string
- String() string
-}
-
-// CompressionTestSuite tests this pkg with controllers can build valid eStargz blobs and parse them.
-func CompressionTestSuite(t *testing.T, controllers ...TestingControllerFactory) {
- t.Run("testBuild", func(t *testing.T) { t.Parallel(); testBuild(t, controllers...) })
- t.Run("testDigestAndVerify", func(t *testing.T) { t.Parallel(); testDigestAndVerify(t, controllers...) })
- t.Run("testWriteAndOpen", func(t *testing.T) { t.Parallel(); testWriteAndOpen(t, controllers...) })
-}
-
-type TestingControllerFactory func() TestingController
-
-const (
- uncompressedType int = iota
- gzipType
- zstdType
-)
-
-var srcCompressions = []int{
- uncompressedType,
- gzipType,
- zstdType,
-}
-
-var allowedPrefix = [4]string{"", "./", "/", "../"}
-
-// testBuild tests the resulting stargz blob built by this pkg has the same
-// contents as the normal stargz blob.
-func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
- tests := []struct {
- name string
- chunkSize int
- minChunkSize []int
- in []tarEntry
- }{
- {
- name: "regfiles and directories",
- chunkSize: 4,
- in: tarOf(
- file("foo", "test1"),
- dir("foo2/"),
- file("foo2/bar", "test2", xAttr(map[string]string{"test": "sample"})),
- ),
- },
- {
- name: "empty files",
- chunkSize: 4,
- in: tarOf(
- file("foo", "tttttt"),
- file("foo_empty", ""),
- file("foo2", "tttttt"),
- file("foo_empty2", ""),
- file("foo3", "tttttt"),
- file("foo_empty3", ""),
- file("foo4", "tttttt"),
- file("foo_empty4", ""),
- file("foo5", "tttttt"),
- file("foo_empty5", ""),
- file("foo6", "tttttt"),
- ),
- },
- {
- name: "various files",
- chunkSize: 4,
- minChunkSize: []int{0, 64000},
- in: tarOf(
- file("baz.txt", "bazbazbazbazbazbazbaz"),
- file("foo1.txt", "a"),
- file("bar/foo2.txt", "b"),
- file("foo3.txt", "c"),
- symlink("barlink", "test/bar.txt"),
- dir("test/"),
- dir("dev/"),
- blockdev("dev/testblock", 3, 4),
- fifo("dev/testfifo"),
- chardev("dev/testchar1", 5, 6),
- file("test/bar.txt", "testbartestbar", xAttr(map[string]string{"test2": "sample2"})),
- dir("test2/"),
- link("test2/bazlink", "baz.txt"),
- chardev("dev/testchar2", 1, 2),
- ),
- },
- {
- name: "no contents",
- chunkSize: 4,
- in: tarOf(
- file("baz.txt", ""),
- symlink("barlink", "test/bar.txt"),
- dir("test/"),
- dir("dev/"),
- blockdev("dev/testblock", 3, 4),
- fifo("dev/testfifo"),
- chardev("dev/testchar1", 5, 6),
- file("test/bar.txt", "", xAttr(map[string]string{"test2": "sample2"})),
- dir("test2/"),
- link("test2/bazlink", "baz.txt"),
- chardev("dev/testchar2", 1, 2),
- ),
- },
- }
- for _, tt := range tests {
- if len(tt.minChunkSize) == 0 {
- tt.minChunkSize = []int{0}
- }
- for _, srcCompression := range srcCompressions {
- srcCompression := srcCompression
- for _, newCL := range controllers {
- newCL := newCL
- for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
- srcTarFormat := srcTarFormat
- for _, prefix := range allowedPrefix {
- prefix := prefix
- for _, minChunkSize := range tt.minChunkSize {
- minChunkSize := minChunkSize
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s,minChunkSize=%d", newCL(), prefix, srcCompression, srcTarFormat, minChunkSize), func(t *testing.T) {
- tarBlob := buildTar(t, tt.in, prefix, srcTarFormat)
- // Test divideEntries()
- entries, err := sortEntries(tarBlob, nil, nil) // identical order
- if err != nil {
- t.Fatalf("failed to parse tar: %v", err)
- }
- var merged []*entry
- for _, part := range divideEntries(entries, 4) {
- merged = append(merged, part...)
- }
- if !reflect.DeepEqual(entries, merged) {
- for _, e := range entries {
- t.Logf("Original: %v", e.header)
- }
- for _, e := range merged {
- t.Logf("Merged: %v", e.header)
- }
- t.Errorf("divided entries couldn't be merged")
- return
- }
-
- // Prepare sample data
- cl1 := newCL()
- wantBuf := new(bytes.Buffer)
- sw := NewWriterWithCompressor(wantBuf, cl1)
- sw.MinChunkSize = minChunkSize
- sw.ChunkSize = tt.chunkSize
- if err := sw.AppendTar(tarBlob); err != nil {
- t.Fatalf("failed to append tar to want stargz: %v", err)
- }
- if _, err := sw.Close(); err != nil {
- t.Fatalf("failed to prepare want stargz: %v", err)
- }
- wantData := wantBuf.Bytes()
- want, err := Open(io.NewSectionReader(
- bytes.NewReader(wantData), 0, int64(len(wantData))),
- WithDecompressors(cl1),
- )
- if err != nil {
- t.Fatalf("failed to parse the want stargz: %v", err)
- }
-
- // Prepare testing data
- var opts []Option
- if minChunkSize > 0 {
- opts = append(opts, WithMinChunkSize(minChunkSize))
- }
- cl2 := newCL()
- rc, err := Build(compressBlob(t, tarBlob, srcCompression),
- append(opts, WithChunkSize(tt.chunkSize), WithCompression(cl2))...)
- if err != nil {
- t.Fatalf("failed to build stargz: %v", err)
- }
- defer rc.Close()
- gotBuf := new(bytes.Buffer)
- if _, err := io.Copy(gotBuf, rc); err != nil {
- t.Fatalf("failed to copy built stargz blob: %v", err)
- }
- gotData := gotBuf.Bytes()
- got, err := Open(io.NewSectionReader(
- bytes.NewReader(gotBuf.Bytes()), 0, int64(len(gotData))),
- WithDecompressors(cl2),
- )
- if err != nil {
- t.Fatalf("failed to parse the got stargz: %v", err)
- }
-
- // Check DiffID is properly calculated
- rc.Close()
- diffID := rc.DiffID()
- wantDiffID := cl2.DiffIDOf(t, gotData)
- if diffID.String() != wantDiffID {
- t.Errorf("DiffID = %q; want %q", diffID, wantDiffID)
- }
-
- // Compare as stargz
- if !isSameVersion(t, cl1, wantData, cl2, gotData) {
- t.Errorf("built stargz hasn't same json")
- return
- }
- if !isSameEntries(t, want, got) {
- t.Errorf("built stargz isn't same as the original")
- return
- }
-
- // Compare as tar.gz
- if !isSameTarGz(t, cl1, wantData, cl2, gotData) {
- t.Errorf("built stargz isn't same tar.gz")
- return
- }
- })
- }
- }
- }
- }
- }
- }
-}
-
-func isSameTarGz(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool {
- aGz, err := cla.Reader(bytes.NewReader(a))
- if err != nil {
- t.Fatalf("failed to read A")
- }
- defer aGz.Close()
- bGz, err := clb.Reader(bytes.NewReader(b))
- if err != nil {
- t.Fatalf("failed to read B")
- }
- defer bGz.Close()
-
- // Same as tar's Next() method but ignores landmarks and TOCJSON file
- next := func(r *tar.Reader) (h *tar.Header, err error) {
- for {
- if h, err = r.Next(); err != nil {
- return
- }
- if h.Name != PrefetchLandmark &&
- h.Name != NoPrefetchLandmark &&
- h.Name != TOCTarName {
- return
- }
- }
- }
-
- aTar := tar.NewReader(aGz)
- bTar := tar.NewReader(bGz)
- for {
- // Fetch and parse next header.
- aH, aErr := next(aTar)
- bH, bErr := next(bTar)
- if aErr != nil || bErr != nil {
- if aErr == io.EOF && bErr == io.EOF {
- break
- }
- t.Fatalf("Failed to parse tar file: A: %v, B: %v", aErr, bErr)
- }
- if !reflect.DeepEqual(aH, bH) {
- t.Logf("different header (A = %v; B = %v)", aH, bH)
- return false
-
- }
- aFile, err := io.ReadAll(aTar)
- if err != nil {
- t.Fatal("failed to read tar payload of A")
- }
- bFile, err := io.ReadAll(bTar)
- if err != nil {
- t.Fatal("failed to read tar payload of B")
- }
- if !bytes.Equal(aFile, bFile) {
- t.Logf("different tar payload (A = %q; B = %q)", string(a), string(b))
- return false
- }
- }
-
- return true
-}
-
-func isSameVersion(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool {
- aJTOC, _, err := parseStargz(io.NewSectionReader(bytes.NewReader(a), 0, int64(len(a))), cla)
- if err != nil {
- t.Fatalf("failed to parse A: %v", err)
- }
- bJTOC, _, err := parseStargz(io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))), clb)
- if err != nil {
- t.Fatalf("failed to parse B: %v", err)
- }
- t.Logf("A: TOCJSON: %v", dumpTOCJSON(t, aJTOC))
- t.Logf("B: TOCJSON: %v", dumpTOCJSON(t, bJTOC))
- return aJTOC.Version == bJTOC.Version
-}
-
-func isSameEntries(t *testing.T, a, b *Reader) bool {
- aroot, ok := a.Lookup("")
- if !ok {
- t.Fatalf("failed to get root of A")
- }
- broot, ok := b.Lookup("")
- if !ok {
- t.Fatalf("failed to get root of B")
- }
- aEntry := stargzEntry{aroot, a}
- bEntry := stargzEntry{broot, b}
- return contains(t, aEntry, bEntry) && contains(t, bEntry, aEntry)
-}
-
-func compressBlob(t *testing.T, src *io.SectionReader, srcCompression int) *io.SectionReader {
- buf := new(bytes.Buffer)
- var w io.WriteCloser
- var err error
- if srcCompression == gzipType {
- w = gzip.NewWriter(buf)
- } else if srcCompression == zstdType {
- w, err = zstd.NewWriter(buf)
- if err != nil {
- t.Fatalf("failed to init zstd writer: %v", err)
- }
- } else {
- return src
- }
- src.Seek(0, io.SeekStart)
- if _, err := io.Copy(w, src); err != nil {
- t.Fatalf("failed to compress source")
- }
- if err := w.Close(); err != nil {
- t.Fatalf("failed to finalize compress source")
- }
- data := buf.Bytes()
- return io.NewSectionReader(bytes.NewReader(data), 0, int64(len(data)))
-
-}
-
-type stargzEntry struct {
- e *TOCEntry
- r *Reader
-}
-
-// contains checks if all child entries in "b" are also contained in "a".
-// This function also checks if the files/chunks contain the same contents among "a" and "b".
-func contains(t *testing.T, a, b stargzEntry) bool {
- ae, ar := a.e, a.r
- be, br := b.e, b.r
- t.Logf("Comparing: %q vs %q", ae.Name, be.Name)
- if !equalEntry(ae, be) {
- t.Logf("%q != %q: entry: a: %v, b: %v", ae.Name, be.Name, ae, be)
- return false
- }
- if ae.Type == "dir" {
- t.Logf("Directory: %q vs %q: %v vs %v", ae.Name, be.Name,
- allChildrenName(ae), allChildrenName(be))
- iscontain := true
- ae.ForeachChild(func(aBaseName string, aChild *TOCEntry) bool {
- // Walk through all files on this stargz file.
-
- if aChild.Name == PrefetchLandmark ||
- aChild.Name == NoPrefetchLandmark {
- return true // Ignore landmarks
- }
-
- // Ignore a TOCEntry of "./" (formated as "" by stargz lib) on root directory
- // because this points to the root directory itself.
- if aChild.Name == "" && ae.Name == "" {
- return true
- }
-
- bChild, ok := be.LookupChild(aBaseName)
- if !ok {
- t.Logf("%q (base: %q): not found in b: %v",
- ae.Name, aBaseName, allChildrenName(be))
- iscontain = false
- return false
- }
-
- childcontain := contains(t, stargzEntry{aChild, a.r}, stargzEntry{bChild, b.r})
- if !childcontain {
- t.Logf("%q != %q: non-equal dir", ae.Name, be.Name)
- iscontain = false
- return false
- }
- return true
- })
- return iscontain
- } else if ae.Type == "reg" {
- af, err := ar.OpenFile(ae.Name)
- if err != nil {
- t.Fatalf("failed to open file %q on A: %v", ae.Name, err)
- }
- bf, err := br.OpenFile(be.Name)
- if err != nil {
- t.Fatalf("failed to open file %q on B: %v", be.Name, err)
- }
-
- var nr int64
- for nr < ae.Size {
- abytes, anext, aok := readOffset(t, af, nr, a)
- bbytes, bnext, bok := readOffset(t, bf, nr, b)
- if !aok && !bok {
- break
- } else if !(aok && bok) || anext != bnext {
- t.Logf("%q != %q (offset=%d): chunk existence a=%v vs b=%v, anext=%v vs bnext=%v",
- ae.Name, be.Name, nr, aok, bok, anext, bnext)
- return false
- }
- nr = anext
- if !bytes.Equal(abytes, bbytes) {
- t.Logf("%q != %q: different contents %v vs %v",
- ae.Name, be.Name, string(abytes), string(bbytes))
- return false
- }
- }
- return true
- }
-
- return true
-}
-
-func allChildrenName(e *TOCEntry) (children []string) {
- e.ForeachChild(func(baseName string, _ *TOCEntry) bool {
- children = append(children, baseName)
- return true
- })
- return
-}
-
-func equalEntry(a, b *TOCEntry) bool {
- // Here, we selectively compare fileds that we are interested in.
- return a.Name == b.Name &&
- a.Type == b.Type &&
- a.Size == b.Size &&
- a.ModTime3339 == b.ModTime3339 &&
- a.Stat().ModTime().Equal(b.Stat().ModTime()) && // modTime time.Time
- a.LinkName == b.LinkName &&
- a.Mode == b.Mode &&
- a.UID == b.UID &&
- a.GID == b.GID &&
- a.Uname == b.Uname &&
- a.Gname == b.Gname &&
- (a.Offset >= 0) == (b.Offset >= 0) &&
- (a.NextOffset() > 0) == (b.NextOffset() > 0) &&
- a.DevMajor == b.DevMajor &&
- a.DevMinor == b.DevMinor &&
- a.NumLink == b.NumLink &&
- reflect.DeepEqual(a.Xattrs, b.Xattrs) &&
- // chunk-related infomations aren't compared in this function.
- // ChunkOffset int64 `json:"chunkOffset,omitempty"`
- // ChunkSize int64 `json:"chunkSize,omitempty"`
- // children map[string]*TOCEntry
- a.Digest == b.Digest
-}
-
-func readOffset(t *testing.T, r *io.SectionReader, offset int64, e stargzEntry) ([]byte, int64, bool) {
- ce, ok := e.r.ChunkEntryForOffset(e.e.Name, offset)
- if !ok {
- return nil, 0, false
- }
- data := make([]byte, ce.ChunkSize)
- t.Logf("Offset: %v, NextOffset: %v", ce.Offset, ce.NextOffset())
- n, err := r.ReadAt(data, ce.ChunkOffset)
- if err != nil {
- t.Fatalf("failed to read file payload of %q (offset:%d,size:%d): %v",
- e.e.Name, ce.ChunkOffset, ce.ChunkSize, err)
- }
- if int64(n) != ce.ChunkSize {
- t.Fatalf("unexpected copied data size %d; want %d",
- n, ce.ChunkSize)
- }
- return data[:n], offset + ce.ChunkSize, true
-}
-
-func dumpTOCJSON(t *testing.T, tocJSON *JTOC) string {
- jtocData, err := json.Marshal(*tocJSON)
- if err != nil {
- t.Fatalf("failed to marshal TOC JSON: %v", err)
- }
- buf := new(bytes.Buffer)
- if _, err := io.Copy(buf, bytes.NewReader(jtocData)); err != nil {
- t.Fatalf("failed to read toc json blob: %v", err)
- }
- return buf.String()
-}
-
-const chunkSize = 3
-
-// type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, compressionLevel int)
-type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory)
-
-// testDigestAndVerify runs specified checks against sample stargz blobs.
-func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory) {
- tests := []struct {
- name string
- tarInit func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry)
- checks []check
- minChunkSize []int
- }{
- {
- name: "no-regfile",
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
- return tarOf(
- dir("test/"),
- )
- },
- checks: []check{
- checkStargzTOC,
- checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTar(t, tarOf(
- dir("test2/"), // modified
- ), allowedPrefix[0])),
- },
- },
- {
- name: "small-files",
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
- return tarOf(
- regDigest(t, "baz.txt", "", dgstMap),
- regDigest(t, "foo.txt", "a", dgstMap),
- dir("test/"),
- regDigest(t, "test/bar.txt", "bbb", dgstMap),
- )
- },
- minChunkSize: []int{0, 64000},
- checks: []check{
- checkStargzTOC,
- checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTar(t, tarOf(
- file("baz.txt", ""),
- file("foo.txt", "M"), // modified
- dir("test/"),
- file("test/bar.txt", "bbb"),
- ), allowedPrefix[0])),
- // checkVerifyInvalidTOCEntryFail("foo.txt"), // TODO
- checkVerifyBrokenContentFail("foo.txt"),
- },
- },
- {
- name: "big-files",
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
- return tarOf(
- regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
- regDigest(t, "foo.txt", "a", dgstMap),
- dir("test/"),
- regDigest(t, "test/bar.txt", "testbartestbar", dgstMap),
- )
- },
- checks: []check{
- checkStargzTOC,
- checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTar(t, tarOf(
- file("baz.txt", "bazbazbazMMMbazbazbaz"), // modified
- file("foo.txt", "a"),
- dir("test/"),
- file("test/bar.txt", "testbartestbar"),
- ), allowedPrefix[0])),
- checkVerifyInvalidTOCEntryFail("test/bar.txt"),
- checkVerifyBrokenContentFail("test/bar.txt"),
- },
- },
- {
- name: "with-non-regfiles",
- minChunkSize: []int{0, 64000},
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
- return tarOf(
- regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
- regDigest(t, "foo.txt", "a", dgstMap),
- regDigest(t, "bar/foo2.txt", "b", dgstMap),
- regDigest(t, "foo3.txt", "c", dgstMap),
- symlink("barlink", "test/bar.txt"),
- dir("test/"),
- regDigest(t, "test/bar.txt", "testbartestbar", dgstMap),
- dir("test2/"),
- link("test2/bazlink", "baz.txt"),
- )
- },
- checks: []check{
- checkStargzTOC,
- checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTar(t, tarOf(
- file("baz.txt", "bazbazbazbazbazbazbaz"),
- file("foo.txt", "a"),
- file("bar/foo2.txt", "b"),
- file("foo3.txt", "c"),
- symlink("barlink", "test/bar.txt"),
- dir("test/"),
- file("test/bar.txt", "testbartestbar"),
- dir("test2/"),
- link("test2/bazlink", "foo.txt"), // modified
- ), allowedPrefix[0])),
- checkVerifyInvalidTOCEntryFail("test/bar.txt"),
- checkVerifyBrokenContentFail("test/bar.txt"),
- },
- },
- }
-
- for _, tt := range tests {
- if len(tt.minChunkSize) == 0 {
- tt.minChunkSize = []int{0}
- }
- for _, srcCompression := range srcCompressions {
- srcCompression := srcCompression
- for _, newCL := range controllers {
- newCL := newCL
- for _, prefix := range allowedPrefix {
- prefix := prefix
- for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
- srcTarFormat := srcTarFormat
- for _, minChunkSize := range tt.minChunkSize {
- minChunkSize := minChunkSize
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s,minChunkSize=%d", newCL(), prefix, srcTarFormat, minChunkSize), func(t *testing.T) {
- // Get original tar file and chunk digests
- dgstMap := make(map[string]digest.Digest)
- tarBlob := buildTar(t, tt.tarInit(t, dgstMap), prefix, srcTarFormat)
-
- cl := newCL()
- rc, err := Build(compressBlob(t, tarBlob, srcCompression),
- WithChunkSize(chunkSize), WithCompression(cl))
- if err != nil {
- t.Fatalf("failed to convert stargz: %v", err)
- }
- tocDigest := rc.TOCDigest()
- defer rc.Close()
- buf := new(bytes.Buffer)
- if _, err := io.Copy(buf, rc); err != nil {
- t.Fatalf("failed to copy built stargz blob: %v", err)
- }
- newStargz := buf.Bytes()
- // NoPrefetchLandmark is added during `Bulid`, which is expected behaviour.
- dgstMap[chunkID(NoPrefetchLandmark, 0, int64(len([]byte{landmarkContents})))] = digest.FromBytes([]byte{landmarkContents})
-
- for _, check := range tt.checks {
- check(t, newStargz, tocDigest, dgstMap, cl, newCL)
- }
- })
- }
- }
- }
- }
- }
- }
-}
-
-// checkStargzTOC checks the TOC JSON of the passed stargz has the expected
-// digest and contains valid chunks. It walks all entries in the stargz and
-// checks all chunk digests stored to the TOC JSON match the actual contents.
-func checkStargzTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
- sgz, err := Open(
- io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
- WithDecompressors(controller),
- )
- if err != nil {
- t.Errorf("failed to parse converted stargz: %v", err)
- return
- }
- digestMapTOC, err := listDigests(io.NewSectionReader(
- bytes.NewReader(sgzData), 0, int64(len(sgzData))),
- controller,
- )
- if err != nil {
- t.Fatalf("failed to list digest: %v", err)
- }
- found := make(map[string]bool)
- for id := range dgstMap {
- found[id] = false
- }
- zr, err := controller.Reader(bytes.NewReader(sgzData))
- if err != nil {
- t.Fatalf("failed to decompress converted stargz: %v", err)
- }
- defer zr.Close()
- tr := tar.NewReader(zr)
- for {
- h, err := tr.Next()
- if err != nil {
- if err != io.EOF {
- t.Errorf("failed to read tar entry: %v", err)
- return
- }
- break
- }
- if h.Name == TOCTarName {
- // Check the digest of TOC JSON based on the actual contents
- // It's sure that TOC JSON exists in this archive because
- // Open succeeded.
- dgstr := digest.Canonical.Digester()
- if _, err := io.Copy(dgstr.Hash(), tr); err != nil {
- t.Fatalf("failed to calculate digest of TOC JSON: %v",
- err)
- }
- if dgstr.Digest() != tocDigest {
- t.Errorf("invalid TOC JSON %q; want %q", tocDigest, dgstr.Digest())
- }
- continue
- }
- if _, ok := sgz.Lookup(h.Name); !ok {
- t.Errorf("lost stargz entry %q in the converted TOC", h.Name)
- return
- }
- var n int64
- for n < h.Size {
- ce, ok := sgz.ChunkEntryForOffset(h.Name, n)
- if !ok {
- t.Errorf("lost chunk %q(offset=%d) in the converted TOC",
- h.Name, n)
- return
- }
-
- // Get the original digest to make sure the file contents are kept unchanged
- // from the original tar, during the whole conversion steps.
- id := chunkID(h.Name, n, ce.ChunkSize)
- want, ok := dgstMap[id]
- if !ok {
- t.Errorf("Unexpected chunk %q(offset=%d,size=%d): %v",
- h.Name, n, ce.ChunkSize, dgstMap)
- return
- }
- found[id] = true
-
- // Check the file contents
- dgstr := digest.Canonical.Digester()
- if _, err := io.CopyN(dgstr.Hash(), tr, ce.ChunkSize); err != nil {
- t.Fatalf("failed to calculate digest of %q (offset=%d,size=%d)",
- h.Name, n, ce.ChunkSize)
- }
- if want != dgstr.Digest() {
- t.Errorf("Invalid contents in converted stargz %q: %q; want %q",
- h.Name, dgstr.Digest(), want)
- return
- }
-
- // Check the digest stored in TOC JSON
- dgstTOC, ok := digestMapTOC[ce.Offset]
- if !ok {
- t.Errorf("digest of %q(offset=%d,size=%d,chunkOffset=%d) isn't registered",
- h.Name, ce.Offset, ce.ChunkSize, ce.ChunkOffset)
- }
- if want != dgstTOC {
- t.Errorf("Invalid digest in TOCEntry %q: %q; want %q",
- h.Name, dgstTOC, want)
- return
- }
-
- n += ce.ChunkSize
- }
- }
-
- for id, ok := range found {
- if !ok {
- t.Errorf("required chunk %q not found in the converted stargz: %v", id, found)
- }
- }
-}
-
-// checkVerifyTOC checks the verification works for the TOC JSON of the passed
-// stargz. It walks all entries in the stargz and checks the verifications for
-// all chunks work.
-func checkVerifyTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
- sgz, err := Open(
- io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
- WithDecompressors(controller),
- )
- if err != nil {
- t.Errorf("failed to parse converted stargz: %v", err)
- return
- }
- ev, err := sgz.VerifyTOC(tocDigest)
- if err != nil {
- t.Errorf("failed to verify stargz: %v", err)
- return
- }
-
- found := make(map[string]bool)
- for id := range dgstMap {
- found[id] = false
- }
- zr, err := controller.Reader(bytes.NewReader(sgzData))
- if err != nil {
- t.Fatalf("failed to decompress converted stargz: %v", err)
- }
- defer zr.Close()
- tr := tar.NewReader(zr)
- for {
- h, err := tr.Next()
- if err != nil {
- if err != io.EOF {
- t.Errorf("failed to read tar entry: %v", err)
- return
- }
- break
- }
- if h.Name == TOCTarName {
- continue
- }
- if _, ok := sgz.Lookup(h.Name); !ok {
- t.Errorf("lost stargz entry %q in the converted TOC", h.Name)
- return
- }
- var n int64
- for n < h.Size {
- ce, ok := sgz.ChunkEntryForOffset(h.Name, n)
- if !ok {
- t.Errorf("lost chunk %q(offset=%d) in the converted TOC",
- h.Name, n)
- return
- }
-
- v, err := ev.Verifier(ce)
- if err != nil {
- t.Errorf("failed to get verifier for %q(offset=%d)", h.Name, n)
- }
-
- found[chunkID(h.Name, n, ce.ChunkSize)] = true
-
- // Check the file contents
- if _, err := io.CopyN(v, tr, ce.ChunkSize); err != nil {
- t.Fatalf("failed to get chunk of %q (offset=%d,size=%d)",
- h.Name, n, ce.ChunkSize)
- }
- if !v.Verified() {
- t.Errorf("Invalid contents in converted stargz %q (should be succeeded)",
- h.Name)
- return
- }
- n += ce.ChunkSize
- }
- }
-
- for id, ok := range found {
- if !ok {
- t.Errorf("required chunk %q not found in the converted stargz: %v", id, found)
- }
- }
-}
-
-// checkVerifyInvalidTOCEntryFail checks if misconfigured TOC JSON can be
-// detected during the verification and the verification returns an error.
-func checkVerifyInvalidTOCEntryFail(filename string) check {
- return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
- funcs := map[string]rewriteFunc{
- "lost digest in a entry": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) {
- var found bool
- for _, e := range toc.Entries {
- if cleanEntryName(e.Name) == filename {
- if e.Type != "reg" && e.Type != "chunk" {
- t.Fatalf("entry %q to break must be regfile or chunk", filename)
- }
- if e.ChunkDigest == "" {
- t.Fatalf("entry %q is already invalid", filename)
- }
- e.ChunkDigest = ""
- found = true
- }
- }
- if !found {
- t.Fatalf("rewrite target not found")
- }
- },
- "duplicated entry offset": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) {
- var (
- sampleEntry *TOCEntry
- targetEntry *TOCEntry
- )
- for _, e := range toc.Entries {
- if e.Type == "reg" || e.Type == "chunk" {
- if cleanEntryName(e.Name) == filename {
- targetEntry = e
- } else {
- sampleEntry = e
- }
- }
- }
- if sampleEntry == nil {
- t.Fatalf("TOC must contain at least one regfile or chunk entry other than the rewrite target")
- return
- }
- if targetEntry == nil {
- t.Fatalf("rewrite target not found")
- return
- }
- targetEntry.Offset = sampleEntry.Offset
- },
- }
-
- for name, rFunc := range funcs {
- t.Run(name, func(t *testing.T) {
- newSgz, newTocDigest := rewriteTOCJSON(t, io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), rFunc, controller)
- buf := new(bytes.Buffer)
- if _, err := io.Copy(buf, newSgz); err != nil {
- t.Fatalf("failed to get converted stargz")
- }
- isgz := buf.Bytes()
-
- sgz, err := Open(
- io.NewSectionReader(bytes.NewReader(isgz), 0, int64(len(isgz))),
- WithDecompressors(controller),
- )
- if err != nil {
- t.Fatalf("failed to parse converted stargz: %v", err)
- return
- }
- _, err = sgz.VerifyTOC(newTocDigest)
- if err == nil {
- t.Errorf("must fail for invalid TOC")
- return
- }
- })
- }
- }
-}
-
-// checkVerifyInvalidStargzFail checks if the verification detects that the
-// given stargz file doesn't match to the expected digest and returns error.
-func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check {
- return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
- cl := newController()
- rc, err := Build(invalid, WithChunkSize(chunkSize), WithCompression(cl))
- if err != nil {
- t.Fatalf("failed to convert stargz: %v", err)
- }
- defer rc.Close()
- buf := new(bytes.Buffer)
- if _, err := io.Copy(buf, rc); err != nil {
- t.Fatalf("failed to copy built stargz blob: %v", err)
- }
- mStargz := buf.Bytes()
-
- sgz, err := Open(
- io.NewSectionReader(bytes.NewReader(mStargz), 0, int64(len(mStargz))),
- WithDecompressors(cl),
- )
- if err != nil {
- t.Fatalf("failed to parse converted stargz: %v", err)
- return
- }
- _, err = sgz.VerifyTOC(tocDigest)
- if err == nil {
- t.Errorf("must fail for invalid TOC")
- return
- }
- }
-}
-
-// checkVerifyBrokenContentFail checks if the verifier detects broken contents
-// that doesn't match to the expected digest and returns error.
-func checkVerifyBrokenContentFail(filename string) check {
- return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
- // Parse stargz file
- sgz, err := Open(
- io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
- WithDecompressors(controller),
- )
- if err != nil {
- t.Fatalf("failed to parse converted stargz: %v", err)
- return
- }
- ev, err := sgz.VerifyTOC(tocDigest)
- if err != nil {
- t.Fatalf("failed to verify stargz: %v", err)
- return
- }
-
- // Open the target file
- sr, err := sgz.OpenFile(filename)
- if err != nil {
- t.Fatalf("failed to open file %q", filename)
- }
- ce, ok := sgz.ChunkEntryForOffset(filename, 0)
- if !ok {
- t.Fatalf("lost chunk %q(offset=%d) in the converted TOC", filename, 0)
- return
- }
- if ce.ChunkSize == 0 {
- t.Fatalf("file mustn't be empty")
- return
- }
- data := make([]byte, ce.ChunkSize)
- if _, err := sr.ReadAt(data, ce.ChunkOffset); err != nil {
- t.Errorf("failed to get data of a chunk of %q(offset=%q)",
- filename, ce.ChunkOffset)
- }
-
- // Check the broken chunk (must fail)
- v, err := ev.Verifier(ce)
- if err != nil {
- t.Fatalf("failed to get verifier for %q", filename)
- }
- broken := append([]byte{^data[0]}, data[1:]...)
- if _, err := io.CopyN(v, bytes.NewReader(broken), ce.ChunkSize); err != nil {
- t.Fatalf("failed to get chunk of %q (offset=%d,size=%d)",
- filename, ce.ChunkOffset, ce.ChunkSize)
- }
- if v.Verified() {
- t.Errorf("verification must fail for broken file chunk %q(org:%q,broken:%q)",
- filename, data, broken)
- }
- }
-}
-
-func chunkID(name string, offset, size int64) string {
- return fmt.Sprintf("%s-%d-%d", cleanEntryName(name), offset, size)
-}
-
-type rewriteFunc func(t *testing.T, toc *JTOC, sgz *io.SectionReader)
-
-func rewriteTOCJSON(t *testing.T, sgz *io.SectionReader, rewrite rewriteFunc, controller TestingController) (newSgz io.Reader, tocDigest digest.Digest) {
- decodedJTOC, jtocOffset, err := parseStargz(sgz, controller)
- if err != nil {
- t.Fatalf("failed to extract TOC JSON: %v", err)
- }
-
- rewrite(t, decodedJTOC, sgz)
-
- tocFooter, tocDigest, err := tocAndFooter(controller, decodedJTOC, jtocOffset)
- if err != nil {
- t.Fatalf("failed to create toc and footer: %v", err)
- }
-
- // Reconstruct stargz file with the modified TOC JSON
- if _, err := sgz.Seek(0, io.SeekStart); err != nil {
- t.Fatalf("failed to reset the seek position of stargz: %v", err)
- }
- return io.MultiReader(
- io.LimitReader(sgz, jtocOffset), // Original stargz (before TOC JSON)
- tocFooter, // Rewritten TOC and footer
- ), tocDigest
-}
-
-func listDigests(sgz *io.SectionReader, controller TestingController) (map[int64]digest.Digest, error) {
- decodedJTOC, _, err := parseStargz(sgz, controller)
- if err != nil {
- return nil, err
- }
- digestMap := make(map[int64]digest.Digest)
- for _, e := range decodedJTOC.Entries {
- if e.Type == "reg" || e.Type == "chunk" {
- if e.Type == "reg" && e.Size == 0 {
- continue // ignores empty file
- }
- if e.ChunkDigest == "" {
- return nil, fmt.Errorf("ChunkDigest of %q(off=%d) not found in TOC JSON",
- e.Name, e.Offset)
- }
- d, err := digest.Parse(e.ChunkDigest)
- if err != nil {
- return nil, err
- }
- digestMap[e.Offset] = d
- }
- }
- return digestMap, nil
-}
-
-func parseStargz(sgz *io.SectionReader, controller TestingController) (decodedJTOC *JTOC, jtocOffset int64, err error) {
- fSize := controller.FooterSize()
- footer := make([]byte, fSize)
- if _, err := sgz.ReadAt(footer, sgz.Size()-fSize); err != nil {
- return nil, 0, fmt.Errorf("error reading footer: %w", err)
- }
- _, tocOffset, _, err := controller.ParseFooter(footer[positive(int64(len(footer))-fSize):])
- if err != nil {
- return nil, 0, fmt.Errorf("failed to parse footer: %w", err)
- }
-
- // Decode the TOC JSON
- var tocReader io.Reader
- if tocOffset >= 0 {
- tocReader = io.NewSectionReader(sgz, tocOffset, sgz.Size()-tocOffset-fSize)
- }
- decodedJTOC, _, err = controller.ParseTOC(tocReader)
- if err != nil {
- return nil, 0, fmt.Errorf("failed to parse TOC: %w", err)
- }
- return decodedJTOC, tocOffset, nil
-}
-
-func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
- const content = "Some contents"
- invalidUtf8 := "\xff\xfe\xfd"
-
- xAttrFile := xAttr{"foo": "bar", "invalid-utf8": invalidUtf8}
- sampleOwner := owner{uid: 50, gid: 100}
-
- data64KB := randomContents(64000)
-
- tests := []struct {
- name string
- chunkSize int
- minChunkSize int
- in []tarEntry
- want []stargzCheck
- wantNumGz int // expected number of streams
-
- wantNumGzLossLess int // expected number of streams (> 0) in lossless mode if it's different from wantNumGz
- wantFailOnLossLess bool
- wantTOCVersion int // default = 1
- }{
- {
- name: "empty",
- in: tarOf(),
- wantNumGz: 2, // (empty tar) + TOC + footer
- want: checks(
- numTOCEntries(0),
- ),
- },
- {
- name: "1dir_1empty_file",
- in: tarOf(
- dir("foo/"),
- file("foo/bar.txt", ""),
- ),
- wantNumGz: 3, // dir, TOC, footer
- want: checks(
- numTOCEntries(2),
- hasDir("foo/"),
- hasFileLen("foo/bar.txt", 0),
- entryHasChildren("foo", "bar.txt"),
- hasFileDigest("foo/bar.txt", digestFor("")),
- ),
- },
- {
- name: "1dir_1file",
- in: tarOf(
- dir("foo/"),
- file("foo/bar.txt", content, xAttrFile),
- ),
- wantNumGz: 4, // var dir, foo.txt alone, TOC, footer
- want: checks(
- numTOCEntries(2),
- hasDir("foo/"),
- hasFileLen("foo/bar.txt", len(content)),
- hasFileDigest("foo/bar.txt", digestFor(content)),
- hasFileContentsRange("foo/bar.txt", 0, content),
- hasFileContentsRange("foo/bar.txt", 1, content[1:]),
- entryHasChildren("", "foo"),
- entryHasChildren("foo", "bar.txt"),
- hasFileXattrs("foo/bar.txt", "foo", "bar"),
- hasFileXattrs("foo/bar.txt", "invalid-utf8", invalidUtf8),
- ),
- },
- {
- name: "2meta_2file",
- in: tarOf(
- dir("bar/", sampleOwner),
- dir("foo/", sampleOwner),
- file("foo/bar.txt", content, sampleOwner),
- ),
- wantNumGz: 4, // both dirs, foo.txt alone, TOC, footer
- want: checks(
- numTOCEntries(3),
- hasDir("bar/"),
- hasDir("foo/"),
- hasFileLen("foo/bar.txt", len(content)),
- entryHasChildren("", "bar", "foo"),
- entryHasChildren("foo", "bar.txt"),
- hasChunkEntries("foo/bar.txt", 1),
- hasEntryOwner("bar/", sampleOwner),
- hasEntryOwner("foo/", sampleOwner),
- hasEntryOwner("foo/bar.txt", sampleOwner),
- ),
- },
- {
- name: "3dir",
- in: tarOf(
- dir("bar/"),
- dir("foo/"),
- dir("foo/bar/"),
- ),
- wantNumGz: 3, // 3 dirs, TOC, footer
- want: checks(
- hasDirLinkCount("bar/", 2),
- hasDirLinkCount("foo/", 3),
- hasDirLinkCount("foo/bar/", 2),
- ),
- },
- {
- name: "symlink",
- in: tarOf(
- dir("foo/"),
- symlink("foo/bar", "../../x"),
- ),
- wantNumGz: 3, // metas + TOC + footer
- want: checks(
- numTOCEntries(2),
- hasSymlink("foo/bar", "../../x"),
- entryHasChildren("", "foo"),
- entryHasChildren("foo", "bar"),
- ),
- },
- {
- name: "chunked_file",
- chunkSize: 4,
- in: tarOf(
- dir("foo/"),
- file("foo/big.txt", "This "+"is s"+"uch "+"a bi"+"g fi"+"le"),
- ),
- wantNumGz: 9, // dir + big.txt(6 chunks) + TOC + footer
- want: checks(
- numTOCEntries(7), // 1 for foo dir, 6 for the foo/big.txt file
- hasDir("foo/"),
- hasFileLen("foo/big.txt", len("This is such a big file")),
- hasFileDigest("foo/big.txt", digestFor("This is such a big file")),
- hasFileContentsRange("foo/big.txt", 0, "This is such a big file"),
- hasFileContentsRange("foo/big.txt", 1, "his is such a big file"),
- hasFileContentsRange("foo/big.txt", 2, "is is such a big file"),
- hasFileContentsRange("foo/big.txt", 3, "s is such a big file"),
- hasFileContentsRange("foo/big.txt", 4, " is such a big file"),
- hasFileContentsRange("foo/big.txt", 5, "is such a big file"),
- hasFileContentsRange("foo/big.txt", 6, "s such a big file"),
- hasFileContentsRange("foo/big.txt", 7, " such a big file"),
- hasFileContentsRange("foo/big.txt", 8, "such a big file"),
- hasFileContentsRange("foo/big.txt", 9, "uch a big file"),
- hasFileContentsRange("foo/big.txt", 10, "ch a big file"),
- hasFileContentsRange("foo/big.txt", 11, "h a big file"),
- hasFileContentsRange("foo/big.txt", 12, " a big file"),
- hasFileContentsRange("foo/big.txt", len("This is such a big file")-1, ""),
- hasChunkEntries("foo/big.txt", 6),
- ),
- },
- {
- name: "recursive",
- in: tarOf(
- dir("/", sampleOwner),
- dir("bar/", sampleOwner),
- dir("foo/", sampleOwner),
- file("foo/bar.txt", content, sampleOwner),
- ),
- wantNumGz: 4, // dirs, bar.txt alone, TOC, footer
- want: checks(
- maxDepth(2), // 0: root directory, 1: "foo/", 2: "bar.txt"
- ),
- },
- {
- name: "block_char_fifo",
- in: tarOf(
- tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- return w.WriteHeader(&tar.Header{
- Name: prefix + "b",
- Typeflag: tar.TypeBlock,
- Devmajor: 123,
- Devminor: 456,
- Format: format,
- })
- }),
- tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- return w.WriteHeader(&tar.Header{
- Name: prefix + "c",
- Typeflag: tar.TypeChar,
- Devmajor: 111,
- Devminor: 222,
- Format: format,
- })
- }),
- tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- return w.WriteHeader(&tar.Header{
- Name: prefix + "f",
- Typeflag: tar.TypeFifo,
- Format: format,
- })
- }),
- ),
- wantNumGz: 3,
- want: checks(
- lookupMatch("b", &TOCEntry{Name: "b", Type: "block", DevMajor: 123, DevMinor: 456, NumLink: 1}),
- lookupMatch("c", &TOCEntry{Name: "c", Type: "char", DevMajor: 111, DevMinor: 222, NumLink: 1}),
- lookupMatch("f", &TOCEntry{Name: "f", Type: "fifo", NumLink: 1}),
- ),
- },
- {
- name: "modes",
- in: tarOf(
- dir("foo1/", 0755|os.ModeDir|os.ModeSetgid),
- file("foo1/bar1", content, 0700|os.ModeSetuid),
- file("foo1/bar2", content, 0755|os.ModeSetgid),
- dir("foo2/", 0755|os.ModeDir|os.ModeSticky),
- file("foo2/bar3", content, 0755|os.ModeSticky),
- dir("foo3/", 0755|os.ModeDir),
- file("foo3/bar4", content, os.FileMode(0700)),
- file("foo3/bar5", content, os.FileMode(0755)),
- ),
- wantNumGz: 8, // dir, bar1 alone, bar2 alone + dir, bar3 alone + dir, bar4 alone, bar5 alone, TOC, footer
- want: checks(
- hasMode("foo1/", 0755|os.ModeDir|os.ModeSetgid),
- hasMode("foo1/bar1", 0700|os.ModeSetuid),
- hasMode("foo1/bar2", 0755|os.ModeSetgid),
- hasMode("foo2/", 0755|os.ModeDir|os.ModeSticky),
- hasMode("foo2/bar3", 0755|os.ModeSticky),
- hasMode("foo3/", 0755|os.ModeDir),
- hasMode("foo3/bar4", os.FileMode(0700)),
- hasMode("foo3/bar5", os.FileMode(0755)),
- ),
- },
- {
- name: "lossy",
- in: tarOf(
- dir("bar/", sampleOwner),
- dir("foo/", sampleOwner),
- file("foo/bar.txt", content, sampleOwner),
- file(TOCTarName, "dummy"), // ignored by the writer. (lossless write returns error)
- ),
- wantNumGz: 4, // both dirs, foo.txt alone, TOC, footer
- want: checks(
- numTOCEntries(3),
- hasDir("bar/"),
- hasDir("foo/"),
- hasFileLen("foo/bar.txt", len(content)),
- entryHasChildren("", "bar", "foo"),
- entryHasChildren("foo", "bar.txt"),
- hasChunkEntries("foo/bar.txt", 1),
- hasEntryOwner("bar/", sampleOwner),
- hasEntryOwner("foo/", sampleOwner),
- hasEntryOwner("foo/bar.txt", sampleOwner),
- ),
- wantFailOnLossLess: true,
- },
- {
- name: "hardlink should be replaced to the destination entry",
- in: tarOf(
- dir("foo/"),
- file("foo/foo1", "test"),
- link("foolink", "foo/foo1"),
- ),
- wantNumGz: 4, // dir, foo1 + link, TOC, footer
- want: checks(
- mustSameEntry("foo/foo1", "foolink"),
- ),
- },
- {
- name: "several_files_in_chunk",
- minChunkSize: 8000,
- in: tarOf(
- dir("foo/"),
- file("foo/foo1", data64KB),
- file("foo2", "bb"),
- file("foo22", "ccc"),
- dir("bar/"),
- file("bar/bar.txt", "aaa"),
- file("foo3", data64KB),
- ),
- // NOTE: we assume that the compressed "data64KB" is still larger than 8KB
- wantNumGz: 4, // dir+foo1, foo2+foo22+dir+bar.txt+foo3, TOC, footer
- want: checks(
- numTOCEntries(7), // dir, foo1, foo2, foo22, dir, bar.txt, foo3
- hasDir("foo/"),
- hasDir("bar/"),
- hasFileLen("foo/foo1", len(data64KB)),
- hasFileLen("foo2", len("bb")),
- hasFileLen("foo22", len("ccc")),
- hasFileLen("bar/bar.txt", len("aaa")),
- hasFileLen("foo3", len(data64KB)),
- hasFileDigest("foo/foo1", digestFor(data64KB)),
- hasFileDigest("foo2", digestFor("bb")),
- hasFileDigest("foo22", digestFor("ccc")),
- hasFileDigest("bar/bar.txt", digestFor("aaa")),
- hasFileDigest("foo3", digestFor(data64KB)),
- hasFileContentsWithPreRead("foo22", 0, "ccc", chunkInfo{"foo2", "bb"}, chunkInfo{"bar/bar.txt", "aaa"}, chunkInfo{"foo3", data64KB}),
- hasFileContentsRange("foo/foo1", 0, data64KB),
- hasFileContentsRange("foo2", 0, "bb"),
- hasFileContentsRange("foo2", 1, "b"),
- hasFileContentsRange("foo22", 0, "ccc"),
- hasFileContentsRange("foo22", 1, "cc"),
- hasFileContentsRange("foo22", 2, "c"),
- hasFileContentsRange("bar/bar.txt", 0, "aaa"),
- hasFileContentsRange("bar/bar.txt", 1, "aa"),
- hasFileContentsRange("bar/bar.txt", 2, "a"),
- hasFileContentsRange("foo3", 0, data64KB),
- hasFileContentsRange("foo3", 1, data64KB[1:]),
- hasFileContentsRange("foo3", 2, data64KB[2:]),
- hasFileContentsRange("foo3", len(data64KB)/2, data64KB[len(data64KB)/2:]),
- hasFileContentsRange("foo3", len(data64KB)-1, data64KB[len(data64KB)-1:]),
- ),
- },
- {
- name: "several_files_in_chunk_chunked",
- minChunkSize: 8000,
- chunkSize: 32000,
- in: tarOf(
- dir("foo/"),
- file("foo/foo1", data64KB),
- file("foo2", "bb"),
- dir("bar/"),
- file("foo3", data64KB),
- ),
- // NOTE: we assume that the compressed chunk of "data64KB" is still larger than 8KB
- wantNumGz: 6, // dir+foo1(1), foo1(2), foo2+dir+foo3(1), foo3(2), TOC, footer
- want: checks(
- numTOCEntries(7), // dir, foo1(2 chunks), foo2, dir, foo3(2 chunks)
- hasDir("foo/"),
- hasDir("bar/"),
- hasFileLen("foo/foo1", len(data64KB)),
- hasFileLen("foo2", len("bb")),
- hasFileLen("foo3", len(data64KB)),
- hasFileDigest("foo/foo1", digestFor(data64KB)),
- hasFileDigest("foo2", digestFor("bb")),
- hasFileDigest("foo3", digestFor(data64KB)),
- hasFileContentsWithPreRead("foo2", 0, "bb", chunkInfo{"foo3", data64KB[:32000]}),
- hasFileContentsRange("foo/foo1", 0, data64KB),
- hasFileContentsRange("foo/foo1", 1, data64KB[1:]),
- hasFileContentsRange("foo/foo1", 2, data64KB[2:]),
- hasFileContentsRange("foo/foo1", len(data64KB)/2, data64KB[len(data64KB)/2:]),
- hasFileContentsRange("foo/foo1", len(data64KB)-1, data64KB[len(data64KB)-1:]),
- hasFileContentsRange("foo2", 0, "bb"),
- hasFileContentsRange("foo2", 1, "b"),
- hasFileContentsRange("foo3", 0, data64KB),
- hasFileContentsRange("foo3", 1, data64KB[1:]),
- hasFileContentsRange("foo3", 2, data64KB[2:]),
- hasFileContentsRange("foo3", len(data64KB)/2, data64KB[len(data64KB)/2:]),
- hasFileContentsRange("foo3", len(data64KB)-1, data64KB[len(data64KB)-1:]),
- ),
- },
- }
-
- for _, tt := range tests {
- for _, newCL := range controllers {
- newCL := newCL
- for _, prefix := range allowedPrefix {
- prefix := prefix
- for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
- srcTarFormat := srcTarFormat
- for _, lossless := range []bool{true, false} {
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", newCL(), prefix, lossless, srcTarFormat), func(t *testing.T) {
- var tr io.Reader = buildTar(t, tt.in, prefix, srcTarFormat)
- origTarDgstr := digest.Canonical.Digester()
- tr = io.TeeReader(tr, origTarDgstr.Hash())
- var stargzBuf bytes.Buffer
- cl1 := newCL()
- w := NewWriterWithCompressor(&stargzBuf, cl1)
- w.ChunkSize = tt.chunkSize
- w.MinChunkSize = tt.minChunkSize
- if lossless {
- err := w.AppendTarLossLess(tr)
- if tt.wantFailOnLossLess {
- if err != nil {
- return // expected to fail
- }
- t.Fatalf("Append wanted to fail on lossless")
- }
- if err != nil {
- t.Fatalf("Append(lossless): %v", err)
- }
- } else {
- if err := w.AppendTar(tr); err != nil {
- t.Fatalf("Append: %v", err)
- }
- }
- if _, err := w.Close(); err != nil {
- t.Fatalf("Writer.Close: %v", err)
- }
- b := stargzBuf.Bytes()
-
- if lossless {
- // Check if the result blob reserves original tar metadata
- rc, err := Unpack(io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))), cl1)
- if err != nil {
- t.Errorf("failed to decompress blob: %v", err)
- return
- }
- defer rc.Close()
- resultDgstr := digest.Canonical.Digester()
- if _, err := io.Copy(resultDgstr.Hash(), rc); err != nil {
- t.Errorf("failed to read result decompressed blob: %v", err)
- return
- }
- if resultDgstr.Digest() != origTarDgstr.Digest() {
- t.Errorf("lossy compression occurred: digest=%v; want %v",
- resultDgstr.Digest(), origTarDgstr.Digest())
- return
- }
- }
-
- diffID := w.DiffID()
- wantDiffID := cl1.DiffIDOf(t, b)
- if diffID != wantDiffID {
- t.Errorf("DiffID = %q; want %q", diffID, wantDiffID)
- }
-
- telemetry, checkCalled := newCalledTelemetry()
- sr := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b)))
- r, err := Open(
- sr,
- WithDecompressors(cl1),
- WithTelemetry(telemetry),
- )
- if err != nil {
- t.Fatalf("stargz.Open: %v", err)
- }
- wantTOCVersion := 1
- if tt.wantTOCVersion > 0 {
- wantTOCVersion = tt.wantTOCVersion
- }
- if r.toc.Version != wantTOCVersion {
- t.Fatalf("invalid TOC Version %d; wanted %d", r.toc.Version, wantTOCVersion)
- }
-
- footerSize := cl1.FooterSize()
- footerOffset := sr.Size() - footerSize
- footer := make([]byte, footerSize)
- if _, err := sr.ReadAt(footer, footerOffset); err != nil {
- t.Errorf("failed to read footer: %v", err)
- }
- _, tocOffset, _, err := cl1.ParseFooter(footer)
- if err != nil {
- t.Errorf("failed to parse footer: %v", err)
- }
- if err := checkCalled(tocOffset >= 0); err != nil {
- t.Errorf("telemetry failure: %v", err)
- }
-
- wantNumGz := tt.wantNumGz
- if lossless && tt.wantNumGzLossLess > 0 {
- wantNumGz = tt.wantNumGzLossLess
- }
- streamOffsets := []int64{0}
- prevOffset := int64(-1)
- streams := 0
- for _, e := range r.toc.Entries {
- if e.Offset > prevOffset {
- streamOffsets = append(streamOffsets, e.Offset)
- prevOffset = e.Offset
- streams++
- }
- }
- streams++ // TOC
- if tocOffset >= 0 {
- // toc is in the blob
- streamOffsets = append(streamOffsets, tocOffset)
- }
- streams++ // footer
- streamOffsets = append(streamOffsets, footerOffset)
- if streams != wantNumGz {
- t.Errorf("number of streams in TOC = %d; want %d", streams, wantNumGz)
- }
-
- t.Logf("testing streams: %+v", streamOffsets)
- cl1.TestStreams(t, b, streamOffsets)
-
- for _, want := range tt.want {
- want.check(t, r)
- }
- })
- }
- }
- }
- }
- }
-}
-
-type chunkInfo struct {
- name string
- data string
-}
-
-func newCalledTelemetry() (telemetry *Telemetry, check func(needsGetTOC bool) error) {
- var getFooterLatencyCalled bool
- var getTocLatencyCalled bool
- var deserializeTocLatencyCalled bool
- return &Telemetry{
- func(time.Time) { getFooterLatencyCalled = true },
- func(time.Time) { getTocLatencyCalled = true },
- func(time.Time) { deserializeTocLatencyCalled = true },
- }, func(needsGetTOC bool) error {
- var allErr []error
- if !getFooterLatencyCalled {
- allErr = append(allErr, fmt.Errorf("metrics GetFooterLatency isn't called"))
- }
- if needsGetTOC {
- if !getTocLatencyCalled {
- allErr = append(allErr, fmt.Errorf("metrics GetTocLatency isn't called"))
- }
- }
- if !deserializeTocLatencyCalled {
- allErr = append(allErr, fmt.Errorf("metrics DeserializeTocLatency isn't called"))
- }
- return errorutil.Aggregate(allErr)
- }
-}
-
-func digestFor(content string) string {
- sum := sha256.Sum256([]byte(content))
- return fmt.Sprintf("sha256:%x", sum)
-}
-
-type numTOCEntries int
-
-func (n numTOCEntries) check(t *testing.T, r *Reader) {
- if r.toc == nil {
- t.Fatal("nil TOC")
- }
- if got, want := len(r.toc.Entries), int(n); got != want {
- t.Errorf("got %d TOC entries; want %d", got, want)
- }
- t.Logf("got TOC entries:")
- for i, ent := range r.toc.Entries {
- entj, _ := json.Marshal(ent)
- t.Logf(" [%d]: %s\n", i, entj)
- }
- if t.Failed() {
- t.FailNow()
- }
-}
-
-func checks(s ...stargzCheck) []stargzCheck { return s }
-
-type stargzCheck interface {
- check(t *testing.T, r *Reader)
-}
-
-type stargzCheckFn func(*testing.T, *Reader)
-
-func (f stargzCheckFn) check(t *testing.T, r *Reader) { f(t, r) }
-
-func maxDepth(max int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- e, ok := r.Lookup("")
- if !ok {
- t.Fatal("root directory not found")
- }
- d, err := getMaxDepth(t, e, 0, 10*max)
- if err != nil {
- t.Errorf("failed to get max depth (wanted %d): %v", max, err)
- return
- }
- if d != max {
- t.Errorf("invalid depth %d; want %d", d, max)
- return
- }
- })
-}
-
-func getMaxDepth(t *testing.T, e *TOCEntry, current, limit int) (max int, rErr error) {
- if current > limit {
- return -1, fmt.Errorf("walkMaxDepth: exceeds limit: current:%d > limit:%d",
- current, limit)
- }
- max = current
- e.ForeachChild(func(baseName string, ent *TOCEntry) bool {
- t.Logf("%q(basename:%q) is child of %q\n", ent.Name, baseName, e.Name)
- d, err := getMaxDepth(t, ent, current+1, limit)
- if err != nil {
- rErr = err
- return false
- }
- if d > max {
- max = d
- }
- return true
- })
- return
-}
-
-func hasFileLen(file string, wantLen int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- for _, ent := range r.toc.Entries {
- if ent.Name == file {
- if ent.Type != "reg" {
- t.Errorf("file type of %q is %q; want \"reg\"", file, ent.Type)
- } else if ent.Size != int64(wantLen) {
- t.Errorf("file size of %q = %d; want %d", file, ent.Size, wantLen)
- }
- return
- }
- }
- t.Errorf("file %q not found", file)
- })
-}
-
-func hasFileXattrs(file, name, value string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- for _, ent := range r.toc.Entries {
- if ent.Name == file {
- if ent.Type != "reg" {
- t.Errorf("file type of %q is %q; want \"reg\"", file, ent.Type)
- }
- if ent.Xattrs == nil {
- t.Errorf("file %q has no xattrs", file)
- return
- }
- valueFound, found := ent.Xattrs[name]
- if !found {
- t.Errorf("file %q has no xattr %q", file, name)
- return
- }
- if string(valueFound) != value {
- t.Errorf("file %q has xattr %q with value %q instead of %q", file, name, valueFound, value)
- }
-
- return
- }
- }
- t.Errorf("file %q not found", file)
- })
-}
-
-func hasFileDigest(file string, digest string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- ent, ok := r.Lookup(file)
- if !ok {
- t.Fatalf("didn't find TOCEntry for file %q", file)
- }
- if ent.Digest != digest {
- t.Fatalf("Digest(%q) = %q, want %q", file, ent.Digest, digest)
- }
- })
-}
-
-func hasFileContentsWithPreRead(file string, offset int, want string, extra ...chunkInfo) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- extraMap := make(map[string]chunkInfo)
- for _, e := range extra {
- extraMap[e.name] = e
- }
- var extraNames []string
- for n := range extraMap {
- extraNames = append(extraNames, n)
- }
- f, err := r.OpenFileWithPreReader(file, func(e *TOCEntry, cr io.Reader) error {
- t.Logf("On %q: got preread of %q", file, e.Name)
- ex, ok := extraMap[e.Name]
- if !ok {
- t.Fatalf("fail on %q: unexpected entry %q: %+v, %+v", file, e.Name, e, extraNames)
- }
- got, err := io.ReadAll(cr)
- if err != nil {
- t.Fatalf("fail on %q: failed to read %q: %v", file, e.Name, err)
- }
- if ex.data != string(got) {
- t.Fatalf("fail on %q: unexpected contents of %q: len=%d; want=%d", file, e.Name, len(got), len(ex.data))
- }
- delete(extraMap, e.Name)
- return nil
- })
- if err != nil {
- t.Fatal(err)
- }
- got := make([]byte, len(want))
- n, err := f.ReadAt(got, int64(offset))
- if err != nil {
- t.Fatalf("ReadAt(len %d, offset %d, size %d) = %v, %v", len(got), offset, f.Size(), n, err)
- }
- if string(got) != want {
- t.Fatalf("ReadAt(len %d, offset %d) = %q, want %q", len(got), offset, viewContent(got), viewContent([]byte(want)))
- }
- if len(extraMap) != 0 {
- var exNames []string
- for _, ex := range extraMap {
- exNames = append(exNames, ex.name)
- }
- t.Fatalf("fail on %q: some entries aren't read: %+v", file, exNames)
- }
- })
-}
-
-func hasFileContentsRange(file string, offset int, want string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- f, err := r.OpenFile(file)
- if err != nil {
- t.Fatal(err)
- }
- got := make([]byte, len(want))
- n, err := f.ReadAt(got, int64(offset))
- if err != nil {
- t.Fatalf("ReadAt(len %d, offset %d) = %v, %v", len(got), offset, n, err)
- }
- if string(got) != want {
- t.Fatalf("ReadAt(len %d, offset %d) = %q, want %q", len(got), offset, viewContent(got), viewContent([]byte(want)))
- }
- })
-}
-
-func hasChunkEntries(file string, wantChunks int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- ent, ok := r.Lookup(file)
- if !ok {
- t.Fatalf("no file for %q", file)
- }
- if ent.Type != "reg" {
- t.Fatalf("file %q has unexpected type %q; want reg", file, ent.Type)
- }
- chunks := r.getChunks(ent)
- if len(chunks) != wantChunks {
- t.Errorf("len(r.getChunks(%q)) = %d; want %d", file, len(chunks), wantChunks)
- return
- }
- f := chunks[0]
-
- var gotChunks []*TOCEntry
- var last *TOCEntry
- for off := int64(0); off < f.Size; off++ {
- e, ok := r.ChunkEntryForOffset(file, off)
- if !ok {
- t.Errorf("no ChunkEntryForOffset at %d", off)
- return
- }
- if last != e {
- gotChunks = append(gotChunks, e)
- last = e
- }
- }
- if !reflect.DeepEqual(chunks, gotChunks) {
- t.Errorf("gotChunks=%d, want=%d; contents mismatch", len(gotChunks), wantChunks)
- }
-
- // And verify the NextOffset
- for i := 0; i < len(gotChunks)-1; i++ {
- ci := gotChunks[i]
- cnext := gotChunks[i+1]
- if ci.NextOffset() != cnext.Offset {
- t.Errorf("chunk %d NextOffset %d != next chunk's Offset of %d", i, ci.NextOffset(), cnext.Offset)
- }
- }
- })
-}
-
-func entryHasChildren(dir string, want ...string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- want := append([]string(nil), want...)
- var got []string
- ent, ok := r.Lookup(dir)
- if !ok {
- t.Fatalf("didn't find TOCEntry for dir node %q", dir)
- }
- for baseName := range ent.children {
- got = append(got, baseName)
- }
- sort.Strings(got)
- sort.Strings(want)
- if !reflect.DeepEqual(got, want) {
- t.Errorf("children of %q = %q; want %q", dir, got, want)
- }
- })
-}
-
-func hasDir(file string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- for _, ent := range r.toc.Entries {
- if ent.Name == cleanEntryName(file) {
- if ent.Type != "dir" {
- t.Errorf("file type of %q is %q; want \"dir\"", file, ent.Type)
- }
- return
- }
- }
- t.Errorf("directory %q not found", file)
- })
-}
-
-func hasDirLinkCount(file string, count int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- for _, ent := range r.toc.Entries {
- if ent.Name == cleanEntryName(file) {
- if ent.Type != "dir" {
- t.Errorf("file type of %q is %q; want \"dir\"", file, ent.Type)
- return
- }
- if ent.NumLink != count {
- t.Errorf("link count of %q = %d; want %d", file, ent.NumLink, count)
- }
- return
- }
- }
- t.Errorf("directory %q not found", file)
- })
-}
-
-func hasMode(file string, mode os.FileMode) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- for _, ent := range r.toc.Entries {
- if ent.Name == cleanEntryName(file) {
- if ent.Stat().Mode() != mode {
- t.Errorf("invalid mode: got %v; want %v", ent.Stat().Mode(), mode)
- return
- }
- return
- }
- }
- t.Errorf("file %q not found", file)
- })
-}
-
-func hasSymlink(file, target string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- for _, ent := range r.toc.Entries {
- if ent.Name == file {
- if ent.Type != "symlink" {
- t.Errorf("file type of %q is %q; want \"symlink\"", file, ent.Type)
- } else if ent.LinkName != target {
- t.Errorf("link target of symlink %q is %q; want %q", file, ent.LinkName, target)
- }
- return
- }
- }
- t.Errorf("symlink %q not found", file)
- })
-}
-
-func lookupMatch(name string, want *TOCEntry) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- e, ok := r.Lookup(name)
- if !ok {
- t.Fatalf("failed to Lookup entry %q", name)
- }
- if !reflect.DeepEqual(e, want) {
- t.Errorf("entry %q mismatch.\n got: %+v\nwant: %+v\n", name, e, want)
- }
-
- })
-}
-
-func hasEntryOwner(entry string, owner owner) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- ent, ok := r.Lookup(strings.TrimSuffix(entry, "/"))
- if !ok {
- t.Errorf("entry %q not found", entry)
- return
- }
- if ent.UID != owner.uid || ent.GID != owner.gid {
- t.Errorf("entry %q has invalid owner (uid:%d, gid:%d) instead of (uid:%d, gid:%d)", entry, ent.UID, ent.GID, owner.uid, owner.gid)
- return
- }
- })
-}
-
-func mustSameEntry(files ...string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
- var first *TOCEntry
- for _, f := range files {
- if first == nil {
- var ok bool
- first, ok = r.Lookup(f)
- if !ok {
- t.Errorf("unknown first file on Lookup: %q", f)
- return
- }
- }
-
- // Test Lookup
- e, ok := r.Lookup(f)
- if !ok {
- t.Errorf("unknown file on Lookup: %q", f)
- return
- }
- if e != first {
- t.Errorf("Lookup: %+v(%p) != %+v(%p)", e, e, first, first)
- return
- }
-
- // Test LookupChild
- pe, ok := r.Lookup(filepath.Dir(filepath.Clean(f)))
- if !ok {
- t.Errorf("failed to get parent of %q", f)
- return
- }
- e, ok = pe.LookupChild(filepath.Base(filepath.Clean(f)))
- if !ok {
- t.Errorf("failed to get %q as the child of %+v", f, pe)
- return
- }
- if e != first {
- t.Errorf("LookupChild: %+v(%p) != %+v(%p)", e, e, first, first)
- return
- }
-
- // Test ForeachChild
- pe.ForeachChild(func(baseName string, e *TOCEntry) bool {
- if baseName == filepath.Base(filepath.Clean(f)) {
- if e != first {
- t.Errorf("ForeachChild: %+v(%p) != %+v(%p)", e, e, first, first)
- return false
- }
- }
- return true
- })
- }
- })
-}
-
-func viewContent(c []byte) string {
- if len(c) < 100 {
- return string(c)
- }
- return string(c[:50]) + "...(omit)..." + string(c[50:100])
-}
-
-func tarOf(s ...tarEntry) []tarEntry { return s }
-
-type tarEntry interface {
- appendTar(tw *tar.Writer, prefix string, format tar.Format) error
-}
-
-type tarEntryFunc func(*tar.Writer, string, tar.Format) error
-
-func (f tarEntryFunc) appendTar(tw *tar.Writer, prefix string, format tar.Format) error {
- return f(tw, prefix, format)
-}
-
-func buildTar(t *testing.T, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader {
- format := tar.FormatUnknown
- for _, opt := range opts {
- switch v := opt.(type) {
- case tar.Format:
- format = v
- default:
- panic(fmt.Errorf("unsupported opt for buildTar: %v", opt))
- }
- }
- buf := new(bytes.Buffer)
- tw := tar.NewWriter(buf)
- for _, ent := range ents {
- if err := ent.appendTar(tw, prefix, format); err != nil {
- t.Fatalf("building input tar: %v", err)
- }
- }
- if err := tw.Close(); err != nil {
- t.Errorf("closing write of input tar: %v", err)
- }
- data := append(buf.Bytes(), make([]byte, 100)...) // append empty bytes at the tail to see lossless works
- return io.NewSectionReader(bytes.NewReader(data), 0, int64(len(data)))
-}
-
-func dir(name string, opts ...interface{}) tarEntry {
- return tarEntryFunc(func(tw *tar.Writer, prefix string, format tar.Format) error {
- var o owner
- mode := os.FileMode(0755)
- for _, opt := range opts {
- switch v := opt.(type) {
- case owner:
- o = v
- case os.FileMode:
- mode = v
- default:
- return errors.New("unsupported opt")
- }
- }
- if !strings.HasSuffix(name, "/") {
- panic(fmt.Sprintf("missing trailing slash in dir %q ", name))
- }
- tm, err := fileModeToTarMode(mode)
- if err != nil {
- return err
- }
- return tw.WriteHeader(&tar.Header{
- Typeflag: tar.TypeDir,
- Name: prefix + name,
- Mode: tm,
- Uid: o.uid,
- Gid: o.gid,
- Format: format,
- })
- })
-}
-
-// xAttr are extended attributes to set on test files created with the file func.
-type xAttr map[string]string
-
-// owner is owner ot set on test files and directories with the file and dir functions.
-type owner struct {
- uid int
- gid int
-}
-
-func file(name, contents string, opts ...interface{}) tarEntry {
- return tarEntryFunc(func(tw *tar.Writer, prefix string, format tar.Format) error {
- var xattrs xAttr
- var o owner
- mode := os.FileMode(0644)
- for _, opt := range opts {
- switch v := opt.(type) {
- case xAttr:
- xattrs = v
- case owner:
- o = v
- case os.FileMode:
- mode = v
- default:
- return errors.New("unsupported opt")
- }
- }
- if strings.HasSuffix(name, "/") {
- return fmt.Errorf("bogus trailing slash in file %q", name)
- }
- tm, err := fileModeToTarMode(mode)
- if err != nil {
- return err
- }
- if len(xattrs) > 0 {
- format = tar.FormatPAX // only PAX supports xattrs
- }
- if err := tw.WriteHeader(&tar.Header{
- Typeflag: tar.TypeReg,
- Name: prefix + name,
- Mode: tm,
- Xattrs: xattrs,
- Size: int64(len(contents)),
- Uid: o.uid,
- Gid: o.gid,
- Format: format,
- }); err != nil {
- return err
- }
- _, err = io.WriteString(tw, contents)
- return err
- })
-}
-
-func symlink(name, target string) tarEntry {
- return tarEntryFunc(func(tw *tar.Writer, prefix string, format tar.Format) error {
- return tw.WriteHeader(&tar.Header{
- Typeflag: tar.TypeSymlink,
- Name: prefix + name,
- Linkname: target,
- Mode: 0644,
- Format: format,
- })
- })
-}
-
-func link(name string, linkname string) tarEntry {
- now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeLink,
- Name: prefix + name,
- Linkname: linkname,
- ModTime: now,
- Format: format,
- })
- })
-}
-
-func chardev(name string, major, minor int64) tarEntry {
- now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeChar,
- Name: prefix + name,
- Devmajor: major,
- Devminor: minor,
- ModTime: now,
- Format: format,
- })
- })
-}
-
-func blockdev(name string, major, minor int64) tarEntry {
- now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeBlock,
- Name: prefix + name,
- Devmajor: major,
- Devminor: minor,
- ModTime: now,
- Format: format,
- })
- })
-}
-func fifo(name string) tarEntry {
- now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeFifo,
- Name: prefix + name,
- ModTime: now,
- Format: format,
- })
- })
-}
-
-func prefetchLandmark() tarEntry {
- return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- if err := w.WriteHeader(&tar.Header{
- Name: PrefetchLandmark,
- Typeflag: tar.TypeReg,
- Size: int64(len([]byte{landmarkContents})),
- Format: format,
- }); err != nil {
- return err
- }
- contents := []byte{landmarkContents}
- if _, err := io.CopyN(w, bytes.NewReader(contents), int64(len(contents))); err != nil {
- return err
- }
- return nil
- })
-}
-
-func noPrefetchLandmark() tarEntry {
- return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- if err := w.WriteHeader(&tar.Header{
- Name: NoPrefetchLandmark,
- Typeflag: tar.TypeReg,
- Size: int64(len([]byte{landmarkContents})),
- Format: format,
- }); err != nil {
- return err
- }
- contents := []byte{landmarkContents}
- if _, err := io.CopyN(w, bytes.NewReader(contents), int64(len(contents))); err != nil {
- return err
- }
- return nil
- })
-}
-
-func regDigest(t *testing.T, name string, contentStr string, digestMap map[string]digest.Digest) tarEntry {
- if digestMap == nil {
- t.Fatalf("digest map mustn't be nil")
- }
- content := []byte(contentStr)
-
- var n int64
- for n < int64(len(content)) {
- size := int64(chunkSize)
- remain := int64(len(content)) - n
- if remain < size {
- size = remain
- }
- dgstr := digest.Canonical.Digester()
- if _, err := io.CopyN(dgstr.Hash(), bytes.NewReader(content[n:n+size]), size); err != nil {
- t.Fatalf("failed to calculate digest of %q (name=%q,offset=%d,size=%d)",
- string(content[n:n+size]), name, n, size)
- }
- digestMap[chunkID(name, n, size)] = dgstr.Digest()
- n += size
- }
-
- return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
- if err := w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeReg,
- Name: prefix + name,
- Size: int64(len(content)),
- Format: format,
- }); err != nil {
- return err
- }
- if _, err := io.CopyN(w, bytes.NewReader(content), int64(len(content))); err != nil {
- return err
- }
- return nil
- })
-}
-
-var runes = []rune("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
-
-func randomContents(n int) string {
- b := make([]rune, n)
- for i := range b {
- bi, err := rand.Int(rand.Reader, big.NewInt(int64(len(runes))))
- if err != nil {
- panic(err)
- }
- b[i] = runes[int(bi.Int64())]
- }
- return string(b)
-}
-
-func fileModeToTarMode(mode os.FileMode) (int64, error) {
- h, err := tar.FileInfoHeader(fileInfoOnlyMode(mode), "")
- if err != nil {
- return 0, err
- }
- return h.Mode, nil
-}
-
-// fileInfoOnlyMode is os.FileMode that populates only file mode.
-type fileInfoOnlyMode os.FileMode
-
-func (f fileInfoOnlyMode) Name() string { return "" }
-func (f fileInfoOnlyMode) Size() int64 { return 0 }
-func (f fileInfoOnlyMode) Mode() os.FileMode { return os.FileMode(f) }
-func (f fileInfoOnlyMode) ModTime() time.Time { return time.Now() }
-func (f fileInfoOnlyMode) IsDir() bool { return os.FileMode(f).IsDir() }
-func (f fileInfoOnlyMode) Sys() interface{} { return nil }
-
-func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) {
- if len(streams) == 0 {
- return // nop
- }
-
- wants := map[int64]struct{}{}
- for _, s := range streams {
- wants[s] = struct{}{}
- }
-
- len0 := len(b)
- br := bytes.NewReader(b)
- zr := new(gzip.Reader)
- t.Logf("got gzip streams:")
- numStreams := 0
- for {
- zoff := len0 - br.Len()
- if err := zr.Reset(br); err != nil {
- if err == io.EOF {
- return
- }
- t.Fatalf("countStreams(gzip), Reset: %v", err)
- }
- zr.Multistream(false)
- n, err := io.Copy(io.Discard, zr)
- if err != nil {
- t.Fatalf("countStreams(gzip), Copy: %v", err)
- }
- var extra string
- if len(zr.Header.Extra) > 0 {
- extra = fmt.Sprintf("; extra=%q", zr.Header.Extra)
- }
- t.Logf(" [%d] at %d in stargz, uncompressed length %d%s", numStreams, zoff, n, extra)
- delete(wants, int64(zoff))
- numStreams++
- }
-}
-
-func GzipDiffIDOf(t *testing.T, b []byte) string {
- h := sha256.New()
- zr, err := gzip.NewReader(bytes.NewReader(b))
- if err != nil {
- t.Fatalf("diffIDOf(gzip): %v", err)
- }
- defer zr.Close()
- if _, err := io.Copy(h, zr); err != nil {
- t.Fatalf("diffIDOf(gzip).Copy: %v", err)
- }
- return fmt.Sprintf("sha256:%x", h.Sum(nil))
-}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/types.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/types.go
deleted file mode 100644
index 57e0aa614e..0000000000
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/types.go
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-/*
- Copyright 2019 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file.
-*/
-
-package estargz
-
-import (
- "archive/tar"
- "hash"
- "io"
- "os"
- "path"
- "time"
-
- digest "github.com/opencontainers/go-digest"
-)
-
-const (
- // TOCTarName is the name of the JSON file in the tar archive in the
- // table of contents gzip stream.
- TOCTarName = "stargz.index.json"
-
- // FooterSize is the number of bytes in the footer
- //
- // The footer is an empty gzip stream with no compression and an Extra
- // header of the form "%016xSTARGZ", where the 64 bit hex-encoded
- // number is the offset to the gzip stream of JSON TOC.
- //
- // 51 comes from:
- //
- // 10 bytes gzip header
- // 2 bytes XLEN (length of Extra field) = 26 (4 bytes header + 16 hex digits + len("STARGZ"))
- // 2 bytes Extra: SI1 = 'S', SI2 = 'G'
- // 2 bytes Extra: LEN = 22 (16 hex digits + len("STARGZ"))
- // 22 bytes Extra: subfield = fmt.Sprintf("%016xSTARGZ", offsetOfTOC)
- // 5 bytes flate header
- // 8 bytes gzip footer
- // (End of the eStargz blob)
- //
- // NOTE: For Extra fields, subfield IDs SI1='S' SI2='G' is used for eStargz.
- FooterSize = 51
-
- // legacyFooterSize is the number of bytes in the legacy stargz footer.
- //
- // 47 comes from:
- //
- // 10 byte gzip header +
- // 2 byte (LE16) length of extra, encoding 22 (16 hex digits + len("STARGZ")) == "\x16\x00" +
- // 22 bytes of extra (fmt.Sprintf("%016xSTARGZ", tocGzipOffset))
- // 5 byte flate header
- // 8 byte gzip footer (two little endian uint32s: digest, size)
- legacyFooterSize = 47
-
- // TOCJSONDigestAnnotation is an annotation for an image layer. This stores the
- // digest of the TOC JSON.
- // This annotation is valid only when it is specified in `.[]layers.annotations`
- // of an image manifest.
- TOCJSONDigestAnnotation = "containerd.io/snapshot/stargz/toc.digest"
-
- // StoreUncompressedSizeAnnotation is an additional annotation key for eStargz to enable lazy
- // pulling on containers/storage. Stargz Store is required to expose the layer's uncompressed size
- // to the runtime but current OCI image doesn't ship this information by default. So we store this
- // to the special annotation.
- StoreUncompressedSizeAnnotation = "io.containers.estargz.uncompressed-size"
-
- // PrefetchLandmark is a file entry which indicates the end position of
- // prefetch in the stargz file.
- PrefetchLandmark = ".prefetch.landmark"
-
- // NoPrefetchLandmark is a file entry which indicates that no prefetch should
- // occur in the stargz file.
- NoPrefetchLandmark = ".no.prefetch.landmark"
-
- landmarkContents = 0xf
-)
-
-// JTOC is the JSON-serialized table of contents index of the files in the stargz file.
-type JTOC struct {
- Version int `json:"version"`
- Entries []*TOCEntry `json:"entries"`
-}
-
-// TOCEntry is an entry in the stargz file's TOC (Table of Contents).
-type TOCEntry struct {
- // Name is the tar entry's name. It is the complete path
- // stored in the tar file, not just the base name.
- Name string `json:"name"`
-
- // Type is one of "dir", "reg", "symlink", "hardlink", "char",
- // "block", "fifo", or "chunk".
- // The "chunk" type is used for regular file data chunks past the first
- // TOCEntry; the 2nd chunk and on have only Type ("chunk"), Offset,
- // ChunkOffset, and ChunkSize populated.
- Type string `json:"type"`
-
- // Size, for regular files, is the logical size of the file.
- Size int64 `json:"size,omitempty"`
-
- // ModTime3339 is the modification time of the tar entry. Empty
- // means zero or unknown. Otherwise it's in UTC RFC3339
- // format. Use the ModTime method to access the time.Time value.
- ModTime3339 string `json:"modtime,omitempty"`
- modTime time.Time
-
- // LinkName, for symlinks and hardlinks, is the link target.
- LinkName string `json:"linkName,omitempty"`
-
- // Mode is the permission and mode bits.
- Mode int64 `json:"mode,omitempty"`
-
- // UID is the user ID of the owner.
- UID int `json:"uid,omitempty"`
-
- // GID is the group ID of the owner.
- GID int `json:"gid,omitempty"`
-
- // Uname is the username of the owner.
- //
- // In the serialized JSON, this field may only be present for
- // the first entry with the same UID.
- Uname string `json:"userName,omitempty"`
-
- // Gname is the group name of the owner.
- //
- // In the serialized JSON, this field may only be present for
- // the first entry with the same GID.
- Gname string `json:"groupName,omitempty"`
-
- // Offset, for regular files, provides the offset in the
- // stargz file to the file's data bytes. See ChunkOffset and
- // ChunkSize.
- Offset int64 `json:"offset,omitempty"`
-
- // InnerOffset is an optional field indicates uncompressed offset
- // of this "reg" or "chunk" payload in a stream starts from Offset.
- // This field enables to put multiple "reg" or "chunk" payloads
- // in one chunk with having the same Offset but different InnerOffset.
- InnerOffset int64 `json:"innerOffset,omitempty"`
-
- nextOffset int64 // the Offset of the next entry with a non-zero Offset
-
- // DevMajor is the major device number for "char" and "block" types.
- DevMajor int `json:"devMajor,omitempty"`
-
- // DevMinor is the major device number for "char" and "block" types.
- DevMinor int `json:"devMinor,omitempty"`
-
- // NumLink is the number of entry names pointing to this entry.
- // Zero means one name references this entry.
- // This field is calculated during runtime and not recorded in TOC JSON.
- NumLink int `json:"-"`
-
- // Xattrs are the extended attribute for the entry.
- Xattrs map[string][]byte `json:"xattrs,omitempty"`
-
- // Digest stores the OCI checksum for regular files payload.
- // It has the form "sha256:abcdef01234....".
- Digest string `json:"digest,omitempty"`
-
- // ChunkOffset is non-zero if this is a chunk of a large,
- // regular file. If so, the Offset is where the gzip header of
- // ChunkSize bytes at ChunkOffset in Name begin.
- //
- // In serialized form, a "chunkSize" JSON field of zero means
- // that the chunk goes to the end of the file. After reading
- // from the stargz TOC, though, the ChunkSize is initialized
- // to a non-zero file for when Type is either "reg" or
- // "chunk".
- ChunkOffset int64 `json:"chunkOffset,omitempty"`
- ChunkSize int64 `json:"chunkSize,omitempty"`
-
- // ChunkDigest stores an OCI digest of the chunk. This must be formed
- // as "sha256:0123abcd...".
- ChunkDigest string `json:"chunkDigest,omitempty"`
-
- children map[string]*TOCEntry
-
- // chunkTopIndex is index of the entry where Offset starts in the blob.
- chunkTopIndex int
-}
-
-// ModTime returns the entry's modification time.
-func (e *TOCEntry) ModTime() time.Time { return e.modTime }
-
-// NextOffset returns the position (relative to the start of the
-// stargz file) of the next gzip boundary after e.Offset.
-func (e *TOCEntry) NextOffset() int64 { return e.nextOffset }
-
-func (e *TOCEntry) addChild(baseName string, child *TOCEntry) {
- if e.children == nil {
- e.children = make(map[string]*TOCEntry)
- }
- if child.Type == "dir" {
- e.NumLink++ // Entry ".." in the subdirectory links to this directory
- }
- e.children[baseName] = child
-}
-
-// isDataType reports whether TOCEntry is a regular file or chunk (something that
-// contains regular file data).
-func (e *TOCEntry) isDataType() bool { return e.Type == "reg" || e.Type == "chunk" }
-
-// Stat returns a FileInfo value representing e.
-func (e *TOCEntry) Stat() os.FileInfo { return fileInfo{e} }
-
-// ForeachChild calls f for each child item. If f returns false, iteration ends.
-// If e is not a directory, f is not called.
-func (e *TOCEntry) ForeachChild(f func(baseName string, ent *TOCEntry) bool) {
- for name, ent := range e.children {
- if !f(name, ent) {
- return
- }
- }
-}
-
-// LookupChild returns the directory e's child by its base name.
-func (e *TOCEntry) LookupChild(baseName string) (child *TOCEntry, ok bool) {
- child, ok = e.children[baseName]
- return
-}
-
-// fileInfo implements os.FileInfo using the wrapped *TOCEntry.
-type fileInfo struct{ e *TOCEntry }
-
-var _ os.FileInfo = fileInfo{}
-
-func (fi fileInfo) Name() string { return path.Base(fi.e.Name) }
-func (fi fileInfo) IsDir() bool { return fi.e.Type == "dir" }
-func (fi fileInfo) Size() int64 { return fi.e.Size }
-func (fi fileInfo) ModTime() time.Time { return fi.e.ModTime() }
-func (fi fileInfo) Sys() interface{} { return fi.e }
-func (fi fileInfo) Mode() (m os.FileMode) {
- // TOCEntry.Mode is tar.Header.Mode so we can understand the these bits using `tar` pkg.
- m = (&tar.Header{Mode: fi.e.Mode}).FileInfo().Mode() &
- (os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky)
- switch fi.e.Type {
- case "dir":
- m |= os.ModeDir
- case "symlink":
- m |= os.ModeSymlink
- case "char":
- m |= os.ModeDevice | os.ModeCharDevice
- case "block":
- m |= os.ModeDevice
- case "fifo":
- m |= os.ModeNamedPipe
- }
- return m
-}
-
-// TOCEntryVerifier holds verifiers that are usable for verifying chunks contained
-// in a eStargz blob.
-type TOCEntryVerifier interface {
-
- // Verifier provides a content verifier that can be used for verifying the
- // contents of the specified TOCEntry.
- Verifier(ce *TOCEntry) (digest.Verifier, error)
-}
-
-// Compression provides the compression helper to be used creating and parsing eStargz.
-// This package provides gzip-based Compression by default, but any compression
-// algorithm (e.g. zstd) can be used as long as it implements Compression.
-type Compression interface {
- Compressor
- Decompressor
-}
-
-// Compressor represents the helper mothods to be used for creating eStargz.
-type Compressor interface {
- // Writer returns WriteCloser to be used for writing a chunk to eStargz.
- // Everytime a chunk is written, the WriteCloser is closed and Writer is
- // called again for writing the next chunk.
- //
- // The returned writer should implement "Flush() error" function that flushes
- // any pending compressed data to the underlying writer.
- Writer(w io.Writer) (WriteFlushCloser, error)
-
- // WriteTOCAndFooter is called to write JTOC to the passed Writer.
- // diffHash calculates the DiffID (uncompressed sha256 hash) of the blob
- // WriteTOCAndFooter can optionally write anything that affects DiffID calculation
- // (e.g. uncompressed TOC JSON).
- //
- // This function returns tocDgst that represents the digest of TOC that will be used
- // to verify this blob when it's parsed.
- WriteTOCAndFooter(w io.Writer, off int64, toc *JTOC, diffHash hash.Hash) (tocDgst digest.Digest, err error)
-}
-
-// Decompressor represents the helper mothods to be used for parsing eStargz.
-type Decompressor interface {
- // Reader returns ReadCloser to be used for decompressing file payload.
- Reader(r io.Reader) (io.ReadCloser, error)
-
- // FooterSize returns the size of the footer of this blob.
- FooterSize() int64
-
- // ParseFooter parses the footer and returns the offset and (compressed) size of TOC.
- // payloadBlobSize is the (compressed) size of the blob payload (i.e. the size between
- // the top until the TOC JSON).
- //
- // If tocOffset < 0, we assume that TOC isn't contained in the blob and pass nil reader
- // to ParseTOC. We expect that ParseTOC acquire TOC from the external location and return it.
- //
- // tocSize is optional. If tocSize <= 0, it's by default the size of the range from tocOffset until the beginning of the
- // footer (blob size - tocOff - FooterSize).
- // If blobPayloadSize < 0, blobPayloadSize become the blob size.
- ParseFooter(p []byte) (blobPayloadSize, tocOffset, tocSize int64, err error)
-
- // ParseTOC parses TOC from the passed reader. The reader provides the partial contents
- // of the underlying blob that has the range specified by ParseFooter method.
- //
- // This function returns tocDgst that represents the digest of TOC that will be used
- // to verify this blob. This must match to the value returned from
- // Compressor.WriteTOCAndFooter that is used when creating this blob.
- //
- // If tocOffset returned by ParseFooter is < 0, we assume that TOC isn't contained in the blob.
- // Pass nil reader to ParseTOC then we expect that ParseTOC acquire TOC from the external location
- // and return it.
- ParseTOC(r io.Reader) (toc *JTOC, tocDgst digest.Digest, err error)
-}
-
-type WriteFlushCloser interface {
- io.WriteCloser
- Flush() error
-}
diff --git a/vendor/github.com/containerd/ttrpc/.gitattributes b/vendor/github.com/containerd/ttrpc/.gitattributes
new file mode 100644
index 0000000000..d207b1802b
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/.gitattributes
@@ -0,0 +1 @@
+*.go text eol=lf
diff --git a/vendor/github.com/containerd/ttrpc/.gitignore b/vendor/github.com/containerd/ttrpc/.gitignore
new file mode 100644
index 0000000000..88ceb2764b
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/.gitignore
@@ -0,0 +1,13 @@
+# Binaries for programs and plugins
+/bin/
+*.exe
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+coverage.txt
diff --git a/vendor/github.com/containerd/ttrpc/.golangci.yml b/vendor/github.com/containerd/ttrpc/.golangci.yml
new file mode 100644
index 0000000000..ef1a7d9635
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/.golangci.yml
@@ -0,0 +1,56 @@
+version: "2"
+linters:
+ enable:
+ - misspell
+ - revive
+ - unconvert
+ disable:
+ - errcheck
+ settings:
+ revive:
+ rules:
+ - name: blank-imports
+ - name: context-as-argument
+ - name: context-keys-type
+ - name: dot-imports
+ - name: error-return
+ - name: error-strings
+ - name: error-naming
+ - name: exported
+ - name: if-return
+ - name: increment-decrement
+ - name: var-naming
+ arguments:
+ - - UID
+ - GID
+ - []
+ - name: var-declaration
+ - name: package-comments
+ - name: range
+ - name: receiver-naming
+ - name: time-naming
+ - name: unexported-return
+ - name: indent-error-flow
+ - name: errorf
+ - name: empty-block
+ - name: superfluous-else
+ - name: unused-parameter
+ - name: unreachable-code
+ - name: redefines-builtin-id
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+ paths:
+ - example
+formatters:
+ enable:
+ - gofmt
+ - goimports
+ exclusions:
+ generated: lax
+ paths:
+ - example
diff --git a/vendor/github.com/containerd/ttrpc/LICENSE b/vendor/github.com/containerd/ttrpc/LICENSE
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/containerd/ttrpc/Makefile b/vendor/github.com/containerd/ttrpc/Makefile
new file mode 100644
index 0000000000..c3a497dcac
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/Makefile
@@ -0,0 +1,180 @@
+# Copyright The containerd Authors.
+
+# 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.
+
+
+# Go command to use for build
+GO ?= go
+INSTALL ?= install
+
+# Root directory of the project (absolute path).
+ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+WHALE = "🇩"
+ONI = "👹"
+
+# Project binaries.
+COMMANDS=protoc-gen-go-ttrpc protoc-gen-gogottrpc
+
+ifdef BUILDTAGS
+ GO_BUILDTAGS = ${BUILDTAGS}
+endif
+GO_BUILDTAGS ?=
+GO_TAGS=$(if $(GO_BUILDTAGS),-tags "$(strip $(GO_BUILDTAGS))",)
+
+# Project packages.
+PACKAGES=$(shell $(GO) list ${GO_TAGS} ./... | grep -v /example)
+TESTPACKAGES=$(shell $(GO) list ${GO_TAGS} ./... | grep -v /cmd | grep -v /integration | grep -v /example)
+BINPACKAGES=$(addprefix ./cmd/,$(COMMANDS))
+
+#Replaces ":" (*nix), ";" (windows) with newline for easy parsing
+GOPATHS=$(shell echo ${GOPATH} | tr ":" "\n" | tr ";" "\n")
+
+TESTFLAGS_RACE=
+GO_BUILD_FLAGS=
+# See Golang issue re: '-trimpath': https://github.com/golang/go/issues/13809
+GO_GCFLAGS=$(shell \
+ set -- ${GOPATHS}; \
+ echo "-gcflags=-trimpath=$${1}/src"; \
+ )
+
+BINARIES=$(addprefix bin/,$(COMMANDS))
+
+# Flags passed to `go test`
+TESTFLAGS ?= $(TESTFLAGS_RACE) $(EXTRA_TESTFLAGS)
+TESTFLAGS_PARALLEL ?= 8
+
+# Use this to replace `go test` with, for instance, `gotestsum`
+GOTEST ?= $(GO) test
+
+.PHONY: clean all AUTHORS build binaries test integration generate protos check-protos coverage ci check help install vendor install-protobuf install-protobuild
+.DEFAULT: default
+
+# Forcibly set the default goal to all, in case an include above brought in a rule definition.
+.DEFAULT_GOAL := all
+
+all: binaries
+
+check: proto-fmt ## run all linters
+ @echo "$(WHALE) $@"
+ GOGC=75 golangci-lint run
+
+ci: check binaries check-protos coverage # coverage-integration ## to be used by the CI
+
+AUTHORS: .mailmap .git/HEAD
+ git log --format='%aN <%aE>' | sort -fu > $@
+
+generate: protos
+ @echo "$(WHALE) $@"
+ @PATH="${ROOTDIR}/bin:${PATH}" $(GO) generate -x ${PACKAGES}
+
+protos: bin/protoc-gen-gogottrpc bin/protoc-gen-go-ttrpc ## generate protobuf
+ @echo "$(WHALE) $@"
+ @(PATH="${ROOTDIR}/bin:${PATH}" protobuild --quiet ${PACKAGES})
+
+check-protos: protos ## check if protobufs needs to be generated again
+ @echo "$(WHALE) $@"
+ @test -z "$$(git status --short | grep ".pb.go" | tee /dev/stderr)" || \
+ ((git diff | cat) && \
+ (echo "$(ONI) please run 'make protos' when making changes to proto files" && false))
+
+check-api-descriptors: protos ## check that protobuf changes aren't present.
+ @echo "$(WHALE) $@"
+ @test -z "$$(git status --short | grep ".pb.txt" | tee /dev/stderr)" || \
+ ((git diff $$(find . -name '*.pb.txt') | cat) && \
+ (echo "$(ONI) please run 'make protos' when making changes to proto files and check-in the generated descriptor file changes" && false))
+
+proto-fmt: ## check format of proto files
+ @echo "$(WHALE) $@"
+ @test -z "$$(find . -name '*.proto' -type f -exec grep -Hn -e "^ " {} \; | tee /dev/stderr)" || \
+ (echo "$(ONI) please indent proto files with tabs only" && false)
+ @test -z "$$(find . -name '*.proto' -type f -exec grep -Hn "Meta meta = " {} \; | grep -v '(gogoproto.nullable) = false' | tee /dev/stderr)" || \
+ (echo "$(ONI) meta fields in proto files must have option (gogoproto.nullable) = false" && false)
+
+build: ## build the go packages
+ @echo "$(WHALE) $@"
+ @$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} ${EXTRA_FLAGS} ${PACKAGES}
+
+test: ## run tests, except integration tests and tests that require root
+ @echo "$(WHALE) $@"
+ @$(GOTEST) ${TESTFLAGS} ${TESTPACKAGES}
+
+integration: ## run integration tests
+ @echo "$(WHALE) $@"
+ @cd "${ROOTDIR}/integration" && $(GOTEST) -v ${TESTFLAGS} -parallel ${TESTFLAGS_PARALLEL} .
+
+benchmark: ## run benchmarks tests
+ @echo "$(WHALE) $@"
+ @$(GO) test ${TESTFLAGS} -bench . -run Benchmark
+
+FORCE:
+
+define BUILD_BINARY
+@echo "$(WHALE) $@"
+@$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@ ${GO_TAGS} ./$<
+endef
+
+# Build a binary from a cmd.
+bin/%: cmd/% FORCE
+ $(call BUILD_BINARY)
+
+binaries: $(BINARIES) ## build binaries
+ @echo "$(WHALE) $@"
+
+clean: ## clean up binaries
+ @echo "$(WHALE) $@"
+ @rm -f $(BINARIES)
+
+install: ## install binaries
+ @echo "$(WHALE) $@ $(BINPACKAGES)"
+ @$(GO) install $(BINPACKAGES)
+
+install-protobuf:
+ @echo "$(WHALE) $@"
+ @script/install-protobuf
+
+install-protobuild:
+ @echo "$(WHALE) $@"
+ @$(GO) install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1
+ @$(GO) install github.com/containerd/protobuild@14832ccc41429f5c4f81028e5af08aa233a219cf
+
+coverage: ## generate coverprofiles from the unit tests, except tests that require root
+ @echo "$(WHALE) $@"
+ @rm -f coverage.txt
+ @$(GO) test ${TESTFLAGS} ${TESTPACKAGES} 2> /dev/null
+ @( for pkg in ${PACKAGES}; do \
+ $(GO) test ${TESTFLAGS} \
+ -cover \
+ -coverprofile=profile.out \
+ -covermode=atomic $$pkg || exit; \
+ if [ -f profile.out ]; then \
+ cat profile.out >> coverage.txt; \
+ rm profile.out; \
+ fi; \
+ done )
+
+vendor: ## ensure all the go.mod/go.sum files are up-to-date
+ @echo "$(WHALE) $@"
+ @$(GO) mod tidy
+ @$(GO) mod verify
+
+verify-vendor: ## verify if all the go.mod/go.sum files are up-to-date
+ @echo "$(WHALE) $@"
+ @$(GO) mod tidy
+ @$(GO) mod verify
+ @test -z "$$(git status --short | grep "go.sum" | tee /dev/stderr)" || \
+ ((git diff | cat) && \
+ (echo "$(ONI) make sure to checkin changes after go mod tidy" && false))
+
+help: ## this help
+ @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort
diff --git a/vendor/github.com/containerd/ttrpc/PROTOCOL.md b/vendor/github.com/containerd/ttrpc/PROTOCOL.md
new file mode 100644
index 0000000000..12b43f6bd6
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/PROTOCOL.md
@@ -0,0 +1,240 @@
+# Protocol Specification
+
+The ttrpc protocol is client/server protocol to support multiple request streams
+over a single connection with lightweight framing. The client represents the
+process which initiated the underlying connection and the server is the process
+which accepted the connection. The protocol is currently defined as
+asymmetrical, with clients sending requests and servers sending responses. Both
+clients and servers are able to send stream data. The roles are also used in
+determining the stream identifiers, with client initiated streams using odd
+number identifiers and server initiated using even number. The protocol may be
+extended in the future to support server initiated streams, that is not
+supported in the latest version.
+
+## Purpose
+
+The ttrpc protocol is designed to be lightweight and optimized for low latency
+and reliable connections between processes on the same host. The protocol does
+not include features for handling unreliable connections such as handshakes,
+resets, pings, or flow control. The protocol is designed to make low-overhead
+implementations as simple as possible. It is not intended as a suitable
+replacement for HTTP2/3 over the network.
+
+## Message Frame
+
+Each Message Frame consists of a 10-byte message header followed
+by message data. The data length and stream ID are both big-endian
+4-byte unsigned integers. The message type is an unsigned 1-byte
+integer. The flags are also an unsigned 1-byte integer and
+use is defined by the message type.
+
+ +---------------------------------------------------------------+
+ | Data Length (32) |
+ +---------------------------------------------------------------+
+ | Stream ID (32) |
+ +---------------+-----------------------------------------------+
+ | Msg Type (8) |
+ +---------------+
+ | Flags (8) |
+ +---------------+-----------------------------------------------+
+ | Data (*) |
+ +---------------------------------------------------------------+
+
+The Data Length field represents the number of bytes in the Data field. The
+total frame size will always be Data Length + 10 bytes. The maximum data length
+is 4MB and any larger size should be rejected. Due to the maximum data size
+being less than 16MB, the first frame byte should always be zero. This first
+byte should be considered reserved for future use.
+
+The Stream ID must be odd for client initiated streams and even for server
+initiated streams. Server initiated streams are not currently supported.
+
+## Mesage Types
+
+| Message Type | Name | Description |
+|--------------|----------|----------------------------------|
+| 0x01 | Request | Initiates stream |
+| 0x02 | Response | Final stream data and terminates |
+| 0x03 | Data | Stream data |
+
+### Request
+
+The request message is used to initiate stream and send along request data for
+properly routing and handling the stream. The stream may indicate unary without
+any inbound or outbound stream data with only a response is expected on the
+stream. The request may also indicate the stream is still open for more data and
+no response is expected until data is finished. If the remote indicates the
+stream is closed, the request may be considered non-unary but without anymore
+stream data sent. In the case of `remote closed`, the remote still expects to
+receive a response or stream data. For compatibility with non streaming clients,
+a request with empty flags indicates a unary request.
+
+#### Request Flags
+
+| Flag | Name | Description |
+|------|-----------------|--------------------------------------------------|
+| 0x01 | `remote closed` | Non-unary, but no more data expected from remote |
+| 0x02 | `remote open` | Non-unary, remote is still sending data |
+
+### Response
+
+The response message is used to end a stream with data, an empty response, or
+an error. A response message is the only expected message after a unary request.
+A non-unary request does not require a response message if the server is sending
+back stream data. A non-unary stream may return a single response message but no
+other stream data may follow.
+
+#### Response Flags
+
+No response flags are defined at this time, flags should be empty.
+
+### Data
+
+The data message is used to send data on an already initialized stream. Either
+client or server may send data. A data message is not allowed on a unary stream.
+A data message should not be sent after indicating `remote closed` to the peer.
+The last data message on a stream must set the `remote closed` flag.
+
+The `no data` flag is used to indicate that the data message does not include
+any data. This is normally used with the `remote closed` flag to indicate the
+stream is now closed without transmitting any data. Since ttrpc normally
+transmits a single object per message, a zero length data message may be
+interpreted as an empty object. For example, transmitting the number zero as a
+protobuf message ends up with a data length of zero, but the message is still
+considered data and should be processed.
+
+#### Data Flags
+
+| Flag | Name | Description |
+|------|-----------------|-----------------------------------|
+| 0x01 | `remote closed` | No more data expected from remote |
+| 0x04 | `no data` | This message does not have data |
+
+## Streaming
+
+All ttrpc requests use streams to transfer data. Unary streams will only have
+two messages sent per stream, a request from a client and a response from the
+server. Non-unary streams, however, may send any numbers of messages from the
+client and the server. This makes stream management more complicated than unary
+streams since both client and server need to track additional state. To keep
+this management as simple as possible, ttrpc minimizes the number of states and
+uses two flags instead of control frames. Each stream has two states while a
+stream is still alive: `local closed` and `remote closed`. Each peer considers
+local and remote from their own perspective and sets flags from the other peer's
+perspective. For example, if a client sends a data frame with the
+`remote closed` flag, that is indicating that the client is now `local closed`
+and the server will be `remote closed`. A unary operation does not need to send
+these flags since each received message always indicates `remote closed`. Once a
+peer is both `local closed` and `remote closed`, the stream is considered
+finished and may be cleaned up.
+
+Due to the asymmetric nature of the current protocol, a client should
+always be in the `local closed` state before `remote closed` and a server should
+always be in the `remote closed` state before `local closed`. This happens
+because the client is always initiating requests and a client always expects a
+final response back from a server to indicate the initiated request has been
+fulfilled. This may mean server sends a final empty response to finish a stream
+even after it has already completed sending data before the client.
+
+### Unary State Diagram
+
+ +--------+ +--------+
+ | Client | | Server |
+ +---+----+ +----+---+
+ | +---------+ |
+ local >---------------+ Request +--------------------> remote
+ closed | +---------+ | closed
+ | |
+ | +----------+ |
+ finished <--------------+ Response +--------------------< finished
+ | +----------+ |
+ | |
+
+### Non-Unary State Diagrams
+
+RC: `remote closed` flag
+RO: `remote open` flag
+
+ +--------+ +--------+
+ | Client | | Server |
+ +---+----+ +----+---+
+ | +--------------+ |
+ >-------------+ Request [RO] +----------------->
+ | +--------------+ |
+ | |
+ | +------+ |
+ >-----------------+ Data +--------------------->
+ | +------+ |
+ | |
+ | +-----------+ |
+ local >---------------+ Data [RC] +------------------> remote
+ closed | +-----------+ | closed
+ | |
+ | +----------+ |
+ finished <--------------+ Response +--------------------< finished
+ | +----------+ |
+ | |
+
+ +--------+ +--------+
+ | Client | | Server |
+ +---+----+ +----+---+
+ | +--------------+ |
+ local >-------------+ Request [RC] +-----------------> remote
+ closed | +--------------+ | closed
+ | |
+ | +------+ |
+ <-----------------+ Data +---------------------<
+ | +------+ |
+ | |
+ | +-----------+ |
+ finished <---------------+ Data [RC] +------------------< finished
+ | +-----------+ |
+ | |
+
+ +--------+ +--------+
+ | Client | | Server |
+ +---+----+ +----+---+
+ | +--------------+ |
+ >-------------+ Request [RO] +----------------->
+ | +--------------+ |
+ | |
+ | +------+ |
+ >-----------------+ Data +--------------------->
+ | +------+ |
+ | |
+ | +------+ |
+ <-----------------+ Data +---------------------<
+ | +------+ |
+ | |
+ | +------+ |
+ >-----------------+ Data +--------------------->
+ | +------+ |
+ | |
+ | +-----------+ |
+ local >---------------+ Data [RC] +------------------> remote
+ closed | +-----------+ | closed
+ | |
+ | +------+ |
+ <-----------------+ Data +---------------------<
+ | +------+ |
+ | |
+ | +-----------+ |
+ finished <---------------+ Data [RC] +------------------< finished
+ | +-----------+ |
+ | |
+
+## RPC
+
+While this protocol is defined primarily to support Remote Procedure Calls, the
+protocol does not define the request and response types beyond the messages
+defined in the protocol. The implementation provides a default protobuf
+definition of request and response which may be used for cross language rpc.
+All implementations should at least define a request type which support
+routing by procedure name and a response type which supports call status.
+
+## Version History
+
+| Version | Features |
+|---------|---------------------|
+| 1.0 | Unary requests only |
+| 1.2 | Streaming support |
diff --git a/vendor/github.com/containerd/ttrpc/Protobuild.toml b/vendor/github.com/containerd/ttrpc/Protobuild.toml
new file mode 100644
index 0000000000..0f6ccbd1e8
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/Protobuild.toml
@@ -0,0 +1,28 @@
+version = "2"
+generators = ["go"]
+
+# Control protoc include paths. Below are usually some good defaults, but feel
+# free to try it without them if it works for your project.
+[includes]
+ # Include paths that will be added before all others. Typically, you want to
+ # treat the root of the project as an include, but this may not be necessary.
+ before = ["."]
+
+ # Paths that will be added untouched to the end of the includes. We use
+ # `/usr/local/include` to pickup the common install location of protobuf.
+ # This is the default.
+ after = ["/usr/local/include"]
+
+# This section maps protobuf imports to Go packages. These will become
+# `-M` directives in the call to the go protobuf generator.
+[packages]
+ "google/protobuf/any.proto" = "github.com/gogo/protobuf/types"
+ "proto/status.proto" = "google.golang.org/genproto/googleapis/rpc/status"
+
+[[overrides]]
+# enable ttrpc and disable fieldpath and grpc for the shim
+prefixes = ["github.com/containerd/ttrpc/integration/streaming"]
+generators = ["go", "go-ttrpc"]
+
+[overrides.parameters.go-ttrpc]
+prefix = "TTRPC"
diff --git a/vendor/github.com/containerd/ttrpc/README.md b/vendor/github.com/containerd/ttrpc/README.md
new file mode 100644
index 0000000000..ce95f63bee
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/README.md
@@ -0,0 +1,59 @@
+# ttrpc
+
+[](https://github.com/containerd/ttrpc/actions/workflows/ci.yml)
+
+GRPC for low-memory environments.
+
+The existing grpc-go project requires a lot of memory overhead for importing
+packages and at runtime. While this is great for many services with low density
+requirements, this can be a problem when running a large number of services on
+a single machine or on a machine with a small amount of memory.
+
+Using the same GRPC definitions, this project reduces the binary size and
+protocol overhead required. We do this by eliding the `net/http`, `net/http2`
+and `grpc` package used by grpc replacing it with a lightweight framing
+protocol. The result are smaller binaries that use less resident memory with
+the same ease of use as GRPC.
+
+Please note that while this project supports generating either end of the
+protocol, the generated service definitions will be incompatible with regular
+GRPC services, as they do not speak the same protocol.
+
+# Protocol
+
+See the [protocol specification](./PROTOCOL.md).
+
+# Usage
+
+Create a gogo vanity binary (see
+[`cmd/protoc-gen-gogottrpc/main.go`](cmd/protoc-gen-gogottrpc/main.go) for an
+example with the ttrpc plugin enabled.
+
+It's recommended to use [`protobuild`](https://github.com/containerd/protobuild)
+to build the protobufs for this project, but this will work with protoc
+directly, if required.
+
+# Differences from GRPC
+
+- The protocol stack has been replaced with a lighter protocol that doesn't
+ require http, http2 and tls.
+- The client and server interface are identical whereas in GRPC there is a
+ client and server interface that are different.
+- The Go stdlib context package is used instead.
+
+# Status
+
+TODO:
+
+- [ ] Add testing under concurrent load to ensure
+- [ ] Verify connection error handling
+
+# Project details
+
+ttrpc is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/ttrpc/channel.go b/vendor/github.com/containerd/ttrpc/channel.go
new file mode 100644
index 0000000000..872261e6de
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/channel.go
@@ -0,0 +1,182 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "bufio"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "net"
+ "sync"
+
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+const (
+ messageHeaderLength = 10
+ messageLengthMax = 4 << 20
+)
+
+type messageType uint8
+
+const (
+ messageTypeRequest messageType = 0x1
+ messageTypeResponse messageType = 0x2
+ messageTypeData messageType = 0x3
+)
+
+func (mt messageType) String() string {
+ switch mt {
+ case messageTypeRequest:
+ return "request"
+ case messageTypeResponse:
+ return "response"
+ case messageTypeData:
+ return "data"
+ default:
+ return "unknown"
+ }
+}
+
+const (
+ flagRemoteClosed uint8 = 0x1
+ flagRemoteOpen uint8 = 0x2
+ flagNoData uint8 = 0x4
+)
+
+// messageHeader represents the fixed-length message header of 10 bytes sent
+// with every request.
+type messageHeader struct {
+ Length uint32 // length excluding this header. b[:4]
+ StreamID uint32 // identifies which request stream message is a part of. b[4:8]
+ Type messageType // message type b[8]
+ Flags uint8 // type specific flags b[9]
+}
+
+func readMessageHeader(p []byte, r io.Reader) (messageHeader, error) {
+ _, err := io.ReadFull(r, p[:messageHeaderLength])
+ if err != nil {
+ return messageHeader{}, err
+ }
+
+ return messageHeader{
+ Length: binary.BigEndian.Uint32(p[:4]),
+ StreamID: binary.BigEndian.Uint32(p[4:8]),
+ Type: messageType(p[8]),
+ Flags: p[9],
+ }, nil
+}
+
+func writeMessageHeader(w io.Writer, p []byte, mh messageHeader) error {
+ binary.BigEndian.PutUint32(p[:4], mh.Length)
+ binary.BigEndian.PutUint32(p[4:8], mh.StreamID)
+ p[8] = byte(mh.Type)
+ p[9] = mh.Flags
+
+ _, err := w.Write(p[:])
+ return err
+}
+
+var buffers sync.Pool
+
+type channel struct {
+ conn net.Conn
+ bw *bufio.Writer
+ br *bufio.Reader
+ hrbuf [messageHeaderLength]byte // avoid alloc when reading header
+ hwbuf [messageHeaderLength]byte
+}
+
+func newChannel(conn net.Conn) *channel {
+ return &channel{
+ conn: conn,
+ bw: bufio.NewWriter(conn),
+ br: bufio.NewReader(conn),
+ }
+}
+
+// recv a message from the channel. The returned buffer contains the message.
+//
+// If a valid grpc status is returned, the message header
+// returned will be valid and caller should send that along to
+// the correct consumer. The bytes on the underlying channel
+// will be discarded.
+func (ch *channel) recv() (messageHeader, []byte, error) {
+ mh, err := readMessageHeader(ch.hrbuf[:], ch.br)
+ if err != nil {
+ return messageHeader{}, nil, err
+ }
+
+ if mh.Length > uint32(messageLengthMax) {
+ if _, err := ch.br.Discard(int(mh.Length)); err != nil {
+ return mh, nil, fmt.Errorf("failed to discard after receiving oversized message: %w", err)
+ }
+
+ return mh, nil, status.Errorf(codes.ResourceExhausted, "message length %v exceed maximum message size of %v", mh.Length, messageLengthMax)
+ }
+
+ var p []byte
+ if mh.Length > 0 {
+ p = ch.getmbuf(int(mh.Length))
+ if _, err := io.ReadFull(ch.br, p); err != nil {
+ return messageHeader{}, nil, fmt.Errorf("failed reading message: %w", err)
+ }
+ }
+
+ return mh, p, nil
+}
+
+func (ch *channel) send(streamID uint32, t messageType, flags uint8, p []byte) error {
+ if len(p) > messageLengthMax {
+ return OversizedMessageError(len(p))
+ }
+
+ if err := writeMessageHeader(ch.bw, ch.hwbuf[:], messageHeader{Length: uint32(len(p)), StreamID: streamID, Type: t, Flags: flags}); err != nil {
+ return err
+ }
+
+ if len(p) > 0 {
+ _, err := ch.bw.Write(p)
+ if err != nil {
+ return err
+ }
+ }
+
+ return ch.bw.Flush()
+}
+
+func (ch *channel) getmbuf(size int) []byte {
+ // we can't use the standard New method on pool because we want to allocate
+ // based on size.
+ b, ok := buffers.Get().(*[]byte)
+ if !ok || cap(*b) < size {
+ // TODO(stevvooe): It may be better to allocate these in fixed length
+ // buckets to reduce fragmentation but its not clear that would help
+ // with performance. An ilogb approach or similar would work well.
+ bb := make([]byte, size)
+ b = &bb
+ } else {
+ *b = (*b)[:size]
+ }
+ return *b
+}
+
+func (ch *channel) putmbuf(p []byte) {
+ buffers.Put(&p)
+}
diff --git a/vendor/github.com/containerd/ttrpc/client.go b/vendor/github.com/containerd/ttrpc/client.go
new file mode 100644
index 0000000000..be20ed4897
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/client.go
@@ -0,0 +1,571 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "strings"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/containerd/log"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
+)
+
+// Client for a ttrpc server
+type Client struct {
+ codec codec
+ conn net.Conn
+ channel *channel
+
+ streamLock sync.RWMutex
+ streams map[streamID]*stream
+ nextStreamID streamID
+ sendLock sync.Mutex
+
+ ctx context.Context
+ closed func()
+
+ closeOnce sync.Once
+ userCloseFunc func()
+ userCloseWaitCh chan struct{}
+
+ interceptor UnaryClientInterceptor
+}
+
+// ClientOpts configures a client
+type ClientOpts func(c *Client)
+
+// WithOnClose sets the close func whenever the client's Close() method is called
+func WithOnClose(onClose func()) ClientOpts {
+ return func(c *Client) {
+ c.userCloseFunc = onClose
+ }
+}
+
+// WithUnaryClientInterceptor sets the provided client interceptor
+func WithUnaryClientInterceptor(i UnaryClientInterceptor) ClientOpts {
+ return func(c *Client) {
+ c.interceptor = i
+ }
+}
+
+// WithChainUnaryClientInterceptor sets the provided chain of client interceptors
+func WithChainUnaryClientInterceptor(interceptors ...UnaryClientInterceptor) ClientOpts {
+ return func(c *Client) {
+ if len(interceptors) == 0 {
+ return
+ }
+ if c.interceptor != nil {
+ interceptors = append([]UnaryClientInterceptor{c.interceptor}, interceptors...)
+ }
+ c.interceptor = func(
+ ctx context.Context,
+ req *Request,
+ reply *Response,
+ info *UnaryClientInfo,
+ final Invoker,
+ ) error {
+ return interceptors[0](ctx, req, reply, info,
+ chainUnaryInterceptors(interceptors[1:], final, info))
+ }
+ }
+}
+
+func chainUnaryInterceptors(interceptors []UnaryClientInterceptor, final Invoker, info *UnaryClientInfo) Invoker {
+ if len(interceptors) == 0 {
+ return final
+ }
+ return func(
+ ctx context.Context,
+ req *Request,
+ reply *Response,
+ ) error {
+ return interceptors[0](ctx, req, reply, info,
+ chainUnaryInterceptors(interceptors[1:], final, info))
+ }
+}
+
+// NewClient creates a new ttrpc client using the given connection
+func NewClient(conn net.Conn, opts ...ClientOpts) *Client {
+ ctx, cancel := context.WithCancel(context.Background())
+ channel := newChannel(conn)
+ c := &Client{
+ codec: codec{},
+ conn: conn,
+ channel: channel,
+ streams: make(map[streamID]*stream),
+ nextStreamID: 1,
+ closed: cancel,
+ ctx: ctx,
+ userCloseFunc: func() {},
+ userCloseWaitCh: make(chan struct{}),
+ }
+
+ for _, o := range opts {
+ o(c)
+ }
+
+ if c.interceptor == nil {
+ c.interceptor = defaultClientInterceptor
+ }
+
+ go c.run()
+ return c
+}
+
+func (c *Client) send(sid uint32, mt messageType, flags uint8, b []byte) error {
+ c.sendLock.Lock()
+ defer c.sendLock.Unlock()
+ return c.channel.send(sid, mt, flags, b)
+}
+
+// Call makes a unary request and returns with response
+func (c *Client) Call(ctx context.Context, service, method string, req, resp interface{}) error {
+ payload, err := c.codec.Marshal(req)
+ if err != nil {
+ return err
+ }
+
+ var (
+ creq = &Request{
+ Service: service,
+ Method: method,
+ Payload: payload,
+ // TODO: metadata from context
+ }
+
+ cresp = &Response{}
+ )
+
+ if metadata, ok := GetMetadata(ctx); ok {
+ metadata.setRequest(creq)
+ }
+
+ if dl, ok := ctx.Deadline(); ok {
+ creq.TimeoutNano = time.Until(dl).Nanoseconds()
+ }
+
+ info := &UnaryClientInfo{
+ FullMethod: fullPath(service, method),
+ }
+ if err := c.interceptor(ctx, creq, cresp, info, c.dispatch); err != nil {
+ return err
+ }
+
+ if err := c.codec.Unmarshal(cresp.Payload, resp); err != nil {
+ return err
+ }
+
+ if cresp.Status != nil && cresp.Status.Code != int32(codes.OK) {
+ return status.ErrorProto(cresp.Status)
+ }
+ return nil
+}
+
+// StreamDesc describes the stream properties, whether the stream has
+// a streaming client, a streaming server, or both
+type StreamDesc struct {
+ StreamingClient bool
+ StreamingServer bool
+}
+
+// ClientStream is used to send or recv messages on the underlying stream
+type ClientStream interface {
+ CloseSend() error
+ SendMsg(m interface{}) error
+ RecvMsg(m interface{}) error
+}
+
+type clientStream struct {
+ ctx context.Context
+ s *stream
+ c *Client
+ desc *StreamDesc
+ localClosed bool
+ remoteClosed bool
+}
+
+func (cs *clientStream) CloseSend() error {
+ if !cs.desc.StreamingClient {
+ return fmt.Errorf("%w: cannot close non-streaming client", ErrProtocol)
+ }
+ if cs.localClosed {
+ return ErrStreamClosed
+ }
+ err := cs.s.send(messageTypeData, flagRemoteClosed|flagNoData, nil)
+ if err != nil {
+ return filterCloseErr(err)
+ }
+ cs.localClosed = true
+ return nil
+}
+
+func (cs *clientStream) SendMsg(m interface{}) error {
+ if !cs.desc.StreamingClient {
+ return fmt.Errorf("%w: cannot send data from non-streaming client", ErrProtocol)
+ }
+ if cs.localClosed {
+ return ErrStreamClosed
+ }
+
+ var (
+ payload []byte
+ err error
+ )
+ if m != nil {
+ payload, err = cs.c.codec.Marshal(m)
+ if err != nil {
+ return err
+ }
+ }
+
+ err = cs.s.send(messageTypeData, 0, payload)
+ if err != nil {
+ return filterCloseErr(err)
+ }
+
+ return nil
+}
+
+func (cs *clientStream) RecvMsg(m interface{}) error {
+ if cs.remoteClosed {
+ return io.EOF
+ }
+
+ var msg *streamMessage
+ select {
+ case <-cs.ctx.Done():
+ return cs.ctx.Err()
+ case <-cs.s.recvClose:
+ // If recv has a pending message, process that first
+ select {
+ case msg = <-cs.s.recv:
+ default:
+ return cs.s.recvErr
+ }
+ case msg = <-cs.s.recv:
+ }
+
+ switch msg.header.Type {
+ case messageTypeResponse:
+ resp := &Response{}
+ err := proto.Unmarshal(msg.payload[:msg.header.Length], resp)
+ // return the payload buffer for reuse
+ cs.c.channel.putmbuf(msg.payload)
+ if err != nil {
+ return err
+ }
+
+ if err := cs.c.codec.Unmarshal(resp.Payload, m); err != nil {
+ return err
+ }
+
+ if resp.Status != nil && resp.Status.Code != int32(codes.OK) {
+ return status.ErrorProto(resp.Status)
+ }
+
+ cs.c.deleteStream(cs.s)
+ cs.remoteClosed = true
+
+ return nil
+ case messageTypeData:
+ if !cs.desc.StreamingServer {
+ cs.c.deleteStream(cs.s)
+ cs.remoteClosed = true
+ return fmt.Errorf("received data from non-streaming server: %w", ErrProtocol)
+ }
+ if msg.header.Flags&flagRemoteClosed == flagRemoteClosed {
+ cs.c.deleteStream(cs.s)
+ cs.remoteClosed = true
+
+ if msg.header.Flags&flagNoData == flagNoData {
+ return io.EOF
+ }
+ }
+
+ err := cs.c.codec.Unmarshal(msg.payload[:msg.header.Length], m)
+ cs.c.channel.putmbuf(msg.payload)
+ if err != nil {
+ return err
+ }
+ return nil
+ default:
+ return fmt.Errorf("unexpected %q message received: %w", msg.header.Type, ErrProtocol)
+ }
+}
+
+// Close closes the ttrpc connection and underlying connection
+func (c *Client) Close() error {
+ c.closeOnce.Do(func() {
+ c.closed()
+
+ c.conn.Close()
+ })
+ return nil
+}
+
+// UserOnCloseWait is used to block until the user's on-close callback
+// finishes.
+func (c *Client) UserOnCloseWait(ctx context.Context) error {
+ select {
+ case <-c.userCloseWaitCh:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
+
+func (c *Client) run() {
+ err := c.receiveLoop()
+ c.Close()
+ c.cleanupStreams(err)
+
+ c.userCloseFunc()
+ close(c.userCloseWaitCh)
+}
+
+func (c *Client) receiveLoop() error {
+ for {
+ select {
+ case <-c.ctx.Done():
+ return ErrClosed
+ default:
+ var (
+ msg = &streamMessage{}
+ err error
+ )
+
+ msg.header, msg.payload, err = c.channel.recv()
+ if err != nil {
+ _, ok := status.FromError(err)
+ if !ok {
+ // treat all errors that are not an rpc status as terminal.
+ // all others poison the connection.
+ return filterCloseErr(err)
+ }
+ }
+ sid := streamID(msg.header.StreamID)
+ s := c.getStream(sid)
+ if s == nil {
+ log.G(c.ctx).WithField("stream", sid).Error("ttrpc: received message on inactive stream")
+ continue
+ }
+
+ if err != nil {
+ s.closeWithError(err)
+ } else {
+ if err := s.receive(c.ctx, msg); err != nil {
+ log.G(c.ctx).WithFields(log.Fields{"error": err, "stream": sid}).Error("ttrpc: failed to handle message")
+ }
+ }
+ }
+ }
+}
+
+// createStream creates a new stream and registers it with the client
+// Introduce stream types for multiple or single response
+func (c *Client) createStream(flags uint8, b []byte) (*stream, error) {
+ // sendLock must be held across both allocation of the stream ID and sending it across the wire.
+ // This ensures that new stream IDs sent on the wire are always increasing, which is a
+ // requirement of the TTRPC protocol.
+ // This use of sendLock could be split into another mutex that covers stream creation + first send,
+ // and just use sendLock to guard writing to the wire, but for now it seems simpler to have fewer mutexes.
+ c.sendLock.Lock()
+ defer c.sendLock.Unlock()
+
+ // Check if closed since lock acquired to prevent adding
+ // anything after cleanup completes
+ select {
+ case <-c.ctx.Done():
+ return nil, ErrClosed
+ default:
+ }
+
+ var s *stream
+ if err := func() error {
+ // In the future this could be replaced with a sync.Map instead of streamLock+map.
+ c.streamLock.Lock()
+ defer c.streamLock.Unlock()
+
+ // Check if closed since lock acquired to prevent adding
+ // anything after cleanup completes
+ select {
+ case <-c.ctx.Done():
+ return ErrClosed
+ default:
+ }
+
+ s = newStream(c.nextStreamID, c)
+ c.streams[s.id] = s
+ c.nextStreamID = c.nextStreamID + 2
+
+ return nil
+ }(); err != nil {
+ return nil, err
+ }
+
+ if err := c.channel.send(uint32(s.id), messageTypeRequest, flags, b); err != nil {
+ return s, filterCloseErr(err)
+ }
+
+ return s, nil
+}
+
+func (c *Client) deleteStream(s *stream) {
+ c.streamLock.Lock()
+ delete(c.streams, s.id)
+ c.streamLock.Unlock()
+ s.closeWithError(nil)
+}
+
+func (c *Client) getStream(sid streamID) *stream {
+ c.streamLock.RLock()
+ s := c.streams[sid]
+ c.streamLock.RUnlock()
+ return s
+}
+
+func (c *Client) cleanupStreams(err error) {
+ c.streamLock.Lock()
+ defer c.streamLock.Unlock()
+
+ for sid, s := range c.streams {
+ s.closeWithError(err)
+ delete(c.streams, sid)
+ }
+}
+
+// filterCloseErr rewrites EOF and EPIPE errors to ErrClosed. Use when
+// returning from call or handling errors from main read loop.
+//
+// This purposely ignores errors with a wrapped cause.
+func filterCloseErr(err error) error {
+ switch {
+ case err == nil:
+ return nil
+ case err == io.EOF:
+ return ErrClosed
+ case errors.Is(err, io.ErrClosedPipe):
+ return ErrClosed
+ case errors.Is(err, io.EOF):
+ return ErrClosed
+ case strings.Contains(err.Error(), "use of closed network connection"):
+ return ErrClosed
+ default:
+ // if we have an epipe on a write or econnreset on a read , we cast to errclosed
+ var oerr *net.OpError
+ if errors.As(err, &oerr) {
+ if (oerr.Op == "write" && errors.Is(err, syscall.EPIPE)) ||
+ (oerr.Op == "read" && errors.Is(err, syscall.ECONNRESET)) {
+ return ErrClosed
+ }
+ }
+ }
+
+ return err
+}
+
+// NewStream creates a new stream with the given stream descriptor to the
+// specified service and method. If not a streaming client, the request object
+// may be provided.
+func (c *Client) NewStream(ctx context.Context, desc *StreamDesc, service, method string, req interface{}) (ClientStream, error) {
+ var payload []byte
+ if req != nil {
+ var err error
+ payload, err = c.codec.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ request := &Request{
+ Service: service,
+ Method: method,
+ Payload: payload,
+ // TODO: metadata from context
+ }
+ p, err := c.codec.Marshal(request)
+ if err != nil {
+ return nil, err
+ }
+
+ var flags uint8
+ if desc.StreamingClient {
+ flags = flagRemoteOpen
+ } else {
+ flags = flagRemoteClosed
+ }
+ s, err := c.createStream(flags, p)
+ if err != nil {
+ return nil, err
+ }
+
+ return &clientStream{
+ ctx: ctx,
+ s: s,
+ c: c,
+ desc: desc,
+ }, nil
+}
+
+func (c *Client) dispatch(ctx context.Context, req *Request, resp *Response) error {
+ p, err := c.codec.Marshal(req)
+ if err != nil {
+ return err
+ }
+
+ s, err := c.createStream(0, p)
+ if err != nil {
+ return err
+ }
+ defer c.deleteStream(s)
+
+ var msg *streamMessage
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-c.ctx.Done():
+ return ErrClosed
+ case <-s.recvClose:
+ // If recv has a pending message, process that first
+ select {
+ case msg = <-s.recv:
+ default:
+ return s.recvErr
+ }
+ case msg = <-s.recv:
+ }
+
+ if msg.header.Type == messageTypeResponse {
+ err = proto.Unmarshal(msg.payload[:msg.header.Length], resp)
+ } else {
+ err = fmt.Errorf("unexpected %q message received: %w", msg.header.Type, ErrProtocol)
+ }
+
+ // return the payload buffer for reuse
+ c.channel.putmbuf(msg.payload)
+
+ return err
+}
diff --git a/vendor/github.com/containerd/ttrpc/codec.go b/vendor/github.com/containerd/ttrpc/codec.go
new file mode 100644
index 0000000000..3e82722a42
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/codec.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "fmt"
+
+ "google.golang.org/protobuf/proto"
+)
+
+type codec struct{}
+
+func (c codec) Marshal(msg interface{}) ([]byte, error) {
+ switch v := msg.(type) {
+ case proto.Message:
+ return proto.Marshal(v)
+ default:
+ return nil, fmt.Errorf("ttrpc: cannot marshal unknown type: %T", msg)
+ }
+}
+
+func (c codec) Unmarshal(p []byte, msg interface{}) error {
+ switch v := msg.(type) {
+ case proto.Message:
+ return proto.Unmarshal(p, v)
+ default:
+ return fmt.Errorf("ttrpc: cannot unmarshal into unknown type: %T", msg)
+ }
+}
diff --git a/vendor/github.com/containerd/ttrpc/config.go b/vendor/github.com/containerd/ttrpc/config.go
new file mode 100644
index 0000000000..f401f67be0
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/config.go
@@ -0,0 +1,86 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "errors"
+)
+
+type serverConfig struct {
+ handshaker Handshaker
+ interceptor UnaryServerInterceptor
+}
+
+// ServerOpt for configuring a ttrpc server
+type ServerOpt func(*serverConfig) error
+
+// WithServerHandshaker can be passed to NewServer to ensure that the
+// handshaker is called before every connection attempt.
+//
+// Only one handshaker is allowed per server.
+func WithServerHandshaker(handshaker Handshaker) ServerOpt {
+ return func(c *serverConfig) error {
+ if c.handshaker != nil {
+ return errors.New("only one handshaker allowed per server")
+ }
+ c.handshaker = handshaker
+ return nil
+ }
+}
+
+// WithUnaryServerInterceptor sets the provided interceptor on the server
+func WithUnaryServerInterceptor(i UnaryServerInterceptor) ServerOpt {
+ return func(c *serverConfig) error {
+ if c.interceptor != nil {
+ return errors.New("only one unchained interceptor allowed per server")
+ }
+ c.interceptor = i
+ return nil
+ }
+}
+
+// WithChainUnaryServerInterceptor sets the provided chain of server interceptors
+func WithChainUnaryServerInterceptor(interceptors ...UnaryServerInterceptor) ServerOpt {
+ return func(c *serverConfig) error {
+ if len(interceptors) == 0 {
+ return nil
+ }
+ if c.interceptor != nil {
+ interceptors = append([]UnaryServerInterceptor{c.interceptor}, interceptors...)
+ }
+ c.interceptor = func(
+ ctx context.Context,
+ unmarshal Unmarshaler,
+ info *UnaryServerInfo,
+ method Method) (interface{}, error) {
+ return interceptors[0](ctx, unmarshal, info,
+ chainUnaryServerInterceptors(info, method, interceptors[1:]))
+ }
+ return nil
+ }
+}
+
+func chainUnaryServerInterceptors(info *UnaryServerInfo, method Method, interceptors []UnaryServerInterceptor) Method {
+ if len(interceptors) == 0 {
+ return method
+ }
+ return func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
+ return interceptors[0](ctx, unmarshal, info,
+ chainUnaryServerInterceptors(info, method, interceptors[1:]))
+ }
+}
diff --git a/vendor/github.com/containerd/ttrpc/doc.go b/vendor/github.com/containerd/ttrpc/doc.go
new file mode 100644
index 0000000000..d80cd424cc
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/doc.go
@@ -0,0 +1,23 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+/*
+package ttrpc defines and implements a low level simple transfer protocol
+optimized for low latency and reliable connections between processes on the same
+host. The protocol uses simple framing for sending requests, responses, and data
+using multiple streams.
+*/
+package ttrpc
diff --git a/vendor/github.com/containerd/ttrpc/errors.go b/vendor/github.com/containerd/ttrpc/errors.go
new file mode 100644
index 0000000000..632dbe8bdf
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/errors.go
@@ -0,0 +1,80 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "errors"
+
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+var (
+ // ErrProtocol is a general error in the handling the protocol.
+ ErrProtocol = errors.New("protocol error")
+
+ // ErrClosed is returned by client methods when the underlying connection is
+ // closed.
+ ErrClosed = errors.New("ttrpc: closed")
+
+ // ErrServerClosed is returned when the Server has closed its connection.
+ ErrServerClosed = errors.New("ttrpc: server closed")
+
+ // ErrStreamClosed is when the streaming connection is closed.
+ ErrStreamClosed = errors.New("ttrpc: stream closed")
+)
+
+// OversizedMessageErr is used to indicate refusal to send an oversized message.
+// It wraps a ResourceExhausted grpc Status together with the offending message
+// length.
+type OversizedMessageErr struct {
+ messageLength int
+ err error
+}
+
+// OversizedMessageError returns an OversizedMessageErr error for the given message
+// length if it exceeds the allowed maximum. Otherwise a nil error is returned.
+func OversizedMessageError(messageLength int) error {
+ if messageLength <= messageLengthMax {
+ return nil
+ }
+
+ return &OversizedMessageErr{
+ messageLength: messageLength,
+ err: status.Errorf(codes.ResourceExhausted, "message length %v exceed maximum message size of %v", messageLength, messageLengthMax),
+ }
+}
+
+// Error returns the error message for the corresponding grpc Status for the error.
+func (e *OversizedMessageErr) Error() string {
+ return e.err.Error()
+}
+
+// Unwrap returns the corresponding error with our grpc status code.
+func (e *OversizedMessageErr) Unwrap() error {
+ return e.err
+}
+
+// RejectedLength retrieves the rejected message length which triggered the error.
+func (e *OversizedMessageErr) RejectedLength() int {
+ return e.messageLength
+}
+
+// MaximumLength retrieves the maximum allowed message length that triggered the error.
+func (*OversizedMessageErr) MaximumLength() int {
+ return messageLengthMax
+}
diff --git a/vendor/github.com/containerd/ttrpc/handshake.go b/vendor/github.com/containerd/ttrpc/handshake.go
new file mode 100644
index 0000000000..3c6b610d35
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/handshake.go
@@ -0,0 +1,50 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "net"
+)
+
+// Handshaker defines the interface for connection handshakes performed on the
+// server or client when first connecting.
+type Handshaker interface {
+ // Handshake should confirm or decorate a connection that may be incoming
+ // to a server or outgoing from a client.
+ //
+ // If this returns without an error, the caller should use the connection
+ // in place of the original connection.
+ //
+ // The second return value can contain credential specific data, such as
+ // unix socket credentials or TLS information.
+ //
+ // While we currently only have implementations on the server-side, this
+ // interface should be sufficient to implement similar handshakes on the
+ // client-side.
+ Handshake(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error)
+}
+
+type handshakerFunc func(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error)
+
+func (fn handshakerFunc) Handshake(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error) {
+ return fn(ctx, conn)
+}
+
+func noopHandshake(_ context.Context, conn net.Conn) (net.Conn, interface{}, error) {
+ return conn, nil, nil
+}
diff --git a/vendor/github.com/containerd/ttrpc/interceptor.go b/vendor/github.com/containerd/ttrpc/interceptor.go
new file mode 100644
index 0000000000..7ff5e9d33f
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/interceptor.go
@@ -0,0 +1,65 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import "context"
+
+// UnaryServerInfo provides information about the server request
+type UnaryServerInfo struct {
+ FullMethod string
+}
+
+// UnaryClientInfo provides information about the client request
+type UnaryClientInfo struct {
+ FullMethod string
+}
+
+// StreamServerInfo provides information about the server request
+type StreamServerInfo struct {
+ FullMethod string
+ StreamingClient bool
+ StreamingServer bool
+}
+
+// Unmarshaler contains the server request data and allows it to be unmarshaled
+// into a concrete type
+type Unmarshaler func(interface{}) error
+
+// Invoker invokes the client's request and response from the ttrpc server
+type Invoker func(context.Context, *Request, *Response) error
+
+// UnaryServerInterceptor specifies the interceptor function for server request/response
+type UnaryServerInterceptor func(context.Context, Unmarshaler, *UnaryServerInfo, Method) (interface{}, error)
+
+// UnaryClientInterceptor specifies the interceptor function for client request/response
+type UnaryClientInterceptor func(context.Context, *Request, *Response, *UnaryClientInfo, Invoker) error
+
+func defaultServerInterceptor(ctx context.Context, unmarshal Unmarshaler, _ *UnaryServerInfo, method Method) (interface{}, error) {
+ return method(ctx, unmarshal)
+}
+
+func defaultClientInterceptor(ctx context.Context, req *Request, resp *Response, _ *UnaryClientInfo, invoker Invoker) error {
+ return invoker(ctx, req, resp)
+}
+
+type StreamServerInterceptor func(context.Context, StreamServer, *StreamServerInfo, StreamHandler) (interface{}, error)
+
+func defaultStreamServerInterceptor(ctx context.Context, ss StreamServer, _ *StreamServerInfo, stream StreamHandler) (interface{}, error) {
+ return stream(ctx, ss)
+}
+
+type StreamClientInterceptor func(context.Context)
diff --git a/vendor/github.com/containerd/ttrpc/metadata.go b/vendor/github.com/containerd/ttrpc/metadata.go
new file mode 100644
index 0000000000..6e00424874
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/metadata.go
@@ -0,0 +1,135 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "strings"
+)
+
+// MD is the user type for ttrpc metadata
+type MD map[string][]string
+
+// Get returns the metadata for a given key when they exist.
+// If there is no metadata, a nil slice and false are returned.
+func (m MD) Get(key string) ([]string, bool) {
+ key = strings.ToLower(key)
+ list, ok := m[key]
+ if !ok || len(list) == 0 {
+ return nil, false
+ }
+
+ return list, true
+}
+
+// Set sets the provided values for a given key.
+// The values will overwrite any existing values.
+// If no values provided, a key will be deleted.
+func (m MD) Set(key string, values ...string) {
+ key = strings.ToLower(key)
+ if len(values) == 0 {
+ delete(m, key)
+ return
+ }
+ m[key] = values
+}
+
+// Append appends additional values to the given key.
+func (m MD) Append(key string, values ...string) {
+ key = strings.ToLower(key)
+ if len(values) == 0 {
+ return
+ }
+ current, ok := m[key]
+ if ok {
+ m.Set(key, append(current, values...)...)
+ } else {
+ m.Set(key, values...)
+ }
+}
+
+// Clone returns a copy of MD or nil if it's nil.
+// It's copied from golang's `http.Header.Clone` implementation:
+// https://cs.opensource.google/go/go/+/refs/tags/go1.23.4:src/net/http/header.go;l=94
+func (m MD) Clone() MD {
+ if m == nil {
+ return nil
+ }
+
+ // Find total number of values.
+ nv := 0
+ for _, vv := range m {
+ nv += len(vv)
+ }
+ sv := make([]string, nv) // shared backing array for headers' values
+ m2 := make(MD, len(m))
+ for k, vv := range m {
+ if vv == nil {
+ // Preserve nil values.
+ m2[k] = nil
+ continue
+ }
+ n := copy(sv, vv)
+ m2[k] = sv[:n:n]
+ sv = sv[n:]
+ }
+ return m2
+}
+
+func (m MD) setRequest(r *Request) {
+ for k, values := range m {
+ for _, v := range values {
+ r.Metadata = append(r.Metadata, &KeyValue{
+ Key: k,
+ Value: v,
+ })
+ }
+ }
+}
+
+func (m MD) fromRequest(r *Request) {
+ for _, kv := range r.Metadata {
+ m[kv.Key] = append(m[kv.Key], kv.Value)
+ }
+}
+
+type metadataKey struct{}
+
+// GetMetadata retrieves metadata from context.Context (previously attached with WithMetadata)
+func GetMetadata(ctx context.Context) (MD, bool) {
+ metadata, ok := ctx.Value(metadataKey{}).(MD)
+ return metadata, ok
+}
+
+// GetMetadataValue gets a specific metadata value by name from context.Context
+func GetMetadataValue(ctx context.Context, name string) (string, bool) {
+ metadata, ok := GetMetadata(ctx)
+ if !ok {
+ return "", false
+ }
+
+ if list, ok := metadata.Get(name); ok {
+ return list[0], true
+ }
+
+ return "", false
+}
+
+// WithMetadata attaches metadata map to a context.Context
+func WithMetadata(ctx context.Context, md MD) context.Context {
+ return context.WithValue(ctx, metadataKey{}, md)
+}
diff --git a/vendor/github.com/containerd/ttrpc/request.pb.go b/vendor/github.com/containerd/ttrpc/request.pb.go
new file mode 100644
index 0000000000..3921ae5a35
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/request.pb.go
@@ -0,0 +1,396 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.28.1
+// protoc v3.20.1
+// source: github.com/containerd/ttrpc/request.proto
+
+package ttrpc
+
+import (
+ status "google.golang.org/genproto/googleapis/rpc/status"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Request struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
+ Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"`
+ Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
+ TimeoutNano int64 `protobuf:"varint,4,opt,name=timeout_nano,json=timeoutNano,proto3" json:"timeout_nano,omitempty"`
+ Metadata []*KeyValue `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty"`
+}
+
+func (x *Request) Reset() {
+ *x = Request{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Request) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Request) ProtoMessage() {}
+
+func (x *Request) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Request.ProtoReflect.Descriptor instead.
+func (*Request) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_ttrpc_request_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Request) GetService() string {
+ if x != nil {
+ return x.Service
+ }
+ return ""
+}
+
+func (x *Request) GetMethod() string {
+ if x != nil {
+ return x.Method
+ }
+ return ""
+}
+
+func (x *Request) GetPayload() []byte {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+func (x *Request) GetTimeoutNano() int64 {
+ if x != nil {
+ return x.TimeoutNano
+ }
+ return 0
+}
+
+func (x *Request) GetMetadata() []*KeyValue {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+type Response struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Status *status.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
+ Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
+}
+
+func (x *Response) Reset() {
+ *x = Response{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Response) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Response) ProtoMessage() {}
+
+func (x *Response) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Response.ProtoReflect.Descriptor instead.
+func (*Response) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_ttrpc_request_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Response) GetStatus() *status.Status {
+ if x != nil {
+ return x.Status
+ }
+ return nil
+}
+
+func (x *Response) GetPayload() []byte {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+type StringList struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ List []string `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
+}
+
+func (x *StringList) Reset() {
+ *x = StringList{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StringList) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StringList) ProtoMessage() {}
+
+func (x *StringList) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StringList.ProtoReflect.Descriptor instead.
+func (*StringList) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_ttrpc_request_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *StringList) GetList() []string {
+ if x != nil {
+ return x.List
+ }
+ return nil
+}
+
+type KeyValue struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *KeyValue) Reset() {
+ *x = KeyValue{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *KeyValue) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*KeyValue) ProtoMessage() {}
+
+func (x *KeyValue) ProtoReflect() protoreflect.Message {
+ mi := &file_github_com_containerd_ttrpc_request_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use KeyValue.ProtoReflect.Descriptor instead.
+func (*KeyValue) Descriptor() ([]byte, []int) {
+ return file_github_com_containerd_ttrpc_request_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *KeyValue) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *KeyValue) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+var File_github_com_containerd_ttrpc_request_proto protoreflect.FileDescriptor
+
+var file_github_com_containerd_ttrpc_request_proto_rawDesc = []byte{
+ 0x0a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e,
+ 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x74, 0x72,
+ 0x70, 0x63, 0x1a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa5, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06,
+ 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65,
+ 0x74, 0x68, 0x6f, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x21,
+ 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4e, 0x61, 0x6e,
+ 0x6f, 0x12, 0x2b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x56,
+ 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x45,
+ 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x06, 0x73, 0x74,
+ 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x53, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70,
+ 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61,
+ 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x20, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c,
+ 0x69, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x32, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61,
+ 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x1d, 0x5a, 0x1b, 0x67,
+ 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
+}
+
+var (
+ file_github_com_containerd_ttrpc_request_proto_rawDescOnce sync.Once
+ file_github_com_containerd_ttrpc_request_proto_rawDescData = file_github_com_containerd_ttrpc_request_proto_rawDesc
+)
+
+func file_github_com_containerd_ttrpc_request_proto_rawDescGZIP() []byte {
+ file_github_com_containerd_ttrpc_request_proto_rawDescOnce.Do(func() {
+ file_github_com_containerd_ttrpc_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_ttrpc_request_proto_rawDescData)
+ })
+ return file_github_com_containerd_ttrpc_request_proto_rawDescData
+}
+
+var file_github_com_containerd_ttrpc_request_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_github_com_containerd_ttrpc_request_proto_goTypes = []interface{}{
+ (*Request)(nil), // 0: ttrpc.Request
+ (*Response)(nil), // 1: ttrpc.Response
+ (*StringList)(nil), // 2: ttrpc.StringList
+ (*KeyValue)(nil), // 3: ttrpc.KeyValue
+ (*status.Status)(nil), // 4: Status
+}
+var file_github_com_containerd_ttrpc_request_proto_depIdxs = []int32{
+ 3, // 0: ttrpc.Request.metadata:type_name -> ttrpc.KeyValue
+ 4, // 1: ttrpc.Response.status:type_name -> Status
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_github_com_containerd_ttrpc_request_proto_init() }
+func file_github_com_containerd_ttrpc_request_proto_init() {
+ if File_github_com_containerd_ttrpc_request_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_github_com_containerd_ttrpc_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Request); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_ttrpc_request_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Response); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_ttrpc_request_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StringList); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_github_com_containerd_ttrpc_request_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*KeyValue); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_github_com_containerd_ttrpc_request_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 4,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_github_com_containerd_ttrpc_request_proto_goTypes,
+ DependencyIndexes: file_github_com_containerd_ttrpc_request_proto_depIdxs,
+ MessageInfos: file_github_com_containerd_ttrpc_request_proto_msgTypes,
+ }.Build()
+ File_github_com_containerd_ttrpc_request_proto = out.File
+ file_github_com_containerd_ttrpc_request_proto_rawDesc = nil
+ file_github_com_containerd_ttrpc_request_proto_goTypes = nil
+ file_github_com_containerd_ttrpc_request_proto_depIdxs = nil
+}
diff --git a/vendor/github.com/containerd/ttrpc/request.proto b/vendor/github.com/containerd/ttrpc/request.proto
new file mode 100644
index 0000000000..37da334fc2
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/request.proto
@@ -0,0 +1,29 @@
+syntax = "proto3";
+
+package ttrpc;
+
+import "proto/status.proto";
+
+option go_package = "github.com/containerd/ttrpc";
+
+message Request {
+ string service = 1;
+ string method = 2;
+ bytes payload = 3;
+ int64 timeout_nano = 4;
+ repeated KeyValue metadata = 5;
+}
+
+message Response {
+ Status status = 1;
+ bytes payload = 2;
+}
+
+message StringList {
+ repeated string list = 1;
+}
+
+message KeyValue {
+ string key = 1;
+ string value = 2;
+}
diff --git a/vendor/github.com/containerd/ttrpc/server.go b/vendor/github.com/containerd/ttrpc/server.go
new file mode 100644
index 0000000000..9606a975dd
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/server.go
@@ -0,0 +1,587 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "errors"
+ "io"
+ "math/rand"
+ "net"
+ "sync"
+ "sync/atomic"
+ "syscall"
+ "time"
+
+ "github.com/containerd/log"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type Server struct {
+ config *serverConfig
+ services *serviceSet
+ codec codec
+
+ mu sync.Mutex
+ listeners map[net.Listener]struct{}
+ connections map[*serverConn]struct{} // all connections to current state
+ done chan struct{} // marks point at which we stop serving requests
+}
+
+func NewServer(opts ...ServerOpt) (*Server, error) {
+ config := &serverConfig{}
+ for _, opt := range opts {
+ if err := opt(config); err != nil {
+ return nil, err
+ }
+ }
+ if config.interceptor == nil {
+ config.interceptor = defaultServerInterceptor
+ }
+
+ return &Server{
+ config: config,
+ services: newServiceSet(config.interceptor),
+ done: make(chan struct{}),
+ listeners: make(map[net.Listener]struct{}),
+ connections: make(map[*serverConn]struct{}),
+ }, nil
+}
+
+// Register registers a map of methods to method handlers
+// TODO: Remove in 2.0, does not support streams
+func (s *Server) Register(name string, methods map[string]Method) {
+ s.services.register(name, &ServiceDesc{Methods: methods})
+}
+
+func (s *Server) RegisterService(name string, desc *ServiceDesc) {
+ s.services.register(name, desc)
+}
+
+func (s *Server) Serve(ctx context.Context, l net.Listener) error {
+ s.mu.Lock()
+ s.addListenerLocked(l)
+ defer s.closeListener(l)
+
+ select {
+ case <-s.done:
+ s.mu.Unlock()
+ return ErrServerClosed
+ default:
+ }
+ s.mu.Unlock()
+
+ var (
+ backoff time.Duration
+ handshaker = s.config.handshaker
+ )
+
+ if handshaker == nil {
+ handshaker = handshakerFunc(noopHandshake)
+ }
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ select {
+ case <-s.done:
+ return ErrServerClosed
+ default:
+ }
+
+ if terr, ok := err.(interface {
+ Temporary() bool
+ }); ok && terr.Temporary() {
+ if backoff == 0 {
+ backoff = time.Millisecond
+ } else {
+ backoff *= 2
+ }
+
+ backoff = min(time.Second, backoff)
+
+ sleep := time.Duration(rand.Int63n(int64(backoff)))
+ log.G(ctx).WithError(err).Errorf("ttrpc: failed accept; backoff %v", sleep)
+ time.Sleep(sleep)
+ continue
+ }
+
+ return err
+ }
+
+ backoff = 0
+
+ approved, handshake, err := handshaker.Handshake(ctx, conn)
+ if err != nil {
+ log.G(ctx).WithError(err).Error("ttrpc: refusing connection after handshake")
+ conn.Close()
+ continue
+ }
+
+ sc, err := s.newConn(approved, handshake)
+ if err != nil {
+ log.G(ctx).WithError(err).Error("ttrpc: create connection failed")
+ conn.Close()
+ continue
+ }
+
+ go sc.run(ctx)
+ }
+}
+
+func (s *Server) Shutdown(ctx context.Context) error {
+ s.mu.Lock()
+ select {
+ case <-s.done:
+ default:
+ // protected by mutex
+ close(s.done)
+ }
+ lnerr := s.closeListeners()
+ s.mu.Unlock()
+
+ ticker := time.NewTicker(200 * time.Millisecond)
+ defer ticker.Stop()
+ for {
+ s.closeIdleConns()
+
+ if s.countConnection() == 0 {
+ break
+ }
+
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-ticker.C:
+ }
+ }
+
+ return lnerr
+}
+
+// Close the server without waiting for active connections.
+func (s *Server) Close() error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ select {
+ case <-s.done:
+ default:
+ // protected by mutex
+ close(s.done)
+ }
+
+ err := s.closeListeners()
+ for c := range s.connections {
+ c.close()
+ delete(s.connections, c)
+ }
+
+ return err
+}
+
+func (s *Server) addListenerLocked(l net.Listener) {
+ s.listeners[l] = struct{}{}
+}
+
+func (s *Server) closeListener(l net.Listener) error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ return s.closeListenerLocked(l)
+}
+
+func (s *Server) closeListenerLocked(l net.Listener) error {
+ defer delete(s.listeners, l)
+ return l.Close()
+}
+
+func (s *Server) closeListeners() error {
+ var err error
+ for l := range s.listeners {
+ if cerr := s.closeListenerLocked(l); cerr != nil && err == nil {
+ err = cerr
+ }
+ }
+ return err
+}
+
+func (s *Server) addConnection(c *serverConn) error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ select {
+ case <-s.done:
+ return ErrServerClosed
+ default:
+ }
+
+ s.connections[c] = struct{}{}
+ return nil
+}
+
+func (s *Server) delConnection(c *serverConn) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ delete(s.connections, c)
+}
+
+func (s *Server) countConnection() int {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ return len(s.connections)
+}
+
+func (s *Server) closeIdleConns() {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ for c := range s.connections {
+ if st, ok := c.getState(); !ok || st == connStateActive {
+ continue
+ }
+ c.close()
+ delete(s.connections, c)
+ }
+}
+
+type connState int
+
+const (
+ connStateActive = iota + 1 // outstanding requests
+ connStateIdle // no requests
+ connStateClosed // closed connection
+)
+
+func (cs connState) String() string {
+ switch cs {
+ case connStateActive:
+ return "active"
+ case connStateIdle:
+ return "idle"
+ case connStateClosed:
+ return "closed"
+ default:
+ return "unknown"
+ }
+}
+
+func (s *Server) newConn(conn net.Conn, handshake interface{}) (*serverConn, error) {
+ c := &serverConn{
+ server: s,
+ conn: conn,
+ handshake: handshake,
+ shutdown: make(chan struct{}),
+ }
+ c.setState(connStateIdle)
+ if err := s.addConnection(c); err != nil {
+ c.close()
+ return nil, err
+ }
+ return c, nil
+}
+
+type serverConn struct {
+ server *Server
+ conn net.Conn
+ handshake interface{} // data from handshake, not used for now
+ state atomic.Value
+
+ shutdownOnce sync.Once
+ shutdown chan struct{} // forced shutdown, used by close
+}
+
+func (c *serverConn) getState() (connState, bool) {
+ cs, ok := c.state.Load().(connState)
+ return cs, ok
+}
+
+func (c *serverConn) setState(newstate connState) {
+ c.state.Store(newstate)
+}
+
+func (c *serverConn) close() error {
+ c.shutdownOnce.Do(func() {
+ close(c.shutdown)
+ })
+
+ return nil
+}
+
+func (c *serverConn) run(sctx context.Context) {
+ type (
+ response struct {
+ id uint32
+ status *status.Status
+ data []byte
+ closeStream bool
+ streaming bool
+ }
+ )
+
+ var (
+ ch = newChannel(c.conn)
+ ctx, cancel = context.WithCancel(sctx)
+ state connState = connStateIdle
+ responses = make(chan response)
+ recvErr = make(chan error, 1)
+ done = make(chan struct{})
+ streams = sync.Map{}
+ active int32
+ lastStreamID uint32
+ )
+
+ defer c.conn.Close()
+ defer cancel()
+ defer close(done)
+ defer c.server.delConnection(c)
+
+ sendStatus := func(id uint32, st *status.Status) bool {
+ select {
+ case responses <- response{
+ // even though we've had an invalid stream id, we send it
+ // back on the same stream id so the client knows which
+ // stream id was bad.
+ id: id,
+ status: st,
+ closeStream: true,
+ }:
+ return true
+ case <-c.shutdown:
+ return false
+ case <-done:
+ return false
+ }
+ }
+
+ go func(recvErr chan error) {
+ defer close(recvErr)
+ for {
+ select {
+ case <-c.shutdown:
+ return
+ case <-done:
+ return
+ default: // proceed
+ }
+
+ mh, p, err := ch.recv()
+ if err != nil {
+ status, ok := status.FromError(err)
+ if !ok {
+ recvErr <- err
+ return
+ }
+
+ // in this case, we send an error for that particular message
+ // when the status is defined.
+ if !sendStatus(mh.StreamID, status) {
+ return
+ }
+
+ continue
+ }
+
+ if mh.StreamID%2 != 1 {
+ // enforce odd client initiated identifiers.
+ if !sendStatus(mh.StreamID, status.Newf(codes.InvalidArgument, "StreamID must be odd for client initiated streams")) {
+ return
+ }
+ continue
+ }
+
+ if mh.Type == messageTypeData {
+ i, ok := streams.Load(mh.StreamID)
+ if !ok {
+ if !sendStatus(mh.StreamID, status.Newf(codes.InvalidArgument, "StreamID is no longer active")) {
+ return
+ }
+ continue
+ }
+ sh := i.(*streamHandler)
+ if mh.Flags&flagNoData != flagNoData {
+ unmarshal := func(obj interface{}) error {
+ err := protoUnmarshal(p, obj)
+ ch.putmbuf(p)
+ return err
+ }
+
+ if err := sh.data(unmarshal); err != nil {
+ if !sendStatus(mh.StreamID, status.Newf(codes.InvalidArgument, "data handling error: %v", err)) {
+ return
+ }
+ continue
+ }
+ }
+
+ if mh.Flags&flagRemoteClosed == flagRemoteClosed {
+ sh.closeSend()
+ if len(p) > 0 {
+ if !sendStatus(mh.StreamID, status.Newf(codes.InvalidArgument, "data close message cannot include data")) {
+ return
+ }
+ continue
+ }
+ }
+ } else if mh.Type == messageTypeRequest {
+ if mh.StreamID <= lastStreamID {
+ // enforce odd client initiated identifiers.
+ if !sendStatus(mh.StreamID, status.Newf(codes.InvalidArgument, "StreamID cannot be re-used and must increment")) {
+ return
+ }
+ continue
+
+ }
+ lastStreamID = mh.StreamID
+
+ // TODO: Make request type configurable
+ // Unmarshaller which takes in a byte array and returns an interface?
+ var req Request
+ if err := c.server.codec.Unmarshal(p, &req); err != nil {
+ ch.putmbuf(p)
+ if !sendStatus(mh.StreamID, status.Newf(codes.InvalidArgument, "unmarshal request error: %v", err)) {
+ return
+ }
+ continue
+ }
+ ch.putmbuf(p)
+
+ id := mh.StreamID
+ respond := func(status *status.Status, data []byte, streaming, closeStream bool) error {
+ select {
+ case responses <- response{
+ id: id,
+ status: status,
+ data: data,
+ closeStream: closeStream,
+ streaming: streaming,
+ }:
+ case <-done:
+ return ErrClosed
+ }
+ return nil
+ }
+ sh, err := c.server.services.handle(ctx, &req, respond)
+ if err != nil {
+ status, _ := status.FromError(err)
+ if !sendStatus(mh.StreamID, status) {
+ return
+ }
+ continue
+ }
+
+ streams.Store(id, sh)
+ atomic.AddInt32(&active, 1)
+ }
+ // TODO: else we must ignore this for future compat. log this?
+ }
+ }(recvErr)
+
+ for {
+ var (
+ newstate connState
+ shutdown chan struct{}
+ )
+
+ activeN := atomic.LoadInt32(&active)
+ if activeN > 0 {
+ newstate = connStateActive
+ shutdown = nil
+ } else {
+ newstate = connStateIdle
+ shutdown = c.shutdown // only enable this branch in idle mode
+ }
+ if newstate != state {
+ c.setState(newstate)
+ state = newstate
+ }
+
+ select {
+ case response := <-responses:
+ if !response.streaming || response.status.Code() != codes.OK {
+ p, err := c.server.codec.Marshal(&Response{
+ Status: response.status.Proto(),
+ Payload: response.data,
+ })
+ if err != nil {
+ log.G(ctx).WithError(err).Error("failed marshaling response")
+ return
+ }
+
+ if err := ch.send(response.id, messageTypeResponse, 0, p); err != nil {
+ log.G(ctx).WithError(err).Error("failed sending message on channel")
+ return
+ }
+ } else {
+ var flags uint8
+ if response.closeStream {
+ flags = flagRemoteClosed
+ }
+ if response.data == nil {
+ flags = flags | flagNoData
+ }
+ if err := ch.send(response.id, messageTypeData, flags, response.data); err != nil {
+ log.G(ctx).WithError(err).Error("failed sending message on channel")
+ return
+ }
+ }
+
+ if response.closeStream {
+ // The ttrpc protocol currently does not support the case where
+ // the server is localClosed but not remoteClosed. Once the server
+ // is closing, the whole stream may be considered finished
+ streams.Delete(response.id)
+ atomic.AddInt32(&active, -1)
+ }
+ case err := <-recvErr:
+ // TODO(stevvooe): Not wildly clear what we should do in this
+ // branch. Basically, it means that we are no longer receiving
+ // requests due to a terminal error.
+ recvErr = nil // connection is now "closing"
+ if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, syscall.ECONNRESET) {
+ // The client went away and we should stop processing
+ // requests, so that the client connection is closed
+ return
+ }
+ log.G(ctx).WithError(err).Error("error receiving message")
+ // else, initiate shutdown
+ case <-shutdown:
+ return
+ }
+ }
+}
+
+var noopFunc = func() {}
+
+func getRequestContext(ctx context.Context, req *Request) (retCtx context.Context, cancel func()) {
+ if len(req.Metadata) > 0 {
+ md := MD{}
+ md.fromRequest(req)
+ ctx = WithMetadata(ctx, md)
+ }
+
+ cancel = noopFunc
+ if req.TimeoutNano == 0 {
+ return ctx, cancel
+ }
+
+ ctx, cancel = context.WithTimeout(ctx, time.Duration(req.TimeoutNano))
+ return ctx, cancel
+}
diff --git a/vendor/github.com/containerd/ttrpc/services.go b/vendor/github.com/containerd/ttrpc/services.go
new file mode 100644
index 0000000000..6d092bf950
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/services.go
@@ -0,0 +1,279 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "unsafe"
+
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
+)
+
+type Method func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error)
+
+type StreamHandler func(context.Context, StreamServer) (interface{}, error)
+
+type Stream struct {
+ Handler StreamHandler
+ StreamingClient bool
+ StreamingServer bool
+}
+
+type ServiceDesc struct {
+ Methods map[string]Method
+ Streams map[string]Stream
+}
+
+type serviceSet struct {
+ services map[string]*ServiceDesc
+ unaryInterceptor UnaryServerInterceptor
+ streamInterceptor StreamServerInterceptor
+}
+
+func newServiceSet(interceptor UnaryServerInterceptor) *serviceSet {
+ return &serviceSet{
+ services: make(map[string]*ServiceDesc),
+ unaryInterceptor: interceptor,
+ streamInterceptor: defaultStreamServerInterceptor,
+ }
+}
+
+func (s *serviceSet) register(name string, desc *ServiceDesc) {
+ if _, ok := s.services[name]; ok {
+ panic(fmt.Errorf("duplicate service %v registered", name))
+ }
+
+ s.services[name] = desc
+}
+
+func (s *serviceSet) unaryCall(ctx context.Context, method Method, info *UnaryServerInfo, data []byte) (p []byte, st *status.Status) {
+ unmarshal := func(obj interface{}) error {
+ return protoUnmarshal(data, obj)
+ }
+
+ resp, err := s.unaryInterceptor(ctx, unmarshal, info, method)
+ if err == nil {
+ if isNil(resp) {
+ err = errors.New("ttrpc: marshal called with nil")
+ } else {
+ p, err = protoMarshal(resp)
+ }
+ }
+
+ st, ok := status.FromError(err)
+ if !ok {
+ st = status.New(convertCode(err), err.Error())
+ }
+
+ return p, st
+}
+
+func (s *serviceSet) streamCall(ctx context.Context, stream StreamHandler, info *StreamServerInfo, ss StreamServer) (p []byte, st *status.Status) {
+ resp, err := s.streamInterceptor(ctx, ss, info, stream)
+ if err == nil {
+ p, err = protoMarshal(resp)
+ }
+ st, ok := status.FromError(err)
+ if !ok {
+ st = status.New(convertCode(err), err.Error())
+ }
+ return
+}
+
+func (s *serviceSet) handle(ctx context.Context, req *Request, respond func(*status.Status, []byte, bool, bool) error) (*streamHandler, error) {
+ srv, ok := s.services[req.Service]
+ if !ok {
+ return nil, status.Errorf(codes.Unimplemented, "service %v", req.Service)
+ }
+
+ if method, ok := srv.Methods[req.Method]; ok {
+ go func() {
+ ctx, cancel := getRequestContext(ctx, req)
+ defer cancel()
+
+ info := &UnaryServerInfo{
+ FullMethod: fullPath(req.Service, req.Method),
+ }
+ p, st := s.unaryCall(ctx, method, info, req.Payload)
+
+ respond(st, p, false, true)
+ }()
+ return nil, nil
+ }
+ if stream, ok := srv.Streams[req.Method]; ok {
+ ctx, cancel := getRequestContext(ctx, req)
+ info := &StreamServerInfo{
+ FullMethod: fullPath(req.Service, req.Method),
+ StreamingClient: stream.StreamingClient,
+ StreamingServer: stream.StreamingServer,
+ }
+ sh := &streamHandler{
+ ctx: ctx,
+ respond: respond,
+ recv: make(chan Unmarshaler, 5),
+ info: info,
+ }
+ go func() {
+ defer cancel()
+ p, st := s.streamCall(ctx, stream.Handler, info, sh)
+ respond(st, p, stream.StreamingServer, true)
+ }()
+
+ // Empty proto messages serialized to 0 payloads,
+ // so signatures like: rpc Stream(google.protobuf.Empty) returns (stream Data);
+ // don't get invoked here, which causes hang on client side.
+ // See https://github.com/containerd/ttrpc/issues/126
+ if req.Payload != nil || !info.StreamingClient {
+ unmarshal := func(obj interface{}) error {
+ return protoUnmarshal(req.Payload, obj)
+ }
+ if err := sh.data(unmarshal); err != nil {
+ return nil, err
+ }
+ }
+
+ return sh, nil
+ }
+ return nil, status.Errorf(codes.Unimplemented, "method %v", req.Method)
+}
+
+type streamHandler struct {
+ ctx context.Context
+ respond func(*status.Status, []byte, bool, bool) error
+ recv chan Unmarshaler
+ info *StreamServerInfo
+
+ remoteClosed bool
+ localClosed bool
+}
+
+func (s *streamHandler) closeSend() {
+ if !s.remoteClosed {
+ s.remoteClosed = true
+ close(s.recv)
+ }
+}
+
+func (s *streamHandler) data(unmarshal Unmarshaler) error {
+ if s.remoteClosed {
+ return ErrStreamClosed
+ }
+ select {
+ case s.recv <- unmarshal:
+ return nil
+ case <-s.ctx.Done():
+ return s.ctx.Err()
+ }
+}
+
+func (s *streamHandler) SendMsg(m interface{}) error {
+ if s.localClosed {
+ return ErrStreamClosed
+ }
+ p, err := protoMarshal(m)
+ if err != nil {
+ return err
+ }
+ return s.respond(nil, p, true, false)
+}
+
+func (s *streamHandler) RecvMsg(m interface{}) error {
+ select {
+ case unmarshal, ok := <-s.recv:
+ if !ok {
+ return io.EOF
+ }
+ return unmarshal(m)
+ case <-s.ctx.Done():
+ return s.ctx.Err()
+
+ }
+}
+
+func protoUnmarshal(p []byte, obj interface{}) error {
+ switch v := obj.(type) {
+ case proto.Message:
+ if err := proto.Unmarshal(p, v); err != nil {
+ return status.Errorf(codes.Internal, "ttrpc: error unmarshalling payload: %v", err.Error())
+ }
+ default:
+ return status.Errorf(codes.Internal, "ttrpc: error unsupported request type: %T", v)
+ }
+ return nil
+}
+
+func protoMarshal(obj interface{}) ([]byte, error) {
+ if obj == nil {
+ return nil, nil
+ }
+
+ switch v := obj.(type) {
+ case proto.Message:
+ r, err := proto.Marshal(v)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "ttrpc: error marshaling payload: %v", err.Error())
+ }
+
+ return r, nil
+ default:
+ return nil, status.Errorf(codes.Internal, "ttrpc: error unsupported response type: %T", v)
+ }
+}
+
+// convertCode maps stdlib go errors into grpc space.
+//
+// This is ripped from the grpc-go code base.
+func convertCode(err error) codes.Code {
+ switch err {
+ case nil:
+ return codes.OK
+ case io.EOF:
+ return codes.OutOfRange
+ case io.ErrClosedPipe, io.ErrNoProgress, io.ErrShortBuffer, io.ErrShortWrite, io.ErrUnexpectedEOF:
+ return codes.FailedPrecondition
+ case os.ErrInvalid:
+ return codes.InvalidArgument
+ case context.Canceled:
+ return codes.Canceled
+ case context.DeadlineExceeded:
+ return codes.DeadlineExceeded
+ }
+ switch {
+ case os.IsExist(err):
+ return codes.AlreadyExists
+ case os.IsNotExist(err):
+ return codes.NotFound
+ case os.IsPermission(err):
+ return codes.PermissionDenied
+ }
+ return codes.Unknown
+}
+
+func fullPath(service, method string) string {
+ return "/" + path.Join(service, method)
+}
+
+func isNil(resp interface{}) bool {
+ return (*[2]uintptr)(unsafe.Pointer(&resp))[1] == 0
+}
diff --git a/vendor/github.com/containerd/ttrpc/stream.go b/vendor/github.com/containerd/ttrpc/stream.go
new file mode 100644
index 0000000000..739a4c9675
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/stream.go
@@ -0,0 +1,84 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "sync"
+)
+
+type streamID uint32
+
+type streamMessage struct {
+ header messageHeader
+ payload []byte
+}
+
+type stream struct {
+ id streamID
+ sender sender
+ recv chan *streamMessage
+
+ closeOnce sync.Once
+ recvErr error
+ recvClose chan struct{}
+}
+
+func newStream(id streamID, send sender) *stream {
+ return &stream{
+ id: id,
+ sender: send,
+ recv: make(chan *streamMessage, 1),
+ recvClose: make(chan struct{}),
+ }
+}
+
+func (s *stream) closeWithError(err error) error {
+ s.closeOnce.Do(func() {
+ if err != nil {
+ s.recvErr = err
+ } else {
+ s.recvErr = ErrClosed
+ }
+ close(s.recvClose)
+ })
+ return nil
+}
+
+func (s *stream) send(mt messageType, flags uint8, b []byte) error {
+ return s.sender.send(uint32(s.id), mt, flags, b)
+}
+
+func (s *stream) receive(ctx context.Context, msg *streamMessage) error {
+ select {
+ case <-s.recvClose:
+ return s.recvErr
+ default:
+ }
+ select {
+ case <-s.recvClose:
+ return s.recvErr
+ case s.recv <- msg:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
+
+type sender interface {
+ send(uint32, messageType, uint8, []byte) error
+}
diff --git a/vendor/github.com/containerd/ttrpc/stream_server.go b/vendor/github.com/containerd/ttrpc/stream_server.go
new file mode 100644
index 0000000000..b6d1ba720a
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/stream_server.go
@@ -0,0 +1,22 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+type StreamServer interface {
+ SendMsg(m interface{}) error
+ RecvMsg(m interface{}) error
+}
diff --git a/vendor/github.com/containerd/ttrpc/test.proto b/vendor/github.com/containerd/ttrpc/test.proto
new file mode 100644
index 0000000000..0e114d5568
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/test.proto
@@ -0,0 +1,16 @@
+syntax = "proto3";
+
+package ttrpc;
+
+option go_package = "github.com/containerd/ttrpc/internal";
+
+message TestPayload {
+ string foo = 1;
+ int64 deadline = 2;
+ string metadata = 3;
+}
+
+message EchoPayload {
+ int64 seq = 1;
+ string msg = 2;
+}
diff --git a/vendor/github.com/containerd/ttrpc/unixcreds_linux.go b/vendor/github.com/containerd/ttrpc/unixcreds_linux.go
new file mode 100644
index 0000000000..c82c9f9d4c
--- /dev/null
+++ b/vendor/github.com/containerd/ttrpc/unixcreds_linux.go
@@ -0,0 +1,105 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package ttrpc
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "os"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+type UnixCredentialsFunc func(*unix.Ucred) error
+
+func (fn UnixCredentialsFunc) Handshake(_ context.Context, conn net.Conn) (net.Conn, interface{}, error) {
+ uc, err := requireUnixSocket(conn)
+ if err != nil {
+ return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: require unix socket: %w", err)
+ }
+
+ rs, err := uc.SyscallConn()
+ if err != nil {
+ return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: (net.UnixConn).SyscallConn failed: %w", err)
+ }
+ var (
+ ucred *unix.Ucred
+ ucredErr error
+ )
+ if err := rs.Control(func(fd uintptr) {
+ ucred, ucredErr = unix.GetsockoptUcred(int(fd), unix.SOL_SOCKET, unix.SO_PEERCRED)
+ }); err != nil {
+ return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: (*syscall.RawConn).Control failed: %w", err)
+ }
+
+ if ucredErr != nil {
+ return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: failed to retrieve socket peer credentials: %w", ucredErr)
+ }
+
+ if err := fn(ucred); err != nil {
+ return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: credential check failed: %w", err)
+ }
+
+ return uc, ucred, nil
+}
+
+// UnixSocketRequireUidGid requires specific *effective* UID/GID, rather than the real UID/GID.
+//
+// For example, if a daemon binary is owned by the root (UID 0) with SUID bit but running as an
+// unprivileged user (UID 1001), the effective UID becomes 0, and the real UID becomes 1001.
+// So calling this function with uid=0 allows a connection from effective UID 0 but rejects
+// a connection from effective UID 1001.
+//
+// See socket(7), SO_PEERCRED: "The returned credentials are those that were in effect at the time of the call to connect(2) or socketpair(2)."
+func UnixSocketRequireUidGid(uid, gid int) UnixCredentialsFunc {
+ return func(ucred *unix.Ucred) error {
+ return requireUidGid(ucred, uid, gid)
+ }
+}
+
+func UnixSocketRequireRoot() UnixCredentialsFunc {
+ return UnixSocketRequireUidGid(0, 0)
+}
+
+// UnixSocketRequireSameUser resolves the current effective unix user and returns a
+// UnixCredentialsFunc that will validate incoming unix connections against the
+// current credentials.
+//
+// This is useful when using abstract sockets that are accessible by all users.
+func UnixSocketRequireSameUser() UnixCredentialsFunc {
+ euid, egid := os.Geteuid(), os.Getegid()
+ return UnixSocketRequireUidGid(euid, egid)
+}
+
+func requireUidGid(ucred *unix.Ucred, uid, gid int) error {
+ if (uid != -1 && uint32(uid) != ucred.Uid) || (gid != -1 && uint32(gid) != ucred.Gid) {
+ return fmt.Errorf("ttrpc: invalid credentials: %v", syscall.EPERM)
+ }
+ return nil
+}
+
+func requireUnixSocket(conn net.Conn) (*net.UnixConn, error) {
+ uc, ok := conn.(*net.UnixConn)
+ if !ok {
+ return nil, errors.New("a unix socket connection is required")
+ }
+
+ return uc, nil
+}
diff --git a/vendor/github.com/containerd/typeurl/README.md b/vendor/github.com/containerd/typeurl/README.md
deleted file mode 100644
index d021e96724..0000000000
--- a/vendor/github.com/containerd/typeurl/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# typeurl
-
-[](https://pkg.go.dev/github.com/containerd/typeurl)
-[](https://github.com/containerd/typeurl/actions?query=workflow%3ACI)
-[](https://codecov.io/gh/containerd/typeurl)
-[](https://goreportcard.com/report/github.com/containerd/typeurl)
-
-A Go package for managing the registration, marshaling, and unmarshaling of encoded types.
-
-This package helps when types are sent over a GRPC API and marshaled as a [protobuf.Any](https://github.com/gogo/protobuf/blob/master/protobuf/google/protobuf/any.proto).
-
-## Project details
-
-**typeurl** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
-As a containerd sub-project, you will find the:
- * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
- * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
- * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
-
-information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/typeurl/types.go b/vendor/github.com/containerd/typeurl/types.go
deleted file mode 100644
index 647d419a29..0000000000
--- a/vendor/github.com/containerd/typeurl/types.go
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- 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.
-*/
-
-package typeurl
-
-import (
- "encoding/json"
- "path"
- "reflect"
- "sync"
-
- "github.com/gogo/protobuf/proto"
- "github.com/gogo/protobuf/types"
- "github.com/pkg/errors"
-)
-
-var (
- mu sync.RWMutex
- registry = make(map[reflect.Type]string)
-)
-
-// Definitions of common error types used throughout typeurl.
-//
-// These error types are used with errors.Wrap and errors.Wrapf to add context
-// to an error.
-//
-// To detect an error class, use errors.Is() functions to tell whether an
-// error is of this type.
-var (
- ErrNotFound = errors.New("not found")
-)
-
-// Register a type with a base URL for JSON marshaling. When the MarshalAny and
-// UnmarshalAny functions are called they will treat the Any type value as JSON.
-// To use protocol buffers for handling the Any value the proto.Register
-// function should be used instead of this function.
-func Register(v interface{}, args ...string) {
- var (
- t = tryDereference(v)
- p = path.Join(args...)
- )
- mu.Lock()
- defer mu.Unlock()
- if et, ok := registry[t]; ok {
- if et != p {
- panic(errors.Errorf("type registered with alternate path %q != %q", et, p))
- }
- return
- }
- registry[t] = p
-}
-
-// TypeURL returns the type url for a registered type.
-func TypeURL(v interface{}) (string, error) {
- mu.RLock()
- u, ok := registry[tryDereference(v)]
- mu.RUnlock()
- if !ok {
- // fallback to the proto registry if it is a proto message
- pb, ok := v.(proto.Message)
- if !ok {
- return "", errors.Wrapf(ErrNotFound, "type %s", reflect.TypeOf(v))
- }
- return proto.MessageName(pb), nil
- }
- return u, nil
-}
-
-// Is returns true if the type of the Any is the same as v.
-func Is(any *types.Any, v interface{}) bool {
- // call to check that v is a pointer
- tryDereference(v)
- url, err := TypeURL(v)
- if err != nil {
- return false
- }
- return any.TypeUrl == url
-}
-
-// MarshalAny marshals the value v into an any with the correct TypeUrl.
-// If the provided object is already a proto.Any message, then it will be
-// returned verbatim. If it is of type proto.Message, it will be marshaled as a
-// protocol buffer. Otherwise, the object will be marshaled to json.
-func MarshalAny(v interface{}) (*types.Any, error) {
- var marshal func(v interface{}) ([]byte, error)
- switch t := v.(type) {
- case *types.Any:
- // avoid reserializing the type if we have an any.
- return t, nil
- case proto.Message:
- marshal = func(v interface{}) ([]byte, error) {
- return proto.Marshal(t)
- }
- default:
- marshal = json.Marshal
- }
-
- url, err := TypeURL(v)
- if err != nil {
- return nil, err
- }
-
- data, err := marshal(v)
- if err != nil {
- return nil, err
- }
- return &types.Any{
- TypeUrl: url,
- Value: data,
- }, nil
-}
-
-// UnmarshalAny unmarshals the any type into a concrete type.
-func UnmarshalAny(any *types.Any) (interface{}, error) {
- return UnmarshalByTypeURL(any.TypeUrl, any.Value)
-}
-
-// UnmarshalByTypeURL unmarshals the given type and value to into a concrete type.
-func UnmarshalByTypeURL(typeURL string, value []byte) (interface{}, error) {
- return unmarshal(typeURL, value, nil)
-}
-
-// UnmarshalTo unmarshals the any type into a concrete type passed in the out
-// argument. It is identical to UnmarshalAny, but lets clients provide a
-// destination type through the out argument.
-func UnmarshalTo(any *types.Any, out interface{}) error {
- return UnmarshalToByTypeURL(any.TypeUrl, any.Value, out)
-}
-
-// UnmarshalTo unmarshals the given type and value into a concrete type passed
-// in the out argument. It is identical to UnmarshalByTypeURL, but lets clients
-// provide a destination type through the out argument.
-func UnmarshalToByTypeURL(typeURL string, value []byte, out interface{}) error {
- _, err := unmarshal(typeURL, value, out)
- return err
-}
-
-func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error) {
- t, err := getTypeByUrl(typeURL)
- if err != nil {
- return nil, err
- }
-
- if v == nil {
- v = reflect.New(t.t).Interface()
- } else {
- // Validate interface type provided by client
- vURL, err := TypeURL(v)
- if err != nil {
- return nil, err
- }
- if typeURL != vURL {
- return nil, errors.Errorf("can't unmarshal type %q to output %q", typeURL, vURL)
- }
- }
-
- if t.isProto {
- err = proto.Unmarshal(value, v.(proto.Message))
- } else {
- err = json.Unmarshal(value, v)
- }
-
- return v, err
-}
-
-type urlType struct {
- t reflect.Type
- isProto bool
-}
-
-func getTypeByUrl(url string) (urlType, error) {
- mu.RLock()
- for t, u := range registry {
- if u == url {
- mu.RUnlock()
- return urlType{
- t: t,
- }, nil
- }
- }
- mu.RUnlock()
- // fallback to proto registry
- t := proto.MessageType(url)
- if t != nil {
- return urlType{
- // get the underlying Elem because proto returns a pointer to the type
- t: t.Elem(),
- isProto: true,
- }, nil
- }
- return urlType{}, errors.Wrapf(ErrNotFound, "type with url %s", url)
-}
-
-func tryDereference(v interface{}) reflect.Type {
- t := reflect.TypeOf(v)
- if t.Kind() == reflect.Ptr {
- // require check of pointer but dereference to register
- return t.Elem()
- }
- panic("v is not a pointer to a type")
-}
diff --git a/vendor/github.com/containerd/typeurl/.gitignore b/vendor/github.com/containerd/typeurl/v2/.gitignore
similarity index 100%
rename from vendor/github.com/containerd/typeurl/.gitignore
rename to vendor/github.com/containerd/typeurl/v2/.gitignore
diff --git a/vendor/github.com/containerd/typeurl/v2/LICENSE b/vendor/github.com/containerd/typeurl/v2/LICENSE
new file mode 100644
index 0000000000..584149b6ee
--- /dev/null
+++ b/vendor/github.com/containerd/typeurl/v2/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd Authors
+
+ 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
+
+ https://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.
diff --git a/vendor/github.com/containerd/typeurl/v2/README.md b/vendor/github.com/containerd/typeurl/v2/README.md
new file mode 100644
index 0000000000..4a664ae58d
--- /dev/null
+++ b/vendor/github.com/containerd/typeurl/v2/README.md
@@ -0,0 +1,27 @@
+# typeurl
+
+[](https://pkg.go.dev/github.com/containerd/typeurl)
+[](https://github.com/containerd/typeurl/actions?query=workflow%3ACI)
+[](https://codecov.io/gh/containerd/typeurl)
+[](https://goreportcard.com/report/github.com/containerd/typeurl)
+
+A Go package for managing the registration, marshaling, and unmarshaling of encoded types.
+
+This package helps when types are sent over a ttrpc/GRPC API and marshaled as a protobuf [Any](https://pkg.go.dev/google.golang.org/protobuf@v1.27.1/types/known/anypb#Any)
+
+## Project details
+
+**typeurl** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
+
+## Gogo Protobuf Support Deprecation
+
+Support for gogoprotobuf was removed in v2.3.0. The upstream package has been deprecated since 2022 and users of
+typeurl should not rely on Gogo Protobuf support anymore. Users which are still transitioning away from it may
+continue to use the v2.2 release until that transition is complete. Since v2.2.1, gogo proto support can be
+explicitly removed using the `!no_gogo` build tag.
diff --git a/vendor/github.com/containerd/typeurl/doc.go b/vendor/github.com/containerd/typeurl/v2/doc.go
similarity index 100%
rename from vendor/github.com/containerd/typeurl/doc.go
rename to vendor/github.com/containerd/typeurl/v2/doc.go
diff --git a/vendor/github.com/containerd/typeurl/v2/types.go b/vendor/github.com/containerd/typeurl/v2/types.go
new file mode 100644
index 0000000000..f52590b6eb
--- /dev/null
+++ b/vendor/github.com/containerd/typeurl/v2/types.go
@@ -0,0 +1,272 @@
+/*
+ Copyright The containerd Authors.
+
+ 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.
+*/
+
+package typeurl
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "path"
+ "reflect"
+ "sync"
+
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoregistry"
+ "google.golang.org/protobuf/types/known/anypb"
+)
+
+var (
+ mu sync.RWMutex
+ registry = make(map[reflect.Type]string)
+)
+
+// Definitions of common error types used throughout typeurl.
+//
+// These error types are used with errors.Wrap and errors.Wrapf to add context
+// to an error.
+//
+// To detect an error class, use errors.Is() functions to tell whether an
+// error is of this type.
+
+var (
+ ErrNotFound = errors.New("not found")
+)
+
+// Any contains an arbitrary protcol buffer message along with its type.
+//
+// While there is google.golang.org/protobuf/types/known/anypb.Any,
+// we'd like to have our own to hide the underlying protocol buffer
+// implementations from containerd clients.
+//
+// https://developers.google.com/protocol-buffers/docs/proto3#any
+type Any interface {
+ // GetTypeUrl returns a URL/resource name that uniquely identifies
+ // the type of the serialized protocol buffer message.
+ GetTypeUrl() string
+
+ // GetValue returns a valid serialized protocol buffer of the type that
+ // GetTypeUrl() indicates.
+ GetValue() []byte
+}
+
+type anyType struct {
+ typeURL string
+ value []byte
+}
+
+func (a *anyType) GetTypeUrl() string {
+ if a == nil {
+ return ""
+ }
+ return a.typeURL
+}
+
+func (a *anyType) GetValue() []byte {
+ if a == nil {
+ return nil
+ }
+ return a.value
+}
+
+// Register a type with a base URL for JSON marshaling. When the MarshalAny and
+// UnmarshalAny functions are called they will treat the Any type value as JSON.
+// To use protocol buffers for handling the Any value the proto.Register
+// function should be used instead of this function.
+func Register(v interface{}, args ...string) {
+ var (
+ t = tryDereference(v)
+ p = path.Join(args...)
+ )
+ mu.Lock()
+ defer mu.Unlock()
+ if et, ok := registry[t]; ok {
+ if et != p {
+ panic(fmt.Errorf("type registered with alternate path %q != %q", et, p))
+ }
+ return
+ }
+ registry[t] = p
+}
+
+// TypeURL returns the type url for a registered type.
+func TypeURL(v interface{}) (string, error) {
+ mu.RLock()
+ u, ok := registry[tryDereference(v)]
+ mu.RUnlock()
+ if !ok {
+ switch t := v.(type) {
+ case proto.Message:
+ return string(t.ProtoReflect().Descriptor().FullName()), nil
+ default:
+ return "", fmt.Errorf("type %s: %w", reflect.TypeOf(v), ErrNotFound)
+ }
+ }
+ return u, nil
+}
+
+// Is returns true if the type of the Any is the same as v.
+func Is(any Any, v interface{}) bool {
+ if any == nil {
+ return false
+ }
+ // call to check that v is a pointer
+ tryDereference(v)
+ url, err := TypeURL(v)
+ if err != nil {
+ return false
+ }
+ return any.GetTypeUrl() == url
+}
+
+// MarshalAny marshals the value v into an any with the correct TypeUrl.
+// If the provided object is already a proto.Any message, then it will be
+// returned verbatim. If it is of type proto.Message, it will be marshaled as a
+// protocol buffer. Otherwise, the object will be marshaled to json.
+func MarshalAny(v interface{}) (Any, error) {
+ var marshal func(v interface{}) ([]byte, error)
+ switch t := v.(type) {
+ case Any:
+ // avoid reserializing the type if we have an any.
+ return t, nil
+ case proto.Message:
+ marshal = func(v interface{}) ([]byte, error) {
+ return proto.Marshal(t)
+ }
+ default:
+ marshal = json.Marshal
+ }
+
+ url, err := TypeURL(v)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err := marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ return &anyType{
+ typeURL: url,
+ value: data,
+ }, nil
+}
+
+// UnmarshalAny unmarshals the any type into a concrete type.
+func UnmarshalAny(any Any) (interface{}, error) {
+ return UnmarshalByTypeURL(any.GetTypeUrl(), any.GetValue())
+}
+
+// UnmarshalByTypeURL unmarshals the given type and value to into a concrete type.
+func UnmarshalByTypeURL(typeURL string, value []byte) (interface{}, error) {
+ return unmarshal(typeURL, value, nil)
+}
+
+// UnmarshalTo unmarshals the any type into a concrete type passed in the out
+// argument. It is identical to UnmarshalAny, but lets clients provide a
+// destination type through the out argument.
+func UnmarshalTo(any Any, out interface{}) error {
+ return UnmarshalToByTypeURL(any.GetTypeUrl(), any.GetValue(), out)
+}
+
+// UnmarshalToByTypeURL unmarshals the given type and value into a concrete type passed
+// in the out argument. It is identical to UnmarshalByTypeURL, but lets clients
+// provide a destination type through the out argument.
+func UnmarshalToByTypeURL(typeURL string, value []byte, out interface{}) error {
+ _, err := unmarshal(typeURL, value, out)
+ return err
+}
+
+// MarshalProto converts typeurl.Any to google.golang.org/protobuf/types/known/anypb.Any.
+func MarshalProto(from Any) *anypb.Any {
+ if from == nil {
+ return nil
+ }
+
+ if pbany, ok := from.(*anypb.Any); ok {
+ return pbany
+ }
+
+ return &anypb.Any{
+ TypeUrl: from.GetTypeUrl(),
+ Value: from.GetValue(),
+ }
+}
+
+// MarshalAnyToProto converts an arbitrary interface to google.golang.org/protobuf/types/known/anypb.Any.
+func MarshalAnyToProto(from interface{}) (*anypb.Any, error) {
+ anyType, err := MarshalAny(from)
+ if err != nil {
+ return nil, err
+ }
+ return MarshalProto(anyType), nil
+}
+
+func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error) {
+ t, isProto, err := getTypeByUrl(typeURL)
+ if err != nil {
+ return nil, err
+ }
+
+ if v == nil {
+ v = reflect.New(t).Interface()
+ } else {
+ // Validate interface type provided by client
+ vURL, err := TypeURL(v)
+ if err != nil {
+ return nil, err
+ }
+ if typeURL != vURL {
+ return nil, fmt.Errorf("can't unmarshal type %q to output %q", typeURL, vURL)
+ }
+ }
+
+ if isProto {
+ pm, ok := v.(proto.Message)
+ if ok {
+ err = proto.Unmarshal(value, pm)
+ return v, err
+ }
+ }
+ return v, json.Unmarshal(value, v)
+
+}
+
+func getTypeByUrl(url string) (_ reflect.Type, isProto bool, _ error) {
+ mu.RLock()
+ for t, u := range registry {
+ if u == url {
+ mu.RUnlock()
+ return t, false, nil
+ }
+ }
+ mu.RUnlock()
+ mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
+ if err != nil {
+ return nil, false, fmt.Errorf("type with url %s: %w", url, ErrNotFound)
+ }
+ empty := mt.New().Interface()
+ return reflect.TypeOf(empty).Elem(), true, nil
+}
+
+func tryDereference(v interface{}) reflect.Type {
+ t := reflect.TypeOf(v)
+ if t.Kind() == reflect.Ptr {
+ // require check of pointer but dereference to register
+ return t.Elem()
+ }
+ panic("v is not a pointer to a type")
+}
diff --git a/vendor/github.com/creack/pty/.editorconfig b/vendor/github.com/creack/pty/.editorconfig
new file mode 100644
index 0000000000..349f67aa2d
--- /dev/null
+++ b/vendor/github.com/creack/pty/.editorconfig
@@ -0,0 +1,54 @@
+root = true
+
+# Sane defaults.
+[*]
+# Always use unix end of line.
+end_of_line = lf
+# Always insert a new line at the end of files.
+insert_final_newline = true
+# Don't leave trailing whitespaces.
+trim_trailing_whitespace = true
+# Default to utf8 encoding.
+charset = utf-8
+# Space > tab for consistent aligns.
+indent_style = space
+# Default to 2 spaces for indent/tabs.
+indent_size = 2
+# Flag long lines.
+max_line_length = 140
+
+# Explicitly define settings for commonly used files.
+
+[*.go]
+indent_style = tab
+indent_size = 8
+
+[*.feature]
+indent_style = space
+indent_size = 2
+
+[*.json]
+indent_style = space
+indent_size = 2
+
+[*.{yml,yaml}]
+indent_style = space
+indent_size = 2
+
+[*.tf]
+indent_style = space
+indent_size = 2
+
+[*.md]
+# Don't check line lenghts in files.
+max_line_length = 0
+
+[{Makefile,*.mk}]
+indent_style = tab
+indent_size = 8
+
+[{Dockerfile,Dockerfile.*}]
+indent_size = 4
+
+[*.sql]
+indent_size = 2
diff --git a/vendor/github.com/creack/pty/.golangci.yml b/vendor/github.com/creack/pty/.golangci.yml
new file mode 100644
index 0000000000..f023e0f76a
--- /dev/null
+++ b/vendor/github.com/creack/pty/.golangci.yml
@@ -0,0 +1,324 @@
+---
+# Reference: https://golangci-lint.run/usage/configuration/
+run:
+ timeout: 5m
+ # modules-download-mode: vendor
+
+ # Include test files.
+ tests: true
+
+ skip-dirs: []
+
+ skip-files: []
+
+output:
+ # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number".
+ format: colored-line-number
+ print-issued-lines: true
+ print-linter-name: true
+
+# Linter specific settings. See below in the `linter.enable` section for details on what each linter is doing.
+linters-settings:
+ dogsled:
+ # Checks assignments with too many blank identifiers. Default is 2.
+ max-blank-identifiers: 2
+
+ dupl:
+ # Tokens count to trigger issue.
+ threshold: 150
+
+ errcheck:
+ # Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
+ # Enabled as this is often overlooked by developers.
+ check-type-assertions: true
+ # Report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`.
+ # Disabled as we consider that if the developer did type `_`, it was on purpose.
+ # Note that while this isn't enforced by the linter, each and every case of ignored error should
+ # be accompanied with a comment explaining why that error is being discarded.
+ check-blank: false
+
+ exhaustive:
+ # Indicates that switch statements are to be considered exhaustive if a
+ # 'default' case is present, even if all enum members aren't listed in the
+ # switch.
+ default-signifies-exhaustive: false
+
+ funlen:
+ # funlen checks the number of lines/statements in a function.
+ # While is is always best to keep functions short for readability, maintainability and testing,
+ # the default are a bit too strict (60 lines / 40 statements), increase it to be more flexible.
+ lines: 160
+ statements: 70
+
+ # NOTE: We don't set `gci` for import order as it supports only one prefix. Use `goimports.local-prefixes` instead.
+
+ gocognit:
+ # Minimal code complexity to report, defaults to 30 in gocognit, defaults 10 in golangci.
+ # Use 15 as it allows for some flexibility while preventing too much complexity.
+ # NOTE: Similar to gocyclo.
+ min-complexity: 35
+
+ nestif:
+ # Minimal complexity of if statements to report.
+ min-complexity: 8
+
+ goconst:
+ # Minimal length of string constant.
+ min-len: 4
+ # Minimal occurrences count to trigger.
+ # Increase the default from 3 to 5 as small number of const usage can reduce readability instead of improving it.
+ min-occurrences: 5
+
+ gocritic:
+ # Which checks should be disabled; can't be combined with 'enabled-checks'.
+ # See https://go-critic.github.io/overview#checks-overview
+ # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run`
+ disabled-checks:
+ - hugeParam # Very strict check on the size of variables being copied. Too strict for most developer.
+ # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
+ # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
+ enabled-tags:
+ - diagnostic
+ - style
+ - opinionated
+ - performance
+ settings:
+ rangeValCopy:
+ sizeThreshold: 1024 # Increase the allowed copied bytes in range.
+
+ cyclop:
+ max-complexity: 35
+
+ gocyclo:
+ # Similar check as gocognit.
+ # NOTE: We might be able to remove this linter as it is redundant with gocyclo. It is in golangci-lint, so we keep it for now.
+ min-complexity: 35
+
+ godot:
+ # Check all top-level comments, not only declarations.
+ check-all: true
+
+ gofmt:
+ # simplify code: gofmt with `-s` option.
+ simplify: true
+
+ # NOTE: the goheader settings are set per-project.
+
+ goimports:
+ # Put imports beginning with prefix after 3rd-party packages.
+ # It's a comma-separated list of prefixes.
+ local-prefixes: "github.com/creack/pty"
+
+ golint:
+ # Minimal confidence for issues, default is 0.8.
+ min-confidence: 0.8
+
+ gosimple:
+ # Select the Go version to target. The default is '1.13'.
+ go: "1.18"
+ # https://staticcheck.io/docs/options#checks
+ checks: ["all"]
+
+ gosec:
+
+ govet:
+ # Enable all available checks from go vet.
+ enable-all: false
+ # Report about shadowed variables.
+ check-shadowing: true
+
+ # NOTE: depguard is disabled as it is very slow and made redundant by gomodguard.
+
+ lll:
+ # Make sure everyone is on the same level, fix the tab width to go's default.
+ tab-width: 8
+ # Increase the default max line length to give more flexibility. Forcing newlines can reduce readability instead of improving it.
+ line-length: 180
+
+ misspell:
+ locale: US
+ ignore-words:
+
+ nakedret:
+ # Make an issue if func has more lines of code than this setting and it has naked returns; default is 30.
+ # NOTE: Consider setting this to 1 to prevent naked returns.
+ max-func-lines: 30
+
+ nolintlint:
+ # Prevent ununsed directive to avoid stale comments.
+ allow-unused: false
+ # Require an explanation of nonzero length after each nolint directive.
+ require-explanation: true
+ # Exclude following linters from requiring an explanation.
+ # NOTE: It is strongly discouraged to put anything in there.
+ allow-no-explanation: []
+ # Enable to require nolint directives to mention the specific linter being suppressed. This ensurce the developer understand the reason being the error.
+ require-specific: true
+
+ prealloc:
+ # NOTE: For most programs usage of prealloc will be a premature optimization.
+ # Keep thing simple, pre-alloc what is obvious and profile the program for more complex scenarios.
+ #
+ simple: true # Checkonly on simple loops that have no returns/breaks/continues/gotos in them.
+ range-loops: true # Check range loops, true by default
+ for-loops: false # Check suggestions on for loops, false by default
+
+ rowserrcheck:
+ packages: []
+
+ staticcheck:
+ # Select the Go version to target. The default is '1.13'.
+ go: "1.18"
+ # https://staticcheck.io/docs/options#checks
+ checks: ["all"]
+
+ stylecheck:
+ # Select the Go version to target. The default is '1.13'.
+ go: "1.18"
+ # https://staticcheck.io/docs/options#checks
+ checks: ["all"] # "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"]
+
+ tagliatelle:
+ # Check the struck tag name case.
+ case:
+ # Use the struct field name to check the name of the struct tag.
+ use-field-name: false
+ rules:
+ # Any struct tag type can be used.
+ # support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`
+ json: snake
+ firestore: camel
+ yaml: camel
+ xml: camel
+ bson: camel
+ avro: snake
+ mapstructure: kebab
+ envconfig: upper
+
+ unparam:
+ # Don't create an error if an exported code have static params being used. It is often expected in libraries.
+ # NOTE: It would be nice if this linter would differentiate between a main package and a lib.
+ check-exported: true
+
+ unused: {}
+
+ whitespace:
+ multi-if: false # Enforces newlines (or comments) after every multi-line if statement
+ multi-func: false # Enforces newlines (or comments) after every multi-line function signature
+
+# Run `golangci-lint help linters` to get the full list of linter with their description.
+linters:
+ disable-all: true
+ # NOTE: enable-all is deprecated because too many people don't pin versions...
+ # We still require explicit documentation on why some linters are disabled.
+ # disable:
+ # - depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
+ # - exhaustivestruct # Checks if all struct's fields are initialized [fast: true, auto-fix: false]
+ # - forbidigo # Forbids identifiers [fast: true, auto-fix: false]
+ # - gci # Gci control golang package import order and make it always deterministic. [fast: true, auto-fix: true]
+ # - godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
+ # - goerr113 # Golang linter to check the errors handling expressions [fast: true, auto-fix: false]
+ # - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes [fast: false, auto-fix: false]
+ # - gomnd # An analyzer to detect magic numbers. [fast: true, auto-fix: false]
+ # - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
+ # - interfacer # Linter that suggests narrower interface types [fast: false, auto-fix: false]
+ # - maligned # Tool to detect Go structs that would take less memory if their fields were sorted [fast: false, auto-fix: false]
+ # - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false]
+ # - scopelint # Scopelint checks for unpinned variables in go programs [fast: true, auto-fix: false]
+ # - wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
+ # - wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false]
+
+ # disable-reasons:
+ # - depguard # Checks whitelisted/blacklisted import path, but runs way too slow. Not that useful.
+ # - exhaustivestruct # Good concept, but not mature enough (errors on not assignable fields like locks) and too noisy when using AWS SDK as most fields are unused.
+ # - forbidigo # Great idea, but too strict out of the box. Probably will re-enable soon.
+ # - gci # Conflicts with goimports/gofumpt.
+ # - godox # Don't fail when finding TODO, FIXME, etc.
+ # - goerr113 # Too many false positives.
+ # - golint # Deprecated (since v1.41.0) due to: The repository of the linter has been archived by the owner. Replaced by revive.
+ # - gomnd # Checks for magic numbers. Disabled due to too many false positives not configurable (03/01/2020 v1.23.7).
+ # - gomoddirectives # Doesn't support //nolint to whitelist.
+ # - interfacer # Deprecated (since v1.38.0) due to: The repository of the linter has been archived by the owner.
+ # - maligned # Deprecated (since v1.38.0) due to: The repository of the linter has been archived by the owner. Replaced by govet 'fieldalignment'.
+ # - nlreturn # Actually reduces readability in most cases.
+ # - scopelint # Deprecated (since v1.39.0) due to: The repository of the linter has been deprecated by the owner. Replaced by exportloopref.
+ # - wrapcheck # Good concept, but always warns for http coded errors. Need to re-enable and whitelist our error package.
+ # - wsl # Forces to add newlines around blocks. Lots of false positives, not that useful.
+
+ enable:
+ - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
+ - bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
+ - cyclop # checks function and package cyclomatic complexity [fast: false, auto-fix: false]
+ - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
+ - dupl # Tool for code clone detection [fast: true, auto-fix: false]
+ - durationcheck # check for two durations multiplied together [fast: false, auto-fix: false]
+ - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
+ - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. [fast: false, auto-fix: false]
+ - errorlint # go-errorlint is a source code linter for Go software that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. [fast: false, auto-fix: false]
+ - exhaustive # check exhaustiveness of enum switch statements [fast: false, auto-fix: false]
+ - exportloopref # checks for pointers to enclosing loop variables [fast: false, auto-fix: false]
+ - forcetypeassert # finds forced type assertions [fast: true, auto-fix: false]
+ - funlen # Tool for detection of long functions [fast: true, auto-fix: false]
+ - gochecknoglobals # check that no global variables exist [fast: true, auto-fix: false]
+ - gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
+ - gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
+ - goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
+ - gocritic # Provides many diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false]
+ - gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
+ - godot # Check if comments end in a period [fast: true, auto-fix: true]
+ - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
+ - gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
+ - goheader # Checks is file header matches to pattern [fast: true, auto-fix: false]
+ - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports [fast: true, auto-fix: true]
+ - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false]
+ - goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
+ - gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
+ - gosimple # (megacheck): Linter for Go source code that specializes in simplifying a code [fast: false, auto-fix: false]
+ - govet # (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false]
+ - importas # Enforces consistent import aliases [fast: false, auto-fix: false]
+ - ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
+ - lll # Reports long lines [fast: true, auto-fix: false]
+ - makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
+ - misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
+ - nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
+ - nestif # Reports deeply nested if statements [fast: true, auto-fix: false]
+ - nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false]
+ - noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false]
+ - nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
+ - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test [fast: true, auto-fix: false]
+ - prealloc # Finds slice declarations that could potentially be preallocated [fast: true, auto-fix: false]
+ - predeclared # find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false]
+ - promlinter # Check Prometheus metrics naming via promlint [fast: true, auto-fix: false]
+ - revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false]
+ # Disabled due to generic. Work in progress upstream.
+ # - rowserrcheck # checks whether Err of rows is checked successfully [fast: false, auto-fix: false]
+ # Disabled due to generic. Work in progress upstream.
+ # - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. [fast: false, auto-fix: false]
+ - staticcheck # (megacheck): Staticcheck is a go vet on steroids, applying a ton of static analysis checks [fast: false, auto-fix: false]
+ - stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false]
+ # Disabled due to generic. Work in progress upstream.
+ # - tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
+ # - testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false]
+ - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false]
+ - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes [fast: false, auto-fix: false]
+ - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: false, auto-fix: false]
+ - unconvert # Remove unnecessary type conversions [fast: false, auto-fix: false]
+ - unparam # Reports unused function parameters [fast: false, auto-fix: false]
+ # Disabled due to way too many false positive in go1.20.
+ # - unused # (megacheck): Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]
+ # Disabled due to generic. Work in progress upstream.
+ # - wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false]
+ - whitespace # Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true]
+
+issues:
+ exclude:
+ # Allow shadowing of 'err'.
+ - 'shadow: declaration of "err" shadows declaration'
+ # Allow shadowing of `ctx`.
+ - 'shadow: declaration of "ctx" shadows declaration'
+ # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
+ max-per-linter: 10
+ # Disable default excludes. Always be explicit on what we exclude.
+ exclude-use-default: false
+ # Exclude some linters from running on tests files.
+ exclude-rules: []
diff --git a/vendor/github.com/creack/pty/Dockerfile.golang b/vendor/github.com/creack/pty/Dockerfile.golang
index 2ee82a3a1f..b6153421c0 100644
--- a/vendor/github.com/creack/pty/Dockerfile.golang
+++ b/vendor/github.com/creack/pty/Dockerfile.golang
@@ -1,4 +1,4 @@
-ARG GOVERSION=1.14
+ARG GOVERSION=1.18.2
FROM golang:${GOVERSION}
# Set base env.
diff --git a/vendor/github.com/creack/pty/Dockerfile.riscv b/vendor/github.com/creack/pty/Dockerfile.riscv
deleted file mode 100644
index e3685fcf66..0000000000
--- a/vendor/github.com/creack/pty/Dockerfile.riscv
+++ /dev/null
@@ -1,23 +0,0 @@
-# NOTE: Using 1.13 as a base to build the RISCV compiler, the resulting version is based on go1.6.
-FROM golang:1.26.3
-
-# Clone and complie a riscv compatible version of the go compiler.
-RUN git clone https://review.gerrithub.io/riscv/riscv-go /riscv-go
-# riscvdev branch HEAD as of 2019-06-29.
-RUN cd /riscv-go && git checkout 04885fddd096d09d4450726064d06dd107e374bf
-ENV PATH=/riscv-go/misc/riscv:/riscv-go/bin:$PATH
-RUN cd /riscv-go/src && GOROOT_BOOTSTRAP=$(go env GOROOT) ./make.bash
-ENV GOROOT=/riscv-go
-
-# Set the base env.
-ENV GOOS=linux GOARCH=riscv CGO_ENABLED=0 GOFLAGS='-v -ldflags=-s -ldflags=-w'
-
-# Pre compile the stdlib.
-RUN go build -a std
-
-# Add the code to the image.
-WORKDIR pty
-ADD . .
-
-# Build the lib.
-RUN go build
diff --git a/vendor/github.com/creack/pty/README.md b/vendor/github.com/creack/pty/README.md
index a4fe7670d4..b6a1cf5685 100644
--- a/vendor/github.com/creack/pty/README.md
+++ b/vendor/github.com/creack/pty/README.md
@@ -10,7 +10,7 @@ go get github.com/creack/pty
## Examples
-Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment.
+Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment. If you want to **set deadlines to work** and `Close()` **interrupting** `Read()` on the returned `*os.File`, you will need to call `syscall.SetNonblock` manually.
### Command
diff --git a/vendor/github.com/creack/pty/ioctl.go b/vendor/github.com/creack/pty/ioctl.go
index 3cabedd96a..7b6b770b7f 100644
--- a/vendor/github.com/creack/pty/ioctl.go
+++ b/vendor/github.com/creack/pty/ioctl.go
@@ -1,19 +1,28 @@
-//go:build !windows && !solaris && !aix
-// +build !windows,!solaris,!aix
+//go:build !windows && go1.12
+// +build !windows,go1.12
package pty
-import "syscall"
+import "os"
-const (
- TIOCGWINSZ = syscall.TIOCGWINSZ
- TIOCSWINSZ = syscall.TIOCSWINSZ
-)
+func ioctl(f *os.File, cmd, ptr uintptr) error {
+ return ioctlInner(f.Fd(), cmd, ptr) // Fall back to blocking io.
+}
+
+// NOTE: Unused. Keeping for reference.
+func ioctlNonblock(f *os.File, cmd, ptr uintptr) error {
+ sc, e := f.SyscallConn()
+ if e != nil {
+ return ioctlInner(f.Fd(), cmd, ptr) // Fall back to blocking io (old behavior).
+ }
+
+ ch := make(chan error, 1)
+ defer close(ch)
-func ioctl(fd, cmd, ptr uintptr) error {
- _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
- if e != 0 {
+ e = sc.Control(func(fd uintptr) { ch <- ioctlInner(fd, cmd, ptr) })
+ if e != nil {
return e
}
- return nil
+ e = <-ch
+ return e
}
diff --git a/vendor/github.com/creack/pty/ioctl_inner.go b/vendor/github.com/creack/pty/ioctl_inner.go
new file mode 100644
index 0000000000..272b50b971
--- /dev/null
+++ b/vendor/github.com/creack/pty/ioctl_inner.go
@@ -0,0 +1,20 @@
+//go:build !windows && !solaris && !aix
+// +build !windows,!solaris,!aix
+
+package pty
+
+import "syscall"
+
+// Local syscall const values.
+const (
+ TIOCGWINSZ = syscall.TIOCGWINSZ
+ TIOCSWINSZ = syscall.TIOCSWINSZ
+)
+
+func ioctlInner(fd, cmd, ptr uintptr) error {
+ _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
+ if e != 0 {
+ return e
+ }
+ return nil
+}
diff --git a/vendor/github.com/creack/pty/ioctl_legacy.go b/vendor/github.com/creack/pty/ioctl_legacy.go
new file mode 100644
index 0000000000..f7e923cd07
--- /dev/null
+++ b/vendor/github.com/creack/pty/ioctl_legacy.go
@@ -0,0 +1,10 @@
+//go:build !windows && !go1.12
+// +build !windows,!go1.12
+
+package pty
+
+import "os"
+
+func ioctl(f *os.File, cmd, ptr uintptr) error {
+ return ioctlInner(f.Fd(), cmd, ptr) // fall back to blocking io (old behavior)
+}
diff --git a/vendor/github.com/creack/pty/ioctl_solaris.go b/vendor/github.com/creack/pty/ioctl_solaris.go
index bff22dad0b..6fd8bfeee5 100644
--- a/vendor/github.com/creack/pty/ioctl_solaris.go
+++ b/vendor/github.com/creack/pty/ioctl_solaris.go
@@ -40,7 +40,7 @@ type strioctl struct {
// Defined in asm_solaris_amd64.s.
func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
-func ioctl(fd, cmd, ptr uintptr) error {
+func ioctlInner(fd, cmd, ptr uintptr) error {
if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, ptr, 0, 0, 0); errno != 0 {
return errno
}
diff --git a/vendor/github.com/creack/pty/ioctl_unsupported.go b/vendor/github.com/creack/pty/ioctl_unsupported.go
index 2449a27ee7..e17908d44a 100644
--- a/vendor/github.com/creack/pty/ioctl_unsupported.go
+++ b/vendor/github.com/creack/pty/ioctl_unsupported.go
@@ -8,6 +8,6 @@ const (
TIOCSWINSZ = 0
)
-func ioctl(fd, cmd, ptr uintptr) error {
+func ioctlInner(fd, cmd, ptr uintptr) error {
return ErrUnsupported
}
diff --git a/vendor/github.com/creack/pty/pty_darwin.go b/vendor/github.com/creack/pty/pty_darwin.go
index 9bdd71d08d..eadf6ab7c7 100644
--- a/vendor/github.com/creack/pty/pty_darwin.go
+++ b/vendor/github.com/creack/pty/pty_darwin.go
@@ -46,7 +46,7 @@ func open() (pty, tty *os.File, err error) {
func ptsname(f *os.File) (string, error) {
n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME))
- err := ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0])))
+ err := ioctl(f, syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0])))
if err != nil {
return "", err
}
@@ -60,9 +60,9 @@ func ptsname(f *os.File) (string, error) {
}
func grantpt(f *os.File) error {
- return ioctl(f.Fd(), syscall.TIOCPTYGRANT, 0)
+ return ioctl(f, syscall.TIOCPTYGRANT, 0)
}
func unlockpt(f *os.File) error {
- return ioctl(f.Fd(), syscall.TIOCPTYUNLK, 0)
+ return ioctl(f, syscall.TIOCPTYUNLK, 0)
}
diff --git a/vendor/github.com/creack/pty/pty_dragonfly.go b/vendor/github.com/creack/pty/pty_dragonfly.go
index aa916aadf1..12803de043 100644
--- a/vendor/github.com/creack/pty/pty_dragonfly.go
+++ b/vendor/github.com/creack/pty/pty_dragonfly.go
@@ -45,17 +45,17 @@ func open() (pty, tty *os.File, err error) {
}
func grantpt(f *os.File) error {
- _, err := isptmaster(f.Fd())
+ _, err := isptmaster(f)
return err
}
func unlockpt(f *os.File) error {
- _, err := isptmaster(f.Fd())
+ _, err := isptmaster(f)
return err
}
-func isptmaster(fd uintptr) (bool, error) {
- err := ioctl(fd, syscall.TIOCISPTMASTER, 0)
+func isptmaster(f *os.File) (bool, error) {
+ err := ioctl(f, syscall.TIOCISPTMASTER, 0)
return err == nil, err
}
@@ -68,7 +68,7 @@ func ptsname(f *os.File) (string, error) {
name := make([]byte, _C_SPECNAMELEN)
fa := fiodgnameArg{Name: (*byte)(unsafe.Pointer(&name[0])), Len: _C_SPECNAMELEN, Pad_cgo_0: [4]byte{0, 0, 0, 0}}
- err := ioctl(f.Fd(), ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa)))
+ err := ioctl(f, ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa)))
if err != nil {
return "", err
}
diff --git a/vendor/github.com/creack/pty/pty_freebsd.go b/vendor/github.com/creack/pty/pty_freebsd.go
index bcd3b6f90f..47afcfeec8 100644
--- a/vendor/github.com/creack/pty/pty_freebsd.go
+++ b/vendor/github.com/creack/pty/pty_freebsd.go
@@ -44,8 +44,8 @@ func open() (pty, tty *os.File, err error) {
return p, t, nil
}
-func isptmaster(fd uintptr) (bool, error) {
- err := ioctl(fd, syscall.TIOCPTMASTER, 0)
+func isptmaster(f *os.File) (bool, error) {
+ err := ioctl(f, syscall.TIOCPTMASTER, 0)
return err == nil, err
}
@@ -55,7 +55,7 @@ var (
)
func ptsname(f *os.File) (string, error) {
- master, err := isptmaster(f.Fd())
+ master, err := isptmaster(f)
if err != nil {
return "", err
}
@@ -68,7 +68,7 @@ func ptsname(f *os.File) (string, error) {
buf = make([]byte, n)
arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))}
)
- if err := ioctl(f.Fd(), ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil {
+ if err := ioctl(f, ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil {
return "", err
}
diff --git a/vendor/github.com/creack/pty/pty_linux.go b/vendor/github.com/creack/pty/pty_linux.go
index a3b368f561..e7e01c0aa5 100644
--- a/vendor/github.com/creack/pty/pty_linux.go
+++ b/vendor/github.com/creack/pty/pty_linux.go
@@ -40,7 +40,7 @@ func open() (pty, tty *os.File, err error) {
func ptsname(f *os.File) (string, error) {
var n _C_uint
- err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) //nolint:gosec // Expected unsafe pointer for Syscall call.
+ err := ioctl(f, syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) //nolint:gosec // Expected unsafe pointer for Syscall call.
if err != nil {
return "", err
}
@@ -49,6 +49,6 @@ func ptsname(f *os.File) (string, error) {
func unlockpt(f *os.File) error {
var u _C_int
- // use TIOCSPTLCK with a pointer to zero to clear the lock
- return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) //nolint:gosec // Expected unsafe pointer for Syscall call.
+ // use TIOCSPTLCK with a pointer to zero to clear the lock.
+ return ioctl(f, syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) //nolint:gosec // Expected unsafe pointer for Syscall call.
}
diff --git a/vendor/github.com/creack/pty/pty_netbsd.go b/vendor/github.com/creack/pty/pty_netbsd.go
index 2b20d944c2..dd5611dbd7 100644
--- a/vendor/github.com/creack/pty/pty_netbsd.go
+++ b/vendor/github.com/creack/pty/pty_netbsd.go
@@ -47,7 +47,7 @@ func ptsname(f *os.File) (string, error) {
* ioctl(fd, TIOCPTSNAME, &pm) == -1 ? NULL : pm.sn;
*/
var ptm ptmget
- if err := ioctl(f.Fd(), uintptr(ioctl_TIOCPTSNAME), uintptr(unsafe.Pointer(&ptm))); err != nil {
+ if err := ioctl(f, uintptr(ioctl_TIOCPTSNAME), uintptr(unsafe.Pointer(&ptm))); err != nil {
return "", err
}
name := make([]byte, len(ptm.Sn))
@@ -65,5 +65,5 @@ func grantpt(f *os.File) error {
* from grantpt(3): Calling grantpt() is equivalent to:
* ioctl(fd, TIOCGRANTPT, 0);
*/
- return ioctl(f.Fd(), uintptr(ioctl_TIOCGRANTPT), 0)
+ return ioctl(f, uintptr(ioctl_TIOCGRANTPT), 0)
}
diff --git a/vendor/github.com/creack/pty/pty_openbsd.go b/vendor/github.com/creack/pty/pty_openbsd.go
index 031367a85b..337c39f3f1 100644
--- a/vendor/github.com/creack/pty/pty_openbsd.go
+++ b/vendor/github.com/creack/pty/pty_openbsd.go
@@ -9,6 +9,17 @@ import (
"unsafe"
)
+func cInt8ToString(in []int8) string {
+ var s []byte
+ for _, v := range in {
+ if v == 0 {
+ break
+ }
+ s = append(s, byte(v))
+ }
+ return string(s)
+}
+
func open() (pty, tty *os.File, err error) {
/*
* from ptm(4):
@@ -25,12 +36,12 @@ func open() (pty, tty *os.File, err error) {
defer p.Close()
var ptm ptmget
- if err := ioctl(p.Fd(), uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil {
+ if err := ioctl(p, uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil {
return nil, nil, err
}
- pty = os.NewFile(uintptr(ptm.Cfd), "/dev/ptm")
- tty = os.NewFile(uintptr(ptm.Sfd), "/dev/ptm")
+ pty = os.NewFile(uintptr(ptm.Cfd), cInt8ToString(ptm.Cn[:]))
+ tty = os.NewFile(uintptr(ptm.Sfd), cInt8ToString(ptm.Sn[:]))
return pty, tty, nil
}
diff --git a/vendor/github.com/creack/pty/pty_solaris.go b/vendor/github.com/creack/pty/pty_solaris.go
index 37f933e600..4e22416b01 100644
--- a/vendor/github.com/creack/pty/pty_solaris.go
+++ b/vendor/github.com/creack/pty/pty_solaris.go
@@ -65,7 +65,7 @@ func open() (pty, tty *os.File, err error) {
}
func ptsname(f *os.File) (string, error) {
- dev, err := ptsdev(f.Fd())
+ dev, err := ptsdev(f)
if err != nil {
return "", err
}
@@ -84,12 +84,12 @@ func unlockpt(f *os.File) error {
icLen: 0,
icDP: nil,
}
- return ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr)))
+ return ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr)))
}
func minor(x uint64) uint64 { return x & 0377 }
-func ptsdev(fd uintptr) (uint64, error) {
+func ptsdev(f *os.File) (uint64, error) {
istr := strioctl{
icCmd: ISPTM,
icTimeout: 0,
@@ -97,14 +97,33 @@ func ptsdev(fd uintptr) (uint64, error) {
icDP: nil,
}
- if err := ioctl(fd, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
+ if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
return 0, err
}
- var status syscall.Stat_t
- if err := syscall.Fstat(int(fd), &status); err != nil {
+ var errors = make(chan error, 1)
+ var results = make(chan uint64, 1)
+ defer close(errors)
+ defer close(results)
+
+ var err error
+ var sc syscall.RawConn
+ sc, err = f.SyscallConn()
+ if err != nil {
+ return 0, err
+ }
+ err = sc.Control(func(fd uintptr) {
+ var status syscall.Stat_t
+ if err := syscall.Fstat(int(fd), &status); err != nil {
+ results <- 0
+ errors <- err
+ }
+ results <- uint64(minor(status.Rdev))
+ errors <- nil
+ })
+ if err != nil {
return 0, err
}
- return uint64(minor(status.Rdev)), nil
+ return <-results, <-errors
}
type ptOwn struct {
@@ -113,7 +132,7 @@ type ptOwn struct {
}
func grantpt(f *os.File) error {
- if _, err := ptsdev(f.Fd()); err != nil {
+ if _, err := ptsdev(f); err != nil {
return err
}
pto := ptOwn{
@@ -127,7 +146,7 @@ func grantpt(f *os.File) error {
icLen: int32(unsafe.Sizeof(strioctl{})),
icDP: unsafe.Pointer(&pto),
}
- if err := ioctl(f.Fd(), I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
+ if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil {
return errors.New("access denied")
}
return nil
@@ -145,8 +164,8 @@ func streamsPush(f *os.File, mod string) error {
// but since we are not using libc or XPG4.2, we should not be
// double-pushing modules
- if err := ioctl(f.Fd(), I_FIND, uintptr(unsafe.Pointer(&buf[0]))); err != nil {
+ if err := ioctl(f, I_FIND, uintptr(unsafe.Pointer(&buf[0]))); err != nil {
return nil
}
- return ioctl(f.Fd(), I_PUSH, uintptr(unsafe.Pointer(&buf[0])))
+ return ioctl(f, I_PUSH, uintptr(unsafe.Pointer(&buf[0])))
}
diff --git a/vendor/github.com/creack/pty/pty_unsupported.go b/vendor/github.com/creack/pty/pty_unsupported.go
index c771020fae..0971dc74e1 100644
--- a/vendor/github.com/creack/pty/pty_unsupported.go
+++ b/vendor/github.com/creack/pty/pty_unsupported.go
@@ -1,5 +1,5 @@
-//go:build !linux && !darwin && !freebsd && !dragonfly && !netbsd && !openbsd && !solaris
-// +build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris
+//go:build !linux && !darwin && !freebsd && !dragonfly && !netbsd && !openbsd && !solaris && !zos
+// +build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris,!zos
package pty
diff --git a/vendor/github.com/creack/pty/pty_zos.go b/vendor/github.com/creack/pty/pty_zos.go
new file mode 100644
index 0000000000..18e61e1963
--- /dev/null
+++ b/vendor/github.com/creack/pty/pty_zos.go
@@ -0,0 +1,141 @@
+//go:build zos
+// +build zos
+
+package pty
+
+import (
+ "os"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ SYS_UNLOCKPT = 0x37B
+ SYS_GRANTPT = 0x37A
+ SYS_POSIX_OPENPT = 0xC66
+ SYS_FCNTL = 0x18C
+ SYS___PTSNAME_A = 0x718
+
+ SETCVTON = 1
+
+ O_NONBLOCK = 0x04
+
+ F_SETFL = 4
+ F_CONTROL_CVT = 13
+)
+
+type f_cnvrt struct {
+ Cvtcmd int32
+ Pccsid int16
+ Fccsid int16
+}
+
+func open() (pty, tty *os.File, err error) {
+ ptmxfd, err := openpt(os.O_RDWR | syscall.O_NOCTTY)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // Needed for z/OS so that the characters are not garbled if ptyp* is untagged
+ cvtreq := f_cnvrt{Cvtcmd: SETCVTON, Pccsid: 0, Fccsid: 1047}
+ if _, err = fcntl(uintptr(ptmxfd), F_CONTROL_CVT, uintptr(unsafe.Pointer(&cvtreq))); err != nil {
+ return nil, nil, err
+ }
+
+ p := os.NewFile(uintptr(ptmxfd), "/dev/ptmx")
+ if p == nil {
+ return nil, nil, err
+ }
+
+ // In case of error after this point, make sure we close the ptmx fd.
+ defer func() {
+ if err != nil {
+ _ = p.Close() // Best effort.
+ }
+ }()
+
+ sname, err := ptsname(ptmxfd)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ _, err = grantpt(ptmxfd)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if _, err = unlockpt(ptmxfd); err != nil {
+ return nil, nil, err
+ }
+
+ ptsfd, err := syscall.Open(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if _, err = fcntl(uintptr(ptsfd), F_CONTROL_CVT, uintptr(unsafe.Pointer(&cvtreq))); err != nil {
+ return nil, nil, err
+ }
+
+ t := os.NewFile(uintptr(ptsfd), sname)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return p, t, nil
+}
+
+func openpt(oflag int) (fd int, err error) {
+ r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_POSIX_OPENPT<<4, uintptr(oflag))
+ fd = int(r0)
+ if e1 != 0 {
+ err = syscall.Errno(e1)
+ }
+ return
+}
+
+func fcntl(fd uintptr, cmd int, arg uintptr) (val int, err error) {
+ r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_FCNTL<<4, uintptr(fd), uintptr(cmd), arg)
+ val = int(r0)
+ if e1 != 0 {
+ err = syscall.Errno(e1)
+ }
+ return
+}
+
+func ptsname(fd int) (name string, err error) {
+ r0, _, e1 := runtime.CallLeFuncWithPtrReturn(runtime.GetZosLibVec()+SYS___PTSNAME_A<<4, uintptr(fd))
+ name = u2s(unsafe.Pointer(r0))
+ if e1 != 0 {
+ err = syscall.Errno(e1)
+ }
+ return
+}
+
+func grantpt(fildes int) (rc int, err error) {
+ r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_GRANTPT<<4, uintptr(fildes))
+ rc = int(r0)
+ if e1 != 0 {
+ err = syscall.Errno(e1)
+ }
+ return
+}
+
+func unlockpt(fildes int) (rc int, err error) {
+ r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+SYS_UNLOCKPT<<4, uintptr(fildes))
+ rc = int(r0)
+ if e1 != 0 {
+ err = syscall.Errno(e1)
+ }
+ return
+}
+
+func u2s(cstr unsafe.Pointer) string {
+ str := (*[1024]uint8)(cstr)
+ i := 0
+ for str[i] != 0 {
+ i++
+ }
+ return string(str[:i])
+}
diff --git a/vendor/github.com/creack/pty/test_crosscompile.sh b/vendor/github.com/creack/pty/test_crosscompile.sh
index 47e8b10643..40df89add6 100644
--- a/vendor/github.com/creack/pty/test_crosscompile.sh
+++ b/vendor/github.com/creack/pty/test_crosscompile.sh
@@ -25,9 +25,9 @@ cross() {
set -e
-cross linux amd64 386 arm arm64 ppc64 ppc64le s390x mips mipsle mips64 mips64le
+cross linux amd64 386 arm arm64 ppc64 ppc64le s390x mips mipsle mips64 mips64le riscv64
cross darwin amd64 arm64
-cross freebsd amd64 386 arm arm64
+cross freebsd amd64 386 arm arm64 riscv64
cross netbsd amd64 386 arm arm64
cross openbsd amd64 386 arm arm64
cross dragonfly amd64
@@ -45,10 +45,6 @@ if ! hash docker; then
return
fi
-echo2 "Build for linux."
-echo2 " - linux/riscv"
-docker build -t creack-pty-test -f Dockerfile.riscv .
-
# Golang dropped support for darwin 32bits since go1.15. Make sure the lib still compile with go1.14 on those archs.
echo2 "Build for darwin (32bits)."
echo2 " - darwin/386"
diff --git a/vendor/github.com/creack/pty/winsize.go b/vendor/github.com/creack/pty/winsize.go
index 57323f40ab..cfa3e5f391 100644
--- a/vendor/github.com/creack/pty/winsize.go
+++ b/vendor/github.com/creack/pty/winsize.go
@@ -10,10 +10,7 @@ func InheritSize(pty, tty *os.File) error {
if err != nil {
return err
}
- if err := Setsize(tty, size); err != nil {
- return err
- }
- return nil
+ return Setsize(tty, size)
}
// Getsize returns the number of rows (lines) and cols (positions
diff --git a/vendor/github.com/creack/pty/winsize_unix.go b/vendor/github.com/creack/pty/winsize_unix.go
index 5d99c3dd9d..8dbbcda0f0 100644
--- a/vendor/github.com/creack/pty/winsize_unix.go
+++ b/vendor/github.com/creack/pty/winsize_unix.go
@@ -11,16 +11,16 @@ import (
// Winsize describes the terminal size.
type Winsize struct {
- Rows uint16 // ws_row: Number of rows (in cells)
- Cols uint16 // ws_col: Number of columns (in cells)
- X uint16 // ws_xpixel: Width in pixels
- Y uint16 // ws_ypixel: Height in pixels
+ Rows uint16 // ws_row: Number of rows (in cells).
+ Cols uint16 // ws_col: Number of columns (in cells).
+ X uint16 // ws_xpixel: Width in pixels.
+ Y uint16 // ws_ypixel: Height in pixels.
}
// Setsize resizes t to s.
func Setsize(t *os.File, ws *Winsize) error {
//nolint:gosec // Expected unsafe pointer for Syscall call.
- return ioctl(t.Fd(), syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(ws)))
+ return ioctl(t, syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(ws)))
}
// GetsizeFull returns the full terminal size description.
@@ -28,7 +28,7 @@ func GetsizeFull(t *os.File) (size *Winsize, err error) {
var ws Winsize
//nolint:gosec // Expected unsafe pointer for Syscall call.
- if err := ioctl(t.Fd(), syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))); err != nil {
+ if err := ioctl(t, syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))); err != nil {
return nil, err
}
return &ws, nil
diff --git a/vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go b/vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go
new file mode 100644
index 0000000000..b3c544098c
--- /dev/null
+++ b/vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go
@@ -0,0 +1,13 @@
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_freebsd.go
+
+package pty
+
+const (
+ _C_SPECNAMELEN = 0x3f
+)
+
+type fiodgnameArg struct {
+ Len int32
+ Buf *byte
+}
diff --git a/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go b/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go
index 1eb0948167..811312dd35 100644
--- a/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go
+++ b/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go
@@ -1,5 +1,4 @@
-//go:build (386 || amd64 || arm || arm64 || mips64) && openbsd
-// +build 386 amd64 arm arm64 mips64
+//go:build openbsd
// +build openbsd
package pty
diff --git a/vendor/github.com/creack/pty/ztypes_ppc.go b/vendor/github.com/creack/pty/ztypes_ppc.go
new file mode 100644
index 0000000000..ff0b8fd838
--- /dev/null
+++ b/vendor/github.com/creack/pty/ztypes_ppc.go
@@ -0,0 +1,9 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types.go
+
+package pty
+
+type (
+ _C_int int32
+ _C_uint uint32
+)
diff --git a/vendor/github.com/creack/pty/ztypes_sparcx.go b/vendor/github.com/creack/pty/ztypes_sparcx.go
new file mode 100644
index 0000000000..06e44311df
--- /dev/null
+++ b/vendor/github.com/creack/pty/ztypes_sparcx.go
@@ -0,0 +1,12 @@
+//go:build sparc || sparc64
+// +build sparc sparc64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types.go
+
+package pty
+
+type (
+ _C_int int32
+ _C_uint uint32
+)
diff --git a/vendor/github.com/cyphar/filepath-securejoin/.golangci.yml b/vendor/github.com/cyphar/filepath-securejoin/.golangci.yml
new file mode 100644
index 0000000000..3e8dd99bd7
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/.golangci.yml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: MPL-2.0
+
+# Copyright (C) 2025 Aleksa Sarai
+# Copyright (C) 2025 SUSE LLC
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+version: "2"
+
+run:
+ build-tags:
+ - libpathrs
+
+linters:
+ enable:
+ - asasalint
+ - asciicheck
+ - containedctx
+ - contextcheck
+ - errcheck
+ - errorlint
+ - exhaustive
+ - forcetypeassert
+ - godot
+ - goprintffuncname
+ - govet
+ - importas
+ - ineffassign
+ - makezero
+ - misspell
+ - musttag
+ - nilerr
+ - nilnesserr
+ - nilnil
+ - noctx
+ - prealloc
+ - revive
+ - staticcheck
+ - testifylint
+ - unconvert
+ - unparam
+ - unused
+ - usetesting
+ settings:
+ govet:
+ enable:
+ - nilness
+ testifylint:
+ enable-all: true
+
+formatters:
+ enable:
+ - gofumpt
+ - goimports
+ settings:
+ goimports:
+ local-prefixes:
+ - github.com/cyphar/filepath-securejoin
diff --git a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
new file mode 100644
index 0000000000..6d016d05c0
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
@@ -0,0 +1,453 @@
+# Changelog #
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## [Unreleased] ##
+
+## [0.6.1] - 2025-11-19 ##
+
+> At last up jumped the cunning spider, and fiercely held her fast.
+
+### Fixed ###
+- Our logic for deciding whether to use `openat2(2)` or fallback to an `O_PATH`
+ resolver would cache the result to avoid doing needless test runs of
+ `openat2(2)`. However, this causes issues when `pathrs-lite` is being used by
+ a program that applies new seccomp-bpf filters onto itself -- if the filter
+ denies `openat2(2)` then we would return that error rather than falling back
+ to the `O_PATH` resolver. To resolve this issue, we no longer cache the
+ result if `openat2(2)` was successful, only if there was an error.
+- A file descriptor leak in our `openat2` wrapper (when doing the necessary
+ `dup` for `RESOLVE_IN_ROOT`) has been removed.
+
+## [0.5.2] - 2025-11-19 ##
+
+> "Will you walk into my parlour?" said a spider to a fly.
+
+### Fixed ###
+- Our logic for deciding whether to use `openat2(2)` or fallback to an `O_PATH`
+ resolver would cache the result to avoid doing needless test runs of
+ `openat2(2)`. However, this causes issues when `pathrs-lite` is being used by
+ a program that applies new seccomp-bpf filters onto itself -- if the filter
+ denies `openat2(2)` then we would return that error rather than falling back
+ to the `O_PATH` resolver. To resolve this issue, we no longer cache the
+ result if `openat2(2)` was successful, only if there was an error.
+- A file descriptor leak in our `openat2` wrapper (when doing the necessary
+ `dup` for `RESOLVE_IN_ROOT`) has been removed.
+
+## [0.6.0] - 2025-11-03 ##
+
+> By the Power of Greyskull!
+
+### Breaking ###
+- The deprecated `MkdirAll`, `MkdirAllHandle`, `OpenInRoot`, `OpenatInRoot` and
+ `Reopen` wrappers have been removed. Please switch to using `pathrs-lite`
+ directly.
+
+### Added ###
+- `pathrs-lite` now has support for using libpathrs as a backend. This is
+ opt-in and can be enabled at build time with the `libpathrs` build tag. The
+ intention is to allow for downstream libraries and other projects to make use
+ of the pure-Go `github.com/cyphar/filepath-securejoin/pathrs-lite` package
+ and distributors can then opt-in to using `libpathrs` for the entire binary
+ if they wish.
+
+## [0.5.1] - 2025-10-31 ##
+
+> Spooky scary skeletons send shivers down your spine!
+
+### Changed ###
+- `openat2` can return `-EAGAIN` if it detects a possible attack in certain
+ scenarios (namely if there was a rename or mount while walking a path with a
+ `..` component). While this is necessary to avoid a denial-of-service in the
+ kernel, it does require retry loops in userspace.
+
+ In previous versions, `pathrs-lite` would retry `openat2` 32 times before
+ returning an error, but we've received user reports that this limit can be
+ hit on systems with very heavy load. In some synthetic benchmarks (testing
+ the worst-case of an attacker doing renames in a tight loop on every core of
+ a 16-core machine) we managed to get a ~3% failure rate in runc. We have
+ improved this situation in two ways:
+
+ * We have now increased this limit to 128, which should be good enough for
+ most use-cases without becoming a denial-of-service vector (the number of
+ syscalls called by the `O_PATH` resolver in a typical case is within the
+ same ballpark). The same benchmarks show a failure rate of ~0.12% which
+ (while not zero) is probably sufficient for most users.
+
+ * In addition, we now return a `unix.EAGAIN` error that is bubbled up and can
+ be detected by callers. This means that callers with stricter requirements
+ to avoid spurious errors can choose to do their own infinite `EAGAIN` retry
+ loop (though we would strongly recommend users use time-based deadlines in
+ such retry loops to avoid potentially unbounded denials-of-service).
+
+## [0.5.0] - 2025-09-26 ##
+
+> Let the past die. Kill it if you have to.
+
+> **NOTE**: With this release, some parts of
+> `github.com/cyphar/filepath-securejoin` are now licensed under the Mozilla
+> Public License (version 2). Please see [COPYING.md][] as well as the the
+> license header in each file for more details.
+
+[COPYING.md]: ./COPYING.md
+
+### Breaking ###
+- The new API introduced in the [0.3.0][] release has been moved to a new
+ subpackage called `pathrs-lite`. This was primarily done to better indicate
+ the split between the new and old APIs, as well as indicate to users the
+ purpose of this subpackage (it is a less complete version of [libpathrs][]).
+
+ We have added some wrappers to the top-level package to ease the transition,
+ but those are deprecated and will be removed in the next minor release of
+ filepath-securejoin. Users should update their import paths.
+
+ This new subpackage has also been relicensed under the Mozilla Public License
+ (version 2), please see [COPYING.md][] for more details.
+
+### Added ###
+- Most of the key bits the safe `procfs` API have now been exported and are
+ available in `github.com/cyphar/filepath-securejoin/pathrs-lite/procfs`. At
+ the moment this primarily consists of a new `procfs.Handle` API:
+
+ * `OpenProcRoot` returns a new handle to `/proc`, endeavouring to make it
+ safe if possible (`subset=pid` to protect against mistaken write attacks
+ and leaks, as well as using `fsopen(2)` to avoid racing mount attacks).
+
+ `OpenUnsafeProcRoot` returns a handle without attempting to create one
+ with `subset=pid`, which makes it more dangerous to leak. Most users
+ should use `OpenProcRoot` (even if you need to use `ProcRoot` as the base
+ of an operation, as filepath-securejoin will internally open a handle when
+ necessary).
+
+ * The `(*procfs.Handle).Open*` family of methods lets you get a safe
+ `O_PATH` handle to subpaths within `/proc` for certain subpaths.
+
+ For `OpenThreadSelf`, the returned `ProcThreadSelfCloser` needs to be
+ called after you completely finish using the handle (this is necessary
+ because Go is multi-threaded and `ProcThreadSelf` references
+ `/proc/thread-self` which may disappear if we do not
+ `runtime.LockOSThread` -- `ProcThreadSelfCloser` is currently equivalent
+ to `runtime.UnlockOSThread`).
+
+ Note that you cannot open any `procfs` symlinks (most notably magic-links)
+ using this API. At the moment, filepath-securejoin does not support this
+ feature (but [libpathrs][] does).
+
+ * `ProcSelfFdReadlink` lets you get the in-kernel path representation of a
+ file descriptor (think `readlink("/proc/self/fd/...")`), except that we
+ verify that there aren't any tricky overmounts that could fool the
+ process.
+
+ Please be aware that the returned string is simply a snapshot at that
+ particular moment, and an attacker could move the file being pointed to.
+ In addition, complex namespace configurations could result in non-sensical
+ or confusing paths to be returned. The value received from this function
+ should only be used as secondary verification of some security property,
+ not as proof that a particular handle has a particular path.
+
+ The procfs handle used internally by the API is the same as the rest of
+ `filepath-securejoin` (for privileged programs this is usually a private
+ in-process `procfs` instance created with `fsopen(2)`).
+
+ As before, this is intended as a stop-gap before users migrate to
+ [libpathrs][], which provides a far more extensive safe `procfs` API and is
+ generally more robust.
+
+- Previously, the hardened procfs implementation (used internally within
+ `Reopen` and `Open(at)InRoot`) only protected against overmount attacks on
+ systems with `openat2(2)` (Linux 5.6) or systems with `fsopen(2)` or
+ `open_tree(2)` (Linux 5.2) and programs with privileges to use them (with
+ some caveats about locked mounts that probably affect very few users). For
+ other users, an attacker with the ability to create malicious mounts (on most
+ systems, a sysadmin) could trick you into operating on files you didn't
+ expect. This attack only really makes sense in the context of container
+ runtime implementations.
+
+ This was considered a reasonable trade-off, as the long-term intention was to
+ get all users to just switch to [libpathrs][] if they wanted to use the safe
+ `procfs` API (which had more extensive protections, and is what these new
+ protections in `filepath-securejoin` are based on). However, as the API
+ is now being exported it seems unwise to advertise the API as "safe" if we do
+ not protect against known attacks.
+
+ The procfs API is now more protected against attackers on systems lacking the
+ aforementioned protections. However, the most comprehensive of these
+ protections effectively rely on [`statx(STATX_MNT_ID)`][statx.2] (Linux 5.8).
+ On older kernel versions, there is no effective protection (there is some
+ minimal protection against non-`procfs` filesystem components but a
+ sufficiently clever attacker can work around those). In addition,
+ `STATX_MNT_ID` is vulnerable to mount ID reuse attacks by sufficiently
+ motivated and privileged attackers -- this problem is mitigated with
+ `STATX_MNT_ID_UNIQUE` (Linux 6.8) but that raises the minimum kernel version
+ for more protection.
+
+ The fact that these protections are quite limited despite needing a fair bit
+ of extra code to handle was one of the primary reasons we did not initially
+ implement this in `filepath-securejoin` ([libpathrs][] supports all of this,
+ of course).
+
+### Fixed ###
+- RHEL 8 kernels have backports of `fsopen(2)` but in some testing we've found
+ that it has very bad (and very difficult to debug) performance issues, and so
+ we will explicitly refuse to use `fsopen(2)` if the running kernel version is
+ pre-5.2 and will instead fallback to `open("/proc")`.
+
+[CVE-2024-21626]: https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv
+[libpathrs]: https://github.com/cyphar/libpathrs
+[statx.2]: https://www.man7.org/linux/man-pages/man2/statx.2.html
+
+## [0.4.1] - 2025-01-28 ##
+
+### Fixed ###
+- The restrictions added for `root` paths passed to `SecureJoin` in 0.4.0 was
+ found to be too strict and caused some regressions when folks tried to
+ update, so this restriction has been relaxed to only return an error if the
+ path contains a `..` component. We still recommend users use `filepath.Clean`
+ (and even `filepath.EvalSymlinks`) on the `root` path they are using, but at
+ least you will no longer be punished for "trivial" unclean paths.
+
+## [0.4.0] - 2025-01-13 ##
+
+### Breaking ####
+- `SecureJoin(VFS)` will now return an error if the provided `root` is not a
+ `filepath.Clean`'d path.
+
+ While it is ultimately the responsibility of the caller to ensure the root is
+ a safe path to use, passing a path like `/symlink/..` as a root would result
+ in the `SecureJoin`'d path being placed in `/` even though `/symlink/..`
+ might be a different directory, and so we should more strongly discourage
+ such usage.
+
+ All major users of `securejoin.SecureJoin` already ensure that the paths they
+ provide are safe (and this is ultimately a question of user error), but
+ removing this foot-gun is probably a good idea. Of course, this is
+ necessarily a breaking API change (though we expect no real users to be
+ affected by it).
+
+ Thanks to [Erik Sjölund](https://github.com/eriksjolund), who initially
+ reported this issue as a possible security issue.
+
+- `MkdirAll` and `MkdirHandle` now take an `os.FileMode`-style mode argument
+ instead of a raw `unix.S_*`-style mode argument, which may cause compile-time
+ type errors depending on how you use `filepath-securejoin`. For most users,
+ there will be no change in behaviour aside from the type change (as the
+ bottom `0o777` bits are the same in both formats, and most users are probably
+ only using those bits).
+
+ However, if you were using `unix.S_ISVTX` to set the sticky bit with
+ `MkdirAll(Handle)` you will need to switch to `os.ModeSticky` otherwise you
+ will get a runtime error with this update. In addition, the error message you
+ will get from passing `unix.S_ISUID` and `unix.S_ISGID` will be different as
+ they are treated as invalid bits now (note that previously passing said bits
+ was also an error).
+
+## [0.3.6] - 2024-12-17 ##
+
+### Compatibility ###
+- The minimum Go version requirement for `filepath-securejoin` is now Go 1.18
+ (we use generics internally).
+
+ For reference, `filepath-securejoin@v0.3.0` somewhat-arbitrarily bumped the
+ Go version requirement to 1.21.
+
+ While we did make some use of Go 1.21 stdlib features (and in principle Go
+ versions <= 1.21 are no longer even supported by upstream anymore), some
+ downstreams have complained that the version bump has meant that they have to
+ do workarounds when backporting fixes that use the new `filepath-securejoin`
+ API onto old branches. This is not an ideal situation, but since using this
+ library is probably better for most downstreams than a hand-rolled
+ workaround, we now have compatibility shims that allow us to build on older
+ Go versions.
+- Lower minimum version requirement for `golang.org/x/sys` to `v0.18.0` (we
+ need the wrappers for `fsconfig(2)`), which should also make backporting
+ patches to older branches easier.
+
+## [0.3.5] - 2024-12-06 ##
+
+### Fixed ###
+- `MkdirAll` will now no longer return an `EEXIST` error if two racing
+ processes are creating the same directory. We will still verify that the path
+ is a directory, but this will avoid spurious errors when multiple threads or
+ programs are trying to `MkdirAll` the same path. opencontainers/runc#4543
+
+## [0.3.4] - 2024-10-09 ##
+
+### Fixed ###
+- Previously, some testing mocks we had resulted in us doing `import "testing"`
+ in non-`_test.go` code, which made some downstreams like Kubernetes unhappy.
+ This has been fixed. (#32)
+
+## [0.3.3] - 2024-09-30 ##
+
+### Fixed ###
+- The mode and owner verification logic in `MkdirAll` has been removed. This
+ was originally intended to protect against some theoretical attacks but upon
+ further consideration these protections don't actually buy us anything and
+ they were causing spurious errors with more complicated filesystem setups.
+- The "is the created directory empty" logic in `MkdirAll` has also been
+ removed. This was not causing us issues yet, but some pseudofilesystems (such
+ as `cgroup`) create non-empty directories and so this logic would've been
+ wrong for such cases.
+
+## [0.3.2] - 2024-09-13 ##
+
+### Changed ###
+- Passing the `S_ISUID` or `S_ISGID` modes to `MkdirAllInRoot` will now return
+ an explicit error saying that those bits are ignored by `mkdirat(2)`. In the
+ past a different error was returned, but since the silent ignoring behaviour
+ is codified in the man pages a more explicit error seems apt. While silently
+ ignoring these bits would be the most compatible option, it could lead to
+ users thinking their code sets these bits when it doesn't. Programs that need
+ to deal with compatibility can mask the bits themselves. (#23, #25)
+
+### Fixed ###
+- If a directory has `S_ISGID` set, then all child directories will have
+ `S_ISGID` set when created and a different gid will be used for any inode
+ created under the directory. Previously, the "expected owner and mode"
+ validation in `securejoin.MkdirAll` did not correctly handle this. We now
+ correctly handle this case. (#24, #25)
+
+## [0.3.1] - 2024-07-23 ##
+
+### Changed ###
+- By allowing `Open(at)InRoot` to opt-out of the extra work done by `MkdirAll`
+ to do the necessary "partial lookups", `Open(at)InRoot` now does less work
+ for both implementations (resulting in a many-fold decrease in the number of
+ operations for `openat2`, and a modest improvement for non-`openat2`) and is
+ far more guaranteed to match the correct `openat2(RESOLVE_IN_ROOT)`
+ behaviour.
+- We now use `readlinkat(fd, "")` where possible. For `Open(at)InRoot` this
+ effectively just means that we no longer risk getting spurious errors during
+ rename races. However, for our hardened procfs handler, this in theory should
+ prevent mount attacks from tricking us when doing magic-link readlinks (even
+ when using the unsafe host `/proc` handle). Unfortunately `Reopen` is still
+ potentially vulnerable to those kinds of somewhat-esoteric attacks.
+
+ Technically this [will only work on post-2.6.39 kernels][linux-readlinkat-emptypath]
+ but it seems incredibly unlikely anyone is using `filepath-securejoin` on a
+ pre-2011 kernel.
+
+### Fixed ###
+- Several improvements were made to the errors returned by `Open(at)InRoot` and
+ `MkdirAll` when dealing with invalid paths under the emulated (ie.
+ non-`openat2`) implementation. Previously, some paths would return the wrong
+ error (`ENOENT` when the last component was a non-directory), and other paths
+ would be returned as though they were acceptable (trailing-slash components
+ after a non-directory would be ignored by `Open(at)InRoot`).
+
+ These changes were done to match `openat2`'s behaviour and purely is a
+ consistency fix (most users are going to be using `openat2` anyway).
+
+[linux-readlinkat-emptypath]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65cfc6722361570bfe255698d9cd4dccaf47570d
+
+## [0.3.0] - 2024-07-11 ##
+
+### Added ###
+- A new set of `*os.File`-based APIs have been added. These are adapted from
+ [libpathrs][] and we strongly suggest using them if possible (as they provide
+ far more protection against attacks than `SecureJoin`):
+
+ - `Open(at)InRoot` resolves a path inside a rootfs and returns an `*os.File`
+ handle to the path. Note that the handle returned is an `O_PATH` handle,
+ which cannot be used for reading or writing (as well as some other
+ operations -- [see open(2) for more details][open.2])
+
+ - `Reopen` takes an `O_PATH` file handle and safely re-opens it to upgrade
+ it to a regular handle. This can also be used with non-`O_PATH` handles,
+ but `O_PATH` is the most obvious application.
+
+ - `MkdirAll` is an implementation of `os.MkdirAll` that is safe to use to
+ create a directory tree within a rootfs.
+
+ As these are new APIs, they may change in the future. However, they should be
+ safe to start migrating to as we have extensive tests ensuring they behave
+ correctly and are safe against various races and other attacks.
+
+[libpathrs]: https://github.com/cyphar/libpathrs
+[open.2]: https://www.man7.org/linux/man-pages/man2/open.2.html
+
+## [0.2.5] - 2024-05-03 ##
+
+### Changed ###
+- Some minor changes were made to how lexical components (like `..` and `.`)
+ are handled during path generation in `SecureJoin`. There is no behaviour
+ change as a result of this fix (the resulting paths are the same).
+
+### Fixed ###
+- The error returned when we hit a symlink loop now references the correct
+ path. (#10)
+
+## [0.2.4] - 2023-09-06 ##
+
+### Security ###
+- This release fixes a potential security issue in filepath-securejoin when
+ used on Windows ([GHSA-6xv5-86q9-7xr8][], which could be used to generate
+ paths outside of the provided rootfs in certain cases), as well as improving
+ the overall behaviour of filepath-securejoin when dealing with Windows paths
+ that contain volume names. Thanks to Paulo Gomes for discovering and fixing
+ these issues.
+
+### Fixed ###
+- Switch to GitHub Actions for CI so we can test on Windows as well as Linux
+ and MacOS.
+
+[GHSA-6xv5-86q9-7xr8]: https://github.com/advisories/GHSA-6xv5-86q9-7xr8
+
+## [0.2.3] - 2021-06-04 ##
+
+### Changed ###
+- Switch to Go 1.13-style `%w` error wrapping, letting us drop the dependency
+ on `github.com/pkg/errors`.
+
+## [0.2.2] - 2018-09-05 ##
+
+### Changed ###
+- Use `syscall.ELOOP` as the base error for symlink loops, rather than our own
+ (internal) error. This allows callers to more easily use `errors.Is` to check
+ for this case.
+
+## [0.2.1] - 2018-09-05 ##
+
+### Fixed ###
+- Use our own `IsNotExist` implementation, which lets us handle `ENOTDIR`
+ properly within `SecureJoin`.
+
+## [0.2.0] - 2017-07-19 ##
+
+We now have 100% test coverage!
+
+### Added ###
+- Add a `SecureJoinVFS` API that can be used for mocking (as we do in our new
+ tests) or for implementing custom handling of lookup operations (such as for
+ rootless containers, where work is necessary to access directories with weird
+ modes because we don't have `CAP_DAC_READ_SEARCH` or `CAP_DAC_OVERRIDE`).
+
+## 0.1.0 - 2017-07-19
+
+This is our first release of `github.com/cyphar/filepath-securejoin`,
+containing a full implementation with a coverage of 93.5% (the only missing
+cases are the error cases, which are hard to mocktest at the moment).
+
+[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.6.1...HEAD
+[0.6.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.6.0...v0.6.1
+[0.6.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.0...v0.6.0
+[0.5.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.1...v0.5.2
+[0.5.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.0...v0.5.1
+[0.5.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.1...v0.5.0
+[0.4.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.0...v0.4.1
+[0.4.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.6...v0.4.0
+[0.3.6]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.5...v0.3.6
+[0.3.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.4...v0.3.5
+[0.3.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.3...v0.3.4
+[0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.2...v0.3.3
+[0.3.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.1...v0.3.2
+[0.3.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.0...v0.3.1
+[0.3.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.5...v0.3.0
+[0.2.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.4...v0.2.5
+[0.2.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.3...v0.2.4
+[0.2.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.2...v0.2.3
+[0.2.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.1...v0.2.2
+[0.2.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.0...v0.2.1
+[0.2.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.1.0...v0.2.0
diff --git a/vendor/github.com/cyphar/filepath-securejoin/COPYING.md b/vendor/github.com/cyphar/filepath-securejoin/COPYING.md
new file mode 100644
index 0000000000..520e822b18
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/COPYING.md
@@ -0,0 +1,447 @@
+## COPYING ##
+
+`SPDX-License-Identifier: BSD-3-Clause AND MPL-2.0`
+
+This project is made up of code licensed under different licenses. Which code
+you use will have an impact on whether only one or both licenses apply to your
+usage of this library.
+
+Note that **each file** in this project individually has a code comment at the
+start describing the license of that particular file -- this is the most
+accurate license information of this project; in case there is any conflict
+between this document and the comment at the start of a file, the comment shall
+take precedence. The only purpose of this document is to work around [a known
+technical limitation of pkg.go.dev's license checking tool when dealing with
+non-trivial project licenses][go75067].
+
+[go75067]: https://go.dev/issue/75067
+
+### `BSD-3-Clause` ###
+
+At time of writing, the following files and directories are licensed under the
+BSD-3-Clause license:
+
+ * `doc.go`
+ * `join*.go`
+ * `vfs.go`
+ * `internal/consts/*.go`
+ * `pathrs-lite/internal/gocompat/*.go`
+ * `pathrs-lite/internal/kernelversion/*.go`
+
+The text of the BSD-3-Clause license used by this project is the following (the
+text is also available from the [`LICENSE.BSD`](./LICENSE.BSD) file):
+
+```
+Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+```
+
+### `MPL-2.0` ###
+
+All other files (unless otherwise marked) are licensed under the Mozilla Public
+License (version 2.0).
+
+The text of the Mozilla Public License (version 2.0) is the following (the text
+is also available from the [`LICENSE.MPL-2.0`](./LICENSE.MPL-2.0) file):
+
+```
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
+```
diff --git a/vendor/github.com/cyphar/filepath-securejoin/LICENSE.BSD b/vendor/github.com/cyphar/filepath-securejoin/LICENSE.BSD
new file mode 100644
index 0000000000..cb1ab88da0
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/LICENSE.BSD
@@ -0,0 +1,28 @@
+Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/cyphar/filepath-securejoin/LICENSE.MPL-2.0 b/vendor/github.com/cyphar/filepath-securejoin/LICENSE.MPL-2.0
new file mode 100644
index 0000000000..d0a1fa1482
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/LICENSE.MPL-2.0
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/cyphar/filepath-securejoin/README.md b/vendor/github.com/cyphar/filepath-securejoin/README.md
new file mode 100644
index 0000000000..6673abfc84
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/README.md
@@ -0,0 +1,184 @@
+## `filepath-securejoin` ##
+
+[](https://pkg.go.dev/github.com/cyphar/filepath-securejoin)
+[](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)
+
+### Old API ###
+
+This library was originally just an implementation of `SecureJoin` which was
+[intended to be included in the Go standard library][go#20126] as a safer
+`filepath.Join` that would restrict the path lookup to be inside a root
+directory.
+
+The implementation was based on code that existed in several container
+runtimes. Unfortunately, this API is **fundamentally unsafe** against attackers
+that can modify path components after `SecureJoin` returns and before the
+caller uses the path, allowing for some fairly trivial TOCTOU attacks.
+
+`SecureJoin` (and `SecureJoinVFS`) are still provided by this library to
+support legacy users, but new users are strongly suggested to avoid using
+`SecureJoin` and instead use the [new api](#new-api) or switch to
+[libpathrs][libpathrs].
+
+With the above limitations in mind, this library guarantees the following:
+
+* If no error is set, the resulting string **must** be a child path of
+ `root` and will not contain any symlink path components (they will all be
+ expanded).
+
+* When expanding symlinks, all symlink path components **must** be resolved
+ relative to the provided root. In particular, this can be considered a
+ userspace implementation of how `chroot(2)` operates on file paths. Note that
+ these symlinks will **not** be expanded lexically (`filepath.Clean` is not
+ called on the input before processing).
+
+* Non-existent path components are unaffected by `SecureJoin` (similar to
+ `filepath.EvalSymlinks`'s semantics).
+
+* The returned path will always be `filepath.Clean`ed and thus not contain any
+ `..` components.
+
+A (trivial) implementation of this function on GNU/Linux systems could be done
+with the following (note that this requires root privileges and is far more
+opaque than the implementation in this library, and also requires that
+`readlink` is inside the `root` path and is trustworthy):
+
+```go
+package securejoin
+
+import (
+ "os/exec"
+ "path/filepath"
+)
+
+func SecureJoin(root, unsafePath string) (string, error) {
+ unsafePath = string(filepath.Separator) + unsafePath
+ cmd := exec.Command("chroot", root,
+ "readlink", "--canonicalize-missing", "--no-newline", unsafePath)
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ return "", err
+ }
+ expanded := string(output)
+ return filepath.Join(root, expanded), nil
+}
+```
+
+[libpathrs]: https://github.com/openSUSE/libpathrs
+[go#20126]: https://github.com/golang/go/issues/20126
+
+### New API ###
+[#new-api]: #new-api
+
+While we recommend users switch to [libpathrs][libpathrs] as soon as it has a
+stable release, some methods implemented by libpathrs have been ported to this
+library to ease the transition. These APIs are only supported on Linux.
+
+These APIs are implemented such that `filepath-securejoin` will
+opportunistically use certain newer kernel APIs that make these operations far
+more secure. In particular:
+
+* All of the lookup operations will use [`openat2`][openat2.2] on new enough
+ kernels (Linux 5.6 or later) to restrict lookups through magic-links and
+ bind-mounts (for certain operations) and to make use of `RESOLVE_IN_ROOT` to
+ efficiently resolve symlinks within a rootfs.
+
+* The APIs provide hardening against a malicious `/proc` mount to either detect
+ or avoid being tricked by a `/proc` that is not legitimate. This is done
+ using [`openat2`][openat2.2] for all users, and privileged users will also be
+ further protected by using [`fsopen`][fsopen.2] and [`open_tree`][open_tree.2]
+ (Linux 5.2 or later).
+
+[openat2.2]: https://www.man7.org/linux/man-pages/man2/openat2.2.html
+[fsopen.2]: https://github.com/brauner/man-pages-md/blob/main/fsopen.md
+[open_tree.2]: https://github.com/brauner/man-pages-md/blob/main/open_tree.md
+
+#### `OpenInRoot` ####
+
+```go
+func OpenInRoot(root, unsafePath string) (*os.File, error)
+func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error)
+func Reopen(handle *os.File, flags int) (*os.File, error)
+```
+
+`OpenInRoot` is a much safer version of
+
+```go
+path, err := securejoin.SecureJoin(root, unsafePath)
+file, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC)
+```
+
+that protects against various race attacks that could lead to serious security
+issues, depending on the application. Note that the returned `*os.File` is an
+`O_PATH` file descriptor, which is quite restricted. Callers will probably need
+to use `Reopen` to get a more usable handle (this split is done to provide
+useful features like PTY spawning and to avoid users accidentally opening bad
+inodes that could cause a DoS).
+
+Callers need to be careful in how they use the returned `*os.File`. Usually it
+is only safe to operate on the handle directly, and it is very easy to create a
+security issue. [libpathrs][libpathrs] provides far more helpers to make using
+these handles safer -- there is currently no plan to port them to
+`filepath-securejoin`.
+
+`OpenatInRoot` is like `OpenInRoot` except that the root is provided using an
+`*os.File`. This allows you to ensure that multiple `OpenatInRoot` (or
+`MkdirAllHandle`) calls are operating on the same rootfs.
+
+> **NOTE**: Unlike `SecureJoin`, `OpenInRoot` will error out as soon as it hits
+> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
+> which treated non-existent components as though they were real directories,
+> and would allow for partial resolution of dangling symlinks. These behaviours
+> are at odds with how Linux treats non-existent paths and dangling symlinks,
+> and so these are no longer allowed.
+
+#### `MkdirAll` ####
+
+```go
+func MkdirAll(root, unsafePath string, mode int) error
+func MkdirAllHandle(root *os.File, unsafePath string, mode int) (*os.File, error)
+```
+
+`MkdirAll` is a much safer version of
+
+```go
+path, err := securejoin.SecureJoin(root, unsafePath)
+err = os.MkdirAll(path, mode)
+```
+
+that protects against the same kinds of races that `OpenInRoot` protects
+against.
+
+`MkdirAllHandle` is like `MkdirAll` except that the root is provided using an
+`*os.File` (the reason for this is the same as with `OpenatInRoot`) and an
+`*os.File` of the final created directory is returned (this directory is
+guaranteed to be effectively identical to the directory created by
+`MkdirAllHandle`, which is not possible to ensure by just using `OpenatInRoot`
+after `MkdirAll`).
+
+> **NOTE**: Unlike `SecureJoin`, `MkdirAll` will error out as soon as it hits
+> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
+> which treated non-existent components as though they were real directories,
+> and would allow for partial resolution of dangling symlinks. These behaviours
+> are at odds with how Linux treats non-existent paths and dangling symlinks,
+> and so these are no longer allowed. This means that `MkdirAll` will not
+> create non-existent directories referenced by a dangling symlink.
+
+### License ###
+
+`SPDX-License-Identifier: BSD-3-Clause AND MPL-2.0`
+
+Some of the code in this project is derived from Go, and is licensed under a
+BSD 3-clause license (available in `LICENSE.BSD`). Other files (many of which
+are derived from [libpathrs][libpathrs]) are licensed under the Mozilla Public
+License version 2.0 (available in `LICENSE.MPL-2.0`). If you are using the
+["New API" described above][#new-api], you are probably using code from files
+released under this license.
+
+Every source file in this project has a copyright header describing its
+license. Please check the license headers of each file to see what license
+applies to it.
+
+See [COPYING.md](./COPYING.md) for some more details.
+
+[umoci]: https://github.com/opencontainers/umoci
diff --git a/vendor/github.com/cyphar/filepath-securejoin/VERSION b/vendor/github.com/cyphar/filepath-securejoin/VERSION
new file mode 100644
index 0000000000..ee6cdce3c2
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/VERSION
@@ -0,0 +1 @@
+0.6.1
diff --git a/vendor/github.com/cyphar/filepath-securejoin/codecov.yml b/vendor/github.com/cyphar/filepath-securejoin/codecov.yml
new file mode 100644
index 0000000000..ff284dbfaf
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/codecov.yml
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: MPL-2.0
+
+# Copyright (C) 2025 Aleksa Sarai
+# Copyright (C) 2025 SUSE LLC
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+comment:
+ layout: "condensed_header, reach, diff, components, condensed_files, condensed_footer"
+ require_changes: true
+ branches:
+ - main
+
+coverage:
+ range: 60..100
+ status:
+ project:
+ default:
+ target: 85%
+ threshold: 0%
+ patch:
+ default:
+ target: auto
+ informational: true
+
+github_checks:
+ annotations: false
diff --git a/vendor/github.com/cyphar/filepath-securejoin/doc.go b/vendor/github.com/cyphar/filepath-securejoin/doc.go
new file mode 100644
index 0000000000..1438fc9c09
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/doc.go
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package securejoin implements a set of helpers to make it easier to write Go
+// code that is safe against symlink-related escape attacks. The primary idea
+// is to let you resolve a path within a rootfs directory as if the rootfs was
+// a chroot.
+//
+// securejoin has two APIs, a "legacy" API and a "modern" API.
+//
+// The legacy API is [SecureJoin] and [SecureJoinVFS]. These methods are
+// **not** safe against race conditions where an attacker changes the
+// filesystem after (or during) the [SecureJoin] operation.
+//
+// The new API is available in the [pathrs-lite] subpackage, and provide
+// protections against racing attackers as well as several other key
+// protections against attacks often seen by container runtimes. As the name
+// suggests, [pathrs-lite] is a stripped down (pure Go) reimplementation of
+// [libpathrs]. The main APIs provided are [OpenInRoot], [MkdirAll], and
+// [procfs.Handle] -- other APIs are not planned to be ported. The long-term
+// goal is for users to migrate to [libpathrs] which is more fully-featured.
+//
+// securejoin has been used by several container runtimes (Docker, runc,
+// Kubernetes, etc) for quite a few years as a de-facto standard for operating
+// on container filesystem paths "safely". However, most users still use the
+// legacy API which is unsafe against various attacks (there is a fairly long
+// history of CVEs in dependent as a result). Users should switch to the modern
+// API as soon as possible (or even better, switch to libpathrs).
+//
+// This project was initially intended to be included in the Go standard
+// library, but it was rejected (see https://go.dev/issue/20126). Much later,
+// [os.Root] was added to the Go stdlib that shares some of the goals of
+// filepath-securejoin. However, its design is intended to work like
+// openat2(RESOLVE_BENEATH) which does not fit the usecase of container
+// runtimes and most system tools.
+//
+// [pathrs-lite]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin/pathrs-lite
+// [libpathrs]: https://github.com/openSUSE/libpathrs
+// [OpenInRoot]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin/pathrs-lite#OpenInRoot
+// [MkdirAll]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin/pathrs-lite#MkdirAll
+// [procfs.Handle]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs#Handle
+// [os.Root]: https:///pkg.go.dev/os#Root
+package securejoin
diff --git a/vendor/github.com/cyphar/filepath-securejoin/internal/consts/consts.go b/vendor/github.com/cyphar/filepath-securejoin/internal/consts/consts.go
new file mode 100644
index 0000000000..c69c4da91e
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/internal/consts/consts.go
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+// Copyright (C) 2017-2025 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package consts contains the definitions of internal constants used
+// throughout filepath-securejoin.
+package consts
+
+// MaxSymlinkLimit is the maximum number of symlinks that can be encountered
+// during a single lookup before returning -ELOOP. At time of writing, Linux
+// has an internal limit of 40.
+const MaxSymlinkLimit = 255
diff --git a/vendor/github.com/cyphar/filepath-securejoin/join.go b/vendor/github.com/cyphar/filepath-securejoin/join.go
new file mode 100644
index 0000000000..199c1d8392
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/join.go
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+// Copyright (C) 2017-2025 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "strings"
+ "syscall"
+
+ "github.com/cyphar/filepath-securejoin/internal/consts"
+)
+
+// IsNotExist tells you if err is an error that implies that either the path
+// accessed does not exist (or path components don't exist). This is
+// effectively a more broad version of [os.IsNotExist].
+func IsNotExist(err error) bool {
+ // Check that it's not actually an ENOTDIR, which in some cases is a more
+ // convoluted case of ENOENT (usually involving weird paths).
+ return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) || errors.Is(err, syscall.ENOENT)
+}
+
+// errUnsafeRoot is returned if the user provides SecureJoinVFS with a path
+// that contains ".." components.
+var errUnsafeRoot = errors.New("root path provided to SecureJoin contains '..' components")
+
+// stripVolume just gets rid of the Windows volume included in a path. Based on
+// some godbolt tests, the Go compiler is smart enough to make this a no-op on
+// Linux.
+func stripVolume(path string) string {
+ return path[len(filepath.VolumeName(path)):]
+}
+
+// hasDotDot checks if the path contains ".." components in a platform-agnostic
+// way.
+func hasDotDot(path string) bool {
+ // If we are on Windows, strip any volume letters. It turns out that
+ // C:..\foo may (or may not) be a valid pathname and we need to handle that
+ // leading "..".
+ path = stripVolume(path)
+ // Look for "/../" in the path, but we need to handle leading and trailing
+ // ".."s by adding separators. Doing this with filepath.Separator is ugly
+ // so just convert to Unix-style "/" first.
+ path = filepath.ToSlash(path)
+ return strings.Contains("/"+path+"/", "/../")
+}
+
+// SecureJoinVFS joins the two given path components (similar to
+// [filepath.Join]) except that the returned path is guaranteed to be scoped
+// inside the provided root path (when evaluated). Any symbolic links in the
+// path are evaluated with the given root treated as the root of the
+// filesystem, similar to a chroot. The filesystem state is evaluated through
+// the given [VFS] interface (if nil, the standard [os].* family of functions
+// are used).
+//
+// Note that the guarantees provided by this function only apply if the path
+// components in the returned string are not modified (in other words are not
+// replaced with symlinks on the filesystem) after this function has returned.
+// Such a symlink race is necessarily out-of-scope of SecureJoinVFS.
+//
+// NOTE: Due to the above limitation, Linux users are strongly encouraged to
+// use [OpenInRoot] instead, which does safely protect against these kinds of
+// attacks. There is no way to solve this problem with SecureJoinVFS because
+// the API is fundamentally wrong (you cannot return a "safe" path string and
+// guarantee it won't be modified afterwards).
+//
+// Volume names in unsafePath are always discarded, regardless if they are
+// provided via direct input or when evaluating symlinks. Therefore:
+//
+// "C:\Temp" + "D:\path\to\file.txt" results in "C:\Temp\path\to\file.txt"
+//
+// If the provided root is not [filepath.Clean] then an error will be returned,
+// as such root paths are bordering on somewhat unsafe and using such paths is
+// not best practice. We also strongly suggest that any root path is first
+// fully resolved using [filepath.EvalSymlinks] or otherwise constructed to
+// avoid containing symlink components. Of course, the root also *must not* be
+// attacker-controlled.
+func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) { //nolint:revive // name is part of public API
+ // The root path must not contain ".." components, otherwise when we join
+ // the subpath we will end up with a weird path. We could work around this
+ // in other ways but users shouldn't be giving us non-lexical root paths in
+ // the first place.
+ if hasDotDot(root) {
+ return "", errUnsafeRoot
+ }
+
+ // Use the os.* VFS implementation if none was specified.
+ if vfs == nil {
+ vfs = osVFS{}
+ }
+
+ unsafePath = filepath.FromSlash(unsafePath)
+ var (
+ currentPath string
+ remainingPath = unsafePath
+ linksWalked int
+ )
+ for remainingPath != "" {
+ // On Windows, if we managed to end up at a path referencing a volume,
+ // drop the volume to make sure we don't end up with broken paths or
+ // escaping the root volume.
+ remainingPath = stripVolume(remainingPath)
+
+ // Get the next path component.
+ var part string
+ if i := strings.IndexRune(remainingPath, filepath.Separator); i == -1 {
+ part, remainingPath = remainingPath, ""
+ } else {
+ part, remainingPath = remainingPath[:i], remainingPath[i+1:]
+ }
+
+ // Apply the component lexically to the path we are building.
+ // currentPath does not contain any symlinks, and we are lexically
+ // dealing with a single component, so it's okay to do a filepath.Clean
+ // here.
+ nextPath := filepath.Join(string(filepath.Separator), currentPath, part)
+ if nextPath == string(filepath.Separator) {
+ currentPath = ""
+ continue
+ }
+ fullPath := root + string(filepath.Separator) + nextPath
+
+ // Figure out whether the path is a symlink.
+ fi, err := vfs.Lstat(fullPath)
+ if err != nil && !IsNotExist(err) {
+ return "", err
+ }
+ // Treat non-existent path components the same as non-symlinks (we
+ // can't do any better here).
+ if IsNotExist(err) || fi.Mode()&os.ModeSymlink == 0 {
+ currentPath = nextPath
+ continue
+ }
+
+ // It's a symlink, so get its contents and expand it by prepending it
+ // to the yet-unparsed path.
+ linksWalked++
+ if linksWalked > consts.MaxSymlinkLimit {
+ return "", &os.PathError{Op: "SecureJoin", Path: root + string(filepath.Separator) + unsafePath, Err: syscall.ELOOP}
+ }
+
+ dest, err := vfs.Readlink(fullPath)
+ if err != nil {
+ return "", err
+ }
+ remainingPath = dest + string(filepath.Separator) + remainingPath
+ // Absolute symlinks reset any work we've already done.
+ if filepath.IsAbs(dest) {
+ currentPath = ""
+ }
+ }
+
+ // There should be no lexical components like ".." left in the path here,
+ // but for safety clean up the path before joining it to the root.
+ finalPath := filepath.Join(string(filepath.Separator), currentPath)
+ return filepath.Join(root, finalPath), nil
+}
+
+// SecureJoin is a wrapper around [SecureJoinVFS] that just uses the [os].* library
+// of functions as the [VFS]. If in doubt, use this function over [SecureJoinVFS].
+func SecureJoin(root, unsafePath string) (string, error) {
+ return SecureJoinVFS(root, unsafePath, nil)
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/vfs.go b/vendor/github.com/cyphar/filepath-securejoin/vfs.go
new file mode 100644
index 0000000000..4d89a481ca
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/vfs.go
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import "os"
+
+// In future this should be moved into a separate package, because now there
+// are several projects (umoci and go-mtree) that are using this sort of
+// interface.
+
+// VFS is the minimal interface necessary to use [SecureJoinVFS]. A nil VFS is
+// equivalent to using the standard [os].* family of functions. This is mainly
+// used for the purposes of mock testing, but also can be used to otherwise use
+// [SecureJoinVFS] with VFS-like system.
+type VFS interface {
+ // Lstat returns an [os.FileInfo] describing the named file. If the
+ // file is a symbolic link, the returned [os.FileInfo] describes the
+ // symbolic link. Lstat makes no attempt to follow the link.
+ // The semantics are identical to [os.Lstat].
+ Lstat(name string) (os.FileInfo, error)
+
+ // Readlink returns the destination of the named symbolic link.
+ // The semantics are identical to [os.Readlink].
+ Readlink(name string) (string, error)
+}
+
+// osVFS is the "nil" VFS, in that it just passes everything through to the os
+// module.
+type osVFS struct{}
+
+func (o osVFS) Lstat(name string) (os.FileInfo, error) { return os.Lstat(name) }
+
+func (o osVFS) Readlink(name string) (string, error) { return os.Readlink(name) }
diff --git a/vendor/github.com/distribution/distribution/v3/LICENSE b/vendor/github.com/distribution/distribution/v3/LICENSE
deleted file mode 100644
index e06d208186..0000000000
--- a/vendor/github.com/distribution/distribution/v3/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- 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.
-
diff --git a/vendor/github.com/distribution/distribution/v3/digestset/set.go b/vendor/github.com/distribution/distribution/v3/digestset/set.go
deleted file mode 100644
index 71327dca72..0000000000
--- a/vendor/github.com/distribution/distribution/v3/digestset/set.go
+++ /dev/null
@@ -1,247 +0,0 @@
-package digestset
-
-import (
- "errors"
- "sort"
- "strings"
- "sync"
-
- digest "github.com/opencontainers/go-digest"
-)
-
-var (
- // ErrDigestNotFound is used when a matching digest
- // could not be found in a set.
- ErrDigestNotFound = errors.New("digest not found")
-
- // ErrDigestAmbiguous is used when multiple digests
- // are found in a set. None of the matching digests
- // should be considered valid matches.
- ErrDigestAmbiguous = errors.New("ambiguous digest string")
-)
-
-// Set is used to hold a unique set of digests which
-// may be easily referenced by easily referenced by a string
-// representation of the digest as well as short representation.
-// The uniqueness of the short representation is based on other
-// digests in the set. If digests are omitted from this set,
-// collisions in a larger set may not be detected, therefore it
-// is important to always do short representation lookups on
-// the complete set of digests. To mitigate collisions, an
-// appropriately long short code should be used.
-type Set struct {
- mutex sync.RWMutex
- entries digestEntries
-}
-
-// NewSet creates an empty set of digests
-// which may have digests added.
-func NewSet() *Set {
- return &Set{
- entries: digestEntries{},
- }
-}
-
-// checkShortMatch checks whether two digests match as either whole
-// values or short values. This function does not test equality,
-// rather whether the second value could match against the first
-// value.
-func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool {
- if len(hex) == len(shortHex) {
- if hex != shortHex {
- return false
- }
- if len(shortAlg) > 0 && string(alg) != shortAlg {
- return false
- }
- } else if !strings.HasPrefix(hex, shortHex) {
- return false
- } else if len(shortAlg) > 0 && string(alg) != shortAlg {
- return false
- }
- return true
-}
-
-// Lookup looks for a digest matching the given string representation.
-// If no digests could be found ErrDigestNotFound will be returned
-// with an empty digest value. If multiple matches are found
-// ErrDigestAmbiguous will be returned with an empty digest value.
-func (dst *Set) Lookup(d string) (digest.Digest, error) {
- dst.mutex.RLock()
- defer dst.mutex.RUnlock()
- if len(dst.entries) == 0 {
- return "", ErrDigestNotFound
- }
- var (
- searchFunc func(int) bool
- alg digest.Algorithm
- hex string
- )
- dgst, err := digest.Parse(d)
- if err == digest.ErrDigestInvalidFormat {
- hex = d
- searchFunc = func(i int) bool {
- return dst.entries[i].val >= d
- }
- } else {
- hex = dgst.Hex()
- alg = dgst.Algorithm()
- searchFunc = func(i int) bool {
- if dst.entries[i].val == hex {
- return dst.entries[i].alg >= alg
- }
- return dst.entries[i].val >= hex
- }
- }
- idx := sort.Search(len(dst.entries), searchFunc)
- if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) {
- return "", ErrDigestNotFound
- }
- if dst.entries[idx].alg == alg && dst.entries[idx].val == hex {
- return dst.entries[idx].digest, nil
- }
- if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) {
- return "", ErrDigestAmbiguous
- }
-
- return dst.entries[idx].digest, nil
-}
-
-// Add adds the given digest to the set. An error will be returned
-// if the given digest is invalid. If the digest already exists in the
-// set, this operation will be a no-op.
-func (dst *Set) Add(d digest.Digest) error {
- if err := d.Validate(); err != nil {
- return err
- }
- dst.mutex.Lock()
- defer dst.mutex.Unlock()
- entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d}
- searchFunc := func(i int) bool {
- if dst.entries[i].val == entry.val {
- return dst.entries[i].alg >= entry.alg
- }
- return dst.entries[i].val >= entry.val
- }
- idx := sort.Search(len(dst.entries), searchFunc)
- if idx == len(dst.entries) {
- dst.entries = append(dst.entries, entry)
- return nil
- } else if dst.entries[idx].digest == d {
- return nil
- }
-
- entries := append(dst.entries, nil)
- copy(entries[idx+1:], entries[idx:len(entries)-1])
- entries[idx] = entry
- dst.entries = entries
- return nil
-}
-
-// Remove removes the given digest from the set. An err will be
-// returned if the given digest is invalid. If the digest does
-// not exist in the set, this operation will be a no-op.
-func (dst *Set) Remove(d digest.Digest) error {
- if err := d.Validate(); err != nil {
- return err
- }
- dst.mutex.Lock()
- defer dst.mutex.Unlock()
- entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d}
- searchFunc := func(i int) bool {
- if dst.entries[i].val == entry.val {
- return dst.entries[i].alg >= entry.alg
- }
- return dst.entries[i].val >= entry.val
- }
- idx := sort.Search(len(dst.entries), searchFunc)
- // Not found if idx is after or value at idx is not digest
- if idx == len(dst.entries) || dst.entries[idx].digest != d {
- return nil
- }
-
- entries := dst.entries
- copy(entries[idx:], entries[idx+1:])
- entries = entries[:len(entries)-1]
- dst.entries = entries
-
- return nil
-}
-
-// All returns all the digests in the set
-func (dst *Set) All() []digest.Digest {
- dst.mutex.RLock()
- defer dst.mutex.RUnlock()
- retValues := make([]digest.Digest, len(dst.entries))
- for i := range dst.entries {
- retValues[i] = dst.entries[i].digest
- }
-
- return retValues
-}
-
-// ShortCodeTable returns a map of Digest to unique short codes. The
-// length represents the minimum value, the maximum length may be the
-// entire value of digest if uniqueness cannot be achieved without the
-// full value. This function will attempt to make short codes as short
-// as possible to be unique.
-func ShortCodeTable(dst *Set, length int) map[digest.Digest]string {
- dst.mutex.RLock()
- defer dst.mutex.RUnlock()
- m := make(map[digest.Digest]string, len(dst.entries))
- l := length
- resetIdx := 0
- for i := 0; i < len(dst.entries); i++ {
- var short string
- extended := true
- for extended {
- extended = false
- if len(dst.entries[i].val) <= l {
- short = dst.entries[i].digest.String()
- } else {
- short = dst.entries[i].val[:l]
- for j := i + 1; j < len(dst.entries); j++ {
- if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) {
- if j > resetIdx {
- resetIdx = j
- }
- extended = true
- } else {
- break
- }
- }
- if extended {
- l++
- }
- }
- }
- m[dst.entries[i].digest] = short
- if i >= resetIdx {
- l = length
- }
- }
- return m
-}
-
-type digestEntry struct {
- alg digest.Algorithm
- val string
- digest digest.Digest
-}
-
-type digestEntries []*digestEntry
-
-func (d digestEntries) Len() int {
- return len(d)
-}
-
-func (d digestEntries) Less(i, j int) bool {
- if d[i].val != d[j].val {
- return d[i].val < d[j].val
- }
- return d[i].alg < d[j].alg
-}
-
-func (d digestEntries) Swap(i, j int) {
- d[i], d[j] = d[j], d[i]
-}
diff --git a/vendor/github.com/distribution/distribution/v3/reference/helpers.go b/vendor/github.com/distribution/distribution/v3/reference/helpers.go
deleted file mode 100644
index 978df7eabb..0000000000
--- a/vendor/github.com/distribution/distribution/v3/reference/helpers.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package reference
-
-import "path"
-
-// IsNameOnly returns true if reference only contains a repo name.
-func IsNameOnly(ref Named) bool {
- if _, ok := ref.(NamedTagged); ok {
- return false
- }
- if _, ok := ref.(Canonical); ok {
- return false
- }
- return true
-}
-
-// FamiliarName returns the familiar name string
-// for the given named, familiarizing if needed.
-func FamiliarName(ref Named) string {
- if nn, ok := ref.(normalizedNamed); ok {
- return nn.Familiar().Name()
- }
- return ref.Name()
-}
-
-// FamiliarString returns the familiar string representation
-// for the given reference, familiarizing if needed.
-func FamiliarString(ref Reference) string {
- if nn, ok := ref.(normalizedNamed); ok {
- return nn.Familiar().String()
- }
- return ref.String()
-}
-
-// FamiliarMatch reports whether ref matches the specified pattern.
-// See https://godoc.org/path#Match for supported patterns.
-func FamiliarMatch(pattern string, ref Reference) (bool, error) {
- matched, err := path.Match(pattern, FamiliarString(ref))
- if namedRef, isNamed := ref.(Named); isNamed && !matched {
- matched, _ = path.Match(pattern, FamiliarName(namedRef))
- }
- return matched, err
-}
diff --git a/vendor/github.com/distribution/distribution/v3/reference/normalize.go b/vendor/github.com/distribution/distribution/v3/reference/normalize.go
deleted file mode 100644
index e7a1f9b528..0000000000
--- a/vendor/github.com/distribution/distribution/v3/reference/normalize.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package reference
-
-import (
- "fmt"
- "strings"
-
- "github.com/distribution/distribution/v3/digestset"
- "github.com/opencontainers/go-digest"
-)
-
-var (
- legacyDefaultDomain = "index.docker.io"
- defaultDomain = "docker.io"
- officialRepoName = "library"
- defaultTag = "latest"
-)
-
-// normalizedNamed represents a name which has been
-// normalized and has a familiar form. A familiar name
-// is what is used in Docker UI. An example normalized
-// name is "docker.io/library/ubuntu" and corresponding
-// familiar name of "ubuntu".
-type normalizedNamed interface {
- Named
- Familiar() Named
-}
-
-// ParseNormalizedNamed parses a string into a named reference
-// transforming a familiar name from Docker UI to a fully
-// qualified reference. If the value may be an identifier
-// use ParseAnyReference.
-func ParseNormalizedNamed(s string) (Named, error) {
- if ok := anchoredIdentifierRegexp.MatchString(s); ok {
- return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
- }
- domain, remainder := splitDockerDomain(s)
- var remoteName string
- if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 {
- remoteName = remainder[:tagSep]
- } else {
- remoteName = remainder
- }
- if strings.ToLower(remoteName) != remoteName {
- return nil, fmt.Errorf("invalid reference format: repository name (%s) must be lowercase", remoteName)
- }
-
- ref, err := Parse(domain + "/" + remainder)
- if err != nil {
- return nil, err
- }
- named, isNamed := ref.(Named)
- if !isNamed {
- return nil, fmt.Errorf("reference %s has no name", ref.String())
- }
- return named, nil
-}
-
-// ParseDockerRef normalizes the image reference following the docker convention. This is added
-// mainly for backward compatibility.
-// The reference returned can only be either tagged or digested. For reference contains both tag
-// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@
-// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as
-// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa.
-func ParseDockerRef(ref string) (Named, error) {
- named, err := ParseNormalizedNamed(ref)
- if err != nil {
- return nil, err
- }
- if _, ok := named.(NamedTagged); ok {
- if canonical, ok := named.(Canonical); ok {
- // The reference is both tagged and digested, only
- // return digested.
- newNamed, err := WithName(canonical.Name())
- if err != nil {
- return nil, err
- }
- newCanonical, err := WithDigest(newNamed, canonical.Digest())
- if err != nil {
- return nil, err
- }
- return newCanonical, nil
- }
- }
- return TagNameOnly(named), nil
-}
-
-// splitDockerDomain splits a repository name to domain and remotename string.
-// If no valid domain is found, the default domain is used. Repository name
-// needs to be already validated before.
-func splitDockerDomain(name string) (domain, remainder string) {
- i := strings.IndexRune(name, '/')
- if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost" && strings.ToLower(name[:i]) == name[:i]) {
- domain, remainder = defaultDomain, name
- } else {
- domain, remainder = name[:i], name[i+1:]
- }
- if domain == legacyDefaultDomain {
- domain = defaultDomain
- }
- if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
- remainder = officialRepoName + "/" + remainder
- }
- return
-}
-
-// familiarizeName returns a shortened version of the name familiar
-// to to the Docker UI. Familiar names have the default domain
-// "docker.io" and "library/" repository prefix removed.
-// For example, "docker.io/library/redis" will have the familiar
-// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp".
-// Returns a familiarized named only reference.
-func familiarizeName(named namedRepository) repository {
- repo := repository{
- domain: named.Domain(),
- path: named.Path(),
- }
-
- if repo.domain == defaultDomain {
- repo.domain = ""
- // Handle official repositories which have the pattern "library/"
- if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName {
- repo.path = split[1]
- }
- }
- return repo
-}
-
-func (r reference) Familiar() Named {
- return reference{
- namedRepository: familiarizeName(r.namedRepository),
- tag: r.tag,
- digest: r.digest,
- }
-}
-
-func (r repository) Familiar() Named {
- return familiarizeName(r)
-}
-
-func (t taggedReference) Familiar() Named {
- return taggedReference{
- namedRepository: familiarizeName(t.namedRepository),
- tag: t.tag,
- }
-}
-
-func (c canonicalReference) Familiar() Named {
- return canonicalReference{
- namedRepository: familiarizeName(c.namedRepository),
- digest: c.digest,
- }
-}
-
-// TagNameOnly adds the default tag "latest" to a reference if it only has
-// a repo name.
-func TagNameOnly(ref Named) Named {
- if IsNameOnly(ref) {
- namedTagged, err := WithTag(ref, defaultTag)
- if err != nil {
- // Default tag must be valid, to create a NamedTagged
- // type with non-validated input the WithTag function
- // should be used instead
- panic(err)
- }
- return namedTagged
- }
- return ref
-}
-
-// ParseAnyReference parses a reference string as a possible identifier,
-// full digest, or familiar name.
-func ParseAnyReference(ref string) (Reference, error) {
- if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
- return digestReference("sha256:" + ref), nil
- }
- if dgst, err := digest.Parse(ref); err == nil {
- return digestReference(dgst), nil
- }
-
- return ParseNormalizedNamed(ref)
-}
-
-// ParseAnyReferenceWithSet parses a reference string as a possible short
-// identifier to be matched in a digest set, a full digest, or familiar name.
-func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) {
- if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok {
- dgst, err := ds.Lookup(ref)
- if err == nil {
- return digestReference(dgst), nil
- }
- } else {
- if dgst, err := digest.Parse(ref); err == nil {
- return digestReference(dgst), nil
- }
- }
-
- return ParseNormalizedNamed(ref)
-}
diff --git a/vendor/github.com/distribution/distribution/v3/reference/reference.go b/vendor/github.com/distribution/distribution/v3/reference/reference.go
deleted file mode 100644
index 8c0c23b2fe..0000000000
--- a/vendor/github.com/distribution/distribution/v3/reference/reference.go
+++ /dev/null
@@ -1,433 +0,0 @@
-// Package reference provides a general type to represent any way of referencing images within the registry.
-// Its main purpose is to abstract tags and digests (content-addressable hash).
-//
-// Grammar
-//
-// reference := name [ ":" tag ] [ "@" digest ]
-// name := [domain '/'] path-component ['/' path-component]*
-// domain := domain-component ['.' domain-component]* [':' port-number]
-// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
-// port-number := /[0-9]+/
-// path-component := alpha-numeric [separator alpha-numeric]*
-// alpha-numeric := /[a-z0-9]+/
-// separator := /[_.]|__|[-]*/
-//
-// tag := /[\w][\w.-]{0,127}/
-//
-// digest := digest-algorithm ":" digest-hex
-// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
-// digest-algorithm-separator := /[+.-_]/
-// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
-// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
-//
-// identifier := /[a-f0-9]{64}/
-// short-identifier := /[a-f0-9]{6,64}/
-package reference
-
-import (
- "errors"
- "fmt"
- "strings"
-
- "github.com/opencontainers/go-digest"
-)
-
-const (
- // NameTotalLengthMax is the maximum total number of characters in a repository name.
- NameTotalLengthMax = 255
-)
-
-var (
- // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference.
- ErrReferenceInvalidFormat = errors.New("invalid reference format")
-
- // ErrTagInvalidFormat represents an error while trying to parse a string as a tag.
- ErrTagInvalidFormat = errors.New("invalid tag format")
-
- // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag.
- ErrDigestInvalidFormat = errors.New("invalid digest format")
-
- // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters.
- ErrNameContainsUppercase = errors.New("repository name must be lowercase")
-
- // ErrNameEmpty is returned for empty, invalid repository names.
- ErrNameEmpty = errors.New("repository name must have at least one component")
-
- // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
- ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
-
- // ErrNameNotCanonical is returned when a name is not canonical.
- ErrNameNotCanonical = errors.New("repository name must be canonical")
-)
-
-// Reference is an opaque object reference identifier that may include
-// modifiers such as a hostname, name, tag, and digest.
-type Reference interface {
- // String returns the full reference
- String() string
-}
-
-// Field provides a wrapper type for resolving correct reference types when
-// working with encoding.
-type Field struct {
- reference Reference
-}
-
-// AsField wraps a reference in a Field for encoding.
-func AsField(reference Reference) Field {
- return Field{reference}
-}
-
-// Reference unwraps the reference type from the field to
-// return the Reference object. This object should be
-// of the appropriate type to further check for different
-// reference types.
-func (f Field) Reference() Reference {
- return f.reference
-}
-
-// MarshalText serializes the field to byte text which
-// is the string of the reference.
-func (f Field) MarshalText() (p []byte, err error) {
- return []byte(f.reference.String()), nil
-}
-
-// UnmarshalText parses text bytes by invoking the
-// reference parser to ensure the appropriately
-// typed reference object is wrapped by field.
-func (f *Field) UnmarshalText(p []byte) error {
- r, err := Parse(string(p))
- if err != nil {
- return err
- }
-
- f.reference = r
- return nil
-}
-
-// Named is an object with a full name
-type Named interface {
- Reference
- Name() string
-}
-
-// Tagged is an object which has a tag
-type Tagged interface {
- Reference
- Tag() string
-}
-
-// NamedTagged is an object including a name and tag.
-type NamedTagged interface {
- Named
- Tag() string
-}
-
-// Digested is an object which has a digest
-// in which it can be referenced by
-type Digested interface {
- Reference
- Digest() digest.Digest
-}
-
-// Canonical reference is an object with a fully unique
-// name including a name with domain and digest
-type Canonical interface {
- Named
- Digest() digest.Digest
-}
-
-// namedRepository is a reference to a repository with a name.
-// A namedRepository has both domain and path components.
-type namedRepository interface {
- Named
- Domain() string
- Path() string
-}
-
-// Domain returns the domain part of the Named reference
-func Domain(named Named) string {
- if r, ok := named.(namedRepository); ok {
- return r.Domain()
- }
- domain, _ := splitDomain(named.Name())
- return domain
-}
-
-// Path returns the name without the domain part of the Named reference
-func Path(named Named) (name string) {
- if r, ok := named.(namedRepository); ok {
- return r.Path()
- }
- _, path := splitDomain(named.Name())
- return path
-}
-
-func splitDomain(name string) (string, string) {
- match := anchoredNameRegexp.FindStringSubmatch(name)
- if len(match) != 3 {
- return "", name
- }
- return match[1], match[2]
-}
-
-// SplitHostname splits a named reference into a
-// hostname and name string. If no valid hostname is
-// found, the hostname is empty and the full value
-// is returned as name
-// DEPRECATED: Use Domain or Path
-func SplitHostname(named Named) (string, string) {
- if r, ok := named.(namedRepository); ok {
- return r.Domain(), r.Path()
- }
- return splitDomain(named.Name())
-}
-
-// Parse parses s and returns a syntactically valid Reference.
-// If an error was encountered it is returned, along with a nil Reference.
-// NOTE: Parse will not handle short digests.
-func Parse(s string) (Reference, error) {
- matches := ReferenceRegexp.FindStringSubmatch(s)
- if matches == nil {
- if s == "" {
- return nil, ErrNameEmpty
- }
- if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil {
- return nil, ErrNameContainsUppercase
- }
- return nil, ErrReferenceInvalidFormat
- }
-
- if len(matches[1]) > NameTotalLengthMax {
- return nil, ErrNameTooLong
- }
-
- var repo repository
-
- nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])
- if len(nameMatch) == 3 {
- repo.domain = nameMatch[1]
- repo.path = nameMatch[2]
- } else {
- repo.domain = ""
- repo.path = matches[1]
- }
-
- ref := reference{
- namedRepository: repo,
- tag: matches[2],
- }
- if matches[3] != "" {
- var err error
- ref.digest, err = digest.Parse(matches[3])
- if err != nil {
- return nil, err
- }
- }
-
- r := getBestReferenceType(ref)
- if r == nil {
- return nil, ErrNameEmpty
- }
-
- return r, nil
-}
-
-// ParseNamed parses s and returns a syntactically valid reference implementing
-// the Named interface. The reference must have a name and be in the canonical
-// form, otherwise an error is returned.
-// If an error was encountered it is returned, along with a nil Reference.
-// NOTE: ParseNamed will not handle short digests.
-func ParseNamed(s string) (Named, error) {
- named, err := ParseNormalizedNamed(s)
- if err != nil {
- return nil, err
- }
- if named.String() != s {
- return nil, ErrNameNotCanonical
- }
- return named, nil
-}
-
-// WithName returns a named object representing the given string. If the input
-// is invalid ErrReferenceInvalidFormat will be returned.
-func WithName(name string) (Named, error) {
- if len(name) > NameTotalLengthMax {
- return nil, ErrNameTooLong
- }
-
- match := anchoredNameRegexp.FindStringSubmatch(name)
- if match == nil || len(match) != 3 {
- return nil, ErrReferenceInvalidFormat
- }
- return repository{
- domain: match[1],
- path: match[2],
- }, nil
-}
-
-// WithTag combines the name from "name" and the tag from "tag" to form a
-// reference incorporating both the name and the tag.
-func WithTag(name Named, tag string) (NamedTagged, error) {
- if !anchoredTagRegexp.MatchString(tag) {
- return nil, ErrTagInvalidFormat
- }
- var repo repository
- if r, ok := name.(namedRepository); ok {
- repo.domain = r.Domain()
- repo.path = r.Path()
- } else {
- repo.path = name.Name()
- }
- if canonical, ok := name.(Canonical); ok {
- return reference{
- namedRepository: repo,
- tag: tag,
- digest: canonical.Digest(),
- }, nil
- }
- return taggedReference{
- namedRepository: repo,
- tag: tag,
- }, nil
-}
-
-// WithDigest combines the name from "name" and the digest from "digest" to form
-// a reference incorporating both the name and the digest.
-func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
- if !anchoredDigestRegexp.MatchString(digest.String()) {
- return nil, ErrDigestInvalidFormat
- }
- var repo repository
- if r, ok := name.(namedRepository); ok {
- repo.domain = r.Domain()
- repo.path = r.Path()
- } else {
- repo.path = name.Name()
- }
- if tagged, ok := name.(Tagged); ok {
- return reference{
- namedRepository: repo,
- tag: tagged.Tag(),
- digest: digest,
- }, nil
- }
- return canonicalReference{
- namedRepository: repo,
- digest: digest,
- }, nil
-}
-
-// TrimNamed removes any tag or digest from the named reference.
-func TrimNamed(ref Named) Named {
- domain, path := SplitHostname(ref)
- return repository{
- domain: domain,
- path: path,
- }
-}
-
-func getBestReferenceType(ref reference) Reference {
- if ref.Name() == "" {
- // Allow digest only references
- if ref.digest != "" {
- return digestReference(ref.digest)
- }
- return nil
- }
- if ref.tag == "" {
- if ref.digest != "" {
- return canonicalReference{
- namedRepository: ref.namedRepository,
- digest: ref.digest,
- }
- }
- return ref.namedRepository
- }
- if ref.digest == "" {
- return taggedReference{
- namedRepository: ref.namedRepository,
- tag: ref.tag,
- }
- }
-
- return ref
-}
-
-type reference struct {
- namedRepository
- tag string
- digest digest.Digest
-}
-
-func (r reference) String() string {
- return r.Name() + ":" + r.tag + "@" + r.digest.String()
-}
-
-func (r reference) Tag() string {
- return r.tag
-}
-
-func (r reference) Digest() digest.Digest {
- return r.digest
-}
-
-type repository struct {
- domain string
- path string
-}
-
-func (r repository) String() string {
- return r.Name()
-}
-
-func (r repository) Name() string {
- if r.domain == "" {
- return r.path
- }
- return r.domain + "/" + r.path
-}
-
-func (r repository) Domain() string {
- return r.domain
-}
-
-func (r repository) Path() string {
- return r.path
-}
-
-type digestReference digest.Digest
-
-func (d digestReference) String() string {
- return digest.Digest(d).String()
-}
-
-func (d digestReference) Digest() digest.Digest {
- return digest.Digest(d)
-}
-
-type taggedReference struct {
- namedRepository
- tag string
-}
-
-func (t taggedReference) String() string {
- return t.Name() + ":" + t.tag
-}
-
-func (t taggedReference) Tag() string {
- return t.tag
-}
-
-type canonicalReference struct {
- namedRepository
- digest digest.Digest
-}
-
-func (c canonicalReference) String() string {
- return c.Name() + "@" + c.digest.String()
-}
-
-func (c canonicalReference) Digest() digest.Digest {
- return c.digest
-}
diff --git a/vendor/github.com/distribution/distribution/v3/reference/regexp.go b/vendor/github.com/distribution/distribution/v3/reference/regexp.go
deleted file mode 100644
index 78e2f9170e..0000000000
--- a/vendor/github.com/distribution/distribution/v3/reference/regexp.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package reference
-
-import "regexp"
-
-var (
- // alphaNumericRegexp defines the alpha numeric atom, typically a
- // component of names. This only allows lower case characters and digits.
- alphaNumericRegexp = match(`[a-z0-9]+`)
-
- // separatorRegexp defines the separators allowed to be embedded in name
- // components. This allow one period, one or two underscore and multiple
- // dashes. Repeated dashes and underscores are intentionally treated
- // differently. In order to support valid hostnames as name components,
- // supporting repeated dash was added. Additionally double underscore is
- // now allowed as a separator to loosen the restriction for previously
- // supported names.
- separatorRegexp = match(`(?:[._]|__|[-]*)`)
-
- // nameComponentRegexp restricts registry path component names to start
- // with at least one letter or number, with following parts able to be
- // separated by one period, one or two underscore and multiple dashes.
- nameComponentRegexp = expression(
- alphaNumericRegexp,
- optional(repeated(separatorRegexp, alphaNumericRegexp)))
-
- // domainComponentRegexp restricts the registry domain component of a
- // repository name to start with a component as defined by DomainRegexp
- // and followed by an optional port.
- domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
-
- // DomainRegexp defines the structure of potential domain components
- // that may be part of image names. This is purposely a subset of what is
- // allowed by DNS to ensure backwards compatibility with Docker image
- // names.
- DomainRegexp = expression(
- domainComponentRegexp,
- optional(repeated(literal(`.`), domainComponentRegexp)),
- optional(literal(`:`), match(`[0-9]+`)))
-
- // TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
- TagRegexp = match(`[\w][\w.-]{0,127}`)
-
- // anchoredTagRegexp matches valid tag names, anchored at the start and
- // end of the matched string.
- anchoredTagRegexp = anchored(TagRegexp)
-
- // DigestRegexp matches valid digests.
- DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`)
-
- // anchoredDigestRegexp matches valid digests, anchored at the start and
- // end of the matched string.
- anchoredDigestRegexp = anchored(DigestRegexp)
-
- // NameRegexp is the format for the name component of references. The
- // regexp has capturing groups for the domain and name part omitting
- // the separating forward slash from either.
- NameRegexp = expression(
- optional(DomainRegexp, literal(`/`)),
- nameComponentRegexp,
- optional(repeated(literal(`/`), nameComponentRegexp)))
-
- // anchoredNameRegexp is used to parse a name value, capturing the
- // domain and trailing components.
- anchoredNameRegexp = anchored(
- optional(capture(DomainRegexp), literal(`/`)),
- capture(nameComponentRegexp,
- optional(repeated(literal(`/`), nameComponentRegexp))))
-
- // ReferenceRegexp is the full supported format of a reference. The regexp
- // is anchored and has capturing groups for name, tag, and digest
- // components.
- ReferenceRegexp = anchored(capture(NameRegexp),
- optional(literal(":"), capture(TagRegexp)),
- optional(literal("@"), capture(DigestRegexp)))
-
- // IdentifierRegexp is the format for string identifier used as a
- // content addressable identifier using sha256. These identifiers
- // are like digests without the algorithm, since sha256 is used.
- IdentifierRegexp = match(`([a-f0-9]{64})`)
-
- // ShortIdentifierRegexp is the format used to represent a prefix
- // of an identifier. A prefix may be used to match a sha256 identifier
- // within a list of trusted identifiers.
- ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`)
-
- // anchoredIdentifierRegexp is used to check or match an
- // identifier value, anchored at start and end of string.
- anchoredIdentifierRegexp = anchored(IdentifierRegexp)
-
- // anchoredShortIdentifierRegexp is used to check if a value
- // is a possible identifier prefix, anchored at start and end
- // of string.
- anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp)
-)
-
-// match compiles the string to a regular expression.
-var match = regexp.MustCompile
-
-// literal compiles s into a literal regular expression, escaping any regexp
-// reserved characters.
-func literal(s string) *regexp.Regexp {
- re := match(regexp.QuoteMeta(s))
-
- if _, complete := re.LiteralPrefix(); !complete {
- panic("must be a literal")
- }
-
- return re
-}
-
-// expression defines a full expression, where each regular expression must
-// follow the previous.
-func expression(res ...*regexp.Regexp) *regexp.Regexp {
- var s string
- for _, re := range res {
- s += re.String()
- }
-
- return match(s)
-}
-
-// optional wraps the expression in a non-capturing group and makes the
-// production optional.
-func optional(res ...*regexp.Regexp) *regexp.Regexp {
- return match(group(expression(res...)).String() + `?`)
-}
-
-// repeated wraps the regexp in a non-capturing group to get one or more
-// matches.
-func repeated(res ...*regexp.Regexp) *regexp.Regexp {
- return match(group(expression(res...)).String() + `+`)
-}
-
-// group wraps the regexp in a non-capturing group.
-func group(res ...*regexp.Regexp) *regexp.Regexp {
- return match(`(?:` + expression(res...).String() + `)`)
-}
-
-// capture wraps the expression in a capturing group.
-func capture(res ...*regexp.Regexp) *regexp.Regexp {
- return match(`(` + expression(res...).String() + `)`)
-}
-
-// anchored anchors the regular expression by adding start and end delimiters.
-func anchored(res ...*regexp.Regexp) *regexp.Regexp {
- return match(`^` + expression(res...).String() + `$`)
-}
diff --git a/vendor/github.com/docker/cli/AUTHORS b/vendor/github.com/docker/cli/AUTHORS
index c5a480b5e5..accbf6c52b 100644
--- a/vendor/github.com/docker/cli/AUTHORS
+++ b/vendor/github.com/docker/cli/AUTHORS
@@ -2,6 +2,7 @@
# This file lists all contributors to the repository.
# See scripts/docs/generate-authors.sh to make modifications.
+4RH1T3CT0R7
A. Lester Buck III
Aanand Prasad
Aaron L. Xu
@@ -42,6 +43,7 @@ Alexander Larsson
Alexander Morozov
Alexander Ryabov
Alexandre González
+Alexandre Vallières-Lagacé
Alexey Igrychev
Alexis Couvreur
Alfred Landrum
@@ -63,6 +65,8 @@ Andreas Köhler
Andres G. Aragoneses
Andres Leon Rangel
Andrew France
+Andrew He
+Andrew Hopp
Andrew Hsu
Andrew Macpherson
Andrew McDonnell
@@ -86,11 +90,12 @@ Archimedes Trajano
Arko Dasgupta
Arnaud Porterie
Arnaud Rebillout
+Arthur Flageul
Arthur Peka
Ashly Mathew
Ashwini Oruganti
Aslam Ahemad
-Austin Vazquez
+Austin Vazquez
Azat Khuyiyakhmetov
Bardia Keyoumarsi
Barnaby Gray
@@ -125,6 +130,7 @@ Brian Goff
Brian Tracy
Brian Wieder
Bruno Sousa
+Bruno Verachten
Bryan Bess
Bryan Boreham
Bryan Murphy
@@ -135,10 +141,12 @@ Cao Weiwei
Carlo Mion
Carlos Alexandro Becker
Carlos de Paula
+carsontham
Carston Schilds
Casey Korver
Ce Gao
Cedric Davies
+Cesar Talledo
Cezar Sa Espinola
Chad Faragher
Chao Wang
@@ -174,6 +182,7 @@ Christopher Svensson
Christy Norman
Chun Chen
Clinton Kitson
+Codex
Coenraad Loubser
Colin Hebert
Collin Guarino
@@ -220,7 +229,7 @@ David Alvarez
David Beitey
David Calavera
David Cramer
-David Dooling
+David Dooling
David Gageot
David Karlsson
David le Blanc
@@ -230,6 +239,7 @@ David Sheets
David Williamson
David Xia
David Young
+Davlat Davydov
Deng Guangxing
Denis Defreyne
Denis Gladkikh
@@ -237,6 +247,7 @@ Denis Ollier
Dennis Docter
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Derek McGowan
+Derek Misler
Des Preston
Deshi Xiao
Dharmit Shah
@@ -256,6 +267,7 @@ Dominik Braun
Don Kjer
Dong Chen
DongGeon Lee
+Dorin Geman
Doug Davis
Drew Erny
Ed Costello
@@ -265,6 +277,7 @@ Eli Uriegas
Eli Uriegas
Elias Faxö
Elliot Luo <956941328@qq.com>
+Eng Zer Jun
Eric Bode
Eric Curtin
Eric Engestrom
@@ -345,6 +358,7 @@ Henning Sprang
Henry N
Hernan Garcia
Hongbin Lu
+Hossein Abbasi <16090309+hsnabszhdn@users.noreply.github.com>
Hu Keping
Huayi Zhang
Hugo Chastel
@@ -352,7 +366,7 @@ Hugo Gabriel Eyherabide
huqun
Huu Nguyen
Hyzhou Zhy
-Iain MacDonald
+Iain MacDonald
Iain Samuel McLean Elder
Ian Campbell
Ian Philpot
@@ -465,6 +479,7 @@ Justyn Temme
Jyrki Puttonen
Jérémie Drouet
Jérôme Petazzoni
+Jörg Sommer
Jörg Thalheim
Kai Blin
Kai Qiang Wu (Kennan)
@@ -533,10 +548,12 @@ Lovekesh Kumar
Luca Favatella
Luca Marturana
Lucas Chan
+Ludovic Temgoua Abanda
Luis Henrique Mulinari
Luka Hartwig
Lukas Heeren
Lukasz Zajaczkowski
+Luo Jiyin
Lydell Manganti
Lénaïc Huard
Ma Shimiao
@@ -595,7 +612,9 @@ Michael Prokop
Michael Scharf
Michael Spetsiotis
Michael Steinert
+Michael Tews
Michael West
+Michael Zampani
Michal Minář
Michał Czeraszkiewicz
Miguel Angel Alvarez Cabrerizo
@@ -610,6 +629,7 @@ Mike Goelzer
Mike MacCana
mikelinjie <294893458@qq.com>
Mikhail Vasin
+Milas Bowman
Milind Chawre
Mindaugas Rukas
Miroslav Gula
@@ -880,6 +900,7 @@ Vincent Batts
Vincent Bernat
Vincent Demeester
Vincent Woo
+Vineet Kumar
Vishnu Kannan
Vivek Goyal
Wang Jie
@@ -896,6 +917,7 @@ Wenlong Zhang
Wenzhi Liang
Wes Morgan
Wewang Xiaorenfine
+Will Wang
William Henry
Xianglin Gao
Xiaodong Liu
@@ -908,6 +930,7 @@ Yanqiang Miao
Yassine Tijani
Yi EungJun
Ying Li
+Yoan Wainmann