[dev.boringcrypto] all: merge master into dev.boringcrypto

Change-Id: Ic5f71c04f08c03319c043f35be501875adb0a3b0
This commit is contained in:
Chressie Himpel 2022-04-27 20:09:28 +02:00
commit ec7f5165dd
204 changed files with 6590 additions and 4889 deletions

View File

@ -35,7 +35,7 @@ Go is the work of thousands of contributors. We appreciate your help!
To contribute, please read the contribution guidelines at https://go.dev/doc/contribute.
Note that the Go project uses the issue tracker for bug reports and
proposals only. See https://golang.org/wiki/Questions for a list of
proposals only. See https://go.dev/wiki/Questions for a list of
places to ask questions about the Go language.
[rf]: https://reneefrench.blogspot.com/

View File

@ -2,12 +2,12 @@
## Supported Versions
We support the past two Go releases (for example, Go 1.12.x and Go 1.13.x).
We support the past two Go releases (for example, Go 1.17.x and Go 1.18.x when Go 1.18.x is the latest stable release).
See https://golang.org/wiki/Go-Release-Cycle and in particular the
[Release Maintenance](https://github.com/golang/go/wiki/Go-Release-Cycle#release-maintenance)
See https://go.dev/wiki/Go-Release-Cycle and in particular the
[Release Maintenance](https://go.dev/wiki/Go-Release-Cycle#release-maintenance)
part of that page.
## Reporting a Vulnerability
See https://golang.org/security for how to report a vulnerability.
See https://go.dev/security for how to report a vulnerability.

3
api/next/30715.txt Normal file
View File

@ -0,0 +1,3 @@
pkg net/http, type MaxBytesError struct #30715
pkg net/http, type MaxBytesError struct, Limit int64 #30715
pkg net/http, method (*MaxBytesError) Error() string #30715

1
api/next/50599.txt Normal file
View File

@ -0,0 +1 @@
pkg os/exec, method (*Cmd) Environ() []string #50599

2
api/next/51684.txt Normal file
View File

@ -0,0 +1,2 @@
pkg regexp/syntax, const ErrNestingDepth = "expression nests too deeply" #51684
pkg regexp/syntax, const ErrNestingDepth ErrorCode #51684

View File

@ -1,3 +0,0 @@
pkg regexp/syntax, const ErrInvalidDepth = "invalid nesting depth" #0
pkg regexp/syntax, const ErrInvalidDepth ErrorCode #0

View File

@ -92,6 +92,16 @@ Do not send CLs removing the interior tags from such phrases.
TODO: complete this section
</p>
<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
<dd>
<p><!-- CL 400974 -->
The <code>tls10default</code> <code>GODEBUG</code> option has been
removed. It is still possible to enable TLS 1.0 client-side by setting
<code>Config.MinVersion</code>.
</p>
</dd>
</dl><!-- crypto/tls -->
<dl id="image/draw"><dt><a href="/pkg/image/draw/">image/draw</a></dt>
<dd>
<p><!-- CL 396795 -->
@ -132,6 +142,21 @@ Do not send CLs removing the interior tags from such phrases.
</dd>
</dl><!-- net -->
<dl id="os/exec"><dt><a href="/pkg/os/exec/">os/exec</a></dt>
<dd><!-- https://go.dev/issue/50599 -->
<p>
An <code>exec.Cmd</code> with a non-empty <code>Dir</code> and a
nil <code>Env</code> now implicitly sets the <code>PWD</code> environment
variable for the subprocess to match <code>Dir</code>.
</p>
<p>
The new method <code>(*exec.Cmd).Environ</code> reports the
environment that would be used to run the command, including the
aforementioned <code>PWD</code> variable.
</p>
</dd>
</dl> <!-- os/exec -->
<dl id="runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
<dd>
<p><!-- https://go.dev/issue/51461 -->

View File

@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
"Subtitle": "Version of March 30, 2022",
"Subtitle": "Version of April 19, 2022",
"Path": "/ref/spec"
}-->
@ -1278,7 +1278,8 @@ then the <code>File</code> interface is implemented by both <code>S1</code> and
<p>
Every type that is a member of the type set of an interface implements that interface.
Any given type may implement several distinct interfaces.
For instance, all types implement the <i>empty interface</i> which stands for the set of all types:
For instance, all types implement the <i>empty interface</i> which stands for the set
of all (non-interface) types:
</p>
<pre>
@ -1380,7 +1381,7 @@ definition of an interface's type set as follows:
of its interface elements.
</li>
<li>The type set of a method specification is the set of types
<li>The type set of a method specification is the set of all non-interface types
whose method sets include that method.
</li>
@ -1389,7 +1390,7 @@ definition of an interface's type set as follows:
</li>
<li>The type set of a term of the form <code>~T</code>
is the set of types whose underlying type is <code>T</code>.
is the set of all types whose underlying type is <code>T</code>.
</li>
<li>The type set of a <i>union</i> of terms
@ -1398,6 +1399,15 @@ definition of an interface's type set as follows:
</li>
</ul>
<p>
The quantification "the set of all non-interface types" refers not just to all (non-interface)
types declared in the program at hand, but all possible types in all possible programs, and
hence is infinite.
Similarly, given the set of all non-interface types that implement a particular method, the
intersection of the method sets of those types will contain exactly that method, even if all
types in the program at hand always pair that method with another method.
</p>
<p>
By construction, an interface's type set never contains an interface type.
</p>

View File

@ -3,8 +3,7 @@
// license that can be found in the LICENSE file.
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "_cgo_export.h"
void
@ -31,32 +30,10 @@ IntoC(void)
BackIntoGo();
}
#ifdef WIN32
#include <windows.h>
long long
mysleep(int seconds) {
long long st = GetTickCount();
Sleep(1000 * seconds);
return st;
}
#else
#include <sys/time.h>
long long
mysleep(int seconds) {
long long st;
struct timeval tv;
gettimeofday(&tv, NULL);
st = tv.tv_sec * 1000 + tv.tv_usec / 1000;
sleep(seconds);
return st;
}
#endif
long long
twoSleep(int n)
void
Issue1560InC(void)
{
BackgroundSleep(n);
return mysleep(n);
Issue1560FromC();
}
void

View File

@ -11,6 +11,7 @@ import "testing"
// These wrappers are here for gotest to find.
func Test1328(t *testing.T) { test1328(t) }
func Test1560(t *testing.T) { test1560(t) }
func Test1635(t *testing.T) { test1635(t) }
func Test3250(t *testing.T) { test3250(t) }
func Test3729(t *testing.T) { test3729(t) }
@ -89,7 +90,6 @@ func TestLibgcc(t *testing.T) { testLibgcc(t) }
func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) }
func TestNaming(t *testing.T) { testNaming(t) }
func TestPanicFromC(t *testing.T) { testPanicFromC(t) }
func TestParallelSleep(t *testing.T) { testParallelSleep(t) }
func TestPrintf(t *testing.T) { testPrintf(t) }
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }

View File

@ -18,7 +18,6 @@ import (
"sync"
"sync/atomic"
"testing"
"time"
"unsafe"
)
@ -30,8 +29,7 @@ extern void doAdd(int, int);
void IntoC(void);
// issue 1560
// mysleep returns the absolute start time in ms.
long long mysleep(int seconds);
extern void Issue1560InC(void);
// twoSleep returns the absolute start time of the first sleep
// in ms.
@ -183,35 +181,40 @@ func test1328(t *testing.T) {
}
// issue 1560
// Test that C functions and Go functions run in parallel.
var sleepDone = make(chan int64)
var (
issue1560 int32
// parallelSleep returns the absolute difference between the start time
// of the two sleeps.
func parallelSleep(n int) int64 {
t := int64(C.twoSleep(C.int(n))) - <-sleepDone
if t < 0 {
return -t
issue1560Ch = make(chan bool, 2)
)
//export Issue1560FromC
func Issue1560FromC() {
for atomic.LoadInt32(&issue1560) != 1 {
runtime.Gosched()
}
return t
atomic.AddInt32(&issue1560, 1)
for atomic.LoadInt32(&issue1560) != 3 {
runtime.Gosched()
}
issue1560Ch <- true
}
//export BackgroundSleep
func BackgroundSleep(n int32) {
go func() {
sleepDone <- int64(C.mysleep(C.int(n)))
}()
func Issue1560FromGo() {
atomic.AddInt32(&issue1560, 1)
for atomic.LoadInt32(&issue1560) != 2 {
runtime.Gosched()
}
atomic.AddInt32(&issue1560, 1)
issue1560Ch <- true
}
func testParallelSleep(t *testing.T) {
sleepSec := 1
dt := time.Duration(parallelSleep(sleepSec)) * time.Millisecond
t.Logf("difference in start time for two sleep(%d) is %v", sleepSec, dt)
// bug used to run sleeps in serial, producing a 2*sleepSec-second delay.
// we detect if the start times of those sleeps are > 0.5*sleepSec-second.
if dt >= time.Duration(sleepSec)*time.Second/2 {
t.Fatalf("parallel %d-second sleeps slept for %f seconds", sleepSec, dt.Seconds())
}
func test1560(t *testing.T) {
go Issue1560FromGo()
go C.Issue1560InC()
<-issue1560Ch
<-issue1560Ch
}
// issue 2462

View File

@ -96,7 +96,7 @@ if [ "$BOOTSTRAP_FORMAT" = "mintgz" ]; then
echo "Preparing to generate build system's ${OUTGZ}; cleaning ..."
rm -rf bin/gofmt
rm -rf src/runtime/race/race_*.syso
rm -rf api test doc misc/cgo/test misc/trace
rm -rf api test doc misc/cgo/test
rm -rf pkg/tool/*_*/{addr2line,api,cgo,cover,doc,fix,nm,objdump,pack,pprof,test2json,trace,vet}
rm -rf pkg/*_*/{image,database,cmd}
rm -rf $(find . -type d -name testdata)

View File

@ -731,13 +731,28 @@ func (b *Writer) WriteRune(r rune) (size int, err error) {
// If the count is less than len(s), it also returns an error explaining
// why the write is short.
func (b *Writer) WriteString(s string) (int, error) {
var sw io.StringWriter
tryStringWriter := true
nn := 0
for len(s) > b.Available() && b.err == nil {
n := copy(b.buf[b.n:], s)
b.n += n
var n int
if b.Buffered() == 0 && sw == nil && tryStringWriter {
// Check at most once whether b.wr is a StringWriter.
sw, tryStringWriter = b.wr.(io.StringWriter)
}
if b.Buffered() == 0 && tryStringWriter {
// Large write, empty buffer, and the underlying writer supports
// WriteString: forward the write to the underlying StringWriter.
// This avoids an extra copy.
n, b.err = sw.WriteString(s)
} else {
n = copy(b.buf[b.n:], s)
b.n += n
b.Flush()
}
nn += n
s = s[n:]
b.Flush()
}
if b.err != nil {
return nn, b.err

View File

@ -762,6 +762,67 @@ func TestWriteString(t *testing.T) {
}
}
func TestWriteStringStringWriter(t *testing.T) {
const BufSize = 8
{
tw := &teststringwriter{}
b := NewWriterSize(tw, BufSize)
b.WriteString("1234")
tw.check(t, "", "")
b.WriteString("56789012") // longer than BufSize
tw.check(t, "12345678", "") // but not enough (after filling the partially-filled buffer)
b.Flush()
tw.check(t, "123456789012", "")
}
{
tw := &teststringwriter{}
b := NewWriterSize(tw, BufSize)
b.WriteString("123456789") // long string, empty buffer:
tw.check(t, "", "123456789") // use WriteString
}
{
tw := &teststringwriter{}
b := NewWriterSize(tw, BufSize)
b.WriteString("abc")
tw.check(t, "", "")
b.WriteString("123456789012345") // long string, non-empty buffer
tw.check(t, "abc12345", "6789012345") // use Write and then WriteString since the remaining part is still longer than BufSize
}
{
tw := &teststringwriter{}
b := NewWriterSize(tw, BufSize)
b.Write([]byte("abc")) // same as above, but use Write instead of WriteString
tw.check(t, "", "")
b.WriteString("123456789012345")
tw.check(t, "abc12345", "6789012345") // same as above
}
}
type teststringwriter struct {
write string
writeString string
}
func (w *teststringwriter) Write(b []byte) (int, error) {
w.write += string(b)
return len(b), nil
}
func (w *teststringwriter) WriteString(s string) (int, error) {
w.writeString += s
return len(s), nil
}
func (w *teststringwriter) check(t *testing.T, write, writeString string) {
t.Helper()
if w.write != write {
t.Errorf("write: expected %q, got %q", write, w.write)
}
if w.writeString != writeString {
t.Errorf("writeString: expected %q, got %q", writeString, w.writeString)
}
}
func TestBufferFull(t *testing.T) {
const longString = "And now, hello, world! It is the time for all good men to come to the aid of their party"
buf := NewReaderSize(strings.NewReader(longString), minReadBufferSize)

View File

@ -32,19 +32,19 @@ specification](/doc/go_spec.html#Size_and_alignment_guarantees).
Those that aren't guaranteed may change in future versions of Go (for
example, we've considered changing the alignment of int64 on 32-bit).
| Type | 64-bit | | 32-bit | |
| --- | --- | --- | --- | --- |
| | Size | Align | Size | Align |
| bool, uint8, int8 | 1 | 1 | 1 | 1 |
| uint16, int16 | 2 | 2 | 2 | 2 |
| uint32, int32 | 4 | 4 | 4 | 4 |
| uint64, int64 | 8 | 8 | 8 | 4 |
| int, uint | 8 | 8 | 4 | 4 |
| float32 | 4 | 4 | 4 | 4 |
| float64 | 8 | 8 | 8 | 4 |
| complex64 | 8 | 4 | 8 | 4 |
| complex128 | 16 | 8 | 16 | 4 |
| uintptr, *T, unsafe.Pointer | 8 | 8 | 4 | 4 |
| Type | 64-bit | | 32-bit | |
|-----------------------------|--------|-------|--------|-------|
| | Size | Align | Size | Align |
| bool, uint8, int8 | 1 | 1 | 1 | 1 |
| uint16, int16 | 2 | 2 | 2 | 2 |
| uint32, int32 | 4 | 4 | 4 | 4 |
| uint64, int64 | 8 | 8 | 8 | 4 |
| int, uint | 8 | 8 | 4 | 4 |
| float32 | 4 | 4 | 4 | 4 |
| float64 | 8 | 8 | 8 | 4 |
| complex64 | 8 | 4 | 8 | 4 |
| complex128 | 16 | 8 | 16 | 4 |
| uintptr, *T, unsafe.Pointer | 8 | 8 | 4 | 4 |
The types `byte` and `rune` are aliases for `uint8` and `int32`,
respectively, and hence have the same size and alignment as these

View File

@ -219,11 +219,13 @@ calling the function.
//go:uintptrescapes
The //go:uintptrescapes directive must be followed by a function declaration.
It specifies that the function's uintptr arguments may be pointer values
that have been converted to uintptr and must be treated as such by the
garbage collector. The conversion from pointer to uintptr must appear in
the argument list of any call to this function. This directive is necessary
for some low-level system call implementations and should be avoided otherwise.
It specifies that the function's uintptr arguments may be pointer values that
have been converted to uintptr and must be on the heap and kept alive for the
duration of the call, even though from the types alone it would appear that the
object is no longer needed during the call. The conversion from pointer to
uintptr must appear in the argument list of any call to this function. This
directive is necessary for some low-level system call implementations and
should be avoided otherwise.
//go:noinline

View File

@ -0,0 +1,272 @@
// Copyright 2022 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 compare contains code for generating comparison
// routines for structs, strings and interfaces.
package compare
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"fmt"
"math/bits"
"sort"
)
// IsRegularMemory reports whether t can be compared/hashed as regular memory.
func IsRegularMemory(t *types.Type) bool {
a, _ := types.AlgType(t)
return a == types.AMEM
}
// Memrun finds runs of struct fields for which memory-only algs are appropriate.
// t is the parent struct type, and start is the field index at which to start the run.
// size is the length in bytes of the memory included in the run.
// next is the index just after the end of the memory run.
func Memrun(t *types.Type, start int) (size int64, next int) {
next = start
for {
next++
if next == t.NumFields() {
break
}
// Stop run after a padded field.
if types.IsPaddedField(t, next-1) {
break
}
// Also, stop before a blank or non-memory field.
if f := t.Field(next); f.Sym.IsBlank() || !IsRegularMemory(f.Type) {
break
}
// For issue 46283, don't combine fields if the resulting load would
// require a larger alignment than the component fields.
if base.Ctxt.Arch.Alignment > 1 {
align := t.Alignment()
if off := t.Field(start).Offset; off&(align-1) != 0 {
// Offset is less aligned than the containing type.
// Use offset to determine alignment.
align = 1 << uint(bits.TrailingZeros64(uint64(off)))
}
size := t.Field(next).End() - t.Field(start).Offset
if size > align {
break
}
}
}
return t.Field(next-1).End() - t.Field(start).Offset, next
}
// EqCanPanic reports whether == on type t could panic (has an interface somewhere).
// t must be comparable.
func EqCanPanic(t *types.Type) bool {
switch t.Kind() {
default:
return false
case types.TINTER:
return true
case types.TARRAY:
return EqCanPanic(t.Elem())
case types.TSTRUCT:
for _, f := range t.FieldSlice() {
if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
return true
}
}
return false
}
}
// EqStruct compares two structs np and nq for equality.
// It works by building a list of boolean conditions to satisfy.
// Conditions must be evaluated in the returned order and
// properly short circuited by the caller.
func EqStruct(t *types.Type, np, nq ir.Node) []ir.Node {
// The conditions are a list-of-lists. Conditions are reorderable
// within each inner list. The outer lists must be evaluated in order.
var conds [][]ir.Node
conds = append(conds, []ir.Node{})
and := func(n ir.Node) {
i := len(conds) - 1
conds[i] = append(conds[i], n)
}
// Walk the struct using memequal for runs of AMEM
// and calling specific equality tests for the others.
for i, fields := 0, t.FieldSlice(); i < len(fields); {
f := fields[i]
// Skip blank-named fields.
if f.Sym.IsBlank() {
i++
continue
}
// Compare non-memory fields with field equality.
if !IsRegularMemory(f.Type) {
if EqCanPanic(f.Type) {
// Enforce ordering by starting a new set of reorderable conditions.
conds = append(conds, []ir.Node{})
}
p := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym)
q := ir.NewSelectorExpr(base.Pos, ir.OXDOT, nq, f.Sym)
switch {
case f.Type.IsString():
eqlen, eqmem := EqString(p, q)
and(eqlen)
and(eqmem)
default:
and(ir.NewBinaryExpr(base.Pos, ir.OEQ, p, q))
}
if EqCanPanic(f.Type) {
// Also enforce ordering after something that can panic.
conds = append(conds, []ir.Node{})
}
i++
continue
}
// Find maximal length run of memory-only fields.
size, next := Memrun(t, i)
// TODO(rsc): All the calls to newname are wrong for
// cross-package unexported fields.
if s := fields[i:next]; len(s) <= 2 {
// Two or fewer fields: use plain field equality.
for _, f := range s {
and(eqfield(np, nq, ir.OEQ, f.Sym))
}
} else {
// More than two fields: use memequal.
cc := eqmem(np, nq, f.Sym, size)
and(cc)
}
i = next
}
// Sort conditions to put runtime calls last.
// Preserve the rest of the ordering.
var flatConds []ir.Node
for _, c := range conds {
isCall := func(n ir.Node) bool {
return n.Op() == ir.OCALL || n.Op() == ir.OCALLFUNC
}
sort.SliceStable(c, func(i, j int) bool {
return !isCall(c[i]) && isCall(c[j])
})
flatConds = append(flatConds, c...)
}
return flatConds
}
// EqString returns the nodes
//
// len(s) == len(t)
//
// and
//
// memequal(s.ptr, t.ptr, len(s))
//
// which can be used to construct string equality comparison.
// eqlen must be evaluated before eqmem, and shortcircuiting is required.
func EqString(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
s = typecheck.Conv(s, types.Types[types.TSTRING])
t = typecheck.Conv(t, types.Types[types.TSTRING])
sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
tptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, t)
slen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, s), types.Types[types.TUINTPTR])
tlen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, t), types.Types[types.TUINTPTR])
fn := typecheck.LookupRuntime("memequal")
fn = typecheck.SubstArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
call := typecheck.Call(base.Pos, fn, []ir.Node{sptr, tptr, ir.Copy(slen)}, false).(*ir.CallExpr)
cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, slen, tlen)
cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
cmp.SetType(types.Types[types.TBOOL])
return cmp, call
}
// EqInterface returns the nodes
//
// s.tab == t.tab (or s.typ == t.typ, as appropriate)
//
// and
//
// ifaceeq(s.tab, s.data, t.data) (or efaceeq(s.typ, s.data, t.data), as appropriate)
//
// which can be used to construct interface equality comparison.
// eqtab must be evaluated before eqdata, and shortcircuiting is required.
func EqInterface(s, t ir.Node) (eqtab *ir.BinaryExpr, eqdata *ir.CallExpr) {
if !types.Identical(s.Type(), t.Type()) {
base.Fatalf("EqInterface %v %v", s.Type(), t.Type())
}
// func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
// func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
var fn ir.Node
if s.Type().IsEmptyInterface() {
fn = typecheck.LookupRuntime("efaceeq")
} else {
fn = typecheck.LookupRuntime("ifaceeq")
}
stab := ir.NewUnaryExpr(base.Pos, ir.OITAB, s)
ttab := ir.NewUnaryExpr(base.Pos, ir.OITAB, t)
sdata := ir.NewUnaryExpr(base.Pos, ir.OIDATA, s)
tdata := ir.NewUnaryExpr(base.Pos, ir.OIDATA, t)
sdata.SetType(types.Types[types.TUNSAFEPTR])
tdata.SetType(types.Types[types.TUNSAFEPTR])
sdata.SetTypecheck(1)
tdata.SetTypecheck(1)
call := typecheck.Call(base.Pos, fn, []ir.Node{stab, sdata, tdata}, false).(*ir.CallExpr)
cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, stab, ttab)
cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
cmp.SetType(types.Types[types.TBOOL])
return cmp, call
}
// eqfield returns the node
//
// p.field == q.field
func eqfield(p ir.Node, q ir.Node, op ir.Op, field *types.Sym) ir.Node {
nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)
ny := ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)
ne := ir.NewBinaryExpr(base.Pos, op, nx, ny)
return ne
}
// eqmem returns the node
//
// memequal(&p.field, &q.field, size])
func eqmem(p ir.Node, q ir.Node, field *types.Sym, size int64) ir.Node {
nx := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)))
ny := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)))
fn, needsize := eqmemfunc(size, nx.Type().Elem())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args.Append(nx)
call.Args.Append(ny)
if needsize {
call.Args.Append(ir.NewInt(size))
}
return call
}
func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) {
switch size {
default:
fn = typecheck.LookupRuntime("memequal")
needsize = true
case 1, 2, 4, 8, 16:
buf := fmt.Sprintf("memequal%d", int(size)*8)
fn = typecheck.LookupRuntime(buf)
}
fn = typecheck.SubstArgTypes(fn, t, t)
return fn, needsize
}

View File

@ -422,8 +422,6 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
}
if fn.Pragma&ir.UintptrEscapes != 0 {
fn.Pragma |= ir.UintptrKeepAlive
if f.Type.IsUintptr() {
if diagnose {
base.WarnfAt(f.Pos, "marking %v as escaping uintptr", name())

View File

@ -120,6 +120,17 @@ func CanInline(fn *ir.Func) {
return
}
// If marked as "go:uintptrkeepalive", don't inline, since the
// keep alive information is lost during inlining.
//
// TODO(prattmic): This is handled on calls during escape analysis,
// which is after inlining. Move prior to inlining so the keep-alive is
// maintained after inlining.
if fn.Pragma&ir.UintptrKeepAlive != 0 {
reason = "marked as having a keep-alive uintptr argument"
return
}
// If marked as "go:uintptrescapes", don't inline, since the
// escape information is lost during inlining.
if fn.Pragma&ir.UintptrEscapes != 0 {

View File

@ -459,7 +459,7 @@ const (
Noinline // func should not be inlined
NoCheckPtr // func should not be instrumented by checkptr
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
UintptrKeepAlive // pointers converted to uintptr must be kept alive (compiler internal only)
UintptrKeepAlive // pointers converted to uintptr must be kept alive
UintptrEscapes // pointers converted to uintptr escape
// Runtime-only func pragmas.

View File

@ -125,8 +125,26 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
}
}
if decl.Body != nil && fn.Pragma&ir.Noescape != 0 {
base.ErrorfAt(fn.Pos(), "can only use //go:noescape with external func implementations")
if decl.Body != nil {
if fn.Pragma&ir.Noescape != 0 {
base.ErrorfAt(fn.Pos(), "can only use //go:noescape with external func implementations")
}
if (fn.Pragma&ir.UintptrKeepAlive != 0 && fn.Pragma&ir.UintptrEscapes == 0) && fn.Pragma&ir.Nosplit == 0 {
// Stack growth can't handle uintptr arguments that may
// be pointers (as we don't know which are pointers
// when creating the stack map). Thus uintptrkeepalive
// functions (and all transitive callees) must be
// nosplit.
//
// N.B. uintptrescapes implies uintptrkeepalive but it
// is OK since the arguments must escape to the heap.
//
// TODO(prattmic): Add recursive nosplit check of callees.
// TODO(prattmic): Functions with no body (i.e.,
// assembly) must also be nosplit, but we can't check
// that here.
base.ErrorfAt(fn.Pos(), "go:uintptrkeepalive requires go:nosplit")
}
}
if decl.Name.Value == "init" && decl.Recv == nil {

View File

@ -30,6 +30,7 @@ const (
ir.NoCheckPtr |
ir.RegisterParams | // TODO(register args) remove after register abi is working
ir.CgoUnsafeArgs |
ir.UintptrKeepAlive |
ir.UintptrEscapes |
ir.Systemstack |
ir.Nowritebarrier |
@ -67,19 +68,13 @@ func pragmaFlag(verb string) ir.PragmaFlag {
return ir.Yeswritebarrierrec
case "go:cgo_unsafe_args":
return ir.CgoUnsafeArgs | ir.NoCheckPtr // implies NoCheckPtr (see #34968)
case "go:uintptrkeepalive":
return ir.UintptrKeepAlive
case "go:uintptrescapes":
// For the next function declared in the file
// any uintptr arguments may be pointer values
// converted to uintptr. This directive
// ensures that the referenced allocated
// object, if any, is retained and not moved
// until the call completes, even though from
// the types alone it would appear that the
// object is no longer needed during the
// call. The conversion to uintptr must appear
// in the argument list.
// Used in syscall/dll_windows.go.
return ir.UintptrEscapes
// This directive extends //go:uintptrkeepalive by forcing
// uintptr arguments to escape to the heap, which makes stack
// growth safe.
return ir.UintptrEscapes | ir.UintptrKeepAlive // implies UintptrKeepAlive
case "go:registerparams": // TODO(register args) remove after register abi is working
return ir.RegisterParams
case "go:notinheap":

View File

@ -340,6 +340,9 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P
if !base.Flag.CompilingRuntime && flag&runtimePragmas != 0 {
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in runtime", verb)})
}
if flag == ir.UintptrKeepAlive && !base.Flag.Std {
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s is only allowed in the standard library", verb)})
}
if flag == 0 && !allowedStdPragmas[verb] && base.Flag.Std {
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s is not allowed in the standard library", verb)})
}

View File

@ -742,6 +742,22 @@ func (w *writer) funcExt(obj *types2.Func) {
if pragma&ir.Noescape != 0 {
w.p.errorf(decl, "can only use //go:noescape with external func implementations")
}
if (pragma&ir.UintptrKeepAlive != 0 && pragma&ir.UintptrEscapes == 0) && pragma&ir.Nosplit == 0 {
// Stack growth can't handle uintptr arguments that may
// be pointers (as we don't know which are pointers
// when creating the stack map). Thus uintptrkeepalive
// functions (and all transitive callees) must be
// nosplit.
//
// N.B. uintptrescapes implies uintptrkeepalive but it
// is OK since the arguments must escape to the heap.
//
// TODO(prattmic): Add recursive nosplit check of callees.
// TODO(prattmic): Functions with no body (i.e.,
// assembly) must also be nosplit, but we can't check
// that here.
w.p.errorf(decl, "go:uintptrkeepalive requires go:nosplit")
}
} else {
if base.Flag.Complete || decl.Name.Value == "init" {
// Linknamed functions are allowed to have no body. Hopefully

View File

@ -6,10 +6,9 @@ package reflectdata
import (
"fmt"
"math/bits"
"sort"
"cmd/compile/internal/base"
"cmd/compile/internal/compare"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
"cmd/compile/internal/typecheck"
@ -17,32 +16,6 @@ import (
"cmd/internal/obj"
)
// isRegularMemory reports whether t can be compared/hashed as regular memory.
func isRegularMemory(t *types.Type) bool {
a, _ := types.AlgType(t)
return a == types.AMEM
}
// eqCanPanic reports whether == on type t could panic (has an interface somewhere).
// t must be comparable.
func eqCanPanic(t *types.Type) bool {
switch t.Kind() {
default:
return false
case types.TINTER:
return true
case types.TARRAY:
return eqCanPanic(t.Elem())
case types.TSTRUCT:
for _, f := range t.FieldSlice() {
if !f.Sym.IsBlank() && eqCanPanic(f.Type) {
return true
}
}
return false
}
}
// AlgType returns the fixed-width AMEMxx variants instead of the general
// AMEM kind when possible.
func AlgType(t *types.Type) types.AlgKind {
@ -206,7 +179,7 @@ func genhash(t *types.Type) *obj.LSym {
}
// Hash non-memory fields with appropriate hash function.
if !isRegularMemory(f.Type) {
if !compare.IsRegularMemory(f.Type) {
hashel := hashfor(f.Type)
call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
@ -219,7 +192,7 @@ func genhash(t *types.Type) *obj.LSym {
}
// Otherwise, hash a maximal length run of raw memory.
size, next := memrun(t, i)
size, next := compare.Memrun(t, i)
// h = hashel(&p.first, size, h)
hashel := hashmem(f.Type)
@ -510,12 +483,12 @@ func geneq(t *types.Type) *obj.LSym {
// Second, check that all the contents match (expensive).
checkAll(3, false, func(pi, qi ir.Node) ir.Node {
// Compare lengths.
eqlen, _ := EqString(pi, qi)
eqlen, _ := compare.EqString(pi, qi)
return eqlen
})
checkAll(1, true, func(pi, qi ir.Node) ir.Node {
// Compare contents.
_, eqmem := EqString(pi, qi)
_, eqmem := compare.EqString(pi, qi)
return eqmem
})
case types.TFLOAT32, types.TFLOAT64:
@ -532,81 +505,7 @@ func geneq(t *types.Type) *obj.LSym {
}
case types.TSTRUCT:
// Build a list of conditions to satisfy.
// The conditions are a list-of-lists. Conditions are reorderable
// within each inner list. The outer lists must be evaluated in order.
var conds [][]ir.Node
conds = append(conds, []ir.Node{})
and := func(n ir.Node) {
i := len(conds) - 1
conds[i] = append(conds[i], n)
}
// Walk the struct using memequal for runs of AMEM
// and calling specific equality tests for the others.
for i, fields := 0, t.FieldSlice(); i < len(fields); {
f := fields[i]
// Skip blank-named fields.
if f.Sym.IsBlank() {
i++
continue
}
// Compare non-memory fields with field equality.
if !isRegularMemory(f.Type) {
if eqCanPanic(f.Type) {
// Enforce ordering by starting a new set of reorderable conditions.
conds = append(conds, []ir.Node{})
}
p := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym)
q := ir.NewSelectorExpr(base.Pos, ir.OXDOT, nq, f.Sym)
switch {
case f.Type.IsString():
eqlen, eqmem := EqString(p, q)
and(eqlen)
and(eqmem)
default:
and(ir.NewBinaryExpr(base.Pos, ir.OEQ, p, q))
}
if eqCanPanic(f.Type) {
// Also enforce ordering after something that can panic.
conds = append(conds, []ir.Node{})
}
i++
continue
}
// Find maximal length run of memory-only fields.
size, next := memrun(t, i)
// TODO(rsc): All the calls to newname are wrong for
// cross-package unexported fields.
if s := fields[i:next]; len(s) <= 2 {
// Two or fewer fields: use plain field equality.
for _, f := range s {
and(eqfield(np, nq, f.Sym))
}
} else {
// More than two fields: use memequal.
and(eqmem(np, nq, f.Sym, size))
}
i = next
}
// Sort conditions to put runtime calls last.
// Preserve the rest of the ordering.
var flatConds []ir.Node
for _, c := range conds {
isCall := func(n ir.Node) bool {
return n.Op() == ir.OCALL || n.Op() == ir.OCALLFUNC
}
sort.SliceStable(c, func(i, j int) bool {
return !isCall(c[i]) && isCall(c[j])
})
flatConds = append(flatConds, c...)
}
flatConds := compare.EqStruct(t, np, nq)
if len(flatConds) == 0 {
fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, ir.NewBool(true)))
} else {
@ -631,7 +530,7 @@ func geneq(t *types.Type) *obj.LSym {
// return (or goto ret)
fn.Body.Append(ir.NewLabelStmt(base.Pos, neq))
fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, ir.NewBool(false)))
if eqCanPanic(t) || anyCall(fn) {
if compare.EqCanPanic(t) || anyCall(fn) {
// Epilogue is large, so share it with the equal case.
fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.OGOTO, ret))
} else {
@ -680,153 +579,6 @@ func anyCall(fn *ir.Func) bool {
})
}
// eqfield returns the node
//
// p.field == q.field
func eqfield(p ir.Node, q ir.Node, field *types.Sym) ir.Node {
nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)
ny := ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)
ne := ir.NewBinaryExpr(base.Pos, ir.OEQ, nx, ny)
return ne
}
// EqString returns the nodes
//
// len(s) == len(t)
//
// and
//
// memequal(s.ptr, t.ptr, len(s))
//
// which can be used to construct string equality comparison.
// eqlen must be evaluated before eqmem, and shortcircuiting is required.
func EqString(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
s = typecheck.Conv(s, types.Types[types.TSTRING])
t = typecheck.Conv(t, types.Types[types.TSTRING])
sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
tptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, t)
slen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, s), types.Types[types.TUINTPTR])
tlen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, t), types.Types[types.TUINTPTR])
fn := typecheck.LookupRuntime("memequal")
fn = typecheck.SubstArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
call := typecheck.Call(base.Pos, fn, []ir.Node{sptr, tptr, ir.Copy(slen)}, false).(*ir.CallExpr)
cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, slen, tlen)
cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
cmp.SetType(types.Types[types.TBOOL])
return cmp, call
}
// EqInterface returns the nodes
//
// s.tab == t.tab (or s.typ == t.typ, as appropriate)
//
// and
//
// ifaceeq(s.tab, s.data, t.data) (or efaceeq(s.typ, s.data, t.data), as appropriate)
//
// which can be used to construct interface equality comparison.
// eqtab must be evaluated before eqdata, and shortcircuiting is required.
func EqInterface(s, t ir.Node) (eqtab *ir.BinaryExpr, eqdata *ir.CallExpr) {
if !types.Identical(s.Type(), t.Type()) {
base.Fatalf("EqInterface %v %v", s.Type(), t.Type())
}
// func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
// func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
var fn ir.Node
if s.Type().IsEmptyInterface() {
fn = typecheck.LookupRuntime("efaceeq")
} else {
fn = typecheck.LookupRuntime("ifaceeq")
}
stab := ir.NewUnaryExpr(base.Pos, ir.OITAB, s)
ttab := ir.NewUnaryExpr(base.Pos, ir.OITAB, t)
sdata := ir.NewUnaryExpr(base.Pos, ir.OIDATA, s)
tdata := ir.NewUnaryExpr(base.Pos, ir.OIDATA, t)
sdata.SetType(types.Types[types.TUNSAFEPTR])
tdata.SetType(types.Types[types.TUNSAFEPTR])
sdata.SetTypecheck(1)
tdata.SetTypecheck(1)
call := typecheck.Call(base.Pos, fn, []ir.Node{stab, sdata, tdata}, false).(*ir.CallExpr)
cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, stab, ttab)
cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
cmp.SetType(types.Types[types.TBOOL])
return cmp, call
}
// eqmem returns the node
//
// memequal(&p.field, &q.field [, size])
func eqmem(p ir.Node, q ir.Node, field *types.Sym, size int64) ir.Node {
nx := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)))
ny := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)))
fn, needsize := eqmemfunc(size, nx.Type().Elem())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args.Append(nx)
call.Args.Append(ny)
if needsize {
call.Args.Append(ir.NewInt(size))
}
return call
}
func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) {
switch size {
default:
fn = typecheck.LookupRuntime("memequal")
needsize = true
case 1, 2, 4, 8, 16:
buf := fmt.Sprintf("memequal%d", int(size)*8)
fn = typecheck.LookupRuntime(buf)
}
fn = typecheck.SubstArgTypes(fn, t, t)
return fn, needsize
}
// memrun finds runs of struct fields for which memory-only algs are appropriate.
// t is the parent struct type, and start is the field index at which to start the run.
// size is the length in bytes of the memory included in the run.
// next is the index just after the end of the memory run.
func memrun(t *types.Type, start int) (size int64, next int) {
next = start
for {
next++
if next == t.NumFields() {
break
}
// Stop run after a padded field.
if types.IsPaddedField(t, next-1) {
break
}
// Also, stop before a blank or non-memory field.
if f := t.Field(next); f.Sym.IsBlank() || !isRegularMemory(f.Type) {
break
}
// For issue 46283, don't combine fields if the resulting load would
// require a larger alignment than the component fields.
if base.Ctxt.Arch.Alignment > 1 {
align := t.Alignment()
if off := t.Field(start).Offset; off&(align-1) != 0 {
// Offset is less aligned than the containing type.
// Use offset to determine alignment.
align = 1 << uint(bits.TrailingZeros64(uint64(off)))
}
size := t.Field(next).End() - t.Field(start).Offset
if size > align {
break
}
}
}
return t.Field(next-1).End() - t.Field(start).Offset, next
}
func hashmem(t *types.Type) ir.Node {
sym := ir.Pkgs.Runtime.Lookup("memhash")

View File

@ -14,6 +14,7 @@ import (
"cmd/compile/internal/base"
"cmd/compile/internal/bitvec"
"cmd/compile/internal/compare"
"cmd/compile/internal/escape"
"cmd/compile/internal/inline"
"cmd/compile/internal/ir"
@ -728,7 +729,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
if t.Sym() != nil && t.Sym().Name != "" {
tflag |= tflagNamed
}
if isRegularMemory(t) {
if compare.IsRegularMemory(t) {
tflag |= tflagRegularMemory
}

View File

@ -827,7 +827,7 @@ func (p *parser) unaryExpr() Expr {
switch p.tok {
case _Operator, _Star:
switch p.op {
case Mul, Add, Sub, Not, Xor:
case Mul, Add, Sub, Not, Xor, Tilde:
x := new(Operation)
x.pos = p.pos()
x.Op = p.op
@ -991,7 +991,7 @@ func (p *parser) operand(keep_parens bool) Expr {
case _Func:
pos := p.pos()
p.next()
_, ftyp := p.funcType("function literal")
_, ftyp := p.funcType("function type")
if p.tok == _Lbrace {
p.xnest++
@ -1499,44 +1499,14 @@ func (p *parser) interfaceType() *InterfaceType {
p.want(_Interface)
p.want(_Lbrace)
p.list("interface type", _Semi, _Rbrace, func() bool {
switch p.tok {
case _Name:
f := p.methodDecl()
if f.Name == nil {
f = p.embeddedElem(f)
}
typ.MethodList = append(typ.MethodList, f)
return false
case _Lparen:
p.syntaxError("cannot parenthesize embedded type")
f := new(Field)
f.pos = p.pos()
p.next()
f.Type = p.qualifiedName(nil)
p.want(_Rparen)
typ.MethodList = append(typ.MethodList, f)
return false
case _Operator:
if p.op == Tilde {
typ.MethodList = append(typ.MethodList, p.embeddedElem(nil))
return false
}
default:
pos := p.pos()
if t := p.typeOrNil(); t != nil {
f := new(Field)
f.pos = pos
f.Type = t
typ.MethodList = append(typ.MethodList, p.embeddedElem(f))
return false
}
var f *Field
if p.tok == _Name {
f = p.methodDecl()
}
p.syntaxError("expecting method or embedded element")
p.advance(_Semi, _Rbrace)
if f == nil || f.Name == nil {
f = p.embeddedElem(f)
}
typ.MethodList = append(typ.MethodList, f)
return false
})

View File

@ -8,7 +8,8 @@ type _ func /* ERROR function type must have no type parameters */ [ /* ERROR em
type _ func /* ERROR function type must have no type parameters */ [ x /* ERROR missing type constraint */ ]()
type _ func /* ERROR function type must have no type parameters */ [P any]()
var _ = func /* ERROR function literal must have no type parameters */ [P any]() {}
var _ = (func /* ERROR function type must have no type parameters */ [P any]())(nil)
var _ = func /* ERROR function type must have no type parameters */ [P any]() {}
type _ interface{
m /* ERROR interface method must have no type parameters */ [P any]()

View File

@ -0,0 +1,17 @@
// Copyright 2022 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
type _ interface {
int
(int)
(*int)
*([]byte)
~(int)
(int) | (string)
(int) | ~(string)
(/* ERROR unexpected ~ */ ~int)
(int /* ERROR unexpected \| */ | /* ERROR unexpected string */ string /* ERROR unexpected \) */ )
}

View File

@ -65,15 +65,17 @@ func _[_ t[t] | t[t]]() {}
// Single-expression type parameter lists and those that don't start
// with a (type parameter) name are considered array sizes.
// The term must be a valid expression (it could be a type - and then
// a type-checker will complain - but we don't allow ~ in the expr).
// The term must be a valid expression (it could be a type incl. a
// tilde term) but the type-checker will complain.
type (
_[t] t
_[/* ERROR unexpected ~ */ ~t] t
_[t|t] t
_[/* ERROR unexpected ~ */ ~t|t] t
_[t| /* ERROR unexpected ~ */ ~t] t
_[/* ERROR unexpected ~ */ ~t|~t] t
// These are invalid and the type-checker will complain.
_[~t] t
_[~t|t] t
_[t|~t] t
_[~t|~t] t
)
type (

View File

@ -128,15 +128,33 @@ func TestIntendedInlining(t *testing.T) {
"ValidRune",
},
"reflect": {
"Value.CanInt",
"Value.CanUint",
"Value.CanFloat",
"Value.CanComplex",
"Value.Bool",
"Value.Bytes",
"Value.CanAddr",
"Value.CanSet",
"Value.CanComplex",
"Value.CanFloat",
"Value.CanInt",
"Value.CanInterface",
"Value.CanSet",
"Value.CanUint",
"Value.Cap",
"Value.Complex",
"Value.Float",
"Value.Int",
"Value.Interface",
"Value.IsNil",
"Value.IsValid",
"Value.Kind",
"Value.Len",
"Value.MapRange",
"Value.OverflowComplex",
"Value.OverflowFloat",
"Value.OverflowInt",
"Value.OverflowUint",
"Value.String",
"Value.Type",
"Value.Uint",
"Value.UnsafeAddr",
"Value.pointer",
"add",
"align",

View File

@ -735,7 +735,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
top := len(check.delayed)
// iota is the index of the current constDecl within the group
if first < 0 || list[index-1].(*syntax.ConstDecl).Group != s.Group {
if first < 0 || s.Group == nil || list[index-1].(*syntax.ConstDecl).Group != s.Group {
first = index
last = nil
}

View File

@ -89,21 +89,11 @@ func (check *Checker) op(m opPredicates, x *operand, op syntax.Operator) bool {
func (check *Checker) overflow(x *operand) {
assert(x.mode == constant_)
// If the corresponding expression is an operation, use the
// operator position rather than the start of the expression
// as error position.
pos := syntax.StartPos(x.expr)
what := "" // operator description, if any
if op, _ := x.expr.(*syntax.Operation); op != nil {
pos = op.Pos()
what = opName(op)
}
if x.val.Kind() == constant.Unknown {
// TODO(gri) We should report exactly what went wrong. At the
// moment we don't have the (go/constant) API for that.
// See also TODO in go/constant/value.go.
check.error(pos, "constant result is not representable")
check.error(opPos(x.expr), "constant result is not representable")
return
}
@ -119,22 +109,37 @@ func (check *Checker) overflow(x *operand) {
// Untyped integer values must not grow arbitrarily.
const prec = 512 // 512 is the constant precision
if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
check.errorf(pos, "constant %s overflow", what)
check.errorf(opPos(x.expr), "constant %s overflow", opName(x.expr))
x.val = constant.MakeUnknown()
}
}
// opName returns the name of an operation, or the empty string.
// Only operations that might overflow are handled.
func opName(e *syntax.Operation) string {
op := int(e.Op)
if e.Y == nil {
if op < len(op2str1) {
return op2str1[op]
}
} else {
if op < len(op2str2) {
return op2str2[op]
// opPos returns the position of the operator if x is an operation;
// otherwise it returns the start position of x.
func opPos(x syntax.Expr) syntax.Pos {
switch op := x.(type) {
case nil:
return nopos // don't crash
case *syntax.Operation:
return op.Pos()
default:
return syntax.StartPos(x)
}
}
// opName returns the name of the operation if x is an operation
// that might overflow; otherwise it returns the empty string.
func opName(x syntax.Expr) string {
if e, _ := x.(*syntax.Operation); e != nil {
op := int(e.Op)
if e.Y == nil {
if op < len(op2str1) {
return op2str1[op]
}
} else {
if op < len(op2str2) {
return op2str2[op]
}
}
}
return ""
@ -203,6 +208,12 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
x.typ = ch.elem
check.hasCallOrRecv = true
return
case syntax.Tilde:
// Provide a better error position and message than what check.op below could do.
check.error(e, "cannot use ~ outside of interface or type constraint")
x.mode = invalid
return
}
if !check.op(unaryOpPredicates, x, e.Op) {

View File

@ -340,7 +340,7 @@ func (check *Checker) collectObjects() {
case *syntax.ConstDecl:
// iota is the index of the current constDecl within the group
if first < 0 || file.DeclList[index-1].(*syntax.ConstDecl).Group != s.Group {
if first < 0 || s.Group == nil || file.DeclList[index-1].(*syntax.ConstDecl).Group != s.Group {
first = index
last = nil
}

View File

@ -166,10 +166,11 @@ func (s *StdSizes) Sizeof(T Type) int64 {
// common architecture word sizes and alignments
var gcArchSizes = map[string]*StdSizes{
"386": {4, 4},
"arm": {4, 4},
"arm64": {8, 8},
"amd64": {8, 8},
"amd64p32": {4, 8},
"arm": {4, 4},
"arm64": {8, 8},
"loong64": {8, 8},
"mips": {4, 4},
"mipsle": {4, 4},
"mips64": {8, 8},
@ -188,7 +189,7 @@ var gcArchSizes = map[string]*StdSizes{
// The result is nil if a compiler/architecture pair is not known.
//
// Supported architectures for compiler "gc":
// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
// "386", "amd64", "amd64p32", "arm", "arm64", "loong64", "mips", "mipsle",
// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "sparc64", "wasm".
func SizesFor(compiler, arch string) Sizes {
var m map[string]*StdSizes

View File

@ -349,6 +349,25 @@ const _ = unsafe.Sizeof(func() {
assert(iota == 0)
})
// issue #52438
const i1 = iota
const i2 = iota
const i3 = iota
func _() {
assert(i1 == 0)
assert(i2 == 0)
assert(i3 == 0)
const i4 = iota
const i5 = iota
const i6 = iota
assert(i4 == 0)
assert(i5 == 0)
assert(i6 == 0)
}
// untyped constants must not get arbitrarily large
const prec = 512 // internal maximum precision for integers
const maxInt = (1<<(prec/2) - 1) * (1<<(prec/2) + 1) // == 1<<prec - 1

View File

@ -178,3 +178,10 @@ func _() {
_ = -g /* ERROR 2-valued g */ ()
_ = <-g /* ERROR 2-valued g */ ()
}
// ~ is accepted as unary operator only permitted in interface type elements
var (
_ = ~ /* ERROR cannot use ~ outside of interface or type constraint */ 0
_ = ~ /* ERROR cannot use ~ outside of interface or type constraint */ "foo"
_ = ~ /* ERROR cannot use ~ outside of interface or type constraint */ i0
)

View File

@ -22,4 +22,4 @@ type _[P /* ERROR non-function P */ (*int)] int
type _[P *struct /* ERROR "not an expression" */ {}| int /* ERROR "not an expression" */ ] struct{}
// The following fails to parse, due to the '~'
type _[P *struct /* ERROR "not an expression" */ {}|~ /* ERROR "unexpected ~" */ int] struct{}
type _[P *struct /* ERROR "not an expression" */ {}|~int /* ERROR "not an expression" */ ] struct{}

View File

@ -0,0 +1,11 @@
// Copyright 2022 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 _() {
const x = 0
x /* ERROR cannot assign to x */ += 1
x /* ERROR cannot assign to x */ ++
}

View File

@ -8,6 +8,7 @@ import (
"go/constant"
"cmd/compile/internal/base"
"cmd/compile/internal/compare"
"cmd/compile/internal/ir"
"cmd/compile/internal/reflectdata"
"cmd/compile/internal/ssagen"
@ -178,7 +179,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
andor = ir.OOROR
}
var expr ir.Node
compare := func(el, er ir.Node) {
comp := func(el, er ir.Node) {
a := ir.NewBinaryExpr(base.Pos, n.Op(), el, er)
if expr == nil {
expr = a
@ -186,18 +187,26 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
expr = ir.NewLogicalExpr(base.Pos, andor, expr, a)
}
}
and := func(cond ir.Node) {
if expr == nil {
expr = cond
} else {
expr = ir.NewLogicalExpr(base.Pos, andor, expr, cond)
}
}
cmpl = safeExpr(cmpl, init)
cmpr = safeExpr(cmpr, init)
if t.IsStruct() {
for _, f := range t.Fields().Slice() {
sym := f.Sym
if sym.IsBlank() {
continue
conds := compare.EqStruct(t, cmpl, cmpr)
if n.Op() == ir.OEQ {
for _, cond := range conds {
and(cond)
}
} else {
for _, cond := range conds {
notCond := ir.NewUnaryExpr(base.Pos, ir.ONOT, cond)
and(notCond)
}
compare(
ir.NewSelectorExpr(base.Pos, ir.OXDOT, cmpl, sym),
ir.NewSelectorExpr(base.Pos, ir.OXDOT, cmpr, sym),
)
}
} else {
step := int64(1)
@ -221,7 +230,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
step = 1
}
if step == 1 {
compare(
comp(
ir.NewIndexExpr(base.Pos, cmpl, ir.NewInt(i)),
ir.NewIndexExpr(base.Pos, cmpr, ir.NewInt(i)),
)
@ -249,7 +258,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
rb = ir.NewBinaryExpr(base.Pos, ir.OLSH, rb, ir.NewInt(8*t.Elem().Size()*offset))
cmprw = ir.NewBinaryExpr(base.Pos, ir.OOR, cmprw, rb)
}
compare(cmplw, cmprw)
comp(cmplw, cmprw)
i += step
remains -= step * t.Elem().Size()
}
@ -270,7 +279,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
func walkCompareInterface(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
n.Y = cheapExpr(n.Y, init)
n.X = cheapExpr(n.X, init)
eqtab, eqdata := reflectdata.EqInterface(n.X, n.Y)
eqtab, eqdata := compare.EqInterface(n.X, n.Y)
var cmp ir.Node
if n.Op() == ir.OEQ {
cmp = ir.NewLogicalExpr(base.Pos, ir.OANDAND, eqtab, eqdata)
@ -384,7 +393,7 @@ func walkCompareString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
// prepare for rewrite below
n.X = cheapExpr(n.X, init)
n.Y = cheapExpr(n.Y, init)
eqlen, eqmem := reflectdata.EqString(n.X, n.Y)
eqlen, eqmem := compare.EqString(n.X, n.Y)
// quick check of len before full compare for == or !=.
// memequal then tests equality up to length len.
if n.Op() == ir.OEQ {

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

@ -556,6 +556,55 @@ func (t *tester) registerTests() {
})
}
// morestack tests. We only run these on in long-test mode
// (with GO_TEST_SHORT=false) because the runtime test is
// already quite long and mayMoreStackMove makes it about
// twice as slow.
if !t.compileOnly && short() == "false" {
// hooks is the set of maymorestack hooks to test with.
hooks := []string{"mayMoreStackPreempt", "mayMoreStackMove"}
// pkgs is the set of test packages to run.
pkgs := []string{"runtime", "reflect", "sync"}
// hookPkgs is the set of package patterns to apply
// the maymorestack hook to.
hookPkgs := []string{"runtime/...", "reflect", "sync"}
// unhookPkgs is the set of package patterns to
// exclude from hookPkgs.
unhookPkgs := []string{"runtime/testdata/..."}
for _, hook := range hooks {
// Construct the build flags to use the
// maymorestack hook in the compiler and
// assembler. We pass this via the GOFLAGS
// environment variable so that it applies to
// both the test itself and to binaries built
// by the test.
goFlagsList := []string{}
for _, flag := range []string{"-gcflags", "-asmflags"} {
for _, hookPkg := range hookPkgs {
goFlagsList = append(goFlagsList, flag+"="+hookPkg+"=-d=maymorestack=runtime."+hook)
}
for _, unhookPkg := range unhookPkgs {
goFlagsList = append(goFlagsList, flag+"="+unhookPkg+"=")
}
}
goFlags := strings.Join(goFlagsList, " ")
for _, pkg := range pkgs {
pkg := pkg
testName := hook + ":" + pkg
t.tests = append(t.tests, distTest{
name: testName,
heading: "maymorestack=" + hook,
fn: func(dt *distTest) error {
cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(600), pkg, "-short")
setEnv(cmd, "GOFLAGS", goFlags)
return nil
},
})
}
}
}
// This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
// See issue 18153.
if goos == "linux" {

View File

@ -4,12 +4,20 @@
package base
import (
"fmt"
"path/filepath"
)
// AppendPWD returns the result of appending PWD=dir to the environment base.
//
// The resulting environment makes os.Getwd more efficient for a subprocess
// running in dir.
func AppendPWD(base []string, dir string) []string {
// Internally we only use absolute paths, so dir is absolute.
// Even if dir is not absolute, no harm done.
// POSIX requires PWD to be absolute.
// Internally we only use absolute paths, so dir should already be absolute.
if !filepath.IsAbs(dir) {
panic(fmt.Sprintf("AppendPWD with relative path %q", dir))
}
return append(base, "PWD="+dir)
}

View File

@ -5,7 +5,9 @@
package generate
import (
"internal/testenv"
"os"
"path/filepath"
"reflect"
"runtime"
"testing"
@ -41,10 +43,11 @@ var splitTests = []splitTest{
}
func TestGenerateCommandParse(t *testing.T) {
dir := filepath.Join(testenv.GOROOT(t), "src", "sys")
g := &Generator{
r: nil, // Unused here.
path: "/usr/ken/sys/proc.go",
dir: "/usr/ken/sys",
path: filepath.Join(dir, "proc.go"),
dir: dir,
file: "proc.go",
pkg: "sys",
commands: make(map[string][]string),
@ -84,10 +87,11 @@ var defEnvMap = map[string]string{
// before executing the test. i.e., execute the split as if it
// processing that source line.
func TestGenerateCommandShorthand(t *testing.T) {
dir := filepath.Join(testenv.GOROOT(t), "src", "sys")
g := &Generator{
r: nil, // Unused here.
path: "/usr/ken/sys/proc.go",
dir: "/usr/ken/sys",
path: filepath.Join(dir, "proc.go"),
dir: dir,
file: "proc.go",
pkg: "sys",
commands: make(map[string][]string),
@ -222,10 +226,11 @@ var splitTestsLines = []splitTestWithLine{
// before executing the test. i.e., execute the split as if it
// processing that source line.
func TestGenerateCommandShortHand2(t *testing.T) {
dir := filepath.Join(testenv.GOROOT(t), "src", "sys")
g := &Generator{
r: nil, // Unused here.
path: "/usr/ken/sys/proc.go",
dir: "/usr/ken/sys",
path: filepath.Join(dir, "proc.go"),
dir: dir,
file: "proc.go",
pkg: "sys",
commands: make(map[string][]string),

View File

@ -568,6 +568,13 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
IgnoreImports: *listFind,
ModResolveTests: *listTest,
LoadVCS: true,
// SuppressDeps is set if the user opts to explicitly ask for the json fields they
// need, don't ask for Deps or DepsErrors. It's not set when using a template string,
// even if *listFmt doesn't contain .Deps because Deps are used to find import cycles
// for test variants of packages and users who have been providing format strings
// might not expect those errors to stop showing up.
// See issue #52443.
SuppressDeps: !listJsonFields.needAny("Deps", "DepsErrors"),
}
pkgs := load.PackagesAndErrors(ctx, pkgOpts, args)
if !*listE {

View File

@ -1944,7 +1944,9 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
}
}
p.Internal.Imports = imports
p.collectDeps()
if !opts.SuppressDeps {
p.collectDeps()
}
if p.Error == nil && p.Name == "main" && !p.Internal.ForceLibrary && len(p.DepsErrors) == 0 {
// TODO(bcmills): loading VCS metadata can be fairly slow.
// Consider starting this as a background goroutine and retrieving the result
@ -2685,6 +2687,12 @@ type PackageOpts struct {
// LoadVCS controls whether we also load version-control metadata for main packages.
LoadVCS bool
// NeedDepsFields is true if the caller does not need Deps and DepsErrors to be populated
// on the package. TestPackagesAndErrors examines the Deps field to determine if the test
// variant has an import cycle, so SuppressDeps should not be set if TestPackagesAndErrors
// will be called on the package.
SuppressDeps bool
}
// PackagesAndErrors returns the packages named by the command line arguments

View File

@ -605,11 +605,13 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
pkg := pathInModuleCache(ctx, absDir, rs)
if pkg == "" {
scope := "main module or its selected dependencies"
if inWorkspaceMode() {
scope = "modules listed in go.work or their selected dependencies"
if mr := findModuleRoot(absDir); mr != "" {
return "", fmt.Errorf("directory %s is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using go work use %s", base.ShortPath(absDir), base.ShortPath(mr))
}
return "", fmt.Errorf("directory %s outside modules listed in go.work or their selected dependencies", base.ShortPath(absDir))
}
return "", fmt.Errorf("directory %s outside %s", base.ShortPath(absDir), scope)
return "", fmt.Errorf("directory %s outside main module or its selected dependencies", base.ShortPath(absDir))
}
return pkg, nil
}

View File

@ -22,7 +22,6 @@ import (
"sync"
"time"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/search"
"cmd/go/internal/str"
@ -657,7 +656,6 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([
cmd := exec.Command(v.Cmd, args...)
cmd.Dir = dir
cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir)
if cfg.BuildX {
fmt.Fprintf(os.Stderr, "cd %s\n", dir)
fmt.Fprintf(os.Stderr, "%s %s\n", v.Cmd, strings.Join(args, " "))
@ -669,7 +667,7 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
os.Stderr.Write(ee.Stderr)
} else {
fmt.Fprintf(os.Stderr, err.Error())
fmt.Fprintln(os.Stderr, err.Error())
}
}
}
@ -678,14 +676,24 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([
// Ping pings to determine scheme to use.
func (v *Cmd) Ping(scheme, repo string) error {
return v.runVerboseOnly(".", v.PingCmd, "scheme", scheme, "repo", repo)
// Run the ping command in an arbitrary working directory,
// but don't let the current working directory pollute the results.
// In module mode, we expect GOMODCACHE to exist and be a safe place for
// commands; in GOPATH mode, we expect that to be true of GOPATH/src.
dir := cfg.GOMODCACHE
if !cfg.ModulesEnabled {
dir = filepath.Join(cfg.BuildContext.GOPATH, "src")
}
os.MkdirAll(dir, 0777) // Ignore errors — if unsuccessful, the command will likely fail.
return v.runVerboseOnly(dir, v.PingCmd, "scheme", scheme, "repo", repo)
}
// Create creates a new copy of repo in dir.
// The parent of dir must exist; dir must not.
func (v *Cmd) Create(dir, repo string) error {
for _, cmd := range v.CreateCmd {
if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
if err := v.run(filepath.Dir(dir), cmd, "dir", dir, "repo", repo); err != nil {
return err
}
}

View File

@ -160,7 +160,6 @@ func (b *Builder) toolID(name string) string {
cmdline := str.StringList(cfg.BuildToolexec, path, "-V=full")
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
@ -219,9 +218,8 @@ func (b *Builder) gccToolID(name, language string) (string, error) {
// compile an empty file on standard input.
cmdline := str.StringList(cfg.BuildToolexec, name, "-###", "-x", language, "-c", "-")
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir)
// Force untranslated output so that we see the string "version".
cmd.Env = append(cmd.Env, "LC_ALL=C")
cmd.Env = append(os.Environ(), "LC_ALL=C")
out, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("%s: %v; output: %q", name, err, out)

View File

@ -2116,8 +2116,10 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...any) ([
cmd.Stderr = &buf
cleanup := passLongArgsInResponseFiles(cmd)
defer cleanup()
cmd.Dir = dir
cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir)
if dir != "." {
cmd.Dir = dir
}
cmd.Env = cmd.Environ() // Pre-allocate with correct PWD.
// Add the TOOLEXEC_IMPORTPATH environment variable for -toolexec tools.
// It doesn't really matter if -toolexec isn't being used.
@ -2606,8 +2608,7 @@ func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
}
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
cmd.Dir = b.WorkDir
cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir)
cmd.Env = append(cmd.Env, "LC_ALL=C")
cmd.Env = append(cmd.Environ(), "LC_ALL=C")
out, _ := cmd.CombinedOutput()
// GCC says "unrecognized command line option".
// clang says "unknown argument".
@ -3071,7 +3072,7 @@ var (
)
func (b *Builder) swigDoVersionCheck() error {
out, err := b.runOut(nil, "", nil, "swig", "-version")
out, err := b.runOut(nil, ".", nil, "swig", "-version")
if err != nil {
return err
}

View File

@ -21,6 +21,11 @@ cmp stdout want-json-name.txt
go list -json=ImportPath,Name,GoFiles,Imports
cmp stdout want-json-multiple.txt
# Test -json=<field> with Deps outputs the Deps field.
go list -json=Deps
stdout '"Deps": \['
stdout '"errors",'
-- go.mod --
module example.com/a

View File

@ -10,7 +10,7 @@ env GOSUMDB=off
# For a while, (*modfetch.codeRepo).Stat was not checking for a go.mod file,
# which would produce a hard error at the subsequent call to GoMod.
go get
go get -v
-- go.mod --
module example.com

View File

@ -6,8 +6,8 @@
! go list ./...
stderr 'pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies'
! go list ./a
stderr 'directory a outside modules listed in go.work'
! go list ./a/c
stderr 'directory a[\\/]c is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using go work use a'
-- go.work --
go 1.18
@ -19,6 +19,8 @@ module example.com/a
go 1.18
-- a/a.go --
package a
-- a/c/c.go --
package c
-- b/go.mod --
module example.com/b

View File

@ -76,6 +76,11 @@ func initParserMode() {
if *allErrors {
parserMode |= parser.AllErrors
}
// Both -r and -s make use of go/ast's object resolution.
// If neither is being used, avoid that unnecessary work.
if *rewriteRule == "" && !*simplifyAST {
parserMode |= parser.SkipObjectResolution
}
}
func isGoFile(f fs.DirEntry) bool {

View File

@ -726,11 +726,13 @@ func genFuncInfoSyms(ctxt *Link) {
}
o.Write(&b)
p := b.Bytes()
isym := &LSym{
Type: objabi.SDATA, // for now, I don't think it matters
PkgIdx: goobj.PkgIdxSelf,
SymIdx: symidx,
P: append([]byte(nil), b.Bytes()...),
P: append([]byte(nil), p...),
Size: int64(len(p)),
}
isym.Set(AttrIndexed, true)
symidx++

View File

@ -101,7 +101,7 @@ func (ctxt *Link) doStackCheck() {
// the same function multiple times at different
// depths, but lets us find all paths.
for _, root := range roots {
ctxt.Errorf(root, "nosplit stack overflow")
ctxt.Errorf(root, "nosplit stack over %d byte limit", limit)
chain := []stackCheckChain{{stackCheckEdge{0, root}, false}}
sc.report(root, limit, &chain)
}

View File

@ -5,13 +5,12 @@
package ld
import (
"cmd/internal/objabi"
"cmd/internal/sys"
"fmt"
"internal/testenv"
"os"
"os/exec"
"regexp"
"strconv"
"testing"
)
@ -24,7 +23,7 @@ func TestStackCheckOutput(t *testing.T) {
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", os.DevNull, "./testdata/stackcheck")
// The rules for computing frame sizes on all of the
// architectures are complicated, so just do this on amd64.
cmd.Env = append(os.Environ(), "GOARCH=amd64")
cmd.Env = append(os.Environ(), "GOARCH=amd64", "GOOS=linux")
outB, err := cmd.CombinedOutput()
if err == nil {
@ -34,13 +33,13 @@ func TestStackCheckOutput(t *testing.T) {
t.Logf("linker output:\n%s", out)
// Construct expected stanzas
arch := sys.ArchAMD64
call := 0
if !arch.HasLR {
call = arch.RegSize
// Get expected limit.
limitRe := regexp.MustCompile("nosplit stack over ([0-9]+) byte limit")
m := limitRe.FindStringSubmatch(out)
if m == nil {
t.Fatalf("no overflow errors in output")
}
limit := objabi.StackLimit - call
limit, _ := strconv.Atoi(m[1])
wantMap := map[string]string{
"main.startSelf": fmt.Sprintf(
@ -67,7 +66,7 @@ func TestStackCheckOutput(t *testing.T) {
}
// Parse stanzas
stanza := regexp.MustCompile(`^(.*): nosplit stack overflow\n(.*\n(?: .*\n)*)`)
stanza := regexp.MustCompile(`^(.*): nosplit stack over [0-9]+ byte limit\n(.*\n(?: .*\n)*)`)
// Strip comments from cmd/go
out = regexp.MustCompile(`(?m)^#.*\n`).ReplaceAllString(out, "")
for len(out) > 0 {

View File

@ -17,7 +17,7 @@ The file was generated by catapult's `vulcanize_trace_viewer` command.
$ git clone https://chromium.googlesource.com/catapult
$ cd catapult
$ ./tracing/bin/vulcanize_trace_viewer --config=full
$ cp tracing/bin/trace_viewer_full.html $GOROOT/misc/trace/trace_viewer_full.html
$ cp tracing/bin/trace_viewer_full.html $GOROOT/src/cmd/trace/static/trace_viewer_full.html
```
We are supposed to use --config=lean (produces smaller html),
@ -31,7 +31,7 @@ to import the `trace_viewer_full.html`.
This is copied from the catapult repo.
```
$ cp third_party/polymer/components/webcomponentsjs/webcomponents.min.js $GOROOT/misc/trace/webcomponents.min.js
$ cp third_party/polymer/components/webcomponentsjs/webcomponents.min.js $GOROOT/src/cmd/trace/static/webcomponents.min.js
```
## Licenses

View File

@ -6,6 +6,7 @@ package main
import (
"cmd/internal/traceviewer"
"embed"
"encoding/json"
"fmt"
"internal/trace"
@ -13,8 +14,6 @@ import (
"log"
"math"
"net/http"
"path/filepath"
"runtime"
"runtime/debug"
"sort"
"strconv"
@ -22,13 +21,16 @@ import (
"time"
)
//go:embed static/trace_viewer_full.html static/webcomponents.min.js
var staticContent embed.FS
func init() {
http.HandleFunc("/trace", httpTrace)
http.HandleFunc("/jsontrace", httpJsonTrace)
http.HandleFunc("/trace_viewer_html", httpTraceViewerHTML)
http.HandleFunc("/webcomponents.min.js", webcomponentsJS)
http.Handle("/static/", http.FileServer(http.FS(staticContent)))
}
// httpTrace serves either whole trace (goid==0) or trace for goid goroutine.
func httpTrace(w http.ResponseWriter, r *http.Request) {
_, err := parseTrace()
@ -50,19 +52,19 @@ func httpTrace(w http.ResponseWriter, r *http.Request) {
var templTrace = `
<html>
<head>
<script src="/webcomponents.min.js"></script>
<script src="/static/webcomponents.min.js"></script>
<script>
'use strict';
function onTraceViewerImportFail() {
document.addEventListener('DOMContentLoaded', function() {
document.body.textContent =
'/trace_viewer_full.html is missing. File a bug in https://golang.org/issue';
'/static/trace_viewer_full.html is missing. File a bug in https://golang.org/issue';
});
}
</script>
<link rel="import" href="/trace_viewer_html"
<link rel="import" href="/static/trace_viewer_full.html"
onerror="onTraceViewerImportFail(event)">
<style type="text/css">
@ -173,16 +175,6 @@ function onTraceViewerImportFail() {
</html>
`
// httpTraceViewerHTML serves static part of trace-viewer.
// This URL is queried from templTrace HTML.
func httpTraceViewerHTML(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filepath.Join(runtime.GOROOT(), "misc", "trace", "trace_viewer_full.html"))
}
func webcomponentsJS(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filepath.Join(runtime.GOROOT(), "misc", "trace", "webcomponents.min.js"))
}
// httpJsonTrace serves json trace, requested from within templTrace HTML.
func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
defer debug.FreeOSMemory()

View File

@ -146,7 +146,7 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
params := c.Params()
// Note that for P-521 this will actually be 63 bits more than the order, as
// division rounds down, but the extra bit is inconsequential.
b := make([]byte, params.BitSize/8+8) // TODO: use params.N.BitLen()
b := make([]byte, params.N.BitLen()/8+8)
_, err = io.ReadFull(rand, b)
if err != nil {
return
@ -264,13 +264,13 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
// Create a CSPRNG that xors a stream of zeros with
// the output of the AES-CTR instance.
csprng := cipher.StreamReader{
csprng := &cipher.StreamReader{
R: zeroReader,
S: cipher.NewCTR(block, []byte(aesIV)),
}
c := priv.PublicKey.Curve
return sign(priv, &csprng, c, hash)
return sign(priv, csprng, c, hash)
}
func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
@ -398,16 +398,14 @@ func VerifyASN1(pub *PublicKey, hash, sig []byte) bool {
return Verify(pub, hash, r, s)
}
type zr struct {
io.Reader
}
type zr struct{}
// Read replaces the contents of dst with zeros.
func (z *zr) Read(dst []byte) (n int, err error) {
// Read replaces the contents of dst with zeros. It is safe for concurrent use.
func (zr) Read(dst []byte) (n int, err error) {
for i := range dst {
dst[i] = 0
}
return len(dst), nil
}
var zeroReader = &zr{}
var zeroReader = zr{}

View File

@ -74,11 +74,22 @@ func TestEd25519Vectors(t *testing.T) {
func downloadEd25519Vectors(t *testing.T) []byte {
testenv.MustHaveExternalNetwork(t)
// Create a temp dir and modcache subdir.
d := t.TempDir()
// Create a spot for the modcache.
modcache := filepath.Join(d, "modcache")
if err := os.Mkdir(modcache, 0777); err != nil {
t.Fatal(err)
}
t.Setenv("GO111MODULE", "on")
t.Setenv("GOMODCACHE", modcache)
// Download the JSON test file from the GOPROXY with `go mod download`,
// pinning the version so test and module caching works as expected.
goTool := testenv.GoToolPath(t)
path := "filippo.io/mostly-harmless/ed25519vectors@v0.0.0-20210322192420-30a2d7243a94"
cmd := exec.Command(goTool, "mod", "download", "-json", path)
cmd := exec.Command(goTool, "mod", "download", "-modcacherw", "-json", path)
// TODO: enable the sumdb once the TryBots proxy supports it.
cmd.Env = append(os.Environ(), "GONOSUMDB=*")
output, err := cmd.Output()

View File

@ -36,295 +36,6 @@ type Curve interface {
ScalarBaseMult(k []byte) (x, y *big.Int)
}
func matchesSpecificCurve(params *CurveParams, available ...Curve) (Curve, bool) {
for _, c := range available {
if params == c.Params() {
return c, true
}
}
return nil, false
}
// CurveParams contains the parameters of an elliptic curve and also provides
// a generic, non-constant time implementation of Curve.
type CurveParams struct {
P *big.Int // the order of the underlying field
N *big.Int // the order of the base point
B *big.Int // the constant of the curve equation
Gx, Gy *big.Int // (x,y) of the base point
BitSize int // the size of the underlying field
Name string // the canonical name of the curve
}
func (curve *CurveParams) Params() *CurveParams {
return curve
}
// CurveParams operates, internally, on Jacobian coordinates. For a given
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
// calculation can be performed within the transform (as in ScalarMult and
// ScalarBaseMult). But even for Add and Double, it's faster to apply and
// reverse the transform than to operate in affine coordinates.
// polynomial returns x³ - 3x + b.
func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
threeX := new(big.Int).Lsh(x, 1)
threeX.Add(threeX, x)
x3.Sub(x3, threeX)
x3.Add(x3, curve.B)
x3.Mod(x3, curve.P)
return x3
}
func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p384, p521); ok {
return specific.IsOnCurve(x, y)
}
if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
return false
}
// y² = x³ - 3x + b
y2 := new(big.Int).Mul(y, y)
y2.Mod(y2, curve.P)
return curve.polynomial(x).Cmp(y2) == 0
}
// zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
// y are zero, it assumes that they represent the point at infinity because (0,
// 0) is not on the any of the curves handled here.
func zForAffine(x, y *big.Int) *big.Int {
z := new(big.Int)
if x.Sign() != 0 || y.Sign() != 0 {
z.SetInt64(1)
}
return z
}
// affineFromJacobian reverses the Jacobian transform. See the comment at the
// top of the file. If the point is ∞ it returns 0, 0.
func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
if z.Sign() == 0 {
return new(big.Int), new(big.Int)
}
zinv := new(big.Int).ModInverse(z, curve.P)
zinvsq := new(big.Int).Mul(zinv, zinv)
xOut = new(big.Int).Mul(x, zinvsq)
xOut.Mod(xOut, curve.P)
zinvsq.Mul(zinvsq, zinv)
yOut = new(big.Int).Mul(y, zinvsq)
yOut.Mod(yOut, curve.P)
return
}
func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p384, p521); ok {
return specific.Add(x1, y1, x2, y2)
}
z1 := zForAffine(x1, y1)
z2 := zForAffine(x2, y2)
return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
}
// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
// (x2, y2, z2) and returns their sum, also in Jacobian form.
func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
if z1.Sign() == 0 {
x3.Set(x2)
y3.Set(y2)
z3.Set(z2)
return x3, y3, z3
}
if z2.Sign() == 0 {
x3.Set(x1)
y3.Set(y1)
z3.Set(z1)
return x3, y3, z3
}
z1z1 := new(big.Int).Mul(z1, z1)
z1z1.Mod(z1z1, curve.P)
z2z2 := new(big.Int).Mul(z2, z2)
z2z2.Mod(z2z2, curve.P)
u1 := new(big.Int).Mul(x1, z2z2)
u1.Mod(u1, curve.P)
u2 := new(big.Int).Mul(x2, z1z1)
u2.Mod(u2, curve.P)
h := new(big.Int).Sub(u2, u1)
xEqual := h.Sign() == 0
if h.Sign() == -1 {
h.Add(h, curve.P)
}
i := new(big.Int).Lsh(h, 1)
i.Mul(i, i)
j := new(big.Int).Mul(h, i)
s1 := new(big.Int).Mul(y1, z2)
s1.Mul(s1, z2z2)
s1.Mod(s1, curve.P)
s2 := new(big.Int).Mul(y2, z1)
s2.Mul(s2, z1z1)
s2.Mod(s2, curve.P)
r := new(big.Int).Sub(s2, s1)
if r.Sign() == -1 {
r.Add(r, curve.P)
}
yEqual := r.Sign() == 0
if xEqual && yEqual {
return curve.doubleJacobian(x1, y1, z1)
}
r.Lsh(r, 1)
v := new(big.Int).Mul(u1, i)
x3.Set(r)
x3.Mul(x3, x3)
x3.Sub(x3, j)
x3.Sub(x3, v)
x3.Sub(x3, v)
x3.Mod(x3, curve.P)
y3.Set(r)
v.Sub(v, x3)
y3.Mul(y3, v)
s1.Mul(s1, j)
s1.Lsh(s1, 1)
y3.Sub(y3, s1)
y3.Mod(y3, curve.P)
z3.Add(z1, z2)
z3.Mul(z3, z3)
z3.Sub(z3, z1z1)
z3.Sub(z3, z2z2)
z3.Mul(z3, h)
z3.Mod(z3, curve.P)
return x3, y3, z3
}
func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p384, p521); ok {
return specific.Double(x1, y1)
}
z1 := zForAffine(x1, y1)
return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
}
// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
// returns its double, also in Jacobian form.
func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
delta := new(big.Int).Mul(z, z)
delta.Mod(delta, curve.P)
gamma := new(big.Int).Mul(y, y)
gamma.Mod(gamma, curve.P)
alpha := new(big.Int).Sub(x, delta)
if alpha.Sign() == -1 {
alpha.Add(alpha, curve.P)
}
alpha2 := new(big.Int).Add(x, delta)
alpha.Mul(alpha, alpha2)
alpha2.Set(alpha)
alpha.Lsh(alpha, 1)
alpha.Add(alpha, alpha2)
beta := alpha2.Mul(x, gamma)
x3 := new(big.Int).Mul(alpha, alpha)
beta8 := new(big.Int).Lsh(beta, 3)
beta8.Mod(beta8, curve.P)
x3.Sub(x3, beta8)
if x3.Sign() == -1 {
x3.Add(x3, curve.P)
}
x3.Mod(x3, curve.P)
z3 := new(big.Int).Add(y, z)
z3.Mul(z3, z3)
z3.Sub(z3, gamma)
if z3.Sign() == -1 {
z3.Add(z3, curve.P)
}
z3.Sub(z3, delta)
if z3.Sign() == -1 {
z3.Add(z3, curve.P)
}
z3.Mod(z3, curve.P)
beta.Lsh(beta, 2)
beta.Sub(beta, x3)
if beta.Sign() == -1 {
beta.Add(beta, curve.P)
}
y3 := alpha.Mul(alpha, beta)
gamma.Mul(gamma, gamma)
gamma.Lsh(gamma, 3)
gamma.Mod(gamma, curve.P)
y3.Sub(y3, gamma)
if y3.Sign() == -1 {
y3.Add(y3, curve.P)
}
y3.Mod(y3, curve.P)
return x3, y3, z3
}
func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p256, p384, p521); ok {
return specific.ScalarMult(Bx, By, k)
}
Bz := new(big.Int).SetInt64(1)
x, y, z := new(big.Int), new(big.Int), new(big.Int)
for _, byte := range k {
for bitNum := 0; bitNum < 8; bitNum++ {
x, y, z = curve.doubleJacobian(x, y, z)
if byte&0x80 == 0x80 {
x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
}
byte <<= 1
}
}
return curve.affineFromJacobian(x, y, z)
}
func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p256, p384, p521); ok {
return specific.ScalarBaseMult(k)
}
return curve.ScalarMult(curve.Gx, curve.Gy, k)
}
var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
// GenerateKey returns a public/private key pair. The private key is

View File

@ -0,0 +1,223 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package elliptic
import (
"crypto/elliptic/internal/nistec"
"crypto/rand"
"errors"
"math/big"
)
var p224 = &nistCurve[*nistec.P224Point]{
newPoint: nistec.NewP224Point,
newGenerator: nistec.NewP224Generator,
}
func initP224() {
p224.params = &CurveParams{
Name: "P-224",
BitSize: 224,
// FIPS 186-4, section D.1.2.2
P: bigFromDecimal("26959946667150639794667015087019630673557916260026308143510066298881"),
N: bigFromDecimal("26959946667150639794667015087019625940457807714424391721682722368061"),
B: bigFromHex("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"),
Gx: bigFromHex("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"),
Gy: bigFromHex("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
}
}
var p384 = &nistCurve[*nistec.P384Point]{
newPoint: nistec.NewP384Point,
newGenerator: nistec.NewP384Generator,
}
func initP384() {
p384.params = &CurveParams{
Name: "P-384",
BitSize: 384,
// FIPS 186-4, section D.1.2.4
P: bigFromDecimal("394020061963944792122790401001436138050797392704654" +
"46667948293404245721771496870329047266088258938001861606973112319"),
N: bigFromDecimal("394020061963944792122790401001436138050797392704654" +
"46667946905279627659399113263569398956308152294913554433653942643"),
B: bigFromHex("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088" +
"f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"),
Gx: bigFromHex("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741" +
"e082542a385502f25dbf55296c3a545e3872760ab7"),
Gy: bigFromHex("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da31" +
"13b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"),
}
}
var p521 = &nistCurve[*nistec.P521Point]{
newPoint: nistec.NewP521Point,
newGenerator: nistec.NewP521Generator,
}
func initP521() {
p521.params = &CurveParams{
Name: "P-521",
BitSize: 521,
// FIPS 186-4, section D.1.2.5
P: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
"0540939446345918554318339765605212255964066145455497729631139148" +
"0858037121987999716643812574028291115057151"),
N: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
"0540939446345918554318339765539424505774633321719753296399637136" +
"3321113864768612440380340372808892707005449"),
B: bigFromHex("0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8" +
"b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef" +
"451fd46b503f00"),
Gx: bigFromHex("00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f8" +
"28af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf9" +
"7e7e31c2e5bd66"),
Gy: bigFromHex("011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817" +
"afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088" +
"be94769fd16650"),
}
}
// nistCurve is a Curve implementation based on a nistec Point.
//
// It's a wrapper that exposes the big.Int-based Curve interface and encodes the
// legacy idiosyncrasies it requires, such as invalid and infinity point
// handling.
//
// To interact with the nistec package, points are encoded into and decoded from
// properly formatted byte slices. All big.Int use is limited to this package.
// Encoding and decoding is 1/1000th of the runtime of a scalar multiplication,
// so the overhead is acceptable.
type nistCurve[Point nistPoint[Point]] struct {
newPoint func() Point
newGenerator func() Point
params *CurveParams
}
// nistPoint is a generic constraint for the nistec Point types.
type nistPoint[T any] interface {
Bytes() []byte
SetBytes([]byte) (T, error)
Add(T, T) T
Double(T) T
ScalarMult(T, []byte) T
}
func (curve *nistCurve[Point]) Params() *CurveParams {
return curve.params
}
func (curve *nistCurve[Point]) IsOnCurve(x, y *big.Int) bool {
// IsOnCurve is documented to reject (0, 0), the conventional point at
// infinity, which however is accepted by pointFromAffine.
if x.Sign() == 0 && y.Sign() == 0 {
return false
}
_, err := curve.pointFromAffine(x, y)
return err == nil
}
func (curve *nistCurve[Point]) pointFromAffine(x, y *big.Int) (p Point, err error) {
p = curve.newPoint()
// (0, 0) is by convention the point at infinity, which can't be represented
// in affine coordinates. See Issue 37294.
if x.Sign() == 0 && y.Sign() == 0 {
return p, nil
}
// Reject values that would not get correctly encoded.
if x.Sign() < 0 || y.Sign() < 0 {
return p, errors.New("negative coordinate")
}
if x.BitLen() > curve.params.BitSize || y.BitLen() > curve.params.BitSize {
return p, errors.New("overflowing coordinate")
}
// Encode the coordinates and let SetBytes reject invalid points.
byteLen := (curve.params.BitSize + 7) / 8
buf := make([]byte, 1+2*byteLen)
buf[0] = 4 // uncompressed point
x.FillBytes(buf[1 : 1+byteLen])
y.FillBytes(buf[1+byteLen : 1+2*byteLen])
return p.SetBytes(buf)
}
func (curve *nistCurve[Point]) pointToAffine(p Point) (x, y *big.Int) {
out := p.Bytes()
if len(out) == 1 && out[0] == 0 {
// This is the correct encoding of the point at infinity, which
// Unmarshal does not support. See Issue 37294.
return new(big.Int), new(big.Int)
}
x, y = Unmarshal(curve, out)
if x == nil {
panic("crypto/elliptic: internal error: Unmarshal rejected a valid point encoding")
}
return x, y
}
// randomPoint returns a random point on the curve. It's used when Add,
// Double, or ScalarMult are fed a point not on the curve, which is undefined
// behavior. Originally, we used to do the math on it anyway (which allows
// invalid curve attacks) and relied on the caller and Unmarshal to avoid this
// happening in the first place. Now, we just can't construct a nistec Point
// for an invalid pair of coordinates, because that API is safer. If we panic,
// we risk introducing a DoS. If we return nil, we risk a panic. If we return
// the input, ecdsa.Verify might fail open. The safest course seems to be to
// return a valid, random point, which hopefully won't help the attacker.
func (curve *nistCurve[Point]) randomPoint() (x, y *big.Int) {
_, x, y, err := GenerateKey(curve, rand.Reader)
if err != nil {
panic("crypto/elliptic: failed to generate random point")
}
return x, y
}
func (curve *nistCurve[Point]) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
p1, err := curve.pointFromAffine(x1, y1)
if err != nil {
return curve.randomPoint()
}
p2, err := curve.pointFromAffine(x2, y2)
if err != nil {
return curve.randomPoint()
}
return curve.pointToAffine(p1.Add(p1, p2))
}
func (curve *nistCurve[Point]) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
p, err := curve.pointFromAffine(x1, y1)
if err != nil {
return curve.randomPoint()
}
return curve.pointToAffine(p.Double(p))
}
func (curve *nistCurve[Point]) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
p, err := curve.pointFromAffine(Bx, By)
if err != nil {
return curve.randomPoint()
}
return curve.pointToAffine(p.ScalarMult(p, scalar))
}
func (curve *nistCurve[Point]) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) {
p := curve.newGenerator()
return curve.pointToAffine(p.ScalarMult(p, scalar))
}
func bigFromDecimal(s string) *big.Int {
b, ok := new(big.Int).SetString(s, 10)
if !ok {
panic("invalid encoding")
}
return b
}
func bigFromHex(s string) *big.Int {
b, ok := new(big.Int).SetString(s, 16)
if !ok {
panic("invalid encoding")
}
return b
}

View File

@ -1,139 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package elliptic
import (
"crypto/elliptic/internal/nistec"
"crypto/rand"
"math/big"
)
// p224Curve is a Curve implementation based on nistec.P224Point.
//
// It's a wrapper that exposes the big.Int-based Curve interface and encodes the
// legacy idiosyncrasies it requires, such as invalid and infinity point
// handling.
//
// To interact with the nistec package, points are encoded into and decoded from
// properly formatted byte slices. All big.Int use is limited to this package.
// Encoding and decoding is 1/1000th of the runtime of a scalar multiplication,
// so the overhead is acceptable.
type p224Curve struct {
params *CurveParams
}
var p224 p224Curve
var _ Curve = p224
func initP224() {
p224.params = &CurveParams{
Name: "P-224",
BitSize: 224,
// FIPS 186-4, section D.1.2.2
P: bigFromDecimal("26959946667150639794667015087019630673557916260026308143510066298881"),
N: bigFromDecimal("26959946667150639794667015087019625940457807714424391721682722368061"),
B: bigFromHex("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"),
Gx: bigFromHex("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"),
Gy: bigFromHex("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
}
}
func (curve p224Curve) Params() *CurveParams {
return curve.params
}
func (curve p224Curve) IsOnCurve(x, y *big.Int) bool {
// IsOnCurve is documented to reject (0, 0), the conventional point at
// infinity, which however is accepted by p224PointFromAffine.
if x.Sign() == 0 && y.Sign() == 0 {
return false
}
_, ok := p224PointFromAffine(x, y)
return ok
}
func p224PointFromAffine(x, y *big.Int) (p *nistec.P224Point, ok bool) {
// (0, 0) is by convention the point at infinity, which can't be represented
// in affine coordinates. Marshal incorrectly encodes it as an uncompressed
// point, which SetBytes would correctly reject. See Issue 37294.
if x.Sign() == 0 && y.Sign() == 0 {
return nistec.NewP224Point(), true
}
if x.Sign() < 0 || y.Sign() < 0 {
return nil, false
}
if x.BitLen() > 224 || y.BitLen() > 224 {
return nil, false
}
p, err := nistec.NewP224Point().SetBytes(Marshal(P224(), x, y))
if err != nil {
return nil, false
}
return p, true
}
func p224PointToAffine(p *nistec.P224Point) (x, y *big.Int) {
out := p.Bytes()
if len(out) == 1 && out[0] == 0 {
// This is the correct encoding of the point at infinity, which
// Unmarshal does not support. See Issue 37294.
return new(big.Int), new(big.Int)
}
x, y = Unmarshal(P224(), out)
if x == nil {
panic("crypto/elliptic: internal error: Unmarshal rejected a valid point encoding")
}
return x, y
}
// p224RandomPoint returns a random point on the curve. It's used when Add,
// Double, or ScalarMult are fed a point not on the curve, which is undefined
// behavior. Originally, we used to do the math on it anyway (which allows
// invalid curve attacks) and relied on the caller and Unmarshal to avoid this
// happening in the first place. Now, we just can't construct a nistec.P224Point
// for an invalid pair of coordinates, because that API is safer. If we panic,
// we risk introducing a DoS. If we return nil, we risk a panic. If we return
// the input, ecdsa.Verify might fail open. The safest course seems to be to
// return a valid, random point, which hopefully won't help the attacker.
func p224RandomPoint() (x, y *big.Int) {
_, x, y, err := GenerateKey(P224(), rand.Reader)
if err != nil {
panic("crypto/elliptic: failed to generate random point")
}
return x, y
}
func (p224Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
p1, ok := p224PointFromAffine(x1, y1)
if !ok {
return p224RandomPoint()
}
p2, ok := p224PointFromAffine(x2, y2)
if !ok {
return p224RandomPoint()
}
return p224PointToAffine(p1.Add(p1, p2))
}
func (p224Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
p, ok := p224PointFromAffine(x1, y1)
if !ok {
return p224RandomPoint()
}
return p224PointToAffine(p.Double(p))
}
func (p224Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
p, ok := p224PointFromAffine(Bx, By)
if !ok {
return p224RandomPoint()
}
return p224PointToAffine(p.ScalarMult(p, scalar))
}
func (p224Curve) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) {
p := nistec.NewP224Generator()
return p224PointToAffine(p.ScalarMult(p, scalar))
}

File diff suppressed because it is too large Load Diff

View File

@ -24,27 +24,18 @@ import (
//go:embed p256_asm_table.bin
var p256Precomputed string
type (
p256Curve struct {
*CurveParams
}
type p256Curve struct {
*CurveParams
}
p256Point struct {
xyz [12]uint64
}
)
type p256Point struct {
xyz [12]uint64
}
var p256 p256Curve
func initP256() {
// See FIPS 186-3, section D.2.3
p256.CurveParams = &CurveParams{Name: "P-256"}
p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
p256.BitSize = 256
func initP256Arch() {
p256 = p256Curve{p256Params}
}
func (curve p256Curve) Params() *CurveParams {

View File

@ -1,14 +1,477 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !amd64 && !s390x && !arm64 && !ppc64le
//go:build !amd64 && !arm64
package elliptic
var p256 p256Curve
// This file contains a constant-time, 32-bit implementation of P256.
func initP256Arch() {
// Use pure Go implementation.
p256 = p256Curve{p256Params}
import "math/big"
type p256Curve struct {
*CurveParams
}
func (curve p256Curve) Params() *CurveParams {
return curve.CurveParams
}
// p256GetScalar endian-swaps the big-endian scalar value from in and writes it
// to out. If the scalar is equal or greater than the order of the group, it's
// reduced modulo that order.
func p256GetScalar(out *[32]byte, in []byte) {
n := new(big.Int).SetBytes(in)
var scalarBytes []byte
if n.Cmp(p256Params.N) >= 0 || len(in) > len(out) {
n.Mod(n, p256Params.N)
scalarBytes = n.Bytes()
} else {
scalarBytes = in
}
for i, v := range scalarBytes {
out[len(scalarBytes)-(1+i)] = v
}
}
func (p256Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
var scalarReversed [32]byte
p256GetScalar(&scalarReversed, scalar)
var x1, y1, z1 [p256Limbs]uint32
p256ScalarBaseMult(&x1, &y1, &z1, &scalarReversed)
return p256ToAffine(&x1, &y1, &z1)
}
func (p256Curve) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
var scalarReversed [32]byte
p256GetScalar(&scalarReversed, scalar)
var px, py, x1, y1, z1 [p256Limbs]uint32
p256FromBig(&px, bigX)
p256FromBig(&py, bigY)
p256ScalarMult(&x1, &y1, &z1, &px, &py, &scalarReversed)
return p256ToAffine(&x1, &y1, &z1)
}
// p256Precomputed contains precomputed values to aid the calculation of scalar
// multiples of the base point, G. It's actually two, equal length, tables
// concatenated.
//
// The first table contains (x,y) field element pairs for 16 multiples of the
// base point, G.
//
// Index | Index (binary) | Value
// 0 | 0000 | 0G (all zeros, omitted)
// 1 | 0001 | G
// 2 | 0010 | 2**64G
// 3 | 0011 | 2**64G + G
// 4 | 0100 | 2**128G
// 5 | 0101 | 2**128G + G
// 6 | 0110 | 2**128G + 2**64G
// 7 | 0111 | 2**128G + 2**64G + G
// 8 | 1000 | 2**192G
// 9 | 1001 | 2**192G + G
// 10 | 1010 | 2**192G + 2**64G
// 11 | 1011 | 2**192G + 2**64G + G
// 12 | 1100 | 2**192G + 2**128G
// 13 | 1101 | 2**192G + 2**128G + G
// 14 | 1110 | 2**192G + 2**128G + 2**64G
// 15 | 1111 | 2**192G + 2**128G + 2**64G + G
//
// The second table follows the same style, but the terms are 2**32G,
// 2**96G, 2**160G, 2**224G.
//
// This is ~2KB of data.
var p256Precomputed = [p256Limbs * 2 * 15 * 2]uint32{
0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee,
0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,
0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c,
0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,
0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050,
0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,
0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa,
0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,
0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609,
0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,
0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca,
0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,
0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6,
0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,
0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0,
0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,
0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a,
0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,
0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b,
0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,
0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133,
0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,
0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29,
0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,
0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8,
0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,
0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39,
0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,
0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa,
0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,
0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1,
0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,
0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72,
0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,
0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b,
0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,
0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a,
0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,
0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb,
0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,
0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9,
0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,
0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2,
0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,
0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229,
0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,
0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c,
0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,
0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651,
0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,
0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7,
0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,
0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927,
0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,
0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8,
0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,
0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d,
0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,
0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8,
0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,
}
// Group operations:
//
// Elements of the elliptic curve group are represented in Jacobian
// coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in
// Jacobian form.
// p256PointDouble sets {xOut,yOut,zOut} = 2*{x,y,z}.
//
// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
func p256PointDouble(xOut, yOut, zOut, x, y, z *[p256Limbs]uint32) {
var delta, gamma, alpha, beta, tmp, tmp2 [p256Limbs]uint32
p256Square(&delta, z)
p256Square(&gamma, y)
p256Mul(&beta, x, &gamma)
p256Sum(&tmp, x, &delta)
p256Diff(&tmp2, x, &delta)
p256Mul(&alpha, &tmp, &tmp2)
p256Scalar3(&alpha)
p256Sum(&tmp, y, z)
p256Square(&tmp, &tmp)
p256Diff(&tmp, &tmp, &gamma)
p256Diff(zOut, &tmp, &delta)
p256Scalar4(&beta)
p256Square(xOut, &alpha)
p256Diff(xOut, xOut, &beta)
p256Diff(xOut, xOut, &beta)
p256Diff(&tmp, &beta, xOut)
p256Mul(&tmp, &alpha, &tmp)
p256Square(&tmp2, &gamma)
p256Scalar8(&tmp2)
p256Diff(yOut, &tmp, &tmp2)
}
// p256PointAddMixed sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,1}.
// (i.e. the second point is affine.)
//
// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
//
// Note that this function does not handle P+P, infinity+P nor P+infinity
// correctly.
func p256PointAddMixed(xOut, yOut, zOut, x1, y1, z1, x2, y2 *[p256Limbs]uint32) {
var z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp [p256Limbs]uint32
p256Square(&z1z1, z1)
p256Sum(&tmp, z1, z1)
p256Mul(&u2, x2, &z1z1)
p256Mul(&z1z1z1, z1, &z1z1)
p256Mul(&s2, y2, &z1z1z1)
p256Diff(&h, &u2, x1)
p256Sum(&i, &h, &h)
p256Square(&i, &i)
p256Mul(&j, &h, &i)
p256Diff(&r, &s2, y1)
p256Sum(&r, &r, &r)
p256Mul(&v, x1, &i)
p256Mul(zOut, &tmp, &h)
p256Square(&rr, &r)
p256Diff(xOut, &rr, &j)
p256Diff(xOut, xOut, &v)
p256Diff(xOut, xOut, &v)
p256Diff(&tmp, &v, xOut)
p256Mul(yOut, &tmp, &r)
p256Mul(&tmp, y1, &j)
p256Diff(yOut, yOut, &tmp)
p256Diff(yOut, yOut, &tmp)
}
// p256PointAdd sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,z2}.
//
// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
//
// Note that this function does not handle P+P, infinity+P nor P+infinity
// correctly.
func p256PointAdd(xOut, yOut, zOut, x1, y1, z1, x2, y2, z2 *[p256Limbs]uint32) {
var z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp [p256Limbs]uint32
p256Square(&z1z1, z1)
p256Square(&z2z2, z2)
p256Mul(&u1, x1, &z2z2)
p256Sum(&tmp, z1, z2)
p256Square(&tmp, &tmp)
p256Diff(&tmp, &tmp, &z1z1)
p256Diff(&tmp, &tmp, &z2z2)
p256Mul(&z2z2z2, z2, &z2z2)
p256Mul(&s1, y1, &z2z2z2)
p256Mul(&u2, x2, &z1z1)
p256Mul(&z1z1z1, z1, &z1z1)
p256Mul(&s2, y2, &z1z1z1)
p256Diff(&h, &u2, &u1)
p256Sum(&i, &h, &h)
p256Square(&i, &i)
p256Mul(&j, &h, &i)
p256Diff(&r, &s2, &s1)
p256Sum(&r, &r, &r)
p256Mul(&v, &u1, &i)
p256Mul(zOut, &tmp, &h)
p256Square(&rr, &r)
p256Diff(xOut, &rr, &j)
p256Diff(xOut, xOut, &v)
p256Diff(xOut, xOut, &v)
p256Diff(&tmp, &v, xOut)
p256Mul(yOut, &tmp, &r)
p256Mul(&tmp, &s1, &j)
p256Diff(yOut, yOut, &tmp)
p256Diff(yOut, yOut, &tmp)
}
// p256SelectAffinePoint sets {out_x,out_y} to the index'th entry of table.
//
// On entry: index < 16, table[0] must be zero.
func p256SelectAffinePoint(xOut, yOut *[p256Limbs]uint32, table []uint32, index uint32) {
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := uint32(1); i < 16; i++ {
mask := i ^ index
mask |= mask >> 2
mask |= mask >> 1
mask &= 1
mask--
for j := range xOut {
xOut[j] |= table[0] & mask
table = table[1:]
}
for j := range yOut {
yOut[j] |= table[0] & mask
table = table[1:]
}
}
}
// p256SelectJacobianPoint sets {out_x,out_y,out_z} to the index'th entry of
// table.
//
// On entry: index < 16, table[0] must be zero.
func p256SelectJacobianPoint(xOut, yOut, zOut *[p256Limbs]uint32, table *[16][3][p256Limbs]uint32, index uint32) {
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := range zOut {
zOut[i] = 0
}
// The implicit value at index 0 is all zero. We don't need to perform that
// iteration of the loop because we already set out_* to zero.
for i := uint32(1); i < 16; i++ {
mask := i ^ index
mask |= mask >> 2
mask |= mask >> 1
mask &= 1
mask--
for j := range xOut {
xOut[j] |= table[i][0][j] & mask
}
for j := range yOut {
yOut[j] |= table[i][1][j] & mask
}
for j := range zOut {
zOut[j] |= table[i][2][j] & mask
}
}
}
// p256GetBit returns the bit'th bit of scalar.
func p256GetBit(scalar *[32]uint8, bit uint) uint32 {
return uint32(((scalar[bit>>3]) >> (bit & 7)) & 1)
}
// p256ScalarBaseMult sets {xOut,yOut,zOut} = scalar*G where scalar is a
// little-endian number. Note that the value of scalar must be less than the
// order of the group.
func p256ScalarBaseMult(xOut, yOut, zOut *[p256Limbs]uint32, scalar *[32]uint8) {
nIsInfinityMask := ^uint32(0)
var pIsNoninfiniteMask, mask, tableOffset uint32
var px, py, tx, ty, tz [p256Limbs]uint32
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := range zOut {
zOut[i] = 0
}
// The loop adds bits at positions 0, 64, 128 and 192, followed by
// positions 32,96,160 and 224 and does this 32 times.
for i := uint(0); i < 32; i++ {
if i != 0 {
p256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
}
tableOffset = 0
for j := uint(0); j <= 32; j += 32 {
bit0 := p256GetBit(scalar, 31-i+j)
bit1 := p256GetBit(scalar, 95-i+j)
bit2 := p256GetBit(scalar, 159-i+j)
bit3 := p256GetBit(scalar, 223-i+j)
index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
p256SelectAffinePoint(&px, &py, p256Precomputed[tableOffset:], index)
tableOffset += 30 * p256Limbs
// Since scalar is less than the order of the group, we know that
// {xOut,yOut,zOut} != {px,py,1}, unless both are zero, which we handle
// below.
p256PointAddMixed(&tx, &ty, &tz, xOut, yOut, zOut, &px, &py)
// The result of pointAddMixed is incorrect if {xOut,yOut,zOut} is zero
// (a.k.a. the point at infinity). We handle that situation by
// copying the point from the table.
p256CopyConditional(xOut, &px, nIsInfinityMask)
p256CopyConditional(yOut, &py, nIsInfinityMask)
p256CopyConditional(zOut, &p256One, nIsInfinityMask)
// Equally, the result is also wrong if the point from the table is
// zero, which happens when the index is zero. We handle that by
// only copying from {tx,ty,tz} to {xOut,yOut,zOut} if index != 0.
pIsNoninfiniteMask = nonZeroToAllOnes(index)
mask = pIsNoninfiniteMask & ^nIsInfinityMask
p256CopyConditional(xOut, &tx, mask)
p256CopyConditional(yOut, &ty, mask)
p256CopyConditional(zOut, &tz, mask)
// If p was not zero, then n is now non-zero.
nIsInfinityMask &^= pIsNoninfiniteMask
}
}
}
// p256PointToAffine converts a Jacobian point to an affine point. If the input
// is the point at infinity then it returns (0, 0) in constant time.
func p256PointToAffine(xOut, yOut, x, y, z *[p256Limbs]uint32) {
var zInv, zInvSq [p256Limbs]uint32
p256Invert(&zInv, z)
p256Square(&zInvSq, &zInv)
p256Mul(xOut, x, &zInvSq)
p256Mul(&zInv, &zInv, &zInvSq)
p256Mul(yOut, y, &zInv)
}
// p256ToAffine returns a pair of *big.Int containing the affine representation
// of {x,y,z}.
func p256ToAffine(x, y, z *[p256Limbs]uint32) (xOut, yOut *big.Int) {
var xx, yy [p256Limbs]uint32
p256PointToAffine(&xx, &yy, x, y, z)
return p256ToBig(&xx), p256ToBig(&yy)
}
// p256ScalarMult sets {xOut,yOut,zOut} = scalar*{x,y}.
func p256ScalarMult(xOut, yOut, zOut, x, y *[p256Limbs]uint32, scalar *[32]uint8) {
var px, py, pz, tx, ty, tz [p256Limbs]uint32
var precomp [16][3][p256Limbs]uint32
var nIsInfinityMask, index, pIsNoninfiniteMask, mask uint32
// We precompute 0,1,2,... times {x,y}.
precomp[1][0] = *x
precomp[1][1] = *y
precomp[1][2] = p256One
for i := 2; i < 16; i += 2 {
p256PointDouble(&precomp[i][0], &precomp[i][1], &precomp[i][2], &precomp[i/2][0], &precomp[i/2][1], &precomp[i/2][2])
p256PointAddMixed(&precomp[i+1][0], &precomp[i+1][1], &precomp[i+1][2], &precomp[i][0], &precomp[i][1], &precomp[i][2], x, y)
}
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := range zOut {
zOut[i] = 0
}
nIsInfinityMask = ^uint32(0)
// We add in a window of four bits each iteration and do this 64 times.
for i := 0; i < 64; i++ {
if i != 0 {
p256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
p256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
p256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
p256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
}
index = uint32(scalar[31-i/2])
if (i & 1) == 1 {
index &= 15
} else {
index >>= 4
}
// See the comments in scalarBaseMult about handling infinities.
p256SelectJacobianPoint(&px, &py, &pz, &precomp, index)
p256PointAdd(&tx, &ty, &tz, xOut, yOut, zOut, &px, &py, &pz)
p256CopyConditional(xOut, &px, nIsInfinityMask)
p256CopyConditional(yOut, &py, nIsInfinityMask)
p256CopyConditional(zOut, &pz, nIsInfinityMask)
pIsNoninfiniteMask = nonZeroToAllOnes(index)
mask = pIsNoninfiniteMask & ^nIsInfinityMask
p256CopyConditional(xOut, &tx, mask)
p256CopyConditional(yOut, &ty, mask)
p256CopyConditional(zOut, &tz, mask)
nIsInfinityMask &^= pIsNoninfiniteMask
}
}

View File

@ -0,0 +1,705 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !amd64 && !arm64
package elliptic
import "math/big"
// Field elements are represented as nine, unsigned 32-bit words.
//
// The value of a field element is:
// x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228)
//
// That is, each limb is alternately 29 or 28-bits wide in little-endian
// order.
//
// This means that a field element hits 2**257, rather than 2**256 as we would
// like. A 28, 29, ... pattern would cause us to hit 2**256, but that causes
// problems when multiplying as terms end up one bit short of a limb which
// would require much bit-shifting to correct.
//
// Finally, the values stored in a field element are in Montgomery form. So the
// value |y| is stored as (y*R) mod p, where p is the P-256 prime and R is
// 2**257.
const (
p256Limbs = 9
bottom29Bits = 0x1fffffff
)
var (
// p256One is the number 1 as a field element.
p256One = [p256Limbs]uint32{2, 0, 0, 0xffff800, 0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff, 0}
p256Zero = [p256Limbs]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0}
// p256P is the prime modulus as a field element.
p256P = [p256Limbs]uint32{0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff, 0, 0, 0x200000, 0xf000000, 0xfffffff}
// p2562P is the twice prime modulus as a field element.
p2562P = [p256Limbs]uint32{0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff, 0, 0, 0x400000, 0xe000000, 0x1fffffff}
)
// Field element operations:
const bottom28Bits = 0xfffffff
// nonZeroToAllOnes returns:
//
// 0xffffffff for 0 < x <= 2**31
// 0 for x == 0 or x > 2**31.
func nonZeroToAllOnes(x uint32) uint32 {
return ((x - 1) >> 31) - 1
}
// p256ReduceCarry adds a multiple of p in order to cancel |carry|,
// which is a term at 2**257.
//
// On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28.
// On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29.
func p256ReduceCarry(inout *[p256Limbs]uint32, carry uint32) {
carry_mask := nonZeroToAllOnes(carry)
inout[0] += carry << 1
inout[3] += 0x10000000 & carry_mask
// carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the
// previous line therefore this doesn't underflow.
inout[3] -= carry << 11
inout[4] += (0x20000000 - 1) & carry_mask
inout[5] += (0x10000000 - 1) & carry_mask
inout[6] += (0x20000000 - 1) & carry_mask
inout[6] -= carry << 22
// This may underflow if carry is non-zero but, if so, we'll fix it in the
// next line.
inout[7] -= 1 & carry_mask
inout[7] += carry << 25
}
// p256Sum sets out = in+in2.
//
// On entry: in[i]+in2[i] must not overflow a 32-bit word.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256Sum(out, in, in2 *[p256Limbs]uint32) {
carry := uint32(0)
for i := 0; ; i++ {
out[i] = in[i] + in2[i]
out[i] += carry
carry = out[i] >> 29
out[i] &= bottom29Bits
i++
if i == p256Limbs {
break
}
out[i] = in[i] + in2[i]
out[i] += carry
carry = out[i] >> 28
out[i] &= bottom28Bits
}
p256ReduceCarry(out, carry)
}
const (
two30m2 = 1<<30 - 1<<2
two30p13m2 = 1<<30 + 1<<13 - 1<<2
two31m2 = 1<<31 - 1<<2
two31m3 = 1<<31 - 1<<3
two31p24m2 = 1<<31 + 1<<24 - 1<<2
two30m27m2 = 1<<30 - 1<<27 - 1<<2
)
// p256Zero31 is 0 mod p.
var p256Zero31 = [p256Limbs]uint32{two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2}
// p256Diff sets out = in-in2.
//
// On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
// in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256Diff(out, in, in2 *[p256Limbs]uint32) {
var carry uint32
for i := 0; ; i++ {
out[i] = in[i] - in2[i]
out[i] += p256Zero31[i]
out[i] += carry
carry = out[i] >> 29
out[i] &= bottom29Bits
i++
if i == p256Limbs {
break
}
out[i] = in[i] - in2[i]
out[i] += p256Zero31[i]
out[i] += carry
carry = out[i] >> 28
out[i] &= bottom28Bits
}
p256ReduceCarry(out, carry)
}
// p256ReduceDegree sets out = tmp/R mod p where tmp contains 64-bit words with
// the same 29,28,... bit positions as a field element.
//
// The values in field elements are in Montgomery form: x*R mod p where R =
// 2**257. Since we just multiplied two Montgomery values together, the result
// is x*y*R*R mod p. We wish to divide by R in order for the result also to be
// in Montgomery form.
//
// On entry: tmp[i] < 2**64.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256ReduceDegree(out *[p256Limbs]uint32, tmp [17]uint64) {
// The following table may be helpful when reading this code:
//
// Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10...
// Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29
// Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285
// (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285
var tmp2 [18]uint32
var carry, x, xMask uint32
// tmp contains 64-bit words with the same 29,28,29-bit positions as a
// field element. So the top of an element of tmp might overlap with
// another element two positions down. The following loop eliminates
// this overlap.
tmp2[0] = uint32(tmp[0]) & bottom29Bits
tmp2[1] = uint32(tmp[0]) >> 29
tmp2[1] |= (uint32(tmp[0]>>32) << 3) & bottom28Bits
tmp2[1] += uint32(tmp[1]) & bottom28Bits
carry = tmp2[1] >> 28
tmp2[1] &= bottom28Bits
for i := 2; i < 17; i++ {
tmp2[i] = (uint32(tmp[i-2] >> 32)) >> 25
tmp2[i] += (uint32(tmp[i-1])) >> 28
tmp2[i] += (uint32(tmp[i-1]>>32) << 4) & bottom29Bits
tmp2[i] += uint32(tmp[i]) & bottom29Bits
tmp2[i] += carry
carry = tmp2[i] >> 29
tmp2[i] &= bottom29Bits
i++
if i == 17 {
break
}
tmp2[i] = uint32(tmp[i-2]>>32) >> 25
tmp2[i] += uint32(tmp[i-1]) >> 29
tmp2[i] += ((uint32(tmp[i-1] >> 32)) << 3) & bottom28Bits
tmp2[i] += uint32(tmp[i]) & bottom28Bits
tmp2[i] += carry
carry = tmp2[i] >> 28
tmp2[i] &= bottom28Bits
}
tmp2[17] = uint32(tmp[15]>>32) >> 25
tmp2[17] += uint32(tmp[16]) >> 29
tmp2[17] += uint32(tmp[16]>>32) << 3
tmp2[17] += carry
// Montgomery elimination of terms:
//
// Since R is 2**257, we can divide by R with a bitwise shift if we can
// ensure that the right-most 257 bits are all zero. We can make that true
// by adding multiplies of p without affecting the value.
//
// So we eliminate limbs from right to left. Since the bottom 29 bits of p
// are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0.
// We can do that for 8 further limbs and then right shift to eliminate the
// extra factor of R.
for i := 0; ; i += 2 {
tmp2[i+1] += tmp2[i] >> 29
x = tmp2[i] & bottom29Bits
xMask = nonZeroToAllOnes(x)
tmp2[i] = 0
// The bounds calculations for this loop are tricky. Each iteration of
// the loop eliminates two words by adding values to words to their
// right.
//
// The following table contains the amounts added to each word (as an
// offset from the value of i at the top of the loop). The amounts are
// accounted for from the first and second half of the loop separately
// and are written as, for example, 28 to mean a value <2**28.
//
// Word: 3 4 5 6 7 8 9 10
// Added in top half: 28 11 29 21 29 28
// 28 29
// 29
// Added in bottom half: 29 10 28 21 28 28
// 29
//
// The value that is currently offset 7 will be offset 5 for the next
// iteration and then offset 3 for the iteration after that. Therefore
// the total value added will be the values added at 7, 5 and 3.
//
// The following table accumulates these values. The sums at the bottom
// are written as, for example, 29+28, to mean a value < 2**29+2**28.
//
// Word: 3 4 5 6 7 8 9 10 11 12 13
// 28 11 10 29 21 29 28 28 28 28 28
// 29 28 11 28 29 28 29 28 29 28
// 29 28 21 21 29 21 29 21
// 10 29 28 21 28 21 28
// 28 29 28 29 28 29 28
// 11 10 29 10 29 10
// 29 28 11 28 11
// 29 29
// --------------------------------------------
// 30+ 31+ 30+ 31+ 30+
// 28+ 29+ 28+ 29+ 21+
// 21+ 28+ 21+ 28+ 10
// 10 21+ 10 21+
// 11 11
//
// So the greatest amount is added to tmp2[10] and tmp2[12]. If
// tmp2[10/12] has an initial value of <2**29, then the maximum value
// will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32,
// as required.
tmp2[i+3] += (x << 10) & bottom28Bits
tmp2[i+4] += (x >> 18)
tmp2[i+6] += (x << 21) & bottom29Bits
tmp2[i+7] += x >> 8
// At position 200, which is the starting bit position for word 7, we
// have a factor of 0xf000000 = 2**28 - 2**24.
tmp2[i+7] += 0x10000000 & xMask
tmp2[i+8] += (x - 1) & xMask
tmp2[i+7] -= (x << 24) & bottom28Bits
tmp2[i+8] -= x >> 4
tmp2[i+8] += 0x20000000 & xMask
tmp2[i+8] -= x
tmp2[i+8] += (x << 28) & bottom29Bits
tmp2[i+9] += ((x >> 1) - 1) & xMask
if i+1 == p256Limbs {
break
}
tmp2[i+2] += tmp2[i+1] >> 28
x = tmp2[i+1] & bottom28Bits
xMask = nonZeroToAllOnes(x)
tmp2[i+1] = 0
tmp2[i+4] += (x << 11) & bottom29Bits
tmp2[i+5] += (x >> 18)
tmp2[i+7] += (x << 21) & bottom28Bits
tmp2[i+8] += x >> 7
// At position 199, which is the starting bit of the 8th word when
// dealing with a context starting on an odd word, we have a factor of
// 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th
// word from i+1 is i+8.
tmp2[i+8] += 0x20000000 & xMask
tmp2[i+9] += (x - 1) & xMask
tmp2[i+8] -= (x << 25) & bottom29Bits
tmp2[i+9] -= x >> 4
tmp2[i+9] += 0x10000000 & xMask
tmp2[i+9] -= x
tmp2[i+10] += (x - 1) & xMask
}
// We merge the right shift with a carry chain. The words above 2**257 have
// widths of 28,29,... which we need to correct when copying them down.
carry = 0
for i := 0; i < 8; i++ {
// The maximum value of tmp2[i + 9] occurs on the first iteration and
// is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is
// therefore safe.
out[i] = tmp2[i+9]
out[i] += carry
out[i] += (tmp2[i+10] << 28) & bottom29Bits
carry = out[i] >> 29
out[i] &= bottom29Bits
i++
out[i] = tmp2[i+9] >> 1
out[i] += carry
carry = out[i] >> 28
out[i] &= bottom28Bits
}
out[8] = tmp2[17]
out[8] += carry
carry = out[8] >> 29
out[8] &= bottom29Bits
p256ReduceCarry(out, carry)
}
// p256Square sets out=in*in.
//
// On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256Square(out, in *[p256Limbs]uint32) {
var tmp [17]uint64
tmp[0] = uint64(in[0]) * uint64(in[0])
tmp[1] = uint64(in[0]) * (uint64(in[1]) << 1)
tmp[2] = uint64(in[0])*(uint64(in[2])<<1) +
uint64(in[1])*(uint64(in[1])<<1)
tmp[3] = uint64(in[0])*(uint64(in[3])<<1) +
uint64(in[1])*(uint64(in[2])<<1)
tmp[4] = uint64(in[0])*(uint64(in[4])<<1) +
uint64(in[1])*(uint64(in[3])<<2) +
uint64(in[2])*uint64(in[2])
tmp[5] = uint64(in[0])*(uint64(in[5])<<1) +
uint64(in[1])*(uint64(in[4])<<1) +
uint64(in[2])*(uint64(in[3])<<1)
tmp[6] = uint64(in[0])*(uint64(in[6])<<1) +
uint64(in[1])*(uint64(in[5])<<2) +
uint64(in[2])*(uint64(in[4])<<1) +
uint64(in[3])*(uint64(in[3])<<1)
tmp[7] = uint64(in[0])*(uint64(in[7])<<1) +
uint64(in[1])*(uint64(in[6])<<1) +
uint64(in[2])*(uint64(in[5])<<1) +
uint64(in[3])*(uint64(in[4])<<1)
// tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60,
// which is < 2**64 as required.
tmp[8] = uint64(in[0])*(uint64(in[8])<<1) +
uint64(in[1])*(uint64(in[7])<<2) +
uint64(in[2])*(uint64(in[6])<<1) +
uint64(in[3])*(uint64(in[5])<<2) +
uint64(in[4])*uint64(in[4])
tmp[9] = uint64(in[1])*(uint64(in[8])<<1) +
uint64(in[2])*(uint64(in[7])<<1) +
uint64(in[3])*(uint64(in[6])<<1) +
uint64(in[4])*(uint64(in[5])<<1)
tmp[10] = uint64(in[2])*(uint64(in[8])<<1) +
uint64(in[3])*(uint64(in[7])<<2) +
uint64(in[4])*(uint64(in[6])<<1) +
uint64(in[5])*(uint64(in[5])<<1)
tmp[11] = uint64(in[3])*(uint64(in[8])<<1) +
uint64(in[4])*(uint64(in[7])<<1) +
uint64(in[5])*(uint64(in[6])<<1)
tmp[12] = uint64(in[4])*(uint64(in[8])<<1) +
uint64(in[5])*(uint64(in[7])<<2) +
uint64(in[6])*uint64(in[6])
tmp[13] = uint64(in[5])*(uint64(in[8])<<1) +
uint64(in[6])*(uint64(in[7])<<1)
tmp[14] = uint64(in[6])*(uint64(in[8])<<1) +
uint64(in[7])*(uint64(in[7])<<1)
tmp[15] = uint64(in[7]) * (uint64(in[8]) << 1)
tmp[16] = uint64(in[8]) * uint64(in[8])
p256ReduceDegree(out, tmp)
}
// p256Mul sets out=in*in2.
//
// On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
// in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256Mul(out, in, in2 *[p256Limbs]uint32) {
var tmp [17]uint64
tmp[0] = uint64(in[0]) * uint64(in2[0])
tmp[1] = uint64(in[0])*(uint64(in2[1])<<0) +
uint64(in[1])*(uint64(in2[0])<<0)
tmp[2] = uint64(in[0])*(uint64(in2[2])<<0) +
uint64(in[1])*(uint64(in2[1])<<1) +
uint64(in[2])*(uint64(in2[0])<<0)
tmp[3] = uint64(in[0])*(uint64(in2[3])<<0) +
uint64(in[1])*(uint64(in2[2])<<0) +
uint64(in[2])*(uint64(in2[1])<<0) +
uint64(in[3])*(uint64(in2[0])<<0)
tmp[4] = uint64(in[0])*(uint64(in2[4])<<0) +
uint64(in[1])*(uint64(in2[3])<<1) +
uint64(in[2])*(uint64(in2[2])<<0) +
uint64(in[3])*(uint64(in2[1])<<1) +
uint64(in[4])*(uint64(in2[0])<<0)
tmp[5] = uint64(in[0])*(uint64(in2[5])<<0) +
uint64(in[1])*(uint64(in2[4])<<0) +
uint64(in[2])*(uint64(in2[3])<<0) +
uint64(in[3])*(uint64(in2[2])<<0) +
uint64(in[4])*(uint64(in2[1])<<0) +
uint64(in[5])*(uint64(in2[0])<<0)
tmp[6] = uint64(in[0])*(uint64(in2[6])<<0) +
uint64(in[1])*(uint64(in2[5])<<1) +
uint64(in[2])*(uint64(in2[4])<<0) +
uint64(in[3])*(uint64(in2[3])<<1) +
uint64(in[4])*(uint64(in2[2])<<0) +
uint64(in[5])*(uint64(in2[1])<<1) +
uint64(in[6])*(uint64(in2[0])<<0)
tmp[7] = uint64(in[0])*(uint64(in2[7])<<0) +
uint64(in[1])*(uint64(in2[6])<<0) +
uint64(in[2])*(uint64(in2[5])<<0) +
uint64(in[3])*(uint64(in2[4])<<0) +
uint64(in[4])*(uint64(in2[3])<<0) +
uint64(in[5])*(uint64(in2[2])<<0) +
uint64(in[6])*(uint64(in2[1])<<0) +
uint64(in[7])*(uint64(in2[0])<<0)
// tmp[8] has the greatest value but doesn't overflow. See logic in
// p256Square.
tmp[8] = uint64(in[0])*(uint64(in2[8])<<0) +
uint64(in[1])*(uint64(in2[7])<<1) +
uint64(in[2])*(uint64(in2[6])<<0) +
uint64(in[3])*(uint64(in2[5])<<1) +
uint64(in[4])*(uint64(in2[4])<<0) +
uint64(in[5])*(uint64(in2[3])<<1) +
uint64(in[6])*(uint64(in2[2])<<0) +
uint64(in[7])*(uint64(in2[1])<<1) +
uint64(in[8])*(uint64(in2[0])<<0)
tmp[9] = uint64(in[1])*(uint64(in2[8])<<0) +
uint64(in[2])*(uint64(in2[7])<<0) +
uint64(in[3])*(uint64(in2[6])<<0) +
uint64(in[4])*(uint64(in2[5])<<0) +
uint64(in[5])*(uint64(in2[4])<<0) +
uint64(in[6])*(uint64(in2[3])<<0) +
uint64(in[7])*(uint64(in2[2])<<0) +
uint64(in[8])*(uint64(in2[1])<<0)
tmp[10] = uint64(in[2])*(uint64(in2[8])<<0) +
uint64(in[3])*(uint64(in2[7])<<1) +
uint64(in[4])*(uint64(in2[6])<<0) +
uint64(in[5])*(uint64(in2[5])<<1) +
uint64(in[6])*(uint64(in2[4])<<0) +
uint64(in[7])*(uint64(in2[3])<<1) +
uint64(in[8])*(uint64(in2[2])<<0)
tmp[11] = uint64(in[3])*(uint64(in2[8])<<0) +
uint64(in[4])*(uint64(in2[7])<<0) +
uint64(in[5])*(uint64(in2[6])<<0) +
uint64(in[6])*(uint64(in2[5])<<0) +
uint64(in[7])*(uint64(in2[4])<<0) +
uint64(in[8])*(uint64(in2[3])<<0)
tmp[12] = uint64(in[4])*(uint64(in2[8])<<0) +
uint64(in[5])*(uint64(in2[7])<<1) +
uint64(in[6])*(uint64(in2[6])<<0) +
uint64(in[7])*(uint64(in2[5])<<1) +
uint64(in[8])*(uint64(in2[4])<<0)
tmp[13] = uint64(in[5])*(uint64(in2[8])<<0) +
uint64(in[6])*(uint64(in2[7])<<0) +
uint64(in[7])*(uint64(in2[6])<<0) +
uint64(in[8])*(uint64(in2[5])<<0)
tmp[14] = uint64(in[6])*(uint64(in2[8])<<0) +
uint64(in[7])*(uint64(in2[7])<<1) +
uint64(in[8])*(uint64(in2[6])<<0)
tmp[15] = uint64(in[7])*(uint64(in2[8])<<0) +
uint64(in[8])*(uint64(in2[7])<<0)
tmp[16] = uint64(in[8]) * (uint64(in2[8]) << 0)
p256ReduceDegree(out, tmp)
}
func p256Assign(out, in *[p256Limbs]uint32) {
*out = *in
}
// p256Invert calculates |out| = |in|^{-1}
//
// Based on Fermat's Little Theorem:
//
// a^p = a (mod p)
// a^{p-1} = 1 (mod p)
// a^{p-2} = a^{-1} (mod p)
func p256Invert(out, in *[p256Limbs]uint32) {
var ftmp, ftmp2 [p256Limbs]uint32
// each e_I will hold |in|^{2^I - 1}
var e2, e4, e8, e16, e32, e64 [p256Limbs]uint32
p256Square(&ftmp, in) // 2^1
p256Mul(&ftmp, in, &ftmp) // 2^2 - 2^0
p256Assign(&e2, &ftmp)
p256Square(&ftmp, &ftmp) // 2^3 - 2^1
p256Square(&ftmp, &ftmp) // 2^4 - 2^2
p256Mul(&ftmp, &ftmp, &e2) // 2^4 - 2^0
p256Assign(&e4, &ftmp)
p256Square(&ftmp, &ftmp) // 2^5 - 2^1
p256Square(&ftmp, &ftmp) // 2^6 - 2^2
p256Square(&ftmp, &ftmp) // 2^7 - 2^3
p256Square(&ftmp, &ftmp) // 2^8 - 2^4
p256Mul(&ftmp, &ftmp, &e4) // 2^8 - 2^0
p256Assign(&e8, &ftmp)
for i := 0; i < 8; i++ {
p256Square(&ftmp, &ftmp)
} // 2^16 - 2^8
p256Mul(&ftmp, &ftmp, &e8) // 2^16 - 2^0
p256Assign(&e16, &ftmp)
for i := 0; i < 16; i++ {
p256Square(&ftmp, &ftmp)
} // 2^32 - 2^16
p256Mul(&ftmp, &ftmp, &e16) // 2^32 - 2^0
p256Assign(&e32, &ftmp)
for i := 0; i < 32; i++ {
p256Square(&ftmp, &ftmp)
} // 2^64 - 2^32
p256Assign(&e64, &ftmp)
p256Mul(&ftmp, &ftmp, in) // 2^64 - 2^32 + 2^0
for i := 0; i < 192; i++ {
p256Square(&ftmp, &ftmp)
} // 2^256 - 2^224 + 2^192
p256Mul(&ftmp2, &e64, &e32) // 2^64 - 2^0
for i := 0; i < 16; i++ {
p256Square(&ftmp2, &ftmp2)
} // 2^80 - 2^16
p256Mul(&ftmp2, &ftmp2, &e16) // 2^80 - 2^0
for i := 0; i < 8; i++ {
p256Square(&ftmp2, &ftmp2)
} // 2^88 - 2^8
p256Mul(&ftmp2, &ftmp2, &e8) // 2^88 - 2^0
for i := 0; i < 4; i++ {
p256Square(&ftmp2, &ftmp2)
} // 2^92 - 2^4
p256Mul(&ftmp2, &ftmp2, &e4) // 2^92 - 2^0
p256Square(&ftmp2, &ftmp2) // 2^93 - 2^1
p256Square(&ftmp2, &ftmp2) // 2^94 - 2^2
p256Mul(&ftmp2, &ftmp2, &e2) // 2^94 - 2^0
p256Square(&ftmp2, &ftmp2) // 2^95 - 2^1
p256Square(&ftmp2, &ftmp2) // 2^96 - 2^2
p256Mul(&ftmp2, &ftmp2, in) // 2^96 - 3
p256Mul(out, &ftmp2, &ftmp) // 2^256 - 2^224 + 2^192 + 2^96 - 3
}
// p256Scalar3 sets out=3*out.
//
// On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256Scalar3(out *[p256Limbs]uint32) {
var carry uint32
for i := 0; ; i++ {
out[i] *= 3
out[i] += carry
carry = out[i] >> 29
out[i] &= bottom29Bits
i++
if i == p256Limbs {
break
}
out[i] *= 3
out[i] += carry
carry = out[i] >> 28
out[i] &= bottom28Bits
}
p256ReduceCarry(out, carry)
}
// p256Scalar4 sets out=4*out.
//
// On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256Scalar4(out *[p256Limbs]uint32) {
var carry, nextCarry uint32
for i := 0; ; i++ {
nextCarry = out[i] >> 27
out[i] <<= 2
out[i] &= bottom29Bits
out[i] += carry
carry = nextCarry + (out[i] >> 29)
out[i] &= bottom29Bits
i++
if i == p256Limbs {
break
}
nextCarry = out[i] >> 26
out[i] <<= 2
out[i] &= bottom28Bits
out[i] += carry
carry = nextCarry + (out[i] >> 28)
out[i] &= bottom28Bits
}
p256ReduceCarry(out, carry)
}
// p256Scalar8 sets out=8*out.
//
// On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
// On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
func p256Scalar8(out *[p256Limbs]uint32) {
var carry, nextCarry uint32
for i := 0; ; i++ {
nextCarry = out[i] >> 26
out[i] <<= 3
out[i] &= bottom29Bits
out[i] += carry
carry = nextCarry + (out[i] >> 29)
out[i] &= bottom29Bits
i++
if i == p256Limbs {
break
}
nextCarry = out[i] >> 25
out[i] <<= 3
out[i] &= bottom28Bits
out[i] += carry
carry = nextCarry + (out[i] >> 28)
out[i] &= bottom28Bits
}
p256ReduceCarry(out, carry)
}
// p256CopyConditional sets out=in if mask = 0xffffffff in constant time.
//
// On entry: mask is either 0 or 0xffffffff.
func p256CopyConditional(out, in *[p256Limbs]uint32, mask uint32) {
for i := 0; i < p256Limbs; i++ {
tmp := mask & (in[i] ^ out[i])
out[i] ^= tmp
}
}
// p256FromBig sets out = R*in.
func p256FromBig(out *[p256Limbs]uint32, in *big.Int) {
tmp := new(big.Int).Lsh(in, 257)
tmp.Mod(tmp, p256Params.P)
for i := 0; i < p256Limbs; i++ {
if bits := tmp.Bits(); len(bits) > 0 {
out[i] = uint32(bits[0]) & bottom29Bits
} else {
out[i] = 0
}
tmp.Rsh(tmp, 29)
i++
if i == p256Limbs {
break
}
if bits := tmp.Bits(); len(bits) > 0 {
out[i] = uint32(bits[0]) & bottom28Bits
} else {
out[i] = 0
}
tmp.Rsh(tmp, 28)
}
}
// p256ToBig returns a *big.Int containing the value of in.
func p256ToBig(in *[p256Limbs]uint32) *big.Int {
result, tmp := new(big.Int), new(big.Int)
result.SetInt64(int64(in[p256Limbs-1]))
for i := p256Limbs - 2; i >= 0; i-- {
if (i & 1) == 0 {
result.Lsh(result, 29)
} else {
result.Lsh(result, 28)
}
tmp.SetInt64(int64(in[i]))
result.Add(result, tmp)
}
result.Mul(result, p256RInverse)
result.Mod(result, p256Params.P)
return result
}

View File

@ -0,0 +1,15 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !amd64 && !s390x && !arm64 && !ppc64le
// +build !amd64,!s390x,!arm64,!ppc64le
package elliptic
var p256 p256Curve
func initP256Arch() {
// Use pure Go constant-time implementation.
p256 = p256Curve{p256Params}
}

View File

@ -35,7 +35,6 @@ var (
func initP256Arch() {
p256 = p256CurveFast{p256Params}
initTable()
return
}
func (curve p256CurveFast) Params() *CurveParams {
@ -73,7 +72,6 @@ func p256MovCond(res, a, b *p256Point, cond int)
//go:noescape
func p256Select(point *p256Point, table []p256Point, idx int)
//
//go:noescape
func p256SelectBase(point *p256Point, table []p256Point, idx int)
@ -85,12 +83,9 @@ func p256SelectBase(point *p256Point, table []p256Point, idx int)
//go:noescape
func p256PointAddAffineAsm(res, in1, in2 *p256Point, sign, sel, zero int)
// Point add
//
//go:noescape
func p256PointAddAsm(res, in1, in2 *p256Point) int
//
//go:noescape
func p256PointDoubleAsm(res, in *p256Point)
@ -340,7 +335,6 @@ func boothW7(in uint) (int, int) {
}
func initTable() {
p256PreFast = new([37][64]p256Point)
// TODO: For big endian, these slices should be in reverse byte order,
@ -352,7 +346,6 @@ func initTable() {
0x25, 0xf3, 0x21, 0xdd, 0x88, 0x86, 0xe8, 0xd2, 0x85, 0x5d, 0x88, 0x25, 0x18, 0xff, 0x71, 0x85}, //(p256.y*2^256)%p
z: [32]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, //(p256.z*2^256)%p
}
t1 := new(p256Point)

View File

@ -60,7 +60,6 @@ func initP256Arch() {
// No vector support, use pure Go implementation.
p256 = p256Curve{p256Params}
return
}
func (curve p256CurveFast) Params() *CurveParams {

View File

@ -1,144 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package elliptic
import (
"crypto/elliptic/internal/nistec"
"crypto/rand"
"math/big"
)
// p384Curve is a Curve implementation based on nistec.P384Point.
//
// It's a wrapper that exposes the big.Int-based Curve interface and encodes the
// legacy idiosyncrasies it requires, such as invalid and infinity point
// handling.
//
// To interact with the nistec package, points are encoded into and decoded from
// properly formatted byte slices. All big.Int use is limited to this package.
// Encoding and decoding is 1/1000th of the runtime of a scalar multiplication,
// so the overhead is acceptable.
type p384Curve struct {
params *CurveParams
}
var p384 p384Curve
var _ Curve = p384
func initP384() {
p384.params = &CurveParams{
Name: "P-384",
BitSize: 384,
// FIPS 186-4, section D.1.2.4
P: bigFromDecimal("394020061963944792122790401001436138050797392704654" +
"46667948293404245721771496870329047266088258938001861606973112319"),
N: bigFromDecimal("394020061963944792122790401001436138050797392704654" +
"46667946905279627659399113263569398956308152294913554433653942643"),
B: bigFromHex("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088" +
"f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"),
Gx: bigFromHex("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741" +
"e082542a385502f25dbf55296c3a545e3872760ab7"),
Gy: bigFromHex("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da31" +
"13b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"),
}
}
func (curve p384Curve) Params() *CurveParams {
return curve.params
}
func (curve p384Curve) IsOnCurve(x, y *big.Int) bool {
// IsOnCurve is documented to reject (0, 0), the conventional point at
// infinity, which however is accepted by p384PointFromAffine.
if x.Sign() == 0 && y.Sign() == 0 {
return false
}
_, ok := p384PointFromAffine(x, y)
return ok
}
func p384PointFromAffine(x, y *big.Int) (p *nistec.P384Point, ok bool) {
// (0, 0) is by convention the point at infinity, which can't be represented
// in affine coordinates. Marshal incorrectly encodes it as an uncompressed
// point, which SetBytes would correctly reject. See Issue 37294.
if x.Sign() == 0 && y.Sign() == 0 {
return nistec.NewP384Point(), true
}
if x.Sign() < 0 || y.Sign() < 0 {
return nil, false
}
if x.BitLen() > 384 || y.BitLen() > 384 {
return nil, false
}
p, err := nistec.NewP384Point().SetBytes(Marshal(P384(), x, y))
if err != nil {
return nil, false
}
return p, true
}
func p384PointToAffine(p *nistec.P384Point) (x, y *big.Int) {
out := p.Bytes()
if len(out) == 1 && out[0] == 0 {
// This is the correct encoding of the point at infinity, which
// Unmarshal does not support. See Issue 37294.
return new(big.Int), new(big.Int)
}
x, y = Unmarshal(P384(), out)
if x == nil {
panic("crypto/elliptic: internal error: Unmarshal rejected a valid point encoding")
}
return x, y
}
// p384RandomPoint returns a random point on the curve. It's used when Add,
// Double, or ScalarMult are fed a point not on the curve, which is undefined
// behavior. Originally, we used to do the math on it anyway (which allows
// invalid curve attacks) and relied on the caller and Unmarshal to avoid this
// happening in the first place. Now, we just can't construct a nistec.P384Point
// for an invalid pair of coordinates, because that API is safer. If we panic,
// we risk introducing a DoS. If we return nil, we risk a panic. If we return
// the input, ecdsa.Verify might fail open. The safest course seems to be to
// return a valid, random point, which hopefully won't help the attacker.
func p384RandomPoint() (x, y *big.Int) {
_, x, y, err := GenerateKey(P384(), rand.Reader)
if err != nil {
panic("crypto/elliptic: failed to generate random point")
}
return x, y
}
func (p384Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
p1, ok := p384PointFromAffine(x1, y1)
if !ok {
return p384RandomPoint()
}
p2, ok := p384PointFromAffine(x2, y2)
if !ok {
return p384RandomPoint()
}
return p384PointToAffine(p1.Add(p1, p2))
}
func (p384Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
p, ok := p384PointFromAffine(x1, y1)
if !ok {
return p384RandomPoint()
}
return p384PointToAffine(p.Double(p))
}
func (p384Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
p, ok := p384PointFromAffine(Bx, By)
if !ok {
return p384RandomPoint()
}
return p384PointToAffine(p.ScalarMult(p, scalar))
}
func (p384Curve) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) {
p := nistec.NewP384Generator()
return p384PointToAffine(p.ScalarMult(p, scalar))
}

View File

@ -1,165 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package elliptic
import (
"crypto/elliptic/internal/nistec"
"crypto/rand"
"math/big"
)
// p521Curve is a Curve implementation based on nistec.P521Point.
//
// It's a wrapper that exposes the big.Int-based Curve interface and encodes the
// legacy idiosyncrasies it requires, such as invalid and infinity point
// handling.
//
// To interact with the nistec package, points are encoded into and decoded from
// properly formatted byte slices. All big.Int use is limited to this package.
// Encoding and decoding is 1/1000th of the runtime of a scalar multiplication,
// so the overhead is acceptable.
type p521Curve struct {
params *CurveParams
}
var p521 p521Curve
var _ Curve = p521
func initP521() {
p521.params = &CurveParams{
Name: "P-521",
BitSize: 521,
// FIPS 186-4, section D.1.2.5
P: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
"0540939446345918554318339765605212255964066145455497729631139148" +
"0858037121987999716643812574028291115057151"),
N: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
"0540939446345918554318339765539424505774633321719753296399637136" +
"3321113864768612440380340372808892707005449"),
B: bigFromHex("0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8" +
"b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef" +
"451fd46b503f00"),
Gx: bigFromHex("00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f8" +
"28af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf9" +
"7e7e31c2e5bd66"),
Gy: bigFromHex("011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817" +
"afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088" +
"be94769fd16650"),
}
}
func (curve p521Curve) Params() *CurveParams {
return curve.params
}
func (curve p521Curve) IsOnCurve(x, y *big.Int) bool {
// IsOnCurve is documented to reject (0, 0), the conventional point at
// infinity, which however is accepted by p521PointFromAffine.
if x.Sign() == 0 && y.Sign() == 0 {
return false
}
_, ok := p521PointFromAffine(x, y)
return ok
}
func p521PointFromAffine(x, y *big.Int) (p *nistec.P521Point, ok bool) {
// (0, 0) is by convention the point at infinity, which can't be represented
// in affine coordinates. Marshal incorrectly encodes it as an uncompressed
// point, which SetBytes would correctly reject. See Issue 37294.
if x.Sign() == 0 && y.Sign() == 0 {
return nistec.NewP521Point(), true
}
if x.Sign() < 0 || y.Sign() < 0 {
return nil, false
}
if x.BitLen() > 521 || y.BitLen() > 521 {
return nil, false
}
p, err := nistec.NewP521Point().SetBytes(Marshal(P521(), x, y))
if err != nil {
return nil, false
}
return p, true
}
func p521PointToAffine(p *nistec.P521Point) (x, y *big.Int) {
out := p.Bytes()
if len(out) == 1 && out[0] == 0 {
// This is the correct encoding of the point at infinity, which
// Unmarshal does not support. See Issue 37294.
return new(big.Int), new(big.Int)
}
x, y = Unmarshal(P521(), out)
if x == nil {
panic("crypto/elliptic: internal error: Unmarshal rejected a valid point encoding")
}
return x, y
}
// p521RandomPoint returns a random point on the curve. It's used when Add,
// Double, or ScalarMult are fed a point not on the curve, which is undefined
// behavior. Originally, we used to do the math on it anyway (which allows
// invalid curve attacks) and relied on the caller and Unmarshal to avoid this
// happening in the first place. Now, we just can't construct a nistec.P521Point
// for an invalid pair of coordinates, because that API is safer. If we panic,
// we risk introducing a DoS. If we return nil, we risk a panic. If we return
// the input, ecdsa.Verify might fail open. The safest course seems to be to
// return a valid, random point, which hopefully won't help the attacker.
func p521RandomPoint() (x, y *big.Int) {
_, x, y, err := GenerateKey(P521(), rand.Reader)
if err != nil {
panic("crypto/elliptic: failed to generate random point")
}
return x, y
}
func (p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
p1, ok := p521PointFromAffine(x1, y1)
if !ok {
return p521RandomPoint()
}
p2, ok := p521PointFromAffine(x2, y2)
if !ok {
return p521RandomPoint()
}
return p521PointToAffine(p1.Add(p1, p2))
}
func (p521Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
p, ok := p521PointFromAffine(x1, y1)
if !ok {
return p521RandomPoint()
}
return p521PointToAffine(p.Double(p))
}
func (p521Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
p, ok := p521PointFromAffine(Bx, By)
if !ok {
return p521RandomPoint()
}
return p521PointToAffine(p.ScalarMult(p, scalar))
}
func (p521Curve) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) {
p := nistec.NewP521Generator()
return p521PointToAffine(p.ScalarMult(p, scalar))
}
func bigFromDecimal(s string) *big.Int {
b, ok := new(big.Int).SetString(s, 10)
if !ok {
panic("invalid encoding")
}
return b
}
func bigFromHex(s string) *big.Int {
b, ok := new(big.Int).SetString(s, 16)
if !ok {
panic("invalid encoding")
}
return b
}

View File

@ -0,0 +1,296 @@
// Copyright 2021 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 elliptic
import "math/big"
// CurveParams contains the parameters of an elliptic curve and also provides
// a generic, non-constant time implementation of Curve.
type CurveParams struct {
P *big.Int // the order of the underlying field
N *big.Int // the order of the base point
B *big.Int // the constant of the curve equation
Gx, Gy *big.Int // (x,y) of the base point
BitSize int // the size of the underlying field
Name string // the canonical name of the curve
}
func (curve *CurveParams) Params() *CurveParams {
return curve
}
// CurveParams operates, internally, on Jacobian coordinates. For a given
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
// calculation can be performed within the transform (as in ScalarMult and
// ScalarBaseMult). But even for Add and Double, it's faster to apply and
// reverse the transform than to operate in affine coordinates.
// polynomial returns x³ - 3x + b.
func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
threeX := new(big.Int).Lsh(x, 1)
threeX.Add(threeX, x)
x3.Sub(x3, threeX)
x3.Add(x3, curve.B)
x3.Mod(x3, curve.P)
return x3
}
func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p384, p521); ok {
return specific.IsOnCurve(x, y)
}
if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
return false
}
// y² = x³ - 3x + b
y2 := new(big.Int).Mul(y, y)
y2.Mod(y2, curve.P)
return curve.polynomial(x).Cmp(y2) == 0
}
// zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
// y are zero, it assumes that they represent the point at infinity because (0,
// 0) is not on the any of the curves handled here.
func zForAffine(x, y *big.Int) *big.Int {
z := new(big.Int)
if x.Sign() != 0 || y.Sign() != 0 {
z.SetInt64(1)
}
return z
}
// affineFromJacobian reverses the Jacobian transform. See the comment at the
// top of the file. If the point is ∞ it returns 0, 0.
func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
if z.Sign() == 0 {
return new(big.Int), new(big.Int)
}
zinv := new(big.Int).ModInverse(z, curve.P)
zinvsq := new(big.Int).Mul(zinv, zinv)
xOut = new(big.Int).Mul(x, zinvsq)
xOut.Mod(xOut, curve.P)
zinvsq.Mul(zinvsq, zinv)
yOut = new(big.Int).Mul(y, zinvsq)
yOut.Mod(yOut, curve.P)
return
}
func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p384, p521); ok {
return specific.Add(x1, y1, x2, y2)
}
z1 := zForAffine(x1, y1)
z2 := zForAffine(x2, y2)
return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
}
// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
// (x2, y2, z2) and returns their sum, also in Jacobian form.
func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
if z1.Sign() == 0 {
x3.Set(x2)
y3.Set(y2)
z3.Set(z2)
return x3, y3, z3
}
if z2.Sign() == 0 {
x3.Set(x1)
y3.Set(y1)
z3.Set(z1)
return x3, y3, z3
}
z1z1 := new(big.Int).Mul(z1, z1)
z1z1.Mod(z1z1, curve.P)
z2z2 := new(big.Int).Mul(z2, z2)
z2z2.Mod(z2z2, curve.P)
u1 := new(big.Int).Mul(x1, z2z2)
u1.Mod(u1, curve.P)
u2 := new(big.Int).Mul(x2, z1z1)
u2.Mod(u2, curve.P)
h := new(big.Int).Sub(u2, u1)
xEqual := h.Sign() == 0
if h.Sign() == -1 {
h.Add(h, curve.P)
}
i := new(big.Int).Lsh(h, 1)
i.Mul(i, i)
j := new(big.Int).Mul(h, i)
s1 := new(big.Int).Mul(y1, z2)
s1.Mul(s1, z2z2)
s1.Mod(s1, curve.P)
s2 := new(big.Int).Mul(y2, z1)
s2.Mul(s2, z1z1)
s2.Mod(s2, curve.P)
r := new(big.Int).Sub(s2, s1)
if r.Sign() == -1 {
r.Add(r, curve.P)
}
yEqual := r.Sign() == 0
if xEqual && yEqual {
return curve.doubleJacobian(x1, y1, z1)
}
r.Lsh(r, 1)
v := new(big.Int).Mul(u1, i)
x3.Set(r)
x3.Mul(x3, x3)
x3.Sub(x3, j)
x3.Sub(x3, v)
x3.Sub(x3, v)
x3.Mod(x3, curve.P)
y3.Set(r)
v.Sub(v, x3)
y3.Mul(y3, v)
s1.Mul(s1, j)
s1.Lsh(s1, 1)
y3.Sub(y3, s1)
y3.Mod(y3, curve.P)
z3.Add(z1, z2)
z3.Mul(z3, z3)
z3.Sub(z3, z1z1)
z3.Sub(z3, z2z2)
z3.Mul(z3, h)
z3.Mod(z3, curve.P)
return x3, y3, z3
}
func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p384, p521); ok {
return specific.Double(x1, y1)
}
z1 := zForAffine(x1, y1)
return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
}
// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
// returns its double, also in Jacobian form.
func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
delta := new(big.Int).Mul(z, z)
delta.Mod(delta, curve.P)
gamma := new(big.Int).Mul(y, y)
gamma.Mod(gamma, curve.P)
alpha := new(big.Int).Sub(x, delta)
if alpha.Sign() == -1 {
alpha.Add(alpha, curve.P)
}
alpha2 := new(big.Int).Add(x, delta)
alpha.Mul(alpha, alpha2)
alpha2.Set(alpha)
alpha.Lsh(alpha, 1)
alpha.Add(alpha, alpha2)
beta := alpha2.Mul(x, gamma)
x3 := new(big.Int).Mul(alpha, alpha)
beta8 := new(big.Int).Lsh(beta, 3)
beta8.Mod(beta8, curve.P)
x3.Sub(x3, beta8)
if x3.Sign() == -1 {
x3.Add(x3, curve.P)
}
x3.Mod(x3, curve.P)
z3 := new(big.Int).Add(y, z)
z3.Mul(z3, z3)
z3.Sub(z3, gamma)
if z3.Sign() == -1 {
z3.Add(z3, curve.P)
}
z3.Sub(z3, delta)
if z3.Sign() == -1 {
z3.Add(z3, curve.P)
}
z3.Mod(z3, curve.P)
beta.Lsh(beta, 2)
beta.Sub(beta, x3)
if beta.Sign() == -1 {
beta.Add(beta, curve.P)
}
y3 := alpha.Mul(alpha, beta)
gamma.Mul(gamma, gamma)
gamma.Lsh(gamma, 3)
gamma.Mod(gamma, curve.P)
y3.Sub(y3, gamma)
if y3.Sign() == -1 {
y3.Add(y3, curve.P)
}
y3.Mod(y3, curve.P)
return x3, y3, z3
}
func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p256, p384, p521); ok {
return specific.ScalarMult(Bx, By, k)
}
Bz := new(big.Int).SetInt64(1)
x, y, z := new(big.Int), new(big.Int), new(big.Int)
for _, byte := range k {
for bitNum := 0; bitNum < 8; bitNum++ {
x, y, z = curve.doubleJacobian(x, y, z)
if byte&0x80 == 0x80 {
x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
}
byte <<= 1
}
}
return curve.affineFromJacobian(x, y, z)
}
func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p256, p384, p521); ok {
return specific.ScalarBaseMult(k)
}
return curve.ScalarMult(curve.Gx, curve.Gy, k)
}
func matchesSpecificCurve(params *CurveParams, available ...Curve) (Curve, bool) {
for _, c := range available {
if params == c.Params() {
return c, true
}
}
return nil, false
}

View File

@ -21,7 +21,7 @@ func init() {
// is returned by a single call to getrandom() on systems where int
// has a size of 32 bits.
maxGetRandomRead = (1 << 25) - 1
case "freebsd", "dragonfly", "solaris":
case "freebsd", "dragonfly", "solaris", "illumos":
maxGetRandomRead = 1 << 8
default:
panic("no maximum specified for GetRandom")

View File

@ -18,7 +18,6 @@ import (
"crypto/x509"
"errors"
"fmt"
"internal/godebug"
"io"
"net"
"strings"
@ -977,9 +976,6 @@ var supportedVersions = []uint16{
VersionTLS10,
}
// debugEnableTLS10 enables TLS 1.0. See issue 45428.
var debugEnableTLS10 = godebug.Get("tls10default") == "1"
// roleClient and roleServer are meant to call supportedVersions and parents
// with more readability at the callsite.
const roleClient = true
@ -991,7 +987,7 @@ func (c *Config) supportedVersions(isClient bool) []uint16 {
if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) {
continue
}
if (c == nil || c.MinVersion == 0) && !debugEnableTLS10 &&
if (c == nil || c.MinVersion == 0) &&
isClient && v < VersionTLS12 {
continue
}

View File

@ -384,6 +384,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
seenExts := make(map[uint16]bool)
for !extensions.Empty() {
var extension uint16
var extData cryptobyte.String
@ -392,6 +393,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
if seenExts[extension] {
return false
}
seenExts[extension] = true
switch extension {
case extensionServerName:
// RFC 6066, Section 3
@ -750,6 +756,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
seenExts := make(map[uint16]bool)
for !extensions.Empty() {
var extension uint16
var extData cryptobyte.String
@ -758,6 +765,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
if seenExts[extension] {
return false
}
seenExts[extension] = true
switch extension {
case extensionStatusRequest:
m.ocspStapling = true

View File

@ -6,6 +6,7 @@ package tls
import (
"bytes"
"encoding/hex"
"math/rand"
"reflect"
"strings"
@ -463,3 +464,23 @@ func TestRejectEmptySCT(t *testing.T) {
t.Fatal("Unmarshaled ServerHello with zero-length SCT")
}
}
func TestRejectDuplicateExtensions(t *testing.T) {
clientHelloBytes, err := hex.DecodeString("010000440303000000000000000000000000000000000000000000000000000000000000000000000000001c0000000a000800000568656c6c6f0000000a000800000568656c6c6f")
if err != nil {
t.Fatalf("failed to decode test ClientHello: %s", err)
}
var clientHelloCopy clientHelloMsg
if clientHelloCopy.unmarshal(clientHelloBytes) {
t.Error("Unmarshaled ClientHello with duplicate extensions")
}
serverHelloBytes, err := hex.DecodeString("02000030030300000000000000000000000000000000000000000000000000000000000000000000000000080005000000050000")
if err != nil {
t.Fatalf("failed to decode test ServerHello: %s", err)
}
var serverHelloCopy serverHelloMsg
if serverHelloCopy.unmarshal(serverHelloBytes) {
t.Fatal("Unmarshaled ServerHello with duplicate extensions")
}
}

View File

@ -400,16 +400,6 @@ func TestVersion(t *testing.T) {
if err == nil {
t.Fatalf("expected failure to connect with TLS 1.0/1.1")
}
defer func(old bool) { debugEnableTLS10 = old }(debugEnableTLS10)
debugEnableTLS10 = true
_, _, err = testHandshake(t, clientConfig, serverConfig)
if err != nil {
t.Fatalf("handshake failed: %s", err)
}
if state.Version != VersionTLS11 {
t.Fatalf("incorrect version %x, should be %x", state.Version, VersionTLS11)
}
}
func TestCipherSuitePreference(t *testing.T) {

View File

@ -7,6 +7,7 @@ package x509
import (
"bytes"
"crypto"
"crypto/x509/pkix"
"errors"
"fmt"
"net"
@ -837,6 +838,50 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
return n
}
// alreadyInChain checks whether a candidate certificate is present in a chain.
// Rather than doing a direct byte for byte equivalency check, we check if the
// subject, public key, and SAN, if present, are equal. This prevents loops that
// are created by mutual cross-signatures, or other cross-signature bridge
// oddities.
func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
type pubKeyEqual interface {
Equal(crypto.PublicKey) bool
}
var candidateSAN *pkix.Extension
for _, ext := range candidate.Extensions {
if ext.Id.Equal(oidExtensionSubjectAltName) {
candidateSAN = &ext
break
}
}
for _, cert := range chain {
if !bytes.Equal(candidate.RawSubject, cert.RawSubject) {
continue
}
if !candidate.PublicKey.(pubKeyEqual).Equal(cert.PublicKey) {
continue
}
var certSAN *pkix.Extension
for _, ext := range cert.Extensions {
if ext.Id.Equal(oidExtensionSubjectAltName) {
certSAN = &ext
break
}
}
if candidateSAN == nil && certSAN == nil {
return true
} else if candidateSAN == nil || certSAN == nil {
return false
}
if bytes.Equal(candidateSAN.Value, certSAN.Value) {
return true
}
}
return false
}
// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
// that an invocation of buildChains will (transitively) make. Most chains are
// less than 15 certificates long, so this leaves space for multiple chains and
@ -849,18 +894,9 @@ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, o
hintCert *Certificate
)
type pubKeyEqual interface {
Equal(crypto.PublicKey) bool
}
considerCandidate := func(certType int, candidate *Certificate) {
for _, cert := range currentChain {
// If a certificate already appeared in the chain we've built, don't
// reconsider it. This prevents loops, for isntance those created by
// mutual cross-signatures, or other cross-signature bridges oddities.
if bytes.Equal(cert.RawSubject, candidate.RawSubject) && cert.PublicKey.(pubKeyEqual).Equal(candidate.PublicKey) {
return
}
if alreadyInChain(candidate, currentChain) {
return
}
if sigChecks == nil {

View File

@ -2340,6 +2340,29 @@ func TestPathBuilding(t *testing.T) {
"CN=leaf -> CN=inter b -> CN=inter c -> CN=root",
},
},
{
// Build a simple two node graph, where the leaf is directly issued from
// the root and both certificates have matching subject and public key, but
// the leaf has SANs.
name: "leaf with same subject, key, as parent but with SAN",
graph: trustGraphDescription{
Roots: []string{"root"},
Leaf: "root",
Graph: []trustGraphEdge{
{
Issuer: "root",
Subject: "root",
Type: leafCertificate,
MutateTemplate: func(c *Certificate) {
c.DNSNames = []string{"localhost"}
},
},
},
},
expectedChains: []string{
"CN=root -> CN=root",
},
},
}
for _, tc := range tests {

View File

@ -1478,21 +1478,14 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return nil, errors.New("x509: no SerialNumber given")
}
// RFC 5280 Section 4.1.2.2: serial number must positive and should not be longer
// than 20 octets.
// RFC 5280 Section 4.1.2.2: serial number must positive
//
// We cannot simply check for len(serialBytes) > 20, because encoding/asn1 may
// pad the slice in order to prevent the integer being mistaken for a negative
// number (DER uses the high bit of the left-most byte to indicate the sign.),
// so we need to double check the composition of the serial if it is exactly
// 20 bytes.
// We _should_ also restrict serials to <= 20 octets, but it turns out a lot of people
// get this wrong, in part because the encoding can itself alter the length of the
// serial. For now we accept these non-conformant serials.
if template.SerialNumber.Sign() == -1 {
return nil, errors.New("x509: serial number must be positive")
}
serialBytes := template.SerialNumber.Bytes()
if len(serialBytes) > 20 || (len(serialBytes) == 20 && serialBytes[0]&0x80 != 0) {
return nil, errors.New("x509: serial number exceeds 20 octets")
}
if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) {
return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")

View File

@ -3589,42 +3589,6 @@ func TestOmitEmptyExtensions(t *testing.T) {
}
}
func TestCreateCertificateLongSerial(t *testing.T) {
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
serialBytes := make([]byte, 21)
serialBytes[0] = 0x80
serialBytes[20] = 1
tooLong := big.NewInt(0).SetBytes(serialBytes)
tmpl := &Certificate{
SerialNumber: tooLong,
Subject: pkix.Name{
CommonName: ":)",
},
NotAfter: time.Now().Add(time.Hour),
NotBefore: time.Now().Add(-time.Hour),
}
expectedErr := "x509: serial number exceeds 20 octets"
_, err = CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
if err == nil || err.Error() != expectedErr {
t.Errorf("CreateCertificate returned unexpected error: want %q, got %q", expectedErr, err)
}
serialBytes = serialBytes[:20]
tmpl.SerialNumber = big.NewInt(0).SetBytes(serialBytes)
_, err = CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
if err == nil || err.Error() != expectedErr {
t.Errorf("CreateCertificate returned unexpected error: want %q, got %q", expectedErr, err)
}
}
var negativeSerialCert = `-----BEGIN CERTIFICATE-----
MIIBBTCBraADAgECAgH/MAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAjopMB4XDTIy
MDQxNDIzNTYwNFoXDTIyMDQxNTAxNTYwNFowDTELMAkGA1UEAxMCOikwWTATBgcq

View File

@ -136,10 +136,9 @@ const (
// auxiliary symbols: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-symbol-records
// COMDAT sections: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#comdat-sections-object-only
// auxiliary info for section definitions: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
//
func (f *File) COFFSymbolReadSectionDefAux(idx int) (*COFFSymbolAuxFormat5, error) {
var rv *COFFSymbolAuxFormat5
if idx < 0 || idx > len(f.COFFSymbols) {
if idx < 0 || idx >= len(f.COFFSymbols) {
return rv, fmt.Errorf("invalid symbol index")
}
pesym := &f.COFFSymbols[idx]

View File

@ -1185,20 +1185,13 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode)
if ctxt.CgoEnabled {
cgo = "1"
}
cmd.Env = append(os.Environ(),
cmd.Env = append(cmd.Environ(),
"GOOS="+ctxt.GOOS,
"GOARCH="+ctxt.GOARCH,
"GOROOT="+ctxt.GOROOT,
"GOPATH="+ctxt.GOPATH,
"CGO_ENABLED="+cgo,
)
if cmd.Dir != "" {
// If possible, set PWD: if an error occurs and PWD includes a symlink, we
// want the error to refer to Dir, not some other name for it.
if abs, err := filepath.Abs(cmd.Dir); err == nil {
cmd.Env = append(cmd.Env, "PWD="+abs)
}
}
if err := cmd.Run(); err != nil {
return fmt.Errorf("go/build: go list %s: %v\n%s\n", path, err, stderr.String())

View File

@ -38,7 +38,7 @@ const (
var config = printer.Config{Mode: printerMode, Tabwidth: tabWidth}
const parserMode = parser.ParseComments
const parserMode = parser.ParseComments | parser.SkipObjectResolution
// Node formats node in canonical gofmt style and writes the result to dst.
//

View File

@ -136,7 +136,7 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
setUsesCgo(&conf)
file, err := p.cgo(bp)
if err != nil {
return nil, err
return nil, fmt.Errorf("error processing cgo for package %q: %w", bp.ImportPath, err)
}
files = append(files, file)
}
@ -223,9 +223,9 @@ func (p *Importer) cgo(bp *build.Package) (*ast.File, error) {
args = append(args, bp.CgoCPPFLAGS...)
if len(bp.CgoPkgConfig) > 0 {
cmd := exec.Command("pkg-config", append([]string{"--cflags"}, bp.CgoPkgConfig...)...)
out, err := cmd.CombinedOutput()
out, err := cmd.Output()
if err != nil {
return nil, err
return nil, fmt.Errorf("pkg-config --cflags: %w", err)
}
args = append(args, strings.Fields(string(out))...)
}
@ -237,7 +237,7 @@ func (p *Importer) cgo(bp *build.Package) (*ast.File, error) {
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = bp.Dir
if err := cmd.Run(); err != nil {
return nil, err
return nil, fmt.Errorf("go tool cgo: %w", err)
}
return parser.ParseFile(p.fset, filepath.Join(tmpdir, "_cgo_gotypes.go"), nil, 0)

View File

@ -414,9 +414,9 @@ func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, i
// AssertableTo reports whether a value of type V can be asserted to have type T.
//
// The behavior of AssertableTo is undefined in two cases:
// - if V is a generalized interface; i.e., an interface that may only be used
// as a type constraint in Go code
// - if T is an uninstantiated generic type
// - if V is a generalized interface; i.e., an interface that may only be used
// as a type constraint in Go code
// - if T is an uninstantiated generic type
func AssertableTo(V *Interface, T Type) bool {
// Checker.newAssertableTo suppresses errors for invalid types, so we need special
// handling here.

View File

@ -9,6 +9,7 @@ package types
import (
"fmt"
"go/ast"
"go/token"
"strings"
)
@ -339,11 +340,10 @@ func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnStmt ast.St
} else if len(rhs) > 0 {
at = rhs[len(rhs)-1].expr // report at last value
}
check.errorf(at, _WrongResultCount, "%s return values\n\thave %s\n\twant %s",
qualifier,
check.typesSummary(operandTypes(rhs), false),
check.typesSummary(varTypes(lhs), false),
)
err := newErrorf(at, _WrongResultCount, "%s return values", qualifier)
err.errorf(token.NoPos, "have %s", check.typesSummary(operandTypes(rhs), false))
err.errorf(token.NoPos, "want %s", check.typesSummary(varTypes(lhs), false))
check.report(err)
return
}
if compilerErrorMessages {

View File

@ -368,11 +368,10 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
if sig.params != nil {
params = sig.params.vars
}
check.errorf(at, _WrongArgCount, "%s arguments in call to %s\n\thave %s\n\twant %s",
qualifier, call.Fun,
check.typesSummary(operandTypes(args), false),
check.typesSummary(varTypes(params), sig.variadic),
)
err := newErrorf(at, _WrongArgCount, "%s arguments in call to %s", qualifier, call.Fun)
err.errorf(token.NoPos, "have %s", check.typesSummary(operandTypes(args), false))
err.errorf(token.NoPos, "want %s", check.typesSummary(varTypes(params), sig.variadic))
check.report(err)
return
}

View File

@ -8,6 +8,7 @@ package types
import (
"go/constant"
"go/token"
"unicode"
)
@ -74,7 +75,9 @@ func (check *Checker) conversion(x *operand, T Type) {
if compilerErrorMessages {
if cause != "" {
// Add colon at end of line if we have a following cause.
check.errorf(x, _InvalidConversion, "cannot convert %s to type %s:\n\t%s", x, T, cause)
err := newErrorf(x, _InvalidConversion, "cannot convert %s to type %s:", x, T)
err.errorf(token.NoPos, cause)
check.report(err)
} else {
check.errorf(x, _InvalidConversion, "cannot convert %s to type %s", x, T)
}

View File

@ -8,7 +8,6 @@ package types
import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/token"
@ -26,6 +25,64 @@ func unreachable() {
panic("unreachable")
}
// An error_ represents a type-checking error.
// To report an error_, call Checker.report.
type error_ struct {
desc []errorDesc
code errorCode
soft bool // TODO(gri) eventually determine this from an error code
}
// An errorDesc describes part of a type-checking error.
type errorDesc struct {
posn positioner
format string
args []interface{}
}
func (err *error_) empty() bool {
return err.desc == nil
}
func (err *error_) pos() token.Pos {
if err.empty() {
return token.NoPos
}
return err.desc[0].posn.Pos()
}
func (err *error_) msg(fset *token.FileSet, qf Qualifier) string {
if err.empty() {
return "no error"
}
var buf bytes.Buffer
for i := range err.desc {
p := &err.desc[i]
if i > 0 {
fmt.Fprint(&buf, "\n\t")
if p.posn.Pos().IsValid() {
fmt.Fprintf(&buf, "%s: ", fset.Position(p.posn.Pos()))
}
}
buf.WriteString(sprintf(fset, qf, false, p.format, p.args...))
}
return buf.String()
}
// String is for testing.
func (err *error_) String() string {
if err.empty() {
return "no error"
}
return fmt.Sprintf("%d: %s", err.pos(), err.msg(nil, nil))
}
// errorf adds formatted error information to err.
// It may be called multiple times to provide additional information.
func (err *error_) errorf(at token.Pos, format string, args ...interface{}) {
err.desc = append(err.desc, errorDesc{atPos(at), format, args})
}
func (check *Checker) qualifier(pkg *Package) string {
// Qualify the package unless it's the package being type-checked.
if pkg != check.pkg {
@ -140,36 +197,46 @@ func (check *Checker) dump(format string, args ...any) {
fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...))
}
func (check *Checker) err(err error) {
if err == nil {
return
// Report records the error pointed to by errp, setting check.firstError if
// necessary.
func (check *Checker) report(errp *error_) {
if errp.empty() {
panic("empty error details")
}
var e Error
isInternal := errors.As(err, &e)
span := spanOf(errp.desc[0].posn)
e := Error{
Fset: check.fset,
Pos: span.pos,
Msg: errp.msg(check.fset, check.qualifier),
Soft: errp.soft,
go116code: errp.code,
go116start: span.start,
go116end: span.end,
}
// Cheap trick: Don't report errors with messages containing
// "invalid operand" or "invalid type" as those tend to be
// follow-on errors which don't add useful information. Only
// exclude them if these strings are not at the beginning,
// and only if we have at least one error already reported.
isInvalidErr := isInternal && (strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0)
isInvalidErr := strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0
if check.firstErr != nil && isInvalidErr {
return
}
if isInternal {
e.Msg = stripAnnotations(e.Msg)
if check.errpos != nil {
// If we have an internal error and the errpos override is set, use it to
// augment our error positioning.
// TODO(rFindley) we may also want to augment the error message and refer
// to the position (pos) in the original expression.
span := spanOf(check.errpos)
e.Pos = span.pos
e.go116start = span.start
e.go116end = span.end
}
err = e
e.Msg = stripAnnotations(e.Msg)
if check.errpos != nil {
// If we have an internal error and the errpos override is set, use it to
// augment our error positioning.
// TODO(rFindley) we may also want to augment the error message and refer
// to the position (pos) in the original expression.
span := spanOf(check.errpos)
e.Pos = span.pos
e.go116start = span.start
e.go116end = span.end
}
err := e
if check.firstErr == nil {
check.firstErr = err
@ -178,10 +245,6 @@ func (check *Checker) err(err error) {
if trace {
pos := e.Pos
msg := e.Msg
if !isInternal {
msg = err.Error()
pos = token.NoPos
}
check.trace(pos, "ERROR: %s", msg)
}
@ -192,35 +255,26 @@ func (check *Checker) err(err error) {
f(err)
}
func (check *Checker) newError(at positioner, code errorCode, soft bool, msg string) error {
span := spanOf(at)
return Error{
Fset: check.fset,
Pos: span.pos,
Msg: msg,
Soft: soft,
go116code: code,
go116start: span.start,
go116end: span.end,
// newErrorf creates a new error_ for later reporting with check.report.
func newErrorf(at positioner, code errorCode, format string, args ...any) *error_ {
return &error_{
desc: []errorDesc{{at, format, args}},
code: code,
}
}
// newErrorf creates a new Error, but does not handle it.
func (check *Checker) newErrorf(at positioner, code errorCode, soft bool, format string, args ...any) error {
msg := check.sprintf(format, args...)
return check.newError(at, code, soft, msg)
}
func (check *Checker) error(at positioner, code errorCode, msg string) {
check.err(check.newError(at, code, false, msg))
check.report(newErrorf(at, code, msg))
}
func (check *Checker) errorf(at positioner, code errorCode, format string, args ...any) {
check.error(at, code, check.sprintf(format, args...))
check.report(newErrorf(at, code, format, args...))
}
func (check *Checker) softErrorf(at positioner, code errorCode, format string, args ...any) {
check.err(check.newErrorf(at, code, true, format, args...))
err := newErrorf(at, code, format, args...)
err.soft = true
check.report(err)
}
func (check *Checker) invalidAST(at positioner, format string, args ...any) {

View File

@ -4,7 +4,30 @@
package types
import "testing"
import (
"go/token"
"testing"
)
func TestError(t *testing.T) {
var err error_
want := "no error"
if got := err.String(); got != want {
t.Errorf("empty error: got %q, want %q", got, want)
}
want = "0: foo 42"
err.errorf(token.NoPos, "foo %d", 42)
if got := err.String(); got != want {
t.Errorf("simple error: got %q, want %q", got, want)
}
want = "0: foo 42\n\tbar 43"
err.errorf(token.NoPos, "bar %d", 43)
if got := err.String(); got != want {
t.Errorf("simple error: got %q, want %q", got, want)
}
}
func TestStripAnnotations(t *testing.T) {
for _, test := range []struct {

View File

@ -87,7 +87,7 @@ func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
// overflow checks that the constant x is representable by its type.
// For untyped constants, it checks that the value doesn't become
// arbitrarily large.
func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
func (check *Checker) overflow(x *operand, opPos token.Pos) {
assert(x.mode == constant_)
if x.val.Kind() == constant.Unknown {
@ -115,8 +115,8 @@ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
}
}
// opName returns the name of an operation, or the empty string.
// Only operations that might overflow are handled.
// opName returns the name of the operation if x is an operation
// that might overflow; otherwise it returns the empty string.
func opName(e ast.Expr) string {
switch e := e.(type) {
case *ast.BinaryExpr:
@ -213,7 +213,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
}
x.val = constant.UnaryOp(e.Op, x.val, prec)
x.expr = e
check.overflow(x, e.Op, x.Pos())
check.overflow(x, x.Pos())
return
}
@ -991,7 +991,7 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
if b, _ := e.(*ast.BinaryExpr); b != nil {
opPos = b.OpPos
}
check.overflow(x, op, opPos)
check.overflow(x, opPos)
return
}
@ -1171,7 +1171,7 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token
}
x.val = constant.BinaryOp(x.val, op, y.val)
x.expr = e
check.overflow(x, op, opPos)
check.overflow(x, opPos)
return
}

View File

@ -166,10 +166,11 @@ func (s *StdSizes) Sizeof(T Type) int64 {
// common architecture word sizes and alignments
var gcArchSizes = map[string]*StdSizes{
"386": {4, 4},
"arm": {4, 4},
"arm64": {8, 8},
"amd64": {8, 8},
"amd64p32": {4, 8},
"arm": {4, 4},
"arm64": {8, 8},
"loong64": {8, 8},
"mips": {4, 4},
"mipsle": {4, 4},
"mips64": {8, 8},
@ -188,7 +189,7 @@ var gcArchSizes = map[string]*StdSizes{
// The result is nil if a compiler/architecture pair is not known.
//
// Supported architectures for compiler "gc":
// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
// "386", "amd64", "amd64p32", "arm", "arm64", "loong64", "mips", "mipsle",
// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "sparc64", "wasm".
func SizesFor(compiler, arch string) Sizes {
var m map[string]*StdSizes

View File

@ -349,6 +349,25 @@ const _ = unsafe.Sizeof(func() {
assert(iota == 0)
})
// issue #52438
const i1 = iota
const i2 = iota
const i3 = iota
func _() {
assert(i1 == 0)
assert(i2 == 0)
assert(i3 == 0)
const i4 = iota
const i5 = iota
const i6 = iota
assert(i4 == 0)
assert(i5 == 0)
assert(i6 == 0)
}
// untyped constants must not get arbitrarily large
const prec = 512 // internal maximum precision for integers
const maxInt = (1<<(prec/2) - 1) * (1<<(prec/2) + 1) // == 1<<prec - 1

View File

@ -0,0 +1,11 @@
// Copyright 2022 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 _() {
const x = 0
x /* ERROR cannot assign to x */ += 1
x /* ERROR cannot assign to x */ ++
}

View File

@ -252,21 +252,20 @@ func (h *Hash) Sum64() uint64 {
// MakeSeed returns a new random seed.
func MakeSeed() Seed {
var s1, s2 uint64
var s uint64
for {
s1 = uint64(runtime_fastrand())
s2 = uint64(runtime_fastrand())
s = runtime_fastrand64()
// We use seed 0 to indicate an uninitialized seed/hash,
// so keep trying until we get a non-zero seed.
if s1|s2 != 0 {
if s != 0 {
break
}
}
return Seed{s: s1<<32 + s2}
return Seed{s: s}
}
//go:linkname runtime_fastrand runtime.fastrand
func runtime_fastrand() uint32
//go:linkname runtime_fastrand64 runtime.fastrand64
func runtime_fastrand64() uint64
func rthash(ptr *byte, len int, seed uint64) uint64 {
if len == 0 {

View File

@ -21,11 +21,12 @@ TEXT ·Compare<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-56
CMP R5,R6,CR7
CMP R3,R4,CR6
BEQ CR7,equal
#ifdef GOARCH_ppc64le
BR cmpbodyLE<>(SB)
#else
BR cmpbodyBE<>(SB)
#endif
MOVBZ internalcpu·PPC64+const_offsetPPC64HasPOWER9(SB), R16
CMP R16,$1
BNE power8
BR cmpbodyp9<>(SB)
power8:
BR cmpbody<>(SB)
equal:
BEQ CR6,done
MOVD $1, R8
@ -52,11 +53,12 @@ TEXT runtime·cmpstring<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
CMP R5,R6,CR7
CMP R3,R4,CR6
BEQ CR7,equal
#ifdef GOARCH_ppc64le
BR cmpbodyLE<>(SB)
#else
BR cmpbodyBE<>(SB)
#endif
MOVBZ internalcpu·PPC64+const_offsetPPC64HasPOWER9(SB), R16
CMP R16,$1
BNE power8
BR cmpbodyp9<>(SB)
power8:
BR cmpbody<>(SB)
equal:
BEQ CR6,done
MOVD $1, R8
@ -70,209 +72,431 @@ done:
MOVD $0, R3
RET
// Do an efficient memcmp for ppc64le
#ifdef GOARCH_ppc64le
DATA byteswap<>+0(SB)/8, $0x0706050403020100
DATA byteswap<>+8(SB)/8, $0x0f0e0d0c0b0a0908
GLOBL byteswap<>+0(SB), RODATA, $16
#define SWAP V21
#endif
// Do an efficient memcmp for ppc64le/ppc64/POWER8
// R3 = a len
// R4 = b len
// R5 = a addr
// R6 = b addr
// On exit:
// R3 = return value
TEXT cmpbodyLE<>(SB),NOSPLIT|NOFRAME,$0-0
TEXT cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0
MOVD R3,R8 // set up length
CMP R3,R4,CR2 // unequal?
BC 12,8,setuplen // BLT CR2
BLT CR2,setuplen // BLT CR2
MOVD R4,R8 // use R4 for comparison len
setuplen:
MOVD R8,CTR // set up loop counter
CMP R8,$8 // only optimize >=8
BLT simplecheck
DCBT (R5) // cache hint
DCBT (R6)
CMP R8,$32 // optimize >= 32
MOVD R8,R9
BLT setup8a // 8 byte moves only
setup32a:
SRADCC $5,R8,R9 // number of 32 byte chunks
MOVD R9,CTR
BLT setup8a // optimize < 32
MOVD $16,R10 // set offsets to load into vectors
CMP R8,$64
BLT cmp32 // process size 32-63
// Special processing for 32 bytes or longer.
// Loading this way is faster and correct as long as the
// doublewords being compared are equal. Once they
// are found unequal, reload them in proper byte order
// to determine greater or less than.
loop32a:
MOVD 0(R5),R9 // doublewords to compare
MOVD 0(R6),R10 // get 4 doublewords
MOVD 8(R5),R14
MOVD 8(R6),R15
CMPU R9,R10 // bytes equal?
MOVD $0,R16 // set up for cmpne
BNE cmpne // further compare for LT or GT
MOVD 16(R5),R9 // get next pair of doublewords
MOVD 16(R6),R10
CMPU R14,R15 // bytes match?
MOVD $8,R16 // set up for cmpne
BNE cmpne // further compare for LT or GT
MOVD 24(R5),R14 // get next pair of doublewords
MOVD 24(R6),R15
CMPU R9,R10 // bytes match?
MOVD $16,R16 // set up for cmpne
BNE cmpne // further compare for LT or GT
MOVD $-8,R16 // for cmpne, R5,R6 already inc by 32
ADD $32,R5 // bump up to next 32
ADD $32,R6
CMPU R14,R15 // bytes match?
BC 8,2,loop32a // br ctr and cr
BNE cmpne
DCBT (R5) // optimize >= 64
DCBT (R6) // cache hint
MOVD $32,R11 // set offsets to load into vector
MOVD $48,R12 // set offsets to load into vector
loop64a:// process size 64 and greater
LXVD2X (R5)(R0),V3 // load bytes of A at offset 0 into vector
LXVD2X (R6)(R0),V4 // load bytes of B at offset 0 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different // jump out if its different
LXVD2X (R5)(R10),V3 // load bytes of A at offset 16 into vector
LXVD2X (R6)(R10),V4 // load bytes of B at offset 16 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
LXVD2X (R5)(R11),V3 // load bytes of A at offset 32 into vector
LXVD2X (R6)(R11),V4 // load bytes of B at offset 32 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
LXVD2X (R5)(R12),V3 // load bytes of A at offset 64 into vector
LXVD2X (R6)(R12),V4 // load bytes of B at offset 64 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
ADD $-64,R9,R9 // reduce remaining size by 64
ADD $64,R5,R5 // increment to next 64 bytes of A
ADD $64,R6,R6 // increment to next 64 bytes of B
CMPU R9,$64
BGE loop64a // loop back to loop64a only if there are >= 64 bytes remaining
CMPU R9,$32
BGE cmp32 // loop to cmp32 if there are 32-64 bytes remaining
CMPU R9,$0
BNE rem // loop to rem if the remainder is not 0
BEQ CR2,equal // remainder is zero, jump to equal if len(A)==len(B)
BLT CR2,less // jump to less if len(A)<len(B)
BR greater // jump to greater otherwise
cmp32:
LXVD2X (R5)(R0),V3 // load bytes of A at offset 0 into vector
LXVD2X (R6)(R0),V4 // load bytes of B at offset 0 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
LXVD2X (R5)(R10),V3 // load bytes of A at offset 16 into vector
LXVD2X (R6)(R10),V4 // load bytes of B at offset 16 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
ADD $-32,R9,R9 // reduce remaining size by 32
ADD $32,R5,R5 // increment to next 32 bytes of A
ADD $32,R6,R6 // increment to next 32 bytes of B
CMPU R9,$0
BNE rem // loop to rem if the remainder is not 0
BEQ CR2,equal // remainder is zero, jump to equal if len(A)==len(B)
BLT CR2,less // jump to less if len(A)<len(B)
BR greater // jump to greater otherwise
rem:
MOVD R9,R8
ANDCC $24,R8,R9 // Any 8 byte chunks?
BEQ leftover // and result is 0
BR setup8a
different:
#ifdef GOARCH_ppc64le
MOVD $byteswap<>+00(SB), R16
LXVD2X (R16)(R0),SWAP // Set up swap string
VPERM V3,V3,SWAP,V3
VPERM V4,V4,SWAP,V4
#endif
MFVSRD VS35,R16 // move upper doublwords of A and B into GPR for comparison
MFVSRD VS36,R10
CMPU R16,R10
BEQ lower
BGT greater
MOVD $-1,R3 // return value if A < B
RET
lower:
VSLDOI $8,V3,V3,V3 // move lower doublwords of A and B into GPR for comparison
MFVSRD VS35,R16
VSLDOI $8,V4,V4,V4
MFVSRD VS36,R10
CMPU R16,R10
BGT greater
MOVD $-1,R3 // return value if A < B
RET
setup8a:
SRADCC $3,R9,R9 // get the 8 byte count
SRADCC $3,R8,R9 // get the 8 byte count
BEQ leftover // shifted value is 0
CMPU R8,$8 // optimize 8byte move
BEQ size8
CMPU R8,$16
BEQ size16
MOVD R9,CTR // loop count for doublewords
loop8:
MOVDBR (R5+R0),R9 // doublewords to compare
#ifdef GOARCH_ppc64le
MOVDBR (R5+R0),R16 // doublewords to compare
MOVDBR (R6+R0),R10 // LE compare order
#else
MOVD (R5+R0),R16 // doublewords to compare
MOVD (R6+R0),R10 // BE compare order
#endif
ADD $8,R5
ADD $8,R6
CMPU R9,R10 // match?
CMPU R16,R10 // match?
BC 8,2,loop8 // bt ctr <> 0 && cr
BGT greater
BLT less
leftover:
ANDCC $7,R8,R9 // check for leftover bytes
MOVD R9,CTR // save the ctr
BNE simple // leftover bytes
BC 12,10,equal // test CR2 for length comparison
BC 12,8,less
BR greater
BEQ zeroremainder
simplecheck:
CMP R8,$0 // remaining compare length 0
BNE simple // do simple compare
BC 12,10,equal // test CR2 for length comparison
BC 12,8,less // 1st len < 2nd len, result less
BR greater // 1st len > 2nd len must be greater
simple:
MOVBZ 0(R5), R9 // get byte from 1st operand
ADD $1,R5
MOVBZ 0(R6), R10 // get byte from 2nd operand
ADD $1,R6
CMPU R9, R10
BC 8,2,simple // bc ctr <> 0 && cr
BGT greater // 1st > 2nd
BLT less // 1st < 2nd
BC 12,10,equal // test CR2 for length comparison
BC 12,9,greater // 2nd len > 1st len
BR less // must be less
cmpne: // only here is not equal
MOVDBR (R5+R16),R8 // reload in reverse order
MOVDBR (R6+R16),R9
CMPU R8,R9 // compare correct endianness
BGT greater // here only if NE
less:
MOVD $-1, R3 // return value if A < B
MOVD R0,R14
CMP R9,$4 // process 4 bytes
BLT halfword
#ifdef GOARCH_ppc64le
MOVWBR (R5)(R14),R10
MOVWBR (R6)(R14),R11
#else
MOVWZ (R5)(R14),R10
MOVWZ (R6)(R14),R11
#endif
CMPU R10,R11
BGT greater
BLT less
ADD $-4,R9
ADD $4,R14
PCALIGN $16
halfword:
CMP R9,$2 // process 2 bytes
BLT byte
#ifdef GOARCH_ppc64le
MOVHBR (R5)(R14),R10
MOVHBR (R6)(R14),R11
#else
MOVHZ (R5)(R14),R10
MOVHZ (R6)(R14),R11
#endif
CMPU R10,R11
BGT greater
BLT less
ADD $-2,R9
ADD $2,R14
PCALIGN $16
byte:
CMP R9,$0 // process 1 byte
BEQ skip
MOVBZ (R5)(R14),R10
MOVBZ (R6)(R14),R11
CMPU R10,R11
BGT greater
BLT less
PCALIGN $16
skip:
BEQ CR2,equal
BGT CR2,greater
less: MOVD $-1,R3 // return value if A < B
RET
size16:
LXVD2X (R5)(R0),V3 // load bytes of A at offset 0 into vector
LXVD2X (R6)(R0),V4 // load bytes of B at offset 0 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
zeroremainder:
BEQ CR2,equal // remainder is zero, jump to equal if len(A)==len(B)
BLT CR2,less // jump to less if len(A)<len(B)
BR greater // jump to greater otherwise
size8:
#ifdef GOARCH_ppc64le
MOVDBR (R5+R0),R16 // doublewords to compare
MOVDBR (R6+R0),R10 // LE compare order
#else
MOVD (R5+R0),R16 // doublewords to compare
MOVD (R6+R0),R10 // BE compare order
#endif
CMPU R16,R10 // match?
BGT greater
BLT less
BGT CR2,greater // 2nd len > 1st len
BLT CR2,less // 2nd len < 1st len
equal:
MOVD $0, R3 // return value if A == B
RET
greater:
MOVD $1, R3 // return value if A > B
MOVD $1,R3 // return value if A > B
RET
// Do an efficient memcmp for ppc64 (BE)
// Do an efficient memcmp for ppc64le/ppc64/POWER9
// R3 = a len
// R4 = b len
// R5 = a addr
// R6 = b addr
// On exit:
// R3 = return value
TEXT cmpbodyBE<>(SB),NOSPLIT|NOFRAME,$0-0
TEXT cmpbodyp9<>(SB),NOSPLIT|NOFRAME,$0-0
MOVD R3,R8 // set up length
CMP R3,R4,CR2 // unequal?
BC 12,8,setuplen // BLT CR2
BLT CR2,setuplen // BLT CR2
MOVD R4,R8 // use R4 for comparison len
setuplen:
MOVD R8,CTR // set up loop counter
CMP R8,$8 // only optimize >=8
BLT simplecheck
DCBT (R5) // cache hint
DCBT (R6)
CMP R8,$32 // optimize >= 32
CMP R8,$16 // optimize for size<16
MOVD R8,R9
BLT setup8a // 8 byte moves only
BLT simplecheck
MOVD $16,R10 // set offsets to load into vectors
CMP R8,$32 // optimize for size 16-31
BLT cmp16
CMP R8,$64
BLT cmp32 // optimize for size 32-63
DCBT (R5) // optimize for size>=64
DCBT (R6) // cache hint
setup32a:
SRADCC $5,R8,R9 // number of 32 byte chunks
MOVD R9,CTR
loop32a:
MOVD 0(R5),R9 // doublewords to compare
MOVD 0(R6),R10 // get 4 doublewords
MOVD 8(R5),R14
MOVD 8(R6),R15
CMPU R9,R10 // bytes equal?
BLT less // found to be less
BGT greater // found to be greater
MOVD 16(R5),R9 // get next pair of doublewords
MOVD 16(R6),R10
CMPU R14,R15 // bytes match?
BLT less // found less
BGT greater // found greater
MOVD 24(R5),R14 // get next pair of doublewords
MOVD 24(R6),R15
CMPU R9,R10 // bytes match?
BLT less // found to be less
BGT greater // found to be greater
ADD $32,R5 // bump up to next 32
ADD $32,R6
CMPU R14,R15 // bytes match?
BC 8,2,loop32a // br ctr and cr
BLT less // with BE, byte ordering is
BGT greater // good for compare
ANDCC $24,R8,R9 // Any 8 byte chunks?
BEQ leftover // and result is 0
setup8a:
SRADCC $3,R9,R9 // get the 8 byte count
BEQ leftover // shifted value is 0
MOVD R9,CTR // loop count for doublewords
loop8:
MOVD (R5),R9
MOVD (R6),R10
ADD $8,R5
ADD $8,R6
CMPU R9,R10 // match?
BC 8,2,loop8 // bt ctr <> 0 && cr
MOVD $32,R11 // set offsets to load into vector
MOVD $48,R12 // set offsets to load into vector
loop64a:// process size 64 and greater
LXVB16X (R0)(R5),V3 // load bytes of A at offset 0 into vector
LXVB16X (R0)(R6),V4 // load bytes of B at offset 0 into vector
VCMPNEBCC V3,V4,V1 // record comparison into V1
BNE CR6,different // jump out if its different
LXVB16X (R10)(R5),V3 // load bytes of A at offset 16 into vector
LXVB16X (R10)(R6),V4 // load bytes of B at offset 16 into vector
VCMPNEBCC V3,V4,V1
BNE CR6,different
LXVB16X (R11)(R5),V3 // load bytes of A at offset 32 into vector
LXVB16X (R11)(R6),V4 // load bytes of B at offset 32 into vector
VCMPNEBCC V3,V4,V1
BNE CR6,different
LXVB16X (R12)(R5),V3 // load bytes of A at offset 48 into vector
LXVB16X (R12)(R6),V4 // load bytes of B at offset 48 into vector
VCMPNEBCC V3,V4,V1
BNE CR6,different
ADD $-64,R9,R9 // reduce remaining size by 64
ADD $64,R5,R5 // increment to next 64 bytes of A
ADD $64,R6,R6 // increment to next 64 bytes of B
CMPU R9,$64
BGE loop64a // loop back to loop64a only if there are >= 64 bytes remaining
CMPU R9,$32
BGE cmp32 // loop to cmp32 if there are 32-64 bytes remaining
CMPU R9,$16
BGE cmp16 // loop to cmp16 if there are 16-31 bytes left
CMPU R9,$0
BNE simplecheck // loop to simplecheck for remaining bytes
BEQ CR2,equal // remainder is zero, jump to equal if len(A)==len(B)
BLT CR2,less // jump to less if len(A)<len(B)
BR greater // jump to greater otherwise
cmp32:
LXVB16X (R0)(R5),V3 // load bytes of A at offset 0 into vector
LXVB16X (R0)(R6),V4 // load bytes of B at offset 0 into vector
VCMPNEBCC V3,V4,V1 // record comparison into V1
BNE CR6,different // jump out if its different
LXVB16X (R10)(R5),V3 // load bytes of A at offset 16 into vector
LXVB16X (R10)(R6),V4 // load bytes of B at offset 16 into vector
VCMPNEBCC V3,V4,V1
BNE CR6,different
ADD $-32,R9,R9 // reduce remaining size by 32
ADD $32,R5,R5 // increment to next 32 bytes of A
ADD $32,R6,R6 // increment to next 32 bytes of B
CMPU R9,$16 // loop to cmp16 if there are 16-31 bytes left
BGE cmp16
CMPU R9,$0
BNE simplecheck // loop to simplecheck for remainder bytes
BEQ CR2,equal // remainder is zero, jump to equal if len(A)==len(B)
BLT CR2,less // jump to less if len(A)<len(B)
BR greater // jump to greater otherwise
different:
MFVSRD VS35,R16 // move upper doublwords of A and B into GPR for comparison
MFVSRD VS36,R10
CMPU R16,R10
BEQ lower
BGT greater
MOVD $-1,R3 // return value if A < B
RET
lower:
MFVSRLD VS35,R16 // next move lower doublewords of A and B into GPR for comparison
MFVSRLD VS36,R10
CMPU R16,R10
BGT greater
MOVD $-1,R3 // return value if A < B
RET
greater:
MOVD $1,R3 // return value if A > B
RET
cmp16:
ANDCC $16,R9,R31
BEQ tail
LXVB16X (R0)(R5),V3 // load bytes of A at offset 16 into vector
LXVB16X (R0)(R6),V4 // load bytes of B at offset 16 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
ADD $16,R5
ADD $16,R6
tail:
ANDCC $15,R9 // Load the last 16 bytes (we know there are at least 32b)
BEQ end
ADD R9,R5
ADD R9,R6
MOVD $-16,R10
LXVB16X (R10)(R5),V3 // load bytes of A at offset 16 into vector
LXVB16X (R10)(R6),V4 // load bytes of B at offset 16 into vector
VCMPEQUDCC V3,V4,V1
BGE CR6,different
end:
BEQ CR2,equal // remainder is zero, jump to equal if len(A)==len(B)
BLT CR2,less // jump to less if BLT CR2 that is, len(A)<len(B)
BR greater // jump to greater otherwise
simplecheck:
MOVD $0,R14 // process 8 bytes
CMP R9,$8
BLT word
#ifdef GOARCH_ppc64le
MOVDBR (R5+R14),R10
MOVDBR (R6+R14),R11
#else
MOVD (R5+R14),R10
MOVD (R6+R14),R11
#endif
CMPU R10,R11
BGT greater
BLT less
leftover:
ANDCC $7,R8,R9 // check for leftover bytes
MOVD R9,CTR // save the ctr
BNE simple // leftover bytes
BC 12,10,equal // test CR2 for length comparison
BC 12,8,less
BR greater
simplecheck:
CMP R8,$0 // remaining compare length 0
BNE simple // do simple compare
BC 12,10,equal // test CR2 for length comparison
BC 12,8,less // 1st len < 2nd len, result less
BR greater // same len, must be equal
simple:
MOVBZ 0(R5),R9 // get byte from 1st operand
ADD $1,R5
MOVBZ 0(R6),R10 // get byte from 2nd operand
ADD $1,R6
CMPU R9,R10
BC 8,2,simple // bc ctr <> 0 && cr
BGT greater // 1st > 2nd
BLT less // 1st < 2nd
BC 12,10,equal // test CR2 for length comparison
BC 12,9,greater // 2nd len > 1st len
ADD $8,R14
ADD $-8,R9
PCALIGN $16
word:
CMP R9,$4 // process 4 bytes
BLT halfword
#ifdef GOARCH_ppc64le
MOVWBR (R5+R14),R10
MOVWBR (R6+R14),R11
#else
MOVWZ (R5+R14),R10
MOVWZ (R6+R14),R11
#endif
CMPU R10,R11
BGT greater
BLT less
ADD $4,R14
ADD $-4,R9
PCALIGN $16
halfword:
CMP R9,$2 // process 2 bytes
BLT byte
#ifdef GOARCH_ppc64le
MOVHBR (R5+R14),R10
MOVHBR (R6+R14),R11
#else
MOVHZ (R5+R14),R10
MOVHZ (R6+R14),R11
#endif
CMPU R10,R11
BGT greater
BLT less
ADD $2,R14
ADD $-2,R9
PCALIGN $16
byte:
CMP R9,$0 // process 1 byte
BEQ skip
MOVBZ (R5+R14),R10
MOVBZ (R6+R14),R11
CMPU R10,R11
BGT greater
BLT less
PCALIGN $16
skip:
BEQ CR2,equal
BGT CR2,greater
less:
MOVD $-1, R3 // return value if A < B
MOVD $-1,R3 // return value if A < B
RET
equal:
MOVD $0, R3 // return value if A == B
RET
greater:
MOVD $1, R3 // return value if A > B
RET

Some files were not shown because too many files have changed in this diff Show More