mirror of https://github.com/golang/go.git
[release-branch.go1.24] all: merge master (9a44df6) into release-branch.go1.24
Merge List: + 2025-01-089a44df6675cmd/go/testdata/script: fix TestScript/env_gocacheprog on Windows + 2025-01-08f025d19e7bruntime: hold traceAcquire across casgstatus in injectglist + 2025-01-081e9835f5b1internal/sync: fix typo of panic message + 2025-01-0739f2032c17testing/synctest: add some examples + 2025-01-07b50ccef67acmd/go/internal/modindex: don't write index entry if file open + 2025-01-07b2aa18b96ccmd/internal/hash: stop using md5, sha1 + 2025-01-07d93b549f05cmd/go/internal/cache: handle cacheprog not responding to close + 2025-01-07d62154db83weak: don't panic when calling Value on a zero Pointer + 2025-01-079d0772b23ecmd/compile/internal/syntax: add test case for invalid label use + 2025-01-071d20bce981go/types, types2: expand documentation for Info.Types map + 2025-01-07a9bd6239a4cmd/go/internal/env: add GOCACHEPROG to go env output + 2025-01-07850b276a67crypto/tls: send illegal_parameter on invalid ECHClientHello.type + 2025-01-0627c5164374crypto/internal/fips140: zeroise integrity test temporary values + 2025-01-06d8ad4af78bcmd/internal/disasm: correct instruction length handling for riscv64 + 2025-01-06a76cc5a4eccrypto/rsa: use λ(N) instead of φ(N) + 2025-01-063f002abb60internal/sync: add test from issue 70970 + 2025-01-067a2e88e911net/http: update NewRequestWithContext wrong link to NewRequest + 2025-01-06c112c0af13Revert "internal/sync: optimize CompareAndSwap and Swap" + 2025-01-03705b5a569acrypto/ecdsa: drop SEC 1 reference from package doc + 2025-01-03f966695ccecontext: use "canceled" in docs to refer to timed-out contexts + 2025-01-035da026354ccmd/go/internal/vcweb: close the .access file + 2025-01-0331cabcf084crypto/internal/fips140: mark OpenBSD unsupported + 2025-01-03eb0c2b2f96crypto/internal/fips140: add Supported + 2025-01-03f0a9b6df45internal/fuzz: remove the exp2 method + 2025-01-035d626c49ecspec: fix a dead link + 2025-01-0381566aff3ainternal/exportdata: add missing return + 2025-01-03e7a8bd5d8bcrypto/internal/fips140/check: remove Enabled + 2025-01-024b652e9f5fcmd/go: fix two typos in helpdoc.go + 2025-01-020afd7e85e5cmd/go: document GOCACHEPROG in go help environment + 2025-01-023c8e5b13dfcmd/go/internal/cacheprog: drop redundant Prog prefixes + 2025-01-0220da34c6d2cmd/go: move GOCACHEPROG protocol types to their own package + 2025-01-02858a0e9dfdcrypto/tls: properly return ECH retry configs + 2025-01-02a63aee4955cmd/go: improve GOCACHEPROG types documentation + 2025-01-02847c357bbbcmd/go: remove references to gopath-get + 2025-01-01d1d9312950crypto/tls: fix Config.Time in tests using expired certificates + 2024-12-3194f15810e6cmd/go: document default GOARM value + 2024-12-30856a7bc8e9builtin: use list instead of indentation for comments in cap, len, and make + 2024-12-305efb4239c6spec: document that string conversions don't guarantee result slice capacity + 2024-12-300d8aa8cce6spec: describe representation of values + 2024-12-308857a5a33fcrypto/tls: fix misspelling in comment + 2024-12-303c4102bfd4encoding/binary: add documentation for endian methods + 2024-12-30b702a26cf8os: mention fsys modifications during CopyFS + 2024-12-3015f232456aencoding/json: remove suggestion on Unmarshaler with JSON null + 2024-12-30ba1deb1ceecmd/link: document that -s implies -w + 2024-12-30fd5e0d26d9go/doc: resolve imports before predeclared identifiers in examples + 2024-12-30a785d11ac4unique: fix typo + 2024-12-272b794ed86cencoding/json: expand and modernize TestInterfaceSet + 2024-12-27e3cd55e9d2cmd/go/internal/work: allow @ character in some -Wl, linker flags on darwin + 2024-12-2739794819aadoc/initial: remove fixed-width spacing notice + 2024-12-277c03fe70b8cmd/compile: improve compiler directive docs + 2024-12-27d7c3e93c16iter: improve documentation with iterator example + 2024-12-26cce75da30bcrypto/mlkem: swap order of return values of Encapsulate + 2024-12-23772f024c61weak: fix typo in warning about tiny allocator optimization + 2024-12-23b9955f0ad9cmd/link, runtime: apply a delta to RODATA->DATA relocations + 2024-12-23eef35e3bd9internal/goexperiment: run go generate for synctest + 2024-12-239f6c80a76acmd/go/internal/work: allow single character values in -Wl, linker flags + 2024-12-2205d8984781net: document LookupTXT behavior with multiple strings per record + 2024-12-21500675a7c8cmd/compile: load map length with the right type + 2024-12-2106b191e11finternal/syscall/unix: apply fstatat fix to linux/mips64le + 2024-12-21110ab1aaf4slices: document two oddities + 2024-12-19669d87a935runtime/pprof: continued attempt to deflake the VMInfo test. + 2024-12-1945f49139f5runtime: test trap panic parsing in TestTracebackSystem + 2024-12-19e63eb98e98net/http: fix nil panic in test + 2024-12-197b6c94dd03cmd/go: drop fips140 build ID hacks + 2024-12-19cb72406c36cmd/go: fix two-step toolchain upgrade through go install, GOTOOLCHAIN + 2024-12-184f0561f9d3cmd/dist: skip fips140test in exe mode on Android + 2024-12-1887dbfb9fa7weak: improve grammar in doc comments + 2024-12-18f4e3ec3dbecrypto/ecdsa: fix condition for fips140=only check + 2024-12-186aa46eb750crypto/tls: normalize spelling of "ClientHello" in comments + 2024-12-1810ca5ba4ffcrypto/pbkdf2: update RFC reference in package doc + 2024-12-188ff4cee564cmd/go,crypto: reject using Go+BoringCrypto and fips140 together + 2024-12-18971448ddf8testing: support B.Context and F.Context + 2024-12-1795b433eed4debug/elf: adjust version API per issue discussion + 2024-12-17b2c0168893crypto/internal/fips140/aes/gcm: use aes.EncryptBlockInternal on ppc64x and s390x + 2024-12-17b9e2ffdcd2crypto/internal/fips140: add Name and Version + 2024-12-178790372a8dcmd, go: fix some typos + 2024-12-17b057b8872dbytes, strings: add cross-references in docstrings + 2024-12-17e977b83b32cmd/go/internal/help: use secure link to swig.org + 2024-12-174ac8f552e9syscall, internal/syscall/unix: fix fstatat on linux/mips64 + 2024-12-17236a0b4ffbspec: explain function invocation and passing of parameters more precisely + 2024-12-179f806bb76cgo/build: streamline the crypto package graph in TestDependencies + 2024-12-170cd833d198go/build: remove nonexistent package from TestDependencies + 2024-12-1731e50af5f3crypto/rsa: revert minimum GenerateKey size to 32 bits + 2024-12-17b47ce8b0e9crypto/cipher: block non-AES CTR and CBC in fips140=only mode + 2024-12-17dd7a7ba38fcrypto/internal/fips140/aes: mark AES-ECB as not approved + 2024-12-17427a2401afcmd/go/testdata/script: update test_flags for new test output + 2024-12-1775736cc169fmt, strconv: document that exponent is always two digits + 2024-12-161218566fe5cmd/link: update runtime dependency list + 2024-12-16d92c34a387cmd/go: don't create test actions for incomplete packages + 2024-12-163bd08b9792runtime: usleep in TestWeakToStrongMarkTermination + 2024-12-1518b5435fc8testing: don't measure cleanup time after B.Loop + 2024-12-15c1f2542c8btesting: improve B.Loop test + 2024-12-156bd56fcaebtesting: improve b.Loop example + 2024-12-15090748d6c7testing: improve B.Loop docs, use B.Loop in examples + 2024-12-13e39e965e0ecmd/go: drop FailedBuild field if gotestjsonbuildtext=1 + 2024-12-1308770a5b94cmd/link: make dwarf name slice index self-describing + 2024-12-13c4f356dd86crypto/ecdsa: fix s390x assembly with P-521 + 2024-12-1308725f9de2crypto/internal/cryptotest: skip TestAllocations on s390x + 2024-12-131cbfe8c482fmt: add more function and allocation tests + 2024-12-138391579eceruntime: migrate missing map linkname allowlists + 2024-12-1280a2982a80spec: align EBNF rules consistently (cosmetic change) + 2024-12-1238e9a671d7syscall: on freebsd-386 only update written for certain errors + 2024-12-126f7a4540b1net: fix example function name for IP.To4 + 2024-12-1214e5093ee5cmd/internal/obj: disallow linknamed access to builtin symbols + 2024-12-12fb764cdad0cmd/link: block new standard library linknames Change-Id: Ie423f050db80034c3af6c12bd6007db273c5d281
This commit is contained in:
commit
b3799ba634
|
|
@ -106,16 +106,6 @@ pkg debug/elf, const VER_FLG_INFO = 4 #63952
|
|||
pkg debug/elf, const VER_FLG_INFO DynamicVersionFlag #63952
|
||||
pkg debug/elf, const VER_FLG_WEAK = 2 #63952
|
||||
pkg debug/elf, const VER_FLG_WEAK DynamicVersionFlag #63952
|
||||
pkg debug/elf, const VersionScopeGlobal = 2 #63952
|
||||
pkg debug/elf, const VersionScopeGlobal SymbolVersionScope #63952
|
||||
pkg debug/elf, const VersionScopeHidden = 4 #63952
|
||||
pkg debug/elf, const VersionScopeHidden SymbolVersionScope #63952
|
||||
pkg debug/elf, const VersionScopeLocal = 1 #63952
|
||||
pkg debug/elf, const VersionScopeLocal SymbolVersionScope #63952
|
||||
pkg debug/elf, const VersionScopeNone = 0 #63952
|
||||
pkg debug/elf, const VersionScopeNone SymbolVersionScope #63952
|
||||
pkg debug/elf, const VersionScopeSpecific = 3 #63952
|
||||
pkg debug/elf, const VersionScopeSpecific SymbolVersionScope #63952
|
||||
pkg debug/elf, method (*File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) #63952
|
||||
pkg debug/elf, method (*File) DynamicVersions() ([]DynamicVersion, error) #63952
|
||||
pkg debug/elf, type DynamicVersion struct #63952
|
||||
|
|
@ -131,9 +121,11 @@ pkg debug/elf, type DynamicVersionFlag uint16 #63952
|
|||
pkg debug/elf, type DynamicVersionNeed struct #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Name string #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Needs []DynamicVersionDep #63952
|
||||
pkg debug/elf, type Symbol struct, VersionScope SymbolVersionScope #63952
|
||||
pkg debug/elf, type Symbol struct, VersionIndex int16 #63952
|
||||
pkg debug/elf, type SymbolVersionScope uint8 #63952
|
||||
pkg debug/elf, type Symbol struct, HasVersion bool #63952
|
||||
pkg debug/elf, type Symbol struct, VersionIndex VersionIndex #63952
|
||||
pkg debug/elf, method (VersionIndex) Index() uint16 #63952
|
||||
pkg debug/elf, method (VersionIndex) IsHidden() bool #63952
|
||||
pkg debug/elf, type VersionIndex uint16 #63952
|
||||
pkg encoding, type BinaryAppender interface { AppendBinary } #62384
|
||||
pkg encoding, type BinaryAppender interface, AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg encoding, type TextAppender interface { AppendText } #62384
|
||||
|
|
|
|||
243
doc/go_spec.html
243
doc/go_spec.html
|
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Language version go1.24 (Nov 20, 2024)",
|
||||
"Subtitle": "Language version go1.24 (Dec 30, 2024)",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
|
@ -798,7 +798,6 @@ If a variable has not yet been assigned a value, its value is the
|
|||
<a href="#The_zero_value">zero value</a> for its type.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="Types">Types</h2>
|
||||
|
||||
<p>
|
||||
|
|
@ -810,12 +809,12 @@ from existing types.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Type = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
|
||||
TypeName = identifier | QualifiedIdent .
|
||||
TypeArgs = "[" TypeList [ "," ] "]" .
|
||||
TypeList = Type { "," Type } .
|
||||
TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
||||
SliceType | MapType | ChannelType .
|
||||
Type = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
|
||||
TypeName = identifier | QualifiedIdent .
|
||||
TypeArgs = "[" TypeList [ "," ] "]" .
|
||||
TypeList = Type { "," Type } .
|
||||
TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
||||
SliceType | MapType | ChannelType .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -1200,7 +1199,7 @@ type (
|
|||
<p>
|
||||
A pointer type denotes the set of all pointers to <a href="#Variables">variables</a> of a given
|
||||
type, called the <i>base type</i> of the pointer.
|
||||
The value of an uninitialized pointer is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized pointer is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
|
|
@ -1216,18 +1215,18 @@ BaseType = Type .
|
|||
<h3 id="Function_types">Function types</h3>
|
||||
|
||||
<p>
|
||||
A function type denotes the set of all functions with the same parameter
|
||||
and result types. The value of an uninitialized variable of function type
|
||||
is <code>nil</code>.
|
||||
A function type denotes the set of all functions with the same parameter and result types.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized variable of function
|
||||
type is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
FunctionType = "func" Signature .
|
||||
Signature = Parameters [ Result ] .
|
||||
Result = Parameters | Type .
|
||||
Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
||||
ParameterList = ParameterDecl { "," ParameterDecl } .
|
||||
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
|
||||
FunctionType = "func" Signature .
|
||||
Signature = Parameters [ Result ] .
|
||||
Result = Parameters | Type .
|
||||
Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
||||
ParameterList = ParameterDecl { "," ParameterDecl } .
|
||||
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -1267,7 +1266,8 @@ An interface type defines a <i>type set</i>.
|
|||
A variable of interface type can store a value of any type that is in the type
|
||||
set of the interface. Such a type is said to
|
||||
<a href="#Implementing_an_interface">implement the interface</a>.
|
||||
The value of an uninitialized variable of interface type is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized variable of
|
||||
interface type is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
|
|
@ -1630,12 +1630,12 @@ implements the interface.
|
|||
A map is an unordered group of elements of one type, called the
|
||||
element type, indexed by a set of unique <i>keys</i> of another type,
|
||||
called the key type.
|
||||
The value of an uninitialized map is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized map is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
MapType = "map" "[" KeyType "]" ElementType .
|
||||
KeyType = Type .
|
||||
MapType = "map" "[" KeyType "]" ElementType .
|
||||
KeyType = Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -1693,7 +1693,7 @@ to communicate by
|
|||
<a href="#Send_statements">sending</a> and
|
||||
<a href="#Receive_operator">receiving</a>
|
||||
values of a specified element type.
|
||||
The value of an uninitialized channel is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized channel is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
|
|
@ -1772,6 +1772,57 @@ received in the order sent.
|
|||
|
||||
<h2 id="Properties_of_types_and_values">Properties of types and values</h2>
|
||||
|
||||
<h3 id="Representation_of_values">Representation of values</h3>
|
||||
|
||||
<p>
|
||||
Values of predeclared types (see below for the interfaces <code>any</code>
|
||||
and <code>error</code>), arrays, and structs are self-contained:
|
||||
Each such value contains a complete copy of all its data,
|
||||
and <a href="#Variables">variables</a> of such types store the entire value.
|
||||
For instance, an array variable provides the storage (the variables)
|
||||
for all elements of the array.
|
||||
The respective <a href="#The_zero_value">zero values</a> are specific to the
|
||||
value's types; they are never <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Non-nil pointer, function, slice, map, and channel values contain references
|
||||
to underlying data which may be shared by multiple values:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
A pointer value is a reference to the variable holding
|
||||
the pointer base type value.
|
||||
</li>
|
||||
<li>
|
||||
A function value contains references to the (possibly
|
||||
<a href="#Function_literals">anonymous</a>) function
|
||||
and enclosed variables.
|
||||
</li>
|
||||
<li>
|
||||
A slice value contains the slice length, capacity, and
|
||||
a reference to its <a href="#Slice_types">underlying array</a>.
|
||||
</li>
|
||||
<li>
|
||||
A map or channel value is a reference to the implementation-specific
|
||||
data structure of the map or channel.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
An interface value may be self-contained or contain references to underlying data
|
||||
depending on the interface's <a href="#Variables">dynamic type</a>.
|
||||
The predeclared identifier <code>nil</code> is the zero value for types whose values
|
||||
can contain references.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When multiple values share underlying data, changing one value may change another.
|
||||
For instance, changing an element of a <a href="#Slice_types">slice</a> will change
|
||||
that element in the underlying array for all slices that share the array.
|
||||
</p>
|
||||
|
||||
<h3 id="Underlying_types">Underlying types</h3>
|
||||
|
||||
<p>
|
||||
|
|
@ -2176,7 +2227,7 @@ within matching brace brackets.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Block = "{" StatementList "}" .
|
||||
Block = "{" StatementList "}" .
|
||||
StatementList = { Statement ";" } .
|
||||
</pre>
|
||||
|
||||
|
|
@ -2233,8 +2284,8 @@ and like the blank identifier it does not introduce a new binding.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Declaration = ConstDecl | TypeDecl | VarDecl .
|
||||
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
|
||||
Declaration = ConstDecl | TypeDecl | VarDecl .
|
||||
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -2679,9 +2730,9 @@ in square brackets rather than parentheses
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
TypeParameters = "[" TypeParamList [ "," ] "]" .
|
||||
TypeParamList = TypeParamDecl { "," TypeParamDecl } .
|
||||
TypeParamDecl = IdentifierList TypeConstraint .
|
||||
TypeParameters = "[" TypeParamList [ "," ] "]" .
|
||||
TypeParamList = TypeParamDecl { "," TypeParamDecl } .
|
||||
TypeParamDecl = IdentifierList TypeConstraint .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -2819,7 +2870,7 @@ values or variables, or components of other, non-interface types.
|
|||
|
||||
<p>
|
||||
A type argument <code>T</code><i> satisfies</i> a type constraint <code>C</code>
|
||||
if <code>T</code> is an element of the type set defined by <code>C</code>; i.e.,
|
||||
if <code>T</code> is an element of the type set defined by <code>C</code>; in other words,
|
||||
if <code>T</code> <a href="#Implementing_an_interface">implements</a> <code>C</code>.
|
||||
As an exception, a <a href="#Comparison_operators">strictly comparable</a>
|
||||
type constraint may also be satisfied by a <a href="#Comparison_operators">comparable</a>
|
||||
|
|
@ -2869,8 +2920,8 @@ binds corresponding identifiers to them, and gives each a type and an initial va
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
|
||||
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
|
||||
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
|
||||
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
|
|
@ -2899,7 +2950,7 @@ initialization value in the assignment.
|
|||
If that value is an untyped constant, it is first implicitly
|
||||
<a href="#Conversions">converted</a> to its <a href="#Constants">default type</a>;
|
||||
if it is an untyped boolean value, it is first implicitly converted to type <code>bool</code>.
|
||||
The predeclared value <code>nil</code> cannot be used to initialize a variable
|
||||
The predeclared identifier <code>nil</code> cannot be used to initialize a variable
|
||||
with no explicit type.
|
||||
</p>
|
||||
|
||||
|
|
@ -3210,15 +3261,15 @@ Each element may optionally be preceded by a corresponding key.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
CompositeLit = LiteralType LiteralValue .
|
||||
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
|
||||
SliceType | MapType | TypeName [ TypeArgs ] .
|
||||
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
|
||||
ElementList = KeyedElement { "," KeyedElement } .
|
||||
KeyedElement = [ Key ":" ] Element .
|
||||
Key = FieldName | Expression | LiteralValue .
|
||||
FieldName = identifier .
|
||||
Element = Expression | LiteralValue .
|
||||
CompositeLit = LiteralType LiteralValue .
|
||||
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
|
||||
SliceType | MapType | TypeName [ TypeArgs ] .
|
||||
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
|
||||
ElementList = KeyedElement { "," KeyedElement } .
|
||||
KeyedElement = [ Key ":" ] Element .
|
||||
Key = FieldName | Expression | LiteralValue .
|
||||
FieldName = identifier .
|
||||
Element = Expression | LiteralValue .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -3450,22 +3501,21 @@ Primary expressions are the operands for unary and binary expressions.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
PrimaryExpr =
|
||||
Operand |
|
||||
Conversion |
|
||||
MethodExpr |
|
||||
PrimaryExpr Selector |
|
||||
PrimaryExpr Index |
|
||||
PrimaryExpr Slice |
|
||||
PrimaryExpr TypeAssertion |
|
||||
PrimaryExpr Arguments .
|
||||
PrimaryExpr = Operand |
|
||||
Conversion |
|
||||
MethodExpr |
|
||||
PrimaryExpr Selector |
|
||||
PrimaryExpr Index |
|
||||
PrimaryExpr Slice |
|
||||
PrimaryExpr TypeAssertion |
|
||||
PrimaryExpr Arguments .
|
||||
|
||||
Selector = "." identifier .
|
||||
Index = "[" Expression [ "," ] "]" .
|
||||
Slice = "[" [ Expression ] ":" [ Expression ] "]" |
|
||||
"[" [ Expression ] ":" Expression ":" Expression "]" .
|
||||
TypeAssertion = "." "(" Type ")" .
|
||||
Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
|
||||
Selector = "." identifier .
|
||||
Index = "[" Expression [ "," ] "]" .
|
||||
Slice = "[" [ Expression ] ":" [ Expression ] "]" |
|
||||
"[" [ Expression ] ":" Expression ":" Expression "]" .
|
||||
TypeAssertion = "." "(" Type ")" .
|
||||
Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
|
||||
</pre>
|
||||
|
||||
|
||||
|
|
@ -3638,8 +3688,8 @@ argument that is the receiver of the method.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
MethodExpr = ReceiverType "." MethodName .
|
||||
ReceiverType = Type .
|
||||
MethodExpr = ReceiverType "." MethodName .
|
||||
ReceiverType = Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -4230,8 +4280,7 @@ calls <code>f</code> with arguments <code>a1, a2, … an</code>.
|
|||
Except for one special case, arguments must be single-valued expressions
|
||||
<a href="#Assignability">assignable</a> to the parameter types of
|
||||
<code>F</code> and are evaluated before the function is called.
|
||||
The type of the expression is the result type
|
||||
of <code>F</code>.
|
||||
The type of the expression is the result type of <code>F</code>.
|
||||
A method invocation is similar but the method itself
|
||||
is specified as a selector upon a value of the receiver type for
|
||||
the method.
|
||||
|
|
@ -4252,9 +4301,14 @@ or used as a function value.
|
|||
<p>
|
||||
In a function call, the function value and arguments are evaluated in
|
||||
<a href="#Order_of_evaluation">the usual order</a>.
|
||||
After they are evaluated, the parameters of the call are passed by value to the function
|
||||
After they are evaluated, new storage is allocated for the function's
|
||||
<a href="#Variables">variables</a>, which includes its parameters
|
||||
and results.
|
||||
Then, the arguments of the call are <i>passed</i> to the function,
|
||||
which means that they are <a href="#Assignment_statements">assigned</a>
|
||||
to their corresponding function parameters,
|
||||
and the called function begins execution.
|
||||
The return parameters of the function are passed by value
|
||||
The return parameters of the function are passed
|
||||
back to the caller when the function returns.
|
||||
</p>
|
||||
|
||||
|
|
@ -4268,9 +4322,9 @@ As a special case, if the return values of a function or method
|
|||
<code>g</code> are equal in number and individually
|
||||
assignable to the parameters of another function or method
|
||||
<code>f</code>, then the call <code>f(g(<i>parameters_of_g</i>))</code>
|
||||
will invoke <code>f</code> after binding the return values of
|
||||
<code>g</code> to the parameters of <code>f</code> in order. The call
|
||||
of <code>f</code> must contain no parameters other than the call of <code>g</code>,
|
||||
will invoke <code>f</code> after passing the return values of
|
||||
<code>g</code> to the parameters of <code>f</code> in order.
|
||||
The call of <code>f</code> must contain no parameters other than the call of <code>g</code>,
|
||||
and <code>g</code> must have at least one return value.
|
||||
If <code>f</code> has a final <code>...</code> parameter, it is
|
||||
assigned the return values of <code>g</code> that remain after
|
||||
|
|
@ -4316,7 +4370,7 @@ If <code>f</code> is <a href="#Function_types">variadic</a> with a final
|
|||
parameter <code>p</code> of type <code>...T</code>, then within <code>f</code>
|
||||
the type of <code>p</code> is equivalent to type <code>[]T</code>.
|
||||
If <code>f</code> is invoked with no actual arguments for <code>p</code>,
|
||||
the value passed to <code>p</code> is <code>nil</code>.
|
||||
the value <a href="#Calls">passed</a> to <code>p</code> is <code>nil</code>.
|
||||
Otherwise, the value passed is a new slice
|
||||
of type <code>[]T</code> with a new underlying array whose successive elements
|
||||
are the actual arguments, which all must be <a href="#Assignability">assignable</a>
|
||||
|
|
@ -5632,6 +5686,8 @@ myString([]myRune{0x1f30e}) // "\U0001f30e" == "🌎"
|
|||
<li>
|
||||
Converting a value of a string type to a slice of bytes type
|
||||
yields a non-nil slice whose successive elements are the bytes of the string.
|
||||
The <a href="#Length_and_capacity">capacity</a> of the resulting slice is
|
||||
implementation-specific and may be larger than the slice length.
|
||||
|
||||
<pre>
|
||||
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
|
||||
|
|
@ -5647,6 +5703,8 @@ bytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
|
|||
<li>
|
||||
Converting a value of a string type to a slice of runes type
|
||||
yields a slice containing the individual Unicode code points of the string.
|
||||
The <a href="#Length_and_capacity">capacity</a> of the resulting slice is
|
||||
implementation-specific and may be larger than the slice length.
|
||||
|
||||
<pre>
|
||||
[]rune(myString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4}
|
||||
|
|
@ -5848,7 +5906,7 @@ Otherwise, when evaluating the <a href="#Operands">operands</a> of an
|
|||
expression, assignment, or
|
||||
<a href="#Return_statements">return statement</a>,
|
||||
all function calls, method calls,
|
||||
<a href="#Receive operator">receive operations</a>,
|
||||
<a href="#Receive_operator">receive operations</a>,
|
||||
and <a href="#Logical_operators">binary logical operations</a>
|
||||
are evaluated in lexical left-to-right order.
|
||||
</p>
|
||||
|
|
@ -5916,11 +5974,10 @@ Statements control execution.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Statement =
|
||||
Declaration | LabeledStmt | SimpleStmt |
|
||||
GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
|
||||
FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
|
||||
DeferStmt .
|
||||
Statement = Declaration | LabeledStmt | SimpleStmt |
|
||||
GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
|
||||
FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
|
||||
DeferStmt .
|
||||
|
||||
SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
|
||||
</pre>
|
||||
|
|
@ -6132,7 +6189,7 @@ matching number of variables.
|
|||
<pre class="ebnf">
|
||||
Assignment = ExpressionList assign_op ExpressionList .
|
||||
|
||||
assign_op = [ add_op | mul_op ] "=" .
|
||||
assign_op = [ add_op | mul_op ] "=" .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -6261,6 +6318,26 @@ to the type of the operand to which it is assigned, with the following special c
|
|||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
When a value is assigned to a variable, only the data that is stored in the variable
|
||||
is replaced. If the value contains a <a href="#Representation_of_values">reference</a>,
|
||||
the assignment copies the reference but does not make a copy of the referenced data
|
||||
(such as the underlying array of a slice).
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var s1 = []int{1, 2, 3}
|
||||
var s2 = s1 // s2 stores the slice descriptor of s1
|
||||
s1 = s1[:1] // s1's length is 1 but it still shares its underlying array with s2
|
||||
s2[0] = 42 // setting s2[0] changes s1[0] as well
|
||||
fmt.Println(s1, s2) // prints [42] [42 2 3]
|
||||
|
||||
var m1 = make(map[string]int)
|
||||
var m2 = m1 // m2 stores the map descriptor of m1
|
||||
m1["foo"] = 42 // setting m1["foo"] changes m2["foo"] as well
|
||||
fmt.Println(m2["foo"]) // prints 42
|
||||
</pre>
|
||||
|
||||
<h3 id="If_statements">If statements</h3>
|
||||
|
||||
<p>
|
||||
|
|
@ -6548,7 +6625,7 @@ The iteration may be controlled by a single condition, a "for" clause, or a "ran
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
|
||||
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
|
||||
Condition = Expression .
|
||||
</pre>
|
||||
|
||||
|
|
@ -6580,8 +6657,8 @@ an increment or decrement statement. The init statement may be a
|
|||
|
||||
<pre class="ebnf">
|
||||
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
|
||||
InitStmt = SimpleStmt .
|
||||
PostStmt = SimpleStmt .
|
||||
InitStmt = SimpleStmt .
|
||||
PostStmt = SimpleStmt .
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
|
|
@ -7909,7 +7986,7 @@ types, variables, and constants.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
|
||||
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
|
||||
</pre>
|
||||
|
||||
<h3 id="Package_clause">Package clause</h3>
|
||||
|
|
@ -7920,8 +7997,8 @@ to which the file belongs.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
PackageClause = "package" PackageName .
|
||||
PackageName = identifier .
|
||||
PackageClause = "package" PackageName .
|
||||
PackageName = identifier .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -7950,9 +8027,9 @@ that specifies the package to be imported.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
|
||||
ImportSpec = [ "." | PackageName ] ImportPath .
|
||||
ImportPath = string_lit .
|
||||
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
|
||||
ImportSpec = [ "." | PackageName ] ImportPath .
|
||||
ImportPath = string_lit .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
<!--
|
||||
NOTE: In this document and others in this directory, the convention is to
|
||||
set fixed-width phrases with non-fixed-width spaces, as in
|
||||
`hello` `world`.
|
||||
-->
|
||||
|
||||
<style>
|
||||
main ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -162,12 +162,12 @@ func delete(m map[Type]Type1, key Type)
|
|||
|
||||
// The len built-in function returns the length of v, according to its type:
|
||||
//
|
||||
// Array: the number of elements in v.
|
||||
// Pointer to array: the number of elements in *v (even if v is nil).
|
||||
// Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
|
||||
// String: the number of bytes in v.
|
||||
// Channel: the number of elements queued (unread) in the channel buffer;
|
||||
// if v is nil, len(v) is zero.
|
||||
// - Array: the number of elements in v.
|
||||
// - Pointer to array: the number of elements in *v (even if v is nil).
|
||||
// - Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
|
||||
// - String: the number of bytes in v.
|
||||
// - Channel: the number of elements queued (unread) in the channel buffer;
|
||||
// if v is nil, len(v) is zero.
|
||||
//
|
||||
// For some arguments, such as a string literal or a simple array expression, the
|
||||
// result can be a constant. See the Go language specification's "Length and
|
||||
|
|
@ -176,12 +176,12 @@ func len(v Type) int
|
|||
|
||||
// The cap built-in function returns the capacity of v, according to its type:
|
||||
//
|
||||
// Array: the number of elements in v (same as len(v)).
|
||||
// Pointer to array: the number of elements in *v (same as len(v)).
|
||||
// Slice: the maximum length the slice can reach when resliced;
|
||||
// if v is nil, cap(v) is zero.
|
||||
// Channel: the channel buffer capacity, in units of elements;
|
||||
// if v is nil, cap(v) is zero.
|
||||
// - Array: the number of elements in v (same as len(v)).
|
||||
// - Pointer to array: the number of elements in *v (same as len(v)).
|
||||
// - Slice: the maximum length the slice can reach when resliced;
|
||||
// if v is nil, cap(v) is zero.
|
||||
// - Channel: the channel buffer capacity, in units of elements;
|
||||
// if v is nil, cap(v) is zero.
|
||||
//
|
||||
// For some arguments, such as a simple array expression, the result can be a
|
||||
// constant. See the Go language specification's "Length and capacity" section for
|
||||
|
|
@ -194,18 +194,18 @@ func cap(v Type) int
|
|||
// argument, not a pointer to it. The specification of the result depends on
|
||||
// the type:
|
||||
//
|
||||
// Slice: The size specifies the length. The capacity of the slice is
|
||||
// equal to its length. A second integer argument may be provided to
|
||||
// specify a different capacity; it must be no smaller than the
|
||||
// length. For example, make([]int, 0, 10) allocates an underlying array
|
||||
// of size 10 and returns a slice of length 0 and capacity 10 that is
|
||||
// backed by this underlying array.
|
||||
// Map: An empty map is allocated with enough space to hold the
|
||||
// specified number of elements. The size may be omitted, in which case
|
||||
// a small starting size is allocated.
|
||||
// Channel: The channel's buffer is initialized with the specified
|
||||
// buffer capacity. If zero, or the size is omitted, the channel is
|
||||
// unbuffered.
|
||||
// - Slice: The size specifies the length. The capacity of the slice is
|
||||
// equal to its length. A second integer argument may be provided to
|
||||
// specify a different capacity; it must be no smaller than the
|
||||
// length. For example, make([]int, 0, 10) allocates an underlying array
|
||||
// of size 10 and returns a slice of length 0 and capacity 10 that is
|
||||
// backed by this underlying array.
|
||||
// - Map: An empty map is allocated with enough space to hold the
|
||||
// specified number of elements. The size may be omitted, in which case
|
||||
// a small starting size is allocated.
|
||||
// - Channel: The channel's buffer is initialized with the specified
|
||||
// buffer capacity. If zero, or the size is omitted, the channel is
|
||||
// unbuffered.
|
||||
func make(t Type, size ...IntegerType) Type
|
||||
|
||||
// The max built-in function returns the largest value of a fixed number of
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] {
|
|||
}
|
||||
|
||||
// SplitSeq returns an iterator over all substrings of s separated by sep.
|
||||
// The iterator yields the same strings that would be returned by Split(s, sep),
|
||||
// The iterator yields the same strings that would be returned by [Split](s, sep),
|
||||
// but without constructing the slice.
|
||||
// It returns a single-use iterator.
|
||||
func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
|
|
@ -76,7 +76,7 @@ func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
|||
}
|
||||
|
||||
// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep.
|
||||
// The iterator yields the same strings that would be returned by SplitAfter(s, sep),
|
||||
// The iterator yields the same strings that would be returned by [SplitAfter](s, sep),
|
||||
// but without constructing the slice.
|
||||
// It returns a single-use iterator.
|
||||
func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
|
|
@ -84,8 +84,8 @@ func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
|||
}
|
||||
|
||||
// FieldsSeq returns an iterator over substrings of s split around runs of
|
||||
// whitespace characters, as defined by unicode.IsSpace.
|
||||
// The iterator yields the same strings that would be returned by Fields(s),
|
||||
// whitespace characters, as defined by [unicode.IsSpace].
|
||||
// The iterator yields the same strings that would be returned by [Fields](s),
|
||||
// but without constructing the slice.
|
||||
func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
|
|
@ -118,7 +118,7 @@ func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
|||
|
||||
// FieldsFuncSeq returns an iterator over substrings of s split around runs of
|
||||
// Unicode code points satisfying f(c).
|
||||
// The iterator yields the same strings that would be returned by FieldsFunc(s),
|
||||
// The iterator yields the same strings that would be returned by [FieldsFunc](s),
|
||||
// but without constructing the slice.
|
||||
func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ the package and about types used by symbols imported by the package from
|
|||
other packages. It is therefore not necessary when compiling client C of
|
||||
package P to read the files of P's dependencies, only the compiled output of P.
|
||||
|
||||
Command Line
|
||||
# Command Line
|
||||
|
||||
Usage:
|
||||
|
||||
|
|
@ -150,14 +150,21 @@ Flags to debug the compiler itself:
|
|||
-w
|
||||
Debug type checking.
|
||||
|
||||
Compiler Directives
|
||||
# Compiler Directives
|
||||
|
||||
The compiler accepts directives in the form of comments.
|
||||
To distinguish them from non-directive comments, directives
|
||||
require no space between the comment opening and the name of the directive. However, since
|
||||
they are comments, tools unaware of the directive convention or of a particular
|
||||
Each directive must be placed its own line, with only leading spaces and tabs
|
||||
allowed before the comment, and there must be no space between the comment
|
||||
opening and the name of the directive, to distinguish it from a regular comment.
|
||||
Tools unaware of the directive convention or of a particular
|
||||
directive can skip over a directive like any other comment.
|
||||
|
||||
Other than the line directive, which is a historical special case;
|
||||
all other compiler directives are of the form
|
||||
//go:name, indicating that they are defined by the Go toolchain.
|
||||
*/
|
||||
// # Line Directives
|
||||
//
|
||||
// Line directives come in several forms:
|
||||
//
|
||||
// //line :line
|
||||
|
|
@ -197,12 +204,9 @@ directive can skip over a directive like any other comment.
|
|||
// Line directives typically appear in machine-generated code, so that compilers and debuggers
|
||||
// will report positions in the original input to the generator.
|
||||
/*
|
||||
The line directive is a historical special case; all other directives are of the form
|
||||
//go:name, indicating that they are defined by the Go toolchain.
|
||||
Each directive must be placed its own line, with only leading spaces and tabs
|
||||
allowed before the comment.
|
||||
Each directive applies to the Go code that immediately follows it,
|
||||
which typically must be a declaration.
|
||||
# Function Directives
|
||||
|
||||
A function directive applies to the Go function that immediately follows it.
|
||||
|
||||
//go:noescape
|
||||
|
||||
|
|
@ -245,6 +249,8 @@ It specifies that the function must omit its usual stack overflow check.
|
|||
This is most commonly used by low-level runtime code invoked
|
||||
at times when it is unsafe for the calling goroutine to be preempted.
|
||||
|
||||
# Linkname Directive
|
||||
|
||||
//go:linkname localname [importpath.name]
|
||||
|
||||
The //go:linkname directive conventionally precedes the var or func
|
||||
|
|
@ -295,17 +301,34 @@ The declaration of lower.f may also have a linkname directive with a
|
|||
single argument, f. This is optional, but helps alert the reader that
|
||||
the function is accessed from outside the package.
|
||||
|
||||
# WebAssembly Directives
|
||||
|
||||
//go:wasmimport importmodule importname
|
||||
|
||||
The //go:wasmimport directive is wasm-only and must be followed by a
|
||||
function declaration.
|
||||
function declaration with no body.
|
||||
It specifies that the function is provided by a wasm module identified
|
||||
by ``importmodule`` and ``importname``.
|
||||
by ``importmodule'' and ``importname''. For example,
|
||||
|
||||
//go:wasmimport a_module f
|
||||
func g()
|
||||
|
||||
The types of parameters and return values to the Go function are translated to
|
||||
causes g to refer to the WebAssembly function f from module a_module.
|
||||
|
||||
//go:wasmexport exportname
|
||||
|
||||
The //go:wasmexport directive is wasm-only and must be followed by a
|
||||
function definition.
|
||||
It specifies that the function is exported to the wasm host as ``exportname''.
|
||||
For example,
|
||||
|
||||
//go:wasmexport h
|
||||
func hWasm() { ... }
|
||||
|
||||
make Go function hWasm available outside this WebAssembly module as h.
|
||||
|
||||
For both go:wasmimport and go:wasmexport,
|
||||
the types of parameters and return values to the Go function are translated to
|
||||
Wasm according to the following table:
|
||||
|
||||
Go types Wasm types
|
||||
|
|
@ -318,24 +341,12 @@ Wasm according to the following table:
|
|||
pointer i32 (more restrictions below)
|
||||
string (i32, i32) (only permitted as a parameters, not a result)
|
||||
|
||||
Any other parameter types are disallowed by the compiler.
|
||||
|
||||
For a pointer type, its element type must be a bool, int8, uint8, int16, uint16,
|
||||
int32, uint32, int64, uint64, float32, float64, an array whose element type is
|
||||
a permitted pointer element type, or a struct, which, if non-empty, embeds
|
||||
structs.HostLayout, and contains only fields whose types are permitted pointer
|
||||
[structs.HostLayout], and contains only fields whose types are permitted pointer
|
||||
element types.
|
||||
|
||||
Any other parameter types are disallowed by the compiler.
|
||||
|
||||
//go:wasmexport exportname
|
||||
|
||||
The //go:wasmexport directive is wasm-only and must be followed by a
|
||||
function definition.
|
||||
It specifies that the function is exported to the wasm host as ``exportname``.
|
||||
|
||||
//go:wasmexport f
|
||||
func g()
|
||||
|
||||
The types of parameters and return values to the Go function are permitted and
|
||||
translated to Wasm in the same way as //go:wasmimport functions.
|
||||
*/
|
||||
package main
|
||||
|
|
|
|||
|
|
@ -5452,12 +5452,15 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
|
|||
if n.X.Type().IsChan() && n.Op() == ir.OCAP {
|
||||
s.Fatalf("cannot inline cap(chan)") // must use runtime.chancap now
|
||||
}
|
||||
if n.X.Type().IsMap() && n.Op() == ir.OCAP {
|
||||
s.Fatalf("cannot inline cap(map)") // cap(map) does not exist
|
||||
}
|
||||
// if n == nil {
|
||||
// return 0
|
||||
// } else {
|
||||
// // len
|
||||
// return *((*int)n)
|
||||
// // cap
|
||||
// // len, the actual loadType depends
|
||||
// return int(*((*loadType)n))
|
||||
// // cap (chan only, not used for now)
|
||||
// return *(((*int)n)+1)
|
||||
// }
|
||||
lenType := n.Type()
|
||||
|
|
@ -5485,7 +5488,9 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
|
|||
case ir.OLEN:
|
||||
if buildcfg.Experiment.SwissMap && n.X.Type().IsMap() {
|
||||
// length is stored in the first word.
|
||||
s.vars[n] = s.load(lenType, x)
|
||||
loadType := reflectdata.SwissMapType().Field(0).Type // uint64
|
||||
load := s.load(loadType, x)
|
||||
s.vars[n] = s.conv(nil, load, loadType, lenType) // integer conversion doesn't need Node
|
||||
} else {
|
||||
// length is stored in the first word for map/chan
|
||||
s.vars[n] = s.load(lenType, x)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
func _() {
|
||||
M:
|
||||
L:
|
||||
for range 0 {
|
||||
break L
|
||||
break /* ERROR invalid break label M */ M
|
||||
}
|
||||
for range 0 {
|
||||
break /* ERROR invalid break label L */ L
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ The tests are in:
|
|||
Tests are .go files annotated with `/* ERROR "msg" */` or `/* ERRORx "msg" */`
|
||||
comments (or the respective line comment form).
|
||||
For each such error comment, typechecking the respective file is expected to
|
||||
report an error at the position of the syntactic token _immediately preceeding_
|
||||
report an error at the position of the syntactic token _immediately preceding_
|
||||
the comment.
|
||||
For `ERROR`, the `"msg"` string must be a substring of the error message
|
||||
reported by the typechecker;
|
||||
|
|
|
|||
|
|
@ -208,11 +208,19 @@ type Info struct {
|
|||
//
|
||||
// The Types map does not record the type of every identifier,
|
||||
// only those that appear where an arbitrary expression is
|
||||
// permitted. For instance, the identifier f in a selector
|
||||
// expression x.f is found only in the Selections map, the
|
||||
// identifier z in a variable declaration 'var z int' is found
|
||||
// only in the Defs map, and identifiers denoting packages in
|
||||
// qualified identifiers are collected in the Uses map.
|
||||
// permitted. For instance:
|
||||
// - an identifier f in a selector expression x.f is found
|
||||
// only in the Selections map;
|
||||
// - an identifier z in a variable declaration 'var z int'
|
||||
// is found only in the Defs map;
|
||||
// - an identifier p denoting a package in a qualified
|
||||
// identifier p.X is found only in the Uses map.
|
||||
//
|
||||
// Similarly, no type is recorded for the (synthetic) FuncType
|
||||
// node in a FuncDecl.Type field, since there is no corresponding
|
||||
// syntactic function type expression in the source in this case
|
||||
// Instead, the function type is found in the Defs.map entry for
|
||||
// the corresponding function declaration.
|
||||
Types map[syntax.Expr]TypeAndValue
|
||||
|
||||
// If StoreTypesInSyntax is set, type information identical to
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (*V
|
|||
} else {
|
||||
// If there are type parameters, rbase must denote a generic base type.
|
||||
// Important: rbase must be resolved before declaring any receiver type
|
||||
// parameters (wich may have the same name, see below).
|
||||
// parameters (which may have the same name, see below).
|
||||
var baseType *Named // nil if not valid
|
||||
var cause string
|
||||
if t := check.genericType(rbase, &cause); isValid(t) {
|
||||
|
|
|
|||
|
|
@ -876,16 +876,18 @@ func (t *tester) registerTests() {
|
|||
}
|
||||
|
||||
if t.extLink() && !t.compileOnly {
|
||||
t.registerTest("external linking, -buildmode=exe",
|
||||
&goTest{
|
||||
variant: "exe_external",
|
||||
timeout: 60 * time.Second,
|
||||
buildmode: "exe",
|
||||
ldflags: "-linkmode=external",
|
||||
env: []string{"CGO_ENABLED=1"},
|
||||
pkg: "crypto/internal/fips140test",
|
||||
runTests: "TestFIPSCheck",
|
||||
})
|
||||
if goos != "android" { // Android does not support non-PIE linking
|
||||
t.registerTest("external linking, -buildmode=exe",
|
||||
&goTest{
|
||||
variant: "exe_external",
|
||||
timeout: 60 * time.Second,
|
||||
buildmode: "exe",
|
||||
ldflags: "-linkmode=external",
|
||||
env: []string{"CGO_ENABLED=1"},
|
||||
pkg: "crypto/internal/fips140test",
|
||||
runTests: "TestFIPSCheck",
|
||||
})
|
||||
}
|
||||
if t.externalLinkPIE() && !disablePIE {
|
||||
t.registerTest("external linking, -buildmode=pie",
|
||||
&goTest{
|
||||
|
|
@ -1795,6 +1797,8 @@ func isEnvSet(evar string) bool {
|
|||
}
|
||||
|
||||
func (t *tester) fipsSupported() bool {
|
||||
// Keep this in sync with [crypto/internal/fips140.Supported].
|
||||
|
||||
// Use GOFIPS140 or GOEXPERIMENT=boringcrypto, but not both.
|
||||
if strings.Contains(goexperiment, "boringcrypto") {
|
||||
return false
|
||||
|
|
@ -1808,6 +1812,7 @@ func (t *tester) fipsSupported() bool {
|
|||
case goarch == "wasm",
|
||||
goos == "windows" && goarch == "386",
|
||||
goos == "windows" && goarch == "arm",
|
||||
goos == "openbsd",
|
||||
goos == "aix":
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -739,11 +739,6 @@
|
|||
//
|
||||
// For more about specifying packages, see 'go help packages'.
|
||||
//
|
||||
// This text describes the behavior of get using modules to manage source
|
||||
// code and dependencies. If instead the go command is running in GOPATH
|
||||
// mode, the details of get's flags and effects change, as does 'go help get'.
|
||||
// See 'go help gopath-get'.
|
||||
//
|
||||
// See also: go build, go install, go clean, go mod.
|
||||
//
|
||||
// # Compile and install packages and dependencies
|
||||
|
|
@ -2186,7 +2181,7 @@
|
|||
// fields of all events to reconstruct the text format output, as it would
|
||||
// have appeared from go build without the -json flag.
|
||||
//
|
||||
// Note that there may also be non-JSON error text on stdnard error, even
|
||||
// Note that there may also be non-JSON error text on standard error, even
|
||||
// with the -json flag. Typically, this indicates an early, serious error.
|
||||
// Consumers should be robust to this.
|
||||
//
|
||||
|
|
@ -2250,7 +2245,7 @@
|
|||
//
|
||||
// The second is the SWIG program, which is a general tool for
|
||||
// interfacing between languages. For information on SWIG see
|
||||
// http://swig.org/. When running go build, any file with a .swig
|
||||
// https://swig.org/. When running go build, any file with a .swig
|
||||
// extension will be passed to SWIG. Any file with a .swigcxx extension
|
||||
// will be passed to SWIG with the -c++ option.
|
||||
//
|
||||
|
|
@ -2338,6 +2333,10 @@
|
|||
// GOCACHE
|
||||
// The directory where the go command will store cached
|
||||
// information for reuse in future builds.
|
||||
// GOCACHEPROG
|
||||
// A command (with optional space-separated flags) that implements an
|
||||
// external go command build cache.
|
||||
// See 'go doc cmd/go/internal/cacheprog'.
|
||||
// GODEBUG
|
||||
// Enable various debugging facilities. See https://go.dev/doc/godebug
|
||||
// for details.
|
||||
|
|
@ -2448,6 +2447,11 @@
|
|||
// GOARM
|
||||
// For GOARCH=arm, the ARM architecture for which to compile.
|
||||
// Valid values are 5, 6, 7.
|
||||
// When the Go tools are built on an arm system,
|
||||
// the default value is set based on what the build system supports.
|
||||
// When the Go tools are not built on an arm system
|
||||
// (that is, when building a cross-compiler),
|
||||
// the default value is 7.
|
||||
// The value can be followed by an option specifying how to implement floating point instructions.
|
||||
// Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7).
|
||||
// GOARM64
|
||||
|
|
@ -2612,7 +2616,7 @@
|
|||
// Example: Data
|
||||
//
|
||||
// If the server responds with any 4xx code, the go command will write the
|
||||
// following to the programs' stdin:
|
||||
// following to the program's stdin:
|
||||
// Response = StatusLine { HeaderLine } BlankLine .
|
||||
// StatusLine = Protocol Space Status '\n' .
|
||||
// Protocol = /* HTTP protocol */ .
|
||||
|
|
@ -2969,11 +2973,7 @@
|
|||
// same meta tag and then git clone https://code.org/r/p/exproj into
|
||||
// GOPATH/src/example.org.
|
||||
//
|
||||
// When using GOPATH, downloaded packages are written to the first directory
|
||||
// listed in the GOPATH environment variable.
|
||||
// (See 'go help gopath-get' and 'go help gopath'.)
|
||||
//
|
||||
// When using modules, downloaded packages are stored in the module cache.
|
||||
// Downloaded packages are stored in the module cache.
|
||||
// See https://golang.org/ref/mod#module-cache.
|
||||
//
|
||||
// When using modules, an additional variant of the go-import meta tag is
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ type Cache interface {
|
|||
// Get returns the cache entry for the provided ActionID.
|
||||
// On miss, the error type should be of type *entryNotFoundError.
|
||||
//
|
||||
// After a success call to Get, OutputFile(Entry.OutputID) must
|
||||
// exist on disk for until Close is called (at the end of the process).
|
||||
// After a successful call to Get, OutputFile(Entry.OutputID) must
|
||||
// exist on disk until Close is called (at the end of the process).
|
||||
Get(ActionID) (Entry, error)
|
||||
|
||||
// Put adds an item to the cache.
|
||||
|
|
@ -50,14 +50,14 @@ type Cache interface {
|
|||
// As a special case, if the ReadSeeker is of type noVerifyReadSeeker,
|
||||
// the verification from GODEBUG=goverifycache=1 is skipped.
|
||||
//
|
||||
// After a success call to Get, OutputFile(Entry.OutputID) must
|
||||
// exist on disk for until Close is called (at the end of the process).
|
||||
// After a successful call to Put, OutputFile(OutputID) must
|
||||
// exist on disk until Close is called (at the end of the process).
|
||||
Put(ActionID, io.ReadSeeker) (_ OutputID, size int64, _ error)
|
||||
|
||||
// Close is called at the end of the go process. Implementations can do
|
||||
// cache cleanup work at this phase, or wait for and report any errors from
|
||||
// background cleanup work started earlier. Any cache trimming should in one
|
||||
// process should not violate cause the invariants of this interface to be
|
||||
// background cleanup work started earlier. Any cache trimming in one
|
||||
// process should not cause the invariants of this interface to be
|
||||
// violated in another process. Namely, a cache trim from one process should
|
||||
// not delete an ObjectID from disk that was recently Get or Put from
|
||||
// another process. As a rule of thumb, don't trim things used in the last
|
||||
|
|
@ -296,19 +296,19 @@ func GetBytes(c Cache, id ActionID) ([]byte, Entry, error) {
|
|||
// GetMmap looks up the action ID in the cache and returns
|
||||
// the corresponding output bytes.
|
||||
// GetMmap should only be used for data that can be expected to fit in memory.
|
||||
func GetMmap(c Cache, id ActionID) ([]byte, Entry, error) {
|
||||
func GetMmap(c Cache, id ActionID) ([]byte, Entry, bool, error) {
|
||||
entry, err := c.Get(id)
|
||||
if err != nil {
|
||||
return nil, entry, err
|
||||
return nil, entry, false, err
|
||||
}
|
||||
md, err := mmap.Mmap(c.OutputFile(entry.OutputID))
|
||||
md, opened, err := mmap.Mmap(c.OutputFile(entry.OutputID))
|
||||
if err != nil {
|
||||
return nil, Entry{}, err
|
||||
return nil, Entry{}, opened, err
|
||||
}
|
||||
if int64(len(md.Data)) != entry.Size {
|
||||
return nil, Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")}
|
||||
return nil, Entry{}, true, &entryNotFoundError{Err: errors.New("file incomplete")}
|
||||
}
|
||||
return md.Data, entry, nil
|
||||
return md.Data, entry, true, nil
|
||||
}
|
||||
|
||||
// OutputFile returns the name of the cache file storing output with the given OutputID.
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ func initDefaultCache() Cache {
|
|||
base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err)
|
||||
}
|
||||
|
||||
if v := cfg.Getenv("GOCACHEPROG"); v != "" {
|
||||
return startCacheProg(v, diskCache)
|
||||
if cfg.GOCACHEPROG != "" {
|
||||
return startCacheProg(cfg.GOCACHEPROG, diskCache)
|
||||
}
|
||||
|
||||
return diskCache
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package cache
|
|||
import (
|
||||
"bufio"
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cacheprog"
|
||||
"cmd/internal/quoted"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
|
|
@ -38,7 +39,7 @@ type ProgCache struct {
|
|||
|
||||
// can are the commands that the child process declared that it supports.
|
||||
// This is effectively the versioning mechanism.
|
||||
can map[ProgCmd]bool
|
||||
can map[cacheprog.Cmd]bool
|
||||
|
||||
// fuzzDirCache is another Cache implementation to use for the FuzzDir
|
||||
// method. In practice this is the default GOCACHE disk-based
|
||||
|
|
@ -55,7 +56,7 @@ type ProgCache struct {
|
|||
|
||||
mu sync.Mutex // guards following fields
|
||||
nextID int64
|
||||
inFlight map[int64]chan<- *ProgResponse
|
||||
inFlight map[int64]chan<- *cacheprog.Response
|
||||
outputFile map[OutputID]string // object => abs path on disk
|
||||
|
||||
// writeMu serializes writing to the child process.
|
||||
|
|
@ -63,95 +64,6 @@ type ProgCache struct {
|
|||
writeMu sync.Mutex
|
||||
}
|
||||
|
||||
// ProgCmd is a command that can be issued to a child process.
|
||||
//
|
||||
// If the interface needs to grow, we can add new commands or new versioned
|
||||
// commands like "get2".
|
||||
type ProgCmd string
|
||||
|
||||
const (
|
||||
cmdGet = ProgCmd("get")
|
||||
cmdPut = ProgCmd("put")
|
||||
cmdClose = ProgCmd("close")
|
||||
)
|
||||
|
||||
// ProgRequest is the JSON-encoded message that's sent from cmd/go to
|
||||
// the GOCACHEPROG child process over stdin. Each JSON object is on its
|
||||
// own line. A ProgRequest of Type "put" with BodySize > 0 will be followed
|
||||
// by a line containing a base64-encoded JSON string literal of the body.
|
||||
type ProgRequest struct {
|
||||
// ID is a unique number per process across all requests.
|
||||
// It must be echoed in the ProgResponse from the child.
|
||||
ID int64
|
||||
|
||||
// Command is the type of request.
|
||||
// The cmd/go tool will only send commands that were declared
|
||||
// as supported by the child.
|
||||
Command ProgCmd
|
||||
|
||||
// ActionID is non-nil for get and puts.
|
||||
ActionID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// OutputID is set for Type "put".
|
||||
//
|
||||
// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
|
||||
// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
|
||||
OutputID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// Body is the body for "put" requests. It's sent after the JSON object
|
||||
// as a base64-encoded JSON string when BodySize is non-zero.
|
||||
// It's sent as a separate JSON value instead of being a struct field
|
||||
// send in this JSON object so large values can be streamed in both directions.
|
||||
// The base64 string body of a ProgRequest will always be written
|
||||
// immediately after the JSON object and a newline.
|
||||
Body io.Reader `json:"-"`
|
||||
|
||||
// BodySize is the number of bytes of Body. If zero, the body isn't written.
|
||||
BodySize int64 `json:",omitempty"`
|
||||
|
||||
// ObjectID is the accidental spelling of OutputID that was used prior to Go
|
||||
// 1.24.
|
||||
//
|
||||
// Deprecated: use OutputID. This field is only populated temporarily for
|
||||
// backwards compatibility with Go 1.23 and earlier when
|
||||
// GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25.
|
||||
ObjectID []byte `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ProgResponse is the JSON response from the child process to cmd/go.
|
||||
//
|
||||
// With the exception of the first protocol message that the child writes to its
|
||||
// stdout with ID==0 and KnownCommands populated, these are only sent in
|
||||
// response to a ProgRequest from cmd/go.
|
||||
//
|
||||
// ProgResponses can be sent in any order. The ID must match the request they're
|
||||
// replying to.
|
||||
type ProgResponse struct {
|
||||
ID int64 // that corresponds to ProgRequest; they can be answered out of order
|
||||
Err string `json:",omitempty"` // if non-empty, the error
|
||||
|
||||
// KnownCommands is included in the first message that cache helper program
|
||||
// writes to stdout on startup (with ID==0). It includes the
|
||||
// ProgRequest.Command types that are supported by the program.
|
||||
//
|
||||
// This lets us extend the protocol gracefully over time (adding "get2",
|
||||
// etc), or fail gracefully when needed. It also lets us verify the program
|
||||
// wants to be a cache helper.
|
||||
KnownCommands []ProgCmd `json:",omitempty"`
|
||||
|
||||
// For Get requests.
|
||||
|
||||
Miss bool `json:",omitempty"` // cache miss
|
||||
OutputID []byte `json:",omitempty"`
|
||||
Size int64 `json:",omitempty"` // in bytes
|
||||
Time *time.Time `json:",omitempty"` // an Entry.Time; when the object was added to the docs
|
||||
|
||||
// DiskPath is the absolute path on disk of the ObjectID corresponding
|
||||
// a "get" request's ActionID (on cache hit) or a "put" request's
|
||||
// provided ObjectID.
|
||||
DiskPath string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// startCacheProg starts the prog binary (with optional space-separated flags)
|
||||
// and returns a Cache implementation that talks to it.
|
||||
//
|
||||
|
|
@ -183,6 +95,8 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
|
|||
base.Fatalf("StdinPipe to GOCACHEPROG: %v", err)
|
||||
}
|
||||
cmd.Stderr = os.Stderr
|
||||
// On close, we cancel the context. Rather than killing the helper,
|
||||
// close its stdin.
|
||||
cmd.Cancel = in.Close
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
|
|
@ -197,14 +111,14 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
|
|||
stdout: out,
|
||||
stdin: in,
|
||||
bw: bufio.NewWriter(in),
|
||||
inFlight: make(map[int64]chan<- *ProgResponse),
|
||||
inFlight: make(map[int64]chan<- *cacheprog.Response),
|
||||
outputFile: make(map[OutputID]string),
|
||||
readLoopDone: make(chan struct{}),
|
||||
}
|
||||
|
||||
// Register our interest in the initial protocol message from the child to
|
||||
// us, saying what it can do.
|
||||
capResc := make(chan *ProgResponse, 1)
|
||||
capResc := make(chan *cacheprog.Response, 1)
|
||||
pc.inFlight[0] = capResc
|
||||
|
||||
pc.jenc = json.NewEncoder(pc.bw)
|
||||
|
|
@ -219,7 +133,7 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
|
|||
case <-timer.C:
|
||||
log.Printf("# still waiting for GOCACHEPROG %v ...", prog)
|
||||
case capRes := <-capResc:
|
||||
can := map[ProgCmd]bool{}
|
||||
can := map[cacheprog.Cmd]bool{}
|
||||
for _, cmd := range capRes.KnownCommands {
|
||||
can[cmd] = true
|
||||
}
|
||||
|
|
@ -236,9 +150,15 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
|
|||
defer close(readLoopDone)
|
||||
jd := json.NewDecoder(c.stdout)
|
||||
for {
|
||||
res := new(ProgResponse)
|
||||
res := new(cacheprog.Response)
|
||||
if err := jd.Decode(res); err != nil {
|
||||
if c.closing.Load() {
|
||||
c.mu.Lock()
|
||||
for _, ch := range c.inFlight {
|
||||
close(ch)
|
||||
}
|
||||
c.inFlight = nil
|
||||
c.mu.Unlock()
|
||||
return // quietly
|
||||
}
|
||||
if err == io.EOF {
|
||||
|
|
@ -261,13 +181,18 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse, error) {
|
||||
resc := make(chan *ProgResponse, 1)
|
||||
var errCacheprogClosed = errors.New("GOCACHEPROG program closed unexpectedly")
|
||||
|
||||
func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cacheprog.Response, error) {
|
||||
resc := make(chan *cacheprog.Response, 1)
|
||||
if err := c.writeToChild(req, resc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
select {
|
||||
case res := <-resc:
|
||||
if res == nil {
|
||||
return nil, errCacheprogClosed
|
||||
}
|
||||
if res.Err != "" {
|
||||
return nil, errors.New(res.Err)
|
||||
}
|
||||
|
|
@ -277,8 +202,11 @@ func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse,
|
|||
}
|
||||
}
|
||||
|
||||
func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (err error) {
|
||||
func (c *ProgCache) writeToChild(req *cacheprog.Request, resc chan<- *cacheprog.Response) (err error) {
|
||||
c.mu.Lock()
|
||||
if c.inFlight == nil {
|
||||
return errCacheprogClosed
|
||||
}
|
||||
c.nextID++
|
||||
req.ID = c.nextID
|
||||
c.inFlight[req.ID] = resc
|
||||
|
|
@ -287,7 +215,9 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e
|
|||
defer func() {
|
||||
if err != nil {
|
||||
c.mu.Lock()
|
||||
delete(c.inFlight, req.ID)
|
||||
if c.inFlight != nil {
|
||||
delete(c.inFlight, req.ID)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
}()
|
||||
|
|
@ -328,7 +258,7 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e
|
|||
}
|
||||
|
||||
func (c *ProgCache) Get(a ActionID) (Entry, error) {
|
||||
if !c.can[cmdGet] {
|
||||
if !c.can[cacheprog.CmdGet] {
|
||||
// They can't do a "get". Maybe they're a write-only cache.
|
||||
//
|
||||
// TODO(bradfitz,bcmills): figure out the proper error type here. Maybe
|
||||
|
|
@ -338,8 +268,8 @@ func (c *ProgCache) Get(a ActionID) (Entry, error) {
|
|||
// error types on the Cache interface.
|
||||
return Entry{}, &entryNotFoundError{}
|
||||
}
|
||||
res, err := c.send(c.ctx, &ProgRequest{
|
||||
Command: cmdGet,
|
||||
res, err := c.send(c.ctx, &cacheprog.Request{
|
||||
Command: cacheprog.CmdGet,
|
||||
ActionID: a[:],
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -395,7 +325,7 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64,
|
|||
return OutputID{}, 0, err
|
||||
}
|
||||
|
||||
if !c.can[cmdPut] {
|
||||
if !c.can[cacheprog.CmdPut] {
|
||||
// Child is a read-only cache. Do nothing.
|
||||
return out, size, nil
|
||||
}
|
||||
|
|
@ -407,8 +337,8 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64,
|
|||
deprecatedValue = out[:]
|
||||
}
|
||||
|
||||
res, err := c.send(c.ctx, &ProgRequest{
|
||||
Command: cmdPut,
|
||||
res, err := c.send(c.ctx, &cacheprog.Request{
|
||||
Command: cacheprog.CmdPut,
|
||||
ActionID: a[:],
|
||||
OutputID: out[:],
|
||||
ObjectID: deprecatedValue, // TODO(bradfitz): remove in Go 1.25
|
||||
|
|
@ -432,10 +362,16 @@ func (c *ProgCache) Close() error {
|
|||
// First write a "close" message to the child so it can exit nicely
|
||||
// and clean up if it wants. Only after that exchange do we cancel
|
||||
// the context that kills the process.
|
||||
if c.can[cmdClose] {
|
||||
_, err = c.send(c.ctx, &ProgRequest{Command: cmdClose})
|
||||
if c.can[cacheprog.CmdClose] {
|
||||
_, err = c.send(c.ctx, &cacheprog.Request{Command: cacheprog.CmdClose})
|
||||
if errors.Is(err, errCacheprogClosed) {
|
||||
// Allow the child to quit without responding to close.
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
// Cancel the context, which will close the helper's stdin.
|
||||
c.ctxCancel()
|
||||
// Wait until the helper closes its stdout.
|
||||
<-c.readLoopDone
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cacheprog defines the protocol for a GOCACHEPROG program.
|
||||
//
|
||||
// By default, the go command manages a build cache stored in the file system
|
||||
// itself. GOCACHEPROG can be set to the name of a command (with optional
|
||||
// space-separated flags) that implements the go command build cache externally.
|
||||
// This permits defining a different cache policy.
|
||||
//
|
||||
// The go command will start the GOCACHEPROG as a subprocess and communicate
|
||||
// with it via JSON messages over stdin/stdout. The subprocess's stderr will be
|
||||
// connected to the go command's stderr.
|
||||
//
|
||||
// The subprocess should immediately send a [Response] with its capabilities.
|
||||
// After that, the go command will send a stream of [Request] messages and the
|
||||
// subprocess should reply to each [Request] with a [Response] message.
|
||||
package cacheprog
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Cmd is a command that can be issued to a child process.
|
||||
//
|
||||
// If the interface needs to grow, the go command can add new commands or new
|
||||
// versioned commands like "get2" in the future. The initial [Response] from
|
||||
// the child process indicates which commands it supports.
|
||||
type Cmd string
|
||||
|
||||
const (
|
||||
// CmdPut tells the cache program to store an object in the cache.
|
||||
//
|
||||
// [Request.ActionID] is the cache key of this object. The cache should
|
||||
// store [Request.OutputID] and [Request.Body] under this key for a
|
||||
// later "get" request. It must also store the Body in a file in the local
|
||||
// file system and return the path to that file in [Response.DiskPath],
|
||||
// which must exist at least until a "close" request.
|
||||
CmdPut = Cmd("put")
|
||||
|
||||
// CmdGet tells the cache program to retrieve an object from the cache.
|
||||
//
|
||||
// [Request.ActionID] specifies the key of the object to get. If the
|
||||
// cache does not contain this object, it should set [Response.Miss] to
|
||||
// true. Otherwise, it should populate the fields of [Response],
|
||||
// including setting [Response.OutputID] to the OutputID of the original
|
||||
// "put" request and [Response.DiskPath] to the path of a local file
|
||||
// containing the Body of the original "put" request. That file must
|
||||
// continue to exist at least until a "close" request.
|
||||
CmdGet = Cmd("get")
|
||||
|
||||
// CmdClose requests that the cache program exit gracefully.
|
||||
//
|
||||
// The cache program should reply to this request and then exit
|
||||
// (thus closing its stdout).
|
||||
CmdClose = Cmd("close")
|
||||
)
|
||||
|
||||
// Request is the JSON-encoded message that's sent from the go command to
|
||||
// the GOCACHEPROG child process over stdin. Each JSON object is on its own
|
||||
// line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
|
||||
// line containing a base64-encoded JSON string literal of the body.
|
||||
type Request struct {
|
||||
// ID is a unique number per process across all requests.
|
||||
// It must be echoed in the Response from the child.
|
||||
ID int64
|
||||
|
||||
// Command is the type of request.
|
||||
// The go command will only send commands that were declared
|
||||
// as supported by the child.
|
||||
Command Cmd
|
||||
|
||||
// ActionID is the cache key for "put" and "get" requests.
|
||||
ActionID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// OutputID is stored with the body for "put" requests.
|
||||
//
|
||||
// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
|
||||
// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
|
||||
OutputID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// Body is the body for "put" requests. It's sent after the JSON object
|
||||
// as a base64-encoded JSON string when BodySize is non-zero.
|
||||
// It's sent as a separate JSON value instead of being a struct field
|
||||
// send in this JSON object so large values can be streamed in both directions.
|
||||
// The base64 string body of a Request will always be written
|
||||
// immediately after the JSON object and a newline.
|
||||
Body io.Reader `json:"-"`
|
||||
|
||||
// BodySize is the number of bytes of Body. If zero, the body isn't written.
|
||||
BodySize int64 `json:",omitempty"`
|
||||
|
||||
// ObjectID is the accidental spelling of OutputID that was used prior to Go
|
||||
// 1.24.
|
||||
//
|
||||
// Deprecated: use OutputID. This field is only populated temporarily for
|
||||
// backwards compatibility with Go 1.23 and earlier when
|
||||
// GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25.
|
||||
ObjectID []byte `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Response is the JSON response from the child process to the go command.
|
||||
//
|
||||
// With the exception of the first protocol message that the child writes to its
|
||||
// stdout with ID==0 and KnownCommands populated, these are only sent in
|
||||
// response to a Request from the go command.
|
||||
//
|
||||
// Responses can be sent in any order. The ID must match the request they're
|
||||
// replying to.
|
||||
type Response struct {
|
||||
ID int64 // that corresponds to Request; they can be answered out of order
|
||||
Err string `json:",omitempty"` // if non-empty, the error
|
||||
|
||||
// KnownCommands is included in the first message that cache helper program
|
||||
// writes to stdout on startup (with ID==0). It includes the
|
||||
// Request.Command types that are supported by the program.
|
||||
//
|
||||
// This lets the go command extend the protocol gracefully over time (adding
|
||||
// "get2", etc), or fail gracefully when needed. It also lets the go command
|
||||
// verify the program wants to be a cache helper.
|
||||
KnownCommands []Cmd `json:",omitempty"`
|
||||
|
||||
// For "get" requests.
|
||||
|
||||
Miss bool `json:",omitempty"` // cache miss
|
||||
OutputID []byte `json:",omitempty"` // the ObjectID stored with the body
|
||||
Size int64 `json:",omitempty"` // body size in bytes
|
||||
Time *time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration)
|
||||
|
||||
// For "get" and "put" requests.
|
||||
|
||||
// DiskPath is the absolute path on disk of the body corresponding to a
|
||||
// "get" (on cache hit) or "put" request's ActionID.
|
||||
DiskPath string `json:",omitempty"`
|
||||
}
|
||||
|
|
@ -425,8 +425,9 @@ var (
|
|||
GOROOTpkg string
|
||||
GOROOTsrc string
|
||||
|
||||
GOBIN = Getenv("GOBIN")
|
||||
GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod"))
|
||||
GOBIN = Getenv("GOBIN")
|
||||
GOCACHEPROG, GOCACHEPROGChanged = EnvOrAndChanged("GOCACHEPROG", "")
|
||||
GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod"))
|
||||
|
||||
// Used in envcmd.MkEnv and build ID computations.
|
||||
GOARM64, goARM64Changed = EnvOrAndChanged("GOARM64", buildcfg.DefaultGOARM64)
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ func MkEnv() []cfg.EnvVar {
|
|||
{Name: "GOAUTH", Value: cfg.GOAUTH, Changed: cfg.GOAUTHChanged},
|
||||
{Name: "GOBIN", Value: cfg.GOBIN},
|
||||
{Name: "GOCACHE"},
|
||||
{Name: "GOCACHEPROG", Value: cfg.GOCACHEPROG, Changed: cfg.GOCACHEPROGChanged},
|
||||
{Name: "GODEBUG", Value: os.Getenv("GODEBUG")},
|
||||
{Name: "GOENV", Value: envFile, Changed: envFileChanged},
|
||||
{Name: "GOEXE", Value: cfg.ExeSuffix},
|
||||
|
|
|
|||
|
|
@ -40,14 +40,8 @@
|
|||
//
|
||||
// GOFIPS140=latest go build -work my/binary
|
||||
//
|
||||
// will leave fips.o behind in $WORK/b001. Auditors like to be able to
|
||||
// see that file. Accordingly, when [Enabled] returns true,
|
||||
// [cmd/go/internal/work.Builder.useCache] arranges never to cache linker
|
||||
// output, so that the link step always runs, and fips.o is always left
|
||||
// behind in the link step. If this proves too slow, we could always
|
||||
// cache fips.o as an extra link output and then restore it when -work is
|
||||
// set, but we went a very long time never caching link steps at all, so
|
||||
// not caching them in FIPS mode seems perfectly fine.
|
||||
// will leave fips.o behind in $WORK/b001
|
||||
// (unless the build result is cached, of course).
|
||||
//
|
||||
// When GOFIPS140 is set to something besides off and latest, [Snapshot]
|
||||
// returns true, indicating that the build should replace the latest copy
|
||||
|
|
@ -119,6 +113,10 @@ func Init() {
|
|||
if Snapshot() {
|
||||
fsys.Bind(Dir(), filepath.Join(cfg.GOROOT, "src/crypto/internal/fips140"))
|
||||
}
|
||||
|
||||
if cfg.Experiment.BoringCrypto && Enabled() {
|
||||
base.Fatalf("go: cannot use GOFIPS140 with GOEXPERIMENT=boringcrypto")
|
||||
}
|
||||
}
|
||||
|
||||
var initDone bool
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ information on how to use it see the cgo documentation (go doc cmd/cgo).
|
|||
|
||||
The second is the SWIG program, which is a general tool for
|
||||
interfacing between languages. For information on SWIG see
|
||||
http://swig.org/. When running go build, any file with a .swig
|
||||
https://swig.org/. When running go build, any file with a .swig
|
||||
extension will be passed to SWIG. Any file with a .swigcxx extension
|
||||
will be passed to SWIG with the -c++ option.
|
||||
|
||||
|
|
@ -270,11 +270,7 @@ the go tool will verify that https://example.org/?go-get=1 contains the
|
|||
same meta tag and then git clone https://code.org/r/p/exproj into
|
||||
GOPATH/src/example.org.
|
||||
|
||||
When using GOPATH, downloaded packages are written to the first directory
|
||||
listed in the GOPATH environment variable.
|
||||
(See 'go help gopath-get' and 'go help gopath'.)
|
||||
|
||||
When using modules, downloaded packages are stored in the module cache.
|
||||
Downloaded packages are stored in the module cache.
|
||||
See https://golang.org/ref/mod#module-cache.
|
||||
|
||||
When using modules, an additional variant of the go-import meta tag is
|
||||
|
|
@ -510,6 +506,10 @@ General-purpose environment variables:
|
|||
GOCACHE
|
||||
The directory where the go command will store cached
|
||||
information for reuse in future builds.
|
||||
GOCACHEPROG
|
||||
A command (with optional space-separated flags) that implements an
|
||||
external go command build cache.
|
||||
See 'go doc cmd/go/internal/cacheprog'.
|
||||
GODEBUG
|
||||
Enable various debugging facilities. See https://go.dev/doc/godebug
|
||||
for details.
|
||||
|
|
@ -620,6 +620,11 @@ Architecture-specific environment variables:
|
|||
GOARM
|
||||
For GOARCH=arm, the ARM architecture for which to compile.
|
||||
Valid values are 5, 6, 7.
|
||||
When the Go tools are built on an arm system,
|
||||
the default value is set based on what the build system supports.
|
||||
When the Go tools are not built on an arm system
|
||||
(that is, when building a cross-compiler),
|
||||
the default value is 7.
|
||||
The value can be followed by an option specifying how to implement floating point instructions.
|
||||
Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7).
|
||||
GOARM64
|
||||
|
|
@ -1029,7 +1034,7 @@ command
|
|||
Example: Data
|
||||
|
||||
If the server responds with any 4xx code, the go command will write the
|
||||
following to the programs' stdin:
|
||||
following to the program's stdin:
|
||||
Response = StatusLine { HeaderLine } BlankLine .
|
||||
StatusLine = Protocol Space Status '\n' .
|
||||
Protocol = /* HTTP protocol */ .
|
||||
|
|
@ -1097,7 +1102,7 @@ Furthermore, as with TestEvent, parsers can simply concatenate the Output
|
|||
fields of all events to reconstruct the text format output, as it would
|
||||
have appeared from go build without the -json flag.
|
||||
|
||||
Note that there may also be non-JSON error text on stdnard error, even
|
||||
Note that there may also be non-JSON error text on standard error, even
|
||||
with the -json flag. Typically, this indicates an early, serious error.
|
||||
Consumers should be robust to this.
|
||||
`,
|
||||
|
|
|
|||
|
|
@ -3068,7 +3068,15 @@ func setPGOProfilePath(pkgs []*Package) {
|
|||
// CheckPackageErrors prints errors encountered loading pkgs and their
|
||||
// dependencies, then exits with a non-zero status if any errors were found.
|
||||
func CheckPackageErrors(pkgs []*Package) {
|
||||
var anyIncomplete bool
|
||||
PackageErrors(pkgs, func(p *Package) {
|
||||
DefaultPrinter().Errorf(p, "%v", p.Error)
|
||||
})
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
|
||||
// PackageErrors calls report for errors encountered loading pkgs and their dependencies.
|
||||
func PackageErrors(pkgs []*Package, report func(*Package)) {
|
||||
var anyIncomplete, anyErrors bool
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Incomplete {
|
||||
anyIncomplete = true
|
||||
|
|
@ -3078,11 +3086,14 @@ func CheckPackageErrors(pkgs []*Package) {
|
|||
all := PackageList(pkgs)
|
||||
for _, p := range all {
|
||||
if p.Error != nil {
|
||||
DefaultPrinter().Errorf(p, "%v", p.Error)
|
||||
report(p)
|
||||
anyErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
if anyErrors {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for duplicate loads of the same package.
|
||||
// That should be impossible, but if it does happen then
|
||||
|
|
@ -3105,7 +3116,9 @@ func CheckPackageErrors(pkgs []*Package) {
|
|||
}
|
||||
seen[key] = true
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
if len(reported) > 0 {
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
}
|
||||
|
||||
// mainPackagesOnly filters out non-main packages matched only by arguments
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ type Data struct {
|
|||
}
|
||||
|
||||
// Mmap maps the given file into memory.
|
||||
func Mmap(file string) (Data, error) {
|
||||
func Mmap(file string) (Data, bool, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return Data{}, err
|
||||
return Data{}, false, err
|
||||
}
|
||||
return mmapFile(f)
|
||||
data, err := mmapFile(f)
|
||||
return data, true, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,11 +125,6 @@ suggested Go toolchain, see https://go.dev/doc/toolchain.
|
|||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
This text describes the behavior of get using modules to manage source
|
||||
code and dependencies. If instead the go command is running in GOPATH
|
||||
mode, the details of get's flags and effects change, as does 'go help get'.
|
||||
See 'go help gopath-get'.
|
||||
|
||||
See also: go build, go install, go clean, go mod.
|
||||
`,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,16 +183,21 @@ func openIndexModule(modroot string, ismodcache bool) (*Module, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, _, err := cache.GetMmap(cache.Default(), id)
|
||||
data, _, opened, err := cache.GetMmap(cache.Default(), id)
|
||||
if err != nil {
|
||||
// Couldn't read from modindex. Assume we couldn't read from
|
||||
// the index because the module hasn't been indexed yet.
|
||||
// But double check on Windows that we haven't opened the file yet,
|
||||
// because once mmap opens the file, we can't close it, and
|
||||
// Windows won't let us open an already opened file.
|
||||
data, err = indexModule(modroot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
if runtime.GOOS != "windows" || !opened {
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
mi, err := fromBytes(modroot, data)
|
||||
|
|
@ -212,13 +217,18 @@ func openIndexPackage(modroot, pkgdir string) (*IndexPackage, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, _, err := cache.GetMmap(cache.Default(), id)
|
||||
data, _, opened, err := cache.GetMmap(cache.Default(), id)
|
||||
if err != nil {
|
||||
// Couldn't read from index. Assume we couldn't read from
|
||||
// the index because the package hasn't been indexed yet.
|
||||
// But double check on Windows that we haven't opened the file yet,
|
||||
// because once mmap opens the file, we can't close it, and
|
||||
// Windows won't let us open an already opened file.
|
||||
data = indexPackage(modroot, pkgdir)
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
if runtime.GOOS != "windows" || !opened {
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
pkg, err := packageFromBytes(modroot, data)
|
||||
|
|
|
|||
|
|
@ -994,14 +994,15 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
|||
|
||||
// Prepare build + run + print actions for all packages being tested.
|
||||
for _, p := range pkgs {
|
||||
buildTest, runTest, printTest, perr, err := builderTest(b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct)
|
||||
if err != nil {
|
||||
reportErr := func(perr *load.Package, err error) {
|
||||
str := err.Error()
|
||||
if p.ImportPath != "" {
|
||||
load.DefaultPrinter().Errorf(perr, "# %s\n%s", p.ImportPath, str)
|
||||
} else {
|
||||
load.DefaultPrinter().Errorf(perr, "%s", str)
|
||||
}
|
||||
}
|
||||
reportSetupFailed := func(perr *load.Package, err error) {
|
||||
var stdout io.Writer = os.Stdout
|
||||
if testJSON {
|
||||
json := test2json.NewConverter(stdout, p.ImportPath, test2json.Timestamp)
|
||||
|
|
@ -1009,11 +1010,34 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
|||
json.Exited(err)
|
||||
json.Close()
|
||||
}()
|
||||
json.SetFailedBuild(perr.Desc())
|
||||
if gotestjsonbuildtext.Value() == "1" {
|
||||
// While this flag is about go build -json, the other effect
|
||||
// of that change was to include "FailedBuild" in the test JSON.
|
||||
gotestjsonbuildtext.IncNonDefault()
|
||||
} else {
|
||||
json.SetFailedBuild(perr.Desc())
|
||||
}
|
||||
stdout = json
|
||||
}
|
||||
fmt.Fprintf(stdout, "FAIL\t%s [setup failed]\n", p.ImportPath)
|
||||
base.SetExitStatus(1)
|
||||
}
|
||||
|
||||
var firstErrPkg *load.Package // arbitrarily report setup failed error for first error pkg reached in DFS
|
||||
load.PackageErrors([]*load.Package{p}, func(p *load.Package) {
|
||||
reportErr(p, p.Error)
|
||||
if firstErrPkg == nil {
|
||||
firstErrPkg = p
|
||||
}
|
||||
})
|
||||
if firstErrPkg != nil {
|
||||
reportSetupFailed(firstErrPkg, firstErrPkg.Error)
|
||||
continue
|
||||
}
|
||||
buildTest, runTest, printTest, perr, err := builderTest(b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct)
|
||||
if err != nil {
|
||||
reportErr(perr, err)
|
||||
reportSetupFailed(perr, err)
|
||||
continue
|
||||
}
|
||||
builds = append(builds, buildTest)
|
||||
|
|
@ -1437,7 +1461,11 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
|
|||
if a.Failed != nil {
|
||||
// We were unable to build the binary.
|
||||
if json != nil && a.Failed.Package != nil {
|
||||
json.SetFailedBuild(a.Failed.Package.Desc())
|
||||
if gotestjsonbuildtext.Value() == "1" {
|
||||
gotestjsonbuildtext.IncNonDefault()
|
||||
} else {
|
||||
json.SetFailedBuild(a.Failed.Package.Desc())
|
||||
}
|
||||
}
|
||||
a.Failed = nil
|
||||
fmt.Fprintf(stdout, "FAIL\t%s [build failed]\n", a.Package.ImportPath)
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ func Select() {
|
|||
}
|
||||
|
||||
gotoolchain = minToolchain
|
||||
if (mode == "auto" || mode == "path") && !goInstallVersion() {
|
||||
if (mode == "auto" || mode == "path") && !goInstallVersion(minVers) {
|
||||
// Read go.mod to find new minimum and suggested toolchain.
|
||||
file, goVers, toolchain := modGoToolchain()
|
||||
gover.Startup.AutoFile = file
|
||||
|
|
@ -549,7 +549,7 @@ func modGoToolchain() (file, goVers, toolchain string) {
|
|||
|
||||
// goInstallVersion reports whether the command line is go install m@v or go run m@v.
|
||||
// If so, Select must not read the go.mod or go.work file in "auto" or "path" mode.
|
||||
func goInstallVersion() bool {
|
||||
func goInstallVersion(minVers string) bool {
|
||||
// Note: We assume there are no flags between 'go' and 'install' or 'run'.
|
||||
// During testing there are some debugging flags that are accepted
|
||||
// in that position, but in production go binaries there are not.
|
||||
|
|
@ -708,7 +708,11 @@ func goInstallVersion() bool {
|
|||
if errors.Is(err, gover.ErrTooNew) {
|
||||
// Run early switch, same one go install or go run would eventually do,
|
||||
// if it understood all the command-line flags.
|
||||
SwitchOrFatal(ctx, err)
|
||||
var s Switcher
|
||||
s.Error(err)
|
||||
if s.TooNew != nil && gover.Compare(s.TooNew.GoVersion, minVers) > 0 {
|
||||
SwitchOrFatal(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
return true // pkg@version found
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ func (h *authHandler) Handler(dir string, env []string, logger *log.Logger) (htt
|
|||
var err error
|
||||
accessFile, err = fs.Open(path.Join(accessDir, ".access"))
|
||||
if err == nil {
|
||||
defer accessFile.Close()
|
||||
break
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import (
|
|||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/fips140"
|
||||
"cmd/go/internal/fsys"
|
||||
"cmd/go/internal/str"
|
||||
"cmd/internal/buildid"
|
||||
|
|
@ -447,19 +446,6 @@ func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string,
|
|||
a.buildID = actionID + buildIDSeparator + mainpkg.buildID + buildIDSeparator + contentID
|
||||
}
|
||||
|
||||
// In FIPS mode, we disable any link caching,
|
||||
// so that we always leave fips.o in $WORK/b001.
|
||||
// This makes sure that labs validating the FIPS
|
||||
// implementation can always run 'go build -work'
|
||||
// and then find fips.o in $WORK/b001/fips.o.
|
||||
// We could instead also save the fips.o and restore it
|
||||
// to $WORK/b001 from the cache,
|
||||
// but we went years without caching binaries anyway,
|
||||
// so not caching them for FIPS will be fine, at least to start.
|
||||
if a.Mode == "link" && fips140.Enabled() && a.Package != nil && !strings.HasSuffix(a.Package.ImportPath, ".test") {
|
||||
return false
|
||||
}
|
||||
|
||||
// If user requested -a, we force a rebuild, so don't use the cache.
|
||||
if cfg.BuildA {
|
||||
if p := a.Package; p != nil && !p.Stale {
|
||||
|
|
@ -519,7 +505,7 @@ func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string,
|
|||
oldBuildID := a.buildID
|
||||
a.buildID = id[1] + buildIDSeparator + id[2]
|
||||
linkID := buildid.HashToString(b.linkActionID(a.triggers[0]))
|
||||
if id[0] == linkID && !fips140.Enabled() {
|
||||
if id[0] == linkID {
|
||||
// Best effort attempt to display output from the compile and link steps.
|
||||
// If it doesn't work, it doesn't work: reusing the cached binary is more
|
||||
// important than reprinting diagnostic information.
|
||||
|
|
|
|||
|
|
@ -1374,6 +1374,7 @@ func (b *Builder) linkActionID(a *Action) cache.ActionID {
|
|||
fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch)
|
||||
fmt.Fprintf(h, "import %q\n", p.ImportPath)
|
||||
fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
|
||||
fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG)
|
||||
if cfg.BuildTrimpath {
|
||||
fmt.Fprintln(h, "trimpath")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,23 +201,23 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
|||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,--(no-)?export-dynamic`),
|
||||
re(`-Wl,-E`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]+`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]*`),
|
||||
re(`-Wl,--hash-style=(sysv|gnu|both)`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
re(`-Wl,--pop-state`),
|
||||
re(`-Wl,--push-state`),
|
||||
re(`-Wl,-R,?([^@\-,][^,@]*$)`),
|
||||
re(`-Wl,--just-symbols[=,]([^,@\-][^,@]+)`),
|
||||
re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,--just-symbols[=,]([^,@\-][^,@]*)`),
|
||||
re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]*)`),
|
||||
re(`-Wl,-s`),
|
||||
re(`-Wl,-search_paths_first`),
|
||||
re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
|
||||
re(`-Wl,-sectcreate,([^,@\-][^,]*),([^,@\-][^,]*),([^,@\-][^,]*)`),
|
||||
re(`-Wl,--start-group`),
|
||||
re(`-Wl,-?-static`),
|
||||
re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`),
|
||||
re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-syslibroot[=,]([^,@\-][^,]*)`),
|
||||
re(`-Wl,-undefined[=,]([^,@\-][^,]*)`),
|
||||
re(`-Wl,-?-unresolved-symbols=[^,]+`),
|
||||
re(`-Wl,--(no-)?warn-([^,]+)`),
|
||||
re(`-Wl,-?-wrap[=,][^,@\-][^,]*`),
|
||||
|
|
@ -227,6 +227,21 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
|||
re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{
|
||||
// The GNU linker interprets `@file` as "read command-line options from
|
||||
// file". Thus, we forbid values starting with `@` on linker flags.
|
||||
// However, this causes a problem when targeting Darwin.
|
||||
// `@executable_path`, `@loader_path`, and `@rpath` are special values
|
||||
// used in Mach-O to change the library search path and can be used in
|
||||
// conjunction with the `-install_name` and `-rpath` linker flags.
|
||||
// Since the GNU linker does not support Mach-O, targeting Darwin
|
||||
// implies not using the GNU linker. Therefore, we allow @ in the linker
|
||||
// flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios".
|
||||
re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`),
|
||||
re(`-Wl,-install_name,@rpath(/[^,]*)?`),
|
||||
re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-F",
|
||||
|
|
@ -249,8 +264,13 @@ func checkCompilerFlags(name, source string, list []string) error {
|
|||
}
|
||||
|
||||
func checkLinkerFlags(name, source string, list []string) error {
|
||||
validLinkerFlagsForPlatform := validLinkerFlags
|
||||
if cfg.Goos == "darwin" || cfg.Goos == "ios" {
|
||||
validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...)
|
||||
}
|
||||
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmd/go/internal/cfg"
|
||||
)
|
||||
|
||||
var goodCompilerFlags = [][]string{
|
||||
|
|
@ -182,6 +184,13 @@ var goodLinkerFlags = [][]string{
|
|||
{"-Wl,--pop-state"},
|
||||
{"-Wl,--push-state,--as-needed"},
|
||||
{"-Wl,--push-state,--no-as-needed,-Bstatic"},
|
||||
{"-Wl,--just-symbols,."},
|
||||
{"-Wl,-framework,."},
|
||||
{"-Wl,-rpath,."},
|
||||
{"-Wl,-rpath-link,."},
|
||||
{"-Wl,-sectcreate,.,.,."},
|
||||
{"-Wl,-syslibroot,."},
|
||||
{"-Wl,-undefined,."},
|
||||
}
|
||||
|
||||
var badLinkerFlags = [][]string{
|
||||
|
|
@ -238,6 +247,8 @@ var badLinkerFlags = [][]string{
|
|||
{"-Wl,--hash-style=foo"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
{"-Wl,-dylib_install_name,@foo"},
|
||||
{"-Wl,-install_name,@foo"},
|
||||
{"-Wl,-rpath,@foo"},
|
||||
{"-Wl,-R,foo,bar"},
|
||||
{"-Wl,-R,@foo"},
|
||||
|
|
@ -254,6 +265,21 @@ var badLinkerFlags = [][]string{
|
|||
{"./-Wl,--push-state,-R.c"},
|
||||
}
|
||||
|
||||
var goodLinkerFlagsOnDarwin = [][]string{
|
||||
{"-Wl,-dylib_install_name,@rpath"},
|
||||
{"-Wl,-dylib_install_name,@rpath/"},
|
||||
{"-Wl,-dylib_install_name,@rpath/foo"},
|
||||
{"-Wl,-install_name,@rpath"},
|
||||
{"-Wl,-install_name,@rpath/"},
|
||||
{"-Wl,-install_name,@rpath/foo"},
|
||||
{"-Wl,-rpath,@executable_path"},
|
||||
{"-Wl,-rpath,@executable_path/"},
|
||||
{"-Wl,-rpath,@executable_path/foo"},
|
||||
{"-Wl,-rpath,@loader_path"},
|
||||
{"-Wl,-rpath,@loader_path/"},
|
||||
{"-Wl,-rpath,@loader_path/foo"},
|
||||
}
|
||||
|
||||
func TestCheckLinkerFlags(t *testing.T) {
|
||||
for _, f := range goodLinkerFlags {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
|
|
@ -265,6 +291,31 @@ func TestCheckLinkerFlags(t *testing.T) {
|
|||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
goos := cfg.Goos
|
||||
|
||||
cfg.Goos = "darwin"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = "ios"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = "linux"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err == nil {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = goos
|
||||
}
|
||||
|
||||
func TestCheckFlagAllowDisallow(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
[short] skip 'builds go programs'
|
||||
|
||||
go build -o cacheprog$GOEXE cacheprog.go
|
||||
env GOCACHEPROG=$GOPATH/src/cacheprog$GOEXE
|
||||
|
||||
# This should not deadlock
|
||||
go build simple.go
|
||||
! stderr 'cacheprog closed'
|
||||
|
||||
-- simple.go --
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
-- cacheprog.go --
|
||||
// This is a minimal GOCACHEPROG program that doesn't respond to close.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
json.NewEncoder(os.Stdout).Encode(map[string][]string{"KnownCommands": {"close"}})
|
||||
var res struct{}
|
||||
json.NewDecoder(os.Stdin).Decode(&res)
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ go version -m example$GOEXE
|
|||
stdout '\s+mod\s+example\s+v1.0.1\s+'
|
||||
rm example$GOEXE
|
||||
|
||||
# Use tag+dirty when there are uncomitted changes present.
|
||||
# Use tag+dirty when there are uncommitted changes present.
|
||||
cp $WORK/copy/README $WORK/repo/README
|
||||
go build
|
||||
go version -m example$GOEXE
|
||||
|
|
@ -82,7 +82,7 @@ go version -m example$GOEXE
|
|||
stdout '\s+mod\s+example\s+v1.0.3-0.20220719150702-deaeab06f7fe\s+'
|
||||
rm example$GOEXE
|
||||
|
||||
# Use pseudo+dirty when uncomitted changes are present.
|
||||
# Use pseudo+dirty when uncommitted changes are present.
|
||||
mv README2 README3
|
||||
go build
|
||||
go version -m example$GOEXE
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
# Test query for non-defaults in the env
|
||||
|
||||
# Go+BoringCrypto conflicts with GOFIPS140.
|
||||
[GOEXPERIMENT:boringcrypto] skip
|
||||
|
||||
env GOROOT=./a
|
||||
env GOTOOLCHAIN=local
|
||||
env GOSUMDB=nodefault
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
# GOCACHEPROG unset
|
||||
env GOCACHEPROG=
|
||||
|
||||
go env
|
||||
stdout 'GOCACHEPROG=''?''?'
|
||||
|
||||
go env -changed
|
||||
! stdout 'GOCACHEPROG'
|
||||
|
||||
go env -changed -json
|
||||
! stdout 'GOCACHEPROG'
|
||||
|
||||
# GOCACHEPROG set
|
||||
[short] skip 'compiles and runs a go program'
|
||||
|
||||
go build -o cacheprog$GOEXE cacheprog.go
|
||||
|
||||
env GOCACHEPROG=$GOPATH/src/cacheprog$GOEXE
|
||||
|
||||
go env
|
||||
stdout 'GOCACHEPROG=''?'$GOCACHEPROG'''?'
|
||||
|
||||
go env -changed
|
||||
stdout 'GOCACHEPROG=''?'$GOCACHEPROG'''?'
|
||||
|
||||
go env -changed -json
|
||||
stdout '"GOCACHEPROG": ".*cacheprog'$GOEXE'"'
|
||||
|
||||
-- cacheprog.go --
|
||||
// This is a minimal GOCACHEPROG program that can't actually do anything but exit.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
json.NewEncoder(os.Stdout).Encode(map[string][]string{"KnownCommands": {"close"}})
|
||||
var res struct{}
|
||||
json.NewDecoder(os.Stdin).Decode(&res)
|
||||
}
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
# Go+BoringCrypto conflicts with GOFIPS140.
|
||||
[GOEXPERIMENT:boringcrypto] skip
|
||||
|
||||
# list with GOFIPS140=off
|
||||
env GOFIPS140=off
|
||||
go list -f '{{.DefaultGODEBUG}}'
|
||||
|
|
@ -17,12 +20,12 @@ go build -x -o x.exe
|
|||
go build -x -o x.exe
|
||||
! stderr link
|
||||
|
||||
# build with GOFIPS140=latest is NOT cached (need fipso)
|
||||
# build with GOFIPS140=latest is cached too
|
||||
env GOFIPS140=latest
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
! stderr link.*-fipso
|
||||
|
||||
# build test with GOFIPS140=off is cached
|
||||
env GOFIPS140=off
|
||||
|
|
@ -38,8 +41,6 @@ stderr link.*-fipso
|
|||
go test -x -c
|
||||
! stderr link
|
||||
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
-- x.go --
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ env alias=inprocess
|
|||
skip 'no snapshots yet'
|
||||
env GOFIPS140=$snap
|
||||
|
||||
# Go+BoringCrypto conflicts with GOFIPS140.
|
||||
[GOEXPERIMENT:boringcrypto] skip
|
||||
|
||||
# default GODEBUG includes fips140=on
|
||||
go list -f '{{.DefaultGODEBUG}}'
|
||||
stdout fips140=on
|
||||
|
|
@ -44,11 +47,11 @@ stdout crypto/internal/fips140/$snap/sha256
|
|||
|
||||
[short] skip
|
||||
|
||||
# build with GOFIPS140=snap is NOT cached (need fipso)
|
||||
# build with GOFIPS140=snap is cached
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
! stderr link.*-fipso
|
||||
|
||||
# build test with GOFIPS140=snap is cached
|
||||
go test -x -c
|
||||
|
|
|
|||
|
|
@ -197,6 +197,17 @@ go mod edit -go=1.501 -toolchain=none
|
|||
go version
|
||||
stdout go1.501
|
||||
|
||||
# avoid two-step switch, first from install target requirement, then from GOTOOLCHAIN min
|
||||
# instead, just jump directly to GOTOOLCHAIN min
|
||||
env TESTGO_VERSION=go1.2.3
|
||||
env GODEBUG=toolchaintrace=1
|
||||
env GOTOOLCHAIN=go1.23.0+auto
|
||||
! go install rsc.io/fortune/nonexist@v0.0.1
|
||||
! stderr 'switching to go1.22.9'
|
||||
stderr 'using go1.23.0'
|
||||
env GODEBUG=
|
||||
env GOTOOLCHAIN=auto
|
||||
|
||||
# go install m@v and go run m@v should ignore go.mod and use m@v
|
||||
env TESTGO_VERSION=go1.2.3
|
||||
go mod edit -go=1.999 -toolchain=go1.998
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ env GO111MODULE=on
|
|||
# go help get shows usage for get
|
||||
go help get
|
||||
stdout 'usage: go get'
|
||||
stdout 'get using modules to manage source'
|
||||
stdout 'updates go.mod to require those versions'
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ stdout '\Aok\s+example.com/x\s+[0-9.s]+\n\z'
|
|||
# Even though ./x looks like a package path, the real package should be
|
||||
# the implicit '.'.
|
||||
! go test --answer=42 ./x
|
||||
stdout '^FAIL\t. \[build failed\]'
|
||||
stderr '^\.: no Go files in '$PWD'$'
|
||||
stdout '^FAIL\t. \[setup failed\]'
|
||||
stderr '^# \.\nno Go files in '$PWD'$'
|
||||
|
||||
# However, *flags* that appear after unrecognized flags should still be
|
||||
# interpreted as flags, under the (possibly-erroneous) assumption that
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
[!fuzz] skip
|
||||
[short] skip
|
||||
env GOCACHE=$WORK/cache
|
||||
|
||||
# Test fuzz.Context.
|
||||
go test -vet=off context_fuzz_test.go
|
||||
stdout ^ok
|
||||
! stdout FAIL
|
||||
|
||||
go test -vet=off -fuzz=Fuzz -fuzztime=1x context_fuzz_test.go
|
||||
stdout ok
|
||||
! stdout FAIL
|
||||
|
||||
-- context_fuzz_test.go --
|
||||
package context_fuzz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Fuzz(f *testing.F) {
|
||||
ctx := f.Context()
|
||||
if err := ctx.Err(); err != nil {
|
||||
f.Fatalf("expected non-canceled context, got %v", err)
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
innerCtx := t.Context()
|
||||
if err := innerCtx.Err(); err != nil {
|
||||
t.Fatalf("expected inner test to not inherit canceled context, got %v", err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
if !errors.Is(innerCtx.Err(), context.Canceled) {
|
||||
t.Fatal("expected context of inner test to be canceled after its fuzz function finished")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
f.Cleanup(func() {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
f.Fatal("expected context canceled before cleanup")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -40,6 +40,18 @@ stdout '"Action":"output","Package":"m/loaderror","Output":"FAIL\\tm/loaderror \
|
|||
stdout '"Action":"fail","Package":"m/loaderror","Elapsed":.*,"FailedBuild":"x"'
|
||||
! stderr '.'
|
||||
|
||||
# Test an import cycle loading error in a non test file. (#70820)
|
||||
! go test -json -o=$devnull ./cycle/p
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"# m/cycle/p\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"package m/cycle/p\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"\\timports m/cycle/q from p.go\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"\\timports m/cycle/q from q.go: import cycle not allowed\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-fail"'
|
||||
stdout '"Action":"start","Package":"m/cycle/p"'
|
||||
stdout '"Action":"output","Package":"m/cycle/p","Output":"FAIL\\tm/cycle/p \[setup failed\]\\n"'
|
||||
stdout '"Action":"fail","Package":"m/cycle/p","Elapsed":.*,"FailedBuild":"m/cycle/q"'
|
||||
! stderr '.'
|
||||
|
||||
# Test a vet error
|
||||
! go test -json -o=$devnull ./veterror
|
||||
stdout '"ImportPath":"m/veterror \[m/veterror.test\]","Action":"build-output","Output":"# m/veterror\\n"'
|
||||
|
|
@ -58,8 +70,9 @@ stderr '# m/builderror \[m/builderror.test\]\n'
|
|||
stderr 'builderror'${/}'main_test.go:3:11: undefined: y\n'
|
||||
stdout '"Action":"start","Package":"m/builderror"'
|
||||
stdout '"Action":"output","Package":"m/builderror","Output":"FAIL\\tm/builderror \[build failed\]\\n"'
|
||||
stdout '"Action":"fail","Package":"m/builderror","Elapsed":.*,"FailedBuild":"m/builderror \[m/builderror\.test\]"'
|
||||
|
||||
stdout '"Action":"fail","Package":"m/builderror","Elapsed":[0-9.]+\}'
|
||||
# FailedBuild should NOT appear in the output in this mode.
|
||||
! stdout '"FailedBuild"'
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
|
@ -98,3 +111,13 @@ import (
|
|||
func TestVetError(t *testing.T) {
|
||||
fmt.Printf("%s")
|
||||
}
|
||||
-- cycle/p/p.go --
|
||||
package p
|
||||
|
||||
import "m/cycle/q"
|
||||
-- cycle/q/q.go --
|
||||
package q
|
||||
|
||||
import (
|
||||
"m/cycle/q"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -33,10 +33,23 @@ stderr '# m/t2/p\n.*package x is not in std'
|
|||
stdout 'FAIL m/t2/p \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
# Finally, this one is a build error, but produced by cmd/go directly
|
||||
# Test that an import cycle error is reported. Test for #70820
|
||||
! go test -o=$devnull ./cycle/p ./t
|
||||
stderr '# m/cycle/p\n.*package m/cycle/p\n\timports m/cycle/p from p\.go: import cycle not allowed'
|
||||
stdout 'FAIL m/cycle/p \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
# Test that multiple errors for the same package under test are reported.
|
||||
! go test -o=$devnull ./cycle/q ./t
|
||||
stderr '# m/cycle/q\n.*package m/cycle/q\n\timports m/cycle/p from q\.go\n\timports m/cycle/p from p\.go: import cycle not allowed'
|
||||
stdout 'FAIL m/cycle/q \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
# Finally, this one is a non-import-cycle load error that
|
||||
# is produced for the package under test.
|
||||
! go test -o=$devnull . ./t
|
||||
stderr '^\.: no Go files in '$PWD'$'
|
||||
stdout 'FAIL . \[build failed\]'
|
||||
stderr '# \.\n.*no Go files in '$PWD'$'
|
||||
stdout 'FAIL . \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
-- go.mod --
|
||||
|
|
@ -68,6 +81,17 @@ package p
|
|||
package p
|
||||
|
||||
import "m/bad"
|
||||
-- cycle/p/p.go --
|
||||
package p
|
||||
|
||||
import "m/cycle/p"
|
||||
-- cycle/q/q.go --
|
||||
package q
|
||||
|
||||
import (
|
||||
"m/bad"
|
||||
"m/cycle/p"
|
||||
)
|
||||
-- bad/bad.go --
|
||||
package bad
|
||||
|
||||
|
|
|
|||
|
|
@ -410,14 +410,16 @@ func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.By
|
|||
func disasm_riscv64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
|
||||
inst, err := riscv64asm.Decode(code)
|
||||
var text string
|
||||
size := inst.Len
|
||||
if err != nil || inst.Op == 0 {
|
||||
size = 2
|
||||
text = "?"
|
||||
} else if gnuAsm {
|
||||
text = fmt.Sprintf("%-36s // %s", riscv64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), riscv64asm.GNUSyntax(inst))
|
||||
} else {
|
||||
text = riscv64asm.GoSyntax(inst, pc, lookup, textReader{code, pc})
|
||||
}
|
||||
return text, 4
|
||||
return text, size
|
||||
}
|
||||
|
||||
func disasm_s390x(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
|
||||
|
|
|
|||
|
|
@ -5,22 +5,33 @@
|
|||
// Package hash implements hash functions used in the compiler toolchain.
|
||||
package hash
|
||||
|
||||
// TODO(rsc): Delete the 16 and 20 forms and use 32 at all call sites.
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"hash"
|
||||
)
|
||||
|
||||
const (
|
||||
// Size32 is the size of 32 bytes hash checksum.
|
||||
Size32 = sha256.Size
|
||||
// Size20 is the size of 20 bytes hash checksum.
|
||||
Size20 = sha1.Size
|
||||
// Size16 is the size of 16 bytes hash checksum.
|
||||
Size16 = md5.Size
|
||||
// Size32 is the size of the 32-byte hash checksum.
|
||||
Size32 = 32
|
||||
// Size20 is the size of the 20-byte hash checksum.
|
||||
Size20 = 20
|
||||
// Size16 is the size of the 16-byte hash checksum.
|
||||
Size16 = 16
|
||||
)
|
||||
|
||||
type shortHash struct {
|
||||
hash.Hash
|
||||
n int
|
||||
}
|
||||
|
||||
func (h *shortHash) Sum(b []byte) []byte {
|
||||
old := b
|
||||
sum := h.Hash.Sum(b)
|
||||
return sum[:len(old)+h.n]
|
||||
}
|
||||
|
||||
// New32 returns a new [hash.Hash] computing the 32 bytes hash checksum.
|
||||
func New32() hash.Hash {
|
||||
h := sha256.New()
|
||||
|
|
@ -30,12 +41,12 @@ func New32() hash.Hash {
|
|||
|
||||
// New20 returns a new [hash.Hash] computing the 20 bytes hash checksum.
|
||||
func New20() hash.Hash {
|
||||
return sha1.New()
|
||||
return &shortHash{New32(), 20}
|
||||
}
|
||||
|
||||
// New16 returns a new [hash.Hash] computing the 16 bytes hash checksum.
|
||||
func New16() hash.Hash {
|
||||
return md5.New()
|
||||
return &shortHash{New32(), 16}
|
||||
}
|
||||
|
||||
// Sum32 returns the 32 bytes checksum of the data.
|
||||
|
|
@ -47,10 +58,16 @@ func Sum32(data []byte) [Size32]byte {
|
|||
|
||||
// Sum20 returns the 20 bytes checksum of the data.
|
||||
func Sum20(data []byte) [Size20]byte {
|
||||
return sha1.Sum(data)
|
||||
sum := Sum32(data)
|
||||
var short [Size20]byte
|
||||
copy(short[:], sum[4:])
|
||||
return short
|
||||
}
|
||||
|
||||
// Sum16 returns the 16 bytes checksum of the data.
|
||||
func Sum16(data []byte) [Size16]byte {
|
||||
return md5.Sum(data)
|
||||
sum := Sum32(data)
|
||||
var short [Size16]byte
|
||||
copy(short[:], sum[8:])
|
||||
return short
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ func (ctxt *Link) NumberSyms() {
|
|||
// Assign special index for builtin symbols.
|
||||
// Don't do it when linking against shared libraries, as the runtime
|
||||
// may be in a different library.
|
||||
if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
|
||||
if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 && !rs.IsLinkname() {
|
||||
rs.PkgIdx = goobj.PkgIdxBuiltin
|
||||
rs.SymIdx = int32(i)
|
||||
rs.Set(AttrIndexed, true)
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ Flags:
|
|||
Link with race detection libraries.
|
||||
-s
|
||||
Omit the symbol table and debug information.
|
||||
Implies the -w flag, which can be negated with -w=0.
|
||||
-tmpdir dir
|
||||
Write temporary files to dir.
|
||||
Temporary files are only used in external linking mode.
|
||||
|
|
|
|||
|
|
@ -55,17 +55,31 @@ import (
|
|||
)
|
||||
|
||||
// isRuntimeDepPkg reports whether pkg is the runtime package or its dependency.
|
||||
// TODO: just compute from the runtime package, and remove this hardcoded list.
|
||||
func isRuntimeDepPkg(pkg string) bool {
|
||||
switch pkg {
|
||||
case "runtime",
|
||||
"sync/atomic", // runtime may call to sync/atomic, due to go:linkname
|
||||
"internal/abi", // used by reflectcall (and maybe more)
|
||||
"internal/bytealg", // for IndexByte
|
||||
"sync/atomic", // runtime may call to sync/atomic, due to go:linkname // TODO: this is not true?
|
||||
"internal/abi", // used by reflectcall (and maybe more)
|
||||
"internal/asan",
|
||||
"internal/bytealg", // for IndexByte
|
||||
"internal/byteorder",
|
||||
"internal/chacha8rand", // for rand
|
||||
"internal/cpu": // for cpu features
|
||||
"internal/coverage/rtcov",
|
||||
"internal/cpu", // for cpu features
|
||||
"internal/goarch",
|
||||
"internal/godebugs",
|
||||
"internal/goexperiment",
|
||||
"internal/goos",
|
||||
"internal/msan",
|
||||
"internal/profilerecord",
|
||||
"internal/race",
|
||||
"internal/stringslite",
|
||||
"unsafe":
|
||||
return true
|
||||
}
|
||||
return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
|
||||
return (strings.HasPrefix(pkg, "runtime/internal/") || strings.HasPrefix(pkg, "internal/runtime/")) &&
|
||||
!strings.HasSuffix(pkg, "_test")
|
||||
}
|
||||
|
||||
// Estimate the max size needed to hold any new trampolines created for this function. This
|
||||
|
|
@ -410,6 +424,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
|
|||
// FIXME: It should be forbidden to have R_ADDR from a
|
||||
// symbol which isn't in .data. However, as .text has the
|
||||
// same address once loaded, this is possible.
|
||||
// TODO: .text (including rodata) to .data relocation
|
||||
// doesn't work correctly, so we should really disallow it.
|
||||
// See also aixStaticDataBase in symtab.go and in runtime.
|
||||
if ldr.SymSect(s).Seg == &Segdata {
|
||||
Xcoffadddynrel(target, ldr, syms, s, r, ri)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@ func (d *dwctxt) defgotype(gotype loader.Sym) loader.Sym {
|
|||
d.linkctxt.Errorf(gotype, "dwarf: type name doesn't start with \"type:\"")
|
||||
return d.mustFind("<unspecified>")
|
||||
}
|
||||
name := sn[5:] // could also decode from Type.string
|
||||
name := sn[len("type:"):] // could also decode from Type.string
|
||||
|
||||
sdie := d.find(name)
|
||||
if sdie != 0 {
|
||||
|
|
@ -534,7 +534,7 @@ func (d *dwctxt) defgotype(gotype loader.Sym) loader.Sym {
|
|||
|
||||
func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
|
||||
sn := d.ldr.SymName(gotype)
|
||||
name := sn[5:] // could also decode from Type.string
|
||||
name := sn[len("type:"):] // could also decode from Type.string
|
||||
tdata := d.ldr.Data(gotype)
|
||||
if len(tdata) == 0 {
|
||||
d.linkctxt.Errorf(gotype, "missing type")
|
||||
|
|
|
|||
|
|
@ -707,6 +707,17 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
|
|||
// except go:buildid which is generated late and not used by the program.
|
||||
addRef("go:buildid")
|
||||
}
|
||||
if ctxt.IsAIX() {
|
||||
// On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol
|
||||
// does not work. See data.go:relocsym, case R_ADDR.
|
||||
// Here we record the unrelocated address in aixStaticDataBase (it is
|
||||
// unrelocated as it is in RODATA) so we can compute the delta at
|
||||
// run time.
|
||||
sb := ldr.CreateSymForUpdate("runtime.aixStaticDataBase", 0)
|
||||
sb.SetSize(0)
|
||||
sb.AddAddr(ctxt.Arch, ldr.Lookup("runtime.data", 0))
|
||||
sb.SetType(sym.SRODATA)
|
||||
}
|
||||
|
||||
// text section information
|
||||
slice(textsectionmapSym, uint64(nsections))
|
||||
|
|
|
|||
|
|
@ -2338,6 +2338,45 @@ var blockedLinknames = map[string][]string{
|
|||
"runtime.newcoro": {"iter"},
|
||||
// fips info
|
||||
"go:fipsinfo": {"crypto/internal/fips140/check"},
|
||||
// New internal linknames in Go 1.24
|
||||
// Pushed from runtime
|
||||
"crypto/internal/fips140.fatal": {"crypto/internal/fips140"},
|
||||
"crypto/internal/fips140.getIndicator": {"crypto/internal/fips140"},
|
||||
"crypto/internal/fips140.setIndicator": {"crypto/internal/fips140"},
|
||||
"crypto/internal/sysrand.fatal": {"crypto/internal/sysrand"},
|
||||
"crypto/rand.fatal": {"crypto/rand"},
|
||||
"internal/runtime/maps.errNilAssign": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.fatal": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.mapKeyError": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.newarray": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.newobject": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.typedmemclr": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.typedmemmove": {"internal/runtime/maps"},
|
||||
"internal/sync.fatal": {"internal/sync"},
|
||||
"internal/sync.runtime_canSpin": {"internal/sync"},
|
||||
"internal/sync.runtime_doSpin": {"internal/sync"},
|
||||
"internal/sync.runtime_nanotime": {"internal/sync"},
|
||||
"internal/sync.runtime_Semrelease": {"internal/sync"},
|
||||
"internal/sync.runtime_SemacquireMutex": {"internal/sync"},
|
||||
"internal/sync.throw": {"internal/sync"},
|
||||
"internal/synctest.Run": {"internal/synctest"},
|
||||
"internal/synctest.Wait": {"internal/synctest"},
|
||||
"internal/synctest.acquire": {"internal/synctest"},
|
||||
"internal/synctest.release": {"internal/synctest"},
|
||||
"internal/synctest.inBubble": {"internal/synctest"},
|
||||
"runtime.getStaticuint64s": {"reflect"},
|
||||
"sync.runtime_SemacquireWaitGroup": {"sync"},
|
||||
"time.runtimeNow": {"time"},
|
||||
"time.runtimeNano": {"time"},
|
||||
// Pushed to runtime from internal/runtime/maps
|
||||
// (other map functions are already linknamed in Go 1.23)
|
||||
"runtime.mapaccess1": {"runtime"},
|
||||
"runtime.mapaccess1_fast32": {"runtime"},
|
||||
"runtime.mapaccess1_fast64": {"runtime"},
|
||||
"runtime.mapaccess1_faststr": {"runtime"},
|
||||
"runtime.mapdelete_fast32": {"runtime"},
|
||||
"runtime.mapdelete_fast64": {"runtime"},
|
||||
"runtime.mapdelete_faststr": {"runtime"},
|
||||
}
|
||||
|
||||
// check if a linkname reference to symbol s from pkg is allowed
|
||||
|
|
|
|||
|
|
@ -1518,6 +1518,8 @@ func TestCheckLinkname(t *testing.T) {
|
|||
{"coro_asm", false},
|
||||
// pull-only linkname is not ok
|
||||
{"coro2.go", false},
|
||||
// pull linkname of a builtin symbol is not ok
|
||||
{"builtin.go", false},
|
||||
// legacy bad linkname is ok, for now
|
||||
{"fastrand.go", true},
|
||||
{"badlinkname.go", true},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
// Linkname builtin symbols (that is not already linknamed,
|
||||
// e.g. mapaccess1) is not allowed.
|
||||
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func main() {
|
||||
mapaccess1(nil, nil, nil)
|
||||
}
|
||||
|
||||
//go:linkname mapaccess1 runtime.mapaccess1
|
||||
func mapaccess1(t, m, k unsafe.Pointer) unsafe.Pointer
|
||||
|
|
@ -108,7 +108,7 @@ func TestVet(t *testing.T) {
|
|||
// is a no-op for files whose version >= go1.22, so we use a
|
||||
// go.mod file in the rangeloop directory to "downgrade".
|
||||
//
|
||||
// TOOD(adonovan): delete when go1.21 goes away.
|
||||
// TODO(adonovan): delete when go1.21 goes away.
|
||||
t.Run("loopclosure", func(t *testing.T) {
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "vet", "-vettool="+vetPath(t), ".")
|
||||
cmd.Env = append(os.Environ(), "GOWORK=off")
|
||||
|
|
|
|||
|
|
@ -10,23 +10,25 @@
|
|||
// calls to servers should accept a Context. The chain of function
|
||||
// calls between them must propagate the Context, optionally replacing
|
||||
// it with a derived Context created using [WithCancel], [WithDeadline],
|
||||
// [WithTimeout], or [WithValue]. When a Context is canceled, all
|
||||
// Contexts derived from it are also canceled.
|
||||
// [WithTimeout], or [WithValue].
|
||||
//
|
||||
// A Context may be canceled to indicate that work done on its behalf should stop.
|
||||
// A Context with a deadline is canceled after the deadline passes.
|
||||
// When a Context is canceled, all Contexts derived from it are also canceled.
|
||||
//
|
||||
// The [WithCancel], [WithDeadline], and [WithTimeout] functions take a
|
||||
// Context (the parent) and return a derived Context (the child) and a
|
||||
// [CancelFunc]. Calling the CancelFunc cancels the child and its
|
||||
// [CancelFunc]. Calling the CancelFunc directly cancels the child and its
|
||||
// children, removes the parent's reference to the child, and stops
|
||||
// any associated timers. Failing to call the CancelFunc leaks the
|
||||
// child and its children until the parent is canceled or the timer
|
||||
// fires. The go vet tool checks that CancelFuncs are used on all
|
||||
// control-flow paths.
|
||||
// child and its children until the parent is canceled. The go vet tool
|
||||
// checks that CancelFuncs are used on all control-flow paths.
|
||||
//
|
||||
// The [WithCancelCause] function returns a [CancelCauseFunc], which
|
||||
// takes an error and records it as the cancellation cause. Calling
|
||||
// [Cause] on the canceled context or any of its children retrieves
|
||||
// the cause. If no cause is specified, Cause(ctx) returns the same
|
||||
// value as ctx.Err().
|
||||
// The [WithCancelCause], [WithDeadlineCause], and [WithTimeoutCause] functions
|
||||
// return a [CancelCauseFunc], which takes an error and records it as
|
||||
// the cancellation cause. Calling [Cause] on the canceled context
|
||||
// or any of its children retrieves the cause. If no cause is specified,
|
||||
// Cause(ctx) returns the same value as ctx.Err().
|
||||
//
|
||||
// Programs that use Contexts should follow these rules to keep interfaces
|
||||
// consistent across packages and enable static analysis tools to check context
|
||||
|
|
@ -107,8 +109,8 @@ type Context interface {
|
|||
|
||||
// If Done is not yet closed, Err returns nil.
|
||||
// If Done is closed, Err returns a non-nil error explaining why:
|
||||
// Canceled if the context was canceled
|
||||
// or DeadlineExceeded if the context's deadline passed.
|
||||
// DeadlineExceeded if the context's deadline passed,
|
||||
// or Canceled if the context was canceled for some other reason.
|
||||
// After Err returns a non-nil error, successive calls to Err return the same error.
|
||||
Err() error
|
||||
|
||||
|
|
@ -160,11 +162,12 @@ type Context interface {
|
|||
Value(key any) any
|
||||
}
|
||||
|
||||
// Canceled is the error returned by [Context.Err] when the context is canceled.
|
||||
// Canceled is the error returned by [Context.Err] when the context is canceled
|
||||
// for some reason other than its deadline passing.
|
||||
var Canceled = errors.New("context canceled")
|
||||
|
||||
// DeadlineExceeded is the error returned by [Context.Err] when the context's
|
||||
// deadline passes.
|
||||
// DeadlineExceeded is the error returned by [Context.Err] when the context is canceled
|
||||
// due to its deadline passing.
|
||||
var DeadlineExceeded error = deadlineExceededError{}
|
||||
|
||||
type deadlineExceededError struct{}
|
||||
|
|
@ -296,9 +299,8 @@ func Cause(c Context) error {
|
|||
return c.Err()
|
||||
}
|
||||
|
||||
// AfterFunc arranges to call f in its own goroutine after ctx is done
|
||||
// (canceled or timed out).
|
||||
// If ctx is already done, AfterFunc calls f immediately in its own goroutine.
|
||||
// AfterFunc arranges to call f in its own goroutine after ctx is canceled.
|
||||
// If ctx is already canceled, AfterFunc calls f immediately in its own goroutine.
|
||||
//
|
||||
// Multiple calls to AfterFunc on a context operate independently;
|
||||
// one does not replace another.
|
||||
|
|
@ -306,7 +308,7 @@ func Cause(c Context) error {
|
|||
// Calling the returned stop function stops the association of ctx with f.
|
||||
// It returns true if the call stopped f from being run.
|
||||
// If stop returns false,
|
||||
// either the context is done and f has been started in its own goroutine;
|
||||
// either the context is canceled and f has been started in its own goroutine;
|
||||
// or f was already stopped.
|
||||
// The stop function does not wait for f to complete before returning.
|
||||
// If the caller needs to know whether f is completed,
|
||||
|
|
|
|||
|
|
@ -146,8 +146,8 @@ func ExampleAfterFunc_cond() {
|
|||
defer stopf()
|
||||
|
||||
// Since the wakeups are using Broadcast instead of Signal, this call to
|
||||
// Wait may unblock due to some other goroutine's context becoming done,
|
||||
// so to be sure that ctx is actually done we need to check it in a loop.
|
||||
// Wait may unblock due to some other goroutine's context being canceled,
|
||||
// so to be sure that ctx is actually canceled we need to check it in a loop.
|
||||
for !conditionMet() {
|
||||
cond.Wait()
|
||||
if ctx.Err() != nil {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
"bytes"
|
||||
"crypto/internal/fips140/aes"
|
||||
"crypto/internal/fips140/alias"
|
||||
"crypto/internal/fips140only"
|
||||
"crypto/subtle"
|
||||
)
|
||||
|
||||
|
|
@ -53,6 +54,9 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode {
|
|||
if b, ok := b.(*aes.Block); ok {
|
||||
return aes.NewCBCEncrypter(b, [16]byte(iv))
|
||||
}
|
||||
if fips140only.Enabled {
|
||||
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if cbc, ok := b.(cbcEncAble); ok {
|
||||
return cbc.NewCBCEncrypter(iv)
|
||||
}
|
||||
|
|
@ -129,6 +133,9 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode {
|
|||
if b, ok := b.(*aes.Block); ok {
|
||||
return aes.NewCBCDecrypter(b, [16]byte(iv))
|
||||
}
|
||||
if fips140only.Enabled {
|
||||
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if cbc, ok := b.(cbcDecAble); ok {
|
||||
return cbc.NewCBCDecrypter(iv)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"bytes"
|
||||
"crypto/internal/fips140/aes"
|
||||
"crypto/internal/fips140/alias"
|
||||
"crypto/internal/fips140only"
|
||||
"crypto/subtle"
|
||||
)
|
||||
|
||||
|
|
@ -41,6 +42,9 @@ func NewCTR(block Block, iv []byte) Stream {
|
|||
if block, ok := block.(*aes.Block); ok {
|
||||
return aesCtrWrapper{aes.NewCTR(block, iv)}
|
||||
}
|
||||
if fips140only.Enabled {
|
||||
panic("crypto/cipher: use of CTR with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if ctr, ok := block.(ctrAble); ok {
|
||||
return ctr.NewCTR(iv)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
|
||||
// defined in FIPS 186-5 and SEC 1, Version 2.0.
|
||||
// defined in [FIPS 186-5].
|
||||
//
|
||||
// Signatures generated by this package are not deterministic, but entropy is
|
||||
// mixed with the private key and the message, achieving the same level of
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
// Operations involving private keys are implemented using constant-time
|
||||
// algorithms, as long as an [elliptic.Curve] returned by [elliptic.P224],
|
||||
// [elliptic.P256], [elliptic.P384], or [elliptic.P521] is used.
|
||||
//
|
||||
// [FIPS 186-5]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
|
||||
package ecdsa
|
||||
|
||||
import (
|
||||
|
|
@ -183,7 +185,7 @@ func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
|||
}
|
||||
|
||||
func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) {
|
||||
if fips140only.Enabled && fips140only.ApprovedRandomReader(rand) {
|
||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
||||
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||
}
|
||||
privateKey, err := ecdsa.GenerateKey(c, rand)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func Enabled() bool {
|
|||
if currentlyEnabled != fips140.Enabled {
|
||||
panic("crypto/fips140: GODEBUG setting changed after program start")
|
||||
}
|
||||
if fips140.Enabled && !check.Enabled() {
|
||||
if fips140.Enabled && !check.Verified {
|
||||
panic("crypto/fips140: FIPS 140-3 mode enabled, but integrity check didn't pass")
|
||||
}
|
||||
return fips140.Enabled
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import "C"
|
|||
import (
|
||||
"crypto/internal/boring/sig"
|
||||
_ "crypto/internal/boring/syso"
|
||||
"crypto/internal/fips140"
|
||||
"internal/stringslite"
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
|
|
@ -31,6 +32,12 @@ func init() {
|
|||
sig.BoringCrypto()
|
||||
}
|
||||
|
||||
func init() {
|
||||
if fips140.Enabled {
|
||||
panic("boringcrypto: cannot use GODEBUG=fips140 with GOEXPERIMENT=boringcrypto")
|
||||
}
|
||||
}
|
||||
|
||||
// Unreachable marks code that should be unreachable
|
||||
// when BoringCrypto is in use. It panics.
|
||||
func Unreachable() {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ func SkipTestAllocations(t *testing.T) {
|
|||
t.Skip("skipping allocations test on plan9")
|
||||
}
|
||||
|
||||
// s390x deviates from other assembly implementations and is very hard to
|
||||
// test due to the lack of LUCI builders. See #67307.
|
||||
if runtime.GOARCH == "s390x" {
|
||||
t.Skip("skipping allocations test on s390x")
|
||||
}
|
||||
|
||||
// Some APIs rely on inliner and devirtualization to allocate on the stack.
|
||||
testenv.SkipIfOptimizationOff(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ func newBlockExpanded(c *blockExpanded, key []byte) {
|
|||
func (c *Block) BlockSize() int { return BlockSize }
|
||||
|
||||
func (c *Block) Encrypt(dst, src []byte) {
|
||||
// AES-ECB is not approved in FIPS 140-3 mode.
|
||||
fips140.RecordNonApproved()
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
|
|
@ -103,11 +105,12 @@ func (c *Block) Encrypt(dst, src []byte) {
|
|||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/aes: invalid buffer overlap")
|
||||
}
|
||||
fips140.RecordApproved()
|
||||
encryptBlock(c, dst, src)
|
||||
}
|
||||
|
||||
func (c *Block) Decrypt(dst, src []byte) {
|
||||
// AES-ECB is not approved in FIPS 140-3 mode.
|
||||
fips140.RecordNonApproved()
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
|
|
@ -117,6 +120,12 @@ func (c *Block) Decrypt(dst, src []byte) {
|
|||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/aes: invalid buffer overlap")
|
||||
}
|
||||
fips140.RecordApproved()
|
||||
decryptBlock(c, dst, src)
|
||||
}
|
||||
|
||||
// EncryptBlockInternal applies the AES encryption function to one block.
|
||||
//
|
||||
// It is an internal function meant only for the gcm package.
|
||||
func EncryptBlockInternal(c *Block, dst, src []byte) {
|
||||
encryptBlock(c, dst, src)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func cryptBlocksEncGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
|
|||
for len(src) > 0 {
|
||||
// Write the xor to dst, then encrypt in place.
|
||||
subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
|
||||
b.Encrypt(dst[:BlockSize], dst[:BlockSize])
|
||||
encryptBlock(b, dst[:BlockSize], dst[:BlockSize])
|
||||
|
||||
// Move to the next block with this block as the next iv.
|
||||
iv = dst[:BlockSize]
|
||||
|
|
@ -111,7 +111,7 @@ func cryptBlocksDecGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
|
|||
copy(civ[:], src[start:end])
|
||||
|
||||
for start >= 0 {
|
||||
b.Decrypt(dst[start:end], src[start:end])
|
||||
decryptBlock(b, dst[start:end], src[start:end])
|
||||
|
||||
if start > 0 {
|
||||
subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ func ctrBlocks(b *Block, dst, src []byte, ivlo, ivhi uint64) {
|
|||
byteorder.BEPutUint64(buf[i:], ivhi)
|
||||
byteorder.BEPutUint64(buf[i+8:], ivlo)
|
||||
ivlo, ivhi = add128(ivlo, ivhi, 1)
|
||||
b.Encrypt(buf[i:], buf[i:])
|
||||
encryptBlock(b, buf[i:], buf[i:])
|
||||
}
|
||||
// XOR into buf first, in case src and dst overlap (see above).
|
||||
subtle.XORBytes(buf, src, buf)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ func NewCMAC(b *aes.Block) *CMAC {
|
|||
}
|
||||
|
||||
func (c *CMAC) deriveSubkeys() {
|
||||
c.b.Encrypt(c.k1[:], c.k1[:])
|
||||
aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:])
|
||||
msb := shiftLeft(&c.k1)
|
||||
c.k1[len(c.k1)-1] ^= msb * 0b10000111
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
|||
// Special-cased as a single empty partial final block.
|
||||
x = c.k2
|
||||
x[len(m)] ^= 0b10000000
|
||||
c.b.Encrypt(x[:], x[:])
|
||||
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||
return x
|
||||
}
|
||||
for len(m) >= aes.BlockSize {
|
||||
|
|
@ -54,7 +54,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
|||
// Final complete block.
|
||||
subtle.XORBytes(x[:], c.k1[:], x[:])
|
||||
}
|
||||
c.b.Encrypt(x[:], x[:])
|
||||
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||
m = m[aes.BlockSize:]
|
||||
}
|
||||
if len(m) > 0 {
|
||||
|
|
@ -62,7 +62,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
|||
subtle.XORBytes(x[:], m, x[:])
|
||||
subtle.XORBytes(x[:], c.k2[:], x[:])
|
||||
x[len(m)] ^= 0b10000000
|
||||
c.b.Encrypt(x[:], x[:])
|
||||
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
|
|||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
||||
}
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
|
||||
var tagOut [gcmTagSize]byte
|
||||
gcmAesData(&g.productTable, data, &tagOut)
|
||||
|
|
@ -114,7 +114,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
|
|||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
||||
}
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
|
||||
var expectedTag [gcmTagSize]byte
|
||||
gcmAesData(&g.productTable, data, &expectedTag)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
|
||||
var H, counter, tagMask [gcmBlockSize]byte
|
||||
g.cipher.Encrypt(H[:], H[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
|
||||
deriveCounterGeneric(&H, &counter, nonce)
|
||||
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
|
|||
|
||||
func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
|
||||
var H, counter, tagMask [gcmBlockSize]byte
|
||||
g.cipher.Encrypt(H[:], H[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
|
||||
deriveCounterGeneric(&H, &counter, nonce)
|
||||
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
|
|||
var mask [gcmBlockSize]byte
|
||||
|
||||
for len(src) >= gcmBlockSize {
|
||||
b.Encrypt(mask[:], counter[:])
|
||||
aes.EncryptBlockInternal(b, mask[:], counter[:])
|
||||
gcmInc32(counter)
|
||||
|
||||
subtle.XORBytes(out, src, mask[:])
|
||||
|
|
@ -79,7 +79,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
|
|||
}
|
||||
|
||||
if len(src) > 0 {
|
||||
b.Encrypt(mask[:], counter[:])
|
||||
aes.EncryptBlockInternal(b, mask[:], counter[:])
|
||||
gcmInc32(counter)
|
||||
subtle.XORBytes(out, src, mask[:])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func initGCM(g *GCM) {
|
|||
}
|
||||
|
||||
hle := make([]byte, gcmBlockSize)
|
||||
g.cipher.Encrypt(hle, hle)
|
||||
aes.EncryptBlockInternal(&g.cipher, hle, hle)
|
||||
|
||||
// Reverse the bytes in each 8 byte chunk
|
||||
// Load little endian, store big endian
|
||||
|
|
@ -133,7 +133,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
|
|||
var counter, tagMask [gcmBlockSize]byte
|
||||
deriveCounter(&counter, nonce, &g.productTable)
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
gcmInc32(&counter)
|
||||
|
||||
counterCrypt(&g.cipher, out, plaintext, &counter)
|
||||
|
|
@ -151,7 +151,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
|
|||
var counter, tagMask [gcmBlockSize]byte
|
||||
deriveCounter(&counter, nonce, &g.productTable)
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
gcmInc32(&counter)
|
||||
|
||||
var expectedTag [gcmTagSize]byte
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func initGCM(g *GCM) {
|
|||
return
|
||||
}
|
||||
// Note that hashKey is also used in the KMA codepath to hash large nonces.
|
||||
g.cipher.Encrypt(g.hashKey[:], g.hashKey[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, g.hashKey[:], g.hashKey[:])
|
||||
}
|
||||
|
||||
// ghashAsm uses the GHASH algorithm to hash data with the given key. The initial
|
||||
|
|
@ -115,7 +115,7 @@ func counterCrypt(g *GCM, dst, src []byte, cnt *[gcmBlockSize]byte) {
|
|||
}
|
||||
if len(src) > 0 {
|
||||
var x [16]byte
|
||||
g.cipher.Encrypt(x[:], cnt[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, x[:], cnt[:])
|
||||
for i := range src {
|
||||
dst[i] = src[i] ^ x[i]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
//go:build asan
|
||||
|
||||
package check
|
||||
package fips140
|
||||
|
||||
const asanEnabled = true
|
||||
|
|
@ -134,6 +134,13 @@ func (x *Nat) set(y *Nat) *Nat {
|
|||
return x
|
||||
}
|
||||
|
||||
// Bits returns x as a little-endian slice of uint. The length of the slice
|
||||
// matches the announced length of x. The result and x share the same underlying
|
||||
// array.
|
||||
func (x *Nat) Bits() []uint {
|
||||
return x.limbs
|
||||
}
|
||||
|
||||
// Bytes returns x as a zero-extended big-endian byte slice. The size of the
|
||||
// slice will match the size of m.
|
||||
//
|
||||
|
|
@ -1058,6 +1065,34 @@ func (out *Nat) ExpShortVarTime(x *Nat, e uint, m *Modulus) *Nat {
|
|||
//
|
||||
//go:norace
|
||||
func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
u, A, err := extendedGCD(a, m.nat)
|
||||
if err != nil {
|
||||
return x, false
|
||||
}
|
||||
if u.IsOne() == no {
|
||||
return x, false
|
||||
}
|
||||
return x.set(A), true
|
||||
}
|
||||
|
||||
// GCDVarTime calculates x = GCD(a, b) where at least one of a or b is odd, and
|
||||
// both are non-zero. If GCDVarTime returns an error, x is not modified.
|
||||
//
|
||||
// The output will be resized to the size of the larger of a and b.
|
||||
func (x *Nat) GCDVarTime(a, b *Nat) (*Nat, error) {
|
||||
u, _, err := extendedGCD(a, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x.set(u), nil
|
||||
}
|
||||
|
||||
// extendedGCD computes u and A such that a = GCD(a, m) and u = A*a - B*m.
|
||||
//
|
||||
// u will have the size of the larger of a and m, and A will have the size of m.
|
||||
//
|
||||
// It is an error if either a or m is zero, or if they are both even.
|
||||
func extendedGCD(a, m *Nat) (u, A *Nat, err error) {
|
||||
// This is the extended binary GCD algorithm described in the Handbook of
|
||||
// Applied Cryptography, Algorithm 14.61, adapted by BoringSSL to bound
|
||||
// coefficients and avoid negative numbers. For more details and proof of
|
||||
|
|
@ -1068,7 +1103,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
|||
// 1. Negate [B] and [C] so they are positive. The invariant now involves a
|
||||
// subtraction.
|
||||
// 2. If step 2 (both [x] and [y] are even) runs, abort immediately. This
|
||||
// algorithm only cares about [x] and [y] relatively prime.
|
||||
// case needs to be handled by the caller.
|
||||
// 3. Subtract copies of [x] and [y] as needed in step 6 (both [u] and [v]
|
||||
// are odd) so coefficients stay in bounds.
|
||||
// 4. Replace the [u >= v] check with [u > v]. This changes the end
|
||||
|
|
@ -1082,21 +1117,21 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
|||
//
|
||||
// Note this algorithm does not handle either input being zero.
|
||||
|
||||
if a.IsZero() == yes {
|
||||
return x, false
|
||||
if a.IsZero() == yes || m.IsZero() == yes {
|
||||
return nil, nil, errors.New("extendedGCD: a or m is zero")
|
||||
}
|
||||
if a.IsOdd() == no && !m.odd {
|
||||
// a and m are not coprime, as they are both even.
|
||||
return x, false
|
||||
if a.IsOdd() == no && m.IsOdd() == no {
|
||||
return nil, nil, errors.New("extendedGCD: both a and m are even")
|
||||
}
|
||||
|
||||
u := NewNat().set(a).ExpandFor(m)
|
||||
v := m.Nat()
|
||||
size := max(len(a.limbs), len(m.limbs))
|
||||
u = NewNat().set(a).expand(size)
|
||||
v := NewNat().set(m).expand(size)
|
||||
|
||||
A := NewNat().reset(len(m.nat.limbs))
|
||||
A = NewNat().reset(len(m.limbs))
|
||||
A.limbs[0] = 1
|
||||
B := NewNat().reset(len(a.limbs))
|
||||
C := NewNat().reset(len(m.nat.limbs))
|
||||
C := NewNat().reset(len(m.limbs))
|
||||
D := NewNat().reset(len(a.limbs))
|
||||
D.limbs[0] = 1
|
||||
|
||||
|
|
@ -1119,11 +1154,11 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
|||
if u.IsOdd() == yes && v.IsOdd() == yes {
|
||||
if v.cmpGeq(u) == no {
|
||||
u.sub(v)
|
||||
A.Add(C, m)
|
||||
A.Add(C, &Modulus{nat: m})
|
||||
B.Add(D, &Modulus{nat: a})
|
||||
} else {
|
||||
v.sub(u)
|
||||
C.Add(A, m)
|
||||
C.Add(A, &Modulus{nat: m})
|
||||
D.Add(B, &Modulus{nat: a})
|
||||
}
|
||||
}
|
||||
|
|
@ -1137,7 +1172,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
|||
if u.IsOdd() == no {
|
||||
rshift1(u, 0)
|
||||
if A.IsOdd() == yes || B.IsOdd() == yes {
|
||||
rshift1(A, A.add(m.nat))
|
||||
rshift1(A, A.add(m))
|
||||
rshift1(B, B.add(a))
|
||||
} else {
|
||||
rshift1(A, 0)
|
||||
|
|
@ -1146,7 +1181,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
|||
} else { // v.IsOdd() == no
|
||||
rshift1(v, 0)
|
||||
if C.IsOdd() == yes || D.IsOdd() == yes {
|
||||
rshift1(C, C.add(m.nat))
|
||||
rshift1(C, C.add(m))
|
||||
rshift1(D, D.add(a))
|
||||
} else {
|
||||
rshift1(C, 0)
|
||||
|
|
@ -1155,10 +1190,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
|||
}
|
||||
|
||||
if v.IsZero() == yes {
|
||||
if u.IsOne() == no {
|
||||
return x, false
|
||||
}
|
||||
return x.set(A), true
|
||||
return u, A, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1177,3 +1209,20 @@ func rshift1(a *Nat, carry uint) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DivShortVarTime calculates x = x / y and returns the remainder.
|
||||
//
|
||||
// It panics if y is zero.
|
||||
//
|
||||
//go:norace
|
||||
func (x *Nat) DivShortVarTime(y uint) uint {
|
||||
if y == 0 {
|
||||
panic("bigmod: division by zero")
|
||||
}
|
||||
|
||||
var r uint
|
||||
for i := len(x.limbs) - 1; i >= 0; i-- {
|
||||
x.limbs[i], r = bits.Div(r, x.limbs[i], y)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
// Keep in sync with notboring.go and crypto/internal/boring/boring.go.
|
||||
//go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan && cgo
|
||||
|
||||
package fips140
|
||||
|
||||
const boringEnabled = true
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package check implements the FIPS-140 load-time code+data verification.
|
||||
// Package check implements the FIPS 140 load-time code+data verification.
|
||||
// Every FIPS package providing cryptographic functionality except hmac and sha256
|
||||
// must import crypto/internal/fips140/check, so that the verification happens
|
||||
// before initialization of package global variables.
|
||||
|
|
@ -13,37 +13,18 @@
|
|||
package check
|
||||
|
||||
import (
|
||||
"crypto/internal/fips140"
|
||||
"crypto/internal/fips140/hmac"
|
||||
"crypto/internal/fips140/sha256"
|
||||
"crypto/internal/fips140deps/byteorder"
|
||||
"crypto/internal/fips140deps/godebug"
|
||||
"io"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Enabled reports whether verification was enabled.
|
||||
// If Enabled returns true, then verification succeeded,
|
||||
// because if it failed the binary would have panicked at init time.
|
||||
func Enabled() bool {
|
||||
return enabled
|
||||
}
|
||||
|
||||
var enabled bool // set when verification is enabled
|
||||
var Verified bool // set when verification succeeds, for testing
|
||||
|
||||
// Supported reports whether the current GOOS/GOARCH is Supported at all.
|
||||
func Supported() bool {
|
||||
// See cmd/internal/obj/fips.go's EnableFIPS for commentary.
|
||||
switch {
|
||||
case runtime.GOARCH == "wasm",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "386",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "arm",
|
||||
runtime.GOOS == "aix":
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// Verified is set when verification succeeded. It can be expected to always be
|
||||
// true when [fips140.Enabled] is true, or init would have panicked.
|
||||
var Verified bool
|
||||
|
||||
// Linkinfo holds the go:fipsinfo symbol prepared by the linker.
|
||||
// See cmd/link/internal/ld/fips.go for details.
|
||||
|
|
@ -71,32 +52,12 @@ const fipsMagic = " Go fipsinfo \xff\x00"
|
|||
var zeroSum [32]byte
|
||||
|
||||
func init() {
|
||||
v := godebug.Value("#fips140")
|
||||
enabled = v != "" && v != "off"
|
||||
if !enabled {
|
||||
if !fips140.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
if asanEnabled {
|
||||
// ASAN disapproves of reading swaths of global memory below.
|
||||
// One option would be to expose runtime.asanunpoison through
|
||||
// crypto/internal/fips140deps and then call it to unpoison the range
|
||||
// before reading it, but it is unclear whether that would then cause
|
||||
// false negatives. For now, FIPS+ASAN doesn't need to work.
|
||||
// If this is made to work, also re-enable the test in check_test.go
|
||||
// and in cmd/dist/test.go.
|
||||
panic("fips140: cannot verify in asan mode")
|
||||
}
|
||||
|
||||
switch v {
|
||||
case "on", "only", "debug":
|
||||
// ok
|
||||
default:
|
||||
panic("fips140: unknown GODEBUG setting fips140=" + v)
|
||||
}
|
||||
|
||||
if !Supported() {
|
||||
panic("fips140: unavailable on " + runtime.GOOS + "-" + runtime.GOARCH)
|
||||
if err := fips140.Supported(); err != nil {
|
||||
panic("fips140: " + err.Error())
|
||||
}
|
||||
|
||||
if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum {
|
||||
|
|
@ -132,7 +93,14 @@ func init() {
|
|||
panic("fips140: verification mismatch")
|
||||
}
|
||||
|
||||
if v == "debug" {
|
||||
// "The temporary value(s) generated during the integrity test of the
|
||||
// module’s software or firmware shall [05.10] be zeroised from the module
|
||||
// upon completion of the integrity test"
|
||||
clear(sum)
|
||||
clear(nbuf[:])
|
||||
h.Reset()
|
||||
|
||||
if godebug.Value("#fips140") == "debug" {
|
||||
println("fips140: verified code+data")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import (
|
|||
|
||||
type PrivateKey struct {
|
||||
pub PublicKey
|
||||
d []byte // bigmod.(*Nat).Bytes output (fixed length)
|
||||
d []byte // bigmod.(*Nat).Bytes output (same length as the curve order)
|
||||
}
|
||||
|
||||
func (priv *PrivateKey) Bytes() []byte {
|
||||
|
|
@ -262,7 +262,7 @@ func randomPoint[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmo
|
|||
var testingOnlyRejectionSamplingLooped func()
|
||||
|
||||
// Signature is an ECDSA signature, where r and s are represented as big-endian
|
||||
// fixed-length byte slices.
|
||||
// byte slices of the same length as the curve order.
|
||||
type Signature struct {
|
||||
R, S []byte
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,15 +47,34 @@ func canUseKDSA(c curveID) (functionCode uint64, blockSize int, ok bool) {
|
|||
case p384:
|
||||
return 2, 48, true
|
||||
case p521:
|
||||
// Note that the block size doesn't match the field size for P-521.
|
||||
return 3, 80, true
|
||||
}
|
||||
return 0, 0, false // A mismatch
|
||||
}
|
||||
|
||||
func hashToBytes[P Point[P]](c *Curve[P], dst, hash []byte) {
|
||||
func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte {
|
||||
e := bigmod.NewNat()
|
||||
hashToNat(c, e, hash)
|
||||
copy(dst, e.Bytes(c.N))
|
||||
return e.Bytes(c.N)
|
||||
}
|
||||
|
||||
func appendBlock(p []byte, blocksize int, b []byte) []byte {
|
||||
if len(b) > blocksize {
|
||||
panic("ecdsa: internal error: appendBlock input larger than block")
|
||||
}
|
||||
padding := blocksize - len(b)
|
||||
p = append(p, make([]byte, padding)...)
|
||||
return append(p, b...)
|
||||
}
|
||||
|
||||
func trimBlock(p []byte, size int) ([]byte, error) {
|
||||
for _, b := range p[:len(p)-size] {
|
||||
if b != 0 {
|
||||
return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature")
|
||||
}
|
||||
}
|
||||
return p[len(p)-size:], nil
|
||||
}
|
||||
|
||||
func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
|
||||
|
|
@ -95,17 +114,27 @@ func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte
|
|||
|
||||
// Copy content into the parameter block. In the sign case,
|
||||
// we copy hashed message, private key and random number into
|
||||
// the parameter block.
|
||||
hashToBytes(c, params[2*blockSize:3*blockSize], hash)
|
||||
copy(params[3*blockSize+blockSize-len(priv.d):], priv.d)
|
||||
copy(params[4*blockSize:5*blockSize], k.Bytes(c.N))
|
||||
// the parameter block. We skip the signature slots.
|
||||
p := params[:2*blockSize]
|
||||
p = appendBlock(p, blockSize, hashToBytes(c, hash))
|
||||
p = appendBlock(p, blockSize, priv.d)
|
||||
p = appendBlock(p, blockSize, k.Bytes(c.N))
|
||||
// Convert verify function code into a sign function code by adding 8.
|
||||
// We also need to set the 'deterministic' bit in the function code, by
|
||||
// adding 128, in order to stop the instruction using its own random number
|
||||
// generator in addition to the random number we supply.
|
||||
switch kdsa(functionCode+136, ¶ms) {
|
||||
case 0: // success
|
||||
return &Signature{R: params[:blockSize], S: params[blockSize : 2*blockSize]}, nil
|
||||
elementSize := (c.N.BitLen() + 7) / 8
|
||||
r, err := trimBlock(params[:blockSize], elementSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := trimBlock(params[blockSize:2*blockSize], elementSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Signature{R: r, S: s}, nil
|
||||
case 1: // error
|
||||
return nil, errors.New("zero parameter")
|
||||
case 2: // retry
|
||||
|
|
@ -149,10 +178,12 @@ func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature
|
|||
// Copy content into the parameter block. In the verify case,
|
||||
// we copy signature (r), signature(s), hashed message, public key x component,
|
||||
// and public key y component into the parameter block.
|
||||
copy(params[0*blockSize+blockSize-len(r):], r)
|
||||
copy(params[1*blockSize+blockSize-len(s):], s)
|
||||
hashToBytes(c, params[2*blockSize:3*blockSize], hash)
|
||||
copy(params[3*blockSize:5*blockSize], pub.q[1:]) // strip 0x04 prefix
|
||||
p := params[:0]
|
||||
p = appendBlock(p, blockSize, r)
|
||||
p = appendBlock(p, blockSize, s)
|
||||
p = appendBlock(p, blockSize, hashToBytes(c, hash))
|
||||
p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2])
|
||||
p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:])
|
||||
if kdsa(functionCode, ¶ms) != 0 {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,64 @@
|
|||
|
||||
package fips140
|
||||
|
||||
import "crypto/internal/fips140deps/godebug"
|
||||
import (
|
||||
"crypto/internal/fips140deps/godebug"
|
||||
"errors"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var Enabled bool
|
||||
|
||||
var debug bool
|
||||
|
||||
func init() {
|
||||
switch godebug.Value("#fips140") {
|
||||
v := godebug.Value("#fips140")
|
||||
switch v {
|
||||
case "on", "only":
|
||||
Enabled = true
|
||||
case "debug":
|
||||
Enabled = true
|
||||
debug = true
|
||||
case "off", "":
|
||||
default:
|
||||
panic("fips140: unknown GODEBUG setting fips140=" + v)
|
||||
}
|
||||
}
|
||||
|
||||
// Supported returns an error if FIPS 140-3 mode can't be enabled.
|
||||
func Supported() error {
|
||||
// Keep this in sync with fipsSupported in cmd/dist/test.go.
|
||||
|
||||
// ASAN disapproves of reading swaths of global memory in fips140/check.
|
||||
// One option would be to expose runtime.asanunpoison through
|
||||
// crypto/internal/fips140deps and then call it to unpoison the range
|
||||
// before reading it, but it is unclear whether that would then cause
|
||||
// false negatives. For now, FIPS+ASAN doesn't need to work.
|
||||
if asanEnabled {
|
||||
return errors.New("FIPS 140-3 mode is incompatible with ASAN")
|
||||
}
|
||||
|
||||
// See EnableFIPS in cmd/internal/obj/fips.go for commentary.
|
||||
switch {
|
||||
case runtime.GOARCH == "wasm",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "386",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "arm",
|
||||
runtime.GOOS == "openbsd", // due to -fexecute-only, see #70880
|
||||
runtime.GOOS == "aix":
|
||||
return errors.New("FIPS 140-3 mode is not supported on " + runtime.GOOS + "-" + runtime.GOARCH)
|
||||
}
|
||||
|
||||
if boringEnabled {
|
||||
return errors.New("FIPS 140-3 mode is incompatible with GOEXPERIMENT=boringcrypto")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Name() string {
|
||||
return "Go Cryptographic Module"
|
||||
}
|
||||
|
||||
func Version() string {
|
||||
return "v1.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ func init() {
|
|||
dk := &DecapsulationKey768{}
|
||||
kemKeyGen(dk, d, z)
|
||||
ek := dk.EncapsulationKey()
|
||||
c, Ke := ek.EncapsulateInternal(m)
|
||||
Ke, c := ek.EncapsulateInternal(m)
|
||||
Kd, err := dk.Decapsulate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ func kemKeyGen1024(dk *DecapsulationKey1024, d, z *[32]byte) {
|
|||
// the first operational use (if not exported before the first use)."
|
||||
func kemPCT1024(dk *DecapsulationKey1024) error {
|
||||
ek := dk.EncapsulationKey()
|
||||
c, K := ek.Encapsulate()
|
||||
K, c := ek.Encapsulate()
|
||||
K1, err := dk.Decapsulate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -204,13 +204,13 @@ func kemPCT1024(dk *DecapsulationKey1024) error {
|
|||
// encapsulation key, drawing random bytes from a DRBG.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (ek *EncapsulationKey1024) Encapsulate() (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
var cc [CiphertextSize1024]byte
|
||||
return ek.encapsulate(&cc)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (sharedKey, ciphertext []byte) {
|
||||
var m [messageSize]byte
|
||||
drbg.Read(m[:])
|
||||
// Note that the modulus check (step 2 of the encapsulation key check from
|
||||
|
|
@ -221,7 +221,7 @@ func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (ciphe
|
|||
|
||||
// EncapsulateInternal is a derandomized version of Encapsulate, exclusively for
|
||||
// use in tests.
|
||||
func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) {
|
||||
cc := &[CiphertextSize1024]byte{}
|
||||
return kemEncaps1024(cc, ek, m)
|
||||
}
|
||||
|
|
@ -229,14 +229,14 @@ func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (ciphertext, sh
|
|||
// kemEncaps1024 generates a shared key and an associated ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17.
|
||||
func kemEncaps1024(cc *[CiphertextSize1024]byte, ek *EncapsulationKey1024, m *[messageSize]byte) (c, K []byte) {
|
||||
func kemEncaps1024(cc *[CiphertextSize1024]byte, ek *EncapsulationKey1024, m *[messageSize]byte) (K, c []byte) {
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(ek.h[:])
|
||||
G := g.Sum(nil)
|
||||
K, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
c = pkeEncrypt1024(cc, &ek.encryptionKey1024, m, r)
|
||||
return c, K
|
||||
return K, c
|
||||
}
|
||||
|
||||
// NewEncapsulationKey1024 parses an encapsulation key from its encoded form.
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ func kemKeyGen(dk *DecapsulationKey768, d, z *[32]byte) {
|
|||
// the first operational use (if not exported before the first use)."
|
||||
func kemPCT(dk *DecapsulationKey768) error {
|
||||
ek := dk.EncapsulationKey()
|
||||
c, K := ek.Encapsulate()
|
||||
K, c := ek.Encapsulate()
|
||||
K1, err := dk.Decapsulate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -261,13 +261,13 @@ func kemPCT(dk *DecapsulationKey768) error {
|
|||
// encapsulation key, drawing random bytes from a DRBG.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (ek *EncapsulationKey768) Encapsulate() (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey768) Encapsulate() (sharedKey, ciphertext []byte) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
var cc [CiphertextSize768]byte
|
||||
return ek.encapsulate(&cc)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (sharedKey, ciphertext []byte) {
|
||||
var m [messageSize]byte
|
||||
drbg.Read(m[:])
|
||||
// Note that the modulus check (step 2 of the encapsulation key check from
|
||||
|
|
@ -278,7 +278,7 @@ func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (ciphert
|
|||
|
||||
// EncapsulateInternal is a derandomized version of Encapsulate, exclusively for
|
||||
// use in tests.
|
||||
func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) {
|
||||
cc := &[CiphertextSize768]byte{}
|
||||
return kemEncaps(cc, ek, m)
|
||||
}
|
||||
|
|
@ -286,14 +286,14 @@ func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (ciphertext, sha
|
|||
// kemEncaps generates a shared key and an associated ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17.
|
||||
func kemEncaps(cc *[CiphertextSize768]byte, ek *EncapsulationKey768, m *[messageSize]byte) (c, K []byte) {
|
||||
func kemEncaps(cc *[CiphertextSize768]byte, ek *EncapsulationKey768, m *[messageSize]byte) (K, c []byte) {
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(ek.h[:])
|
||||
G := g.Sum(nil)
|
||||
K, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
c = pkeEncrypt(cc, &ek.encryptionKey, m, r)
|
||||
return c, K
|
||||
return K, c
|
||||
}
|
||||
|
||||
// NewEncapsulationKey768 parses an encapsulation key from its encoded form.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
//go:build !asan
|
||||
|
||||
package check
|
||||
package fips140
|
||||
|
||||
const asanEnabled = false
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2024 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 !(boringcrypto && linux && (amd64 || arm64) && !android && !msan && cgo)
|
||||
|
||||
package fips140
|
||||
|
||||
const boringEnabled = false
|
||||
|
|
@ -13,9 +13,9 @@ import (
|
|||
)
|
||||
|
||||
// GenerateKey generates a new RSA key pair of the given bit size.
|
||||
// bits must be at least 128.
|
||||
// bits must be at least 32.
|
||||
func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
|
||||
if bits < 128 {
|
||||
if bits < 32 {
|
||||
return nil, errors.New("rsa: key too small")
|
||||
}
|
||||
fips140.RecordApproved()
|
||||
|
|
@ -54,23 +54,42 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
|
|||
return nil, errors.New("rsa: internal error: modulus size incorrect")
|
||||
}
|
||||
|
||||
φ, err := bigmod.NewModulusProduct(P.Nat().SubOne(P).Bytes(P),
|
||||
Q.Nat().SubOne(Q).Bytes(Q))
|
||||
// d can be safely computed as e⁻¹ mod φ(N) where φ(N) = (p-1)(q-1), and
|
||||
// indeed that's what both the original RSA paper and the pre-FIPS
|
||||
// crypto/rsa implementation did.
|
||||
//
|
||||
// However, FIPS 186-5, A.1.1(3) requires computing it as e⁻¹ mod λ(N)
|
||||
// where λ(N) = lcm(p-1, q-1).
|
||||
//
|
||||
// This makes d smaller by 1.5 bits on average, which is irrelevant both
|
||||
// because we exclusively use the CRT for private operations and because
|
||||
// we use constant time windowed exponentiation. On the other hand, it
|
||||
// requires computing a GCD of two values that are not coprime, and then
|
||||
// a division, both complex variable-time operations.
|
||||
λ, err := totient(P, Q)
|
||||
if err == errDivisorTooLarge {
|
||||
// The divisor is too large, try again with different primes.
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e := bigmod.NewNat().SetUint(65537)
|
||||
d, ok := bigmod.NewNat().InverseVarTime(e, φ)
|
||||
d, ok := bigmod.NewNat().InverseVarTime(e, λ)
|
||||
if !ok {
|
||||
// This checks that GCD(e, (p-1)(q-1)) = 1, which is equivalent
|
||||
// This checks that GCD(e, lcm(p-1, q-1)) = 1, which is equivalent
|
||||
// to checking GCD(e, p-1) = 1 and GCD(e, q-1) = 1 separately in
|
||||
// FIPS 186-5, Appendix A.1.3, steps 4.5 and 5.6.
|
||||
//
|
||||
// We waste a prime by retrying the whole process, since 65537 is
|
||||
// probably only a factor of one of p-1 or q-1, but the probability
|
||||
// of this check failing is only 1/65537, so it doesn't matter.
|
||||
continue
|
||||
}
|
||||
|
||||
if e.ExpandFor(φ).Mul(d, φ).IsOne() == 0 {
|
||||
return nil, errors.New("rsa: internal error: e*d != 1 mod φ(N)")
|
||||
if e.ExpandFor(λ).Mul(d, λ).IsOne() == 0 {
|
||||
return nil, errors.New("rsa: internal error: e*d != 1 mod λ(N)")
|
||||
}
|
||||
|
||||
// FIPS 186-5, A.1.1(3) requires checking that d > 2^(nlen / 2).
|
||||
|
|
@ -90,11 +109,57 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// errDivisorTooLarge is returned by [totient] when gcd(p-1, q-1) is too large.
|
||||
var errDivisorTooLarge = errors.New("divisor too large")
|
||||
|
||||
// totient computes the Carmichael totient function λ(N) = lcm(p-1, q-1).
|
||||
func totient(p, q *bigmod.Modulus) (*bigmod.Modulus, error) {
|
||||
a, b := p.Nat().SubOne(p), q.Nat().SubOne(q)
|
||||
|
||||
// lcm(a, b) = a×b / gcd(a, b) = a × (b / gcd(a, b))
|
||||
|
||||
// Our GCD requires at least one of the numbers to be odd. For LCM we only
|
||||
// need to preserve the larger prime power of each prime factor, so we can
|
||||
// right-shift the number with the fewest trailing zeros until it's odd.
|
||||
// For odd a, b and m >= n, lcm(a×2ᵐ, b×2ⁿ) = lcm(a×2ᵐ, b).
|
||||
az, bz := a.TrailingZeroBitsVarTime(), b.TrailingZeroBitsVarTime()
|
||||
if az < bz {
|
||||
a = a.ShiftRightVarTime(az)
|
||||
} else {
|
||||
b = b.ShiftRightVarTime(bz)
|
||||
}
|
||||
|
||||
gcd, err := bigmod.NewNat().GCDVarTime(a, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gcd.IsOdd() == 0 {
|
||||
return nil, errors.New("rsa: internal error: gcd(a, b) is even")
|
||||
}
|
||||
|
||||
// To avoid implementing multiple-precision division, we just try again if
|
||||
// the divisor doesn't fit in a single word. This would have a chance of
|
||||
// 2⁻⁶⁴ on 64-bit platforms, and 2⁻³² on 32-bit platforms, but testing 2⁻⁶⁴
|
||||
// edge cases is impractical, and we'd rather not behave differently on
|
||||
// different platforms, so we reject divisors above 2³²-1.
|
||||
if gcd.BitLenVarTime() > 32 {
|
||||
return nil, errDivisorTooLarge
|
||||
}
|
||||
if gcd.IsZero() == 1 || gcd.Bits()[0] == 0 {
|
||||
return nil, errors.New("rsa: internal error: gcd(a, b) is zero")
|
||||
}
|
||||
if rem := b.DivShortVarTime(gcd.Bits()[0]); rem != 0 {
|
||||
return nil, errors.New("rsa: internal error: b is not divisible by gcd(a, b)")
|
||||
}
|
||||
|
||||
return bigmod.NewModulusProduct(a.Bytes(p), b.Bytes(q))
|
||||
}
|
||||
|
||||
// randomPrime returns a random prime number of the given bit size following
|
||||
// the process in FIPS 186-5, Appendix A.1.3.
|
||||
func randomPrime(rand io.Reader, bits int) ([]byte, error) {
|
||||
if bits < 64 {
|
||||
return nil, errors.New("rsa: prime size must be at least 32-bit")
|
||||
if bits < 16 {
|
||||
return nil, errors.New("rsa: prime size must be at least 16 bits")
|
||||
}
|
||||
|
||||
b := make([]byte, (bits+7)/8)
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ package rsa
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/internal/fips140/bigmod"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -83,8 +85,94 @@ func TestMillerRabin(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTotient(t *testing.T) {
|
||||
f, err := os.Open("testdata/gcd_lcm_tests.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var GCD, A, B, LCM string
|
||||
var lineNum int
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
lineNum++
|
||||
line := scanner.Text()
|
||||
if len(line) == 0 || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
k, v, _ := strings.Cut(line, " = ")
|
||||
switch k {
|
||||
case "GCD":
|
||||
GCD = v
|
||||
case "A":
|
||||
A = v
|
||||
case "B":
|
||||
B = v
|
||||
case "LCM":
|
||||
LCM = v
|
||||
|
||||
t.Run(fmt.Sprintf("line %d", lineNum), func(t *testing.T) {
|
||||
if A == "0" || B == "0" {
|
||||
t.Skip("skipping test with zero input")
|
||||
}
|
||||
if LCM == "1" {
|
||||
t.Skip("skipping test with LCM=1")
|
||||
}
|
||||
|
||||
p, _ := bigmod.NewModulus(addOne(decodeHex(t, A)))
|
||||
a, _ := bigmod.NewNat().SetBytes(decodeHex(t, A), p)
|
||||
q, _ := bigmod.NewModulus(addOne(decodeHex(t, B)))
|
||||
b, _ := bigmod.NewNat().SetBytes(decodeHex(t, B), q)
|
||||
|
||||
gcd, err := bigmod.NewNat().GCDVarTime(a, b)
|
||||
// GCD doesn't work if a and b are both even, but LCM handles it.
|
||||
if err == nil {
|
||||
if got := strings.TrimLeft(hex.EncodeToString(gcd.Bytes(p)), "0"); got != GCD {
|
||||
t.Fatalf("unexpected GCD: got %s, want %s", got, GCD)
|
||||
}
|
||||
}
|
||||
|
||||
lcm, err := totient(p, q)
|
||||
if oddDivisorLargerThan32Bits(decodeHex(t, GCD)) {
|
||||
if err != errDivisorTooLarge {
|
||||
t.Fatalf("expected divisor too large error, got %v", err)
|
||||
}
|
||||
t.Skip("GCD too large")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("failed to calculate totient: %v", err)
|
||||
}
|
||||
if got := strings.TrimLeft(hex.EncodeToString(lcm.Nat().Bytes(lcm)), "0"); got != LCM {
|
||||
t.Fatalf("unexpected LCM: got %s, want %s", got, LCM)
|
||||
}
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unknown key %q on line %d", k, lineNum)
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func oddDivisorLargerThan32Bits(b []byte) bool {
|
||||
x := new(big.Int).SetBytes(b)
|
||||
x.Rsh(x, x.TrailingZeroBits())
|
||||
return x.BitLen() > 32
|
||||
}
|
||||
|
||||
func addOne(b []byte) []byte {
|
||||
x := new(big.Int).SetBytes(b)
|
||||
x.Add(x, big.NewInt(1))
|
||||
return x.Bytes()
|
||||
}
|
||||
|
||||
func decodeHex(t *testing.T, s string) []byte {
|
||||
t.Helper()
|
||||
if len(s)%2 != 0 {
|
||||
s = "0" + s
|
||||
}
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decode hex %q: %v", s, err)
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ func checkPrivateKey(priv *PrivateKey) error {
|
|||
// Check that de ≡ 1 mod p-1, and de ≡ 1 mod q-1.
|
||||
//
|
||||
// This implies that e is coprime to each p-1 as e has a multiplicative
|
||||
// inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = exponent(ℤ/nℤ).
|
||||
// inverse. Therefore e is coprime to lcm(p-1,q-1) = λ(N).
|
||||
// It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 mod p. Thus a^de ≡ a
|
||||
// mod n for all a coprime to n, as required.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,279 @@
|
|||
# GCD tests.
|
||||
#
|
||||
# These test vectors satisfy gcd(A, B) = GCD and lcm(A, B) = LCM.
|
||||
|
||||
GCD = 0
|
||||
A = 0
|
||||
B = 0
|
||||
# Just to appease the syntax-checker.
|
||||
LCM = 0
|
||||
|
||||
GCD = 1
|
||||
A = 92ff140ac8a659b31dd904161f9213706a08a817ae845e522c3af0c9096699e059b47c8c2f16434b1c5766ebb384b79190f2b2a62c2378f45e116890e7bb407a
|
||||
B = 2f532c9e5902b0d68cd2ed69b2083bc226e8b04c549212c425a5287bb171c6a47fcb926c70cc0d34b8d6201c617aee66af865d31fdc8a2eeb986c19da8bb0897
|
||||
LCM = 1b2c97003e520b0bdd59d8c35a180b4aa36bce14211590435b990ad8f4c034ce3c77899581cb4ee1a022874203459b6d53859ab1d99ff755efa253fc0e5d8487bb000c13c566e8937f0fe90b95b68bc278610d4f232770b08d1f31bee55a03da47f2d0ebb9e7861c4f16cc22168b68593e9efcde00f54104b4c3e1a0b294d7f6
|
||||
|
||||
GCD = a
|
||||
A = faaffa431343074f5c5d6f5788500d7bc68b86eb37edf166f699b4d75b76dae2cb7c8f6eccae8f18f6d510ef72f0b9633d5740c0bebb934d3be796bd9a53808e
|
||||
B = 2f48ec5aa5511283c2935b15725d30f62244185573203b48c7eb135b2e6db5c115c9446ac78b020574665b06a75eb287e0dbeb5da7c193294699b4c2129d2ac4
|
||||
LCM = 4a15f305e9622aa19bd8f39e968bfc16d527a47f7a5219d7b02c242c77ef8b608a4a6141f643ca97cedf07c0f1f3e8879d2568b056718aa15c0756899a08ccbe0a658bae67face96fa110edb91757bfa4828e8ff7c5d71b204f36238b12dd26f17be8ba9771f7068d63e41d423671f898f054b1187605754bc5546f2b02c5ac
|
||||
|
||||
GCD = 16
|
||||
A = cf0b21bde98b41b479ac8071086687a6707e9efaacd4e5299668ce1be8b13290f27fd32ae68df87c292e8583a09d73ec8e8a04a65a487380dcd7dacca3b6e692
|
||||
B = 3be3f563f81d5ad5c1211db7eff430aa345e830ce07b4bde7d4d32dba3ac618d2034351e5435fd6c7f077971fb4a1e83a7396a74fdff7fce1267112851db2582
|
||||
LCM = 233a2188de2c017235024b182286f17562b2ee5ab9fdfe4efa2f61c4ff99fa44e1ead5bf6cde05bd7502ce78373c83e3f9dbab0c9bb8620a87c2640bce5d12c685af656df789bb3d0ba1edbaa98cf4f0166d422ab17aa6706f8132264d45b72827d6671a00a9186e723379e3a3bb7902d08865f357c74100059f83800241976
|
||||
|
||||
GCD = 1
|
||||
A = dd7b7597d7c1eb399b1cea9b3042c14bd6022d31b1d2642a8f82fc32de6eadaf012fbbf349eaec4922a8468740ca73c6090833d6a69a380ed947b39c2f9b0b76
|
||||
B = 8e0dc8654e70eec55496038a8d3fff3c2086bc6dbfc0e2dbdf5bd7de03c5aef01a3982556ac3fc34fd5f13368be6cdc252c82367b7462e210f940f847d382dd9
|
||||
LCM = 7ae667df4bd4dd35bbec28719a9f1b5e1f396a9ab386c086742a6ab3014a3386d39f35b50624d0c5b4e6b206c2635c7de5ea69e2faa85dd616a7e36622962a07632839857aa49332942feccff2aee1c962e2f4e8ccfd738a5da5bf528b4c5a2440409350f5a17a39d234403e8482ccf838e0d2758ccfb8018198a51dbb407506
|
||||
|
||||
GCD = 1
|
||||
A = 0
|
||||
B = 1
|
||||
LCM = 0
|
||||
|
||||
GCD = 1
|
||||
A = 1
|
||||
B = 0
|
||||
LCM = 0
|
||||
|
||||
GCD = 1
|
||||
A = 1
|
||||
B = 1
|
||||
LCM = 1
|
||||
|
||||
GCD = 2b2
|
||||
A = dfccaa3549c1b59ab3e114fe87dc5d187719abad58c51724e972741eb895ab79a49f385f61d531ec5c88dbb505ae375093fa848165f71a5ed65e7832a42ade191a
|
||||
B = fa58a81f43088da45e659fc1117d0f1cd015aa096c8e5377cf1832191baf7cc28b5c24998b93b64f8900a0973faedb9babaaf1854345f011739da8f1175d9684c
|
||||
LCM = 5132f7ab7a982b9dc55114bd96800b7637f9742cf8a7a00a0d69d5e4574fc85792c89a1c52bcfc74b9d7f3f6164819466c46b2d622e280ced7ad1211604084a15dc1fd1951a05c8ce37122c0ec15891d818a70d3763670ea3195098de9b1ca50ea89893a9753fb9ea801541058f44801f7f50967124abfc864a2b01c41f94193c
|
||||
|
||||
GCD = 8e
|
||||
A = 248d96a8a4cab0a1b194e08c1146868b094597cadbc35531f0ed2d77cba9f15cb5cc7c10e64ce054bf93396d25259d750b3de3aba65073db1fd2b852a6454ac1a
|
||||
B = 4c7bad8e1844901fd6a2ce2edc82e698d28ec95d6672ca148d85b49ecc78dd0a8b870e202244210bc98592b99ff6abbd20630f9eee7d46b15ccfae8d08b86799de
|
||||
LCM = 13b01f9d9c6c13e90c97e3d95bbce5a835c631b3de3bd4ff5df13ad850f5223dbdf71c53912275d0397df9335ef3a3ba8e4684c6b25962bb7b18bc74144cb5edf0196f79863a7ff032619a71646a92281f7baace7f223d254cb4d05ec19bf8d4c8ce4455a9d770daec89c0d3cf338cbdae39cf982b3c4568f5c9def4e1133d28a
|
||||
|
||||
GCD = 3e55
|
||||
A = 2fa97382f46676b7a4cc2b8153f17b58792d24660e187d33ce55c81cc193ccb6e1e2b89feea1d5fd8faa36e13bf947fb48635e450a4d1488d0978324194a1f43c6
|
||||
B = ab08ad074139963bc18e5d87ba68db64ca6f4c279616c64039b02c55f2375b3bc04114e8e05e1ba92fb6470768f61d123845aea36774c18612736a220934561faf
|
||||
LCM = 82c7c377ecda2cb9228604cd287df5eff94edd4a539c3eb3b3fdd4b4a79d2f4eaf2b22f8286272d3dad2e370cfcd9ea4d93ebb3f049c52b8fa23b68a5bf79af989822e2cfb978f68c6a5058f47319dffcb455b089b06ae6db9e5c8a2b6e951d6e118bd2b4cd08b6e5733476a446a57387d940d1289ec00e24315821ed3a5daf2
|
||||
|
||||
GCD = a7a
|
||||
A = 923706dfed67834a1e7e6c8e8e9f93bfbc0b43ca1f324886cf1f1380fb9b77109275d4b50af1b7689802fe9b3623ac46c7ba0e17e908c20278127b07a5c12d86ec
|
||||
B = 64473e878a29021fac1c1ce34a63eae1f4f83ee6851333b67213278b9a4a16f005cba0e8cdb410035bb580062f0e486c1a3a01f4a4edf782495f1dc3ebfa837d86
|
||||
LCM = 57785ca45b8873032f1709331436995525eed815c55140582ce57fd852116835deac7ca9d95ce9f280e246ea4d4f1b7140ab7e0dd6dc869de87f1b27372098b155ad0a1828fd387dff514acc92eae708609285edaab900583a786caf95153f71e6e6092c8c5ee727346567e6f58d60a5e01c2fa8ebcf86da9ea46876ecc58e914
|
||||
|
||||
GCD = 42
|
||||
A = 0
|
||||
B = 42
|
||||
LCM = 0
|
||||
|
||||
GCD = 42
|
||||
A = 42
|
||||
B = 0
|
||||
LCM = 0
|
||||
|
||||
GCD = 42
|
||||
A = 42
|
||||
B = 42
|
||||
LCM = 42
|
||||
|
||||
GCD = f60d
|
||||
A = ef7886c3391407529d5cf2e75ed53e5c3f74439ad2e2dc48a79bc1a5322789b4ced2914b97f8ff4b9910d212243b54001eb8b375365b9a87bd022dd3772c78a9fd63
|
||||
B = d1d3ec32fa3103911830d4ec9f629c5f75af7039e307e05bc2977d01446cd2cbeeb8a8435b2170cf4d9197d83948c7b8999d901fe47d3ce7e4d30dc1b2de8af0c6e4
|
||||
LCM = cc376ed2dc362c38a45a719b2ed48201dab3e5506e3f1314e57af229dc7f3a6a0dad3d21cfb148c23a0bbb0092d667051aa0b35cff5b5cc61a7c52dec4ed72f6783edf181b3bf0500b79f87bb95abc66e4055f259791e4e5eb897d82de0e128ecf8a091119475351d65b7f320272db190898a02d33f45f03e27c36cb1c45208037dc
|
||||
|
||||
GCD = 9370
|
||||
A = 1ee02fb1c02100d1937f9749f628c65384ff822e638fdb0f42e27b10ee36e380564d6e861fcad0518f4da0f8636c1b9f5124c0bc2beb3ca891004a14cd7b118ddfe0
|
||||
B = 67432fd1482d19c4a1c2a4997eab5dbf9c5421977d1de60b739af94c41a5ad384cd339ebfaa43e5ad6441d5b9aaed5a9f7485025f4b4d5014e1e406d5bd838a44e50
|
||||
LCM = 159ff177bdb0ffbd09e2aa7d86de266c5de910c12a48cbe61f6fa446f63a2151194777555cd59903d24cb30965973571fb1f89c26f2b760526f73ded7ee8a34ebcecd1a3374a7559bcdb9ac6e78be17a62b830d6bb3982afdf10cf83d61fd0d588eab17d6abef8e6a7a5763fcb766d9a4d86adf5bb904f2dd6b528b9faec603987a0
|
||||
|
||||
GCD = c5f
|
||||
A = 5a3a2088b5c759420ed0fb9c4c7685da3725b659c132a710ef01e79435e63d009d2931ea0a9ed9432f3d6b8851730c323efb9db686486614332c6e6ba54d597cf98
|
||||
B = 1b1eb33b006a98178bb35bbcf09c5bebd92d9ace79fa34c1567efa8d6cf6361547807cd3f8e7b8cd3ddb6209dccbae4b4c16c8c1ec19741a3a57f61571882b7aed7
|
||||
LCM = c5cbbbe9532d30d2a7dd7c1c8a6e69fd4fa4828a844d6afb44f3747fef584f7f1f3b835b006f8747d84f7699e88f6267b634e7aef78d6c7584829537d79514eec7d11219721f91015f5cefdc296261d85dba388729438991a8027de4827cd9eb575622e2912b28c9ce26d441e97880d18db025812cef5de01adeaec1322a9c9858
|
||||
|
||||
GCD = e052
|
||||
A = 67429f79b2ec3847cfc7e662880ab1d94acdf04284260fcfffd67c2862d59704ed45bcc53700c88a5eea023bc09029e9fd114fc94c227fd47a1faa1a5ef117b09bd2
|
||||
B = 39faa7cbdeb78f9028c1d50ab34fbe6924c83a1262596f6b85865d4e19cc258b3c3af1ee2898e39e5bee5839e92eac6753bbbb0253bd576d1839a59748b778846a86
|
||||
LCM = 1ab071fb733ef142e94def10b26d69982128561669e58b20b80d39cf7c2759d26b4a65d73b7f940c6e8fc417180ef62d7e52ac24678137bd927cd8d004ad52b02affe176a1ecde903dbc26dcc705678f76dd8cd874c0c3fe737474309767507bbe70dd7fb671bbb3694cedf0dcdaa0c716250ddd6dfec525261572fa3e1387f7b906
|
||||
|
||||
GCD = 3523
|
||||
A = 0
|
||||
B = 3523
|
||||
LCM = 0
|
||||
|
||||
GCD = 3523
|
||||
A = 3523
|
||||
B = 0
|
||||
LCM = 0
|
||||
|
||||
GCD = 3523
|
||||
A = 3523
|
||||
B = 3523
|
||||
LCM = 3523
|
||||
|
||||
GCD = f035a941
|
||||
A = 16cd5745464dfc426726359312398f3c4486ed8aaeea6386a67598b10f744f336c89cdafcb18e643d55c3a62f4ab2c658a0d19ea3967ea1af3aee22e11f12c6df6e886f7
|
||||
B = 74df09f309541d26b4b39e0c01152b8ad05ad2dfe9dd2b6706240e9d9f0c530bfb9e4b1cad3d4a94342aab309e66dd42d9df01b47a45173b507e41826f24eb1e8bcc4459
|
||||
LCM = b181771d0e9d6b36fdfcbf01d349c7de6b7e305e1485ea2aa32938aa919a3eee9811e1c3c649068a7572f5d251b424308da31400d81ac4078463f9f71d7efd2e681f92b13a6ab3ca5c9063032dcbdf3d3a9940ce65e54786463bbc06544e1280f25bc7579d264f6f1590cf09d1badbf542ce435a14ab04d25d88ddbac7d22e8cae1c91f
|
||||
|
||||
GCD = 33ad1b8f
|
||||
A = 1af010429a74e1b612c2fc4d7127436f2a5dafda99015ad15385783bd3af8d81798a57d85038bcf09a2a9e99df713b4d6fc1e3926910fbbf1f006133cb27dc5ebb9cca85
|
||||
B = 92a4f45a90965a4ef454f1cdd883d20f0f3be34d43588b5914677c39d577a052d1b25a522be1a656860a540970f99cbc8a3adf3e2139770f664b4b7b9379e13daf7d26c
|
||||
LCM = 4c715520ed920718c3b2f62821bc75e3ff9fd184f76c60faf2906ef68d28cd540d3d6c071fa8704edd519709c3b09dfaee12cb02ab01ad0f3af4f5923d5705ce6d18bcab705a97e21896bb5dd8acb36ee8ec98c254a4ddc744297827a33c241f09016a5f109248c83dd41e4cea73ce3eabb28d76678b7e15545b96d22da83c111b6b624
|
||||
|
||||
GCD = dc0429aa
|
||||
A = ccb423cfb78d7150201a97114b6644e8e0bbbb33cadb0ef5da5d3c521a244ec96e6d1538c64c10c85b2089bdd702d74c505adce9235aa4195068c9077217c0d431de7f96
|
||||
B = 710786f3d9022fc3acbf47ac901f62debcfda684a39234644bac630ab2d211111df71c0844b02c969fc5b4c5a15b785c96efd1e403514235dc9356f7faf75a0888de5e5a
|
||||
LCM = 6929af911850c55450e2f2c4c9a72adf284fe271cf26e41c66e1a2ee19e30d928ae824f13d4e2a6d7bb12d10411573e04011725d3b6089c28d87738749107d990162b485805f5eedc8f788345bcbb5963641f73c303b2d92f80529902d3c2d7899623958499c8a9133aae49a616c96a2c5482a37947f23af18c3247203ac2d0e760340e6
|
||||
|
||||
GCD = 743166058
|
||||
A = 16cd476e8031d4624716238a3f85badd97f274cdfd9d53e0bd74de2a6c46d1827cc83057f3889588b6b7ca0640e7d743ed4a6eaf6f9b8df130011ecc72f56ef0af79680
|
||||
B = 86eba1fc8d761f22e0f596a03fcb6fe53ad15a03f5b4e37999f60b20966f78ba3280f02d3853f9ace40438ccfaf8faed7ace2f2bf089b2cdd4713f3f293bf602666c39f8
|
||||
LCM = 1a7a1b38727324d6ba0290f259b8e2b89c339b2445cada38a5a00ded1468ab069f40678ce76f7f78c7c6f97783cc8a49ef7e2a0c73abbac3abc66d1ce99566ce7f874a8949ca3442051e71967695dc65361184748c1908e1b587dc02ed899a524b34eb30b6f8db302432cfa1a8fbf2c46591e0ab3db7fd32c01b1f86c39832ee9f0c80
|
||||
|
||||
GCD = 6612ba2c
|
||||
A = 0
|
||||
B = 6612ba2c
|
||||
LCM = 0
|
||||
|
||||
GCD = 6612ba2c
|
||||
A = 6612ba2c
|
||||
B = 0
|
||||
LCM = 0
|
||||
|
||||
GCD = 6612ba2c
|
||||
A = 6612ba2c
|
||||
B = 6612ba2c
|
||||
LCM = 6612ba2c
|
||||
|
||||
GCD = 2272525aa08ccb20
|
||||
A = 11b9e23001e7446f6483fc9977140d91c3d82568dabb1f043a5620544fc3dda233b51009274cdb004fdff3f5c4267d34181d543d913553b6bdb11ce2a9392365fec8f9a3797e1200
|
||||
B = 11295529342bfb795f0611d03afb873c70bd16322b2cf9483f357f723b5b19f796a6206cf3ae3982daaeafcd9a68f0ce3355a7eba3fe4e743683709a2dd4b2ff46158bd99ff4d5a0
|
||||
LCM = 8d4cbf00d02f6adbaa70484bcd42ea932000843dcb667c69b75142426255f79b6c3b6bf22572597100c06c3277e40bf60c14c1f4a6822d86167812038cf1eefec2b0b19981ad99ad3125ff4a455a4a8344cbc609e1b3a173533db432bd717c72be25e05ed488d3970e7ed17a46353c5e0d91c8428d2fec7a93210759589df042cab028f545e3a00
|
||||
|
||||
GCD = 3480bf145713d56f9
|
||||
A = 8cf8ef1d4f216c6bcec673208fd93b7561b0eb8303af57113edc5c6ff4e1eeae9ddc3112b943d947653ba2179b7f63505465126d88ad0a0a15b682f5c89aa4a2a51c768cd9fdeaa9
|
||||
B = a6fd114023e7d79017c552a9051ca827f3ffa9f31e2ee9d78f8408967064fcdc9466e95cc8fac9a4fa88248987caf7cf57af58400d27abd60d9b79d2fe03fad76b879eceb504d7f
|
||||
LCM = 1c05eee73a4f0db210a9007f94a5af88c1cdd2cba456061fd41de1e746d836fa4e0e972812842e0f44f10a61505f5d55760c48ba0d06af78bb6bde7da8b0080b29f82b1161e9c0b5458e05ac090b00f4d78b1cc10cf065124ba610e3acab092a36fe408525e21c0ddc7c9696ed4e48bd2f70423deecfe62cecc865c6088f265da0e5961d3f3a84f
|
||||
|
||||
GCD = 917e74ae941fcaae
|
||||
A = 652f8a92d96cbf0a309629011d0fbaceb1266bc2e8243d9e494eead4cf7100c661b537a8bea93dec88cfc68597d88a976c125c3b4de19aba38d4ea9578202e59848d42652518348a
|
||||
B = 32e07b71979d57e8344e97c39680a61e07d692d824ae26b682156890792d8a766ee29a4968f461aaced5bf049044fba2f4120b1c1f05985676f975d4582e9e82750d73c532cd07b2
|
||||
LCM = 23620c7b897dc26c7717e32f3517ac70bf09fbe08f7255ab010cf4cf946f4e96304c425043452c5d5a0e841d3a3cfd9c2d84d9256f3b5974fe3ebfa9255fe20a710d3e6511606c0d85970381101c7f4986d65ad6a73a71507f146b11f903043cfa805cc0b14d4f3072da98bf22282f7762040406c02d5b3ef9e7587f63bab8b29c61d8e30911aa96
|
||||
|
||||
GCD = 2b9adc82005b2697
|
||||
A = 19764a84f46045ef1bca571d3cbf49b4545998e64d2e564cc343a53bc7a0bcfbe0baa5383f2b346e224eb9ce1137d9a4f79e8e19f946a493ff08c9b423574d56cbe053155177c37
|
||||
B = 1bbd489ad2ab825885cdac571a95ab4924e7446ce06c0f77cf29666a1e20ed5d9bc65e4102e11131d824acad1592075e13024e11f12f8210d86ab52aa60deb250b3930aabd960e5a
|
||||
LCM = 1032a0c5fffc0425e6478185db0e5985c645dd929c7ebfeb5c1ee12ee3d7b842cfab8c9aa7ff3131ac41d4988fb928c0073103cea6bb2cc39808f1b0ad79a6d080eac5a0fc6e3853d43f903729549e03dba0a4405500e0096b9c8e00510c1852982baec441ed94efb80a78ed28ed526d055ad34751b831b8749b7c19728bf229357cc5e17eb8e1a
|
||||
|
||||
GCD = 8d9d4f30773c4edf
|
||||
A = 0
|
||||
B = 8d9d4f30773c4edf
|
||||
LCM = 0
|
||||
|
||||
GCD = 8d9d4f30773c4edf
|
||||
A = 8d9d4f30773c4edf
|
||||
B = 0
|
||||
LCM = 0
|
||||
|
||||
GCD = 8d9d4f30773c4edf
|
||||
A = 8d9d4f30773c4edf
|
||||
B = 8d9d4f30773c4edf
|
||||
LCM = 8d9d4f30773c4edf
|
||||
|
||||
GCD = 6ebd8eafb9a957a6c3d3d5016be604f9624b0debf04d19cdabccf3612bbd59e00
|
||||
A = 34dc66a0ffd5b8b5e0ffc858dfc4655753e59247c4f82a4d2543b1f7bb7be0e24d2bbf27bb0b2b7e56ee22b29bbde7baf0d7bfb96331e27ba029de9ffdff7bdb7dc4da836d0e58a0829367ec84ea256833fd4fe1456ad4dd920557a345e12000
|
||||
B = 1f3406a20e20ebf96ccb765f898889a19b7636608fd7dc7c212607b641399543f71111d60e42989de01eaa6ff19a86ea8fbde1a3d368c0d86dc899e8e250fc764090f337958ca493119cbb4ad70cbfae7097d06d4f90ec62fbdd3f0a4496e600
|
||||
LCM = ee502c50e3667946e9089d0a9a0382e7fd0b75a17db23b56a0eec997a112c4dbd56d188808f76fe90451e5605550c9559ef14a95014c6eb97e9c1c659b98515c41470142843de60f72fb4c235faa55b0a97d943221003d44e2c28928f0b84bf071256254897ed31a7fd8d174fc962bc1311f67900ac3abcad83a28e259812f1ee229511ab1d82d41f5add34693ba7519babd52eb4ec9de31581f5f2e40a000
|
||||
|
||||
GCD = ef7399b217fc6a62b90461e58a44b22e5280d480b148ec4e3b4d106583f8e428
|
||||
A = 7025e2fe5f00aec73d90f5ad80d99ca873f71997d58e59937423a5e6ddeb5e1925ed2fd2c36a5a9fc560c9023d6332c5d8a4b333d3315ed419d60b2f98ccf28bbf5bf539284fd070d2690aeaac747a3d6384ee6450903a64c3017de33c969c98
|
||||
B = df0ac41dbabce1deeb0bceb1b65b1079850052ecf6534d0cff84a5a7fb5e63baee028d240f4419925154b96eaa69e8fbb1aae5102db7916234f290aa60c5d7e69406f02aeea9fe9384afbff7d878c9ac87cd31f7c35dff243b1441e09baff478
|
||||
LCM = 687669343f5208a6b2bb2e2efcac41ec467a438fde288cc5ef7157d130139ba65db9eb53e86a30c870bd769c0e0ab15a50f656cd9626621ae68d85eaff491b98da3ea5812062e4145af11ea5e1da457084911961ef2cd2ac45715f885ba94b4082aa76ffd1f32461f47c845b229d350bf36514c5ce3a7c782418746be342eca2721346ade73a59475f178c4f2448e1326110f5d26a0fef1a7a0c9288489e4dc8
|
||||
|
||||
GCD = 84b917557acf24dff70cb282a07fc52548b6fbbe96ca8c46d0397c8e44d30573
|
||||
A = 81dbb771713342b33912b03f08649fb2506874b96125a1ac712bc94bfd09b679db7327a824f0a5837046f58af3a8365c89e06ff4d48784f60086a99816e0065a5f6f0f49066b0ff4c972a6b837b63373ca4bb04dcc21e5effb6dfe38271cb0fa
|
||||
B = 1da91553c0a2217442f1c502a437bb14d8c385aa595db47b23a97b53927b4493dd19f1bc8baf145bc10052394243089a7b88d19b6f106e64a5ab34acad94538ab504d1c8ebf22ac42048bbd1d4b0294a2e12c09fe2a3bd92756ba7578cb34b39
|
||||
LCM = 1d0530f8142754d1ee0249b0c3968d0ae7570e37dadbe4824ab966d655abf04cd6de5eb700eba89d8352dec3ae51f2a10267c32fbd39b788c7c5047fe69da3d7ad505435a6212f44899ba7e983bb780f62bcdee6f94b7dba8af7070a4cc008f351ae8be4579bc4a2e5c659ce000ad9c8cdc83723b32c96aeb0f5f4127f6347353d05525f559a8543cd389ad0af6f9d08a75b8c0b32419c097e6efe8746aee92e
|
||||
|
||||
GCD = 66091477ea3b37f115038095814605896e845b20259a772f09405a8818f644aa
|
||||
A = cedac27069a68edfd49bd5a859173c8e318ba8be65673d9d2ba13c717568754ed9cbc10bb6c32da3b7238cff8c1352d6325668fd21b4e82620c2e75ee0c4b1aff6fb1e9b948bbdb1af83cecdf356299b50543b72f801b6a58444b176e4369e0
|
||||
B = 5f64ca1ba481f42c4c9cf1ffa0e515b52aa9d69ceb97c4a2897f2e9fa87f72bae56ee6c5227f354304994c6a5cc742d9f09b2c058521975f69ca5835bce898cf22b28457cd7e28870df14e663bb46c9be8f6662f4ff34d5c4ae17a888eba504e
|
||||
LCM = c163cb28642e19a40aa77887c63180c2c49fc10cda98f6f929c8131752ea30b5283a814a81681b69b9d1762e6c1a9db85f480bc17f998d235fd7e64c1caa70ef170c9e816d3e80f516b29f2c80cfb68bf208b4d5082ef078da4314b3f20c7d6c54b0aeb378096b029a7b61c0a4cd14aeddc01004c53915a4f692d2291752e5af46b23d7fa6dd61f2d56c6f4bf8e6119688abac8fd7aba80e846a7764bb3fca0
|
||||
|
||||
GCD = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
A = 0
|
||||
B = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
LCM = 0
|
||||
|
||||
GCD = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
A = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
B = 0
|
||||
LCM = 0
|
||||
|
||||
GCD = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
A = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
B = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
LCM = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182
|
||||
|
||||
GCD = 120451d8307219aa0c96f328ad653ccd462e92423ca93ed8a3dde45bf5cb9b13cdaf9800e4d05dd71c4db6a129fb3280ee4ec96ec5297d881c1a8b5efccbd91fef21f5c5bf5fba42a4c8eaa358f620a074b7a17054527bdaa58d5acaa0dfdc48ecba1a10ebf4d57bb4215de406e6be13fed3fe493b1cd1e2d11a8d4ac03c47756
|
||||
A = 3f8179a8e1f0b342475a855c3e1bae402dd41424cf24a0b4d2e263c8efb08bde7d92eae8607fb5e88b1378f0f1bd0733f229a35be6b1383a48d32749d5d6b32427d26323b7ab05bb5781289e96bfbc21971439319b15f6c0fe93fdb35d0b67ec41443c59a081dd3cef047ac797fccb45bece84c0bb0bb7e1797259526d8ec9cc63ba4d32cfc692ccd3d243cb2b53ac216312f3a8e8c0daa09d21b6150d697639a5e52059414a417c607be8ec0eee2e708219cadbaf37a369c4485b01ed87bbc2
|
||||
B = 2c474e396a2dd9cd10b9d7313f69d3b4ca123e9fd853edd488339236d14c56453a1381958864a04d2624e81995dabcdd0ccf60db9917813f887de68da075d0ea4440001e18f470e43b38ee3440b49be651d709fbdef980e3e4149913f4ae2681124f54523f4881376ddb533b5219e804cc26f4c2e577be4e02613c4da80ba1215775b0a5178a965ad47bd2befb32493943ded1004ef66347b4983f8d1ba990d4a943505dfce6debcfb322842ed88106cd6dee9aa592ff0d2274bc727a6e1f14c
|
||||
LCM = 9c129cf649555bfd2d3d9c64dc6d6f022295e53bca5d2f218adaa66aa60eb4694429b7e83bf81b6df4459c5104023ab9a33f006ffcd8114507baa17e2ef6fe23ebdd4740f66879033da2041f2cb7ba517ad3526ffe75614ea9432c085f71b2d65a736bac7ba42b639e330b82733372083843dcb78b6a273ab20e0d4b7c8998a14048aa15bb20a0a0bd997917107274c89b4cec175fb98043d52e6c555bd9e0036566d052a6d4e7e276d1e8835e1f06e3ca46d47747ba586e95fb1a790d992834b7c3e136141eb8a434e6c12067246ac3c0a81c69e03b1ed28aa0b3173d6eff83d278c2f461a47a416f3f9a5dae3bb410fd18817bd4115e7f1e84b936cc02364
|
||||
|
||||
GCD = 95aa569a2c76854300d7660847dd20fe0b8c445fdbcaa98465cee61aee76ad6a438e75a8c573198570ffb62bc07ec3a2be0ae0a1f631670fa88d6f75f3161e8b9a4d44b6801ffc884c7f469c5ed1f27b1edecce9f2977f9e92d1a3b230492fea7e6f2af739dc158a7fbd29856cbedb57b4119e64b27ab09eb1c2df01507d6e7fd
|
||||
A = 4c653b5bfec44e9be100c064dffe5d8cd59b0cf4cc56b03eabb4ef87cfda6506c9a756b811907fe9d8b783eb7a0b9e129773bf1da365ddb488d27b16fb983e89345d1ccdb4f06a67a11925c3f266373be5d7b0075189c6f3c2157e2da197058fe0a7bcc50adc34e99e254a29abbe2d5948d3157e1b0c3fca3d641760f7b9862843b63abef0b3d83fd486f4526b30382fda355575da30e9a106718a3921774c4d69f5311f8d737fe618f5236b4763fe1b2ee7f13184db67367d3903c535ff6d7b
|
||||
B = 2dcca83c99a28e9fd2f84e78973699baf2f04fd454094730948b22477834a0064817b86e0835e6d7b26e5b0b1dcf4ad91a07ac0780d6522df1fcac758cf5db6c2a5623d7c0f1afefd5718f7b6de639867d07a9ec525991304e9355d1635104bea837f74758d6aa2aab4e4afbb606af1d98de7417505e4710cd0589bdff9a0bf38a857cc59a5f1781043e694fc2337fd84bdeb28b13a222bb09328a81ec409ad586e74236393d27398cc24d412135e34247c589149e134b97f4bd538ac9a3424b
|
||||
LCM = 1760c0b0066aa0695767099e87e9388729ea89b8e8c36bddcd04d257591e741613c07b0e69447c0a468c33a745084171e06523d987d8db40a1433bf435325e8a724a0876503b34495170ff3671d42117a2e4f3a75b1d9dd809a34fa0fb26fe50d84f80a9b02e40190e5efb927a5a61a03f13edbce2e666af6c3a2a9bcb84e47e3090008753ff27c4b8cf06480f471379a93f5230923623a83b286b71a555cd5e5347282f664ed90b14b2c4de84a70375e488211a7b3931119ef3bbe029b712389fe784818a0bf29d80733ce9cc940c547aa1eb3f06d492eb676bf37802283c82ce76156dfaab5c2d5107e08062681b5fa169f6eb68e1ab8bd9b2005e90bd4fd
|
||||
|
||||
GCD = 244b9b1290cf5b4ba2f810574c050651489f2d3a2b03e702b76ebfaf4e33de9bbe5da24c919e68d3a72eadd35982b3a89c6b18b38ff7082ac65263e52b6ec75a5717b971c98257b194c828bff0216a99536603b41a396ea2fb50f5ea7cf3edf10bb0d039123e78593ae9ffcbbba02e51e038533e83b6bc73c70551d6467f39809
|
||||
A = 41a0b1310669500681cdf888836f6c556758750f562d743ac780dd4c0d161856380e44fdbb1f8a2786bf45be6b0e7f1cb2cd85f6b9e50acc72793d92383c7d7fb796fc74d32e8fac8225bdc19ae47546d9c9c75f5f06ca684f07daccaf89ccf2cddeb7ec255d530c7dd1e71daf44cafdc9d30fbcb1cbaefae3480585f79f4177e3834a5bc91845e2e8cd8aeb27f484e5e5b2c3c076dbb6c23e91303f0a0fdde83cd33a8ea6ed1549e727b4d766c1017c169710fd98e1585d60f66e121f9180b3
|
||||
B = 251f5aeaa60b3959285f49540cdaf8e21451110bbddb9933bbbcaea3112f4eb45e435a3ba37c52d2ab79ce997a8f6c829b3aa561f2852924b8effb52396d09d2bf257ebb4fb56c7aa25648f69b06d2cd01e876c9f9c0679de9e6fffa79eb7e603723e5af7de46ee405a5a079229577b5b6fffb8d43e391fe6f4eb89638e64d6eff8026249aaa355a91625eb0bfd14caa81e4c3586aaa2e94fde143a44f223a91e226661d12f55dfcdb4215e5a64e14e968005733be6a71c465de312ca109b34a
|
||||
LCM = 431f918b274f3e43f446e4e85567883d6536a0332db662cef088f5a36b0f4b68372048174ba10fee94b9f8f1c2e189c974be2e6e8ae8e2ae108445326d40f63e38d8d4e2e46174589a3cbc9583e0036dc8146e79eee9e96f4436313b3f143dd0f5aceab05243def7f915169c360f55ef123977cf623c5ba432c3259c62fb5e37d5adab0f24b825aa4ada99ec4e83e9ca4698399e1ed633091ce5f9844c540a642cd264201116ed4168aa2105a5159f5df064f845830c469140f766c7319052ce59bd1ad7c3f2d8c30e54f147f6aeb5586c70c984302ba18d854a60aec01b394c7d66fa33fe18fe4a8cfb3238df219294e6e42190a30d28b10049a1b75853a4e
|
||||
|
||||
GCD = 206695d52bc391a4db61bf8cb6ea96188333a9c78f477ee76976c2346dad682cf56ca6f176d86ef67d41ff5921b6162b0eca52359975872430dd14c45643eacdf028d830770714c033fd150669705851b2f02de932322d271d565d26768530c3f6cb84f0b3356f970b9070b26c050ead0417152c324c8ffe266d4e8b5b7bef3a
|
||||
A = 1114eb9f1a9d5947eb1399e57f5c980833489685023ed2fe537fe1276c1e026b9a19e6fff55aa889d6c4e977b6e6f3111e2ad463138637b50f42cf32e57d83f282de9e72f813e5969195159a666d74dcd689bd527c60199ae327f7bd548ac36868fea5fdf6f35d19b921e7c10b6448ca480de6826478cd0642d72f05af3f8e65ce42409fbd49f56e81946e89c8e83962c4edc0ed54600600a305e52d081aed3c351e450e11f8fb0ce5754c92cf765b71393b2b7a89c95df79b9ea1b3cb600862
|
||||
B = 1d8f3179ca7b5cc7119360c10de939ffa57c9043da2f2b0ca3009c9bdad9f19ed16e3c2c197bef4b527fa1bf2bbab98b77e26c329911db68bd63d3d0fbfc727a977395b9ad067106de3094d68e097830858c5ccfa505fc25e972bdee6f347e7d1163efacd3d29a791ec2a94ffeed467884ae04896efc5e7e5f43d8d76c147e3c9951a1999173bc4e5767d51268b92cc68487ba1295372143b538711e0a62bf0ac111cc750ca4dd6c318c9cbe106d7fc492261404b86a1ba728e2d25b1976dc42
|
||||
LCM = f9570211f694141bfb096560551080cbe02a80271b4505591aaea9e3b99ea1d5ac1c1f2378fd72799e117ac2a73381b1ad26314e39972164d93971479ee3ba21a4d98cef0bd299d540ce5826995dcee0de420dff73d30b23cbf3188c625c7696df517535bc5675d71faa00807efbebdca547933f4a37849d1c014484a77da6df0670c4974bcc91eb5f5fe5faf9dd095ef195ec32ad9eeebf0e63288b4032ed9e70b888afc642f4ff96f0b4c0a68787301c12e4527fe79bdfe72dd3844ab5e094a9295df6616f24d1b9eeebc2116177dacf91969dda73667bc421ef3ccd8d5c23dddc283f5d36568d31f2654926be67f78e181075bdc148f2b39c630b141ae8a
|
||||
|
||||
GCD = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
A = 0
|
||||
B = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
LCM = 0
|
||||
|
||||
GCD = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
A = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
B = 0
|
||||
LCM = 0
|
||||
|
||||
GCD = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
A = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
B = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
LCM = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423
|
||||
|
||||
GCD = 2
|
||||
A = 14e95a85e59ade9ef39e2f400c65db18702fa5fc485b9bba479a5282b2206129160e54f73ef4917983c17b4c5ebff7be112a886de069706eee29ba902515cb038
|
||||
B = ddcfff1d39c90c599f55495bf71c1e7597c6b08b7430707f360c6a6e5137bbc7b403c6d9e2c34f3d2f29d5d32b869346853c2de239cc35381bdfb4a01569211a
|
||||
LCM = 90f38564ee72e55d362c04599e7d74f068c75f541b84e97abba2841f1a9f66b06b5c9009f6a4c2e319fced85270588de03ccebddbd9279aaecb13bdc1dbea7f42acaee751cb7da83779b8785cc86f41b94b13b54964208ca287d981634778d1096f20e76ca636c0717fd27e0800c43f599a5eded807421b502eaf9990a8c8ed8
|
||||
|
||||
GCD = 4
|
||||
A = 3c719c1c363cdeb7b57c2aabb71f425da4c3e6d3e447204d555e7cf0f3d372bdda906f36078045044978dafc20171767c8b1464d52dfdf3e2ba8a4906da033a8
|
||||
B = 30fe0ef151ac51404e128c064d836b191921769dc02d9b09889ed40eb68d15bfdd2edea33580a1a4d7dcee918fefd5c776cbe80ca6131aa080d3989b5e77e1b24
|
||||
LCM = 2e4526157bbd765b0486d90bcd4728f890bc6dbd9a855c67ca5cb2d6b48f8e74e1d99485999e04b193afca58dbf282610185d6c0272007744ff26e00dbdc813929b47940b137dc56ba974da07d54a1c50ec4a5c2b26e83f47cf17f4ccce8c3687e8d1e91d7c491a599f3d057c73473723ce9eee52c20fe8ae1595447552a7ee8
|
||||
|
||||
GCD = 10
|
||||
A = 44e04071d09119ea9783a53df35de4a989200133bb20280fdca6003d3ca63fdd9350ad1a1673d444d2f7c7be639824681643ec4f77535c626bd3ee8fa100e0bb0
|
||||
B = ca927a5a3124ce89accd6ac41a8441d352a5d42feb7f62687a5ebc0e181cc2679888ecc2d38516bdc3b3443550efccac81e53044ae9341ecace2598fe5ce67780
|
||||
LCM = 36805ba9b2412a0cb3fe4ed9bdabfa55515c9d615a3d0af268c45c5f6098d2de4a583f3791f1e3883c55d51ce23c5658fd0e8faa9a3709a1cfbd6a61dbab861690f27c86664f084c86cfd4a183b24aaadf59a6f8cbec04f1b0ded8a59b188cb46ae920052e3e099a570540dbc00f7d4a571eef08aa70d2d189a1804bf04e94a80
|
||||
|
||||
GCD = 100
|
||||
A = 73725032b214a677687c811031555b0c51c1703f10d59b97a4d732b7feaec5726cb3882193419d3f057583b2bc02b297d76bb689977936febaae92638fdfc46a00
|
||||
B = 979f4c10f4dc60ad15068cedd62ff0ab293aeaa1d6935763aed41fe3e445de2e366e8661eadf345201529310f4b805c5800b99f351fddab95d7f313e3bb429d900
|
||||
LCM = 4460439b4be72f533e9c7232f7e99c48328b457969364c951868ceab56cb2cbbeda8be2e8e3cae45c0758048468b841fdb246b2086d19b59d17b389333166ab82ed785860620d53c44f7aaaff4625ee70fb8072df10fb4d1acb142eadc02978ff2bb07cea9f434e35424b3323a7bda3a1a57aa60c75e49ebb2f59fb653aa77da00
|
||||
|
||||
GCD = 100000000
|
||||
A = f8b4f19e09f5862d79fb2931c4d616a1b8e0dd44781ca52902c8035166c8fca52d33a56ff484c365ec1257de7fa8ed2786163cfc051d5223b4aad859a049e8ba00000000
|
||||
B = 6e54cb41b454b080e68a2c3dd0fa79f516eb80239af2be8250ca9cd377ba501aabafc09146fad4402bdc7a49f2c3eec815e25f4c0a223f58e36709eefd92410500000000
|
||||
LCM = 6b3020a880ddeff9d17d3dc234da8771962de3322cd15ba7b1e4b1dd4a6a2a802a16c49653865c6fdf6c207cbe0940f8d81ef4cb0e159385fd709d515ee99d109ad9ad680031cbae4eab2ed62944babdade4e3036426b18920022f737897c7d751dce98d626cdda761fec48ad87a377fb70f97a0a15aa3d10d865785719cc5a200000000
|
||||
|
|
@ -5,15 +5,14 @@
|
|||
package fipstest
|
||||
|
||||
import (
|
||||
"crypto/internal/fips140"
|
||||
. "crypto/internal/fips140/check"
|
||||
"crypto/internal/fips140/check/checktest"
|
||||
"fmt"
|
||||
"internal/abi"
|
||||
"internal/asan"
|
||||
"internal/godebug"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
"unicode"
|
||||
"unsafe"
|
||||
|
|
@ -35,12 +34,8 @@ func TestFIPSCheckVerify(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
if !Supported() {
|
||||
t.Skipf("skipping on %s-%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
if asan.Enabled {
|
||||
// Verification panics with asan; don't bother.
|
||||
t.Skipf("skipping with -asan")
|
||||
if err := fips140.Supported(); err != nil {
|
||||
t.Skipf("skipping: %v", err)
|
||||
}
|
||||
|
||||
cmd := testenv.Command(t, os.Args[0], "-test.v", "-test.run=TestFIPSCheck")
|
||||
|
|
@ -57,8 +52,8 @@ func TestFIPSCheckInfo(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
if !Supported() {
|
||||
t.Skipf("skipping on %s-%s", runtime.GOOS, runtime.GOARCH)
|
||||
if err := fips140.Supported(); err != nil {
|
||||
t.Skipf("skipping: %v", err)
|
||||
}
|
||||
|
||||
// Check that the checktest symbols are initialized properly.
|
||||
|
|
|
|||
|
|
@ -91,6 +91,6 @@ func (ek *EncapsulationKey1024) Bytes() []byte {
|
|||
// encapsulation key, drawing random bytes from crypto/rand.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (ek *EncapsulationKey1024) Encapsulate() (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) {
|
||||
return ek.key.Encapsulate()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,6 @@ func (ek *EncapsulationKey768) Bytes() []byte {
|
|||
// encapsulation key, drawing random bytes from crypto/rand.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (ek *EncapsulationKey768) Encapsulate() (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey768) Encapsulate() (sharedKey, ciphertext []byte) {
|
||||
return ek.key.Encapsulate()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func testRoundTrip[E encapsulationKey, D decapsulationKey[E]](
|
|||
t.Fatal(err)
|
||||
}
|
||||
ek := dk.EncapsulationKey()
|
||||
c, Ke := ek.Encapsulate()
|
||||
Ke, c := ek.Encapsulate()
|
||||
Kd, err := dk.Decapsulate(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -66,7 +66,7 @@ func testRoundTrip[E encapsulationKey, D decapsulationKey[E]](
|
|||
if !bytes.Equal(dk.Bytes(), dk1.Bytes()) {
|
||||
t.Fail()
|
||||
}
|
||||
c1, Ke1 := ek1.Encapsulate()
|
||||
Ke1, c1 := ek1.Encapsulate()
|
||||
Kd1, err := dk1.Decapsulate(c1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -86,7 +86,7 @@ func testRoundTrip[E encapsulationKey, D decapsulationKey[E]](
|
|||
t.Fail()
|
||||
}
|
||||
|
||||
c2, Ke2 := dk.EncapsulationKey().Encapsulate()
|
||||
Ke2, c2 := dk.EncapsulationKey().Encapsulate()
|
||||
if bytes.Equal(c, c2) {
|
||||
t.Fail()
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ func testBadLengths[E encapsulationKey, D decapsulationKey[E]](
|
|||
}
|
||||
ek := dk.EncapsulationKey()
|
||||
ekBytes := dk.EncapsulationKey().Bytes()
|
||||
c, _ := ek.Encapsulate()
|
||||
_, c := ek.Encapsulate()
|
||||
|
||||
for i := 0; i < len(dkBytes)-1; i++ {
|
||||
if _, err := newDecapsulationKey(dkBytes[:i]); err == nil {
|
||||
|
|
@ -189,7 +189,7 @@ func TestAccumulated(t *testing.T) {
|
|||
o.Write(ek.Bytes())
|
||||
|
||||
s.Read(msg[:])
|
||||
ct, k := ek.key.EncapsulateInternal(&msg)
|
||||
k, ct := ek.key.EncapsulateInternal(&msg)
|
||||
o.Write(ct)
|
||||
o.Write(k)
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ func BenchmarkEncaps(b *testing.B) {
|
|||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
c, K := ek.key.EncapsulateInternal(&m)
|
||||
K, c := ek.key.EncapsulateInternal(&m)
|
||||
sink ^= c[0] ^ K[0]
|
||||
}
|
||||
}
|
||||
|
|
@ -255,7 +255,7 @@ func BenchmarkDecaps(b *testing.B) {
|
|||
b.Fatal(err)
|
||||
}
|
||||
ek := dk.EncapsulationKey()
|
||||
c, _ := ek.Encapsulate()
|
||||
_, c := ek.Encapsulate()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
K, _ := dk.Decapsulate(c)
|
||||
|
|
@ -270,7 +270,7 @@ func BenchmarkRoundTrip(b *testing.B) {
|
|||
}
|
||||
ek := dk.EncapsulationKey()
|
||||
ekBytes := ek.Bytes()
|
||||
c, _ := ek.Encapsulate()
|
||||
_, c := ek.Encapsulate()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
@ -296,7 +296,7 @@ func BenchmarkRoundTrip(b *testing.B) {
|
|||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
cS, Ks := ek.Encapsulate()
|
||||
Ks, cS := ek.Encapsulate()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,20 +2,12 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
|
||||
2898 / PKCS #5 v2.0.
|
||||
|
||||
A key derivation function is useful when encrypting data based on a password
|
||||
or any other not-fully-random data. It uses a pseudorandom function to derive
|
||||
a secure encryption key based on the password.
|
||||
|
||||
While v2.0 of the standard defines only one pseudorandom function to use,
|
||||
HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
|
||||
Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
|
||||
choose, you can pass the `New` functions from the different SHA packages to
|
||||
pbkdf2.Key.
|
||||
*/
|
||||
// Package pbkdf2 implements the key derivation function PBKDF2 as defined in
|
||||
// RFC 8018 (PKCS #5 v2.1).
|
||||
//
|
||||
// A key derivation function is useful when encrypting data based on a password
|
||||
// or any other not-fully-random data. It uses a pseudorandom function to derive
|
||||
// a secure encryption key based on the password.
|
||||
package pbkdf2
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ func TestImpossibleKeyGeneration(t *testing.T) {
|
|||
// This test ensures that trying to generate or validate toy RSA keys
|
||||
// doesn't enter an infinite loop or panic.
|
||||
t.Setenv("GODEBUG", "rsa1024min=0")
|
||||
for i := 0; i < 128; i++ {
|
||||
for i := 0; i < 32; i++ {
|
||||
GenerateKey(rand.Reader, i)
|
||||
GenerateMultiPrimeKey(rand.Reader, 3, i)
|
||||
GenerateMultiPrimeKey(rand.Reader, 4, i)
|
||||
|
|
@ -184,7 +184,7 @@ func TestEverything(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Setenv("GODEBUG", "rsa1024min=0")
|
||||
min := 128
|
||||
min := 32
|
||||
max := 560 // any smaller than this and not all tests will run
|
||||
if *allFlag {
|
||||
max = 2048
|
||||
|
|
|
|||
|
|
@ -246,5 +246,8 @@
|
|||
25,
|
||||
29,
|
||||
4588
|
||||
]
|
||||
],
|
||||
"ErrorMap": {
|
||||
":ECH_REJECTED:": "tls: server rejected ECH"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ type ClientHelloInfo struct {
|
|||
SupportedVersions []uint16
|
||||
|
||||
// Extensions lists the IDs of the extensions presented by the client
|
||||
// in the client hello.
|
||||
// in the ClientHello.
|
||||
Extensions []uint16
|
||||
|
||||
// Conn is the underlying net.Conn for the connection. Do not read
|
||||
|
|
@ -821,7 +821,7 @@ type Config struct {
|
|||
|
||||
// EncryptedClientHelloRejectionVerify, if not nil, is called when ECH is
|
||||
// rejected by the remote server, in order to verify the ECH provider
|
||||
// certificate in the outer Client Hello. If it returns a non-nil error, the
|
||||
// certificate in the outer ClientHello. If it returns a non-nil error, the
|
||||
// handshake is aborted and that error results.
|
||||
//
|
||||
// On the server side this field is not used.
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ func decodeInnerClientHello(outer *clientHelloMsg, encoded []byte) (*clientHello
|
|||
}
|
||||
|
||||
if !bytes.Equal(inner.encryptedClientHello, []byte{uint8(innerECHExt)}) {
|
||||
return nil, errors.New("tls: client sent invalid encrypted_client_hello extension")
|
||||
return nil, errInvalidECHExt
|
||||
}
|
||||
|
||||
if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) {
|
||||
|
|
@ -481,6 +481,7 @@ func (e *ECHRejectionError) Error() string {
|
|||
}
|
||||
|
||||
var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension")
|
||||
var errInvalidECHExt = errors.New("tls: client sent invalid encrypted_client_hello extension")
|
||||
|
||||
type echExtType uint8
|
||||
|
||||
|
|
@ -507,7 +508,7 @@ func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8,
|
|||
return echType, cs, 0, nil, nil, nil
|
||||
}
|
||||
if echType != outerECHExt {
|
||||
err = errMalformedECHExt
|
||||
err = errInvalidECHExt
|
||||
return
|
||||
}
|
||||
if !s.ReadUint16(&cs.KDFID) {
|
||||
|
|
@ -549,8 +550,13 @@ func marshalEncryptedClientHelloConfigList(configs []EncryptedClientHelloKey) ([
|
|||
func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *echServerContext, error) {
|
||||
echType, echCiphersuite, configID, encap, payload, err := parseECHExt(outer.encryptedClientHello)
|
||||
if err != nil {
|
||||
c.sendAlert(alertDecodeError)
|
||||
return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension")
|
||||
if errors.Is(err, errInvalidECHExt) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
} else {
|
||||
c.sendAlert(alertDecodeError)
|
||||
}
|
||||
|
||||
return nil, nil, errInvalidECHExt
|
||||
}
|
||||
|
||||
if echType == innerECHExt {
|
||||
|
|
@ -597,7 +603,7 @@ func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *e
|
|||
echInner, err := decodeInnerClientHello(outer, encodedInner)
|
||||
if err != nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension")
|
||||
return nil, nil, errInvalidECHExt
|
||||
}
|
||||
|
||||
c.echAccepted = true
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ type echClientContext struct {
|
|||
kdfID uint16
|
||||
aeadID uint16
|
||||
echRejected bool
|
||||
retryConfigs []byte
|
||||
}
|
||||
|
||||
func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
|
|
@ -944,7 +945,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
|||
}
|
||||
|
||||
// checkALPN ensure that the server's choice of ALPN protocol is compatible with
|
||||
// the protocols that we advertised in the Client Hello.
|
||||
// the protocols that we advertised in the ClientHello.
|
||||
func checkALPN(clientProtos []string, serverProto string, quic bool) error {
|
||||
if serverProto == "" {
|
||||
if quic && len(clientProtos) > 0 {
|
||||
|
|
|
|||
|
|
@ -856,6 +856,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
|
||||
Certificates: testCertificates,
|
||||
Time: testTime,
|
||||
}
|
||||
|
||||
issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer)
|
||||
|
|
@ -872,6 +873,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
ClientSessionCache: NewLRUClientSessionCache(32),
|
||||
RootCAs: rootCAs,
|
||||
ServerName: "example.golang",
|
||||
Time: testTime,
|
||||
}
|
||||
|
||||
testResumeState := func(test string, didResume bool) {
|
||||
|
|
@ -918,7 +920,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
|
||||
// An old session ticket is replaced with a ticket encrypted with a fresh key.
|
||||
ticket = getTicket()
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
|
||||
testResumeState("ResumeWithOldTicket", true)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("old first ticket matches the fresh one")
|
||||
|
|
@ -926,13 +928,13 @@ func testResumption(t *testing.T, version uint16) {
|
|||
|
||||
// Once the session master secret is expired, a full handshake should occur.
|
||||
ticket = getTicket()
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + time.Minute) }
|
||||
testResumeState("ResumeWithExpiredTicket", false)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("expired first ticket matches the fresh one")
|
||||
}
|
||||
|
||||
serverConfig.Time = func() time.Time { return time.Now() } // reset the time back
|
||||
serverConfig.Time = testTime // reset the time back
|
||||
key1 := randomKey()
|
||||
serverConfig.SetSessionTicketKeys([][32]byte{key1})
|
||||
|
||||
|
|
@ -949,11 +951,11 @@ func testResumption(t *testing.T, version uint16) {
|
|||
testResumeState("KeyChangeFinish", true)
|
||||
|
||||
// Age the session ticket a bit, but not yet expired.
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
|
||||
testResumeState("OldSessionTicket", true)
|
||||
ticket = getTicket()
|
||||
// Expire the session ticket, which would force a full handshake.
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + 2*time.Minute) }
|
||||
testResumeState("ExpiredSessionTicket", false)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("new ticket wasn't provided after old ticket expired")
|
||||
|
|
@ -961,7 +963,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
|
||||
// Age the session ticket a bit at a time, but don't expire it.
|
||||
d := 0 * time.Hour
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(d) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(d) }
|
||||
deleteTicket()
|
||||
testResumeState("GetFreshSessionTicket", false)
|
||||
for i := 0; i < 13; i++ {
|
||||
|
|
@ -972,7 +974,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
// handshake occurs for TLS 1.2. Resumption should still occur for
|
||||
// TLS 1.3 since the client should be using a fresh ticket sent over
|
||||
// by the server.
|
||||
d += 12 * time.Hour
|
||||
d += 12*time.Hour + time.Minute
|
||||
if version == VersionTLS13 {
|
||||
testResumeState("ExpiredSessionTicket", true)
|
||||
} else {
|
||||
|
|
@ -988,6 +990,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
|
||||
Certificates: testCertificates,
|
||||
Time: testTime,
|
||||
}
|
||||
serverConfig.SetSessionTicketKeys([][32]byte{key2})
|
||||
|
||||
|
|
@ -1013,6 +1016,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256},
|
||||
MaxVersion: version,
|
||||
Certificates: testCertificates,
|
||||
Time: testTime,
|
||||
}
|
||||
testResumeState("InitialHandshake", false)
|
||||
testResumeState("WithHelloRetryRequest", true)
|
||||
|
|
@ -1022,6 +1026,7 @@ func testResumption(t *testing.T, version uint16) {
|
|||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
|
||||
Certificates: testCertificates,
|
||||
Time: testTime,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1743,6 +1748,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
|
|||
serverConfig := &Config{
|
||||
MaxVersion: version,
|
||||
Certificates: testCertificates,
|
||||
Time: testTime,
|
||||
ClientCAs: rootCAs,
|
||||
NextProtos: []string{"protocol1"},
|
||||
}
|
||||
|
|
@ -1756,6 +1762,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
|
|||
RootCAs: rootCAs,
|
||||
ServerName: "example.golang",
|
||||
Certificates: testCertificates,
|
||||
Time: testTime,
|
||||
NextProtos: []string{"protocol1"},
|
||||
}
|
||||
test.configureClient(clientConfig, &clientCalled)
|
||||
|
|
@ -1799,8 +1806,6 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
|||
rootCAs := x509.NewCertPool()
|
||||
rootCAs.AddCert(issuer)
|
||||
|
||||
now := func() time.Time { return time.Unix(1476984729, 0) }
|
||||
|
||||
sentinelErr := errors.New("TestVerifyPeerCertificate")
|
||||
|
||||
verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
|
||||
|
|
@ -2046,7 +2051,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
|||
config.ServerName = "example.golang"
|
||||
config.ClientAuth = RequireAndVerifyClientCert
|
||||
config.ClientCAs = rootCAs
|
||||
config.Time = now
|
||||
config.Time = testTime
|
||||
config.MaxVersion = version
|
||||
config.Certificates = make([]Certificate, 1)
|
||||
config.Certificates[0].Certificate = [][]byte{testRSA2048Certificate}
|
||||
|
|
@ -2064,7 +2069,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
|||
config.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}}
|
||||
config.ServerName = "example.golang"
|
||||
config.RootCAs = rootCAs
|
||||
config.Time = now
|
||||
config.Time = testTime
|
||||
config.MaxVersion = version
|
||||
test.configureClient(config, &clientCalled)
|
||||
clientErr := Client(c, config).Handshake()
|
||||
|
|
@ -2379,7 +2384,7 @@ func testGetClientCertificate(t *testing.T, version uint16) {
|
|||
serverConfig.RootCAs = x509.NewCertPool()
|
||||
serverConfig.RootCAs.AddCert(issuer)
|
||||
serverConfig.ClientCAs = serverConfig.RootCAs
|
||||
serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
|
||||
serverConfig.Time = testTime
|
||||
serverConfig.MaxVersion = version
|
||||
|
||||
clientConfig := testConfig.Clone()
|
||||
|
|
@ -2562,6 +2567,7 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
|
|||
ClientSessionCache: NewLRUClientSessionCache(32),
|
||||
ServerName: "example.golang",
|
||||
RootCAs: roots,
|
||||
Time: testTime,
|
||||
}
|
||||
serverConfig := testConfig.Clone()
|
||||
serverConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
|||
}
|
||||
}
|
||||
|
||||
var echRetryConfigList []byte
|
||||
if hs.echContext != nil {
|
||||
confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash)
|
||||
confTranscript.Write(hs.serverHello.original[:30])
|
||||
|
|
@ -114,9 +113,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
|||
}
|
||||
} else {
|
||||
hs.echContext.echRejected = true
|
||||
// If the server sent us retry configs, we'll return these to
|
||||
// the user so they can update their Config.
|
||||
echRetryConfigList = hs.serverHello.encryptedClientHello
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +151,7 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
|||
|
||||
if hs.echContext != nil && hs.echContext.echRejected {
|
||||
c.sendAlert(alertECHRequired)
|
||||
return &ECHRejectionError{echRetryConfigList}
|
||||
return &ECHRejectionError{hs.echContext.retryConfigs}
|
||||
}
|
||||
|
||||
c.isHandshakeComplete.Store(true)
|
||||
|
|
@ -601,9 +597,13 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
|
|||
return errors.New("tls: server accepted 0-RTT with the wrong ALPN")
|
||||
}
|
||||
}
|
||||
if hs.echContext != nil && !hs.echContext.echRejected && encryptedExtensions.echRetryConfigs != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello")
|
||||
if hs.echContext != nil {
|
||||
if hs.echContext.echRejected {
|
||||
hs.echContext.retryConfigs = encryptedExtensions.echRetryConfigs
|
||||
} else if encryptedExtensions.echRetryConfigs != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ type clientHelloMsg struct {
|
|||
pskBinders [][]byte
|
||||
quicTransportParameters []byte
|
||||
encryptedClientHello []byte
|
||||
// extensions are only populated on the servers-ide of a handshake
|
||||
// extensions are only populated on the server-side of a handshake
|
||||
extensions []uint16
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue