|  | // 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) | 
|  | } | 
|  | ` |