Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fab3f0b97b | ||
|
|
3819ee38f5 | ||
|
|
74261a7a01 | ||
|
|
ca39ff6e29 | ||
|
|
5d00b3c932 | ||
|
|
a380b5e8ae | ||
|
|
9ff5024a58 | ||
|
|
d6dd082e59 |
@@ -13,14 +13,14 @@ require (
|
||||
github.com/docker/cli v28.4.0+incompatible
|
||||
github.com/docker/docker v28.5.2+incompatible
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/go-git/go-git/v5 v5.19.2
|
||||
github.com/go-git/go-git/v5 v5.19.3
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/leonelquinteros/gotext v1.7.2
|
||||
github.com/moby/sys/signal v0.7.1
|
||||
github.com/moby/term v0.5.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/schollz/progressbar/v3 v3.19.1
|
||||
golang.org/x/term v0.45.0
|
||||
golang.org/x/term v0.46.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gotest.tools/v3 v3.5.2
|
||||
)
|
||||
@@ -59,7 +59,7 @@ require (
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // 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-git/go-billy/v5 v5.9.2 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@@ -73,7 +73,6 @@ require (
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.18.5 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||
@@ -95,7 +94,7 @@ require (
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/runc v1.1.13 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.6.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.7.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.5 // indirect
|
||||
github.com/prometheus/procfs v0.20.1 // indirect
|
||||
@@ -122,10 +121,10 @@ require (
|
||||
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.5 // indirect
|
||||
golang.org/x/crypto v0.53.0 // indirect
|
||||
golang.org/x/crypto v0.56.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
|
||||
golang.org/x/net v0.56.0 // indirect
|
||||
golang.org/x/text v0.39.0 // indirect
|
||||
golang.org/x/net v0.57.0 // indirect
|
||||
golang.org/x/text v0.41.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||
@@ -153,7 +152,7 @@ require (
|
||||
github.com/stretchr/testify v1.12.1
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
golang.org/x/sys v0.47.0
|
||||
golang.org/x/sys v0.48.0
|
||||
)
|
||||
|
||||
replace github.com/docker/cli v28.4.0+incompatible => git.coopcloud.tech/toolshed/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible
|
||||
|
||||
@@ -388,12 +388,12 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
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-billy/v5 v5.9.2 h1:OXFSRyz4g20upsGDJgQG9Bak1l/ZEv8GHVYB52O71sE=
|
||||
github.com/go-git/go-billy/v5 v5.9.2/go.mod h1:ExsU+jcGwXTBOnyilvAnEM1wug1IxHr4yP2ZXsNRtV0=
|
||||
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-git/go-git/v5 v5.19.3 h1:qHttbZ+Am7wEjdTpR1XMQ4rl42FK9SIXzZ4o9x7s6M4=
|
||||
github.com/go-git/go-git/v5 v5.19.3/go.mod h1:Ye4C8dVigkqrv9UsB4NMdSLV4yAIkLiIhW61gcOyhl4=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -585,8 +585,6 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
|
||||
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
|
||||
github.com/klauspost/compress v1.18.5/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.5/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.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -752,8 +750,8 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
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/pjbgf/sha1cd v0.7.0 h1:ZRNPKHj+gfkLBf0KJv/p1Hmz+7bqCT5o311YX0nq+DA=
|
||||
github.com/pjbgf/sha1cd v0.7.0/go.mod h1:pKR5Li+qTCo+ebqITZfwPlJGoCFCvSO00qxjbNtTUFQ=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -965,8 +963,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y=
|
||||
golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1042,8 +1040,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1138,13 +1136,13 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/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-20220722155257-8c9f86f7a55f/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/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
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/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
|
||||
golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1154,8 +1152,8 @@ golang.org/x/text v0.3.4/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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
|
||||
golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=
|
||||
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-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
@@ -3,7 +3,7 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nginx:1.31.5
|
||||
image: nginx:1.31.6
|
||||
secrets:
|
||||
- test_pass_one
|
||||
- test_pass_two
|
||||
|
||||
@@ -3,7 +3,7 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nginx:1.31.5
|
||||
image: nginx:1.31.6
|
||||
networks:
|
||||
- proxy
|
||||
deploy:
|
||||
|
||||
+4
@@ -329,6 +329,10 @@ func (c *Config) unmarshalCore() {
|
||||
if parsed := parseConfigBool(s.Options.Get(protectHFSKey)); parsed.IsSet() {
|
||||
c.Core.ProtectHFS = parsed
|
||||
}
|
||||
|
||||
if s.Options.Get(repositoryFormatVersionKey) == string(format.Version_1) {
|
||||
c.Core.RepositoryFormatVersion = format.Version_1
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) unmarshalUser() {
|
||||
|
||||
+25
-3
@@ -139,8 +139,12 @@ func (dw *deltaSelector) fixAndBreakChains(objectsToPack []*ObjectToPack) error
|
||||
m[otp.Hash()] = otp
|
||||
}
|
||||
|
||||
// visiting holds the objects on the current resolution path, so that a
|
||||
// delta chain looping back on itself can be detected and broken.
|
||||
visiting := make(map[plumbing.Hash]bool)
|
||||
|
||||
for _, otp := range objectsToPack {
|
||||
if err := dw.fixAndBreakChainsOne(m, otp); err != nil {
|
||||
if err := dw.fixAndBreakChainsOne(m, otp, visiting); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -148,7 +152,11 @@ func (dw *deltaSelector) fixAndBreakChains(objectsToPack []*ObjectToPack) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dw *deltaSelector) fixAndBreakChainsOne(objectsToPack map[plumbing.Hash]*ObjectToPack, otp *ObjectToPack) error {
|
||||
func (dw *deltaSelector) fixAndBreakChainsOne(
|
||||
objectsToPack map[plumbing.Hash]*ObjectToPack,
|
||||
otp *ObjectToPack,
|
||||
visiting map[plumbing.Hash]bool,
|
||||
) error {
|
||||
if !otp.Object.Type().IsDelta() {
|
||||
return nil
|
||||
}
|
||||
@@ -174,7 +182,21 @@ func (dw *deltaSelector) fixAndBreakChainsOne(objectsToPack map[plumbing.Hash]*O
|
||||
return dw.undeltify(otp)
|
||||
}
|
||||
|
||||
if err := dw.fixAndBreakChainsOne(objectsToPack, base); err != nil {
|
||||
// Mark this object as being resolved before looking at its base, so that
|
||||
// a delta based on itself is caught by the check below.
|
||||
h := otp.Hash()
|
||||
visiting[h] = true
|
||||
defer delete(visiting, h)
|
||||
|
||||
// A delta chain that loops back onto an object we are already resolving
|
||||
// cannot be written: every delta needs its base written first. Break the
|
||||
// chain here instead of following the cycle, which would recurse until
|
||||
// the goroutine stack is exhausted.
|
||||
if visiting[do.BaseHash()] {
|
||||
return dw.undeltify(otp)
|
||||
}
|
||||
|
||||
if err := dw.fixAndBreakChainsOne(objectsToPack, base, visiting); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
+34
-2
@@ -474,6 +474,14 @@ type TreeWalker struct {
|
||||
recursive bool
|
||||
seen map[plumbing.Hash]bool
|
||||
|
||||
// skipPathValidation disables the pathutil.ValidTreePath check in Next.
|
||||
// It is set by inspection-only callers (e.g. the revlist object walk)
|
||||
// that never funnel entry names into the filesystem and must enumerate
|
||||
// trees faithfully, including entries with names upstream Git accepts
|
||||
// but that are unsafe to materialise (control characters, `.git`-shaped
|
||||
// names).
|
||||
skipPathValidation bool
|
||||
|
||||
s storer.EncodedObjectStorer
|
||||
t *Tree
|
||||
}
|
||||
@@ -496,10 +504,32 @@ func NewTreeWalker(t *Tree, recursive bool, seen map[plumbing.Hash]bool) *TreeWa
|
||||
}
|
||||
}
|
||||
|
||||
// SkipPathValidation disables the pathutil.ValidTreePath check performed by
|
||||
// Next, and must be called before the first Next.
|
||||
//
|
||||
// It is for inspection-only walks that never funnel an entry name into the
|
||||
// filesystem — enumerating which objects exist, rather than materialising
|
||||
// them — and that must therefore see the tree faithfully, including entries
|
||||
// whose names upstream Git accepts but that are unsafe to check out. Callers
|
||||
// that hand the returned name to filesystem or archive output must not use
|
||||
// it; path safety for those is enforced at the materialisation boundaries
|
||||
// (FindEntry, TreeEntryFile, archive, FileIter).
|
||||
func (w *TreeWalker) SkipPathValidation() {
|
||||
w.skipPathValidation = true
|
||||
}
|
||||
|
||||
// Next returns the next object from the tree. Objects are returned in order
|
||||
// and subtrees are included. After the last object has been returned further
|
||||
// calls to Next() will return io.EOF.
|
||||
//
|
||||
// Each entry's name is validated against pathutil.ValidTreePath as it
|
||||
// surfaces, so callers that funnel the returned name into filesystem
|
||||
// or archive output can trust it is free of `.git`-shaped components,
|
||||
// HFS+/NTFS variants, Windows reserved names, and traversal sequences.
|
||||
// A malformed entry stops the walk with the validator's error;
|
||||
// inspection-only callers that need to enumerate raw, unvalidated
|
||||
// names can read Tree.Entries directly or call SkipPathValidation.
|
||||
//
|
||||
// In the current implementation any objects which cannot be found in the
|
||||
// underlying repository will be skipped automatically. It is possible that this
|
||||
// may change in future versions.
|
||||
@@ -536,8 +566,10 @@ func (w *TreeWalker) Next() (name string, entry TreeEntry, err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := pathutil.ValidTreePath(entry.Name); err != nil {
|
||||
return name, entry, err
|
||||
if !w.skipPathValidation {
|
||||
if err := pathutil.ValidTreePath(entry.Name); err != nil {
|
||||
return name, entry, err
|
||||
}
|
||||
}
|
||||
|
||||
if entry.Mode == filemode.Dir {
|
||||
|
||||
+6
@@ -106,6 +106,12 @@ func transformChildren(t *Tree) ([]noder.Noder, error) {
|
||||
ret := make([]noder.Noder, 0, len(t.Entries))
|
||||
|
||||
walker := NewTreeWalker(t, false, nil) // don't recurse
|
||||
// The diff walk is read-only and never materialises entry names into the
|
||||
// filesystem, so it must enumerate the tree faithfully — including entries
|
||||
// with names that are unsafe to check out but valid per upstream Git (e.g.
|
||||
// control characters). Path safety is enforced at materialisation
|
||||
// boundaries (FindEntry, TreeEntryFile, archive, FileIter), not here.
|
||||
walker.SkipPathValidation()
|
||||
// don't defer walker.Close() for efficiency reasons.
|
||||
for {
|
||||
_, e, err = walker.Next()
|
||||
|
||||
+7
@@ -187,6 +187,13 @@ func iterateCommitTrees(
|
||||
cb(tree.Hash)
|
||||
|
||||
treeWalker := object.NewTreeWalker(tree, true, seen)
|
||||
// This walk only enumerates which objects are reachable, to decide what
|
||||
// to send; it never materialises an entry name into the filesystem. It
|
||||
// must therefore enumerate the tree faithfully, including entries with
|
||||
// names that are unsafe to check out but valid per upstream Git (e.g.
|
||||
// control characters). Path safety is enforced at materialisation
|
||||
// boundaries (FindEntry, TreeEntryFile, archive, FileIter), not here.
|
||||
treeWalker.SkipPathValidation()
|
||||
|
||||
for {
|
||||
_, e, err := treeWalker.Next()
|
||||
|
||||
+379
-22
@@ -6,8 +6,12 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -73,7 +77,7 @@ func advertisedReferences(ctx context.Context, s *session, serviceName string) (
|
||||
s.endpoint.String(), infoRefsPath, serviceName,
|
||||
)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
req, err := newRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -177,6 +181,24 @@ func NewClient(c *http.Client) transport.Transport {
|
||||
// and other custom options specific to the client.
|
||||
// If the net/http client is nil or empty, it will use a net/http client configured
|
||||
// with http.DefaultTransport.
|
||||
//
|
||||
// Credentials this client adds where the transport cannot see them are not
|
||||
// subject to the redirect stripping described on AuthMethod: a RoundTripper
|
||||
// injects after the hop is decided, and Client.Jar is consulted after
|
||||
// CheckRedirect, so a domain cookie still follows a redirect to a subdomain
|
||||
// the transport counts as another origin. Apply them in an AuthMethod instead
|
||||
// if that is not wanted. A CheckRedirect hook set on this client runs
|
||||
// alongside the transport's own, but any header it adds when a redirect
|
||||
// leaves the repository's origin is discarded the same way.
|
||||
//
|
||||
// A RoundTripper is therefore also how to authenticate to a new origin a
|
||||
// redirect has moved the repository to: match on the request URL and inject
|
||||
// the credential only for that origin, so it is not sent anywhere else. The
|
||||
// transport keeps its own CheckRedirect on the copy it makes of this client,
|
||||
// so the policy and the origin checks still apply.
|
||||
//
|
||||
// None of this applies to a RoundTripper that follows redirects itself:
|
||||
// CheckRedirect is not consulted then, so no stripping happens at all.
|
||||
func NewClientWithOptions(c *http.Client, opts *ClientOptions) transport.Transport {
|
||||
if c == nil {
|
||||
c = &http.Client{
|
||||
@@ -370,11 +392,20 @@ func (s *session) ModifyEndpointIfRedirect(res *http.Response) error {
|
||||
if !strings.HasSuffix(r.URL.Path, infoRefsPath) {
|
||||
return fmt.Errorf("http redirect: target %q does not end with %s", r.URL.Path, infoRefsPath)
|
||||
}
|
||||
if r.URL.Scheme != "http" && r.URL.Scheme != "https" {
|
||||
// A scheme is case-insensitive per RFC 3986, and checkRedirect folds case
|
||||
// when it reads the same hop, so fold here too rather than reject a
|
||||
// spelling that check let through. url.Parse and transport.NewEndpoint
|
||||
// both lowercase what they parse, so only a hand-built URL or Endpoint
|
||||
// arrives uppercased. The folded form is what gets stored below, so every
|
||||
// later request built from the endpoint carries the canonical spelling.
|
||||
scheme := strings.ToLower(r.URL.Scheme)
|
||||
if scheme != "http" && scheme != "https" {
|
||||
return fmt.Errorf("http redirect: unsupported scheme %q", r.URL.Scheme)
|
||||
}
|
||||
if r.URL.Scheme != s.endpoint.Protocol &&
|
||||
!(s.endpoint.Protocol == "http" && r.URL.Scheme == "https") {
|
||||
// schemeUpgrade rather than an inline comparison, so the one cross-scheme
|
||||
// change go-git permits has a single definition shared with
|
||||
// credentialsMayFollow.
|
||||
if !strings.EqualFold(scheme, s.endpoint.Protocol) && !schemeUpgrade(s.endpoint.Protocol, scheme) {
|
||||
return fmt.Errorf("http redirect: changes scheme from %q to %q", s.endpoint.Protocol, r.URL.Scheme)
|
||||
}
|
||||
|
||||
@@ -384,7 +415,20 @@ func (s *session) ModifyEndpointIfRedirect(res *http.Response) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if host != s.endpoint.Host || effectivePort(r.URL.Scheme, port) != effectivePort(s.endpoint.Protocol, s.endpoint.Port) {
|
||||
// The session stores the endpoint and re-applies its credentials on every
|
||||
// later request, so clear them once the redirect has left the origin they
|
||||
// were issued for. This uses the same predicate as stripCredentials, so
|
||||
// both halves share one definition of an origin.
|
||||
//
|
||||
// The two are deliberately asymmetric in one respect: stripCredentials is
|
||||
// sticky over the whole chain, so an origin -> evil -> origin redirect
|
||||
// leaves the discovery GET's later hops unauthenticated even though the
|
||||
// chain returned home. This compares the endpoint only against the final
|
||||
// URL, so the same round trip leaves the session authenticated. That is
|
||||
// not a leak - the final URL's origin is the original one - but it means
|
||||
// such a chain can make the discovery GET anonymous while the session's
|
||||
// POSTs are authenticated, which can surface as a confusing 401.
|
||||
if !credentialsMayFollow(endpointURL(s.endpoint), r.URL) {
|
||||
s.endpoint.User = ""
|
||||
s.endpoint.Password = ""
|
||||
s.auth = nil
|
||||
@@ -393,7 +437,7 @@ func (s *session) ModifyEndpointIfRedirect(res *http.Response) error {
|
||||
s.endpoint.Host = host
|
||||
s.endpoint.Port = port
|
||||
|
||||
s.endpoint.Protocol = r.URL.Scheme
|
||||
s.endpoint.Protocol = scheme
|
||||
s.endpoint.Path = r.URL.Path[:len(r.URL.Path)-len(infoRefsPath)]
|
||||
return nil
|
||||
}
|
||||
@@ -419,19 +463,132 @@ func endpointPort(port string) (int, error) {
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func effectivePort(scheme string, port int) int {
|
||||
if port != 0 {
|
||||
return port
|
||||
}
|
||||
// schemeUpgrade reports whether the scheme transition from one URL to another
|
||||
// is the one cross-scheme change go-git permits: a plain-http origin upgrading
|
||||
// to https. It strictly improves confidentiality and is how servers steer
|
||||
// clients off cleartext.
|
||||
//
|
||||
// Permitting it at all is a deliberate deviation: curl, git and the Fetch
|
||||
// standard all count scheme as part of host identity and drop credentials on
|
||||
// the upgrade. Auth is sent pre-emptively here, so an http origin has already
|
||||
// spent its credential in cleartext on the first request and refusing the
|
||||
// upgrade would break the clone without unspending it. The host is unchanged,
|
||||
// where an on-path attacker needs a valid certificate to receive anything.
|
||||
func schemeUpgrade(from, to string) bool {
|
||||
return strings.EqualFold(from, "http") && strings.EqualFold(to, "https")
|
||||
}
|
||||
|
||||
switch strings.ToLower(scheme) {
|
||||
case "http":
|
||||
return 80
|
||||
case "https":
|
||||
return 443
|
||||
default:
|
||||
return 0
|
||||
// canonicalHost returns u's hostname in the form origins are compared in.
|
||||
//
|
||||
// An address literal is normalised by netip, so the many spellings of one
|
||||
// address are one origin. Two literals are the same origin exactly when netip
|
||||
// parses them to the same Addr, which is also how the WHATWG URL Standard
|
||||
// compares hosts. An IPv4-mapped literal is deliberately not unmapped onto
|
||||
// the IPv4 it dials: reaching the same endpoint is not the same authority,
|
||||
// since net/http sends the literal as written in Host and a server may route
|
||||
// the two spellings to different virtual hosts.
|
||||
//
|
||||
// netip also keeps a scope zone verbatim, which is what origin comparison
|
||||
// needs: net resolves a zone to an interface by exact name, so folding %eth0
|
||||
// onto %ETH0 would call two hosts the same origin that net dials down
|
||||
// different interfaces.
|
||||
//
|
||||
// A registered name is ASCII-lowercased. That fold is the only liberty taken;
|
||||
// every other difference in spelling is a different origin.
|
||||
//
|
||||
// A trailing root dot is one such difference and is kept, for the same reason
|
||||
// as the IPv4-mapped literal: curl and the WHATWG URL Standard both hold
|
||||
// "example.com." and "example.com" to be distinct hosts, and although
|
||||
// crypto/tls and crypto/x509 fold the dot when they authenticate the peer,
|
||||
// net/http sends the name as written in Host.
|
||||
//
|
||||
// The fold is deliberately ASCII-only. strings.ToLower and strings.EqualFold
|
||||
// apply Unicode case mapping, which folds U+03C2 onto U+03C3 and so would
|
||||
// call two hosts the same origin when they resolve to different servers. An
|
||||
// ASCII-only fold cannot merge two names DNS keeps apart.
|
||||
//
|
||||
// No IDNA mapping is applied either, so a unicode hostname is a different
|
||||
// origin from the punycode encoding of it, and from another Unicode case of
|
||||
// itself, even though all three reach the same server. Mapping through
|
||||
// golang.org/x/net/idna would join them, but it can only widen this equality,
|
||||
// never narrow it, so leaving it out can cost a credential across such a
|
||||
// redirect and cannot forward one. Against that cost, go-git pins x/net while
|
||||
// net/http uses the copy vendored into the toolchain: the two are versioned
|
||||
// separately, so a release that moves the Unicode tables under one and not
|
||||
// the other would have this merge origins net/http still dials apart. That is
|
||||
// the failure this comparison exists to prevent, and comparing bytes has no
|
||||
// such mode.
|
||||
func canonicalHost(u *url.URL) string {
|
||||
host := u.Hostname()
|
||||
if addr, err := netip.ParseAddr(host); err == nil {
|
||||
return addr.String()
|
||||
}
|
||||
b := []byte(host)
|
||||
for i := range b {
|
||||
if b[i] >= 'A' && b[i] <= 'Z' {
|
||||
b[i] += 'a' - 'A'
|
||||
}
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// effectivePort returns u's port as the connection will use it: the scheme's
|
||||
// well-known port when the URL does not spell one out, and without leading
|
||||
// zeroes, so "https://x", "https://x:443" and "https://x:0443" all agree.
|
||||
func effectivePort(u *url.URL) string {
|
||||
port := u.Port()
|
||||
if port == "" {
|
||||
switch strings.ToLower(u.Scheme) {
|
||||
case "http":
|
||||
return "80"
|
||||
case "https":
|
||||
return "443"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
if trimmed := strings.TrimLeft(port, "0"); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
|
||||
// credentialsMayFollow reports whether credentials issued for one URL may be
|
||||
// sent to another.
|
||||
//
|
||||
// The relation is deliberately asymmetric: scheme, host and effective port
|
||||
// must all match, except that a plain http origin may upgrade to https on the
|
||||
// same host (see schemeUpgrade). That exception is confined to the two
|
||||
// default ports: 80 to 443 is the upgrade servers actually steer clients
|
||||
// through, whereas a non-default port carries no such convention, so
|
||||
// http://host:8080 to https://host:8443 is a move to another origin like any
|
||||
// other port change.
|
||||
//
|
||||
// Host matching is exact. Unlike Go's http.Client, which forwards credentials
|
||||
// from a host to any subdomain of it, a subdomain is a different origin here —
|
||||
// matching canonical git and libcurl.
|
||||
func credentialsMayFollow(from, to *url.URL) bool {
|
||||
if canonicalHost(from) != canonicalHost(to) {
|
||||
return false
|
||||
}
|
||||
if strings.EqualFold(from.Scheme, to.Scheme) {
|
||||
return effectivePort(from) == effectivePort(to)
|
||||
}
|
||||
return schemeUpgrade(from.Scheme, to.Scheme) &&
|
||||
effectivePort(from) == "80" && effectivePort(to) == "443"
|
||||
}
|
||||
|
||||
// endpointURL renders an Endpoint's origin as a URL, so that the session's
|
||||
// credential clearing and the per-hop stripping share one definition of an
|
||||
// origin and cannot drift apart.
|
||||
func endpointURL(ep *transport.Endpoint) *url.URL {
|
||||
host := strings.Trim(ep.Host, "[]")
|
||||
if ep.Port != 0 {
|
||||
host = net.JoinHostPort(host, strconv.Itoa(ep.Port))
|
||||
} else if strings.Contains(host, ":") {
|
||||
host = "[" + host + "]"
|
||||
}
|
||||
return &url.URL{Scheme: ep.Protocol, Host: host}
|
||||
}
|
||||
|
||||
func (c *client) cloneHTTPClient(transport http.RoundTripper) *http.Client {
|
||||
@@ -448,26 +605,215 @@ func wrapCheckRedirect(policy RedirectPolicy, next func(*http.Request, []*http.R
|
||||
if err := checkRedirect(req, via, policy); err != nil {
|
||||
return err
|
||||
}
|
||||
// Strip before the caller's hook so it observes what will actually
|
||||
// be sent, and again afterwards so a hook of the common "preserve
|
||||
// my headers across redirects" shape - which copies from via[0],
|
||||
// the original unsanitized request - cannot reinstate them.
|
||||
// Carrying credentials across an origin boundary is deliberately
|
||||
// unsupported.
|
||||
stripCredentials(req, via)
|
||||
if next != nil {
|
||||
return next(req, via)
|
||||
if err := next(req, via); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
stripCredentials(req, via)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// safeHeaders lists the headers go-git sets itself, none of which can carry a
|
||||
// caller credential. stripCredentials keeps only these when a redirect leaves
|
||||
// the credential's origin. Adding a name here makes it forwardable across an
|
||||
// origin boundary - do not add anything a caller can put a secret in.
|
||||
//
|
||||
// This narrows rather than eliminates the exposure: an AuthMethod that writes
|
||||
// a credential into one of these names directly - for example
|
||||
// Header.Set("User-Agent", "token "+secret) - still survives a cross-origin
|
||||
// redirect. Such a value is also sent to the origin and to any proxy in path,
|
||||
// so it should not be placed there whether or not a redirect follows.
|
||||
var safeHeaders = map[string]struct{}{
|
||||
"User-Agent": {},
|
||||
"Host": {},
|
||||
"Accept": {},
|
||||
"Content-Type": {},
|
||||
"Content-Length": {},
|
||||
}
|
||||
|
||||
func filterHeaders(h http.Header) http.Header {
|
||||
filtered := make(http.Header)
|
||||
for key, values := range h {
|
||||
if _, ok := safeHeaders[http.CanonicalHeaderKey(key)]; ok {
|
||||
filtered[key] = values
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// stripCredentials removes credentials from req once the redirect chain has
|
||||
// left the origin of the original, credential-bearing request.
|
||||
//
|
||||
// CheckRedirect is the only hook that runs while a redirected request's
|
||||
// headers are still mutable: http.Client.Do performs the entire chain
|
||||
// internally, so anything the transport does after Do returns - including
|
||||
// ModifyEndpointIfRedirect - is too late for the hops themselves.
|
||||
//
|
||||
// Two subtleties:
|
||||
//
|
||||
// - net/http rebuilds every redirect request from the original request's
|
||||
// headers before calling this, so a header removed at one hop reappears
|
||||
// at the next. The decision is therefore recomputed per hop.
|
||||
// - The decision is sticky: once the chain has left the origin, credentials
|
||||
// stay gone even if a later hop returns to it. Stickiness is derived from
|
||||
// via rather than stored, because this closure is shared across a
|
||||
// session's requests.
|
||||
//
|
||||
// Stripping keeps only the headers go-git sets itself (safeHeaders). An
|
||||
// allowlist is used rather than a list of credential header names because
|
||||
// caller credentials arrive under names that cannot be enumerated -
|
||||
// PRIVATE-TOKEN, X-Api-Key, gateway headers - which is exactly what
|
||||
// net/http's fixed list of sensitive header names gets wrong. It is also
|
||||
// immune to header-name canonicalisation: an AuthMethod that writes a raw map
|
||||
// key is still removed.
|
||||
func stripCredentials(req *http.Request, via []*http.Request) {
|
||||
if len(via) == 0 {
|
||||
return
|
||||
}
|
||||
// net/http sets a URL on every request it builds, and req.URL is non-nil
|
||||
// by construction: checkRedirect dereferences req.URL.Scheme on each path
|
||||
// that returns nil, so it runs first or not at all. This nil check and
|
||||
// the two in crossedOrigin are defensive, against a synthetic caller.
|
||||
// Each treats a URL it cannot read as an origin crossing; removing one
|
||||
// panics in canonicalHost rather than leaking.
|
||||
if origin := via[0].URL; origin != nil && !crossedOrigin(origin, req, via) {
|
||||
return
|
||||
}
|
||||
req.Header = filterHeaders(req.Header)
|
||||
if req.URL != nil {
|
||||
req.URL.User = nil
|
||||
}
|
||||
}
|
||||
|
||||
// crossedOrigin reports whether any hop so far, including the pending one, has
|
||||
// left origin.
|
||||
func crossedOrigin(origin *url.URL, req *http.Request, via []*http.Request) bool {
|
||||
if req.URL == nil || !credentialsMayFollow(origin, req.URL) {
|
||||
return true
|
||||
}
|
||||
for _, prev := range via[1:] {
|
||||
if prev.URL == nil || !credentialsMayFollow(origin, prev.URL) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// redactedURL returns the string form of u with the userinfo password
|
||||
// replaced, for use in error messages. (*url.URL).String() renders the
|
||||
// password verbatim, and request URLs are built from the endpoint, which
|
||||
// carries whatever credentials the caller put in the clone URL.
|
||||
func redactedURL(u *url.URL) string {
|
||||
if u == nil {
|
||||
return ""
|
||||
}
|
||||
if u.User == nil {
|
||||
return u.String()
|
||||
}
|
||||
if _, hasPassword := u.User.Password(); !hasPassword {
|
||||
return u.String()
|
||||
}
|
||||
redacted := *u
|
||||
redacted.User = url.UserPassword(u.User.Username(), "REDACTED")
|
||||
return redacted.String()
|
||||
}
|
||||
|
||||
// redactedRawURL is redactedURL for a string that may not parse. Request URLs
|
||||
// are assembled from Endpoint.String(), which re-emits Endpoint.Path raw, so a
|
||||
// path holding a stray percent produces a string url.Parse rejects. url.Parse
|
||||
// reports the input verbatim and applies no redaction of its own; only
|
||||
// http.Client strips a password, and only from errors it raises itself.
|
||||
func redactedRawURL(raw string) string {
|
||||
i := strings.Index(raw, "://")
|
||||
if i < 0 {
|
||||
return raw
|
||||
}
|
||||
authority := raw[i+3:]
|
||||
if end := strings.IndexByte(authority, '/'); end >= 0 {
|
||||
authority = authority[:end]
|
||||
}
|
||||
at := strings.LastIndexByte(authority, '@')
|
||||
if at < 0 {
|
||||
return raw
|
||||
}
|
||||
colon := strings.IndexByte(authority[:at], ':')
|
||||
if colon < 0 {
|
||||
// Username only, left alone, as redactedURL leaves it.
|
||||
return raw
|
||||
}
|
||||
return raw[:i+3+colon+1] + "REDACTED" + raw[i+3+at:]
|
||||
}
|
||||
|
||||
// newRequest wraps http.NewRequest so that a URL it cannot parse does not
|
||||
// reach the caller with the endpoint's credentials still in it.
|
||||
func newRequest(method, rawURL string, body io.Reader) (*http.Request, error) {
|
||||
req, err := http.NewRequest(method, rawURL, body)
|
||||
if err != nil {
|
||||
var uerr *url.Error
|
||||
if errors.As(err, &uerr) {
|
||||
uerr.URL = redactedRawURL(uerr.URL)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func checkRedirect(req *http.Request, via []*http.Request, policy RedirectPolicy) error {
|
||||
// CheckRedirect is the only hook that runs before the next hop leaves
|
||||
// the client. ModifyEndpointIfRedirect inspects the chain after
|
||||
// client.Do has followed all of it, so a hop rejected there has already
|
||||
// carried the request headers to its server.
|
||||
//
|
||||
// The wording matches the message ModifyEndpointIfRedirect produces for
|
||||
// the same hop, which this check reaches first.
|
||||
if len(via) != 0 {
|
||||
// A hop whose scheme cannot be read cannot be shown not to have been
|
||||
// https, so it is assumed to have been, and a cleartext target is
|
||||
// rejected. Skipping the comparison instead would let an
|
||||
// undeterminable hop turn the check off, which is the wrong default
|
||||
// for a credential control; crossedOrigin fails closed the same way.
|
||||
// An empty scheme is as unreadable as a nil URL, so both take the
|
||||
// assumed-https default.
|
||||
//
|
||||
// The comparisons fold case because a scheme is case-insensitive per
|
||||
// RFC 3986. net/url lowercases what it parses, so only a hand-built
|
||||
// URL reaches here uppercased - the same synthetic caller the nil
|
||||
// checks guard against - and for that caller "HTTPS" to "http" is
|
||||
// still a downgrade.
|
||||
prevScheme := "https"
|
||||
if prev := via[len(via)-1]; prev.URL != nil && prev.URL.Scheme != "" {
|
||||
prevScheme = prev.URL.Scheme
|
||||
}
|
||||
if strings.EqualFold(prevScheme, "https") && strings.EqualFold(req.URL.Scheme, "http") {
|
||||
return fmt.Errorf("http redirect: changes scheme from %q to %q: %s",
|
||||
prevScheme, req.URL.Scheme, redactedURL(req.URL))
|
||||
}
|
||||
}
|
||||
|
||||
switch policy {
|
||||
case FollowRedirects:
|
||||
case NoFollowRedirects:
|
||||
return fmt.Errorf("http redirect: redirects disabled to %s", req.URL)
|
||||
return fmt.Errorf("http redirect: redirects disabled to %s", redactedURL(req.URL))
|
||||
case "", FollowInitialRedirects:
|
||||
if !isInitialRequest(req) {
|
||||
return fmt.Errorf("http redirect: redirect on non-initial request to %s", req.URL)
|
||||
return fmt.Errorf("http redirect: redirect on non-initial request to %s", redactedURL(req.URL))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("http redirect: invalid redirect policy %q", policy)
|
||||
}
|
||||
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
|
||||
// Folded for the same reason as the guard above: a scheme is
|
||||
// case-insensitive per RFC 3986, so a spelling the downgrade check read
|
||||
// as https must not be rejected here as a scheme go-git cannot speak.
|
||||
if !strings.EqualFold(req.URL.Scheme, "http") && !strings.EqualFold(req.URL.Scheme, "https") {
|
||||
return fmt.Errorf("http redirect: unsupported scheme %q", req.URL.Scheme)
|
||||
}
|
||||
if len(via) >= 10 {
|
||||
@@ -481,6 +827,17 @@ func (*session) Close() error {
|
||||
}
|
||||
|
||||
// AuthMethod is concrete implementation of common.AuthMethod for HTTP services
|
||||
//
|
||||
// Headers SetAuth adds are dropped when a redirect leaves the repository's
|
||||
// origin: only the headers the transport sets itself survive that boundary.
|
||||
// This applies to non-credential headers too, so an implementation that adds a
|
||||
// trace or tenant header loses it on such a hop.
|
||||
//
|
||||
// That filter matches header names, not values. An implementation that writes
|
||||
// a credential into a name the transport also uses - User-Agent, Host, Accept,
|
||||
// Content-Type, Content-Length - has that value carried across the boundary
|
||||
// with the name. Such a credential is also sent to the origin and to any proxy
|
||||
// in path, so it should not be placed there whether or not a redirect follows.
|
||||
type AuthMethod interface {
|
||||
transport.AuthMethod
|
||||
SetAuth(r *http.Request)
|
||||
@@ -598,6 +955,6 @@ func (e *Err) StatusCode() int {
|
||||
|
||||
func (e *Err) Error() string {
|
||||
return fmt.Sprintf("unexpected requesting %q status code: %d",
|
||||
e.Response.Request.URL, e.Response.StatusCode,
|
||||
redactedURL(e.Response.Request.URL), e.Response.StatusCode,
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ func (s *rpSession) doRequest(
|
||||
body = content
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
req, err := newRequest(method, url, body)
|
||||
if err != nil {
|
||||
return nil, plumbing.NewPermanentError(err)
|
||||
}
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ func (s *upSession) doRequest(
|
||||
body = content
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
req, err := newRequest(method, url, body)
|
||||
if err != nil {
|
||||
return nil, plumbing.NewPermanentError(err)
|
||||
}
|
||||
|
||||
+1
@@ -433,6 +433,7 @@ func dotGitCommonDirectory(fs billy.Filesystem) (commonDir billy.Filesystem, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ioutil.CheckClose(f, &err)
|
||||
|
||||
b, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
version: 2
|
||||
|
||||
builds:
|
||||
-
|
||||
id: "cpuid"
|
||||
binary: cpuid
|
||||
main: ./cmd/cpuid/main.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
flags:
|
||||
- -ldflags=-s -w
|
||||
goos:
|
||||
- aix
|
||||
- linux
|
||||
- freebsd
|
||||
- netbsd
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm64
|
||||
goarm:
|
||||
- 7
|
||||
|
||||
archives:
|
||||
-
|
||||
id: cpuid
|
||||
name_template: "cpuid-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
files:
|
||||
- LICENSE
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^doc:'
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
- '^tests:'
|
||||
- '^Update\sREADME.md'
|
||||
|
||||
nfpms:
|
||||
-
|
||||
file_name_template: "cpuid_package_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
||||
vendor: Klaus Post
|
||||
homepage: https://github.com/klauspost/cpuid
|
||||
maintainer: Klaus Post <klauspost@gmail.com>
|
||||
description: CPUID Tool
|
||||
license: BSD 3-Clause
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2015- Klaus Post & Contributors.
|
||||
Email: klauspost@gmail.com
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Klaus Post
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-512
@@ -1,512 +0,0 @@
|
||||
# cpuid
|
||||
Package cpuid provides information about the CPU running the current program.
|
||||
|
||||
CPU features are detected on startup, and kept for fast access through the life of the application.
|
||||
Currently x86 / x64 (AMD64/i386) and ARM (ARM64) is supported, and no external C (cgo) code is used, which should make the library very easy to use.
|
||||
|
||||
You can access the CPU information by accessing the shared CPU variable of the cpuid library.
|
||||
|
||||
Package home: https://github.com/klauspost/cpuid
|
||||
|
||||
[](https://pkg.go.dev/github.com/klauspost/cpuid/v2)
|
||||
[](https://github.com/klauspost/cpuid/actions/workflows/go.yml)
|
||||
|
||||
## installing
|
||||
|
||||
`go get -u github.com/klauspost/cpuid/v2` using modules.
|
||||
Drop `v2` for others.
|
||||
|
||||
Installing binary:
|
||||
|
||||
`go install github.com/klauspost/cpuid/v2/cmd/cpuid@latest`
|
||||
|
||||
Or download binaries from release page: https://github.com/klauspost/cpuid/releases
|
||||
|
||||
### Homebrew
|
||||
|
||||
For macOS/Linux users, you can install via [brew](https://brew.sh/)
|
||||
|
||||
```sh
|
||||
$ brew install cpuid
|
||||
```
|
||||
|
||||
## example
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
. "github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Print basic CPU information:
|
||||
fmt.Println("Name:", CPU.BrandName)
|
||||
fmt.Println("PhysicalCores:", CPU.PhysicalCores)
|
||||
fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore)
|
||||
fmt.Println("LogicalCores:", CPU.LogicalCores)
|
||||
fmt.Println("Family", CPU.Family, "Model:", CPU.Model, "Vendor ID:", CPU.VendorID)
|
||||
fmt.Println("Features:", strings.Join(CPU.FeatureSet(), ","))
|
||||
fmt.Println("Cacheline bytes:", CPU.CacheLine)
|
||||
fmt.Println("L1 Data Cache:", CPU.Cache.L1D, "bytes")
|
||||
fmt.Println("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
|
||||
fmt.Println("L2 Cache:", CPU.Cache.L2, "bytes")
|
||||
fmt.Println("L3 Cache:", CPU.Cache.L3, "bytes")
|
||||
fmt.Println("Frequency", CPU.Hz, "hz")
|
||||
|
||||
// Test if we have these specific features:
|
||||
if CPU.Supports(SSE, SSE2) {
|
||||
fmt.Println("We have Streaming SIMD 2 Extensions")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
>go run main.go
|
||||
Name: AMD Ryzen 9 3950X 16-Core Processor
|
||||
PhysicalCores: 16
|
||||
ThreadsPerCore: 2
|
||||
LogicalCores: 32
|
||||
Family 23 Model: 113 Vendor ID: AMD
|
||||
Features: ADX,AESNI,AVX,AVX2,BMI1,BMI2,CLMUL,CMOV,CX16,F16C,FMA3,HTT,HYPERVISOR,LZCNT,MMX,MMXEXT,NX,POPCNT,RDRAND,RDSEED,RDTSCP,SHA,SSE,SSE2,SSE3,SSE4,SSE42,SSE4A,SSSE3
|
||||
Cacheline bytes: 64
|
||||
L1 Data Cache: 32768 bytes
|
||||
L1 Instruction Cache: 32768 bytes
|
||||
L2 Cache: 524288 bytes
|
||||
L3 Cache: 16777216 bytes
|
||||
Frequency 0 hz
|
||||
We have Streaming SIMD 2 Extensions
|
||||
```
|
||||
|
||||
# usage
|
||||
|
||||
The `cpuid.CPU` provides access to CPU features. Use `cpuid.CPU.Supports()` to check for CPU features.
|
||||
A faster `cpuid.CPU.Has()` is provided which will usually be inlined by the gc compiler.
|
||||
|
||||
To test a larger number of features, they can be combined using `f := CombineFeatures(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2)`, etc.
|
||||
This can be using with `cpuid.CPU.HasAll(f)` to quickly test if all features are supported.
|
||||
|
||||
Note that for some cpu/os combinations some features will not be detected.
|
||||
`amd64` has rather good support and should work reliably on all platforms.
|
||||
|
||||
Note that hypervisors may not pass through all CPU features through to the guest OS,
|
||||
so even if your host supports a feature it may not be visible on guests.
|
||||
|
||||
## arm64 feature detection
|
||||
|
||||
Not all operating systems provide ARM features directly
|
||||
and there is no safe way to do so for the rest.
|
||||
|
||||
Currently `arm64/linux` and `arm64/freebsd` should be quite reliable.
|
||||
`arm64/darwin` adds features expected from the M1 processor, but a lot remains undetected.
|
||||
|
||||
A `DetectARM()` can be used if you are able to control your deployment,
|
||||
it will detect CPU features, but may crash if the OS doesn't intercept the calls.
|
||||
A `-cpu.arm` flag for detecting unsafe ARM features can be added. See below.
|
||||
|
||||
Note that currently only features are detected on ARM,
|
||||
no additional information is currently available.
|
||||
|
||||
## flags
|
||||
|
||||
It is possible to add flags that affects cpu detection.
|
||||
|
||||
For this the `Flags()` command is provided.
|
||||
|
||||
This must be called *before* `flag.Parse()` AND after the flags have been parsed `Detect()` must be called.
|
||||
|
||||
This means that any detection used in `init()` functions will not contain these flags.
|
||||
|
||||
Example:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cpuid.Flags()
|
||||
flag.Parse()
|
||||
cpuid.Detect()
|
||||
|
||||
// Test if we have these specific features:
|
||||
if cpuid.CPU.Supports(cpuid.SSE, cpuid.SSE2) {
|
||||
fmt.Println("We have Streaming SIMD 2 Extensions")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## commandline
|
||||
|
||||
Download as binary from: https://github.com/klauspost/cpuid/releases
|
||||
|
||||
Install from source:
|
||||
|
||||
`go install github.com/klauspost/cpuid/v2/cmd/cpuid@latest`
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
λ cpuid
|
||||
Name: AMD Ryzen 9 3950X 16-Core Processor
|
||||
Vendor String: AuthenticAMD
|
||||
Vendor ID: AMD
|
||||
PhysicalCores: 16
|
||||
Threads Per Core: 2
|
||||
Logical Cores: 32
|
||||
CPU Family 23 Model: 113
|
||||
Features: ADX,AESNI,AVX,AVX2,BMI1,BMI2,CLMUL,CLZERO,CMOV,CMPXCHG8,CPBOOST,CX16,F16C,FMA3,FXSR,FXSROPT,HTT,HYPERVISOR,LAHF,LZCNT,MCAOVERFLOW,MMX,MMXEXT,MOVBE,NX,OSXSAVE,POPCNT,RDRAND,RDSEED,RDTSCP,SCE,SHA,SSE,SSE2,SSE3,SSE4,SSE42,SSE4A,SSSE3,SUCCOR,X87,XSAVE
|
||||
Microarchitecture level: 3
|
||||
Cacheline bytes: 64
|
||||
L1 Instruction Cache: 32768 bytes
|
||||
L1 Data Cache: 32768 bytes
|
||||
L2 Cache: 524288 bytes
|
||||
L3 Cache: 16777216 bytes
|
||||
|
||||
```
|
||||
### JSON Output:
|
||||
|
||||
```
|
||||
λ cpuid --json
|
||||
{
|
||||
"BrandName": "AMD Ryzen 9 3950X 16-Core Processor",
|
||||
"VendorID": 2,
|
||||
"VendorString": "AuthenticAMD",
|
||||
"PhysicalCores": 16,
|
||||
"ThreadsPerCore": 2,
|
||||
"LogicalCores": 32,
|
||||
"Family": 23,
|
||||
"Model": 113,
|
||||
"CacheLine": 64,
|
||||
"Hz": 0,
|
||||
"BoostFreq": 0,
|
||||
"Cache": {
|
||||
"L1I": 32768,
|
||||
"L1D": 32768,
|
||||
"L2": 524288,
|
||||
"L3": 16777216
|
||||
},
|
||||
"SGX": {
|
||||
"Available": false,
|
||||
"LaunchControl": false,
|
||||
"SGX1Supported": false,
|
||||
"SGX2Supported": false,
|
||||
"MaxEnclaveSizeNot64": 0,
|
||||
"MaxEnclaveSize64": 0,
|
||||
"EPCSections": null
|
||||
},
|
||||
"Features": [
|
||||
"ADX",
|
||||
"AESNI",
|
||||
"AVX",
|
||||
"AVX2",
|
||||
"BMI1",
|
||||
"BMI2",
|
||||
"CLMUL",
|
||||
"CLZERO",
|
||||
"CMOV",
|
||||
"CMPXCHG8",
|
||||
"CPBOOST",
|
||||
"CX16",
|
||||
"F16C",
|
||||
"FMA3",
|
||||
"FXSR",
|
||||
"FXSROPT",
|
||||
"HTT",
|
||||
"HYPERVISOR",
|
||||
"LAHF",
|
||||
"LZCNT",
|
||||
"MCAOVERFLOW",
|
||||
"MMX",
|
||||
"MMXEXT",
|
||||
"MOVBE",
|
||||
"NX",
|
||||
"OSXSAVE",
|
||||
"POPCNT",
|
||||
"RDRAND",
|
||||
"RDSEED",
|
||||
"RDTSCP",
|
||||
"SCE",
|
||||
"SHA",
|
||||
"SSE",
|
||||
"SSE2",
|
||||
"SSE3",
|
||||
"SSE4",
|
||||
"SSE42",
|
||||
"SSE4A",
|
||||
"SSSE3",
|
||||
"SUCCOR",
|
||||
"X87",
|
||||
"XSAVE"
|
||||
],
|
||||
"X64Level": 3
|
||||
}
|
||||
```
|
||||
|
||||
### Check CPU microarch level
|
||||
|
||||
```
|
||||
λ cpuid --check-level=3
|
||||
2022/03/18 17:04:40 AMD Ryzen 9 3950X 16-Core Processor
|
||||
2022/03/18 17:04:40 Microarchitecture level 3 is supported. Max level is 3.
|
||||
Exit Code 0
|
||||
|
||||
λ cpuid --check-level=4
|
||||
2022/03/18 17:06:18 AMD Ryzen 9 3950X 16-Core Processor
|
||||
2022/03/18 17:06:18 Microarchitecture level 4 not supported. Max level is 3.
|
||||
Exit Code 1
|
||||
```
|
||||
|
||||
|
||||
## Available flags
|
||||
|
||||
### x86 & amd64
|
||||
|
||||
| Feature Flag | Description |
|
||||
|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ADX | Intel ADX (Multi-Precision Add-Carry Instruction Extensions) |
|
||||
| AESNI | Advanced Encryption Standard New Instructions |
|
||||
| AMD3DNOW | AMD 3DNOW |
|
||||
| AMD3DNOWEXT | AMD 3DNowExt |
|
||||
| AMXBF16 | Tile computational operations on BFLOAT16 numbers |
|
||||
| AMXINT8 | Tile computational operations on 8-bit integers |
|
||||
| AMXFP16 | Tile computational operations on FP16 numbers |
|
||||
| AMXFP8 | Tile computational operations on FP8 numbers |
|
||||
| AMXCOMPLEX | Tile computational operations on complex numbers |
|
||||
| AMXTILE | Tile architecture |
|
||||
| AMXTF32 | Matrix Multiplication of TF32 Tiles into Packed Single Precision Tile |
|
||||
| AMXTRANSPOSE | Tile multiply where the first operand is transposed |
|
||||
| APX_F | Intel APX |
|
||||
| AVX | AVX functions |
|
||||
| AVX10 | If set the Intel AVX10 Converged Vector ISA is supported |
|
||||
| AVX10_128 | If set indicates that AVX10 128-bit vector support is present |
|
||||
| AVX10_256 | If set indicates that AVX10 256-bit vector support is present |
|
||||
| AVX10_512 | If set indicates that AVX10 512-bit vector support is present |
|
||||
| AVX2 | AVX2 functions |
|
||||
| AVX512BF16 | AVX-512 BFLOAT16 Instructions |
|
||||
| AVX512BITALG | AVX-512 Bit Algorithms |
|
||||
| AVX512BW | AVX-512 Byte and Word Instructions |
|
||||
| AVX512CD | AVX-512 Conflict Detection Instructions |
|
||||
| AVX512DQ | AVX-512 Doubleword and Quadword Instructions |
|
||||
| AVX512ER | AVX-512 Exponential and Reciprocal Instructions |
|
||||
| AVX512F | AVX-512 Foundation |
|
||||
| AVX512FP16 | AVX-512 FP16 Instructions |
|
||||
| AVX512IFMA | AVX-512 Integer Fused Multiply-Add Instructions |
|
||||
| AVX512PF | AVX-512 Prefetch Instructions |
|
||||
| AVX512VBMI | AVX-512 Vector Bit Manipulation Instructions |
|
||||
| AVX512VBMI2 | AVX-512 Vector Bit Manipulation Instructions, Version 2 |
|
||||
| AVX512VL | AVX-512 Vector Length Extensions |
|
||||
| AVX512VNNI | AVX-512 Vector Neural Network Instructions |
|
||||
| AVX512VP2INTERSECT | AVX-512 Intersect for D/Q |
|
||||
| AVX512VPOPCNTDQ | AVX-512 Vector Population Count Doubleword and Quadword |
|
||||
| AVXIFMA | AVX-IFMA instructions |
|
||||
| AVXNECONVERT | AVX-NE-CONVERT instructions |
|
||||
| AVXSLOW | Indicates the CPU performs 2 128 bit operations instead of one |
|
||||
| AVXVNNI | AVX (VEX encoded) VNNI neural network instructions |
|
||||
| AVXVNNIINT8 | AVX-VNNI-INT8 instructions |
|
||||
| AVXVNNIINT16 | AVX-VNNI-INT16 instructions |
|
||||
| BHI_CTRL | Branch History Injection and Intra-mode Branch Target Injection / CVE-2022-0001, CVE-2022-0002 / INTEL-SA-00598 |
|
||||
| BMI1 | Bit Manipulation Instruction Set 1 |
|
||||
| BMI2 | Bit Manipulation Instruction Set 2 |
|
||||
| CETIBT | Intel CET Indirect Branch Tracking |
|
||||
| CETSS | Intel CET Shadow Stack |
|
||||
| CLDEMOTE | Cache Line Demote |
|
||||
| CLMUL | Carry-less Multiplication |
|
||||
| CLZERO | CLZERO instruction supported |
|
||||
| CMOV | i686 CMOV |
|
||||
| CMPCCXADD | CMPCCXADD instructions |
|
||||
| CMPSB_SCADBS_SHORT | Fast short CMPSB and SCASB |
|
||||
| CMPXCHG8 | CMPXCHG8 instruction |
|
||||
| CPBOOST | Core Performance Boost |
|
||||
| CPPC | AMD: Collaborative Processor Performance Control |
|
||||
| CX16 | CMPXCHG16B Instruction |
|
||||
| EFER_LMSLE_UNS | AMD: =Core::X86::Msr::EFER[LMSLE] is not supported, and MBZ |
|
||||
| ENQCMD | Enqueue Command |
|
||||
| ERMS | Enhanced REP MOVSB/STOSB |
|
||||
| F16C | Half-precision floating-point conversion |
|
||||
| FLUSH_L1D | Flush L1D cache |
|
||||
| FMA3 | Intel FMA 3. Does not imply AVX. |
|
||||
| FMA4 | Bulldozer FMA4 functions |
|
||||
| FP128 | AMD: When set, the internal FP/SIMD execution datapath is 128-bits wide |
|
||||
| FP256 | AMD: When set, the internal FP/SIMD execution datapath is 256-bits wide |
|
||||
| FSRM | Fast Short Rep Mov |
|
||||
| FXSR | FXSAVE, FXRESTOR instructions, CR4 bit 9 |
|
||||
| FXSROPT | FXSAVE/FXRSTOR optimizations |
|
||||
| GFNI | Galois Field New Instructions. May require other features (AVX, AVX512VL,AVX512F) based on usage. |
|
||||
| HLE | Hardware Lock Elision |
|
||||
| HRESET | If set CPU supports history reset and the IA32_HRESET_ENABLE MSR |
|
||||
| HTT | Hyperthreading (enabled) |
|
||||
| HWA | Hardware assert supported. Indicates support for MSRC001_10 |
|
||||
| HYBRID_CPU | This part has CPUs of more than one type. |
|
||||
| HYPERVISOR | This bit has been reserved by Intel & AMD for use by hypervisors |
|
||||
| IA32_ARCH_CAP | IA32_ARCH_CAPABILITIES MSR (Intel) |
|
||||
| IA32_CORE_CAP | IA32_CORE_CAPABILITIES MSR |
|
||||
| IBPB | Indirect Branch Restricted Speculation (IBRS) and Indirect Branch Predictor Barrier (IBPB) |
|
||||
| IBRS | AMD: Indirect Branch Restricted Speculation |
|
||||
| IBRS_PREFERRED | AMD: IBRS is preferred over software solution |
|
||||
| IBRS_PROVIDES_SMP | AMD: IBRS provides Same Mode Protection |
|
||||
| IBS | Instruction Based Sampling (AMD) |
|
||||
| IBSBRNTRGT | Instruction Based Sampling Feature (AMD) |
|
||||
| IBSFETCHSAM | Instruction Based Sampling Feature (AMD) |
|
||||
| IBSFFV | Instruction Based Sampling Feature (AMD) |
|
||||
| IBSOPCNT | Instruction Based Sampling Feature (AMD) |
|
||||
| IBSOPCNTEXT | Instruction Based Sampling Feature (AMD) |
|
||||
| IBSOPSAM | Instruction Based Sampling Feature (AMD) |
|
||||
| IBSRDWROPCNT | Instruction Based Sampling Feature (AMD) |
|
||||
| IBSRIPINVALIDCHK | Instruction Based Sampling Feature (AMD) |
|
||||
| IBS_FETCH_CTLX | AMD: IBS fetch control extended MSR supported |
|
||||
| IBS_OPDATA4 | AMD: IBS op data 4 MSR supported |
|
||||
| IBS_OPFUSE | AMD: Indicates support for IbsOpFuse |
|
||||
| IBS_PREVENTHOST | Disallowing IBS use by the host supported |
|
||||
| IBS_ZEN4 | Fetch and Op IBS support IBS extensions added with Zen4 |
|
||||
| IDPRED_CTRL | IPRED_DIS |
|
||||
| INT_WBINVD | WBINVD/WBNOINVD are interruptible. |
|
||||
| INVLPGB | NVLPGB and TLBSYNC instruction supported |
|
||||
| KEYLOCKER | Key locker |
|
||||
| KEYLOCKERW | Key locker wide |
|
||||
| LAHF | LAHF/SAHF in long mode |
|
||||
| LAM | If set, CPU supports Linear Address Masking |
|
||||
| LBRVIRT | LBR virtualization |
|
||||
| LZCNT | LZCNT instruction |
|
||||
| MCAOVERFLOW | MCA overflow recovery support. |
|
||||
| MCDT_NO | Processor do not exhibit MXCSR Configuration Dependent Timing behavior and do not need to mitigate it. |
|
||||
| MCOMMIT | MCOMMIT instruction supported |
|
||||
| MD_CLEAR | VERW clears CPU buffers |
|
||||
| MMX | standard MMX |
|
||||
| MMXEXT | SSE integer functions or AMD MMX ext |
|
||||
| MOVBE | MOVBE instruction (big-endian) |
|
||||
| MOVDIR64B | Move 64 Bytes as Direct Store |
|
||||
| MOVDIRI | Move Doubleword as Direct Store |
|
||||
| MOVSB_ZL | Fast Zero-Length MOVSB |
|
||||
| MPX | Intel MPX (Memory Protection Extensions) |
|
||||
| MOVU | MOVU SSE instructions are more efficient and should be preferred to SSE MOVL/MOVH. MOVUPS is more efficient than MOVLPS/MOVHPS. MOVUPD is more efficient than MOVLPD/MOVHPD |
|
||||
| MSRIRC | Instruction Retired Counter MSR available |
|
||||
| MSRLIST | Read/Write List of Model Specific Registers |
|
||||
| MSR_PAGEFLUSH | Page Flush MSR available |
|
||||
| NRIPS | Indicates support for NRIP save on VMEXIT |
|
||||
| NX | NX (No-Execute) bit |
|
||||
| OSXSAVE | XSAVE enabled by OS |
|
||||
| PCONFIG | PCONFIG for Intel Multi-Key Total Memory Encryption |
|
||||
| POPCNT | POPCNT instruction |
|
||||
| PPIN | AMD: Protected Processor Inventory Number support. Indicates that Protected Processor Inventory Number (PPIN) capability can be enabled |
|
||||
| PREFETCHI | PREFETCHIT0/1 instructions |
|
||||
| PSFD | Predictive Store Forward Disable |
|
||||
| RDPRU | RDPRU instruction supported |
|
||||
| RDRAND | RDRAND instruction is available |
|
||||
| RDSEED | RDSEED instruction is available |
|
||||
| RDTSCP | RDTSCP Instruction |
|
||||
| RRSBA_CTRL | Restricted RSB Alternate |
|
||||
| RTM | Restricted Transactional Memory |
|
||||
| RTM_ALWAYS_ABORT | Indicates that the loaded microcode is forcing RTM abort. |
|
||||
| SERIALIZE | Serialize Instruction Execution |
|
||||
| SEV | AMD Secure Encrypted Virtualization supported |
|
||||
| SEV_64BIT | AMD SEV guest execution only allowed from a 64-bit host |
|
||||
| SEV_ALTERNATIVE | AMD SEV Alternate Injection supported |
|
||||
| SEV_DEBUGSWAP | Full debug state swap supported for SEV-ES guests |
|
||||
| SEV_ES | AMD SEV Encrypted State supported |
|
||||
| SEV_RESTRICTED | AMD SEV Restricted Injection supported |
|
||||
| SEV_SNP | AMD SEV Secure Nested Paging supported |
|
||||
| SGX | Software Guard Extensions |
|
||||
| SGXLC | Software Guard Extensions Launch Control |
|
||||
| SGXPQC | Software Guard Extensions 256-bit Encryption |
|
||||
| SHA | Intel SHA Extensions |
|
||||
| SME | AMD Secure Memory Encryption supported |
|
||||
| SME_COHERENT | AMD Hardware cache coherency across encryption domains enforced |
|
||||
| SM3_X86 | SM3 instructions |
|
||||
| SM4_X86 | SM4 instructions |
|
||||
| SPEC_CTRL_SSBD | Speculative Store Bypass Disable |
|
||||
| SRBDS_CTRL | SRBDS mitigation MSR available |
|
||||
| SSE | SSE functions |
|
||||
| SSE2 | P4 SSE functions |
|
||||
| SSE3 | Prescott SSE3 functions |
|
||||
| SSE4 | Penryn SSE4.1 functions |
|
||||
| SSE42 | Nehalem SSE4.2 functions |
|
||||
| SSE4A | AMD Barcelona microarchitecture SSE4a instructions |
|
||||
| SSSE3 | Conroe SSSE3 functions |
|
||||
| STIBP | Single Thread Indirect Branch Predictors |
|
||||
| STIBP_ALWAYSON | AMD: Single Thread Indirect Branch Prediction Mode has Enhanced Performance and may be left Always On |
|
||||
| STOSB_SHORT | Fast short STOSB |
|
||||
| SUCCOR | Software uncorrectable error containment and recovery capability. |
|
||||
| SVM | AMD Secure Virtual Machine |
|
||||
| SVMDA | Indicates support for the SVM decode assists. |
|
||||
| SVMFBASID | SVM, Indicates that TLB flush events, including CR3 writes and CR4.PGE toggles, flush only the current ASID's TLB entries. Also indicates support for the extended VMCBTLB_Control |
|
||||
| SVML | AMD SVM lock. Indicates support for SVM-Lock. |
|
||||
| SVMNP | AMD SVM nested paging |
|
||||
| SVMPF | SVM pause intercept filter. Indicates support for the pause intercept filter |
|
||||
| SVMPFT | SVM PAUSE filter threshold. Indicates support for the PAUSE filter cycle count threshold |
|
||||
| SYSCALL | System-Call Extension (SCE): SYSCALL and SYSRET instructions. |
|
||||
| SYSEE | SYSENTER and SYSEXIT instructions |
|
||||
| TBM | AMD Trailing Bit Manipulation |
|
||||
| TDX_GUEST | Intel Trust Domain Extensions Guest |
|
||||
| TLB_FLUSH_NESTED | AMD: Flushing includes all the nested translations for guest translations |
|
||||
| TME | Intel Total Memory Encryption. The following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE. |
|
||||
| TOPEXT | TopologyExtensions: topology extensions support. Indicates support for CPUID Fn8000_001D_EAX_x[N:0]-CPUID Fn8000_001E_EDX. |
|
||||
| TSA_L1_NO | AMD only: Not vulnerable to TSA-L1 |
|
||||
| TSA_SQ_NO | AMD only: Not vulnerable to TSA-SQ |
|
||||
| TSA_VERW_CLEAR | AMD: If set, the memory form of the VERW instruction may be used to help mitigate TSA |
|
||||
| TSCRATEMSR | MSR based TSC rate control. Indicates support for MSR TSC ratio MSRC000_0104 |
|
||||
| TSXLDTRK | Intel TSX Suspend Load Address Tracking |
|
||||
| VAES | Vector AES. AVX(512) versions requires additional checks. |
|
||||
| VMCBCLEAN | VMCB clean bits. Indicates support for VMCB clean bits. |
|
||||
| VMPL | AMD VM Permission Levels supported |
|
||||
| VMSA_REGPROT | AMD VMSA Register Protection supported |
|
||||
| VMX | Virtual Machine Extensions |
|
||||
| VPCLMULQDQ | Carry-Less Multiplication Quadword. Requires AVX for 3 register versions. |
|
||||
| VTE | AMD Virtual Transparent Encryption supported |
|
||||
| WAITPKG | TPAUSE, UMONITOR, UMWAIT |
|
||||
| WBNOINVD | Write Back and Do Not Invalidate Cache |
|
||||
| WRMSRNS | Non-Serializing Write to Model Specific Register |
|
||||
| X87 | FPU |
|
||||
| XGETBV1 | Supports XGETBV with ECX = 1 |
|
||||
| XOP | Bulldozer XOP functions |
|
||||
| XSAVE | XSAVE, XRESTOR, XSETBV, XGETBV |
|
||||
| XSAVEC | Supports XSAVEC and the compacted form of XRSTOR. |
|
||||
| XSAVEOPT | XSAVEOPT available |
|
||||
| XSAVES | Supports XSAVES/XRSTORS and IA32_XSS |
|
||||
|
||||
# ARM features:
|
||||
|
||||
| Feature Flag | Description |
|
||||
|--------------|------------------------------------------------------------------|
|
||||
| AESARM | AES instructions |
|
||||
| ARMCPUID | Some CPU ID registers readable at user-level |
|
||||
| ASIMD | Advanced SIMD |
|
||||
| ASIMDDP | SIMD Dot Product |
|
||||
| ASIMDHP | Advanced SIMD half-precision floating point |
|
||||
| ASIMDRDM | Rounding Double Multiply Accumulate/Subtract (SQRDMLAH/SQRDMLSH) |
|
||||
| ATOMICS | Large System Extensions (LSE) |
|
||||
| CRC32 | CRC32/CRC32C instructions |
|
||||
| DCPOP | Data cache clean to Point of Persistence (DC CVAP) |
|
||||
| EVTSTRM | Generic timer |
|
||||
| FCMA | Floatin point complex number addition and multiplication |
|
||||
| FHM | FMLAL and FMLSL instructions |
|
||||
| FP | Single-precision and double-precision floating point |
|
||||
| FPHP | Half-precision floating point |
|
||||
| GPA | Generic Pointer Authentication |
|
||||
| JSCVT | Javascript-style double->int convert (FJCVTZS) |
|
||||
| LRCPC | Weaker release consistency (LDAPR, etc) |
|
||||
| PMULL | Polynomial Multiply instructions (PMULL/PMULL2) |
|
||||
| RNDR | Random Number instructions |
|
||||
| TLB | Outer Shareable and TLB range maintenance instructions |
|
||||
| TS | Flag manipulation instructions |
|
||||
| SHA1 | SHA-1 instructions (SHA1C, etc) |
|
||||
| SHA2 | SHA-2 instructions (SHA256H, etc) |
|
||||
| SHA3 | SHA-3 instructions (EOR3, RAXI, XAR, BCAX) |
|
||||
| SHA512 | SHA512 instructions |
|
||||
| SM3 | SM3 instructions |
|
||||
| SM4 | SM4 instructions |
|
||||
| SVE | Scalable Vector Extension |
|
||||
|
||||
# license
|
||||
|
||||
This code is published under an MIT license. See LICENSE file for more information.
|
||||
-1679
File diff suppressed because it is too large
Load Diff
-47
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build 386,!gccgo,!noasm,!appengine
|
||||
|
||||
// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuid(SB), 7, $0
|
||||
XORL CX, CX
|
||||
MOVL op+0(FP), AX
|
||||
CPUID
|
||||
MOVL AX, eax+4(FP)
|
||||
MOVL BX, ebx+8(FP)
|
||||
MOVL CX, ecx+12(FP)
|
||||
MOVL DX, edx+16(FP)
|
||||
RET
|
||||
|
||||
// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuidex(SB), 7, $0
|
||||
MOVL op+0(FP), AX
|
||||
MOVL op2+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func xgetbv(index uint32) (eax, edx uint32)
|
||||
TEXT ·asmXgetbv(SB), 7, $0
|
||||
MOVL index+0(FP), CX
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
|
||||
MOVL AX, eax+4(FP)
|
||||
MOVL DX, edx+8(FP)
|
||||
RET
|
||||
|
||||
// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmRdtscpAsm(SB), 7, $0
|
||||
BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
|
||||
MOVL AX, eax+0(FP)
|
||||
MOVL BX, ebx+4(FP)
|
||||
MOVL CX, ecx+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
|
||||
// func asmDarwinHasAVX512() bool
|
||||
TEXT ·asmDarwinHasAVX512(SB), 7, $0
|
||||
MOVL $0, eax+0(FP)
|
||||
RET
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build amd64,!gccgo,!noasm,!appengine
|
||||
|
||||
// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuid(SB), 7, $0
|
||||
XORQ CX, CX
|
||||
MOVL op+0(FP), AX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuidex(SB), 7, $0
|
||||
MOVL op+0(FP), AX
|
||||
MOVL op2+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func asmXgetbv(index uint32) (eax, edx uint32)
|
||||
TEXT ·asmXgetbv(SB), 7, $0
|
||||
MOVL index+0(FP), CX
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
|
||||
// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmRdtscpAsm(SB), 7, $0
|
||||
BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
|
||||
MOVL AX, eax+0(FP)
|
||||
MOVL BX, ebx+4(FP)
|
||||
MOVL CX, ecx+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
|
||||
// From https://go-review.googlesource.com/c/sys/+/285572/
|
||||
// func asmDarwinHasAVX512() bool
|
||||
TEXT ·asmDarwinHasAVX512(SB), 7, $0-1
|
||||
MOVB $0, ret+0(FP) // default to false
|
||||
|
||||
#ifdef GOOS_darwin // return if not darwin
|
||||
#ifdef GOARCH_amd64 // return if not amd64
|
||||
// These values from:
|
||||
// https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h
|
||||
#define commpage64_base_address 0x00007fffffe00000
|
||||
#define commpage64_cpu_capabilities64 (commpage64_base_address+0x010)
|
||||
#define commpage64_version (commpage64_base_address+0x01E)
|
||||
#define hasAVX512F 0x0000004000000000
|
||||
MOVQ $commpage64_version, BX
|
||||
MOVW (BX), AX
|
||||
CMPW AX, $13 // versions < 13 do not support AVX512
|
||||
JL no_avx512
|
||||
MOVQ $commpage64_cpu_capabilities64, BX
|
||||
MOVQ (BX), AX
|
||||
MOVQ $hasAVX512F, CX
|
||||
ANDQ CX, AX
|
||||
JZ no_avx512
|
||||
MOVB $1, ret+0(FP)
|
||||
|
||||
no_avx512:
|
||||
#endif
|
||||
#endif
|
||||
RET
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build arm64,!gccgo,!noasm,!appengine
|
||||
|
||||
// See https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
|
||||
|
||||
// func getMidr
|
||||
TEXT ·getMidr(SB), 7, $0
|
||||
WORD $0xd5380000 // mrs x0, midr_el1 /* Main ID Register */
|
||||
MOVD R0, midr+0(FP)
|
||||
RET
|
||||
|
||||
// func getProcFeatures
|
||||
TEXT ·getProcFeatures(SB), 7, $0
|
||||
WORD $0xd5380400 // mrs x0, id_aa64pfr0_el1 /* Processor Feature Register 0 */
|
||||
MOVD R0, procFeatures+0(FP)
|
||||
RET
|
||||
|
||||
// func getInstAttributes
|
||||
TEXT ·getInstAttributes(SB), 7, $0
|
||||
WORD $0xd5380600 // mrs x0, id_aa64isar0_el1 /* Instruction Set Attribute Register 0 */
|
||||
WORD $0xd5380621 // mrs x1, id_aa64isar1_el1 /* Instruction Set Attribute Register 1 */
|
||||
MOVD R0, instAttrReg0+0(FP)
|
||||
MOVD R1, instAttrReg1+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·getVectorLength(SB), 7, $0
|
||||
WORD $0xd2800002 // mov x2, #0
|
||||
WORD $0x04225022 // addvl x2, x2, #1
|
||||
WORD $0xd37df042 // lsl x2, x2, #3
|
||||
WORD $0xd2800003 // mov x3, #0
|
||||
WORD $0x04635023 // addpl x3, x3, #1
|
||||
WORD $0xd37df063 // lsl x3, x3, #3
|
||||
MOVD R2, vl+0(FP)
|
||||
MOVD R3, pl+8(FP)
|
||||
RET
|
||||
-250
@@ -1,250 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build arm64 && !gccgo && !noasm && !appengine
|
||||
// +build arm64,!gccgo,!noasm,!appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
import "runtime"
|
||||
|
||||
func getMidr() (midr uint64)
|
||||
func getProcFeatures() (procFeatures uint64)
|
||||
func getInstAttributes() (instAttrReg0, instAttrReg1 uint64)
|
||||
func getVectorLength() (vl, pl uint64)
|
||||
|
||||
func initCPU() {
|
||||
cpuid = func(uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
cpuidex = func(x, y uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
xgetbv = func(uint32) (a, b uint32) { return 0, 0 }
|
||||
rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
}
|
||||
|
||||
func addInfo(c *CPUInfo, safe bool) {
|
||||
// Seems to be safe to assume on ARM64
|
||||
c.CacheLine = 64
|
||||
detectOS(c)
|
||||
|
||||
// ARM64 disabled since it may crash if interrupt is not intercepted by OS.
|
||||
if safe && !c.Has(ARMCPUID) && runtime.GOOS != "freebsd" {
|
||||
return
|
||||
}
|
||||
midr := getMidr()
|
||||
|
||||
// MIDR_EL1 - Main ID Register
|
||||
// https://developer.arm.com/docs/ddi0595/h/aarch64-system-registers/midr_el1
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | Implementer | [31-24] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | Variant | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | Architecture | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | PartNum | [15-4] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | Revision | [3-0] | y |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
switch (midr >> 24) & 0xff {
|
||||
case 0xC0:
|
||||
c.VendorString = "Ampere Computing"
|
||||
c.VendorID = Ampere
|
||||
case 0x41:
|
||||
c.VendorString = "Arm Limited"
|
||||
c.VendorID = ARM
|
||||
case 0x42:
|
||||
c.VendorString = "Broadcom Corporation"
|
||||
c.VendorID = Broadcom
|
||||
case 0x43:
|
||||
c.VendorString = "Cavium Inc"
|
||||
c.VendorID = Cavium
|
||||
case 0x44:
|
||||
c.VendorString = "Digital Equipment Corporation"
|
||||
c.VendorID = DEC
|
||||
case 0x46:
|
||||
c.VendorString = "Fujitsu Ltd"
|
||||
c.VendorID = Fujitsu
|
||||
case 0x49:
|
||||
c.VendorString = "Infineon Technologies AG"
|
||||
c.VendorID = Infineon
|
||||
case 0x4D:
|
||||
c.VendorString = "Motorola or Freescale Semiconductor Inc"
|
||||
c.VendorID = Motorola
|
||||
case 0x4E:
|
||||
c.VendorString = "NVIDIA Corporation"
|
||||
c.VendorID = NVIDIA
|
||||
case 0x50:
|
||||
c.VendorString = "Applied Micro Circuits Corporation"
|
||||
c.VendorID = AMCC
|
||||
case 0x51:
|
||||
c.VendorString = "Qualcomm Inc"
|
||||
c.VendorID = Qualcomm
|
||||
case 0x56:
|
||||
c.VendorString = "Marvell International Ltd"
|
||||
c.VendorID = Marvell
|
||||
case 0x69:
|
||||
c.VendorString = "Intel Corporation"
|
||||
c.VendorID = Intel
|
||||
}
|
||||
|
||||
// Lower 4 bits: Architecture
|
||||
// Architecture Meaning
|
||||
// 0b0001 Armv4.
|
||||
// 0b0010 Armv4T.
|
||||
// 0b0011 Armv5 (obsolete).
|
||||
// 0b0100 Armv5T.
|
||||
// 0b0101 Armv5TE.
|
||||
// 0b0110 Armv5TEJ.
|
||||
// 0b0111 Armv6.
|
||||
// 0b1111 Architectural features are individually identified in the ID_* registers, see 'ID registers'.
|
||||
// Upper 4 bit: Variant
|
||||
// An IMPLEMENTATION DEFINED variant number.
|
||||
// Typically, this field is used to distinguish between different product variants, or major revisions of a product.
|
||||
c.Family = int(midr>>16) & 0xff
|
||||
|
||||
// PartNum, bits [15:4]
|
||||
// An IMPLEMENTATION DEFINED primary part number for the device.
|
||||
// On processors implemented by Arm, if the top four bits of the primary
|
||||
// part number are 0x0 or 0x7, the variant and architecture are encoded differently.
|
||||
// Revision, bits [3:0]
|
||||
// An IMPLEMENTATION DEFINED revision number for the device.
|
||||
c.Model = int(midr) & 0xffff
|
||||
|
||||
procFeatures := getProcFeatures()
|
||||
|
||||
// ID_AA64PFR0_EL1 - Processor Feature Register 0
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | DIT | [51-48] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SVE | [35-32] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | GIC | [27-24] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | AdvSIMD | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | FP | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | EL3 | [15-12] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | EL2 | [11-8] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | EL1 | [7-4] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | EL0 | [3-0] | n |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
var f flagSet
|
||||
// if procFeatures&(0xf<<48) != 0 {
|
||||
// fmt.Println("DIT")
|
||||
// }
|
||||
f.setIf(procFeatures&(0xf<<32) != 0, SVE)
|
||||
if procFeatures&(0xf<<20) != 15<<20 {
|
||||
f.set(ASIMD)
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64pfr0_el1
|
||||
// 0b0001 --> As for 0b0000, and also includes support for half-precision floating-point arithmetic.
|
||||
f.setIf(procFeatures&(0xf<<20) == 1<<20, FPHP, ASIMDHP)
|
||||
}
|
||||
f.setIf(procFeatures&(0xf<<16) != 0, FP)
|
||||
|
||||
instAttrReg0, instAttrReg1 := getInstAttributes()
|
||||
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
|
||||
//
|
||||
// ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | RNDR | [63-60] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | TLB | [59-56] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | TS | [55-52] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | FHM | [51-48] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | DP | [47-44] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SM4 | [43-40] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SM3 | [39-36] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SHA3 | [35-32] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | RDM | [31-28] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | ATOMICS | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | CRC32 | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SHA2 | [15-12] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SHA1 | [11-8] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | AES | [7-4] | y |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
f.setIf(instAttrReg0&(0xf<<60) != 0, RNDR)
|
||||
f.setIf(instAttrReg0&(0xf<<56) != 0, TLB)
|
||||
f.setIf(instAttrReg0&(0xf<<52) != 0, TS)
|
||||
f.setIf(instAttrReg0&(0xf<<48) != 0, FHM)
|
||||
f.setIf(instAttrReg0&(0xf<<44) != 0, ASIMDDP)
|
||||
f.setIf(instAttrReg0&(0xf<<40) != 0, SM4)
|
||||
f.setIf(instAttrReg0&(0xf<<36) != 0, SM3)
|
||||
f.setIf(instAttrReg0&(0xf<<32) != 0, SHA3)
|
||||
f.setIf(instAttrReg0&(0xf<<28) != 0, ASIMDRDM)
|
||||
f.setIf(instAttrReg0&(0xf<<20) != 0, ATOMICS)
|
||||
f.setIf(instAttrReg0&(0xf<<16) != 0, CRC32)
|
||||
f.setIf(instAttrReg0&(0xf<<12) != 0, SHA2)
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
|
||||
// 0b0010 --> As 0b0001, plus SHA512H, SHA512H2, SHA512SU0, and SHA512SU1 instructions implemented.
|
||||
f.setIf(instAttrReg0&(0xf<<12) == 2<<12, SHA512)
|
||||
f.setIf(instAttrReg0&(0xf<<8) != 0, SHA1)
|
||||
f.setIf(instAttrReg0&(0xf<<4) != 0, AESARM)
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
|
||||
// 0b0010 --> As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit data quantities.
|
||||
f.setIf(instAttrReg0&(0xf<<4) == 2<<4, PMULL)
|
||||
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar1_el1
|
||||
//
|
||||
// ID_AA64ISAR1_EL1 - Instruction set attribute register 1
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | GPI | [31-28] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | GPA | [27-24] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | LRCPC | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | FCMA | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | JSCVT | [15-12] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | API | [11-8] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | APA | [7-4] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | DPB | [3-0] | y |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
// if instAttrReg1&(0xf<<28) != 0 {
|
||||
// fmt.Println("GPI")
|
||||
// }
|
||||
f.setIf(instAttrReg1&(0xf<<28) != 24, GPA)
|
||||
f.setIf(instAttrReg1&(0xf<<20) != 0, LRCPC)
|
||||
f.setIf(instAttrReg1&(0xf<<16) != 0, FCMA)
|
||||
f.setIf(instAttrReg1&(0xf<<12) != 0, JSCVT)
|
||||
// if instAttrReg1&(0xf<<8) != 0 {
|
||||
// fmt.Println("API")
|
||||
// }
|
||||
// if instAttrReg1&(0xf<<4) != 0 {
|
||||
// fmt.Println("APA")
|
||||
// }
|
||||
f.setIf(instAttrReg1&(0xf<<0) != 0, DCPOP)
|
||||
|
||||
// Store
|
||||
c.featureSet.or(f)
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build (!amd64 && !386 && !arm64) || gccgo || noasm || appengine
|
||||
// +build !amd64,!386,!arm64 gccgo noasm appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
func initCPU() {
|
||||
cpuid = func(uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
cpuidex = func(x, y uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
xgetbv = func(uint32) (a, b uint32) { return 0, 0 }
|
||||
rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
|
||||
}
|
||||
|
||||
func addInfo(info *CPUInfo, safe bool) {}
|
||||
func getVectorLength() (vl, pl uint64) { return 0, 0 }
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build (386 && !gccgo && !noasm && !appengine) || (amd64 && !gccgo && !noasm && !appengine)
|
||||
// +build 386,!gccgo,!noasm,!appengine amd64,!gccgo,!noasm,!appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
|
||||
func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
|
||||
func asmXgetbv(index uint32) (eax, edx uint32)
|
||||
func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
|
||||
func asmDarwinHasAVX512() bool
|
||||
|
||||
func initCPU() {
|
||||
cpuid = asmCpuid
|
||||
cpuidex = asmCpuidex
|
||||
xgetbv = asmXgetbv
|
||||
rdtscpAsm = asmRdtscpAsm
|
||||
darwinHasAVX512 = asmDarwinHasAVX512
|
||||
}
|
||||
|
||||
func addInfo(c *CPUInfo, safe bool) {
|
||||
c.maxFunc = maxFunctionID()
|
||||
c.maxExFunc = maxExtendedFunction()
|
||||
c.BrandName = brandName()
|
||||
c.CacheLine = cacheLine()
|
||||
c.Family, c.Model, c.Stepping = familyModel()
|
||||
c.featureSet = support()
|
||||
c.SGX = hasSGX(c.featureSet.inSet(SGX), c.featureSet.inSet(SGXLC))
|
||||
c.AMDMemEncryption = hasAMDMemEncryption(c.featureSet.inSet(SME) || c.featureSet.inSet(SEV))
|
||||
c.ThreadsPerCore = threadsPerCore()
|
||||
c.LogicalCores = logicalCores()
|
||||
c.PhysicalCores = physicalCores()
|
||||
c.VendorID, c.VendorString = vendorID()
|
||||
c.HypervisorVendorID, c.HypervisorVendorString = hypervisorVendorID()
|
||||
c.AVX10Level = c.supportAVX10()
|
||||
c.cacheSize()
|
||||
c.frequencies()
|
||||
if c.maxFunc >= 0x0A {
|
||||
eax, ebx, _, edx := cpuid(0x0A)
|
||||
c.PMU = parseLeaf0AH(c, eax, ebx, edx)
|
||||
}
|
||||
}
|
||||
|
||||
func getVectorLength() (vl, pl uint64) { return 0, 0 }
|
||||
-308
@@ -1,308 +0,0 @@
|
||||
// Code generated by "stringer -type=FeatureID,Vendor"; DO NOT EDIT.
|
||||
|
||||
package cpuid
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ADX-1]
|
||||
_ = x[AESNI-2]
|
||||
_ = x[AMD3DNOW-3]
|
||||
_ = x[AMD3DNOWEXT-4]
|
||||
_ = x[AMXBF16-5]
|
||||
_ = x[AMXFP16-6]
|
||||
_ = x[AMXINT8-7]
|
||||
_ = x[AMXFP8-8]
|
||||
_ = x[AMXTILE-9]
|
||||
_ = x[AMXTF32-10]
|
||||
_ = x[AMXCOMPLEX-11]
|
||||
_ = x[AMXTRANSPOSE-12]
|
||||
_ = x[APX_F-13]
|
||||
_ = x[AVX-14]
|
||||
_ = x[AVX10-15]
|
||||
_ = x[AVX10_128-16]
|
||||
_ = x[AVX10_256-17]
|
||||
_ = x[AVX10_512-18]
|
||||
_ = x[AVX2-19]
|
||||
_ = x[AVX512BF16-20]
|
||||
_ = x[AVX512BITALG-21]
|
||||
_ = x[AVX512BW-22]
|
||||
_ = x[AVX512CD-23]
|
||||
_ = x[AVX512DQ-24]
|
||||
_ = x[AVX512ER-25]
|
||||
_ = x[AVX512F-26]
|
||||
_ = x[AVX512FP16-27]
|
||||
_ = x[AVX512IFMA-28]
|
||||
_ = x[AVX512PF-29]
|
||||
_ = x[AVX512VBMI-30]
|
||||
_ = x[AVX512VBMI2-31]
|
||||
_ = x[AVX512VL-32]
|
||||
_ = x[AVX512VNNI-33]
|
||||
_ = x[AVX512VP2INTERSECT-34]
|
||||
_ = x[AVX512VPOPCNTDQ-35]
|
||||
_ = x[AVXIFMA-36]
|
||||
_ = x[AVXNECONVERT-37]
|
||||
_ = x[AVXSLOW-38]
|
||||
_ = x[AVXVNNI-39]
|
||||
_ = x[AVXVNNIINT8-40]
|
||||
_ = x[AVXVNNIINT16-41]
|
||||
_ = x[BHI_CTRL-42]
|
||||
_ = x[BMI1-43]
|
||||
_ = x[BMI2-44]
|
||||
_ = x[CETIBT-45]
|
||||
_ = x[CETSS-46]
|
||||
_ = x[CLDEMOTE-47]
|
||||
_ = x[CLMUL-48]
|
||||
_ = x[CLZERO-49]
|
||||
_ = x[CMOV-50]
|
||||
_ = x[CMPCCXADD-51]
|
||||
_ = x[CMPSB_SCADBS_SHORT-52]
|
||||
_ = x[CMPXCHG8-53]
|
||||
_ = x[CPBOOST-54]
|
||||
_ = x[CPPC-55]
|
||||
_ = x[CX16-56]
|
||||
_ = x[EFER_LMSLE_UNS-57]
|
||||
_ = x[ENQCMD-58]
|
||||
_ = x[ERMS-59]
|
||||
_ = x[F16C-60]
|
||||
_ = x[FLUSH_L1D-61]
|
||||
_ = x[FMA3-62]
|
||||
_ = x[FMA4-63]
|
||||
_ = x[FP128-64]
|
||||
_ = x[FP256-65]
|
||||
_ = x[FSRM-66]
|
||||
_ = x[FXSR-67]
|
||||
_ = x[FXSROPT-68]
|
||||
_ = x[GFNI-69]
|
||||
_ = x[HLE-70]
|
||||
_ = x[HRESET-71]
|
||||
_ = x[HTT-72]
|
||||
_ = x[HWA-73]
|
||||
_ = x[HYBRID_CPU-74]
|
||||
_ = x[HYPERVISOR-75]
|
||||
_ = x[IA32_ARCH_CAP-76]
|
||||
_ = x[IA32_CORE_CAP-77]
|
||||
_ = x[IBPB-78]
|
||||
_ = x[IBPB_BRTYPE-79]
|
||||
_ = x[IBRS-80]
|
||||
_ = x[IBRS_PREFERRED-81]
|
||||
_ = x[IBRS_PROVIDES_SMP-82]
|
||||
_ = x[IBS-83]
|
||||
_ = x[IBSBRNTRGT-84]
|
||||
_ = x[IBSFETCHSAM-85]
|
||||
_ = x[IBSFFV-86]
|
||||
_ = x[IBSOPCNT-87]
|
||||
_ = x[IBSOPCNTEXT-88]
|
||||
_ = x[IBSOPSAM-89]
|
||||
_ = x[IBSRDWROPCNT-90]
|
||||
_ = x[IBSRIPINVALIDCHK-91]
|
||||
_ = x[IBS_FETCH_CTLX-92]
|
||||
_ = x[IBS_OPDATA4-93]
|
||||
_ = x[IBS_OPFUSE-94]
|
||||
_ = x[IBS_PREVENTHOST-95]
|
||||
_ = x[IBS_ZEN4-96]
|
||||
_ = x[IDPRED_CTRL-97]
|
||||
_ = x[INT_WBINVD-98]
|
||||
_ = x[INVLPGB-99]
|
||||
_ = x[KEYLOCKER-100]
|
||||
_ = x[KEYLOCKERW-101]
|
||||
_ = x[LAHF-102]
|
||||
_ = x[LAM-103]
|
||||
_ = x[LBRVIRT-104]
|
||||
_ = x[LZCNT-105]
|
||||
_ = x[MCAOVERFLOW-106]
|
||||
_ = x[MCDT_NO-107]
|
||||
_ = x[MCOMMIT-108]
|
||||
_ = x[MD_CLEAR-109]
|
||||
_ = x[MMX-110]
|
||||
_ = x[MMXEXT-111]
|
||||
_ = x[MOVBE-112]
|
||||
_ = x[MOVDIR64B-113]
|
||||
_ = x[MOVDIRI-114]
|
||||
_ = x[MOVSB_ZL-115]
|
||||
_ = x[MOVU-116]
|
||||
_ = x[MPX-117]
|
||||
_ = x[MSRIRC-118]
|
||||
_ = x[MSRLIST-119]
|
||||
_ = x[MSR_PAGEFLUSH-120]
|
||||
_ = x[NRIPS-121]
|
||||
_ = x[NX-122]
|
||||
_ = x[OSXSAVE-123]
|
||||
_ = x[PCONFIG-124]
|
||||
_ = x[POPCNT-125]
|
||||
_ = x[PPIN-126]
|
||||
_ = x[PREFETCHI-127]
|
||||
_ = x[PSFD-128]
|
||||
_ = x[RDPRU-129]
|
||||
_ = x[RDRAND-130]
|
||||
_ = x[RDSEED-131]
|
||||
_ = x[RDTSCP-132]
|
||||
_ = x[RRSBA_CTRL-133]
|
||||
_ = x[RTM-134]
|
||||
_ = x[RTM_ALWAYS_ABORT-135]
|
||||
_ = x[SBPB-136]
|
||||
_ = x[SERIALIZE-137]
|
||||
_ = x[SEV-138]
|
||||
_ = x[SEV_64BIT-139]
|
||||
_ = x[SEV_ALTERNATIVE-140]
|
||||
_ = x[SEV_DEBUGSWAP-141]
|
||||
_ = x[SEV_ES-142]
|
||||
_ = x[SEV_RESTRICTED-143]
|
||||
_ = x[SEV_SNP-144]
|
||||
_ = x[SGX-145]
|
||||
_ = x[SGXLC-146]
|
||||
_ = x[SGXPQC-147]
|
||||
_ = x[SHA-148]
|
||||
_ = x[SME-149]
|
||||
_ = x[SME_COHERENT-150]
|
||||
_ = x[SM3_X86-151]
|
||||
_ = x[SM4_X86-152]
|
||||
_ = x[SPEC_CTRL_SSBD-153]
|
||||
_ = x[SRBDS_CTRL-154]
|
||||
_ = x[SRSO_MSR_FIX-155]
|
||||
_ = x[SRSO_NO-156]
|
||||
_ = x[SRSO_USER_KERNEL_NO-157]
|
||||
_ = x[SSE-158]
|
||||
_ = x[SSE2-159]
|
||||
_ = x[SSE3-160]
|
||||
_ = x[SSE4-161]
|
||||
_ = x[SSE42-162]
|
||||
_ = x[SSE4A-163]
|
||||
_ = x[SSSE3-164]
|
||||
_ = x[STIBP-165]
|
||||
_ = x[STIBP_ALWAYSON-166]
|
||||
_ = x[STOSB_SHORT-167]
|
||||
_ = x[SUCCOR-168]
|
||||
_ = x[SVM-169]
|
||||
_ = x[SVMDA-170]
|
||||
_ = x[SVMFBASID-171]
|
||||
_ = x[SVML-172]
|
||||
_ = x[SVMNP-173]
|
||||
_ = x[SVMPF-174]
|
||||
_ = x[SVMPFT-175]
|
||||
_ = x[SYSCALL-176]
|
||||
_ = x[SYSEE-177]
|
||||
_ = x[TBM-178]
|
||||
_ = x[TDX_GUEST-179]
|
||||
_ = x[TLB_FLUSH_NESTED-180]
|
||||
_ = x[TME-181]
|
||||
_ = x[TOPEXT-182]
|
||||
_ = x[TSA_L1_NO-183]
|
||||
_ = x[TSA_SQ_NO-184]
|
||||
_ = x[TSA_VERW_CLEAR-185]
|
||||
_ = x[TSCRATEMSR-186]
|
||||
_ = x[TSXLDTRK-187]
|
||||
_ = x[VAES-188]
|
||||
_ = x[VMCBCLEAN-189]
|
||||
_ = x[VMPL-190]
|
||||
_ = x[VMSA_REGPROT-191]
|
||||
_ = x[VMX-192]
|
||||
_ = x[VPCLMULQDQ-193]
|
||||
_ = x[VTE-194]
|
||||
_ = x[WAITPKG-195]
|
||||
_ = x[WBNOINVD-196]
|
||||
_ = x[WRMSRNS-197]
|
||||
_ = x[X87-198]
|
||||
_ = x[XGETBV1-199]
|
||||
_ = x[XOP-200]
|
||||
_ = x[XSAVE-201]
|
||||
_ = x[XSAVEC-202]
|
||||
_ = x[XSAVEOPT-203]
|
||||
_ = x[XSAVES-204]
|
||||
_ = x[AESARM-205]
|
||||
_ = x[ARMCPUID-206]
|
||||
_ = x[ASIMD-207]
|
||||
_ = x[ASIMDDP-208]
|
||||
_ = x[ASIMDHP-209]
|
||||
_ = x[ASIMDRDM-210]
|
||||
_ = x[ATOMICS-211]
|
||||
_ = x[CRC32-212]
|
||||
_ = x[DCPOP-213]
|
||||
_ = x[EVTSTRM-214]
|
||||
_ = x[FCMA-215]
|
||||
_ = x[FHM-216]
|
||||
_ = x[FP-217]
|
||||
_ = x[FPHP-218]
|
||||
_ = x[GPA-219]
|
||||
_ = x[JSCVT-220]
|
||||
_ = x[LRCPC-221]
|
||||
_ = x[PMULL-222]
|
||||
_ = x[RNDR-223]
|
||||
_ = x[TLB-224]
|
||||
_ = x[TS-225]
|
||||
_ = x[SHA1-226]
|
||||
_ = x[SHA2-227]
|
||||
_ = x[SHA3-228]
|
||||
_ = x[SHA512-229]
|
||||
_ = x[SM3-230]
|
||||
_ = x[SM4-231]
|
||||
_ = x[SVE-232]
|
||||
_ = x[PMU_FIXEDCOUNTER_CYCLES-233]
|
||||
_ = x[PMU_FIXEDCOUNTER_REFCYCLES-234]
|
||||
_ = x[PMU_FIXEDCOUNTER_INSTRUCTIONS-235]
|
||||
_ = x[PMU_FIXEDCOUNTER_TOPDOWN_SLOTS-236]
|
||||
_ = x[lastID-237]
|
||||
_ = x[firstID-0]
|
||||
}
|
||||
|
||||
const _FeatureID_name = "firstIDADXAESNIAMD3DNOWAMD3DNOWEXTAMXBF16AMXFP16AMXINT8AMXFP8AMXTILEAMXTF32AMXCOMPLEXAMXTRANSPOSEAPX_FAVXAVX10AVX10_128AVX10_256AVX10_512AVX2AVX512BF16AVX512BITALGAVX512BWAVX512CDAVX512DQAVX512ERAVX512FAVX512FP16AVX512IFMAAVX512PFAVX512VBMIAVX512VBMI2AVX512VLAVX512VNNIAVX512VP2INTERSECTAVX512VPOPCNTDQAVXIFMAAVXNECONVERTAVXSLOWAVXVNNIAVXVNNIINT8AVXVNNIINT16BHI_CTRLBMI1BMI2CETIBTCETSSCLDEMOTECLMULCLZEROCMOVCMPCCXADDCMPSB_SCADBS_SHORTCMPXCHG8CPBOOSTCPPCCX16EFER_LMSLE_UNSENQCMDERMSF16CFLUSH_L1DFMA3FMA4FP128FP256FSRMFXSRFXSROPTGFNIHLEHRESETHTTHWAHYBRID_CPUHYPERVISORIA32_ARCH_CAPIA32_CORE_CAPIBPBIBPB_BRTYPEIBRSIBRS_PREFERREDIBRS_PROVIDES_SMPIBSIBSBRNTRGTIBSFETCHSAMIBSFFVIBSOPCNTIBSOPCNTEXTIBSOPSAMIBSRDWROPCNTIBSRIPINVALIDCHKIBS_FETCH_CTLXIBS_OPDATA4IBS_OPFUSEIBS_PREVENTHOSTIBS_ZEN4IDPRED_CTRLINT_WBINVDINVLPGBKEYLOCKERKEYLOCKERWLAHFLAMLBRVIRTLZCNTMCAOVERFLOWMCDT_NOMCOMMITMD_CLEARMMXMMXEXTMOVBEMOVDIR64BMOVDIRIMOVSB_ZLMOVUMPXMSRIRCMSRLISTMSR_PAGEFLUSHNRIPSNXOSXSAVEPCONFIGPOPCNTPPINPREFETCHIPSFDRDPRURDRANDRDSEEDRDTSCPRRSBA_CTRLRTMRTM_ALWAYS_ABORTSBPBSERIALIZESEVSEV_64BITSEV_ALTERNATIVESEV_DEBUGSWAPSEV_ESSEV_RESTRICTEDSEV_SNPSGXSGXLCSGXPQCSHASMESME_COHERENTSM3_X86SM4_X86SPEC_CTRL_SSBDSRBDS_CTRLSRSO_MSR_FIXSRSO_NOSRSO_USER_KERNEL_NOSSESSE2SSE3SSE4SSE42SSE4ASSSE3STIBPSTIBP_ALWAYSONSTOSB_SHORTSUCCORSVMSVMDASVMFBASIDSVMLSVMNPSVMPFSVMPFTSYSCALLSYSEETBMTDX_GUESTTLB_FLUSH_NESTEDTMETOPEXTTSA_L1_NOTSA_SQ_NOTSA_VERW_CLEARTSCRATEMSRTSXLDTRKVAESVMCBCLEANVMPLVMSA_REGPROTVMXVPCLMULQDQVTEWAITPKGWBNOINVDWRMSRNSX87XGETBV1XOPXSAVEXSAVECXSAVEOPTXSAVESAESARMARMCPUIDASIMDASIMDDPASIMDHPASIMDRDMATOMICSCRC32DCPOPEVTSTRMFCMAFHMFPFPHPGPAJSCVTLRCPCPMULLRNDRTLBTSSHA1SHA2SHA3SHA512SM3SM4SVEPMU_FIXEDCOUNTER_CYCLESPMU_FIXEDCOUNTER_REFCYCLESPMU_FIXEDCOUNTER_INSTRUCTIONSPMU_FIXEDCOUNTER_TOPDOWN_SLOTSlastID"
|
||||
|
||||
var _FeatureID_index = [...]uint16{0, 7, 10, 15, 23, 34, 41, 48, 55, 61, 68, 75, 85, 97, 102, 105, 110, 119, 128, 137, 141, 151, 163, 171, 179, 187, 195, 202, 212, 222, 230, 240, 251, 259, 269, 287, 302, 309, 321, 328, 335, 346, 358, 366, 370, 374, 380, 385, 393, 398, 404, 408, 417, 435, 443, 450, 454, 458, 472, 478, 482, 486, 495, 499, 503, 508, 513, 517, 521, 528, 532, 535, 541, 544, 547, 557, 567, 580, 593, 597, 608, 612, 626, 643, 646, 656, 667, 673, 681, 692, 700, 712, 728, 742, 753, 763, 778, 786, 797, 807, 814, 823, 833, 837, 840, 847, 852, 863, 870, 877, 885, 888, 894, 899, 908, 915, 923, 927, 930, 936, 943, 956, 961, 963, 970, 977, 983, 987, 996, 1000, 1005, 1011, 1017, 1023, 1033, 1036, 1052, 1056, 1065, 1068, 1077, 1092, 1105, 1111, 1125, 1132, 1135, 1140, 1146, 1149, 1152, 1164, 1171, 1178, 1192, 1202, 1214, 1221, 1240, 1243, 1247, 1251, 1255, 1260, 1265, 1270, 1275, 1289, 1300, 1306, 1309, 1314, 1323, 1327, 1332, 1337, 1343, 1350, 1355, 1358, 1367, 1383, 1386, 1392, 1401, 1410, 1424, 1434, 1442, 1446, 1455, 1459, 1471, 1474, 1484, 1487, 1494, 1502, 1509, 1512, 1519, 1522, 1527, 1533, 1541, 1547, 1553, 1561, 1566, 1573, 1580, 1588, 1595, 1600, 1605, 1612, 1616, 1619, 1621, 1625, 1628, 1633, 1638, 1643, 1647, 1650, 1652, 1656, 1660, 1664, 1670, 1673, 1676, 1679, 1702, 1728, 1757, 1787, 1793}
|
||||
|
||||
func (i FeatureID) String() string {
|
||||
if i < 0 || i >= FeatureID(len(_FeatureID_index)-1) {
|
||||
return "FeatureID(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _FeatureID_name[_FeatureID_index[i]:_FeatureID_index[i+1]]
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[VendorUnknown-0]
|
||||
_ = x[Intel-1]
|
||||
_ = x[AMD-2]
|
||||
_ = x[VIA-3]
|
||||
_ = x[Transmeta-4]
|
||||
_ = x[NSC-5]
|
||||
_ = x[KVM-6]
|
||||
_ = x[MSVM-7]
|
||||
_ = x[VMware-8]
|
||||
_ = x[XenHVM-9]
|
||||
_ = x[Bhyve-10]
|
||||
_ = x[Hygon-11]
|
||||
_ = x[SiS-12]
|
||||
_ = x[RDC-13]
|
||||
_ = x[Ampere-14]
|
||||
_ = x[ARM-15]
|
||||
_ = x[Broadcom-16]
|
||||
_ = x[Cavium-17]
|
||||
_ = x[DEC-18]
|
||||
_ = x[Fujitsu-19]
|
||||
_ = x[Infineon-20]
|
||||
_ = x[Motorola-21]
|
||||
_ = x[NVIDIA-22]
|
||||
_ = x[AMCC-23]
|
||||
_ = x[Qualcomm-24]
|
||||
_ = x[Marvell-25]
|
||||
_ = x[QEMU-26]
|
||||
_ = x[QNX-27]
|
||||
_ = x[ACRN-28]
|
||||
_ = x[SRE-29]
|
||||
_ = x[Apple-30]
|
||||
_ = x[lastVendor-31]
|
||||
}
|
||||
|
||||
const _Vendor_name = "VendorUnknownIntelAMDVIATransmetaNSCKVMMSVMVMwareXenHVMBhyveHygonSiSRDCAmpereARMBroadcomCaviumDECFujitsuInfineonMotorolaNVIDIAAMCCQualcommMarvellQEMUQNXACRNSREApplelastVendor"
|
||||
|
||||
var _Vendor_index = [...]uint8{0, 13, 18, 21, 24, 33, 36, 39, 43, 49, 55, 60, 65, 68, 71, 77, 80, 88, 94, 97, 104, 112, 120, 126, 130, 138, 145, 149, 152, 156, 159, 164, 174}
|
||||
|
||||
func (i Vendor) String() string {
|
||||
if i < 0 || i >= Vendor(len(_Vendor_index)-1) {
|
||||
return "Vendor(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Vendor_name[_Vendor_index[i]:_Vendor_index[i+1]]
|
||||
}
|
||||
-129
@@ -1,129 +0,0 @@
|
||||
// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
package cpuid
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func detectOS(c *CPUInfo) bool {
|
||||
if runtime.GOOS != "ios" {
|
||||
tryToFillCPUInfoFomSysctl(c)
|
||||
}
|
||||
// There are no hw.optional sysctl values for the below features on Mac OS 11.0
|
||||
// to detect their supported state dynamically. Assume the CPU features that
|
||||
// Apple Silicon M1 supports to be available as a minimal set of features
|
||||
// to all Go programs running on darwin/arm64.
|
||||
// TODO: Add more if we know them.
|
||||
c.featureSet.setIf(runtime.GOOS != "ios", AESARM, PMULL, SHA1, SHA2)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func sysctlGetBool(name string) bool {
|
||||
value, err := unix.SysctlUint32(name)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return value != 0
|
||||
}
|
||||
|
||||
func sysctlGetString(name string) string {
|
||||
value, err := unix.Sysctl(name)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func sysctlGetInt(unknown int, names ...string) int {
|
||||
for _, name := range names {
|
||||
value, err := unix.SysctlUint32(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if value != 0 {
|
||||
return int(value)
|
||||
}
|
||||
}
|
||||
return unknown
|
||||
}
|
||||
|
||||
func sysctlGetInt64(unknown int, names ...string) int {
|
||||
for _, name := range names {
|
||||
value64, err := unix.SysctlUint64(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if int(value64) != unknown {
|
||||
return int(value64)
|
||||
}
|
||||
}
|
||||
return unknown
|
||||
}
|
||||
|
||||
func setFeature(c *CPUInfo, feature FeatureID, aliases ...string) {
|
||||
for _, alias := range aliases {
|
||||
set := sysctlGetBool(alias)
|
||||
c.featureSet.setIf(set, feature)
|
||||
if set {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tryToFillCPUInfoFomSysctl(c *CPUInfo) {
|
||||
c.BrandName = sysctlGetString("machdep.cpu.brand_string")
|
||||
|
||||
if len(c.BrandName) != 0 {
|
||||
c.VendorString = strings.Fields(c.BrandName)[0]
|
||||
}
|
||||
|
||||
c.PhysicalCores = sysctlGetInt(runtime.NumCPU(), "hw.physicalcpu")
|
||||
c.ThreadsPerCore = sysctlGetInt(1, "machdep.cpu.thread_count", "kern.num_threads") /
|
||||
sysctlGetInt(1, "hw.physicalcpu")
|
||||
c.LogicalCores = sysctlGetInt(runtime.NumCPU(), "machdep.cpu.core_count")
|
||||
c.Family = sysctlGetInt(0, "machdep.cpu.family", "hw.cpufamily")
|
||||
c.Model = sysctlGetInt(0, "machdep.cpu.model")
|
||||
c.CacheLine = sysctlGetInt64(0, "hw.cachelinesize")
|
||||
c.Cache.L1I = sysctlGetInt64(-1, "hw.l1icachesize")
|
||||
c.Cache.L1D = sysctlGetInt64(-1, "hw.l1dcachesize")
|
||||
c.Cache.L2 = sysctlGetInt64(-1, "hw.l2cachesize")
|
||||
c.Cache.L3 = sysctlGetInt64(-1, "hw.l3cachesize")
|
||||
|
||||
// ARM features:
|
||||
//
|
||||
// Note: On some Apple Silicon system, some feats have aliases. See:
|
||||
// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
|
||||
// When so, we look at all aliases and consider a feature available when at least one identifier matches.
|
||||
setFeature(c, AESARM, "hw.optional.arm.FEAT_AES") // AES instructions
|
||||
setFeature(c, ASIMD, "hw.optional.arm.AdvSIMD", "hw.optional.neon") // Advanced SIMD
|
||||
setFeature(c, ASIMDDP, "hw.optional.arm.FEAT_DotProd") // SIMD Dot Product
|
||||
setFeature(c, ASIMDHP, "hw.optional.arm.AdvSIMD_HPFPCvt", "hw.optional.neon_hpfp") // Advanced SIMD half-precision floating point
|
||||
setFeature(c, ASIMDRDM, "hw.optional.arm.FEAT_RDM") // Rounding Double Multiply Accumulate/Subtract
|
||||
setFeature(c, ATOMICS, "hw.optional.arm.FEAT_LSE", "hw.optional.armv8_1_atomics") // Large System Extensions (LSE)
|
||||
setFeature(c, CRC32, "hw.optional.arm.FEAT_CRC32", "hw.optional.armv8_crc32") // CRC32/CRC32C instructions
|
||||
setFeature(c, DCPOP, "hw.optional.arm.FEAT_DPB") // Data cache clean to Point of Persistence (DC CVAP)
|
||||
setFeature(c, EVTSTRM, "hw.optional.arm.FEAT_ECV") // Generic timer
|
||||
setFeature(c, FCMA, "hw.optional.arm.FEAT_FCMA", "hw.optional.armv8_3_compnum") // Floating point complex number addition and multiplication
|
||||
setFeature(c, FHM, "hw.optional.armv8_2_fhm", "hw.optional.arm.FEAT_FHM") // FMLAL and FMLSL instructions
|
||||
setFeature(c, FP, "hw.optional.floatingpoint") // Single-precision and double-precision floating point
|
||||
setFeature(c, FPHP, "hw.optional.arm.FEAT_FP16", "hw.optional.neon_fp16") // Half-precision floating point
|
||||
setFeature(c, GPA, "hw.optional.arm.FEAT_PAuth") // Generic Pointer Authentication
|
||||
setFeature(c, JSCVT, "hw.optional.arm.FEAT_JSCVT") // Javascript-style double->int convert (FJCVTZS)
|
||||
setFeature(c, LRCPC, "hw.optional.arm.FEAT_LRCPC") // Weaker release consistency (LDAPR, etc)
|
||||
setFeature(c, PMULL, "hw.optional.arm.FEAT_PMULL") // Polynomial Multiply instructions (PMULL/PMULL2)
|
||||
setFeature(c, RNDR, "hw.optional.arm.FEAT_RNG") // Random Number instructions
|
||||
setFeature(c, TLB, "hw.optional.arm.FEAT_TLBIOS", "hw.optional.arm.FEAT_TLBIRANGE") // Outer Shareable and TLB range maintenance instructions
|
||||
setFeature(c, TS, "hw.optional.arm.FEAT_FlagM", "hw.optional.arm.FEAT_FlagM2") // Flag manipulation instructions
|
||||
setFeature(c, SHA1, "hw.optional.arm.FEAT_SHA1") // SHA-1 instructions (SHA1C, etc)
|
||||
setFeature(c, SHA2, "hw.optional.arm.FEAT_SHA256") // SHA-2 instructions (SHA256H, etc)
|
||||
setFeature(c, SHA3, "hw.optional.arm.FEAT_SHA3") // SHA-3 instructions (EOR3, RAXI, XAR, BCAX)
|
||||
setFeature(c, SHA512, "hw.optional.arm.FEAT_SHA512") // SHA512 instructions
|
||||
setFeature(c, SM3, "hw.optional.arm.FEAT_SM3") // SM3 instructions
|
||||
setFeature(c, SM4, "hw.optional.arm.FEAT_SM4") // SM4 instructions
|
||||
setFeature(c, SVE, "hw.optional.arm.FEAT_SVE") // Scalable Vector Extension
|
||||
}
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
// 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 located
|
||||
// here https://github.com/golang/sys/blob/master/LICENSE
|
||||
|
||||
package cpuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// HWCAP bits.
|
||||
const (
|
||||
hwcap_FP = 1 << 0
|
||||
hwcap_ASIMD = 1 << 1
|
||||
hwcap_EVTSTRM = 1 << 2
|
||||
hwcap_AES = 1 << 3
|
||||
hwcap_PMULL = 1 << 4
|
||||
hwcap_SHA1 = 1 << 5
|
||||
hwcap_SHA2 = 1 << 6
|
||||
hwcap_CRC32 = 1 << 7
|
||||
hwcap_ATOMICS = 1 << 8
|
||||
hwcap_FPHP = 1 << 9
|
||||
hwcap_ASIMDHP = 1 << 10
|
||||
hwcap_CPUID = 1 << 11
|
||||
hwcap_ASIMDRDM = 1 << 12
|
||||
hwcap_JSCVT = 1 << 13
|
||||
hwcap_FCMA = 1 << 14
|
||||
hwcap_LRCPC = 1 << 15
|
||||
hwcap_DCPOP = 1 << 16
|
||||
hwcap_SHA3 = 1 << 17
|
||||
hwcap_SM3 = 1 << 18
|
||||
hwcap_SM4 = 1 << 19
|
||||
hwcap_ASIMDDP = 1 << 20
|
||||
hwcap_SHA512 = 1 << 21
|
||||
hwcap_SVE = 1 << 22
|
||||
hwcap_ASIMDFHM = 1 << 23
|
||||
hwcap_DIT = 1 << 24
|
||||
hwcap_USCAT = 1 << 25
|
||||
hwcap_ILRCPC = 1 << 26
|
||||
hwcap_FLAGM = 1 << 27
|
||||
hwcap_SSBS = 1 << 28
|
||||
hwcap_SB = 1 << 29
|
||||
hwcap_PACA = 1 << 30
|
||||
hwcap_PACG = 1 << 31
|
||||
hwcap_GCS = 1 << 32
|
||||
|
||||
hwcap2_DCPODP = 1 << 0
|
||||
hwcap2_SVE2 = 1 << 1
|
||||
hwcap2_SVEAES = 1 << 2
|
||||
hwcap2_SVEPMULL = 1 << 3
|
||||
hwcap2_SVEBITPERM = 1 << 4
|
||||
hwcap2_SVESHA3 = 1 << 5
|
||||
hwcap2_SVESM4 = 1 << 6
|
||||
hwcap2_FLAGM2 = 1 << 7
|
||||
hwcap2_FRINT = 1 << 8
|
||||
hwcap2_SVEI8MM = 1 << 9
|
||||
hwcap2_SVEF32MM = 1 << 10
|
||||
hwcap2_SVEF64MM = 1 << 11
|
||||
hwcap2_SVEBF16 = 1 << 12
|
||||
hwcap2_I8MM = 1 << 13
|
||||
hwcap2_BF16 = 1 << 14
|
||||
hwcap2_DGH = 1 << 15
|
||||
hwcap2_RNG = 1 << 16
|
||||
hwcap2_BTI = 1 << 17
|
||||
hwcap2_MTE = 1 << 18
|
||||
hwcap2_ECV = 1 << 19
|
||||
hwcap2_AFP = 1 << 20
|
||||
hwcap2_RPRES = 1 << 21
|
||||
hwcap2_MTE3 = 1 << 22
|
||||
hwcap2_SME = 1 << 23
|
||||
hwcap2_SME_I16I64 = 1 << 24
|
||||
hwcap2_SME_F64F64 = 1 << 25
|
||||
hwcap2_SME_I8I32 = 1 << 26
|
||||
hwcap2_SME_F16F32 = 1 << 27
|
||||
hwcap2_SME_B16F32 = 1 << 28
|
||||
hwcap2_SME_F32F32 = 1 << 29
|
||||
hwcap2_SME_FA64 = 1 << 30
|
||||
hwcap2_WFXT = 1 << 31
|
||||
hwcap2_EBF16 = 1 << 32
|
||||
hwcap2_SVE_EBF16 = 1 << 33
|
||||
hwcap2_CSSC = 1 << 34
|
||||
hwcap2_RPRFM = 1 << 35
|
||||
hwcap2_SVE2P1 = 1 << 36
|
||||
hwcap2_SME2 = 1 << 37
|
||||
hwcap2_SME2P1 = 1 << 38
|
||||
hwcap2_SME_I16I32 = 1 << 39
|
||||
hwcap2_SME_BI32I32 = 1 << 40
|
||||
hwcap2_SME_B16B16 = 1 << 41
|
||||
hwcap2_SME_F16F16 = 1 << 42
|
||||
hwcap2_MOPS = 1 << 43
|
||||
hwcap2_HBC = 1 << 44
|
||||
hwcap2_SVE_B16B16 = 1 << 45
|
||||
hwcap2_LRCPC3 = 1 << 46
|
||||
hwcap2_LSE128 = 1 << 47
|
||||
hwcap2_FPMR = 1 << 48
|
||||
hwcap2_LUT = 1 << 49
|
||||
hwcap2_FAMINMAX = 1 << 50
|
||||
hwcap2_F8CVT = 1 << 51
|
||||
hwcap2_F8FMA = 1 << 52
|
||||
hwcap2_F8DP4 = 1 << 53
|
||||
hwcap2_F8DP2 = 1 << 54
|
||||
hwcap2_F8E4M3 = 1 << 55
|
||||
hwcap2_F8E5M2 = 1 << 56
|
||||
hwcap2_SME_LUTV2 = 1 << 57
|
||||
hwcap2_SME_F8F16 = 1 << 58
|
||||
hwcap2_SME_F8F32 = 1 << 59
|
||||
hwcap2_SME_SF8FMA = 1 << 60
|
||||
hwcap2_SME_SF8DP4 = 1 << 61
|
||||
hwcap2_SME_SF8DP2 = 1 << 62
|
||||
hwcap2_POE = 1 << 63
|
||||
)
|
||||
|
||||
func detectOS(c *CPUInfo) bool {
|
||||
// For now assuming no hyperthreading is reasonable.
|
||||
c.LogicalCores = runtime.NumCPU()
|
||||
c.PhysicalCores = c.LogicalCores
|
||||
c.ThreadsPerCore = 1
|
||||
if hwcap == 0 {
|
||||
// We did not get values from the runtime.
|
||||
// Try reading /proc/self/auxv
|
||||
|
||||
// From https://github.com/golang/sys
|
||||
const (
|
||||
_AT_HWCAP = 16
|
||||
_AT_HWCAP2 = 26
|
||||
|
||||
uintSize = int(32 << (^uint(0) >> 63))
|
||||
)
|
||||
|
||||
buf, err := ioutil.ReadFile("/proc/self/auxv")
|
||||
if err != nil {
|
||||
// e.g. on android /proc/self/auxv is not accessible, so silently
|
||||
// ignore the error and leave Initialized = false. On some
|
||||
// architectures (e.g. arm64) doinit() implements a fallback
|
||||
// readout and will set Initialized = true again.
|
||||
return false
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
for len(buf) >= 2*(uintSize/8) {
|
||||
var tag, val uint
|
||||
switch uintSize {
|
||||
case 32:
|
||||
tag = uint(bo.Uint32(buf[0:]))
|
||||
val = uint(bo.Uint32(buf[4:]))
|
||||
buf = buf[8:]
|
||||
case 64:
|
||||
tag = uint(bo.Uint64(buf[0:]))
|
||||
val = uint(bo.Uint64(buf[8:]))
|
||||
buf = buf[16:]
|
||||
}
|
||||
switch tag {
|
||||
case _AT_HWCAP:
|
||||
hwcap = val
|
||||
case _AT_HWCAP2:
|
||||
// Not used
|
||||
}
|
||||
}
|
||||
if hwcap == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// HWCap was populated by the runtime from the auxiliary vector.
|
||||
// Use HWCap information since reading aarch64 system registers
|
||||
// is not supported in user space on older linux kernels.
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_AES), AESARM)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMD), ASIMD)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDDP), ASIMDDP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDHP), ASIMDHP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDRDM), ASIMDRDM)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_CPUID), ARMCPUID)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_CRC32), CRC32)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_DCPOP), DCPOP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_EVTSTRM), EVTSTRM)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_FCMA), FCMA)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDFHM), FHM)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_FP), FP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_FPHP), FPHP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_JSCVT), JSCVT)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_LRCPC), LRCPC)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_PMULL), PMULL)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap2_RNG), RNDR)
|
||||
// c.featureSet.setIf(isSet(hwcap, hwcap_), TLB)
|
||||
// c.featureSet.setIf(isSet(hwcap, hwcap_), TS)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA1), SHA1)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA2), SHA2)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA3), SHA3)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA512), SHA512)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SM3), SM3)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SM4), SM4)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SVE), SVE)
|
||||
|
||||
// The Samsung S9+ kernel reports support for atomics, but not all cores
|
||||
// actually support them, resulting in SIGILL. See issue #28431.
|
||||
// TODO(elias.naur): Only disable the optimization on bad chipsets on android.
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ATOMICS) && runtime.GOOS != "android", ATOMICS)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func isSet(hwc uint, value uint) bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build arm64 && !linux && !darwin
|
||||
// +build arm64,!linux,!darwin
|
||||
|
||||
package cpuid
|
||||
|
||||
import "runtime"
|
||||
|
||||
func detectOS(c *CPUInfo) bool {
|
||||
c.PhysicalCores = runtime.NumCPU()
|
||||
// For now assuming 1 thread per core...
|
||||
c.ThreadsPerCore = 1
|
||||
c.LogicalCores = c.PhysicalCores
|
||||
return false
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build nounsafe
|
||||
// +build nounsafe
|
||||
|
||||
package cpuid
|
||||
|
||||
var hwcap uint
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build !nounsafe
|
||||
// +build !nounsafe
|
||||
|
||||
package cpuid
|
||||
|
||||
import _ "unsafe" // needed for go:linkname
|
||||
|
||||
//go:linkname hwcap internal/cpu.HWCap
|
||||
var hwcap uint
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
go tool dist list | while IFS=/ read os arch; do
|
||||
echo "Checking $os/$arch..."
|
||||
echo " normal"
|
||||
GOARCH=$arch GOOS=$os go build -o /dev/null .
|
||||
echo " noasm"
|
||||
GOARCH=$arch GOOS=$os go build -tags noasm -o /dev/null .
|
||||
echo " appengine"
|
||||
GOARCH=$arch GOOS=$os go build -tags appengine -o /dev/null .
|
||||
echo " noasm,appengine"
|
||||
GOARCH=$arch GOOS=$os go build -tags 'appengine noasm' -o /dev/null .
|
||||
done
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.27@sha256:eb37f58646a901dc7727cf448cae36daaefaba79de33b5058dab79aa4c04aefb
|
||||
FROM golang:1.27@sha256:e0174e51e81218523251d85d248a90d24c3d5e81543b4f07a5d66229397db190
|
||||
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=arm
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.27@sha256:eb37f58646a901dc7727cf448cae36daaefaba79de33b5058dab79aa4c04aefb
|
||||
FROM golang:1.27@sha256:e0174e51e81218523251d85d248a90d24c3d5e81543b4f07a5d66229397db190
|
||||
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=arm64
|
||||
|
||||
+23
-4
@@ -1,18 +1,35 @@
|
||||
FUZZ_TIME ?= 1m
|
||||
FUZZ_FLAGS ?=
|
||||
|
||||
# The fuzz targets of each package, along with the tags needed to build them.
|
||||
FUZZ_TARGETS = ./test/:gofuzz .:sha1cd_asmtest
|
||||
|
||||
export CGO_ENABLED := 1
|
||||
|
||||
# The hashing tests run a second time with SHA-NI off, so that CPUs with it
|
||||
# also cover the AVX2 fallback that CPUs without it use.
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -race -timeout 15s ./...
|
||||
go test -race -timeout 15s -tags sha1cd_asmtest ./...
|
||||
SHA1CD_TEST_NOSHANI=1 go test -race -timeout 15s -tags sha1cd_asmtest ./test/
|
||||
|
||||
.PHONY: bench
|
||||
bench:
|
||||
go test -benchmem -run=^$$ -bench ^Benchmark ./...
|
||||
|
||||
# go test only fuzzes a single target per invocation, so each one is run in
|
||||
# turn for FUZZ_TIME.
|
||||
.PHONY: fuzz
|
||||
fuzz:
|
||||
go test -tags gofuzz -fuzz=. -fuzztime=$(FUZZ_TIME) ./test/
|
||||
@set -e; for entry in $(FUZZ_TARGETS); do \
|
||||
pkg="$${entry%%:*}"; tags="$${entry##*:}"; \
|
||||
listed="$$(go test -tags "$$tags" -list '^Fuzz' "$$pkg")"; \
|
||||
for target in $$(echo "$$listed" | grep '^Fuzz'); do \
|
||||
echo "fuzzing $$target in $$pkg for $(FUZZ_TIME)"; \
|
||||
go test $(FUZZ_FLAGS) -tags "$$tags" -run '^$$' -fuzz "^$$target"'$$' \
|
||||
-fuzztime=$(FUZZ_TIME) "$$pkg"; \
|
||||
done; \
|
||||
done
|
||||
|
||||
# Cross build project in arm/v7.
|
||||
build-arm:
|
||||
@@ -24,9 +41,11 @@ build-arm64:
|
||||
docker build -t sha1cd-arm64 -f Dockerfile.arm64 .
|
||||
docker run --rm sha1cd-arm64
|
||||
|
||||
# Build with cgo disabled.
|
||||
# Build with cgo disabled. Vetting every package (not just ./cgo) is what
|
||||
# catches the cgo and non-cgo builds drifting apart in their exported API.
|
||||
build-nocgo:
|
||||
CGO_ENABLED=0 go build ./cgo
|
||||
CGO_ENABLED=0 go build ./...
|
||||
CGO_ENABLED=0 go vet ./...
|
||||
|
||||
# Run cross-compilation to assure supported architectures.
|
||||
cross-build: build-arm build-arm64 build-nocgo
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Package cpu detects the CPU features that sha1cd dispatches on.
|
||||
//
|
||||
// It covers only what the assembly implementations need, which keeps
|
||||
// start up cheap and avoids an external dependency. Every flag is false
|
||||
// where a feature cannot be detected safely, which selects the generic
|
||||
// implementation.
|
||||
package cpu
|
||||
|
||||
// X86 holds the features of the current amd64 CPU. All flags are false on
|
||||
// other architectures.
|
||||
var X86 struct {
|
||||
// HasAVX and HasAVX2 are set only when the OS also preserves the YMM
|
||||
// state, and HasAVX512F only when it preserves the ZMM and opmask state.
|
||||
HasAVX bool
|
||||
HasAVX2 bool
|
||||
HasAVX512F bool
|
||||
HasBMI1 bool
|
||||
HasBMI2 bool
|
||||
HasSHA bool
|
||||
HasSSSE3 bool
|
||||
HasSSE41 bool
|
||||
}
|
||||
|
||||
// ARM64 holds the features of the current arm64 CPU. All flags are false on
|
||||
// other architectures.
|
||||
var ARM64 struct {
|
||||
HasSHA1 bool
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
//go:build !noasm && gc && amd64
|
||||
|
||||
package cpu
|
||||
|
||||
// cpuid and xgetbv are implemented in cpu_amd64.s.
|
||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||
func xgetbv() (eax, edx uint32)
|
||||
|
||||
func init() {
|
||||
const (
|
||||
// CPUID EAX=1: ECX
|
||||
ssse3 = 1 << 9
|
||||
sse41 = 1 << 19
|
||||
osxsave = 1 << 27
|
||||
avx = 1 << 28
|
||||
|
||||
// CPUID EAX=7, ECX=0: EBX
|
||||
bmi1 = 1 << 3
|
||||
avx2 = 1 << 5
|
||||
bmi2 = 1 << 8
|
||||
avx512f = 1 << 16
|
||||
sha = 1 << 29
|
||||
|
||||
// XCR0
|
||||
xmmState = 1 << 1
|
||||
ymmState = 1 << 2
|
||||
opmaskState = 1 << 5
|
||||
zmmHi256State = 1 << 6
|
||||
hi16ZMMState = 1 << 7
|
||||
zmmState = opmaskState | zmmHi256State | hi16ZMMState
|
||||
)
|
||||
|
||||
maxID, _, _, _ := cpuid(0, 0)
|
||||
if maxID < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
_, _, ecx1, _ := cpuid(1, 0)
|
||||
X86.HasSSSE3 = ecx1&ssse3 != 0
|
||||
X86.HasSSE41 = ecx1&sse41 != 0
|
||||
|
||||
// VEX encoded instructions also need the OS to preserve the YMM state,
|
||||
// which XGETBV reports once OSXSAVE says it is available.
|
||||
// macOS enables the ZMM state lazily, so XCR0 may not report it and
|
||||
// AVX-512 is then left unused, which is safe.
|
||||
var osYMM, osZMM bool
|
||||
if ecx1&(osxsave|avx) == osxsave|avx {
|
||||
xcr0, _ := xgetbv()
|
||||
osYMM = xcr0&(xmmState|ymmState) == xmmState|ymmState
|
||||
osZMM = osYMM && xcr0&zmmState == zmmState
|
||||
}
|
||||
X86.HasAVX = osYMM
|
||||
|
||||
if maxID < 7 {
|
||||
return
|
||||
}
|
||||
_, ebx7, _, _ := cpuid(7, 0)
|
||||
X86.HasAVX2 = osYMM && ebx7&avx2 != 0
|
||||
X86.HasAVX512F = osZMM && ebx7&avx512f != 0
|
||||
X86.HasBMI1 = ebx7&bmi1 != 0
|
||||
X86.HasBMI2 = ebx7&bmi2 != 0
|
||||
X86.HasSHA = ebx7&sha != 0
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
//go:build !noasm && gc && amd64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·cpuid(SB), NOSPLIT, $0-24
|
||||
MOVL eaxArg+0(FP), AX
|
||||
MOVL ecxArg+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func xgetbv() (eax, edx uint32)
|
||||
TEXT ·xgetbv(SB), NOSPLIT, $0-8
|
||||
MOVL $0, CX
|
||||
XGETBV
|
||||
MOVL AX, eax+0(FP)
|
||||
MOVL DX, edx+4(FP)
|
||||
RET
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
//go:build !noasm && gc && arm64 && darwin
|
||||
|
||||
package cpu
|
||||
|
||||
// Every Apple arm64 chip implements the ARMv8 Cryptographic Extension. The Go
|
||||
// runtime makes the same assumption for crypto/sha1 on darwin/arm64.
|
||||
func init() {
|
||||
ARM64.HasSHA1 = true
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
//go:build !noasm && gc && arm64 && freebsd
|
||||
|
||||
package cpu
|
||||
|
||||
// getisar0 is implemented in cpu_arm64_freebsd.s.
|
||||
func getisar0() uint64
|
||||
|
||||
// FreeBSD emulates user space reads of ID_AA64ISAR0_EL1. Its SHA1 field, bits
|
||||
// [11:8], is non zero when the SHA1 instructions are implemented.
|
||||
func init() {
|
||||
ARM64.HasSHA1 = (getisar0()>>8)&0xf != 0
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
//go:build !noasm && gc && arm64 && freebsd
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func getisar0() uint64
|
||||
TEXT ·getisar0(SB), NOSPLIT, $0-8
|
||||
MRS ID_AA64ISAR0_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
//go:build !noasm && gc && arm64 && linux
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"os"
|
||||
_ "unsafe" // for go:linkname
|
||||
)
|
||||
|
||||
// runtime_getAuxv returns the auxiliary vector the kernel passed to the
|
||||
// process. The runtime keeps it reachable for golang.org/x/sys/cpu and
|
||||
// others, see go.dev/issue/57336 and go.dev/issue/67401.
|
||||
//
|
||||
//go:linkname runtime_getAuxv runtime.getAuxv
|
||||
func runtime_getAuxv() []uintptr
|
||||
|
||||
// Linux, and so Android, reports the SHA1 instructions through HWCAP, as
|
||||
// not every kernel lets user space read the ID registers.
|
||||
func init() {
|
||||
hwcap, ok := hwcapFromAuxv(runtime_getAuxv())
|
||||
if !ok {
|
||||
// The procfs copy may not be readable in restricted environments,
|
||||
// in which case the generic implementation is used.
|
||||
if buf, err := os.ReadFile("/proc/self/auxv"); err == nil {
|
||||
hwcap, _ = hwcapFromProcAuxv(buf)
|
||||
}
|
||||
}
|
||||
ARM64.HasSHA1 = hwcap&hwcapSHA1 != 0
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
//go:build !noasm && gc && arm64 && windows
|
||||
|
||||
package cpu
|
||||
|
||||
import "syscall"
|
||||
|
||||
// Windows reports the ARMv8 Cryptographic Extension, which includes the SHA1
|
||||
// instructions, through IsProcessorFeaturePresent.
|
||||
func init() {
|
||||
const _PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
|
||||
|
||||
proc := syscall.NewLazyDLL("kernel32.dll").NewProc("IsProcessorFeaturePresent")
|
||||
if proc.Find() != nil {
|
||||
return
|
||||
}
|
||||
ret, _, _ := proc.Call(_PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSHA1 = ret != 0
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package cpu
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
const (
|
||||
_AT_HWCAP = 16
|
||||
|
||||
// hwcapSHA1 is HWCAP_SHA1 on linux/arm64.
|
||||
hwcapSHA1 = 1 << 5
|
||||
)
|
||||
|
||||
// hwcapFromAuxv returns AT_HWCAP from an auxiliary vector of tag and value
|
||||
// pairs, and whether it was present.
|
||||
func hwcapFromAuxv(auxv []uintptr) (uint64, bool) {
|
||||
for i := 0; i+1 < len(auxv); i += 2 {
|
||||
if auxv[i] == _AT_HWCAP {
|
||||
return uint64(auxv[i+1]), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// hwcapFromProcAuxv does the same for the contents of /proc/self/auxv on a
|
||||
// 64-bit little endian system.
|
||||
func hwcapFromProcAuxv(buf []byte) (uint64, bool) {
|
||||
for ; len(buf) >= 16; buf = buf[16:] {
|
||||
if binary.LittleEndian.Uint64(buf) == _AT_HWCAP {
|
||||
return binary.LittleEndian.Uint64(buf[8:]), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
+28
-18
@@ -4,30 +4,39 @@
|
||||
package sha1cd
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
shared "github.com/pjbgf/sha1cd/internal"
|
||||
"github.com/pjbgf/sha1cd/internal/cpu"
|
||||
"github.com/pjbgf/sha1cd/ubc"
|
||||
)
|
||||
|
||||
var hasSHANI = (runtime.GOARCH == "amd64" &&
|
||||
cpuid.CPU.Supports(cpuid.AVX) &&
|
||||
cpuid.CPU.Supports(cpuid.SHA) &&
|
||||
cpuid.CPU.Supports(cpuid.SSE3) &&
|
||||
cpuid.CPU.Supports(cpuid.SSE4))
|
||||
// hasSHANI reports whether blockAMD64 can run. It uses legacy SSE encodings
|
||||
// only, so it does not need AVX and also runs on the Goldmont, Goldmont Plus
|
||||
// and Tremont Atoms, which implement SHA-NI without AVX.
|
||||
var hasSHANI = cpu.X86.HasSHA && cpu.X86.HasSSSE3 && cpu.X86.HasSSE41
|
||||
|
||||
// blockAMD64 hashes the message p into the current state in h.
|
||||
// blockAMD64 hashes a single chunk of p into the current state in h.
|
||||
// p must hold at least one whole chunk. Anything beyond the first chunk is
|
||||
// ignored, as the collision detection the caller runs afterwards inspects m1
|
||||
// and cs for one chunk only.
|
||||
// Both m1 and cs are used to store intermediate results which are used by the collision detection logic.
|
||||
//
|
||||
//go:noescape
|
||||
func blockAMD64(h []uint32, p []byte, m1 []uint32, cs [][5]uint32)
|
||||
|
||||
func block(dig *digest, p []byte) {
|
||||
if forceGeneric || !hasSHANI {
|
||||
switch {
|
||||
case forceGeneric:
|
||||
blockGeneric(dig, p)
|
||||
case hasSHANI:
|
||||
blockSHANI(dig, p)
|
||||
case hasAVX2:
|
||||
blockAVX2(dig, p)
|
||||
default:
|
||||
blockGeneric(dig, p)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func blockSHANI(dig *digest, p []byte) {
|
||||
m1 := [shared.Rounds]uint32{}
|
||||
cs := [shared.PreStepState][shared.WordBuffers]uint32{}
|
||||
|
||||
@@ -37,14 +46,15 @@ func block(dig *digest, p []byte) {
|
||||
chunk := p[:shared.Chunk]
|
||||
|
||||
blockAMD64(dig.h[:], chunk, m1[:], cs[:])
|
||||
rectifyCompressionState(&m1, &cs)
|
||||
// Assembly states need repair only when a disturbance vector survives.
|
||||
if mask := ubc.CalculateDvMask(&m1); mask != 0 {
|
||||
rectifyCompressionState(&m1, &cs)
|
||||
if checkCollision(&m1, &cs, &dig.h, mask) {
|
||||
dig.col = true
|
||||
|
||||
col := checkCollision(&m1, &cs, &dig.h)
|
||||
if col {
|
||||
dig.col = true
|
||||
|
||||
blockAMD64(dig.h[:], chunk, m1[:], cs[:])
|
||||
blockAMD64(dig.h[:], chunk, m1[:], cs[:])
|
||||
blockAMD64(dig.h[:], chunk, m1[:], cs[:])
|
||||
blockAMD64(dig.h[:], chunk, m1[:], cs[:])
|
||||
}
|
||||
}
|
||||
|
||||
p = p[shared.Chunk:]
|
||||
|
||||
+44
-49
@@ -12,27 +12,30 @@
|
||||
// - https://github.com/golang/go/blob/master/src/crypto/sha1/sha1block_amd64.s
|
||||
|
||||
// Reverse the dword order in abcd via PSHUFD then store the 16 bytes in one
|
||||
// move, instead of issuing four VPEXTRD's that each go through the store port.
|
||||
// move, instead of issuing four PEXTRD's that each go through the store port.
|
||||
#define LOADCS(abcd, e, index, target) \
|
||||
VPSHUFD $0x1B, abcd, X8; \
|
||||
VMOVDQU X8, ((index*20)+0)(target); \
|
||||
PSHUFD $0x1B, abcd, X8; \
|
||||
MOVOU X8, ((index*20)+0)(target); \
|
||||
MOVL e, ((index*20)+16)(target);
|
||||
|
||||
#define LOADM1(m1, index, target) \
|
||||
VPSHUFD $0x1B, m1, X8; \
|
||||
VMOVDQU X8, ((index*16)+0)(target);
|
||||
PSHUFD $0x1B, m1, X8; \
|
||||
MOVOU X8, ((index*16)+0)(target);
|
||||
|
||||
// func blockAMD64(h []uint32, p []byte, m1 []uint32, cs [][5]uint32)
|
||||
// Requires: AVX, SHA, SSE2, SSE4.1, SSSE3
|
||||
// Requires: SHA, SSE2, SSE4.1, SSSE3
|
||||
TEXT ·blockAMD64(SB), NOSPLIT, $80-96
|
||||
MOVQ h_base+0(FP), DI
|
||||
MOVQ p_base+24(FP), SI
|
||||
MOVQ p_len+32(FP), DX
|
||||
MOVQ m1_base+48(FP), R13
|
||||
MOVQ cs_base+72(FP), R15
|
||||
CMPQ DX, $0x00
|
||||
JEQ done
|
||||
ADDQ SI, DX
|
||||
|
||||
// Truncate the length to whole chunks and skip the block if none is left.
|
||||
// The caller compresses exactly one chunk per call, so that the collision
|
||||
// detection it runs afterwards sees this chunk's m1 and cs.
|
||||
ANDQ $-64, DX
|
||||
JZ done
|
||||
|
||||
// Allocate space on the stack for saving ABCD and E0, and align it to 16 bytes
|
||||
LEAQ 15(SP), AX
|
||||
@@ -42,52 +45,51 @@ TEXT ·blockAMD64(SB), NOSPLIT, $80-96
|
||||
|
||||
// Load initial hash state
|
||||
PINSRD $0x03, 16(DI), X5
|
||||
VMOVDQU (DI), X0
|
||||
MOVOU (DI), X0
|
||||
PAND upper_mask<>+0(SB), X5
|
||||
PSHUFD $0x1b, X0, X0
|
||||
VMOVDQA shuffle_mask<>+0(SB), X7
|
||||
MOVO shuffle_mask<>+0(SB), X7
|
||||
|
||||
loop:
|
||||
// Save ABCD and E working values
|
||||
VMOVDQA X5, (AX)
|
||||
VMOVDQA X0, 16(AX)
|
||||
MOVO X5, (AX)
|
||||
MOVO X0, 16(AX)
|
||||
|
||||
// LOAD CS 0
|
||||
VPEXTRD $3, X5, R12
|
||||
PEXTRD $3, X5, R12
|
||||
LOADCS(X0, R12, 0, R15)
|
||||
|
||||
// Rounds 0-3
|
||||
VMOVDQU (SI), X1
|
||||
MOVOU (SI), X1
|
||||
PSHUFB X7, X1
|
||||
PADDD X1, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1RNDS4 $0x00, X5, X0
|
||||
LOADM1(X1, 0, R13)
|
||||
|
||||
// Rounds 4-7
|
||||
VMOVDQU 16(SI), X2
|
||||
MOVOU 16(SI), X2
|
||||
PSHUFB X7, X2
|
||||
SHA1NEXTE X2, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1RNDS4 $0x00, X6, X0
|
||||
SHA1MSG1 X2, X1
|
||||
LOADM1(X2, 1, R13)
|
||||
|
||||
// Rounds 8-11
|
||||
VMOVDQU 32(SI), X3
|
||||
MOVOU 32(SI), X3
|
||||
PSHUFB X7, X3
|
||||
SHA1NEXTE X3, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1RNDS4 $0x00, X5, X0
|
||||
SHA1MSG1 X3, X2
|
||||
PXOR X3, X1
|
||||
LOADM1(X3, 2, R13)
|
||||
|
||||
// Rounds 12-15
|
||||
VMOVDQU 48(SI), X4
|
||||
MOVOU 48(SI), X4
|
||||
PSHUFB X7, X4
|
||||
SHA1NEXTE X4, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X4, X1
|
||||
SHA1RNDS4 $0x00, X6, X0
|
||||
SHA1MSG1 X4, X3
|
||||
@@ -96,7 +98,7 @@ loop:
|
||||
|
||||
// Rounds 16-19
|
||||
SHA1NEXTE X1, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X1, X2
|
||||
SHA1RNDS4 $0x00, X5, X0
|
||||
SHA1MSG1 X1, X4
|
||||
@@ -105,7 +107,7 @@ loop:
|
||||
|
||||
// Rounds 20-23
|
||||
SHA1NEXTE X2, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X2, X3
|
||||
SHA1RNDS4 $0x01, X6, X0
|
||||
SHA1MSG1 X2, X1
|
||||
@@ -114,7 +116,7 @@ loop:
|
||||
|
||||
// Rounds 24-27
|
||||
SHA1NEXTE X3, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X3, X4
|
||||
SHA1RNDS4 $0x01, X5, X0
|
||||
SHA1MSG1 X3, X2
|
||||
@@ -123,7 +125,7 @@ loop:
|
||||
|
||||
// Rounds 28-31
|
||||
SHA1NEXTE X4, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X4, X1
|
||||
SHA1RNDS4 $0x01, X6, X0
|
||||
SHA1MSG1 X4, X3
|
||||
@@ -132,7 +134,7 @@ loop:
|
||||
|
||||
// Rounds 32-35
|
||||
SHA1NEXTE X1, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X1, X2
|
||||
SHA1RNDS4 $0x01, X5, X0
|
||||
SHA1MSG1 X1, X4
|
||||
@@ -141,7 +143,7 @@ loop:
|
||||
|
||||
// Rounds 36-39
|
||||
SHA1NEXTE X2, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X2, X3
|
||||
SHA1RNDS4 $0x01, X6, X0
|
||||
SHA1MSG1 X2, X1
|
||||
@@ -150,7 +152,7 @@ loop:
|
||||
|
||||
// Rounds 40-43
|
||||
SHA1NEXTE X3, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X3, X4
|
||||
SHA1RNDS4 $0x02, X5, X0
|
||||
SHA1MSG1 X3, X2
|
||||
@@ -159,7 +161,7 @@ loop:
|
||||
|
||||
// Rounds 44-47
|
||||
SHA1NEXTE X4, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X4, X1
|
||||
SHA1RNDS4 $0x02, X6, X0
|
||||
SHA1MSG1 X4, X3
|
||||
@@ -168,21 +170,20 @@ loop:
|
||||
|
||||
// Rounds 48-51
|
||||
SHA1NEXTE X1, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X1, X2
|
||||
SHA1RNDS4 $0x02, X5, X0
|
||||
VPEXTRD $0, X5, R12
|
||||
SHA1MSG1 X1, X4
|
||||
PXOR X1, X3
|
||||
LOADM1(X1, 12, R13)
|
||||
|
||||
// derive pre-round 56's E out of round 51's A.
|
||||
VPEXTRD $3, X0, R12
|
||||
PEXTRD $3, X0, R12
|
||||
ROLL $30, R12
|
||||
|
||||
// Rounds 52-55
|
||||
SHA1NEXTE X2, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X2, X3
|
||||
SHA1RNDS4 $0x02, X6, X0
|
||||
SHA1MSG1 X2, X1
|
||||
@@ -194,21 +195,20 @@ loop:
|
||||
|
||||
// Rounds 56-59
|
||||
SHA1NEXTE X3, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X3, X4
|
||||
SHA1RNDS4 $0x02, X5, X0
|
||||
VPEXTRD $0, X5, R12
|
||||
SHA1MSG1 X3, X2
|
||||
PXOR X3, X1
|
||||
LOADM1(X3, 14, R13)
|
||||
|
||||
// derive pre-round 64's E out of round 59's A.
|
||||
VPEXTRD $3, X0, R12
|
||||
PEXTRD $3, X0, R12
|
||||
ROLL $30, R12
|
||||
|
||||
// Rounds 60-63
|
||||
SHA1NEXTE X4, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X4, X1
|
||||
SHA1RNDS4 $0x03, X6, X0
|
||||
SHA1MSG1 X4, X3
|
||||
@@ -220,7 +220,7 @@ loop:
|
||||
|
||||
// Rounds 64-67
|
||||
SHA1NEXTE X1, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X1, X2
|
||||
SHA1RNDS4 $0x03, X5, X0
|
||||
SHA1MSG1 X1, X4
|
||||
@@ -229,7 +229,7 @@ loop:
|
||||
|
||||
// Rounds 68-71
|
||||
SHA1NEXTE X2, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1MSG2 X2, X3
|
||||
SHA1RNDS4 $0x03, X6, X0
|
||||
PXOR X2, X4
|
||||
@@ -237,14 +237,14 @@ loop:
|
||||
|
||||
// Rounds 72-75
|
||||
SHA1NEXTE X3, X5
|
||||
VMOVDQA X0, X6
|
||||
MOVO X0, X6
|
||||
SHA1MSG2 X3, X4
|
||||
SHA1RNDS4 $0x03, X5, X0
|
||||
LOADM1(X3, 18, R13)
|
||||
|
||||
// Rounds 76-79
|
||||
SHA1NEXTE X4, X6
|
||||
VMOVDQA X0, X5
|
||||
MOVO X0, X5
|
||||
SHA1RNDS4 $0x03, X6, X0
|
||||
LOADM1(X4, 19, R13)
|
||||
|
||||
@@ -252,14 +252,9 @@ loop:
|
||||
SHA1NEXTE (AX), X5
|
||||
PADDD 16(AX), X0
|
||||
|
||||
// Check if we are done, if not return to the loop
|
||||
ADDQ $0x40, SI
|
||||
CMPQ SI, DX
|
||||
JNE loop
|
||||
|
||||
// Write the hash state back to digest
|
||||
PSHUFD $0x1b, X0, X0
|
||||
VMOVDQU X0, (DI)
|
||||
MOVOU X0, (DI)
|
||||
PEXTRD $0x03, X5, 16(DI)
|
||||
|
||||
done:
|
||||
|
||||
+15
-11
@@ -4,15 +4,17 @@
|
||||
package sha1cd
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
shared "github.com/pjbgf/sha1cd/internal"
|
||||
"github.com/pjbgf/sha1cd/internal/cpu"
|
||||
"github.com/pjbgf/sha1cd/ubc"
|
||||
)
|
||||
|
||||
var hasSHA1 = (runtime.GOARCH == "arm64" && cpuid.CPU.Supports(cpuid.SHA1))
|
||||
var hasSHA1 = cpu.ARM64.HasSHA1
|
||||
|
||||
// blockARM64 hashes the message p into the current state in h.
|
||||
// blockARM64 hashes a single chunk of p into the current state in h.
|
||||
// p must hold at least one whole chunk. Anything beyond the first chunk is
|
||||
// ignored, as the collision detection the caller runs afterwards inspects m1
|
||||
// and cs for one chunk only.
|
||||
// Both m1 and cs are used to store intermediate results which are used by the collision detection logic.
|
||||
//
|
||||
//go:noescape
|
||||
@@ -34,13 +36,15 @@ func block(dig *digest, p []byte) {
|
||||
|
||||
blockARM64(dig.h[:], chunk, m1[:], cs[:])
|
||||
|
||||
rectifyCompressionState(&m1, &cs)
|
||||
col := checkCollision(&m1, &cs, &dig.h)
|
||||
if col {
|
||||
dig.col = true
|
||||
// Assembly states need repair only when a disturbance vector survives.
|
||||
if mask := ubc.CalculateDvMask(&m1); mask != 0 {
|
||||
rectifyCompressionState(&m1, &cs)
|
||||
if checkCollision(&m1, &cs, &dig.h, mask) {
|
||||
dig.col = true
|
||||
|
||||
blockARM64(dig.h[:], chunk, m1[:], cs[:])
|
||||
blockARM64(dig.h[:], chunk, m1[:], cs[:])
|
||||
blockARM64(dig.h[:], chunk, m1[:], cs[:])
|
||||
blockARM64(dig.h[:], chunk, m1[:], cs[:])
|
||||
}
|
||||
}
|
||||
|
||||
p = p[shared.Chunk:]
|
||||
|
||||
+2
-4
@@ -37,15 +37,13 @@ TEXT ·blockARM64(SB), NOSPLIT, $80-96
|
||||
|
||||
LSR $6, R2, R2
|
||||
LSL $6, R2, R2
|
||||
ADD R16, R2, R21
|
||||
|
||||
VLD1.P 16(R0), [V0.S4]
|
||||
FMOVS (R0), F20
|
||||
SUB $16, R0, R0
|
||||
|
||||
loop:
|
||||
CMP R16, R21
|
||||
BLS end
|
||||
// The caller passes exactly one block; skip hashing only if p is shorter.
|
||||
CBZ R2, end
|
||||
|
||||
// Load block (p) into 16-bytes vectors.
|
||||
VLD1.P 16(R1), [V4.B16]
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
//go:build !noasm && gc && arm64 && !amd64 && sha1cd_asmtest
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// callBlockARM64DirtyRegs calls blockARM64 with every general-purpose and
|
||||
// vector register the caller does not own set to all ones. It is only built
|
||||
// with the sha1cd_asmtest tag, to catch the assembly reading a register before
|
||||
// writing it.
|
||||
//
|
||||
// func callBlockARM64DirtyRegs(h []uint32, p []byte, m1 []uint32, cs [][5]uint32)
|
||||
TEXT ·callBlockARM64DirtyRegs(SB), NOSPLIT, $104-96
|
||||
MOVD h_base+0(FP), R0
|
||||
MOVD R0, 8(RSP)
|
||||
MOVD h_len+8(FP), R0
|
||||
MOVD R0, 16(RSP)
|
||||
MOVD h_cap+16(FP), R0
|
||||
MOVD R0, 24(RSP)
|
||||
MOVD p_base+24(FP), R0
|
||||
MOVD R0, 32(RSP)
|
||||
MOVD p_len+32(FP), R0
|
||||
MOVD R0, 40(RSP)
|
||||
MOVD p_cap+40(FP), R0
|
||||
MOVD R0, 48(RSP)
|
||||
MOVD m1_base+48(FP), R0
|
||||
MOVD R0, 56(RSP)
|
||||
MOVD m1_len+56(FP), R0
|
||||
MOVD R0, 64(RSP)
|
||||
MOVD m1_cap+64(FP), R0
|
||||
MOVD R0, 72(RSP)
|
||||
MOVD cs_base+72(FP), R0
|
||||
MOVD R0, 80(RSP)
|
||||
MOVD cs_len+80(FP), R0
|
||||
MOVD R0, 88(RSP)
|
||||
MOVD cs_cap+88(FP), R0
|
||||
MOVD R0, 96(RSP)
|
||||
|
||||
// R18 is reserved by the platform, R27 by the assembler, R28 holds g,
|
||||
// R29 is the frame pointer and R30 the link register.
|
||||
MOVD $-1, R0
|
||||
MOVD R0, R1
|
||||
MOVD R0, R2
|
||||
MOVD R0, R3
|
||||
MOVD R0, R4
|
||||
MOVD R0, R5
|
||||
MOVD R0, R6
|
||||
MOVD R0, R7
|
||||
MOVD R0, R8
|
||||
MOVD R0, R9
|
||||
MOVD R0, R10
|
||||
MOVD R0, R11
|
||||
MOVD R0, R12
|
||||
MOVD R0, R13
|
||||
MOVD R0, R14
|
||||
MOVD R0, R15
|
||||
MOVD R0, R16
|
||||
MOVD R0, R17
|
||||
MOVD R0, R19
|
||||
MOVD R0, R20
|
||||
MOVD R0, R21
|
||||
MOVD R0, R22
|
||||
MOVD R0, R23
|
||||
MOVD R0, R24
|
||||
MOVD R0, R25
|
||||
MOVD R0, R26
|
||||
|
||||
VMOVI $0xff, V0.B16
|
||||
VMOVI $0xff, V1.B16
|
||||
VMOVI $0xff, V2.B16
|
||||
VMOVI $0xff, V3.B16
|
||||
VMOVI $0xff, V4.B16
|
||||
VMOVI $0xff, V5.B16
|
||||
VMOVI $0xff, V6.B16
|
||||
VMOVI $0xff, V7.B16
|
||||
VMOVI $0xff, V8.B16
|
||||
VMOVI $0xff, V9.B16
|
||||
VMOVI $0xff, V10.B16
|
||||
VMOVI $0xff, V11.B16
|
||||
VMOVI $0xff, V12.B16
|
||||
VMOVI $0xff, V13.B16
|
||||
VMOVI $0xff, V14.B16
|
||||
VMOVI $0xff, V15.B16
|
||||
VMOVI $0xff, V16.B16
|
||||
VMOVI $0xff, V17.B16
|
||||
VMOVI $0xff, V18.B16
|
||||
VMOVI $0xff, V19.B16
|
||||
VMOVI $0xff, V20.B16
|
||||
VMOVI $0xff, V21.B16
|
||||
VMOVI $0xff, V22.B16
|
||||
VMOVI $0xff, V23.B16
|
||||
VMOVI $0xff, V24.B16
|
||||
VMOVI $0xff, V25.B16
|
||||
VMOVI $0xff, V26.B16
|
||||
VMOVI $0xff, V27.B16
|
||||
VMOVI $0xff, V28.B16
|
||||
VMOVI $0xff, V29.B16
|
||||
VMOVI $0xff, V30.B16
|
||||
VMOVI $0xff, V31.B16
|
||||
|
||||
BL ·blockARM64(SB)
|
||||
RET
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
//go:build !noasm && gc && amd64
|
||||
|
||||
package sha1cd
|
||||
|
||||
import (
|
||||
shared "github.com/pjbgf/sha1cd/internal"
|
||||
"github.com/pjbgf/sha1cd/internal/cpu"
|
||||
"github.com/pjbgf/sha1cd/ubc"
|
||||
)
|
||||
|
||||
// hasAVX2 reports whether blockAVX2 can run. It is the fallback for CPUs
|
||||
// without SHA-NI, such as Intel's big cores before Ice Lake.
|
||||
var hasAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI1 && cpu.X86.HasBMI2
|
||||
|
||||
// scheduleAVX2 expands the message schedules of the blocks at pa and pb, which
|
||||
// may be the same, into m1a and m1b.
|
||||
//
|
||||
//go:noescape
|
||||
func scheduleAVX2(pa, pb *byte, m1a, m1b *[shared.Rounds]uint32)
|
||||
|
||||
// roundsBMI2 compresses the block whose schedule is in m1 into h, and stores
|
||||
// the states before steps 0, 58 and 65 into cs.
|
||||
//
|
||||
//go:noescape
|
||||
func roundsBMI2(h *[shared.WordBuffers]uint32, m1 *[shared.Rounds]uint32,
|
||||
cs *[shared.PreStepState][shared.WordBuffers]uint32)
|
||||
|
||||
func blockAVX2(dig *digest, p []byte) {
|
||||
var m1 [2][shared.Rounds]uint32
|
||||
cs := [shared.PreStepState][shared.WordBuffers]uint32{}
|
||||
|
||||
for len(p) >= shared.Chunk {
|
||||
// The schedules do not depend on the chaining state, so expand two
|
||||
// blocks at once. The rounds must still run one block at a time, as a
|
||||
// detected collision changes the state the next block starts from.
|
||||
n, pb := 1, p
|
||||
if len(p) >= 2*shared.Chunk {
|
||||
n, pb = 2, p[shared.Chunk:]
|
||||
}
|
||||
scheduleAVX2(&p[0], &pb[0], &m1[0], &m1[1])
|
||||
|
||||
for j := 0; j < n; j++ {
|
||||
w := &m1[j]
|
||||
roundsBMI2(&dig.h, w, &cs)
|
||||
if mask := ubc.CalculateDvMask(w); mask != 0 && checkCollision(w, &cs, &dig.h, mask) {
|
||||
dig.col = true
|
||||
|
||||
roundsBMI2(&dig.h, w, &cs)
|
||||
roundsBMI2(&dig.h, w, &cs)
|
||||
}
|
||||
}
|
||||
|
||||
p = p[n*shared.Chunk:]
|
||||
}
|
||||
}
|
||||
+415
@@ -0,0 +1,415 @@
|
||||
//go:build !noasm && gc && amd64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// The fallback for CPUs without SHA-NI. The message schedule is expanded with
|
||||
// AVX2 for two blocks at a time, one per 128-bit lane, as it does not depend
|
||||
// on the chaining state. The rounds then run one block at a time with scalar
|
||||
// BMI instructions, so that the collision detection can run between blocks
|
||||
// and gets the exact states before steps 58 and 65, with no repair needed.
|
||||
|
||||
// func scheduleAVX2(pa, pb *byte, m1a, m1b *[80]uint32)
|
||||
// Requires: AVX, AVX2
|
||||
//
|
||||
// Expands the blocks at pa and pb, which may be the same, into m1a and m1b.
|
||||
// Y0-Y7 hold the last eight groups of four words, group g in Y(g%8).
|
||||
TEXT ·scheduleAVX2(SB), NOSPLIT, $0-32
|
||||
MOVQ pa+0(FP), AX
|
||||
MOVQ pb+8(FP), BX
|
||||
MOVQ m1a+16(FP), CX
|
||||
MOVQ m1b+24(FP), DX
|
||||
VBROADCASTI128 bswap_mask<>(SB), Y13
|
||||
|
||||
// W[0..3] loaded from the blocks
|
||||
VMOVDQU 0(AX), X0
|
||||
VINSERTI128 $1, 0(BX), Y0, Y0
|
||||
VPSHUFB Y13, Y0, Y0
|
||||
VMOVDQU X0, 0(CX)
|
||||
VEXTRACTI128 $1, Y0, 0(DX)
|
||||
|
||||
// W[4..7] loaded from the blocks
|
||||
VMOVDQU 16(AX), X1
|
||||
VINSERTI128 $1, 16(BX), Y1, Y1
|
||||
VPSHUFB Y13, Y1, Y1
|
||||
VMOVDQU X1, 16(CX)
|
||||
VEXTRACTI128 $1, Y1, 16(DX)
|
||||
|
||||
// W[8..11] loaded from the blocks
|
||||
VMOVDQU 32(AX), X2
|
||||
VINSERTI128 $1, 32(BX), Y2, Y2
|
||||
VPSHUFB Y13, Y2, Y2
|
||||
VMOVDQU X2, 32(CX)
|
||||
VEXTRACTI128 $1, Y2, 32(DX)
|
||||
|
||||
// W[12..15] loaded from the blocks
|
||||
VMOVDQU 48(AX), X3
|
||||
VINSERTI128 $1, 48(BX), Y3, Y3
|
||||
VPSHUFB Y13, Y3, Y3
|
||||
VMOVDQU X3, 48(CX)
|
||||
VEXTRACTI128 $1, Y3, 48(DX)
|
||||
|
||||
// W[16..19] = rol1(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]). W[i+3] needs
|
||||
// W[i] from this group, which is added in afterwards.
|
||||
VPALIGNR $8, Y0, Y1, Y8 // W[i-14..i-11]
|
||||
VPXOR Y0, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y2, Y8, Y8 // W[i-8..i-5]
|
||||
VPSRLDQ $4, Y3, Y9 // W[i-3..i-1], 0
|
||||
VPXOR Y9, Y8, Y8
|
||||
VPSRLD $31, Y8, Y9
|
||||
VPSLLD $1, Y8, Y4
|
||||
VPOR Y9, Y4, Y4
|
||||
VPSLLDQ $12, Y8, Y10 // 0, 0, 0, the input to W[i]
|
||||
VPSRLD $30, Y10, Y9
|
||||
VPSLLD $2, Y10, Y10
|
||||
VPOR Y9, Y10, Y10 // rol1(W[i]) in the lane of W[i+3]
|
||||
VPXOR Y10, Y4, Y4
|
||||
VMOVDQU X4, 64(CX)
|
||||
VEXTRACTI128 $1, Y4, 64(DX)
|
||||
|
||||
// W[20..23] = rol1(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]). W[i+3] needs
|
||||
// W[i] from this group, which is added in afterwards.
|
||||
VPALIGNR $8, Y1, Y2, Y8 // W[i-14..i-11]
|
||||
VPXOR Y1, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y3, Y8, Y8 // W[i-8..i-5]
|
||||
VPSRLDQ $4, Y4, Y9 // W[i-3..i-1], 0
|
||||
VPXOR Y9, Y8, Y8
|
||||
VPSRLD $31, Y8, Y9
|
||||
VPSLLD $1, Y8, Y5
|
||||
VPOR Y9, Y5, Y5
|
||||
VPSLLDQ $12, Y8, Y10 // 0, 0, 0, the input to W[i]
|
||||
VPSRLD $30, Y10, Y9
|
||||
VPSLLD $2, Y10, Y10
|
||||
VPOR Y9, Y10, Y10 // rol1(W[i]) in the lane of W[i+3]
|
||||
VPXOR Y10, Y5, Y5
|
||||
VMOVDQU X5, 80(CX)
|
||||
VEXTRACTI128 $1, Y5, 80(DX)
|
||||
|
||||
// W[24..27] = rol1(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]). W[i+3] needs
|
||||
// W[i] from this group, which is added in afterwards.
|
||||
VPALIGNR $8, Y2, Y3, Y8 // W[i-14..i-11]
|
||||
VPXOR Y2, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y4, Y8, Y8 // W[i-8..i-5]
|
||||
VPSRLDQ $4, Y5, Y9 // W[i-3..i-1], 0
|
||||
VPXOR Y9, Y8, Y8
|
||||
VPSRLD $31, Y8, Y9
|
||||
VPSLLD $1, Y8, Y6
|
||||
VPOR Y9, Y6, Y6
|
||||
VPSLLDQ $12, Y8, Y10 // 0, 0, 0, the input to W[i]
|
||||
VPSRLD $30, Y10, Y9
|
||||
VPSLLD $2, Y10, Y10
|
||||
VPOR Y9, Y10, Y10 // rol1(W[i]) in the lane of W[i+3]
|
||||
VPXOR Y10, Y6, Y6
|
||||
VMOVDQU X6, 96(CX)
|
||||
VEXTRACTI128 $1, Y6, 96(DX)
|
||||
|
||||
// W[28..31] = rol1(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]). W[i+3] needs
|
||||
// W[i] from this group, which is added in afterwards.
|
||||
VPALIGNR $8, Y3, Y4, Y8 // W[i-14..i-11]
|
||||
VPXOR Y3, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y5, Y8, Y8 // W[i-8..i-5]
|
||||
VPSRLDQ $4, Y6, Y9 // W[i-3..i-1], 0
|
||||
VPXOR Y9, Y8, Y8
|
||||
VPSRLD $31, Y8, Y9
|
||||
VPSLLD $1, Y8, Y7
|
||||
VPOR Y9, Y7, Y7
|
||||
VPSLLDQ $12, Y8, Y10 // 0, 0, 0, the input to W[i]
|
||||
VPSRLD $30, Y10, Y9
|
||||
VPSLLD $2, Y10, Y10
|
||||
VPOR Y9, Y10, Y10 // rol1(W[i]) in the lane of W[i+3]
|
||||
VPXOR Y10, Y7, Y7
|
||||
VMOVDQU X7, 112(CX)
|
||||
VEXTRACTI128 $1, Y7, 112(DX)
|
||||
|
||||
// W[32..35] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y6, Y7, Y8 // W[i-6..i-3]
|
||||
VPXOR Y4, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y1, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y0, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y0
|
||||
VPOR Y9, Y0, Y0
|
||||
VMOVDQU X0, 128(CX)
|
||||
VEXTRACTI128 $1, Y0, 128(DX)
|
||||
|
||||
// W[36..39] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y7, Y0, Y8 // W[i-6..i-3]
|
||||
VPXOR Y5, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y2, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y1, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y1
|
||||
VPOR Y9, Y1, Y1
|
||||
VMOVDQU X1, 144(CX)
|
||||
VEXTRACTI128 $1, Y1, 144(DX)
|
||||
|
||||
// W[40..43] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y0, Y1, Y8 // W[i-6..i-3]
|
||||
VPXOR Y6, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y3, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y2, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y2
|
||||
VPOR Y9, Y2, Y2
|
||||
VMOVDQU X2, 160(CX)
|
||||
VEXTRACTI128 $1, Y2, 160(DX)
|
||||
|
||||
// W[44..47] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y1, Y2, Y8 // W[i-6..i-3]
|
||||
VPXOR Y7, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y4, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y3, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y3
|
||||
VPOR Y9, Y3, Y3
|
||||
VMOVDQU X3, 176(CX)
|
||||
VEXTRACTI128 $1, Y3, 176(DX)
|
||||
|
||||
// W[48..51] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y2, Y3, Y8 // W[i-6..i-3]
|
||||
VPXOR Y0, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y5, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y4, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y4
|
||||
VPOR Y9, Y4, Y4
|
||||
VMOVDQU X4, 192(CX)
|
||||
VEXTRACTI128 $1, Y4, 192(DX)
|
||||
|
||||
// W[52..55] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y3, Y4, Y8 // W[i-6..i-3]
|
||||
VPXOR Y1, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y6, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y5, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y5
|
||||
VPOR Y9, Y5, Y5
|
||||
VMOVDQU X5, 208(CX)
|
||||
VEXTRACTI128 $1, Y5, 208(DX)
|
||||
|
||||
// W[56..59] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y4, Y5, Y8 // W[i-6..i-3]
|
||||
VPXOR Y2, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y7, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y6, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y6
|
||||
VPOR Y9, Y6, Y6
|
||||
VMOVDQU X6, 224(CX)
|
||||
VEXTRACTI128 $1, Y6, 224(DX)
|
||||
|
||||
// W[60..63] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y5, Y6, Y8 // W[i-6..i-3]
|
||||
VPXOR Y3, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y0, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y7, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y7
|
||||
VPOR Y9, Y7, Y7
|
||||
VMOVDQU X7, 240(CX)
|
||||
VEXTRACTI128 $1, Y7, 240(DX)
|
||||
|
||||
// W[64..67] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y6, Y7, Y8 // W[i-6..i-3]
|
||||
VPXOR Y4, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y1, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y0, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y0
|
||||
VPOR Y9, Y0, Y0
|
||||
VMOVDQU X0, 256(CX)
|
||||
VEXTRACTI128 $1, Y0, 256(DX)
|
||||
|
||||
// W[68..71] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y7, Y0, Y8 // W[i-6..i-3]
|
||||
VPXOR Y5, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y2, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y1, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y1
|
||||
VPOR Y9, Y1, Y1
|
||||
VMOVDQU X1, 272(CX)
|
||||
VEXTRACTI128 $1, Y1, 272(DX)
|
||||
|
||||
// W[72..75] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y0, Y1, Y8 // W[i-6..i-3]
|
||||
VPXOR Y6, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y3, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y2, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y2
|
||||
VPOR Y9, Y2, Y2
|
||||
VMOVDQU X2, 288(CX)
|
||||
VEXTRACTI128 $1, Y2, 288(DX)
|
||||
|
||||
// W[76..79] = rol2(W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32])
|
||||
VPALIGNR $8, Y1, Y2, Y8 // W[i-6..i-3]
|
||||
VPXOR Y7, Y8, Y8 // W[i-16..i-13]
|
||||
VPXOR Y4, Y8, Y8 // W[i-28..i-25]
|
||||
VPXOR Y3, Y8, Y8 // W[i-32..i-29]
|
||||
VPSRLD $30, Y8, Y9
|
||||
VPSLLD $2, Y8, Y3
|
||||
VPOR Y9, Y3, Y3
|
||||
VMOVDQU X3, 304(CX)
|
||||
VEXTRACTI128 $1, Y3, 304(DX)
|
||||
|
||||
VZEROUPPER
|
||||
RET
|
||||
|
||||
// Each round adds W[i], K, f(b, c, d) and rol5(a) into e and rotates b by 30.
|
||||
// The callers rotate the register names instead of moving values around, and
|
||||
// rol5(a) goes in last, as a is the only input the previous round produced.
|
||||
#define ROUND_CH(a, b, c, d, e, i) \
|
||||
ADDL ((i)*4)(SI), e; \
|
||||
ADDL $0x5a827999, e; \
|
||||
ANDNL d, b, AX; \
|
||||
MOVL c, BX; \
|
||||
ANDL b, BX; \
|
||||
ADDL AX, e; \
|
||||
ADDL BX, e; \
|
||||
RORXL $27, a, CX; \
|
||||
RORXL $2, b, b; \
|
||||
ADDL CX, e
|
||||
|
||||
#define ROUND_PARITY(a, b, c, d, e, i, k) \
|
||||
ADDL ((i)*4)(SI), e; \
|
||||
ADDL k, e; \
|
||||
MOVL b, AX; \
|
||||
XORL c, AX; \
|
||||
XORL d, AX; \
|
||||
ADDL AX, e; \
|
||||
RORXL $27, a, CX; \
|
||||
RORXL $2, b, b; \
|
||||
ADDL CX, e
|
||||
|
||||
// maj(b, c, d) = (b & c) + ((b ^ c) & d), as the two never share a bit.
|
||||
#define ROUND_MAJ(a, b, c, d, e, i) \
|
||||
ADDL ((i)*4)(SI), e; \
|
||||
ADDL $0x8f1bbcdc, e; \
|
||||
MOVL b, AX; \
|
||||
XORL c, AX; \
|
||||
ANDL d, AX; \
|
||||
MOVL b, BX; \
|
||||
ANDL c, BX; \
|
||||
ADDL AX, e; \
|
||||
ADDL BX, e; \
|
||||
RORXL $27, a, CX; \
|
||||
RORXL $2, b, b; \
|
||||
ADDL CX, e
|
||||
|
||||
#define SAVECS(a, b, c, d, e, index) \
|
||||
MOVL a, ((index)*20+0)(DX); \
|
||||
MOVL b, ((index)*20+4)(DX); \
|
||||
MOVL c, ((index)*20+8)(DX); \
|
||||
MOVL d, ((index)*20+12)(DX); \
|
||||
MOVL e, ((index)*20+16)(DX)
|
||||
|
||||
// func roundsBMI2(h *[5]uint32, m1 *[80]uint32, cs *[3][5]uint32)
|
||||
// Requires: BMI1, BMI2
|
||||
//
|
||||
// Compresses the block whose schedule is in m1 into h, storing the states
|
||||
// before steps 0, 58 and 65 into cs.
|
||||
TEXT ·roundsBMI2(SB), NOSPLIT, $0-24
|
||||
MOVQ h+0(FP), DI
|
||||
MOVQ m1+8(FP), SI
|
||||
MOVQ cs+16(FP), DX
|
||||
MOVL 0(DI), R8
|
||||
MOVL 4(DI), R9
|
||||
MOVL 8(DI), R10
|
||||
MOVL 12(DI), R11
|
||||
MOVL 16(DI), R12
|
||||
|
||||
SAVECS(R8, R9, R10, R11, R12, 0)
|
||||
ROUND_CH(R8, R9, R10, R11, R12, 0)
|
||||
ROUND_CH(R12, R8, R9, R10, R11, 1)
|
||||
ROUND_CH(R11, R12, R8, R9, R10, 2)
|
||||
ROUND_CH(R10, R11, R12, R8, R9, 3)
|
||||
ROUND_CH(R9, R10, R11, R12, R8, 4)
|
||||
ROUND_CH(R8, R9, R10, R11, R12, 5)
|
||||
ROUND_CH(R12, R8, R9, R10, R11, 6)
|
||||
ROUND_CH(R11, R12, R8, R9, R10, 7)
|
||||
ROUND_CH(R10, R11, R12, R8, R9, 8)
|
||||
ROUND_CH(R9, R10, R11, R12, R8, 9)
|
||||
ROUND_CH(R8, R9, R10, R11, R12, 10)
|
||||
ROUND_CH(R12, R8, R9, R10, R11, 11)
|
||||
ROUND_CH(R11, R12, R8, R9, R10, 12)
|
||||
ROUND_CH(R10, R11, R12, R8, R9, 13)
|
||||
ROUND_CH(R9, R10, R11, R12, R8, 14)
|
||||
ROUND_CH(R8, R9, R10, R11, R12, 15)
|
||||
ROUND_CH(R12, R8, R9, R10, R11, 16)
|
||||
ROUND_CH(R11, R12, R8, R9, R10, 17)
|
||||
ROUND_CH(R10, R11, R12, R8, R9, 18)
|
||||
ROUND_CH(R9, R10, R11, R12, R8, 19)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 20, $0x6ed9eba1)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 21, $0x6ed9eba1)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 22, $0x6ed9eba1)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 23, $0x6ed9eba1)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 24, $0x6ed9eba1)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 25, $0x6ed9eba1)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 26, $0x6ed9eba1)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 27, $0x6ed9eba1)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 28, $0x6ed9eba1)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 29, $0x6ed9eba1)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 30, $0x6ed9eba1)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 31, $0x6ed9eba1)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 32, $0x6ed9eba1)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 33, $0x6ed9eba1)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 34, $0x6ed9eba1)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 35, $0x6ed9eba1)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 36, $0x6ed9eba1)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 37, $0x6ed9eba1)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 38, $0x6ed9eba1)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 39, $0x6ed9eba1)
|
||||
ROUND_MAJ(R8, R9, R10, R11, R12, 40)
|
||||
ROUND_MAJ(R12, R8, R9, R10, R11, 41)
|
||||
ROUND_MAJ(R11, R12, R8, R9, R10, 42)
|
||||
ROUND_MAJ(R10, R11, R12, R8, R9, 43)
|
||||
ROUND_MAJ(R9, R10, R11, R12, R8, 44)
|
||||
ROUND_MAJ(R8, R9, R10, R11, R12, 45)
|
||||
ROUND_MAJ(R12, R8, R9, R10, R11, 46)
|
||||
ROUND_MAJ(R11, R12, R8, R9, R10, 47)
|
||||
ROUND_MAJ(R10, R11, R12, R8, R9, 48)
|
||||
ROUND_MAJ(R9, R10, R11, R12, R8, 49)
|
||||
ROUND_MAJ(R8, R9, R10, R11, R12, 50)
|
||||
ROUND_MAJ(R12, R8, R9, R10, R11, 51)
|
||||
ROUND_MAJ(R11, R12, R8, R9, R10, 52)
|
||||
ROUND_MAJ(R10, R11, R12, R8, R9, 53)
|
||||
ROUND_MAJ(R9, R10, R11, R12, R8, 54)
|
||||
ROUND_MAJ(R8, R9, R10, R11, R12, 55)
|
||||
ROUND_MAJ(R12, R8, R9, R10, R11, 56)
|
||||
ROUND_MAJ(R11, R12, R8, R9, R10, 57)
|
||||
SAVECS(R10, R11, R12, R8, R9, 1)
|
||||
ROUND_MAJ(R10, R11, R12, R8, R9, 58)
|
||||
ROUND_MAJ(R9, R10, R11, R12, R8, 59)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 60, $0xca62c1d6)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 61, $0xca62c1d6)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 62, $0xca62c1d6)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 63, $0xca62c1d6)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 64, $0xca62c1d6)
|
||||
SAVECS(R8, R9, R10, R11, R12, 2)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 65, $0xca62c1d6)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 66, $0xca62c1d6)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 67, $0xca62c1d6)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 68, $0xca62c1d6)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 69, $0xca62c1d6)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 70, $0xca62c1d6)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 71, $0xca62c1d6)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 72, $0xca62c1d6)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 73, $0xca62c1d6)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 74, $0xca62c1d6)
|
||||
ROUND_PARITY(R8, R9, R10, R11, R12, 75, $0xca62c1d6)
|
||||
ROUND_PARITY(R12, R8, R9, R10, R11, 76, $0xca62c1d6)
|
||||
ROUND_PARITY(R11, R12, R8, R9, R10, 77, $0xca62c1d6)
|
||||
ROUND_PARITY(R10, R11, R12, R8, R9, 78, $0xca62c1d6)
|
||||
ROUND_PARITY(R9, R10, R11, R12, R8, 79, $0xca62c1d6)
|
||||
|
||||
ADDL R8, 0(DI)
|
||||
ADDL R9, 4(DI)
|
||||
ADDL R10, 8(DI)
|
||||
ADDL R11, 12(DI)
|
||||
ADDL R12, 16(DI)
|
||||
RET
|
||||
|
||||
// Swaps the bytes of each word, as SHA-1 reads the block big endian.
|
||||
DATA bswap_mask<>+0(SB)/8, $0x0405060700010203
|
||||
DATA bswap_mask<>+8(SB)/8, $0x0c0d0e0f08090a0b
|
||||
GLOBL bswap_mask<>(SB), RODATA|NOPTR, $16
|
||||
+32
-46
@@ -20,7 +20,9 @@ var forceGeneric bool
|
||||
// blockGeneric is a portable, pure Go version of the SHA-1 block step.
|
||||
// It's used by sha1block_generic.go and tests.
|
||||
func blockGeneric(dig *digest, p []byte) {
|
||||
var w [16]uint32
|
||||
// Expand directly into the schedule retained for collision detection.
|
||||
// Every word is overwritten for each block, including rehashes.
|
||||
var m1 [shared.Rounds]uint32
|
||||
|
||||
// cs stores the pre-step compression state for only the steps required for the
|
||||
// collision detection, which are 0, 58 and 65.
|
||||
@@ -29,7 +31,6 @@ func blockGeneric(dig *digest, p []byte) {
|
||||
|
||||
h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
|
||||
for len(p) >= shared.Chunk {
|
||||
m1 := [shared.Rounds]uint32{}
|
||||
hi := 1
|
||||
|
||||
// Collision attacks are thwarted by hashing a detected near-collision block 3 times.
|
||||
@@ -51,36 +52,27 @@ func blockGeneric(dig *digest, p []byte) {
|
||||
for ; i < 16; i++ {
|
||||
// load step
|
||||
j := i * 4
|
||||
w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
|
||||
m1[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
|
||||
|
||||
f := b&c | (^b)&d
|
||||
t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + shared.K0
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[i] + shared.K0
|
||||
a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
|
||||
// Store compression state for the collision detection.
|
||||
m1[i] = w[i&0xf]
|
||||
}
|
||||
for ; i < 20; i++ {
|
||||
tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
|
||||
w[i&0xf] = tmp<<1 | tmp>>(32-1)
|
||||
tmp := m1[i-3] ^ m1[i-8] ^ m1[i-14] ^ m1[i-16]
|
||||
m1[i] = tmp<<1 | tmp>>(32-1)
|
||||
|
||||
f := b&c | (^b)&d
|
||||
t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + shared.K0
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[i] + shared.K0
|
||||
a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
|
||||
// Store compression state for the collision detection.
|
||||
m1[i] = w[i&0xf]
|
||||
}
|
||||
for ; i < 40; i++ {
|
||||
tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
|
||||
w[i&0xf] = tmp<<1 | tmp>>(32-1)
|
||||
tmp := m1[i-3] ^ m1[i-8] ^ m1[i-14] ^ m1[i-16]
|
||||
m1[i] = tmp<<1 | tmp>>(32-1)
|
||||
|
||||
f := b ^ c ^ d
|
||||
t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + shared.K1
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[i] + shared.K1
|
||||
a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
|
||||
// Store compression state for the collision detection.
|
||||
m1[i] = w[i&0xf]
|
||||
}
|
||||
for ; i < 60; i++ {
|
||||
if i == 58 {
|
||||
@@ -88,15 +80,12 @@ func blockGeneric(dig *digest, p []byte) {
|
||||
cs[1] = [shared.WordBuffers]uint32{a, b, c, d, e}
|
||||
}
|
||||
|
||||
tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
|
||||
w[i&0xf] = tmp<<1 | tmp>>(32-1)
|
||||
tmp := m1[i-3] ^ m1[i-8] ^ m1[i-14] ^ m1[i-16]
|
||||
m1[i] = tmp<<1 | tmp>>(32-1)
|
||||
|
||||
f := ((b | c) & d) | (b & c)
|
||||
t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + shared.K2
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[i] + shared.K2
|
||||
a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
|
||||
// Store compression state for the collision detection.
|
||||
m1[i] = w[i&0xf]
|
||||
}
|
||||
for ; i < 80; i++ {
|
||||
if i == 65 {
|
||||
@@ -104,15 +93,12 @@ func blockGeneric(dig *digest, p []byte) {
|
||||
cs[2] = [shared.WordBuffers]uint32{a, b, c, d, e}
|
||||
}
|
||||
|
||||
tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
|
||||
w[i&0xf] = tmp<<1 | tmp>>(32-1)
|
||||
tmp := m1[i-3] ^ m1[i-8] ^ m1[i-14] ^ m1[i-16]
|
||||
m1[i] = tmp<<1 | tmp>>(32-1)
|
||||
|
||||
f := b ^ c ^ d
|
||||
t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + shared.K3
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[i] + shared.K3
|
||||
a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
|
||||
// Store compression state for the collision detection.
|
||||
m1[i] = w[i&0xf]
|
||||
}
|
||||
|
||||
h0 += a
|
||||
@@ -128,7 +114,7 @@ func blockGeneric(dig *digest, p []byte) {
|
||||
|
||||
if hi == 1 {
|
||||
h := [shared.WordBuffers]uint32{h0, h1, h2, h3, h4}
|
||||
col := checkCollision(&m1, &cs, &h)
|
||||
col := checkCollision(&m1, &cs, &h, ubc.CalculateDvMask(&m1))
|
||||
if col {
|
||||
dig.col = true
|
||||
hi++
|
||||
@@ -147,8 +133,9 @@ func checkCollision(
|
||||
m1 *[shared.Rounds]uint32,
|
||||
cs *[shared.PreStepState][shared.WordBuffers]uint32,
|
||||
h *[shared.WordBuffers]uint32,
|
||||
mask uint32,
|
||||
) bool {
|
||||
if mask := ubc.CalculateDvMask(m1); mask != 0 {
|
||||
if mask != 0 {
|
||||
dvs := ubc.SHA1_dvs()
|
||||
|
||||
for i := 0; dvs[i].DvType != 0; i++ {
|
||||
@@ -290,23 +277,22 @@ func rectifyCompressionState(
|
||||
return
|
||||
}
|
||||
|
||||
func3 := func(state [shared.WordBuffers]uint32, i int) [shared.WordBuffers]uint32 {
|
||||
a, b, c, d, e := state[0], state[1], state[2], state[3], state[4]
|
||||
// The words are loaded and stored one at a time. Passing [5]uint32 values
|
||||
// around made the compiler reload them with wider moves than they were
|
||||
// stored with, which stalled on store forwarding each time.
|
||||
|
||||
// Advance cs[1] from the state before step 56 to the one before step 58.
|
||||
a, b, c, d, e := cs[1][0], cs[1][1], cs[1][2], cs[1][3], cs[1][4]
|
||||
for i := 56; i < 58; i++ {
|
||||
f := ((b | c) & d) | (b & c)
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[i] + shared.K2
|
||||
a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
return [shared.WordBuffers]uint32{a, b, c, d, e}
|
||||
}
|
||||
func4 := func(state [shared.WordBuffers]uint32, i int) [shared.WordBuffers]uint32 {
|
||||
a, b, c, d, e := state[0], state[1], state[2], state[3], state[4]
|
||||
f := b ^ c ^ d
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[i] + shared.K3
|
||||
a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
return [shared.WordBuffers]uint32{a, b, c, d, e}
|
||||
}
|
||||
cs[1][0], cs[1][1], cs[1][2], cs[1][3], cs[1][4] = a, b, c, d, e
|
||||
|
||||
cs57 := func3(cs[1], 56)
|
||||
cs[1] = func3(cs57, 57)
|
||||
cs[2] = func4(cs[2], 64)
|
||||
// Advance cs[2] from the state before step 64 to the one before step 65.
|
||||
a, b, c, d, e = cs[2][0], cs[2][1], cs[2][2], cs[2][3], cs[2][4]
|
||||
f := b ^ c ^ d
|
||||
t := bits.RotateLeft32(a, 5) + f + e + m1[64] + shared.K3
|
||||
cs[2][0], cs[2][1], cs[2][2], cs[2][3], cs[2][4] = t, a, bits.RotateLeft32(b, 30), c, d
|
||||
}
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
//go:build !noasm && gc && amd64
|
||||
|
||||
package ubc
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/pjbgf/sha1cd/internal/cpu"
|
||||
)
|
||||
|
||||
// useAVX512 reports whether calculateDvMaskAVX512 can run. Its only
|
||||
// instructions outside AVX-512F are VMOVD and VZEROUPPER, which need AVX.
|
||||
// HasAVX512F is set only when the CPU reports AVX as well.
|
||||
var useAVX512 = cpu.X86.HasAVX512F
|
||||
|
||||
//go:noescape
|
||||
func calculateDvMaskAVX512(W *[80]uint32, terms *uint32, groups int) uint32
|
||||
|
||||
// avx512Lanes is the number of terms a group of avx512Terms describes, and
|
||||
// avx512Fields the vectors it holds for them.
|
||||
const (
|
||||
avx512Lanes = 16
|
||||
avx512Fields = 6
|
||||
)
|
||||
|
||||
// avx512Groups is how many passes of the kernel loop the table needs.
|
||||
const avx512Groups = len(avx512Terms) / (avx512Fields * avx512Lanes)
|
||||
|
||||
// alignedTerms is a copy of avx512Terms that starts on a cache line. The
|
||||
// linker aligns data to 32 bytes at most, and a 64 byte load that straddles
|
||||
// two cache lines costs about twice as much.
|
||||
var alignedTerms = func() *uint32 {
|
||||
buf := make([]uint32, len(avx512Terms)+16)
|
||||
off := (64 - uintptr(unsafe.Pointer(&buf[0]))%64) % 64 / 4
|
||||
copy(buf[off:], avx512Terms[:])
|
||||
return &buf[off]
|
||||
}()
|
||||
|
||||
// CalculateDvMask takes as input an expanded message block and
|
||||
// verifies the unavoidable bitconditions for all listed DVs. It returns
|
||||
// a dvmask where each bit belonging to a DV is set if all unavoidable
|
||||
// bitconditions for that DV have been met.
|
||||
func CalculateDvMask(W *[80]uint32) uint32 {
|
||||
if W == nil {
|
||||
return 0
|
||||
}
|
||||
if useAVX512 {
|
||||
return calculateDvMaskAVX512(W, alignedTerms, avx512Groups)
|
||||
}
|
||||
return calculateDvMaskGeneric(W)
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
//go:build !noasm && gc && amd64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func calculateDvMaskAVX512(W *[80]uint32, terms *uint32, groups int) uint32
|
||||
// Requires: AVX, AVX512F
|
||||
//
|
||||
// Each group of avx512Terms describes 16 of the bit tests of CalculateDvMask,
|
||||
// as vectors of word indices, shift counts, expected parities and the masks
|
||||
// that clear the DVs of a failing test. One pass of the loop runs a group.
|
||||
//
|
||||
// terms only has to be 64 byte aligned for speed, as otherwise every load of
|
||||
// it straddles two cache lines. The word indices are biased by 34, matching
|
||||
// the two vectors of W loaded below.
|
||||
TEXT ·calculateDvMaskAVX512(SB), NOSPLIT, $0-28
|
||||
MOVQ W+0(FP), AX
|
||||
MOVQ terms+8(FP), BX
|
||||
MOVQ groups+16(FP), CX
|
||||
VMOVDQU32 136(AX), Z0 // W[34..49]
|
||||
VMOVDQU32 200(AX), Z1 // W[50..65]
|
||||
VPTERNLOGD $0xff, Z2, Z2, Z2 // mask = all ones
|
||||
MOVL $1, DX
|
||||
VPBROADCASTD DX, Z3
|
||||
|
||||
loop:
|
||||
VMOVDQU32 0(BX), Z4
|
||||
VMOVDQU32 64(BX), Z5
|
||||
VPERMI2D Z1, Z0, Z4 // W[a]
|
||||
VPERMI2D Z1, Z0, Z5 // W[b]
|
||||
VPSRLVD 128(BX), Z4, Z4 // >> ka
|
||||
VPSRLVD 192(BX), Z5, Z5 // >> kb
|
||||
VPTERNLOGD $0x96, 256(BX), Z5, Z4 // ^ e
|
||||
VPTESTMD Z3, Z4, K1 // the terms whose bit test fails
|
||||
VPANDD 320(BX), Z2, K1, Z2 // clear their DVs
|
||||
ADDQ $384, BX
|
||||
DECQ CX
|
||||
JNZ loop
|
||||
|
||||
// AND the 16 lanes together, first the 128 bit lanes and then the
|
||||
// words within them.
|
||||
VSHUFI64X2 $0x4e, Z2, Z2, Z4
|
||||
VPANDD Z4, Z2, Z2
|
||||
VSHUFI64X2 $0xb1, Z2, Z2, Z4
|
||||
VPANDD Z4, Z2, Z2
|
||||
VPSHUFD $0x4e, Z2, Z4
|
||||
VPANDD Z4, Z2, Z2
|
||||
VPSHUFD $0xb1, Z2, Z4
|
||||
VPANDD Z4, Z2, Z2
|
||||
VMOVD X2, AX
|
||||
VZEROUPPER
|
||||
MOVL AX, ret+24(FP)
|
||||
RET
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
//go:build !noasm && gc && amd64
|
||||
|
||||
package ubc
|
||||
|
||||
// avx512Terms holds the bit tests of CalculateDvMask in the layout the
|
||||
// AVX-512 kernel consumes, 16 terms per group. Each term says that a set of
|
||||
// DVs survives only if bit ka of W[a] XOR bit kb of W[b] equals e, and names
|
||||
// the mask that clears those DVs when it does not.
|
||||
//
|
||||
// The six vectors of a group are, in order: a-34, b-34, ka, kb, e, and the
|
||||
// clear mask. Word indices are biased by 34 because the kernel keeps W[34..65]
|
||||
// in two registers. A group is 384 bytes, and the kernel runs one per pass.
|
||||
//
|
||||
// The terms are those of calculateDvMaskGeneric, which is a port of
|
||||
// ubc_check.c and has not changed since the collision detection was published
|
||||
// in 2017. TestAVX512MatchesGeneric holds the two implementations to the same
|
||||
// results over inputs that reach every DV, so a mistake here is a test
|
||||
// failure rather than a missed collision. The comment above each group names
|
||||
// its terms as a.ka^b.kb=e.
|
||||
var avx512Terms = [960]uint32{
|
||||
// terms 0-15
|
||||
// 44.29^45.29=0 49.29^50.29=0 48.29^49.29=0 47.4^50.29=0 47.29^48.29=0 46.4^49.29=0 46.29^47.29=0 45.4^48.29=0
|
||||
// 45.29^46.29=0 44.4^47.29=0 43.4^46.29=0 43.29^44.29=0 42.4^45.29=0 41.4^44.29=0 40.29^41.29=0 54.29^55.29=0
|
||||
0x0000000a, 0x0000000f, 0x0000000e, 0x0000000d, 0x0000000d, 0x0000000c, 0x0000000c, 0x0000000b, 0x0000000b, 0x0000000a, 0x00000009, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000014,
|
||||
0x0000000b, 0x00000010, 0x0000000f, 0x00000010, 0x0000000e, 0x0000000f, 0x0000000d, 0x0000000e, 0x0000000c, 0x0000000d, 0x0000000c, 0x0000000a, 0x0000000b, 0x0000000a, 0x00000007, 0x00000015,
|
||||
0x0000001d, 0x0000001d, 0x0000001d, 0x00000004, 0x0000001d, 0x00000004, 0x0000001d, 0x00000004, 0x0000001d, 0x00000004, 0x00000004, 0x0000001d, 0x00000004, 0x00000004, 0x0000001d, 0x0000001d,
|
||||
0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xfd7c5f7f, 0x3d7efff7, 0x9f5f7ffb, 0x7dfedddf, 0xcfcfdffd, 0xbf7f7777, 0xe7e7f7fe, 0xdfdfdddb, 0xf5f57dff, 0xefeff775, 0xf7f7fdda, 0xff5ed7df, 0xfdfd7f75, 0xff7edfda, 0x7ff5ff5d, 0x3f77dfff,
|
||||
// terms 16-31
|
||||
// 53.29^54.29=0 52.29^53.29=0 50.4^53.29=0 50.29^51.29=0 49.4^52.29=0 48.4^51.29=0 42.29^43.29=0 41.29^42.29=0
|
||||
// 40.4^43.29=0 39.4^42.29=0 38.4^41.29=0 37.4^40.29=0 55.29^56.29=0 52.4^55.29=0 51.4^54.29=0 51.29^52.29=0
|
||||
0x00000013, 0x00000012, 0x00000010, 0x00000010, 0x0000000f, 0x0000000e, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 0x00000004, 0x00000003, 0x00000015, 0x00000012, 0x00000011, 0x00000011,
|
||||
0x00000014, 0x00000013, 0x00000013, 0x00000011, 0x00000012, 0x00000011, 0x00000009, 0x00000008, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000016, 0x00000015, 0x00000014, 0x00000012,
|
||||
0x0000001d, 0x0000001d, 0x00000004, 0x0000001d, 0x00000004, 0x00000004, 0x0000001d, 0x0000001d, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x0000001d, 0x00000004, 0x00000004, 0x0000001d,
|
||||
0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x9fddf7ff, 0xcfeefdff, 0xdfed77ff, 0x75fdffdf, 0xeff6ddff, 0xf7fd777f, 0xffcff5f7, 0xffe7fd7b, 0x7fdff7f5, 0xbfeffdfa, 0x5ff7ff7d, 0xaffdffde, 0x7def7fff, 0x7f6f7fff, 0xbfd7dfff, 0xe7f7ff7f,
|
||||
// terms 32-47
|
||||
// 36.4^40.29=0 53.29^56.29=1 51.29^54.29=1 50.29^52.29=1 49.29^51.29=1 48.29^50.29=1 47.29^49.29=1 46.29^48.29=1
|
||||
// 45.6^47.6=0 45.29^47.29=1 44.6^46.6=0 44.29^46.29=1 41.1^42.6=1 40.1^41.6=1 40.4^42.4=1 39.1^40.6=1
|
||||
0x00000002, 0x00000013, 0x00000011, 0x00000010, 0x0000000f, 0x0000000e, 0x0000000d, 0x0000000c, 0x0000000b, 0x0000000b, 0x0000000a, 0x0000000a, 0x00000007, 0x00000006, 0x00000006, 0x00000005,
|
||||
0x00000006, 0x00000016, 0x00000014, 0x00000012, 0x00000011, 0x00000010, 0x0000000f, 0x0000000e, 0x0000000d, 0x0000000d, 0x0000000c, 0x0000000c, 0x00000008, 0x00000007, 0x00000008, 0x00000006,
|
||||
0x00000004, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x00000006, 0x0000001d, 0x00000006, 0x0000001d, 0x00000001, 0x00000001, 0x00000004, 0x00000001,
|
||||
0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x00000006, 0x0000001d, 0x00000006, 0x0000001d, 0x00000006, 0x00000006, 0x00000004, 0x00000006,
|
||||
0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
|
||||
0xffeefdf7, 0xffcf7fff, 0xfff5f7ff, 0xfffeddff, 0xffff777f, 0xffffdddf, 0xfffff777, 0xfffffddb, 0xffffbbbf, 0xffffff75, 0xffffeeef, 0xffffffda, 0xfbfbfeff, 0xfeffbfbf, 0x7ffffff5, 0xffbfefef,
|
||||
// terms 48-63
|
||||
// 39.4^41.4=1 38.4^40.4=1 37.4^39.4=1 36.1^37.6=1 35.4^39.29=0 63.0^64.5=1 63.1^64.6=1 62.0^63.5=1
|
||||
// 61.0^62.5=1 61.2^62.7=1 60.0^61.5=1 58.29^59.29=0 57.29^58.29=0 56.4^59.29=0 56.29^59.29=1 56.29^57.29=0
|
||||
0x00000005, 0x00000004, 0x00000003, 0x00000002, 0x00000001, 0x0000001d, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001b, 0x0000001a, 0x00000018, 0x00000017, 0x00000016, 0x00000016, 0x00000016,
|
||||
0x00000007, 0x00000006, 0x00000005, 0x00000003, 0x00000005, 0x0000001e, 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001c, 0x0000001b, 0x00000019, 0x00000018, 0x00000019, 0x00000019, 0x00000017,
|
||||
0x00000004, 0x00000004, 0x00000004, 0x00000001, 0x00000004, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x0000001d, 0x0000001d, 0x00000004, 0x0000001d, 0x0000001d,
|
||||
0x00000004, 0x00000004, 0x00000004, 0x00000006, 0x0000001d, 0x00000005, 0x00000006, 0x00000005, 0x00000005, 0x00000007, 0x00000005, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d,
|
||||
0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
|
||||
0xbffffffa, 0x5ffffffd, 0xaffffffe, 0xfffbefbf, 0xfff7ff7b, 0xffefff7f, 0xfffefffb, 0xfff7ffdf, 0xfffdfff7, 0xfffbffef, 0xfffefffb, 0xddffffff, 0xef7fffff, 0xd7ffffff, 0xf5ffffff, 0xf7dfffff,
|
||||
// terms 64-79
|
||||
// 55.4^58.29=0 54.4^57.29=0 53.4^56.29=0 50.6^51.1=0 48.6^50.6=0 48.29^55.29=1 47.6^49.6=0 47.6^48.1=0
|
||||
// 46.6^48.6=0 46.6^47.1=0 44.1^45.6=1 43.6^45.6=0 42.6^44.6=0 42.6^43.1=0 41.6^42.1=0 40.6^41.1=0
|
||||
0x00000015, 0x00000014, 0x00000013, 0x00000010, 0x0000000e, 0x0000000e, 0x0000000d, 0x0000000d, 0x0000000c, 0x0000000c, 0x0000000a, 0x00000009, 0x00000008, 0x00000008, 0x00000007, 0x00000006,
|
||||
0x00000018, 0x00000017, 0x00000016, 0x00000011, 0x00000010, 0x00000015, 0x0000000f, 0x0000000e, 0x0000000e, 0x0000000d, 0x0000000b, 0x0000000b, 0x0000000a, 0x00000009, 0x00000008, 0x00000007,
|
||||
0x00000004, 0x00000004, 0x00000004, 0x00000006, 0x00000006, 0x0000001d, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000001, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006,
|
||||
0x0000001d, 0x0000001d, 0x0000001d, 0x00000001, 0x00000006, 0x0000001d, 0x00000006, 0x00000001, 0x00000006, 0x00000001, 0x00000006, 0x00000006, 0x00000006, 0x00000001, 0x00000001, 0x00000001,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xedffffff, 0xf77fffff, 0xfddfffff, 0xfffbefff, 0xfffbefff, 0xffff5fff, 0xffffbbff, 0xfbffffbf, 0xffffeeff, 0xfeffffef, 0xffbfbfff, 0xfffffbbf, 0xfffffeef, 0xfbfbffff, 0xfeffbfff, 0xffbfefff,
|
||||
// terms 80-95
|
||||
// 39.4^43.29=0 38.4^42.29=0 37.1^38.6=1 37.4^41.29=0 36.4^38.4=1 35.1^36.6=1 35.3^39.28=0 61.1^62.6=1
|
||||
// 59.5^63.30=0 58.0^63.30=1 62.1^63.6=1 60.5^64.30=0 59.0^64.30=1 40.6^42.6=0 62.2^63.7=1 41.6^43.6=0
|
||||
0x00000005, 0x00000004, 0x00000003, 0x00000003, 0x00000002, 0x00000001, 0x00000001, 0x0000001b, 0x00000019, 0x00000018, 0x0000001c, 0x0000001a, 0x00000019, 0x00000006, 0x0000001c, 0x00000007,
|
||||
0x00000009, 0x00000008, 0x00000004, 0x00000007, 0x00000004, 0x00000002, 0x00000005, 0x0000001c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001e, 0x0000001e, 0x00000008, 0x0000001d, 0x00000009,
|
||||
0x00000004, 0x00000004, 0x00000001, 0x00000004, 0x00000004, 0x00000001, 0x00000003, 0x00000001, 0x00000005, 0x00000000, 0x00000001, 0x00000005, 0x00000000, 0x00000006, 0x00000002, 0x00000006,
|
||||
0x0000001d, 0x0000001d, 0x00000006, 0x0000001d, 0x00000004, 0x00000006, 0x0000001c, 0x00000006, 0x0000001e, 0x0000001e, 0x00000006, 0x0000001e, 0x0000001e, 0x00000006, 0x00000007, 0x00000006,
|
||||
0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000,
|
||||
0xfdff7fff, 0xff7fdfff, 0xffffbeff, 0xffdff7ff, 0xd7ffffff, 0xfffffbef, 0xfff7dfff, 0xfffffffe, 0xfffffffe, 0xfffffffe, 0xfffffffd, 0xfffffffd, 0xfffffffd, 0xffffffef, 0xffffffbf, 0xffffffbf,
|
||||
// terms 96-111
|
||||
// 63.2^64.7=1 48.6^49.1=0 49.6^50.1=0 42.1^50.1=1 39.6^40.1=0 38.1^40.1=1 36.4^37.4=1 43.1^51.1=1
|
||||
// 37.4^38.4=1 51.6^52.1=0 49.6^51.6=0 37.1^37.6=0 35.5^39.30=0 38.4^39.4=1 47.1^51.1=1 36.3^40.28=0
|
||||
0x0000001d, 0x0000000e, 0x0000000f, 0x00000008, 0x00000005, 0x00000004, 0x00000002, 0x00000009, 0x00000003, 0x00000011, 0x0000000f, 0x00000003, 0x00000001, 0x00000004, 0x0000000d, 0x00000002,
|
||||
0x0000001e, 0x0000000f, 0x00000010, 0x00000010, 0x00000006, 0x00000006, 0x00000003, 0x00000011, 0x00000004, 0x00000012, 0x00000011, 0x00000003, 0x00000005, 0x00000005, 0x00000011, 0x00000006,
|
||||
0x00000002, 0x00000006, 0x00000006, 0x00000001, 0x00000006, 0x00000001, 0x00000004, 0x00000001, 0x00000004, 0x00000006, 0x00000006, 0x00000001, 0x00000005, 0x00000004, 0x00000001, 0x00000003,
|
||||
0x00000007, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000004, 0x00000001, 0x00000004, 0x00000001, 0x00000006, 0x00000006, 0x0000001e, 0x00000004, 0x00000001, 0x0000001c,
|
||||
0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
|
||||
0xfffffeff, 0xfffffeff, 0xfffffbff, 0xfffffbff, 0xfffffbff, 0xfffffbff, 0xfffff7ff, 0xffffefff, 0xffffdfff, 0xffffbfff, 0xffffbfff, 0xffffbfff, 0xffffbfff, 0xffff7fff, 0xfffbffff, 0xffefffff,
|
||||
// terms 112-127
|
||||
// 35.30^40.28=1 37.3^41.28=0 36.30^41.28=1 53.6^54.1=0 51.6^53.6=0 50.1^54.1=1 45.6^46.1=0 37.5^41.30=0
|
||||
// 36.0^41.30=1 55.29^58.29=1 38.3^42.28=0 37.30^42.28=1 54.6^55.1=0 52.6^54.6=0 51.1^55.1=1 45.1^47.1=1
|
||||
0x00000001, 0x00000003, 0x00000002, 0x00000013, 0x00000011, 0x00000010, 0x0000000b, 0x00000003, 0x00000002, 0x00000015, 0x00000004, 0x00000003, 0x00000014, 0x00000012, 0x00000011, 0x0000000b,
|
||||
0x00000006, 0x00000007, 0x00000007, 0x00000014, 0x00000013, 0x00000014, 0x0000000c, 0x00000007, 0x00000007, 0x00000018, 0x00000008, 0x00000008, 0x00000015, 0x00000014, 0x00000015, 0x0000000d,
|
||||
0x0000001e, 0x00000003, 0x0000001e, 0x00000006, 0x00000006, 0x00000001, 0x00000006, 0x00000005, 0x00000000, 0x0000001d, 0x00000003, 0x0000001e, 0x00000006, 0x00000006, 0x00000001, 0x00000001,
|
||||
0x0000001c, 0x0000001c, 0x0000001c, 0x00000001, 0x00000006, 0x00000001, 0x00000001, 0x0000001e, 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001c, 0x00000001, 0x00000006, 0x00000001, 0x00000001,
|
||||
0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001,
|
||||
0xffefffff, 0xffdfffff, 0xffdfffff, 0xffbfffff, 0xffbfffff, 0xffbfffff, 0xffbfffff, 0xffbfffff, 0xffbfffff, 0xff7fffff, 0xff7fffff, 0xff7fffff, 0xfeffffff, 0xfeffffff, 0xfeffffff, 0xfeffffff,
|
||||
// terms 128-143
|
||||
// 38.5^42.30=0 37.0^42.30=1 39.3^43.28=0 38.30^43.28=1 55.6^56.1=0 53.6^55.6=0 52.1^56.1=1 46.1^48.1=1
|
||||
// 39.5^43.30=0 38.0^43.30=1 59.29^60.29=0 40.3^44.28=0 40.4^44.29=0 39.30^44.28=1 58.29^61.29=1 57.4^61.29=0
|
||||
0x00000004, 0x00000003, 0x00000005, 0x00000004, 0x00000015, 0x00000013, 0x00000012, 0x0000000c, 0x00000005, 0x00000004, 0x00000019, 0x00000006, 0x00000006, 0x00000005, 0x00000018, 0x00000017,
|
||||
0x00000008, 0x00000008, 0x00000009, 0x00000009, 0x00000016, 0x00000015, 0x00000016, 0x0000000e, 0x00000009, 0x00000009, 0x0000001a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000001b, 0x0000001b,
|
||||
0x00000005, 0x00000000, 0x00000003, 0x0000001e, 0x00000006, 0x00000006, 0x00000001, 0x00000001, 0x00000005, 0x00000000, 0x0000001d, 0x00000003, 0x00000004, 0x0000001e, 0x0000001d, 0x00000004,
|
||||
0x0000001e, 0x0000001e, 0x0000001c, 0x0000001c, 0x00000001, 0x00000006, 0x00000001, 0x00000001, 0x0000001e, 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001d, 0x0000001c, 0x0000001d, 0x0000001d,
|
||||
0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
|
||||
0xfeffffff, 0xfeffffff, 0xfdffffff, 0xfdffffff, 0xfbffffff, 0xfbffffff, 0xfbffffff, 0xfbffffff, 0xfbffffff, 0xfbffffff, 0xf7ffffff, 0xf7ffffff, 0xf7ffffff, 0xf7ffffff, 0xefffffff, 0xefffffff,
|
||||
// terms 144-159
|
||||
// 41.3^45.28=0 41.4^45.29=0 58.4^62.29=0 42.3^46.28=0 42.4^46.29=0 59.4^63.29=0 57.4^59.29=0 43.3^47.28=0
|
||||
// 43.4^47.29=0 60.4^64.29=0 44.3^48.28=0 44.4^48.29=0 35.0^35.0=0 35.0^35.0=0 35.0^35.0=0 35.0^35.0=0
|
||||
0x00000007, 0x00000007, 0x00000018, 0x00000008, 0x00000008, 0x00000019, 0x00000017, 0x00000009, 0x00000009, 0x0000001a, 0x0000000a, 0x0000000a, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
|
||||
0x0000000b, 0x0000000b, 0x0000001c, 0x0000000c, 0x0000000c, 0x0000001d, 0x00000019, 0x0000000d, 0x0000000d, 0x0000001e, 0x0000000e, 0x0000000e, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
|
||||
0x00000003, 0x00000004, 0x00000004, 0x00000003, 0x00000004, 0x00000004, 0x00000004, 0x00000003, 0x00000004, 0x00000004, 0x00000003, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x0000001c, 0x0000001d, 0x0000001d, 0x0000001c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001c, 0x0000001d, 0x0000001d, 0x0000001c, 0x0000001d, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xefffffff, 0xefffffff, 0xdfffffff, 0xdfffffff, 0xdfffffff, 0xbfffffff, 0xbfffffff, 0xbfffffff, 0xbfffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//go:build noasm || !gc || !amd64
|
||||
|
||||
package ubc
|
||||
|
||||
// CalculateDvMask takes as input an expanded message block and
|
||||
// verifies the unavoidable bitconditions for all listed DVs. It returns
|
||||
// a dvmask where each bit belonging to a DV is set if all unavoidable
|
||||
// bitconditions for that DV have been met.
|
||||
func CalculateDvMask(W *[80]uint32) uint32 {
|
||||
if W == nil {
|
||||
return 0
|
||||
}
|
||||
return calculateDvMaskGeneric(W)
|
||||
}
|
||||
+4
-8
@@ -23,16 +23,12 @@ type DvInfo struct {
|
||||
Dm [80]uint32
|
||||
}
|
||||
|
||||
// CalculateDvMask takes as input an expanded message block and
|
||||
// verifies the unavoidable bitconditions for all listed DVs. It returns
|
||||
// a dvmask where each bit belonging to a DV is set if all unavoidable
|
||||
// bitconditions for that DV have been met.
|
||||
// calculateDvMaskGeneric is the portable implementation of CalculateDvMask.
|
||||
// The AVX-512 kernel runs the same bit tests from avx512Terms, and
|
||||
// TestAVX512MatchesGeneric holds the two to the same results.
|
||||
//
|
||||
//go:nosplit
|
||||
func CalculateDvMask(W *[80]uint32) uint32 {
|
||||
if W == nil {
|
||||
return 0
|
||||
}
|
||||
func calculateDvMaskGeneric(W *[80]uint32) uint32 {
|
||||
mask := uint32(0xFFFFFFFF)
|
||||
mask &= (((((W[44] ^ W[45]) >> 29) & 1) - 1) | ^(DV_I_48_0_bit | DV_I_51_0_bit | DV_I_52_0_bit | DV_II_45_0_bit | DV_II_46_0_bit | DV_II_50_0_bit | DV_II_51_0_bit))
|
||||
mask &= (((((W[49] ^ W[50]) >> 29) & 1) - 1) | ^(DV_I_46_0_bit | DV_II_45_0_bit | DV_II_50_0_bit | DV_II_51_0_bit | DV_II_55_0_bit | DV_II_56_0_bit))
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# This is a renovate-friendly source of Docker images.
|
||||
FROM python:3.13.6-slim-bullseye@sha256:e98b521460ee75bca92175c16247bdf7275637a8faaeb2bcfa19d879ae5c4b9a AS python
|
||||
FROM otel/weaver:v0.26.1@sha256:9094862c0ab261bdbcb079bb981f9a573b3659b130a6d2ab8616eca6ba37aaec AS weaver
|
||||
FROM otel/weaver:v0.21.2@sha256:2401de985c38bdb98b43918e2f43aa36b2afed4aa5669ac1c1de0a17301cd36d AS weaver
|
||||
FROM avtodev/markdown-lint:v1@sha256:6aeedc2f49138ce7a1cd0adffc1b1c0321b841dc2102408967d9301c031949ee AS markdown
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
codespell==2.4.3
|
||||
codespell==2.4.2
|
||||
|
||||
+18
-17
@@ -17,8 +17,8 @@
|
||||
// It uses data-independent memory access, which is preferred for password
|
||||
// hashing and password-based key derivation. Argon2i requires more passes over
|
||||
// memory than Argon2id to protect from trade-off attacks. The recommended
|
||||
// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive operations are time=3 and to
|
||||
// use the maximum available memory.
|
||||
// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive
|
||||
// operations are time=3 and to use the maximum available memory.
|
||||
//
|
||||
// # Argon2id
|
||||
//
|
||||
@@ -26,11 +26,14 @@
|
||||
// Argon2i and Argon2d. It uses data-independent memory access for the first
|
||||
// half of the first iteration over the memory and data-dependent memory access
|
||||
// for the rest. Argon2id is side-channel resistant and provides better brute-
|
||||
// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
|
||||
// parameters for non-interactive operations (taken from [RFC 9106 Section 7.3]) are time=1 and to
|
||||
// use the maximum available memory.
|
||||
// force cost savings due to time-memory tradeoffs than Argon2i. [RFC 9106
|
||||
// Section 4] recommends time=1, memory=2*1024*1024 KiB (2 GiB), and threads=4
|
||||
// as the first recommended option. If much less memory is available, it
|
||||
// recommends time=3, memory=64*1024 KiB (64 MiB), and threads=4 as the second
|
||||
// recommended option.
|
||||
//
|
||||
// [argon2-specs.pdf]: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
|
||||
// [RFC 9106 Section 4]: https://www.rfc-editor.org/rfc/rfc9106.html#section-4
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
package argon2
|
||||
|
||||
@@ -59,9 +62,9 @@ const (
|
||||
//
|
||||
// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
|
||||
//
|
||||
// [RFC 9106 Section 7.3] recommends time=3, and memory=32*1024 as a sensible number.
|
||||
// If using that amount of memory (32 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
// The example above uses time=3 and memory=32*1024. Argon2i generally
|
||||
// requires more passes over memory than Argon2id. If in doubt, prefer IDKey
|
||||
// and its Argon2id parameter recommendations.
|
||||
//
|
||||
// The time parameter specifies the number of passes over the memory and the
|
||||
// memory parameter specifies the size of the memory in KiB. For example
|
||||
@@ -69,8 +72,6 @@ const (
|
||||
// adjusted to the number of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
//
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
@@ -83,20 +84,20 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3
|
||||
// For example, you can get a derived key for e.g. AES-256 (which needs a
|
||||
// 32-byte key) by doing:
|
||||
//
|
||||
// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
|
||||
// key := argon2.IDKey([]byte("some password"), salt, 1, 2*1024*1024, 4, 32)
|
||||
//
|
||||
// [RFC 9106 Section 7.3] recommends time=1, and memory=64*1024 as a sensible number.
|
||||
// If using that amount of memory (64 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
// The example above uses the first [RFC 9106 Section 4] recommended option.
|
||||
// If much less memory is available, the second recommended option is time=3,
|
||||
// memory=64*1024 KiB (64 MiB), and threads=4.
|
||||
//
|
||||
// The time parameter specifies the number of passes over the memory and the
|
||||
// memory parameter specifies the size of the memory in KiB. For example
|
||||
// memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be
|
||||
// adjusted to the numbers of available CPUs. The cost parameters should be
|
||||
// memory=2*1024*1024 sets the memory cost to ~2 GiB. The number of threads can
|
||||
// be adjusted to the numbers of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
//
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
// [RFC 9106 Section 4]: https://www.rfc-editor.org/rfc/rfc9106.html#section-4
|
||||
func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !s390x) || !gc || purego
|
||||
//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !riscv64 && !s390x) || !gc || purego
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le)
|
||||
//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le || riscv64)
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
// Copyright 2026 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 gc && !purego
|
||||
|
||||
#define LOAD64U(base, offset, t0, t1, t2, t3, dst) \
|
||||
MOVBU (offset+0*1)(base), t0; \
|
||||
MOVBU (offset+1*1)(base), t1; \
|
||||
MOVBU (offset+2*1)(base), t2; \
|
||||
MOVBU (offset+3*1)(base), t3; \
|
||||
SLL $8, t1; \
|
||||
SLL $16, t2; \
|
||||
SLL $24, t3; \
|
||||
OR t1, t0; \
|
||||
OR t3, t2; \
|
||||
OR t2, t0, dst; \
|
||||
MOVBU (offset+4*1)(base), t0; \
|
||||
MOVBU (offset+5*1)(base), t1; \
|
||||
MOVBU (offset+6*1)(base), t2; \
|
||||
MOVBU (offset+7*1)(base), t3; \
|
||||
SLL $32, t0; \
|
||||
SLL $40, t1; \
|
||||
SLL $48, t2; \
|
||||
SLL $56, t3; \
|
||||
OR t1, t0; \
|
||||
OR t3, t2; \
|
||||
OR t2, t0; \
|
||||
OR t0, dst
|
||||
|
||||
// func update(state *macState, msg []byte)
|
||||
TEXT ·update(SB), $0-32
|
||||
MOV state+0(FP), X5
|
||||
MOV msg_base+8(FP), X6
|
||||
MOV msg_len+16(FP), X7
|
||||
|
||||
MOV $16, X8
|
||||
|
||||
AND $7, X6, X28
|
||||
|
||||
MOV (0*8)(X5), X9 // h0
|
||||
MOV (1*8)(X5), X10 // h1
|
||||
MOV (2*8)(X5), X11 // h2
|
||||
MOV (3*8)(X5), X12 // r0
|
||||
MOV (4*8)(X5), X13 // r1
|
||||
|
||||
BLT X7, X8, tail
|
||||
|
||||
loop:
|
||||
BEQZ X28, aligned_load
|
||||
|
||||
LOAD64U(X6, 0*8, X16, X18, X19, X20, X15) // msg[0:8]
|
||||
LOAD64U(X6, 1*8, X16, X18, X19, X20, X17) // msg[8:16]
|
||||
JMP block
|
||||
|
||||
aligned_load:
|
||||
MOV (0*8)(X6), X15 // msg[0:8]
|
||||
MOV (1*8)(X6), X17 // msg[8:16]
|
||||
|
||||
block:
|
||||
ADD X15, X9 // h0 (x1 + y1 = z1', if z1' < x1 then z1' overflow)
|
||||
SLTU X15, X9, X19 // h0.carry
|
||||
ADD X17, X10, X22
|
||||
SLTU X17, X22, X23
|
||||
ADD X22, X19, X10 // h1
|
||||
SLTU X22, X10, X19
|
||||
OR X23, X19 // h1.carry
|
||||
ADD $1, X19
|
||||
ADD X19, X11 // h2
|
||||
|
||||
ADD $16, X6 // msg = msg[16:]
|
||||
|
||||
multiply:
|
||||
MULHU X9, X12, X16 // h0r0.hi
|
||||
MUL X9, X12, X15 // h0r0.lo
|
||||
MULHU X10, X12, X17 // h1r0.hi
|
||||
MUL X10, X12, X14 // h1r0.lo
|
||||
ADD X14, X16
|
||||
SLTU X14, X16, X19
|
||||
ADD X19, X17
|
||||
MUL X11, X12, X20
|
||||
ADD X17, X20
|
||||
MULHU X9, X13, X17 // h0r1.hi
|
||||
MUL X9, X13, X14 // h0r1.lo
|
||||
ADD X14, X16
|
||||
SLTU X14, X16, X19
|
||||
ADD X19, X17
|
||||
MOV X17, X9
|
||||
MUL X11, X13, X21 // h2r1
|
||||
MULHU X10, X13, X17 // h1r1.hi
|
||||
MUL X10, X13, X14 // h1r1.lo
|
||||
ADD X14, X20
|
||||
ADD X17, X21, X22
|
||||
SLTU X14, X20, X19
|
||||
ADD X22, X19, X21
|
||||
ADD X9, X20
|
||||
SLTU X9, X20, X19
|
||||
ADD X19, X21
|
||||
AND $3, X20, X11
|
||||
AND $-4, X20, X18
|
||||
ADD X18, X15, X9
|
||||
ADD X21, X16, X22
|
||||
SLTU X18, X9, X19
|
||||
SLTU X21, X22, X23
|
||||
ADD X22, X19, X10
|
||||
SLTU X22, X10, X19
|
||||
OR X19, X23, X19
|
||||
ADD X19, X11
|
||||
SLL $62, X21, X22
|
||||
SRL $2, X20, X23
|
||||
SRL $2, X21, X21
|
||||
OR X22, X23, X20
|
||||
ADD X20, X9, X9
|
||||
ADD X21, X10, X22
|
||||
SLTU X20, X9, X19
|
||||
SLTU X21, X22, X23
|
||||
ADD X22, X19, X10
|
||||
SLTU X22, X10, X19
|
||||
OR X19, X23, X19
|
||||
ADD X19, X11, X11
|
||||
|
||||
SUB $16, X7, X7
|
||||
BGE X7, X8, loop
|
||||
|
||||
tail:
|
||||
BEQ X7, X0, done
|
||||
MOV $1, X15
|
||||
MOV $0, X16
|
||||
ADD X7, X6, X6
|
||||
|
||||
flush_buffer:
|
||||
MOVBU -1(X6), X20
|
||||
SRL $56, X15, X19
|
||||
SLL $8, X16, X23
|
||||
SLL $8, X15, X15
|
||||
OR X19, X23, X16
|
||||
XOR X20, X15
|
||||
SUB $1, X7, X7
|
||||
SUB $1, X6, X6
|
||||
BNE X7, X0, flush_buffer
|
||||
|
||||
ADD X15, X9
|
||||
SLTU X15, X9, X19
|
||||
ADD X16, X10, X22
|
||||
SLTU X16, X22, X23
|
||||
ADD X22, X19, X10
|
||||
SLTU X22, X10, X19
|
||||
OR X23, X19
|
||||
ADD X19, X11
|
||||
|
||||
MOV $16, X7
|
||||
JMP multiply
|
||||
|
||||
done:
|
||||
MOV X9, (0*8)(X5) // h0
|
||||
MOV X10, (1*8)(X5)
|
||||
MOV X11, (2*8)(X5)
|
||||
RET
|
||||
+2
@@ -41,6 +41,7 @@ func ForwardToAgent(client *ssh.Client, keyring Agent) error {
|
||||
continue
|
||||
}
|
||||
go ssh.DiscardRequests(reqs)
|
||||
go io.Copy(io.Discard, channel.Stderr())
|
||||
go func() {
|
||||
ServeAgent(keyring, channel)
|
||||
channel.Close()
|
||||
@@ -72,6 +73,7 @@ func ForwardToRemote(client *ssh.Client, addr string) error {
|
||||
continue
|
||||
}
|
||||
go ssh.DiscardRequests(reqs)
|
||||
go io.Copy(io.Discard, channel.Stderr())
|
||||
go forwardUnixSocket(channel, addr)
|
||||
}
|
||||
}()
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ func (r *keyring) Unlock(passphrase []byte) error {
|
||||
if !r.locked {
|
||||
return errors.New("agent: not locked")
|
||||
}
|
||||
if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) {
|
||||
if subtle.ConstantTimeCompare(passphrase, r.passphrase) != 1 {
|
||||
return fmt.Errorf("agent: incorrect passphrase")
|
||||
}
|
||||
|
||||
|
||||
+49
-8
@@ -246,10 +246,10 @@ func setConstraints(key *AddedKey, constraintBytes []byte) error {
|
||||
// on arbitrary inputs; the CRT coefficient recomputation is cubic in
|
||||
// |p| and can consume excessive CPU on oversized keys.
|
||||
func checkRSAKeyParams(N, E, P, Q *big.Int) error {
|
||||
if N.BitLen() > 8192 {
|
||||
if N.BitLen() > 16384 {
|
||||
return errors.New("agent: RSA modulus too large")
|
||||
}
|
||||
if P.BitLen() > 4096 || Q.BitLen() > 4096 {
|
||||
if P.BitLen() > 8192 || Q.BitLen() > 8192 {
|
||||
return errors.New("agent: RSA prime too large")
|
||||
}
|
||||
if E.BitLen() > 24 {
|
||||
@@ -304,19 +304,60 @@ func parseEd25519Key(req []byte) (*AddedKey, error) {
|
||||
return addedKey, nil
|
||||
}
|
||||
|
||||
func checkDSAParams(param *dsa.Parameters) error {
|
||||
// SSH specifies FIPS 186-2, which only provided a single size
|
||||
// (1024 bits) DSA key. FIPS 186-3 allows for larger key
|
||||
// sizes, which would confuse SSH.
|
||||
if l := param.P.BitLen(); l != 1024 {
|
||||
return fmt.Errorf("ssh: unsupported DSA key size %d", l)
|
||||
}
|
||||
|
||||
// FIPS 186-2 specifies that Q must be exactly 160 bits. We must enforce
|
||||
// this to prevent DoS attacks where an attacker sends a huge Q which makes
|
||||
// verification slow.
|
||||
if l := param.Q.BitLen(); l != 160 {
|
||||
return fmt.Errorf("ssh: unsupported DSA sub-prime size %d", l)
|
||||
}
|
||||
|
||||
// The generator G is an element of the group, so it must be strictly less
|
||||
// than the modulus P.
|
||||
if param.G.Cmp(param.P) >= 0 {
|
||||
return errors.New("ssh: DSA generator larger than modulus")
|
||||
}
|
||||
|
||||
// G must be positive.
|
||||
if param.G.Sign() <= 0 {
|
||||
return errors.New("ssh: DSA generator must be positive")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseDSAKey(req []byte) (*AddedKey, error) {
|
||||
var k dsaKeyMsg
|
||||
if err := ssh.Unmarshal(req, &k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params := dsa.Parameters{
|
||||
P: k.P,
|
||||
Q: k.Q,
|
||||
G: k.G,
|
||||
}
|
||||
if err := checkDSAParams(¶ms); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The public value Y must be a non-zero element of the group, i.e. strictly
|
||||
// between 0 and P, to prevent a maliciously oversized Y from slowing
|
||||
// signature operations.
|
||||
if k.Y.Sign() <= 0 || k.Y.Cmp(k.P) >= 0 {
|
||||
return nil, errors.New("agent: DSA public value Y out of range")
|
||||
}
|
||||
|
||||
priv := &dsa.PrivateKey{
|
||||
PublicKey: dsa.PublicKey{
|
||||
Parameters: dsa.Parameters{
|
||||
P: k.P,
|
||||
Q: k.Q,
|
||||
G: k.G,
|
||||
},
|
||||
Y: k.Y,
|
||||
Parameters: params,
|
||||
Y: k.Y,
|
||||
},
|
||||
X: k.X,
|
||||
}
|
||||
|
||||
+27
-26
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"slices"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
@@ -229,15 +230,20 @@ func parseCert(in []byte, privAlgo string) (*Certificate, error) {
|
||||
return nil, err
|
||||
}
|
||||
c.Reserved = g.Reserved
|
||||
// Reject a certificate whose signature key is itself a certificate before
|
||||
// parsing it. Certificates signed by certificates are not supported (see
|
||||
// PROTOCOL.certkeys), and rejecting after ParsePublicKey returns would allow
|
||||
// a chain of nested certificates to recurse once per level, exhausting the
|
||||
// goroutine stack.
|
||||
if sigAlgo, _, ok := parseString(g.SignatureKey); !ok {
|
||||
return nil, errShortRead
|
||||
} else if _, ok := certKeyAlgoNames[string(sigAlgo)]; ok {
|
||||
return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", sigAlgo)
|
||||
}
|
||||
k, err := ParsePublicKey(g.SignatureKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The Type() function is intended to return only certificate key types, but
|
||||
// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
|
||||
if _, ok := certKeyAlgoNames[k.Type()]; ok {
|
||||
return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", k.Type())
|
||||
}
|
||||
c.SignatureKey = k
|
||||
c.Signature, rest, ok = parseSignatureBody(g.Signature)
|
||||
if !ok || len(rest) > 0 {
|
||||
@@ -300,8 +306,11 @@ const sourceAddressCriticalOption = "source-address"
|
||||
// minimally, the IsAuthority callback should be set.
|
||||
type CertChecker struct {
|
||||
// SupportedCriticalOptions lists the CriticalOptions that the
|
||||
// server application layer understands. These are only used
|
||||
// for user certificates.
|
||||
// application layer understands. A certificate carrying a critical
|
||||
// option that is not listed here is rejected.
|
||||
// CertChecker.Authenticate additionally accepts the source-address
|
||||
// option, which the server enforces on the Permissions that
|
||||
// Authenticate returns.
|
||||
SupportedCriticalOptions []string
|
||||
|
||||
// IsUserAuthority should return true if the key is recognized as an
|
||||
@@ -364,8 +373,9 @@ func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey)
|
||||
return c.CheckCert(hostname, cert)
|
||||
}
|
||||
|
||||
// Authenticate checks a user certificate. Authenticate can be used as
|
||||
// a value for ServerConfig.PublicKeyCallback.
|
||||
// Authenticate checks a user certificate. Authenticate can be used as a value
|
||||
// for ServerConfig.PublicKeyCallback. The source-address critical option is
|
||||
// allowed, as it will be enforced by the server.
|
||||
func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
|
||||
cert, ok := pubKey.(*Certificate)
|
||||
if !ok {
|
||||
@@ -384,8 +394,11 @@ func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permis
|
||||
if !c.IsUserAuthority(cert.SignatureKey) {
|
||||
return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
|
||||
}
|
||||
|
||||
if err := c.CheckCert(conn.User(), cert); err != nil {
|
||||
// The source-address critical option is enforced by serverAuthenticate,
|
||||
// so it is supported regardless of SupportedCriticalOptions
|
||||
cc := *c
|
||||
cc.SupportedCriticalOptions = append(slices.Clip(cc.SupportedCriticalOptions), sourceAddressCriticalOption)
|
||||
if err := cc.CheckCert(conn.User(), cert); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -393,27 +406,15 @@ func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permis
|
||||
}
|
||||
|
||||
// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
|
||||
// the signature of the certificate.
|
||||
// the signature of the certificate. Critical options that are not listed in
|
||||
// SupportedCriticalOptions are rejected.
|
||||
func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
|
||||
if c.IsRevoked != nil && c.IsRevoked(cert) {
|
||||
return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial)
|
||||
}
|
||||
|
||||
for opt := range cert.CriticalOptions {
|
||||
// sourceAddressCriticalOption will be enforced by
|
||||
// serverAuthenticate
|
||||
if opt == sourceAddressCriticalOption {
|
||||
continue
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, supp := range c.SupportedCriticalOptions {
|
||||
if supp == opt {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if !slices.Contains(c.SupportedCriticalOptions, opt) {
|
||||
return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
|
||||
}
|
||||
}
|
||||
|
||||
+61
-26
@@ -173,6 +173,12 @@ type channel struct {
|
||||
// (for outbound channels) or received (for inbound channels).
|
||||
decided bool
|
||||
|
||||
// established is set to true once the channel is open and may carry normal
|
||||
// channel traffic: for an outbound channel when the peer's open
|
||||
// confirmation is received, for an inbound channel when the local side
|
||||
// accepts it. It is set and read from different goroutines.
|
||||
established atomic.Bool
|
||||
|
||||
// direction contains either channelOutbound, for channels created
|
||||
// locally, or channelInbound, for channels created by the peer.
|
||||
direction channelDirection
|
||||
@@ -216,6 +222,10 @@ type channel struct {
|
||||
// packetPool has a buffer for each extended channel ID to
|
||||
// save allocations during writes.
|
||||
packetPool map[uint32][]byte
|
||||
|
||||
// closeOnce guards close so it is idempotent: closing the internal Go
|
||||
// channels (msg, incomingRequests) more than once would panic.
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// writePacket sends a packet. If the packet is a channel close, it updates
|
||||
@@ -340,7 +350,18 @@ func (ch *channel) handleData(packet []byte) error {
|
||||
if extended == 1 {
|
||||
ch.extPending.write(data)
|
||||
} else if extended > 0 {
|
||||
// discard other extended data.
|
||||
// RFC 4254, Section 5.2 defines no extended data types other
|
||||
// than stderr (type 1, handled above) and this package provides
|
||||
// no API to read them, so the data is discarded. Credit its
|
||||
// window back immediately: it can never be read, so the
|
||||
// deduction above would otherwise shrink the window permanently.
|
||||
// adjustWindow returns io.EOF if the local side has already
|
||||
// sent a channel close; ignore it like ReadExtended does, since
|
||||
// an error returned here would terminate the mux read loop and
|
||||
// tear down the whole connection.
|
||||
if err := ch.adjustWindow(length); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ch.pending.write(data)
|
||||
}
|
||||
@@ -393,17 +414,19 @@ func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error)
|
||||
}
|
||||
|
||||
func (c *channel) close() {
|
||||
c.pending.eof()
|
||||
c.extPending.eof()
|
||||
close(c.msg)
|
||||
close(c.incomingRequests)
|
||||
c.writeMu.Lock()
|
||||
// This is not necessary for a normal channel teardown, but if
|
||||
// there was another error, it is.
|
||||
c.sentClose = true
|
||||
c.writeMu.Unlock()
|
||||
// Unblock writers.
|
||||
c.remoteWin.close()
|
||||
c.closeOnce.Do(func() {
|
||||
c.pending.eof()
|
||||
c.extPending.eof()
|
||||
close(c.msg)
|
||||
close(c.incomingRequests)
|
||||
c.writeMu.Lock()
|
||||
// This is not necessary for a normal channel teardown, but if
|
||||
// there was another error, it is.
|
||||
c.sentClose = true
|
||||
c.writeMu.Unlock()
|
||||
// Unblock writers.
|
||||
c.remoteWin.close()
|
||||
})
|
||||
}
|
||||
|
||||
// responseMessageReceived is called when a success or failure message is
|
||||
@@ -417,10 +440,20 @@ func (ch *channel) responseMessageReceived() error {
|
||||
return errors.New("ssh: duplicate response received for channel")
|
||||
}
|
||||
ch.decided = true
|
||||
ch.established.Store(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch *channel) handlePacket(packet []byte) error {
|
||||
// Only the open response is expected before the channel is established.
|
||||
if !ch.established.Load() {
|
||||
switch packet[0] {
|
||||
case msgChannelOpenConfirm, msgChannelOpenFailure:
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
switch packet[0] {
|
||||
case msgChannelData, msgChannelExtendedData:
|
||||
return ch.handleData(packet)
|
||||
@@ -486,26 +519,28 @@ func (ch *channel) handlePacket(packet []byte) error {
|
||||
default:
|
||||
}
|
||||
default:
|
||||
ch.msg <- msg
|
||||
// No other message type is expected on an established channel.
|
||||
return fmt.Errorf("ssh: unexpected message type %d on channel %d", packet[0], ch.localId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel {
|
||||
ch := &channel{
|
||||
remoteWin: window{Cond: newCond()},
|
||||
myWindow: channelWindowSize,
|
||||
pending: newBuffer(),
|
||||
extPending: newBuffer(),
|
||||
direction: direction,
|
||||
incomingRequests: make(chan *Request, chanSize),
|
||||
msg: make(chan interface{}, chanSize),
|
||||
chanType: chanType,
|
||||
extraData: extraData,
|
||||
mux: m,
|
||||
packetPool: make(map[uint32][]byte),
|
||||
remoteWin: window{Cond: newCond()},
|
||||
myWindow: channelWindowSize,
|
||||
maxIncomingPayload: channelMaxPacket,
|
||||
pending: newBuffer(),
|
||||
extPending: newBuffer(),
|
||||
direction: direction,
|
||||
incomingRequests: make(chan *Request, chanSize),
|
||||
msg: make(chan interface{}, chanSize),
|
||||
chanType: chanType,
|
||||
extraData: extraData,
|
||||
mux: m,
|
||||
packetPool: make(map[uint32][]byte),
|
||||
}
|
||||
ch.localId = m.chanList.add(ch)
|
||||
m.chanList.add(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
@@ -529,7 +564,6 @@ func (ch *channel) Accept() (Channel, <-chan *Request, error) {
|
||||
if ch.decided {
|
||||
return nil, nil, errDecidedAlready
|
||||
}
|
||||
ch.maxIncomingPayload = channelMaxPacket
|
||||
confirm := channelOpenConfirmMsg{
|
||||
PeersID: ch.remoteId,
|
||||
MyID: ch.localId,
|
||||
@@ -537,6 +571,7 @@ func (ch *channel) Accept() (Channel, <-chan *Request, error) {
|
||||
MaxPacketSize: ch.maxIncomingPayload,
|
||||
}
|
||||
ch.decided = true
|
||||
ch.established.Store(true)
|
||||
if err := ch.sendMessage(confirm); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
+1
-1
@@ -798,7 +798,7 @@ func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn,
|
||||
return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+
|
||||
"Major Status: %d\n"+
|
||||
"Minor Status: %d\n"+
|
||||
"Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus,
|
||||
"Error Message: %q\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus,
|
||||
userAuthGSSAPIErrorResp.Message)
|
||||
case msgUserAuthGSSAPIToken:
|
||||
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
|
||||
|
||||
+4
-4
@@ -419,7 +419,7 @@ type AlgorithmNegotiationError struct {
|
||||
}
|
||||
|
||||
func (a *AlgorithmNegotiationError) Error() string {
|
||||
return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %v, peer offered: %v",
|
||||
return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %q, peer offered: %q",
|
||||
a.What, a.SupportedAlgorithms, a.RequestedAlgorithms)
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ func (c *Config) SetDefaults() {
|
||||
if c.Rand == nil {
|
||||
c.Rand = rand.Reader
|
||||
}
|
||||
if c.Ciphers == nil {
|
||||
if len(c.Ciphers) == 0 {
|
||||
c.Ciphers = defaultCiphers
|
||||
}
|
||||
var ciphers []string
|
||||
@@ -556,7 +556,7 @@ func (c *Config) SetDefaults() {
|
||||
}
|
||||
c.Ciphers = ciphers
|
||||
|
||||
if c.KeyExchanges == nil {
|
||||
if len(c.KeyExchanges) == 0 {
|
||||
c.KeyExchanges = defaultKexAlgos
|
||||
}
|
||||
var kexs []string
|
||||
@@ -571,7 +571,7 @@ func (c *Config) SetDefaults() {
|
||||
}
|
||||
c.KeyExchanges = kexs
|
||||
|
||||
if c.MACs == nil {
|
||||
if len(c.MACs) == 0 {
|
||||
c.MACs = defaultMACs
|
||||
}
|
||||
var macs []string
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ type OpenChannelError struct {
|
||||
}
|
||||
|
||||
func (e *OpenChannelError) Error() string {
|
||||
return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
|
||||
return fmt.Sprintf("ssh: rejected: %s (%q)", e.Reason, e.Message)
|
||||
}
|
||||
|
||||
// ConnMetadata holds metadata for the connection.
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
|
||||
t.remoteAddr = addr
|
||||
t.hostKeyCallback = config.HostKeyCallback
|
||||
t.bannerCallback = config.BannerCallback
|
||||
if config.HostKeyAlgorithms != nil {
|
||||
if len(config.HostKeyAlgorithms) > 0 {
|
||||
t.hostKeyAlgorithms = config.HostKeyAlgorithms
|
||||
} else {
|
||||
t.hostKeyAlgorithms = defaultHostKeyAlgos
|
||||
|
||||
+35
-18
@@ -182,14 +182,19 @@ func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey
|
||||
}
|
||||
|
||||
hosts := string(keyFields[0])
|
||||
// keyFields[1] contains the key type (e.g. “ssh-rsa”).
|
||||
// However, that information is duplicated inside the
|
||||
// base64-encoded key and so is ignored here.
|
||||
// keyFields[1] contains the key type (e.g. "ssh-rsa"). This information
|
||||
// is duplicated within the base64-encoded key blob. As OpenSSH's
|
||||
// sshkey_read does, we verify that the declared key type matches the
|
||||
// type embedded in the key blob.
|
||||
wantType := string(keyFields[1])
|
||||
|
||||
key := bytes.Join(keyFields[2:], []byte(" "))
|
||||
if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
|
||||
return "", nil, nil, "", nil, err
|
||||
}
|
||||
if pubKey.Type() != wantType {
|
||||
return "", nil, nil, "", nil, fmt.Errorf("ssh: known hosts key type mismatch: human-readable type %q, encoded type %q", wantType, pubKey.Type())
|
||||
}
|
||||
|
||||
return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
|
||||
}
|
||||
@@ -228,10 +233,17 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str
|
||||
}
|
||||
|
||||
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
|
||||
return out, comment, options, rest, nil
|
||||
} else {
|
||||
lastErr = err
|
||||
// The first field contains the declared key type. As OpenSSH's
|
||||
// sshkey_read does, we verify that it matches the type embedded in
|
||||
// the key blob. Without this check, a single-token option (e.g.
|
||||
// "restrict") appearing in the key type position could be silently
|
||||
// discarded along with its intended effect.
|
||||
if string(in[:i]) == out.Type() {
|
||||
return out, comment, options, rest, nil
|
||||
}
|
||||
err = fmt.Errorf("ssh: authorized keys key type mismatch: human-readable type %q, encoded type %q", in[:i], out.Type())
|
||||
}
|
||||
lastErr = err
|
||||
|
||||
// No key type recognised. Maybe there's an options field at
|
||||
// the beginning.
|
||||
@@ -271,11 +283,15 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str
|
||||
}
|
||||
|
||||
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
|
||||
options = candidateOptions
|
||||
return out, comment, options, rest, nil
|
||||
} else {
|
||||
lastErr = err
|
||||
// As above, the declared key type (here following the options
|
||||
// field) must match the type embedded in the key blob.
|
||||
if string(in[:i]) == out.Type() {
|
||||
options = candidateOptions
|
||||
return out, comment, options, rest, nil
|
||||
}
|
||||
err = fmt.Errorf("ssh: authorized keys key type mismatch: human-readable type %q, encoded type %q", in[:i], out.Type())
|
||||
}
|
||||
lastErr = err
|
||||
|
||||
in = rest
|
||||
continue
|
||||
@@ -469,10 +485,11 @@ func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// 8192 bits is also the maximum RSA key size accepted by crypto/tls for
|
||||
// signature verification:
|
||||
// https://github.com/golang/go/blob/69801b25/src/crypto/tls/handshake_client.go#L1096
|
||||
if w.N.BitLen() > 8192 {
|
||||
// 16384 bits is the largest RSA key OpenSSH will generate (ssh-keygen
|
||||
// caps -b at 16384), so it is the practical upper bound for keys seen on
|
||||
// the wire. Rejecting anything larger bounds the CPU spent verifying an
|
||||
// attacker-supplied key and signature, mitigating a denial of service.
|
||||
if w.N.BitLen() > 16384 {
|
||||
return nil, nil, errors.New("ssh: rsa modulus too large")
|
||||
}
|
||||
if w.E.BitLen() > 24 {
|
||||
@@ -1653,13 +1670,13 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
|
||||
}
|
||||
|
||||
// Mirror the validation done in parseRSA for public keys: cap the
|
||||
// modulus at the same limit enforced by crypto/tls, reject oversized
|
||||
// or invalid exponents, and additionally bound the prime factors to
|
||||
// modulus at the OpenSSH-generated maximum, reject oversized or
|
||||
// invalid exponents, and additionally bound the prime factors to
|
||||
// avoid the expensive CRT coefficient recomputation in pk.Precompute.
|
||||
if key.N.BitLen() > 8192 {
|
||||
if key.N.BitLen() > 16384 {
|
||||
return nil, errors.New("ssh: rsa modulus too large")
|
||||
}
|
||||
if key.P.BitLen() > 4096 || key.Q.BitLen() > 4096 {
|
||||
if key.P.BitLen() > 8192 || key.Q.BitLen() > 8192 {
|
||||
return nil, errors.New("ssh: rsa prime too large")
|
||||
}
|
||||
if key.E.BitLen() > 24 {
|
||||
|
||||
+13
-4
@@ -142,6 +142,15 @@ func keyEq(a, b ssh.PublicKey) bool {
|
||||
return bytes.Equal(a.Marshal(), b.Marshal())
|
||||
}
|
||||
|
||||
// plainKeyBlob returns the serialized public portion of key: for a
|
||||
// certificate this is the certified key, otherwise the key itself.
|
||||
func plainKeyBlob(key ssh.PublicKey) string {
|
||||
if cert, ok := key.(*ssh.Certificate); ok {
|
||||
return string(cert.Key.Marshal())
|
||||
}
|
||||
return string(key.Marshal())
|
||||
}
|
||||
|
||||
// IsHostAuthority can be used as a callback in ssh.CertChecker
|
||||
func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool {
|
||||
h, p, err := net.SplitHostPort(address)
|
||||
@@ -160,10 +169,10 @@ func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool
|
||||
|
||||
// IsRevoked can be used as a callback in ssh.CertChecker
|
||||
func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool {
|
||||
if _, ok := db.revoked[string(key.Marshal())]; ok {
|
||||
if _, ok := db.revoked[plainKeyBlob(key)]; ok {
|
||||
return true
|
||||
}
|
||||
if _, ok := db.revoked[string(key.SignatureKey.Marshal())]; ok {
|
||||
if _, ok := db.revoked[plainKeyBlob(key.SignatureKey)]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -228,7 +237,7 @@ func (db *hostKeyDB) parseLine(line []byte, filename string, linenum int) error
|
||||
}
|
||||
|
||||
if marker == markerRevoked {
|
||||
db.revoked[string(key.Marshal())] = &KnownKey{
|
||||
db.revoked[plainKeyBlob(key)] = &KnownKey{
|
||||
Key: key,
|
||||
Filename: filename,
|
||||
Line: linenum,
|
||||
@@ -341,7 +350,7 @@ func (r *RevokedError) Error() string {
|
||||
// check checks a key against the host database. This should not be
|
||||
// used for verifying certificates.
|
||||
func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.PublicKey) error {
|
||||
if revoked := db.revoked[string(remoteKey.Marshal())]; revoked != nil {
|
||||
if revoked := db.revoked[plainKeyBlob(remoteKey)]; revoked != nil {
|
||||
return &RevokedError{Revoked: *revoked}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ type disconnectMsg struct {
|
||||
}
|
||||
|
||||
func (d *disconnectMsg) Error() string {
|
||||
return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
|
||||
return fmt.Sprintf("ssh: disconnect, reason %d: %q", d.Reason, d.Message)
|
||||
}
|
||||
|
||||
// See RFC 4253, section 7.1.
|
||||
|
||||
+7
-6
@@ -32,18 +32,21 @@ type chanList struct {
|
||||
offset uint32
|
||||
}
|
||||
|
||||
// Assigns a channel ID to the given channel.
|
||||
func (c *chanList) add(ch *channel) uint32 {
|
||||
// add stores the given channel and assigns its localId while holding the
|
||||
// lock, so that getChan can never return a channel whose localId is not yet
|
||||
// initialized.
|
||||
func (c *chanList) add(ch *channel) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
for i := range c.chans {
|
||||
if c.chans[i] == nil {
|
||||
c.chans[i] = ch
|
||||
return uint32(i) + c.offset
|
||||
ch.localId = uint32(i) + c.offset
|
||||
return
|
||||
}
|
||||
}
|
||||
c.chans = append(c.chans, ch)
|
||||
return uint32(len(c.chans)-1) + c.offset
|
||||
ch.localId = uint32(len(c.chans)-1) + c.offset
|
||||
}
|
||||
|
||||
// getChan returns the channel for the given ID.
|
||||
@@ -343,8 +346,6 @@ func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Reque
|
||||
func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
|
||||
ch := m.newChannel(chanType, channelOutbound, extra)
|
||||
|
||||
ch.maxIncomingPayload = channelMaxPacket
|
||||
|
||||
open := channelOpenMsg{
|
||||
ChanType: chanType,
|
||||
PeersWindow: ch.myWindow,
|
||||
|
||||
+56
-23
@@ -26,10 +26,16 @@ type Permissions struct {
|
||||
// defines "force-command" (only allow the given command to
|
||||
// execute) and "source-address" (only allow connections from
|
||||
// the given address). The SSH package currently only enforces
|
||||
// the "source-address" critical option. It is up to server
|
||||
// implementations to enforce other critical options, such as
|
||||
// "force-command", by checking them after the SSH handshake
|
||||
// is successful. In general, SSH servers should reject
|
||||
// the "source-address" critical option: it is validated against
|
||||
// the client's remote address whenever it is present in the
|
||||
// Permissions returned by any authentication callback. Its value
|
||||
// is a comma-separated list of IP addresses and CIDR blocks;
|
||||
// consistently with OpenSSH, a connection whose remote address is
|
||||
// not an IP address, such as a Unix domain socket, never matches
|
||||
// the list and is rejected when the option is present. It is up
|
||||
// to server implementations to enforce other critical options,
|
||||
// such as "force-command", by checking them after the SSH
|
||||
// handshake is successful. In general, SSH servers should reject
|
||||
// connections that specify critical options that are unknown
|
||||
// or not supported.
|
||||
CriticalOptions map[string]string
|
||||
@@ -223,7 +229,9 @@ type ServerConfig struct {
|
||||
// Permissions object can be the same object, optionally modified, or a
|
||||
// completely new object. If VerifiedPublicKeyCallback is non-nil,
|
||||
// PublicKeyCallback is not allowed to return a PartialSuccessError, which
|
||||
// can instead be returned by VerifiedPublicKeyCallback.
|
||||
// can instead be returned by VerifiedPublicKeyCallback. The
|
||||
// signatureAlgorithm argument is the format of the signature that was
|
||||
// successfully verified.
|
||||
//
|
||||
// VerifiedPublicKeyCallback does not affect which authentication methods
|
||||
// are included in the list of methods that can be attempted by the client.
|
||||
@@ -442,6 +450,10 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error)
|
||||
return perms, err
|
||||
}
|
||||
|
||||
// checkSourceAddress matches addr against sourceAddrs, a comma-separated list
|
||||
// of IP addresses and CIDR blocks. Consistently with OpenSSH, a remote address
|
||||
// that is not IP-based, such as a Unix domain socket, never matches the list
|
||||
// and is rejected.
|
||||
func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
|
||||
if addr == nil {
|
||||
return errors.New("ssh: no address known for client, but source-address match required")
|
||||
@@ -449,7 +461,7 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
|
||||
|
||||
tcpAddr, ok := addr.(*net.TCPAddr)
|
||||
if !ok {
|
||||
return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
|
||||
return fmt.Errorf("ssh: remote address %v is not a TCP address when checking source-address match", addr)
|
||||
}
|
||||
|
||||
for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
|
||||
@@ -472,6 +484,21 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
|
||||
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
|
||||
}
|
||||
|
||||
// checkSourceAddressCriticalOption enforces the source-address critical
|
||||
// option, if present in perms, as documented in Permissions.CriticalOptions.
|
||||
// A present but empty value matches no address, so it denies authentication,
|
||||
// consistently with OpenSSH, rather than being treated as absent.
|
||||
func checkSourceAddressCriticalOption(addr net.Addr, perms *Permissions) error {
|
||||
if perms == nil {
|
||||
return nil
|
||||
}
|
||||
saco, ok := perms.CriticalOptions[sourceAddressCriticalOption]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return checkSourceAddress(addr, saco)
|
||||
}
|
||||
|
||||
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
|
||||
sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
|
||||
gssAPIServer := gssapiConfig.Server
|
||||
@@ -685,7 +712,7 @@ userAuthLoop:
|
||||
}
|
||||
|
||||
if userAuthReq.Service != serviceSSH {
|
||||
return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
|
||||
return nil, fmt.Errorf("ssh: client attempted to negotiate for unknown service: %q", userAuthReq.Service)
|
||||
}
|
||||
|
||||
if s.user != userAuthReq.User && partialSuccessReturned {
|
||||
@@ -771,7 +798,8 @@ userAuthLoop:
|
||||
|
||||
pubKey, err := ParsePublicKey(pubKeyData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
authErr = err
|
||||
break
|
||||
}
|
||||
|
||||
candidate, ok := cache.get(s.user, pubKeyData)
|
||||
@@ -784,13 +812,14 @@ userAuthLoop:
|
||||
return nil, errors.New("ssh: invalid library usage: PublicKeyCallback must not return partial success when VerifiedPublicKeyCallback is defined")
|
||||
}
|
||||
|
||||
if (candidate.result == nil || isPartialSuccessError) &&
|
||||
candidate.perms != nil &&
|
||||
candidate.perms.CriticalOptions != nil &&
|
||||
candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
|
||||
if err := checkSourceAddress(
|
||||
s.RemoteAddr(),
|
||||
candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil {
|
||||
// This check is authoritative for the Permissions returned by
|
||||
// PublicKeyCallback: the check at the end of the auth loop sees
|
||||
// the final Permissions, which VerifiedPublicKeyCallback may
|
||||
// have replaced, and is skipped on partial success. It also
|
||||
// makes public key queries fail before the client signs when
|
||||
// PublicKeyCallback supplies the restriction.
|
||||
if candidate.result == nil || isPartialSuccessError {
|
||||
if err := checkSourceAddressCriticalOption(s.RemoteAddr(), candidate.perms); err != nil {
|
||||
candidate.result = err
|
||||
}
|
||||
}
|
||||
@@ -864,14 +893,7 @@ userAuthLoop:
|
||||
// Only call VerifiedPublicKeyCallback after the key has been accepted
|
||||
// and successfully verified. If authErr is non-nil, the key is not
|
||||
// considered verified and the callback must not run.
|
||||
perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo)
|
||||
}
|
||||
if authErr == nil && perms != nil && perms.CriticalOptions != nil {
|
||||
if saco := perms.CriticalOptions[sourceAddressCriticalOption]; saco != "" {
|
||||
if err := checkSourceAddress(s.RemoteAddr(), saco); err != nil {
|
||||
authErr = err
|
||||
}
|
||||
}
|
||||
perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, sig.Format)
|
||||
}
|
||||
}
|
||||
case "gssapi-with-mic":
|
||||
@@ -925,6 +947,17 @@ userAuthLoop:
|
||||
authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
|
||||
}
|
||||
|
||||
// The source-address critical option is enforced on the Permissions
|
||||
// returned by any authentication callback. Permissions returned
|
||||
// together with a PartialSuccessError skip this check: that is safe
|
||||
// because they are required to be nil, as enforced in the partial
|
||||
// success handling below.
|
||||
if authErr == nil {
|
||||
if err := checkSourceAddressCriticalOption(s.RemoteAddr(), perms); err != nil {
|
||||
authErr = err
|
||||
}
|
||||
}
|
||||
|
||||
authErrs = append(authErrs, authErr)
|
||||
|
||||
if config.AuthLogCallback != nil {
|
||||
|
||||
+10
-6
@@ -118,24 +118,28 @@ func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
|
||||
OIDS: make([]asn1.ObjectIdentifier, n),
|
||||
}
|
||||
for i := 0; i < int(n); i++ {
|
||||
var (
|
||||
desiredMech []byte
|
||||
err error
|
||||
)
|
||||
var desiredMech []byte
|
||||
desiredMech, rest, ok = parseString(rest)
|
||||
if !ok {
|
||||
return nil, errors.New("parse string failed")
|
||||
}
|
||||
if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
|
||||
trailing, err := asn1.Unmarshal(desiredMech, &s.OIDS[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(trailing) != 0 {
|
||||
return nil, errors.New("trailing bytes after OID")
|
||||
}
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
return nil, errors.New("trailing bytes after mechanisms")
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// See RFC 4462 section 3.6.
|
||||
func buildMIC(sessionID string, username string, service string, authMethod string) []byte {
|
||||
out := make([]byte, 0, 0)
|
||||
out := make([]byte, 0)
|
||||
out = appendString(out, sessionID)
|
||||
out = append(out, msgUserAuthRequest)
|
||||
out = appendString(out, username)
|
||||
|
||||
+2
@@ -58,6 +58,7 @@ func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
|
||||
return nil, err
|
||||
}
|
||||
go DiscardRequests(in)
|
||||
go io.Copy(io.Discard, ch.Stderr())
|
||||
return ch, err
|
||||
}
|
||||
|
||||
@@ -79,6 +80,7 @@ func (l *unixListener) Accept() (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
go DiscardRequests(incoming)
|
||||
go io.Copy(io.Discard, ch.Stderr())
|
||||
|
||||
return &chanConn{
|
||||
Channel: ch,
|
||||
|
||||
+2
@@ -332,6 +332,7 @@ func (l *tcpListener) Accept() (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
go DiscardRequests(incoming)
|
||||
go io.Copy(io.Discard, ch.Stderr())
|
||||
|
||||
return &chanConn{
|
||||
Channel: ch,
|
||||
@@ -495,6 +496,7 @@ func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel
|
||||
return nil, err
|
||||
}
|
||||
go DiscardRequests(in)
|
||||
go io.Copy(io.Discard, ch.Stderr())
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -331,13 +331,19 @@ func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err er
|
||||
// chars
|
||||
const maxVersionStringBytes = 255
|
||||
|
||||
// maxPreVersionLines is the maximum number of lines sent by the peer
|
||||
// before the version string. Each of these lines is limited to a maximum
|
||||
// of maxVersionStringBytes chars. Lines sent before the version string
|
||||
// are silently ignored.
|
||||
const maxPreVersionLines = 1024
|
||||
|
||||
// Read version string as specified by RFC 4253, section 4.2.
|
||||
func readVersion(r io.Reader) ([]byte, error) {
|
||||
versionString := make([]byte, 0, 64)
|
||||
var ok bool
|
||||
var buf [1]byte
|
||||
|
||||
for length := 0; length < maxVersionStringBytes; length++ {
|
||||
for lines := 0; len(versionString) < maxVersionStringBytes && lines < maxPreVersionLines; {
|
||||
_, err := io.ReadFull(r, buf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -347,9 +353,9 @@ func readVersion(r io.Reader) ([]byte, error) {
|
||||
if buf[0] == '\n' {
|
||||
if !bytes.HasPrefix(versionString, []byte("SSH-")) {
|
||||
// RFC 4253 says we need to ignore all version string lines
|
||||
// except the one containing the SSH version (provided that
|
||||
// all the lines do not exceed 255 bytes in total).
|
||||
// except the one containing the SSH version.
|
||||
versionString = versionString[:0]
|
||||
lines++
|
||||
continue
|
||||
}
|
||||
ok = true
|
||||
|
||||
+13
-11
@@ -55,7 +55,7 @@ type transportConfig struct {
|
||||
// Registered is called by net/http.Transport.RegisterProtocol,
|
||||
// to let us know that it understands the registration mechanism we're using.
|
||||
func (t transportConfig) Registered(t1 *http.Transport) {
|
||||
t.t.t1 = t1
|
||||
t.t.lazyt1 = t1
|
||||
}
|
||||
|
||||
func (t transportConfig) DisableCompression() bool {
|
||||
@@ -145,29 +145,30 @@ func (t transportConfig) DialFromContext(ctx context.Context, network, address s
|
||||
|
||||
type transportInternal struct {
|
||||
initOnce sync.Once
|
||||
t1 *http.Transport
|
||||
lazyt1 *http.Transport
|
||||
}
|
||||
|
||||
func (t *Transport) init() {
|
||||
func (t *Transport) init() *http.Transport {
|
||||
t.initOnce.Do(func() {
|
||||
if t.t1 != nil {
|
||||
if t.lazyt1 != nil {
|
||||
return
|
||||
}
|
||||
t1 := &http.Transport{}
|
||||
t.configure(t1)
|
||||
})
|
||||
return t.lazyt1
|
||||
}
|
||||
|
||||
func (t *Transport) configure(t1 *http.Transport) {
|
||||
t1.RegisterProtocol("http/2", transportConfig{t})
|
||||
// tr2.t1 is set by transportConfig.Registered.
|
||||
if t.t1 != t1 {
|
||||
// tr2.lazyt1 is set by transportConfig.Registered.
|
||||
if t.lazyt1 != t1 {
|
||||
panic("http2: net/http does not support this version of x/net/http2")
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
|
||||
t.init()
|
||||
t1 := t.init()
|
||||
|
||||
if req.URL.Scheme == "http" && !t.AllowHTTP {
|
||||
return nil, errors.New("http2: unencrypted HTTP/2 not enabled")
|
||||
@@ -188,22 +189,23 @@ func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
|
||||
ctx := context.WithValue(req.Context(), http2TransportContextKey{}, t)
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
return t.t1.RoundTrip(req)
|
||||
return t1.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (t *Transport) closeIdleConnections() {
|
||||
t.init()
|
||||
t.t1.CloseIdleConnections()
|
||||
t1 := t.init()
|
||||
t1.CloseIdleConnections()
|
||||
}
|
||||
|
||||
func (t *Transport) newUserClientConn(c net.Conn) (*ClientConn, error) {
|
||||
t1 := t.init()
|
||||
// http.Transport's NewClientConn doesn't provide a supported way to create
|
||||
// a connection from a net.Conn. (This might be useful to add in the future?)
|
||||
// We're going to craftily sneak one in via the context key, with the
|
||||
// scheme of "http/2" telling NewClientConn to look for it.
|
||||
ctx := context.WithValue(context.Background(), netConnContextKey{}, c)
|
||||
|
||||
nhcc, err := t.t1.NewClientConn(ctx, "http/2", "")
|
||||
nhcc, err := t1.NewClientConn(ctx, "http/2", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+5
-1
@@ -400,7 +400,11 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||
// Spec says keep the old label.
|
||||
continue
|
||||
}
|
||||
if unicode16 && err == nil && len(u) > 0 && isASCII(u) {
|
||||
if err == nil && len(u) > 0 && isASCII(u) {
|
||||
// UTS 43 pre-revision 33 doesn't classify a xn-- label
|
||||
// which contains only ASCII characters as an error,
|
||||
// but that's a specification bug and a security issue.
|
||||
// Always return an error in this case.
|
||||
err = punyError(enc)
|
||||
}
|
||||
isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight
|
||||
|
||||
+15
-6
@@ -182,12 +182,13 @@ var MIPS64X struct {
|
||||
// require kernel support to work (DARN, SCV), so there are feature bits for
|
||||
// those as well. The struct is padded to avoid false sharing.
|
||||
var PPC64 struct {
|
||||
_ CacheLinePad
|
||||
HasDARN bool // Hardware random number generator (requires kernel enablement)
|
||||
HasSCV bool // Syscall vectored (requires kernel enablement)
|
||||
IsPOWER8 bool // ISA v2.07 (POWER8)
|
||||
IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8
|
||||
_ CacheLinePad
|
||||
_ CacheLinePad
|
||||
HasDARN bool // Hardware random number generator (requires kernel enablement)
|
||||
HasSCV bool // Syscall vectored (requires kernel enablement)
|
||||
IsPOWER8 bool // ISA v2.07 (POWER8)
|
||||
IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8
|
||||
IsPOWER10 bool // ISA v3.1 (POWER10 and POWER11; POWER11 did not add a new architected level), implies IsPOWER9
|
||||
_ CacheLinePad
|
||||
}
|
||||
|
||||
// S390X contains the supported CPU features of the current IBM Z
|
||||
@@ -248,13 +249,21 @@ var RISCV64 struct {
|
||||
HasZvks bool // ShangMi Algorithm Suite
|
||||
HasZvksc bool // ShangMi Algorithm Suite with carryless multiplication
|
||||
HasZvksg bool // ShangMi Algorithm Suite with GCM
|
||||
VLENB uint // Vector register length in bytes, 0 if undetected
|
||||
_ CacheLinePad
|
||||
}
|
||||
|
||||
// doDerived, if non-nil, is called after processing GODEBUG to set "derived"
|
||||
// feature flags.
|
||||
var doDerived func()
|
||||
|
||||
func init() {
|
||||
archInit()
|
||||
initOptions()
|
||||
processOptions()
|
||||
if doDerived != nil {
|
||||
doDerived()
|
||||
}
|
||||
}
|
||||
|
||||
// options contains the cpu debug options that can be used in GODEBUG.
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2026 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 gc
|
||||
|
||||
package cpu
|
||||
|
||||
// Can only be called when the vector extension is present.
|
||||
// Implemented in cpu_riscv64.s.
|
||||
func readVLENB() uint
|
||||
+4
@@ -11,6 +11,7 @@ const (
|
||||
// ISA Level
|
||||
_PPC_FEATURE2_ARCH_2_07 = 0x80000000
|
||||
_PPC_FEATURE2_ARCH_3_00 = 0x00800000
|
||||
_PPC_FEATURE2_ARCH_3_1 = 0x00040000
|
||||
|
||||
// CPU features
|
||||
_PPC_FEATURE2_DARN = 0x00200000
|
||||
@@ -21,6 +22,9 @@ func doinit() {
|
||||
// HWCAP2 feature bits
|
||||
PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07)
|
||||
PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00)
|
||||
// ISA 3.1 covers both POWER10 and POWER11: POWER11 did not introduce a
|
||||
// new architected HWCAP level, so there is no separate IsPOWER11.
|
||||
PPC64.IsPOWER10 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_1)
|
||||
PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN)
|
||||
PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV)
|
||||
}
|
||||
|
||||
+11
@@ -130,6 +130,9 @@ func doinit() {
|
||||
RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST
|
||||
}
|
||||
}
|
||||
if RISCV64.HasV {
|
||||
RISCV64.VLENB = readVLENB()
|
||||
}
|
||||
|
||||
// Let's double check with HWCAP if the C extension does not appear to be supported.
|
||||
// This may happen if we're running on a kernel older than 6.4.
|
||||
@@ -137,6 +140,14 @@ func doinit() {
|
||||
if !RISCV64.HasC {
|
||||
RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C)
|
||||
}
|
||||
|
||||
doDerived = func() {
|
||||
// If the vector extension is disabled by GODEBUG, then the VLENB is zero.
|
||||
if !RISCV64.HasV {
|
||||
RISCV64.VLENB = 0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func isSet(hwc uint, value uint) bool {
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Copyright 2026 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 netbsd && amd64 && gc
|
||||
|
||||
package cpu
|
||||
|
||||
func doinit() {
|
||||
// NetBSD corrupts avx registers when receiving signals.
|
||||
// See issue 80285.
|
||||
// TODO: when NetBSD fixes the bug, add a version
|
||||
// check and skip here.
|
||||
X86.HasAVX = false
|
||||
X86.HasAVX2 = false
|
||||
// Set these also, just to be safe
|
||||
X86.HasAVXVNNI = false
|
||||
X86.HasAVX512 = false
|
||||
X86.HasAVX512F = false
|
||||
X86.HasAVX512CD = false
|
||||
X86.HasAVX512CD = false
|
||||
X86.HasAVX512ER = false
|
||||
X86.HasAVX512PF = false
|
||||
X86.HasAVX512VL = false
|
||||
X86.HasAVX512BW = false
|
||||
X86.HasAVX512DQ = false
|
||||
X86.HasAVX512IFMA = false
|
||||
X86.HasAVX512VBMI = false
|
||||
X86.HasAVX5124VNNIW = false
|
||||
X86.HasAVX5124FMAPS = false
|
||||
X86.HasAVX512VPOPCNTDQ = false
|
||||
X86.HasAVX512VPCLMULQDQ = false
|
||||
X86.HasAVX512VNNI = false
|
||||
X86.HasAVX512GFNI = false
|
||||
X86.HasAVX512VAES = false
|
||||
X86.HasAVX512VBMI2 = false
|
||||
X86.HasAVX512BITALG = false
|
||||
X86.HasAVX512BF16 = false
|
||||
X86.HasAVXIFMA = false
|
||||
X86.HasAVXVNNI = false
|
||||
X86.HasAVXVNNIInt8 = false
|
||||
|
||||
}
|
||||
|
||||
func darwinSupportsAVX512() bool {
|
||||
panic("only implemented for gc && amd64 && darwin")
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build 386 || amd64p32 || (amd64 && (!darwin || !gc))
|
||||
//go:build 386 || amd64p32 || (amd64 && ((!darwin && !netbsd) || !gc))
|
||||
|
||||
package cpu
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// Copyright 2026 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 gc
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Read the vector register length in bytes from the vlenb CSR.
|
||||
// May only be called when the vector extension is present.
|
||||
// func readVLENB() uint
|
||||
TEXT ·readVLENB(SB), NOSPLIT|NOFRAME, $0-8
|
||||
// Go 1.25's assembler does not recognize VLENB, so use its raw CSRR encoding.
|
||||
// Replace WORD with CSRR VLENB, X10 once go.mod requires Go 1.27.
|
||||
WORD $0xc2202573
|
||||
MOV X10, ret+0(FP)
|
||||
RET
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2026 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 sparc64
|
||||
|
||||
package cpu
|
||||
|
||||
// The L1 line is 32 bytes; false sharing is governed by the 64-byte L2 line.
|
||||
const cacheLineSize = 64
|
||||
|
||||
func initOptions() {}
|
||||
+7
-1
@@ -22,7 +22,13 @@ import (
|
||||
// fields can be get and set using the following methods:
|
||||
// - Uint16/SetUint16: flags
|
||||
// - Uint32/SetUint32: ifindex, metric, mtu
|
||||
type Ifreq struct{ raw ifreq }
|
||||
type Ifreq struct {
|
||||
// Aligns the union for the accessors below, which cast it in place;
|
||||
// the generated ifreq is all byte arrays, so its alignment is one.
|
||||
_ [0]int64
|
||||
|
||||
raw ifreq
|
||||
}
|
||||
|
||||
// NewIfreq creates an Ifreq with the input network interface name after
|
||||
// validating the name does not exceed IFNAMSIZ-1 (trailing NULL required)
|
||||
|
||||
+7
@@ -332,3 +332,10 @@ func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
|
||||
func IoctlLoopConfigure(fd int, value *LoopConfig) error {
|
||||
return ioctlPtr(fd, LOOP_CONFIGURE, unsafe.Pointer(value))
|
||||
}
|
||||
|
||||
// IoctlPidfdInfo fetches information about a pidfd.
|
||||
// The Mask field of the info argument indicates which
|
||||
// values to fetch.
|
||||
func IoctlPidfdInfo(fd int, info *PidfdInfo) error {
|
||||
return ioctlPtr(fd, PIDFD_GET_INFO, unsafe.Pointer(info))
|
||||
}
|
||||
|
||||
+1
-8
@@ -290,14 +290,7 @@ struct ltchars {
|
||||
#include <mtd/mtd-user.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#if defined(__sparc__)
|
||||
// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
|
||||
// definition in glibc. As only the error constants are needed here, include the
|
||||
// generic termibits.h (which is included by termbits.h on sparc).
|
||||
#include <asm-generic/termbits.h>
|
||||
#else
|
||||
#include <asm/termbits.h>
|
||||
#endif
|
||||
|
||||
#ifndef PTRACE_GETREGS
|
||||
#define PTRACE_GETREGS 0xc
|
||||
@@ -544,7 +537,7 @@ ccflags="$@"
|
||||
$2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
|
||||
$2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
|
||||
$2 == "LOOP_CONFIGURE" ||
|
||||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
|
||||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|MLOCK|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
|
||||
$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
|
||||
$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
|
||||
$2 ~ /^PTP_/ ||
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ func BytePtrToString(p *byte) string {
|
||||
// Find NUL terminator.
|
||||
n := 0
|
||||
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
|
||||
ptr = unsafe.Pointer(uintptr(ptr) + 1)
|
||||
ptr = unsafe.Add(ptr, 1)
|
||||
}
|
||||
|
||||
return string(unsafe.Slice(p, n))
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
}
|
||||
sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
|
||||
sa.raw.Family = AF_UNIX
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
sa.raw.Path[i] = int8(name[i])
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
|
||||
|
||||
+1
-1
@@ -2363,7 +2363,7 @@ func (fh *FileHandle) Bytes() []byte {
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type))+4)), n)
|
||||
return unsafe.Slice((*byte)(unsafe.Add(unsafe.Pointer(&fh.fileHandle.Type), 4)), n)
|
||||
}
|
||||
|
||||
// NameToHandleAt wraps the name_to_handle_at system call; it obtains
|
||||
|
||||
+2
@@ -2048,6 +2048,7 @@ const (
|
||||
MINIX3_SUPER_MAGIC = 0x4d5a
|
||||
MINIX_SUPER_MAGIC = 0x137f
|
||||
MINIX_SUPER_MAGIC2 = 0x138f
|
||||
MLOCK_ONFAULT = 0x1
|
||||
MNT_DETACH = 0x2
|
||||
MNT_EXPIRE = 0x4
|
||||
MNT_FORCE = 0x1
|
||||
@@ -3862,6 +3863,7 @@ const (
|
||||
TIOCPKT_NOSTOP = 0x10
|
||||
TIOCPKT_START = 0x8
|
||||
TIOCPKT_STOP = 0x4
|
||||
TIOCSER_TEMT = 0x1
|
||||
TIPC_ADDR_ID = 0x3
|
||||
TIPC_ADDR_MCAST = 0x1
|
||||
TIPC_ADDR_NAME = 0x2
|
||||
|
||||
-1
@@ -483,7 +483,6 @@ const (
|
||||
TIOCSERGWILD = 0x5454
|
||||
TIOCSERSETMULTI = 0x545b
|
||||
TIOCSERSWILD = 0x5455
|
||||
TIOCSER_TEMT = 0x1
|
||||
TIOCSETD = 0x5423
|
||||
TIOCSIG = 0x40045436
|
||||
TIOCSISO7816 = 0xc0285443
|
||||
|
||||
-1
@@ -484,7 +484,6 @@ const (
|
||||
TIOCSERGWILD = 0x5454
|
||||
TIOCSERSETMULTI = 0x545b
|
||||
TIOCSERSWILD = 0x5455
|
||||
TIOCSER_TEMT = 0x1
|
||||
TIOCSETD = 0x5423
|
||||
TIOCSIG = 0x40045436
|
||||
TIOCSISO7816 = 0xc0285443
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user