| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,330 @@ | ||
| // 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. | ||
|
|
||
| //go:build ignore | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "go/format" | ||
| "io" | ||
| "log" | ||
| "os" | ||
| "os/exec" | ||
| "text/template" | ||
| ) | ||
|
|
||
| var curves = []struct { | ||
| Element string | ||
| Prime string | ||
| Prefix string | ||
| FiatType string | ||
| BytesLen int | ||
| }{ | ||
| { | ||
| Element: "P224Element", | ||
| Prime: "2^224 - 2^96 + 1", | ||
| Prefix: "p224", | ||
| FiatType: "[4]uint64", | ||
| BytesLen: 28, | ||
| }, | ||
| // The 32-bit pure Go P-256 in crypto/elliptic is still faster than the | ||
| // autogenerated code here, regrettably. | ||
| // { | ||
| // Element: "P256Element", | ||
| // Prime: "2^256 - 2^224 + 2^192 + 2^96 - 1", | ||
| // Prefix: "p256", | ||
| // FiatType: "[4]uint64", | ||
| // BytesLen: 32, | ||
| // }, | ||
| { | ||
| Element: "P384Element", | ||
| Prime: "2^384 - 2^128 - 2^96 + 2^32 - 1", | ||
| Prefix: "p384", | ||
| FiatType: "[6]uint64", | ||
| BytesLen: 48, | ||
| }, | ||
| // Note that unsaturated_solinas would be about 2x faster than | ||
| // word_by_word_montgomery for P-521, but this curve is used rarely enough | ||
| // that it's not worth carrying unsaturated_solinas support for it. | ||
| { | ||
| Element: "P521Element", | ||
| Prime: "2^521 - 1", | ||
| Prefix: "p521", | ||
| FiatType: "[9]uint64", | ||
| BytesLen: 66, | ||
| }, | ||
| } | ||
|
|
||
| func main() { | ||
| t := template.Must(template.New("montgomery").Parse(tmplWrapper)) | ||
|
|
||
| tmplAddchainFile, err := os.CreateTemp("", "addchain-template") | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| defer os.Remove(tmplAddchainFile.Name()) | ||
| if _, err := io.WriteString(tmplAddchainFile, tmplAddchain); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| if err := tmplAddchainFile.Close(); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| for _, c := range curves { | ||
| log.Printf("Generating %s.go...", c.Prefix) | ||
| f, err := os.Create(c.Prefix + ".go") | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| if err := t.Execute(f, c); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| if err := f.Close(); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| log.Printf("Generating %s_fiat64.go...", c.Prefix) | ||
| cmd := exec.Command("docker", "run", "--rm", "--entrypoint", "word_by_word_montgomery", | ||
| "fiat-crypto:v0.0.9", "--lang", "Go", "--no-wide-int", "--cmovznz-by-mul", | ||
| "--relax-primitive-carry-to-bitwidth", "32,64", "--internal-static", | ||
| "--public-function-case", "camelCase", "--public-type-case", "camelCase", | ||
| "--private-function-case", "camelCase", "--private-type-case", "camelCase", | ||
| "--doc-text-before-function-name", "", "--doc-newline-before-package-declaration", | ||
| "--doc-prepend-header", "Code generated by Fiat Cryptography. DO NOT EDIT.", | ||
| "--package-name", "fiat", "--no-prefix-fiat", c.Prefix, "64", c.Prime, | ||
| "mul", "square", "add", "sub", "one", "from_montgomery", "to_montgomery", | ||
| "selectznz", "to_bytes", "from_bytes") | ||
| cmd.Stderr = os.Stderr | ||
| out, err := cmd.Output() | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| out, err = format.Source(out) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| if err := os.WriteFile(c.Prefix+"_fiat64.go", out, 0644); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| log.Printf("Generating %s_invert.go...", c.Prefix) | ||
| f, err = os.CreateTemp("", "addchain-"+c.Prefix) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| defer os.Remove(f.Name()) | ||
| cmd = exec.Command("addchain", "search", c.Prime+" - 2") | ||
| cmd.Stderr = os.Stderr | ||
| cmd.Stdout = f | ||
| if err := cmd.Run(); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| if err := f.Close(); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| cmd = exec.Command("addchain", "gen", "-tmpl", tmplAddchainFile.Name(), f.Name()) | ||
| cmd.Stderr = os.Stderr | ||
| out, err = cmd.Output() | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| out = bytes.Replace(out, []byte("Element"), []byte(c.Element), -1) | ||
| out, err = format.Source(out) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| if err := os.WriteFile(c.Prefix+"_invert.go", out, 0644); err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const tmplWrapper = `// 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. | ||
| // Code generated by generate.go. DO NOT EDIT. | ||
| package fiat | ||
| import ( | ||
| "crypto/subtle" | ||
| "errors" | ||
| ) | ||
| // {{ .Element }} is an integer modulo {{ .Prime }}. | ||
| // | ||
| // The zero value is a valid zero element. | ||
| type {{ .Element }} struct { | ||
| // Values are represented internally always in the Montgomery domain, and | ||
| // converted in Bytes and SetBytes. | ||
| x {{ .Prefix }}MontgomeryDomainFieldElement | ||
| } | ||
| const {{ .Prefix }}ElementLen = {{ .BytesLen }} | ||
| type {{ .Prefix }}UntypedFieldElement = {{ .FiatType }} | ||
| // One sets e = 1, and returns e. | ||
| func (e *{{ .Element }}) One() *{{ .Element }} { | ||
| {{ .Prefix }}SetOne(&e.x) | ||
| return e | ||
| } | ||
| // Equal returns 1 if e == t, and zero otherwise. | ||
| func (e *{{ .Element }}) Equal(t *{{ .Element }}) int { | ||
| eBytes := e.Bytes() | ||
| tBytes := t.Bytes() | ||
| return subtle.ConstantTimeCompare(eBytes, tBytes) | ||
| } | ||
| var {{ .Prefix }}ZeroEncoding = new({{ .Element }}).Bytes() | ||
| // IsZero returns 1 if e == 0, and zero otherwise. | ||
| func (e *{{ .Element }}) IsZero() int { | ||
| eBytes := e.Bytes() | ||
| return subtle.ConstantTimeCompare(eBytes, {{ .Prefix }}ZeroEncoding) | ||
| } | ||
| // Set sets e = t, and returns e. | ||
| func (e *{{ .Element }}) Set(t *{{ .Element }}) *{{ .Element }} { | ||
| e.x = t.x | ||
| return e | ||
| } | ||
| // Bytes returns the {{ .BytesLen }}-byte big-endian encoding of e. | ||
| func (e *{{ .Element }}) Bytes() []byte { | ||
| // This function is outlined to make the allocations inline in the caller | ||
| // rather than happen on the heap. | ||
| var out [{{ .Prefix }}ElementLen]byte | ||
| return e.bytes(&out) | ||
| } | ||
| func (e *{{ .Element }}) bytes(out *[{{ .Prefix }}ElementLen]byte) []byte { | ||
| var tmp {{ .Prefix }}NonMontgomeryDomainFieldElement | ||
| {{ .Prefix }}FromMontgomery(&tmp, &e.x) | ||
| {{ .Prefix }}ToBytes(out, (*{{ .Prefix }}UntypedFieldElement)(&tmp)) | ||
| {{ .Prefix }}InvertEndianness(out[:]) | ||
| return out[:] | ||
| } | ||
| // {{ .Prefix }}MinusOneEncoding is the encoding of -1 mod p, so p - 1, the | ||
| // highest canonical encoding. It is used by SetBytes to check for non-canonical | ||
| // encodings such as p + k, 2p + k, etc. | ||
| var {{ .Prefix }}MinusOneEncoding = new({{ .Element }}).Sub( | ||
| new({{ .Element }}), new({{ .Element }}).One()).Bytes() | ||
| // SetBytes sets e = v, where v is a big-endian {{ .BytesLen }}-byte encoding, and returns e. | ||
| // If v is not {{ .BytesLen }} bytes or it encodes a value higher than {{ .Prime }}, | ||
| // SetBytes returns nil and an error, and e is unchanged. | ||
| func (e *{{ .Element }}) SetBytes(v []byte) (*{{ .Element }}, error) { | ||
| if len(v) != {{ .Prefix }}ElementLen { | ||
| return nil, errors.New("invalid {{ .Element }} encoding") | ||
| } | ||
| for i := range v { | ||
| if v[i] < {{ .Prefix }}MinusOneEncoding[i] { | ||
| break | ||
| } | ||
| if v[i] > {{ .Prefix }}MinusOneEncoding[i] { | ||
| return nil, errors.New("invalid {{ .Element }} encoding") | ||
| } | ||
| } | ||
| var in [{{ .Prefix }}ElementLen]byte | ||
| copy(in[:], v) | ||
| {{ .Prefix }}InvertEndianness(in[:]) | ||
| var tmp {{ .Prefix }}NonMontgomeryDomainFieldElement | ||
| {{ .Prefix }}FromBytes((*{{ .Prefix }}UntypedFieldElement)(&tmp), &in) | ||
| {{ .Prefix }}ToMontgomery(&e.x, &tmp) | ||
| return e, nil | ||
| } | ||
| // Add sets e = t1 + t2, and returns e. | ||
| func (e *{{ .Element }}) Add(t1, t2 *{{ .Element }}) *{{ .Element }} { | ||
| {{ .Prefix }}Add(&e.x, &t1.x, &t2.x) | ||
| return e | ||
| } | ||
| // Sub sets e = t1 - t2, and returns e. | ||
| func (e *{{ .Element }}) Sub(t1, t2 *{{ .Element }}) *{{ .Element }} { | ||
| {{ .Prefix }}Sub(&e.x, &t1.x, &t2.x) | ||
| return e | ||
| } | ||
| // Mul sets e = t1 * t2, and returns e. | ||
| func (e *{{ .Element }}) Mul(t1, t2 *{{ .Element }}) *{{ .Element }} { | ||
| {{ .Prefix }}Mul(&e.x, &t1.x, &t2.x) | ||
| return e | ||
| } | ||
| // Square sets e = t * t, and returns e. | ||
| func (e *{{ .Element }}) Square(t *{{ .Element }}) *{{ .Element }} { | ||
| {{ .Prefix }}Square(&e.x, &t.x) | ||
| return e | ||
| } | ||
| // Select sets v to a if cond == 1, and to b if cond == 0. | ||
| func (v *{{ .Element }}) Select(a, b *{{ .Element }}, cond int) *{{ .Element }} { | ||
| {{ .Prefix }}Selectznz((*{{ .Prefix }}UntypedFieldElement)(&v.x), {{ .Prefix }}Uint1(cond), | ||
| (*{{ .Prefix }}UntypedFieldElement)(&b.x), (*{{ .Prefix }}UntypedFieldElement)(&a.x)) | ||
| return v | ||
| } | ||
| func {{ .Prefix }}InvertEndianness(v []byte) { | ||
| for i := 0; i < len(v)/2; i++ { | ||
| v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i] | ||
| } | ||
| } | ||
| ` | ||
|
|
||
| const tmplAddchain = `// 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. | ||
| // Code generated by {{ .Meta.Name }}. DO NOT EDIT. | ||
| package fiat | ||
| // Invert sets e = 1/x, and returns e. | ||
| // | ||
| // If x == 0, Invert returns e = 0. | ||
| func (e *Element) Invert(x *Element) *Element { | ||
| // Inversion is implemented as exponentiation with exponent p − 2. | ||
| // The sequence of {{ .Ops.Adds }} multiplications and {{ .Ops.Doubles }} squarings is derived from the | ||
| // following addition chain generated with {{ .Meta.Module }} {{ .Meta.ReleaseTag }}. | ||
| // | ||
| {{- range lines (format .Script) }} | ||
| // {{ . }} | ||
| {{- end }} | ||
| // | ||
| var z = new(Element).Set(e) | ||
| {{- range .Program.Temporaries }} | ||
| var {{ . }} = new(Element) | ||
| {{- end }} | ||
| {{ range $i := .Program.Instructions -}} | ||
| {{- with add $i.Op }} | ||
| {{ $i.Output }}.Mul({{ .X }}, {{ .Y }}) | ||
| {{- end -}} | ||
| {{- with double $i.Op }} | ||
| {{ $i.Output }}.Square({{ .X }}) | ||
| {{- end -}} | ||
| {{- with shift $i.Op -}} | ||
| {{- $first := 0 -}} | ||
| {{- if ne $i.Output.Identifier .X.Identifier }} | ||
| {{ $i.Output }}.Square({{ .X }}) | ||
| {{- $first = 1 -}} | ||
| {{- end }} | ||
| for s := {{ $first }}; s < {{ .S }}; s++ { | ||
| {{ $i.Output }}.Square({{ $i.Output }}) | ||
| } | ||
| {{- end -}} | ||
| {{- end }} | ||
| return e.Set(z) | ||
| } | ||
| ` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| // 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 nistec_test | ||
|
|
||
| import ( | ||
| "crypto/elliptic/internal/nistec" | ||
| "math/rand" | ||
| "os" | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| func TestAllocations(t *testing.T) { | ||
| if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-noopt") { | ||
| t.Skip("skipping allocations test without relevant optimizations") | ||
| } | ||
| t.Run("P224", func(t *testing.T) { | ||
| if allocs := testing.AllocsPerRun(100, func() { | ||
| p := nistec.NewP224Generator() | ||
| scalar := make([]byte, 66) | ||
| rand.Read(scalar) | ||
| p.ScalarMult(p, scalar) | ||
| out := p.Bytes() | ||
| if _, err := p.SetBytes(out); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| }); allocs > 0 { | ||
| t.Errorf("expected zero allocations, got %0.1f", allocs) | ||
| } | ||
| }) | ||
| t.Run("P384", func(t *testing.T) { | ||
| if allocs := testing.AllocsPerRun(100, func() { | ||
| p := nistec.NewP384Generator() | ||
| scalar := make([]byte, 66) | ||
| rand.Read(scalar) | ||
| p.ScalarMult(p, scalar) | ||
| out := p.Bytes() | ||
| if _, err := p.SetBytes(out); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| }); allocs > 0 { | ||
| t.Errorf("expected zero allocations, got %0.1f", allocs) | ||
| } | ||
| }) | ||
| t.Run("P521", func(t *testing.T) { | ||
| if allocs := testing.AllocsPerRun(100, func() { | ||
| p := nistec.NewP521Generator() | ||
| scalar := make([]byte, 66) | ||
| rand.Read(scalar) | ||
| p.ScalarMult(p, scalar) | ||
| out := p.Bytes() | ||
| if _, err := p.SetBytes(out); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| }); allocs > 0 { | ||
| t.Errorf("expected zero allocations, got %0.1f", allocs) | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| func BenchmarkScalarMult(b *testing.B) { | ||
| b.Run("P224", func(b *testing.B) { | ||
| scalar := make([]byte, 66) | ||
| rand.Read(scalar) | ||
| p := nistec.NewP224Generator() | ||
| b.ReportAllocs() | ||
| b.ResetTimer() | ||
| for i := 0; i < b.N; i++ { | ||
| p.ScalarMult(p, scalar) | ||
| } | ||
| }) | ||
| b.Run("P384", func(b *testing.B) { | ||
| scalar := make([]byte, 66) | ||
| rand.Read(scalar) | ||
| p := nistec.NewP384Generator() | ||
| b.ReportAllocs() | ||
| b.ResetTimer() | ||
| for i := 0; i < b.N; i++ { | ||
| p.ScalarMult(p, scalar) | ||
| } | ||
| }) | ||
| b.Run("P521", func(b *testing.B) { | ||
| scalar := make([]byte, 66) | ||
| rand.Read(scalar) | ||
| p := nistec.NewP521Generator() | ||
| b.ReportAllocs() | ||
| b.ResetTimer() | ||
| for i := 0; i < b.N; i++ { | ||
| p.ScalarMult(p, scalar) | ||
| } | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,293 @@ | ||
| // 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 nistec | ||
|
|
||
| import ( | ||
| "crypto/elliptic/internal/fiat" | ||
| "crypto/subtle" | ||
| "errors" | ||
| ) | ||
|
|
||
| var p224B, _ = new(fiat.P224Element).SetBytes([]byte{0xb4, 0x05, 0x0a, 0x85, | ||
| 0x0c, 0x04, 0xb3, 0xab, 0xf5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7, | ||
| 0xd7, 0xbf, 0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43, 0x23, 0x55, 0xff, 0xb4}) | ||
|
|
||
| var p224G, _ = NewP224Point().SetBytes([]byte{0x04, | ||
| 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9, | ||
| 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, | ||
| 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, | ||
| 0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, | ||
| 0x44, 0xd5, 0x81, 0x99, 0x85, 0x0, 0x7e, 0x34}) | ||
|
|
||
| const p224ElementLength = 28 | ||
|
|
||
| // P224Point is a P-224 point. The zero value is NOT valid. | ||
| type P224Point struct { | ||
| // The point is represented in projective coordinates (X:Y:Z), | ||
| // where x = X/Z and y = Y/Z. | ||
| x, y, z *fiat.P224Element | ||
| } | ||
|
|
||
| // NewP224Point returns a new P224Point representing the point at infinity point. | ||
| func NewP224Point() *P224Point { | ||
| return &P224Point{ | ||
| x: new(fiat.P224Element), | ||
| y: new(fiat.P224Element).One(), | ||
| z: new(fiat.P224Element), | ||
| } | ||
| } | ||
|
|
||
| // NewP224Generator returns a new P224Point set to the canonical generator. | ||
| func NewP224Generator() *P224Point { | ||
| return (&P224Point{ | ||
| x: new(fiat.P224Element), | ||
| y: new(fiat.P224Element), | ||
| z: new(fiat.P224Element), | ||
| }).Set(p224G) | ||
| } | ||
|
|
||
| // Set sets p = q and returns p. | ||
| func (p *P224Point) Set(q *P224Point) *P224Point { | ||
| p.x.Set(q.x) | ||
| p.y.Set(q.y) | ||
| p.z.Set(q.z) | ||
| return p | ||
| } | ||
|
|
||
| // SetBytes sets p to the compressed, uncompressed, or infinity value encoded in | ||
| // b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on | ||
| // the curve, it returns nil and an error, and the receiver is unchanged. | ||
| // Otherwise, it returns p. | ||
| func (p *P224Point) SetBytes(b []byte) (*P224Point, error) { | ||
| switch { | ||
| // Point at infinity. | ||
| case len(b) == 1 && b[0] == 0: | ||
| return p.Set(NewP224Point()), nil | ||
|
|
||
| // Uncompressed form. | ||
| case len(b) == 1+2*p224ElementLength && b[0] == 4: | ||
| x, err := new(fiat.P224Element).SetBytes(b[1 : 1+p224ElementLength]) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| y, err := new(fiat.P224Element).SetBytes(b[1+p224ElementLength:]) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| if err := p224CheckOnCurve(x, y); err != nil { | ||
| return nil, err | ||
| } | ||
| p.x.Set(x) | ||
| p.y.Set(y) | ||
| p.z.One() | ||
| return p, nil | ||
|
|
||
| // Compressed form | ||
| case len(b) == 1+p224ElementLength && b[0] == 0: | ||
| return nil, errors.New("unimplemented") // TODO(filippo) | ||
|
|
||
| default: | ||
| return nil, errors.New("invalid P224 point encoding") | ||
| } | ||
| } | ||
|
|
||
| func p224CheckOnCurve(x, y *fiat.P224Element) error { | ||
| // x³ - 3x + b. | ||
| x3 := new(fiat.P224Element).Square(x) | ||
| x3.Mul(x3, x) | ||
|
|
||
| threeX := new(fiat.P224Element).Add(x, x) | ||
| threeX.Add(threeX, x) | ||
|
|
||
| x3.Sub(x3, threeX) | ||
| x3.Add(x3, p224B) | ||
|
|
||
| // y² = x³ - 3x + b | ||
| y2 := new(fiat.P224Element).Square(y) | ||
|
|
||
| if x3.Equal(y2) != 1 { | ||
| return errors.New("P224 point not on curve") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // Bytes returns the uncompressed or infinity encoding of p, as specified in | ||
| // SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at | ||
| // infinity is shorter than all other encodings. | ||
| func (p *P224Point) Bytes() []byte { | ||
| // This function is outlined to make the allocations inline in the caller | ||
| // rather than happen on the heap. | ||
| var out [133]byte | ||
| return p.bytes(&out) | ||
| } | ||
|
|
||
| func (p *P224Point) bytes(out *[133]byte) []byte { | ||
| if p.z.IsZero() == 1 { | ||
| return append(out[:0], 0) | ||
| } | ||
|
|
||
| zinv := new(fiat.P224Element).Invert(p.z) | ||
| xx := new(fiat.P224Element).Mul(p.x, zinv) | ||
| yy := new(fiat.P224Element).Mul(p.y, zinv) | ||
|
|
||
| buf := append(out[:0], 4) | ||
| buf = append(buf, xx.Bytes()...) | ||
| buf = append(buf, yy.Bytes()...) | ||
| return buf | ||
| } | ||
|
|
||
| // Add sets q = p1 + p2, and returns q. The points may overlap. | ||
| func (q *P224Point) Add(p1, p2 *P224Point) *P224Point { | ||
| // Complete addition formula for a = -3 from "Complete addition formulas for | ||
| // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2. | ||
|
|
||
| t0 := new(fiat.P224Element).Mul(p1.x, p2.x) // t0 := X1 * X2 | ||
| t1 := new(fiat.P224Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2 | ||
| t2 := new(fiat.P224Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2 | ||
| t3 := new(fiat.P224Element).Add(p1.x, p1.y) // t3 := X1 + Y1 | ||
| t4 := new(fiat.P224Element).Add(p2.x, p2.y) // t4 := X2 + Y2 | ||
| t3.Mul(t3, t4) // t3 := t3 * t4 | ||
| t4.Add(t0, t1) // t4 := t0 + t1 | ||
| t3.Sub(t3, t4) // t3 := t3 - t4 | ||
| t4.Add(p1.y, p1.z) // t4 := Y1 + Z1 | ||
| x3 := new(fiat.P224Element).Add(p2.y, p2.z) // X3 := Y2 + Z2 | ||
| t4.Mul(t4, x3) // t4 := t4 * X3 | ||
| x3.Add(t1, t2) // X3 := t1 + t2 | ||
| t4.Sub(t4, x3) // t4 := t4 - X3 | ||
| x3.Add(p1.x, p1.z) // X3 := X1 + Z1 | ||
| y3 := new(fiat.P224Element).Add(p2.x, p2.z) // Y3 := X2 + Z2 | ||
| x3.Mul(x3, y3) // X3 := X3 * Y3 | ||
| y3.Add(t0, t2) // Y3 := t0 + t2 | ||
| y3.Sub(x3, y3) // Y3 := X3 - Y3 | ||
| z3 := new(fiat.P224Element).Mul(p224B, t2) // Z3 := b * t2 | ||
| x3.Sub(y3, z3) // X3 := Y3 - Z3 | ||
| z3.Add(x3, x3) // Z3 := X3 + X3 | ||
| x3.Add(x3, z3) // X3 := X3 + Z3 | ||
| z3.Sub(t1, x3) // Z3 := t1 - X3 | ||
| x3.Add(t1, x3) // X3 := t1 + X3 | ||
| y3.Mul(p224B, y3) // Y3 := b * Y3 | ||
| t1.Add(t2, t2) // t1 := t2 + t2 | ||
| t2.Add(t1, t2) // t2 := t1 + t2 | ||
| y3.Sub(y3, t2) // Y3 := Y3 - t2 | ||
| y3.Sub(y3, t0) // Y3 := Y3 - t0 | ||
| t1.Add(y3, y3) // t1 := Y3 + Y3 | ||
| y3.Add(t1, y3) // Y3 := t1 + Y3 | ||
| t1.Add(t0, t0) // t1 := t0 + t0 | ||
| t0.Add(t1, t0) // t0 := t1 + t0 | ||
| t0.Sub(t0, t2) // t0 := t0 - t2 | ||
| t1.Mul(t4, y3) // t1 := t4 * Y3 | ||
| t2.Mul(t0, y3) // t2 := t0 * Y3 | ||
| y3.Mul(x3, z3) // Y3 := X3 * Z3 | ||
| y3.Add(y3, t2) // Y3 := Y3 + t2 | ||
| x3.Mul(t3, x3) // X3 := t3 * X3 | ||
| x3.Sub(x3, t1) // X3 := X3 - t1 | ||
| z3.Mul(t4, z3) // Z3 := t4 * Z3 | ||
| t1.Mul(t3, t0) // t1 := t3 * t0 | ||
| z3.Add(z3, t1) // Z3 := Z3 + t1 | ||
|
|
||
| q.x.Set(x3) | ||
| q.y.Set(y3) | ||
| q.z.Set(z3) | ||
| return q | ||
| } | ||
|
|
||
| // Double sets q = p + p, and returns q. The points may overlap. | ||
| func (q *P224Point) Double(p *P224Point) *P224Point { | ||
| // Complete addition formula for a = -3 from "Complete addition formulas for | ||
| // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2. | ||
|
|
||
| t0 := new(fiat.P224Element).Square(p.x) // t0 := X ^ 2 | ||
| t1 := new(fiat.P224Element).Square(p.y) // t1 := Y ^ 2 | ||
| t2 := new(fiat.P224Element).Square(p.z) // t2 := Z ^ 2 | ||
| t3 := new(fiat.P224Element).Mul(p.x, p.y) // t3 := X * Y | ||
| t3.Add(t3, t3) // t3 := t3 + t3 | ||
| z3 := new(fiat.P224Element).Mul(p.x, p.z) // Z3 := X * Z | ||
| z3.Add(z3, z3) // Z3 := Z3 + Z3 | ||
| y3 := new(fiat.P224Element).Mul(p224B, t2) // Y3 := b * t2 | ||
| y3.Sub(y3, z3) // Y3 := Y3 - Z3 | ||
| x3 := new(fiat.P224Element).Add(y3, y3) // X3 := Y3 + Y3 | ||
| y3.Add(x3, y3) // Y3 := X3 + Y3 | ||
| x3.Sub(t1, y3) // X3 := t1 - Y3 | ||
| y3.Add(t1, y3) // Y3 := t1 + Y3 | ||
| y3.Mul(x3, y3) // Y3 := X3 * Y3 | ||
| x3.Mul(x3, t3) // X3 := X3 * t3 | ||
| t3.Add(t2, t2) // t3 := t2 + t2 | ||
| t2.Add(t2, t3) // t2 := t2 + t3 | ||
| z3.Mul(p224B, z3) // Z3 := b * Z3 | ||
| z3.Sub(z3, t2) // Z3 := Z3 - t2 | ||
| z3.Sub(z3, t0) // Z3 := Z3 - t0 | ||
| t3.Add(z3, z3) // t3 := Z3 + Z3 | ||
| z3.Add(z3, t3) // Z3 := Z3 + t3 | ||
| t3.Add(t0, t0) // t3 := t0 + t0 | ||
| t0.Add(t3, t0) // t0 := t3 + t0 | ||
| t0.Sub(t0, t2) // t0 := t0 - t2 | ||
| t0.Mul(t0, z3) // t0 := t0 * Z3 | ||
| y3.Add(y3, t0) // Y3 := Y3 + t0 | ||
| t0.Mul(p.y, p.z) // t0 := Y * Z | ||
| t0.Add(t0, t0) // t0 := t0 + t0 | ||
| z3.Mul(t0, z3) // Z3 := t0 * Z3 | ||
| x3.Sub(x3, z3) // X3 := X3 - Z3 | ||
| z3.Mul(t0, t1) // Z3 := t0 * t1 | ||
| z3.Add(z3, z3) // Z3 := Z3 + Z3 | ||
| z3.Add(z3, z3) // Z3 := Z3 + Z3 | ||
|
|
||
| q.x.Set(x3) | ||
| q.y.Set(y3) | ||
| q.z.Set(z3) | ||
| return q | ||
| } | ||
|
|
||
| // Select sets q to p1 if cond == 1, and to p2 if cond == 0. | ||
| func (q *P224Point) Select(p1, p2 *P224Point, cond int) *P224Point { | ||
| q.x.Select(p1.x, p2.x, cond) | ||
| q.y.Select(p1.y, p2.y, cond) | ||
| q.z.Select(p1.z, p2.z, cond) | ||
| return q | ||
| } | ||
|
|
||
| // ScalarMult sets p = scalar * q, and returns p. | ||
| func (p *P224Point) ScalarMult(q *P224Point, scalar []byte) *P224Point { | ||
| // table holds the first 16 multiples of q. The explicit newP224Point calls | ||
| // get inlined, letting the allocations live on the stack. | ||
| var table = [16]*P224Point{ | ||
| NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(), | ||
| NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(), | ||
| NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(), | ||
| NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(), | ||
| } | ||
| for i := 1; i < 16; i++ { | ||
| table[i].Add(table[i-1], q) | ||
| } | ||
|
|
||
| // Instead of doing the classic double-and-add chain, we do it with a | ||
| // four-bit window: we double four times, and then add [0-15]P. | ||
| t := NewP224Point() | ||
| p.Set(NewP224Point()) | ||
| for _, byte := range scalar { | ||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
|
|
||
| for i := uint8(0); i < 16; i++ { | ||
| cond := subtle.ConstantTimeByteEq(byte>>4, i) | ||
| t.Select(table[i], t, cond) | ||
| } | ||
| p.Add(p, t) | ||
|
|
||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
|
|
||
| for i := uint8(0); i < 16; i++ { | ||
| cond := subtle.ConstantTimeByteEq(byte&0b1111, i) | ||
| t.Select(table[i], t, cond) | ||
| } | ||
| p.Add(p, t) | ||
| } | ||
|
|
||
| return p | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,298 @@ | ||
| // 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 nistec | ||
|
|
||
| import ( | ||
| "crypto/elliptic/internal/fiat" | ||
| "crypto/subtle" | ||
| "errors" | ||
| ) | ||
|
|
||
| var p384B, _ = new(fiat.P384Element).SetBytes([]byte{ | ||
| 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4, 0x98, 0x8e, 0x05, 0x6b, | ||
| 0xe3, 0xf8, 0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12, | ||
| 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, | ||
| 0x8a, 0x2e, 0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef}) | ||
|
|
||
| var p384G, _ = NewP384Point().SetBytes([]byte{0x4, | ||
| 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, | ||
| 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, | ||
| 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, | ||
| 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, | ||
| 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, | ||
| 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, | ||
| 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, | ||
| 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f}) | ||
|
|
||
| const p384ElementLength = 48 | ||
|
|
||
| // P384Point is a P-384 point. The zero value is NOT valid. | ||
| type P384Point struct { | ||
| // The point is represented in projective coordinates (X:Y:Z), | ||
| // where x = X/Z and y = Y/Z. | ||
| x, y, z *fiat.P384Element | ||
| } | ||
|
|
||
| // NewP384Point returns a new P384Point representing the point at infinity point. | ||
| func NewP384Point() *P384Point { | ||
| return &P384Point{ | ||
| x: new(fiat.P384Element), | ||
| y: new(fiat.P384Element).One(), | ||
| z: new(fiat.P384Element), | ||
| } | ||
| } | ||
|
|
||
| // NewP384Generator returns a new P384Point set to the canonical generator. | ||
| func NewP384Generator() *P384Point { | ||
| return (&P384Point{ | ||
| x: new(fiat.P384Element), | ||
| y: new(fiat.P384Element), | ||
| z: new(fiat.P384Element), | ||
| }).Set(p384G) | ||
| } | ||
|
|
||
| // Set sets p = q and returns p. | ||
| func (p *P384Point) Set(q *P384Point) *P384Point { | ||
| p.x.Set(q.x) | ||
| p.y.Set(q.y) | ||
| p.z.Set(q.z) | ||
| return p | ||
| } | ||
|
|
||
| // SetBytes sets p to the compressed, uncompressed, or infinity value encoded in | ||
| // b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on | ||
| // the curve, it returns nil and an error, and the receiver is unchanged. | ||
| // Otherwise, it returns p. | ||
| func (p *P384Point) SetBytes(b []byte) (*P384Point, error) { | ||
| switch { | ||
| // Point at infinity. | ||
| case len(b) == 1 && b[0] == 0: | ||
| return p.Set(NewP384Point()), nil | ||
|
|
||
| // Uncompressed form. | ||
| case len(b) == 1+2*p384ElementLength && b[0] == 4: | ||
| x, err := new(fiat.P384Element).SetBytes(b[1 : 1+p384ElementLength]) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| y, err := new(fiat.P384Element).SetBytes(b[1+p384ElementLength:]) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| if err := p384CheckOnCurve(x, y); err != nil { | ||
| return nil, err | ||
| } | ||
| p.x.Set(x) | ||
| p.y.Set(y) | ||
| p.z.One() | ||
| return p, nil | ||
|
|
||
| // Compressed form | ||
| case len(b) == 1+p384ElementLength && b[0] == 0: | ||
| return nil, errors.New("unimplemented") // TODO(filippo) | ||
|
|
||
| default: | ||
| return nil, errors.New("invalid P384 point encoding") | ||
| } | ||
| } | ||
|
|
||
| func p384CheckOnCurve(x, y *fiat.P384Element) error { | ||
| // x³ - 3x + b. | ||
| x3 := new(fiat.P384Element).Square(x) | ||
| x3.Mul(x3, x) | ||
|
|
||
| threeX := new(fiat.P384Element).Add(x, x) | ||
| threeX.Add(threeX, x) | ||
|
|
||
| x3.Sub(x3, threeX) | ||
| x3.Add(x3, p384B) | ||
|
|
||
| // y² = x³ - 3x + b | ||
| y2 := new(fiat.P384Element).Square(y) | ||
|
|
||
| if x3.Equal(y2) != 1 { | ||
| return errors.New("P384 point not on curve") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // Bytes returns the uncompressed or infinity encoding of p, as specified in | ||
| // SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at | ||
| // infinity is shorter than all other encodings. | ||
| func (p *P384Point) Bytes() []byte { | ||
| // This function is outlined to make the allocations inline in the caller | ||
| // rather than happen on the heap. | ||
| var out [133]byte | ||
| return p.bytes(&out) | ||
| } | ||
|
|
||
| func (p *P384Point) bytes(out *[133]byte) []byte { | ||
| if p.z.IsZero() == 1 { | ||
| return append(out[:0], 0) | ||
| } | ||
|
|
||
| zinv := new(fiat.P384Element).Invert(p.z) | ||
| xx := new(fiat.P384Element).Mul(p.x, zinv) | ||
| yy := new(fiat.P384Element).Mul(p.y, zinv) | ||
|
|
||
| buf := append(out[:0], 4) | ||
| buf = append(buf, xx.Bytes()...) | ||
| buf = append(buf, yy.Bytes()...) | ||
| return buf | ||
| } | ||
|
|
||
| // Add sets q = p1 + p2, and returns q. The points may overlap. | ||
| func (q *P384Point) Add(p1, p2 *P384Point) *P384Point { | ||
| // Complete addition formula for a = -3 from "Complete addition formulas for | ||
| // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2. | ||
|
|
||
| t0 := new(fiat.P384Element).Mul(p1.x, p2.x) // t0 := X1 * X2 | ||
| t1 := new(fiat.P384Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2 | ||
| t2 := new(fiat.P384Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2 | ||
| t3 := new(fiat.P384Element).Add(p1.x, p1.y) // t3 := X1 + Y1 | ||
| t4 := new(fiat.P384Element).Add(p2.x, p2.y) // t4 := X2 + Y2 | ||
| t3.Mul(t3, t4) // t3 := t3 * t4 | ||
| t4.Add(t0, t1) // t4 := t0 + t1 | ||
| t3.Sub(t3, t4) // t3 := t3 - t4 | ||
| t4.Add(p1.y, p1.z) // t4 := Y1 + Z1 | ||
| x3 := new(fiat.P384Element).Add(p2.y, p2.z) // X3 := Y2 + Z2 | ||
| t4.Mul(t4, x3) // t4 := t4 * X3 | ||
| x3.Add(t1, t2) // X3 := t1 + t2 | ||
| t4.Sub(t4, x3) // t4 := t4 - X3 | ||
| x3.Add(p1.x, p1.z) // X3 := X1 + Z1 | ||
| y3 := new(fiat.P384Element).Add(p2.x, p2.z) // Y3 := X2 + Z2 | ||
| x3.Mul(x3, y3) // X3 := X3 * Y3 | ||
| y3.Add(t0, t2) // Y3 := t0 + t2 | ||
| y3.Sub(x3, y3) // Y3 := X3 - Y3 | ||
| z3 := new(fiat.P384Element).Mul(p384B, t2) // Z3 := b * t2 | ||
| x3.Sub(y3, z3) // X3 := Y3 - Z3 | ||
| z3.Add(x3, x3) // Z3 := X3 + X3 | ||
| x3.Add(x3, z3) // X3 := X3 + Z3 | ||
| z3.Sub(t1, x3) // Z3 := t1 - X3 | ||
| x3.Add(t1, x3) // X3 := t1 + X3 | ||
| y3.Mul(p384B, y3) // Y3 := b * Y3 | ||
| t1.Add(t2, t2) // t1 := t2 + t2 | ||
| t2.Add(t1, t2) // t2 := t1 + t2 | ||
| y3.Sub(y3, t2) // Y3 := Y3 - t2 | ||
| y3.Sub(y3, t0) // Y3 := Y3 - t0 | ||
| t1.Add(y3, y3) // t1 := Y3 + Y3 | ||
| y3.Add(t1, y3) // Y3 := t1 + Y3 | ||
| t1.Add(t0, t0) // t1 := t0 + t0 | ||
| t0.Add(t1, t0) // t0 := t1 + t0 | ||
| t0.Sub(t0, t2) // t0 := t0 - t2 | ||
| t1.Mul(t4, y3) // t1 := t4 * Y3 | ||
| t2.Mul(t0, y3) // t2 := t0 * Y3 | ||
| y3.Mul(x3, z3) // Y3 := X3 * Z3 | ||
| y3.Add(y3, t2) // Y3 := Y3 + t2 | ||
| x3.Mul(t3, x3) // X3 := t3 * X3 | ||
| x3.Sub(x3, t1) // X3 := X3 - t1 | ||
| z3.Mul(t4, z3) // Z3 := t4 * Z3 | ||
| t1.Mul(t3, t0) // t1 := t3 * t0 | ||
| z3.Add(z3, t1) // Z3 := Z3 + t1 | ||
|
|
||
| q.x.Set(x3) | ||
| q.y.Set(y3) | ||
| q.z.Set(z3) | ||
| return q | ||
| } | ||
|
|
||
| // Double sets q = p + p, and returns q. The points may overlap. | ||
| func (q *P384Point) Double(p *P384Point) *P384Point { | ||
| // Complete addition formula for a = -3 from "Complete addition formulas for | ||
| // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2. | ||
|
|
||
| t0 := new(fiat.P384Element).Square(p.x) // t0 := X ^ 2 | ||
| t1 := new(fiat.P384Element).Square(p.y) // t1 := Y ^ 2 | ||
| t2 := new(fiat.P384Element).Square(p.z) // t2 := Z ^ 2 | ||
| t3 := new(fiat.P384Element).Mul(p.x, p.y) // t3 := X * Y | ||
| t3.Add(t3, t3) // t3 := t3 + t3 | ||
| z3 := new(fiat.P384Element).Mul(p.x, p.z) // Z3 := X * Z | ||
| z3.Add(z3, z3) // Z3 := Z3 + Z3 | ||
| y3 := new(fiat.P384Element).Mul(p384B, t2) // Y3 := b * t2 | ||
| y3.Sub(y3, z3) // Y3 := Y3 - Z3 | ||
| x3 := new(fiat.P384Element).Add(y3, y3) // X3 := Y3 + Y3 | ||
| y3.Add(x3, y3) // Y3 := X3 + Y3 | ||
| x3.Sub(t1, y3) // X3 := t1 - Y3 | ||
| y3.Add(t1, y3) // Y3 := t1 + Y3 | ||
| y3.Mul(x3, y3) // Y3 := X3 * Y3 | ||
| x3.Mul(x3, t3) // X3 := X3 * t3 | ||
| t3.Add(t2, t2) // t3 := t2 + t2 | ||
| t2.Add(t2, t3) // t2 := t2 + t3 | ||
| z3.Mul(p384B, z3) // Z3 := b * Z3 | ||
| z3.Sub(z3, t2) // Z3 := Z3 - t2 | ||
| z3.Sub(z3, t0) // Z3 := Z3 - t0 | ||
| t3.Add(z3, z3) // t3 := Z3 + Z3 | ||
| z3.Add(z3, t3) // Z3 := Z3 + t3 | ||
| t3.Add(t0, t0) // t3 := t0 + t0 | ||
| t0.Add(t3, t0) // t0 := t3 + t0 | ||
| t0.Sub(t0, t2) // t0 := t0 - t2 | ||
| t0.Mul(t0, z3) // t0 := t0 * Z3 | ||
| y3.Add(y3, t0) // Y3 := Y3 + t0 | ||
| t0.Mul(p.y, p.z) // t0 := Y * Z | ||
| t0.Add(t0, t0) // t0 := t0 + t0 | ||
| z3.Mul(t0, z3) // Z3 := t0 * Z3 | ||
| x3.Sub(x3, z3) // X3 := X3 - Z3 | ||
| z3.Mul(t0, t1) // Z3 := t0 * t1 | ||
| z3.Add(z3, z3) // Z3 := Z3 + Z3 | ||
| z3.Add(z3, z3) // Z3 := Z3 + Z3 | ||
|
|
||
| q.x.Set(x3) | ||
| q.y.Set(y3) | ||
| q.z.Set(z3) | ||
| return q | ||
| } | ||
|
|
||
| // Select sets q to p1 if cond == 1, and to p2 if cond == 0. | ||
| func (q *P384Point) Select(p1, p2 *P384Point, cond int) *P384Point { | ||
| q.x.Select(p1.x, p2.x, cond) | ||
| q.y.Select(p1.y, p2.y, cond) | ||
| q.z.Select(p1.z, p2.z, cond) | ||
| return q | ||
| } | ||
|
|
||
| // ScalarMult sets p = scalar * q, and returns p. | ||
| func (p *P384Point) ScalarMult(q *P384Point, scalar []byte) *P384Point { | ||
| // table holds the first 16 multiples of q. The explicit newP384Point calls | ||
| // get inlined, letting the allocations live on the stack. | ||
| var table = [16]*P384Point{ | ||
| NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(), | ||
| NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(), | ||
| NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(), | ||
| NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(), | ||
| } | ||
| for i := 1; i < 16; i++ { | ||
| table[i].Add(table[i-1], q) | ||
| } | ||
|
|
||
| // Instead of doing the classic double-and-add chain, we do it with a | ||
| // four-bit window: we double four times, and then add [0-15]P. | ||
| t := NewP384Point() | ||
| p.Set(NewP384Point()) | ||
| for _, byte := range scalar { | ||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
|
|
||
| for i := uint8(0); i < 16; i++ { | ||
| cond := subtle.ConstantTimeByteEq(byte>>4, i) | ||
| t.Select(table[i], t, cond) | ||
| } | ||
| p.Add(p, t) | ||
|
|
||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
| p.Double(p) | ||
|
|
||
| for i := uint8(0); i < 16; i++ { | ||
| cond := subtle.ConstantTimeByteEq(byte&0b1111, i) | ||
| t.Select(table[i], t, cond) | ||
| } | ||
| p.Add(p, t) | ||
| } | ||
|
|
||
| return p | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| // 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.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)) | ||
| } |