[release-branch.go1.24] all: merge master (9a44df6) into release-branch.go1.24

Merge List:

+ 2025-01-08 9a44df6675 cmd/go/testdata/script: fix TestScript/env_gocacheprog on Windows
+ 2025-01-08 f025d19e7b runtime: hold traceAcquire across casgstatus in injectglist
+ 2025-01-08 1e9835f5b1 internal/sync: fix typo of panic message
+ 2025-01-07 39f2032c17 testing/synctest: add some examples
+ 2025-01-07 b50ccef67a cmd/go/internal/modindex: don't write index entry if file open
+ 2025-01-07 b2aa18b96c cmd/internal/hash: stop using md5, sha1
+ 2025-01-07 d93b549f05 cmd/go/internal/cache: handle cacheprog not responding to close
+ 2025-01-07 d62154db83 weak: don't panic when calling Value on a zero Pointer
+ 2025-01-07 9d0772b23e cmd/compile/internal/syntax: add test case for invalid label use
+ 2025-01-07 1d20bce981 go/types, types2: expand documentation for Info.Types map
+ 2025-01-07 a9bd6239a4 cmd/go/internal/env: add GOCACHEPROG to go env output
+ 2025-01-07 850b276a67 crypto/tls: send illegal_parameter on invalid ECHClientHello.type
+ 2025-01-06 27c5164374 crypto/internal/fips140: zeroise integrity test temporary values
+ 2025-01-06 d8ad4af78b cmd/internal/disasm: correct instruction length handling for riscv64
+ 2025-01-06 a76cc5a4ec crypto/rsa: use λ(N) instead of φ(N)
+ 2025-01-06 3f002abb60 internal/sync: add test from issue 70970
+ 2025-01-06 7a2e88e911 net/http: update NewRequestWithContext wrong link to NewRequest
+ 2025-01-06 c112c0af13 Revert "internal/sync: optimize CompareAndSwap and Swap"
+ 2025-01-03 705b5a569a crypto/ecdsa: drop SEC 1 reference from package doc
+ 2025-01-03 f966695cce context: use "canceled" in docs to refer to timed-out contexts
+ 2025-01-03 5da026354c cmd/go/internal/vcweb: close the .access file
+ 2025-01-03 31cabcf084 crypto/internal/fips140: mark OpenBSD unsupported
+ 2025-01-03 eb0c2b2f96 crypto/internal/fips140: add Supported
+ 2025-01-03 f0a9b6df45 internal/fuzz: remove the exp2 method
+ 2025-01-03 5d626c49ec spec: fix a dead link
+ 2025-01-03 81566aff3a internal/exportdata: add missing return
+ 2025-01-03 e7a8bd5d8b crypto/internal/fips140/check: remove Enabled
+ 2025-01-02 4b652e9f5f cmd/go: fix two typos in helpdoc.go
+ 2025-01-02 0afd7e85e5 cmd/go: document GOCACHEPROG in go help environment
+ 2025-01-02 3c8e5b13df cmd/go/internal/cacheprog: drop redundant Prog prefixes
+ 2025-01-02 20da34c6d2 cmd/go: move GOCACHEPROG protocol types to their own package
+ 2025-01-02 858a0e9dfd crypto/tls: properly return ECH retry configs
+ 2025-01-02 a63aee4955 cmd/go: improve GOCACHEPROG types documentation
+ 2025-01-02 847c357bbb cmd/go: remove references to gopath-get
+ 2025-01-01 d1d9312950 crypto/tls: fix Config.Time in tests using expired certificates
+ 2024-12-31 94f15810e6 cmd/go: document default GOARM value
+ 2024-12-30 856a7bc8e9 builtin: use list instead of indentation for comments in cap, len, and make
+ 2024-12-30 5efb4239c6 spec: document that string conversions don't guarantee result slice capacity
+ 2024-12-30 0d8aa8cce6 spec: describe representation of values
+ 2024-12-30 8857a5a33f crypto/tls: fix misspelling in comment
+ 2024-12-30 3c4102bfd4 encoding/binary: add documentation for endian methods
+ 2024-12-30 b702a26cf8 os: mention fsys modifications during CopyFS
+ 2024-12-30 15f232456a encoding/json: remove suggestion on Unmarshaler with JSON null
+ 2024-12-30 ba1deb1cee cmd/link: document that -s implies -w
+ 2024-12-30 fd5e0d26d9 go/doc: resolve imports before predeclared identifiers in examples
+ 2024-12-30 a785d11ac4 unique: fix typo
+ 2024-12-27 2b794ed86c encoding/json: expand and modernize TestInterfaceSet
+ 2024-12-27 e3cd55e9d2 cmd/go/internal/work: allow @ character in some -Wl, linker flags on darwin
+ 2024-12-27 39794819aa doc/initial: remove fixed-width spacing notice
+ 2024-12-27 7c03fe70b8 cmd/compile: improve compiler directive docs
+ 2024-12-27 d7c3e93c16 iter: improve documentation with iterator example
+ 2024-12-26 cce75da30b crypto/mlkem: swap order of return values of Encapsulate
+ 2024-12-23 772f024c61 weak: fix typo in warning about tiny allocator optimization
+ 2024-12-23 b9955f0ad9 cmd/link, runtime: apply a delta to RODATA->DATA relocations
+ 2024-12-23 eef35e3bd9 internal/goexperiment: run go generate for synctest
+ 2024-12-23 9f6c80a76a cmd/go/internal/work: allow single character values in -Wl, linker flags
+ 2024-12-22 05d8984781 net: document LookupTXT behavior with multiple strings per record
+ 2024-12-21 500675a7c8 cmd/compile: load map length with the right type
+ 2024-12-21 06b191e11f internal/syscall/unix: apply fstatat fix to linux/mips64le
+ 2024-12-21 110ab1aaf4 slices: document two oddities
+ 2024-12-19 669d87a935 runtime/pprof: continued attempt to deflake the VMInfo test.
+ 2024-12-19 45f49139f5 runtime: test trap panic parsing in TestTracebackSystem
+ 2024-12-19 e63eb98e98 net/http: fix nil panic in test
+ 2024-12-19 7b6c94dd03 cmd/go: drop fips140 build ID hacks
+ 2024-12-19 cb72406c36 cmd/go: fix two-step toolchain upgrade through go install, GOTOOLCHAIN
+ 2024-12-18 4f0561f9d3 cmd/dist: skip fips140test in exe mode on Android
+ 2024-12-18 87dbfb9fa7 weak: improve grammar in doc comments
+ 2024-12-18 f4e3ec3dbe crypto/ecdsa: fix condition for fips140=only check
+ 2024-12-18 6aa46eb750 crypto/tls: normalize spelling of "ClientHello" in comments
+ 2024-12-18 10ca5ba4ff crypto/pbkdf2: update RFC reference in package doc
+ 2024-12-18 8ff4cee564 cmd/go,crypto: reject using Go+BoringCrypto and fips140 together
+ 2024-12-18 971448ddf8 testing: support B.Context and F.Context
+ 2024-12-17 95b433eed4 debug/elf: adjust version API per issue discussion
+ 2024-12-17 b2c0168893 crypto/internal/fips140/aes/gcm: use aes.EncryptBlockInternal on ppc64x and s390x
+ 2024-12-17 b9e2ffdcd2 crypto/internal/fips140: add Name and Version
+ 2024-12-17 8790372a8d cmd, go: fix some typos
+ 2024-12-17 b057b8872d bytes, strings: add cross-references in docstrings
+ 2024-12-17 e977b83b32 cmd/go/internal/help: use secure link to swig.org
+ 2024-12-17 4ac8f552e9 syscall, internal/syscall/unix: fix fstatat on linux/mips64
+ 2024-12-17 236a0b4ffb spec: explain function invocation and passing of parameters more precisely
+ 2024-12-17 9f806bb76c go/build: streamline the crypto package graph in TestDependencies
+ 2024-12-17 0cd833d198 go/build: remove nonexistent package from TestDependencies
+ 2024-12-17 31e50af5f3 crypto/rsa: revert minimum GenerateKey size to 32 bits
+ 2024-12-17 b47ce8b0e9 crypto/cipher: block non-AES CTR and CBC in fips140=only mode
+ 2024-12-17 dd7a7ba38f crypto/internal/fips140/aes: mark AES-ECB as not approved
+ 2024-12-17 427a2401af cmd/go/testdata/script: update test_flags for new test output
+ 2024-12-17 75736cc169 fmt, strconv: document that exponent is always two digits
+ 2024-12-16 1218566fe5 cmd/link: update runtime dependency list
+ 2024-12-16 d92c34a387 cmd/go: don't create test actions for incomplete packages
+ 2024-12-16 3bd08b9792 runtime: usleep in TestWeakToStrongMarkTermination
+ 2024-12-15 18b5435fc8 testing: don't measure cleanup time after B.Loop
+ 2024-12-15 c1f2542c8b testing: improve B.Loop test
+ 2024-12-15 6bd56fcaeb testing: improve b.Loop example
+ 2024-12-15 090748d6c7 testing: improve B.Loop docs, use B.Loop in examples
+ 2024-12-13 e39e965e0e cmd/go: drop FailedBuild field if gotestjsonbuildtext=1
+ 2024-12-13 08770a5b94 cmd/link: make dwarf name slice index self-describing
+ 2024-12-13 c4f356dd86 crypto/ecdsa: fix s390x assembly with P-521
+ 2024-12-13 08725f9de2 crypto/internal/cryptotest: skip TestAllocations on s390x
+ 2024-12-13 1cbfe8c482 fmt: add more function and allocation tests
+ 2024-12-13 8391579ece runtime: migrate missing map linkname allowlists
+ 2024-12-12 80a2982a80 spec: align EBNF rules consistently (cosmetic change)
+ 2024-12-12 38e9a671d7 syscall: on freebsd-386 only update written for certain errors
+ 2024-12-12 6f7a4540b1 net: fix example function name for IP.To4
+ 2024-12-12 14e5093ee5 cmd/internal/obj: disallow linknamed access to builtin symbols
+ 2024-12-12 fb764cdad0 cmd/link: block new standard library linknames

Change-Id: Ie423f050db80034c3af6c12bd6007db273c5d281
This commit is contained in:
Michael Pratt 2025-01-08 13:20:26 -05:00
commit b3799ba634
160 changed files with 3501 additions and 1527 deletions

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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)

View File

@ -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
}
}

View File

@ -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;

View File

@ -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

View File

@ -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) {

25
src/cmd/dist/test.go vendored
View File

@ -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
}

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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)

View File

@ -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},

View File

@ -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

View File

@ -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.
`,

View File

@ -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

View File

@ -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
}

View File

@ -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.
`,
}

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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.

View File

@ -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")
}

View File

@ -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'

View File

@ -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) {

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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 --

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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")
}
})
}

View File

@ -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"
)

View File

@ -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

View File

@ -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) {

View File

@ -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
}

View File

@ -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)

View File

@ -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.

View File

@ -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)
}

View File

@ -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")

View File

@ -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))

View File

@ -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

View File

@ -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},

View File

@ -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

View File

@ -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")

View File

@ -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,

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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

View File

@ -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() {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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])

View File

@ -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)

View File

@ -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
}

View File

@ -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)

View File

@ -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[:])
}

View File

@ -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

View File

@ -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]
}

View File

@ -4,6 +4,6 @@
//go:build asan
package check
package fips140
const asanEnabled = true

View File

@ -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
}

View File

@ -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

View File

@ -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
// modules 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")
}

View File

@ -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
}

View File

@ -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, &params) {
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, &params) != 0 {
return errors.New("invalid signature")
}

View File

@ -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"
}

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -4,6 +4,6 @@
//go:build !asan
package check
package fips140
const asanEnabled = false

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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.
//

View File

@ -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

View File

@ -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.

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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 (

View File

@ -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

View File

@ -246,5 +246,8 @@
25,
29,
4588
]
],
"ErrorMap": {
":ECH_REJECTED:": "tls: server rejected ECH"
}
}

View File

@ -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.

View File

@ -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

View File

@ -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 {

View File

@ -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}}

View File

@ -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

View File

@ -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