mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-25 19:56:18 +08:00
278 lines
8.7 KiB
Go
278 lines
8.7 KiB
Go
![]() |
// 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
|
|||
|
// +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: "SM2P256Element",
|
|||
|
Prime: "2^256 - 2^224 - 2^96 + 2^64 - 1",
|
|||
|
Prefix: "sm2p256",
|
|||
|
FiatType: "[4]uint64",
|
|||
|
BytesLen: 32,
|
|||
|
},
|
|||
|
}
|
|||
|
|
|||
|
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)
|
|||
|
}
|
|||
|
`
|