From 1a7f6b728bb4f568e099e7f3b7ad7e00eaa62f77 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Fri, 3 Oct 2025 15:31:24 -0700 Subject: [PATCH 1/5] Copy crypto/x509 files from upstream go v1.24.8 --- ca/x509pq/oid.go | 395 +++++++ ca/x509pq/parser.go | 1319 ++++++++++++++++++++++ ca/x509pq/pkcs1.go | 202 ++++ ca/x509pq/verify.go | 1620 +++++++++++++++++++++++++++ ca/x509pq/x509.go | 2569 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 6105 insertions(+) create mode 100644 ca/x509pq/oid.go create mode 100644 ca/x509pq/parser.go create mode 100644 ca/x509pq/pkcs1.go create mode 100644 ca/x509pq/verify.go create mode 100644 ca/x509pq/x509.go diff --git a/ca/x509pq/oid.go b/ca/x509pq/oid.go new file mode 100644 index 00000000..b1464346 --- /dev/null +++ b/ca/x509pq/oid.go @@ -0,0 +1,395 @@ +// Copyright 2023 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 x509 + +import ( + "bytes" + "encoding/asn1" + "errors" + "math" + "math/big" + "math/bits" + "strconv" + "strings" +) + +var ( + errInvalidOID = errors.New("invalid oid") +) + +// An OID represents an ASN.1 OBJECT IDENTIFIER. +type OID struct { + der []byte +} + +// ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots. +func ParseOID(oid string) (OID, error) { + var o OID + return o, o.unmarshalOIDText(oid) +} + +func newOIDFromDER(der []byte) (OID, bool) { + if len(der) == 0 || der[len(der)-1]&0x80 != 0 { + return OID{}, false + } + + start := 0 + for i, v := range der { + // ITU-T X.690, section 8.19.2: + // The subidentifier shall be encoded in the fewest possible octets, + // that is, the leading octet of the subidentifier shall not have the value 0x80. + if i == start && v == 0x80 { + return OID{}, false + } + if v&0x80 == 0 { + start = i + 1 + } + } + + return OID{der}, true +} + +// OIDFromInts creates a new OID using ints, each integer is a separate component. +func OIDFromInts(oid []uint64) (OID, error) { + if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { + return OID{}, errInvalidOID + } + + length := base128IntLength(oid[0]*40 + oid[1]) + for _, v := range oid[2:] { + length += base128IntLength(v) + } + + der := make([]byte, 0, length) + der = appendBase128Int(der, oid[0]*40+oid[1]) + for _, v := range oid[2:] { + der = appendBase128Int(der, v) + } + return OID{der}, nil +} + +func base128IntLength(n uint64) int { + if n == 0 { + return 1 + } + return (bits.Len64(n) + 6) / 7 +} + +func appendBase128Int(dst []byte, n uint64) []byte { + for i := base128IntLength(n) - 1; i >= 0; i-- { + o := byte(n >> uint(i*7)) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + dst = append(dst, o) + } + return dst +} + +func base128BigIntLength(n *big.Int) int { + if n.Cmp(big.NewInt(0)) == 0 { + return 1 + } + return (n.BitLen() + 6) / 7 +} + +func appendBase128BigInt(dst []byte, n *big.Int) []byte { + if n.Cmp(big.NewInt(0)) == 0 { + return append(dst, 0) + } + + for i := base128BigIntLength(n) - 1; i >= 0; i-- { + o := byte(big.NewInt(0).Rsh(n, uint(i)*7).Bits()[0]) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + dst = append(dst, o) + } + return dst +} + +// AppendText implements [encoding.TextAppender] +func (o OID) AppendText(b []byte) ([]byte, error) { + return append(b, o.String()...), nil +} + +// MarshalText implements [encoding.TextMarshaler] +func (o OID) MarshalText() ([]byte, error) { + return o.AppendText(nil) +} + +// UnmarshalText implements [encoding.TextUnmarshaler] +func (o *OID) UnmarshalText(text []byte) error { + return o.unmarshalOIDText(string(text)) +} + +func (o *OID) unmarshalOIDText(oid string) error { + // (*big.Int).SetString allows +/- signs, but we don't want + // to allow them in the string representation of Object Identifier, so + // reject such encodings. + for _, c := range oid { + isDigit := c >= '0' && c <= '9' + if !isDigit && c != '.' { + return errInvalidOID + } + } + + var ( + firstNum string + secondNum string + ) + + var nextComponentExists bool + firstNum, oid, nextComponentExists = strings.Cut(oid, ".") + if !nextComponentExists { + return errInvalidOID + } + secondNum, oid, nextComponentExists = strings.Cut(oid, ".") + + var ( + first = big.NewInt(0) + second = big.NewInt(0) + ) + + if _, ok := first.SetString(firstNum, 10); !ok { + return errInvalidOID + } + if _, ok := second.SetString(secondNum, 10); !ok { + return errInvalidOID + } + + if first.Cmp(big.NewInt(2)) > 0 || (first.Cmp(big.NewInt(2)) < 0 && second.Cmp(big.NewInt(40)) >= 0) { + return errInvalidOID + } + + firstComponent := first.Mul(first, big.NewInt(40)) + firstComponent.Add(firstComponent, second) + + der := appendBase128BigInt(make([]byte, 0, 32), firstComponent) + + for nextComponentExists { + var strNum string + strNum, oid, nextComponentExists = strings.Cut(oid, ".") + b, ok := big.NewInt(0).SetString(strNum, 10) + if !ok { + return errInvalidOID + } + der = appendBase128BigInt(der, b) + } + + o.der = der + return nil +} + +// AppendBinary implements [encoding.BinaryAppender] +func (o OID) AppendBinary(b []byte) ([]byte, error) { + return append(b, o.der...), nil +} + +// MarshalBinary implements [encoding.BinaryMarshaler] +func (o OID) MarshalBinary() ([]byte, error) { + return o.AppendBinary(nil) +} + +// UnmarshalBinary implements [encoding.BinaryUnmarshaler] +func (o *OID) UnmarshalBinary(b []byte) error { + oid, ok := newOIDFromDER(bytes.Clone(b)) + if !ok { + return errInvalidOID + } + *o = oid + return nil +} + +// Equal returns true when oid and other represents the same Object Identifier. +func (oid OID) Equal(other OID) bool { + // There is only one possible DER encoding of + // each unique Object Identifier. + return bytes.Equal(oid.der, other.der) +} + +func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, failed bool) { + offset = initOffset + var ret64 int64 + for shifted := 0; offset < len(bytes); shifted++ { + // 5 * 7 bits per byte == 35 bits of data + // Thus the representation is either non-minimal or too large for an int32 + if shifted == 5 { + failed = true + return + } + ret64 <<= 7 + b := bytes[offset] + // integers should be minimally encoded, so the leading octet should + // never be 0x80 + if shifted == 0 && b == 0x80 { + failed = true + return + } + ret64 |= int64(b & 0x7f) + offset++ + if b&0x80 == 0 { + ret = int(ret64) + // Ensure that the returned value fits in an int on all platforms + if ret64 > math.MaxInt32 { + failed = true + } + return + } + } + failed = true + return +} + +// EqualASN1OID returns whether an OID equals an asn1.ObjectIdentifier. If +// asn1.ObjectIdentifier cannot represent the OID specified by oid, because +// a component of OID requires more than 31 bits, it returns false. +func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool { + if len(other) < 2 { + return false + } + v, offset, failed := parseBase128Int(oid.der, 0) + if failed { + // This should never happen, since we've already parsed the OID, + // but just in case. + return false + } + if v < 80 { + a, b := v/40, v%40 + if other[0] != a || other[1] != b { + return false + } + } else { + a, b := 2, v-80 + if other[0] != a || other[1] != b { + return false + } + } + + i := 2 + for ; offset < len(oid.der); i++ { + v, offset, failed = parseBase128Int(oid.der, offset) + if failed { + // Again, shouldn't happen, since we've already parsed + // the OID, but better safe than sorry. + return false + } + if i >= len(other) || v != other[i] { + return false + } + } + + return i == len(other) +} + +// Strings returns the string representation of the Object Identifier. +func (oid OID) String() string { + var b strings.Builder + b.Grow(32) + const ( + valSize = 64 // size in bits of val. + bitsPerByte = 7 + maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1 + ) + var ( + start = 0 + val = uint64(0) + numBuf = make([]byte, 0, 21) + bigVal *big.Int + overflow bool + ) + for i, v := range oid.der { + curVal := v & 0x7F + valEnd := v&0x80 == 0 + if valEnd { + if start != 0 { + b.WriteByte('.') + } + } + if !overflow && val > maxValSafeShift { + if bigVal == nil { + bigVal = new(big.Int) + } + bigVal = bigVal.SetUint64(val) + overflow = true + } + if overflow { + bigVal = bigVal.Lsh(bigVal, bitsPerByte).Or(bigVal, big.NewInt(int64(curVal))) + if valEnd { + if start == 0 { + b.WriteString("2.") + bigVal = bigVal.Sub(bigVal, big.NewInt(80)) + } + numBuf = bigVal.Append(numBuf, 10) + b.Write(numBuf) + numBuf = numBuf[:0] + val = 0 + start = i + 1 + overflow = false + } + continue + } + val <<= bitsPerByte + val |= uint64(curVal) + if valEnd { + if start == 0 { + if val < 80 { + b.Write(strconv.AppendUint(numBuf, val/40, 10)) + b.WriteByte('.') + b.Write(strconv.AppendUint(numBuf, val%40, 10)) + } else { + b.WriteString("2.") + b.Write(strconv.AppendUint(numBuf, val-80, 10)) + } + } else { + b.Write(strconv.AppendUint(numBuf, val, 10)) + } + val = 0 + start = i + 1 + } + } + return b.String() +} + +func (oid OID) toASN1OID() (asn1.ObjectIdentifier, bool) { + out := make([]int, 0, len(oid.der)+1) + + const ( + valSize = 31 // amount of usable bits of val for OIDs. + bitsPerByte = 7 + maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1 + ) + + val := 0 + + for _, v := range oid.der { + if val > maxValSafeShift { + return nil, false + } + + val <<= bitsPerByte + val |= int(v & 0x7F) + + if v&0x80 == 0 { + if len(out) == 0 { + if val < 80 { + out = append(out, val/40) + out = append(out, val%40) + } else { + out = append(out, 2) + out = append(out, val-80) + } + val = 0 + continue + } + out = append(out, val) + val = 0 + } + } + + return out, true +} diff --git a/ca/x509pq/parser.go b/ca/x509pq/parser.go new file mode 100644 index 00000000..4abcc1b7 --- /dev/null +++ b/ca/x509pq/parser.go @@ -0,0 +1,1319 @@ +// 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 x509 + +import ( + "bytes" + "crypto/dsa" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" + "internal/godebug" + "math" + "math/big" + "net" + "net/url" + "strconv" + "strings" + "time" + "unicode/utf16" + "unicode/utf8" + + "golang.org/x/crypto/cryptobyte" + cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" +) + +// isPrintable reports whether the given b is in the ASN.1 PrintableString set. +// This is a simplified version of encoding/asn1.isPrintable. +func isPrintable(b byte) bool { + return 'a' <= b && b <= 'z' || + 'A' <= b && b <= 'Z' || + '0' <= b && b <= '9' || + '\'' <= b && b <= ')' || + '+' <= b && b <= '/' || + b == ' ' || + b == ':' || + b == '=' || + b == '?' || + // This is technically not allowed in a PrintableString. + // However, x509 certificates with wildcard strings don't + // always use the correct string type so we permit it. + b == '*' || + // This is not technically allowed either. However, not + // only is it relatively common, but there are also a + // handful of CA certificates that contain it. At least + // one of which will not expire until 2027. + b == '&' +} + +// parseASN1String parses the ASN.1 string types T61String, PrintableString, +// UTF8String, BMPString, IA5String, and NumericString. This is mostly copied +// from the respective encoding/asn1.parse... methods, rather than just +// increasing the API surface of that package. +func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) { + switch tag { + case cryptobyte_asn1.T61String: + // T.61 is a defunct ITU 8-bit character encoding which preceded Unicode. + // T.61 uses a code page layout that _almost_ exactly maps to the code + // page layout of the ISO 8859-1 (Latin-1) character encoding, with the + // exception that a number of characters in Latin-1 are not present + // in T.61. + // + // Instead of mapping which characters are present in Latin-1 but not T.61, + // we just treat these strings as being encoded using Latin-1. This matches + // what most of the world does, including BoringSSL. + buf := make([]byte, 0, len(value)) + for _, v := range value { + // All the 1-byte UTF-8 runes map 1-1 with Latin-1. + buf = utf8.AppendRune(buf, rune(v)) + } + return string(buf), nil + case cryptobyte_asn1.PrintableString: + for _, b := range value { + if !isPrintable(b) { + return "", errors.New("invalid PrintableString") + } + } + return string(value), nil + case cryptobyte_asn1.UTF8String: + if !utf8.Valid(value) { + return "", errors.New("invalid UTF-8 string") + } + return string(value), nil + case cryptobyte_asn1.Tag(asn1.TagBMPString): + // BMPString uses the defunct UCS-2 16-bit character encoding, which + // covers the Basic Multilingual Plane (BMP). UTF-16 was an extension of + // UCS-2, containing all of the same code points, but also including + // multi-code point characters (by using surrogate code points). We can + // treat a UCS-2 encoded string as a UTF-16 encoded string, as long as + // we reject out the UTF-16 specific code points. This matches the + // BoringSSL behavior. + + if len(value)%2 != 0 { + return "", errors.New("invalid BMPString") + } + + // Strip terminator if present. + if l := len(value); l >= 2 && value[l-1] == 0 && value[l-2] == 0 { + value = value[:l-2] + } + + s := make([]uint16, 0, len(value)/2) + for len(value) > 0 { + point := uint16(value[0])<<8 + uint16(value[1]) + // Reject UTF-16 code points that are permanently reserved + // noncharacters (0xfffe, 0xffff, and 0xfdd0-0xfdef) and surrogates + // (0xd800-0xdfff). + if point == 0xfffe || point == 0xffff || + (point >= 0xfdd0 && point <= 0xfdef) || + (point >= 0xd800 && point <= 0xdfff) { + return "", errors.New("invalid BMPString") + } + s = append(s, point) + value = value[2:] + } + + return string(utf16.Decode(s)), nil + case cryptobyte_asn1.IA5String: + s := string(value) + if isIA5String(s) != nil { + return "", errors.New("invalid IA5String") + } + return s, nil + case cryptobyte_asn1.Tag(asn1.TagNumericString): + for _, b := range value { + if !('0' <= b && b <= '9' || b == ' ') { + return "", errors.New("invalid NumericString") + } + } + return string(value), nil + } + return "", fmt.Errorf("unsupported string type: %v", tag) +} + +// parseName parses a DER encoded Name as defined in RFC 5280. We may +// want to export this function in the future for use in crypto/tls. +func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { + if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid RDNSequence") + } + + var rdnSeq pkix.RDNSequence + for !raw.Empty() { + var rdnSet pkix.RelativeDistinguishedNameSET + var set cryptobyte.String + if !raw.ReadASN1(&set, cryptobyte_asn1.SET) { + return nil, errors.New("x509: invalid RDNSequence") + } + for !set.Empty() { + var atav cryptobyte.String + if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid RDNSequence: invalid attribute") + } + var attr pkix.AttributeTypeAndValue + if !atav.ReadASN1ObjectIdentifier(&attr.Type) { + return nil, errors.New("x509: invalid RDNSequence: invalid attribute type") + } + var rawValue cryptobyte.String + var valueTag cryptobyte_asn1.Tag + if !atav.ReadAnyASN1(&rawValue, &valueTag) { + return nil, errors.New("x509: invalid RDNSequence: invalid attribute value") + } + var err error + attr.Value, err = parseASN1String(valueTag, rawValue) + if err != nil { + return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", err) + } + rdnSet = append(rdnSet, attr) + } + + rdnSeq = append(rdnSeq, rdnSet) + } + + return &rdnSeq, nil +} + +func parseAI(der cryptobyte.String) (pkix.AlgorithmIdentifier, error) { + ai := pkix.AlgorithmIdentifier{} + if !der.ReadASN1ObjectIdentifier(&ai.Algorithm) { + return ai, errors.New("x509: malformed OID") + } + if der.Empty() { + return ai, nil + } + var params cryptobyte.String + var tag cryptobyte_asn1.Tag + if !der.ReadAnyASN1Element(¶ms, &tag) { + return ai, errors.New("x509: malformed parameters") + } + ai.Parameters.Tag = int(tag) + ai.Parameters.FullBytes = params + return ai, nil +} + +func parseTime(der *cryptobyte.String) (time.Time, error) { + var t time.Time + switch { + case der.PeekASN1Tag(cryptobyte_asn1.UTCTime): + if !der.ReadASN1UTCTime(&t) { + return t, errors.New("x509: malformed UTCTime") + } + case der.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime): + if !der.ReadASN1GeneralizedTime(&t) { + return t, errors.New("x509: malformed GeneralizedTime") + } + default: + return t, errors.New("x509: unsupported time format") + } + return t, nil +} + +func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) { + notBefore, err := parseTime(&der) + if err != nil { + return time.Time{}, time.Time{}, err + } + notAfter, err := parseTime(&der) + if err != nil { + return time.Time{}, time.Time{}, err + } + + return notBefore, notAfter, nil +} + +func parseExtension(der cryptobyte.String) (pkix.Extension, error) { + var ext pkix.Extension + if !der.ReadASN1ObjectIdentifier(&ext.Id) { + return ext, errors.New("x509: malformed extension OID field") + } + if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { + if !der.ReadASN1Boolean(&ext.Critical) { + return ext, errors.New("x509: malformed extension critical field") + } + } + var val cryptobyte.String + if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) { + return ext, errors.New("x509: malformed extension value field") + } + ext.Value = val + return ext, nil +} + +func parsePublicKey(keyData *publicKeyInfo) (any, error) { + oid := keyData.Algorithm.Algorithm + params := keyData.Algorithm.Parameters + der := cryptobyte.String(keyData.PublicKey.RightAlign()) + switch { + case oid.Equal(oidPublicKeyRSA): + // RSA public keys must have a NULL in the parameters. + // See RFC 3279, Section 2.3.1. + if !bytes.Equal(params.FullBytes, asn1.NullBytes) { + return nil, errors.New("x509: RSA key missing NULL parameters") + } + + p := &pkcs1PublicKey{N: new(big.Int)} + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid RSA public key") + } + if !der.ReadASN1Integer(p.N) { + return nil, errors.New("x509: invalid RSA modulus") + } + if !der.ReadASN1Integer(&p.E) { + return nil, errors.New("x509: invalid RSA public exponent") + } + + if p.N.Sign() <= 0 { + return nil, errors.New("x509: RSA modulus is not a positive number") + } + if p.E <= 0 { + return nil, errors.New("x509: RSA public exponent is not a positive number") + } + + pub := &rsa.PublicKey{ + E: p.E, + N: p.N, + } + return pub, nil + case oid.Equal(oidPublicKeyECDSA): + paramsDer := cryptobyte.String(params.FullBytes) + namedCurveOID := new(asn1.ObjectIdentifier) + if !paramsDer.ReadASN1ObjectIdentifier(namedCurveOID) { + return nil, errors.New("x509: invalid ECDSA parameters") + } + namedCurve := namedCurveFromOID(*namedCurveOID) + if namedCurve == nil { + return nil, errors.New("x509: unsupported elliptic curve") + } + x, y := elliptic.Unmarshal(namedCurve, der) + if x == nil { + return nil, errors.New("x509: failed to unmarshal elliptic curve point") + } + pub := &ecdsa.PublicKey{ + Curve: namedCurve, + X: x, + Y: y, + } + return pub, nil + case oid.Equal(oidPublicKeyEd25519): + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: Ed25519 key encoded with illegal parameters") + } + if len(der) != ed25519.PublicKeySize { + return nil, errors.New("x509: wrong Ed25519 public key size") + } + return ed25519.PublicKey(der), nil + case oid.Equal(oidPublicKeyX25519): + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: X25519 key encoded with illegal parameters") + } + return ecdh.X25519().NewPublicKey(der) + case oid.Equal(oidPublicKeyDSA): + y := new(big.Int) + if !der.ReadASN1Integer(y) { + return nil, errors.New("x509: invalid DSA public key") + } + pub := &dsa.PublicKey{ + Y: y, + Parameters: dsa.Parameters{ + P: new(big.Int), + Q: new(big.Int), + G: new(big.Int), + }, + } + paramsDer := cryptobyte.String(params.FullBytes) + if !paramsDer.ReadASN1(¶msDer, cryptobyte_asn1.SEQUENCE) || + !paramsDer.ReadASN1Integer(pub.Parameters.P) || + !paramsDer.ReadASN1Integer(pub.Parameters.Q) || + !paramsDer.ReadASN1Integer(pub.Parameters.G) { + return nil, errors.New("x509: invalid DSA parameters") + } + if pub.Y.Sign() <= 0 || pub.Parameters.P.Sign() <= 0 || + pub.Parameters.Q.Sign() <= 0 || pub.Parameters.G.Sign() <= 0 { + return nil, errors.New("x509: zero or negative DSA parameter") + } + return pub, nil + default: + return nil, errors.New("x509: unknown public key algorithm") + } +} + +func parseKeyUsageExtension(der cryptobyte.String) (KeyUsage, error) { + var usageBits asn1.BitString + if !der.ReadASN1BitString(&usageBits) { + return 0, errors.New("x509: invalid key usage") + } + + var usage int + for i := 0; i < 9; i++ { + if usageBits.At(i) != 0 { + usage |= 1 << uint(i) + } + } + return KeyUsage(usage), nil +} + +func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) { + var isCA bool + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return false, 0, errors.New("x509: invalid basic constraints") + } + if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { + if !der.ReadASN1Boolean(&isCA) { + return false, 0, errors.New("x509: invalid basic constraints") + } + } + + maxPathLen := -1 + if der.PeekASN1Tag(cryptobyte_asn1.INTEGER) { + var mpl uint + if !der.ReadASN1Integer(&mpl) || mpl > math.MaxInt { + return false, 0, errors.New("x509: invalid basic constraints") + } + maxPathLen = int(mpl) + } + + return isCA, maxPathLen, nil +} + +func forEachSAN(der cryptobyte.String, callback func(tag int, data []byte) error) error { + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid subject alternative names") + } + for !der.Empty() { + var san cryptobyte.String + var tag cryptobyte_asn1.Tag + if !der.ReadAnyASN1(&san, &tag) { + return errors.New("x509: invalid subject alternative name") + } + if err := callback(int(tag^0x80), san); err != nil { + return err + } + } + + return nil +} + +func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { + err = forEachSAN(der, func(tag int, data []byte) error { + switch tag { + case nameTypeEmail: + email := string(data) + if err := isIA5String(email); err != nil { + return errors.New("x509: SAN rfc822Name is malformed") + } + emailAddresses = append(emailAddresses, email) + case nameTypeDNS: + name := string(data) + if err := isIA5String(name); err != nil { + return errors.New("x509: SAN dNSName is malformed") + } + dnsNames = append(dnsNames, string(name)) + case nameTypeURI: + uriStr := string(data) + if err := isIA5String(uriStr); err != nil { + return errors.New("x509: SAN uniformResourceIdentifier is malformed") + } + uri, err := url.Parse(uriStr) + if err != nil { + return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err) + } + if len(uri.Host) > 0 { + if _, ok := domainToReverseLabels(uri.Host); !ok { + return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr) + } + } + uris = append(uris, uri) + case nameTypeIP: + switch len(data) { + case net.IPv4len, net.IPv6len: + ipAddresses = append(ipAddresses, data) + default: + return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data))) + } + } + + return nil + }) + + return +} + +func parseAuthorityKeyIdentifier(e pkix.Extension) ([]byte, error) { + // RFC 5280, Section 4.2.1.1 + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return nil, errors.New("x509: authority key identifier incorrectly marked critical") + } + val := cryptobyte.String(e.Value) + var akid cryptobyte.String + if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid authority key identifier") + } + if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { + if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { + return nil, errors.New("x509: invalid authority key identifier") + } + return akid, nil + } + return nil, nil +} + +func parseExtKeyUsageExtension(der cryptobyte.String) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) { + var extKeyUsages []ExtKeyUsage + var unknownUsages []asn1.ObjectIdentifier + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return nil, nil, errors.New("x509: invalid extended key usages") + } + for !der.Empty() { + var eku asn1.ObjectIdentifier + if !der.ReadASN1ObjectIdentifier(&eku) { + return nil, nil, errors.New("x509: invalid extended key usages") + } + if extKeyUsage, ok := extKeyUsageFromOID(eku); ok { + extKeyUsages = append(extKeyUsages, extKeyUsage) + } else { + unknownUsages = append(unknownUsages, eku) + } + } + return extKeyUsages, unknownUsages, nil +} + +func parseCertificatePoliciesExtension(der cryptobyte.String) ([]OID, error) { + var oids []OID + seenOIDs := map[string]bool{} + if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid certificate policies") + } + for !der.Empty() { + var cp cryptobyte.String + var OIDBytes cryptobyte.String + if !der.ReadASN1(&cp, cryptobyte_asn1.SEQUENCE) || !cp.ReadASN1(&OIDBytes, cryptobyte_asn1.OBJECT_IDENTIFIER) { + return nil, errors.New("x509: invalid certificate policies") + } + if seenOIDs[string(OIDBytes)] { + return nil, errors.New("x509: invalid certificate policies") + } + seenOIDs[string(OIDBytes)] = true + oid, ok := newOIDFromDER(OIDBytes) + if !ok { + return nil, errors.New("x509: invalid certificate policies") + } + oids = append(oids, oid) + } + return oids, nil +} + +// isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. +func isValidIPMask(mask []byte) bool { + seenZero := false + + for _, b := range mask { + if seenZero { + if b != 0 { + return false + } + + continue + } + + switch b { + case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: + seenZero = true + case 0xff: + default: + return false + } + } + + return true +} + +func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) { + // RFC 5280, 4.2.1.10 + + // NameConstraints ::= SEQUENCE { + // permittedSubtrees [0] GeneralSubtrees OPTIONAL, + // excludedSubtrees [1] GeneralSubtrees OPTIONAL } + // + // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + // + // GeneralSubtree ::= SEQUENCE { + // base GeneralName, + // minimum [0] BaseDistance DEFAULT 0, + // maximum [1] BaseDistance OPTIONAL } + // + // BaseDistance ::= INTEGER (0..MAX) + + outer := cryptobyte.String(e.Value) + var toplevel, permitted, excluded cryptobyte.String + var havePermitted, haveExcluded bool + if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || + !outer.Empty() || + !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || + !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || + !toplevel.Empty() { + return false, errors.New("x509: invalid NameConstraints extension") + } + + if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { + // From RFC 5280, Section 4.2.1.10: + // “either the permittedSubtrees field + // or the excludedSubtrees MUST be + // present” + return false, errors.New("x509: empty name constraints extension") + } + + getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { + for !subtrees.Empty() { + var seq, value cryptobyte.String + var tag cryptobyte_asn1.Tag + if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || + !seq.ReadAnyASN1(&value, &tag) { + return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") + } + + var ( + dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() + emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() + ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() + uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() + ) + + switch tag { + case dnsTag: + domain := string(value) + if err := isIA5String(domain); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + trimmedDomain := domain + if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { + // constraints can have a leading + // period to exclude the domain + // itself, but that's not valid in a + // normal domain name. + trimmedDomain = trimmedDomain[1:] + } + if _, ok := domainToReverseLabels(trimmedDomain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) + } + dnsNames = append(dnsNames, domain) + + case ipTag: + l := len(value) + var ip, mask []byte + + switch l { + case 8: + ip = value[:4] + mask = value[4:] + + case 32: + ip = value[:16] + mask = value[16:] + + default: + return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) + } + + if !isValidIPMask(mask) { + return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) + } + + ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) + + case emailTag: + constraint := string(value) + if err := isIA5String(constraint); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + // If the constraint contains an @ then + // it specifies an exact mailbox name. + if strings.Contains(constraint, "@") { + if _, ok := parseRFC2821Mailbox(constraint); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) + } + } else { + // Otherwise it's a domain name. + domain := constraint + if len(domain) > 0 && domain[0] == '.' { + domain = domain[1:] + } + if _, ok := domainToReverseLabels(domain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) + } + } + emails = append(emails, constraint) + + case uriTag: + domain := string(value) + if err := isIA5String(domain); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + if net.ParseIP(domain) != nil { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) + } + + trimmedDomain := domain + if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { + // constraints can have a leading + // period to exclude the domain itself, + // but that's not valid in a normal + // domain name. + trimmedDomain = trimmedDomain[1:] + } + if _, ok := domainToReverseLabels(trimmedDomain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) + } + uriDomains = append(uriDomains, domain) + + default: + unhandled = true + } + } + + return dnsNames, ips, emails, uriDomains, nil + } + + if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { + return false, err + } + if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { + return false, err + } + out.PermittedDNSDomainsCritical = e.Critical + + return unhandled, nil +} + +func processExtensions(out *Certificate) error { + var err error + for _, e := range out.Extensions { + unhandled := false + + if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { + switch e.Id[3] { + case 15: + out.KeyUsage, err = parseKeyUsageExtension(e.Value) + if err != nil { + return err + } + case 19: + out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value) + if err != nil { + return err + } + out.BasicConstraintsValid = true + out.MaxPathLenZero = out.MaxPathLen == 0 + case 17: + out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value) + if err != nil { + return err + } + + if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { + // If we didn't parse anything then we do the critical check, below. + unhandled = true + } + + case 30: + unhandled, err = parseNameConstraintsExtension(out, e) + if err != nil { + return err + } + + case 31: + // RFC 5280, 4.2.1.13 + + // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + // + // DistributionPoint ::= SEQUENCE { + // distributionPoint [0] DistributionPointName OPTIONAL, + // reasons [1] ReasonFlags OPTIONAL, + // cRLIssuer [2] GeneralNames OPTIONAL } + // + // DistributionPointName ::= CHOICE { + // fullName [0] GeneralNames, + // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + val := cryptobyte.String(e.Value) + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid CRL distribution points") + } + for !val.Empty() { + var dpDER cryptobyte.String + if !val.ReadASN1(&dpDER, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid CRL distribution point") + } + var dpNameDER cryptobyte.String + var dpNamePresent bool + if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { + return errors.New("x509: invalid CRL distribution point") + } + if !dpNamePresent { + continue + } + if !dpNameDER.ReadASN1(&dpNameDER, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { + return errors.New("x509: invalid CRL distribution point") + } + for !dpNameDER.Empty() { + if !dpNameDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { + break + } + var uri cryptobyte.String + if !dpNameDER.ReadASN1(&uri, cryptobyte_asn1.Tag(6).ContextSpecific()) { + return errors.New("x509: invalid CRL distribution point") + } + out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(uri)) + } + } + + case 35: + out.AuthorityKeyId, err = parseAuthorityKeyIdentifier(e) + if err != nil { + return err + } + case 36: + val := cryptobyte.String(e.Value) + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid policy constraints extension") + } + if val.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { + var v int64 + if !val.ReadASN1Int64WithTag(&v, cryptobyte_asn1.Tag(0).ContextSpecific()) { + return errors.New("x509: invalid policy constraints extension") + } + out.RequireExplicitPolicy = int(v) + // Check for overflow. + if int64(out.RequireExplicitPolicy) != v { + return errors.New("x509: policy constraints requireExplicitPolicy field overflows int") + } + out.RequireExplicitPolicyZero = out.RequireExplicitPolicy == 0 + } + if val.PeekASN1Tag(cryptobyte_asn1.Tag(1).ContextSpecific()) { + var v int64 + if !val.ReadASN1Int64WithTag(&v, cryptobyte_asn1.Tag(1).ContextSpecific()) { + return errors.New("x509: invalid policy constraints extension") + } + out.InhibitPolicyMapping = int(v) + // Check for overflow. + if int64(out.InhibitPolicyMapping) != v { + return errors.New("x509: policy constraints inhibitPolicyMapping field overflows int") + } + out.InhibitPolicyMappingZero = out.InhibitPolicyMapping == 0 + } + case 37: + out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value) + if err != nil { + return err + } + case 14: // RFC 5280, 4.2.1.2 + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return errors.New("x509: subject key identifier incorrectly marked critical") + } + val := cryptobyte.String(e.Value) + var skid cryptobyte.String + if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) { + return errors.New("x509: invalid subject key identifier") + } + out.SubjectKeyId = skid + case 32: + out.Policies, err = parseCertificatePoliciesExtension(e.Value) + if err != nil { + return err + } + out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, 0, len(out.Policies)) + for _, oid := range out.Policies { + if oid, ok := oid.toASN1OID(); ok { + out.PolicyIdentifiers = append(out.PolicyIdentifiers, oid) + } + } + case 33: + val := cryptobyte.String(e.Value) + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid policy mappings extension") + } + for !val.Empty() { + var s cryptobyte.String + var issuer, subject cryptobyte.String + if !val.ReadASN1(&s, cryptobyte_asn1.SEQUENCE) || + !s.ReadASN1(&issuer, cryptobyte_asn1.OBJECT_IDENTIFIER) || + !s.ReadASN1(&subject, cryptobyte_asn1.OBJECT_IDENTIFIER) { + return errors.New("x509: invalid policy mappings extension") + } + out.PolicyMappings = append(out.PolicyMappings, PolicyMapping{OID{issuer}, OID{subject}}) + } + case 54: + val := cryptobyte.String(e.Value) + if !val.ReadASN1Integer(&out.InhibitAnyPolicy) { + return errors.New("x509: invalid inhibit any policy extension") + } + out.InhibitAnyPolicyZero = out.InhibitAnyPolicy == 0 + default: + // Unknown extensions are recorded if critical. + unhandled = true + } + } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { + // RFC 5280 4.2.2.1: Authority Information Access + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return errors.New("x509: authority info access incorrectly marked critical") + } + val := cryptobyte.String(e.Value) + if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid authority info access") + } + for !val.Empty() { + var aiaDER cryptobyte.String + if !val.ReadASN1(&aiaDER, cryptobyte_asn1.SEQUENCE) { + return errors.New("x509: invalid authority info access") + } + var method asn1.ObjectIdentifier + if !aiaDER.ReadASN1ObjectIdentifier(&method) { + return errors.New("x509: invalid authority info access") + } + if !aiaDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { + continue + } + if !aiaDER.ReadASN1(&aiaDER, cryptobyte_asn1.Tag(6).ContextSpecific()) { + return errors.New("x509: invalid authority info access") + } + switch { + case method.Equal(oidAuthorityInfoAccessOcsp): + out.OCSPServer = append(out.OCSPServer, string(aiaDER)) + case method.Equal(oidAuthorityInfoAccessIssuers): + out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(aiaDER)) + } + } + } else { + // Unknown extensions are recorded if critical. + unhandled = true + } + + if e.Critical && unhandled { + out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) + } + } + + return nil +} + +var x509negativeserial = godebug.New("x509negativeserial") + +func parseCertificate(der []byte) (*Certificate, error) { + cert := &Certificate{} + + input := cryptobyte.String(der) + // we read the SEQUENCE including length and tag bytes so that + // we can populate Certificate.Raw, before unwrapping the + // SEQUENCE so it can be operated on + if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed certificate") + } + cert.Raw = input + if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed certificate") + } + + var tbs cryptobyte.String + // do the same trick again as above to extract the raw + // bytes for Certificate.RawTBSCertificate + if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs certificate") + } + cert.RawTBSCertificate = tbs + if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs certificate") + } + + if !tbs.ReadOptionalASN1Integer(&cert.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) { + return nil, errors.New("x509: malformed version") + } + if cert.Version < 0 { + return nil, errors.New("x509: malformed version") + } + // for backwards compat reasons Version is one-indexed, + // rather than zero-indexed as defined in 5280 + cert.Version++ + if cert.Version > 3 { + return nil, errors.New("x509: invalid version") + } + + serial := new(big.Int) + if !tbs.ReadASN1Integer(serial) { + return nil, errors.New("x509: malformed serial number") + } + if serial.Sign() == -1 { + if x509negativeserial.Value() != "1" { + return nil, errors.New("x509: negative serial number") + } else { + x509negativeserial.IncNonDefault() + } + } + cert.SerialNumber = serial + + var sigAISeq cryptobyte.String + if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed signature algorithm identifier") + } + // Before parsing the inner algorithm identifier, extract + // the outer algorithm identifier and make sure that they + // match. + var outerSigAISeq cryptobyte.String + if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed algorithm identifier") + } + if !bytes.Equal(outerSigAISeq, sigAISeq) { + return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") + } + sigAI, err := parseAI(sigAISeq) + if err != nil { + return nil, err + } + cert.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) + + var issuerSeq cryptobyte.String + if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed issuer") + } + cert.RawIssuer = issuerSeq + issuerRDNs, err := parseName(issuerSeq) + if err != nil { + return nil, err + } + cert.Issuer.FillFromRDNSequence(issuerRDNs) + + var validity cryptobyte.String + if !tbs.ReadASN1(&validity, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed validity") + } + cert.NotBefore, cert.NotAfter, err = parseValidity(validity) + if err != nil { + return nil, err + } + + var subjectSeq cryptobyte.String + if !tbs.ReadASN1Element(&subjectSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed issuer") + } + cert.RawSubject = subjectSeq + subjectRDNs, err := parseName(subjectSeq) + if err != nil { + return nil, err + } + cert.Subject.FillFromRDNSequence(subjectRDNs) + + var spki cryptobyte.String + if !tbs.ReadASN1Element(&spki, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed spki") + } + cert.RawSubjectPublicKeyInfo = spki + if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed spki") + } + var pkAISeq cryptobyte.String + if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed public key algorithm identifier") + } + pkAI, err := parseAI(pkAISeq) + if err != nil { + return nil, err + } + cert.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(pkAI.Algorithm) + var spk asn1.BitString + if !spki.ReadASN1BitString(&spk) { + return nil, errors.New("x509: malformed subjectPublicKey") + } + if cert.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { + cert.PublicKey, err = parsePublicKey(&publicKeyInfo{ + Algorithm: pkAI, + PublicKey: spk, + }) + if err != nil { + return nil, err + } + } + + if cert.Version > 1 { + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) { + return nil, errors.New("x509: malformed issuerUniqueID") + } + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) { + return nil, errors.New("x509: malformed subjectUniqueID") + } + if cert.Version == 3 { + var extensions cryptobyte.String + var present bool + if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) { + return nil, errors.New("x509: malformed extensions") + } + if present { + seenExts := make(map[string]bool) + if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extensions") + } + for !extensions.Empty() { + var extension cryptobyte.String + if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extension") + } + ext, err := parseExtension(extension) + if err != nil { + return nil, err + } + oidStr := ext.Id.String() + if seenExts[oidStr] { + return nil, fmt.Errorf("x509: certificate contains duplicate extension with OID %q", oidStr) + } + seenExts[oidStr] = true + cert.Extensions = append(cert.Extensions, ext) + } + err = processExtensions(cert) + if err != nil { + return nil, err + } + } + } + } + + var signature asn1.BitString + if !input.ReadASN1BitString(&signature) { + return nil, errors.New("x509: malformed signature") + } + cert.Signature = signature.RightAlign() + + return cert, nil +} + +// ParseCertificate parses a single certificate from the given ASN.1 DER data. +// +// Before Go 1.23, ParseCertificate accepted certificates with negative serial +// numbers. This behavior can be restored by including "x509negativeserial=1" in +// the GODEBUG environment variable. +func ParseCertificate(der []byte) (*Certificate, error) { + cert, err := parseCertificate(der) + if err != nil { + return nil, err + } + if len(der) != len(cert.Raw) { + return nil, errors.New("x509: trailing data") + } + return cert, nil +} + +// ParseCertificates parses one or more certificates from the given ASN.1 DER +// data. The certificates must be concatenated with no intermediate padding. +func ParseCertificates(der []byte) ([]*Certificate, error) { + var certs []*Certificate + for len(der) > 0 { + cert, err := parseCertificate(der) + if err != nil { + return nil, err + } + certs = append(certs, cert) + der = der[len(cert.Raw):] + } + return certs, nil +} + +// The X.509 standards confusingly 1-indexed the version names, but 0-indexed +// the actual encoded version, so the version for X.509v2 is 1. +const x509v2Version = 1 + +// ParseRevocationList parses a X509 v2 [Certificate] Revocation List from the given +// ASN.1 DER data. +func ParseRevocationList(der []byte) (*RevocationList, error) { + rl := &RevocationList{} + + input := cryptobyte.String(der) + // we read the SEQUENCE including length and tag bytes so that + // we can populate RevocationList.Raw, before unwrapping the + // SEQUENCE so it can be operated on + if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + rl.Raw = input + if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + + var tbs cryptobyte.String + // do the same trick again as above to extract the raw + // bytes for Certificate.RawTBSCertificate + if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs crl") + } + rl.RawTBSRevocationList = tbs + if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed tbs crl") + } + + var version int + if !tbs.PeekASN1Tag(cryptobyte_asn1.INTEGER) { + return nil, errors.New("x509: unsupported crl version") + } + if !tbs.ReadASN1Integer(&version) { + return nil, errors.New("x509: malformed crl") + } + if version != x509v2Version { + return nil, fmt.Errorf("x509: unsupported crl version: %d", version) + } + + var sigAISeq cryptobyte.String + if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed signature algorithm identifier") + } + // Before parsing the inner algorithm identifier, extract + // the outer algorithm identifier and make sure that they + // match. + var outerSigAISeq cryptobyte.String + if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed algorithm identifier") + } + if !bytes.Equal(outerSigAISeq, sigAISeq) { + return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") + } + sigAI, err := parseAI(sigAISeq) + if err != nil { + return nil, err + } + rl.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) + + var signature asn1.BitString + if !input.ReadASN1BitString(&signature) { + return nil, errors.New("x509: malformed signature") + } + rl.Signature = signature.RightAlign() + + var issuerSeq cryptobyte.String + if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed issuer") + } + rl.RawIssuer = issuerSeq + issuerRDNs, err := parseName(issuerSeq) + if err != nil { + return nil, err + } + rl.Issuer.FillFromRDNSequence(issuerRDNs) + + rl.ThisUpdate, err = parseTime(&tbs) + if err != nil { + return nil, err + } + if tbs.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime) || tbs.PeekASN1Tag(cryptobyte_asn1.UTCTime) { + rl.NextUpdate, err = parseTime(&tbs) + if err != nil { + return nil, err + } + } + + if tbs.PeekASN1Tag(cryptobyte_asn1.SEQUENCE) { + var revokedSeq cryptobyte.String + if !tbs.ReadASN1(&revokedSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + for !revokedSeq.Empty() { + rce := RevocationListEntry{} + + var certSeq cryptobyte.String + if !revokedSeq.ReadASN1Element(&certSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + rce.Raw = certSeq + if !certSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + + rce.SerialNumber = new(big.Int) + if !certSeq.ReadASN1Integer(rce.SerialNumber) { + return nil, errors.New("x509: malformed serial number") + } + rce.RevocationTime, err = parseTime(&certSeq) + if err != nil { + return nil, err + } + var extensions cryptobyte.String + var present bool + if !certSeq.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extensions") + } + if present { + for !extensions.Empty() { + var extension cryptobyte.String + if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extension") + } + ext, err := parseExtension(extension) + if err != nil { + return nil, err + } + if ext.Id.Equal(oidExtensionReasonCode) { + val := cryptobyte.String(ext.Value) + if !val.ReadASN1Enum(&rce.ReasonCode) { + return nil, fmt.Errorf("x509: malformed reasonCode extension") + } + } + rce.Extensions = append(rce.Extensions, ext) + } + } + + rl.RevokedCertificateEntries = append(rl.RevokedCertificateEntries, rce) + rcDeprecated := pkix.RevokedCertificate{ + SerialNumber: rce.SerialNumber, + RevocationTime: rce.RevocationTime, + Extensions: rce.Extensions, + } + rl.RevokedCertificates = append(rl.RevokedCertificates, rcDeprecated) + } + } + + var extensions cryptobyte.String + var present bool + if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { + return nil, errors.New("x509: malformed extensions") + } + if present { + if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extensions") + } + for !extensions.Empty() { + var extension cryptobyte.String + if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed extension") + } + ext, err := parseExtension(extension) + if err != nil { + return nil, err + } + if ext.Id.Equal(oidExtensionAuthorityKeyId) { + rl.AuthorityKeyId, err = parseAuthorityKeyIdentifier(ext) + if err != nil { + return nil, err + } + } else if ext.Id.Equal(oidExtensionCRLNumber) { + value := cryptobyte.String(ext.Value) + rl.Number = new(big.Int) + if !value.ReadASN1Integer(rl.Number) { + return nil, errors.New("x509: malformed crl number") + } + } + rl.Extensions = append(rl.Extensions, ext) + } + } + + return rl, nil +} diff --git a/ca/x509pq/pkcs1.go b/ca/x509pq/pkcs1.go new file mode 100644 index 00000000..68aa8dd9 --- /dev/null +++ b/ca/x509pq/pkcs1.go @@ -0,0 +1,202 @@ +// Copyright 2011 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 x509 + +import ( + "crypto/rsa" + "encoding/asn1" + "errors" + "internal/godebug" + "math/big" +) + +// pkcs1PrivateKey is a structure which mirrors the PKCS #1 ASN.1 for an RSA private key. +type pkcs1PrivateKey struct { + Version int + N *big.Int + E int + D *big.Int + P *big.Int + Q *big.Int + Dp *big.Int `asn1:"optional"` + Dq *big.Int `asn1:"optional"` + Qinv *big.Int `asn1:"optional"` + + AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"` +} + +type pkcs1AdditionalRSAPrime struct { + Prime *big.Int + + // We ignore these values because rsa will calculate them. + Exp *big.Int + Coeff *big.Int +} + +// pkcs1PublicKey reflects the ASN.1 structure of a PKCS #1 public key. +type pkcs1PublicKey struct { + N *big.Int + E int +} + +// x509rsacrt, if zero, makes ParsePKCS1PrivateKey ignore and recompute invalid +// CRT values in the RSA private key. +var x509rsacrt = godebug.New("x509rsacrt") + +// ParsePKCS1PrivateKey parses an [RSA] private key in PKCS #1, ASN.1 DER form. +// +// This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY". +// +// Before Go 1.24, the CRT parameters were ignored and recomputed. To restore +// the old behavior, use the GODEBUG=x509rsacrt=0 environment variable. +func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) { + var priv pkcs1PrivateKey + rest, err := asn1.Unmarshal(der, &priv) + if len(rest) > 0 { + return nil, asn1.SyntaxError{Msg: "trailing data"} + } + if err != nil { + if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil { + return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)") + } + if _, err := asn1.Unmarshal(der, &pkcs8{}); err == nil { + return nil, errors.New("x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)") + } + return nil, err + } + + if priv.Version > 1 { + return nil, errors.New("x509: unsupported private key version") + } + + if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 || + priv.Dp != nil && priv.Dp.Sign() <= 0 || + priv.Dq != nil && priv.Dq.Sign() <= 0 || + priv.Qinv != nil && priv.Qinv.Sign() <= 0 { + return nil, errors.New("x509: private key contains zero or negative value") + } + + key := new(rsa.PrivateKey) + key.PublicKey = rsa.PublicKey{ + E: priv.E, + N: priv.N, + } + + key.D = priv.D + key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes)) + key.Primes[0] = priv.P + key.Primes[1] = priv.Q + key.Precomputed.Dp = priv.Dp + key.Precomputed.Dq = priv.Dq + key.Precomputed.Qinv = priv.Qinv + for i, a := range priv.AdditionalPrimes { + if a.Prime.Sign() <= 0 { + return nil, errors.New("x509: private key contains zero or negative prime") + } + key.Primes[i+2] = a.Prime + // We ignore the other two values because rsa will calculate + // them as needed. + } + + key.Precompute() + if err := key.Validate(); err != nil { + // If x509rsacrt=0 is set, try dropping the CRT values and + // rerunning precomputation and key validation. + if x509rsacrt.Value() == "0" { + key.Precomputed.Dp = nil + key.Precomputed.Dq = nil + key.Precomputed.Qinv = nil + key.Precompute() + if err := key.Validate(); err == nil { + x509rsacrt.IncNonDefault() + return key, nil + } + } + + return nil, err + } + + return key, nil +} + +// MarshalPKCS1PrivateKey converts an [RSA] private key to PKCS #1, ASN.1 DER form. +// +// This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY". +// For a more flexible key format which is not [RSA] specific, use +// [MarshalPKCS8PrivateKey]. +// +// The key must have passed validation by calling [rsa.PrivateKey.Validate] +// first. MarshalPKCS1PrivateKey calls [rsa.PrivateKey.Precompute], which may +// modify the key if not already precomputed. +func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { + key.Precompute() + + version := 0 + if len(key.Primes) > 2 { + version = 1 + } + + priv := pkcs1PrivateKey{ + Version: version, + N: key.N, + E: key.PublicKey.E, + D: key.D, + P: key.Primes[0], + Q: key.Primes[1], + Dp: key.Precomputed.Dp, + Dq: key.Precomputed.Dq, + Qinv: key.Precomputed.Qinv, + } + + priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues)) + for i, values := range key.Precomputed.CRTValues { + priv.AdditionalPrimes[i].Prime = key.Primes[2+i] + priv.AdditionalPrimes[i].Exp = values.Exp + priv.AdditionalPrimes[i].Coeff = values.Coeff + } + + b, _ := asn1.Marshal(priv) + return b +} + +// ParsePKCS1PublicKey parses an [RSA] public key in PKCS #1, ASN.1 DER form. +// +// This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY". +func ParsePKCS1PublicKey(der []byte) (*rsa.PublicKey, error) { + var pub pkcs1PublicKey + rest, err := asn1.Unmarshal(der, &pub) + if err != nil { + if _, err := asn1.Unmarshal(der, &publicKeyInfo{}); err == nil { + return nil, errors.New("x509: failed to parse public key (use ParsePKIXPublicKey instead for this key format)") + } + return nil, err + } + if len(rest) > 0 { + return nil, asn1.SyntaxError{Msg: "trailing data"} + } + + if pub.N.Sign() <= 0 || pub.E <= 0 { + return nil, errors.New("x509: public key contains zero or negative value") + } + if pub.E > 1<<31-1 { + return nil, errors.New("x509: public key contains large public exponent") + } + + return &rsa.PublicKey{ + E: pub.E, + N: pub.N, + }, nil +} + +// MarshalPKCS1PublicKey converts an [RSA] public key to PKCS #1, ASN.1 DER form. +// +// This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY". +func MarshalPKCS1PublicKey(key *rsa.PublicKey) []byte { + derBytes, _ := asn1.Marshal(pkcs1PublicKey{ + N: key.N, + E: key.E, + }) + return derBytes +} diff --git a/ca/x509pq/verify.go b/ca/x509pq/verify.go new file mode 100644 index 00000000..7cc0fb2e --- /dev/null +++ b/ca/x509pq/verify.go @@ -0,0 +1,1620 @@ +// Copyright 2011 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 x509 + +import ( + "bytes" + "crypto" + "crypto/x509/pkix" + "errors" + "fmt" + "iter" + "maps" + "net" + "net/netip" + "net/url" + "reflect" + "runtime" + "strings" + "time" + "unicode/utf8" +) + +type InvalidReason int + +const ( + // NotAuthorizedToSign results when a certificate is signed by another + // which isn't marked as a CA certificate. + NotAuthorizedToSign InvalidReason = iota + // Expired results when a certificate has expired, based on the time + // given in the VerifyOptions. + Expired + // CANotAuthorizedForThisName results when an intermediate or root + // certificate has a name constraint which doesn't permit a DNS or + // other name (including IP address) in the leaf certificate. + CANotAuthorizedForThisName + // TooManyIntermediates results when a path length constraint is + // violated. + TooManyIntermediates + // IncompatibleUsage results when the certificate's key usage indicates + // that it may only be used for a different purpose. + IncompatibleUsage + // NameMismatch results when the subject name of a parent certificate + // does not match the issuer name in the child. + NameMismatch + // NameConstraintsWithoutSANs is a legacy error and is no longer returned. + NameConstraintsWithoutSANs + // UnconstrainedName results when a CA certificate contains permitted + // name constraints, but leaf certificate contains a name of an + // unsupported or unconstrained type. + UnconstrainedName + // TooManyConstraints results when the number of comparison operations + // needed to check a certificate exceeds the limit set by + // VerifyOptions.MaxConstraintComparisions. This limit exists to + // prevent pathological certificates can consuming excessive amounts of + // CPU time to verify. + TooManyConstraints + // CANotAuthorizedForExtKeyUsage results when an intermediate or root + // certificate does not permit a requested extended key usage. + CANotAuthorizedForExtKeyUsage + // NoValidChains results when there are no valid chains to return. + NoValidChains +) + +// CertificateInvalidError results when an odd error occurs. Users of this +// library probably want to handle all these errors uniformly. +type CertificateInvalidError struct { + Cert *Certificate + Reason InvalidReason + Detail string +} + +func (e CertificateInvalidError) Error() string { + switch e.Reason { + case NotAuthorizedToSign: + return "x509: certificate is not authorized to sign other certificates" + case Expired: + return "x509: certificate has expired or is not yet valid: " + e.Detail + case CANotAuthorizedForThisName: + return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail + case CANotAuthorizedForExtKeyUsage: + return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail + case TooManyIntermediates: + return "x509: too many intermediates for path length constraint" + case IncompatibleUsage: + return "x509: certificate specifies an incompatible key usage" + case NameMismatch: + return "x509: issuer name does not match subject from issuing certificate" + case NameConstraintsWithoutSANs: + return "x509: issuer has name constraints but leaf doesn't have a SAN extension" + case UnconstrainedName: + return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail + case NoValidChains: + s := "x509: no valid chains built" + if e.Detail != "" { + s = fmt.Sprintf("%s: %s", s, e.Detail) + } + return s + } + return "x509: unknown error" +} + +// HostnameError results when the set of authorized names doesn't match the +// requested name. +type HostnameError struct { + Certificate *Certificate + Host string +} + +func (h HostnameError) Error() string { + c := h.Certificate + + if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) { + return "x509: certificate relies on legacy Common Name field, use SANs instead" + } + + var valid string + if ip := net.ParseIP(h.Host); ip != nil { + // Trying to validate an IP + if len(c.IPAddresses) == 0 { + return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" + } + for _, san := range c.IPAddresses { + if len(valid) > 0 { + valid += ", " + } + valid += san.String() + } + } else { + valid = strings.Join(c.DNSNames, ", ") + } + + if len(valid) == 0 { + return "x509: certificate is not valid for any names, but wanted to match " + h.Host + } + return "x509: certificate is valid for " + valid + ", not " + h.Host +} + +// UnknownAuthorityError results when the certificate issuer is unknown +type UnknownAuthorityError struct { + Cert *Certificate + // hintErr contains an error that may be helpful in determining why an + // authority wasn't found. + hintErr error + // hintCert contains a possible authority certificate that was rejected + // because of the error in hintErr. + hintCert *Certificate +} + +func (e UnknownAuthorityError) Error() string { + s := "x509: certificate signed by unknown authority" + if e.hintErr != nil { + certName := e.hintCert.Subject.CommonName + if len(certName) == 0 { + if len(e.hintCert.Subject.Organization) > 0 { + certName = e.hintCert.Subject.Organization[0] + } else { + certName = "serial:" + e.hintCert.SerialNumber.String() + } + } + s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName) + } + return s +} + +// SystemRootsError results when we fail to load the system root certificates. +type SystemRootsError struct { + Err error +} + +func (se SystemRootsError) Error() string { + msg := "x509: failed to load system roots and no roots provided" + if se.Err != nil { + return msg + "; " + se.Err.Error() + } + return msg +} + +func (se SystemRootsError) Unwrap() error { return se.Err } + +// errNotParsed is returned when a certificate without ASN.1 contents is +// verified. Platform-specific verification needs the ASN.1 contents. +var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate") + +// VerifyOptions contains parameters for Certificate.Verify. +type VerifyOptions struct { + // DNSName, if set, is checked against the leaf certificate with + // Certificate.VerifyHostname or the platform verifier. + DNSName string + + // Intermediates is an optional pool of certificates that are not trust + // anchors, but can be used to form a chain from the leaf certificate to a + // root certificate. + Intermediates *CertPool + // Roots is the set of trusted root certificates the leaf certificate needs + // to chain up to. If nil, the system roots or the platform verifier are used. + Roots *CertPool + + // CurrentTime is used to check the validity of all certificates in the + // chain. If zero, the current time is used. + CurrentTime time.Time + + // KeyUsages specifies which Extended Key Usage values are acceptable. A + // chain is accepted if it allows any of the listed values. An empty list + // means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny. + KeyUsages []ExtKeyUsage + + // MaxConstraintComparisions is the maximum number of comparisons to + // perform when checking a given certificate's name constraints. If + // zero, a sensible default is used. This limit prevents pathological + // certificates from consuming excessive amounts of CPU time when + // validating. It does not apply to the platform verifier. + MaxConstraintComparisions int + + // CertificatePolicies specifies which certificate policy OIDs are + // acceptable during policy validation. An empty CertificatePolices + // field implies any valid policy is acceptable. + CertificatePolicies []OID + + // The following policy fields are unexported, because we do not expect + // users to actually need to use them, but are useful for testing the + // policy validation code. + + // inhibitPolicyMapping indicates if policy mapping should be allowed + // during path validation. + inhibitPolicyMapping bool + + // requireExplicitPolicy indidicates if explicit policies must be present + // for each certificate being validated. + requireExplicitPolicy bool + + // inhibitAnyPolicy indicates if the anyPolicy policy should be + // processed if present in a certificate being validated. + inhibitAnyPolicy bool +} + +const ( + leafCertificate = iota + intermediateCertificate + rootCertificate +) + +// rfc2821Mailbox represents a “mailbox” (which is an email address to most +// people) by breaking it into the “local” (i.e. before the '@') and “domain” +// parts. +type rfc2821Mailbox struct { + local, domain string +} + +// parseRFC2821Mailbox parses an email address into local and domain parts, +// based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280, +// Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The +// format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”. +func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) { + if len(in) == 0 { + return mailbox, false + } + + localPartBytes := make([]byte, 0, len(in)/2) + + if in[0] == '"' { + // Quoted-string = DQUOTE *qcontent DQUOTE + // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 + // qcontent = qtext / quoted-pair + // qtext = non-whitespace-control / + // %d33 / %d35-91 / %d93-126 + // quoted-pair = ("\" text) / obs-qp + // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text + // + // (Names beginning with “obs-” are the obsolete syntax from RFC 2822, + // Section 4. Since it has been 16 years, we no longer accept that.) + in = in[1:] + QuotedString: + for { + if len(in) == 0 { + return mailbox, false + } + c := in[0] + in = in[1:] + + switch { + case c == '"': + break QuotedString + + case c == '\\': + // quoted-pair + if len(in) == 0 { + return mailbox, false + } + if in[0] == 11 || + in[0] == 12 || + (1 <= in[0] && in[0] <= 9) || + (14 <= in[0] && in[0] <= 127) { + localPartBytes = append(localPartBytes, in[0]) + in = in[1:] + } else { + return mailbox, false + } + + case c == 11 || + c == 12 || + // Space (char 32) is not allowed based on the + // BNF, but RFC 3696 gives an example that + // assumes that it is. Several “verified” + // errata continue to argue about this point. + // We choose to accept it. + c == 32 || + c == 33 || + c == 127 || + (1 <= c && c <= 8) || + (14 <= c && c <= 31) || + (35 <= c && c <= 91) || + (93 <= c && c <= 126): + // qtext + localPartBytes = append(localPartBytes, c) + + default: + return mailbox, false + } + } + } else { + // Atom ("." Atom)* + NextChar: + for len(in) > 0 { + // atext from RFC 2822, Section 3.2.4 + c := in[0] + + switch { + case c == '\\': + // Examples given in RFC 3696 suggest that + // escaped characters can appear outside of a + // quoted string. Several “verified” errata + // continue to argue the point. We choose to + // accept it. + in = in[1:] + if len(in) == 0 { + return mailbox, false + } + fallthrough + + case ('0' <= c && c <= '9') || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + c == '!' || c == '#' || c == '$' || c == '%' || + c == '&' || c == '\'' || c == '*' || c == '+' || + c == '-' || c == '/' || c == '=' || c == '?' || + c == '^' || c == '_' || c == '`' || c == '{' || + c == '|' || c == '}' || c == '~' || c == '.': + localPartBytes = append(localPartBytes, in[0]) + in = in[1:] + + default: + break NextChar + } + } + + if len(localPartBytes) == 0 { + return mailbox, false + } + + // From RFC 3696, Section 3: + // “period (".") may also appear, but may not be used to start + // or end the local part, nor may two or more consecutive + // periods appear.” + twoDots := []byte{'.', '.'} + if localPartBytes[0] == '.' || + localPartBytes[len(localPartBytes)-1] == '.' || + bytes.Contains(localPartBytes, twoDots) { + return mailbox, false + } + } + + if len(in) == 0 || in[0] != '@' { + return mailbox, false + } + in = in[1:] + + // The RFC species a format for domains, but that's known to be + // violated in practice so we accept that anything after an '@' is the + // domain part. + if _, ok := domainToReverseLabels(in); !ok { + return mailbox, false + } + + mailbox.local = string(localPartBytes) + mailbox.domain = in + return mailbox, true +} + +// domainToReverseLabels converts a textual domain name like foo.example.com to +// the list of labels in reverse order, e.g. ["com", "example", "foo"]. +func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { + for len(domain) > 0 { + if i := strings.LastIndexByte(domain, '.'); i == -1 { + reverseLabels = append(reverseLabels, domain) + domain = "" + } else { + reverseLabels = append(reverseLabels, domain[i+1:]) + domain = domain[:i] + if i == 0 { // domain == "" + // domain is prefixed with an empty label, append an empty + // string to reverseLabels to indicate this. + reverseLabels = append(reverseLabels, "") + } + } + } + + if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 { + // An empty label at the end indicates an absolute value. + return nil, false + } + + for _, label := range reverseLabels { + if len(label) == 0 { + // Empty labels are otherwise invalid. + return nil, false + } + + for _, c := range label { + if c < 33 || c > 126 { + // Invalid character. + return nil, false + } + } + } + + return reverseLabels, true +} + +func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) { + // If the constraint contains an @, then it specifies an exact mailbox + // name. + if strings.Contains(constraint, "@") { + constraintMailbox, ok := parseRFC2821Mailbox(constraint) + if !ok { + return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint) + } + return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil + } + + // Otherwise the constraint is like a DNS constraint of the domain part + // of the mailbox. + return matchDomainConstraint(mailbox.domain, constraint) +} + +func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { + // From RFC 5280, Section 4.2.1.10: + // “a uniformResourceIdentifier that does not include an authority + // component with a host name specified as a fully qualified domain + // name (e.g., if the URI either does not include an authority + // component or includes an authority component in which the host name + // is specified as an IP address), then the application MUST reject the + // certificate.” + + host := uri.Host + if len(host) == 0 { + return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String()) + } + + if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") { + var err error + host, _, err = net.SplitHostPort(uri.Host) + if err != nil { + return false, err + } + } + + // netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we + // check if _either_ the string parses as an IP, or if it is enclosed in + // square brackets. + if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) { + return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) + } + + return matchDomainConstraint(host, constraint) +} + +func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { + if len(ip) != len(constraint.IP) { + return false, nil + } + + for i := range ip { + if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask { + return false, nil + } + } + + return true, nil +} + +func matchDomainConstraint(domain, constraint string) (bool, error) { + // The meaning of zero length constraints is not specified, but this + // code follows NSS and accepts them as matching everything. + if len(constraint) == 0 { + return true, nil + } + + domainLabels, ok := domainToReverseLabels(domain) + if !ok { + return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) + } + + // RFC 5280 says that a leading period in a domain name means that at + // least one label must be prepended, but only for URI and email + // constraints, not DNS constraints. The code also supports that + // behaviour for DNS constraints. + + mustHaveSubdomains := false + if constraint[0] == '.' { + mustHaveSubdomains = true + constraint = constraint[1:] + } + + constraintLabels, ok := domainToReverseLabels(constraint) + if !ok { + return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) + } + + if len(domainLabels) < len(constraintLabels) || + (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) { + return false, nil + } + + for i, constraintLabel := range constraintLabels { + if !strings.EqualFold(constraintLabel, domainLabels[i]) { + return false, nil + } + } + + return true, nil +} + +// checkNameConstraints checks that c permits a child certificate to claim the +// given name, of type nameType. The argument parsedName contains the parsed +// form of name, suitable for passing to the match function. The total number +// of comparisons is tracked in the given count and should not exceed the given +// limit. +func (c *Certificate) checkNameConstraints(count *int, + maxConstraintComparisons int, + nameType string, + name string, + parsedName any, + match func(parsedName, constraint any) (match bool, err error), + permitted, excluded any) error { + + excludedValue := reflect.ValueOf(excluded) + + *count += excludedValue.Len() + if *count > maxConstraintComparisons { + return CertificateInvalidError{c, TooManyConstraints, ""} + } + + for i := 0; i < excludedValue.Len(); i++ { + constraint := excludedValue.Index(i).Interface() + match, err := match(parsedName, constraint) + if err != nil { + return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} + } + + if match { + return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)} + } + } + + permittedValue := reflect.ValueOf(permitted) + + *count += permittedValue.Len() + if *count > maxConstraintComparisons { + return CertificateInvalidError{c, TooManyConstraints, ""} + } + + ok := true + for i := 0; i < permittedValue.Len(); i++ { + constraint := permittedValue.Index(i).Interface() + + var err error + if ok, err = match(parsedName, constraint); err != nil { + return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} + } + + if ok { + break + } + } + + if !ok { + return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)} + } + + return nil +} + +// isValid performs validity checks on c given that it is a candidate to append +// to the chain in currentChain. +func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { + if len(c.UnhandledCriticalExtensions) > 0 { + return UnhandledCriticalExtension{} + } + + if len(currentChain) > 0 { + child := currentChain[len(currentChain)-1] + if !bytes.Equal(child.RawIssuer, c.RawSubject) { + return CertificateInvalidError{c, NameMismatch, ""} + } + } + + now := opts.CurrentTime + if now.IsZero() { + now = time.Now() + } + if now.Before(c.NotBefore) { + return CertificateInvalidError{ + Cert: c, + Reason: Expired, + Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)), + } + } else if now.After(c.NotAfter) { + return CertificateInvalidError{ + Cert: c, + Reason: Expired, + Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)), + } + } + + maxConstraintComparisons := opts.MaxConstraintComparisions + if maxConstraintComparisons == 0 { + maxConstraintComparisons = 250000 + } + comparisonCount := 0 + + if certType == intermediateCertificate || certType == rootCertificate { + if len(currentChain) == 0 { + return errors.New("x509: internal error: empty chain when appending CA cert") + } + } + + if (certType == intermediateCertificate || certType == rootCertificate) && + c.hasNameConstraints() { + toCheck := []*Certificate{} + for _, c := range currentChain { + if c.hasSANExtension() { + toCheck = append(toCheck, c) + } + } + for _, sanCert := range toCheck { + err := forEachSAN(sanCert.getSANExtension(), func(tag int, data []byte) error { + switch tag { + case nameTypeEmail: + name := string(data) + mailbox, ok := parseRFC2821Mailbox(name) + if !ok { + return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox) + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, + func(parsedName, constraint any) (bool, error) { + return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string)) + }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { + return err + } + + case nameTypeDNS: + name := string(data) + if _, ok := domainToReverseLabels(name); !ok { + return fmt.Errorf("x509: cannot parse dnsName %q", name) + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, + func(parsedName, constraint any) (bool, error) { + return matchDomainConstraint(parsedName.(string), constraint.(string)) + }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { + return err + } + + case nameTypeURI: + name := string(data) + uri, err := url.Parse(name) + if err != nil { + return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name) + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, + func(parsedName, constraint any) (bool, error) { + return matchURIConstraint(parsedName.(*url.URL), constraint.(string)) + }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { + return err + } + + case nameTypeIP: + ip := net.IP(data) + if l := len(ip); l != net.IPv4len && l != net.IPv6len { + return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data) + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip, + func(parsedName, constraint any) (bool, error) { + return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet)) + }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil { + return err + } + + default: + // Unknown SAN types are ignored. + } + + return nil + }) + + if err != nil { + return err + } + } + } + + // KeyUsage status flags are ignored. From Engineering Security, Peter + // Gutmann: A European government CA marked its signing certificates as + // being valid for encryption only, but no-one noticed. Another + // European CA marked its signature keys as not being valid for + // signatures. A different CA marked its own trusted root certificate + // as being invalid for certificate signing. Another national CA + // distributed a certificate to be used to encrypt data for the + // country’s tax authority that was marked as only being usable for + // digital signatures but not for encryption. Yet another CA reversed + // the order of the bit flags in the keyUsage due to confusion over + // encoding endianness, essentially setting a random keyUsage in + // certificates that it issued. Another CA created a self-invalidating + // certificate by adding a certificate policy statement stipulating + // that the certificate had to be used strictly as specified in the + // keyUsage, and a keyUsage containing a flag indicating that the RSA + // encryption key could only be used for Diffie-Hellman key agreement. + + if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) { + return CertificateInvalidError{c, NotAuthorizedToSign, ""} + } + + if c.BasicConstraintsValid && c.MaxPathLen >= 0 { + numIntermediates := len(currentChain) - 1 + if numIntermediates > c.MaxPathLen { + return CertificateInvalidError{c, TooManyIntermediates, ""} + } + } + + return nil +} + +// Verify attempts to verify c by building one or more chains from c to a +// certificate in opts.Roots, using certificates in opts.Intermediates if +// needed. If successful, it returns one or more chains where the first +// element of the chain is c and the last element is from opts.Roots. +// +// If opts.Roots is nil, the platform verifier might be used, and +// verification details might differ from what is described below. If system +// roots are unavailable the returned error will be of type SystemRootsError. +// +// Name constraints in the intermediates will be applied to all names claimed +// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim +// example.com if an intermediate doesn't permit it, even if example.com is not +// the name being validated. Note that DirectoryName constraints are not +// supported. +// +// Name constraint validation follows the rules from RFC 5280, with the +// addition that DNS name constraints may use the leading period format +// defined for emails and URIs. When a constraint has a leading period +// it indicates that at least one additional label must be prepended to +// the constrained name to be considered valid. +// +// Extended Key Usage values are enforced nested down a chain, so an intermediate +// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that +// list. (While this is not specified, it is common practice in order to limit +// the types of certificates a CA can issue.) +// +// Certificates that use SHA1WithRSA and ECDSAWithSHA1 signatures are not supported, +// and will not be used to build chains. +// +// Certificates other than c in the returned chains should not be modified. +// +// WARNING: this function doesn't do any revocation checking. +func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { + // Platform-specific verification needs the ASN.1 contents so + // this makes the behavior consistent across platforms. + if len(c.Raw) == 0 { + return nil, errNotParsed + } + for i := 0; i < opts.Intermediates.len(); i++ { + c, _, err := opts.Intermediates.cert(i) + if err != nil { + return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err) + } + if len(c.Raw) == 0 { + return nil, errNotParsed + } + } + + // Use platform verifiers, where available, if Roots is from SystemCertPool. + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" { + // Don't use the system verifier if the system pool was replaced with a non-system pool, + // i.e. if SetFallbackRoots was called with x509usefallbackroots=1. + systemPool := systemRootsPool() + if opts.Roots == nil && (systemPool == nil || systemPool.systemPool) { + return c.systemVerify(&opts) + } + if opts.Roots != nil && opts.Roots.systemPool { + platformChains, err := c.systemVerify(&opts) + // If the platform verifier succeeded, or there are no additional + // roots, return the platform verifier result. Otherwise, continue + // with the Go verifier. + if err == nil || opts.Roots.len() == 0 { + return platformChains, err + } + } + } + + if opts.Roots == nil { + opts.Roots = systemRootsPool() + if opts.Roots == nil { + return nil, SystemRootsError{systemRootsErr} + } + } + + err = c.isValid(leafCertificate, nil, &opts) + if err != nil { + return + } + + if len(opts.DNSName) > 0 { + err = c.VerifyHostname(opts.DNSName) + if err != nil { + return + } + } + + var candidateChains [][]*Certificate + if opts.Roots.contains(c) { + candidateChains = [][]*Certificate{{c}} + } else { + candidateChains, err = c.buildChains([]*Certificate{c}, nil, &opts) + if err != nil { + return nil, err + } + } + + chains = make([][]*Certificate, 0, len(candidateChains)) + + var invalidPoliciesChains int + for _, candidate := range candidateChains { + if !policiesValid(candidate, opts) { + invalidPoliciesChains++ + continue + } + chains = append(chains, candidate) + } + + if len(chains) == 0 { + return nil, CertificateInvalidError{c, NoValidChains, "all candidate chains have invalid policies"} + } + + for _, eku := range opts.KeyUsages { + if eku == ExtKeyUsageAny { + // If any key usage is acceptable, no need to check the chain for + // key usages. + return chains, nil + } + } + + if len(opts.KeyUsages) == 0 { + opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} + } + + candidateChains = chains + chains = chains[:0] + + var incompatibleKeyUsageChains int + for _, candidate := range candidateChains { + if !checkChainForKeyUsage(candidate, opts.KeyUsages) { + incompatibleKeyUsageChains++ + continue + } + chains = append(chains, candidate) + } + + if len(chains) == 0 { + var details []string + if incompatibleKeyUsageChains > 0 { + if invalidPoliciesChains == 0 { + return nil, CertificateInvalidError{c, IncompatibleUsage, ""} + } + details = append(details, fmt.Sprintf("%d chains with incompatible key usage", incompatibleKeyUsageChains)) + } + if invalidPoliciesChains > 0 { + details = append(details, fmt.Sprintf("%d chains with invalid policies", invalidPoliciesChains)) + } + err = CertificateInvalidError{c, NoValidChains, strings.Join(details, ", ")} + return nil, err + } + + return chains, nil +} + +func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { + n := make([]*Certificate, len(chain)+1) + copy(n, chain) + n[len(chain)] = cert + 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 +// for failed checks due to different intermediates having the same Subject. +const maxChainSignatureChecks = 100 + +func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) { + var ( + hintErr error + hintCert *Certificate + ) + + considerCandidate := func(certType int, candidate potentialParent) { + if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) { + return + } + + if sigChecks == nil { + sigChecks = new(int) + } + *sigChecks++ + if *sigChecks > maxChainSignatureChecks { + err = errors.New("x509: signature check attempts limit reached while verifying certificate chain") + return + } + + if err := c.CheckSignatureFrom(candidate.cert); err != nil { + if hintErr == nil { + hintErr = err + hintCert = candidate.cert + } + return + } + + err = candidate.cert.isValid(certType, currentChain, opts) + if err != nil { + if hintErr == nil { + hintErr = err + hintCert = candidate.cert + } + return + } + + if candidate.constraint != nil { + if err := candidate.constraint(currentChain); err != nil { + if hintErr == nil { + hintErr = err + hintCert = candidate.cert + } + return + } + } + + switch certType { + case rootCertificate: + chains = append(chains, appendToFreshChain(currentChain, candidate.cert)) + case intermediateCertificate: + var childChains [][]*Certificate + childChains, err = candidate.cert.buildChains(appendToFreshChain(currentChain, candidate.cert), sigChecks, opts) + chains = append(chains, childChains...) + } + } + + for _, root := range opts.Roots.findPotentialParents(c) { + considerCandidate(rootCertificate, root) + } + for _, intermediate := range opts.Intermediates.findPotentialParents(c) { + considerCandidate(intermediateCertificate, intermediate) + } + + if len(chains) > 0 { + err = nil + } + if len(chains) == 0 && err == nil { + err = UnknownAuthorityError{c, hintErr, hintCert} + } + + return +} + +func validHostnamePattern(host string) bool { return validHostname(host, true) } +func validHostnameInput(host string) bool { return validHostname(host, false) } + +// validHostname reports whether host is a valid hostname that can be matched or +// matched against according to RFC 6125 2.2, with some leniency to accommodate +// legacy values. +func validHostname(host string, isPattern bool) bool { + if !isPattern { + host = strings.TrimSuffix(host, ".") + } + if len(host) == 0 { + return false + } + if host == "*" { + // Bare wildcards are not allowed, they are not valid DNS names, + // nor are they allowed per RFC 6125. + return false + } + + for i, part := range strings.Split(host, ".") { + if part == "" { + // Empty label. + return false + } + if isPattern && i == 0 && part == "*" { + // Only allow full left-most wildcards, as those are the only ones + // we match, and matching literal '*' characters is probably never + // the expected behavior. + continue + } + for j, c := range part { + if 'a' <= c && c <= 'z' { + continue + } + if '0' <= c && c <= '9' { + continue + } + if 'A' <= c && c <= 'Z' { + continue + } + if c == '-' && j != 0 { + continue + } + if c == '_' { + // Not a valid character in hostnames, but commonly + // found in deployments outside the WebPKI. + continue + } + return false + } + } + + return true +} + +func matchExactly(hostA, hostB string) bool { + if hostA == "" || hostA == "." || hostB == "" || hostB == "." { + return false + } + return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB) +} + +func matchHostnames(pattern, host string) bool { + pattern = toLowerCaseASCII(pattern) + host = toLowerCaseASCII(strings.TrimSuffix(host, ".")) + + if len(pattern) == 0 || len(host) == 0 { + return false + } + + patternParts := strings.Split(pattern, ".") + hostParts := strings.Split(host, ".") + + if len(patternParts) != len(hostParts) { + return false + } + + for i, patternPart := range patternParts { + if i == 0 && patternPart == "*" { + continue + } + if patternPart != hostParts[i] { + return false + } + } + + return true +} + +// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use +// an explicitly ASCII function to avoid any sharp corners resulting from +// performing Unicode operations on DNS labels. +func toLowerCaseASCII(in string) string { + // If the string is already lower-case then there's nothing to do. + isAlreadyLowerCase := true + for _, c := range in { + if c == utf8.RuneError { + // If we get a UTF-8 error then there might be + // upper-case ASCII bytes in the invalid sequence. + isAlreadyLowerCase = false + break + } + if 'A' <= c && c <= 'Z' { + isAlreadyLowerCase = false + break + } + } + + if isAlreadyLowerCase { + return in + } + + out := []byte(in) + for i, c := range out { + if 'A' <= c && c <= 'Z' { + out[i] += 'a' - 'A' + } + } + return string(out) +} + +// VerifyHostname returns nil if c is a valid certificate for the named host. +// Otherwise it returns an error describing the mismatch. +// +// IP addresses can be optionally enclosed in square brackets and are checked +// against the IPAddresses field. Other names are checked case insensitively +// against the DNSNames field. If the names are valid hostnames, the certificate +// fields can have a wildcard as the complete left-most label (e.g. *.example.com). +// +// Note that the legacy Common Name field is ignored. +func (c *Certificate) VerifyHostname(h string) error { + // IP addresses may be written in [ ]. + candidateIP := h + if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { + candidateIP = h[1 : len(h)-1] + } + if ip := net.ParseIP(candidateIP); ip != nil { + // We only match IP addresses against IP SANs. + // See RFC 6125, Appendix B.2. + for _, candidate := range c.IPAddresses { + if ip.Equal(candidate) { + return nil + } + } + return HostnameError{c, candidateIP} + } + + candidateName := toLowerCaseASCII(h) // Save allocations inside the loop. + validCandidateName := validHostnameInput(candidateName) + + for _, match := range c.DNSNames { + // Ideally, we'd only match valid hostnames according to RFC 6125 like + // browsers (more or less) do, but in practice Go is used in a wider + // array of contexts and can't even assume DNS resolution. Instead, + // always allow perfect matches, and only apply wildcard and trailing + // dot processing to valid hostnames. + if validCandidateName && validHostnamePattern(match) { + if matchHostnames(match, candidateName) { + return nil + } + } else { + if matchExactly(match, candidateName) { + return nil + } + } + } + + return HostnameError{c, h} +} + +func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { + usages := make([]ExtKeyUsage, len(keyUsages)) + copy(usages, keyUsages) + + if len(chain) == 0 { + return false + } + + usagesRemaining := len(usages) + + // We walk down the list and cross out any usages that aren't supported + // by each certificate. If we cross out all the usages, then the chain + // is unacceptable. + +NextCert: + for i := len(chain) - 1; i >= 0; i-- { + cert := chain[i] + if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { + // The certificate doesn't have any extended key usage specified. + continue + } + + for _, usage := range cert.ExtKeyUsage { + if usage == ExtKeyUsageAny { + // The certificate is explicitly good for any usage. + continue NextCert + } + } + + const invalidUsage ExtKeyUsage = -1 + + NextRequestedUsage: + for i, requestedUsage := range usages { + if requestedUsage == invalidUsage { + continue + } + + for _, usage := range cert.ExtKeyUsage { + if requestedUsage == usage { + continue NextRequestedUsage + } + } + + usages[i] = invalidUsage + usagesRemaining-- + if usagesRemaining == 0 { + return false + } + } + } + + return true +} + +func mustNewOIDFromInts(ints []uint64) OID { + oid, err := OIDFromInts(ints) + if err != nil { + panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err)) + } + return oid +} + +type policyGraphNode struct { + validPolicy OID + expectedPolicySet []OID + // we do not implement qualifiers, so we don't track qualifier_set + + parents map[*policyGraphNode]bool + children map[*policyGraphNode]bool +} + +func newPolicyGraphNode(valid OID, parents []*policyGraphNode) *policyGraphNode { + n := &policyGraphNode{ + validPolicy: valid, + expectedPolicySet: []OID{valid}, + children: map[*policyGraphNode]bool{}, + parents: map[*policyGraphNode]bool{}, + } + for _, p := range parents { + p.children[n] = true + n.parents[p] = true + } + return n +} + +type policyGraph struct { + strata []map[string]*policyGraphNode + // map of OID -> nodes at strata[depth-1] with OID in their expectedPolicySet + parentIndex map[string][]*policyGraphNode + depth int +} + +var anyPolicyOID = mustNewOIDFromInts([]uint64{2, 5, 29, 32, 0}) + +func newPolicyGraph() *policyGraph { + root := policyGraphNode{ + validPolicy: anyPolicyOID, + expectedPolicySet: []OID{anyPolicyOID}, + children: map[*policyGraphNode]bool{}, + parents: map[*policyGraphNode]bool{}, + } + return &policyGraph{ + depth: 0, + strata: []map[string]*policyGraphNode{{string(anyPolicyOID.der): &root}}, + } +} + +func (pg *policyGraph) insert(n *policyGraphNode) { + pg.strata[pg.depth][string(n.validPolicy.der)] = n +} + +func (pg *policyGraph) parentsWithExpected(expected OID) []*policyGraphNode { + if pg.depth == 0 { + return nil + } + return pg.parentIndex[string(expected.der)] +} + +func (pg *policyGraph) parentWithAnyPolicy() *policyGraphNode { + if pg.depth == 0 { + return nil + } + return pg.strata[pg.depth-1][string(anyPolicyOID.der)] +} + +func (pg *policyGraph) parents() iter.Seq[*policyGraphNode] { + if pg.depth == 0 { + return nil + } + return maps.Values(pg.strata[pg.depth-1]) +} + +func (pg *policyGraph) leaves() map[string]*policyGraphNode { + return pg.strata[pg.depth] +} + +func (pg *policyGraph) leafWithPolicy(policy OID) *policyGraphNode { + return pg.strata[pg.depth][string(policy.der)] +} + +func (pg *policyGraph) deleteLeaf(policy OID) { + n := pg.strata[pg.depth][string(policy.der)] + if n == nil { + return + } + for p := range n.parents { + delete(p.children, n) + } + for c := range n.children { + delete(c.parents, n) + } + delete(pg.strata[pg.depth], string(policy.der)) +} + +func (pg *policyGraph) validPolicyNodes() []*policyGraphNode { + var validNodes []*policyGraphNode + for i := pg.depth; i >= 0; i-- { + for _, n := range pg.strata[i] { + if n.validPolicy.Equal(anyPolicyOID) { + continue + } + + if len(n.parents) == 1 { + for p := range n.parents { + if p.validPolicy.Equal(anyPolicyOID) { + validNodes = append(validNodes, n) + } + } + } + } + } + return validNodes +} + +func (pg *policyGraph) prune() { + for i := pg.depth - 1; i > 0; i-- { + for _, n := range pg.strata[i] { + if len(n.children) == 0 { + for p := range n.parents { + delete(p.children, n) + } + delete(pg.strata[i], string(n.validPolicy.der)) + } + } + } +} + +func (pg *policyGraph) incrDepth() { + pg.parentIndex = map[string][]*policyGraphNode{} + for _, n := range pg.strata[pg.depth] { + for _, e := range n.expectedPolicySet { + pg.parentIndex[string(e.der)] = append(pg.parentIndex[string(e.der)], n) + } + } + + pg.depth++ + pg.strata = append(pg.strata, map[string]*policyGraphNode{}) +} + +func policiesValid(chain []*Certificate, opts VerifyOptions) bool { + // The following code implements the policy verification algorithm as + // specified in RFC 5280 and updated by RFC 9618. In particular the + // following sections are replaced by RFC 9618: + // * 6.1.2 (a) + // * 6.1.3 (d) + // * 6.1.3 (e) + // * 6.1.3 (f) + // * 6.1.4 (b) + // * 6.1.5 (g) + + if len(chain) == 1 { + return true + } + + // n is the length of the chain minus the trust anchor + n := len(chain) - 1 + + pg := newPolicyGraph() + var inhibitAnyPolicy, explicitPolicy, policyMapping int + if !opts.inhibitAnyPolicy { + inhibitAnyPolicy = n + 1 + } + if !opts.requireExplicitPolicy { + explicitPolicy = n + 1 + } + if !opts.inhibitPolicyMapping { + policyMapping = n + 1 + } + + initialUserPolicySet := map[string]bool{} + for _, p := range opts.CertificatePolicies { + initialUserPolicySet[string(p.der)] = true + } + // If the user does not pass any policies, we consider + // that equivalent to passing anyPolicyOID. + if len(initialUserPolicySet) == 0 { + initialUserPolicySet[string(anyPolicyOID.der)] = true + } + + for i := n - 1; i >= 0; i-- { + cert := chain[i] + + isSelfSigned := bytes.Equal(cert.RawIssuer, cert.RawSubject) + + // 6.1.3 (e) -- as updated by RFC 9618 + if len(cert.Policies) == 0 { + pg = nil + } + + // 6.1.3 (f) -- as updated by RFC 9618 + if explicitPolicy == 0 && pg == nil { + return false + } + + if pg != nil { + pg.incrDepth() + + policies := map[string]bool{} + + // 6.1.3 (d) (1) -- as updated by RFC 9618 + for _, policy := range cert.Policies { + policies[string(policy.der)] = true + + if policy.Equal(anyPolicyOID) { + continue + } + + // 6.1.3 (d) (1) (i) -- as updated by RFC 9618 + parents := pg.parentsWithExpected(policy) + if len(parents) == 0 { + // 6.1.3 (d) (1) (ii) -- as updated by RFC 9618 + if anyParent := pg.parentWithAnyPolicy(); anyParent != nil { + parents = []*policyGraphNode{anyParent} + } + } + if len(parents) > 0 { + pg.insert(newPolicyGraphNode(policy, parents)) + } + } + + // 6.1.3 (d) (2) -- as updated by RFC 9618 + // NOTE: in the check "n-i < n" our i is different from the i in the specification. + // In the specification chains go from the trust anchor to the leaf, whereas our + // chains go from the leaf to the trust anchor, so our i's our inverted. Our + // check here matches the check "i < n" in the specification. + if policies[string(anyPolicyOID.der)] && (inhibitAnyPolicy > 0 || (n-i < n && isSelfSigned)) { + missing := map[string][]*policyGraphNode{} + leaves := pg.leaves() + for p := range pg.parents() { + for _, expected := range p.expectedPolicySet { + if leaves[string(expected.der)] == nil { + missing[string(expected.der)] = append(missing[string(expected.der)], p) + } + } + } + + for oidStr, parents := range missing { + pg.insert(newPolicyGraphNode(OID{der: []byte(oidStr)}, parents)) + } + } + + // 6.1.3 (d) (3) -- as updated by RFC 9618 + pg.prune() + + if i != 0 { + // 6.1.4 (b) -- as updated by RFC 9618 + if len(cert.PolicyMappings) > 0 { + // collect map of issuer -> []subject + mappings := map[string][]OID{} + + for _, mapping := range cert.PolicyMappings { + if policyMapping > 0 { + if mapping.IssuerDomainPolicy.Equal(anyPolicyOID) || mapping.SubjectDomainPolicy.Equal(anyPolicyOID) { + // Invalid mapping + return false + } + mappings[string(mapping.IssuerDomainPolicy.der)] = append(mappings[string(mapping.IssuerDomainPolicy.der)], mapping.SubjectDomainPolicy) + } else { + // 6.1.4 (b) (3) (i) -- as updated by RFC 9618 + pg.deleteLeaf(mapping.IssuerDomainPolicy) + + // 6.1.4 (b) (3) (ii) -- as updated by RFC 9618 + pg.prune() + } + } + + for issuerStr, subjectPolicies := range mappings { + // 6.1.4 (b) (1) -- as updated by RFC 9618 + if matching := pg.leafWithPolicy(OID{der: []byte(issuerStr)}); matching != nil { + matching.expectedPolicySet = subjectPolicies + } else if matching := pg.leafWithPolicy(anyPolicyOID); matching != nil { + // 6.1.4 (b) (2) -- as updated by RFC 9618 + n := newPolicyGraphNode(OID{der: []byte(issuerStr)}, []*policyGraphNode{matching}) + n.expectedPolicySet = subjectPolicies + pg.insert(n) + } + } + } + } + } + + if i != 0 { + // 6.1.4 (h) + if !isSelfSigned { + if explicitPolicy > 0 { + explicitPolicy-- + } + if policyMapping > 0 { + policyMapping-- + } + if inhibitAnyPolicy > 0 { + inhibitAnyPolicy-- + } + } + + // 6.1.4 (i) + if (cert.RequireExplicitPolicy > 0 || cert.RequireExplicitPolicyZero) && cert.RequireExplicitPolicy < explicitPolicy { + explicitPolicy = cert.RequireExplicitPolicy + } + if (cert.InhibitPolicyMapping > 0 || cert.InhibitPolicyMappingZero) && cert.InhibitPolicyMapping < policyMapping { + policyMapping = cert.InhibitPolicyMapping + } + // 6.1.4 (j) + if (cert.InhibitAnyPolicy > 0 || cert.InhibitAnyPolicyZero) && cert.InhibitAnyPolicy < inhibitAnyPolicy { + inhibitAnyPolicy = cert.InhibitAnyPolicy + } + } + } + + // 6.1.5 (a) + if explicitPolicy > 0 { + explicitPolicy-- + } + + // 6.1.5 (b) + if chain[0].RequireExplicitPolicyZero { + explicitPolicy = 0 + } + + // 6.1.5 (g) (1) -- as updated by RFC 9618 + var validPolicyNodeSet []*policyGraphNode + // 6.1.5 (g) (2) -- as updated by RFC 9618 + if pg != nil { + validPolicyNodeSet = pg.validPolicyNodes() + // 6.1.5 (g) (3) -- as updated by RFC 9618 + if currentAny := pg.leafWithPolicy(anyPolicyOID); currentAny != nil { + validPolicyNodeSet = append(validPolicyNodeSet, currentAny) + } + } + + // 6.1.5 (g) (4) -- as updated by RFC 9618 + authorityConstrainedPolicySet := map[string]bool{} + for _, n := range validPolicyNodeSet { + authorityConstrainedPolicySet[string(n.validPolicy.der)] = true + } + // 6.1.5 (g) (5) -- as updated by RFC 9618 + userConstrainedPolicySet := maps.Clone(authorityConstrainedPolicySet) + // 6.1.5 (g) (6) -- as updated by RFC 9618 + if len(initialUserPolicySet) != 1 || !initialUserPolicySet[string(anyPolicyOID.der)] { + // 6.1.5 (g) (6) (i) -- as updated by RFC 9618 + for p := range userConstrainedPolicySet { + if !initialUserPolicySet[p] { + delete(userConstrainedPolicySet, p) + } + } + // 6.1.5 (g) (6) (ii) -- as updated by RFC 9618 + if authorityConstrainedPolicySet[string(anyPolicyOID.der)] { + for policy := range initialUserPolicySet { + userConstrainedPolicySet[policy] = true + } + } + } + + if explicitPolicy == 0 && len(userConstrainedPolicySet) == 0 { + return false + } + + return true +} diff --git a/ca/x509pq/x509.go b/ca/x509pq/x509.go new file mode 100644 index 00000000..88eaadb4 --- /dev/null +++ b/ca/x509pq/x509.go @@ -0,0 +1,2569 @@ +// Copyright 2009 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 x509 implements a subset of the X.509 standard. +// +// It allows parsing and generating certificates, certificate signing +// requests, certificate revocation lists, and encoded public and private keys. +// It provides a certificate verifier, complete with a chain builder. +// +// The package targets the X.509 technical profile defined by the IETF (RFC +// 2459/3280/5280), and as further restricted by the CA/Browser Forum Baseline +// Requirements. There is minimal support for features outside of these +// profiles, as the primary goal of the package is to provide compatibility +// with the publicly trusted TLS certificate ecosystem and its policies and +// constraints. +// +// On macOS and Windows, certificate verification is handled by system APIs, but +// the package aims to apply consistent validation rules across operating +// systems. +package x509 + +import ( + "bytes" + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/pem" + "errors" + "fmt" + "internal/godebug" + "io" + "math/big" + "net" + "net/url" + "strconv" + "time" + "unicode" + + // Explicitly import these for their crypto.RegisterHash init side-effects. + // Keep these as blank imports, even if they're imported above. + _ "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" + + "golang.org/x/crypto/cryptobyte" + cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" +) + +// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo +// in RFC 3280. +type pkixPublicKey struct { + Algo pkix.AlgorithmIdentifier + BitString asn1.BitString +} + +// ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form. The encoded +// public key is a SubjectPublicKeyInfo structure (see RFC 5280, Section 4.1). +// +// It returns a *[rsa.PublicKey], *[dsa.PublicKey], *[ecdsa.PublicKey], +// [ed25519.PublicKey] (not a pointer), or *[ecdh.PublicKey] (for X25519). +// More types might be supported in the future. +// +// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". +func ParsePKIXPublicKey(derBytes []byte) (pub any, err error) { + var pki publicKeyInfo + if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { + if _, err := asn1.Unmarshal(derBytes, &pkcs1PublicKey{}); err == nil { + return nil, errors.New("x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)") + } + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after ASN.1 of public-key") + } + return parsePublicKey(&pki) +} + +func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { + switch pub := pub.(type) { + case *rsa.PublicKey: + publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{ + N: pub.N, + E: pub.E, + }) + if err != nil { + return nil, pkix.AlgorithmIdentifier{}, err + } + publicKeyAlgorithm.Algorithm = oidPublicKeyRSA + // This is a NULL parameters value which is required by + // RFC 3279, Section 2.3.1. + publicKeyAlgorithm.Parameters = asn1.NullRawValue + case *ecdsa.PublicKey: + oid, ok := oidFromNamedCurve(pub.Curve) + if !ok { + return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve") + } + if !pub.Curve.IsOnCurve(pub.X, pub.Y) { + return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: invalid elliptic curve public key") + } + publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) + publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA + var paramBytes []byte + paramBytes, err = asn1.Marshal(oid) + if err != nil { + return + } + publicKeyAlgorithm.Parameters.FullBytes = paramBytes + case ed25519.PublicKey: + publicKeyBytes = pub + publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519 + case *ecdh.PublicKey: + publicKeyBytes = pub.Bytes() + if pub.Curve() == ecdh.X25519() { + publicKeyAlgorithm.Algorithm = oidPublicKeyX25519 + } else { + oid, ok := oidFromECDHCurve(pub.Curve()) + if !ok { + return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve") + } + publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA + var paramBytes []byte + paramBytes, err = asn1.Marshal(oid) + if err != nil { + return + } + publicKeyAlgorithm.Parameters.FullBytes = paramBytes + } + default: + return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub) + } + + return publicKeyBytes, publicKeyAlgorithm, nil +} + +// MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form. +// The encoded public key is a SubjectPublicKeyInfo structure +// (see RFC 5280, Section 4.1). +// +// The following key types are currently supported: *[rsa.PublicKey], +// *[ecdsa.PublicKey], [ed25519.PublicKey] (not a pointer), and *[ecdh.PublicKey]. +// Unsupported key types result in an error. +// +// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". +func MarshalPKIXPublicKey(pub any) ([]byte, error) { + var publicKeyBytes []byte + var publicKeyAlgorithm pkix.AlgorithmIdentifier + var err error + + if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil { + return nil, err + } + + pkix := pkixPublicKey{ + Algo: publicKeyAlgorithm, + BitString: asn1.BitString{ + Bytes: publicKeyBytes, + BitLength: 8 * len(publicKeyBytes), + }, + } + + ret, _ := asn1.Marshal(pkix) + return ret, nil +} + +// These structures reflect the ASN.1 structure of X.509 certificates.: + +type certificate struct { + TBSCertificate tbsCertificate + SignatureAlgorithm pkix.AlgorithmIdentifier + SignatureValue asn1.BitString +} + +type tbsCertificate struct { + Raw asn1.RawContent + Version int `asn1:"optional,explicit,default:0,tag:0"` + SerialNumber *big.Int + SignatureAlgorithm pkix.AlgorithmIdentifier + Issuer asn1.RawValue + Validity validity + Subject asn1.RawValue + PublicKey publicKeyInfo + UniqueId asn1.BitString `asn1:"optional,tag:1"` + SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"` + Extensions []pkix.Extension `asn1:"omitempty,optional,explicit,tag:3"` +} + +type dsaAlgorithmParameters struct { + P, Q, G *big.Int +} + +type validity struct { + NotBefore, NotAfter time.Time +} + +type publicKeyInfo struct { + Raw asn1.RawContent + Algorithm pkix.AlgorithmIdentifier + PublicKey asn1.BitString +} + +// RFC 5280, 4.2.1.1 +type authKeyId struct { + Id []byte `asn1:"optional,tag:0"` +} + +type SignatureAlgorithm int + +const ( + UnknownSignatureAlgorithm SignatureAlgorithm = iota + + MD2WithRSA // Unsupported. + MD5WithRSA // Only supported for signing, not verification. + SHA1WithRSA // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. + SHA256WithRSA + SHA384WithRSA + SHA512WithRSA + DSAWithSHA1 // Unsupported. + DSAWithSHA256 // Unsupported. + ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. + ECDSAWithSHA256 + ECDSAWithSHA384 + ECDSAWithSHA512 + SHA256WithRSAPSS + SHA384WithRSAPSS + SHA512WithRSAPSS + PureEd25519 +) + +func (algo SignatureAlgorithm) isRSAPSS() bool { + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.isRSAPSS + } + } + return false +} + +func (algo SignatureAlgorithm) hashFunc() crypto.Hash { + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.hash + } + } + return crypto.Hash(0) +} + +func (algo SignatureAlgorithm) String() string { + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.name + } + } + return strconv.Itoa(int(algo)) +} + +type PublicKeyAlgorithm int + +const ( + UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota + RSA + DSA // Only supported for parsing. + ECDSA + Ed25519 +) + +var publicKeyAlgoName = [...]string{ + RSA: "RSA", + DSA: "DSA", + ECDSA: "ECDSA", + Ed25519: "Ed25519", +} + +func (algo PublicKeyAlgorithm) String() string { + if 0 < algo && int(algo) < len(publicKeyAlgoName) { + return publicKeyAlgoName[algo] + } + return strconv.Itoa(int(algo)) +} + +// OIDs for signature algorithms +// +// pkcs-1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } +// +// RFC 3279 2.2.1 RSA Signature Algorithms +// +// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } +// +// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } +// +// dsaWithSha1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } +// +// RFC 3279 2.2.3 ECDSA Signature Algorithm +// +// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) ansi-x962(10045) +// signatures(4) ecdsa-with-SHA1(1)} +// +// RFC 4055 5 PKCS #1 Version 1.5 +// +// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } +// +// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } +// +// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } +// +// RFC 5758 3.1 DSA Signature Algorithms +// +// dsaWithSha256 OBJECT IDENTIFIER ::= { +// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) +// csor(3) algorithms(4) id-dsa-with-sha2(3) 2} +// +// RFC 5758 3.2 ECDSA Signature Algorithm +// +// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } +// +// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } +// +// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } +// +// RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers +// +// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } +var ( + oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} + oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} + oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} + oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} + oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} + oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} + oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} + oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} + oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} + oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} + oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} + oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} + oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} + + oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} + oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} + oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} + + oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} + + // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA + // but it's specified by ISO. Microsoft's makecert.exe has been known + // to produce certificates with this OID. + oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} +) + +var signatureAlgorithmDetails = []struct { + algo SignatureAlgorithm + name string + oid asn1.ObjectIdentifier + params asn1.RawValue + pubKeyAlgo PublicKeyAlgorithm + hash crypto.Hash + isRSAPSS bool +}{ + {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false}, + {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, + {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, + {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false}, + {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false}, + {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false}, + {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true}, + {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true}, + {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true}, + {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false}, + {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false}, + {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false}, + {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false}, + {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false}, + {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false}, + {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false}, +} + +var emptyRawValue = asn1.RawValue{} + +// DER encoded RSA PSS parameters for the +// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3. +// The parameters contain the following values: +// - hashAlgorithm contains the associated hash identifier with NULL parameters +// - maskGenAlgorithm always contains the default mgf1SHA1 identifier +// - saltLength contains the length of the associated hash +// - trailerField always contains the default trailerFieldBC value +var ( + pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}} + pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}} + pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}} +) + +// pssParameters reflects the parameters in an AlgorithmIdentifier that +// specifies RSA PSS. See RFC 3447, Appendix A.2.3. +type pssParameters struct { + // The following three fields are not marked as + // optional because the default values specify SHA-1, + // which is no longer suitable for use in signatures. + Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` + MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` + SaltLength int `asn1:"explicit,tag:2"` + TrailerField int `asn1:"optional,explicit,tag:3,default:1"` +} + +func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { + if ai.Algorithm.Equal(oidSignatureEd25519) { + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(ai.Parameters.FullBytes) != 0 { + return UnknownSignatureAlgorithm + } + } + + if !ai.Algorithm.Equal(oidSignatureRSAPSS) { + for _, details := range signatureAlgorithmDetails { + if ai.Algorithm.Equal(details.oid) { + return details.algo + } + } + return UnknownSignatureAlgorithm + } + + // RSA PSS is special because it encodes important parameters + // in the Parameters. + + var params pssParameters + if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { + return UnknownSignatureAlgorithm + } + + var mgf1HashFunc pkix.AlgorithmIdentifier + if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { + return UnknownSignatureAlgorithm + } + + // PSS is greatly overburdened with options. This code forces them into + // three buckets by requiring that the MGF1 hash function always match the + // message hash function (as recommended in RFC 3447, Section 8.1), that the + // salt length matches the hash length, and that the trailer field has the + // default value. + if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) || + !params.MGF.Algorithm.Equal(oidMGF1) || + !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || + (len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) || + params.TrailerField != 1 { + return UnknownSignatureAlgorithm + } + + switch { + case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: + return SHA256WithRSAPSS + case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: + return SHA384WithRSAPSS + case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: + return SHA512WithRSAPSS + } + + return UnknownSignatureAlgorithm +} + +var ( + // RFC 3279, 2.3 Public Key Algorithms + // + // pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) + // rsadsi(113549) pkcs(1) 1 } + // + // rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 } + // + // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) + // x9-57(10040) x9cm(4) 1 } + oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} + oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} + // RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters + // + // id-ecPublicKey OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } + oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} + // RFC 8410, Section 3 + // + // id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 } + // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } + oidPublicKeyX25519 = asn1.ObjectIdentifier{1, 3, 101, 110} + oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} +) + +// getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm +// identifier for public key types supported in certificates and CSRs. Marshal +// and Parse functions may support a different set of public key types. +func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm { + switch { + case oid.Equal(oidPublicKeyRSA): + return RSA + case oid.Equal(oidPublicKeyDSA): + return DSA + case oid.Equal(oidPublicKeyECDSA): + return ECDSA + case oid.Equal(oidPublicKeyEd25519): + return Ed25519 + } + return UnknownPublicKeyAlgorithm +} + +// RFC 5480, 2.1.1.1. Named Curve +// +// secp224r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 33 } +// +// secp256r1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) +// prime(1) 7 } +// +// secp384r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 34 } +// +// secp521r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 35 } +// +// NB: secp256r1 is equivalent to prime256v1 +var ( + oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} + oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} + oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} + oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} +) + +func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { + switch { + case oid.Equal(oidNamedCurveP224): + return elliptic.P224() + case oid.Equal(oidNamedCurveP256): + return elliptic.P256() + case oid.Equal(oidNamedCurveP384): + return elliptic.P384() + case oid.Equal(oidNamedCurveP521): + return elliptic.P521() + } + return nil +} + +func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { + switch curve { + case elliptic.P224(): + return oidNamedCurveP224, true + case elliptic.P256(): + return oidNamedCurveP256, true + case elliptic.P384(): + return oidNamedCurveP384, true + case elliptic.P521(): + return oidNamedCurveP521, true + } + + return nil, false +} + +func oidFromECDHCurve(curve ecdh.Curve) (asn1.ObjectIdentifier, bool) { + switch curve { + case ecdh.X25519(): + return oidPublicKeyX25519, true + case ecdh.P256(): + return oidNamedCurveP256, true + case ecdh.P384(): + return oidNamedCurveP384, true + case ecdh.P521(): + return oidNamedCurveP521, true + } + + return nil, false +} + +// KeyUsage represents the set of actions that are valid for a given key. It's +// a bitmap of the KeyUsage* constants. +type KeyUsage int + +const ( + KeyUsageDigitalSignature KeyUsage = 1 << iota + KeyUsageContentCommitment + KeyUsageKeyEncipherment + KeyUsageDataEncipherment + KeyUsageKeyAgreement + KeyUsageCertSign + KeyUsageCRLSign + KeyUsageEncipherOnly + KeyUsageDecipherOnly +) + +// RFC 5280, 4.2.1.12 Extended Key Usage +// +// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } +// +// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } +// +// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } +// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } +// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } +// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } +// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } +// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } +var ( + oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} + oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} + oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} + oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} + oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} + oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} + oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} + oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} + oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} + oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} + oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} + oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} + oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} + oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} +) + +// ExtKeyUsage represents an extended set of actions that are valid for a given key. +// Each of the ExtKeyUsage* constants define a unique action. +type ExtKeyUsage int + +const ( + ExtKeyUsageAny ExtKeyUsage = iota + ExtKeyUsageServerAuth + ExtKeyUsageClientAuth + ExtKeyUsageCodeSigning + ExtKeyUsageEmailProtection + ExtKeyUsageIPSECEndSystem + ExtKeyUsageIPSECTunnel + ExtKeyUsageIPSECUser + ExtKeyUsageTimeStamping + ExtKeyUsageOCSPSigning + ExtKeyUsageMicrosoftServerGatedCrypto + ExtKeyUsageNetscapeServerGatedCrypto + ExtKeyUsageMicrosoftCommercialCodeSigning + ExtKeyUsageMicrosoftKernelCodeSigning +) + +// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. +var extKeyUsageOIDs = []struct { + extKeyUsage ExtKeyUsage + oid asn1.ObjectIdentifier +}{ + {ExtKeyUsageAny, oidExtKeyUsageAny}, + {ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth}, + {ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth}, + {ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning}, + {ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection}, + {ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem}, + {ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel}, + {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, + {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, + {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, + {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, + {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, + {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning}, + {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning}, +} + +func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { + for _, pair := range extKeyUsageOIDs { + if oid.Equal(pair.oid) { + return pair.extKeyUsage, true + } + } + return +} + +func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) { + for _, pair := range extKeyUsageOIDs { + if eku == pair.extKeyUsage { + return pair.oid, true + } + } + return +} + +// A Certificate represents an X.509 certificate. +type Certificate struct { + Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). + RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content. + RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. + RawSubject []byte // DER encoded Subject + RawIssuer []byte // DER encoded Issuer + + Signature []byte + SignatureAlgorithm SignatureAlgorithm + + PublicKeyAlgorithm PublicKeyAlgorithm + PublicKey any + + Version int + SerialNumber *big.Int + Issuer pkix.Name + Subject pkix.Name + NotBefore, NotAfter time.Time // Validity bounds. + KeyUsage KeyUsage + + // Extensions contains raw X.509 extensions. When parsing certificates, + // this can be used to extract non-critical extensions that are not + // parsed by this package. When marshaling certificates, the Extensions + // field is ignored, see ExtraExtensions. + Extensions []pkix.Extension + + // ExtraExtensions contains extensions to be copied, raw, into any + // marshaled certificates. Values override any extensions that would + // otherwise be produced based on the other fields. The ExtraExtensions + // field is not populated when parsing certificates, see Extensions. + ExtraExtensions []pkix.Extension + + // UnhandledCriticalExtensions contains a list of extension IDs that + // were not (fully) processed when parsing. Verify will fail if this + // slice is non-empty, unless verification is delegated to an OS + // library which understands all the critical extensions. + // + // Users can access these extensions using Extensions and can remove + // elements from this slice if they believe that they have been + // handled. + UnhandledCriticalExtensions []asn1.ObjectIdentifier + + ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. + UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. + + // BasicConstraintsValid indicates whether IsCA, MaxPathLen, + // and MaxPathLenZero are valid. + BasicConstraintsValid bool + IsCA bool + + // MaxPathLen and MaxPathLenZero indicate the presence and + // value of the BasicConstraints' "pathLenConstraint". + // + // When parsing a certificate, a positive non-zero MaxPathLen + // means that the field was specified, -1 means it was unset, + // and MaxPathLenZero being true mean that the field was + // explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false + // should be treated equivalent to -1 (unset). + // + // When generating a certificate, an unset pathLenConstraint + // can be requested with either MaxPathLen == -1 or using the + // zero value for both MaxPathLen and MaxPathLenZero. + MaxPathLen int + // MaxPathLenZero indicates that BasicConstraintsValid==true + // and MaxPathLen==0 should be interpreted as an actual + // maximum path length of zero. Otherwise, that combination is + // interpreted as MaxPathLen not being set. + MaxPathLenZero bool + + SubjectKeyId []byte + AuthorityKeyId []byte + + // RFC 5280, 4.2.2.1 (Authority Information Access) + OCSPServer []string + IssuingCertificateURL []string + + // Subject Alternate Name values. (Note that these values may not be valid + // if invalid values were contained within a parsed certificate. For + // example, an element of DNSNames may not be a valid DNS domain name.) + DNSNames []string + EmailAddresses []string + IPAddresses []net.IP + URIs []*url.URL + + // Name constraints + PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. + PermittedDNSDomains []string + ExcludedDNSDomains []string + PermittedIPRanges []*net.IPNet + ExcludedIPRanges []*net.IPNet + PermittedEmailAddresses []string + ExcludedEmailAddresses []string + PermittedURIDomains []string + ExcludedURIDomains []string + + // CRL Distribution Points + CRLDistributionPoints []string + + // PolicyIdentifiers contains asn1.ObjectIdentifiers, the components + // of which are limited to int32. If a certificate contains a policy which + // cannot be represented by asn1.ObjectIdentifier, it will not be included in + // PolicyIdentifiers, but will be present in Policies, which contains all parsed + // policy OIDs. + // See CreateCertificate for context about how this field and the Policies field + // interact. + PolicyIdentifiers []asn1.ObjectIdentifier + + // Policies contains all policy identifiers included in the certificate. + // See CreateCertificate for context about how this field and the PolicyIdentifiers field + // interact. + // In Go 1.22, encoding/gob cannot handle and ignores this field. + Policies []OID + + // InhibitAnyPolicy and InhibitAnyPolicyZero indicate the presence and value + // of the inhibitAnyPolicy extension. + // + // The value of InhibitAnyPolicy indicates the number of additional + // certificates in the path after this certificate that may use the + // anyPolicy policy OID to indicate a match with any other policy. + // + // When parsing a certificate, a positive non-zero InhibitAnyPolicy means + // that the field was specified, -1 means it was unset, and + // InhibitAnyPolicyZero being true mean that the field was explicitly set to + // zero. The case of InhibitAnyPolicy==0 with InhibitAnyPolicyZero==false + // should be treated equivalent to -1 (unset). + InhibitAnyPolicy int + // InhibitAnyPolicyZero indicates that InhibitAnyPolicy==0 should be + // interpreted as an actual maximum path length of zero. Otherwise, that + // combination is interpreted as InhibitAnyPolicy not being set. + InhibitAnyPolicyZero bool + + // InhibitPolicyMapping and InhibitPolicyMappingZero indicate the presence + // and value of the inhibitPolicyMapping field of the policyConstraints + // extension. + // + // The value of InhibitPolicyMapping indicates the number of additional + // certificates in the path after this certificate that may use policy + // mapping. + // + // When parsing a certificate, a positive non-zero InhibitPolicyMapping + // means that the field was specified, -1 means it was unset, and + // InhibitPolicyMappingZero being true mean that the field was explicitly + // set to zero. The case of InhibitPolicyMapping==0 with + // InhibitPolicyMappingZero==false should be treated equivalent to -1 + // (unset). + InhibitPolicyMapping int + // InhibitPolicyMappingZero indicates that InhibitPolicyMapping==0 should be + // interpreted as an actual maximum path length of zero. Otherwise, that + // combination is interpreted as InhibitAnyPolicy not being set. + InhibitPolicyMappingZero bool + + // RequireExplicitPolicy and RequireExplicitPolicyZero indicate the presence + // and value of the requireExplicitPolicy field of the policyConstraints + // extension. + // + // The value of RequireExplicitPolicy indicates the number of additional + // certificates in the path after this certificate before an explicit policy + // is required for the rest of the path. When an explicit policy is required, + // each subsequent certificate in the path must contain a required policy OID, + // or a policy OID which has been declared as equivalent through the policy + // mapping extension. + // + // When parsing a certificate, a positive non-zero RequireExplicitPolicy + // means that the field was specified, -1 means it was unset, and + // RequireExplicitPolicyZero being true mean that the field was explicitly + // set to zero. The case of RequireExplicitPolicy==0 with + // RequireExplicitPolicyZero==false should be treated equivalent to -1 + // (unset). + RequireExplicitPolicy int + // RequireExplicitPolicyZero indicates that RequireExplicitPolicy==0 should be + // interpreted as an actual maximum path length of zero. Otherwise, that + // combination is interpreted as InhibitAnyPolicy not being set. + RequireExplicitPolicyZero bool + + // PolicyMappings contains a list of policy mappings included in the certificate. + PolicyMappings []PolicyMapping +} + +// PolicyMapping represents a policy mapping entry in the policyMappings extension. +type PolicyMapping struct { + // IssuerDomainPolicy contains a policy OID the issuing certificate considers + // equivalent to SubjectDomainPolicy in the subject certificate. + IssuerDomainPolicy OID + // SubjectDomainPolicy contains a OID the issuing certificate considers + // equivalent to IssuerDomainPolicy in the subject certificate. + SubjectDomainPolicy OID +} + +// ErrUnsupportedAlgorithm results from attempting to perform an operation that +// involves algorithms that are not currently implemented. +var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented") + +// An InsecureAlgorithmError indicates that the [SignatureAlgorithm] used to +// generate the signature is not secure, and the signature has been rejected. +type InsecureAlgorithmError SignatureAlgorithm + +func (e InsecureAlgorithmError) Error() string { + return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e)) +} + +// ConstraintViolationError results when a requested usage is not permitted by +// a certificate. For example: checking a signature when the public key isn't a +// certificate signing key. +type ConstraintViolationError struct{} + +func (ConstraintViolationError) Error() string { + return "x509: invalid signature: parent certificate cannot sign this kind of certificate" +} + +func (c *Certificate) Equal(other *Certificate) bool { + if c == nil || other == nil { + return c == other + } + return bytes.Equal(c.Raw, other.Raw) +} + +func (c *Certificate) hasSANExtension() bool { + return oidInExtensions(oidExtensionSubjectAltName, c.Extensions) +} + +// CheckSignatureFrom verifies that the signature on c is a valid signature from parent. +// +// This is a low-level API that performs very limited checks, and not a full +// path verifier. Most users should use [Certificate.Verify] instead. +func (c *Certificate) CheckSignatureFrom(parent *Certificate) error { + // RFC 5280, 4.2.1.9: + // "If the basic constraints extension is not present in a version 3 + // certificate, or the extension is present but the cA boolean is not + // asserted, then the certified public key MUST NOT be used to verify + // certificate signatures." + if parent.Version == 3 && !parent.BasicConstraintsValid || + parent.BasicConstraintsValid && !parent.IsCA { + return ConstraintViolationError{} + } + + if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 { + return ConstraintViolationError{} + } + + if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { + return ErrUnsupportedAlgorithm + } + + return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, false) +} + +// CheckSignature verifies that signature is a valid signature over signed from +// c's public key. +// +// This is a low-level API that performs no validity checks on the certificate. +// +// [MD5WithRSA] signatures are rejected, while [SHA1WithRSA] and [ECDSAWithSHA1] +// signatures are currently accepted. +func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error { + return checkSignature(algo, signed, signature, c.PublicKey, true) +} + +func (c *Certificate) hasNameConstraints() bool { + return oidInExtensions(oidExtensionNameConstraints, c.Extensions) +} + +func (c *Certificate) getSANExtension() []byte { + for _, e := range c.Extensions { + if e.Id.Equal(oidExtensionSubjectAltName) { + return e.Value + } + } + return nil +} + +func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey any) error { + return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey) +} + +// checkSignature verifies that signature is a valid signature over signed from +// a crypto.PublicKey. +func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey, allowSHA1 bool) (err error) { + var hashType crypto.Hash + var pubKeyAlgo PublicKeyAlgorithm + + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + hashType = details.hash + pubKeyAlgo = details.pubKeyAlgo + break + } + } + + switch hashType { + case crypto.Hash(0): + if pubKeyAlgo != Ed25519 { + return ErrUnsupportedAlgorithm + } + case crypto.MD5: + return InsecureAlgorithmError(algo) + case crypto.SHA1: + // SHA-1 signatures are only allowed for CRLs and CSRs. + if !allowSHA1 { + return InsecureAlgorithmError(algo) + } + fallthrough + default: + if !hashType.Available() { + return ErrUnsupportedAlgorithm + } + h := hashType.New() + h.Write(signed) + signed = h.Sum(nil) + } + + switch pub := publicKey.(type) { + case *rsa.PublicKey: + if pubKeyAlgo != RSA { + return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) + } + if algo.isRSAPSS() { + return rsa.VerifyPSS(pub, hashType, signed, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) + } else { + return rsa.VerifyPKCS1v15(pub, hashType, signed, signature) + } + case *ecdsa.PublicKey: + if pubKeyAlgo != ECDSA { + return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) + } + if !ecdsa.VerifyASN1(pub, signed, signature) { + return errors.New("x509: ECDSA verification failure") + } + return + case ed25519.PublicKey: + if pubKeyAlgo != Ed25519 { + return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) + } + if !ed25519.Verify(pub, signed, signature) { + return errors.New("x509: Ed25519 verification failure") + } + return + } + return ErrUnsupportedAlgorithm +} + +// CheckCRLSignature checks that the signature in crl is from c. +// +// Deprecated: Use [RevocationList.CheckSignatureFrom] instead. +func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error { + algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm) + return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) +} + +type UnhandledCriticalExtension struct{} + +func (h UnhandledCriticalExtension) Error() string { + return "x509: unhandled critical extension" +} + +type basicConstraints struct { + IsCA bool `asn1:"optional"` + MaxPathLen int `asn1:"optional,default:-1"` +} + +// RFC 5280 4.2.1.4 +type policyInformation struct { + Policy asn1.ObjectIdentifier + // policyQualifiers omitted +} + +const ( + nameTypeEmail = 1 + nameTypeDNS = 2 + nameTypeURI = 6 + nameTypeIP = 7 +) + +// RFC 5280, 4.2.2.1 +type authorityInfoAccess struct { + Method asn1.ObjectIdentifier + Location asn1.RawValue +} + +// RFC 5280, 4.2.1.14 +type distributionPoint struct { + DistributionPoint distributionPointName `asn1:"optional,tag:0"` + Reason asn1.BitString `asn1:"optional,tag:1"` + CRLIssuer asn1.RawValue `asn1:"optional,tag:2"` +} + +type distributionPointName struct { + FullName []asn1.RawValue `asn1:"optional,tag:0"` + RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` +} + +func reverseBitsInAByte(in byte) byte { + b1 := in>>4 | in<<4 + b2 := b1>>2&0x33 | b1<<2&0xcc + b3 := b2>>1&0x55 | b2<<1&0xaa + return b3 +} + +// asn1BitLength returns the bit-length of bitString by considering the +// most-significant bit in a byte to be the "first" bit. This convention +// matches ASN.1, but differs from almost everything else. +func asn1BitLength(bitString []byte) int { + bitLen := len(bitString) * 8 + + for i := range bitString { + b := bitString[len(bitString)-i-1] + + for bit := uint(0); bit < 8; bit++ { + if (b>>bit)&1 == 1 { + return bitLen + } + bitLen-- + } + } + + return 0 +} + +var ( + oidExtensionSubjectKeyId = []int{2, 5, 29, 14} + oidExtensionKeyUsage = []int{2, 5, 29, 15} + oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37} + oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} + oidExtensionBasicConstraints = []int{2, 5, 29, 19} + oidExtensionSubjectAltName = []int{2, 5, 29, 17} + oidExtensionCertificatePolicies = []int{2, 5, 29, 32} + oidExtensionNameConstraints = []int{2, 5, 29, 30} + oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31} + oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1} + oidExtensionCRLNumber = []int{2, 5, 29, 20} + oidExtensionReasonCode = []int{2, 5, 29, 21} +) + +var ( + oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} + oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} +) + +// oidInExtensions reports whether an extension with the given oid exists in +// extensions. +func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool { + for _, e := range extensions { + if e.Id.Equal(oid) { + return true + } + } + return false +} + +// marshalSANs marshals a list of addresses into a the contents of an X.509 +// SubjectAlternativeName extension. +func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) { + var rawValues []asn1.RawValue + for _, name := range dnsNames { + if err := isIA5String(name); err != nil { + return nil, err + } + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)}) + } + for _, email := range emailAddresses { + if err := isIA5String(email); err != nil { + return nil, err + } + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)}) + } + for _, rawIP := range ipAddresses { + // If possible, we always want to encode IPv4 addresses in 4 bytes. + ip := rawIP.To4() + if ip == nil { + ip = rawIP + } + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip}) + } + for _, uri := range uris { + uriStr := uri.String() + if err := isIA5String(uriStr); err != nil { + return nil, err + } + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uriStr)}) + } + return asn1.Marshal(rawValues) +} + +func isIA5String(s string) error { + for _, r := range s { + // Per RFC5280 "IA5String is limited to the set of ASCII characters" + if r > unicode.MaxASCII { + return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s) + } + } + + return nil +} + +var x509usepolicies = godebug.New("x509usepolicies") + +func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) { + ret = make([]pkix.Extension, 10 /* maximum number of elements. */) + n := 0 + + if template.KeyUsage != 0 && + !oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) { + ret[n], err = marshalKeyUsage(template.KeyUsage) + if err != nil { + return nil, err + } + n++ + } + + if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) && + !oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) { + ret[n], err = marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage) + if err != nil { + return nil, err + } + n++ + } + + if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) { + ret[n], err = marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero) + if err != nil { + return nil, err + } + n++ + } + + if len(subjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) { + ret[n].Id = oidExtensionSubjectKeyId + ret[n].Value, err = asn1.Marshal(subjectKeyId) + if err != nil { + return + } + n++ + } + + if len(authorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) { + ret[n].Id = oidExtensionAuthorityKeyId + ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId}) + if err != nil { + return + } + n++ + } + + if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) && + !oidInExtensions(oidExtensionAuthorityInfoAccess, template.ExtraExtensions) { + ret[n].Id = oidExtensionAuthorityInfoAccess + var aiaValues []authorityInfoAccess + for _, name := range template.OCSPServer { + aiaValues = append(aiaValues, authorityInfoAccess{ + Method: oidAuthorityInfoAccessOcsp, + Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}, + }) + } + for _, name := range template.IssuingCertificateURL { + aiaValues = append(aiaValues, authorityInfoAccess{ + Method: oidAuthorityInfoAccessIssuers, + Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}, + }) + } + ret[n].Value, err = asn1.Marshal(aiaValues) + if err != nil { + return + } + n++ + } + + if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && + !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { + ret[n].Id = oidExtensionSubjectAltName + // From RFC 5280, Section 4.2.1.6: + // “If the subject field contains an empty sequence ... then + // subjectAltName extension ... is marked as critical” + ret[n].Critical = subjectIsEmpty + ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) + if err != nil { + return + } + n++ + } + + usePolicies := x509usepolicies.Value() != "0" + if ((!usePolicies && len(template.PolicyIdentifiers) > 0) || (usePolicies && len(template.Policies) > 0)) && + !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { + ret[n], err = marshalCertificatePolicies(template.Policies, template.PolicyIdentifiers) + if err != nil { + return nil, err + } + n++ + } + + if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0 || + len(template.PermittedIPRanges) > 0 || len(template.ExcludedIPRanges) > 0 || + len(template.PermittedEmailAddresses) > 0 || len(template.ExcludedEmailAddresses) > 0 || + len(template.PermittedURIDomains) > 0 || len(template.ExcludedURIDomains) > 0) && + !oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) { + ret[n].Id = oidExtensionNameConstraints + ret[n].Critical = template.PermittedDNSDomainsCritical + + ipAndMask := func(ipNet *net.IPNet) []byte { + maskedIP := ipNet.IP.Mask(ipNet.Mask) + ipAndMask := make([]byte, 0, len(maskedIP)+len(ipNet.Mask)) + ipAndMask = append(ipAndMask, maskedIP...) + ipAndMask = append(ipAndMask, ipNet.Mask...) + return ipAndMask + } + + serialiseConstraints := func(dns []string, ips []*net.IPNet, emails []string, uriDomains []string) (der []byte, err error) { + var b cryptobyte.Builder + + for _, name := range dns { + if err = isIA5String(name); err != nil { + return nil, err + } + + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(2).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes([]byte(name)) + }) + }) + } + + for _, ipNet := range ips { + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(7).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes(ipAndMask(ipNet)) + }) + }) + } + + for _, email := range emails { + if err = isIA5String(email); err != nil { + return nil, err + } + + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes([]byte(email)) + }) + }) + } + + for _, uriDomain := range uriDomains { + if err = isIA5String(uriDomain); err != nil { + return nil, err + } + + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(6).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes([]byte(uriDomain)) + }) + }) + } + + return b.Bytes() + } + + permitted, err := serialiseConstraints(template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains) + if err != nil { + return nil, err + } + + excluded, err := serialiseConstraints(template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains) + if err != nil { + return nil, err + } + + var b cryptobyte.Builder + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + if len(permitted) > 0 { + b.AddASN1(cryptobyte_asn1.Tag(0).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { + b.AddBytes(permitted) + }) + } + + if len(excluded) > 0 { + b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { + b.AddBytes(excluded) + }) + } + }) + + ret[n].Value, err = b.Bytes() + if err != nil { + return nil, err + } + n++ + } + + if len(template.CRLDistributionPoints) > 0 && + !oidInExtensions(oidExtensionCRLDistributionPoints, template.ExtraExtensions) { + ret[n].Id = oidExtensionCRLDistributionPoints + + var crlDp []distributionPoint + for _, name := range template.CRLDistributionPoints { + dp := distributionPoint{ + DistributionPoint: distributionPointName{ + FullName: []asn1.RawValue{ + {Tag: 6, Class: 2, Bytes: []byte(name)}, + }, + }, + } + crlDp = append(crlDp, dp) + } + + ret[n].Value, err = asn1.Marshal(crlDp) + if err != nil { + return + } + n++ + } + + // Adding another extension here? Remember to update the maximum number + // of elements in the make() at the top of the function and the list of + // template fields used in CreateCertificate documentation. + + return append(ret[:n], template.ExtraExtensions...), nil +} + +func marshalKeyUsage(ku KeyUsage) (pkix.Extension, error) { + ext := pkix.Extension{Id: oidExtensionKeyUsage, Critical: true} + + var a [2]byte + a[0] = reverseBitsInAByte(byte(ku)) + a[1] = reverseBitsInAByte(byte(ku >> 8)) + + l := 1 + if a[1] != 0 { + l = 2 + } + + bitString := a[:l] + var err error + ext.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)}) + return ext, err +} + +func marshalExtKeyUsage(extUsages []ExtKeyUsage, unknownUsages []asn1.ObjectIdentifier) (pkix.Extension, error) { + ext := pkix.Extension{Id: oidExtensionExtendedKeyUsage} + + oids := make([]asn1.ObjectIdentifier, len(extUsages)+len(unknownUsages)) + for i, u := range extUsages { + if oid, ok := oidFromExtKeyUsage(u); ok { + oids[i] = oid + } else { + return ext, errors.New("x509: unknown extended key usage") + } + } + + copy(oids[len(extUsages):], unknownUsages) + + var err error + ext.Value, err = asn1.Marshal(oids) + return ext, err +} + +func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pkix.Extension, error) { + ext := pkix.Extension{Id: oidExtensionBasicConstraints, Critical: true} + // Leaving MaxPathLen as zero indicates that no maximum path + // length is desired, unless MaxPathLenZero is set. A value of + // -1 causes encoding/asn1 to omit the value as desired. + if maxPathLen == 0 && !maxPathLenZero { + maxPathLen = -1 + } + var err error + ext.Value, err = asn1.Marshal(basicConstraints{isCA, maxPathLen}) + return ext, err +} + +func marshalCertificatePolicies(policies []OID, policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) { + ext := pkix.Extension{Id: oidExtensionCertificatePolicies} + + b := cryptobyte.NewBuilder(make([]byte, 0, 128)) + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { + if x509usepolicies.Value() != "0" { + x509usepolicies.IncNonDefault() + for _, v := range policies { + child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { + child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) { + if len(v.der) == 0 { + child.SetError(errors.New("invalid policy object identifier")) + return + } + child.AddBytes(v.der) + }) + }) + } + } else { + for _, v := range policyIdentifiers { + child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { + child.AddASN1ObjectIdentifier(v) + }) + } + } + }) + + var err error + ext.Value, err = b.Bytes() + return ext, err +} + +func buildCSRExtensions(template *CertificateRequest) ([]pkix.Extension, error) { + var ret []pkix.Extension + + if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && + !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { + sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) + if err != nil { + return nil, err + } + + ret = append(ret, pkix.Extension{ + Id: oidExtensionSubjectAltName, + Value: sanBytes, + }) + } + + return append(ret, template.ExtraExtensions...), nil +} + +func subjectBytes(cert *Certificate) ([]byte, error) { + if len(cert.RawSubject) > 0 { + return cert.RawSubject, nil + } + + return asn1.Marshal(cert.Subject.ToRDNSequence()) +} + +// signingParamsForKey returns the signature algorithm and its Algorithm +// Identifier to use for signing, based on the key type. If sigAlgo is not zero +// then it overrides the default. +func signingParamsForKey(key crypto.Signer, sigAlgo SignatureAlgorithm) (SignatureAlgorithm, pkix.AlgorithmIdentifier, error) { + var ai pkix.AlgorithmIdentifier + var pubType PublicKeyAlgorithm + var defaultAlgo SignatureAlgorithm + + switch pub := key.Public().(type) { + case *rsa.PublicKey: + pubType = RSA + defaultAlgo = SHA256WithRSA + + case *ecdsa.PublicKey: + pubType = ECDSA + switch pub.Curve { + case elliptic.P224(), elliptic.P256(): + defaultAlgo = ECDSAWithSHA256 + case elliptic.P384(): + defaultAlgo = ECDSAWithSHA384 + case elliptic.P521(): + defaultAlgo = ECDSAWithSHA512 + default: + return 0, ai, errors.New("x509: unsupported elliptic curve") + } + + case ed25519.PublicKey: + pubType = Ed25519 + defaultAlgo = PureEd25519 + + default: + return 0, ai, errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") + } + + if sigAlgo == 0 { + sigAlgo = defaultAlgo + } + + for _, details := range signatureAlgorithmDetails { + if details.algo == sigAlgo { + if details.pubKeyAlgo != pubType { + return 0, ai, errors.New("x509: requested SignatureAlgorithm does not match private key type") + } + if details.hash == crypto.MD5 { + return 0, ai, errors.New("x509: signing with MD5 is not supported") + } + + return sigAlgo, pkix.AlgorithmIdentifier{ + Algorithm: details.oid, + Parameters: details.params, + }, nil + } + } + + return 0, ai, errors.New("x509: unknown SignatureAlgorithm") +} + +func signTBS(tbs []byte, key crypto.Signer, sigAlg SignatureAlgorithm, rand io.Reader) ([]byte, error) { + signed := tbs + hashFunc := sigAlg.hashFunc() + if hashFunc != 0 { + h := hashFunc.New() + h.Write(signed) + signed = h.Sum(nil) + } + var signerOpts crypto.SignerOpts = hashFunc + if sigAlg.isRSAPSS() { + signerOpts = &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthEqualsHash, + Hash: hashFunc, + } + } + signature, err := key.Sign(rand, signed, signerOpts) + if err != nil { + return nil, err + } + + // Check the signature to ensure the crypto.Signer behaved correctly. + if err := checkSignature(sigAlg, tbs, signature, key.Public(), true); err != nil { + return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err) + } + + return signature, nil +} + +// emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is +// just an empty SEQUENCE. +var emptyASN1Subject = []byte{0x30, 0} + +// CreateCertificate creates a new X.509 v3 certificate based on a template. +// The following members of template are currently used: +// +// - AuthorityKeyId +// - BasicConstraintsValid +// - CRLDistributionPoints +// - DNSNames +// - EmailAddresses +// - ExcludedDNSDomains +// - ExcludedEmailAddresses +// - ExcludedIPRanges +// - ExcludedURIDomains +// - ExtKeyUsage +// - ExtraExtensions +// - IPAddresses +// - IsCA +// - IssuingCertificateURL +// - KeyUsage +// - MaxPathLen +// - MaxPathLenZero +// - NotAfter +// - NotBefore +// - OCSPServer +// - PermittedDNSDomains +// - PermittedDNSDomainsCritical +// - PermittedEmailAddresses +// - PermittedIPRanges +// - PermittedURIDomains +// - PolicyIdentifiers (see note below) +// - Policies (see note below) +// - SerialNumber +// - SignatureAlgorithm +// - Subject +// - SubjectKeyId +// - URIs +// - UnknownExtKeyUsage +// +// The certificate is signed by parent. If parent is equal to template then the +// certificate is self-signed. The parameter pub is the public key of the +// certificate to be generated and priv is the private key of the signer. +// +// The returned slice is the certificate in DER encoding. +// +// The currently supported key types are *rsa.PublicKey, *ecdsa.PublicKey and +// ed25519.PublicKey. pub must be a supported key type, and priv must be a +// crypto.Signer or crypto.MessageSigner with a supported public key. +// +// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any, +// unless the resulting certificate is self-signed. Otherwise the value from +// template will be used. +// +// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId +// will be generated from the hash of the public key. +// +// If template.SerialNumber is nil, a serial number will be generated which +// conforms to RFC 5280, Section 4.1.2.2 using entropy from rand. +// +// The PolicyIdentifier and Policies fields can both be used to marshal certificate +// policy OIDs. By default, only the Policies is marshaled, but if the +// GODEBUG setting "x509usepolicies" has the value "0", the PolicyIdentifiers field will +// be marshaled instead of the Policies field. This changed in Go 1.24. The Policies field can +// be used to marshal policy OIDs which have components that are larger than 31 +// bits. +func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv any) ([]byte, error) { + key, ok := priv.(crypto.Signer) + if !ok { + return nil, errors.New("x509: certificate private key does not implement crypto.Signer") + } + + serialNumber := template.SerialNumber + if serialNumber == nil { + // Generate a serial number following RFC 5280, Section 4.1.2.2 if one + // is not provided. The serial number must be positive and at most 20 + // octets *when encoded*. + serialBytes := make([]byte, 20) + if _, err := io.ReadFull(rand, serialBytes); err != nil { + return nil, err + } + // If the top bit is set, the serial will be padded with a leading zero + // byte during encoding, so that it's not interpreted as a negative + // integer. This padding would make the serial 21 octets so we clear the + // top bit to ensure the correct length in all cases. + serialBytes[0] &= 0b0111_1111 + serialNumber = new(big.Int).SetBytes(serialBytes) + } + + // RFC 5280 Section 4.1.2.2: serial number must be positive + // + // 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 serialNumber.Sign() == -1 { + return nil, errors.New("x509: serial number must be positive") + } + + if template.BasicConstraintsValid && template.MaxPathLen < -1 { + return nil, errors.New("x509: invalid MaxPathLen, must be greater or equal to -1") + } + + 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") + } + + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm) + if err != nil { + return nil, err + } + + publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub) + if err != nil { + return nil, err + } + if getPublicKeyAlgorithmFromOID(publicKeyAlgorithm.Algorithm) == UnknownPublicKeyAlgorithm { + return nil, fmt.Errorf("x509: unsupported public key type: %T", pub) + } + + asn1Issuer, err := subjectBytes(parent) + if err != nil { + return nil, err + } + + asn1Subject, err := subjectBytes(template) + if err != nil { + return nil, err + } + + authorityKeyId := template.AuthorityKeyId + if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { + authorityKeyId = parent.SubjectKeyId + } + + subjectKeyId := template.SubjectKeyId + if len(subjectKeyId) == 0 && template.IsCA { + if x509sha256skid.Value() == "0" { + x509sha256skid.IncNonDefault() + // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2: + // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + // value of the BIT STRING subjectPublicKey (excluding the tag, + // length, and number of unused bits). + h := sha1.Sum(publicKeyBytes) + subjectKeyId = h[:] + } else { + // SubjectKeyId generated using method 1 in RFC 7093, Section 2: + // 1) The keyIdentifier is composed of the leftmost 160-bits of the + // SHA-256 hash of the value of the BIT STRING subjectPublicKey + // (excluding the tag, length, and number of unused bits). + h := sha256.Sum256(publicKeyBytes) + subjectKeyId = h[:20] + } + } + + // Check that the signer's public key matches the private key, if available. + type privateKey interface { + Equal(crypto.PublicKey) bool + } + if privPub, ok := key.Public().(privateKey); !ok { + return nil, errors.New("x509: internal error: supported public key does not implement Equal") + } else if parent.PublicKey != nil && !privPub.Equal(parent.PublicKey) { + return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey") + } + + extensions, err := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId) + if err != nil { + return nil, err + } + + encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} + c := tbsCertificate{ + Version: 2, + SerialNumber: serialNumber, + SignatureAlgorithm: algorithmIdentifier, + Issuer: asn1.RawValue{FullBytes: asn1Issuer}, + Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, + Subject: asn1.RawValue{FullBytes: asn1Subject}, + PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, + Extensions: extensions, + } + + tbsCertContents, err := asn1.Marshal(c) + if err != nil { + return nil, err + } + c.Raw = tbsCertContents + + signature, err := signTBS(tbsCertContents, key, signatureAlgorithm, rand) + if err != nil { + return nil, err + } + + return asn1.Marshal(certificate{ + TBSCertificate: c, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + }) +} + +var x509sha256skid = godebug.New("x509sha256skid") + +// pemCRLPrefix is the magic string that indicates that we have a PEM encoded +// CRL. +var pemCRLPrefix = []byte("-----BEGIN X509 CRL") + +// pemType is the type of a PEM encoded CRL. +var pemType = "X509 CRL" + +// ParseCRL parses a CRL from the given bytes. It's often the case that PEM +// encoded CRLs will appear where they should be DER encoded, so this function +// will transparently handle PEM encoding as long as there isn't any leading +// garbage. +// +// Deprecated: Use [ParseRevocationList] instead. +func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) { + if bytes.HasPrefix(crlBytes, pemCRLPrefix) { + block, _ := pem.Decode(crlBytes) + if block != nil && block.Type == pemType { + crlBytes = block.Bytes + } + } + return ParseDERCRL(crlBytes) +} + +// ParseDERCRL parses a DER encoded CRL from the given bytes. +// +// Deprecated: Use [ParseRevocationList] instead. +func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) { + certList := new(pkix.CertificateList) + if rest, err := asn1.Unmarshal(derBytes, certList); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after CRL") + } + return certList, nil +} + +// CreateCRL returns a DER encoded CRL, signed by this Certificate, that +// contains the given list of revoked certificates. +// +// Deprecated: this method does not generate an RFC 5280 conformant X.509 v2 CRL. +// To generate a standards compliant CRL, use [CreateRevocationList] instead. +func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { + key, ok := priv.(crypto.Signer) + if !ok { + return nil, errors.New("x509: certificate private key does not implement crypto.Signer") + } + + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, 0) + if err != nil { + return nil, err + } + + // Force revocation times to UTC per RFC 5280. + revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts)) + for i, rc := range revokedCerts { + rc.RevocationTime = rc.RevocationTime.UTC() + revokedCertsUTC[i] = rc + } + + tbsCertList := pkix.TBSCertificateList{ + Version: 1, + Signature: algorithmIdentifier, + Issuer: c.Subject.ToRDNSequence(), + ThisUpdate: now.UTC(), + NextUpdate: expiry.UTC(), + RevokedCertificates: revokedCertsUTC, + } + + // Authority Key Id + if len(c.SubjectKeyId) > 0 { + var aki pkix.Extension + aki.Id = oidExtensionAuthorityKeyId + aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) + if err != nil { + return nil, err + } + tbsCertList.Extensions = append(tbsCertList.Extensions, aki) + } + + tbsCertListContents, err := asn1.Marshal(tbsCertList) + if err != nil { + return nil, err + } + tbsCertList.Raw = tbsCertListContents + + signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand) + if err != nil { + return nil, err + } + + return asn1.Marshal(pkix.CertificateList{ + TBSCertList: tbsCertList, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + }) +} + +// CertificateRequest represents a PKCS #10, certificate signature request. +type CertificateRequest struct { + Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature). + RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content. + RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. + RawSubject []byte // DER encoded Subject. + + Version int + Signature []byte + SignatureAlgorithm SignatureAlgorithm + + PublicKeyAlgorithm PublicKeyAlgorithm + PublicKey any + + Subject pkix.Name + + // Attributes contains the CSR attributes that can parse as + // pkix.AttributeTypeAndValueSET. + // + // Deprecated: Use Extensions and ExtraExtensions instead for parsing and + // generating the requestedExtensions attribute. + Attributes []pkix.AttributeTypeAndValueSET + + // Extensions contains all requested extensions, in raw form. When parsing + // CSRs, this can be used to extract extensions that are not parsed by this + // package. + Extensions []pkix.Extension + + // ExtraExtensions contains extensions to be copied, raw, into any CSR + // marshaled by CreateCertificateRequest. Values override any extensions + // that would otherwise be produced based on the other fields but are + // overridden by any extensions specified in Attributes. + // + // The ExtraExtensions field is not populated by ParseCertificateRequest, + // see Extensions instead. + ExtraExtensions []pkix.Extension + + // Subject Alternate Name values. + DNSNames []string + EmailAddresses []string + IPAddresses []net.IP + URIs []*url.URL +} + +// These structures reflect the ASN.1 structure of X.509 certificate +// signature requests (see RFC 2986): + +type tbsCertificateRequest struct { + Raw asn1.RawContent + Version int + Subject asn1.RawValue + PublicKey publicKeyInfo + RawAttributes []asn1.RawValue `asn1:"tag:0"` +} + +type certificateRequest struct { + Raw asn1.RawContent + TBSCSR tbsCertificateRequest + SignatureAlgorithm pkix.AlgorithmIdentifier + SignatureValue asn1.BitString +} + +// oidExtensionRequest is a PKCS #9 OBJECT IDENTIFIER that indicates requested +// extensions in a CSR. +var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} + +// newRawAttributes converts AttributeTypeAndValueSETs from a template +// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes. +func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { + var rawAttributes []asn1.RawValue + b, err := asn1.Marshal(attributes) + if err != nil { + return nil, err + } + rest, err := asn1.Unmarshal(b, &rawAttributes) + if err != nil { + return nil, err + } + if len(rest) != 0 { + return nil, errors.New("x509: failed to unmarshal raw CSR Attributes") + } + return rawAttributes, nil +} + +// parseRawAttributes Unmarshals RawAttributes into AttributeTypeAndValueSETs. +func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET { + var attributes []pkix.AttributeTypeAndValueSET + for _, rawAttr := range rawAttributes { + var attr pkix.AttributeTypeAndValueSET + rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr) + // Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET + // (i.e.: challengePassword or unstructuredName). + if err == nil && len(rest) == 0 { + attributes = append(attributes, attr) + } + } + return attributes +} + +// parseCSRExtensions parses the attributes from a CSR and extracts any +// requested extensions. +func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) { + // pkcs10Attribute reflects the Attribute structure from RFC 2986, Section 4.1. + type pkcs10Attribute struct { + Id asn1.ObjectIdentifier + Values []asn1.RawValue `asn1:"set"` + } + + var ret []pkix.Extension + requestedExts := make(map[string]bool) + for _, rawAttr := range rawAttributes { + var attr pkcs10Attribute + if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 { + // Ignore attributes that don't parse. + continue + } + + if !attr.Id.Equal(oidExtensionRequest) { + continue + } + + var extensions []pkix.Extension + if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil { + return nil, err + } + for _, ext := range extensions { + oidStr := ext.Id.String() + if requestedExts[oidStr] { + return nil, errors.New("x509: certificate request contains duplicate requested extensions") + } + requestedExts[oidStr] = true + } + ret = append(ret, extensions...) + } + + return ret, nil +} + +// CreateCertificateRequest creates a new certificate request based on a +// template. The following members of template are used: +// +// - SignatureAlgorithm +// - Subject +// - DNSNames +// - EmailAddresses +// - IPAddresses +// - URIs +// - ExtraExtensions +// - Attributes (deprecated) +// +// priv is the private key to sign the CSR with, and the corresponding public +// key will be included in the CSR. It must implement crypto.Signer or +// crypto.MessageSigner and its Public() method must return a *rsa.PublicKey or +// a *ecdsa.PublicKey or a ed25519.PublicKey. (A *rsa.PrivateKey, +// *ecdsa.PrivateKey or ed25519.PrivateKey satisfies this.) +// +// The returned slice is the certificate request in DER encoding. +func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv any) (csr []byte, err error) { + key, ok := priv.(crypto.Signer) + if !ok { + return nil, errors.New("x509: certificate private key does not implement crypto.Signer") + } + + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm) + if err != nil { + return nil, err + } + + var publicKeyBytes []byte + var publicKeyAlgorithm pkix.AlgorithmIdentifier + publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public()) + if err != nil { + return nil, err + } + + extensions, err := buildCSRExtensions(template) + if err != nil { + return nil, err + } + + // Make a copy of template.Attributes because we may alter it below. + attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes)) + for _, attr := range template.Attributes { + values := make([][]pkix.AttributeTypeAndValue, len(attr.Value)) + copy(values, attr.Value) + attributes = append(attributes, pkix.AttributeTypeAndValueSET{ + Type: attr.Type, + Value: values, + }) + } + + extensionsAppended := false + if len(extensions) > 0 { + // Append the extensions to an existing attribute if possible. + for _, atvSet := range attributes { + if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 { + continue + } + + // specifiedExtensions contains all the extensions that we + // found specified via template.Attributes. + specifiedExtensions := make(map[string]bool) + + for _, atvs := range atvSet.Value { + for _, atv := range atvs { + specifiedExtensions[atv.Type.String()] = true + } + } + + newValue := make([]pkix.AttributeTypeAndValue, 0, len(atvSet.Value[0])+len(extensions)) + newValue = append(newValue, atvSet.Value[0]...) + + for _, e := range extensions { + if specifiedExtensions[e.Id.String()] { + // Attributes already contained a value for + // this extension and it takes priority. + continue + } + + newValue = append(newValue, pkix.AttributeTypeAndValue{ + // There is no place for the critical + // flag in an AttributeTypeAndValue. + Type: e.Id, + Value: e.Value, + }) + } + + atvSet.Value[0] = newValue + extensionsAppended = true + break + } + } + + rawAttributes, err := newRawAttributes(attributes) + if err != nil { + return nil, err + } + + // If not included in attributes, add a new attribute for the + // extensions. + if len(extensions) > 0 && !extensionsAppended { + attr := struct { + Type asn1.ObjectIdentifier + Value [][]pkix.Extension `asn1:"set"` + }{ + Type: oidExtensionRequest, + Value: [][]pkix.Extension{extensions}, + } + + b, err := asn1.Marshal(attr) + if err != nil { + return nil, errors.New("x509: failed to serialise extensions attribute: " + err.Error()) + } + + var rawValue asn1.RawValue + if _, err := asn1.Unmarshal(b, &rawValue); err != nil { + return nil, err + } + + rawAttributes = append(rawAttributes, rawValue) + } + + asn1Subject := template.RawSubject + if len(asn1Subject) == 0 { + asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence()) + if err != nil { + return nil, err + } + } + + tbsCSR := tbsCertificateRequest{ + Version: 0, // PKCS #10, RFC 2986 + Subject: asn1.RawValue{FullBytes: asn1Subject}, + PublicKey: publicKeyInfo{ + Algorithm: publicKeyAlgorithm, + PublicKey: asn1.BitString{ + Bytes: publicKeyBytes, + BitLength: len(publicKeyBytes) * 8, + }, + }, + RawAttributes: rawAttributes, + } + + tbsCSRContents, err := asn1.Marshal(tbsCSR) + if err != nil { + return nil, err + } + tbsCSR.Raw = tbsCSRContents + + signature, err := signTBS(tbsCSRContents, key, signatureAlgorithm, rand) + if err != nil { + return nil, err + } + + return asn1.Marshal(certificateRequest{ + TBSCSR: tbsCSR, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + }) +} + +// ParseCertificateRequest parses a single certificate request from the +// given ASN.1 DER data. +func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) { + var csr certificateRequest + + rest, err := asn1.Unmarshal(asn1Data, &csr) + if err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, asn1.SyntaxError{Msg: "trailing data"} + } + + return parseCertificateRequest(&csr) +} + +func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) { + out := &CertificateRequest{ + Raw: in.Raw, + RawTBSCertificateRequest: in.TBSCSR.Raw, + RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw, + RawSubject: in.TBSCSR.Subject.FullBytes, + + Signature: in.SignatureValue.RightAlign(), + SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm), + + PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm), + + Version: in.TBSCSR.Version, + Attributes: parseRawAttributes(in.TBSCSR.RawAttributes), + } + + var err error + if out.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { + out.PublicKey, err = parsePublicKey(&in.TBSCSR.PublicKey) + if err != nil { + return nil, err + } + } + + var subject pkix.RDNSequence + if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 Subject") + } + + out.Subject.FillFromRDNSequence(&subject) + + if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil { + return nil, err + } + + for _, extension := range out.Extensions { + switch { + case extension.Id.Equal(oidExtensionSubjectAltName): + out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value) + if err != nil { + return nil, err + } + } + } + + return out, nil +} + +// CheckSignature reports whether the signature on c is valid. +func (c *CertificateRequest) CheckSignature() error { + return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey, true) +} + +// RevocationListEntry represents an entry in the revokedCertificates +// sequence of a CRL. +type RevocationListEntry struct { + // Raw contains the raw bytes of the revokedCertificates entry. It is set when + // parsing a CRL; it is ignored when generating a CRL. + Raw []byte + + // SerialNumber represents the serial number of a revoked certificate. It is + // both used when creating a CRL and populated when parsing a CRL. It must not + // be nil. + SerialNumber *big.Int + // RevocationTime represents the time at which the certificate was revoked. It + // is both used when creating a CRL and populated when parsing a CRL. It must + // not be the zero time. + RevocationTime time.Time + // ReasonCode represents the reason for revocation, using the integer enum + // values specified in RFC 5280 Section 5.3.1. When creating a CRL, the zero + // value will result in the reasonCode extension being omitted. When parsing a + // CRL, the zero value may represent either the reasonCode extension being + // absent (which implies the default revocation reason of 0/Unspecified), or + // it may represent the reasonCode extension being present and explicitly + // containing a value of 0/Unspecified (which should not happen according to + // the DER encoding rules, but can and does happen anyway). + ReasonCode int + + // Extensions contains raw X.509 extensions. When parsing CRL entries, + // this can be used to extract non-critical extensions that are not + // parsed by this package. When marshaling CRL entries, the Extensions + // field is ignored, see ExtraExtensions. + Extensions []pkix.Extension + // ExtraExtensions contains extensions to be copied, raw, into any + // marshaled CRL entries. Values override any extensions that would + // otherwise be produced based on the other fields. The ExtraExtensions + // field is not populated when parsing CRL entries, see Extensions. + ExtraExtensions []pkix.Extension +} + +// RevocationList represents a [Certificate] Revocation List (CRL) as specified +// by RFC 5280. +type RevocationList struct { + // Raw contains the complete ASN.1 DER content of the CRL (tbsCertList, + // signatureAlgorithm, and signatureValue.) + Raw []byte + // RawTBSRevocationList contains just the tbsCertList portion of the ASN.1 + // DER. + RawTBSRevocationList []byte + // RawIssuer contains the DER encoded Issuer. + RawIssuer []byte + + // Issuer contains the DN of the issuing certificate. + Issuer pkix.Name + // AuthorityKeyId is used to identify the public key associated with the + // issuing certificate. It is populated from the authorityKeyIdentifier + // extension when parsing a CRL. It is ignored when creating a CRL; the + // extension is populated from the issuing certificate itself. + AuthorityKeyId []byte + + Signature []byte + // SignatureAlgorithm is used to determine the signature algorithm to be + // used when signing the CRL. If 0 the default algorithm for the signing + // key will be used. + SignatureAlgorithm SignatureAlgorithm + + // RevokedCertificateEntries represents the revokedCertificates sequence in + // the CRL. It is used when creating a CRL and also populated when parsing a + // CRL. When creating a CRL, it may be empty or nil, in which case the + // revokedCertificates ASN.1 sequence will be omitted from the CRL entirely. + RevokedCertificateEntries []RevocationListEntry + + // RevokedCertificates is used to populate the revokedCertificates + // sequence in the CRL if RevokedCertificateEntries is empty. It may be empty + // or nil, in which case an empty CRL will be created. + // + // Deprecated: Use RevokedCertificateEntries instead. + RevokedCertificates []pkix.RevokedCertificate + + // Number is used to populate the X.509 v2 cRLNumber extension in the CRL, + // which should be a monotonically increasing sequence number for a given + // CRL scope and CRL issuer. It is also populated from the cRLNumber + // extension when parsing a CRL. + Number *big.Int + + // ThisUpdate is used to populate the thisUpdate field in the CRL, which + // indicates the issuance date of the CRL. + ThisUpdate time.Time + // NextUpdate is used to populate the nextUpdate field in the CRL, which + // indicates the date by which the next CRL will be issued. NextUpdate + // must be greater than ThisUpdate. + NextUpdate time.Time + + // Extensions contains raw X.509 extensions. When creating a CRL, + // the Extensions field is ignored, see ExtraExtensions. + Extensions []pkix.Extension + + // ExtraExtensions contains any additional extensions to add directly to + // the CRL. + ExtraExtensions []pkix.Extension +} + +// These structures reflect the ASN.1 structure of X.509 CRLs better than +// the existing crypto/x509/pkix variants do. These mirror the existing +// certificate structs in this file. +// +// Notably, we include issuer as an asn1.RawValue, mirroring the behavior of +// tbsCertificate and allowing raw (unparsed) subjects to be passed cleanly. +type certificateList struct { + TBSCertList tbsCertificateList + SignatureAlgorithm pkix.AlgorithmIdentifier + SignatureValue asn1.BitString +} + +type tbsCertificateList struct { + Raw asn1.RawContent + Version int `asn1:"optional,default:0"` + Signature pkix.AlgorithmIdentifier + Issuer asn1.RawValue + ThisUpdate time.Time + NextUpdate time.Time `asn1:"optional"` + RevokedCertificates []pkix.RevokedCertificate `asn1:"optional"` + Extensions []pkix.Extension `asn1:"tag:0,optional,explicit"` +} + +// CreateRevocationList creates a new X.509 v2 [Certificate] Revocation List, +// according to RFC 5280, based on template. +// +// The CRL is signed by priv which should be a crypto.Signer or +// crypto.MessageSigner associated with the public key in the issuer +// certificate. +// +// The issuer may not be nil, and the crlSign bit must be set in [KeyUsage] in +// order to use it as a CRL issuer. +// +// The issuer distinguished name CRL field and authority key identifier +// extension are populated using the issuer certificate. issuer must have +// SubjectKeyId set. +func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) { + if template == nil { + return nil, errors.New("x509: template can not be nil") + } + if issuer == nil { + return nil, errors.New("x509: issuer can not be nil") + } + if (issuer.KeyUsage & KeyUsageCRLSign) == 0 { + return nil, errors.New("x509: issuer must have the crlSign key usage bit set") + } + if len(issuer.SubjectKeyId) == 0 { + return nil, errors.New("x509: issuer certificate doesn't contain a subject key identifier") + } + if template.NextUpdate.Before(template.ThisUpdate) { + return nil, errors.New("x509: template.ThisUpdate is after template.NextUpdate") + } + if template.Number == nil { + return nil, errors.New("x509: template contains nil Number field") + } + + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(priv, template.SignatureAlgorithm) + if err != nil { + return nil, err + } + + var revokedCerts []pkix.RevokedCertificate + // Only process the deprecated RevokedCertificates field if it is populated + // and the new RevokedCertificateEntries field is not populated. + if len(template.RevokedCertificates) > 0 && len(template.RevokedCertificateEntries) == 0 { + // Force revocation times to UTC per RFC 5280. + revokedCerts = make([]pkix.RevokedCertificate, len(template.RevokedCertificates)) + for i, rc := range template.RevokedCertificates { + rc.RevocationTime = rc.RevocationTime.UTC() + revokedCerts[i] = rc + } + } else { + // Convert the ReasonCode field to a proper extension, and force revocation + // times to UTC per RFC 5280. + revokedCerts = make([]pkix.RevokedCertificate, len(template.RevokedCertificateEntries)) + for i, rce := range template.RevokedCertificateEntries { + if rce.SerialNumber == nil { + return nil, errors.New("x509: template contains entry with nil SerialNumber field") + } + if rce.RevocationTime.IsZero() { + return nil, errors.New("x509: template contains entry with zero RevocationTime field") + } + + rc := pkix.RevokedCertificate{ + SerialNumber: rce.SerialNumber, + RevocationTime: rce.RevocationTime.UTC(), + } + + // Copy over any extra extensions, except for a Reason Code extension, + // because we'll synthesize that ourselves to ensure it is correct. + exts := make([]pkix.Extension, 0, len(rce.ExtraExtensions)) + for _, ext := range rce.ExtraExtensions { + if ext.Id.Equal(oidExtensionReasonCode) { + return nil, errors.New("x509: template contains entry with ReasonCode ExtraExtension; use ReasonCode field instead") + } + exts = append(exts, ext) + } + + // Only add a reasonCode extension if the reason is non-zero, as per + // RFC 5280 Section 5.3.1. + if rce.ReasonCode != 0 { + reasonBytes, err := asn1.Marshal(asn1.Enumerated(rce.ReasonCode)) + if err != nil { + return nil, err + } + + exts = append(exts, pkix.Extension{ + Id: oidExtensionReasonCode, + Value: reasonBytes, + }) + } + + if len(exts) > 0 { + rc.Extensions = exts + } + revokedCerts[i] = rc + } + } + + aki, err := asn1.Marshal(authKeyId{Id: issuer.SubjectKeyId}) + if err != nil { + return nil, err + } + + if numBytes := template.Number.Bytes(); len(numBytes) > 20 || (len(numBytes) == 20 && numBytes[0]&0x80 != 0) { + return nil, errors.New("x509: CRL number exceeds 20 octets") + } + crlNum, err := asn1.Marshal(template.Number) + if err != nil { + return nil, err + } + + // Correctly use the issuer's subject sequence if one is specified. + issuerSubject, err := subjectBytes(issuer) + if err != nil { + return nil, err + } + + tbsCertList := tbsCertificateList{ + Version: 1, // v2 + Signature: algorithmIdentifier, + Issuer: asn1.RawValue{FullBytes: issuerSubject}, + ThisUpdate: template.ThisUpdate.UTC(), + NextUpdate: template.NextUpdate.UTC(), + Extensions: []pkix.Extension{ + { + Id: oidExtensionAuthorityKeyId, + Value: aki, + }, + { + Id: oidExtensionCRLNumber, + Value: crlNum, + }, + }, + } + if len(revokedCerts) > 0 { + tbsCertList.RevokedCertificates = revokedCerts + } + + if len(template.ExtraExtensions) > 0 { + tbsCertList.Extensions = append(tbsCertList.Extensions, template.ExtraExtensions...) + } + + tbsCertListContents, err := asn1.Marshal(tbsCertList) + if err != nil { + return nil, err + } + + // Optimization to only marshal this struct once, when signing and + // then embedding in certificateList below. + tbsCertList.Raw = tbsCertListContents + + signature, err := signTBS(tbsCertListContents, priv, signatureAlgorithm, rand) + if err != nil { + return nil, err + } + + return asn1.Marshal(certificateList{ + TBSCertList: tbsCertList, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + }) +} + +// CheckSignatureFrom verifies that the signature on rl is a valid signature +// from issuer. +func (rl *RevocationList) CheckSignatureFrom(parent *Certificate) error { + if parent.Version == 3 && !parent.BasicConstraintsValid || + parent.BasicConstraintsValid && !parent.IsCA { + return ConstraintViolationError{} + } + + if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCRLSign == 0 { + return ConstraintViolationError{} + } + + if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { + return ErrUnsupportedAlgorithm + } + + return parent.CheckSignature(rl.SignatureAlgorithm, rl.RawTBSRevocationList, rl.Signature) +} From 420bbb9d3544513a5870eae6026121ff9be2a116 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Mon, 6 Oct 2025 16:40:42 -0700 Subject: [PATCH 2/5] Remove things we don't need from the copied files --- ca/x509pq/oid.go | 47 +- ca/x509pq/parser.go | 406 +---------- ca/x509pq/pkcs1.go | 189 +----- ca/x509pq/verify.go | 1573 +------------------------------------------ ca/x509pq/x509.go | 937 +------------------------- 5 files changed, 24 insertions(+), 3128 deletions(-) diff --git a/ca/x509pq/oid.go b/ca/x509pq/oid.go index b1464346..1826c940 100644 --- a/ca/x509pq/oid.go +++ b/ca/x509pq/oid.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package x509 +package x509pq import ( "bytes" @@ -10,7 +10,6 @@ import ( "errors" "math" "math/big" - "math/bits" "strconv" "strings" ) @@ -24,12 +23,6 @@ type OID struct { der []byte } -// ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots. -func ParseOID(oid string) (OID, error) { - var o OID - return o, o.unmarshalOIDText(oid) -} - func newOIDFromDER(der []byte) (OID, bool) { if len(der) == 0 || der[len(der)-1]&0x80 != 0 { return OID{}, false @@ -51,44 +44,6 @@ func newOIDFromDER(der []byte) (OID, bool) { return OID{der}, true } -// OIDFromInts creates a new OID using ints, each integer is a separate component. -func OIDFromInts(oid []uint64) (OID, error) { - if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { - return OID{}, errInvalidOID - } - - length := base128IntLength(oid[0]*40 + oid[1]) - for _, v := range oid[2:] { - length += base128IntLength(v) - } - - der := make([]byte, 0, length) - der = appendBase128Int(der, oid[0]*40+oid[1]) - for _, v := range oid[2:] { - der = appendBase128Int(der, v) - } - return OID{der}, nil -} - -func base128IntLength(n uint64) int { - if n == 0 { - return 1 - } - return (bits.Len64(n) + 6) / 7 -} - -func appendBase128Int(dst []byte, n uint64) []byte { - for i := base128IntLength(n) - 1; i >= 0; i-- { - o := byte(n >> uint(i*7)) - o &= 0x7f - if i != 0 { - o |= 0x80 - } - dst = append(dst, o) - } - return dst -} - func base128BigIntLength(n *big.Int) int { if n.Cmp(big.NewInt(0)) == 0 { return 1 diff --git a/ca/x509pq/parser.go b/ca/x509pq/parser.go index 4abcc1b7..6c99bd6c 100644 --- a/ca/x509pq/parser.go +++ b/ca/x509pq/parser.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package x509 +package x509pq import ( "bytes" @@ -16,13 +16,11 @@ import ( "encoding/asn1" "errors" "fmt" - "internal/godebug" "math" "math/big" "net" "net/url" "strconv" - "strings" "time" "unicode/utf16" "unicode/utf8" @@ -515,191 +513,6 @@ func parseCertificatePoliciesExtension(der cryptobyte.String) ([]OID, error) { return oids, nil } -// isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. -func isValidIPMask(mask []byte) bool { - seenZero := false - - for _, b := range mask { - if seenZero { - if b != 0 { - return false - } - - continue - } - - switch b { - case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: - seenZero = true - case 0xff: - default: - return false - } - } - - return true -} - -func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) { - // RFC 5280, 4.2.1.10 - - // NameConstraints ::= SEQUENCE { - // permittedSubtrees [0] GeneralSubtrees OPTIONAL, - // excludedSubtrees [1] GeneralSubtrees OPTIONAL } - // - // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree - // - // GeneralSubtree ::= SEQUENCE { - // base GeneralName, - // minimum [0] BaseDistance DEFAULT 0, - // maximum [1] BaseDistance OPTIONAL } - // - // BaseDistance ::= INTEGER (0..MAX) - - outer := cryptobyte.String(e.Value) - var toplevel, permitted, excluded cryptobyte.String - var havePermitted, haveExcluded bool - if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || - !outer.Empty() || - !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || - !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || - !toplevel.Empty() { - return false, errors.New("x509: invalid NameConstraints extension") - } - - if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { - // From RFC 5280, Section 4.2.1.10: - // “either the permittedSubtrees field - // or the excludedSubtrees MUST be - // present” - return false, errors.New("x509: empty name constraints extension") - } - - getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { - for !subtrees.Empty() { - var seq, value cryptobyte.String - var tag cryptobyte_asn1.Tag - if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || - !seq.ReadAnyASN1(&value, &tag) { - return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") - } - - var ( - dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() - emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() - ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() - uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() - ) - - switch tag { - case dnsTag: - domain := string(value) - if err := isIA5String(domain); err != nil { - return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) - } - - trimmedDomain := domain - if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { - // constraints can have a leading - // period to exclude the domain - // itself, but that's not valid in a - // normal domain name. - trimmedDomain = trimmedDomain[1:] - } - if _, ok := domainToReverseLabels(trimmedDomain); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) - } - dnsNames = append(dnsNames, domain) - - case ipTag: - l := len(value) - var ip, mask []byte - - switch l { - case 8: - ip = value[:4] - mask = value[4:] - - case 32: - ip = value[:16] - mask = value[16:] - - default: - return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) - } - - if !isValidIPMask(mask) { - return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) - } - - ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) - - case emailTag: - constraint := string(value) - if err := isIA5String(constraint); err != nil { - return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) - } - - // If the constraint contains an @ then - // it specifies an exact mailbox name. - if strings.Contains(constraint, "@") { - if _, ok := parseRFC2821Mailbox(constraint); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) - } - } else { - // Otherwise it's a domain name. - domain := constraint - if len(domain) > 0 && domain[0] == '.' { - domain = domain[1:] - } - if _, ok := domainToReverseLabels(domain); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) - } - } - emails = append(emails, constraint) - - case uriTag: - domain := string(value) - if err := isIA5String(domain); err != nil { - return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) - } - - if net.ParseIP(domain) != nil { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) - } - - trimmedDomain := domain - if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { - // constraints can have a leading - // period to exclude the domain itself, - // but that's not valid in a normal - // domain name. - trimmedDomain = trimmedDomain[1:] - } - if _, ok := domainToReverseLabels(trimmedDomain); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) - } - uriDomains = append(uriDomains, domain) - - default: - unhandled = true - } - } - - return dnsNames, ips, emails, uriDomains, nil - } - - if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { - return false, err - } - if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { - return false, err - } - out.PermittedDNSDomainsCritical = e.Critical - - return unhandled, nil -} - func processExtensions(out *Certificate) error { var err error for _, e := range out.Extensions { @@ -730,12 +543,6 @@ func processExtensions(out *Certificate) error { unhandled = true } - case 30: - unhandled, err = parseNameConstraintsExtension(out, e) - if err != nil { - return err - } - case 31: // RFC 5280, 4.2.1.13 @@ -912,8 +719,6 @@ func processExtensions(out *Certificate) error { return nil } -var x509negativeserial = godebug.New("x509negativeserial") - func parseCertificate(der []byte) (*Certificate, error) { cert := &Certificate{} @@ -958,11 +763,7 @@ func parseCertificate(der []byte) (*Certificate, error) { return nil, errors.New("x509: malformed serial number") } if serial.Sign() == -1 { - if x509negativeserial.Value() != "1" { - return nil, errors.New("x509: negative serial number") - } else { - x509negativeserial.IncNonDefault() - } + return nil, errors.New("x509: negative serial number") } cert.SerialNumber = serial @@ -1114,206 +915,3 @@ func ParseCertificate(der []byte) (*Certificate, error) { } return cert, nil } - -// ParseCertificates parses one or more certificates from the given ASN.1 DER -// data. The certificates must be concatenated with no intermediate padding. -func ParseCertificates(der []byte) ([]*Certificate, error) { - var certs []*Certificate - for len(der) > 0 { - cert, err := parseCertificate(der) - if err != nil { - return nil, err - } - certs = append(certs, cert) - der = der[len(cert.Raw):] - } - return certs, nil -} - -// The X.509 standards confusingly 1-indexed the version names, but 0-indexed -// the actual encoded version, so the version for X.509v2 is 1. -const x509v2Version = 1 - -// ParseRevocationList parses a X509 v2 [Certificate] Revocation List from the given -// ASN.1 DER data. -func ParseRevocationList(der []byte) (*RevocationList, error) { - rl := &RevocationList{} - - input := cryptobyte.String(der) - // we read the SEQUENCE including length and tag bytes so that - // we can populate RevocationList.Raw, before unwrapping the - // SEQUENCE so it can be operated on - if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed crl") - } - rl.Raw = input - if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed crl") - } - - var tbs cryptobyte.String - // do the same trick again as above to extract the raw - // bytes for Certificate.RawTBSCertificate - if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed tbs crl") - } - rl.RawTBSRevocationList = tbs - if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed tbs crl") - } - - var version int - if !tbs.PeekASN1Tag(cryptobyte_asn1.INTEGER) { - return nil, errors.New("x509: unsupported crl version") - } - if !tbs.ReadASN1Integer(&version) { - return nil, errors.New("x509: malformed crl") - } - if version != x509v2Version { - return nil, fmt.Errorf("x509: unsupported crl version: %d", version) - } - - var sigAISeq cryptobyte.String - if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed signature algorithm identifier") - } - // Before parsing the inner algorithm identifier, extract - // the outer algorithm identifier and make sure that they - // match. - var outerSigAISeq cryptobyte.String - if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed algorithm identifier") - } - if !bytes.Equal(outerSigAISeq, sigAISeq) { - return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") - } - sigAI, err := parseAI(sigAISeq) - if err != nil { - return nil, err - } - rl.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) - - var signature asn1.BitString - if !input.ReadASN1BitString(&signature) { - return nil, errors.New("x509: malformed signature") - } - rl.Signature = signature.RightAlign() - - var issuerSeq cryptobyte.String - if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed issuer") - } - rl.RawIssuer = issuerSeq - issuerRDNs, err := parseName(issuerSeq) - if err != nil { - return nil, err - } - rl.Issuer.FillFromRDNSequence(issuerRDNs) - - rl.ThisUpdate, err = parseTime(&tbs) - if err != nil { - return nil, err - } - if tbs.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime) || tbs.PeekASN1Tag(cryptobyte_asn1.UTCTime) { - rl.NextUpdate, err = parseTime(&tbs) - if err != nil { - return nil, err - } - } - - if tbs.PeekASN1Tag(cryptobyte_asn1.SEQUENCE) { - var revokedSeq cryptobyte.String - if !tbs.ReadASN1(&revokedSeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed crl") - } - for !revokedSeq.Empty() { - rce := RevocationListEntry{} - - var certSeq cryptobyte.String - if !revokedSeq.ReadASN1Element(&certSeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed crl") - } - rce.Raw = certSeq - if !certSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed crl") - } - - rce.SerialNumber = new(big.Int) - if !certSeq.ReadASN1Integer(rce.SerialNumber) { - return nil, errors.New("x509: malformed serial number") - } - rce.RevocationTime, err = parseTime(&certSeq) - if err != nil { - return nil, err - } - var extensions cryptobyte.String - var present bool - if !certSeq.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed extensions") - } - if present { - for !extensions.Empty() { - var extension cryptobyte.String - if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed extension") - } - ext, err := parseExtension(extension) - if err != nil { - return nil, err - } - if ext.Id.Equal(oidExtensionReasonCode) { - val := cryptobyte.String(ext.Value) - if !val.ReadASN1Enum(&rce.ReasonCode) { - return nil, fmt.Errorf("x509: malformed reasonCode extension") - } - } - rce.Extensions = append(rce.Extensions, ext) - } - } - - rl.RevokedCertificateEntries = append(rl.RevokedCertificateEntries, rce) - rcDeprecated := pkix.RevokedCertificate{ - SerialNumber: rce.SerialNumber, - RevocationTime: rce.RevocationTime, - Extensions: rce.Extensions, - } - rl.RevokedCertificates = append(rl.RevokedCertificates, rcDeprecated) - } - } - - var extensions cryptobyte.String - var present bool - if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { - return nil, errors.New("x509: malformed extensions") - } - if present { - if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed extensions") - } - for !extensions.Empty() { - var extension cryptobyte.String - if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed extension") - } - ext, err := parseExtension(extension) - if err != nil { - return nil, err - } - if ext.Id.Equal(oidExtensionAuthorityKeyId) { - rl.AuthorityKeyId, err = parseAuthorityKeyIdentifier(ext) - if err != nil { - return nil, err - } - } else if ext.Id.Equal(oidExtensionCRLNumber) { - value := cryptobyte.String(ext.Value) - rl.Number = new(big.Int) - if !value.ReadASN1Integer(rl.Number) { - return nil, errors.New("x509: malformed crl number") - } - } - rl.Extensions = append(rl.Extensions, ext) - } - } - - return rl, nil -} diff --git a/ca/x509pq/pkcs1.go b/ca/x509pq/pkcs1.go index 68aa8dd9..96c8d1c4 100644 --- a/ca/x509pq/pkcs1.go +++ b/ca/x509pq/pkcs1.go @@ -2,201 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package x509 +package x509pq import ( - "crypto/rsa" - "encoding/asn1" - "errors" - "internal/godebug" "math/big" ) -// pkcs1PrivateKey is a structure which mirrors the PKCS #1 ASN.1 for an RSA private key. -type pkcs1PrivateKey struct { - Version int - N *big.Int - E int - D *big.Int - P *big.Int - Q *big.Int - Dp *big.Int `asn1:"optional"` - Dq *big.Int `asn1:"optional"` - Qinv *big.Int `asn1:"optional"` - - AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"` -} - -type pkcs1AdditionalRSAPrime struct { - Prime *big.Int - - // We ignore these values because rsa will calculate them. - Exp *big.Int - Coeff *big.Int -} - // pkcs1PublicKey reflects the ASN.1 structure of a PKCS #1 public key. type pkcs1PublicKey struct { N *big.Int E int } - -// x509rsacrt, if zero, makes ParsePKCS1PrivateKey ignore and recompute invalid -// CRT values in the RSA private key. -var x509rsacrt = godebug.New("x509rsacrt") - -// ParsePKCS1PrivateKey parses an [RSA] private key in PKCS #1, ASN.1 DER form. -// -// This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY". -// -// Before Go 1.24, the CRT parameters were ignored and recomputed. To restore -// the old behavior, use the GODEBUG=x509rsacrt=0 environment variable. -func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) { - var priv pkcs1PrivateKey - rest, err := asn1.Unmarshal(der, &priv) - if len(rest) > 0 { - return nil, asn1.SyntaxError{Msg: "trailing data"} - } - if err != nil { - if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil { - return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)") - } - if _, err := asn1.Unmarshal(der, &pkcs8{}); err == nil { - return nil, errors.New("x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)") - } - return nil, err - } - - if priv.Version > 1 { - return nil, errors.New("x509: unsupported private key version") - } - - if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 || - priv.Dp != nil && priv.Dp.Sign() <= 0 || - priv.Dq != nil && priv.Dq.Sign() <= 0 || - priv.Qinv != nil && priv.Qinv.Sign() <= 0 { - return nil, errors.New("x509: private key contains zero or negative value") - } - - key := new(rsa.PrivateKey) - key.PublicKey = rsa.PublicKey{ - E: priv.E, - N: priv.N, - } - - key.D = priv.D - key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes)) - key.Primes[0] = priv.P - key.Primes[1] = priv.Q - key.Precomputed.Dp = priv.Dp - key.Precomputed.Dq = priv.Dq - key.Precomputed.Qinv = priv.Qinv - for i, a := range priv.AdditionalPrimes { - if a.Prime.Sign() <= 0 { - return nil, errors.New("x509: private key contains zero or negative prime") - } - key.Primes[i+2] = a.Prime - // We ignore the other two values because rsa will calculate - // them as needed. - } - - key.Precompute() - if err := key.Validate(); err != nil { - // If x509rsacrt=0 is set, try dropping the CRT values and - // rerunning precomputation and key validation. - if x509rsacrt.Value() == "0" { - key.Precomputed.Dp = nil - key.Precomputed.Dq = nil - key.Precomputed.Qinv = nil - key.Precompute() - if err := key.Validate(); err == nil { - x509rsacrt.IncNonDefault() - return key, nil - } - } - - return nil, err - } - - return key, nil -} - -// MarshalPKCS1PrivateKey converts an [RSA] private key to PKCS #1, ASN.1 DER form. -// -// This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY". -// For a more flexible key format which is not [RSA] specific, use -// [MarshalPKCS8PrivateKey]. -// -// The key must have passed validation by calling [rsa.PrivateKey.Validate] -// first. MarshalPKCS1PrivateKey calls [rsa.PrivateKey.Precompute], which may -// modify the key if not already precomputed. -func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { - key.Precompute() - - version := 0 - if len(key.Primes) > 2 { - version = 1 - } - - priv := pkcs1PrivateKey{ - Version: version, - N: key.N, - E: key.PublicKey.E, - D: key.D, - P: key.Primes[0], - Q: key.Primes[1], - Dp: key.Precomputed.Dp, - Dq: key.Precomputed.Dq, - Qinv: key.Precomputed.Qinv, - } - - priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues)) - for i, values := range key.Precomputed.CRTValues { - priv.AdditionalPrimes[i].Prime = key.Primes[2+i] - priv.AdditionalPrimes[i].Exp = values.Exp - priv.AdditionalPrimes[i].Coeff = values.Coeff - } - - b, _ := asn1.Marshal(priv) - return b -} - -// ParsePKCS1PublicKey parses an [RSA] public key in PKCS #1, ASN.1 DER form. -// -// This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY". -func ParsePKCS1PublicKey(der []byte) (*rsa.PublicKey, error) { - var pub pkcs1PublicKey - rest, err := asn1.Unmarshal(der, &pub) - if err != nil { - if _, err := asn1.Unmarshal(der, &publicKeyInfo{}); err == nil { - return nil, errors.New("x509: failed to parse public key (use ParsePKIXPublicKey instead for this key format)") - } - return nil, err - } - if len(rest) > 0 { - return nil, asn1.SyntaxError{Msg: "trailing data"} - } - - if pub.N.Sign() <= 0 || pub.E <= 0 { - return nil, errors.New("x509: public key contains zero or negative value") - } - if pub.E > 1<<31-1 { - return nil, errors.New("x509: public key contains large public exponent") - } - - return &rsa.PublicKey{ - E: pub.E, - N: pub.N, - }, nil -} - -// MarshalPKCS1PublicKey converts an [RSA] public key to PKCS #1, ASN.1 DER form. -// -// This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY". -func MarshalPKCS1PublicKey(key *rsa.PublicKey) []byte { - derBytes, _ := asn1.Marshal(pkcs1PublicKey{ - N: key.N, - E: key.E, - }) - return derBytes -} diff --git a/ca/x509pq/verify.go b/ca/x509pq/verify.go index 7cc0fb2e..5cf60f6a 100644 --- a/ca/x509pq/verify.go +++ b/ca/x509pq/verify.go @@ -2,392 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package x509 +package x509pq import ( - "bytes" - "crypto" - "crypto/x509/pkix" - "errors" - "fmt" - "iter" - "maps" - "net" - "net/netip" - "net/url" - "reflect" - "runtime" "strings" - "time" - "unicode/utf8" ) -type InvalidReason int - -const ( - // NotAuthorizedToSign results when a certificate is signed by another - // which isn't marked as a CA certificate. - NotAuthorizedToSign InvalidReason = iota - // Expired results when a certificate has expired, based on the time - // given in the VerifyOptions. - Expired - // CANotAuthorizedForThisName results when an intermediate or root - // certificate has a name constraint which doesn't permit a DNS or - // other name (including IP address) in the leaf certificate. - CANotAuthorizedForThisName - // TooManyIntermediates results when a path length constraint is - // violated. - TooManyIntermediates - // IncompatibleUsage results when the certificate's key usage indicates - // that it may only be used for a different purpose. - IncompatibleUsage - // NameMismatch results when the subject name of a parent certificate - // does not match the issuer name in the child. - NameMismatch - // NameConstraintsWithoutSANs is a legacy error and is no longer returned. - NameConstraintsWithoutSANs - // UnconstrainedName results when a CA certificate contains permitted - // name constraints, but leaf certificate contains a name of an - // unsupported or unconstrained type. - UnconstrainedName - // TooManyConstraints results when the number of comparison operations - // needed to check a certificate exceeds the limit set by - // VerifyOptions.MaxConstraintComparisions. This limit exists to - // prevent pathological certificates can consuming excessive amounts of - // CPU time to verify. - TooManyConstraints - // CANotAuthorizedForExtKeyUsage results when an intermediate or root - // certificate does not permit a requested extended key usage. - CANotAuthorizedForExtKeyUsage - // NoValidChains results when there are no valid chains to return. - NoValidChains -) - -// CertificateInvalidError results when an odd error occurs. Users of this -// library probably want to handle all these errors uniformly. -type CertificateInvalidError struct { - Cert *Certificate - Reason InvalidReason - Detail string -} - -func (e CertificateInvalidError) Error() string { - switch e.Reason { - case NotAuthorizedToSign: - return "x509: certificate is not authorized to sign other certificates" - case Expired: - return "x509: certificate has expired or is not yet valid: " + e.Detail - case CANotAuthorizedForThisName: - return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail - case CANotAuthorizedForExtKeyUsage: - return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail - case TooManyIntermediates: - return "x509: too many intermediates for path length constraint" - case IncompatibleUsage: - return "x509: certificate specifies an incompatible key usage" - case NameMismatch: - return "x509: issuer name does not match subject from issuing certificate" - case NameConstraintsWithoutSANs: - return "x509: issuer has name constraints but leaf doesn't have a SAN extension" - case UnconstrainedName: - return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail - case NoValidChains: - s := "x509: no valid chains built" - if e.Detail != "" { - s = fmt.Sprintf("%s: %s", s, e.Detail) - } - return s - } - return "x509: unknown error" -} - -// HostnameError results when the set of authorized names doesn't match the -// requested name. -type HostnameError struct { - Certificate *Certificate - Host string -} - -func (h HostnameError) Error() string { - c := h.Certificate - - if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) { - return "x509: certificate relies on legacy Common Name field, use SANs instead" - } - - var valid string - if ip := net.ParseIP(h.Host); ip != nil { - // Trying to validate an IP - if len(c.IPAddresses) == 0 { - return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" - } - for _, san := range c.IPAddresses { - if len(valid) > 0 { - valid += ", " - } - valid += san.String() - } - } else { - valid = strings.Join(c.DNSNames, ", ") - } - - if len(valid) == 0 { - return "x509: certificate is not valid for any names, but wanted to match " + h.Host - } - return "x509: certificate is valid for " + valid + ", not " + h.Host -} - -// UnknownAuthorityError results when the certificate issuer is unknown -type UnknownAuthorityError struct { - Cert *Certificate - // hintErr contains an error that may be helpful in determining why an - // authority wasn't found. - hintErr error - // hintCert contains a possible authority certificate that was rejected - // because of the error in hintErr. - hintCert *Certificate -} - -func (e UnknownAuthorityError) Error() string { - s := "x509: certificate signed by unknown authority" - if e.hintErr != nil { - certName := e.hintCert.Subject.CommonName - if len(certName) == 0 { - if len(e.hintCert.Subject.Organization) > 0 { - certName = e.hintCert.Subject.Organization[0] - } else { - certName = "serial:" + e.hintCert.SerialNumber.String() - } - } - s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName) - } - return s -} - -// SystemRootsError results when we fail to load the system root certificates. -type SystemRootsError struct { - Err error -} - -func (se SystemRootsError) Error() string { - msg := "x509: failed to load system roots and no roots provided" - if se.Err != nil { - return msg + "; " + se.Err.Error() - } - return msg -} - -func (se SystemRootsError) Unwrap() error { return se.Err } - -// errNotParsed is returned when a certificate without ASN.1 contents is -// verified. Platform-specific verification needs the ASN.1 contents. -var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate") - -// VerifyOptions contains parameters for Certificate.Verify. -type VerifyOptions struct { - // DNSName, if set, is checked against the leaf certificate with - // Certificate.VerifyHostname or the platform verifier. - DNSName string - - // Intermediates is an optional pool of certificates that are not trust - // anchors, but can be used to form a chain from the leaf certificate to a - // root certificate. - Intermediates *CertPool - // Roots is the set of trusted root certificates the leaf certificate needs - // to chain up to. If nil, the system roots or the platform verifier are used. - Roots *CertPool - - // CurrentTime is used to check the validity of all certificates in the - // chain. If zero, the current time is used. - CurrentTime time.Time - - // KeyUsages specifies which Extended Key Usage values are acceptable. A - // chain is accepted if it allows any of the listed values. An empty list - // means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny. - KeyUsages []ExtKeyUsage - - // MaxConstraintComparisions is the maximum number of comparisons to - // perform when checking a given certificate's name constraints. If - // zero, a sensible default is used. This limit prevents pathological - // certificates from consuming excessive amounts of CPU time when - // validating. It does not apply to the platform verifier. - MaxConstraintComparisions int - - // CertificatePolicies specifies which certificate policy OIDs are - // acceptable during policy validation. An empty CertificatePolices - // field implies any valid policy is acceptable. - CertificatePolicies []OID - - // The following policy fields are unexported, because we do not expect - // users to actually need to use them, but are useful for testing the - // policy validation code. - - // inhibitPolicyMapping indicates if policy mapping should be allowed - // during path validation. - inhibitPolicyMapping bool - - // requireExplicitPolicy indidicates if explicit policies must be present - // for each certificate being validated. - requireExplicitPolicy bool - - // inhibitAnyPolicy indicates if the anyPolicy policy should be - // processed if present in a certificate being validated. - inhibitAnyPolicy bool -} - -const ( - leafCertificate = iota - intermediateCertificate - rootCertificate -) - -// rfc2821Mailbox represents a “mailbox” (which is an email address to most -// people) by breaking it into the “local” (i.e. before the '@') and “domain” -// parts. -type rfc2821Mailbox struct { - local, domain string -} - -// parseRFC2821Mailbox parses an email address into local and domain parts, -// based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280, -// Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The -// format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”. -func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) { - if len(in) == 0 { - return mailbox, false - } - - localPartBytes := make([]byte, 0, len(in)/2) - - if in[0] == '"' { - // Quoted-string = DQUOTE *qcontent DQUOTE - // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 - // qcontent = qtext / quoted-pair - // qtext = non-whitespace-control / - // %d33 / %d35-91 / %d93-126 - // quoted-pair = ("\" text) / obs-qp - // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text - // - // (Names beginning with “obs-” are the obsolete syntax from RFC 2822, - // Section 4. Since it has been 16 years, we no longer accept that.) - in = in[1:] - QuotedString: - for { - if len(in) == 0 { - return mailbox, false - } - c := in[0] - in = in[1:] - - switch { - case c == '"': - break QuotedString - - case c == '\\': - // quoted-pair - if len(in) == 0 { - return mailbox, false - } - if in[0] == 11 || - in[0] == 12 || - (1 <= in[0] && in[0] <= 9) || - (14 <= in[0] && in[0] <= 127) { - localPartBytes = append(localPartBytes, in[0]) - in = in[1:] - } else { - return mailbox, false - } - - case c == 11 || - c == 12 || - // Space (char 32) is not allowed based on the - // BNF, but RFC 3696 gives an example that - // assumes that it is. Several “verified” - // errata continue to argue about this point. - // We choose to accept it. - c == 32 || - c == 33 || - c == 127 || - (1 <= c && c <= 8) || - (14 <= c && c <= 31) || - (35 <= c && c <= 91) || - (93 <= c && c <= 126): - // qtext - localPartBytes = append(localPartBytes, c) - - default: - return mailbox, false - } - } - } else { - // Atom ("." Atom)* - NextChar: - for len(in) > 0 { - // atext from RFC 2822, Section 3.2.4 - c := in[0] - - switch { - case c == '\\': - // Examples given in RFC 3696 suggest that - // escaped characters can appear outside of a - // quoted string. Several “verified” errata - // continue to argue the point. We choose to - // accept it. - in = in[1:] - if len(in) == 0 { - return mailbox, false - } - fallthrough - - case ('0' <= c && c <= '9') || - ('a' <= c && c <= 'z') || - ('A' <= c && c <= 'Z') || - c == '!' || c == '#' || c == '$' || c == '%' || - c == '&' || c == '\'' || c == '*' || c == '+' || - c == '-' || c == '/' || c == '=' || c == '?' || - c == '^' || c == '_' || c == '`' || c == '{' || - c == '|' || c == '}' || c == '~' || c == '.': - localPartBytes = append(localPartBytes, in[0]) - in = in[1:] - - default: - break NextChar - } - } - - if len(localPartBytes) == 0 { - return mailbox, false - } - - // From RFC 3696, Section 3: - // “period (".") may also appear, but may not be used to start - // or end the local part, nor may two or more consecutive - // periods appear.” - twoDots := []byte{'.', '.'} - if localPartBytes[0] == '.' || - localPartBytes[len(localPartBytes)-1] == '.' || - bytes.Contains(localPartBytes, twoDots) { - return mailbox, false - } - } - - if len(in) == 0 || in[0] != '@' { - return mailbox, false - } - in = in[1:] - - // The RFC species a format for domains, but that's known to be - // violated in practice so we accept that anything after an '@' is the - // domain part. - if _, ok := domainToReverseLabels(in); !ok { - return mailbox, false - } - - mailbox.local = string(localPartBytes) - mailbox.domain = in - return mailbox, true -} - // domainToReverseLabels converts a textual domain name like foo.example.com to // the list of labels in reverse order, e.g. ["com", "example", "foo"]. func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { @@ -427,1194 +47,3 @@ func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { return reverseLabels, true } - -func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) { - // If the constraint contains an @, then it specifies an exact mailbox - // name. - if strings.Contains(constraint, "@") { - constraintMailbox, ok := parseRFC2821Mailbox(constraint) - if !ok { - return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint) - } - return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil - } - - // Otherwise the constraint is like a DNS constraint of the domain part - // of the mailbox. - return matchDomainConstraint(mailbox.domain, constraint) -} - -func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { - // From RFC 5280, Section 4.2.1.10: - // “a uniformResourceIdentifier that does not include an authority - // component with a host name specified as a fully qualified domain - // name (e.g., if the URI either does not include an authority - // component or includes an authority component in which the host name - // is specified as an IP address), then the application MUST reject the - // certificate.” - - host := uri.Host - if len(host) == 0 { - return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String()) - } - - if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") { - var err error - host, _, err = net.SplitHostPort(uri.Host) - if err != nil { - return false, err - } - } - - // netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we - // check if _either_ the string parses as an IP, or if it is enclosed in - // square brackets. - if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) { - return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) - } - - return matchDomainConstraint(host, constraint) -} - -func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { - if len(ip) != len(constraint.IP) { - return false, nil - } - - for i := range ip { - if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask { - return false, nil - } - } - - return true, nil -} - -func matchDomainConstraint(domain, constraint string) (bool, error) { - // The meaning of zero length constraints is not specified, but this - // code follows NSS and accepts them as matching everything. - if len(constraint) == 0 { - return true, nil - } - - domainLabels, ok := domainToReverseLabels(domain) - if !ok { - return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) - } - - // RFC 5280 says that a leading period in a domain name means that at - // least one label must be prepended, but only for URI and email - // constraints, not DNS constraints. The code also supports that - // behaviour for DNS constraints. - - mustHaveSubdomains := false - if constraint[0] == '.' { - mustHaveSubdomains = true - constraint = constraint[1:] - } - - constraintLabels, ok := domainToReverseLabels(constraint) - if !ok { - return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) - } - - if len(domainLabels) < len(constraintLabels) || - (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) { - return false, nil - } - - for i, constraintLabel := range constraintLabels { - if !strings.EqualFold(constraintLabel, domainLabels[i]) { - return false, nil - } - } - - return true, nil -} - -// checkNameConstraints checks that c permits a child certificate to claim the -// given name, of type nameType. The argument parsedName contains the parsed -// form of name, suitable for passing to the match function. The total number -// of comparisons is tracked in the given count and should not exceed the given -// limit. -func (c *Certificate) checkNameConstraints(count *int, - maxConstraintComparisons int, - nameType string, - name string, - parsedName any, - match func(parsedName, constraint any) (match bool, err error), - permitted, excluded any) error { - - excludedValue := reflect.ValueOf(excluded) - - *count += excludedValue.Len() - if *count > maxConstraintComparisons { - return CertificateInvalidError{c, TooManyConstraints, ""} - } - - for i := 0; i < excludedValue.Len(); i++ { - constraint := excludedValue.Index(i).Interface() - match, err := match(parsedName, constraint) - if err != nil { - return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} - } - - if match { - return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)} - } - } - - permittedValue := reflect.ValueOf(permitted) - - *count += permittedValue.Len() - if *count > maxConstraintComparisons { - return CertificateInvalidError{c, TooManyConstraints, ""} - } - - ok := true - for i := 0; i < permittedValue.Len(); i++ { - constraint := permittedValue.Index(i).Interface() - - var err error - if ok, err = match(parsedName, constraint); err != nil { - return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} - } - - if ok { - break - } - } - - if !ok { - return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)} - } - - return nil -} - -// isValid performs validity checks on c given that it is a candidate to append -// to the chain in currentChain. -func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { - if len(c.UnhandledCriticalExtensions) > 0 { - return UnhandledCriticalExtension{} - } - - if len(currentChain) > 0 { - child := currentChain[len(currentChain)-1] - if !bytes.Equal(child.RawIssuer, c.RawSubject) { - return CertificateInvalidError{c, NameMismatch, ""} - } - } - - now := opts.CurrentTime - if now.IsZero() { - now = time.Now() - } - if now.Before(c.NotBefore) { - return CertificateInvalidError{ - Cert: c, - Reason: Expired, - Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)), - } - } else if now.After(c.NotAfter) { - return CertificateInvalidError{ - Cert: c, - Reason: Expired, - Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)), - } - } - - maxConstraintComparisons := opts.MaxConstraintComparisions - if maxConstraintComparisons == 0 { - maxConstraintComparisons = 250000 - } - comparisonCount := 0 - - if certType == intermediateCertificate || certType == rootCertificate { - if len(currentChain) == 0 { - return errors.New("x509: internal error: empty chain when appending CA cert") - } - } - - if (certType == intermediateCertificate || certType == rootCertificate) && - c.hasNameConstraints() { - toCheck := []*Certificate{} - for _, c := range currentChain { - if c.hasSANExtension() { - toCheck = append(toCheck, c) - } - } - for _, sanCert := range toCheck { - err := forEachSAN(sanCert.getSANExtension(), func(tag int, data []byte) error { - switch tag { - case nameTypeEmail: - name := string(data) - mailbox, ok := parseRFC2821Mailbox(name) - if !ok { - return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox) - } - - if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, - func(parsedName, constraint any) (bool, error) { - return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string)) - }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { - return err - } - - case nameTypeDNS: - name := string(data) - if _, ok := domainToReverseLabels(name); !ok { - return fmt.Errorf("x509: cannot parse dnsName %q", name) - } - - if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, - func(parsedName, constraint any) (bool, error) { - return matchDomainConstraint(parsedName.(string), constraint.(string)) - }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { - return err - } - - case nameTypeURI: - name := string(data) - uri, err := url.Parse(name) - if err != nil { - return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name) - } - - if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, - func(parsedName, constraint any) (bool, error) { - return matchURIConstraint(parsedName.(*url.URL), constraint.(string)) - }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { - return err - } - - case nameTypeIP: - ip := net.IP(data) - if l := len(ip); l != net.IPv4len && l != net.IPv6len { - return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data) - } - - if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip, - func(parsedName, constraint any) (bool, error) { - return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet)) - }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil { - return err - } - - default: - // Unknown SAN types are ignored. - } - - return nil - }) - - if err != nil { - return err - } - } - } - - // KeyUsage status flags are ignored. From Engineering Security, Peter - // Gutmann: A European government CA marked its signing certificates as - // being valid for encryption only, but no-one noticed. Another - // European CA marked its signature keys as not being valid for - // signatures. A different CA marked its own trusted root certificate - // as being invalid for certificate signing. Another national CA - // distributed a certificate to be used to encrypt data for the - // country’s tax authority that was marked as only being usable for - // digital signatures but not for encryption. Yet another CA reversed - // the order of the bit flags in the keyUsage due to confusion over - // encoding endianness, essentially setting a random keyUsage in - // certificates that it issued. Another CA created a self-invalidating - // certificate by adding a certificate policy statement stipulating - // that the certificate had to be used strictly as specified in the - // keyUsage, and a keyUsage containing a flag indicating that the RSA - // encryption key could only be used for Diffie-Hellman key agreement. - - if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) { - return CertificateInvalidError{c, NotAuthorizedToSign, ""} - } - - if c.BasicConstraintsValid && c.MaxPathLen >= 0 { - numIntermediates := len(currentChain) - 1 - if numIntermediates > c.MaxPathLen { - return CertificateInvalidError{c, TooManyIntermediates, ""} - } - } - - return nil -} - -// Verify attempts to verify c by building one or more chains from c to a -// certificate in opts.Roots, using certificates in opts.Intermediates if -// needed. If successful, it returns one or more chains where the first -// element of the chain is c and the last element is from opts.Roots. -// -// If opts.Roots is nil, the platform verifier might be used, and -// verification details might differ from what is described below. If system -// roots are unavailable the returned error will be of type SystemRootsError. -// -// Name constraints in the intermediates will be applied to all names claimed -// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim -// example.com if an intermediate doesn't permit it, even if example.com is not -// the name being validated. Note that DirectoryName constraints are not -// supported. -// -// Name constraint validation follows the rules from RFC 5280, with the -// addition that DNS name constraints may use the leading period format -// defined for emails and URIs. When a constraint has a leading period -// it indicates that at least one additional label must be prepended to -// the constrained name to be considered valid. -// -// Extended Key Usage values are enforced nested down a chain, so an intermediate -// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that -// list. (While this is not specified, it is common practice in order to limit -// the types of certificates a CA can issue.) -// -// Certificates that use SHA1WithRSA and ECDSAWithSHA1 signatures are not supported, -// and will not be used to build chains. -// -// Certificates other than c in the returned chains should not be modified. -// -// WARNING: this function doesn't do any revocation checking. -func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { - // Platform-specific verification needs the ASN.1 contents so - // this makes the behavior consistent across platforms. - if len(c.Raw) == 0 { - return nil, errNotParsed - } - for i := 0; i < opts.Intermediates.len(); i++ { - c, _, err := opts.Intermediates.cert(i) - if err != nil { - return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err) - } - if len(c.Raw) == 0 { - return nil, errNotParsed - } - } - - // Use platform verifiers, where available, if Roots is from SystemCertPool. - if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" { - // Don't use the system verifier if the system pool was replaced with a non-system pool, - // i.e. if SetFallbackRoots was called with x509usefallbackroots=1. - systemPool := systemRootsPool() - if opts.Roots == nil && (systemPool == nil || systemPool.systemPool) { - return c.systemVerify(&opts) - } - if opts.Roots != nil && opts.Roots.systemPool { - platformChains, err := c.systemVerify(&opts) - // If the platform verifier succeeded, or there are no additional - // roots, return the platform verifier result. Otherwise, continue - // with the Go verifier. - if err == nil || opts.Roots.len() == 0 { - return platformChains, err - } - } - } - - if opts.Roots == nil { - opts.Roots = systemRootsPool() - if opts.Roots == nil { - return nil, SystemRootsError{systemRootsErr} - } - } - - err = c.isValid(leafCertificate, nil, &opts) - if err != nil { - return - } - - if len(opts.DNSName) > 0 { - err = c.VerifyHostname(opts.DNSName) - if err != nil { - return - } - } - - var candidateChains [][]*Certificate - if opts.Roots.contains(c) { - candidateChains = [][]*Certificate{{c}} - } else { - candidateChains, err = c.buildChains([]*Certificate{c}, nil, &opts) - if err != nil { - return nil, err - } - } - - chains = make([][]*Certificate, 0, len(candidateChains)) - - var invalidPoliciesChains int - for _, candidate := range candidateChains { - if !policiesValid(candidate, opts) { - invalidPoliciesChains++ - continue - } - chains = append(chains, candidate) - } - - if len(chains) == 0 { - return nil, CertificateInvalidError{c, NoValidChains, "all candidate chains have invalid policies"} - } - - for _, eku := range opts.KeyUsages { - if eku == ExtKeyUsageAny { - // If any key usage is acceptable, no need to check the chain for - // key usages. - return chains, nil - } - } - - if len(opts.KeyUsages) == 0 { - opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} - } - - candidateChains = chains - chains = chains[:0] - - var incompatibleKeyUsageChains int - for _, candidate := range candidateChains { - if !checkChainForKeyUsage(candidate, opts.KeyUsages) { - incompatibleKeyUsageChains++ - continue - } - chains = append(chains, candidate) - } - - if len(chains) == 0 { - var details []string - if incompatibleKeyUsageChains > 0 { - if invalidPoliciesChains == 0 { - return nil, CertificateInvalidError{c, IncompatibleUsage, ""} - } - details = append(details, fmt.Sprintf("%d chains with incompatible key usage", incompatibleKeyUsageChains)) - } - if invalidPoliciesChains > 0 { - details = append(details, fmt.Sprintf("%d chains with invalid policies", invalidPoliciesChains)) - } - err = CertificateInvalidError{c, NoValidChains, strings.Join(details, ", ")} - return nil, err - } - - return chains, nil -} - -func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { - n := make([]*Certificate, len(chain)+1) - copy(n, chain) - n[len(chain)] = cert - 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 -// for failed checks due to different intermediates having the same Subject. -const maxChainSignatureChecks = 100 - -func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) { - var ( - hintErr error - hintCert *Certificate - ) - - considerCandidate := func(certType int, candidate potentialParent) { - if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) { - return - } - - if sigChecks == nil { - sigChecks = new(int) - } - *sigChecks++ - if *sigChecks > maxChainSignatureChecks { - err = errors.New("x509: signature check attempts limit reached while verifying certificate chain") - return - } - - if err := c.CheckSignatureFrom(candidate.cert); err != nil { - if hintErr == nil { - hintErr = err - hintCert = candidate.cert - } - return - } - - err = candidate.cert.isValid(certType, currentChain, opts) - if err != nil { - if hintErr == nil { - hintErr = err - hintCert = candidate.cert - } - return - } - - if candidate.constraint != nil { - if err := candidate.constraint(currentChain); err != nil { - if hintErr == nil { - hintErr = err - hintCert = candidate.cert - } - return - } - } - - switch certType { - case rootCertificate: - chains = append(chains, appendToFreshChain(currentChain, candidate.cert)) - case intermediateCertificate: - var childChains [][]*Certificate - childChains, err = candidate.cert.buildChains(appendToFreshChain(currentChain, candidate.cert), sigChecks, opts) - chains = append(chains, childChains...) - } - } - - for _, root := range opts.Roots.findPotentialParents(c) { - considerCandidate(rootCertificate, root) - } - for _, intermediate := range opts.Intermediates.findPotentialParents(c) { - considerCandidate(intermediateCertificate, intermediate) - } - - if len(chains) > 0 { - err = nil - } - if len(chains) == 0 && err == nil { - err = UnknownAuthorityError{c, hintErr, hintCert} - } - - return -} - -func validHostnamePattern(host string) bool { return validHostname(host, true) } -func validHostnameInput(host string) bool { return validHostname(host, false) } - -// validHostname reports whether host is a valid hostname that can be matched or -// matched against according to RFC 6125 2.2, with some leniency to accommodate -// legacy values. -func validHostname(host string, isPattern bool) bool { - if !isPattern { - host = strings.TrimSuffix(host, ".") - } - if len(host) == 0 { - return false - } - if host == "*" { - // Bare wildcards are not allowed, they are not valid DNS names, - // nor are they allowed per RFC 6125. - return false - } - - for i, part := range strings.Split(host, ".") { - if part == "" { - // Empty label. - return false - } - if isPattern && i == 0 && part == "*" { - // Only allow full left-most wildcards, as those are the only ones - // we match, and matching literal '*' characters is probably never - // the expected behavior. - continue - } - for j, c := range part { - if 'a' <= c && c <= 'z' { - continue - } - if '0' <= c && c <= '9' { - continue - } - if 'A' <= c && c <= 'Z' { - continue - } - if c == '-' && j != 0 { - continue - } - if c == '_' { - // Not a valid character in hostnames, but commonly - // found in deployments outside the WebPKI. - continue - } - return false - } - } - - return true -} - -func matchExactly(hostA, hostB string) bool { - if hostA == "" || hostA == "." || hostB == "" || hostB == "." { - return false - } - return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB) -} - -func matchHostnames(pattern, host string) bool { - pattern = toLowerCaseASCII(pattern) - host = toLowerCaseASCII(strings.TrimSuffix(host, ".")) - - if len(pattern) == 0 || len(host) == 0 { - return false - } - - patternParts := strings.Split(pattern, ".") - hostParts := strings.Split(host, ".") - - if len(patternParts) != len(hostParts) { - return false - } - - for i, patternPart := range patternParts { - if i == 0 && patternPart == "*" { - continue - } - if patternPart != hostParts[i] { - return false - } - } - - return true -} - -// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use -// an explicitly ASCII function to avoid any sharp corners resulting from -// performing Unicode operations on DNS labels. -func toLowerCaseASCII(in string) string { - // If the string is already lower-case then there's nothing to do. - isAlreadyLowerCase := true - for _, c := range in { - if c == utf8.RuneError { - // If we get a UTF-8 error then there might be - // upper-case ASCII bytes in the invalid sequence. - isAlreadyLowerCase = false - break - } - if 'A' <= c && c <= 'Z' { - isAlreadyLowerCase = false - break - } - } - - if isAlreadyLowerCase { - return in - } - - out := []byte(in) - for i, c := range out { - if 'A' <= c && c <= 'Z' { - out[i] += 'a' - 'A' - } - } - return string(out) -} - -// VerifyHostname returns nil if c is a valid certificate for the named host. -// Otherwise it returns an error describing the mismatch. -// -// IP addresses can be optionally enclosed in square brackets and are checked -// against the IPAddresses field. Other names are checked case insensitively -// against the DNSNames field. If the names are valid hostnames, the certificate -// fields can have a wildcard as the complete left-most label (e.g. *.example.com). -// -// Note that the legacy Common Name field is ignored. -func (c *Certificate) VerifyHostname(h string) error { - // IP addresses may be written in [ ]. - candidateIP := h - if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { - candidateIP = h[1 : len(h)-1] - } - if ip := net.ParseIP(candidateIP); ip != nil { - // We only match IP addresses against IP SANs. - // See RFC 6125, Appendix B.2. - for _, candidate := range c.IPAddresses { - if ip.Equal(candidate) { - return nil - } - } - return HostnameError{c, candidateIP} - } - - candidateName := toLowerCaseASCII(h) // Save allocations inside the loop. - validCandidateName := validHostnameInput(candidateName) - - for _, match := range c.DNSNames { - // Ideally, we'd only match valid hostnames according to RFC 6125 like - // browsers (more or less) do, but in practice Go is used in a wider - // array of contexts and can't even assume DNS resolution. Instead, - // always allow perfect matches, and only apply wildcard and trailing - // dot processing to valid hostnames. - if validCandidateName && validHostnamePattern(match) { - if matchHostnames(match, candidateName) { - return nil - } - } else { - if matchExactly(match, candidateName) { - return nil - } - } - } - - return HostnameError{c, h} -} - -func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { - usages := make([]ExtKeyUsage, len(keyUsages)) - copy(usages, keyUsages) - - if len(chain) == 0 { - return false - } - - usagesRemaining := len(usages) - - // We walk down the list and cross out any usages that aren't supported - // by each certificate. If we cross out all the usages, then the chain - // is unacceptable. - -NextCert: - for i := len(chain) - 1; i >= 0; i-- { - cert := chain[i] - if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { - // The certificate doesn't have any extended key usage specified. - continue - } - - for _, usage := range cert.ExtKeyUsage { - if usage == ExtKeyUsageAny { - // The certificate is explicitly good for any usage. - continue NextCert - } - } - - const invalidUsage ExtKeyUsage = -1 - - NextRequestedUsage: - for i, requestedUsage := range usages { - if requestedUsage == invalidUsage { - continue - } - - for _, usage := range cert.ExtKeyUsage { - if requestedUsage == usage { - continue NextRequestedUsage - } - } - - usages[i] = invalidUsage - usagesRemaining-- - if usagesRemaining == 0 { - return false - } - } - } - - return true -} - -func mustNewOIDFromInts(ints []uint64) OID { - oid, err := OIDFromInts(ints) - if err != nil { - panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err)) - } - return oid -} - -type policyGraphNode struct { - validPolicy OID - expectedPolicySet []OID - // we do not implement qualifiers, so we don't track qualifier_set - - parents map[*policyGraphNode]bool - children map[*policyGraphNode]bool -} - -func newPolicyGraphNode(valid OID, parents []*policyGraphNode) *policyGraphNode { - n := &policyGraphNode{ - validPolicy: valid, - expectedPolicySet: []OID{valid}, - children: map[*policyGraphNode]bool{}, - parents: map[*policyGraphNode]bool{}, - } - for _, p := range parents { - p.children[n] = true - n.parents[p] = true - } - return n -} - -type policyGraph struct { - strata []map[string]*policyGraphNode - // map of OID -> nodes at strata[depth-1] with OID in their expectedPolicySet - parentIndex map[string][]*policyGraphNode - depth int -} - -var anyPolicyOID = mustNewOIDFromInts([]uint64{2, 5, 29, 32, 0}) - -func newPolicyGraph() *policyGraph { - root := policyGraphNode{ - validPolicy: anyPolicyOID, - expectedPolicySet: []OID{anyPolicyOID}, - children: map[*policyGraphNode]bool{}, - parents: map[*policyGraphNode]bool{}, - } - return &policyGraph{ - depth: 0, - strata: []map[string]*policyGraphNode{{string(anyPolicyOID.der): &root}}, - } -} - -func (pg *policyGraph) insert(n *policyGraphNode) { - pg.strata[pg.depth][string(n.validPolicy.der)] = n -} - -func (pg *policyGraph) parentsWithExpected(expected OID) []*policyGraphNode { - if pg.depth == 0 { - return nil - } - return pg.parentIndex[string(expected.der)] -} - -func (pg *policyGraph) parentWithAnyPolicy() *policyGraphNode { - if pg.depth == 0 { - return nil - } - return pg.strata[pg.depth-1][string(anyPolicyOID.der)] -} - -func (pg *policyGraph) parents() iter.Seq[*policyGraphNode] { - if pg.depth == 0 { - return nil - } - return maps.Values(pg.strata[pg.depth-1]) -} - -func (pg *policyGraph) leaves() map[string]*policyGraphNode { - return pg.strata[pg.depth] -} - -func (pg *policyGraph) leafWithPolicy(policy OID) *policyGraphNode { - return pg.strata[pg.depth][string(policy.der)] -} - -func (pg *policyGraph) deleteLeaf(policy OID) { - n := pg.strata[pg.depth][string(policy.der)] - if n == nil { - return - } - for p := range n.parents { - delete(p.children, n) - } - for c := range n.children { - delete(c.parents, n) - } - delete(pg.strata[pg.depth], string(policy.der)) -} - -func (pg *policyGraph) validPolicyNodes() []*policyGraphNode { - var validNodes []*policyGraphNode - for i := pg.depth; i >= 0; i-- { - for _, n := range pg.strata[i] { - if n.validPolicy.Equal(anyPolicyOID) { - continue - } - - if len(n.parents) == 1 { - for p := range n.parents { - if p.validPolicy.Equal(anyPolicyOID) { - validNodes = append(validNodes, n) - } - } - } - } - } - return validNodes -} - -func (pg *policyGraph) prune() { - for i := pg.depth - 1; i > 0; i-- { - for _, n := range pg.strata[i] { - if len(n.children) == 0 { - for p := range n.parents { - delete(p.children, n) - } - delete(pg.strata[i], string(n.validPolicy.der)) - } - } - } -} - -func (pg *policyGraph) incrDepth() { - pg.parentIndex = map[string][]*policyGraphNode{} - for _, n := range pg.strata[pg.depth] { - for _, e := range n.expectedPolicySet { - pg.parentIndex[string(e.der)] = append(pg.parentIndex[string(e.der)], n) - } - } - - pg.depth++ - pg.strata = append(pg.strata, map[string]*policyGraphNode{}) -} - -func policiesValid(chain []*Certificate, opts VerifyOptions) bool { - // The following code implements the policy verification algorithm as - // specified in RFC 5280 and updated by RFC 9618. In particular the - // following sections are replaced by RFC 9618: - // * 6.1.2 (a) - // * 6.1.3 (d) - // * 6.1.3 (e) - // * 6.1.3 (f) - // * 6.1.4 (b) - // * 6.1.5 (g) - - if len(chain) == 1 { - return true - } - - // n is the length of the chain minus the trust anchor - n := len(chain) - 1 - - pg := newPolicyGraph() - var inhibitAnyPolicy, explicitPolicy, policyMapping int - if !opts.inhibitAnyPolicy { - inhibitAnyPolicy = n + 1 - } - if !opts.requireExplicitPolicy { - explicitPolicy = n + 1 - } - if !opts.inhibitPolicyMapping { - policyMapping = n + 1 - } - - initialUserPolicySet := map[string]bool{} - for _, p := range opts.CertificatePolicies { - initialUserPolicySet[string(p.der)] = true - } - // If the user does not pass any policies, we consider - // that equivalent to passing anyPolicyOID. - if len(initialUserPolicySet) == 0 { - initialUserPolicySet[string(anyPolicyOID.der)] = true - } - - for i := n - 1; i >= 0; i-- { - cert := chain[i] - - isSelfSigned := bytes.Equal(cert.RawIssuer, cert.RawSubject) - - // 6.1.3 (e) -- as updated by RFC 9618 - if len(cert.Policies) == 0 { - pg = nil - } - - // 6.1.3 (f) -- as updated by RFC 9618 - if explicitPolicy == 0 && pg == nil { - return false - } - - if pg != nil { - pg.incrDepth() - - policies := map[string]bool{} - - // 6.1.3 (d) (1) -- as updated by RFC 9618 - for _, policy := range cert.Policies { - policies[string(policy.der)] = true - - if policy.Equal(anyPolicyOID) { - continue - } - - // 6.1.3 (d) (1) (i) -- as updated by RFC 9618 - parents := pg.parentsWithExpected(policy) - if len(parents) == 0 { - // 6.1.3 (d) (1) (ii) -- as updated by RFC 9618 - if anyParent := pg.parentWithAnyPolicy(); anyParent != nil { - parents = []*policyGraphNode{anyParent} - } - } - if len(parents) > 0 { - pg.insert(newPolicyGraphNode(policy, parents)) - } - } - - // 6.1.3 (d) (2) -- as updated by RFC 9618 - // NOTE: in the check "n-i < n" our i is different from the i in the specification. - // In the specification chains go from the trust anchor to the leaf, whereas our - // chains go from the leaf to the trust anchor, so our i's our inverted. Our - // check here matches the check "i < n" in the specification. - if policies[string(anyPolicyOID.der)] && (inhibitAnyPolicy > 0 || (n-i < n && isSelfSigned)) { - missing := map[string][]*policyGraphNode{} - leaves := pg.leaves() - for p := range pg.parents() { - for _, expected := range p.expectedPolicySet { - if leaves[string(expected.der)] == nil { - missing[string(expected.der)] = append(missing[string(expected.der)], p) - } - } - } - - for oidStr, parents := range missing { - pg.insert(newPolicyGraphNode(OID{der: []byte(oidStr)}, parents)) - } - } - - // 6.1.3 (d) (3) -- as updated by RFC 9618 - pg.prune() - - if i != 0 { - // 6.1.4 (b) -- as updated by RFC 9618 - if len(cert.PolicyMappings) > 0 { - // collect map of issuer -> []subject - mappings := map[string][]OID{} - - for _, mapping := range cert.PolicyMappings { - if policyMapping > 0 { - if mapping.IssuerDomainPolicy.Equal(anyPolicyOID) || mapping.SubjectDomainPolicy.Equal(anyPolicyOID) { - // Invalid mapping - return false - } - mappings[string(mapping.IssuerDomainPolicy.der)] = append(mappings[string(mapping.IssuerDomainPolicy.der)], mapping.SubjectDomainPolicy) - } else { - // 6.1.4 (b) (3) (i) -- as updated by RFC 9618 - pg.deleteLeaf(mapping.IssuerDomainPolicy) - - // 6.1.4 (b) (3) (ii) -- as updated by RFC 9618 - pg.prune() - } - } - - for issuerStr, subjectPolicies := range mappings { - // 6.1.4 (b) (1) -- as updated by RFC 9618 - if matching := pg.leafWithPolicy(OID{der: []byte(issuerStr)}); matching != nil { - matching.expectedPolicySet = subjectPolicies - } else if matching := pg.leafWithPolicy(anyPolicyOID); matching != nil { - // 6.1.4 (b) (2) -- as updated by RFC 9618 - n := newPolicyGraphNode(OID{der: []byte(issuerStr)}, []*policyGraphNode{matching}) - n.expectedPolicySet = subjectPolicies - pg.insert(n) - } - } - } - } - } - - if i != 0 { - // 6.1.4 (h) - if !isSelfSigned { - if explicitPolicy > 0 { - explicitPolicy-- - } - if policyMapping > 0 { - policyMapping-- - } - if inhibitAnyPolicy > 0 { - inhibitAnyPolicy-- - } - } - - // 6.1.4 (i) - if (cert.RequireExplicitPolicy > 0 || cert.RequireExplicitPolicyZero) && cert.RequireExplicitPolicy < explicitPolicy { - explicitPolicy = cert.RequireExplicitPolicy - } - if (cert.InhibitPolicyMapping > 0 || cert.InhibitPolicyMappingZero) && cert.InhibitPolicyMapping < policyMapping { - policyMapping = cert.InhibitPolicyMapping - } - // 6.1.4 (j) - if (cert.InhibitAnyPolicy > 0 || cert.InhibitAnyPolicyZero) && cert.InhibitAnyPolicy < inhibitAnyPolicy { - inhibitAnyPolicy = cert.InhibitAnyPolicy - } - } - } - - // 6.1.5 (a) - if explicitPolicy > 0 { - explicitPolicy-- - } - - // 6.1.5 (b) - if chain[0].RequireExplicitPolicyZero { - explicitPolicy = 0 - } - - // 6.1.5 (g) (1) -- as updated by RFC 9618 - var validPolicyNodeSet []*policyGraphNode - // 6.1.5 (g) (2) -- as updated by RFC 9618 - if pg != nil { - validPolicyNodeSet = pg.validPolicyNodes() - // 6.1.5 (g) (3) -- as updated by RFC 9618 - if currentAny := pg.leafWithPolicy(anyPolicyOID); currentAny != nil { - validPolicyNodeSet = append(validPolicyNodeSet, currentAny) - } - } - - // 6.1.5 (g) (4) -- as updated by RFC 9618 - authorityConstrainedPolicySet := map[string]bool{} - for _, n := range validPolicyNodeSet { - authorityConstrainedPolicySet[string(n.validPolicy.der)] = true - } - // 6.1.5 (g) (5) -- as updated by RFC 9618 - userConstrainedPolicySet := maps.Clone(authorityConstrainedPolicySet) - // 6.1.5 (g) (6) -- as updated by RFC 9618 - if len(initialUserPolicySet) != 1 || !initialUserPolicySet[string(anyPolicyOID.der)] { - // 6.1.5 (g) (6) (i) -- as updated by RFC 9618 - for p := range userConstrainedPolicySet { - if !initialUserPolicySet[p] { - delete(userConstrainedPolicySet, p) - } - } - // 6.1.5 (g) (6) (ii) -- as updated by RFC 9618 - if authorityConstrainedPolicySet[string(anyPolicyOID.der)] { - for policy := range initialUserPolicySet { - userConstrainedPolicySet[policy] = true - } - } - } - - if explicitPolicy == 0 && len(userConstrainedPolicySet) == 0 { - return false - } - - return true -} diff --git a/ca/x509pq/x509.go b/ca/x509pq/x509.go index 88eaadb4..4c651a10 100644 --- a/ca/x509pq/x509.go +++ b/ca/x509pq/x509.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package x509 implements a subset of the X.509 standard. +// Package x509pq implements a subset of the X.509 standard. // // It allows parsing and generating certificates, certificate signing // requests, certificate revocation lists, and encoded public and private keys. @@ -18,7 +18,7 @@ // On macOS and Windows, certificate verification is handled by system APIs, but // the package aims to apply consistent validation rules across operating // systems. -package x509 +package x509pq import ( "bytes" @@ -28,14 +28,11 @@ import ( "crypto/ed25519" "crypto/elliptic" "crypto/rsa" - "crypto/sha1" "crypto/sha256" "crypto/x509/pkix" "encoding/asn1" - "encoding/pem" "errors" "fmt" - "internal/godebug" "io" "math/big" "net" @@ -61,27 +58,6 @@ type pkixPublicKey struct { BitString asn1.BitString } -// ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form. The encoded -// public key is a SubjectPublicKeyInfo structure (see RFC 5280, Section 4.1). -// -// It returns a *[rsa.PublicKey], *[dsa.PublicKey], *[ecdsa.PublicKey], -// [ed25519.PublicKey] (not a pointer), or *[ecdh.PublicKey] (for X25519). -// More types might be supported in the future. -// -// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". -func ParsePKIXPublicKey(derBytes []byte) (pub any, err error) { - var pki publicKeyInfo - if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { - if _, err := asn1.Unmarshal(derBytes, &pkcs1PublicKey{}); err == nil { - return nil, errors.New("x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)") - } - return nil, err - } else if len(rest) != 0 { - return nil, errors.New("x509: trailing data after ASN.1 of public-key") - } - return parsePublicKey(&pki) -} - func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { switch pub := pub.(type) { case *rsa.PublicKey: @@ -900,60 +876,6 @@ func (c *Certificate) Equal(other *Certificate) bool { return bytes.Equal(c.Raw, other.Raw) } -func (c *Certificate) hasSANExtension() bool { - return oidInExtensions(oidExtensionSubjectAltName, c.Extensions) -} - -// CheckSignatureFrom verifies that the signature on c is a valid signature from parent. -// -// This is a low-level API that performs very limited checks, and not a full -// path verifier. Most users should use [Certificate.Verify] instead. -func (c *Certificate) CheckSignatureFrom(parent *Certificate) error { - // RFC 5280, 4.2.1.9: - // "If the basic constraints extension is not present in a version 3 - // certificate, or the extension is present but the cA boolean is not - // asserted, then the certified public key MUST NOT be used to verify - // certificate signatures." - if parent.Version == 3 && !parent.BasicConstraintsValid || - parent.BasicConstraintsValid && !parent.IsCA { - return ConstraintViolationError{} - } - - if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 { - return ConstraintViolationError{} - } - - if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { - return ErrUnsupportedAlgorithm - } - - return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, false) -} - -// CheckSignature verifies that signature is a valid signature over signed from -// c's public key. -// -// This is a low-level API that performs no validity checks on the certificate. -// -// [MD5WithRSA] signatures are rejected, while [SHA1WithRSA] and [ECDSAWithSHA1] -// signatures are currently accepted. -func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error { - return checkSignature(algo, signed, signature, c.PublicKey, true) -} - -func (c *Certificate) hasNameConstraints() bool { - return oidInExtensions(oidExtensionNameConstraints, c.Extensions) -} - -func (c *Certificate) getSANExtension() []byte { - for _, e := range c.Extensions { - if e.Id.Equal(oidExtensionSubjectAltName) { - return e.Value - } - } - return nil -} - func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey any) error { return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey) } @@ -1024,14 +946,6 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey return ErrUnsupportedAlgorithm } -// CheckCRLSignature checks that the signature in crl is from c. -// -// Deprecated: Use [RevocationList.CheckSignatureFrom] instead. -func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error { - algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm) - return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) -} - type UnhandledCriticalExtension struct{} func (h UnhandledCriticalExtension) Error() string { @@ -1177,8 +1091,6 @@ func isIA5String(s string) error { return nil } -var x509usepolicies = godebug.New("x509usepolicies") - func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) n := 0 @@ -1264,8 +1176,7 @@ func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKe n++ } - usePolicies := x509usepolicies.Value() != "0" - if ((!usePolicies && len(template.PolicyIdentifiers) > 0) || (usePolicies && len(template.Policies) > 0)) && + if len(template.Policies) > 0 && !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { ret[n], err = marshalCertificatePolicies(template.Policies, template.PolicyIdentifiers) if err != nil { @@ -1452,30 +1363,21 @@ func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pk return ext, err } -func marshalCertificatePolicies(policies []OID, policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) { +func marshalCertificatePolicies(policies []OID, _ []asn1.ObjectIdentifier) (pkix.Extension, error) { ext := pkix.Extension{Id: oidExtensionCertificatePolicies} b := cryptobyte.NewBuilder(make([]byte, 0, 128)) b.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - if x509usepolicies.Value() != "0" { - x509usepolicies.IncNonDefault() - for _, v := range policies { - child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) { - if len(v.der) == 0 { - child.SetError(errors.New("invalid policy object identifier")) - return - } - child.AddBytes(v.der) - }) + for _, v := range policies { + child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { + child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) { + if len(v.der) == 0 { + child.SetError(errors.New("invalid policy object identifier")) + return + } + child.AddBytes(v.der) }) - } - } else { - for _, v := range policyIdentifiers { - child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - child.AddASN1ObjectIdentifier(v) - }) - } + }) } }) @@ -1484,25 +1386,6 @@ func marshalCertificatePolicies(policies []OID, policyIdentifiers []asn1.ObjectI return ext, err } -func buildCSRExtensions(template *CertificateRequest) ([]pkix.Extension, error) { - var ret []pkix.Extension - - if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && - !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { - sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) - if err != nil { - return nil, err - } - - ret = append(ret, pkix.Extension{ - Id: oidExtensionSubjectAltName, - Value: sanBytes, - }) - } - - return append(ret, template.ExtraExtensions...), nil -} - func subjectBytes(cert *Certificate) ([]byte, error) { if len(cert.RawSubject) > 0 { return cert.RawSubject, nil @@ -1733,22 +1616,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv subjectKeyId := template.SubjectKeyId if len(subjectKeyId) == 0 && template.IsCA { - if x509sha256skid.Value() == "0" { - x509sha256skid.IncNonDefault() - // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2: - // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the - // value of the BIT STRING subjectPublicKey (excluding the tag, - // length, and number of unused bits). - h := sha1.Sum(publicKeyBytes) - subjectKeyId = h[:] - } else { - // SubjectKeyId generated using method 1 in RFC 7093, Section 2: - // 1) The keyIdentifier is composed of the leftmost 160-bits of the - // SHA-256 hash of the value of the BIT STRING subjectPublicKey - // (excluding the tag, length, and number of unused bits). - h := sha256.Sum256(publicKeyBytes) - subjectKeyId = h[:20] - } + // SubjectKeyId generated using method 1 in RFC 7093, Section 2: + // 1) The keyIdentifier is composed of the leftmost 160-bits of the + // SHA-256 hash of the value of the BIT STRING subjectPublicKey + // (excluding the tag, length, and number of unused bits). + h := sha256.Sum256(publicKeyBytes) + subjectKeyId = h[:20] } // Check that the signer's public key matches the private key, if available. @@ -1795,775 +1668,3 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } - -var x509sha256skid = godebug.New("x509sha256skid") - -// pemCRLPrefix is the magic string that indicates that we have a PEM encoded -// CRL. -var pemCRLPrefix = []byte("-----BEGIN X509 CRL") - -// pemType is the type of a PEM encoded CRL. -var pemType = "X509 CRL" - -// ParseCRL parses a CRL from the given bytes. It's often the case that PEM -// encoded CRLs will appear where they should be DER encoded, so this function -// will transparently handle PEM encoding as long as there isn't any leading -// garbage. -// -// Deprecated: Use [ParseRevocationList] instead. -func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) { - if bytes.HasPrefix(crlBytes, pemCRLPrefix) { - block, _ := pem.Decode(crlBytes) - if block != nil && block.Type == pemType { - crlBytes = block.Bytes - } - } - return ParseDERCRL(crlBytes) -} - -// ParseDERCRL parses a DER encoded CRL from the given bytes. -// -// Deprecated: Use [ParseRevocationList] instead. -func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) { - certList := new(pkix.CertificateList) - if rest, err := asn1.Unmarshal(derBytes, certList); err != nil { - return nil, err - } else if len(rest) != 0 { - return nil, errors.New("x509: trailing data after CRL") - } - return certList, nil -} - -// CreateCRL returns a DER encoded CRL, signed by this Certificate, that -// contains the given list of revoked certificates. -// -// Deprecated: this method does not generate an RFC 5280 conformant X.509 v2 CRL. -// To generate a standards compliant CRL, use [CreateRevocationList] instead. -func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { - key, ok := priv.(crypto.Signer) - if !ok { - return nil, errors.New("x509: certificate private key does not implement crypto.Signer") - } - - signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, 0) - if err != nil { - return nil, err - } - - // Force revocation times to UTC per RFC 5280. - revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts)) - for i, rc := range revokedCerts { - rc.RevocationTime = rc.RevocationTime.UTC() - revokedCertsUTC[i] = rc - } - - tbsCertList := pkix.TBSCertificateList{ - Version: 1, - Signature: algorithmIdentifier, - Issuer: c.Subject.ToRDNSequence(), - ThisUpdate: now.UTC(), - NextUpdate: expiry.UTC(), - RevokedCertificates: revokedCertsUTC, - } - - // Authority Key Id - if len(c.SubjectKeyId) > 0 { - var aki pkix.Extension - aki.Id = oidExtensionAuthorityKeyId - aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) - if err != nil { - return nil, err - } - tbsCertList.Extensions = append(tbsCertList.Extensions, aki) - } - - tbsCertListContents, err := asn1.Marshal(tbsCertList) - if err != nil { - return nil, err - } - tbsCertList.Raw = tbsCertListContents - - signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand) - if err != nil { - return nil, err - } - - return asn1.Marshal(pkix.CertificateList{ - TBSCertList: tbsCertList, - SignatureAlgorithm: algorithmIdentifier, - SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, - }) -} - -// CertificateRequest represents a PKCS #10, certificate signature request. -type CertificateRequest struct { - Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature). - RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content. - RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. - RawSubject []byte // DER encoded Subject. - - Version int - Signature []byte - SignatureAlgorithm SignatureAlgorithm - - PublicKeyAlgorithm PublicKeyAlgorithm - PublicKey any - - Subject pkix.Name - - // Attributes contains the CSR attributes that can parse as - // pkix.AttributeTypeAndValueSET. - // - // Deprecated: Use Extensions and ExtraExtensions instead for parsing and - // generating the requestedExtensions attribute. - Attributes []pkix.AttributeTypeAndValueSET - - // Extensions contains all requested extensions, in raw form. When parsing - // CSRs, this can be used to extract extensions that are not parsed by this - // package. - Extensions []pkix.Extension - - // ExtraExtensions contains extensions to be copied, raw, into any CSR - // marshaled by CreateCertificateRequest. Values override any extensions - // that would otherwise be produced based on the other fields but are - // overridden by any extensions specified in Attributes. - // - // The ExtraExtensions field is not populated by ParseCertificateRequest, - // see Extensions instead. - ExtraExtensions []pkix.Extension - - // Subject Alternate Name values. - DNSNames []string - EmailAddresses []string - IPAddresses []net.IP - URIs []*url.URL -} - -// These structures reflect the ASN.1 structure of X.509 certificate -// signature requests (see RFC 2986): - -type tbsCertificateRequest struct { - Raw asn1.RawContent - Version int - Subject asn1.RawValue - PublicKey publicKeyInfo - RawAttributes []asn1.RawValue `asn1:"tag:0"` -} - -type certificateRequest struct { - Raw asn1.RawContent - TBSCSR tbsCertificateRequest - SignatureAlgorithm pkix.AlgorithmIdentifier - SignatureValue asn1.BitString -} - -// oidExtensionRequest is a PKCS #9 OBJECT IDENTIFIER that indicates requested -// extensions in a CSR. -var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} - -// newRawAttributes converts AttributeTypeAndValueSETs from a template -// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes. -func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { - var rawAttributes []asn1.RawValue - b, err := asn1.Marshal(attributes) - if err != nil { - return nil, err - } - rest, err := asn1.Unmarshal(b, &rawAttributes) - if err != nil { - return nil, err - } - if len(rest) != 0 { - return nil, errors.New("x509: failed to unmarshal raw CSR Attributes") - } - return rawAttributes, nil -} - -// parseRawAttributes Unmarshals RawAttributes into AttributeTypeAndValueSETs. -func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET { - var attributes []pkix.AttributeTypeAndValueSET - for _, rawAttr := range rawAttributes { - var attr pkix.AttributeTypeAndValueSET - rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr) - // Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET - // (i.e.: challengePassword or unstructuredName). - if err == nil && len(rest) == 0 { - attributes = append(attributes, attr) - } - } - return attributes -} - -// parseCSRExtensions parses the attributes from a CSR and extracts any -// requested extensions. -func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) { - // pkcs10Attribute reflects the Attribute structure from RFC 2986, Section 4.1. - type pkcs10Attribute struct { - Id asn1.ObjectIdentifier - Values []asn1.RawValue `asn1:"set"` - } - - var ret []pkix.Extension - requestedExts := make(map[string]bool) - for _, rawAttr := range rawAttributes { - var attr pkcs10Attribute - if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 { - // Ignore attributes that don't parse. - continue - } - - if !attr.Id.Equal(oidExtensionRequest) { - continue - } - - var extensions []pkix.Extension - if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil { - return nil, err - } - for _, ext := range extensions { - oidStr := ext.Id.String() - if requestedExts[oidStr] { - return nil, errors.New("x509: certificate request contains duplicate requested extensions") - } - requestedExts[oidStr] = true - } - ret = append(ret, extensions...) - } - - return ret, nil -} - -// CreateCertificateRequest creates a new certificate request based on a -// template. The following members of template are used: -// -// - SignatureAlgorithm -// - Subject -// - DNSNames -// - EmailAddresses -// - IPAddresses -// - URIs -// - ExtraExtensions -// - Attributes (deprecated) -// -// priv is the private key to sign the CSR with, and the corresponding public -// key will be included in the CSR. It must implement crypto.Signer or -// crypto.MessageSigner and its Public() method must return a *rsa.PublicKey or -// a *ecdsa.PublicKey or a ed25519.PublicKey. (A *rsa.PrivateKey, -// *ecdsa.PrivateKey or ed25519.PrivateKey satisfies this.) -// -// The returned slice is the certificate request in DER encoding. -func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv any) (csr []byte, err error) { - key, ok := priv.(crypto.Signer) - if !ok { - return nil, errors.New("x509: certificate private key does not implement crypto.Signer") - } - - signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm) - if err != nil { - return nil, err - } - - var publicKeyBytes []byte - var publicKeyAlgorithm pkix.AlgorithmIdentifier - publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public()) - if err != nil { - return nil, err - } - - extensions, err := buildCSRExtensions(template) - if err != nil { - return nil, err - } - - // Make a copy of template.Attributes because we may alter it below. - attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes)) - for _, attr := range template.Attributes { - values := make([][]pkix.AttributeTypeAndValue, len(attr.Value)) - copy(values, attr.Value) - attributes = append(attributes, pkix.AttributeTypeAndValueSET{ - Type: attr.Type, - Value: values, - }) - } - - extensionsAppended := false - if len(extensions) > 0 { - // Append the extensions to an existing attribute if possible. - for _, atvSet := range attributes { - if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 { - continue - } - - // specifiedExtensions contains all the extensions that we - // found specified via template.Attributes. - specifiedExtensions := make(map[string]bool) - - for _, atvs := range atvSet.Value { - for _, atv := range atvs { - specifiedExtensions[atv.Type.String()] = true - } - } - - newValue := make([]pkix.AttributeTypeAndValue, 0, len(atvSet.Value[0])+len(extensions)) - newValue = append(newValue, atvSet.Value[0]...) - - for _, e := range extensions { - if specifiedExtensions[e.Id.String()] { - // Attributes already contained a value for - // this extension and it takes priority. - continue - } - - newValue = append(newValue, pkix.AttributeTypeAndValue{ - // There is no place for the critical - // flag in an AttributeTypeAndValue. - Type: e.Id, - Value: e.Value, - }) - } - - atvSet.Value[0] = newValue - extensionsAppended = true - break - } - } - - rawAttributes, err := newRawAttributes(attributes) - if err != nil { - return nil, err - } - - // If not included in attributes, add a new attribute for the - // extensions. - if len(extensions) > 0 && !extensionsAppended { - attr := struct { - Type asn1.ObjectIdentifier - Value [][]pkix.Extension `asn1:"set"` - }{ - Type: oidExtensionRequest, - Value: [][]pkix.Extension{extensions}, - } - - b, err := asn1.Marshal(attr) - if err != nil { - return nil, errors.New("x509: failed to serialise extensions attribute: " + err.Error()) - } - - var rawValue asn1.RawValue - if _, err := asn1.Unmarshal(b, &rawValue); err != nil { - return nil, err - } - - rawAttributes = append(rawAttributes, rawValue) - } - - asn1Subject := template.RawSubject - if len(asn1Subject) == 0 { - asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence()) - if err != nil { - return nil, err - } - } - - tbsCSR := tbsCertificateRequest{ - Version: 0, // PKCS #10, RFC 2986 - Subject: asn1.RawValue{FullBytes: asn1Subject}, - PublicKey: publicKeyInfo{ - Algorithm: publicKeyAlgorithm, - PublicKey: asn1.BitString{ - Bytes: publicKeyBytes, - BitLength: len(publicKeyBytes) * 8, - }, - }, - RawAttributes: rawAttributes, - } - - tbsCSRContents, err := asn1.Marshal(tbsCSR) - if err != nil { - return nil, err - } - tbsCSR.Raw = tbsCSRContents - - signature, err := signTBS(tbsCSRContents, key, signatureAlgorithm, rand) - if err != nil { - return nil, err - } - - return asn1.Marshal(certificateRequest{ - TBSCSR: tbsCSR, - SignatureAlgorithm: algorithmIdentifier, - SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, - }) -} - -// ParseCertificateRequest parses a single certificate request from the -// given ASN.1 DER data. -func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) { - var csr certificateRequest - - rest, err := asn1.Unmarshal(asn1Data, &csr) - if err != nil { - return nil, err - } else if len(rest) != 0 { - return nil, asn1.SyntaxError{Msg: "trailing data"} - } - - return parseCertificateRequest(&csr) -} - -func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) { - out := &CertificateRequest{ - Raw: in.Raw, - RawTBSCertificateRequest: in.TBSCSR.Raw, - RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw, - RawSubject: in.TBSCSR.Subject.FullBytes, - - Signature: in.SignatureValue.RightAlign(), - SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm), - - PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm), - - Version: in.TBSCSR.Version, - Attributes: parseRawAttributes(in.TBSCSR.RawAttributes), - } - - var err error - if out.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { - out.PublicKey, err = parsePublicKey(&in.TBSCSR.PublicKey) - if err != nil { - return nil, err - } - } - - var subject pkix.RDNSequence - if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil { - return nil, err - } else if len(rest) != 0 { - return nil, errors.New("x509: trailing data after X.509 Subject") - } - - out.Subject.FillFromRDNSequence(&subject) - - if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil { - return nil, err - } - - for _, extension := range out.Extensions { - switch { - case extension.Id.Equal(oidExtensionSubjectAltName): - out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value) - if err != nil { - return nil, err - } - } - } - - return out, nil -} - -// CheckSignature reports whether the signature on c is valid. -func (c *CertificateRequest) CheckSignature() error { - return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey, true) -} - -// RevocationListEntry represents an entry in the revokedCertificates -// sequence of a CRL. -type RevocationListEntry struct { - // Raw contains the raw bytes of the revokedCertificates entry. It is set when - // parsing a CRL; it is ignored when generating a CRL. - Raw []byte - - // SerialNumber represents the serial number of a revoked certificate. It is - // both used when creating a CRL and populated when parsing a CRL. It must not - // be nil. - SerialNumber *big.Int - // RevocationTime represents the time at which the certificate was revoked. It - // is both used when creating a CRL and populated when parsing a CRL. It must - // not be the zero time. - RevocationTime time.Time - // ReasonCode represents the reason for revocation, using the integer enum - // values specified in RFC 5280 Section 5.3.1. When creating a CRL, the zero - // value will result in the reasonCode extension being omitted. When parsing a - // CRL, the zero value may represent either the reasonCode extension being - // absent (which implies the default revocation reason of 0/Unspecified), or - // it may represent the reasonCode extension being present and explicitly - // containing a value of 0/Unspecified (which should not happen according to - // the DER encoding rules, but can and does happen anyway). - ReasonCode int - - // Extensions contains raw X.509 extensions. When parsing CRL entries, - // this can be used to extract non-critical extensions that are not - // parsed by this package. When marshaling CRL entries, the Extensions - // field is ignored, see ExtraExtensions. - Extensions []pkix.Extension - // ExtraExtensions contains extensions to be copied, raw, into any - // marshaled CRL entries. Values override any extensions that would - // otherwise be produced based on the other fields. The ExtraExtensions - // field is not populated when parsing CRL entries, see Extensions. - ExtraExtensions []pkix.Extension -} - -// RevocationList represents a [Certificate] Revocation List (CRL) as specified -// by RFC 5280. -type RevocationList struct { - // Raw contains the complete ASN.1 DER content of the CRL (tbsCertList, - // signatureAlgorithm, and signatureValue.) - Raw []byte - // RawTBSRevocationList contains just the tbsCertList portion of the ASN.1 - // DER. - RawTBSRevocationList []byte - // RawIssuer contains the DER encoded Issuer. - RawIssuer []byte - - // Issuer contains the DN of the issuing certificate. - Issuer pkix.Name - // AuthorityKeyId is used to identify the public key associated with the - // issuing certificate. It is populated from the authorityKeyIdentifier - // extension when parsing a CRL. It is ignored when creating a CRL; the - // extension is populated from the issuing certificate itself. - AuthorityKeyId []byte - - Signature []byte - // SignatureAlgorithm is used to determine the signature algorithm to be - // used when signing the CRL. If 0 the default algorithm for the signing - // key will be used. - SignatureAlgorithm SignatureAlgorithm - - // RevokedCertificateEntries represents the revokedCertificates sequence in - // the CRL. It is used when creating a CRL and also populated when parsing a - // CRL. When creating a CRL, it may be empty or nil, in which case the - // revokedCertificates ASN.1 sequence will be omitted from the CRL entirely. - RevokedCertificateEntries []RevocationListEntry - - // RevokedCertificates is used to populate the revokedCertificates - // sequence in the CRL if RevokedCertificateEntries is empty. It may be empty - // or nil, in which case an empty CRL will be created. - // - // Deprecated: Use RevokedCertificateEntries instead. - RevokedCertificates []pkix.RevokedCertificate - - // Number is used to populate the X.509 v2 cRLNumber extension in the CRL, - // which should be a monotonically increasing sequence number for a given - // CRL scope and CRL issuer. It is also populated from the cRLNumber - // extension when parsing a CRL. - Number *big.Int - - // ThisUpdate is used to populate the thisUpdate field in the CRL, which - // indicates the issuance date of the CRL. - ThisUpdate time.Time - // NextUpdate is used to populate the nextUpdate field in the CRL, which - // indicates the date by which the next CRL will be issued. NextUpdate - // must be greater than ThisUpdate. - NextUpdate time.Time - - // Extensions contains raw X.509 extensions. When creating a CRL, - // the Extensions field is ignored, see ExtraExtensions. - Extensions []pkix.Extension - - // ExtraExtensions contains any additional extensions to add directly to - // the CRL. - ExtraExtensions []pkix.Extension -} - -// These structures reflect the ASN.1 structure of X.509 CRLs better than -// the existing crypto/x509/pkix variants do. These mirror the existing -// certificate structs in this file. -// -// Notably, we include issuer as an asn1.RawValue, mirroring the behavior of -// tbsCertificate and allowing raw (unparsed) subjects to be passed cleanly. -type certificateList struct { - TBSCertList tbsCertificateList - SignatureAlgorithm pkix.AlgorithmIdentifier - SignatureValue asn1.BitString -} - -type tbsCertificateList struct { - Raw asn1.RawContent - Version int `asn1:"optional,default:0"` - Signature pkix.AlgorithmIdentifier - Issuer asn1.RawValue - ThisUpdate time.Time - NextUpdate time.Time `asn1:"optional"` - RevokedCertificates []pkix.RevokedCertificate `asn1:"optional"` - Extensions []pkix.Extension `asn1:"tag:0,optional,explicit"` -} - -// CreateRevocationList creates a new X.509 v2 [Certificate] Revocation List, -// according to RFC 5280, based on template. -// -// The CRL is signed by priv which should be a crypto.Signer or -// crypto.MessageSigner associated with the public key in the issuer -// certificate. -// -// The issuer may not be nil, and the crlSign bit must be set in [KeyUsage] in -// order to use it as a CRL issuer. -// -// The issuer distinguished name CRL field and authority key identifier -// extension are populated using the issuer certificate. issuer must have -// SubjectKeyId set. -func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) { - if template == nil { - return nil, errors.New("x509: template can not be nil") - } - if issuer == nil { - return nil, errors.New("x509: issuer can not be nil") - } - if (issuer.KeyUsage & KeyUsageCRLSign) == 0 { - return nil, errors.New("x509: issuer must have the crlSign key usage bit set") - } - if len(issuer.SubjectKeyId) == 0 { - return nil, errors.New("x509: issuer certificate doesn't contain a subject key identifier") - } - if template.NextUpdate.Before(template.ThisUpdate) { - return nil, errors.New("x509: template.ThisUpdate is after template.NextUpdate") - } - if template.Number == nil { - return nil, errors.New("x509: template contains nil Number field") - } - - signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(priv, template.SignatureAlgorithm) - if err != nil { - return nil, err - } - - var revokedCerts []pkix.RevokedCertificate - // Only process the deprecated RevokedCertificates field if it is populated - // and the new RevokedCertificateEntries field is not populated. - if len(template.RevokedCertificates) > 0 && len(template.RevokedCertificateEntries) == 0 { - // Force revocation times to UTC per RFC 5280. - revokedCerts = make([]pkix.RevokedCertificate, len(template.RevokedCertificates)) - for i, rc := range template.RevokedCertificates { - rc.RevocationTime = rc.RevocationTime.UTC() - revokedCerts[i] = rc - } - } else { - // Convert the ReasonCode field to a proper extension, and force revocation - // times to UTC per RFC 5280. - revokedCerts = make([]pkix.RevokedCertificate, len(template.RevokedCertificateEntries)) - for i, rce := range template.RevokedCertificateEntries { - if rce.SerialNumber == nil { - return nil, errors.New("x509: template contains entry with nil SerialNumber field") - } - if rce.RevocationTime.IsZero() { - return nil, errors.New("x509: template contains entry with zero RevocationTime field") - } - - rc := pkix.RevokedCertificate{ - SerialNumber: rce.SerialNumber, - RevocationTime: rce.RevocationTime.UTC(), - } - - // Copy over any extra extensions, except for a Reason Code extension, - // because we'll synthesize that ourselves to ensure it is correct. - exts := make([]pkix.Extension, 0, len(rce.ExtraExtensions)) - for _, ext := range rce.ExtraExtensions { - if ext.Id.Equal(oidExtensionReasonCode) { - return nil, errors.New("x509: template contains entry with ReasonCode ExtraExtension; use ReasonCode field instead") - } - exts = append(exts, ext) - } - - // Only add a reasonCode extension if the reason is non-zero, as per - // RFC 5280 Section 5.3.1. - if rce.ReasonCode != 0 { - reasonBytes, err := asn1.Marshal(asn1.Enumerated(rce.ReasonCode)) - if err != nil { - return nil, err - } - - exts = append(exts, pkix.Extension{ - Id: oidExtensionReasonCode, - Value: reasonBytes, - }) - } - - if len(exts) > 0 { - rc.Extensions = exts - } - revokedCerts[i] = rc - } - } - - aki, err := asn1.Marshal(authKeyId{Id: issuer.SubjectKeyId}) - if err != nil { - return nil, err - } - - if numBytes := template.Number.Bytes(); len(numBytes) > 20 || (len(numBytes) == 20 && numBytes[0]&0x80 != 0) { - return nil, errors.New("x509: CRL number exceeds 20 octets") - } - crlNum, err := asn1.Marshal(template.Number) - if err != nil { - return nil, err - } - - // Correctly use the issuer's subject sequence if one is specified. - issuerSubject, err := subjectBytes(issuer) - if err != nil { - return nil, err - } - - tbsCertList := tbsCertificateList{ - Version: 1, // v2 - Signature: algorithmIdentifier, - Issuer: asn1.RawValue{FullBytes: issuerSubject}, - ThisUpdate: template.ThisUpdate.UTC(), - NextUpdate: template.NextUpdate.UTC(), - Extensions: []pkix.Extension{ - { - Id: oidExtensionAuthorityKeyId, - Value: aki, - }, - { - Id: oidExtensionCRLNumber, - Value: crlNum, - }, - }, - } - if len(revokedCerts) > 0 { - tbsCertList.RevokedCertificates = revokedCerts - } - - if len(template.ExtraExtensions) > 0 { - tbsCertList.Extensions = append(tbsCertList.Extensions, template.ExtraExtensions...) - } - - tbsCertListContents, err := asn1.Marshal(tbsCertList) - if err != nil { - return nil, err - } - - // Optimization to only marshal this struct once, when signing and - // then embedding in certificateList below. - tbsCertList.Raw = tbsCertListContents - - signature, err := signTBS(tbsCertListContents, priv, signatureAlgorithm, rand) - if err != nil { - return nil, err - } - - return asn1.Marshal(certificateList{ - TBSCertList: tbsCertList, - SignatureAlgorithm: algorithmIdentifier, - SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, - }) -} - -// CheckSignatureFrom verifies that the signature on rl is a valid signature -// from issuer. -func (rl *RevocationList) CheckSignatureFrom(parent *Certificate) error { - if parent.Version == 3 && !parent.BasicConstraintsValid || - parent.BasicConstraintsValid && !parent.IsCA { - return ConstraintViolationError{} - } - - if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCRLSign == 0 { - return ConstraintViolationError{} - } - - if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { - return ErrUnsupportedAlgorithm - } - - return parent.CheckSignature(rl.SignatureAlgorithm, rl.RawTBSRevocationList, rl.Signature) -} From 2508c25b808946724d53fa7de76ea4c2b8c6c031 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Mon, 6 Oct 2025 16:41:20 -0700 Subject: [PATCH 3/5] Update x509pq to support mldsa keys and signatures --- ca/x509pq/parser.go | 21 + ca/x509pq/x509.go | 76 +- go.mod | 3 +- go.sum | 2 + vendor/github.com/cloudflare/circl/LICENSE | 57 + .../circl/ecc/goldilocks/constants.go | 71 + .../cloudflare/circl/ecc/goldilocks/curve.go | 84 + .../circl/ecc/goldilocks/isogeny.go | 52 + .../cloudflare/circl/ecc/goldilocks/point.go | 171 + .../cloudflare/circl/ecc/goldilocks/scalar.go | 203 + .../cloudflare/circl/ecc/goldilocks/twist.go | 138 + .../circl/ecc/goldilocks/twistPoint.go | 135 + .../circl/ecc/goldilocks/twistTables.go | 216 + .../circl/ecc/goldilocks/twist_basemult.go | 62 + .../cloudflare/circl/internal/conv/conv.go | 173 + .../cloudflare/circl/internal/sha3/doc.go | 62 + .../cloudflare/circl/internal/sha3/hashes.go | 69 + .../cloudflare/circl/internal/sha3/keccakf.go | 391 + .../cloudflare/circl/internal/sha3/rc.go | 29 + .../cloudflare/circl/internal/sha3/sha3.go | 200 + .../circl/internal/sha3/sha3_s390x.s | 33 + .../cloudflare/circl/internal/sha3/shake.go | 119 + .../cloudflare/circl/internal/sha3/xor.go | 15 + .../circl/internal/sha3/xor_generic.go | 33 + .../circl/internal/sha3/xor_unaligned.go | 61 + .../cloudflare/circl/math/fp25519/fp.go | 205 + .../cloudflare/circl/math/fp25519/fp_amd64.go | 45 + .../cloudflare/circl/math/fp25519/fp_amd64.h | 351 + .../cloudflare/circl/math/fp25519/fp_amd64.s | 112 + .../circl/math/fp25519/fp_generic.go | 317 + .../cloudflare/circl/math/fp25519/fp_noasm.go | 13 + .../cloudflare/circl/math/fp448/fp.go | 164 + .../cloudflare/circl/math/fp448/fp_amd64.go | 43 + .../cloudflare/circl/math/fp448/fp_amd64.h | 591 ++ .../cloudflare/circl/math/fp448/fp_amd64.s | 75 + .../cloudflare/circl/math/fp448/fp_generic.go | 339 + .../cloudflare/circl/math/fp448/fp_noasm.go | 12 + .../cloudflare/circl/math/fp448/fuzzer.go | 75 + .../cloudflare/circl/math/integer.go | 16 + .../cloudflare/circl/math/mlsbset/mlsbset.go | 122 + .../cloudflare/circl/math/mlsbset/power.go | 64 + .../cloudflare/circl/math/primes.go | 34 + .../github.com/cloudflare/circl/math/wnaf.go | 84 + vendor/github.com/cloudflare/circl/pki/pki.go | 182 + .../circl/sign/dilithium/mode2/dilithium.go | 295 + .../dilithium/mode2/internal/dilithium.go | 491 + .../sign/dilithium/mode2/internal/mat.go | 59 + .../sign/dilithium/mode2/internal/pack.go | 270 + .../sign/dilithium/mode2/internal/params.go | 18 + .../sign/dilithium/mode2/internal/rounding.go | 142 + .../sign/dilithium/mode2/internal/sample.go | 339 + .../sign/dilithium/mode2/internal/vec.go | 281 + .../circl/sign/dilithium/mode3/dilithium.go | 295 + .../dilithium/mode3/internal/dilithium.go | 489 + .../sign/dilithium/mode3/internal/mat.go | 57 + .../sign/dilithium/mode3/internal/pack.go | 268 + .../sign/dilithium/mode3/internal/params.go | 18 + .../sign/dilithium/mode3/internal/rounding.go | 140 + .../sign/dilithium/mode3/internal/sample.go | 337 + .../sign/dilithium/mode3/internal/vec.go | 279 + .../circl/sign/dilithium/mode5/dilithium.go | 295 + .../dilithium/mode5/internal/dilithium.go | 491 + .../sign/dilithium/mode5/internal/mat.go | 59 + .../sign/dilithium/mode5/internal/pack.go | 270 + .../sign/dilithium/mode5/internal/params.go | 18 + .../sign/dilithium/mode5/internal/rounding.go | 142 + .../sign/dilithium/mode5/internal/sample.go | 339 + .../sign/dilithium/mode5/internal/vec.go | 281 + .../cloudflare/circl/sign/ed25519/ed25519.go | 453 + .../cloudflare/circl/sign/ed25519/modular.go | 175 + .../cloudflare/circl/sign/ed25519/mult.go | 180 + .../cloudflare/circl/sign/ed25519/point.go | 195 + .../cloudflare/circl/sign/ed25519/pubkey.go | 9 + .../circl/sign/ed25519/pubkey112.go | 7 + .../cloudflare/circl/sign/ed25519/signapi.go | 87 + .../cloudflare/circl/sign/ed25519/tables.go | 213 + .../cloudflare/circl/sign/ed448/ed448.go | 411 + .../cloudflare/circl/sign/ed448/signapi.go | 87 + .../circl/sign/eddilithium2/eddilithium.go | 239 + .../circl/sign/eddilithium2/signapi.go | 93 + .../circl/sign/eddilithium3/eddilithium.go | 234 + .../circl/sign/eddilithium3/signapi.go | 93 + .../circl/sign/internal/dilithium/amd64.go | 154 + .../circl/sign/internal/dilithium/amd64.s | 8407 +++++++++++++++++ .../circl/sign/internal/dilithium/field.go | 52 + .../circl/sign/internal/dilithium/generic.go | 81 + .../circl/sign/internal/dilithium/ntt.go | 217 + .../circl/sign/internal/dilithium/pack.go | 160 + .../circl/sign/internal/dilithium/params.go | 18 + .../sign/internal/dilithium/params/params.go | 25 + .../circl/sign/internal/dilithium/poly.go | 101 + .../sign/internal/dilithium/stubs_amd64.go | 35 + .../circl/sign/mldsa/mldsa44/dilithium.go | 361 + .../sign/mldsa/mldsa44/internal/dilithium.go | 491 + .../circl/sign/mldsa/mldsa44/internal/mat.go | 59 + .../circl/sign/mldsa/mldsa44/internal/pack.go | 270 + .../sign/mldsa/mldsa44/internal/params.go | 18 + .../sign/mldsa/mldsa44/internal/rounding.go | 142 + .../sign/mldsa/mldsa44/internal/sample.go | 339 + .../circl/sign/mldsa/mldsa44/internal/vec.go | 281 + .../circl/sign/mldsa/mldsa65/dilithium.go | 361 + .../sign/mldsa/mldsa65/internal/dilithium.go | 491 + .../circl/sign/mldsa/mldsa65/internal/mat.go | 59 + .../circl/sign/mldsa/mldsa65/internal/pack.go | 270 + .../sign/mldsa/mldsa65/internal/params.go | 18 + .../sign/mldsa/mldsa65/internal/rounding.go | 142 + .../sign/mldsa/mldsa65/internal/sample.go | 339 + .../circl/sign/mldsa/mldsa65/internal/vec.go | 281 + .../circl/sign/mldsa/mldsa87/dilithium.go | 361 + .../sign/mldsa/mldsa87/internal/dilithium.go | 491 + .../circl/sign/mldsa/mldsa87/internal/mat.go | 59 + .../circl/sign/mldsa/mldsa87/internal/pack.go | 270 + .../sign/mldsa/mldsa87/internal/params.go | 18 + .../sign/mldsa/mldsa87/internal/rounding.go | 142 + .../sign/mldsa/mldsa87/internal/sample.go | 339 + .../circl/sign/mldsa/mldsa87/internal/vec.go | 281 + .../cloudflare/circl/sign/schemes/schemes.go | 59 + .../github.com/cloudflare/circl/sign/sign.go | 113 + .../circl/simd/keccakf1600/f1600x.go | 163 + .../circl/simd/keccakf1600/f1600x2_arm64.go | 13 + .../circl/simd/keccakf1600/f1600x2_arm64.s | 136 + .../circl/simd/keccakf1600/f1600x4_amd64.go | 10 + .../circl/simd/keccakf1600/f1600x4_amd64.s | 899 ++ .../simd/keccakf1600/f1600x4stubs_amd64.go | 8 + .../circl/simd/keccakf1600/fallback.go | 8 + vendor/golang.org/x/crypto/cryptobyte/asn1.go | 825 ++ .../x/crypto/cryptobyte/asn1/asn1.go | 46 + .../golang.org/x/crypto/cryptobyte/builder.go | 350 + .../golang.org/x/crypto/cryptobyte/string.go | 183 + vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 17 + .../golang.org/x/sys/cpu/asm_darwin_x86_gc.s | 17 + vendor/golang.org/x/sys/cpu/byteorder.go | 66 + vendor/golang.org/x/sys/cpu/cpu.go | 338 + vendor/golang.org/x/sys/cpu/cpu_aix.go | 33 + vendor/golang.org/x/sys/cpu/cpu_arm.go | 73 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 194 + vendor/golang.org/x/sys/cpu/cpu_arm64.s | 39 + vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go | 61 + vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 21 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 15 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.s | 26 + .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 11 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 22 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c | 37 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 25 + vendor/golang.org/x/sys/cpu/cpu_linux.go | 15 + vendor/golang.org/x/sys/cpu/cpu_linux_arm.go | 39 + .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 120 + .../golang.org/x/sys/cpu/cpu_linux_loong64.go | 22 + .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 22 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 9 + .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 30 + .../golang.org/x/sys/cpu/cpu_linux_riscv64.go | 160 + .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 40 + vendor/golang.org/x/sys/cpu/cpu_loong64.go | 50 + vendor/golang.org/x/sys/cpu/cpu_loong64.s | 13 + vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 15 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 11 + .../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 173 + .../golang.org/x/sys/cpu/cpu_openbsd_arm64.go | 65 + .../golang.org/x/sys/cpu/cpu_openbsd_arm64.s | 11 + vendor/golang.org/x/sys/cpu/cpu_other_arm.go | 9 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 9 + .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 11 + .../golang.org/x/sys/cpu/cpu_other_ppc64x.go | 12 + .../golang.org/x/sys/cpu/cpu_other_riscv64.go | 11 + vendor/golang.org/x/sys/cpu/cpu_other_x86.go | 11 + vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 16 + vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 32 + vendor/golang.org/x/sys/cpu/cpu_s390x.go | 172 + vendor/golang.org/x/sys/cpu/cpu_s390x.s | 57 + vendor/golang.org/x/sys/cpu/cpu_wasm.go | 17 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 162 + vendor/golang.org/x/sys/cpu/cpu_zos.go | 10 + vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go | 25 + vendor/golang.org/x/sys/cpu/endian_big.go | 10 + vendor/golang.org/x/sys/cpu/endian_little.go | 10 + vendor/golang.org/x/sys/cpu/hwcap_linux.go | 71 + vendor/golang.org/x/sys/cpu/parse.go | 43 + .../x/sys/cpu/proc_cpuinfo_linux.go | 53 + vendor/golang.org/x/sys/cpu/runtime_auxv.go | 16 + .../x/sys/cpu/runtime_auxv_go121.go | 18 + .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 26 + .../x/sys/cpu/syscall_aix_ppc64_gc.go | 35 + .../x/sys/cpu/syscall_darwin_x86_gc.go | 98 + vendor/modules.txt | 34 + 187 files changed, 34182 insertions(+), 3 deletions(-) create mode 100644 vendor/github.com/cloudflare/circl/LICENSE create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go create mode 100644 vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go create mode 100644 vendor/github.com/cloudflare/circl/internal/conv/conv.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/doc.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/hashes.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/rc.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/sha3.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/shake.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/xor.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go create mode 100644 vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp25519/fp.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h create mode 100644 vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.s create mode 100644 vendor/github.com/cloudflare/circl/math/fp25519/fp_generic.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp448/fp.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h create mode 100644 vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s create mode 100644 vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go create mode 100644 vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go create mode 100644 vendor/github.com/cloudflare/circl/math/integer.go create mode 100644 vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go create mode 100644 vendor/github.com/cloudflare/circl/math/mlsbset/power.go create mode 100644 vendor/github.com/cloudflare/circl/math/primes.go create mode 100644 vendor/github.com/cloudflare/circl/math/wnaf.go create mode 100644 vendor/github.com/cloudflare/circl/pki/pki.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/modular.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/mult.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/point.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed25519/tables.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed448/ed448.go create mode 100644 vendor/github.com/cloudflare/circl/sign/ed448/signapi.go create mode 100644 vendor/github.com/cloudflare/circl/sign/eddilithium2/eddilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/eddilithium2/signapi.go create mode 100644 vendor/github.com/cloudflare/circl/sign/eddilithium3/eddilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/eddilithium3/signapi.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.s create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/field.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/ntt.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/schemes/schemes.go create mode 100644 vendor/github.com/cloudflare/circl/sign/sign.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/builder.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/string.go create mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s create mode 100644 vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s create mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/endian_big.go create mode 100644 vendor/golang.org/x/sys/cpu/endian_little.go create mode 100644 vendor/golang.org/x/sys/cpu/hwcap_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/parse.go create mode 100644 vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go diff --git a/ca/x509pq/parser.go b/ca/x509pq/parser.go index 6c99bd6c..5efa5eaa 100644 --- a/ca/x509pq/parser.go +++ b/ca/x509pq/parser.go @@ -25,6 +25,9 @@ import ( "unicode/utf16" "unicode/utf8" + "github.com/cloudflare/circl/sign/mldsa/mldsa44" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/cloudflare/circl/sign/mldsa/mldsa87" "golang.org/x/crypto/cryptobyte" cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" ) @@ -342,6 +345,24 @@ func parsePublicKey(keyData *publicKeyInfo) (any, error) { return nil, errors.New("x509: zero or negative DSA parameter") } return pub, nil + case oid.Equal(oidPublicKeyMLDSA44): + pub, err := mldsa44.Scheme().UnmarshalBinaryPublicKey(der) + if err != nil { + return nil, fmt.Errorf("x509: invalid ML-DSA-44 public key: %w", err) + } + return pub, nil + case oid.Equal(oidPublicKeyMLDSA65): + pub, err := mldsa65.Scheme().UnmarshalBinaryPublicKey(der) + if err != nil { + return nil, fmt.Errorf("x509: invalid ML-DSA-65 public key: %w", err) + } + return pub, nil + case oid.Equal(oidPublicKeyMLDSA87): + pub, err := mldsa87.Scheme().UnmarshalBinaryPublicKey(der) + if err != nil { + return nil, fmt.Errorf("x509: invalid ML-DSA-87 public key: %w", err) + } + return pub, nil default: return nil, errors.New("x509: unknown public key algorithm") } diff --git a/ca/x509pq/x509.go b/ca/x509pq/x509.go index 4c651a10..95359662 100644 --- a/ca/x509pq/x509.go +++ b/ca/x509pq/x509.go @@ -37,6 +37,7 @@ import ( "math/big" "net" "net/url" + "slices" "strconv" "time" "unicode" @@ -47,6 +48,12 @@ import ( _ "crypto/sha256" _ "crypto/sha512" + "github.com/cloudflare/circl/pki" + mldsa "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/mldsa/mldsa44" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/cloudflare/circl/sign/mldsa/mldsa87" + "golang.org/x/crypto/cryptobyte" cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" ) @@ -108,6 +115,13 @@ func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.A } publicKeyAlgorithm.Parameters.FullBytes = paramBytes } + case mldsa.PublicKey: + publicKeyBytes, err = pub.MarshalBinary() + if err != nil { + return nil, pkix.AlgorithmIdentifier{}, err + } + publicKeyAlgorithm.Algorithm = pub.Scheme().(pki.CertificateScheme).Oid() + publicKeyAlgorithm.Parameters = asn1.NullRawValue default: return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub) } @@ -207,6 +221,9 @@ const ( SHA384WithRSAPSS SHA512WithRSAPSS PureEd25519 + PureMLDSA44 + PureMLDSA65 + PureMLDSA87 ) func (algo SignatureAlgorithm) isRSAPSS() bool { @@ -244,6 +261,9 @@ const ( DSA // Only supported for parsing. ECDSA Ed25519 + MLDSA44 + MLDSA65 + MLDSA87 ) var publicKeyAlgoName = [...]string{ @@ -251,6 +271,9 @@ var publicKeyAlgoName = [...]string{ DSA: "DSA", ECDSA: "ECDSA", Ed25519: "Ed25519", + MLDSA44: "ML-DSA-44", + MLDSA65: "ML-DSA-65", + MLDSA87: "ML-DSA-87", } func (algo PublicKeyAlgorithm) String() string { @@ -333,6 +356,12 @@ var ( // but it's specified by ISO. Microsoft's makecert.exe has been known // to produce certificates with this OID. oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} + + // ML-DSA uses the same OIDs to identify both its Public Key Algorithms and + // its Signature Algorithms + oidSignatureMLDSA44 = mldsa44.Scheme().(pki.CertificateScheme).Oid() + oidSignatureMLDSA65 = mldsa65.Scheme().(pki.CertificateScheme).Oid() + oidSignatureMLDSA87 = mldsa87.Scheme().(pki.CertificateScheme).Oid() ) var signatureAlgorithmDetails = []struct { @@ -360,6 +389,9 @@ var signatureAlgorithmDetails = []struct { {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false}, {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false}, {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false}, + {PureMLDSA44, "ML-DSA-44", oidSignatureMLDSA44, emptyRawValue, MLDSA44, crypto.Hash(0) /* no pre-hashing */, false}, + {PureMLDSA65, "ML-DSA-65", oidSignatureMLDSA65, emptyRawValue, MLDSA65, crypto.Hash(0) /* no pre-hashing */, false}, + {PureMLDSA87, "ML-DSA-87", oidSignatureMLDSA87, emptyRawValue, MLDSA87, crypto.Hash(0) /* no pre-hashing */, false}, } var emptyRawValue = asn1.RawValue{} @@ -468,6 +500,23 @@ var ( // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } oidPublicKeyX25519 = asn1.ObjectIdentifier{1, 3, 101, 110} oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} + // draft-ietf-lamps-dilithium-certificates-13 + // Algorithm Identifiers for the Module-Lattice-Based Digital Signature Algorithm (ML-DSA) + // + // id-ml-dsa-44 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + // country(16) us(840) organization(1) gov(101) csor(3) + // nistAlgorithm(4) sigAlgs(3) id-ml-dsa-44(17) } + + // id-ml-dsa-65 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + // country(16) us(840) organization(1) gov(101) csor(3) + // nistAlgorithm(4) sigAlgs(3) id-ml-dsa-65(18) } + + // id-ml-dsa-87 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + // country(16) us(840) organization(1) gov(101) csor(3) + // nistAlgorithm(4) sigAlgs(3) id-ml-dsa-87(19) } + oidPublicKeyMLDSA44 = mldsa44.Scheme().(pki.CertificateScheme).Oid() + oidPublicKeyMLDSA65 = mldsa65.Scheme().(pki.CertificateScheme).Oid() + oidPublicKeyMLDSA87 = mldsa87.Scheme().(pki.CertificateScheme).Oid() ) // getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm @@ -483,6 +532,12 @@ func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm return ECDSA case oid.Equal(oidPublicKeyEd25519): return Ed25519 + case oid.Equal(oidPublicKeyMLDSA44): + return MLDSA44 + case oid.Equal(oidPublicKeyMLDSA65): + return MLDSA65 + case oid.Equal(oidPublicKeyMLDSA87): + return MLDSA87 } return UnknownPublicKeyAlgorithm } @@ -896,8 +951,8 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey switch hashType { case crypto.Hash(0): - if pubKeyAlgo != Ed25519 { - return ErrUnsupportedAlgorithm + if !slices.Contains([]PublicKeyAlgorithm{Ed25519, MLDSA44, MLDSA65, MLDSA87}, pubKeyAlgo) { + return fmt.Errorf("bad hash: %w", ErrUnsupportedAlgorithm) } case crypto.MD5: return InsecureAlgorithmError(algo) @@ -942,6 +997,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey return errors.New("x509: Ed25519 verification failure") } return + case mldsa.PublicKey: + if !pub.Scheme().Verify(pub, signed, signature, nil) { + return errors.New("x509: ML-DSA verification failure") + } + return } return ErrUnsupportedAlgorithm } @@ -1424,6 +1484,18 @@ func signingParamsForKey(key crypto.Signer, sigAlgo SignatureAlgorithm) (Signatu pubType = Ed25519 defaultAlgo = PureEd25519 + case *mldsa44.PublicKey: + pubType = MLDSA44 + defaultAlgo = PureMLDSA44 + + case *mldsa65.PublicKey: + pubType = MLDSA65 + defaultAlgo = PureMLDSA65 + + case *mldsa87.PublicKey: + pubType = MLDSA87 + defaultAlgo = PureMLDSA87 + default: return 0, ai, errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") } diff --git a/go.mod b/go.mod index 0a00b39a..f89d356e 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,14 @@ go 1.24 toolchain go1.24.2 require ( + github.com/cloudflare/circl v1.6.1 github.com/go-jose/go-jose/v4 v4.1.2 github.com/letsencrypt/challtestsrv v1.3.2 github.com/miekg/dns v1.1.62 + golang.org/x/crypto v0.39.0 ) require ( - golang.org/x/crypto v0.39.0 // indirect golang.org/x/mod v0.24.0 // indirect golang.org/x/net v0.40.0 // indirect golang.org/x/sync v0.14.0 // indirect diff --git a/go.sum b/go.sum index 0a7cd592..1445943f 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/vendor/github.com/cloudflare/circl/LICENSE b/vendor/github.com/cloudflare/circl/LICENSE new file mode 100644 index 00000000..67edaa90 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/LICENSE @@ -0,0 +1,57 @@ +Copyright (c) 2019 Cloudflare. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Cloudflare nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go new file mode 100644 index 00000000..b6b236e5 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/constants.go @@ -0,0 +1,71 @@ +package goldilocks + +import fp "github.com/cloudflare/circl/math/fp448" + +var ( + // genX is the x-coordinate of the generator of Goldilocks curve. + genX = fp.Elt{ + 0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26, + 0x8e, 0x93, 0x00, 0x8b, 0xe1, 0x80, 0x3b, 0x43, + 0x11, 0x65, 0xb6, 0x2a, 0xf7, 0x1a, 0xae, 0x12, + 0x64, 0xa4, 0xd3, 0xa3, 0x24, 0xe3, 0x6d, 0xea, + 0x67, 0x17, 0x0f, 0x47, 0x70, 0x65, 0x14, 0x9e, + 0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22, + 0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f, + } + // genY is the y-coordinate of the generator of Goldilocks curve. + genY = fp.Elt{ + 0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98, + 0xad, 0xc8, 0xd7, 0x4e, 0x2c, 0x13, 0xbd, 0xfd, + 0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a, + 0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87, + 0x40, 0x98, 0xa3, 0x6c, 0x73, 0x73, 0xea, 0x4b, + 0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88, + 0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69, + } + // paramD is -39081 in Fp. + paramD = fp.Elt{ + 0x56, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + } + // order is 2^446-0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d, + // which is the number of points in the prime subgroup. + order = Scalar{ + 0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23, + 0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21, + 0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4, + 0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, + } + // residue448 is 2^448 mod order. + residue448 = [4]uint64{ + 0x721cf5b5529eec34, 0x7a4cf635c8e9c2ab, 0xeec492d944a725bf, 0x20cd77058, + } + // invFour is 1/4 mod order. + invFour = Scalar{ + 0x3d, 0x11, 0xd6, 0xaa, 0xa4, 0x30, 0xde, 0x48, + 0xd5, 0x63, 0x71, 0xa3, 0x9c, 0x30, 0x5b, 0x08, + 0xa4, 0x8d, 0xb5, 0x6b, 0xd2, 0xb6, 0x13, 0x71, + 0xfa, 0x88, 0x32, 0xdf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + } + // paramDTwist is -39082 in Fp. The D parameter of the twist curve. + paramDTwist = fp.Elt{ + 0x55, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + } +) diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go new file mode 100644 index 00000000..1f165141 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go @@ -0,0 +1,84 @@ +// Package goldilocks provides elliptic curve operations over the goldilocks curve. +package goldilocks + +import fp "github.com/cloudflare/circl/math/fp448" + +// Curve is the Goldilocks curve x^2+y^2=z^2-39081x^2y^2. +type Curve struct{} + +// Identity returns the identity point. +func (Curve) Identity() *Point { + return &Point{ + y: fp.One(), + z: fp.One(), + } +} + +// IsOnCurve returns true if the point lies on the curve. +func (Curve) IsOnCurve(P *Point) bool { + x2, y2, t, t2, z2 := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{} + rhs, lhs := &fp.Elt{}, &fp.Elt{} + // Check z != 0 + eq0 := !fp.IsZero(&P.z) + + fp.Mul(t, &P.ta, &P.tb) // t = ta*tb + fp.Sqr(x2, &P.x) // x^2 + fp.Sqr(y2, &P.y) // y^2 + fp.Sqr(z2, &P.z) // z^2 + fp.Sqr(t2, t) // t^2 + fp.Add(lhs, x2, y2) // x^2 + y^2 + fp.Mul(rhs, t2, ¶mD) // dt^2 + fp.Add(rhs, rhs, z2) // z^2 + dt^2 + fp.Sub(lhs, lhs, rhs) // x^2 + y^2 - (z^2 + dt^2) + eq1 := fp.IsZero(lhs) + + fp.Mul(lhs, &P.x, &P.y) // xy + fp.Mul(rhs, t, &P.z) // tz + fp.Sub(lhs, lhs, rhs) // xy - tz + eq2 := fp.IsZero(lhs) + + return eq0 && eq1 && eq2 +} + +// Generator returns the generator point. +func (Curve) Generator() *Point { + return &Point{ + x: genX, + y: genY, + z: fp.One(), + ta: genX, + tb: genY, + } +} + +// Order returns the number of points in the prime subgroup. +func (Curve) Order() Scalar { return order } + +// Double returns 2P. +func (Curve) Double(P *Point) *Point { R := *P; R.Double(); return &R } + +// Add returns P+Q. +func (Curve) Add(P, Q *Point) *Point { R := *P; R.Add(Q); return &R } + +// ScalarMult returns kP. This function runs in constant time. +func (e Curve) ScalarMult(k *Scalar, P *Point) *Point { + k4 := &Scalar{} + k4.divBy4(k) + return e.pull(twistCurve{}.ScalarMult(k4, e.push(P))) +} + +// ScalarBaseMult returns kG where G is the generator point. This function runs in constant time. +func (e Curve) ScalarBaseMult(k *Scalar) *Point { + k4 := &Scalar{} + k4.divBy4(k) + return e.pull(twistCurve{}.ScalarBaseMult(k4)) +} + +// CombinedMult returns mG+nP, where G is the generator point. This function is non-constant time. +func (e Curve) CombinedMult(m, n *Scalar, P *Point) *Point { + m4 := &Scalar{} + n4 := &Scalar{} + m4.divBy4(m) + n4.divBy4(n) + return e.pull(twistCurve{}.CombinedMult(m4, n4, twistCurve{}.pull(P))) +} diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go new file mode 100644 index 00000000..b1daab85 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/isogeny.go @@ -0,0 +1,52 @@ +package goldilocks + +import fp "github.com/cloudflare/circl/math/fp448" + +func (Curve) pull(P *twistPoint) *Point { return twistCurve{}.push(P) } +func (twistCurve) pull(P *Point) *twistPoint { return Curve{}.push(P) } + +// push sends a point on the Goldilocks curve to a point on the twist curve. +func (Curve) push(P *Point) *twistPoint { + Q := &twistPoint{} + Px, Py, Pz := &P.x, &P.y, &P.z + a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &fp.Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb + fp.Add(e, Px, Py) // x+y + fp.Sqr(a, Px) // A = x^2 + fp.Sqr(b, Py) // B = y^2 + fp.Sqr(c, Pz) // z^2 + fp.Add(c, c, c) // C = 2*z^2 + *d = *a // D = A + fp.Sqr(e, e) // (x+y)^2 + fp.Sub(e, e, a) // (x+y)^2-A + fp.Sub(e, e, b) // E = (x+y)^2-A-B + fp.Add(h, b, d) // H = B+D + fp.Sub(g, b, d) // G = B-D + fp.Sub(f, c, h) // F = C-H + fp.Mul(&Q.z, f, g) // Z = F * G + fp.Mul(&Q.x, e, f) // X = E * F + fp.Mul(&Q.y, g, h) // Y = G * H, // T = E * H + return Q +} + +// push sends a point on the twist curve to a point on the Goldilocks curve. +func (twistCurve) push(P *twistPoint) *Point { + Q := &Point{} + Px, Py, Pz := &P.x, &P.y, &P.z + a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &fp.Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb + fp.Add(e, Px, Py) // x+y + fp.Sqr(a, Px) // A = x^2 + fp.Sqr(b, Py) // B = y^2 + fp.Sqr(c, Pz) // z^2 + fp.Add(c, c, c) // C = 2*z^2 + fp.Neg(d, a) // D = -A + fp.Sqr(e, e) // (x+y)^2 + fp.Sub(e, e, a) // (x+y)^2-A + fp.Sub(e, e, b) // E = (x+y)^2-A-B + fp.Add(h, b, d) // H = B+D + fp.Sub(g, b, d) // G = B-D + fp.Sub(f, c, h) // F = C-H + fp.Mul(&Q.z, f, g) // Z = F * G + fp.Mul(&Q.x, e, f) // X = E * F + fp.Mul(&Q.y, g, h) // Y = G * H, // T = E * H + return Q +} diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go new file mode 100644 index 00000000..11f73de0 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go @@ -0,0 +1,171 @@ +package goldilocks + +import ( + "errors" + "fmt" + + fp "github.com/cloudflare/circl/math/fp448" +) + +// Point is a point on the Goldilocks Curve. +type Point struct{ x, y, z, ta, tb fp.Elt } + +func (P Point) String() string { + return fmt.Sprintf("x: %v\ny: %v\nz: %v\nta: %v\ntb: %v", P.x, P.y, P.z, P.ta, P.tb) +} + +// FromAffine creates a point from affine coordinates. +func FromAffine(x, y *fp.Elt) (*Point, error) { + P := &Point{ + x: *x, + y: *y, + z: fp.One(), + ta: *x, + tb: *y, + } + if !(Curve{}).IsOnCurve(P) { + return P, errors.New("point not on curve") + } + return P, nil +} + +// isLessThan returns true if 0 <= x < y, and assumes that slices are of the +// same length and are interpreted in little-endian order. +func isLessThan(x, y []byte) bool { + i := len(x) - 1 + for i > 0 && x[i] == y[i] { + i-- + } + return x[i] < y[i] +} + +// FromBytes returns a point from the input buffer. +func FromBytes(in []byte) (*Point, error) { + if len(in) < fp.Size+1 { + return nil, errors.New("wrong input length") + } + err := errors.New("invalid decoding") + P := &Point{} + signX := in[fp.Size] >> 7 + copy(P.y[:], in[:fp.Size]) + p := fp.P() + if !isLessThan(P.y[:], p[:]) { + return nil, err + } + + u, v := &fp.Elt{}, &fp.Elt{} + one := fp.One() + fp.Sqr(u, &P.y) // u = y^2 + fp.Mul(v, u, ¶mD) // v = dy^2 + fp.Sub(u, u, &one) // u = y^2-1 + fp.Sub(v, v, &one) // v = dy^2-1 + isQR := fp.InvSqrt(&P.x, u, v) // x = sqrt(u/v) + if !isQR { + return nil, err + } + fp.Modp(&P.x) // x = x mod p + if fp.IsZero(&P.x) && signX == 1 { + return nil, err + } + if signX != (P.x[0] & 1) { + fp.Neg(&P.x, &P.x) + } + P.ta = P.x + P.tb = P.y + P.z = fp.One() + return P, nil +} + +// IsIdentity returns true is P is the identity Point. +func (P *Point) IsIdentity() bool { + return fp.IsZero(&P.x) && !fp.IsZero(&P.y) && !fp.IsZero(&P.z) && P.y == P.z +} + +// IsEqual returns true if P is equivalent to Q. +func (P *Point) IsEqual(Q *Point) bool { + l, r := &fp.Elt{}, &fp.Elt{} + fp.Mul(l, &P.x, &Q.z) + fp.Mul(r, &Q.x, &P.z) + fp.Sub(l, l, r) + b := fp.IsZero(l) + fp.Mul(l, &P.y, &Q.z) + fp.Mul(r, &Q.y, &P.z) + fp.Sub(l, l, r) + b = b && fp.IsZero(l) + fp.Mul(l, &P.ta, &P.tb) + fp.Mul(l, l, &Q.z) + fp.Mul(r, &Q.ta, &Q.tb) + fp.Mul(r, r, &P.z) + fp.Sub(l, l, r) + b = b && fp.IsZero(l) + return b +} + +// Neg obtains the inverse of the Point. +func (P *Point) Neg() { fp.Neg(&P.x, &P.x); fp.Neg(&P.ta, &P.ta) } + +// ToAffine returns the x,y affine coordinates of P. +func (P *Point) ToAffine() (x, y fp.Elt) { + fp.Inv(&P.z, &P.z) // 1/z + fp.Mul(&P.x, &P.x, &P.z) // x/z + fp.Mul(&P.y, &P.y, &P.z) // y/z + fp.Modp(&P.x) + fp.Modp(&P.y) + fp.SetOne(&P.z) + P.ta = P.x + P.tb = P.y + return P.x, P.y +} + +// ToBytes stores P into a slice of bytes. +func (P *Point) ToBytes(out []byte) error { + if len(out) < fp.Size+1 { + return errors.New("invalid decoding") + } + x, y := P.ToAffine() + out[fp.Size] = (x[0] & 1) << 7 + return fp.ToBytes(out[:fp.Size], &y) +} + +// MarshalBinary encodes the receiver into a binary form and returns the result. +func (P *Point) MarshalBinary() (data []byte, err error) { + data = make([]byte, fp.Size+1) + err = P.ToBytes(data[:fp.Size+1]) + return data, err +} + +// UnmarshalBinary must be able to decode the form generated by MarshalBinary. +func (P *Point) UnmarshalBinary(data []byte) error { Q, err := FromBytes(data); *P = *Q; return err } + +// Double sets P = 2Q. +func (P *Point) Double() { P.Add(P) } + +// Add sets P =P+Q.. +func (P *Point) Add(Q *Point) { + // This is formula (5) from "Twisted Edwards Curves Revisited" by + // Hisil H., Wong K.KH., Carter G., Dawson E. (2008) + // https://doi.org/10.1007/978-3-540-89255-7_20 + x1, y1, z1, ta1, tb1 := &P.x, &P.y, &P.z, &P.ta, &P.tb + x2, y2, z2, ta2, tb2 := &Q.x, &Q.y, &Q.z, &Q.ta, &Q.tb + x3, y3, z3, E, H := &P.x, &P.y, &P.z, &P.ta, &P.tb + A, B, C, D := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{} + t1, t2, F, G := C, D, &fp.Elt{}, &fp.Elt{} + fp.Mul(t1, ta1, tb1) // t1 = ta1*tb1 + fp.Mul(t2, ta2, tb2) // t2 = ta2*tb2 + fp.Mul(A, x1, x2) // A = x1*x2 + fp.Mul(B, y1, y2) // B = y1*y2 + fp.Mul(C, t1, t2) // t1*t2 + fp.Mul(C, C, ¶mD) // C = d*t1*t2 + fp.Mul(D, z1, z2) // D = z1*z2 + fp.Add(F, x1, y1) // x1+y1 + fp.Add(E, x2, y2) // x2+y2 + fp.Mul(E, E, F) // (x1+y1)*(x2+y2) + fp.Sub(E, E, A) // (x1+y1)*(x2+y2)-A + fp.Sub(E, E, B) // E = (x1+y1)*(x2+y2)-A-B + fp.Sub(F, D, C) // F = D-C + fp.Add(G, D, C) // G = D+C + fp.Sub(H, B, A) // H = B-A + fp.Mul(z3, F, G) // Z = F * G + fp.Mul(x3, E, F) // X = E * F + fp.Mul(y3, G, H) // Y = G * H, T = E * H +} diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go new file mode 100644 index 00000000..f98117b2 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/scalar.go @@ -0,0 +1,203 @@ +package goldilocks + +import ( + "encoding/binary" + "math/bits" +) + +// ScalarSize is the size (in bytes) of scalars. +const ScalarSize = 56 // 448 / 8 + +// _N is the number of 64-bit words to store scalars. +const _N = 7 // 448 / 64 + +// Scalar represents a positive integer stored in little-endian order. +type Scalar [ScalarSize]byte + +type scalar64 [_N]uint64 + +func (z *scalar64) fromScalar(x *Scalar) { + z[0] = binary.LittleEndian.Uint64(x[0*8 : 1*8]) + z[1] = binary.LittleEndian.Uint64(x[1*8 : 2*8]) + z[2] = binary.LittleEndian.Uint64(x[2*8 : 3*8]) + z[3] = binary.LittleEndian.Uint64(x[3*8 : 4*8]) + z[4] = binary.LittleEndian.Uint64(x[4*8 : 5*8]) + z[5] = binary.LittleEndian.Uint64(x[5*8 : 6*8]) + z[6] = binary.LittleEndian.Uint64(x[6*8 : 7*8]) +} + +func (z *scalar64) toScalar(x *Scalar) { + binary.LittleEndian.PutUint64(x[0*8:1*8], z[0]) + binary.LittleEndian.PutUint64(x[1*8:2*8], z[1]) + binary.LittleEndian.PutUint64(x[2*8:3*8], z[2]) + binary.LittleEndian.PutUint64(x[3*8:4*8], z[3]) + binary.LittleEndian.PutUint64(x[4*8:5*8], z[4]) + binary.LittleEndian.PutUint64(x[5*8:6*8], z[5]) + binary.LittleEndian.PutUint64(x[6*8:7*8], z[6]) +} + +// add calculates z = x + y. Assumes len(z) > max(len(x),len(y)). +func add(z, x, y []uint64) uint64 { + l, L, zz := len(x), len(y), y + if l > L { + l, L, zz = L, l, x + } + c := uint64(0) + for i := 0; i < l; i++ { + z[i], c = bits.Add64(x[i], y[i], c) + } + for i := l; i < L; i++ { + z[i], c = bits.Add64(zz[i], 0, c) + } + return c +} + +// sub calculates z = x - y. Assumes len(z) > max(len(x),len(y)). +func sub(z, x, y []uint64) uint64 { + l, L, zz := len(x), len(y), y + if l > L { + l, L, zz = L, l, x + } + c := uint64(0) + for i := 0; i < l; i++ { + z[i], c = bits.Sub64(x[i], y[i], c) + } + for i := l; i < L; i++ { + z[i], c = bits.Sub64(zz[i], 0, c) + } + return c +} + +// mulWord calculates z = x * y. Assumes len(z) >= len(x)+1. +func mulWord(z, x []uint64, y uint64) { + for i := range z { + z[i] = 0 + } + carry := uint64(0) + for i := range x { + hi, lo := bits.Mul64(x[i], y) + lo, cc := bits.Add64(lo, z[i], 0) + hi, _ = bits.Add64(hi, 0, cc) + z[i], cc = bits.Add64(lo, carry, 0) + carry, _ = bits.Add64(hi, 0, cc) + } + z[len(x)] = carry +} + +// Cmov moves x into z if b=1. +func (z *scalar64) Cmov(b uint64, x *scalar64) { + m := uint64(0) - b + for i := range z { + z[i] = (z[i] &^ m) | (x[i] & m) + } +} + +// leftShift shifts to the left the words of z returning the more significant word. +func (z *scalar64) leftShift(low uint64) uint64 { + high := z[_N-1] + for i := _N - 1; i > 0; i-- { + z[i] = z[i-1] + } + z[0] = low + return high +} + +// reduceOneWord calculates z = z + 2^448*x such that the result fits in a Scalar. +func (z *scalar64) reduceOneWord(x uint64) { + prod := (&scalar64{})[:] + mulWord(prod, residue448[:], x) + cc := add(z[:], z[:], prod) + mulWord(prod, residue448[:], cc) + add(z[:], z[:], prod) +} + +// modOrder reduces z mod order. +func (z *scalar64) modOrder() { + var o64, x scalar64 + o64.fromScalar(&order) + // Performs: while (z >= order) { z = z-order } + // At most 8 (eight) iterations reduce 3 bits by subtracting. + for i := 0; i < 8; i++ { + c := sub(x[:], z[:], o64[:]) // (c || x) = z-order + z.Cmov(1-c, &x) // if c != 0 { z = x } + } +} + +// FromBytes stores z = x mod order, where x is a number stored in little-endian order. +func (z *Scalar) FromBytes(x []byte) { + n := len(x) + nCeil := (n + 7) >> 3 + for i := range z { + z[i] = 0 + } + if nCeil < _N { + copy(z[:], x) + return + } + copy(z[:], x[8*(nCeil-_N):]) + var z64 scalar64 + z64.fromScalar(z) + for i := nCeil - _N - 1; i >= 0; i-- { + low := binary.LittleEndian.Uint64(x[8*i:]) + high := z64.leftShift(low) + z64.reduceOneWord(high) + } + z64.modOrder() + z64.toScalar(z) +} + +// divBy4 calculates z = x/4 mod order. +func (z *Scalar) divBy4(x *Scalar) { z.Mul(x, &invFour) } + +// Red reduces z mod order. +func (z *Scalar) Red() { var t scalar64; t.fromScalar(z); t.modOrder(); t.toScalar(z) } + +// Neg calculates z = -z mod order. +func (z *Scalar) Neg() { z.Sub(&order, z) } + +// Add calculates z = x+y mod order. +func (z *Scalar) Add(x, y *Scalar) { + var z64, x64, y64, t scalar64 + x64.fromScalar(x) + y64.fromScalar(y) + c := add(z64[:], x64[:], y64[:]) + add(t[:], z64[:], residue448[:]) + z64.Cmov(c, &t) + z64.modOrder() + z64.toScalar(z) +} + +// Sub calculates z = x-y mod order. +func (z *Scalar) Sub(x, y *Scalar) { + var z64, x64, y64, t scalar64 + x64.fromScalar(x) + y64.fromScalar(y) + c := sub(z64[:], x64[:], y64[:]) + sub(t[:], z64[:], residue448[:]) + z64.Cmov(c, &t) + z64.modOrder() + z64.toScalar(z) +} + +// Mul calculates z = x*y mod order. +func (z *Scalar) Mul(x, y *Scalar) { + var z64, x64, y64 scalar64 + prod := (&[_N + 1]uint64{})[:] + x64.fromScalar(x) + y64.fromScalar(y) + mulWord(prod, x64[:], y64[_N-1]) + copy(z64[:], prod[:_N]) + z64.reduceOneWord(prod[_N]) + for i := _N - 2; i >= 0; i-- { + h := z64.leftShift(0) + z64.reduceOneWord(h) + mulWord(prod, x64[:], y64[i]) + c := add(z64[:], z64[:], prod[:_N]) + z64.reduceOneWord(prod[_N] + c) + } + z64.modOrder() + z64.toScalar(z) +} + +// IsZero returns true if z=0. +func (z *Scalar) IsZero() bool { z.Red(); return *z == Scalar{} } diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go new file mode 100644 index 00000000..83d7cdad --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go @@ -0,0 +1,138 @@ +package goldilocks + +import ( + "crypto/subtle" + "math/bits" + + "github.com/cloudflare/circl/internal/conv" + "github.com/cloudflare/circl/math" + fp "github.com/cloudflare/circl/math/fp448" +) + +// twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogenous to Goldilocks. +type twistCurve struct{} + +// Identity returns the identity point. +func (twistCurve) Identity() *twistPoint { + return &twistPoint{ + y: fp.One(), + z: fp.One(), + } +} + +// subYDiv16 update x = (x - y) / 16. +func subYDiv16(x *scalar64, y int64) { + s := uint64(y >> 63) + x0, b0 := bits.Sub64((*x)[0], uint64(y), 0) + x1, b1 := bits.Sub64((*x)[1], s, b0) + x2, b2 := bits.Sub64((*x)[2], s, b1) + x3, b3 := bits.Sub64((*x)[3], s, b2) + x4, b4 := bits.Sub64((*x)[4], s, b3) + x5, b5 := bits.Sub64((*x)[5], s, b4) + x6, _ := bits.Sub64((*x)[6], s, b5) + x[0] = (x0 >> 4) | (x1 << 60) + x[1] = (x1 >> 4) | (x2 << 60) + x[2] = (x2 >> 4) | (x3 << 60) + x[3] = (x3 >> 4) | (x4 << 60) + x[4] = (x4 >> 4) | (x5 << 60) + x[5] = (x5 >> 4) | (x6 << 60) + x[6] = (x6 >> 4) +} + +func recodeScalar(d *[113]int8, k *Scalar) { + var k64 scalar64 + k64.fromScalar(k) + for i := 0; i < 112; i++ { + d[i] = int8((k64[0] & 0x1f) - 16) + subYDiv16(&k64, int64(d[i])) + } + d[112] = int8(k64[0]) +} + +// ScalarMult returns kP. +func (e twistCurve) ScalarMult(k *Scalar, P *twistPoint) *twistPoint { + var TabP [8]preTwistPointProy + var S preTwistPointProy + var d [113]int8 + + var isZero int + if k.IsZero() { + isZero = 1 + } + subtle.ConstantTimeCopy(isZero, k[:], order[:]) + + minusK := *k + isEven := 1 - int(k[0]&0x1) + minusK.Neg() + subtle.ConstantTimeCopy(isEven, k[:], minusK[:]) + recodeScalar(&d, k) + + P.oddMultiples(TabP[:]) + Q := e.Identity() + for i := 112; i >= 0; i-- { + Q.Double() + Q.Double() + Q.Double() + Q.Double() + mask := d[i] >> 7 + absDi := (d[i] + mask) ^ mask + inx := int32((absDi - 1) >> 1) + sig := int((d[i] >> 7) & 0x1) + for j := range TabP { + S.cmov(&TabP[j], uint(subtle.ConstantTimeEq(inx, int32(j)))) + } + S.cneg(sig) + Q.mixAdd(&S) + } + Q.cneg(uint(isEven)) + return Q +} + +const ( + omegaFix = 7 + omegaVar = 5 +) + +// CombinedMult returns mG+nP. +func (e twistCurve) CombinedMult(m, n *Scalar, P *twistPoint) *twistPoint { + nafFix := math.OmegaNAF(conv.BytesLe2BigInt(m[:]), omegaFix) + nafVar := math.OmegaNAF(conv.BytesLe2BigInt(n[:]), omegaVar) + + if len(nafFix) > len(nafVar) { + nafVar = append(nafVar, make([]int32, len(nafFix)-len(nafVar))...) + } else if len(nafFix) < len(nafVar) { + nafFix = append(nafFix, make([]int32, len(nafVar)-len(nafFix))...) + } + + var TabQ [1 << (omegaVar - 2)]preTwistPointProy + P.oddMultiples(TabQ[:]) + Q := e.Identity() + for i := len(nafFix) - 1; i >= 0; i-- { + Q.Double() + // Generator point + if nafFix[i] != 0 { + idxM := absolute(nafFix[i]) >> 1 + R := tabVerif[idxM] + if nafFix[i] < 0 { + R.neg() + } + Q.mixAddZ1(&R) + } + // Variable input point + if nafVar[i] != 0 { + idxN := absolute(nafVar[i]) >> 1 + S := TabQ[idxN] + if nafVar[i] < 0 { + S.neg() + } + Q.mixAdd(&S) + } + } + return Q +} + +// absolute returns always a positive value. +func absolute(x int32) int32 { + mask := x >> 31 + return (x + mask) ^ mask +} diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go new file mode 100644 index 00000000..c55db77b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistPoint.go @@ -0,0 +1,135 @@ +package goldilocks + +import ( + "fmt" + + fp "github.com/cloudflare/circl/math/fp448" +) + +type twistPoint struct{ x, y, z, ta, tb fp.Elt } + +type preTwistPointAffine struct{ addYX, subYX, dt2 fp.Elt } + +type preTwistPointProy struct { + preTwistPointAffine + z2 fp.Elt +} + +func (P *twistPoint) String() string { + return fmt.Sprintf("x: %v\ny: %v\nz: %v\nta: %v\ntb: %v", P.x, P.y, P.z, P.ta, P.tb) +} + +// cneg conditionally negates the point if b=1. +func (P *twistPoint) cneg(b uint) { + t := &fp.Elt{} + fp.Neg(t, &P.x) + fp.Cmov(&P.x, t, b) + fp.Neg(t, &P.ta) + fp.Cmov(&P.ta, t, b) +} + +// Double updates P with 2P. +func (P *twistPoint) Double() { + // This is formula (7) from "Twisted Edwards Curves Revisited" by + // Hisil H., Wong K.KH., Carter G., Dawson E. (2008) + // https://doi.org/10.1007/978-3-540-89255-7_20 + Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb + a, b, c, e, f, g, h := Px, Py, Pz, Pta, Px, Py, Ptb + fp.Add(e, Px, Py) // x+y + fp.Sqr(a, Px) // A = x^2 + fp.Sqr(b, Py) // B = y^2 + fp.Sqr(c, Pz) // z^2 + fp.Add(c, c, c) // C = 2*z^2 + fp.Add(h, a, b) // H = A+B + fp.Sqr(e, e) // (x+y)^2 + fp.Sub(e, e, h) // E = (x+y)^2-A-B + fp.Sub(g, b, a) // G = B-A + fp.Sub(f, c, g) // F = C-G + fp.Mul(Pz, f, g) // Z = F * G + fp.Mul(Px, e, f) // X = E * F + fp.Mul(Py, g, h) // Y = G * H, T = E * H +} + +// mixAdd calculates P= P+Q, where Q is a precomputed point with Z_Q = 1. +func (P *twistPoint) mixAddZ1(Q *preTwistPointAffine) { + fp.Add(&P.z, &P.z, &P.z) // D = 2*z1 (z2=1) + P.coreAddition(Q) +} + +// coreAddition calculates P=P+Q for curves with A=-1. +func (P *twistPoint) coreAddition(Q *preTwistPointAffine) { + // This is the formula following (5) from "Twisted Edwards Curves Revisited" by + // Hisil H., Wong K.KH., Carter G., Dawson E. (2008) + // https://doi.org/10.1007/978-3-540-89255-7_20 + Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb + addYX2, subYX2, dt2 := &Q.addYX, &Q.subYX, &Q.dt2 + a, b, c, d, e, f, g, h := Px, Py, &fp.Elt{}, Pz, Pta, Px, Py, Ptb + fp.Mul(c, Pta, Ptb) // t1 = ta*tb + fp.Sub(h, Py, Px) // y1-x1 + fp.Add(b, Py, Px) // y1+x1 + fp.Mul(a, h, subYX2) // A = (y1-x1)*(y2-x2) + fp.Mul(b, b, addYX2) // B = (y1+x1)*(y2+x2) + fp.Mul(c, c, dt2) // C = 2*D*t1*t2 + fp.Sub(e, b, a) // E = B-A + fp.Add(h, b, a) // H = B+A + fp.Sub(f, d, c) // F = D-C + fp.Add(g, d, c) // G = D+C + fp.Mul(Pz, f, g) // Z = F * G + fp.Mul(Px, e, f) // X = E * F + fp.Mul(Py, g, h) // Y = G * H, T = E * H +} + +func (P *preTwistPointAffine) neg() { + P.addYX, P.subYX = P.subYX, P.addYX + fp.Neg(&P.dt2, &P.dt2) +} + +func (P *preTwistPointAffine) cneg(b int) { + t := &fp.Elt{} + fp.Cswap(&P.addYX, &P.subYX, uint(b)) + fp.Neg(t, &P.dt2) + fp.Cmov(&P.dt2, t, uint(b)) +} + +func (P *preTwistPointAffine) cmov(Q *preTwistPointAffine, b uint) { + fp.Cmov(&P.addYX, &Q.addYX, b) + fp.Cmov(&P.subYX, &Q.subYX, b) + fp.Cmov(&P.dt2, &Q.dt2, b) +} + +// mixAdd calculates P= P+Q, where Q is a precomputed point with Z_Q != 1. +func (P *twistPoint) mixAdd(Q *preTwistPointProy) { + fp.Mul(&P.z, &P.z, &Q.z2) // D = 2*z1*z2 + P.coreAddition(&Q.preTwistPointAffine) +} + +// oddMultiples calculates T[i] = (2*i-1)P for 0 < i < len(T). +func (P *twistPoint) oddMultiples(T []preTwistPointProy) { + if n := len(T); n > 0 { + T[0].FromTwistPoint(P) + _2P := *P + _2P.Double() + R := &preTwistPointProy{} + R.FromTwistPoint(&_2P) + for i := 1; i < n; i++ { + P.mixAdd(R) + T[i].FromTwistPoint(P) + } + } +} + +// cmov conditionally moves Q into P if b=1. +func (P *preTwistPointProy) cmov(Q *preTwistPointProy, b uint) { + P.preTwistPointAffine.cmov(&Q.preTwistPointAffine, b) + fp.Cmov(&P.z2, &Q.z2, b) +} + +// FromTwistPoint precomputes some coordinates of Q for missed addition. +func (P *preTwistPointProy) FromTwistPoint(Q *twistPoint) { + fp.Add(&P.addYX, &Q.y, &Q.x) // addYX = X + Y + fp.Sub(&P.subYX, &Q.y, &Q.x) // subYX = Y - X + fp.Mul(&P.dt2, &Q.ta, &Q.tb) // T = ta*tb + fp.Mul(&P.dt2, &P.dt2, ¶mDTwist) // D*T + fp.Add(&P.dt2, &P.dt2, &P.dt2) // dt2 = 2*D*T + fp.Add(&P.z2, &Q.z, &Q.z) // z2 = 2*Z +} diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go new file mode 100644 index 00000000..ed432e02 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twistTables.go @@ -0,0 +1,216 @@ +package goldilocks + +import fp "github.com/cloudflare/circl/math/fp448" + +var tabFixMult = [fxV][fx2w1]preTwistPointAffine{ + { + { + addYX: fp.Elt{0x65, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2b, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05}, + subYX: fp.Elt{0x64, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2d, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05}, + dt2: fp.Elt{0x1a, 0x33, 0xea, 0x64, 0x45, 0x1c, 0xdf, 0x17, 0x1d, 0x16, 0x34, 0x28, 0xd6, 0x61, 0x19, 0x67, 0x79, 0xb4, 0x13, 0xcf, 0x3e, 0x7c, 0x0e, 0x72, 0xda, 0xf1, 0x5f, 0xda, 0xe6, 0xcf, 0x42, 0xd3, 0xb6, 0x17, 0xc2, 0x68, 0x13, 0x2d, 0xd9, 0x60, 0x3e, 0xae, 0xf0, 0x5b, 0x96, 0xf0, 0xcd, 0xaf, 0xea, 0xb7, 0x0d, 0x59, 0x16, 0xa7, 0xff, 0x55}, + }, + { + addYX: fp.Elt{0xca, 0xd8, 0x7d, 0x86, 0x1a, 0xef, 0xad, 0x11, 0xe3, 0x27, 0x41, 0x7e, 0x7f, 0x3e, 0xa9, 0xd2, 0xb5, 0x4e, 0x50, 0xe0, 0x77, 0x91, 0xc2, 0x13, 0x52, 0x73, 0x41, 0x09, 0xa6, 0x57, 0x9a, 0xc8, 0xa8, 0x90, 0x9d, 0x26, 0x14, 0xbb, 0xa1, 0x2a, 0xf7, 0x45, 0x43, 0x4e, 0xea, 0x35, 0x62, 0xe1, 0x08, 0x85, 0x46, 0xb8, 0x24, 0x05, 0x2d, 0xab}, + subYX: fp.Elt{0x9b, 0xe6, 0xd3, 0xe5, 0xfe, 0x50, 0x36, 0x3c, 0x3c, 0x6d, 0x74, 0x1d, 0x74, 0xc0, 0xde, 0x5b, 0x45, 0x27, 0xe5, 0x12, 0xee, 0x63, 0x35, 0x6b, 0x13, 0xe2, 0x41, 0x6b, 0x3a, 0x05, 0x2b, 0xb1, 0x89, 0x26, 0xb6, 0xc6, 0xd1, 0x84, 0xff, 0x0e, 0x9b, 0xa3, 0xfb, 0x21, 0x36, 0x6b, 0x01, 0xf7, 0x9f, 0x7c, 0xeb, 0xf5, 0x18, 0x7a, 0x2a, 0x70}, + dt2: fp.Elt{0x09, 0xad, 0x99, 0x1a, 0x38, 0xd3, 0xdf, 0x22, 0x37, 0x32, 0x61, 0x8b, 0xf3, 0x19, 0x48, 0x08, 0xe8, 0x49, 0xb6, 0x4a, 0xa7, 0xed, 0xa4, 0xa2, 0xee, 0x86, 0xd7, 0x31, 0x5e, 0xce, 0x95, 0x76, 0x86, 0x42, 0x1c, 0x9d, 0x07, 0x14, 0x8c, 0x34, 0x18, 0x9c, 0x6d, 0x3a, 0xdf, 0xa9, 0xe8, 0x36, 0x7e, 0xe4, 0x95, 0xbe, 0xb5, 0x09, 0xf8, 0x9c}, + }, + { + addYX: fp.Elt{0x51, 0xdb, 0x49, 0xa8, 0x9f, 0xe3, 0xd7, 0xec, 0x0d, 0x0f, 0x49, 0xe8, 0xb6, 0xc5, 0x0f, 0x5a, 0x1c, 0xce, 0x54, 0x0d, 0xb1, 0x8d, 0x5b, 0xbf, 0xf4, 0xaa, 0x34, 0x77, 0xc4, 0x5d, 0x59, 0xb6, 0xc5, 0x0e, 0x5a, 0xd8, 0x5b, 0x30, 0xc2, 0x1d, 0xec, 0x85, 0x1c, 0x42, 0xbe, 0x24, 0x2e, 0x50, 0x55, 0x44, 0xb2, 0x3a, 0x01, 0xaa, 0x98, 0xfb}, + subYX: fp.Elt{0xe7, 0x29, 0xb7, 0xd0, 0xaa, 0x4f, 0x32, 0x53, 0x56, 0xde, 0xbc, 0xd1, 0x92, 0x5d, 0x19, 0xbe, 0xa3, 0xe3, 0x75, 0x48, 0xe0, 0x7a, 0x1b, 0x54, 0x7a, 0xb7, 0x41, 0x77, 0x84, 0x38, 0xdd, 0x14, 0x9f, 0xca, 0x3f, 0xa3, 0xc8, 0xa7, 0x04, 0x70, 0xf1, 0x4d, 0x3d, 0xb3, 0x84, 0x79, 0xcb, 0xdb, 0xe4, 0xc5, 0x42, 0x9b, 0x57, 0x19, 0xf1, 0x2d}, + dt2: fp.Elt{0x20, 0xb4, 0x94, 0x9e, 0xdf, 0x31, 0x44, 0x0b, 0xc9, 0x7b, 0x75, 0x40, 0x9d, 0xd1, 0x96, 0x39, 0x70, 0x71, 0x15, 0xc8, 0x93, 0xd5, 0xc5, 0xe5, 0xba, 0xfe, 0xee, 0x08, 0x6a, 0x98, 0x0a, 0x1b, 0xb2, 0xaa, 0x3a, 0xf4, 0xa4, 0x79, 0xf9, 0x8e, 0x4d, 0x65, 0x10, 0x9b, 0x3a, 0x6e, 0x7c, 0x87, 0x94, 0x92, 0x11, 0x65, 0xbf, 0x1a, 0x09, 0xde}, + }, + { + addYX: fp.Elt{0xf3, 0x84, 0x76, 0x77, 0xa5, 0x6b, 0x27, 0x3b, 0x83, 0x3d, 0xdf, 0xa0, 0xeb, 0x32, 0x6d, 0x58, 0x81, 0x57, 0x64, 0xc2, 0x21, 0x7c, 0x9b, 0xea, 0xe6, 0xb0, 0x93, 0xf9, 0xe7, 0xc3, 0xed, 0x5a, 0x8e, 0xe2, 0xb4, 0x72, 0x76, 0x66, 0x0f, 0x22, 0x29, 0x94, 0x3e, 0x63, 0x48, 0x5e, 0x80, 0xcb, 0xac, 0xfa, 0x95, 0xb6, 0x4b, 0xc4, 0x95, 0x33}, + subYX: fp.Elt{0x0c, 0x55, 0xd1, 0x5e, 0x5f, 0xbf, 0xbf, 0xe2, 0x4c, 0xfc, 0x37, 0x4a, 0xc4, 0xb1, 0xf4, 0x83, 0x61, 0x93, 0x60, 0x8e, 0x9f, 0x31, 0xf0, 0xa0, 0x41, 0xff, 0x1d, 0xe2, 0x7f, 0xca, 0x40, 0xd6, 0x88, 0xe8, 0x91, 0x61, 0xe2, 0x11, 0x18, 0x83, 0xf3, 0x25, 0x2f, 0x3f, 0x49, 0x40, 0xd4, 0x83, 0xe2, 0xd7, 0x74, 0x6a, 0x16, 0x86, 0x4e, 0xab}, + dt2: fp.Elt{0xdd, 0x58, 0x65, 0xd8, 0x9f, 0xdd, 0x70, 0x7f, 0x0f, 0xec, 0xbd, 0x5c, 0x5c, 0x9b, 0x7e, 0x1b, 0x9f, 0x79, 0x36, 0x1f, 0xfd, 0x79, 0x10, 0x1c, 0x52, 0xf3, 0x22, 0xa4, 0x1f, 0x71, 0x6e, 0x63, 0x14, 0xf4, 0xa7, 0x3e, 0xbe, 0xad, 0x43, 0x30, 0x38, 0x8c, 0x29, 0xc6, 0xcf, 0x50, 0x75, 0x21, 0xe5, 0x78, 0xfd, 0xb0, 0x9a, 0xc4, 0x6d, 0xd4}, + }, + }, + { + { + addYX: fp.Elt{0x7a, 0xa1, 0x38, 0xa6, 0xfd, 0x0e, 0x96, 0xd5, 0x26, 0x76, 0x86, 0x70, 0x80, 0x30, 0xa6, 0x67, 0xeb, 0xf4, 0x39, 0xdb, 0x22, 0xf5, 0x9f, 0x98, 0xe4, 0xb5, 0x3a, 0x0c, 0x59, 0xbf, 0x85, 0xc6, 0xf0, 0x0b, 0x1c, 0x41, 0x38, 0x09, 0x01, 0xdb, 0xd6, 0x3c, 0xb7, 0xf1, 0x08, 0x6b, 0x4b, 0x9e, 0x63, 0x53, 0x83, 0xd3, 0xab, 0xa3, 0x72, 0x0d}, + subYX: fp.Elt{0x84, 0x68, 0x25, 0xe8, 0xe9, 0x8f, 0x91, 0xbf, 0xf7, 0xa4, 0x30, 0xae, 0xea, 0x9f, 0xdd, 0x56, 0x64, 0x09, 0xc9, 0x54, 0x68, 0x4e, 0x33, 0xc5, 0x6f, 0x7b, 0x2d, 0x52, 0x2e, 0x42, 0xbe, 0xbe, 0xf5, 0x64, 0xbf, 0x77, 0x54, 0xdf, 0xb0, 0x10, 0xd2, 0x16, 0x5d, 0xce, 0xaf, 0x9f, 0xfb, 0xa3, 0x63, 0x50, 0xcb, 0xc0, 0xd0, 0x88, 0x44, 0xa3}, + dt2: fp.Elt{0xc3, 0x8b, 0xa5, 0xf1, 0x44, 0xe4, 0x41, 0xcd, 0x75, 0xe3, 0x17, 0x69, 0x5b, 0xb9, 0xbb, 0xee, 0x82, 0xbb, 0xce, 0x57, 0xdf, 0x2a, 0x9c, 0x12, 0xab, 0x66, 0x08, 0x68, 0x05, 0x1b, 0x87, 0xee, 0x5d, 0x1e, 0x18, 0x14, 0x22, 0x4b, 0x99, 0x61, 0x75, 0x28, 0xe7, 0x65, 0x1c, 0x36, 0xb6, 0x18, 0x09, 0xa8, 0xdf, 0xef, 0x30, 0x35, 0xbc, 0x58}, + }, + { + addYX: fp.Elt{0xc5, 0xd3, 0x0e, 0x6f, 0xaf, 0x06, 0x69, 0xc4, 0x07, 0x9e, 0x58, 0x6e, 0x3f, 0x49, 0xd9, 0x0a, 0x3c, 0x2c, 0x37, 0xcd, 0x27, 0x4d, 0x87, 0x91, 0x7a, 0xb0, 0x28, 0xad, 0x2f, 0x68, 0x92, 0x05, 0x97, 0xf1, 0x30, 0x5f, 0x4c, 0x10, 0x20, 0x30, 0xd3, 0x08, 0x3f, 0xc1, 0xc6, 0xb7, 0xb5, 0xd1, 0x71, 0x7b, 0xa8, 0x0a, 0xd8, 0xf5, 0x17, 0xcf}, + subYX: fp.Elt{0x64, 0xd4, 0x8f, 0x91, 0x40, 0xab, 0x6e, 0x1a, 0x62, 0x83, 0xdc, 0xd7, 0x30, 0x1a, 0x4a, 0x2a, 0x4c, 0x54, 0x86, 0x19, 0x81, 0x5d, 0x04, 0x52, 0xa3, 0xca, 0x82, 0x38, 0xdc, 0x1e, 0xf0, 0x7a, 0x78, 0x76, 0x49, 0x4f, 0x71, 0xc4, 0x74, 0x2f, 0xf0, 0x5b, 0x2e, 0x5e, 0xac, 0xef, 0x17, 0xe4, 0x8e, 0x6e, 0xed, 0x43, 0x23, 0x61, 0x99, 0x49}, + dt2: fp.Elt{0x64, 0x90, 0x72, 0x76, 0xf8, 0x2c, 0x7d, 0x57, 0xf9, 0x30, 0x5e, 0x7a, 0x10, 0x74, 0x19, 0x39, 0xd9, 0xaf, 0x0a, 0xf1, 0x43, 0xed, 0x88, 0x9c, 0x8b, 0xdc, 0x9b, 0x1c, 0x90, 0xe7, 0xf7, 0xa3, 0xa5, 0x0d, 0xc6, 0xbc, 0x30, 0xfb, 0x91, 0x1a, 0x51, 0xba, 0x2d, 0xbe, 0x89, 0xdf, 0x1d, 0xdc, 0x53, 0xa8, 0x82, 0x8a, 0xd3, 0x8d, 0x16, 0x68}, + }, + { + addYX: fp.Elt{0xef, 0x5c, 0xe3, 0x74, 0xbf, 0x13, 0x4a, 0xbf, 0x66, 0x73, 0x64, 0xb7, 0xd4, 0xce, 0x98, 0x82, 0x05, 0xfa, 0x98, 0x0c, 0x0a, 0xae, 0xe5, 0x6b, 0x9f, 0xac, 0xbb, 0x6e, 0x1f, 0xcf, 0xff, 0xa6, 0x71, 0x9a, 0xa8, 0x7a, 0x9e, 0x64, 0x1f, 0x20, 0x4a, 0x61, 0xa2, 0xd6, 0x50, 0xe3, 0xba, 0x81, 0x0c, 0x50, 0x59, 0x69, 0x59, 0x15, 0x55, 0xdb}, + subYX: fp.Elt{0xe8, 0x77, 0x4d, 0xe8, 0x66, 0x3d, 0xc1, 0x00, 0x3c, 0xf2, 0x25, 0x00, 0xdc, 0xb2, 0xe5, 0x9b, 0x12, 0x89, 0xf3, 0xd6, 0xea, 0x85, 0x60, 0xfe, 0x67, 0x91, 0xfd, 0x04, 0x7c, 0xe0, 0xf1, 0x86, 0x06, 0x11, 0x66, 0xee, 0xd4, 0xd5, 0xbe, 0x3b, 0x0f, 0xe3, 0x59, 0xb3, 0x4f, 0x00, 0xb6, 0xce, 0x80, 0xc1, 0x61, 0xf7, 0xaf, 0x04, 0x6a, 0x3c}, + dt2: fp.Elt{0x00, 0xd7, 0x32, 0x93, 0x67, 0x70, 0x6f, 0xd7, 0x69, 0xab, 0xb1, 0xd3, 0xdc, 0xd6, 0xa8, 0xdd, 0x35, 0x25, 0xca, 0xd3, 0x8a, 0x6d, 0xce, 0xfb, 0xfd, 0x2b, 0x83, 0xf0, 0xd4, 0xac, 0x66, 0xfb, 0x72, 0x87, 0x7e, 0x55, 0xb7, 0x91, 0x58, 0x10, 0xc3, 0x11, 0x7e, 0x15, 0xfe, 0x7c, 0x55, 0x90, 0xa3, 0x9e, 0xed, 0x9a, 0x7f, 0xa7, 0xb7, 0xeb}, + }, + { + addYX: fp.Elt{0x25, 0x0f, 0xc2, 0x09, 0x9c, 0x10, 0xc8, 0x7c, 0x93, 0xa7, 0xbe, 0xe9, 0x26, 0x25, 0x7c, 0x21, 0xfe, 0xe7, 0x5f, 0x3c, 0x02, 0x83, 0xa7, 0x9e, 0xdf, 0xc0, 0x94, 0x2b, 0x7d, 0x1a, 0xd0, 0x1d, 0xcc, 0x2e, 0x7d, 0xd4, 0x85, 0xe7, 0xc1, 0x15, 0x66, 0xd6, 0xd6, 0x32, 0xb8, 0xf7, 0x63, 0xaa, 0x3b, 0xa5, 0xea, 0x49, 0xad, 0x88, 0x9b, 0x66}, + subYX: fp.Elt{0x09, 0x97, 0x79, 0x36, 0x41, 0x56, 0x9b, 0xdf, 0x15, 0xd8, 0x43, 0x28, 0x17, 0x5b, 0x96, 0xc9, 0xcf, 0x39, 0x1f, 0x13, 0xf7, 0x4d, 0x1d, 0x1f, 0xda, 0x51, 0x56, 0xe7, 0x0a, 0x5a, 0x65, 0xb6, 0x2a, 0x87, 0x49, 0x86, 0xc2, 0x2b, 0xcd, 0xfe, 0x07, 0xf6, 0x4c, 0xe2, 0x1d, 0x9b, 0xd8, 0x82, 0x09, 0x5b, 0x11, 0x10, 0x62, 0x56, 0x89, 0xbd}, + dt2: fp.Elt{0xd9, 0x15, 0x73, 0xf2, 0x96, 0x35, 0x53, 0xb0, 0xe7, 0xa8, 0x0b, 0x93, 0x35, 0x0b, 0x3a, 0x00, 0xf5, 0x18, 0xb1, 0xc3, 0x12, 0x3f, 0x91, 0x17, 0xc1, 0x4c, 0x15, 0x5a, 0x86, 0x92, 0x11, 0xbd, 0x44, 0x40, 0x5a, 0x7b, 0x15, 0x89, 0xba, 0xc1, 0xc1, 0xbc, 0x43, 0x45, 0xe6, 0x52, 0x02, 0x73, 0x0a, 0xd0, 0x2a, 0x19, 0xda, 0x47, 0xa8, 0xff}, + }, + }, +} + +// tabVerif contains the odd multiples of P. The entry T[i] = (2i+1)P, where +// P = phi(G) and G is the generator of the Goldilocks curve, and phi is a +// 4-degree isogeny. +var tabVerif = [1 << (omegaFix - 2)]preTwistPointAffine{ + { /* 1P*/ + addYX: fp.Elt{0x65, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2b, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05}, + subYX: fp.Elt{0x64, 0x4a, 0xdd, 0xdf, 0xb4, 0x79, 0x60, 0xc8, 0xa1, 0x70, 0xb4, 0x3a, 0x1e, 0x0c, 0x9b, 0x19, 0xe5, 0x48, 0x3f, 0xd7, 0x44, 0x18, 0x18, 0x14, 0x14, 0x27, 0x45, 0xd0, 0x2d, 0x24, 0xd5, 0x93, 0xc3, 0x74, 0x4c, 0x50, 0x70, 0x43, 0x26, 0x05, 0x08, 0x24, 0xca, 0x78, 0x30, 0xc1, 0x06, 0x8d, 0xd4, 0x86, 0x42, 0xf0, 0x14, 0xde, 0x08, 0x05}, + dt2: fp.Elt{0x1a, 0x33, 0xea, 0x64, 0x45, 0x1c, 0xdf, 0x17, 0x1d, 0x16, 0x34, 0x28, 0xd6, 0x61, 0x19, 0x67, 0x79, 0xb4, 0x13, 0xcf, 0x3e, 0x7c, 0x0e, 0x72, 0xda, 0xf1, 0x5f, 0xda, 0xe6, 0xcf, 0x42, 0xd3, 0xb6, 0x17, 0xc2, 0x68, 0x13, 0x2d, 0xd9, 0x60, 0x3e, 0xae, 0xf0, 0x5b, 0x96, 0xf0, 0xcd, 0xaf, 0xea, 0xb7, 0x0d, 0x59, 0x16, 0xa7, 0xff, 0x55}, + }, + { /* 3P*/ + addYX: fp.Elt{0xd1, 0xe9, 0xa8, 0x33, 0x20, 0x76, 0x18, 0x08, 0x45, 0x2a, 0xc9, 0x67, 0x2a, 0xc3, 0x15, 0x24, 0xf9, 0x74, 0x21, 0x30, 0x99, 0x59, 0x8b, 0xb2, 0xf0, 0xa4, 0x07, 0xe2, 0x6a, 0x36, 0x8d, 0xd9, 0xd2, 0x4a, 0x7f, 0x73, 0x50, 0x39, 0x3d, 0xaa, 0xa7, 0x51, 0x73, 0x0d, 0x2b, 0x8b, 0x96, 0x47, 0xac, 0x3c, 0x5d, 0xaa, 0x39, 0x9c, 0xcf, 0xd5}, + subYX: fp.Elt{0x6b, 0x11, 0x5d, 0x1a, 0xf9, 0x41, 0x9d, 0xc5, 0x30, 0x3e, 0xad, 0x25, 0x2c, 0x04, 0x45, 0xea, 0xcc, 0x67, 0x07, 0x85, 0xe9, 0xda, 0x0e, 0xb5, 0x40, 0xb7, 0x32, 0xb4, 0x49, 0xdd, 0xff, 0xaa, 0xfc, 0xbb, 0x19, 0xca, 0x8b, 0x79, 0x2b, 0x8f, 0x8d, 0x00, 0x33, 0xc2, 0xad, 0xe9, 0xd3, 0x12, 0xa8, 0xaa, 0x87, 0x62, 0xad, 0x2d, 0xff, 0xa4}, + dt2: fp.Elt{0xb0, 0xaf, 0x3b, 0xea, 0xf0, 0x42, 0x0b, 0x5e, 0x88, 0xd3, 0x98, 0x08, 0x87, 0x59, 0x72, 0x0a, 0xc2, 0xdf, 0xcb, 0x7f, 0x59, 0xb5, 0x4c, 0x63, 0x68, 0xe8, 0x41, 0x38, 0x67, 0x4f, 0xe9, 0xc6, 0xb2, 0x6b, 0x08, 0xa7, 0xf7, 0x0e, 0xcd, 0xea, 0xca, 0x3d, 0xaf, 0x8e, 0xda, 0x4b, 0x2e, 0xd2, 0x88, 0x64, 0x8d, 0xc5, 0x5f, 0x76, 0x0f, 0x3d}, + }, + { /* 5P*/ + addYX: fp.Elt{0xe5, 0x65, 0xc9, 0xe2, 0x75, 0xf0, 0x7d, 0x1a, 0xba, 0xa4, 0x40, 0x4b, 0x93, 0x12, 0xa2, 0x80, 0x95, 0x0d, 0x03, 0x93, 0xe8, 0xa5, 0x4d, 0xe2, 0x3d, 0x81, 0xf5, 0xce, 0xd4, 0x2d, 0x25, 0x59, 0x16, 0x5c, 0xe7, 0xda, 0xc7, 0x45, 0xd2, 0x7e, 0x2c, 0x38, 0xd4, 0x37, 0x64, 0xb2, 0xc2, 0x28, 0xc5, 0x72, 0x16, 0x32, 0x45, 0x36, 0x6f, 0x9f}, + subYX: fp.Elt{0x09, 0xf4, 0x7e, 0xbd, 0x89, 0xdb, 0x19, 0x58, 0xe1, 0x08, 0x00, 0x8a, 0xf4, 0x5f, 0x2a, 0x32, 0x40, 0xf0, 0x2c, 0x3f, 0x5d, 0xe4, 0xfc, 0x89, 0x11, 0x24, 0xb4, 0x2f, 0x97, 0xad, 0xac, 0x8f, 0x19, 0xab, 0xfa, 0x12, 0xe5, 0xf9, 0x50, 0x4e, 0x50, 0x6f, 0x32, 0x30, 0x88, 0xa6, 0xe5, 0x48, 0x28, 0xa2, 0x1b, 0x9f, 0xcd, 0xe2, 0x43, 0x38}, + dt2: fp.Elt{0xa9, 0xcc, 0x53, 0x39, 0x86, 0x02, 0x60, 0x75, 0x34, 0x99, 0x57, 0xbd, 0xfc, 0x5a, 0x8e, 0xce, 0x5e, 0x98, 0x22, 0xd0, 0xa5, 0x24, 0xff, 0x90, 0x28, 0x9f, 0x58, 0xf3, 0x39, 0xe9, 0xba, 0x36, 0x23, 0xfb, 0x7f, 0x41, 0xcc, 0x2b, 0x5a, 0x25, 0x3f, 0x4c, 0x2a, 0xf1, 0x52, 0x6f, 0x2f, 0x07, 0xe3, 0x88, 0x81, 0x77, 0xdd, 0x7c, 0x88, 0x82}, + }, + { /* 7P*/ + addYX: fp.Elt{0xf7, 0xee, 0x88, 0xfd, 0x3a, 0xbf, 0x7e, 0x28, 0x39, 0x23, 0x79, 0xe6, 0x5c, 0x56, 0xcb, 0xb5, 0x48, 0x6a, 0x80, 0x6d, 0x37, 0x60, 0x6c, 0x10, 0x35, 0x49, 0x4b, 0x46, 0x60, 0xd4, 0x79, 0xd4, 0x53, 0xd3, 0x67, 0x88, 0xd0, 0x41, 0xd5, 0x43, 0x85, 0xc8, 0x71, 0xe3, 0x1c, 0xb6, 0xda, 0x22, 0x64, 0x8f, 0x80, 0xac, 0xad, 0x7d, 0xd5, 0x82}, + subYX: fp.Elt{0x92, 0x40, 0xc1, 0x83, 0x21, 0x9b, 0xd5, 0x7d, 0x3f, 0x29, 0xb6, 0x26, 0xef, 0x12, 0xb9, 0x27, 0x39, 0x42, 0x37, 0x97, 0x09, 0x9a, 0x08, 0xe1, 0x68, 0xb6, 0x7a, 0x3f, 0x9f, 0x45, 0xf8, 0x37, 0x19, 0x83, 0x97, 0xe6, 0x73, 0x30, 0x32, 0x35, 0xcf, 0xae, 0x5c, 0x12, 0x68, 0xdf, 0x6e, 0x2b, 0xde, 0x83, 0xa0, 0x44, 0x74, 0x2e, 0x4a, 0xe9}, + dt2: fp.Elt{0xcb, 0x22, 0x0a, 0xda, 0x6b, 0xc1, 0x8a, 0x29, 0xa1, 0xac, 0x8b, 0x5b, 0x8b, 0x32, 0x20, 0xf2, 0x21, 0xae, 0x0c, 0x43, 0xc4, 0xd7, 0x19, 0x37, 0x3d, 0x79, 0x25, 0x98, 0x6c, 0x9c, 0x22, 0x31, 0x2a, 0x55, 0x9f, 0xda, 0x5e, 0xa8, 0x13, 0xdb, 0x8e, 0x2e, 0x16, 0x39, 0xf4, 0x91, 0x6f, 0xec, 0x71, 0x71, 0xc9, 0x10, 0xf2, 0xa4, 0x8f, 0x11}, + }, + { /* 9P*/ + addYX: fp.Elt{0x85, 0xdd, 0x37, 0x62, 0x74, 0x8e, 0x33, 0x5b, 0x25, 0x12, 0x1b, 0xe7, 0xdf, 0x47, 0xe5, 0x12, 0xfd, 0x3a, 0x3a, 0xf5, 0x5d, 0x4c, 0xa2, 0x29, 0x3c, 0x5c, 0x2f, 0xee, 0x18, 0x19, 0x0a, 0x2b, 0xef, 0x67, 0x50, 0x7a, 0x0d, 0x29, 0xae, 0x55, 0x82, 0xcd, 0xd6, 0x41, 0x90, 0xb4, 0x13, 0x31, 0x5d, 0x11, 0xb8, 0xaa, 0x12, 0x86, 0x08, 0xac}, + subYX: fp.Elt{0xcc, 0x37, 0x8d, 0x83, 0x5f, 0xfd, 0xde, 0xd5, 0xf7, 0xf1, 0xae, 0x0a, 0xa7, 0x0b, 0xeb, 0x6d, 0x19, 0x8a, 0xb6, 0x1a, 0x59, 0xd8, 0xff, 0x3c, 0xbc, 0xbc, 0xef, 0x9c, 0xda, 0x7b, 0x75, 0x12, 0xaf, 0x80, 0x8f, 0x2c, 0x3c, 0xaa, 0x0b, 0x17, 0x86, 0x36, 0x78, 0x18, 0xc8, 0x8a, 0xf6, 0xb8, 0x2c, 0x2f, 0x57, 0x2c, 0x62, 0x57, 0xf6, 0x90}, + dt2: fp.Elt{0x83, 0xbc, 0xa2, 0x07, 0xa5, 0x38, 0x96, 0xea, 0xfe, 0x11, 0x46, 0x1d, 0x3b, 0xcd, 0x42, 0xc5, 0xee, 0x67, 0x04, 0x72, 0x08, 0xd8, 0xd9, 0x96, 0x07, 0xf7, 0xac, 0xc3, 0x64, 0xf1, 0x98, 0x2c, 0x55, 0xd7, 0x7d, 0xc8, 0x6c, 0xbd, 0x2c, 0xff, 0x15, 0xd6, 0x6e, 0xb8, 0x17, 0x8e, 0xa8, 0x27, 0x66, 0xb1, 0x73, 0x79, 0x96, 0xff, 0x29, 0x10}, + }, + { /* 11P*/ + addYX: fp.Elt{0x76, 0xcb, 0x9b, 0x0c, 0x5b, 0xfe, 0xe1, 0x2a, 0xdd, 0x6f, 0x6c, 0xdd, 0x6f, 0xb4, 0xc0, 0xc2, 0x1b, 0x4b, 0x38, 0xe8, 0x66, 0x8c, 0x1e, 0x31, 0x63, 0xb9, 0x94, 0xcd, 0xc3, 0x8c, 0x44, 0x25, 0x7b, 0xd5, 0x39, 0x80, 0xfc, 0x01, 0xaa, 0xf7, 0x2a, 0x61, 0x8a, 0x25, 0xd2, 0x5f, 0xc5, 0x66, 0x38, 0xa4, 0x17, 0xcf, 0x3e, 0x11, 0x0f, 0xa3}, + subYX: fp.Elt{0xe0, 0xb6, 0xd1, 0x9c, 0x71, 0x49, 0x2e, 0x7b, 0xde, 0x00, 0xda, 0x6b, 0xf1, 0xec, 0xe6, 0x7a, 0x15, 0x38, 0x71, 0xe9, 0x7b, 0xdb, 0xf8, 0x98, 0xc0, 0x91, 0x2e, 0x53, 0xee, 0x92, 0x87, 0x25, 0xc9, 0xb0, 0xbb, 0x33, 0x15, 0x46, 0x7f, 0xfd, 0x4f, 0x8b, 0x77, 0x05, 0x96, 0xb6, 0xe2, 0x08, 0xdb, 0x0d, 0x09, 0xee, 0x5b, 0xd1, 0x2a, 0x63}, + dt2: fp.Elt{0x8f, 0x7b, 0x57, 0x8c, 0xbf, 0x06, 0x0d, 0x43, 0x21, 0x92, 0x94, 0x2d, 0x6a, 0x38, 0x07, 0x0f, 0xa0, 0xf1, 0xe3, 0xd8, 0x2a, 0xbf, 0x46, 0xc6, 0x9e, 0x1f, 0x8f, 0x2b, 0x46, 0x84, 0x0b, 0x74, 0xed, 0xff, 0xf8, 0xa5, 0x94, 0xae, 0xf1, 0x67, 0xb1, 0x9b, 0xdd, 0x4a, 0xd0, 0xdb, 0xc2, 0xb5, 0x58, 0x49, 0x0c, 0xa9, 0x1d, 0x7d, 0xa9, 0xd3}, + }, + { /* 13P*/ + addYX: fp.Elt{0x73, 0x84, 0x2e, 0x31, 0x1f, 0xdc, 0xed, 0x9f, 0x74, 0xfa, 0xe0, 0x35, 0xb1, 0x85, 0x6a, 0x8d, 0x86, 0xd0, 0xff, 0xd6, 0x08, 0x43, 0x73, 0x1a, 0xd5, 0xf8, 0x43, 0xd4, 0xb3, 0xe5, 0x3f, 0xa8, 0x84, 0x17, 0x59, 0x65, 0x4e, 0xe6, 0xee, 0x54, 0x9c, 0xda, 0x5e, 0x7e, 0x98, 0x29, 0x6d, 0x73, 0x34, 0x1f, 0x99, 0x80, 0x54, 0x54, 0x81, 0x0b}, + subYX: fp.Elt{0xb1, 0xe5, 0xbb, 0x80, 0x22, 0x9c, 0x81, 0x6d, 0xaf, 0x27, 0x65, 0x6f, 0x7e, 0x9c, 0xb6, 0x8d, 0x35, 0x5c, 0x2e, 0x20, 0x48, 0x7a, 0x28, 0xf0, 0x97, 0xfe, 0xb7, 0x71, 0xce, 0xd6, 0xad, 0x3a, 0x81, 0xf6, 0x74, 0x5e, 0xf3, 0xfd, 0x1b, 0xd4, 0x1e, 0x7c, 0xc2, 0xb7, 0xc8, 0xa6, 0xc9, 0x89, 0x03, 0x47, 0xec, 0x24, 0xd6, 0x0e, 0xec, 0x9c}, + dt2: fp.Elt{0x91, 0x0a, 0x43, 0x34, 0x20, 0xc2, 0x64, 0xf7, 0x4e, 0x48, 0xc8, 0xd2, 0x95, 0x83, 0xd1, 0xa4, 0xfb, 0x4e, 0x41, 0x3b, 0x0d, 0xd5, 0x07, 0xd9, 0xf1, 0x13, 0x16, 0x78, 0x54, 0x57, 0xd0, 0xf1, 0x4f, 0x20, 0xac, 0xcf, 0x9c, 0x3b, 0x33, 0x0b, 0x99, 0x54, 0xc3, 0x7f, 0x3e, 0x57, 0x26, 0x86, 0xd5, 0xa5, 0x2b, 0x8d, 0xe3, 0x19, 0x36, 0xf7}, + }, + { /* 15P*/ + addYX: fp.Elt{0x23, 0x69, 0x47, 0x14, 0xf9, 0x9a, 0x50, 0xff, 0x64, 0xd1, 0x50, 0x35, 0xc3, 0x11, 0xd3, 0x19, 0xcf, 0x87, 0xda, 0x30, 0x0b, 0x50, 0xda, 0xc0, 0xe0, 0x25, 0x00, 0xe5, 0x68, 0x93, 0x04, 0xc2, 0xaf, 0xbd, 0x2f, 0x36, 0x5f, 0x47, 0x96, 0x10, 0xa8, 0xbd, 0xe4, 0x88, 0xac, 0x80, 0x52, 0x61, 0x73, 0xe9, 0x63, 0xdd, 0x99, 0xad, 0x20, 0x5b}, + subYX: fp.Elt{0x1b, 0x5e, 0xa2, 0x2a, 0x25, 0x0f, 0x86, 0xc0, 0xb1, 0x2e, 0x0c, 0x13, 0x40, 0x8d, 0xf0, 0xe6, 0x00, 0x55, 0x08, 0xc5, 0x7d, 0xf4, 0xc9, 0x31, 0x25, 0x3a, 0x99, 0x69, 0xdd, 0x67, 0x63, 0x9a, 0xd6, 0x89, 0x2e, 0xa1, 0x19, 0xca, 0x2c, 0xd9, 0x59, 0x5f, 0x5d, 0xc3, 0x6e, 0x62, 0x36, 0x12, 0x59, 0x15, 0xe1, 0xdc, 0xa4, 0xad, 0xc9, 0xd0}, + dt2: fp.Elt{0xbc, 0xea, 0xfc, 0xaf, 0x66, 0x23, 0xb7, 0x39, 0x6b, 0x2a, 0x96, 0xa8, 0x54, 0x43, 0xe9, 0xaa, 0x32, 0x40, 0x63, 0x92, 0x5e, 0xdf, 0x35, 0xc2, 0x9f, 0x24, 0x0c, 0xed, 0xfc, 0xde, 0x73, 0x8f, 0xa7, 0xd5, 0xa3, 0x2b, 0x18, 0x1f, 0xb0, 0xf8, 0xeb, 0x55, 0xd9, 0xc3, 0xfd, 0x28, 0x7c, 0x4f, 0xce, 0x0d, 0xf7, 0xae, 0xc2, 0x83, 0xc3, 0x78}, + }, + { /* 17P*/ + addYX: fp.Elt{0x71, 0xe6, 0x60, 0x93, 0x37, 0xdb, 0x01, 0xa5, 0x4c, 0xba, 0xe8, 0x8e, 0xd5, 0xf9, 0xd3, 0x98, 0xe5, 0xeb, 0xab, 0x3a, 0x15, 0x8b, 0x35, 0x60, 0xbe, 0xe5, 0x9c, 0x2d, 0x10, 0x9b, 0x2e, 0xcf, 0x65, 0x64, 0xea, 0x8f, 0x72, 0xce, 0xf5, 0x18, 0xe5, 0xe2, 0xf0, 0x0e, 0xae, 0x04, 0xec, 0xa0, 0x20, 0x65, 0x63, 0x07, 0xb1, 0x9f, 0x03, 0x97}, + subYX: fp.Elt{0x9e, 0x41, 0x64, 0x30, 0x95, 0x7f, 0x3a, 0x89, 0x7b, 0x0a, 0x79, 0x59, 0x23, 0x9a, 0x3b, 0xfe, 0xa4, 0x13, 0x08, 0xb2, 0x2e, 0x04, 0x50, 0x10, 0x30, 0xcd, 0x2e, 0xa4, 0x91, 0x71, 0x50, 0x36, 0x4a, 0x02, 0xf4, 0x8d, 0xa3, 0x36, 0x1b, 0xf4, 0x52, 0xba, 0x15, 0x04, 0x8b, 0x80, 0x25, 0xd9, 0xae, 0x67, 0x20, 0xd9, 0x88, 0x8f, 0x97, 0xa6}, + dt2: fp.Elt{0xb5, 0xe7, 0x46, 0xbd, 0x55, 0x23, 0xa0, 0x68, 0xc0, 0x12, 0xd9, 0xf1, 0x0a, 0x75, 0xe2, 0xda, 0xf4, 0x6b, 0xca, 0x14, 0xe4, 0x9f, 0x0f, 0xb5, 0x3c, 0xa6, 0xa5, 0xa2, 0x63, 0x94, 0xd1, 0x1c, 0x39, 0x58, 0x57, 0x02, 0x27, 0x98, 0xb6, 0x47, 0xc6, 0x61, 0x4b, 0x5c, 0xab, 0x6f, 0x2d, 0xab, 0xe3, 0xc1, 0x69, 0xf9, 0x12, 0xb0, 0xc8, 0xd5}, + }, + { /* 19P*/ + addYX: fp.Elt{0x19, 0x7d, 0xd5, 0xac, 0x79, 0xa2, 0x82, 0x9b, 0x28, 0x31, 0x22, 0xc0, 0x73, 0x02, 0x76, 0x17, 0x10, 0x70, 0x79, 0x57, 0xc9, 0x84, 0x62, 0x8e, 0x04, 0x04, 0x61, 0x67, 0x08, 0x48, 0xb4, 0x4b, 0xde, 0x53, 0x8c, 0xff, 0x36, 0x1b, 0x62, 0x86, 0x5d, 0xe1, 0x9b, 0xb1, 0xe5, 0xe8, 0x44, 0x64, 0xa1, 0x68, 0x3f, 0xa8, 0x45, 0x52, 0x91, 0xed}, + subYX: fp.Elt{0x42, 0x1a, 0x36, 0x1f, 0x90, 0x15, 0x24, 0x8d, 0x24, 0x80, 0xe6, 0xfe, 0x1e, 0xf0, 0xad, 0xaf, 0x6a, 0x93, 0xf0, 0xa6, 0x0d, 0x5d, 0xea, 0xf6, 0x62, 0x96, 0x7a, 0x05, 0x76, 0x85, 0x74, 0x32, 0xc7, 0xc8, 0x64, 0x53, 0x62, 0xe7, 0x54, 0x84, 0xe0, 0x40, 0x66, 0x19, 0x70, 0x40, 0x95, 0x35, 0x68, 0x64, 0x43, 0xcd, 0xba, 0x29, 0x32, 0xa8}, + dt2: fp.Elt{0x3e, 0xf6, 0xd6, 0xe4, 0x99, 0xeb, 0x20, 0x66, 0x08, 0x2e, 0x26, 0x64, 0xd7, 0x76, 0xf3, 0xb4, 0xc5, 0xa4, 0x35, 0x92, 0xd2, 0x99, 0x70, 0x5a, 0x1a, 0xe9, 0xe9, 0x3d, 0x3b, 0xe1, 0xcd, 0x0e, 0xee, 0x24, 0x13, 0x03, 0x22, 0xd6, 0xd6, 0x72, 0x08, 0x2b, 0xde, 0xfd, 0x93, 0xed, 0x0c, 0x7f, 0x5e, 0x31, 0x22, 0x4d, 0x80, 0x78, 0xc0, 0x48}, + }, + { /* 21P*/ + addYX: fp.Elt{0x8f, 0x72, 0xd2, 0x9e, 0xc4, 0xcd, 0x2c, 0xbf, 0xa8, 0xd3, 0x24, 0x62, 0x28, 0xee, 0x39, 0x0a, 0x19, 0x3a, 0x58, 0xff, 0x21, 0x2e, 0x69, 0x6c, 0x6e, 0x18, 0xd0, 0xcd, 0x61, 0xc1, 0x18, 0x02, 0x5a, 0xe9, 0xe3, 0xef, 0x1f, 0x8e, 0x10, 0xe8, 0x90, 0x2b, 0x48, 0xcd, 0xee, 0x38, 0xbd, 0x3a, 0xca, 0xbc, 0x2d, 0xe2, 0x3a, 0x03, 0x71, 0x02}, + subYX: fp.Elt{0xf8, 0xa4, 0x32, 0x26, 0x66, 0xaf, 0x3b, 0x53, 0xe7, 0xb0, 0x91, 0x92, 0xf5, 0x3c, 0x74, 0xce, 0xf2, 0xdd, 0x68, 0xa9, 0xf4, 0xcd, 0x5f, 0x60, 0xab, 0x71, 0xdf, 0xcd, 0x5c, 0x5d, 0x51, 0x72, 0x3a, 0x96, 0xea, 0xd6, 0xde, 0x54, 0x8e, 0x55, 0x4c, 0x08, 0x4c, 0x60, 0xdd, 0x34, 0xa9, 0x6f, 0xf3, 0x04, 0x02, 0xa8, 0xa6, 0x4e, 0x4d, 0x62}, + dt2: fp.Elt{0x76, 0x4a, 0xae, 0x38, 0x62, 0x69, 0x72, 0xdc, 0xe8, 0x43, 0xbe, 0x1d, 0x61, 0xde, 0x31, 0xc3, 0x42, 0x8f, 0x33, 0x9d, 0xca, 0xc7, 0x9c, 0xec, 0x6a, 0xe2, 0xaa, 0x01, 0x49, 0x78, 0x8d, 0x72, 0x4f, 0x38, 0xea, 0x52, 0xc2, 0xd3, 0xc9, 0x39, 0x71, 0xba, 0xb9, 0x09, 0x9b, 0xa3, 0x7f, 0x45, 0x43, 0x65, 0x36, 0x29, 0xca, 0xe7, 0x5c, 0x5f}, + }, + { /* 23P*/ + addYX: fp.Elt{0x89, 0x42, 0x35, 0x48, 0x6d, 0x74, 0xe5, 0x1f, 0xc3, 0xdd, 0x28, 0x5b, 0x84, 0x41, 0x33, 0x9f, 0x42, 0xf3, 0x1d, 0x5d, 0x15, 0x6d, 0x76, 0x33, 0x36, 0xaf, 0xe9, 0xdd, 0xfa, 0x63, 0x4f, 0x7a, 0x9c, 0xeb, 0x1c, 0x4f, 0x34, 0x65, 0x07, 0x54, 0xbb, 0x4c, 0x8b, 0x62, 0x9d, 0xd0, 0x06, 0x99, 0xb3, 0xe9, 0xda, 0x85, 0x19, 0xb0, 0x3d, 0x3c}, + subYX: fp.Elt{0xbb, 0x99, 0xf6, 0xbf, 0xaf, 0x2c, 0x22, 0x0d, 0x7a, 0xaa, 0x98, 0x6f, 0x01, 0x82, 0x99, 0xcf, 0x88, 0xbd, 0x0e, 0x3a, 0x89, 0xe0, 0x9c, 0x8c, 0x17, 0x20, 0xc4, 0xe0, 0xcf, 0x43, 0x7a, 0xef, 0x0d, 0x9f, 0x87, 0xd4, 0xfb, 0xf2, 0x96, 0xb8, 0x03, 0xe8, 0xcb, 0x5c, 0xec, 0x65, 0x5f, 0x49, 0xa4, 0x7c, 0x85, 0xb4, 0xf6, 0xc7, 0xdb, 0xa3}, + dt2: fp.Elt{0x11, 0xf3, 0x32, 0xa3, 0xa7, 0xb2, 0x7d, 0x51, 0x82, 0x44, 0xeb, 0xa2, 0x7d, 0x72, 0xcb, 0xc6, 0xf6, 0xc7, 0xb2, 0x38, 0x0e, 0x0f, 0x4f, 0x29, 0x00, 0xe4, 0x5b, 0x94, 0x46, 0x86, 0x66, 0xa1, 0x83, 0xb3, 0xeb, 0x15, 0xb6, 0x31, 0x50, 0x28, 0xeb, 0xed, 0x0d, 0x32, 0x39, 0xe9, 0x23, 0x81, 0x99, 0x3e, 0xff, 0x17, 0x4c, 0x11, 0x43, 0xd1}, + }, + { /* 25P*/ + addYX: fp.Elt{0xce, 0xe7, 0xf8, 0x94, 0x8f, 0x96, 0xf8, 0x96, 0xe6, 0x72, 0x20, 0x44, 0x2c, 0xa7, 0xfc, 0xba, 0xc8, 0xe1, 0xbb, 0xc9, 0x16, 0x85, 0xcd, 0x0b, 0xe5, 0xb5, 0x5a, 0x7f, 0x51, 0x43, 0x63, 0x8b, 0x23, 0x8e, 0x1d, 0x31, 0xff, 0x46, 0x02, 0x66, 0xcc, 0x9e, 0x4d, 0xa2, 0xca, 0xe2, 0xc7, 0xfd, 0x22, 0xb1, 0xdb, 0xdf, 0x6f, 0xe6, 0xa5, 0x82}, + subYX: fp.Elt{0xd0, 0xf5, 0x65, 0x40, 0xec, 0x8e, 0x65, 0x42, 0x78, 0xc1, 0x65, 0xe4, 0x10, 0xc8, 0x0b, 0x1b, 0xdd, 0x96, 0x68, 0xce, 0xee, 0x45, 0x55, 0xd8, 0x6e, 0xd3, 0xe6, 0x77, 0x19, 0xae, 0xc2, 0x8d, 0x8d, 0x3e, 0x14, 0x3f, 0x6d, 0x00, 0x2f, 0x9b, 0xd1, 0x26, 0x60, 0x28, 0x0f, 0x3a, 0x47, 0xb3, 0xe6, 0x68, 0x28, 0x24, 0x25, 0xca, 0xc8, 0x06}, + dt2: fp.Elt{0x54, 0xbb, 0x60, 0x92, 0xdb, 0x8f, 0x0f, 0x38, 0xe0, 0xe6, 0xe4, 0xc9, 0xcc, 0x14, 0x62, 0x01, 0xc4, 0x2b, 0x0f, 0xcf, 0xed, 0x7d, 0x8e, 0xa4, 0xd9, 0x73, 0x0b, 0xba, 0x0c, 0xaf, 0x0c, 0xf9, 0xe2, 0xeb, 0x29, 0x2a, 0x53, 0xdf, 0x2c, 0x5a, 0xfa, 0x8f, 0xc1, 0x01, 0xd7, 0xb1, 0x45, 0x73, 0x92, 0x32, 0x83, 0x85, 0x12, 0x74, 0x89, 0x44}, + }, + { /* 27P*/ + addYX: fp.Elt{0x0b, 0x73, 0x3c, 0xc2, 0xb1, 0x2e, 0xe1, 0xa7, 0xf5, 0xc9, 0x7a, 0xfb, 0x3d, 0x2d, 0xac, 0x59, 0xdb, 0xfa, 0x36, 0x11, 0xd1, 0x13, 0x04, 0x51, 0x1d, 0xab, 0x9b, 0x6b, 0x93, 0xfe, 0xda, 0xb0, 0x8e, 0xb4, 0x79, 0x11, 0x21, 0x0f, 0x65, 0xb9, 0xbb, 0x79, 0x96, 0x2a, 0xfd, 0x30, 0xe0, 0xb4, 0x2d, 0x9a, 0x55, 0x25, 0x5d, 0xd4, 0xad, 0x2a}, + subYX: fp.Elt{0x9e, 0xc5, 0x04, 0xfe, 0xec, 0x3c, 0x64, 0x1c, 0xed, 0x95, 0xed, 0xae, 0xaf, 0x5c, 0x6e, 0x08, 0x9e, 0x02, 0x29, 0x59, 0x7e, 0x5f, 0xc4, 0x9a, 0xd5, 0x32, 0x72, 0x86, 0xe1, 0x4e, 0x3c, 0xce, 0x99, 0x69, 0x3b, 0xc4, 0xdd, 0x4d, 0xb7, 0xbb, 0xda, 0x3b, 0x1a, 0x99, 0xaa, 0x62, 0x15, 0xc1, 0xf0, 0xb6, 0x6c, 0xec, 0x56, 0xc1, 0xff, 0x0c}, + dt2: fp.Elt{0x2f, 0xf1, 0x3f, 0x7a, 0x2d, 0x56, 0x19, 0x7f, 0xea, 0xbe, 0x59, 0x2e, 0x13, 0x67, 0x81, 0xfb, 0xdb, 0xc8, 0xa3, 0x1d, 0xd5, 0xe9, 0x13, 0x8b, 0x29, 0xdf, 0xcf, 0x9f, 0xe7, 0xd9, 0x0b, 0x70, 0xd3, 0x15, 0x57, 0x4a, 0xe9, 0x50, 0x12, 0x1b, 0x81, 0x4b, 0x98, 0x98, 0xa8, 0x31, 0x1d, 0x27, 0x47, 0x38, 0xed, 0x57, 0x99, 0x26, 0xb2, 0xee}, + }, + { /* 29P*/ + addYX: fp.Elt{0x1c, 0xb2, 0xb2, 0x67, 0x3b, 0x8b, 0x3d, 0x5a, 0x30, 0x7e, 0x38, 0x7e, 0x3c, 0x3d, 0x28, 0x56, 0x59, 0xd8, 0x87, 0x53, 0x8b, 0xe6, 0x6c, 0x5d, 0xe5, 0x0a, 0x33, 0x10, 0xce, 0xa2, 0x17, 0x0d, 0xe8, 0x76, 0xee, 0x68, 0xa8, 0x72, 0x54, 0xbd, 0xa6, 0x24, 0x94, 0x6e, 0x77, 0xc7, 0x53, 0xb7, 0x89, 0x1c, 0x7a, 0xe9, 0x78, 0x9a, 0x74, 0x5f}, + subYX: fp.Elt{0x76, 0x96, 0x1c, 0xcf, 0x08, 0x55, 0xd8, 0x1e, 0x0d, 0xa3, 0x59, 0x95, 0x32, 0xf4, 0xc2, 0x8e, 0x84, 0x5e, 0x4b, 0x04, 0xda, 0x71, 0xc9, 0x78, 0x52, 0xde, 0x14, 0xb4, 0x31, 0xf4, 0xd4, 0xb8, 0x58, 0xc5, 0x20, 0xe8, 0xdd, 0x15, 0xb5, 0xee, 0xea, 0x61, 0xe0, 0xf5, 0xd6, 0xae, 0x55, 0x59, 0x05, 0x3e, 0xaf, 0x74, 0xac, 0x1f, 0x17, 0x82}, + dt2: fp.Elt{0x59, 0x24, 0xcd, 0xfc, 0x11, 0x7e, 0x85, 0x18, 0x3d, 0x69, 0xf7, 0x71, 0x31, 0x66, 0x98, 0x42, 0x95, 0x00, 0x8c, 0xb2, 0xae, 0x39, 0x7e, 0x85, 0xd6, 0xb0, 0x02, 0xec, 0xce, 0xfc, 0x25, 0xb2, 0xe3, 0x99, 0x8e, 0x5b, 0x61, 0x96, 0x2e, 0x6d, 0x96, 0x57, 0x71, 0xa5, 0x93, 0x41, 0x0e, 0x6f, 0xfd, 0x0a, 0xbf, 0xa9, 0xf7, 0x56, 0xa9, 0x3e}, + }, + { /* 31P*/ + addYX: fp.Elt{0xa2, 0x2e, 0x0c, 0x17, 0x4d, 0xcc, 0x85, 0x2c, 0x18, 0xa0, 0xd2, 0x08, 0xba, 0x11, 0xfa, 0x47, 0x71, 0x86, 0xaf, 0x36, 0x6a, 0xd7, 0xfe, 0xb9, 0xb0, 0x2f, 0x89, 0x98, 0x49, 0x69, 0xf8, 0x6a, 0xad, 0x27, 0x5e, 0x0a, 0x22, 0x60, 0x5e, 0x5d, 0xca, 0x06, 0x51, 0x27, 0x99, 0x29, 0x85, 0x68, 0x98, 0xe1, 0xc4, 0x21, 0x50, 0xa0, 0xe9, 0xc1}, + subYX: fp.Elt{0x4d, 0x70, 0xee, 0x91, 0x92, 0x3f, 0xb7, 0xd3, 0x1d, 0xdb, 0x8d, 0x6e, 0x16, 0xf5, 0x65, 0x7d, 0x5f, 0xb5, 0x6c, 0x59, 0x26, 0x70, 0x4b, 0xf2, 0xfc, 0xe7, 0xdf, 0x86, 0xfe, 0xa5, 0xa7, 0xa6, 0x5d, 0xfb, 0x06, 0xe9, 0xf9, 0xcc, 0xc0, 0x37, 0xcc, 0xd8, 0x09, 0x04, 0xd2, 0xa5, 0x1d, 0xd7, 0xb7, 0xce, 0x92, 0xac, 0x3c, 0xad, 0xfb, 0xae}, + dt2: fp.Elt{0x17, 0xa3, 0x9a, 0xc7, 0x86, 0x2a, 0x51, 0xf7, 0x96, 0x79, 0x49, 0x22, 0x2e, 0x5a, 0x01, 0x5c, 0xb5, 0x95, 0xd4, 0xe8, 0xcb, 0x00, 0xca, 0x2d, 0x55, 0xb6, 0x34, 0x36, 0x0b, 0x65, 0x46, 0xf0, 0x49, 0xfc, 0x87, 0x86, 0xe5, 0xc3, 0x15, 0xdb, 0x32, 0xcd, 0xf2, 0xd3, 0x82, 0x4c, 0xe6, 0x61, 0x8a, 0xaf, 0xd4, 0x9e, 0x0f, 0x5a, 0xf2, 0x81}, + }, + { /* 33P*/ + addYX: fp.Elt{0x88, 0x10, 0xc0, 0xcb, 0xf5, 0x77, 0xae, 0xa5, 0xbe, 0xf6, 0xcd, 0x2e, 0x8b, 0x7e, 0xbd, 0x79, 0x62, 0x4a, 0xeb, 0x69, 0xc3, 0x28, 0xaa, 0x72, 0x87, 0xa9, 0x25, 0x87, 0x46, 0xea, 0x0e, 0x62, 0xa3, 0x6a, 0x1a, 0xe2, 0xba, 0xdc, 0x81, 0x10, 0x33, 0x01, 0xf6, 0x16, 0x89, 0x80, 0xc6, 0xcd, 0xdb, 0xdc, 0xba, 0x0e, 0x09, 0x4a, 0x35, 0x4a}, + subYX: fp.Elt{0x86, 0xb2, 0x2b, 0xd0, 0xb8, 0x4a, 0x6d, 0x66, 0x7b, 0x32, 0xdf, 0x3b, 0x1a, 0x19, 0x1f, 0x63, 0xee, 0x1f, 0x3d, 0x1c, 0x5c, 0x14, 0x60, 0x5b, 0x72, 0x49, 0x07, 0xb1, 0x0d, 0x72, 0xc6, 0x35, 0xf0, 0xbc, 0x5e, 0xda, 0x80, 0x6b, 0x64, 0x5b, 0xe5, 0x34, 0x54, 0x39, 0xdd, 0xe6, 0x3c, 0xcb, 0xe5, 0x29, 0x32, 0x06, 0xc6, 0xb1, 0x96, 0x34}, + dt2: fp.Elt{0x85, 0x86, 0xf5, 0x84, 0x86, 0xe6, 0x77, 0x8a, 0x71, 0x85, 0x0c, 0x4f, 0x81, 0x5b, 0x29, 0x06, 0xb5, 0x2e, 0x26, 0x71, 0x07, 0x78, 0x07, 0xae, 0xbc, 0x95, 0x46, 0xc3, 0x65, 0xac, 0xe3, 0x76, 0x51, 0x7d, 0xd4, 0x85, 0x31, 0xe3, 0x43, 0xf3, 0x1b, 0x7c, 0xf7, 0x6b, 0x2c, 0xf8, 0x1c, 0xbb, 0x8d, 0xca, 0xab, 0x4b, 0xba, 0x7f, 0xa4, 0xe2}, + }, + { /* 35P*/ + addYX: fp.Elt{0x1a, 0xee, 0xe7, 0xa4, 0x8a, 0x9d, 0x53, 0x80, 0xc6, 0xb8, 0x4e, 0xdc, 0x89, 0xe0, 0xc4, 0x2b, 0x60, 0x52, 0x6f, 0xec, 0x81, 0xd2, 0x55, 0x6b, 0x1b, 0x6f, 0x17, 0x67, 0x8e, 0x42, 0x26, 0x4c, 0x65, 0x23, 0x29, 0xc6, 0x7b, 0xcd, 0x9f, 0xad, 0x4b, 0x42, 0xd3, 0x0c, 0x75, 0xc3, 0x8a, 0xf5, 0xbe, 0x9e, 0x55, 0xf7, 0x47, 0x5d, 0xbd, 0x3a}, + subYX: fp.Elt{0x0d, 0xa8, 0x3b, 0xf9, 0xc7, 0x7e, 0xc6, 0x86, 0x94, 0xc0, 0x01, 0xff, 0x27, 0xce, 0x43, 0xac, 0xe5, 0xe1, 0xd2, 0x8d, 0xc1, 0x22, 0x31, 0xbe, 0xe1, 0xaf, 0xf9, 0x4a, 0x78, 0xa1, 0x0c, 0xaa, 0xd4, 0x80, 0xe4, 0x09, 0x8d, 0xfb, 0x1d, 0x52, 0xc8, 0x60, 0x2d, 0xf2, 0xa2, 0x89, 0x02, 0x56, 0x3d, 0x56, 0x27, 0x85, 0xc7, 0xf0, 0x2b, 0x9a}, + dt2: fp.Elt{0x62, 0x7c, 0xc7, 0x6b, 0x2c, 0x9d, 0x0a, 0x7c, 0xe5, 0x50, 0x3c, 0xe6, 0x87, 0x1c, 0x82, 0x30, 0x67, 0x3c, 0x39, 0xb6, 0xa0, 0x31, 0xfb, 0x03, 0x7b, 0xa1, 0x58, 0xdf, 0x12, 0x76, 0x5d, 0x5d, 0x0a, 0x8f, 0x9b, 0x37, 0x32, 0xc3, 0x60, 0x33, 0xea, 0x9f, 0x0a, 0x99, 0xfa, 0x20, 0xd0, 0x33, 0x21, 0xc3, 0x94, 0xd4, 0x86, 0x49, 0x7c, 0x4e}, + }, + { /* 37P*/ + addYX: fp.Elt{0xc7, 0x0c, 0x71, 0xfe, 0x55, 0xd1, 0x95, 0x8f, 0x43, 0xbb, 0x6b, 0x74, 0x30, 0xbd, 0xe8, 0x6f, 0x1c, 0x1b, 0x06, 0x62, 0xf5, 0xfc, 0x65, 0xa0, 0xeb, 0x81, 0x12, 0xc9, 0x64, 0x66, 0x61, 0xde, 0xf3, 0x6d, 0xd4, 0xae, 0x8e, 0xb1, 0x72, 0xe0, 0xcd, 0x37, 0x01, 0x28, 0x52, 0xd7, 0x39, 0x46, 0x0c, 0x55, 0xcf, 0x47, 0x70, 0xef, 0xa1, 0x17}, + subYX: fp.Elt{0x8d, 0x58, 0xde, 0x83, 0x88, 0x16, 0x0e, 0x12, 0x42, 0x03, 0x50, 0x60, 0x4b, 0xdf, 0xbf, 0x95, 0xcc, 0x7d, 0x18, 0x17, 0x7e, 0x31, 0x5d, 0x8a, 0x66, 0xc1, 0xcf, 0x14, 0xea, 0xf4, 0xf4, 0xe5, 0x63, 0x2d, 0x32, 0x86, 0x9b, 0xed, 0x1f, 0x4f, 0x03, 0xaf, 0x33, 0x92, 0xcb, 0xaf, 0x9c, 0x05, 0x0d, 0x47, 0x1b, 0x42, 0xba, 0x13, 0x22, 0x98}, + dt2: fp.Elt{0xb5, 0x48, 0xeb, 0x7d, 0x3d, 0x10, 0x9f, 0x59, 0xde, 0xf8, 0x1c, 0x4f, 0x7d, 0x9d, 0x40, 0x4d, 0x9e, 0x13, 0x24, 0xb5, 0x21, 0x09, 0xb7, 0xee, 0x98, 0x5c, 0x56, 0xbc, 0x5e, 0x2b, 0x78, 0x38, 0x06, 0xac, 0xe3, 0xe0, 0xfa, 0x2e, 0xde, 0x4f, 0xd2, 0xb3, 0xfb, 0x2d, 0x71, 0x84, 0xd1, 0x9d, 0x12, 0x5b, 0x35, 0xc8, 0x03, 0x68, 0x67, 0xc7}, + }, + { /* 39P*/ + addYX: fp.Elt{0xb6, 0x65, 0xfb, 0xa7, 0x06, 0x35, 0xbb, 0xe0, 0x31, 0x8d, 0x91, 0x40, 0x98, 0xab, 0x30, 0xe4, 0xca, 0x12, 0x59, 0x89, 0xed, 0x65, 0x5d, 0x7f, 0xae, 0x69, 0xa0, 0xa4, 0xfa, 0x78, 0xb4, 0xf7, 0xed, 0xae, 0x86, 0x78, 0x79, 0x64, 0x24, 0xa6, 0xd4, 0xe1, 0xf6, 0xd3, 0xa0, 0x89, 0xba, 0x20, 0xf4, 0x54, 0x0d, 0x8f, 0xdb, 0x1a, 0x79, 0xdb}, + subYX: fp.Elt{0xe1, 0x82, 0x0c, 0x4d, 0xde, 0x9f, 0x40, 0xf0, 0xc1, 0xbd, 0x8b, 0xd3, 0x24, 0x03, 0xcd, 0xf2, 0x92, 0x7d, 0xe2, 0x68, 0x7f, 0xf1, 0xbe, 0x69, 0xde, 0x34, 0x67, 0x4c, 0x85, 0x3b, 0xec, 0x98, 0xcc, 0x4d, 0x3e, 0xc0, 0x96, 0x27, 0xe6, 0x75, 0xfc, 0xdf, 0x37, 0xc0, 0x1e, 0x27, 0xe0, 0xf6, 0xc2, 0xbd, 0xbc, 0x3d, 0x9b, 0x39, 0xdc, 0xe2}, + dt2: fp.Elt{0xd8, 0x29, 0xa7, 0x39, 0xe3, 0x9f, 0x2f, 0x0e, 0x4b, 0x24, 0x21, 0x70, 0xef, 0xfd, 0x91, 0xea, 0xbf, 0xe1, 0x72, 0x90, 0xcc, 0xc9, 0x84, 0x0e, 0xad, 0xd5, 0xe6, 0xbb, 0xc5, 0x99, 0x7f, 0xa4, 0xf0, 0x2e, 0xcc, 0x95, 0x64, 0x27, 0x19, 0xd8, 0x4c, 0x27, 0x0d, 0xff, 0xb6, 0x29, 0xe2, 0x6c, 0xfa, 0xbb, 0x4d, 0x9c, 0xbb, 0xaf, 0xa5, 0xec}, + }, + { /* 41P*/ + addYX: fp.Elt{0xd6, 0x33, 0x3f, 0x9f, 0xcf, 0xfd, 0x4c, 0xd1, 0xfe, 0xe5, 0xeb, 0x64, 0x27, 0xae, 0x7a, 0xa2, 0x82, 0x50, 0x6d, 0xaa, 0xe3, 0x5d, 0xe2, 0x48, 0x60, 0xb3, 0x76, 0x04, 0xd9, 0x19, 0xa7, 0xa1, 0x73, 0x8d, 0x38, 0xa9, 0xaf, 0x45, 0xb5, 0xb2, 0x62, 0x9b, 0xf1, 0x35, 0x7b, 0x84, 0x66, 0xeb, 0x06, 0xef, 0xf1, 0xb2, 0x2d, 0x6a, 0x61, 0x15}, + subYX: fp.Elt{0x86, 0x50, 0x42, 0xf7, 0xda, 0x59, 0xb2, 0xcf, 0x0d, 0x3d, 0xee, 0x8e, 0x53, 0x5d, 0xf7, 0x9e, 0x6a, 0x26, 0x2d, 0xc7, 0x8c, 0x8e, 0x18, 0x50, 0x6d, 0xb7, 0x51, 0x4c, 0xa7, 0x52, 0x6e, 0x0e, 0x0a, 0x16, 0x74, 0xb2, 0x81, 0x8b, 0x56, 0x27, 0x22, 0x84, 0xf4, 0x56, 0xc5, 0x06, 0xe1, 0x8b, 0xca, 0x2d, 0xdb, 0x9a, 0xf6, 0x10, 0x9c, 0x51}, + dt2: fp.Elt{0x1f, 0x16, 0xa2, 0x78, 0x96, 0x1b, 0x85, 0x9c, 0x76, 0x49, 0xd4, 0x0f, 0xac, 0xb0, 0xf4, 0xd0, 0x06, 0x2c, 0x7e, 0x6d, 0x6e, 0x8e, 0xc7, 0x9f, 0x18, 0xad, 0xfc, 0x88, 0x0c, 0x0c, 0x09, 0x05, 0x05, 0xa0, 0x79, 0x72, 0x32, 0x72, 0x87, 0x0f, 0x49, 0x87, 0x0c, 0xb4, 0x12, 0xc2, 0x09, 0xf8, 0x9f, 0x30, 0x72, 0xa9, 0x47, 0x13, 0x93, 0x49}, + }, + { /* 43P*/ + addYX: fp.Elt{0xcc, 0xb1, 0x4c, 0xd3, 0xc0, 0x9e, 0x9e, 0x4d, 0x6d, 0x28, 0x0b, 0xa5, 0x94, 0xa7, 0x2e, 0xc2, 0xc7, 0xaf, 0x29, 0x73, 0xc9, 0x68, 0xea, 0x0f, 0x34, 0x37, 0x8d, 0x96, 0x8f, 0x3a, 0x3d, 0x73, 0x1e, 0x6d, 0x9f, 0xcf, 0x8d, 0x83, 0xb5, 0x71, 0xb9, 0xe1, 0x4b, 0x67, 0x71, 0xea, 0xcf, 0x56, 0xe5, 0xeb, 0x72, 0x15, 0x2f, 0x9e, 0xa8, 0xaa}, + subYX: fp.Elt{0xf4, 0x3e, 0x85, 0x1c, 0x1a, 0xef, 0x50, 0xd1, 0xb4, 0x20, 0xb2, 0x60, 0x05, 0x98, 0xfe, 0x47, 0x3b, 0xc1, 0x76, 0xca, 0x2c, 0x4e, 0x5a, 0x42, 0xa3, 0xf7, 0x20, 0xaa, 0x57, 0x39, 0xee, 0x34, 0x1f, 0xe1, 0x68, 0xd3, 0x7e, 0x06, 0xc4, 0x6c, 0xc7, 0x76, 0x2b, 0xe4, 0x1c, 0x48, 0x44, 0xe6, 0xe5, 0x44, 0x24, 0x8d, 0xb3, 0xb6, 0x88, 0x32}, + dt2: fp.Elt{0x18, 0xa7, 0xba, 0xd0, 0x44, 0x6f, 0x33, 0x31, 0x00, 0xf8, 0xf6, 0x12, 0xe3, 0xc5, 0xc7, 0xb5, 0x91, 0x9c, 0x91, 0xb5, 0x75, 0x18, 0x18, 0x8a, 0xab, 0xed, 0x24, 0x11, 0x2e, 0xce, 0x5a, 0x0f, 0x94, 0x5f, 0x2e, 0xca, 0xd3, 0x80, 0xea, 0xe5, 0x34, 0x96, 0x67, 0x8b, 0x6a, 0x26, 0x5e, 0xc8, 0x9d, 0x2c, 0x5e, 0x6c, 0xa2, 0x0c, 0xbf, 0xf0}, + }, + { /* 45P*/ + addYX: fp.Elt{0xb3, 0xbf, 0xa3, 0x85, 0xee, 0xf6, 0x58, 0x02, 0x78, 0xc4, 0x30, 0xd6, 0x57, 0x59, 0x8c, 0x88, 0x08, 0x7c, 0xbc, 0xbe, 0x0a, 0x74, 0xa9, 0xde, 0x69, 0xe7, 0x41, 0xd8, 0xbf, 0x66, 0x8d, 0x3d, 0x28, 0x00, 0x8c, 0x47, 0x65, 0x34, 0xfe, 0x86, 0x9e, 0x6a, 0xf2, 0x41, 0x6a, 0x94, 0xc4, 0x88, 0x75, 0x23, 0x0d, 0x52, 0x69, 0xee, 0x07, 0x89}, + subYX: fp.Elt{0x22, 0x3c, 0xa1, 0x70, 0x58, 0x97, 0x93, 0xbe, 0x59, 0xa8, 0x0b, 0x8a, 0x46, 0x2a, 0x38, 0x1e, 0x08, 0x6b, 0x61, 0x9f, 0xf2, 0x4a, 0x8b, 0x80, 0x68, 0x6e, 0xc8, 0x92, 0x60, 0xf3, 0xc9, 0x89, 0xb2, 0x6d, 0x63, 0xb0, 0xeb, 0x83, 0x15, 0x63, 0x0e, 0x64, 0xbb, 0xb8, 0xfe, 0xb4, 0x81, 0x90, 0x01, 0x28, 0x10, 0xb9, 0x74, 0x6e, 0xde, 0xa4}, + dt2: fp.Elt{0x1a, 0x23, 0x45, 0xa8, 0x6f, 0x4e, 0xa7, 0x4a, 0x0c, 0xeb, 0xb0, 0x43, 0xf9, 0xef, 0x99, 0x60, 0x5b, 0xdb, 0x66, 0xc0, 0x86, 0x71, 0x43, 0xb1, 0x22, 0x7b, 0x1c, 0xe7, 0x8d, 0x09, 0x1d, 0x83, 0x76, 0x9c, 0xd3, 0x5a, 0xdd, 0x42, 0xd9, 0x2f, 0x2d, 0xba, 0x7a, 0xc2, 0xd9, 0x6b, 0xd4, 0x7a, 0xf1, 0xd5, 0x5f, 0x6b, 0x85, 0xbf, 0x0b, 0xf1}, + }, + { /* 47P*/ + addYX: fp.Elt{0xb2, 0x83, 0xfa, 0x1f, 0xd2, 0xce, 0xb6, 0xf2, 0x2d, 0xea, 0x1b, 0xe5, 0x29, 0xa5, 0x72, 0xf9, 0x25, 0x48, 0x4e, 0xf2, 0x50, 0x1b, 0x39, 0xda, 0x34, 0xc5, 0x16, 0x13, 0xb4, 0x0c, 0xa1, 0x00, 0x79, 0x7a, 0xf5, 0x8b, 0xf3, 0x70, 0x14, 0xb6, 0xfc, 0x9a, 0x47, 0x68, 0x1e, 0x42, 0x70, 0x64, 0x2a, 0x84, 0x3e, 0x3d, 0x20, 0x58, 0xf9, 0x6a}, + subYX: fp.Elt{0xd9, 0xee, 0xc0, 0xc4, 0xf5, 0xc2, 0x86, 0xaf, 0x45, 0xd2, 0xd2, 0x87, 0x1b, 0x64, 0xd5, 0xe0, 0x8c, 0x44, 0x00, 0x4f, 0x43, 0x89, 0x04, 0x48, 0x4a, 0x0b, 0xca, 0x94, 0x06, 0x2f, 0x23, 0x5b, 0x6c, 0x8d, 0x44, 0x66, 0x53, 0xf5, 0x5a, 0x20, 0x72, 0x28, 0x58, 0x84, 0xcc, 0x73, 0x22, 0x5e, 0xd1, 0x0b, 0x56, 0x5e, 0x6a, 0xa3, 0x11, 0x91}, + dt2: fp.Elt{0x6e, 0x9f, 0x88, 0xa8, 0x68, 0x2f, 0x12, 0x37, 0x88, 0xfc, 0x92, 0x8f, 0x24, 0xeb, 0x5b, 0x2a, 0x2a, 0xd0, 0x14, 0x40, 0x4c, 0xa9, 0xa4, 0x03, 0x0c, 0x45, 0x48, 0x13, 0xe8, 0xa6, 0x37, 0xab, 0xc0, 0x06, 0x38, 0x6c, 0x96, 0x73, 0x40, 0x6c, 0xc6, 0xea, 0x56, 0xc6, 0xe9, 0x1a, 0x69, 0xeb, 0x7a, 0xd1, 0x33, 0x69, 0x58, 0x2b, 0xea, 0x2f}, + }, + { /* 49P*/ + addYX: fp.Elt{0x58, 0xa8, 0x05, 0x41, 0x00, 0x9d, 0xaa, 0xd9, 0x98, 0xcf, 0xb9, 0x41, 0xb5, 0x4a, 0x8d, 0xe2, 0xe7, 0xc0, 0x72, 0xef, 0xc8, 0x28, 0x6b, 0x68, 0x9d, 0xc9, 0xdf, 0x05, 0x8b, 0xd0, 0x04, 0x74, 0x79, 0x45, 0x52, 0x05, 0xa3, 0x6e, 0x35, 0x3a, 0xe3, 0xef, 0xb2, 0xdc, 0x08, 0x6f, 0x4e, 0x76, 0x85, 0x67, 0xba, 0x23, 0x8f, 0xdd, 0xaf, 0x09}, + subYX: fp.Elt{0xb4, 0x38, 0xc8, 0xff, 0x4f, 0x65, 0x2a, 0x7e, 0xad, 0xb1, 0xc6, 0xb9, 0x3d, 0xd6, 0xf7, 0x14, 0xcf, 0xf6, 0x98, 0x75, 0xbb, 0x47, 0x83, 0x90, 0xe7, 0xe1, 0xf6, 0x14, 0x99, 0x7e, 0xfa, 0xe4, 0x77, 0x24, 0xe3, 0xe7, 0xf0, 0x1e, 0xdb, 0x27, 0x4e, 0x16, 0x04, 0xf2, 0x08, 0x52, 0xfc, 0xec, 0x55, 0xdb, 0x2e, 0x67, 0xe1, 0x94, 0x32, 0x89}, + dt2: fp.Elt{0x00, 0xad, 0x03, 0x35, 0x1a, 0xb1, 0x88, 0xf0, 0xc9, 0x11, 0xe4, 0x12, 0x52, 0x61, 0xfd, 0x8a, 0x1b, 0x6a, 0x0a, 0x4c, 0x42, 0x46, 0x22, 0x0e, 0xa5, 0xf9, 0xe2, 0x50, 0xf2, 0xb2, 0x1f, 0x20, 0x78, 0x10, 0xf6, 0xbf, 0x7f, 0x0c, 0x9c, 0xad, 0x40, 0x8b, 0x82, 0xd4, 0xba, 0x69, 0x09, 0xac, 0x4b, 0x6d, 0xc4, 0x49, 0x17, 0x81, 0x57, 0x3b}, + }, + { /* 51P*/ + addYX: fp.Elt{0x0d, 0xfe, 0xb4, 0x35, 0x11, 0xbd, 0x1d, 0x6b, 0xc2, 0xc5, 0x3b, 0xd2, 0x23, 0x2c, 0x72, 0xe3, 0x48, 0xb1, 0x48, 0x73, 0xfb, 0xa3, 0x21, 0x6e, 0xc0, 0x09, 0x69, 0xac, 0xe1, 0x60, 0xbc, 0x24, 0x03, 0x99, 0x63, 0x0a, 0x00, 0xf0, 0x75, 0xf6, 0x92, 0xc5, 0xd6, 0xdb, 0x51, 0xd4, 0x7d, 0xe6, 0xf4, 0x11, 0x79, 0xd7, 0xc3, 0xaf, 0x48, 0xd0}, + subYX: fp.Elt{0xf4, 0x4f, 0xaf, 0x31, 0xe3, 0x10, 0x89, 0x95, 0xf0, 0x8a, 0xf6, 0x31, 0x9f, 0x48, 0x02, 0xba, 0x42, 0x2b, 0x3c, 0x22, 0x8b, 0xcc, 0x12, 0x98, 0x6e, 0x7a, 0x64, 0x3a, 0xc4, 0xca, 0x32, 0x2a, 0x72, 0xf8, 0x2c, 0xcf, 0x78, 0x5e, 0x7a, 0x75, 0x6e, 0x72, 0x46, 0x48, 0x62, 0x28, 0xac, 0x58, 0x1a, 0xc6, 0x59, 0x88, 0x2a, 0x44, 0x9e, 0x83}, + dt2: fp.Elt{0xb3, 0xde, 0x36, 0xfd, 0xeb, 0x1b, 0xd4, 0x24, 0x1b, 0x08, 0x8c, 0xfe, 0xa9, 0x41, 0xa1, 0x64, 0xf2, 0x6d, 0xdb, 0xf9, 0x94, 0xae, 0x86, 0x71, 0xab, 0x10, 0xbf, 0xa3, 0xb2, 0xa0, 0xdf, 0x10, 0x8c, 0x74, 0xce, 0xb3, 0xfc, 0xdb, 0xba, 0x15, 0xf6, 0x91, 0x7a, 0x9c, 0x36, 0x1e, 0x45, 0x07, 0x3c, 0xec, 0x1a, 0x61, 0x26, 0x93, 0xe3, 0x50}, + }, + { /* 53P*/ + addYX: fp.Elt{0xc5, 0x50, 0xc5, 0x83, 0xb0, 0xbd, 0xd9, 0xf6, 0x6d, 0x15, 0x5e, 0xc1, 0x1a, 0x33, 0xa0, 0xce, 0x13, 0x70, 0x3b, 0xe1, 0x31, 0xc6, 0xc4, 0x02, 0xec, 0x8c, 0xd5, 0x9c, 0x97, 0xd3, 0x12, 0xc4, 0xa2, 0xf9, 0xd5, 0xfb, 0x22, 0x69, 0x94, 0x09, 0x2f, 0x59, 0xce, 0xdb, 0xf2, 0xf2, 0x00, 0xe0, 0xa9, 0x08, 0x44, 0x2e, 0x8b, 0x6b, 0xf5, 0xb3}, + subYX: fp.Elt{0x90, 0xdd, 0xec, 0xa2, 0x65, 0xb7, 0x61, 0xbc, 0xaa, 0x70, 0xa2, 0x15, 0xd8, 0xb0, 0xf8, 0x8e, 0x23, 0x3d, 0x9f, 0x46, 0xa3, 0x29, 0x20, 0xd1, 0xa1, 0x15, 0x81, 0xc6, 0xb6, 0xde, 0xbe, 0x60, 0x63, 0x24, 0xac, 0x15, 0xfb, 0xeb, 0xd3, 0xea, 0x57, 0x13, 0x86, 0x38, 0x1e, 0x22, 0xf4, 0x8c, 0x5d, 0xaf, 0x1b, 0x27, 0x21, 0x4f, 0xa3, 0x63}, + dt2: fp.Elt{0x07, 0x15, 0x87, 0xc4, 0xfd, 0xa1, 0x97, 0x7a, 0x07, 0x1f, 0x56, 0xcc, 0xe3, 0x6a, 0x01, 0x90, 0xce, 0xf9, 0xfa, 0x50, 0xb2, 0xe0, 0x87, 0x8b, 0x6c, 0x63, 0x6c, 0xf6, 0x2a, 0x09, 0xef, 0xef, 0xd2, 0x31, 0x40, 0x25, 0xf6, 0x84, 0xcb, 0xe0, 0xc4, 0x23, 0xc1, 0xcb, 0xe2, 0x02, 0x83, 0x2d, 0xed, 0x74, 0x74, 0x8b, 0xf8, 0x7c, 0x81, 0x18}, + }, + { /* 55P*/ + addYX: fp.Elt{0x9e, 0xe5, 0x59, 0x95, 0x63, 0x2e, 0xac, 0x8b, 0x03, 0x3c, 0xc1, 0x8e, 0xe1, 0x5b, 0x56, 0x3c, 0x16, 0x41, 0xe4, 0xc2, 0x60, 0x0c, 0x6d, 0x65, 0x9f, 0xfc, 0x27, 0x68, 0x43, 0x44, 0x05, 0x12, 0x6c, 0xda, 0x04, 0xef, 0xcf, 0xcf, 0xdc, 0x0a, 0x1a, 0x7f, 0x12, 0xd3, 0xeb, 0x02, 0xb6, 0x04, 0xca, 0xd6, 0xcb, 0xf0, 0x22, 0xba, 0x35, 0x6d}, + subYX: fp.Elt{0x09, 0x6d, 0xf9, 0x64, 0x4c, 0xe6, 0x41, 0xff, 0x01, 0x4d, 0xce, 0x1e, 0xfa, 0x38, 0xa2, 0x25, 0x62, 0xff, 0x03, 0x39, 0x18, 0x91, 0xbb, 0x9d, 0xce, 0x02, 0xf0, 0xf1, 0x3c, 0x55, 0x18, 0xa9, 0xab, 0x4d, 0xd2, 0x35, 0xfd, 0x8d, 0xa9, 0xb2, 0xad, 0xb7, 0x06, 0x6e, 0xc6, 0x69, 0x49, 0xd6, 0x98, 0x98, 0x0b, 0x22, 0x81, 0x6b, 0xbd, 0xa0}, + dt2: fp.Elt{0x22, 0xf4, 0x85, 0x5d, 0x2b, 0xf1, 0x55, 0xa5, 0xd6, 0x27, 0x86, 0x57, 0x12, 0x1f, 0x16, 0x0a, 0x5a, 0x9b, 0xf2, 0x38, 0xb6, 0x28, 0xd8, 0x99, 0x0c, 0x89, 0x1d, 0x7f, 0xca, 0x21, 0x17, 0x1a, 0x0b, 0x02, 0x5f, 0x77, 0x2f, 0x73, 0x30, 0x7c, 0xc8, 0xd7, 0x2b, 0xcc, 0xe7, 0xf3, 0x21, 0xac, 0x53, 0xa7, 0x11, 0x5d, 0xd8, 0x1d, 0x9b, 0xf5}, + }, + { /* 57P*/ + addYX: fp.Elt{0x94, 0x63, 0x5d, 0xef, 0xfd, 0x6d, 0x25, 0x4e, 0x6d, 0x29, 0x03, 0xed, 0x24, 0x28, 0x27, 0x57, 0x47, 0x3e, 0x6a, 0x1a, 0xfe, 0x37, 0xee, 0x5f, 0x83, 0x29, 0x14, 0xfd, 0x78, 0x25, 0x8a, 0xe1, 0x02, 0x38, 0xd8, 0xca, 0x65, 0x55, 0x40, 0x7d, 0x48, 0x2c, 0x7c, 0x7e, 0x60, 0xb6, 0x0c, 0x6d, 0xf7, 0xe8, 0xb3, 0x62, 0x53, 0xd6, 0x9c, 0x2b}, + subYX: fp.Elt{0x47, 0x25, 0x70, 0x62, 0xf5, 0x65, 0x93, 0x62, 0x08, 0xac, 0x59, 0x66, 0xdb, 0x08, 0xd9, 0x1a, 0x19, 0xaf, 0xf4, 0xef, 0x02, 0xa2, 0x78, 0xa9, 0x55, 0x1c, 0xfa, 0x08, 0x11, 0xcb, 0xa3, 0x71, 0x74, 0xb1, 0x62, 0xe7, 0xc7, 0xf3, 0x5a, 0xb5, 0x8b, 0xd4, 0xf6, 0x10, 0x57, 0x79, 0x72, 0x2f, 0x13, 0x86, 0x7b, 0x44, 0x5f, 0x48, 0xfd, 0x88}, + dt2: fp.Elt{0x10, 0x02, 0xcd, 0x05, 0x9a, 0xc3, 0x32, 0x6d, 0x10, 0x3a, 0x74, 0xba, 0x06, 0xc4, 0x3b, 0x34, 0xbc, 0x36, 0xed, 0xa3, 0xba, 0x9a, 0xdb, 0x6d, 0xd4, 0x69, 0x99, 0x97, 0xd0, 0xe4, 0xdd, 0xf5, 0xd4, 0x7c, 0xd3, 0x4e, 0xab, 0xd1, 0x3b, 0xbb, 0xe9, 0xc7, 0x6a, 0x94, 0x25, 0x61, 0xf0, 0x06, 0xc5, 0x12, 0xa8, 0x86, 0xe5, 0x35, 0x46, 0xeb}, + }, + { /* 59P*/ + addYX: fp.Elt{0x9e, 0x95, 0x11, 0xc6, 0xc7, 0xe8, 0xee, 0x5a, 0x26, 0xa0, 0x72, 0x72, 0x59, 0x91, 0x59, 0x16, 0x49, 0x99, 0x7e, 0xbb, 0xd7, 0x15, 0xb4, 0xf2, 0x40, 0xf9, 0x5a, 0x4d, 0xc8, 0xa0, 0xe2, 0x34, 0x7b, 0x34, 0xf3, 0x99, 0xbf, 0xa9, 0xf3, 0x79, 0xc1, 0x1a, 0x0c, 0xf4, 0x86, 0x74, 0x4e, 0xcb, 0xbc, 0x90, 0xad, 0xb6, 0x51, 0x6d, 0xaa, 0x33}, + subYX: fp.Elt{0x9f, 0xd1, 0xc5, 0xa2, 0x6c, 0x24, 0x88, 0x15, 0x71, 0x68, 0xf6, 0x07, 0x45, 0x02, 0xc4, 0x73, 0x7e, 0x75, 0x87, 0xca, 0x7c, 0xf0, 0x92, 0x00, 0x75, 0xd6, 0x5a, 0xdd, 0xe0, 0x64, 0x16, 0x9d, 0x62, 0x80, 0x33, 0x9f, 0xf4, 0x8e, 0x1a, 0x15, 0x1c, 0xd3, 0x0f, 0x4d, 0x4f, 0x62, 0x2d, 0xd7, 0xa5, 0x77, 0xe3, 0xea, 0xf0, 0xfb, 0x1a, 0xdb}, + dt2: fp.Elt{0x6a, 0xa2, 0xb1, 0xaa, 0xfb, 0x5a, 0x32, 0x4e, 0xff, 0x47, 0x06, 0xd5, 0x9a, 0x4f, 0xce, 0x83, 0x5b, 0x82, 0x34, 0x3e, 0x47, 0xb8, 0xf8, 0xe9, 0x7c, 0x67, 0x69, 0x8d, 0x9c, 0xb7, 0xde, 0x57, 0xf4, 0x88, 0x41, 0x56, 0x0c, 0x87, 0x1e, 0xc9, 0x2f, 0x54, 0xbf, 0x5c, 0x68, 0x2c, 0xd9, 0xc4, 0xef, 0x53, 0x73, 0x1e, 0xa6, 0x38, 0x02, 0x10}, + }, + { /* 61P*/ + addYX: fp.Elt{0x08, 0x80, 0x4a, 0xc9, 0xb7, 0xa8, 0x88, 0xd9, 0xfc, 0x6a, 0xc0, 0x3e, 0xc2, 0x33, 0x4d, 0x2b, 0x2a, 0xa3, 0x6d, 0x72, 0x3e, 0xdc, 0x34, 0x68, 0x08, 0xbf, 0x27, 0xef, 0xf4, 0xff, 0xe2, 0x0c, 0x31, 0x0c, 0xa2, 0x0a, 0x1f, 0x65, 0xc1, 0x4c, 0x61, 0xd3, 0x1b, 0xbc, 0x25, 0xb1, 0xd0, 0xd4, 0x89, 0xb2, 0x53, 0xfb, 0x43, 0xa5, 0xaf, 0x04}, + subYX: fp.Elt{0xe3, 0xe1, 0x37, 0xad, 0x58, 0xa9, 0x55, 0x81, 0xee, 0x64, 0x21, 0xb9, 0xf5, 0x4c, 0x35, 0xea, 0x4a, 0xd3, 0x26, 0xaa, 0x90, 0xd4, 0x60, 0x46, 0x09, 0x4b, 0x4a, 0x62, 0xf9, 0xcd, 0xe1, 0xee, 0xbb, 0xc2, 0x09, 0x0b, 0xb0, 0x96, 0x8e, 0x43, 0x77, 0xaf, 0x25, 0x20, 0x5e, 0x47, 0xe4, 0x1d, 0x50, 0x69, 0x74, 0x08, 0xd7, 0xb9, 0x90, 0x13}, + dt2: fp.Elt{0x51, 0x91, 0x95, 0x64, 0x03, 0x16, 0xfd, 0x6e, 0x26, 0x94, 0x6b, 0x61, 0xe7, 0xd9, 0xe0, 0x4a, 0x6d, 0x7c, 0xfa, 0xc0, 0xe2, 0x43, 0x23, 0x53, 0x70, 0xf5, 0x6f, 0x73, 0x8b, 0x81, 0xb0, 0x0c, 0xee, 0x2e, 0x46, 0xf2, 0x8d, 0xa6, 0xfb, 0xb5, 0x1c, 0x33, 0xbf, 0x90, 0x59, 0xc9, 0x7c, 0xb8, 0x6f, 0xad, 0x75, 0x02, 0x90, 0x8e, 0x59, 0x75}, + }, + { /* 63P*/ + addYX: fp.Elt{0x36, 0x4d, 0x77, 0x04, 0xb8, 0x7d, 0x4a, 0xd1, 0xc5, 0xbb, 0x7b, 0x50, 0x5f, 0x8d, 0x9d, 0x62, 0x0f, 0x66, 0x71, 0xec, 0x87, 0xc5, 0x80, 0x82, 0xc8, 0xf4, 0x6a, 0x94, 0x92, 0x5b, 0xb0, 0x16, 0x9b, 0xb2, 0xc9, 0x6f, 0x2b, 0x2d, 0xee, 0x95, 0x73, 0x2e, 0xc2, 0x1b, 0xc5, 0x55, 0x36, 0x86, 0x24, 0xf8, 0x20, 0x05, 0x0d, 0x93, 0xd7, 0x76}, + subYX: fp.Elt{0x7f, 0x01, 0xeb, 0x2e, 0x48, 0x4d, 0x1d, 0xf1, 0x06, 0x7e, 0x7c, 0x2a, 0x43, 0xbf, 0x28, 0xac, 0xe9, 0x58, 0x13, 0xc8, 0xbf, 0x8e, 0xc0, 0xef, 0xe8, 0x4f, 0x46, 0x8a, 0xe7, 0xc0, 0xf6, 0x0f, 0x0a, 0x03, 0x48, 0x91, 0x55, 0x39, 0x2a, 0xe3, 0xdc, 0xf6, 0x22, 0x9d, 0x4d, 0x71, 0x55, 0x68, 0x25, 0x6e, 0x95, 0x52, 0xee, 0x4c, 0xd9, 0x01}, + dt2: fp.Elt{0xac, 0x33, 0x3f, 0x7c, 0x27, 0x35, 0x15, 0x91, 0x33, 0x8d, 0xf9, 0xc4, 0xf4, 0xf3, 0x90, 0x09, 0x75, 0x69, 0x62, 0x9f, 0x61, 0x35, 0x83, 0x92, 0x04, 0xef, 0x96, 0x38, 0x80, 0x9e, 0x88, 0xb3, 0x67, 0x95, 0xbe, 0x79, 0x3c, 0x35, 0xd8, 0xdc, 0xb2, 0x3e, 0x2d, 0xe6, 0x46, 0xbe, 0x81, 0xf3, 0x32, 0x0e, 0x37, 0x23, 0x75, 0x2a, 0x3d, 0xa0}, + }, +} diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go new file mode 100644 index 00000000..f6ac5edb --- /dev/null +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist_basemult.go @@ -0,0 +1,62 @@ +package goldilocks + +import ( + "crypto/subtle" + + mlsb "github.com/cloudflare/circl/math/mlsbset" +) + +const ( + // MLSBRecoding parameters + fxT = 448 + fxV = 2 + fxW = 3 + fx2w1 = 1 << (uint(fxW) - 1) +) + +// ScalarBaseMult returns kG where G is the generator point. +func (e twistCurve) ScalarBaseMult(k *Scalar) *twistPoint { + m, err := mlsb.New(fxT, fxV, fxW) + if err != nil { + panic(err) + } + if m.IsExtended() { + panic("not extended") + } + + var isZero int + if k.IsZero() { + isZero = 1 + } + subtle.ConstantTimeCopy(isZero, k[:], order[:]) + + minusK := *k + isEven := 1 - int(k[0]&0x1) + minusK.Neg() + subtle.ConstantTimeCopy(isEven, k[:], minusK[:]) + c, err := m.Encode(k[:]) + if err != nil { + panic(err) + } + + gP := c.Exp(groupMLSB{}) + P := gP.(*twistPoint) + P.cneg(uint(isEven)) + return P +} + +type groupMLSB struct{} + +func (e groupMLSB) ExtendedEltP() mlsb.EltP { return nil } +func (e groupMLSB) Sqr(x mlsb.EltG) { x.(*twistPoint).Double() } +func (e groupMLSB) Mul(x mlsb.EltG, y mlsb.EltP) { x.(*twistPoint).mixAddZ1(y.(*preTwistPointAffine)) } +func (e groupMLSB) Identity() mlsb.EltG { return twistCurve{}.Identity() } +func (e groupMLSB) NewEltP() mlsb.EltP { return &preTwistPointAffine{} } +func (e groupMLSB) Lookup(a mlsb.EltP, v uint, s, u int32) { + Tabj := &tabFixMult[v] + P := a.(*preTwistPointAffine) + for k := range Tabj { + P.cmov(&Tabj[k], uint(subtle.ConstantTimeEq(int32(k), u))) + } + P.cneg(int(s >> 31)) +} diff --git a/vendor/github.com/cloudflare/circl/internal/conv/conv.go b/vendor/github.com/cloudflare/circl/internal/conv/conv.go new file mode 100644 index 00000000..3fd0df49 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/conv/conv.go @@ -0,0 +1,173 @@ +package conv + +import ( + "encoding/binary" + "fmt" + "math/big" + "strings" + + "golang.org/x/crypto/cryptobyte" +) + +// BytesLe2Hex returns an hexadecimal string of a number stored in a +// little-endian order slice x. +func BytesLe2Hex(x []byte) string { + b := &strings.Builder{} + b.Grow(2*len(x) + 2) + fmt.Fprint(b, "0x") + if len(x) == 0 { + fmt.Fprint(b, "00") + } + for i := len(x) - 1; i >= 0; i-- { + fmt.Fprintf(b, "%02x", x[i]) + } + return b.String() +} + +// BytesLe2BigInt converts a little-endian slice x into a big-endian +// math/big.Int. +func BytesLe2BigInt(x []byte) *big.Int { + n := len(x) + b := new(big.Int) + if len(x) > 0 { + y := make([]byte, n) + for i := 0; i < n; i++ { + y[n-1-i] = x[i] + } + b.SetBytes(y) + } + return b +} + +// BytesBe2Uint64Le converts a big-endian slice x to a little-endian slice of uint64. +func BytesBe2Uint64Le(x []byte) []uint64 { + l := len(x) + z := make([]uint64, (l+7)/8) + blocks := l / 8 + for i := 0; i < blocks; i++ { + z[i] = binary.BigEndian.Uint64(x[l-8*(i+1):]) + } + remBytes := l % 8 + for i := 0; i < remBytes; i++ { + z[blocks] |= uint64(x[l-1-8*blocks-i]) << uint(8*i) + } + return z +} + +// BigInt2BytesLe stores a positive big.Int number x into a little-endian slice z. +// The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros). +// If x does not fit in the slice or is negative, z is not modified. +func BigInt2BytesLe(z []byte, x *big.Int) { + xLen := (x.BitLen() + 7) >> 3 + zLen := len(z) + if zLen >= xLen && x.Sign() >= 0 { + y := x.Bytes() + for i := 0; i < xLen; i++ { + z[i] = y[xLen-1-i] + } + for i := xLen; i < zLen; i++ { + z[i] = 0 + } + } +} + +// Uint64Le2BigInt converts a little-endian slice x into a big number. +func Uint64Le2BigInt(x []uint64) *big.Int { + n := len(x) + b := new(big.Int) + var bi big.Int + for i := n - 1; i >= 0; i-- { + bi.SetUint64(x[i]) + b.Lsh(b, 64) + b.Add(b, &bi) + } + return b +} + +// Uint64Le2BytesLe converts a little-endian slice x to a little-endian slice of bytes. +func Uint64Le2BytesLe(x []uint64) []byte { + b := make([]byte, 8*len(x)) + n := len(x) + for i := 0; i < n; i++ { + binary.LittleEndian.PutUint64(b[i*8:], x[i]) + } + return b +} + +// Uint64Le2BytesBe converts a little-endian slice x to a big-endian slice of bytes. +func Uint64Le2BytesBe(x []uint64) []byte { + b := make([]byte, 8*len(x)) + n := len(x) + for i := 0; i < n; i++ { + binary.BigEndian.PutUint64(b[i*8:], x[n-1-i]) + } + return b +} + +// Uint64Le2Hex returns an hexadecimal string of a number stored in a +// little-endian order slice x. +func Uint64Le2Hex(x []uint64) string { + b := new(strings.Builder) + b.Grow(16*len(x) + 2) + fmt.Fprint(b, "0x") + if len(x) == 0 { + fmt.Fprint(b, "00") + } + for i := len(x) - 1; i >= 0; i-- { + fmt.Fprintf(b, "%016x", x[i]) + } + return b.String() +} + +// BigInt2Uint64Le stores a positive big.Int number x into a little-endian slice z. +// The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros). +// If x does not fit in the slice or is negative, z is not modified. +func BigInt2Uint64Le(z []uint64, x *big.Int) { + xLen := (x.BitLen() + 63) >> 6 // number of 64-bit words + zLen := len(z) + if zLen >= xLen && x.Sign() > 0 { + var y, yi big.Int + y.Set(x) + two64 := big.NewInt(1) + two64.Lsh(two64, 64).Sub(two64, big.NewInt(1)) + for i := 0; i < xLen; i++ { + yi.And(&y, two64) + z[i] = yi.Uint64() + y.Rsh(&y, 64) + } + } + for i := xLen; i < zLen; i++ { + z[i] = 0 + } +} + +// MarshalBinary encodes a value into a byte array in a format readable by UnmarshalBinary. +func MarshalBinary(v cryptobyte.MarshalingValue) ([]byte, error) { + const DefaultSize = 32 + b := cryptobyte.NewBuilder(make([]byte, 0, DefaultSize)) + b.AddValue(v) + return b.Bytes() +} + +// MarshalBinaryLen encodes a value into an array of n bytes in a format readable by UnmarshalBinary. +func MarshalBinaryLen(v cryptobyte.MarshalingValue, length uint) ([]byte, error) { + b := cryptobyte.NewFixedBuilder(make([]byte, 0, length)) + b.AddValue(v) + return b.Bytes() +} + +// A UnmarshalingValue decodes itself from a cryptobyte.String and advances the pointer. +// It reports whether the read was successful. +type UnmarshalingValue interface { + Unmarshal(*cryptobyte.String) bool +} + +// UnmarshalBinary recovers a value from a byte array. +// It returns an error if the read was unsuccessful. +func UnmarshalBinary(v UnmarshalingValue, data []byte) (err error) { + s := cryptobyte.String(data) + if data == nil || !v.Unmarshal(&s) || !s.Empty() { + err = fmt.Errorf("cannot read %T from input string", v) + } + return +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/doc.go b/vendor/github.com/cloudflare/circl/internal/sha3/doc.go new file mode 100644 index 00000000..7e023090 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/doc.go @@ -0,0 +1,62 @@ +// Copyright 2014 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 sha3 implements the SHA-3 fixed-output-length hash functions and +// the SHAKE variable-output-length hash functions defined by FIPS-202. +// +// Both types of hash function use the "sponge" construction and the Keccak +// permutation. For a detailed specification see http://keccak.noekeon.org/ +// +// # Guidance +// +// If you aren't sure what function you need, use SHAKE256 with at least 64 +// bytes of output. The SHAKE instances are faster than the SHA3 instances; +// the latter have to allocate memory to conform to the hash.Hash interface. +// +// If you need a secret-key MAC (message authentication code), prepend the +// secret key to the input, hash with SHAKE256 and read at least 32 bytes of +// output. +// +// # Security strengths +// +// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security +// strength against preimage attacks of x bits. Since they only produce "x" +// bits of output, their collision-resistance is only "x/2" bits. +// +// The SHAKE-256 and -128 functions have a generic security strength of 256 and +// 128 bits against all attacks, provided that at least 2x bits of their output +// is used. Requesting more than 64 or 32 bytes of output, respectively, does +// not increase the collision-resistance of the SHAKE functions. +// +// # The sponge construction +// +// A sponge builds a pseudo-random function from a public pseudo-random +// permutation, by applying the permutation to a state of "rate + capacity" +// bytes, but hiding "capacity" of the bytes. +// +// A sponge starts out with a zero state. To hash an input using a sponge, up +// to "rate" bytes of the input are XORed into the sponge's state. The sponge +// is then "full" and the permutation is applied to "empty" it. This process is +// repeated until all the input has been "absorbed". The input is then padded. +// The digest is "squeezed" from the sponge in the same way, except that output +// is copied out instead of input being XORed in. +// +// A sponge is parameterized by its generic security strength, which is equal +// to half its capacity; capacity + rate is equal to the permutation's width. +// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means +// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. +// +// # Recommendations +// +// The SHAKE functions are recommended for most new uses. They can produce +// output of arbitrary length. SHAKE256, with an output length of at least +// 64 bytes, provides 256-bit security against all attacks. The Keccak team +// recommends it for most applications upgrading from SHA2-512. (NIST chose a +// much stronger, but much slower, sponge instance for SHA3-512.) +// +// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions. +// They produce output of the same length, with the same security strengths +// against all attacks. This means, in particular, that SHA3-256 only has +// 128-bit collision resistance, because its output length is 32 bytes. +package sha3 diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/hashes.go b/vendor/github.com/cloudflare/circl/internal/sha3/hashes.go new file mode 100644 index 00000000..7d2365a7 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/hashes.go @@ -0,0 +1,69 @@ +// Copyright 2014 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 sha3 + +// This file provides functions for creating instances of the SHA-3 +// and SHAKE hash functions, as well as utility functions for hashing +// bytes. + +// New224 creates a new SHA3-224 hash. +// Its generic security strength is 224 bits against preimage attacks, +// and 112 bits against collision attacks. +func New224() State { + return State{rate: 144, outputLen: 28, dsbyte: 0x06} +} + +// New256 creates a new SHA3-256 hash. +// Its generic security strength is 256 bits against preimage attacks, +// and 128 bits against collision attacks. +func New256() State { + return State{rate: 136, outputLen: 32, dsbyte: 0x06} +} + +// New384 creates a new SHA3-384 hash. +// Its generic security strength is 384 bits against preimage attacks, +// and 192 bits against collision attacks. +func New384() State { + return State{rate: 104, outputLen: 48, dsbyte: 0x06} +} + +// New512 creates a new SHA3-512 hash. +// Its generic security strength is 512 bits against preimage attacks, +// and 256 bits against collision attacks. +func New512() State { + return State{rate: 72, outputLen: 64, dsbyte: 0x06} +} + +// Sum224 returns the SHA3-224 digest of the data. +func Sum224(data []byte) (digest [28]byte) { + h := New224() + _, _ = h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum256 returns the SHA3-256 digest of the data. +func Sum256(data []byte) (digest [32]byte) { + h := New256() + _, _ = h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum384 returns the SHA3-384 digest of the data. +func Sum384(data []byte) (digest [48]byte) { + h := New384() + _, _ = h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum512 returns the SHA3-512 digest of the data. +func Sum512(data []byte) (digest [64]byte) { + h := New512() + _, _ = h.Write(data) + h.Sum(digest[:0]) + return +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go b/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go new file mode 100644 index 00000000..1755fd1e --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go @@ -0,0 +1,391 @@ +// Copyright 2014 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 sha3 + +// KeccakF1600 applies the Keccak permutation to a 1600b-wide +// state represented as a slice of 25 uint64s. +// If turbo is true, applies the 12-round variant instead of the +// regular 24-round variant. +// nolint:funlen +func KeccakF1600(a *[25]uint64, turbo bool) { + // Implementation translated from Keccak-inplace.c + // in the keccak reference code. + var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 + + i := 0 + + if turbo { + i = 12 + } + + for ; i < 24; i += 4 { + // Combines the 5 steps in each round into 2 steps. + // Unrolls 4 rounds per loop and spreads some steps across rounds. + + // Round 1 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[6] ^ d1 + bc1 = t<<44 | t>>(64-44) + t = a[12] ^ d2 + bc2 = t<<43 | t>>(64-43) + t = a[18] ^ d3 + bc3 = t<<21 | t>>(64-21) + t = a[24] ^ d4 + bc4 = t<<14 | t>>(64-14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i] + a[6] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc2 = t<<3 | t>>(64-3) + t = a[16] ^ d1 + bc3 = t<<45 | t>>(64-45) + t = a[22] ^ d2 + bc4 = t<<61 | t>>(64-61) + t = a[3] ^ d3 + bc0 = t<<28 | t>>(64-28) + t = a[9] ^ d4 + bc1 = t<<20 | t>>(64-20) + a[10] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc4 = t<<18 | t>>(64-18) + t = a[1] ^ d1 + bc0 = t<<1 | t>>(64-1) + t = a[7] ^ d2 + bc1 = t<<6 | t>>(64-6) + t = a[13] ^ d3 + bc2 = t<<25 | t>>(64-25) + t = a[19] ^ d4 + bc3 = t<<8 | t>>(64-8) + a[20] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc1 = t<<36 | t>>(64-36) + t = a[11] ^ d1 + bc2 = t<<10 | t>>(64-10) + t = a[17] ^ d2 + bc3 = t<<15 | t>>(64-15) + t = a[23] ^ d3 + bc4 = t<<56 | t>>(64-56) + t = a[4] ^ d4 + bc0 = t<<27 | t>>(64-27) + a[5] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc3 = t<<41 | t>>(64-41) + t = a[21] ^ d1 + bc4 = t<<2 | t>>(64-2) + t = a[2] ^ d2 + bc0 = t<<62 | t>>(64-62) + t = a[8] ^ d3 + bc1 = t<<55 | t>>(64-55) + t = a[14] ^ d4 + bc2 = t<<39 | t>>(64-39) + a[15] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + // Round 2 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[16] ^ d1 + bc1 = t<<44 | t>>(64-44) + t = a[7] ^ d2 + bc2 = t<<43 | t>>(64-43) + t = a[23] ^ d3 + bc3 = t<<21 | t>>(64-21) + t = a[14] ^ d4 + bc4 = t<<14 | t>>(64-14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i+1] + a[16] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc2 = t<<3 | t>>(64-3) + t = a[11] ^ d1 + bc3 = t<<45 | t>>(64-45) + t = a[2] ^ d2 + bc4 = t<<61 | t>>(64-61) + t = a[18] ^ d3 + bc0 = t<<28 | t>>(64-28) + t = a[9] ^ d4 + bc1 = t<<20 | t>>(64-20) + a[20] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc4 = t<<18 | t>>(64-18) + t = a[6] ^ d1 + bc0 = t<<1 | t>>(64-1) + t = a[22] ^ d2 + bc1 = t<<6 | t>>(64-6) + t = a[13] ^ d3 + bc2 = t<<25 | t>>(64-25) + t = a[4] ^ d4 + bc3 = t<<8 | t>>(64-8) + a[15] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc1 = t<<36 | t>>(64-36) + t = a[1] ^ d1 + bc2 = t<<10 | t>>(64-10) + t = a[17] ^ d2 + bc3 = t<<15 | t>>(64-15) + t = a[8] ^ d3 + bc4 = t<<56 | t>>(64-56) + t = a[24] ^ d4 + bc0 = t<<27 | t>>(64-27) + a[10] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc3 = t<<41 | t>>(64-41) + t = a[21] ^ d1 + bc4 = t<<2 | t>>(64-2) + t = a[12] ^ d2 + bc0 = t<<62 | t>>(64-62) + t = a[3] ^ d3 + bc1 = t<<55 | t>>(64-55) + t = a[19] ^ d4 + bc2 = t<<39 | t>>(64-39) + a[5] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + // Round 3 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[11] ^ d1 + bc1 = t<<44 | t>>(64-44) + t = a[22] ^ d2 + bc2 = t<<43 | t>>(64-43) + t = a[8] ^ d3 + bc3 = t<<21 | t>>(64-21) + t = a[19] ^ d4 + bc4 = t<<14 | t>>(64-14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i+2] + a[11] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc2 = t<<3 | t>>(64-3) + t = a[1] ^ d1 + bc3 = t<<45 | t>>(64-45) + t = a[12] ^ d2 + bc4 = t<<61 | t>>(64-61) + t = a[23] ^ d3 + bc0 = t<<28 | t>>(64-28) + t = a[9] ^ d4 + bc1 = t<<20 | t>>(64-20) + a[15] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc4 = t<<18 | t>>(64-18) + t = a[16] ^ d1 + bc0 = t<<1 | t>>(64-1) + t = a[2] ^ d2 + bc1 = t<<6 | t>>(64-6) + t = a[13] ^ d3 + bc2 = t<<25 | t>>(64-25) + t = a[24] ^ d4 + bc3 = t<<8 | t>>(64-8) + a[5] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc1 = t<<36 | t>>(64-36) + t = a[6] ^ d1 + bc2 = t<<10 | t>>(64-10) + t = a[17] ^ d2 + bc3 = t<<15 | t>>(64-15) + t = a[3] ^ d3 + bc4 = t<<56 | t>>(64-56) + t = a[14] ^ d4 + bc0 = t<<27 | t>>(64-27) + a[20] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc3 = t<<41 | t>>(64-41) + t = a[21] ^ d1 + bc4 = t<<2 | t>>(64-2) + t = a[7] ^ d2 + bc0 = t<<62 | t>>(64-62) + t = a[18] ^ d3 + bc1 = t<<55 | t>>(64-55) + t = a[4] ^ d4 + bc2 = t<<39 | t>>(64-39) + a[10] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + // Round 4 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[1] ^ d1 + bc1 = t<<44 | t>>(64-44) + t = a[2] ^ d2 + bc2 = t<<43 | t>>(64-43) + t = a[3] ^ d3 + bc3 = t<<21 | t>>(64-21) + t = a[4] ^ d4 + bc4 = t<<14 | t>>(64-14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ RC[i+3] + a[1] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc2 = t<<3 | t>>(64-3) + t = a[6] ^ d1 + bc3 = t<<45 | t>>(64-45) + t = a[7] ^ d2 + bc4 = t<<61 | t>>(64-61) + t = a[8] ^ d3 + bc0 = t<<28 | t>>(64-28) + t = a[9] ^ d4 + bc1 = t<<20 | t>>(64-20) + a[5] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc4 = t<<18 | t>>(64-18) + t = a[11] ^ d1 + bc0 = t<<1 | t>>(64-1) + t = a[12] ^ d2 + bc1 = t<<6 | t>>(64-6) + t = a[13] ^ d3 + bc2 = t<<25 | t>>(64-25) + t = a[14] ^ d4 + bc3 = t<<8 | t>>(64-8) + a[10] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc1 = t<<36 | t>>(64-36) + t = a[16] ^ d1 + bc2 = t<<10 | t>>(64-10) + t = a[17] ^ d2 + bc3 = t<<15 | t>>(64-15) + t = a[18] ^ d3 + bc4 = t<<56 | t>>(64-56) + t = a[19] ^ d4 + bc0 = t<<27 | t>>(64-27) + a[15] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc3 = t<<41 | t>>(64-41) + t = a[21] ^ d1 + bc4 = t<<2 | t>>(64-2) + t = a[22] ^ d2 + bc0 = t<<62 | t>>(64-62) + t = a[23] ^ d3 + bc1 = t<<55 | t>>(64-55) + t = a[24] ^ d4 + bc2 = t<<39 | t>>(64-39) + a[20] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + } +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/rc.go b/vendor/github.com/cloudflare/circl/internal/sha3/rc.go new file mode 100644 index 00000000..6a3df42f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/rc.go @@ -0,0 +1,29 @@ +package sha3 + +// RC stores the round constants for use in the ι step. +var RC = [24]uint64{ + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808A, + 0x8000000080008000, + 0x000000000000808B, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008A, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000A, + 0x000000008000808B, + 0x800000000000008B, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800A, + 0x800000008000000A, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go b/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go new file mode 100644 index 00000000..a0df5aa6 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go @@ -0,0 +1,200 @@ +// Copyright 2014 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 sha3 + +// spongeDirection indicates the direction bytes are flowing through the sponge. +type spongeDirection int + +const ( + // spongeAbsorbing indicates that the sponge is absorbing input. + spongeAbsorbing spongeDirection = iota + // spongeSqueezing indicates that the sponge is being squeezed. + spongeSqueezing +) + +const ( + // maxRate is the maximum size of the internal buffer. SHAKE-256 + // currently needs the largest buffer. + maxRate = 168 +) + +func (d *State) buf() []byte { + return d.storage.asBytes()[d.bufo:d.bufe] +} + +type State struct { + // Generic sponge components. + a [25]uint64 // main state of the hash + rate int // the number of bytes of state to use + + bufo int // offset of buffer in storage + bufe int // end of buffer in storage + + // dsbyte contains the "domain separation" bits and the first bit of + // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the + // SHA-3 and SHAKE functions by appending bitstrings to the message. + // Using a little-endian bit-ordering convention, these are "01" for SHA-3 + // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the + // padding rule from section 5.1 is applied to pad the message to a multiple + // of the rate, which involves adding a "1" bit, zero or more "0" bits, and + // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, + // giving 00000110b (0x06) and 00011111b (0x1f). + // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf + // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and + // Extendable-Output Functions (May 2014)" + dsbyte byte + + storage storageBuf + + // Specific to SHA-3 and SHAKE. + outputLen int // the default output size in bytes + state spongeDirection // whether the sponge is absorbing or squeezing + turbo bool // Whether we're using 12 rounds instead of 24 +} + +// BlockSize returns the rate of sponge underlying this hash function. +func (d *State) BlockSize() int { return d.rate } + +// Size returns the output size of the hash function in bytes. +func (d *State) Size() int { return d.outputLen } + +// Reset clears the internal state by zeroing the sponge state and +// the byte buffer, and setting Sponge.state to absorbing. +func (d *State) Reset() { + // Zero the permutation's state. + for i := range d.a { + d.a[i] = 0 + } + d.state = spongeAbsorbing + d.bufo = 0 + d.bufe = 0 +} + +func (d *State) clone() *State { + ret := *d + return &ret +} + +// permute applies the KeccakF-1600 permutation. It handles +// any input-output buffering. +func (d *State) permute() { + switch d.state { + case spongeAbsorbing: + // If we're absorbing, we need to xor the input into the state + // before applying the permutation. + xorIn(d, d.buf()) + d.bufe = 0 + d.bufo = 0 + KeccakF1600(&d.a, d.turbo) + case spongeSqueezing: + // If we're squeezing, we need to apply the permutation before + // copying more output. + KeccakF1600(&d.a, d.turbo) + d.bufe = d.rate + d.bufo = 0 + copyOut(d, d.buf()) + } +} + +// pads appends the domain separation bits in dsbyte, applies +// the multi-bitrate 10..1 padding rule, and permutes the state. +func (d *State) padAndPermute(dsbyte byte) { + // Pad with this instance's domain-separator bits. We know that there's + // at least one byte of space in d.buf() because, if it were full, + // permute would have been called to empty it. dsbyte also contains the + // first one bit for the padding. See the comment in the state struct. + zerosStart := d.bufe + 1 + d.bufe = d.rate + buf := d.buf() + buf[zerosStart-1] = dsbyte + for i := zerosStart; i < d.rate; i++ { + buf[i] = 0 + } + // This adds the final one bit for the padding. Because of the way that + // bits are numbered from the LSB upwards, the final bit is the MSB of + // the last byte. + buf[d.rate-1] ^= 0x80 + // Apply the permutation + d.permute() + d.state = spongeSqueezing + d.bufe = d.rate + copyOut(d, buf) +} + +// Write absorbs more data into the hash's state. It produces an error +// if more data is written to the ShakeHash after writing +func (d *State) Write(p []byte) (written int, err error) { + if d.state != spongeAbsorbing { + panic("sha3: write to sponge after read") + } + written = len(p) + + for len(p) > 0 { + bufl := d.bufe - d.bufo + if bufl == 0 && len(p) >= d.rate { + // The fast path; absorb a full "rate" bytes of input and apply the permutation. + xorIn(d, p[:d.rate]) + p = p[d.rate:] + KeccakF1600(&d.a, d.turbo) + } else { + // The slow path; buffer the input until we can fill the sponge, and then xor it in. + todo := d.rate - bufl + if todo > len(p) { + todo = len(p) + } + d.bufe += todo + buf := d.buf() + copy(buf[bufl:], p[:todo]) + p = p[todo:] + + // If the sponge is full, apply the permutation. + if d.bufe == d.rate { + d.permute() + } + } + } + + return written, nil +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (d *State) Read(out []byte) (n int, err error) { + // If we're still absorbing, pad and apply the permutation. + if d.state == spongeAbsorbing { + d.padAndPermute(d.dsbyte) + } + + n = len(out) + + // Now, do the squeezing. + for len(out) > 0 { + buf := d.buf() + n := copy(out, buf) + d.bufo += n + out = out[n:] + + // Apply the permutation if we've squeezed the sponge dry. + if d.bufo == d.bufe { + d.permute() + } + } + + return +} + +// Sum applies padding to the hash state and then squeezes out the desired +// number of output bytes. +func (d *State) Sum(in []byte) []byte { + // Make a copy of the original hash so that caller can keep writing + // and summing. + dup := d.clone() + hash := make([]byte, dup.outputLen) + _, _ = dup.Read(hash) + return append(in, hash...) +} + +func (d *State) IsAbsorbing() bool { + return d.state == spongeAbsorbing +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s b/vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s new file mode 100644 index 00000000..8a4458f6 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/sha3_s390x.s @@ -0,0 +1,33 @@ +// Copyright 2017 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. + +// +build !gccgo,!appengine + +#include "textflag.h" + +// func kimd(function code, chain *[200]byte, src []byte) +TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG src+16(FP), R2, R3 // R2=base, R3=len + +continue: + WORD $0xB93E0002 // KIMD --, R2 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET + +// func klmd(function code, chain *[200]byte, dst, src []byte) +TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 + // TODO: SHAKE support + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG dst+16(FP), R2, R3 // R2=base, R3=len + LMG src+40(FP), R4, R5 // R4=base, R5=len + +continue: + WORD $0xB93F0024 // KLMD R2, R4 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/shake.go b/vendor/github.com/cloudflare/circl/internal/sha3/shake.go new file mode 100644 index 00000000..77817f75 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/shake.go @@ -0,0 +1,119 @@ +// Copyright 2014 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 sha3 + +// This file defines the ShakeHash interface, and provides +// functions for creating SHAKE and cSHAKE instances, as well as utility +// functions for hashing bytes to arbitrary-length output. +// +// +// SHAKE implementation is based on FIPS PUB 202 [1] +// cSHAKE implementations is based on NIST SP 800-185 [2] +// +// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +// [2] https://doi.org/10.6028/NIST.SP.800-185 + +import ( + "io" +) + +// ShakeHash defines the interface to hash functions that +// support arbitrary-length output. +type ShakeHash interface { + // Write absorbs more data into the hash's state. It panics if input is + // written to it after output has been read from it. + io.Writer + + // Read reads more output from the hash; reading affects the hash's + // state. (ShakeHash.Read is thus very different from Hash.Sum) + // It never returns an error. + io.Reader + + // Clone returns a copy of the ShakeHash in its current state. + Clone() ShakeHash + + // Reset resets the ShakeHash to its initial state. + Reset() +} + +// Consts for configuring initial SHA-3 state +const ( + dsbyteShake = 0x1f + rate128 = 168 + rate256 = 136 +) + +// Clone returns copy of SHAKE context within its current state. +func (d *State) Clone() ShakeHash { + return d.clone() +} + +// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. +// Its generic security strength is 128 bits against all attacks if at +// least 32 bytes of its output are used. +func NewShake128() State { + return State{rate: rate128, dsbyte: dsbyteShake} +} + +// NewTurboShake128 creates a new TurboSHAKE128 variable-output-length ShakeHash. +// Its generic security strength is 128 bits against all attacks if at +// least 32 bytes of its output are used. +// D is the domain separation byte and must be between 0x01 and 0x7f inclusive. +func NewTurboShake128(D byte) State { + if D == 0 || D > 0x7f { + panic("turboshake: D out of range") + } + return State{rate: rate128, dsbyte: D, turbo: true} +} + +// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. +// Its generic security strength is 256 bits against all attacks if +// at least 64 bytes of its output are used. +func NewShake256() State { + return State{rate: rate256, dsbyte: dsbyteShake} +} + +// NewTurboShake256 creates a new TurboSHAKE256 variable-output-length ShakeHash. +// Its generic security strength is 256 bits against all attacks if +// at least 64 bytes of its output are used. +// D is the domain separation byte and must be between 0x01 and 0x7f inclusive. +func NewTurboShake256(D byte) State { + if D == 0 || D > 0x7f { + panic("turboshake: D out of range") + } + return State{rate: rate256, dsbyte: D, turbo: true} +} + +// ShakeSum128 writes an arbitrary-length digest of data into hash. +func ShakeSum128(hash, data []byte) { + h := NewShake128() + _, _ = h.Write(data) + _, _ = h.Read(hash) +} + +// ShakeSum256 writes an arbitrary-length digest of data into hash. +func ShakeSum256(hash, data []byte) { + h := NewShake256() + _, _ = h.Write(data) + _, _ = h.Read(hash) +} + +// TurboShakeSum128 writes an arbitrary-length digest of data into hash. +func TurboShakeSum128(hash, data []byte, D byte) { + h := NewTurboShake128(D) + _, _ = h.Write(data) + _, _ = h.Read(hash) +} + +// TurboShakeSum256 writes an arbitrary-length digest of data into hash. +func TurboShakeSum256(hash, data []byte, D byte) { + h := NewTurboShake256(D) + _, _ = h.Write(data) + _, _ = h.Read(hash) +} + +func (d *State) SwitchDS(D byte) { + d.dsbyte = D +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/xor.go b/vendor/github.com/cloudflare/circl/internal/sha3/xor.go new file mode 100644 index 00000000..1e213374 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/xor.go @@ -0,0 +1,15 @@ +// Copyright 2015 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 && !386 && !ppc64le) || appengine +// +build !amd64,!386,!ppc64le appengine + +package sha3 + +// A storageBuf is an aligned array of maxRate bytes. +type storageBuf [maxRate]byte + +func (b *storageBuf) asBytes() *[maxRate]byte { + return (*[maxRate]byte)(b) +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go b/vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go new file mode 100644 index 00000000..2b0c6617 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/xor_generic.go @@ -0,0 +1,33 @@ +// Copyright 2015 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 || appengine) && (!386 || appengine) && (!ppc64le || appengine) +// +build !amd64 appengine +// +build !386 appengine +// +build !ppc64le appengine + +package sha3 + +import "encoding/binary" + +// xorIn xors the bytes in buf into the state; it +// makes no non-portable assumptions about memory layout +// or alignment. +func xorIn(d *State, buf []byte) { + n := len(buf) / 8 + + for i := 0; i < n; i++ { + a := binary.LittleEndian.Uint64(buf) + d.a[i] ^= a + buf = buf[8:] + } +} + +// copyOut copies ulint64s to a byte buffer. +func copyOut(d *State, b []byte) { + for i := 0; len(b) >= 8; i++ { + binary.LittleEndian.PutUint64(b, d.a[i]) + b = b[8:] + } +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go b/vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go new file mode 100644 index 00000000..052fc8d3 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/internal/sha3/xor_unaligned.go @@ -0,0 +1,61 @@ +// Copyright 2015 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 || 386 || ppc64le) && !appengine +// +build amd64 386 ppc64le +// +build !appengine + +package sha3 + +import "unsafe" + +// A storageBuf is an aligned array of maxRate bytes. +type storageBuf [maxRate / 8]uint64 + +func (b *storageBuf) asBytes() *[maxRate]byte { + return (*[maxRate]byte)(unsafe.Pointer(b)) +} + +// xorInuses unaligned reads and writes to update d.a to contain d.a +// XOR buf. +func xorIn(d *State, buf []byte) { + n := len(buf) + bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8] + if n >= 72 { + d.a[0] ^= bw[0] + d.a[1] ^= bw[1] + d.a[2] ^= bw[2] + d.a[3] ^= bw[3] + d.a[4] ^= bw[4] + d.a[5] ^= bw[5] + d.a[6] ^= bw[6] + d.a[7] ^= bw[7] + d.a[8] ^= bw[8] + } + if n >= 104 { + d.a[9] ^= bw[9] + d.a[10] ^= bw[10] + d.a[11] ^= bw[11] + d.a[12] ^= bw[12] + } + if n >= 136 { + d.a[13] ^= bw[13] + d.a[14] ^= bw[14] + d.a[15] ^= bw[15] + d.a[16] ^= bw[16] + } + if n >= 144 { + d.a[17] ^= bw[17] + } + if n >= 168 { + d.a[18] ^= bw[18] + d.a[19] ^= bw[19] + d.a[20] ^= bw[20] + } +} + +func copyOut(d *State, buf []byte) { + ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0])) + copy(buf, ab[:]) +} diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp.go b/vendor/github.com/cloudflare/circl/math/fp25519/fp.go new file mode 100644 index 00000000..57a50ff5 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp.go @@ -0,0 +1,205 @@ +// Package fp25519 provides prime field arithmetic over GF(2^255-19). +package fp25519 + +import ( + "errors" + + "github.com/cloudflare/circl/internal/conv" +) + +// Size in bytes of an element. +const Size = 32 + +// Elt is a prime field element. +type Elt [Size]byte + +func (e Elt) String() string { return conv.BytesLe2Hex(e[:]) } + +// p is the prime modulus 2^255-19. +var p = Elt{ + 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, +} + +// P returns the prime modulus 2^255-19. +func P() Elt { return p } + +// ToBytes stores in b the little-endian byte representation of x. +func ToBytes(b []byte, x *Elt) error { + if len(b) != Size { + return errors.New("wrong size") + } + Modp(x) + copy(b, x[:]) + return nil +} + +// IsZero returns true if x is equal to 0. +func IsZero(x *Elt) bool { Modp(x); return *x == Elt{} } + +// SetOne assigns x=1. +func SetOne(x *Elt) { *x = Elt{}; x[0] = 1 } + +// Neg calculates z = -x. +func Neg(z, x *Elt) { Sub(z, &p, x) } + +// InvSqrt calculates z = sqrt(x/y) iff x/y is a quadratic-residue, which is +// indicated by returning isQR = true. Otherwise, when x/y is a quadratic +// non-residue, z will have an undetermined value and isQR = false. +func InvSqrt(z, x, y *Elt) (isQR bool) { + sqrtMinusOne := &Elt{ + 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4, + 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f, + 0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b, + 0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b, + } + t0, t1, t2, t3 := &Elt{}, &Elt{}, &Elt{}, &Elt{} + + Mul(t0, x, y) // t0 = u*v + Sqr(t1, y) // t1 = v^2 + Mul(t2, t0, t1) // t2 = u*v^3 + Sqr(t0, t1) // t0 = v^4 + Mul(t1, t0, t2) // t1 = u*v^7 + + var Tab [4]*Elt + Tab[0] = &Elt{} + Tab[1] = &Elt{} + Tab[2] = t3 + Tab[3] = t1 + + *Tab[0] = *t1 + Sqr(Tab[0], Tab[0]) + Sqr(Tab[1], Tab[0]) + Sqr(Tab[1], Tab[1]) + Mul(Tab[1], Tab[1], Tab[3]) + Mul(Tab[0], Tab[0], Tab[1]) + Sqr(Tab[0], Tab[0]) + Mul(Tab[0], Tab[0], Tab[1]) + Sqr(Tab[1], Tab[0]) + for i := 0; i < 4; i++ { + Sqr(Tab[1], Tab[1]) + } + Mul(Tab[1], Tab[1], Tab[0]) + Sqr(Tab[2], Tab[1]) + for i := 0; i < 4; i++ { + Sqr(Tab[2], Tab[2]) + } + Mul(Tab[2], Tab[2], Tab[0]) + Sqr(Tab[1], Tab[2]) + for i := 0; i < 14; i++ { + Sqr(Tab[1], Tab[1]) + } + Mul(Tab[1], Tab[1], Tab[2]) + Sqr(Tab[2], Tab[1]) + for i := 0; i < 29; i++ { + Sqr(Tab[2], Tab[2]) + } + Mul(Tab[2], Tab[2], Tab[1]) + Sqr(Tab[1], Tab[2]) + for i := 0; i < 59; i++ { + Sqr(Tab[1], Tab[1]) + } + Mul(Tab[1], Tab[1], Tab[2]) + for i := 0; i < 5; i++ { + Sqr(Tab[1], Tab[1]) + } + Mul(Tab[1], Tab[1], Tab[0]) + Sqr(Tab[2], Tab[1]) + for i := 0; i < 124; i++ { + Sqr(Tab[2], Tab[2]) + } + Mul(Tab[2], Tab[2], Tab[1]) + Sqr(Tab[2], Tab[2]) + Sqr(Tab[2], Tab[2]) + Mul(Tab[2], Tab[2], Tab[3]) + + Mul(z, t3, t2) // z = xy^(p+3)/8 = xy^3*(xy^7)^(p-5)/8 + // Checking whether y z^2 == x + Sqr(t0, z) // t0 = z^2 + Mul(t0, t0, y) // t0 = yz^2 + Sub(t1, t0, x) // t1 = t0-u + Add(t2, t0, x) // t2 = t0+u + if IsZero(t1) { + return true + } else if IsZero(t2) { + Mul(z, z, sqrtMinusOne) // z = z*sqrt(-1) + return true + } else { + return false + } +} + +// Inv calculates z = 1/x mod p. +func Inv(z, x *Elt) { + x0, x1, x2 := &Elt{}, &Elt{}, &Elt{} + Sqr(x1, x) + Sqr(x0, x1) + Sqr(x0, x0) + Mul(x0, x0, x) + Mul(z, x0, x1) + Sqr(x1, z) + Mul(x0, x0, x1) + Sqr(x1, x0) + for i := 0; i < 4; i++ { + Sqr(x1, x1) + } + Mul(x0, x0, x1) + Sqr(x1, x0) + for i := 0; i < 9; i++ { + Sqr(x1, x1) + } + Mul(x1, x1, x0) + Sqr(x2, x1) + for i := 0; i < 19; i++ { + Sqr(x2, x2) + } + Mul(x2, x2, x1) + for i := 0; i < 10; i++ { + Sqr(x2, x2) + } + Mul(x2, x2, x0) + Sqr(x0, x2) + for i := 0; i < 49; i++ { + Sqr(x0, x0) + } + Mul(x0, x0, x2) + Sqr(x1, x0) + for i := 0; i < 99; i++ { + Sqr(x1, x1) + } + Mul(x1, x1, x0) + for i := 0; i < 50; i++ { + Sqr(x1, x1) + } + Mul(x1, x1, x2) + for i := 0; i < 5; i++ { + Sqr(x1, x1) + } + Mul(z, z, x1) +} + +// Cmov assigns y to x if n is 1. +func Cmov(x, y *Elt, n uint) { cmov(x, y, n) } + +// Cswap interchanges x and y if n is 1. +func Cswap(x, y *Elt, n uint) { cswap(x, y, n) } + +// Add calculates z = x+y mod p. +func Add(z, x, y *Elt) { add(z, x, y) } + +// Sub calculates z = x-y mod p. +func Sub(z, x, y *Elt) { sub(z, x, y) } + +// AddSub calculates (x,y) = (x+y mod p, x-y mod p). +func AddSub(x, y *Elt) { addsub(x, y) } + +// Mul calculates z = x*y mod p. +func Mul(z, x, y *Elt) { mul(z, x, y) } + +// Sqr calculates z = x^2 mod p. +func Sqr(z, x *Elt) { sqr(z, x) } + +// Modp ensures that z is between [0,p-1]. +func Modp(z *Elt) { modp(z) } diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go new file mode 100644 index 00000000..057f0d28 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.go @@ -0,0 +1,45 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package fp25519 + +import ( + "golang.org/x/sys/cpu" +) + +var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX + +var _ = hasBmi2Adx + +func cmov(x, y *Elt, n uint) { cmovAmd64(x, y, n) } +func cswap(x, y *Elt, n uint) { cswapAmd64(x, y, n) } +func add(z, x, y *Elt) { addAmd64(z, x, y) } +func sub(z, x, y *Elt) { subAmd64(z, x, y) } +func addsub(x, y *Elt) { addsubAmd64(x, y) } +func mul(z, x, y *Elt) { mulAmd64(z, x, y) } +func sqr(z, x *Elt) { sqrAmd64(z, x) } +func modp(z *Elt) { modpAmd64(z) } + +//go:noescape +func cmovAmd64(x, y *Elt, n uint) + +//go:noescape +func cswapAmd64(x, y *Elt, n uint) + +//go:noescape +func addAmd64(z, x, y *Elt) + +//go:noescape +func subAmd64(z, x, y *Elt) + +//go:noescape +func addsubAmd64(x, y *Elt) + +//go:noescape +func mulAmd64(z, x, y *Elt) + +//go:noescape +func sqrAmd64(z, x *Elt) + +//go:noescape +func modpAmd64(z *Elt) diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h new file mode 100644 index 00000000..b884b584 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp_amd64.h @@ -0,0 +1,351 @@ +// This code was imported from https://github.com/armfazh/rfc7748_precomputed + +// CHECK_BMI2ADX triggers bmi2adx if supported, +// otherwise it fallbacks to legacy code. +#define CHECK_BMI2ADX(label, legacy, bmi2adx) \ + CMPB ·hasBmi2Adx(SB), $0 \ + JE label \ + bmi2adx \ + RET \ + label: \ + legacy \ + RET + +// cselect is a conditional move +// if b=1: it copies y into x; +// if b=0: x remains with the same value; +// if b<> 0,1: undefined. +// Uses: AX, DX, FLAGS +// Instr: x86_64, cmov +#define cselect(x,y,b) \ + TESTQ b, b \ + MOVQ 0+x, AX; MOVQ 0+y, DX; CMOVQNE DX, AX; MOVQ AX, 0+x; \ + MOVQ 8+x, AX; MOVQ 8+y, DX; CMOVQNE DX, AX; MOVQ AX, 8+x; \ + MOVQ 16+x, AX; MOVQ 16+y, DX; CMOVQNE DX, AX; MOVQ AX, 16+x; \ + MOVQ 24+x, AX; MOVQ 24+y, DX; CMOVQNE DX, AX; MOVQ AX, 24+x; + +// cswap is a conditional swap +// if b=1: x,y <- y,x; +// if b=0: x,y remain with the same values; +// if b<> 0,1: undefined. +// Uses: AX, DX, R8, FLAGS +// Instr: x86_64, cmov +#define cswap(x,y,b) \ + TESTQ b, b \ + MOVQ 0+x, AX; MOVQ AX, R8; MOVQ 0+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 0+x; MOVQ DX, 0+y; \ + MOVQ 8+x, AX; MOVQ AX, R8; MOVQ 8+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 8+x; MOVQ DX, 8+y; \ + MOVQ 16+x, AX; MOVQ AX, R8; MOVQ 16+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 16+x; MOVQ DX, 16+y; \ + MOVQ 24+x, AX; MOVQ AX, R8; MOVQ 24+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 24+x; MOVQ DX, 24+y; + +// additionLeg adds x and y and stores in z +// Uses: AX, DX, R8-R11, FLAGS +// Instr: x86_64, cmov +#define additionLeg(z,x,y) \ + MOVL $38, AX; \ + MOVL $0, DX; \ + MOVQ 0+x, R8; ADDQ 0+y, R8; \ + MOVQ 8+x, R9; ADCQ 8+y, R9; \ + MOVQ 16+x, R10; ADCQ 16+y, R10; \ + MOVQ 24+x, R11; ADCQ 24+y, R11; \ + CMOVQCS AX, DX; \ + ADDQ DX, R8; \ + ADCQ $0, R9; MOVQ R9, 8+z; \ + ADCQ $0, R10; MOVQ R10, 16+z; \ + ADCQ $0, R11; MOVQ R11, 24+z; \ + MOVL $0, DX; \ + CMOVQCS AX, DX; \ + ADDQ DX, R8; MOVQ R8, 0+z; + +// additionAdx adds x and y and stores in z +// Uses: AX, DX, R8-R11, FLAGS +// Instr: x86_64, cmov, adx +#define additionAdx(z,x,y) \ + MOVL $38, AX; \ + XORL DX, DX; \ + MOVQ 0+x, R8; ADCXQ 0+y, R8; \ + MOVQ 8+x, R9; ADCXQ 8+y, R9; \ + MOVQ 16+x, R10; ADCXQ 16+y, R10; \ + MOVQ 24+x, R11; ADCXQ 24+y, R11; \ + CMOVQCS AX, DX ; \ + XORL AX, AX; \ + ADCXQ DX, R8; \ + ADCXQ AX, R9; MOVQ R9, 8+z; \ + ADCXQ AX, R10; MOVQ R10, 16+z; \ + ADCXQ AX, R11; MOVQ R11, 24+z; \ + MOVL $38, DX; \ + CMOVQCS DX, AX; \ + ADDQ AX, R8; MOVQ R8, 0+z; + +// subtraction subtracts y from x and stores in z +// Uses: AX, DX, R8-R11, FLAGS +// Instr: x86_64, cmov +#define subtraction(z,x,y) \ + MOVL $38, AX; \ + MOVQ 0+x, R8; SUBQ 0+y, R8; \ + MOVQ 8+x, R9; SBBQ 8+y, R9; \ + MOVQ 16+x, R10; SBBQ 16+y, R10; \ + MOVQ 24+x, R11; SBBQ 24+y, R11; \ + MOVL $0, DX; \ + CMOVQCS AX, DX; \ + SUBQ DX, R8; \ + SBBQ $0, R9; MOVQ R9, 8+z; \ + SBBQ $0, R10; MOVQ R10, 16+z; \ + SBBQ $0, R11; MOVQ R11, 24+z; \ + MOVL $0, DX; \ + CMOVQCS AX, DX; \ + SUBQ DX, R8; MOVQ R8, 0+z; + +// integerMulAdx multiplies x and y and stores in z +// Uses: AX, DX, R8-R15, FLAGS +// Instr: x86_64, bmi2, adx +#define integerMulAdx(z,x,y) \ + MOVL $0,R15; \ + MOVQ 0+y, DX; XORL AX, AX; \ + MULXQ 0+x, AX, R8; MOVQ AX, 0+z; \ + MULXQ 8+x, AX, R9; ADCXQ AX, R8; \ + MULXQ 16+x, AX, R10; ADCXQ AX, R9; \ + MULXQ 24+x, AX, R11; ADCXQ AX, R10; \ + MOVL $0, AX;;;;;;;;; ADCXQ AX, R11; \ + MOVQ 8+y, DX; XORL AX, AX; \ + MULXQ 0+x, AX, R12; ADCXQ R8, AX; MOVQ AX, 8+z; \ + MULXQ 8+x, AX, R13; ADCXQ R9, R12; ADOXQ AX, R12; \ + MULXQ 16+x, AX, R14; ADCXQ R10, R13; ADOXQ AX, R13; \ + MULXQ 24+x, AX, R15; ADCXQ R11, R14; ADOXQ AX, R14; \ + MOVL $0, AX;;;;;;;;; ADCXQ AX, R15; ADOXQ AX, R15; \ + MOVQ 16+y, DX; XORL AX, AX; \ + MULXQ 0+x, AX, R8; ADCXQ R12, AX; MOVQ AX, 16+z; \ + MULXQ 8+x, AX, R9; ADCXQ R13, R8; ADOXQ AX, R8; \ + MULXQ 16+x, AX, R10; ADCXQ R14, R9; ADOXQ AX, R9; \ + MULXQ 24+x, AX, R11; ADCXQ R15, R10; ADOXQ AX, R10; \ + MOVL $0, AX;;;;;;;;; ADCXQ AX, R11; ADOXQ AX, R11; \ + MOVQ 24+y, DX; XORL AX, AX; \ + MULXQ 0+x, AX, R12; ADCXQ R8, AX; MOVQ AX, 24+z; \ + MULXQ 8+x, AX, R13; ADCXQ R9, R12; ADOXQ AX, R12; MOVQ R12, 32+z; \ + MULXQ 16+x, AX, R14; ADCXQ R10, R13; ADOXQ AX, R13; MOVQ R13, 40+z; \ + MULXQ 24+x, AX, R15; ADCXQ R11, R14; ADOXQ AX, R14; MOVQ R14, 48+z; \ + MOVL $0, AX;;;;;;;;; ADCXQ AX, R15; ADOXQ AX, R15; MOVQ R15, 56+z; + +// integerMulLeg multiplies x and y and stores in z +// Uses: AX, DX, R8-R15, FLAGS +// Instr: x86_64 +#define integerMulLeg(z,x,y) \ + MOVQ 0+y, R8; \ + MOVQ 0+x, AX; MULQ R8; MOVQ AX, 0+z; MOVQ DX, R15; \ + MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \ + MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \ + MOVQ 24+x, AX; MULQ R8; \ + ADDQ R13, R15; \ + ADCQ R14, R10; MOVQ R10, 16+z; \ + ADCQ AX, R11; MOVQ R11, 24+z; \ + ADCQ $0, DX; MOVQ DX, 32+z; \ + MOVQ 8+y, R8; \ + MOVQ 0+x, AX; MULQ R8; MOVQ AX, R12; MOVQ DX, R9; \ + MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \ + MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \ + MOVQ 24+x, AX; MULQ R8; \ + ADDQ R12, R15; MOVQ R15, 8+z; \ + ADCQ R13, R9; \ + ADCQ R14, R10; \ + ADCQ AX, R11; \ + ADCQ $0, DX; \ + ADCQ 16+z, R9; MOVQ R9, R15; \ + ADCQ 24+z, R10; MOVQ R10, 24+z; \ + ADCQ 32+z, R11; MOVQ R11, 32+z; \ + ADCQ $0, DX; MOVQ DX, 40+z; \ + MOVQ 16+y, R8; \ + MOVQ 0+x, AX; MULQ R8; MOVQ AX, R12; MOVQ DX, R9; \ + MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \ + MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \ + MOVQ 24+x, AX; MULQ R8; \ + ADDQ R12, R15; MOVQ R15, 16+z; \ + ADCQ R13, R9; \ + ADCQ R14, R10; \ + ADCQ AX, R11; \ + ADCQ $0, DX; \ + ADCQ 24+z, R9; MOVQ R9, R15; \ + ADCQ 32+z, R10; MOVQ R10, 32+z; \ + ADCQ 40+z, R11; MOVQ R11, 40+z; \ + ADCQ $0, DX; MOVQ DX, 48+z; \ + MOVQ 24+y, R8; \ + MOVQ 0+x, AX; MULQ R8; MOVQ AX, R12; MOVQ DX, R9; \ + MOVQ 8+x, AX; MULQ R8; MOVQ AX, R13; MOVQ DX, R10; \ + MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; \ + MOVQ 24+x, AX; MULQ R8; \ + ADDQ R12, R15; MOVQ R15, 24+z; \ + ADCQ R13, R9; \ + ADCQ R14, R10; \ + ADCQ AX, R11; \ + ADCQ $0, DX; \ + ADCQ 32+z, R9; MOVQ R9, 32+z; \ + ADCQ 40+z, R10; MOVQ R10, 40+z; \ + ADCQ 48+z, R11; MOVQ R11, 48+z; \ + ADCQ $0, DX; MOVQ DX, 56+z; + +// integerSqrLeg squares x and stores in z +// Uses: AX, CX, DX, R8-R15, FLAGS +// Instr: x86_64 +#define integerSqrLeg(z,x) \ + MOVQ 0+x, R8; \ + MOVQ 8+x, AX; MULQ R8; MOVQ AX, R9; MOVQ DX, R10; /* A[0]*A[1] */ \ + MOVQ 16+x, AX; MULQ R8; MOVQ AX, R14; MOVQ DX, R11; /* A[0]*A[2] */ \ + MOVQ 24+x, AX; MULQ R8; MOVQ AX, R15; MOVQ DX, R12; /* A[0]*A[3] */ \ + MOVQ 24+x, R8; \ + MOVQ 8+x, AX; MULQ R8; MOVQ AX, CX; MOVQ DX, R13; /* A[3]*A[1] */ \ + MOVQ 16+x, AX; MULQ R8; /* A[3]*A[2] */ \ + \ + ADDQ R14, R10;\ + ADCQ R15, R11; MOVL $0, R15;\ + ADCQ CX, R12;\ + ADCQ AX, R13;\ + ADCQ $0, DX; MOVQ DX, R14;\ + MOVQ 8+x, AX; MULQ 16+x;\ + \ + ADDQ AX, R11;\ + ADCQ DX, R12;\ + ADCQ $0, R13;\ + ADCQ $0, R14;\ + ADCQ $0, R15;\ + \ + SHLQ $1, R14, R15; MOVQ R15, 56+z;\ + SHLQ $1, R13, R14; MOVQ R14, 48+z;\ + SHLQ $1, R12, R13; MOVQ R13, 40+z;\ + SHLQ $1, R11, R12; MOVQ R12, 32+z;\ + SHLQ $1, R10, R11; MOVQ R11, 24+z;\ + SHLQ $1, R9, R10; MOVQ R10, 16+z;\ + SHLQ $1, R9; MOVQ R9, 8+z;\ + \ + MOVQ 0+x,AX; MULQ AX; MOVQ AX, 0+z; MOVQ DX, R9;\ + MOVQ 8+x,AX; MULQ AX; MOVQ AX, R10; MOVQ DX, R11;\ + MOVQ 16+x,AX; MULQ AX; MOVQ AX, R12; MOVQ DX, R13;\ + MOVQ 24+x,AX; MULQ AX; MOVQ AX, R14; MOVQ DX, R15;\ + \ + ADDQ 8+z, R9; MOVQ R9, 8+z;\ + ADCQ 16+z, R10; MOVQ R10, 16+z;\ + ADCQ 24+z, R11; MOVQ R11, 24+z;\ + ADCQ 32+z, R12; MOVQ R12, 32+z;\ + ADCQ 40+z, R13; MOVQ R13, 40+z;\ + ADCQ 48+z, R14; MOVQ R14, 48+z;\ + ADCQ 56+z, R15; MOVQ R15, 56+z; + +// integerSqrAdx squares x and stores in z +// Uses: AX, CX, DX, R8-R15, FLAGS +// Instr: x86_64, bmi2, adx +#define integerSqrAdx(z,x) \ + MOVQ 0+x, DX; /* A[0] */ \ + MULXQ 8+x, R8, R14; /* A[1]*A[0] */ XORL R15, R15; \ + MULXQ 16+x, R9, R10; /* A[2]*A[0] */ ADCXQ R14, R9; \ + MULXQ 24+x, AX, CX; /* A[3]*A[0] */ ADCXQ AX, R10; \ + MOVQ 24+x, DX; /* A[3] */ \ + MULXQ 8+x, R11, R12; /* A[1]*A[3] */ ADCXQ CX, R11; \ + MULXQ 16+x, AX, R13; /* A[2]*A[3] */ ADCXQ AX, R12; \ + MOVQ 8+x, DX; /* A[1] */ ADCXQ R15, R13; \ + MULXQ 16+x, AX, CX; /* A[2]*A[1] */ MOVL $0, R14; \ + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ADCXQ R15, R14; \ + XORL R15, R15; \ + ADOXQ AX, R10; ADCXQ R8, R8; \ + ADOXQ CX, R11; ADCXQ R9, R9; \ + ADOXQ R15, R12; ADCXQ R10, R10; \ + ADOXQ R15, R13; ADCXQ R11, R11; \ + ADOXQ R15, R14; ADCXQ R12, R12; \ + ;;;;;;;;;;;;;;; ADCXQ R13, R13; \ + ;;;;;;;;;;;;;;; ADCXQ R14, R14; \ + MOVQ 0+x, DX; MULXQ DX, AX, CX; /* A[0]^2 */ \ + ;;;;;;;;;;;;;;; MOVQ AX, 0+z; \ + ADDQ CX, R8; MOVQ R8, 8+z; \ + MOVQ 8+x, DX; MULXQ DX, AX, CX; /* A[1]^2 */ \ + ADCQ AX, R9; MOVQ R9, 16+z; \ + ADCQ CX, R10; MOVQ R10, 24+z; \ + MOVQ 16+x, DX; MULXQ DX, AX, CX; /* A[2]^2 */ \ + ADCQ AX, R11; MOVQ R11, 32+z; \ + ADCQ CX, R12; MOVQ R12, 40+z; \ + MOVQ 24+x, DX; MULXQ DX, AX, CX; /* A[3]^2 */ \ + ADCQ AX, R13; MOVQ R13, 48+z; \ + ADCQ CX, R14; MOVQ R14, 56+z; + +// reduceFromDouble finds z congruent to x modulo p such that 0> 63) + // PUT BIT 255 IN CARRY FLAG AND CLEAR + x3 &^= 1 << 63 + + x0, c0 := bits.Add64(x0, cx, 0) + x1, c1 := bits.Add64(x1, 0, c0) + x2, c2 := bits.Add64(x2, 0, c1) + x3, _ = bits.Add64(x3, 0, c2) + + // TEST FOR BIT 255 AGAIN; ONLY TRIGGERED ON OVERFLOW MODULO 2^255-19 + // cx = C[255] ? 0 : 19 + cx = uint64(19) &^ (-(x3 >> 63)) + // CLEAR BIT 255 + x3 &^= 1 << 63 + + x0, c0 = bits.Sub64(x0, cx, 0) + x1, c1 = bits.Sub64(x1, 0, c0) + x2, c2 = bits.Sub64(x2, 0, c1) + x3, _ = bits.Sub64(x3, 0, c2) + + binary.LittleEndian.PutUint64(x[0*8:1*8], x0) + binary.LittleEndian.PutUint64(x[1*8:2*8], x1) + binary.LittleEndian.PutUint64(x[2*8:3*8], x2) + binary.LittleEndian.PutUint64(x[3*8:4*8], x3) +} + +func red64(z *Elt, x0, x1, x2, x3, x4, x5, x6, x7 uint64) { + h0, l0 := bits.Mul64(x4, 38) + h1, l1 := bits.Mul64(x5, 38) + h2, l2 := bits.Mul64(x6, 38) + h3, l3 := bits.Mul64(x7, 38) + + l1, c0 := bits.Add64(h0, l1, 0) + l2, c1 := bits.Add64(h1, l2, c0) + l3, c2 := bits.Add64(h2, l3, c1) + l4, _ := bits.Add64(h3, 0, c2) + + l0, c0 = bits.Add64(l0, x0, 0) + l1, c1 = bits.Add64(l1, x1, c0) + l2, c2 = bits.Add64(l2, x2, c1) + l3, c3 := bits.Add64(l3, x3, c2) + l4, _ = bits.Add64(l4, 0, c3) + + _, l4 = bits.Mul64(l4, 38) + l0, c0 = bits.Add64(l0, l4, 0) + z1, c1 := bits.Add64(l1, 0, c0) + z2, c2 := bits.Add64(l2, 0, c1) + z3, c3 := bits.Add64(l3, 0, c2) + z0, _ := bits.Add64(l0, (-c3)&38, 0) + + binary.LittleEndian.PutUint64(z[0*8:1*8], z0) + binary.LittleEndian.PutUint64(z[1*8:2*8], z1) + binary.LittleEndian.PutUint64(z[2*8:3*8], z2) + binary.LittleEndian.PutUint64(z[3*8:4*8], z3) +} diff --git a/vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go b/vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go new file mode 100644 index 00000000..26ca4d01 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp25519/fp_noasm.go @@ -0,0 +1,13 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +package fp25519 + +func cmov(x, y *Elt, n uint) { cmovGeneric(x, y, n) } +func cswap(x, y *Elt, n uint) { cswapGeneric(x, y, n) } +func add(z, x, y *Elt) { addGeneric(z, x, y) } +func sub(z, x, y *Elt) { subGeneric(z, x, y) } +func addsub(x, y *Elt) { addsubGeneric(x, y) } +func mul(z, x, y *Elt) { mulGeneric(z, x, y) } +func sqr(z, x *Elt) { sqrGeneric(z, x) } +func modp(z *Elt) { modpGeneric(z) } diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp.go b/vendor/github.com/cloudflare/circl/math/fp448/fp.go new file mode 100644 index 00000000..a5e36600 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp448/fp.go @@ -0,0 +1,164 @@ +// Package fp448 provides prime field arithmetic over GF(2^448-2^224-1). +package fp448 + +import ( + "errors" + + "github.com/cloudflare/circl/internal/conv" +) + +// Size in bytes of an element. +const Size = 56 + +// Elt is a prime field element. +type Elt [Size]byte + +func (e Elt) String() string { return conv.BytesLe2Hex(e[:]) } + +// p is the prime modulus 2^448-2^224-1. +var p = Elt{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +} + +// P returns the prime modulus 2^448-2^224-1. +func P() Elt { return p } + +// ToBytes stores in b the little-endian byte representation of x. +func ToBytes(b []byte, x *Elt) error { + if len(b) != Size { + return errors.New("wrong size") + } + Modp(x) + copy(b, x[:]) + return nil +} + +// IsZero returns true if x is equal to 0. +func IsZero(x *Elt) bool { Modp(x); return *x == Elt{} } + +// IsOne returns true if x is equal to 1. +func IsOne(x *Elt) bool { Modp(x); return *x == Elt{1} } + +// SetOne assigns x=1. +func SetOne(x *Elt) { *x = Elt{1} } + +// One returns the 1 element. +func One() (x Elt) { x = Elt{1}; return } + +// Neg calculates z = -x. +func Neg(z, x *Elt) { Sub(z, &p, x) } + +// Modp ensures that z is between [0,p-1]. +func Modp(z *Elt) { Sub(z, z, &p) } + +// InvSqrt calculates z = sqrt(x/y) iff x/y is a quadratic-residue. If so, +// isQR = true; otherwise, isQR = false, since x/y is a quadratic non-residue, +// and z = sqrt(-x/y). +func InvSqrt(z, x, y *Elt) (isQR bool) { + // First note that x^(2(k+1)) = x^(p-1)/2 * x = legendre(x) * x + // so that's x if x is a quadratic residue and -x otherwise. + // Next, y^(6k+3) = y^(4k+2) * y^(2k+1) = y^(p-1) * y^((p-1)/2) = legendre(y). + // So the z we compute satisfies z^2 y = x^(2(k+1)) y^(6k+3) = legendre(x)*legendre(y). + // Thus if x and y are quadratic residues, then z is indeed sqrt(x/y). + t0, t1 := &Elt{}, &Elt{} + Mul(t0, x, y) // x*y + Sqr(t1, y) // y^2 + Mul(t1, t0, t1) // x*y^3 + powPminus3div4(z, t1) // (x*y^3)^k + Mul(z, z, t0) // z = x*y*(x*y^3)^k = x^(k+1) * y^(3k+1) + + // Check if x/y is a quadratic residue + Sqr(t0, z) // z^2 + Mul(t0, t0, y) // y*z^2 + Sub(t0, t0, x) // y*z^2-x + return IsZero(t0) +} + +// Inv calculates z = 1/x mod p. +func Inv(z, x *Elt) { + // Calculates z = x^(4k+1) = x^(p-3+1) = x^(p-2) = x^-1, where k = (p-3)/4. + t := &Elt{} + powPminus3div4(t, x) // t = x^k + Sqr(t, t) // t = x^2k + Sqr(t, t) // t = x^4k + Mul(z, t, x) // z = x^(4k+1) +} + +// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4. +func powPminus3div4(z, x *Elt) { + x0, x1 := &Elt{}, &Elt{} + Sqr(z, x) + Mul(z, z, x) + Sqr(x0, z) + Mul(x0, x0, x) + Sqr(z, x0) + Sqr(z, z) + Sqr(z, z) + Mul(z, z, x0) + Sqr(x1, z) + for i := 0; i < 5; i++ { + Sqr(x1, x1) + } + Mul(x1, x1, z) + Sqr(z, x1) + for i := 0; i < 11; i++ { + Sqr(z, z) + } + Mul(z, z, x1) + Sqr(z, z) + Sqr(z, z) + Sqr(z, z) + Mul(z, z, x0) + Sqr(x1, z) + for i := 0; i < 26; i++ { + Sqr(x1, x1) + } + Mul(x1, x1, z) + Sqr(z, x1) + for i := 0; i < 53; i++ { + Sqr(z, z) + } + Mul(z, z, x1) + Sqr(z, z) + Sqr(z, z) + Sqr(z, z) + Mul(z, z, x0) + Sqr(x1, z) + for i := 0; i < 110; i++ { + Sqr(x1, x1) + } + Mul(x1, x1, z) + Sqr(z, x1) + Mul(z, z, x) + for i := 0; i < 223; i++ { + Sqr(z, z) + } + Mul(z, z, x1) +} + +// Cmov assigns y to x if n is 1. +func Cmov(x, y *Elt, n uint) { cmov(x, y, n) } + +// Cswap interchanges x and y if n is 1. +func Cswap(x, y *Elt, n uint) { cswap(x, y, n) } + +// Add calculates z = x+y mod p. +func Add(z, x, y *Elt) { add(z, x, y) } + +// Sub calculates z = x-y mod p. +func Sub(z, x, y *Elt) { sub(z, x, y) } + +// AddSub calculates (x,y) = (x+y mod p, x-y mod p). +func AddSub(x, y *Elt) { addsub(x, y) } + +// Mul calculates z = x*y mod p. +func Mul(z, x, y *Elt) { mul(z, x, y) } + +// Sqr calculates z = x^2 mod p. +func Sqr(z, x *Elt) { sqr(z, x) } diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go new file mode 100644 index 00000000..6a12209a --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.go @@ -0,0 +1,43 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package fp448 + +import ( + "golang.org/x/sys/cpu" +) + +var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX + +var _ = hasBmi2Adx + +func cmov(x, y *Elt, n uint) { cmovAmd64(x, y, n) } +func cswap(x, y *Elt, n uint) { cswapAmd64(x, y, n) } +func add(z, x, y *Elt) { addAmd64(z, x, y) } +func sub(z, x, y *Elt) { subAmd64(z, x, y) } +func addsub(x, y *Elt) { addsubAmd64(x, y) } +func mul(z, x, y *Elt) { mulAmd64(z, x, y) } +func sqr(z, x *Elt) { sqrAmd64(z, x) } + +/* Functions defined in fp_amd64.s */ + +//go:noescape +func cmovAmd64(x, y *Elt, n uint) + +//go:noescape +func cswapAmd64(x, y *Elt, n uint) + +//go:noescape +func addAmd64(z, x, y *Elt) + +//go:noescape +func subAmd64(z, x, y *Elt) + +//go:noescape +func addsubAmd64(x, y *Elt) + +//go:noescape +func mulAmd64(z, x, y *Elt) + +//go:noescape +func sqrAmd64(z, x *Elt) diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h new file mode 100644 index 00000000..536fe5bd --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.h @@ -0,0 +1,591 @@ +// This code was imported from https://github.com/armfazh/rfc7748_precomputed + +// CHECK_BMI2ADX triggers bmi2adx if supported, +// otherwise it fallbacks to legacy code. +#define CHECK_BMI2ADX(label, legacy, bmi2adx) \ + CMPB ·hasBmi2Adx(SB), $0 \ + JE label \ + bmi2adx \ + RET \ + label: \ + legacy \ + RET + +// cselect is a conditional move +// if b=1: it copies y into x; +// if b=0: x remains with the same value; +// if b<> 0,1: undefined. +// Uses: AX, DX, FLAGS +// Instr: x86_64, cmov +#define cselect(x,y,b) \ + TESTQ b, b \ + MOVQ 0+x, AX; MOVQ 0+y, DX; CMOVQNE DX, AX; MOVQ AX, 0+x; \ + MOVQ 8+x, AX; MOVQ 8+y, DX; CMOVQNE DX, AX; MOVQ AX, 8+x; \ + MOVQ 16+x, AX; MOVQ 16+y, DX; CMOVQNE DX, AX; MOVQ AX, 16+x; \ + MOVQ 24+x, AX; MOVQ 24+y, DX; CMOVQNE DX, AX; MOVQ AX, 24+x; \ + MOVQ 32+x, AX; MOVQ 32+y, DX; CMOVQNE DX, AX; MOVQ AX, 32+x; \ + MOVQ 40+x, AX; MOVQ 40+y, DX; CMOVQNE DX, AX; MOVQ AX, 40+x; \ + MOVQ 48+x, AX; MOVQ 48+y, DX; CMOVQNE DX, AX; MOVQ AX, 48+x; + +// cswap is a conditional swap +// if b=1: x,y <- y,x; +// if b=0: x,y remain with the same values; +// if b<> 0,1: undefined. +// Uses: AX, DX, R8, FLAGS +// Instr: x86_64, cmov +#define cswap(x,y,b) \ + TESTQ b, b \ + MOVQ 0+x, AX; MOVQ AX, R8; MOVQ 0+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 0+x; MOVQ DX, 0+y; \ + MOVQ 8+x, AX; MOVQ AX, R8; MOVQ 8+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 8+x; MOVQ DX, 8+y; \ + MOVQ 16+x, AX; MOVQ AX, R8; MOVQ 16+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 16+x; MOVQ DX, 16+y; \ + MOVQ 24+x, AX; MOVQ AX, R8; MOVQ 24+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 24+x; MOVQ DX, 24+y; \ + MOVQ 32+x, AX; MOVQ AX, R8; MOVQ 32+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 32+x; MOVQ DX, 32+y; \ + MOVQ 40+x, AX; MOVQ AX, R8; MOVQ 40+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 40+x; MOVQ DX, 40+y; \ + MOVQ 48+x, AX; MOVQ AX, R8; MOVQ 48+y, DX; CMOVQNE DX, AX; CMOVQNE R8, DX; MOVQ AX, 48+x; MOVQ DX, 48+y; + +// additionLeg adds x and y and stores in z +// Uses: AX, DX, R8-R14, FLAGS +// Instr: x86_64 +#define additionLeg(z,x,y) \ + MOVQ 0+x, R8; ADDQ 0+y, R8; \ + MOVQ 8+x, R9; ADCQ 8+y, R9; \ + MOVQ 16+x, R10; ADCQ 16+y, R10; \ + MOVQ 24+x, R11; ADCQ 24+y, R11; \ + MOVQ 32+x, R12; ADCQ 32+y, R12; \ + MOVQ 40+x, R13; ADCQ 40+y, R13; \ + MOVQ 48+x, R14; ADCQ 48+y, R14; \ + MOVQ $0, AX; ADCQ $0, AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + ADDQ AX, R8; MOVQ $0, AX; \ + ADCQ $0, R9; \ + ADCQ $0, R10; \ + ADCQ DX, R11; \ + ADCQ $0, R12; \ + ADCQ $0, R13; \ + ADCQ $0, R14; \ + ADCQ $0, AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + ADDQ AX, R8; MOVQ R8, 0+z; \ + ADCQ $0, R9; MOVQ R9, 8+z; \ + ADCQ $0, R10; MOVQ R10, 16+z; \ + ADCQ DX, R11; MOVQ R11, 24+z; \ + ADCQ $0, R12; MOVQ R12, 32+z; \ + ADCQ $0, R13; MOVQ R13, 40+z; \ + ADCQ $0, R14; MOVQ R14, 48+z; + + +// additionAdx adds x and y and stores in z +// Uses: AX, DX, R8-R15, FLAGS +// Instr: x86_64, adx +#define additionAdx(z,x,y) \ + MOVL $32, R15; \ + XORL DX, DX; \ + MOVQ 0+x, R8; ADCXQ 0+y, R8; \ + MOVQ 8+x, R9; ADCXQ 8+y, R9; \ + MOVQ 16+x, R10; ADCXQ 16+y, R10; \ + MOVQ 24+x, R11; ADCXQ 24+y, R11; \ + MOVQ 32+x, R12; ADCXQ 32+y, R12; \ + MOVQ 40+x, R13; ADCXQ 40+y, R13; \ + MOVQ 48+x, R14; ADCXQ 48+y, R14; \ + ;;;;;;;;;;;;;;; ADCXQ DX, DX; \ + XORL AX, AX; \ + ADCXQ DX, R8; SHLXQ R15, DX, DX; \ + ADCXQ AX, R9; \ + ADCXQ AX, R10; \ + ADCXQ DX, R11; \ + ADCXQ AX, R12; \ + ADCXQ AX, R13; \ + ADCXQ AX, R14; \ + ADCXQ AX, AX; \ + XORL DX, DX; \ + ADCXQ AX, R8; MOVQ R8, 0+z; SHLXQ R15, AX, AX; \ + ADCXQ DX, R9; MOVQ R9, 8+z; \ + ADCXQ DX, R10; MOVQ R10, 16+z; \ + ADCXQ AX, R11; MOVQ R11, 24+z; \ + ADCXQ DX, R12; MOVQ R12, 32+z; \ + ADCXQ DX, R13; MOVQ R13, 40+z; \ + ADCXQ DX, R14; MOVQ R14, 48+z; + +// subtraction subtracts y from x and stores in z +// Uses: AX, DX, R8-R14, FLAGS +// Instr: x86_64 +#define subtraction(z,x,y) \ + MOVQ 0+x, R8; SUBQ 0+y, R8; \ + MOVQ 8+x, R9; SBBQ 8+y, R9; \ + MOVQ 16+x, R10; SBBQ 16+y, R10; \ + MOVQ 24+x, R11; SBBQ 24+y, R11; \ + MOVQ 32+x, R12; SBBQ 32+y, R12; \ + MOVQ 40+x, R13; SBBQ 40+y, R13; \ + MOVQ 48+x, R14; SBBQ 48+y, R14; \ + MOVQ $0, AX; SETCS AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + SUBQ AX, R8; MOVQ $0, AX; \ + SBBQ $0, R9; \ + SBBQ $0, R10; \ + SBBQ DX, R11; \ + SBBQ $0, R12; \ + SBBQ $0, R13; \ + SBBQ $0, R14; \ + SETCS AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + SUBQ AX, R8; MOVQ R8, 0+z; \ + SBBQ $0, R9; MOVQ R9, 8+z; \ + SBBQ $0, R10; MOVQ R10, 16+z; \ + SBBQ DX, R11; MOVQ R11, 24+z; \ + SBBQ $0, R12; MOVQ R12, 32+z; \ + SBBQ $0, R13; MOVQ R13, 40+z; \ + SBBQ $0, R14; MOVQ R14, 48+z; + +// maddBmi2Adx multiplies x and y and accumulates in z +// Uses: AX, DX, R15, FLAGS +// Instr: x86_64, bmi2, adx +#define maddBmi2Adx(z,x,y,i,r0,r1,r2,r3,r4,r5,r6) \ + MOVQ i+y, DX; XORL AX, AX; \ + MULXQ 0+x, AX, R8; ADOXQ AX, r0; ADCXQ R8, r1; MOVQ r0,i+z; \ + MULXQ 8+x, AX, r0; ADOXQ AX, r1; ADCXQ r0, r2; MOVQ $0, R8; \ + MULXQ 16+x, AX, r0; ADOXQ AX, r2; ADCXQ r0, r3; \ + MULXQ 24+x, AX, r0; ADOXQ AX, r3; ADCXQ r0, r4; \ + MULXQ 32+x, AX, r0; ADOXQ AX, r4; ADCXQ r0, r5; \ + MULXQ 40+x, AX, r0; ADOXQ AX, r5; ADCXQ r0, r6; \ + MULXQ 48+x, AX, r0; ADOXQ AX, r6; ADCXQ R8, r0; \ + ;;;;;;;;;;;;;;;;;;; ADOXQ R8, r0; + +// integerMulAdx multiplies x and y and stores in z +// Uses: AX, DX, R8-R15, FLAGS +// Instr: x86_64, bmi2, adx +#define integerMulAdx(z,x,y) \ + MOVL $0,R15; \ + MOVQ 0+y, DX; XORL AX, AX; MOVQ $0, R8; \ + MULXQ 0+x, AX, R9; MOVQ AX, 0+z; \ + MULXQ 8+x, AX, R10; ADCXQ AX, R9; \ + MULXQ 16+x, AX, R11; ADCXQ AX, R10; \ + MULXQ 24+x, AX, R12; ADCXQ AX, R11; \ + MULXQ 32+x, AX, R13; ADCXQ AX, R12; \ + MULXQ 40+x, AX, R14; ADCXQ AX, R13; \ + MULXQ 48+x, AX, R15; ADCXQ AX, R14; \ + ;;;;;;;;;;;;;;;;;;;; ADCXQ R8, R15; \ + maddBmi2Adx(z,x,y, 8, R9,R10,R11,R12,R13,R14,R15) \ + maddBmi2Adx(z,x,y,16,R10,R11,R12,R13,R14,R15, R9) \ + maddBmi2Adx(z,x,y,24,R11,R12,R13,R14,R15, R9,R10) \ + maddBmi2Adx(z,x,y,32,R12,R13,R14,R15, R9,R10,R11) \ + maddBmi2Adx(z,x,y,40,R13,R14,R15, R9,R10,R11,R12) \ + maddBmi2Adx(z,x,y,48,R14,R15, R9,R10,R11,R12,R13) \ + MOVQ R15, 56+z; \ + MOVQ R9, 64+z; \ + MOVQ R10, 72+z; \ + MOVQ R11, 80+z; \ + MOVQ R12, 88+z; \ + MOVQ R13, 96+z; \ + MOVQ R14, 104+z; + +// maddLegacy multiplies x and y and accumulates in z +// Uses: AX, DX, R15, FLAGS +// Instr: x86_64 +#define maddLegacy(z,x,y,i) \ + MOVQ i+y, R15; \ + MOVQ 0+x, AX; MULQ R15; MOVQ AX, R8; ;;;;;;;;;;;; MOVQ DX, R9; \ + MOVQ 8+x, AX; MULQ R15; ADDQ AX, R9; ADCQ $0, DX; MOVQ DX, R10; \ + MOVQ 16+x, AX; MULQ R15; ADDQ AX, R10; ADCQ $0, DX; MOVQ DX, R11; \ + MOVQ 24+x, AX; MULQ R15; ADDQ AX, R11; ADCQ $0, DX; MOVQ DX, R12; \ + MOVQ 32+x, AX; MULQ R15; ADDQ AX, R12; ADCQ $0, DX; MOVQ DX, R13; \ + MOVQ 40+x, AX; MULQ R15; ADDQ AX, R13; ADCQ $0, DX; MOVQ DX, R14; \ + MOVQ 48+x, AX; MULQ R15; ADDQ AX, R14; ADCQ $0, DX; \ + ADDQ 0+i+z, R8; MOVQ R8, 0+i+z; \ + ADCQ 8+i+z, R9; MOVQ R9, 8+i+z; \ + ADCQ 16+i+z, R10; MOVQ R10, 16+i+z; \ + ADCQ 24+i+z, R11; MOVQ R11, 24+i+z; \ + ADCQ 32+i+z, R12; MOVQ R12, 32+i+z; \ + ADCQ 40+i+z, R13; MOVQ R13, 40+i+z; \ + ADCQ 48+i+z, R14; MOVQ R14, 48+i+z; \ + ADCQ $0, DX; MOVQ DX, 56+i+z; + +// integerMulLeg multiplies x and y and stores in z +// Uses: AX, DX, R8-R15, FLAGS +// Instr: x86_64 +#define integerMulLeg(z,x,y) \ + MOVQ 0+y, R15; \ + MOVQ 0+x, AX; MULQ R15; MOVQ AX, 0+z; ;;;;;;;;;;;; MOVQ DX, R8; \ + MOVQ 8+x, AX; MULQ R15; ADDQ AX, R8; ADCQ $0, DX; MOVQ DX, R9; MOVQ R8, 8+z; \ + MOVQ 16+x, AX; MULQ R15; ADDQ AX, R9; ADCQ $0, DX; MOVQ DX, R10; MOVQ R9, 16+z; \ + MOVQ 24+x, AX; MULQ R15; ADDQ AX, R10; ADCQ $0, DX; MOVQ DX, R11; MOVQ R10, 24+z; \ + MOVQ 32+x, AX; MULQ R15; ADDQ AX, R11; ADCQ $0, DX; MOVQ DX, R12; MOVQ R11, 32+z; \ + MOVQ 40+x, AX; MULQ R15; ADDQ AX, R12; ADCQ $0, DX; MOVQ DX, R13; MOVQ R12, 40+z; \ + MOVQ 48+x, AX; MULQ R15; ADDQ AX, R13; ADCQ $0, DX; MOVQ DX,56+z; MOVQ R13, 48+z; \ + maddLegacy(z,x,y, 8) \ + maddLegacy(z,x,y,16) \ + maddLegacy(z,x,y,24) \ + maddLegacy(z,x,y,32) \ + maddLegacy(z,x,y,40) \ + maddLegacy(z,x,y,48) + +// integerSqrLeg squares x and stores in z +// Uses: AX, CX, DX, R8-R15, FLAGS +// Instr: x86_64 +#define integerSqrLeg(z,x) \ + XORL R15, R15; \ + MOVQ 0+x, CX; \ + MOVQ CX, AX; MULQ CX; MOVQ AX, 0+z; MOVQ DX, R8; \ + ADDQ CX, CX; ADCQ $0, R15; \ + MOVQ 8+x, AX; MULQ CX; ADDQ AX, R8; ADCQ $0, DX; MOVQ DX, R9; MOVQ R8, 8+z; \ + MOVQ 16+x, AX; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; MOVQ DX, R10; \ + MOVQ 24+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; MOVQ DX, R11; \ + MOVQ 32+x, AX; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; MOVQ DX, R12; \ + MOVQ 40+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; MOVQ DX, R13; \ + MOVQ 48+x, AX; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; MOVQ DX, R14; \ + \ + MOVQ 8+x, CX; \ + MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \ + ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; MOVQ R9,16+z; \ + MOVQ R15, AX; NEGQ AX; ANDQ 8+x, AX; ADDQ AX, DX; ADCQ $0, R11; MOVQ DX, R8; \ + ADDQ 8+x, CX; ADCQ $0, R15; \ + MOVQ 16+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; ADDQ R8, R10; ADCQ $0, DX; MOVQ DX, R8; MOVQ R10, 24+z; \ + MOVQ 24+x, AX; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; ADDQ R8, R11; ADCQ $0, DX; MOVQ DX, R8; \ + MOVQ 32+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; ADDQ R8, R12; ADCQ $0, DX; MOVQ DX, R8; \ + MOVQ 40+x, AX; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; ADDQ R8, R13; ADCQ $0, DX; MOVQ DX, R8; \ + MOVQ 48+x, AX; MULQ CX; ADDQ AX, R14; ADCQ $0, DX; ADDQ R8, R14; ADCQ $0, DX; MOVQ DX, R9; \ + \ + MOVQ 16+x, CX; \ + MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \ + ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; MOVQ R11, 32+z; \ + MOVQ R15, AX; NEGQ AX; ANDQ 16+x,AX; ADDQ AX, DX; ADCQ $0, R13; MOVQ DX, R8; \ + ADDQ 16+x, CX; ADCQ $0, R15; \ + MOVQ 24+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; ADDQ R8, R12; ADCQ $0, DX; MOVQ DX, R8; MOVQ R12, 40+z; \ + MOVQ 32+x, AX; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; ADDQ R8, R13; ADCQ $0, DX; MOVQ DX, R8; \ + MOVQ 40+x, AX; MULQ CX; ADDQ AX, R14; ADCQ $0, DX; ADDQ R8, R14; ADCQ $0, DX; MOVQ DX, R8; \ + MOVQ 48+x, AX; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; ADDQ R8, R9; ADCQ $0, DX; MOVQ DX,R10; \ + \ + MOVQ 24+x, CX; \ + MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \ + ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; MOVQ R13, 48+z; \ + MOVQ R15, AX; NEGQ AX; ANDQ 24+x,AX; ADDQ AX, DX; ADCQ $0, R9; MOVQ DX, R8; \ + ADDQ 24+x, CX; ADCQ $0, R15; \ + MOVQ 32+x, AX; MULQ CX; ADDQ AX, R14; ADCQ $0, DX; ADDQ R8, R14; ADCQ $0, DX; MOVQ DX, R8; MOVQ R14, 56+z; \ + MOVQ 40+x, AX; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; ADDQ R8, R9; ADCQ $0, DX; MOVQ DX, R8; \ + MOVQ 48+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; ADDQ R8, R10; ADCQ $0, DX; MOVQ DX,R11; \ + \ + MOVQ 32+x, CX; \ + MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \ + ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R9; ADCQ $0, DX; MOVQ R9, 64+z; \ + MOVQ R15, AX; NEGQ AX; ANDQ 32+x,AX; ADDQ AX, DX; ADCQ $0, R11; MOVQ DX, R8; \ + ADDQ 32+x, CX; ADCQ $0, R15; \ + MOVQ 40+x, AX; MULQ CX; ADDQ AX, R10; ADCQ $0, DX; ADDQ R8, R10; ADCQ $0, DX; MOVQ DX, R8; MOVQ R10, 72+z; \ + MOVQ 48+x, AX; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; ADDQ R8, R11; ADCQ $0, DX; MOVQ DX,R12; \ + \ + XORL R13, R13; \ + XORL R14, R14; \ + MOVQ 40+x, CX; \ + MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \ + ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R11; ADCQ $0, DX; MOVQ R11, 80+z; \ + MOVQ R15, AX; NEGQ AX; ANDQ 40+x,AX; ADDQ AX, DX; ADCQ $0, R13; MOVQ DX, R8; \ + ADDQ 40+x, CX; ADCQ $0, R15; \ + MOVQ 48+x, AX; MULQ CX; ADDQ AX, R12; ADCQ $0, DX; ADDQ R8, R12; ADCQ $0, DX; MOVQ DX, R8; MOVQ R12, 88+z; \ + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ADDQ R8, R13; ADCQ $0,R14; \ + \ + XORL R9, R9; \ + MOVQ 48+x, CX; \ + MOVQ CX, AX; ADDQ R15, CX; MOVQ $0, R15; ADCQ $0, R15; \ + ;;;;;;;;;;;;;; MULQ CX; ADDQ AX, R13; ADCQ $0, DX; MOVQ R13, 96+z; \ + MOVQ R15, AX; NEGQ AX; ANDQ 48+x,AX; ADDQ AX, DX; ADCQ $0, R9; MOVQ DX, R8; \ + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ADDQ R8,R14; ADCQ $0, R9; MOVQ R14, 104+z; + + +// integerSqrAdx squares x and stores in z +// Uses: AX, CX, DX, R8-R15, FLAGS +// Instr: x86_64, bmi2, adx +#define integerSqrAdx(z,x) \ + XORL R15, R15; \ + MOVQ 0+x, DX; \ + ;;;;;;;;;;;;;; MULXQ DX, AX, R8; MOVQ AX, 0+z; \ + ADDQ DX, DX; ADCQ $0, R15; CLC; \ + MULXQ 8+x, AX, R9; ADCXQ AX, R8; MOVQ R8, 8+z; \ + MULXQ 16+x, AX, R10; ADCXQ AX, R9; MOVQ $0, R8;\ + MULXQ 24+x, AX, R11; ADCXQ AX, R10; \ + MULXQ 32+x, AX, R12; ADCXQ AX, R11; \ + MULXQ 40+x, AX, R13; ADCXQ AX, R12; \ + MULXQ 48+x, AX, R14; ADCXQ AX, R13; \ + ;;;;;;;;;;;;;;;;;;;; ADCXQ R8, R14; \ + \ + MOVQ 8+x, DX; \ + MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \ + MULXQ AX, AX, CX; \ + MOVQ R15, R8; NEGQ R8; ANDQ 8+x, R8; \ + ADDQ AX, R9; MOVQ R9, 16+z; \ + ADCQ CX, R8; \ + ADCQ $0, R11; \ + ADDQ 8+x, DX; \ + ADCQ $0, R15; \ + XORL R9, R9; ;;;;;;;;;;;;;;;;;;;;; ADOXQ R8, R10; \ + MULXQ 16+x, AX, CX; ADCXQ AX, R10; ADOXQ CX, R11; MOVQ R10, 24+z; \ + MULXQ 24+x, AX, CX; ADCXQ AX, R11; ADOXQ CX, R12; MOVQ $0, R10; \ + MULXQ 32+x, AX, CX; ADCXQ AX, R12; ADOXQ CX, R13; \ + MULXQ 40+x, AX, CX; ADCXQ AX, R13; ADOXQ CX, R14; \ + MULXQ 48+x, AX, CX; ADCXQ AX, R14; ADOXQ CX, R9; \ + ;;;;;;;;;;;;;;;;;;; ADCXQ R10, R9; \ + \ + MOVQ 16+x, DX; \ + MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \ + MULXQ AX, AX, CX; \ + MOVQ R15, R8; NEGQ R8; ANDQ 16+x, R8; \ + ADDQ AX, R11; MOVQ R11, 32+z; \ + ADCQ CX, R8; \ + ADCQ $0, R13; \ + ADDQ 16+x, DX; \ + ADCQ $0, R15; \ + XORL R11, R11; ;;;;;;;;;;;;;;;;;;; ADOXQ R8, R12; \ + MULXQ 24+x, AX, CX; ADCXQ AX, R12; ADOXQ CX, R13; MOVQ R12, 40+z; \ + MULXQ 32+x, AX, CX; ADCXQ AX, R13; ADOXQ CX, R14; MOVQ $0, R12; \ + MULXQ 40+x, AX, CX; ADCXQ AX, R14; ADOXQ CX, R9; \ + MULXQ 48+x, AX, CX; ADCXQ AX, R9; ADOXQ CX, R10; \ + ;;;;;;;;;;;;;;;;;;; ADCXQ R11,R10; \ + \ + MOVQ 24+x, DX; \ + MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \ + MULXQ AX, AX, CX; \ + MOVQ R15, R8; NEGQ R8; ANDQ 24+x, R8; \ + ADDQ AX, R13; MOVQ R13, 48+z; \ + ADCQ CX, R8; \ + ADCQ $0, R9; \ + ADDQ 24+x, DX; \ + ADCQ $0, R15; \ + XORL R13, R13; ;;;;;;;;;;;;;;;;;;; ADOXQ R8, R14; \ + MULXQ 32+x, AX, CX; ADCXQ AX, R14; ADOXQ CX, R9; MOVQ R14, 56+z; \ + MULXQ 40+x, AX, CX; ADCXQ AX, R9; ADOXQ CX, R10; MOVQ $0, R14; \ + MULXQ 48+x, AX, CX; ADCXQ AX, R10; ADOXQ CX, R11; \ + ;;;;;;;;;;;;;;;;;;; ADCXQ R12,R11; \ + \ + MOVQ 32+x, DX; \ + MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \ + MULXQ AX, AX, CX; \ + MOVQ R15, R8; NEGQ R8; ANDQ 32+x, R8; \ + ADDQ AX, R9; MOVQ R9, 64+z; \ + ADCQ CX, R8; \ + ADCQ $0, R11; \ + ADDQ 32+x, DX; \ + ADCQ $0, R15; \ + XORL R9, R9; ;;;;;;;;;;;;;;;;;;;;; ADOXQ R8, R10; \ + MULXQ 40+x, AX, CX; ADCXQ AX, R10; ADOXQ CX, R11; MOVQ R10, 72+z; \ + MULXQ 48+x, AX, CX; ADCXQ AX, R11; ADOXQ CX, R12; \ + ;;;;;;;;;;;;;;;;;;; ADCXQ R13,R12; \ + \ + MOVQ 40+x, DX; \ + MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \ + MULXQ AX, AX, CX; \ + MOVQ R15, R8; NEGQ R8; ANDQ 40+x, R8; \ + ADDQ AX, R11; MOVQ R11, 80+z; \ + ADCQ CX, R8; \ + ADCQ $0, R13; \ + ADDQ 40+x, DX; \ + ADCQ $0, R15; \ + XORL R11, R11; ;;;;;;;;;;;;;;;;;;; ADOXQ R8, R12; \ + MULXQ 48+x, AX, CX; ADCXQ AX, R12; ADOXQ CX, R13; MOVQ R12, 88+z; \ + ;;;;;;;;;;;;;;;;;;; ADCXQ R14,R13; \ + \ + MOVQ 48+x, DX; \ + MOVQ DX, AX; ADDQ R15, DX; MOVQ $0, R15; ADCQ $0, R15; \ + MULXQ AX, AX, CX; \ + MOVQ R15, R8; NEGQ R8; ANDQ 48+x, R8; \ + XORL R10, R10; ;;;;;;;;;;;;;; ADOXQ CX, R14; \ + ;;;;;;;;;;;;;; ADCXQ AX, R13; ;;;;;;;;;;;;;; MOVQ R13, 96+z; \ + ;;;;;;;;;;;;;; ADCXQ R8, R14; MOVQ R14, 104+z; + +// reduceFromDoubleLeg finds a z=x modulo p such that z<2^448 and stores in z +// Uses: AX, R8-R15, FLAGS +// Instr: x86_64 +#define reduceFromDoubleLeg(z,x) \ + /* ( ,2C13,2C12,2C11,2C10|C10,C9,C8, C7) + (C6,...,C0) */ \ + /* (r14, r13, r12, r11, r10,r9,r8,r15) */ \ + MOVQ 80+x,AX; MOVQ AX,R10; \ + MOVQ $0xFFFFFFFF00000000, R8; \ + ANDQ R8,R10; \ + \ + MOVQ $0,R14; \ + MOVQ 104+x,R13; SHLQ $1,R13,R14; \ + MOVQ 96+x,R12; SHLQ $1,R12,R13; \ + MOVQ 88+x,R11; SHLQ $1,R11,R12; \ + MOVQ 72+x, R9; SHLQ $1,R10,R11; \ + MOVQ 64+x, R8; SHLQ $1,R10; \ + MOVQ $0xFFFFFFFF,R15; ANDQ R15,AX; ORQ AX,R10; \ + MOVQ 56+x,R15; \ + \ + ADDQ 0+x,R15; MOVQ R15, 0+z; MOVQ 56+x,R15; \ + ADCQ 8+x, R8; MOVQ R8, 8+z; MOVQ 64+x, R8; \ + ADCQ 16+x, R9; MOVQ R9,16+z; MOVQ 72+x, R9; \ + ADCQ 24+x,R10; MOVQ R10,24+z; MOVQ 80+x,R10; \ + ADCQ 32+x,R11; MOVQ R11,32+z; MOVQ 88+x,R11; \ + ADCQ 40+x,R12; MOVQ R12,40+z; MOVQ 96+x,R12; \ + ADCQ 48+x,R13; MOVQ R13,48+z; MOVQ 104+x,R13; \ + ADCQ $0,R14; \ + /* (c10c9,c9c8,c8c7,c7c13,c13c12,c12c11,c11c10) + (c6,...,c0) */ \ + /* ( r9, r8, r15, r13, r12, r11, r10) */ \ + MOVQ R10, AX; \ + SHRQ $32,R11,R10; \ + SHRQ $32,R12,R11; \ + SHRQ $32,R13,R12; \ + SHRQ $32,R15,R13; \ + SHRQ $32, R8,R15; \ + SHRQ $32, R9, R8; \ + SHRQ $32, AX, R9; \ + \ + ADDQ 0+z,R10; \ + ADCQ 8+z,R11; \ + ADCQ 16+z,R12; \ + ADCQ 24+z,R13; \ + ADCQ 32+z,R15; \ + ADCQ 40+z, R8; \ + ADCQ 48+z, R9; \ + ADCQ $0,R14; \ + /* ( c7) + (c6,...,c0) */ \ + /* (r14) */ \ + MOVQ R14, AX; SHLQ $32, AX; \ + ADDQ R14,R10; MOVQ $0,R14; \ + ADCQ $0,R11; \ + ADCQ $0,R12; \ + ADCQ AX,R13; \ + ADCQ $0,R15; \ + ADCQ $0, R8; \ + ADCQ $0, R9; \ + ADCQ $0,R14; \ + /* ( c7) + (c6,...,c0) */ \ + /* (r14) */ \ + MOVQ R14, AX; SHLQ $32,AX; \ + ADDQ R14,R10; MOVQ R10, 0+z; \ + ADCQ $0,R11; MOVQ R11, 8+z; \ + ADCQ $0,R12; MOVQ R12,16+z; \ + ADCQ AX,R13; MOVQ R13,24+z; \ + ADCQ $0,R15; MOVQ R15,32+z; \ + ADCQ $0, R8; MOVQ R8,40+z; \ + ADCQ $0, R9; MOVQ R9,48+z; + +// reduceFromDoubleAdx finds a z=x modulo p such that z<2^448 and stores in z +// Uses: AX, R8-R15, FLAGS +// Instr: x86_64, adx +#define reduceFromDoubleAdx(z,x) \ + /* ( ,2C13,2C12,2C11,2C10|C10,C9,C8, C7) + (C6,...,C0) */ \ + /* (r14, r13, r12, r11, r10,r9,r8,r15) */ \ + MOVQ 80+x,AX; MOVQ AX,R10; \ + MOVQ $0xFFFFFFFF00000000, R8; \ + ANDQ R8,R10; \ + \ + MOVQ $0,R14; \ + MOVQ 104+x,R13; SHLQ $1,R13,R14; \ + MOVQ 96+x,R12; SHLQ $1,R12,R13; \ + MOVQ 88+x,R11; SHLQ $1,R11,R12; \ + MOVQ 72+x, R9; SHLQ $1,R10,R11; \ + MOVQ 64+x, R8; SHLQ $1,R10; \ + MOVQ $0xFFFFFFFF,R15; ANDQ R15,AX; ORQ AX,R10; \ + MOVQ 56+x,R15; \ + \ + XORL AX,AX; \ + ADCXQ 0+x,R15; MOVQ R15, 0+z; MOVQ 56+x,R15; \ + ADCXQ 8+x, R8; MOVQ R8, 8+z; MOVQ 64+x, R8; \ + ADCXQ 16+x, R9; MOVQ R9,16+z; MOVQ 72+x, R9; \ + ADCXQ 24+x,R10; MOVQ R10,24+z; MOVQ 80+x,R10; \ + ADCXQ 32+x,R11; MOVQ R11,32+z; MOVQ 88+x,R11; \ + ADCXQ 40+x,R12; MOVQ R12,40+z; MOVQ 96+x,R12; \ + ADCXQ 48+x,R13; MOVQ R13,48+z; MOVQ 104+x,R13; \ + ADCXQ AX,R14; \ + /* (c10c9,c9c8,c8c7,c7c13,c13c12,c12c11,c11c10) + (c6,...,c0) */ \ + /* ( r9, r8, r15, r13, r12, r11, r10) */ \ + MOVQ R10, AX; \ + SHRQ $32,R11,R10; \ + SHRQ $32,R12,R11; \ + SHRQ $32,R13,R12; \ + SHRQ $32,R15,R13; \ + SHRQ $32, R8,R15; \ + SHRQ $32, R9, R8; \ + SHRQ $32, AX, R9; \ + \ + XORL AX,AX; \ + ADCXQ 0+z,R10; \ + ADCXQ 8+z,R11; \ + ADCXQ 16+z,R12; \ + ADCXQ 24+z,R13; \ + ADCXQ 32+z,R15; \ + ADCXQ 40+z, R8; \ + ADCXQ 48+z, R9; \ + ADCXQ AX,R14; \ + /* ( c7) + (c6,...,c0) */ \ + /* (r14) */ \ + MOVQ R14, AX; SHLQ $32, AX; \ + CLC; \ + ADCXQ R14,R10; MOVQ $0,R14; \ + ADCXQ R14,R11; \ + ADCXQ R14,R12; \ + ADCXQ AX,R13; \ + ADCXQ R14,R15; \ + ADCXQ R14, R8; \ + ADCXQ R14, R9; \ + ADCXQ R14,R14; \ + /* ( c7) + (c6,...,c0) */ \ + /* (r14) */ \ + MOVQ R14, AX; SHLQ $32, AX; \ + CLC; \ + ADCXQ R14,R10; MOVQ R10, 0+z; MOVQ $0,R14; \ + ADCXQ R14,R11; MOVQ R11, 8+z; \ + ADCXQ R14,R12; MOVQ R12,16+z; \ + ADCXQ AX,R13; MOVQ R13,24+z; \ + ADCXQ R14,R15; MOVQ R15,32+z; \ + ADCXQ R14, R8; MOVQ R8,40+z; \ + ADCXQ R14, R9; MOVQ R9,48+z; + +// addSub calculates two operations: x,y = x+y,x-y +// Uses: AX, DX, R8-R15, FLAGS +#define addSub(x,y) \ + MOVQ 0+x, R8; ADDQ 0+y, R8; \ + MOVQ 8+x, R9; ADCQ 8+y, R9; \ + MOVQ 16+x, R10; ADCQ 16+y, R10; \ + MOVQ 24+x, R11; ADCQ 24+y, R11; \ + MOVQ 32+x, R12; ADCQ 32+y, R12; \ + MOVQ 40+x, R13; ADCQ 40+y, R13; \ + MOVQ 48+x, R14; ADCQ 48+y, R14; \ + MOVQ $0, AX; ADCQ $0, AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + ADDQ AX, R8; MOVQ $0, AX; \ + ADCQ $0, R9; \ + ADCQ $0, R10; \ + ADCQ DX, R11; \ + ADCQ $0, R12; \ + ADCQ $0, R13; \ + ADCQ $0, R14; \ + ADCQ $0, AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + ADDQ AX, R8; MOVQ 0+x,AX; MOVQ R8, 0+x; MOVQ AX, R8; \ + ADCQ $0, R9; MOVQ 8+x,AX; MOVQ R9, 8+x; MOVQ AX, R9; \ + ADCQ $0, R10; MOVQ 16+x,AX; MOVQ R10, 16+x; MOVQ AX, R10; \ + ADCQ DX, R11; MOVQ 24+x,AX; MOVQ R11, 24+x; MOVQ AX, R11; \ + ADCQ $0, R12; MOVQ 32+x,AX; MOVQ R12, 32+x; MOVQ AX, R12; \ + ADCQ $0, R13; MOVQ 40+x,AX; MOVQ R13, 40+x; MOVQ AX, R13; \ + ADCQ $0, R14; MOVQ 48+x,AX; MOVQ R14, 48+x; MOVQ AX, R14; \ + SUBQ 0+y, R8; \ + SBBQ 8+y, R9; \ + SBBQ 16+y, R10; \ + SBBQ 24+y, R11; \ + SBBQ 32+y, R12; \ + SBBQ 40+y, R13; \ + SBBQ 48+y, R14; \ + MOVQ $0, AX; SETCS AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + SUBQ AX, R8; MOVQ $0, AX; \ + SBBQ $0, R9; \ + SBBQ $0, R10; \ + SBBQ DX, R11; \ + SBBQ $0, R12; \ + SBBQ $0, R13; \ + SBBQ $0, R14; \ + SETCS AX; \ + MOVQ AX, DX; \ + SHLQ $32, DX; \ + SUBQ AX, R8; MOVQ R8, 0+y; \ + SBBQ $0, R9; MOVQ R9, 8+y; \ + SBBQ $0, R10; MOVQ R10, 16+y; \ + SBBQ DX, R11; MOVQ R11, 24+y; \ + SBBQ $0, R12; MOVQ R12, 32+y; \ + SBBQ $0, R13; MOVQ R13, 40+y; \ + SBBQ $0, R14; MOVQ R14, 48+y; diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s new file mode 100644 index 00000000..3f1f07c9 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_amd64.s @@ -0,0 +1,75 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +#include "textflag.h" +#include "fp_amd64.h" + +// func cmovAmd64(x, y *Elt, n uint) +TEXT ·cmovAmd64(SB),NOSPLIT,$0-24 + MOVQ x+0(FP), DI + MOVQ y+8(FP), SI + MOVQ n+16(FP), BX + cselect(0(DI),0(SI),BX) + RET + +// func cswapAmd64(x, y *Elt, n uint) +TEXT ·cswapAmd64(SB),NOSPLIT,$0-24 + MOVQ x+0(FP), DI + MOVQ y+8(FP), SI + MOVQ n+16(FP), BX + cswap(0(DI),0(SI),BX) + RET + +// func subAmd64(z, x, y *Elt) +TEXT ·subAmd64(SB),NOSPLIT,$0-24 + MOVQ z+0(FP), DI + MOVQ x+8(FP), SI + MOVQ y+16(FP), BX + subtraction(0(DI),0(SI),0(BX)) + RET + +// func addsubAmd64(x, y *Elt) +TEXT ·addsubAmd64(SB),NOSPLIT,$0-16 + MOVQ x+0(FP), DI + MOVQ y+8(FP), SI + addSub(0(DI),0(SI)) + RET + +#define addLegacy \ + additionLeg(0(DI),0(SI),0(BX)) +#define addBmi2Adx \ + additionAdx(0(DI),0(SI),0(BX)) + +#define mulLegacy \ + integerMulLeg(0(SP),0(SI),0(BX)) \ + reduceFromDoubleLeg(0(DI),0(SP)) +#define mulBmi2Adx \ + integerMulAdx(0(SP),0(SI),0(BX)) \ + reduceFromDoubleAdx(0(DI),0(SP)) + +#define sqrLegacy \ + integerSqrLeg(0(SP),0(SI)) \ + reduceFromDoubleLeg(0(DI),0(SP)) +#define sqrBmi2Adx \ + integerSqrAdx(0(SP),0(SI)) \ + reduceFromDoubleAdx(0(DI),0(SP)) + +// func addAmd64(z, x, y *Elt) +TEXT ·addAmd64(SB),NOSPLIT,$0-24 + MOVQ z+0(FP), DI + MOVQ x+8(FP), SI + MOVQ y+16(FP), BX + CHECK_BMI2ADX(LADD, addLegacy, addBmi2Adx) + +// func mulAmd64(z, x, y *Elt) +TEXT ·mulAmd64(SB),NOSPLIT,$112-24 + MOVQ z+0(FP), DI + MOVQ x+8(FP), SI + MOVQ y+16(FP), BX + CHECK_BMI2ADX(LMUL, mulLegacy, mulBmi2Adx) + +// func sqrAmd64(z, x *Elt) +TEXT ·sqrAmd64(SB),NOSPLIT,$112-16 + MOVQ z+0(FP), DI + MOVQ x+8(FP), SI + CHECK_BMI2ADX(LSQR, sqrLegacy, sqrBmi2Adx) diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go b/vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go new file mode 100644 index 00000000..47a0b632 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_generic.go @@ -0,0 +1,339 @@ +package fp448 + +import ( + "encoding/binary" + "math/bits" +) + +func cmovGeneric(x, y *Elt, n uint) { + m := -uint64(n & 0x1) + x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8]) + x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8]) + x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8]) + x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8]) + x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8]) + x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8]) + x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8]) + + y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8]) + y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8]) + y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8]) + y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8]) + y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8]) + y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8]) + y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8]) + + x0 = (x0 &^ m) | (y0 & m) + x1 = (x1 &^ m) | (y1 & m) + x2 = (x2 &^ m) | (y2 & m) + x3 = (x3 &^ m) | (y3 & m) + x4 = (x4 &^ m) | (y4 & m) + x5 = (x5 &^ m) | (y5 & m) + x6 = (x6 &^ m) | (y6 & m) + + binary.LittleEndian.PutUint64(x[0*8:1*8], x0) + binary.LittleEndian.PutUint64(x[1*8:2*8], x1) + binary.LittleEndian.PutUint64(x[2*8:3*8], x2) + binary.LittleEndian.PutUint64(x[3*8:4*8], x3) + binary.LittleEndian.PutUint64(x[4*8:5*8], x4) + binary.LittleEndian.PutUint64(x[5*8:6*8], x5) + binary.LittleEndian.PutUint64(x[6*8:7*8], x6) +} + +func cswapGeneric(x, y *Elt, n uint) { + m := -uint64(n & 0x1) + x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8]) + x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8]) + x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8]) + x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8]) + x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8]) + x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8]) + x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8]) + + y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8]) + y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8]) + y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8]) + y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8]) + y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8]) + y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8]) + y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8]) + + t0 := m & (x0 ^ y0) + t1 := m & (x1 ^ y1) + t2 := m & (x2 ^ y2) + t3 := m & (x3 ^ y3) + t4 := m & (x4 ^ y4) + t5 := m & (x5 ^ y5) + t6 := m & (x6 ^ y6) + x0 ^= t0 + x1 ^= t1 + x2 ^= t2 + x3 ^= t3 + x4 ^= t4 + x5 ^= t5 + x6 ^= t6 + y0 ^= t0 + y1 ^= t1 + y2 ^= t2 + y3 ^= t3 + y4 ^= t4 + y5 ^= t5 + y6 ^= t6 + + binary.LittleEndian.PutUint64(x[0*8:1*8], x0) + binary.LittleEndian.PutUint64(x[1*8:2*8], x1) + binary.LittleEndian.PutUint64(x[2*8:3*8], x2) + binary.LittleEndian.PutUint64(x[3*8:4*8], x3) + binary.LittleEndian.PutUint64(x[4*8:5*8], x4) + binary.LittleEndian.PutUint64(x[5*8:6*8], x5) + binary.LittleEndian.PutUint64(x[6*8:7*8], x6) + + binary.LittleEndian.PutUint64(y[0*8:1*8], y0) + binary.LittleEndian.PutUint64(y[1*8:2*8], y1) + binary.LittleEndian.PutUint64(y[2*8:3*8], y2) + binary.LittleEndian.PutUint64(y[3*8:4*8], y3) + binary.LittleEndian.PutUint64(y[4*8:5*8], y4) + binary.LittleEndian.PutUint64(y[5*8:6*8], y5) + binary.LittleEndian.PutUint64(y[6*8:7*8], y6) +} + +func addGeneric(z, x, y *Elt) { + x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8]) + x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8]) + x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8]) + x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8]) + x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8]) + x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8]) + x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8]) + + y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8]) + y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8]) + y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8]) + y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8]) + y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8]) + y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8]) + y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8]) + + z0, c0 := bits.Add64(x0, y0, 0) + z1, c1 := bits.Add64(x1, y1, c0) + z2, c2 := bits.Add64(x2, y2, c1) + z3, c3 := bits.Add64(x3, y3, c2) + z4, c4 := bits.Add64(x4, y4, c3) + z5, c5 := bits.Add64(x5, y5, c4) + z6, z7 := bits.Add64(x6, y6, c5) + + z0, c0 = bits.Add64(z0, z7, 0) + z1, c1 = bits.Add64(z1, 0, c0) + z2, c2 = bits.Add64(z2, 0, c1) + z3, c3 = bits.Add64(z3, z7<<32, c2) + z4, c4 = bits.Add64(z4, 0, c3) + z5, c5 = bits.Add64(z5, 0, c4) + z6, z7 = bits.Add64(z6, 0, c5) + + z0, c0 = bits.Add64(z0, z7, 0) + z1, c1 = bits.Add64(z1, 0, c0) + z2, c2 = bits.Add64(z2, 0, c1) + z3, c3 = bits.Add64(z3, z7<<32, c2) + z4, c4 = bits.Add64(z4, 0, c3) + z5, c5 = bits.Add64(z5, 0, c4) + z6, _ = bits.Add64(z6, 0, c5) + + binary.LittleEndian.PutUint64(z[0*8:1*8], z0) + binary.LittleEndian.PutUint64(z[1*8:2*8], z1) + binary.LittleEndian.PutUint64(z[2*8:3*8], z2) + binary.LittleEndian.PutUint64(z[3*8:4*8], z3) + binary.LittleEndian.PutUint64(z[4*8:5*8], z4) + binary.LittleEndian.PutUint64(z[5*8:6*8], z5) + binary.LittleEndian.PutUint64(z[6*8:7*8], z6) +} + +func subGeneric(z, x, y *Elt) { + x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8]) + x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8]) + x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8]) + x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8]) + x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8]) + x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8]) + x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8]) + + y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8]) + y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8]) + y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8]) + y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8]) + y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8]) + y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8]) + y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8]) + + z0, c0 := bits.Sub64(x0, y0, 0) + z1, c1 := bits.Sub64(x1, y1, c0) + z2, c2 := bits.Sub64(x2, y2, c1) + z3, c3 := bits.Sub64(x3, y3, c2) + z4, c4 := bits.Sub64(x4, y4, c3) + z5, c5 := bits.Sub64(x5, y5, c4) + z6, z7 := bits.Sub64(x6, y6, c5) + + z0, c0 = bits.Sub64(z0, z7, 0) + z1, c1 = bits.Sub64(z1, 0, c0) + z2, c2 = bits.Sub64(z2, 0, c1) + z3, c3 = bits.Sub64(z3, z7<<32, c2) + z4, c4 = bits.Sub64(z4, 0, c3) + z5, c5 = bits.Sub64(z5, 0, c4) + z6, z7 = bits.Sub64(z6, 0, c5) + + z0, c0 = bits.Sub64(z0, z7, 0) + z1, c1 = bits.Sub64(z1, 0, c0) + z2, c2 = bits.Sub64(z2, 0, c1) + z3, c3 = bits.Sub64(z3, z7<<32, c2) + z4, c4 = bits.Sub64(z4, 0, c3) + z5, c5 = bits.Sub64(z5, 0, c4) + z6, _ = bits.Sub64(z6, 0, c5) + + binary.LittleEndian.PutUint64(z[0*8:1*8], z0) + binary.LittleEndian.PutUint64(z[1*8:2*8], z1) + binary.LittleEndian.PutUint64(z[2*8:3*8], z2) + binary.LittleEndian.PutUint64(z[3*8:4*8], z3) + binary.LittleEndian.PutUint64(z[4*8:5*8], z4) + binary.LittleEndian.PutUint64(z[5*8:6*8], z5) + binary.LittleEndian.PutUint64(z[6*8:7*8], z6) +} + +func addsubGeneric(x, y *Elt) { + z := &Elt{} + addGeneric(z, x, y) + subGeneric(y, x, y) + *x = *z +} + +func mulGeneric(z, x, y *Elt) { + x0 := binary.LittleEndian.Uint64(x[0*8 : 1*8]) + x1 := binary.LittleEndian.Uint64(x[1*8 : 2*8]) + x2 := binary.LittleEndian.Uint64(x[2*8 : 3*8]) + x3 := binary.LittleEndian.Uint64(x[3*8 : 4*8]) + x4 := binary.LittleEndian.Uint64(x[4*8 : 5*8]) + x5 := binary.LittleEndian.Uint64(x[5*8 : 6*8]) + x6 := binary.LittleEndian.Uint64(x[6*8 : 7*8]) + + y0 := binary.LittleEndian.Uint64(y[0*8 : 1*8]) + y1 := binary.LittleEndian.Uint64(y[1*8 : 2*8]) + y2 := binary.LittleEndian.Uint64(y[2*8 : 3*8]) + y3 := binary.LittleEndian.Uint64(y[3*8 : 4*8]) + y4 := binary.LittleEndian.Uint64(y[4*8 : 5*8]) + y5 := binary.LittleEndian.Uint64(y[5*8 : 6*8]) + y6 := binary.LittleEndian.Uint64(y[6*8 : 7*8]) + + yy := [7]uint64{y0, y1, y2, y3, y4, y5, y6} + zz := [7]uint64{} + + yi := yy[0] + h0, l0 := bits.Mul64(x0, yi) + h1, l1 := bits.Mul64(x1, yi) + h2, l2 := bits.Mul64(x2, yi) + h3, l3 := bits.Mul64(x3, yi) + h4, l4 := bits.Mul64(x4, yi) + h5, l5 := bits.Mul64(x5, yi) + h6, l6 := bits.Mul64(x6, yi) + + zz[0] = l0 + a0, c0 := bits.Add64(h0, l1, 0) + a1, c1 := bits.Add64(h1, l2, c0) + a2, c2 := bits.Add64(h2, l3, c1) + a3, c3 := bits.Add64(h3, l4, c2) + a4, c4 := bits.Add64(h4, l5, c3) + a5, c5 := bits.Add64(h5, l6, c4) + a6, _ := bits.Add64(h6, 0, c5) + + for i := 1; i < 7; i++ { + yi = yy[i] + h0, l0 = bits.Mul64(x0, yi) + h1, l1 = bits.Mul64(x1, yi) + h2, l2 = bits.Mul64(x2, yi) + h3, l3 = bits.Mul64(x3, yi) + h4, l4 = bits.Mul64(x4, yi) + h5, l5 = bits.Mul64(x5, yi) + h6, l6 = bits.Mul64(x6, yi) + + zz[i], c0 = bits.Add64(a0, l0, 0) + a0, c1 = bits.Add64(a1, l1, c0) + a1, c2 = bits.Add64(a2, l2, c1) + a2, c3 = bits.Add64(a3, l3, c2) + a3, c4 = bits.Add64(a4, l4, c3) + a4, c5 = bits.Add64(a5, l5, c4) + a5, a6 = bits.Add64(a6, l6, c5) + + a0, c0 = bits.Add64(a0, h0, 0) + a1, c1 = bits.Add64(a1, h1, c0) + a2, c2 = bits.Add64(a2, h2, c1) + a3, c3 = bits.Add64(a3, h3, c2) + a4, c4 = bits.Add64(a4, h4, c3) + a5, c5 = bits.Add64(a5, h5, c4) + a6, _ = bits.Add64(a6, h6, c5) + } + red64(z, &zz, &[7]uint64{a0, a1, a2, a3, a4, a5, a6}) +} + +func sqrGeneric(z, x *Elt) { mulGeneric(z, x, x) } + +func red64(z *Elt, l, h *[7]uint64) { + /* (2C13, 2C12, 2C11, 2C10|C10, C9, C8, C7) + (C6,...,C0) */ + h0 := h[0] + h1 := h[1] + h2 := h[2] + h3 := ((h[3] & (0xFFFFFFFF << 32)) << 1) | (h[3] & 0xFFFFFFFF) + h4 := (h[3] >> 63) | (h[4] << 1) + h5 := (h[4] >> 63) | (h[5] << 1) + h6 := (h[5] >> 63) | (h[6] << 1) + h7 := (h[6] >> 63) + + l0, c0 := bits.Add64(h0, l[0], 0) + l1, c1 := bits.Add64(h1, l[1], c0) + l2, c2 := bits.Add64(h2, l[2], c1) + l3, c3 := bits.Add64(h3, l[3], c2) + l4, c4 := bits.Add64(h4, l[4], c3) + l5, c5 := bits.Add64(h5, l[5], c4) + l6, c6 := bits.Add64(h6, l[6], c5) + l7, _ := bits.Add64(h7, 0, c6) + + /* (C10C9, C9C8,C8C7,C7C13,C13C12,C12C11,C11C10) + (C6,...,C0) */ + h0 = (h[3] >> 32) | (h[4] << 32) + h1 = (h[4] >> 32) | (h[5] << 32) + h2 = (h[5] >> 32) | (h[6] << 32) + h3 = (h[6] >> 32) | (h[0] << 32) + h4 = (h[0] >> 32) | (h[1] << 32) + h5 = (h[1] >> 32) | (h[2] << 32) + h6 = (h[2] >> 32) | (h[3] << 32) + + l0, c0 = bits.Add64(l0, h0, 0) + l1, c1 = bits.Add64(l1, h1, c0) + l2, c2 = bits.Add64(l2, h2, c1) + l3, c3 = bits.Add64(l3, h3, c2) + l4, c4 = bits.Add64(l4, h4, c3) + l5, c5 = bits.Add64(l5, h5, c4) + l6, c6 = bits.Add64(l6, h6, c5) + l7, _ = bits.Add64(l7, 0, c6) + + /* (C7) + (C6,...,C0) */ + l0, c0 = bits.Add64(l0, l7, 0) + l1, c1 = bits.Add64(l1, 0, c0) + l2, c2 = bits.Add64(l2, 0, c1) + l3, c3 = bits.Add64(l3, l7<<32, c2) + l4, c4 = bits.Add64(l4, 0, c3) + l5, c5 = bits.Add64(l5, 0, c4) + l6, l7 = bits.Add64(l6, 0, c5) + + /* (C7) + (C6,...,C0) */ + l0, c0 = bits.Add64(l0, l7, 0) + l1, c1 = bits.Add64(l1, 0, c0) + l2, c2 = bits.Add64(l2, 0, c1) + l3, c3 = bits.Add64(l3, l7<<32, c2) + l4, c4 = bits.Add64(l4, 0, c3) + l5, c5 = bits.Add64(l5, 0, c4) + l6, _ = bits.Add64(l6, 0, c5) + + binary.LittleEndian.PutUint64(z[0*8:1*8], l0) + binary.LittleEndian.PutUint64(z[1*8:2*8], l1) + binary.LittleEndian.PutUint64(z[2*8:3*8], l2) + binary.LittleEndian.PutUint64(z[3*8:4*8], l3) + binary.LittleEndian.PutUint64(z[4*8:5*8], l4) + binary.LittleEndian.PutUint64(z[5*8:6*8], l5) + binary.LittleEndian.PutUint64(z[6*8:7*8], l6) +} diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go b/vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go new file mode 100644 index 00000000..a62225d2 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp448/fp_noasm.go @@ -0,0 +1,12 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +package fp448 + +func cmov(x, y *Elt, n uint) { cmovGeneric(x, y, n) } +func cswap(x, y *Elt, n uint) { cswapGeneric(x, y, n) } +func add(z, x, y *Elt) { addGeneric(z, x, y) } +func sub(z, x, y *Elt) { subGeneric(z, x, y) } +func addsub(x, y *Elt) { addsubGeneric(x, y) } +func mul(z, x, y *Elt) { mulGeneric(z, x, y) } +func sqr(z, x *Elt) { sqrGeneric(z, x) } diff --git a/vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go b/vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go new file mode 100644 index 00000000..2d7afc80 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/fp448/fuzzer.go @@ -0,0 +1,75 @@ +//go:build gofuzz +// +build gofuzz + +// How to run the fuzzer: +// +// $ go get -u github.com/dvyukov/go-fuzz/go-fuzz +// $ go get -u github.com/dvyukov/go-fuzz/go-fuzz-build +// $ go-fuzz-build -libfuzzer -func FuzzReduction -o lib.a +// $ clang -fsanitize=fuzzer lib.a -o fu.exe +// $ ./fu.exe +package fp448 + +import ( + "encoding/binary" + "fmt" + "math/big" + + "github.com/cloudflare/circl/internal/conv" +) + +// FuzzReduction is a fuzzer target for red64 function, which reduces t +// (112 bits) to a number t' (56 bits) congruent modulo p448. +func FuzzReduction(data []byte) int { + if len(data) != 2*Size { + return -1 + } + var got, want Elt + var lo, hi [7]uint64 + a := data[:Size] + b := data[Size:] + lo[0] = binary.LittleEndian.Uint64(a[0*8 : 1*8]) + lo[1] = binary.LittleEndian.Uint64(a[1*8 : 2*8]) + lo[2] = binary.LittleEndian.Uint64(a[2*8 : 3*8]) + lo[3] = binary.LittleEndian.Uint64(a[3*8 : 4*8]) + lo[4] = binary.LittleEndian.Uint64(a[4*8 : 5*8]) + lo[5] = binary.LittleEndian.Uint64(a[5*8 : 6*8]) + lo[6] = binary.LittleEndian.Uint64(a[6*8 : 7*8]) + + hi[0] = binary.LittleEndian.Uint64(b[0*8 : 1*8]) + hi[1] = binary.LittleEndian.Uint64(b[1*8 : 2*8]) + hi[2] = binary.LittleEndian.Uint64(b[2*8 : 3*8]) + hi[3] = binary.LittleEndian.Uint64(b[3*8 : 4*8]) + hi[4] = binary.LittleEndian.Uint64(b[4*8 : 5*8]) + hi[5] = binary.LittleEndian.Uint64(b[5*8 : 6*8]) + hi[6] = binary.LittleEndian.Uint64(b[6*8 : 7*8]) + + red64(&got, &lo, &hi) + + t := conv.BytesLe2BigInt(data[:2*Size]) + + two448 := big.NewInt(1) + two448.Lsh(two448, 448) // 2^448 + mask448 := big.NewInt(1) + mask448.Sub(two448, mask448) // 2^448-1 + two224plus1 := big.NewInt(1) + two224plus1.Lsh(two224plus1, 224) + two224plus1.Add(two224plus1, big.NewInt(1)) // 2^224+1 + + var loBig, hiBig big.Int + for t.Cmp(two448) >= 0 { + loBig.And(t, mask448) + hiBig.Rsh(t, 448) + t.Mul(&hiBig, two224plus1) + t.Add(t, &loBig) + } + conv.BigInt2BytesLe(want[:], t) + + if got != want { + fmt.Printf("in: %v\n", conv.BytesLe2BigInt(data[:2*Size])) + fmt.Printf("got: %v\n", got) + fmt.Printf("want: %v\n", want) + panic("error found") + } + return 1 +} diff --git a/vendor/github.com/cloudflare/circl/math/integer.go b/vendor/github.com/cloudflare/circl/math/integer.go new file mode 100644 index 00000000..9c80c23b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/integer.go @@ -0,0 +1,16 @@ +package math + +import "math/bits" + +// NextPow2 finds the next power of two (N=2^k, k>=0) greater than n. +// If n is already a power of two, then this function returns n, and log2(n). +func NextPow2(n uint) (N uint, k uint) { + if bits.OnesCount(n) == 1 { + k = uint(bits.TrailingZeros(n)) + N = n + } else { + k = uint(bits.Len(n)) + N = uint(1) << k + } + return +} diff --git a/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go b/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go new file mode 100644 index 00000000..a43851b8 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go @@ -0,0 +1,122 @@ +// Package mlsbset provides a constant-time exponentiation method with precomputation. +// +// References: "Efficient and secure algorithms for GLV-based scalar +// multiplication and their implementation on GLV–GLS curves" by (Faz-Hernandez et al.) +// - https://doi.org/10.1007/s13389-014-0085-7 +// - https://eprint.iacr.org/2013/158 +package mlsbset + +import ( + "errors" + "fmt" + "math/big" + + "github.com/cloudflare/circl/internal/conv" +) + +// EltG is a group element. +type EltG interface{} + +// EltP is a precomputed group element. +type EltP interface{} + +// Group defines the operations required by MLSBSet exponentiation method. +type Group interface { + Identity() EltG // Returns the identity of the group. + Sqr(x EltG) // Calculates x = x^2. + Mul(x EltG, y EltP) // Calculates x = x*y. + NewEltP() EltP // Returns an arbitrary precomputed element. + ExtendedEltP() EltP // Returns the precomputed element x^(2^(w*d)). + Lookup(a EltP, v uint, s, u int32) // Sets a = s*T[v][u]. +} + +// Params contains the parameters of the encoding. +type Params struct { + T uint // T is the maximum size (in bits) of exponents. + V uint // V is the number of tables. + W uint // W is the window size. + E uint // E is the number of digits per table. + D uint // D is the number of digits in total. + L uint // L is the length of the code. +} + +// Encoder allows to convert integers into valid powers. +type Encoder struct{ p Params } + +// New produces an encoder of the MLSBSet algorithm. +func New(t, v, w uint) (Encoder, error) { + if !(t > 1 && v >= 1 && w >= 2) { + return Encoder{}, errors.New("t>1, v>=1, w>=2") + } + e := (t + w*v - 1) / (w * v) + d := e * v + l := d * w + return Encoder{Params{t, v, w, e, d, l}}, nil +} + +// Encode converts an odd integer k into a valid power for exponentiation. +func (m Encoder) Encode(k []byte) (*Power, error) { + if len(k) == 0 { + return nil, errors.New("empty slice") + } + if !(len(k) <= int(m.p.L+7)>>3) { + return nil, errors.New("k too big") + } + if k[0]%2 == 0 { + return nil, errors.New("k must be odd") + } + ap := int((m.p.L+7)/8) - len(k) + k = append(k, make([]byte, ap)...) + s := m.signs(k) + b := make([]int32, m.p.L-m.p.D) + c := conv.BytesLe2BigInt(k) + c.Rsh(c, m.p.D) + var bi big.Int + for i := m.p.D; i < m.p.L; i++ { + c0 := int32(c.Bit(0)) + b[i-m.p.D] = s[i%m.p.D] * c0 + bi.SetInt64(int64(b[i-m.p.D] >> 1)) + c.Rsh(c, 1) + c.Sub(c, &bi) + } + carry := int(c.Int64()) + return &Power{m, s, b, carry}, nil +} + +// signs calculates the set of signs. +func (m Encoder) signs(k []byte) []int32 { + s := make([]int32, m.p.D) + s[m.p.D-1] = 1 + for i := uint(1); i < m.p.D; i++ { + ki := int32((k[i>>3] >> (i & 0x7)) & 0x1) + s[i-1] = 2*ki - 1 + } + return s +} + +// GetParams returns the complementary parameters of the encoding. +func (m Encoder) GetParams() Params { return m.p } + +// tableSize returns the size of each table. +func (m Encoder) tableSize() uint { return 1 << (m.p.W - 1) } + +// Elts returns the total number of elements that must be precomputed. +func (m Encoder) Elts() uint { return m.p.V * m.tableSize() } + +// IsExtended returns true if the element x^(2^(wd)) must be calculated. +func (m Encoder) IsExtended() bool { q := m.p.T / (m.p.V * m.p.W); return m.p.T == q*m.p.V*m.p.W } + +// Ops returns the number of squares and multiplications executed during an exponentiation. +func (m Encoder) Ops() (S uint, M uint) { + S = m.p.E + M = m.p.E * m.p.V + if m.IsExtended() { + M++ + } + return +} + +func (m Encoder) String() string { + return fmt.Sprintf("T: %v W: %v V: %v e: %v d: %v l: %v wv|t: %v", + m.p.T, m.p.W, m.p.V, m.p.E, m.p.D, m.p.L, m.IsExtended()) +} diff --git a/vendor/github.com/cloudflare/circl/math/mlsbset/power.go b/vendor/github.com/cloudflare/circl/math/mlsbset/power.go new file mode 100644 index 00000000..3f214c30 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/mlsbset/power.go @@ -0,0 +1,64 @@ +package mlsbset + +import "fmt" + +// Power is a valid exponent produced by the MLSBSet encoding algorithm. +type Power struct { + set Encoder // parameters of code. + s []int32 // set of signs. + b []int32 // set of digits. + c int // carry is {0,1}. +} + +// Exp is calculates x^k, where x is a predetermined element of a group G. +func (p *Power) Exp(G Group) EltG { + a, b := G.Identity(), G.NewEltP() + for e := int(p.set.p.E - 1); e >= 0; e-- { + G.Sqr(a) + for v := uint(0); v < p.set.p.V; v++ { + sgnElt, idElt := p.Digit(v, uint(e)) + G.Lookup(b, v, sgnElt, idElt) + G.Mul(a, b) + } + } + if p.set.IsExtended() && p.c == 1 { + G.Mul(a, G.ExtendedEltP()) + } + return a +} + +// Digit returns the (v,e)-th digit and its sign. +func (p *Power) Digit(v, e uint) (sgn, dig int32) { + sgn = p.bit(0, v, e) + dig = 0 + for i := p.set.p.W - 1; i > 0; i-- { + dig = 2*dig + p.bit(i, v, e) + } + mask := dig >> 31 + dig = (dig + mask) ^ mask + return sgn, dig +} + +// bit returns the (w,v,e)-th bit of the code. +func (p *Power) bit(w, v, e uint) int32 { + if !(w < p.set.p.W && + v < p.set.p.V && + e < p.set.p.E) { + panic(fmt.Errorf("indexes outside (%v,%v,%v)", w, v, e)) + } + if w == 0 { + return p.s[p.set.p.E*v+e] + } + return p.b[p.set.p.D*(w-1)+p.set.p.E*v+e] +} + +func (p *Power) String() string { + dig := "" + for j := uint(0); j < p.set.p.V; j++ { + for i := uint(0); i < p.set.p.E; i++ { + s, d := p.Digit(j, i) + dig += fmt.Sprintf("(%2v,%2v) = %+2v %+2v\n", j, i, s, d) + } + } + return fmt.Sprintf("len: %v\ncarry: %v\ndigits:\n%v", len(p.b)+len(p.s), p.c, dig) +} diff --git a/vendor/github.com/cloudflare/circl/math/primes.go b/vendor/github.com/cloudflare/circl/math/primes.go new file mode 100644 index 00000000..158fd83a --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/primes.go @@ -0,0 +1,34 @@ +package math + +import ( + "crypto/rand" + "io" + "math/big" +) + +// IsSafePrime reports whether p is (probably) a safe prime. +// The prime p=2*q+1 is safe prime if both p and q are primes. +// Note that ProbablyPrime is not suitable for judging primes +// that an adversary may have crafted to fool the test. +func IsSafePrime(p *big.Int) bool { + pdiv2 := new(big.Int).Rsh(p, 1) + return p.ProbablyPrime(20) && pdiv2.ProbablyPrime(20) +} + +// SafePrime returns a number of the given bit length that is a safe prime with high probability. +// The number returned p=2*q+1 is a safe prime if both p and q are primes. +// SafePrime will return error for any error returned by rand.Read or if bits < 2. +func SafePrime(random io.Reader, bits int) (*big.Int, error) { + one := big.NewInt(1) + p := new(big.Int) + for { + q, err := rand.Prime(random, bits-1) + if err != nil { + return nil, err + } + p.Lsh(q, 1).Add(p, one) + if p.ProbablyPrime(20) { + return p, nil + } + } +} diff --git a/vendor/github.com/cloudflare/circl/math/wnaf.go b/vendor/github.com/cloudflare/circl/math/wnaf.go new file mode 100644 index 00000000..94a1ec50 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/wnaf.go @@ -0,0 +1,84 @@ +// Package math provides some utility functions for big integers. +package math + +import "math/big" + +// SignedDigit obtains the signed-digit recoding of n and returns a list L of +// digits such that n = sum( L[i]*2^(i*(w-1)) ), and each L[i] is an odd number +// in the set {±1, ±3, ..., ±2^(w-1)-1}. The third parameter ensures that the +// output has ceil(l/(w-1)) digits. +// +// Restrictions: +// - n is odd and n > 0. +// - 1 < w < 32. +// - l >= bit length of n. +// +// References: +// - Alg.6 in "Exponent Recoding and Regular Exponentiation Algorithms" +// by Joye-Tunstall. http://doi.org/10.1007/978-3-642-02384-2_21 +// - Alg.6 in "Selecting Elliptic Curves for Cryptography: An Efficiency and +// Security Analysis" by Bos et al. http://doi.org/10.1007/s13389-015-0097-y +func SignedDigit(n *big.Int, w, l uint) []int32 { + if n.Sign() <= 0 || n.Bit(0) == 0 { + panic("n must be non-zero, odd, and positive") + } + if w <= 1 || w >= 32 { + panic("Verify that 1 < w < 32") + } + if uint(n.BitLen()) > l { + panic("n is too big to fit in l digits") + } + lenN := (l + (w - 1) - 1) / (w - 1) // ceil(l/(w-1)) + L := make([]int32, lenN+1) + var k, v big.Int + k.Set(n) + + var i uint + for i = 0; i < lenN; i++ { + words := k.Bits() + value := int32(words[0] & ((1 << w) - 1)) + value -= int32(1) << (w - 1) + L[i] = value + v.SetInt64(int64(value)) + k.Sub(&k, &v) + k.Rsh(&k, w-1) + } + L[i] = int32(k.Int64()) + return L +} + +// OmegaNAF obtains the window-w Non-Adjacent Form of a positive number n and +// 1 < w < 32. The returned slice L holds n = sum( L[i]*2^i ). +// +// Reference: +// - Alg.9 "Efficient arithmetic on Koblitz curves" by Solinas. +// http://doi.org/10.1023/A:1008306223194 +func OmegaNAF(n *big.Int, w uint) (L []int32) { + if n.Sign() < 0 { + panic("n must be positive") + } + if w <= 1 || w >= 32 { + panic("Verify that 1 < w < 32") + } + + L = make([]int32, n.BitLen()+1) + var k, v big.Int + k.Set(n) + + i := 0 + for ; k.Sign() > 0; i++ { + value := int32(0) + if k.Bit(0) == 1 { + words := k.Bits() + value = int32(words[0] & ((1 << w) - 1)) + if value >= (int32(1) << (w - 1)) { + value -= int32(1) << w + } + v.SetInt64(int64(value)) + k.Sub(&k, &v) + } + L[i] = value + k.Rsh(&k, 1) + } + return L[:i] +} diff --git a/vendor/github.com/cloudflare/circl/pki/pki.go b/vendor/github.com/cloudflare/circl/pki/pki.go new file mode 100644 index 00000000..a2edebdb --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pki/pki.go @@ -0,0 +1,182 @@ +package pki + +import ( + "crypto/x509/pkix" + "encoding/asn1" + "encoding/pem" + "errors" + "strings" + + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/schemes" +) + +var ( + allSchemesByOID map[string]sign.Scheme + allSchemesByTLS map[uint]sign.Scheme +) + +type pkixPrivKey struct { + Version int + Algorithm pkix.AlgorithmIdentifier + PrivateKey []byte +} + +func init() { + allSchemesByOID = make(map[string]sign.Scheme) + allSchemesByTLS = make(map[uint]sign.Scheme) + for _, scheme := range schemes.All() { + if cert, ok := scheme.(CertificateScheme); ok { + allSchemesByOID[cert.Oid().String()] = scheme + } + if tlsScheme, ok := scheme.(TLSScheme); ok { + allSchemesByTLS[tlsScheme.TLSIdentifier()] = scheme + } + } +} + +func SchemeByOid(oid asn1.ObjectIdentifier) sign.Scheme { return allSchemesByOID[oid.String()] } + +func SchemeByTLSID(id uint) sign.Scheme { return allSchemesByTLS[id] } + +// Additional methods when the signature scheme is supported in X509. +type CertificateScheme interface { + // Return the appropriate OIDs for this instance. It is implicitly + // assumed that the encoding is simple: e.g. uses the same OID for + // signature and public key like Ed25519. + Oid() asn1.ObjectIdentifier +} + +// Additional methods when the signature scheme is supported in TLS. +type TLSScheme interface { + TLSIdentifier() uint +} + +func UnmarshalPEMPublicKey(data []byte) (sign.PublicKey, error) { + block, rest := pem.Decode(data) + if len(rest) != 0 { + return nil, errors.New("trailing data") + } + if !strings.HasSuffix(block.Type, "PUBLIC KEY") { + return nil, errors.New("pem block type is not public key") + } + + return UnmarshalPKIXPublicKey(block.Bytes) +} + +func UnmarshalPKIXPublicKey(data []byte) (sign.PublicKey, error) { + var pkix struct { + Raw asn1.RawContent + Algorithm pkix.AlgorithmIdentifier + PublicKey asn1.BitString + } + if rest, err := asn1.Unmarshal(data, &pkix); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("trailing data") + } + scheme := SchemeByOid(pkix.Algorithm.Algorithm) + if scheme == nil { + return nil, errors.New("unsupported public key algorithm") + } + return scheme.UnmarshalBinaryPublicKey(pkix.PublicKey.RightAlign()) +} + +func UnmarshalPEMPrivateKey(data []byte) (sign.PrivateKey, error) { + block, rest := pem.Decode(data) + if len(rest) != 0 { + return nil, errors.New("trailing") + } + if !strings.HasSuffix(block.Type, "PRIVATE KEY") { + return nil, errors.New("pem block type is not private key") + } + + return UnmarshalPKIXPrivateKey(block.Bytes) +} + +func UnmarshalPKIXPrivateKey(data []byte) (sign.PrivateKey, error) { + var pkix pkixPrivKey + if rest, err := asn1.Unmarshal(data, &pkix); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("trailing data") + } + scheme := SchemeByOid(pkix.Algorithm.Algorithm) + if scheme == nil { + return nil, errors.New("unsupported public key algorithm") + } + var sk []byte + if rest, err := asn1.Unmarshal(pkix.PrivateKey, &sk); err != nil { + return nil, err + } else if len(rest) > 0 { + return nil, errors.New("trailing data") + } + return scheme.UnmarshalBinaryPrivateKey(sk) +} + +func MarshalPEMPublicKey(pk sign.PublicKey) ([]byte, error) { + data, err := MarshalPKIXPublicKey(pk) + if err != nil { + return nil, err + } + str := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: data, + }) + return str, nil +} + +func MarshalPKIXPublicKey(pk sign.PublicKey) ([]byte, error) { + data, err := pk.MarshalBinary() + if err != nil { + return nil, err + } + + scheme := pk.Scheme() + return asn1.Marshal(struct { + pkix.AlgorithmIdentifier + asn1.BitString + }{ + pkix.AlgorithmIdentifier{ + Algorithm: scheme.(CertificateScheme).Oid(), + }, + asn1.BitString{ + Bytes: data, + BitLength: len(data) * 8, + }, + }) +} + +func MarshalPEMPrivateKey(sk sign.PrivateKey) ([]byte, error) { + data, err := MarshalPKIXPrivateKey(sk) + if err != nil { + return nil, err + } + str := pem.EncodeToMemory(&pem.Block{ + Type: sk.Scheme().Name() + " PRIVATE KEY", + Bytes: data, + }, + ) + return str, nil +} + +func MarshalPKIXPrivateKey(sk sign.PrivateKey) ([]byte, error) { + data, err := sk.MarshalBinary() + if err != nil { + return nil, err + } + + data, err = asn1.Marshal(data) + if err != nil { + return nil, err + } + + scheme := sk.Scheme() + return asn1.Marshal(pkixPrivKey{ + 0, + pkix.AlgorithmIdentifier{ + Algorithm: scheme.(CertificateScheme).Oid(), + }, + data, + }) +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/dilithium.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/dilithium.go new file mode 100644 index 00000000..5e693895 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/dilithium.go @@ -0,0 +1,295 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mode2 implements the CRYSTALS-Dilithium signature scheme Dilithium2 +// as submitted to round3 of the NIST PQC competition and described in +// +// https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf +package mode2 + +import ( + "crypto" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/dilithium/mode2/internal" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of Dilithium2 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of Dilithium2 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +func SignTo(sk *PrivateKey, msg, sig []byte) { + var rnd [32]byte + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + w.Write(msg) + }, + rnd, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +func Verify(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mode2.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mode2.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + SignTo(sk, msg, ret[:]) + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for Dilithium2. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "Dilithium2" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() + +func (*scheme) SupportsContext() bool { + return false +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + SignTo(priv, msg, sig) + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, msg, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/dilithium.go new file mode 100644 index 00000000..8f1c8e5c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/dilithium.go @@ -0,0 +1,491 @@ +// Code generated from mode3/internal/dilithium.go by gen.go + +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr *[TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + if len(buf) < SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + pk.tr = new([TRSize]byte) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = &sk.tr + + return &pk, &sk +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: &sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/mat.go new file mode 100644 index 00000000..ceaf634f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/mat.go @@ -0,0 +1,59 @@ +// Code generated from mode3/internal/mat.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/pack.go new file mode 100644 index 00000000..1854b419 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/pack.go @@ -0,0 +1,270 @@ +// Code generated from mode3/internal/pack.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/params.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/params.go new file mode 100644 index 00000000..c3341f6d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "Dilithium2" + K = 4 + L = 4 + Eta = 2 + DoubleEtaBits = 3 + Omega = 80 + Tau = 39 + Gamma1Bits = 17 + Gamma2 = 95232 + NIST = false + TRSize = 32 + CTildeSize = 32 +) diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/rounding.go new file mode 100644 index 00000000..58123c09 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/rounding.go @@ -0,0 +1,142 @@ +// Code generated from mode3/internal/rounding.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/sample.go new file mode 100644 index 00000000..b37370a4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/sample.go @@ -0,0 +1,339 @@ +// Code generated from mode3/internal/sample.go by gen.go + +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/vec.go new file mode 100644 index 00000000..d07d3b24 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode2/internal/vec.go @@ -0,0 +1,281 @@ +// Code generated from mode3/internal/vec.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/dilithium.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/dilithium.go new file mode 100644 index 00000000..5a335612 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/dilithium.go @@ -0,0 +1,295 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mode3 implements the CRYSTALS-Dilithium signature scheme Dilithium3 +// as submitted to round3 of the NIST PQC competition and described in +// +// https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf +package mode3 + +import ( + "crypto" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/dilithium/mode3/internal" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of Dilithium3 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of Dilithium3 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +func SignTo(sk *PrivateKey, msg, sig []byte) { + var rnd [32]byte + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + w.Write(msg) + }, + rnd, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +func Verify(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mode3.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mode3.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + SignTo(sk, msg, ret[:]) + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for Dilithium3. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "Dilithium3" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() + +func (*scheme) SupportsContext() bool { + return false +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + SignTo(priv, msg, sig) + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, msg, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/dilithium.go new file mode 100644 index 00000000..0f9b76da --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/dilithium.go @@ -0,0 +1,489 @@ +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr *[TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + if len(buf) < SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + pk.tr = new([TRSize]byte) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = &sk.tr + + return &pk, &sk +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: &sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/mat.go new file mode 100644 index 00000000..3d6cc47b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/mat.go @@ -0,0 +1,57 @@ +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/pack.go new file mode 100644 index 00000000..d9c80d0e --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/pack.go @@ -0,0 +1,268 @@ +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/params.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/params.go new file mode 100644 index 00000000..5aa596d1 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "Dilithium3" + K = 6 + L = 5 + Eta = 4 + DoubleEtaBits = 4 + Omega = 55 + Tau = 49 + Gamma1Bits = 19 + Gamma2 = 261888 + NIST = false + TRSize = 32 + CTildeSize = 32 +) diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/rounding.go new file mode 100644 index 00000000..4005e569 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/rounding.go @@ -0,0 +1,140 @@ +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/sample.go new file mode 100644 index 00000000..f90d211d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/sample.go @@ -0,0 +1,337 @@ +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/vec.go new file mode 100644 index 00000000..5817acb7 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode3/internal/vec.go @@ -0,0 +1,279 @@ +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/dilithium.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/dilithium.go new file mode 100644 index 00000000..3058692e --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/dilithium.go @@ -0,0 +1,295 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mode5 implements the CRYSTALS-Dilithium signature scheme Dilithium5 +// as submitted to round3 of the NIST PQC competition and described in +// +// https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf +package mode5 + +import ( + "crypto" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/dilithium/mode5/internal" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of Dilithium5 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of Dilithium5 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +func SignTo(sk *PrivateKey, msg, sig []byte) { + var rnd [32]byte + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + w.Write(msg) + }, + rnd, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +func Verify(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mode5.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mode5.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + SignTo(sk, msg, ret[:]) + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for Dilithium5. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "Dilithium5" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() + +func (*scheme) SupportsContext() bool { + return false +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + SignTo(priv, msg, sig) + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, msg, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/dilithium.go new file mode 100644 index 00000000..8f1c8e5c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/dilithium.go @@ -0,0 +1,491 @@ +// Code generated from mode3/internal/dilithium.go by gen.go + +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr *[TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + if len(buf) < SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + pk.tr = new([TRSize]byte) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = &sk.tr + + return &pk, &sk +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: &sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/mat.go new file mode 100644 index 00000000..ceaf634f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/mat.go @@ -0,0 +1,59 @@ +// Code generated from mode3/internal/mat.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/pack.go new file mode 100644 index 00000000..1854b419 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/pack.go @@ -0,0 +1,270 @@ +// Code generated from mode3/internal/pack.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/params.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/params.go new file mode 100644 index 00000000..6f65f033 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "Dilithium5" + K = 8 + L = 7 + Eta = 2 + DoubleEtaBits = 3 + Omega = 75 + Tau = 60 + Gamma1Bits = 19 + Gamma2 = 261888 + NIST = false + TRSize = 32 + CTildeSize = 32 +) diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/rounding.go new file mode 100644 index 00000000..58123c09 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/rounding.go @@ -0,0 +1,142 @@ +// Code generated from mode3/internal/rounding.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/sample.go new file mode 100644 index 00000000..b37370a4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/sample.go @@ -0,0 +1,339 @@ +// Code generated from mode3/internal/sample.go by gen.go + +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/vec.go new file mode 100644 index 00000000..d07d3b24 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/dilithium/mode5/internal/vec.go @@ -0,0 +1,281 @@ +// Code generated from mode3/internal/vec.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go new file mode 100644 index 00000000..2c73c26f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go @@ -0,0 +1,453 @@ +// Package ed25519 implements Ed25519 signature scheme as described in RFC-8032. +// +// This package provides optimized implementations of the three signature +// variants and maintaining closer compatibility with crypto/ed25519. +// +// | Scheme Name | Sign Function | Verification | Context | +// |-------------|-------------------|---------------|-------------------| +// | Ed25519 | Sign | Verify | None | +// | Ed25519Ph | SignPh | VerifyPh | Yes, can be empty | +// | Ed25519Ctx | SignWithCtx | VerifyWithCtx | Yes, non-empty | +// | All above | (PrivateKey).Sign | VerifyAny | As above | +// +// Specific functions for sign and verify are defined. A generic signing +// function for all schemes is available through the crypto.Signer interface, +// which is implemented by the PrivateKey type. A correspond all-in-one +// verification method is provided by the VerifyAny function. +// +// Signing with Ed25519Ph or Ed25519Ctx requires a context string for domain +// separation. This parameter is passed using a SignerOptions struct defined +// in this package. While Ed25519Ph accepts an empty context, Ed25519Ctx +// enforces non-empty context strings. +// +// # Compatibility with crypto.ed25519 +// +// These functions are compatible with the “Ed25519” function defined in +// RFC-8032. However, unlike RFC 8032's formulation, this package's private +// key representation includes a public key suffix to make multiple signing +// operations with the same key more efficient. This package refers to the +// RFC-8032 private key as the “seed”. +// +// References +// +// - RFC-8032: https://rfc-editor.org/rfc/rfc8032.txt +// - Ed25519: https://ed25519.cr.yp.to/ +// - EdDSA: High-speed high-security signatures. https://doi.org/10.1007/s13389-012-0027-1 +package ed25519 + +import ( + "bytes" + "crypto" + cryptoRand "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "fmt" + "io" + "strconv" + + "github.com/cloudflare/circl/sign" +) + +const ( + // ContextMaxSize is the maximum length (in bytes) allowed for context. + ContextMaxSize = 255 + // PublicKeySize is the size, in bytes, of public keys as used in this package. + PublicKeySize = 32 + // PrivateKeySize is the size, in bytes, of private keys as used in this package. + PrivateKeySize = 64 + // SignatureSize is the size, in bytes, of signatures generated and verified by this package. + SignatureSize = 64 + // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. + SeedSize = 32 +) + +const ( + paramB = 256 / 8 // Size of keys in bytes. +) + +// SignerOptions implements crypto.SignerOpts and augments with parameters +// that are specific to the Ed25519 signature schemes. +type SignerOptions struct { + // Hash must be crypto.Hash(0) for Ed25519/Ed25519ctx, or crypto.SHA512 + // for Ed25519ph. + crypto.Hash + + // Context is an optional domain separation string for Ed25519ph and a + // must for Ed25519ctx. Its length must be less or equal than 255 bytes. + Context string + + // Scheme is an identifier for choosing a signature scheme. The zero value + // is ED25519. + Scheme SchemeID +} + +// SchemeID is an identifier for each signature scheme. +type SchemeID uint + +const ( + ED25519 SchemeID = iota + ED25519Ph + ED25519Ctx +) + +// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. +type PrivateKey []byte + +// Equal reports whether priv and x have the same value. +func (priv PrivateKey) Equal(x crypto.PrivateKey) bool { + xx, ok := x.(PrivateKey) + return ok && subtle.ConstantTimeCompare(priv, xx) == 1 +} + +// Public returns the PublicKey corresponding to priv. +func (priv PrivateKey) Public() crypto.PublicKey { + publicKey := make(PublicKey, PublicKeySize) + copy(publicKey, priv[SeedSize:]) + return publicKey +} + +// Seed returns the private key seed corresponding to priv. It is provided for +// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds +// in this package. +func (priv PrivateKey) Seed() []byte { + seed := make([]byte, SeedSize) + copy(seed, priv[:SeedSize]) + return seed +} + +func (priv PrivateKey) Scheme() sign.Scheme { return sch } + +func (pub PublicKey) Scheme() sign.Scheme { return sch } + +func (priv PrivateKey) MarshalBinary() (data []byte, err error) { + privateKey := make(PrivateKey, PrivateKeySize) + copy(privateKey, priv) + return privateKey, nil +} + +func (pub PublicKey) MarshalBinary() (data []byte, err error) { + publicKey := make(PublicKey, PublicKeySize) + copy(publicKey, pub) + return publicKey, nil +} + +// Equal reports whether pub and x have the same value. +func (pub PublicKey) Equal(x crypto.PublicKey) bool { + xx, ok := x.(PublicKey) + return ok && bytes.Equal(pub, xx) +} + +// Sign creates a signature of a message with priv key. +// This function is compatible with crypto.ed25519 and also supports the +// three signature variants defined in RFC-8032, namely Ed25519 (or pure +// EdDSA), Ed25519Ph, and Ed25519Ctx. +// The opts.HashFunc() must return zero to specify either Ed25519 or Ed25519Ctx +// variant. This can be achieved by passing crypto.Hash(0) as the value for +// opts. +// The opts.HashFunc() must return SHA512 to specify the Ed25519Ph variant. +// This can be achieved by passing crypto.SHA512 as the value for opts. +// Use a SignerOptions struct (defined in this package) to pass a context +// string for signing. +func (priv PrivateKey) Sign( + rand io.Reader, + message []byte, + opts crypto.SignerOpts, +) (signature []byte, err error) { + var ctx string + var scheme SchemeID + if o, ok := opts.(SignerOptions); ok { + ctx = o.Context + scheme = o.Scheme + } + + switch true { + case scheme == ED25519 && opts.HashFunc() == crypto.Hash(0): + return Sign(priv, message), nil + case scheme == ED25519Ph && opts.HashFunc() == crypto.SHA512: + return SignPh(priv, message, ctx), nil + case scheme == ED25519Ctx && opts.HashFunc() == crypto.Hash(0) && len(ctx) > 0: + return SignWithCtx(priv, message, ctx), nil + default: + return nil, errors.New("ed25519: bad hash algorithm") + } +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { + if rand == nil { + rand = cryptoRand.Reader + } + + seed := make([]byte, SeedSize) + if _, err := io.ReadFull(rand, seed); err != nil { + return nil, nil, err + } + + privateKey := NewKeyFromSeed(seed) + publicKey := make(PublicKey, PublicKeySize) + copy(publicKey, privateKey[SeedSize:]) + + return publicKey, privateKey, nil +} + +// NewKeyFromSeed calculates a private key from a seed. It will panic if +// len(seed) is not SeedSize. This function is provided for interoperability +// with RFC 8032. RFC 8032's private keys correspond to seeds in this +// package. +func NewKeyFromSeed(seed []byte) PrivateKey { + privateKey := make(PrivateKey, PrivateKeySize) + newKeyFromSeed(privateKey, seed) + return privateKey +} + +func newKeyFromSeed(privateKey, seed []byte) { + if l := len(seed); l != SeedSize { + panic("ed25519: bad seed length: " + strconv.Itoa(l)) + } + var P pointR1 + k := sha512.Sum512(seed) + clamp(k[:]) + reduceModOrder(k[:paramB], false) + P.fixedMult(k[:paramB]) + copy(privateKey[:SeedSize], seed) + _ = P.ToBytes(privateKey[SeedSize:]) +} + +func signAll(signature []byte, privateKey PrivateKey, message, ctx []byte, preHash bool) { + if l := len(privateKey); l != PrivateKeySize { + panic("ed25519: bad private key length: " + strconv.Itoa(l)) + } + + H := sha512.New() + var PHM []byte + + if preHash { + _, _ = H.Write(message) + PHM = H.Sum(nil) + H.Reset() + } else { + PHM = message + } + + // 1. Hash the 32-byte private key using SHA-512. + _, _ = H.Write(privateKey[:SeedSize]) + h := H.Sum(nil) + clamp(h[:]) + prefix, s := h[paramB:], h[:paramB] + + // 2. Compute SHA-512(dom2(F, C) || prefix || PH(M)) + H.Reset() + + writeDom(H, ctx, preHash) + + _, _ = H.Write(prefix) + _, _ = H.Write(PHM) + r := H.Sum(nil) + reduceModOrder(r[:], true) + + // 3. Compute the point [r]B. + var P pointR1 + P.fixedMult(r[:paramB]) + R := (&[paramB]byte{})[:] + if err := P.ToBytes(R); err != nil { + panic(err) + } + + // 4. Compute SHA512(dom2(F, C) || R || A || PH(M)). + H.Reset() + + writeDom(H, ctx, preHash) + + _, _ = H.Write(R) + _, _ = H.Write(privateKey[SeedSize:]) + _, _ = H.Write(PHM) + hRAM := H.Sum(nil) + + reduceModOrder(hRAM[:], true) + + // 5. Compute S = (r + k * s) mod order. + S := (&[paramB]byte{})[:] + calculateS(S, r[:paramB], hRAM[:paramB], s) + + // 6. The signature is the concatenation of R and S. + copy(signature[:paramB], R[:]) + copy(signature[paramB:], S[:]) +} + +// Sign signs the message with privateKey and returns a signature. +// This function supports the signature variant defined in RFC-8032: Ed25519, +// also known as the pure version of EdDSA. +// It will panic if len(privateKey) is not PrivateKeySize. +func Sign(privateKey PrivateKey, message []byte) []byte { + signature := make([]byte, SignatureSize) + signAll(signature, privateKey, message, []byte(""), false) + return signature +} + +// SignPh creates a signature of a message with private key and context. +// This function supports the signature variant defined in RFC-8032: Ed25519ph, +// meaning it internally hashes the message using SHA-512, and optionally +// accepts a context string. +// It will panic if len(privateKey) is not PrivateKeySize. +// Context could be passed to this function, which length should be no more than +// ContextMaxSize=255. It can be empty. +func SignPh(privateKey PrivateKey, message []byte, ctx string) []byte { + if len(ctx) > ContextMaxSize { + panic(fmt.Errorf("ed25519: bad context length: %v", len(ctx))) + } + + signature := make([]byte, SignatureSize) + signAll(signature, privateKey, message, []byte(ctx), true) + return signature +} + +// SignWithCtx creates a signature of a message with private key and context. +// This function supports the signature variant defined in RFC-8032: Ed25519ctx, +// meaning it accepts a non-empty context string. +// It will panic if len(privateKey) is not PrivateKeySize. +// Context must be passed to this function, which length should be no more than +// ContextMaxSize=255 and cannot be empty. +func SignWithCtx(privateKey PrivateKey, message []byte, ctx string) []byte { + if len(ctx) == 0 || len(ctx) > ContextMaxSize { + panic(fmt.Errorf("ed25519: bad context length: %v > %v", len(ctx), ContextMaxSize)) + } + + signature := make([]byte, SignatureSize) + signAll(signature, privateKey, message, []byte(ctx), false) + return signature +} + +func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool { + if len(public) != PublicKeySize || + len(signature) != SignatureSize || + !isLessThanOrder(signature[paramB:]) { + return false + } + + var P pointR1 + if ok := P.FromBytes(public); !ok { + return false + } + + H := sha512.New() + var PHM []byte + + if preHash { + _, _ = H.Write(message) + PHM = H.Sum(nil) + H.Reset() + } else { + PHM = message + } + + R := signature[:paramB] + + writeDom(H, ctx, preHash) + + _, _ = H.Write(R) + _, _ = H.Write(public) + _, _ = H.Write(PHM) + hRAM := H.Sum(nil) + reduceModOrder(hRAM[:], true) + + var Q pointR1 + encR := (&[paramB]byte{})[:] + P.neg() + Q.doubleMult(&P, signature[paramB:], hRAM[:paramB]) + _ = Q.ToBytes(encR) + return bytes.Equal(R, encR) +} + +// VerifyAny returns true if the signature is valid. Failure cases are invalid +// signature, or when the public key cannot be decoded. +// This function supports all the three signature variants defined in RFC-8032, +// namely Ed25519 (or pure EdDSA), Ed25519Ph, and Ed25519Ctx. +// The opts.HashFunc() must return zero to specify either Ed25519 or Ed25519Ctx +// variant. This can be achieved by passing crypto.Hash(0) as the value for opts. +// The opts.HashFunc() must return SHA512 to specify the Ed25519Ph variant. +// This can be achieved by passing crypto.SHA512 as the value for opts. +// Use a SignerOptions struct to pass a context string for signing. +func VerifyAny(public PublicKey, message, signature []byte, opts crypto.SignerOpts) bool { + var ctx string + var scheme SchemeID + if o, ok := opts.(SignerOptions); ok { + ctx = o.Context + scheme = o.Scheme + } + + switch true { + case scheme == ED25519 && opts.HashFunc() == crypto.Hash(0): + return Verify(public, message, signature) + case scheme == ED25519Ph && opts.HashFunc() == crypto.SHA512: + return VerifyPh(public, message, signature, ctx) + case scheme == ED25519Ctx && opts.HashFunc() == crypto.Hash(0) && len(ctx) > 0: + return VerifyWithCtx(public, message, signature, ctx) + default: + return false + } +} + +// Verify returns true if the signature is valid. Failure cases are invalid +// signature, or when the public key cannot be decoded. +// This function supports the signature variant defined in RFC-8032: Ed25519, +// also known as the pure version of EdDSA. +func Verify(public PublicKey, message, signature []byte) bool { + return verify(public, message, signature, []byte(""), false) +} + +// VerifyPh returns true if the signature is valid. Failure cases are invalid +// signature, or when the public key cannot be decoded. +// This function supports the signature variant defined in RFC-8032: Ed25519ph, +// meaning it internally hashes the message using SHA-512. +// Context could be passed to this function, which length should be no more than +// 255. It can be empty. +func VerifyPh(public PublicKey, message, signature []byte, ctx string) bool { + return verify(public, message, signature, []byte(ctx), true) +} + +// VerifyWithCtx returns true if the signature is valid. Failure cases are invalid +// signature, or when the public key cannot be decoded, or when context is +// not provided. +// This function supports the signature variant defined in RFC-8032: Ed25519ctx, +// meaning it does not handle prehashed messages. Non-empty context string must be +// provided, and must not be more than 255 of length. +func VerifyWithCtx(public PublicKey, message, signature []byte, ctx string) bool { + if len(ctx) == 0 || len(ctx) > ContextMaxSize { + return false + } + + return verify(public, message, signature, []byte(ctx), false) +} + +func clamp(k []byte) { + k[0] &= 248 + k[paramB-1] = (k[paramB-1] & 127) | 64 +} + +// isLessThanOrder returns true if 0 <= x < order. +func isLessThanOrder(x []byte) bool { + i := len(order) - 1 + for i > 0 && x[i] == order[i] { + i-- + } + return x[i] < order[i] +} + +func writeDom(h io.Writer, ctx []byte, preHash bool) { + dom2 := "SigEd25519 no Ed25519 collisions" + + if len(ctx) > 0 { + _, _ = h.Write([]byte(dom2)) + if preHash { + _, _ = h.Write([]byte{byte(0x01), byte(len(ctx))}) + } else { + _, _ = h.Write([]byte{byte(0x00), byte(len(ctx))}) + } + _, _ = h.Write(ctx) + } else if preHash { + _, _ = h.Write([]byte(dom2)) + _, _ = h.Write([]byte{0x01, 0x00}) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/modular.go b/vendor/github.com/cloudflare/circl/sign/ed25519/modular.go new file mode 100644 index 00000000..10efafdc --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/modular.go @@ -0,0 +1,175 @@ +package ed25519 + +import ( + "encoding/binary" + "math/bits" +) + +var order = [paramB]byte{ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +} + +// isLessThan returns true if 0 <= x < y, and assumes that slices have the same length. +func isLessThan(x, y []byte) bool { + i := len(x) - 1 + for i > 0 && x[i] == y[i] { + i-- + } + return x[i] < y[i] +} + +// reduceModOrder calculates k = k mod order of the curve. +func reduceModOrder(k []byte, is512Bit bool) { + var X [((2 * paramB) * 8) / 64]uint64 + numWords := len(k) >> 3 + for i := 0; i < numWords; i++ { + X[i] = binary.LittleEndian.Uint64(k[i*8 : (i+1)*8]) + } + red512(&X, is512Bit) + for i := 0; i < numWords; i++ { + binary.LittleEndian.PutUint64(k[i*8:(i+1)*8], X[i]) + } +} + +// red512 calculates x = x mod Order of the curve. +func red512(x *[8]uint64, full bool) { + // Implementation of Algs.(14.47)+(14.52) of Handbook of Applied + // Cryptography, by A. Menezes, P. van Oorschot, and S. Vanstone. + const ( + ell0 = uint64(0x5812631a5cf5d3ed) + ell1 = uint64(0x14def9dea2f79cd6) + ell160 = uint64(0x812631a5cf5d3ed0) + ell161 = uint64(0x4def9dea2f79cd65) + ell162 = uint64(0x0000000000000001) + ) + + var c0, c1, c2, c3 uint64 + r0, r1, r2, r3, r4 := x[0], x[1], x[2], x[3], uint64(0) + + if full { + q0, q1, q2, q3 := x[4], x[5], x[6], x[7] + + for i := 0; i < 3; i++ { + h0, s0 := bits.Mul64(q0, ell160) + h1, s1 := bits.Mul64(q1, ell160) + h2, s2 := bits.Mul64(q2, ell160) + h3, s3 := bits.Mul64(q3, ell160) + + s1, c0 = bits.Add64(h0, s1, 0) + s2, c1 = bits.Add64(h1, s2, c0) + s3, c2 = bits.Add64(h2, s3, c1) + s4, _ := bits.Add64(h3, 0, c2) + + h0, l0 := bits.Mul64(q0, ell161) + h1, l1 := bits.Mul64(q1, ell161) + h2, l2 := bits.Mul64(q2, ell161) + h3, l3 := bits.Mul64(q3, ell161) + + l1, c0 = bits.Add64(h0, l1, 0) + l2, c1 = bits.Add64(h1, l2, c0) + l3, c2 = bits.Add64(h2, l3, c1) + l4, _ := bits.Add64(h3, 0, c2) + + s1, c0 = bits.Add64(s1, l0, 0) + s2, c1 = bits.Add64(s2, l1, c0) + s3, c2 = bits.Add64(s3, l2, c1) + s4, c3 = bits.Add64(s4, l3, c2) + s5, s6 := bits.Add64(l4, 0, c3) + + s2, c0 = bits.Add64(s2, q0, 0) + s3, c1 = bits.Add64(s3, q1, c0) + s4, c2 = bits.Add64(s4, q2, c1) + s5, c3 = bits.Add64(s5, q3, c2) + s6, s7 := bits.Add64(s6, 0, c3) + + q := q0 | q1 | q2 | q3 + m := -((q | -q) >> 63) // if q=0 then m=0...0 else m=1..1 + s0 &= m + s1 &= m + s2 &= m + s3 &= m + q0, q1, q2, q3 = s4, s5, s6, s7 + + if (i+1)%2 == 0 { + r0, c0 = bits.Add64(r0, s0, 0) + r1, c1 = bits.Add64(r1, s1, c0) + r2, c2 = bits.Add64(r2, s2, c1) + r3, c3 = bits.Add64(r3, s3, c2) + r4, _ = bits.Add64(r4, 0, c3) + } else { + r0, c0 = bits.Sub64(r0, s0, 0) + r1, c1 = bits.Sub64(r1, s1, c0) + r2, c2 = bits.Sub64(r2, s2, c1) + r3, c3 = bits.Sub64(r3, s3, c2) + r4, _ = bits.Sub64(r4, 0, c3) + } + } + + m := -(r4 >> 63) + r0, c0 = bits.Add64(r0, m&ell160, 0) + r1, c1 = bits.Add64(r1, m&ell161, c0) + r2, c2 = bits.Add64(r2, m&ell162, c1) + r3, c3 = bits.Add64(r3, 0, c2) + r4, _ = bits.Add64(r4, m&1, c3) + x[4], x[5], x[6], x[7] = 0, 0, 0, 0 + } + + q0 := (r4 << 4) | (r3 >> 60) + r3 &= (uint64(1) << 60) - 1 + + h0, s0 := bits.Mul64(ell0, q0) + h1, s1 := bits.Mul64(ell1, q0) + s1, c0 = bits.Add64(h0, s1, 0) + s2, _ := bits.Add64(h1, 0, c0) + + r0, c0 = bits.Sub64(r0, s0, 0) + r1, c1 = bits.Sub64(r1, s1, c0) + r2, c2 = bits.Sub64(r2, s2, c1) + r3, _ = bits.Sub64(r3, 0, c2) + + x[0], x[1], x[2], x[3] = r0, r1, r2, r3 +} + +// calculateS performs s = r+k*a mod Order of the curve. +func calculateS(s, r, k, a []byte) { + K := [4]uint64{ + binary.LittleEndian.Uint64(k[0*8 : 1*8]), + binary.LittleEndian.Uint64(k[1*8 : 2*8]), + binary.LittleEndian.Uint64(k[2*8 : 3*8]), + binary.LittleEndian.Uint64(k[3*8 : 4*8]), + } + S := [8]uint64{ + binary.LittleEndian.Uint64(r[0*8 : 1*8]), + binary.LittleEndian.Uint64(r[1*8 : 2*8]), + binary.LittleEndian.Uint64(r[2*8 : 3*8]), + binary.LittleEndian.Uint64(r[3*8 : 4*8]), + } + var c3 uint64 + for i := range K { + ai := binary.LittleEndian.Uint64(a[i*8 : (i+1)*8]) + + h0, l0 := bits.Mul64(K[0], ai) + h1, l1 := bits.Mul64(K[1], ai) + h2, l2 := bits.Mul64(K[2], ai) + h3, l3 := bits.Mul64(K[3], ai) + + l1, c0 := bits.Add64(h0, l1, 0) + l2, c1 := bits.Add64(h1, l2, c0) + l3, c2 := bits.Add64(h2, l3, c1) + l4, _ := bits.Add64(h3, 0, c2) + + S[i+0], c0 = bits.Add64(S[i+0], l0, 0) + S[i+1], c1 = bits.Add64(S[i+1], l1, c0) + S[i+2], c2 = bits.Add64(S[i+2], l2, c1) + S[i+3], c3 = bits.Add64(S[i+3], l3, c2) + S[i+4], _ = bits.Add64(S[i+4], l4, c3) + } + red512(&S, true) + binary.LittleEndian.PutUint64(s[0*8:1*8], S[0]) + binary.LittleEndian.PutUint64(s[1*8:2*8], S[1]) + binary.LittleEndian.PutUint64(s[2*8:3*8], S[2]) + binary.LittleEndian.PutUint64(s[3*8:4*8], S[3]) +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/mult.go b/vendor/github.com/cloudflare/circl/sign/ed25519/mult.go new file mode 100644 index 00000000..3216aae3 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/mult.go @@ -0,0 +1,180 @@ +package ed25519 + +import ( + "crypto/subtle" + "encoding/binary" + "math/bits" + + "github.com/cloudflare/circl/internal/conv" + "github.com/cloudflare/circl/math" + fp "github.com/cloudflare/circl/math/fp25519" +) + +var paramD = fp.Elt{ + 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, + 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, + 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, + 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52, +} + +// mLSBRecoding parameters. +const ( + fxT = 257 + fxV = 2 + fxW = 3 + fx2w1 = 1 << (uint(fxW) - 1) + numWords64 = (paramB * 8 / 64) +) + +// mLSBRecoding is the odd-only modified LSB-set. +// +// Reference: +// +// "Efficient and secure algorithms for GLV-based scalar multiplication and +// their implementation on GLV–GLS curves" by (Faz-Hernandez et al.) +// http://doi.org/10.1007/s13389-014-0085-7. +func mLSBRecoding(L []int8, k []byte) { + const ee = (fxT + fxW*fxV - 1) / (fxW * fxV) + const dd = ee * fxV + const ll = dd * fxW + if len(L) == (ll + 1) { + var m [numWords64 + 1]uint64 + for i := 0; i < numWords64; i++ { + m[i] = binary.LittleEndian.Uint64(k[8*i : 8*i+8]) + } + condAddOrderN(&m) + L[dd-1] = 1 + for i := 0; i < dd-1; i++ { + kip1 := (m[(i+1)/64] >> (uint(i+1) % 64)) & 0x1 + L[i] = int8(kip1<<1) - 1 + } + { // right-shift by d + right := uint(dd % 64) + left := uint(64) - right + lim := ((numWords64+1)*64 - dd) / 64 + j := dd / 64 + for i := 0; i < lim; i++ { + m[i] = (m[i+j] >> right) | (m[i+j+1] << left) + } + m[lim] = m[lim+j] >> right + } + for i := dd; i < ll; i++ { + L[i] = L[i%dd] * int8(m[0]&0x1) + div2subY(m[:], int64(L[i]>>1), numWords64) + } + L[ll] = int8(m[0]) + } +} + +// absolute returns always a positive value. +func absolute(x int32) int32 { + mask := x >> 31 + return (x + mask) ^ mask +} + +// condAddOrderN updates x = x+order if x is even, otherwise x remains unchanged. +func condAddOrderN(x *[numWords64 + 1]uint64) { + isOdd := (x[0] & 0x1) - 1 + c := uint64(0) + for i := 0; i < numWords64; i++ { + orderWord := binary.LittleEndian.Uint64(order[8*i : 8*i+8]) + o := isOdd & orderWord + x0, c0 := bits.Add64(x[i], o, c) + x[i] = x0 + c = c0 + } + x[numWords64], _ = bits.Add64(x[numWords64], 0, c) +} + +// div2subY update x = (x/2) - y. +func div2subY(x []uint64, y int64, l int) { + s := uint64(y >> 63) + for i := 0; i < l-1; i++ { + x[i] = (x[i] >> 1) | (x[i+1] << 63) + } + x[l-1] = (x[l-1] >> 1) + + b := uint64(0) + x0, b0 := bits.Sub64(x[0], uint64(y), b) + x[0] = x0 + b = b0 + for i := 1; i < l-1; i++ { + x0, b0 := bits.Sub64(x[i], s, b) + x[i] = x0 + b = b0 + } + x[l-1], _ = bits.Sub64(x[l-1], s, b) +} + +func (P *pointR1) fixedMult(scalar []byte) { + if len(scalar) != paramB { + panic("wrong scalar size") + } + const ee = (fxT + fxW*fxV - 1) / (fxW * fxV) + const dd = ee * fxV + const ll = dd * fxW + + L := make([]int8, ll+1) + mLSBRecoding(L[:], scalar) + S := &pointR3{} + P.SetIdentity() + for ii := ee - 1; ii >= 0; ii-- { + P.double() + for j := 0; j < fxV; j++ { + dig := L[fxW*dd-j*ee+ii-ee] + for i := (fxW-1)*dd - j*ee + ii - ee; i >= (2*dd - j*ee + ii - ee); i = i - dd { + dig = 2*dig + L[i] + } + idx := absolute(int32(dig)) + sig := L[dd-j*ee+ii-ee] + Tabj := &tabSign[fxV-j-1] + for k := 0; k < fx2w1; k++ { + S.cmov(&Tabj[k], subtle.ConstantTimeEq(int32(k), idx)) + } + S.cneg(subtle.ConstantTimeEq(int32(sig), -1)) + P.mixAdd(S) + } + } +} + +const ( + omegaFix = 7 + omegaVar = 5 +) + +// doubleMult returns P=mG+nQ. +func (P *pointR1) doubleMult(Q *pointR1, m, n []byte) { + nafFix := math.OmegaNAF(conv.BytesLe2BigInt(m), omegaFix) + nafVar := math.OmegaNAF(conv.BytesLe2BigInt(n), omegaVar) + + if len(nafFix) > len(nafVar) { + nafVar = append(nafVar, make([]int32, len(nafFix)-len(nafVar))...) + } else if len(nafFix) < len(nafVar) { + nafFix = append(nafFix, make([]int32, len(nafVar)-len(nafFix))...) + } + + var TabQ [1 << (omegaVar - 2)]pointR2 + Q.oddMultiples(TabQ[:]) + P.SetIdentity() + for i := len(nafFix) - 1; i >= 0; i-- { + P.double() + // Generator point + if nafFix[i] != 0 { + idxM := absolute(nafFix[i]) >> 1 + R := tabVerif[idxM] + if nafFix[i] < 0 { + R.neg() + } + P.mixAdd(&R) + } + // Variable input point + if nafVar[i] != 0 { + idxN := absolute(nafVar[i]) >> 1 + S := TabQ[idxN] + if nafVar[i] < 0 { + S.neg() + } + P.add(&S) + } + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/point.go b/vendor/github.com/cloudflare/circl/sign/ed25519/point.go new file mode 100644 index 00000000..d1c3b146 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/point.go @@ -0,0 +1,195 @@ +package ed25519 + +import fp "github.com/cloudflare/circl/math/fp25519" + +type ( + pointR1 struct{ x, y, z, ta, tb fp.Elt } + pointR2 struct { + pointR3 + z2 fp.Elt + } +) +type pointR3 struct{ addYX, subYX, dt2 fp.Elt } + +func (P *pointR1) neg() { + fp.Neg(&P.x, &P.x) + fp.Neg(&P.ta, &P.ta) +} + +func (P *pointR1) SetIdentity() { + P.x = fp.Elt{} + fp.SetOne(&P.y) + fp.SetOne(&P.z) + P.ta = fp.Elt{} + P.tb = fp.Elt{} +} + +func (P *pointR1) toAffine() { + fp.Inv(&P.z, &P.z) + fp.Mul(&P.x, &P.x, &P.z) + fp.Mul(&P.y, &P.y, &P.z) + fp.Modp(&P.x) + fp.Modp(&P.y) + fp.SetOne(&P.z) + P.ta = P.x + P.tb = P.y +} + +func (P *pointR1) ToBytes(k []byte) error { + P.toAffine() + var x [fp.Size]byte + err := fp.ToBytes(k[:fp.Size], &P.y) + if err != nil { + return err + } + err = fp.ToBytes(x[:], &P.x) + if err != nil { + return err + } + b := x[0] & 1 + k[paramB-1] = k[paramB-1] | (b << 7) + return nil +} + +func (P *pointR1) FromBytes(k []byte) bool { + if len(k) != paramB { + panic("wrong size") + } + signX := k[paramB-1] >> 7 + copy(P.y[:], k[:fp.Size]) + P.y[fp.Size-1] &= 0x7F + p := fp.P() + if !isLessThan(P.y[:], p[:]) { + return false + } + + one, u, v := &fp.Elt{}, &fp.Elt{}, &fp.Elt{} + fp.SetOne(one) + fp.Sqr(u, &P.y) // u = y^2 + fp.Mul(v, u, ¶mD) // v = dy^2 + fp.Sub(u, u, one) // u = y^2-1 + fp.Add(v, v, one) // v = dy^2+1 + isQR := fp.InvSqrt(&P.x, u, v) // x = sqrt(u/v) + if !isQR { + return false + } + fp.Modp(&P.x) // x = x mod p + if fp.IsZero(&P.x) && signX == 1 { + return false + } + if signX != (P.x[0] & 1) { + fp.Neg(&P.x, &P.x) + } + P.ta = P.x + P.tb = P.y + fp.SetOne(&P.z) + return true +} + +// double calculates 2P for curves with A=-1. +func (P *pointR1) double() { + Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb + a, b, c, e, f, g, h := Px, Py, Pz, Pta, Px, Py, Ptb + fp.Add(e, Px, Py) // x+y + fp.Sqr(a, Px) // A = x^2 + fp.Sqr(b, Py) // B = y^2 + fp.Sqr(c, Pz) // z^2 + fp.Add(c, c, c) // C = 2*z^2 + fp.Add(h, a, b) // H = A+B + fp.Sqr(e, e) // (x+y)^2 + fp.Sub(e, e, h) // E = (x+y)^2-A-B + fp.Sub(g, b, a) // G = B-A + fp.Sub(f, c, g) // F = C-G + fp.Mul(Pz, f, g) // Z = F * G + fp.Mul(Px, e, f) // X = E * F + fp.Mul(Py, g, h) // Y = G * H, T = E * H +} + +func (P *pointR1) mixAdd(Q *pointR3) { + fp.Add(&P.z, &P.z, &P.z) // D = 2*z1 + P.coreAddition(Q) +} + +func (P *pointR1) add(Q *pointR2) { + fp.Mul(&P.z, &P.z, &Q.z2) // D = 2*z1*z2 + P.coreAddition(&Q.pointR3) +} + +// coreAddition calculates P=P+Q for curves with A=-1. +func (P *pointR1) coreAddition(Q *pointR3) { + Px, Py, Pz, Pta, Ptb := &P.x, &P.y, &P.z, &P.ta, &P.tb + addYX2, subYX2, dt2 := &Q.addYX, &Q.subYX, &Q.dt2 + a, b, c, d, e, f, g, h := Px, Py, &fp.Elt{}, Pz, Pta, Px, Py, Ptb + fp.Mul(c, Pta, Ptb) // t1 = ta*tb + fp.Sub(h, Py, Px) // y1-x1 + fp.Add(b, Py, Px) // y1+x1 + fp.Mul(a, h, subYX2) // A = (y1-x1)*(y2-x2) + fp.Mul(b, b, addYX2) // B = (y1+x1)*(y2+x2) + fp.Mul(c, c, dt2) // C = 2*D*t1*t2 + fp.Sub(e, b, a) // E = B-A + fp.Add(h, b, a) // H = B+A + fp.Sub(f, d, c) // F = D-C + fp.Add(g, d, c) // G = D+C + fp.Mul(Pz, f, g) // Z = F * G + fp.Mul(Px, e, f) // X = E * F + fp.Mul(Py, g, h) // Y = G * H, T = E * H +} + +func (P *pointR1) oddMultiples(T []pointR2) { + var R pointR2 + n := len(T) + T[0].fromR1(P) + _2P := *P + _2P.double() + R.fromR1(&_2P) + for i := 1; i < n; i++ { + P.add(&R) + T[i].fromR1(P) + } +} + +func (P *pointR1) isEqual(Q *pointR1) bool { + l, r := &fp.Elt{}, &fp.Elt{} + fp.Mul(l, &P.x, &Q.z) + fp.Mul(r, &Q.x, &P.z) + fp.Sub(l, l, r) + b := fp.IsZero(l) + fp.Mul(l, &P.y, &Q.z) + fp.Mul(r, &Q.y, &P.z) + fp.Sub(l, l, r) + b = b && fp.IsZero(l) + fp.Mul(l, &P.ta, &P.tb) + fp.Mul(l, l, &Q.z) + fp.Mul(r, &Q.ta, &Q.tb) + fp.Mul(r, r, &P.z) + fp.Sub(l, l, r) + b = b && fp.IsZero(l) + return b && !fp.IsZero(&P.z) && !fp.IsZero(&Q.z) +} + +func (P *pointR3) neg() { + P.addYX, P.subYX = P.subYX, P.addYX + fp.Neg(&P.dt2, &P.dt2) +} + +func (P *pointR2) fromR1(Q *pointR1) { + fp.Add(&P.addYX, &Q.y, &Q.x) + fp.Sub(&P.subYX, &Q.y, &Q.x) + fp.Mul(&P.dt2, &Q.ta, &Q.tb) + fp.Mul(&P.dt2, &P.dt2, ¶mD) + fp.Add(&P.dt2, &P.dt2, &P.dt2) + fp.Add(&P.z2, &Q.z, &Q.z) +} + +func (P *pointR3) cneg(b int) { + t := &fp.Elt{} + fp.Cswap(&P.addYX, &P.subYX, uint(b)) + fp.Neg(t, &P.dt2) + fp.Cmov(&P.dt2, t, uint(b)) +} + +func (P *pointR3) cmov(Q *pointR3, b int) { + fp.Cmov(&P.addYX, &Q.addYX, uint(b)) + fp.Cmov(&P.subYX, &Q.subYX, uint(b)) + fp.Cmov(&P.dt2, &Q.dt2, uint(b)) +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go new file mode 100644 index 00000000..c3505b67 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey.go @@ -0,0 +1,9 @@ +//go:build go1.13 +// +build go1.13 + +package ed25519 + +import cryptoEd25519 "crypto/ed25519" + +// PublicKey is the type of Ed25519 public keys. +type PublicKey cryptoEd25519.PublicKey diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go new file mode 100644 index 00000000..d57d86ef --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/pubkey112.go @@ -0,0 +1,7 @@ +//go:build !go1.13 +// +build !go1.13 + +package ed25519 + +// PublicKey is the type of Ed25519 public keys. +type PublicKey []byte diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go b/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go new file mode 100644 index 00000000..e4520f52 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go @@ -0,0 +1,87 @@ +package ed25519 + +import ( + "crypto/rand" + "encoding/asn1" + + "github.com/cloudflare/circl/sign" +) + +var sch sign.Scheme = &scheme{} + +// Scheme returns a signature interface. +func Scheme() sign.Scheme { return sch } + +type scheme struct{} + +func (*scheme) Name() string { return "Ed25519" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } +func (*scheme) TLSIdentifier() uint { return 0x0807 } +func (*scheme) SupportsContext() bool { return false } +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{1, 3, 101, 112} +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(rand.Reader) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + message []byte, + opts *sign.SignatureOpts, +) []byte { + priv, ok := sk.(PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Sign(priv, message) +} + +func (*scheme) Verify( + pk sign.PublicKey, + message, signature []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil { + if opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + } + return Verify(pub, message, signature) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + privateKey := NewKeyFromSeed(seed) + publicKey := make(PublicKey, PublicKeySize) + copy(publicKey, privateKey[SeedSize:]) + return publicKey, privateKey +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) < PublicKeySize { + return nil, sign.ErrPubKeySize + } + pub := make(PublicKey, PublicKeySize) + copy(pub, buf[:PublicKeySize]) + return pub, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) < PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + priv := make(PrivateKey, PrivateKeySize) + copy(priv, buf[:PrivateKeySize]) + return priv, nil +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/tables.go b/vendor/github.com/cloudflare/circl/sign/ed25519/tables.go new file mode 100644 index 00000000..8763b426 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/tables.go @@ -0,0 +1,213 @@ +package ed25519 + +import fp "github.com/cloudflare/circl/math/fp25519" + +var tabSign = [fxV][fx2w1]pointR3{ + { + pointR3{ + addYX: fp.Elt{0x85, 0x3b, 0x8c, 0xf5, 0xc6, 0x93, 0xbc, 0x2f, 0x19, 0x0e, 0x8c, 0xfb, 0xc6, 0x2d, 0x93, 0xcf, 0xc2, 0x42, 0x3d, 0x64, 0x98, 0x48, 0x0b, 0x27, 0x65, 0xba, 0xd4, 0x33, 0x3a, 0x9d, 0xcf, 0x07}, + subYX: fp.Elt{0x3e, 0x91, 0x40, 0xd7, 0x05, 0x39, 0x10, 0x9d, 0xb3, 0xbe, 0x40, 0xd1, 0x05, 0x9f, 0x39, 0xfd, 0x09, 0x8a, 0x8f, 0x68, 0x34, 0x84, 0xc1, 0xa5, 0x67, 0x12, 0xf8, 0x98, 0x92, 0x2f, 0xfd, 0x44}, + dt2: fp.Elt{0x68, 0xaa, 0x7a, 0x87, 0x05, 0x12, 0xc9, 0xab, 0x9e, 0xc4, 0xaa, 0xcc, 0x23, 0xe8, 0xd9, 0x26, 0x8c, 0x59, 0x43, 0xdd, 0xcb, 0x7d, 0x1b, 0x5a, 0xa8, 0x65, 0x0c, 0x9f, 0x68, 0x7b, 0x11, 0x6f}, + }, + { + addYX: fp.Elt{0x7c, 0xb0, 0x9e, 0xe6, 0xc5, 0xbf, 0xfa, 0x13, 0x8e, 0x0d, 0x22, 0xde, 0xc8, 0xd1, 0xce, 0x52, 0x02, 0xd5, 0x62, 0x31, 0x71, 0x0e, 0x8e, 0x9d, 0xb0, 0xd6, 0x00, 0xa5, 0x5a, 0x0e, 0xce, 0x72}, + subYX: fp.Elt{0x1a, 0x8e, 0x5c, 0xdc, 0xa4, 0xb3, 0x6c, 0x51, 0x18, 0xa0, 0x09, 0x80, 0x9a, 0x46, 0x33, 0xd5, 0xe0, 0x3c, 0x4d, 0x3b, 0xfc, 0x49, 0xa2, 0x43, 0x29, 0xe1, 0x29, 0xa9, 0x93, 0xea, 0x7c, 0x35}, + dt2: fp.Elt{0x08, 0x46, 0x6f, 0x68, 0x7f, 0x0b, 0x7c, 0x9e, 0xad, 0xba, 0x07, 0x61, 0x74, 0x83, 0x2f, 0xfc, 0x26, 0xd6, 0x09, 0xb9, 0x00, 0x34, 0x36, 0x4f, 0x01, 0xf3, 0x48, 0xdb, 0x43, 0xba, 0x04, 0x44}, + }, + { + addYX: fp.Elt{0x4c, 0xda, 0x0d, 0x13, 0x66, 0xfd, 0x82, 0x84, 0x9f, 0x75, 0x5b, 0xa2, 0x17, 0xfe, 0x34, 0xbf, 0x1f, 0xcb, 0xba, 0x90, 0x55, 0x80, 0x83, 0xfd, 0x63, 0xb9, 0x18, 0xf8, 0x5b, 0x5d, 0x94, 0x1e}, + subYX: fp.Elt{0xb9, 0xdb, 0x6c, 0x04, 0x88, 0x22, 0xd8, 0x79, 0x83, 0x2f, 0x8d, 0x65, 0x6b, 0xd2, 0xab, 0x1b, 0xdd, 0x65, 0xe5, 0x93, 0x63, 0xf8, 0xa2, 0xd8, 0x3c, 0xf1, 0x4b, 0xc5, 0x99, 0xd1, 0xf2, 0x12}, + dt2: fp.Elt{0x05, 0x4c, 0xb8, 0x3b, 0xfe, 0xf5, 0x9f, 0x2e, 0xd1, 0xb2, 0xb8, 0xff, 0xfe, 0x6d, 0xd9, 0x37, 0xe0, 0xae, 0xb4, 0x5a, 0x51, 0x80, 0x7e, 0x9b, 0x1d, 0xd1, 0x8d, 0x8c, 0x56, 0xb1, 0x84, 0x35}, + }, + { + addYX: fp.Elt{0x39, 0x71, 0x43, 0x34, 0xe3, 0x42, 0x45, 0xa1, 0xf2, 0x68, 0x71, 0xa7, 0xe8, 0x23, 0xfd, 0x9f, 0x86, 0x48, 0xff, 0xe5, 0x96, 0x74, 0xcf, 0x05, 0x49, 0xe2, 0xb3, 0x6c, 0x17, 0x77, 0x2f, 0x6d}, + subYX: fp.Elt{0x73, 0x3f, 0xc1, 0xc7, 0x6a, 0x66, 0xa1, 0x20, 0xdd, 0x11, 0xfb, 0x7a, 0x6e, 0xa8, 0x51, 0xb8, 0x3f, 0x9d, 0xa2, 0x97, 0x84, 0xb5, 0xc7, 0x90, 0x7c, 0xab, 0x48, 0xd6, 0x84, 0xa3, 0xd5, 0x1a}, + dt2: fp.Elt{0x63, 0x27, 0x3c, 0x49, 0x4b, 0xfc, 0x22, 0xf2, 0x0b, 0x50, 0xc2, 0x0f, 0xb4, 0x1f, 0x31, 0x0c, 0x2f, 0x53, 0xab, 0xaa, 0x75, 0x6f, 0xe0, 0x69, 0x39, 0x56, 0xe0, 0x3b, 0xb7, 0xa8, 0xbf, 0x45}, + }, + }, + { + { + addYX: fp.Elt{0x00, 0x45, 0xd9, 0x0d, 0x58, 0x03, 0xfc, 0x29, 0x93, 0xec, 0xbb, 0x6f, 0xa4, 0x7a, 0xd2, 0xec, 0xf8, 0xa7, 0xe2, 0xc2, 0x5f, 0x15, 0x0a, 0x13, 0xd5, 0xa1, 0x06, 0xb7, 0x1a, 0x15, 0x6b, 0x41}, + subYX: fp.Elt{0x85, 0x8c, 0xb2, 0x17, 0xd6, 0x3b, 0x0a, 0xd3, 0xea, 0x3b, 0x77, 0x39, 0xb7, 0x77, 0xd3, 0xc5, 0xbf, 0x5c, 0x6a, 0x1e, 0x8c, 0xe7, 0xc6, 0xc6, 0xc4, 0xb7, 0x2a, 0x8b, 0xf7, 0xb8, 0x61, 0x0d}, + dt2: fp.Elt{0xb0, 0x36, 0xc1, 0xe9, 0xef, 0xd7, 0xa8, 0x56, 0x20, 0x4b, 0xe4, 0x58, 0xcd, 0xe5, 0x07, 0xbd, 0xab, 0xe0, 0x57, 0x1b, 0xda, 0x2f, 0xe6, 0xaf, 0xd2, 0xe8, 0x77, 0x42, 0xf7, 0x2a, 0x1a, 0x19}, + }, + { + addYX: fp.Elt{0x6a, 0x6d, 0x6d, 0xd1, 0xfa, 0xf5, 0x03, 0x30, 0xbd, 0x6d, 0xc2, 0xc8, 0xf5, 0x38, 0x80, 0x4f, 0xb2, 0xbe, 0xa1, 0x76, 0x50, 0x1a, 0x73, 0xf2, 0x78, 0x2b, 0x8e, 0x3a, 0x1e, 0x34, 0x47, 0x7b}, + subYX: fp.Elt{0xc3, 0x2c, 0x36, 0xdc, 0xc5, 0x45, 0xbc, 0xef, 0x1b, 0x64, 0xd6, 0x65, 0x28, 0xe9, 0xda, 0x84, 0x13, 0xbe, 0x27, 0x8e, 0x3f, 0x98, 0x2a, 0x37, 0xee, 0x78, 0x97, 0xd6, 0xc0, 0x6f, 0xb4, 0x53}, + dt2: fp.Elt{0x58, 0x5d, 0xa7, 0xa3, 0x68, 0xbb, 0x20, 0x30, 0x2e, 0x03, 0xe9, 0xb1, 0xd4, 0x90, 0x72, 0xe3, 0x71, 0xb2, 0x36, 0x3e, 0x73, 0xa0, 0x2e, 0x3d, 0xd1, 0x85, 0x33, 0x62, 0x4e, 0xa7, 0x7b, 0x31}, + }, + { + addYX: fp.Elt{0xbf, 0xc4, 0x38, 0x53, 0xfb, 0x68, 0xa9, 0x77, 0xce, 0x55, 0xf9, 0x05, 0xcb, 0xeb, 0xfb, 0x8c, 0x46, 0xc2, 0x32, 0x7c, 0xf0, 0xdb, 0xd7, 0x2c, 0x62, 0x8e, 0xdd, 0x54, 0x75, 0xcf, 0x3f, 0x33}, + subYX: fp.Elt{0x49, 0x50, 0x1f, 0x4e, 0x6e, 0x55, 0x55, 0xde, 0x8c, 0x4e, 0x77, 0x96, 0x38, 0x3b, 0xfe, 0xb6, 0x43, 0x3c, 0x86, 0x69, 0xc2, 0x72, 0x66, 0x1f, 0x6b, 0xf9, 0x87, 0xbc, 0x4f, 0x37, 0x3e, 0x3c}, + dt2: fp.Elt{0xd2, 0x2f, 0x06, 0x6b, 0x08, 0x07, 0x69, 0x77, 0xc0, 0x94, 0xcc, 0xae, 0x43, 0x00, 0x59, 0x6e, 0xa3, 0x63, 0xa8, 0xdd, 0xfa, 0x24, 0x18, 0xd0, 0x35, 0xc7, 0x78, 0xf7, 0x0d, 0xd4, 0x5a, 0x1e}, + }, + { + addYX: fp.Elt{0x45, 0xc1, 0x17, 0x51, 0xf8, 0xed, 0x7e, 0xc7, 0xa9, 0x1a, 0x11, 0x6e, 0x2d, 0xef, 0x0b, 0xd5, 0x3f, 0x98, 0xb0, 0xa3, 0x9d, 0x65, 0xf1, 0xcd, 0x53, 0x4a, 0x8a, 0x18, 0x70, 0x0a, 0x7f, 0x23}, + subYX: fp.Elt{0xdd, 0xef, 0xbe, 0x3a, 0x31, 0xe0, 0xbc, 0xbe, 0x6d, 0x5d, 0x79, 0x87, 0xd6, 0xbe, 0x68, 0xe3, 0x59, 0x76, 0x8c, 0x86, 0x0e, 0x7a, 0x92, 0x13, 0x14, 0x8f, 0x67, 0xb3, 0xcb, 0x1a, 0x76, 0x76}, + dt2: fp.Elt{0x56, 0x7a, 0x1c, 0x9d, 0xca, 0x96, 0xf9, 0xf9, 0x03, 0x21, 0xd4, 0xe8, 0xb3, 0xd5, 0xe9, 0x52, 0xc8, 0x54, 0x1e, 0x1b, 0x13, 0xb6, 0xfd, 0x47, 0x7d, 0x02, 0x32, 0x33, 0x27, 0xe2, 0x1f, 0x19}, + }, + }, +} + +var tabVerif = [1 << (omegaFix - 2)]pointR3{ + { /* 1P */ + addYX: fp.Elt{0x85, 0x3b, 0x8c, 0xf5, 0xc6, 0x93, 0xbc, 0x2f, 0x19, 0x0e, 0x8c, 0xfb, 0xc6, 0x2d, 0x93, 0xcf, 0xc2, 0x42, 0x3d, 0x64, 0x98, 0x48, 0x0b, 0x27, 0x65, 0xba, 0xd4, 0x33, 0x3a, 0x9d, 0xcf, 0x07}, + subYX: fp.Elt{0x3e, 0x91, 0x40, 0xd7, 0x05, 0x39, 0x10, 0x9d, 0xb3, 0xbe, 0x40, 0xd1, 0x05, 0x9f, 0x39, 0xfd, 0x09, 0x8a, 0x8f, 0x68, 0x34, 0x84, 0xc1, 0xa5, 0x67, 0x12, 0xf8, 0x98, 0x92, 0x2f, 0xfd, 0x44}, + dt2: fp.Elt{0x68, 0xaa, 0x7a, 0x87, 0x05, 0x12, 0xc9, 0xab, 0x9e, 0xc4, 0xaa, 0xcc, 0x23, 0xe8, 0xd9, 0x26, 0x8c, 0x59, 0x43, 0xdd, 0xcb, 0x7d, 0x1b, 0x5a, 0xa8, 0x65, 0x0c, 0x9f, 0x68, 0x7b, 0x11, 0x6f}, + }, + { /* 3P */ + addYX: fp.Elt{0x30, 0x97, 0xee, 0x4c, 0xa8, 0xb0, 0x25, 0xaf, 0x8a, 0x4b, 0x86, 0xe8, 0x30, 0x84, 0x5a, 0x02, 0x32, 0x67, 0x01, 0x9f, 0x02, 0x50, 0x1b, 0xc1, 0xf4, 0xf8, 0x80, 0x9a, 0x1b, 0x4e, 0x16, 0x7a}, + subYX: fp.Elt{0x65, 0xd2, 0xfc, 0xa4, 0xe8, 0x1f, 0x61, 0x56, 0x7d, 0xba, 0xc1, 0xe5, 0xfd, 0x53, 0xd3, 0x3b, 0xbd, 0xd6, 0x4b, 0x21, 0x1a, 0xf3, 0x31, 0x81, 0x62, 0xda, 0x5b, 0x55, 0x87, 0x15, 0xb9, 0x2a}, + dt2: fp.Elt{0x89, 0xd8, 0xd0, 0x0d, 0x3f, 0x93, 0xae, 0x14, 0x62, 0xda, 0x35, 0x1c, 0x22, 0x23, 0x94, 0x58, 0x4c, 0xdb, 0xf2, 0x8c, 0x45, 0xe5, 0x70, 0xd1, 0xc6, 0xb4, 0xb9, 0x12, 0xaf, 0x26, 0x28, 0x5a}, + }, + { /* 5P */ + addYX: fp.Elt{0x33, 0xbb, 0xa5, 0x08, 0x44, 0xbc, 0x12, 0xa2, 0x02, 0xed, 0x5e, 0xc7, 0xc3, 0x48, 0x50, 0x8d, 0x44, 0xec, 0xbf, 0x5a, 0x0c, 0xeb, 0x1b, 0xdd, 0xeb, 0x06, 0xe2, 0x46, 0xf1, 0xcc, 0x45, 0x29}, + subYX: fp.Elt{0xba, 0xd6, 0x47, 0xa4, 0xc3, 0x82, 0x91, 0x7f, 0xb7, 0x29, 0x27, 0x4b, 0xd1, 0x14, 0x00, 0xd5, 0x87, 0xa0, 0x64, 0xb8, 0x1c, 0xf1, 0x3c, 0xe3, 0xf3, 0x55, 0x1b, 0xeb, 0x73, 0x7e, 0x4a, 0x15}, + dt2: fp.Elt{0x85, 0x82, 0x2a, 0x81, 0xf1, 0xdb, 0xbb, 0xbc, 0xfc, 0xd1, 0xbd, 0xd0, 0x07, 0x08, 0x0e, 0x27, 0x2d, 0xa7, 0xbd, 0x1b, 0x0b, 0x67, 0x1b, 0xb4, 0x9a, 0xb6, 0x3b, 0x6b, 0x69, 0xbe, 0xaa, 0x43}, + }, + { /* 7P */ + addYX: fp.Elt{0xbf, 0xa3, 0x4e, 0x94, 0xd0, 0x5c, 0x1a, 0x6b, 0xd2, 0xc0, 0x9d, 0xb3, 0x3a, 0x35, 0x70, 0x74, 0x49, 0x2e, 0x54, 0x28, 0x82, 0x52, 0xb2, 0x71, 0x7e, 0x92, 0x3c, 0x28, 0x69, 0xea, 0x1b, 0x46}, + subYX: fp.Elt{0xb1, 0x21, 0x32, 0xaa, 0x9a, 0x2c, 0x6f, 0xba, 0xa7, 0x23, 0xba, 0x3b, 0x53, 0x21, 0xa0, 0x6c, 0x3a, 0x2c, 0x19, 0x92, 0x4f, 0x76, 0xea, 0x9d, 0xe0, 0x17, 0x53, 0x2e, 0x5d, 0xdd, 0x6e, 0x1d}, + dt2: fp.Elt{0xa2, 0xb3, 0xb8, 0x01, 0xc8, 0x6d, 0x83, 0xf1, 0x9a, 0xa4, 0x3e, 0x05, 0x47, 0x5f, 0x03, 0xb3, 0xf3, 0xad, 0x77, 0x58, 0xba, 0x41, 0x9c, 0x52, 0xa7, 0x90, 0x0f, 0x6a, 0x1c, 0xbb, 0x9f, 0x7a}, + }, + { /* 9P */ + addYX: fp.Elt{0x2f, 0x63, 0xa8, 0xa6, 0x8a, 0x67, 0x2e, 0x9b, 0xc5, 0x46, 0xbc, 0x51, 0x6f, 0x9e, 0x50, 0xa6, 0xb5, 0xf5, 0x86, 0xc6, 0xc9, 0x33, 0xb2, 0xce, 0x59, 0x7f, 0xdd, 0x8a, 0x33, 0xed, 0xb9, 0x34}, + subYX: fp.Elt{0x64, 0x80, 0x9d, 0x03, 0x7e, 0x21, 0x6e, 0xf3, 0x9b, 0x41, 0x20, 0xf5, 0xb6, 0x81, 0xa0, 0x98, 0x44, 0xb0, 0x5e, 0xe7, 0x08, 0xc6, 0xcb, 0x96, 0x8f, 0x9c, 0xdc, 0xfa, 0x51, 0x5a, 0xc0, 0x49}, + dt2: fp.Elt{0x1b, 0xaf, 0x45, 0x90, 0xbf, 0xe8, 0xb4, 0x06, 0x2f, 0xd2, 0x19, 0xa7, 0xe8, 0x83, 0xff, 0xe2, 0x16, 0xcf, 0xd4, 0x93, 0x29, 0xfc, 0xf6, 0xaa, 0x06, 0x8b, 0x00, 0x1b, 0x02, 0x72, 0xc1, 0x73}, + }, + { /* 11P */ + addYX: fp.Elt{0xde, 0x2a, 0x80, 0x8a, 0x84, 0x00, 0xbf, 0x2f, 0x27, 0x2e, 0x30, 0x02, 0xcf, 0xfe, 0xd9, 0xe5, 0x06, 0x34, 0x70, 0x17, 0x71, 0x84, 0x3e, 0x11, 0xaf, 0x8f, 0x6d, 0x54, 0xe2, 0xaa, 0x75, 0x42}, + subYX: fp.Elt{0x48, 0x43, 0x86, 0x49, 0x02, 0x5b, 0x5f, 0x31, 0x81, 0x83, 0x08, 0x77, 0x69, 0xb3, 0xd6, 0x3e, 0x95, 0xeb, 0x8d, 0x6a, 0x55, 0x75, 0xa0, 0xa3, 0x7f, 0xc7, 0xd5, 0x29, 0x80, 0x59, 0xab, 0x18}, + dt2: fp.Elt{0xe9, 0x89, 0x60, 0xfd, 0xc5, 0x2c, 0x2b, 0xd8, 0xa4, 0xe4, 0x82, 0x32, 0xa1, 0xb4, 0x1e, 0x03, 0x22, 0x86, 0x1a, 0xb5, 0x99, 0x11, 0x31, 0x44, 0x48, 0xf9, 0x3d, 0xb5, 0x22, 0x55, 0xc6, 0x3d}, + }, + { /* 13P */ + addYX: fp.Elt{0x6d, 0x7f, 0x00, 0xa2, 0x22, 0xc2, 0x70, 0xbf, 0xdb, 0xde, 0xbc, 0xb5, 0x9a, 0xb3, 0x84, 0xbf, 0x07, 0xba, 0x07, 0xfb, 0x12, 0x0e, 0x7a, 0x53, 0x41, 0xf2, 0x46, 0xc3, 0xee, 0xd7, 0x4f, 0x23}, + subYX: fp.Elt{0x93, 0xbf, 0x7f, 0x32, 0x3b, 0x01, 0x6f, 0x50, 0x6b, 0x6f, 0x77, 0x9b, 0xc9, 0xeb, 0xfc, 0xae, 0x68, 0x59, 0xad, 0xaa, 0x32, 0xb2, 0x12, 0x9d, 0xa7, 0x24, 0x60, 0x17, 0x2d, 0x88, 0x67, 0x02}, + dt2: fp.Elt{0x78, 0xa3, 0x2e, 0x73, 0x19, 0xa1, 0x60, 0x53, 0x71, 0xd4, 0x8d, 0xdf, 0xb1, 0xe6, 0x37, 0x24, 0x33, 0xe5, 0xa7, 0x91, 0xf8, 0x37, 0xef, 0xa2, 0x63, 0x78, 0x09, 0xaa, 0xfd, 0xa6, 0x7b, 0x49}, + }, + { /* 15P */ + addYX: fp.Elt{0xa0, 0xea, 0xcf, 0x13, 0x03, 0xcc, 0xce, 0x24, 0x6d, 0x24, 0x9c, 0x18, 0x8d, 0xc2, 0x48, 0x86, 0xd0, 0xd4, 0xf2, 0xc1, 0xfa, 0xbd, 0xbd, 0x2d, 0x2b, 0xe7, 0x2d, 0xf1, 0x17, 0x29, 0xe2, 0x61}, + subYX: fp.Elt{0x0b, 0xcf, 0x8c, 0x46, 0x86, 0xcd, 0x0b, 0x04, 0xd6, 0x10, 0x99, 0x2a, 0xa4, 0x9b, 0x82, 0xd3, 0x92, 0x51, 0xb2, 0x07, 0x08, 0x30, 0x08, 0x75, 0xbf, 0x5e, 0xd0, 0x18, 0x42, 0xcd, 0xb5, 0x43}, + dt2: fp.Elt{0x16, 0xb5, 0xd0, 0x9b, 0x2f, 0x76, 0x9a, 0x5d, 0xee, 0xde, 0x3f, 0x37, 0x4e, 0xaf, 0x38, 0xeb, 0x70, 0x42, 0xd6, 0x93, 0x7d, 0x5a, 0x2e, 0x03, 0x42, 0xd8, 0xe4, 0x0a, 0x21, 0x61, 0x1d, 0x51}, + }, + { /* 17P */ + addYX: fp.Elt{0x81, 0x9d, 0x0e, 0x95, 0xef, 0x76, 0xc6, 0x92, 0x4f, 0x04, 0xd7, 0xc0, 0xcd, 0x20, 0x46, 0xa5, 0x48, 0x12, 0x8f, 0x6f, 0x64, 0x36, 0x9b, 0xaa, 0xe3, 0x55, 0xb8, 0xdd, 0x24, 0x59, 0x32, 0x6d}, + subYX: fp.Elt{0x87, 0xde, 0x20, 0x44, 0x48, 0x86, 0x13, 0x08, 0xb4, 0xed, 0x92, 0xb5, 0x16, 0xf0, 0x1c, 0x8a, 0x25, 0x2d, 0x94, 0x29, 0x27, 0x4e, 0xfa, 0x39, 0x10, 0x28, 0x48, 0xe2, 0x6f, 0xfe, 0xa7, 0x71}, + dt2: fp.Elt{0x54, 0xc8, 0xc8, 0xa5, 0xb8, 0x82, 0x71, 0x6c, 0x03, 0x2a, 0x5f, 0xfe, 0x79, 0x14, 0xfd, 0x33, 0x0c, 0x8d, 0x77, 0x83, 0x18, 0x59, 0xcf, 0x72, 0xa9, 0xea, 0x9e, 0x55, 0xb6, 0xc4, 0x46, 0x47}, + }, + { /* 19P */ + addYX: fp.Elt{0x2b, 0x9a, 0xc6, 0x6d, 0x3c, 0x7b, 0x77, 0xd3, 0x17, 0xf6, 0x89, 0x6f, 0x27, 0xb2, 0xfa, 0xde, 0xb5, 0x16, 0x3a, 0xb5, 0xf7, 0x1c, 0x65, 0x45, 0xb7, 0x9f, 0xfe, 0x34, 0xde, 0x51, 0x9a, 0x5c}, + subYX: fp.Elt{0x47, 0x11, 0x74, 0x64, 0xc8, 0x46, 0x85, 0x34, 0x49, 0xc8, 0xfc, 0x0e, 0xdd, 0xae, 0x35, 0x7d, 0x32, 0xa3, 0x72, 0x06, 0x76, 0x9a, 0x93, 0xff, 0xd6, 0xe6, 0xb5, 0x7d, 0x49, 0x63, 0x96, 0x21}, + dt2: fp.Elt{0x67, 0x0e, 0xf1, 0x79, 0xcf, 0xf1, 0x10, 0xf5, 0x5b, 0x51, 0x58, 0xe6, 0xa1, 0xda, 0xdd, 0xff, 0x77, 0x22, 0x14, 0x10, 0x17, 0xa7, 0xc3, 0x09, 0xbb, 0x23, 0x82, 0x60, 0x3c, 0x50, 0x04, 0x48}, + }, + { /* 21P */ + addYX: fp.Elt{0xc7, 0x7f, 0xa3, 0x2c, 0xd0, 0x9e, 0x24, 0xc4, 0xab, 0xac, 0x15, 0xa6, 0xe3, 0xa0, 0x59, 0xa0, 0x23, 0x0e, 0x6e, 0xc9, 0xd7, 0x6e, 0xa9, 0x88, 0x6d, 0x69, 0x50, 0x16, 0xa5, 0x98, 0x33, 0x55}, + subYX: fp.Elt{0x75, 0xd1, 0x36, 0x3a, 0xd2, 0x21, 0x68, 0x3b, 0x32, 0x9e, 0x9b, 0xe9, 0xa7, 0x0a, 0xb4, 0xbb, 0x47, 0x8a, 0x83, 0x20, 0xe4, 0x5c, 0x9e, 0x5d, 0x5e, 0x4c, 0xde, 0x58, 0x88, 0x09, 0x1e, 0x77}, + dt2: fp.Elt{0xdf, 0x1e, 0x45, 0x78, 0xd2, 0xf5, 0x12, 0x9a, 0xcb, 0x9c, 0x89, 0x85, 0x79, 0x5d, 0xda, 0x3a, 0x08, 0x95, 0xa5, 0x9f, 0x2d, 0x4a, 0x7f, 0x47, 0x11, 0xa6, 0xf5, 0x8f, 0xd6, 0xd1, 0x5e, 0x5a}, + }, + { /* 23P */ + addYX: fp.Elt{0x83, 0x0e, 0x15, 0xfe, 0x2a, 0x12, 0x95, 0x11, 0xd8, 0x35, 0x4b, 0x7e, 0x25, 0x9a, 0x20, 0xcf, 0x20, 0x1e, 0x71, 0x1e, 0x29, 0xf8, 0x87, 0x73, 0xf0, 0x92, 0xbf, 0xd8, 0x97, 0xb8, 0xac, 0x44}, + subYX: fp.Elt{0x59, 0x73, 0x52, 0x58, 0xc5, 0xe0, 0xe5, 0xba, 0x7e, 0x9d, 0xdb, 0xca, 0x19, 0x5c, 0x2e, 0x39, 0xe9, 0xab, 0x1c, 0xda, 0x1e, 0x3c, 0x65, 0x28, 0x44, 0xdc, 0xef, 0x5f, 0x13, 0x60, 0x9b, 0x01}, + dt2: fp.Elt{0x83, 0x4b, 0x13, 0x5e, 0x14, 0x68, 0x60, 0x1e, 0x16, 0x4c, 0x30, 0x24, 0x4f, 0xe6, 0xf5, 0xc4, 0xd7, 0x3e, 0x1a, 0xfc, 0xa8, 0x88, 0x6e, 0x50, 0x92, 0x2f, 0xad, 0xe6, 0xfd, 0x49, 0x0c, 0x15}, + }, + { /* 25P */ + addYX: fp.Elt{0x38, 0x11, 0x47, 0x09, 0x95, 0xf2, 0x7b, 0x8e, 0x51, 0xa6, 0x75, 0x4f, 0x39, 0xef, 0x6f, 0x5d, 0xad, 0x08, 0xa7, 0x25, 0xc4, 0x79, 0xaf, 0x10, 0x22, 0x99, 0xb9, 0x5b, 0x07, 0x5a, 0x2b, 0x6b}, + subYX: fp.Elt{0x68, 0xa8, 0xdc, 0x9c, 0x3c, 0x86, 0x49, 0xb8, 0xd0, 0x4a, 0x71, 0xb8, 0xdb, 0x44, 0x3f, 0xc8, 0x8d, 0x16, 0x36, 0x0c, 0x56, 0xe3, 0x3e, 0xfe, 0xc1, 0xfb, 0x05, 0x1e, 0x79, 0xd7, 0xa6, 0x78}, + dt2: fp.Elt{0x76, 0xb9, 0xa0, 0x47, 0x4b, 0x70, 0xbf, 0x58, 0xd5, 0x48, 0x17, 0x74, 0x55, 0xb3, 0x01, 0xa6, 0x90, 0xf5, 0x42, 0xd5, 0xb1, 0x1f, 0x2b, 0xaa, 0x00, 0x5d, 0xd5, 0x4a, 0xfc, 0x7f, 0x5c, 0x72}, + }, + { /* 27P */ + addYX: fp.Elt{0xb2, 0x99, 0xcf, 0xd1, 0x15, 0x67, 0x42, 0xe4, 0x34, 0x0d, 0xa2, 0x02, 0x11, 0xd5, 0x52, 0x73, 0x9f, 0x10, 0x12, 0x8b, 0x7b, 0x15, 0xd1, 0x23, 0xa3, 0xf3, 0xb1, 0x7c, 0x27, 0xc9, 0x4c, 0x79}, + subYX: fp.Elt{0xc0, 0x98, 0xd0, 0x1c, 0xf7, 0x2b, 0x80, 0x91, 0x66, 0x63, 0x5e, 0xed, 0xa4, 0x6c, 0x41, 0xfe, 0x4c, 0x99, 0x02, 0x49, 0x71, 0x5d, 0x58, 0xdf, 0xe7, 0xfa, 0x55, 0xf8, 0x25, 0x46, 0xd5, 0x4c}, + dt2: fp.Elt{0x53, 0x50, 0xac, 0xc2, 0x26, 0xc4, 0xf6, 0x4a, 0x58, 0x72, 0xf6, 0x32, 0xad, 0xed, 0x9a, 0xbc, 0x21, 0x10, 0x31, 0x0a, 0xf1, 0x32, 0xd0, 0x2a, 0x85, 0x8e, 0xcc, 0x6f, 0x7b, 0x35, 0x08, 0x70}, + }, + { /* 29P */ + addYX: fp.Elt{0x01, 0x3f, 0x77, 0x38, 0x27, 0x67, 0x88, 0x0b, 0xfb, 0xcc, 0xfb, 0x95, 0xfa, 0xc8, 0xcc, 0xb8, 0xb6, 0x29, 0xad, 0xb9, 0xa3, 0xd5, 0x2d, 0x8d, 0x6a, 0x0f, 0xad, 0x51, 0x98, 0x7e, 0xef, 0x06}, + subYX: fp.Elt{0x34, 0x4a, 0x58, 0x82, 0xbb, 0x9f, 0x1b, 0xd0, 0x2b, 0x79, 0xb4, 0xd2, 0x63, 0x64, 0xab, 0x47, 0x02, 0x62, 0x53, 0x48, 0x9c, 0x63, 0x31, 0xb6, 0x28, 0xd4, 0xd6, 0x69, 0x36, 0x2a, 0xa9, 0x13}, + dt2: fp.Elt{0xe5, 0x7d, 0x57, 0xc0, 0x1c, 0x77, 0x93, 0xca, 0x5c, 0xdc, 0x35, 0x50, 0x1e, 0xe4, 0x40, 0x75, 0x71, 0xe0, 0x02, 0xd8, 0x01, 0x0f, 0x68, 0x24, 0x6a, 0xf8, 0x2a, 0x8a, 0xdf, 0x6d, 0x29, 0x3c}, + }, + { /* 31P */ + addYX: fp.Elt{0x13, 0xa7, 0x14, 0xd9, 0xf9, 0x15, 0xad, 0xae, 0x12, 0xf9, 0x8f, 0x8c, 0xf9, 0x7b, 0x2f, 0xa9, 0x30, 0xd7, 0x53, 0x9f, 0x17, 0x23, 0xf8, 0xaf, 0xba, 0x77, 0x0c, 0x49, 0x93, 0xd3, 0x99, 0x7a}, + subYX: fp.Elt{0x41, 0x25, 0x1f, 0xbb, 0x2e, 0x4d, 0xeb, 0xfc, 0x1f, 0xb9, 0xad, 0x40, 0xc7, 0x10, 0x95, 0xb8, 0x05, 0xad, 0xa1, 0xd0, 0x7d, 0xa3, 0x71, 0xfc, 0x7b, 0x71, 0x47, 0x07, 0x70, 0x2c, 0x89, 0x0a}, + dt2: fp.Elt{0xe8, 0xa3, 0xbd, 0x36, 0x24, 0xed, 0x52, 0x8f, 0x94, 0x07, 0xe8, 0x57, 0x41, 0xc8, 0xa8, 0x77, 0xe0, 0x9c, 0x2f, 0x26, 0x63, 0x65, 0xa9, 0xa5, 0xd2, 0xf7, 0x02, 0x83, 0xd2, 0x62, 0x67, 0x28}, + }, + { /* 33P */ + addYX: fp.Elt{0x25, 0x5b, 0xe3, 0x3c, 0x09, 0x36, 0x78, 0x4e, 0x97, 0xaa, 0x6b, 0xb2, 0x1d, 0x18, 0xe1, 0x82, 0x3f, 0xb8, 0xc7, 0xcb, 0xd3, 0x92, 0xc1, 0x0c, 0x3a, 0x9d, 0x9d, 0x6a, 0x04, 0xda, 0xf1, 0x32}, + subYX: fp.Elt{0xbd, 0xf5, 0x2e, 0xce, 0x2b, 0x8e, 0x55, 0x7c, 0x63, 0xbc, 0x47, 0x67, 0xb4, 0x6c, 0x98, 0xe4, 0xb8, 0x89, 0xbb, 0x3b, 0x9f, 0x17, 0x4a, 0x15, 0x7a, 0x76, 0xf1, 0xd6, 0xa3, 0xf2, 0x86, 0x76}, + dt2: fp.Elt{0x6a, 0x7c, 0x59, 0x6d, 0xa6, 0x12, 0x8d, 0xaa, 0x2b, 0x85, 0xd3, 0x04, 0x03, 0x93, 0x11, 0x8f, 0x22, 0xb0, 0x09, 0xc2, 0x73, 0xdc, 0x91, 0x3f, 0xa6, 0x28, 0xad, 0xa9, 0xf8, 0x05, 0x13, 0x56}, + }, + { /* 35P */ + addYX: fp.Elt{0xd1, 0xae, 0x92, 0xec, 0x8d, 0x97, 0x0c, 0x10, 0xe5, 0x73, 0x6d, 0x4d, 0x43, 0xd5, 0x43, 0xca, 0x48, 0xba, 0x47, 0xd8, 0x22, 0x1b, 0x13, 0x83, 0x2c, 0x4d, 0x5d, 0xe3, 0x53, 0xec, 0xaa}, + subYX: fp.Elt{0xd5, 0xc0, 0xb0, 0xe7, 0x28, 0xcc, 0x22, 0x67, 0x53, 0x5c, 0x07, 0xdb, 0xbb, 0xe9, 0x9d, 0x70, 0x61, 0x0a, 0x01, 0xd7, 0xa7, 0x8d, 0xf6, 0xca, 0x6c, 0xcc, 0x57, 0x2c, 0xef, 0x1a, 0x0a, 0x03}, + dt2: fp.Elt{0xaa, 0xd2, 0x3a, 0x00, 0x73, 0xf7, 0xb1, 0x7b, 0x08, 0x66, 0x21, 0x2b, 0x80, 0x29, 0x3f, 0x0b, 0x3e, 0xd2, 0x0e, 0x52, 0x86, 0xdc, 0x21, 0x78, 0x80, 0x54, 0x06, 0x24, 0x1c, 0x9c, 0xbe, 0x20}, + }, + { /* 37P */ + addYX: fp.Elt{0xa6, 0x73, 0x96, 0x24, 0xd8, 0x87, 0x53, 0xe1, 0x93, 0xe4, 0x46, 0xf5, 0x2d, 0xbc, 0x43, 0x59, 0xb5, 0x63, 0x6f, 0xc3, 0x81, 0x9a, 0x7f, 0x1c, 0xde, 0xc1, 0x0a, 0x1f, 0x36, 0xb3, 0x0a, 0x75}, + subYX: fp.Elt{0x60, 0x5e, 0x02, 0xe2, 0x4a, 0xe4, 0xe0, 0x20, 0x38, 0xb9, 0xdc, 0xcb, 0x2f, 0x3b, 0x3b, 0xb0, 0x1c, 0x0d, 0x5a, 0xf9, 0x9c, 0x63, 0x5d, 0x10, 0x11, 0xe3, 0x67, 0x50, 0x54, 0x4c, 0x76, 0x69}, + dt2: fp.Elt{0x37, 0x10, 0xf8, 0xa2, 0x83, 0x32, 0x8a, 0x1e, 0xf1, 0xcb, 0x7f, 0xbd, 0x23, 0xda, 0x2e, 0x6f, 0x63, 0x25, 0x2e, 0xac, 0x5b, 0xd1, 0x2f, 0xb7, 0x40, 0x50, 0x07, 0xb7, 0x3f, 0x6b, 0xf9, 0x54}, + }, + { /* 39P */ + addYX: fp.Elt{0x79, 0x92, 0x66, 0x29, 0x04, 0xf2, 0xad, 0x0f, 0x4a, 0x72, 0x7d, 0x7d, 0x04, 0xa2, 0xdd, 0x3a, 0xf1, 0x60, 0x57, 0x8c, 0x82, 0x94, 0x3d, 0x6f, 0x9e, 0x53, 0xb7, 0x2b, 0xc5, 0xe9, 0x7f, 0x3d}, + subYX: fp.Elt{0xcd, 0x1e, 0xb1, 0x16, 0xc6, 0xaf, 0x7d, 0x17, 0x79, 0x64, 0x57, 0xfa, 0x9c, 0x4b, 0x76, 0x89, 0x85, 0xe7, 0xec, 0xe6, 0x10, 0xa1, 0xa8, 0xb7, 0xf0, 0xdb, 0x85, 0xbe, 0x9f, 0x83, 0xe6, 0x78}, + dt2: fp.Elt{0x6b, 0x85, 0xb8, 0x37, 0xf7, 0x2d, 0x33, 0x70, 0x8a, 0x17, 0x1a, 0x04, 0x43, 0x5d, 0xd0, 0x75, 0x22, 0x9e, 0xe5, 0xa0, 0x4a, 0xf7, 0x0f, 0x32, 0x42, 0x82, 0x08, 0x50, 0xf3, 0x68, 0xf2, 0x70}, + }, + { /* 41P */ + addYX: fp.Elt{0x47, 0x5f, 0x80, 0xb1, 0x83, 0x45, 0x86, 0x66, 0x19, 0x7c, 0xdd, 0x60, 0xd1, 0xc5, 0x35, 0xf5, 0x06, 0xb0, 0x4c, 0x1e, 0xb7, 0x4e, 0x87, 0xe9, 0xd9, 0x89, 0xd8, 0xfa, 0x5c, 0x34, 0x0d, 0x7c}, + subYX: fp.Elt{0x55, 0xf3, 0xdc, 0x70, 0x20, 0x11, 0x24, 0x23, 0x17, 0xe1, 0xfc, 0xe7, 0x7e, 0xc9, 0x0c, 0x38, 0x98, 0xb6, 0x52, 0x35, 0xed, 0xde, 0x1d, 0xb3, 0xb9, 0xc4, 0xb8, 0x39, 0xc0, 0x56, 0x4e, 0x40}, + dt2: fp.Elt{0x8a, 0x33, 0x78, 0x8c, 0x4b, 0x1f, 0x1f, 0x59, 0xe1, 0xb5, 0xe0, 0x67, 0xb1, 0x6a, 0x36, 0xa0, 0x44, 0x3d, 0x5f, 0xb4, 0x52, 0x41, 0xbc, 0x5c, 0x77, 0xc7, 0xae, 0x2a, 0x76, 0x54, 0xd7, 0x20}, + }, + { /* 43P */ + addYX: fp.Elt{0x58, 0xb7, 0x3b, 0xc7, 0x6f, 0xc3, 0x8f, 0x5e, 0x9a, 0xbb, 0x3c, 0x36, 0xa5, 0x43, 0xe5, 0xac, 0x22, 0xc9, 0x3b, 0x90, 0x7d, 0x4a, 0x93, 0xa9, 0x62, 0xec, 0xce, 0xf3, 0x46, 0x1e, 0x8f, 0x2b}, + subYX: fp.Elt{0x43, 0xf5, 0xb9, 0x35, 0xb1, 0xfe, 0x74, 0x9d, 0x6c, 0x95, 0x8c, 0xde, 0xf1, 0x7d, 0xb3, 0x84, 0xa9, 0x8b, 0x13, 0x57, 0x07, 0x2b, 0x32, 0xe9, 0xe1, 0x4c, 0x0b, 0x79, 0xa8, 0xad, 0xb8, 0x38}, + dt2: fp.Elt{0x5d, 0xf9, 0x51, 0xdf, 0x9c, 0x4a, 0xc0, 0xb5, 0xac, 0xde, 0x1f, 0xcb, 0xae, 0x52, 0x39, 0x2b, 0xda, 0x66, 0x8b, 0x32, 0x8b, 0x6d, 0x10, 0x1d, 0x53, 0x19, 0xba, 0xce, 0x32, 0xeb, 0x9a, 0x04}, + }, + { /* 45P */ + addYX: fp.Elt{0x31, 0x79, 0xfc, 0x75, 0x0b, 0x7d, 0x50, 0xaa, 0xd3, 0x25, 0x67, 0x7a, 0x4b, 0x92, 0xef, 0x0f, 0x30, 0x39, 0x6b, 0x39, 0x2b, 0x54, 0x82, 0x1d, 0xfc, 0x74, 0xf6, 0x30, 0x75, 0xe1, 0x5e, 0x79}, + subYX: fp.Elt{0x7e, 0xfe, 0xdc, 0x63, 0x3c, 0x7d, 0x76, 0xd7, 0x40, 0x6e, 0x85, 0x97, 0x48, 0x59, 0x9c, 0x20, 0x13, 0x7c, 0x4f, 0xe1, 0x61, 0x68, 0x67, 0xb6, 0xfc, 0x25, 0xd6, 0xc8, 0xe0, 0x65, 0xc6, 0x51}, + dt2: fp.Elt{0x81, 0xbd, 0xec, 0x52, 0x0a, 0x5b, 0x4a, 0x25, 0xe7, 0xaf, 0x34, 0xe0, 0x6e, 0x1f, 0x41, 0x5d, 0x31, 0x4a, 0xee, 0xca, 0x0d, 0x4d, 0xa2, 0xe6, 0x77, 0x44, 0xc5, 0x9d, 0xf4, 0x9b, 0xd1, 0x6c}, + }, + { /* 47P */ + addYX: fp.Elt{0x86, 0xc3, 0xaf, 0x65, 0x21, 0x61, 0xfe, 0x1f, 0x10, 0x1b, 0xd5, 0xb8, 0x88, 0x2a, 0x2a, 0x08, 0xaa, 0x0b, 0x99, 0x20, 0x7e, 0x62, 0xf6, 0x76, 0xe7, 0x43, 0x9e, 0x42, 0xa7, 0xb3, 0x01, 0x5e}, + subYX: fp.Elt{0xa3, 0x9c, 0x17, 0x52, 0x90, 0x61, 0x87, 0x7e, 0x85, 0x9f, 0x2c, 0x0b, 0x06, 0x0a, 0x1d, 0x57, 0x1e, 0x71, 0x99, 0x84, 0xa8, 0xba, 0xa2, 0x80, 0x38, 0xe6, 0xb2, 0x40, 0xdb, 0xf3, 0x20, 0x75}, + dt2: fp.Elt{0xa1, 0x57, 0x93, 0xd3, 0xe3, 0x0b, 0xb5, 0x3d, 0xa5, 0x94, 0x9e, 0x59, 0xdd, 0x6c, 0x7b, 0x96, 0x6e, 0x1e, 0x31, 0xdf, 0x64, 0x9a, 0x30, 0x1a, 0x86, 0xc9, 0xf3, 0xce, 0x9c, 0x2c, 0x09, 0x71}, + }, + { /* 49P */ + addYX: fp.Elt{0xcf, 0x1d, 0x05, 0x74, 0xac, 0xd8, 0x6b, 0x85, 0x1e, 0xaa, 0xb7, 0x55, 0x08, 0xa4, 0xf6, 0x03, 0xeb, 0x3c, 0x74, 0xc9, 0xcb, 0xe7, 0x4a, 0x3a, 0xde, 0xab, 0x37, 0x71, 0xbb, 0xa5, 0x73, 0x41}, + subYX: fp.Elt{0x8c, 0x91, 0x64, 0x03, 0x3f, 0x52, 0xd8, 0x53, 0x1c, 0x6b, 0xab, 0x3f, 0xf4, 0x04, 0xb4, 0xa2, 0xa4, 0xe5, 0x81, 0x66, 0x9e, 0x4a, 0x0b, 0x08, 0xa7, 0x7b, 0x25, 0xd0, 0x03, 0x5b, 0xa1, 0x0e}, + dt2: fp.Elt{0x8a, 0x21, 0xf9, 0xf0, 0x31, 0x6e, 0xc5, 0x17, 0x08, 0x47, 0xfc, 0x1a, 0x2b, 0x6e, 0x69, 0x5a, 0x76, 0xf1, 0xb2, 0xf4, 0x68, 0x16, 0x93, 0xf7, 0x67, 0x3a, 0x4e, 0x4a, 0x61, 0x65, 0xc5, 0x5f}, + }, + { /* 51P */ + addYX: fp.Elt{0x8e, 0x98, 0x90, 0x77, 0xe6, 0xe1, 0x92, 0x48, 0x22, 0xd7, 0x5c, 0x1c, 0x0f, 0x95, 0xd5, 0x01, 0xed, 0x3e, 0x92, 0xe5, 0x9a, 0x81, 0xb0, 0xe3, 0x1b, 0x65, 0x46, 0x9d, 0x40, 0xc7, 0x14, 0x32}, + subYX: fp.Elt{0xe5, 0x7a, 0x6d, 0xc4, 0x0d, 0x57, 0x6e, 0x13, 0x8f, 0xdc, 0xf8, 0x54, 0xcc, 0xaa, 0xd0, 0x0f, 0x86, 0xad, 0x0d, 0x31, 0x03, 0x9f, 0x54, 0x59, 0xa1, 0x4a, 0x45, 0x4c, 0x41, 0x1c, 0x71, 0x62}, + dt2: fp.Elt{0x70, 0x17, 0x65, 0x06, 0x74, 0x82, 0x29, 0x13, 0x36, 0x94, 0x27, 0x8a, 0x66, 0xa0, 0xa4, 0x3b, 0x3c, 0x22, 0x5d, 0x18, 0xec, 0xb8, 0xb6, 0xd9, 0x3c, 0x83, 0xcb, 0x3e, 0x07, 0x94, 0xea, 0x5b}, + }, + { /* 53P */ + addYX: fp.Elt{0xf8, 0xd2, 0x43, 0xf3, 0x63, 0xce, 0x70, 0xb4, 0xf1, 0xe8, 0x43, 0x05, 0x8f, 0xba, 0x67, 0x00, 0x6f, 0x7b, 0x11, 0xa2, 0xa1, 0x51, 0xda, 0x35, 0x2f, 0xbd, 0xf1, 0x44, 0x59, 0x78, 0xd0, 0x4a}, + subYX: fp.Elt{0xe4, 0x9b, 0xc8, 0x12, 0x09, 0xbf, 0x1d, 0x64, 0x9c, 0x57, 0x6e, 0x7d, 0x31, 0x8b, 0xf3, 0xac, 0x65, 0xb0, 0x97, 0xf6, 0x02, 0x9e, 0xfe, 0xab, 0xec, 0x1e, 0xf6, 0x48, 0xc1, 0xd5, 0xac, 0x3a}, + dt2: fp.Elt{0x01, 0x83, 0x31, 0xc3, 0x34, 0x3b, 0x8e, 0x85, 0x26, 0x68, 0x31, 0x07, 0x47, 0xc0, 0x99, 0xdc, 0x8c, 0xa8, 0x9d, 0xd3, 0x2e, 0x5b, 0x08, 0x34, 0x3d, 0x85, 0x02, 0xd9, 0xb1, 0x0c, 0xff, 0x3a}, + }, + { /* 55P */ + addYX: fp.Elt{0x05, 0x35, 0xc5, 0xf4, 0x0b, 0x43, 0x26, 0x92, 0x83, 0x22, 0x1f, 0x26, 0x13, 0x9c, 0xe4, 0x68, 0xc6, 0x27, 0xd3, 0x8f, 0x78, 0x33, 0xef, 0x09, 0x7f, 0x9e, 0xd9, 0x2b, 0x73, 0x9f, 0xcf, 0x2c}, + subYX: fp.Elt{0x5e, 0x40, 0x20, 0x3a, 0xeb, 0xc7, 0xc5, 0x87, 0xc9, 0x56, 0xad, 0xed, 0xef, 0x11, 0xe3, 0x8e, 0xf9, 0xd5, 0x29, 0xad, 0x48, 0x2e, 0x25, 0x29, 0x1d, 0x25, 0xcd, 0xf4, 0x86, 0x7e, 0x0e, 0x11}, + dt2: fp.Elt{0xe4, 0xf5, 0x03, 0xd6, 0x9e, 0xd8, 0xc0, 0x57, 0x0c, 0x20, 0xb0, 0xf0, 0x28, 0x86, 0x88, 0x12, 0xb7, 0x3b, 0x2e, 0xa0, 0x09, 0x27, 0x17, 0x53, 0x37, 0x3a, 0x69, 0xb9, 0xe0, 0x57, 0xc5, 0x05}, + }, + { /* 57P */ + addYX: fp.Elt{0xb0, 0x0e, 0xc2, 0x89, 0xb0, 0xbb, 0x76, 0xf7, 0x5c, 0xd8, 0x0f, 0xfa, 0xf6, 0x5b, 0xf8, 0x61, 0xfb, 0x21, 0x44, 0x63, 0x4e, 0x3f, 0xb9, 0xb6, 0x05, 0x12, 0x86, 0x41, 0x08, 0xef, 0x9f, 0x28}, + subYX: fp.Elt{0x6f, 0x7e, 0xc9, 0x1f, 0x31, 0xce, 0xf9, 0xd8, 0xae, 0xfd, 0xf9, 0x11, 0x30, 0x26, 0x3f, 0x7a, 0xdd, 0x25, 0xed, 0x8b, 0xa0, 0x7e, 0x5b, 0xe1, 0x5a, 0x87, 0xe9, 0x8f, 0x17, 0x4c, 0x15, 0x6e}, + dt2: fp.Elt{0xbf, 0x9a, 0xd6, 0xfe, 0x36, 0x63, 0x61, 0xcf, 0x4f, 0xc9, 0x35, 0x83, 0xe7, 0xe4, 0x16, 0x9b, 0xe7, 0x7f, 0x3a, 0x75, 0x65, 0x97, 0x78, 0x13, 0x19, 0xa3, 0x5c, 0xa9, 0x42, 0xf6, 0xfb, 0x6a}, + }, + { /* 59P */ + addYX: fp.Elt{0xcc, 0xa8, 0x13, 0xf9, 0x70, 0x50, 0xe5, 0x5d, 0x61, 0xf5, 0x0c, 0x2b, 0x7b, 0x16, 0x1d, 0x7d, 0x89, 0xd4, 0xea, 0x90, 0xb6, 0x56, 0x29, 0xda, 0xd9, 0x1e, 0x80, 0xdb, 0xce, 0x93, 0xc0, 0x12}, + subYX: fp.Elt{0xc1, 0xd2, 0xf5, 0x62, 0x0c, 0xde, 0xa8, 0x7d, 0x9a, 0x7b, 0x0e, 0xb0, 0xa4, 0x3d, 0xfc, 0x98, 0xe0, 0x70, 0xad, 0x0d, 0xda, 0x6a, 0xeb, 0x7d, 0xc4, 0x38, 0x50, 0xb9, 0x51, 0xb8, 0xb4, 0x0d}, + dt2: fp.Elt{0x0f, 0x19, 0xb8, 0x08, 0x93, 0x7f, 0x14, 0xfc, 0x10, 0xe3, 0x1a, 0xa1, 0xa0, 0x9d, 0x96, 0x06, 0xfd, 0xd7, 0xc7, 0xda, 0x72, 0x55, 0xe7, 0xce, 0xe6, 0x5c, 0x63, 0xc6, 0x99, 0x87, 0xaa, 0x33}, + }, + { /* 61P */ + addYX: fp.Elt{0xb1, 0x6c, 0x15, 0xfc, 0x88, 0xf5, 0x48, 0x83, 0x27, 0x6d, 0x0a, 0x1a, 0x9b, 0xba, 0xa2, 0x6d, 0xb6, 0x5a, 0xca, 0x87, 0x5c, 0x2d, 0x26, 0xe2, 0xa6, 0x89, 0xd5, 0xc8, 0xc1, 0xd0, 0x2c, 0x21}, + subYX: fp.Elt{0xf2, 0x5c, 0x08, 0xbd, 0x1e, 0xf5, 0x0f, 0xaf, 0x1f, 0x3f, 0xd3, 0x67, 0x89, 0x1a, 0xf5, 0x78, 0x3c, 0x03, 0x60, 0x50, 0xe1, 0xbf, 0xc2, 0x6e, 0x86, 0x1a, 0xe2, 0xe8, 0x29, 0x6f, 0x3c, 0x23}, + dt2: fp.Elt{0x81, 0xc7, 0x18, 0x7f, 0x10, 0xd5, 0xf4, 0xd2, 0x28, 0x9d, 0x7e, 0x52, 0xf2, 0xcd, 0x2e, 0x12, 0x41, 0x33, 0x3d, 0x3d, 0x2a, 0x86, 0x0a, 0xa7, 0xe3, 0x4c, 0x91, 0x11, 0x89, 0x77, 0xb7, 0x1d}, + }, + { /* 63P */ + addYX: fp.Elt{0xb6, 0x1a, 0x70, 0xdd, 0x69, 0x47, 0x39, 0xb3, 0xa5, 0x8d, 0xcf, 0x19, 0xd4, 0xde, 0xb8, 0xe2, 0x52, 0xc8, 0x2a, 0xfd, 0x61, 0x41, 0xdf, 0x15, 0xbe, 0x24, 0x7d, 0x01, 0x8a, 0xca, 0xe2, 0x7a}, + subYX: fp.Elt{0x6f, 0xc2, 0x6b, 0x7c, 0x39, 0x52, 0xf3, 0xdd, 0x13, 0x01, 0xd5, 0x53, 0xcc, 0xe2, 0x97, 0x7a, 0x30, 0xa3, 0x79, 0xbf, 0x3a, 0xf4, 0x74, 0x7c, 0xfc, 0xad, 0xe2, 0x26, 0xad, 0x97, 0xad, 0x31}, + dt2: fp.Elt{0x62, 0xb9, 0x20, 0x09, 0xed, 0x17, 0xe8, 0xb7, 0x9d, 0xda, 0x19, 0x3f, 0xcc, 0x18, 0x85, 0x1e, 0x64, 0x0a, 0x56, 0x25, 0x4f, 0xc1, 0x91, 0xe4, 0x83, 0x2c, 0x62, 0xa6, 0x53, 0xfc, 0xd1, 0x1e}, + }, +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go b/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go new file mode 100644 index 00000000..c368b181 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go @@ -0,0 +1,411 @@ +// Package ed448 implements Ed448 signature scheme as described in RFC-8032. +// +// This package implements two signature variants. +// +// | Scheme Name | Sign Function | Verification | Context | +// |-------------|-------------------|---------------|-------------------| +// | Ed448 | Sign | Verify | Yes, can be empty | +// | Ed448Ph | SignPh | VerifyPh | Yes, can be empty | +// | All above | (PrivateKey).Sign | VerifyAny | As above | +// +// Specific functions for sign and verify are defined. A generic signing +// function for all schemes is available through the crypto.Signer interface, +// which is implemented by the PrivateKey type. A correspond all-in-one +// verification method is provided by the VerifyAny function. +// +// Both schemes require a context string for domain separation. This parameter +// is passed using a SignerOptions struct defined in this package. +// +// References: +// +// - RFC8032: https://rfc-editor.org/rfc/rfc8032.txt +// - EdDSA for more curves: https://eprint.iacr.org/2015/677 +// - High-speed high-security signatures: https://doi.org/10.1007/s13389-012-0027-1 +package ed448 + +import ( + "bytes" + "crypto" + cryptoRand "crypto/rand" + "crypto/subtle" + "errors" + "fmt" + "io" + "strconv" + + "github.com/cloudflare/circl/ecc/goldilocks" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/sign" +) + +const ( + // ContextMaxSize is the maximum length (in bytes) allowed for context. + ContextMaxSize = 255 + // PublicKeySize is the length in bytes of Ed448 public keys. + PublicKeySize = 57 + // PrivateKeySize is the length in bytes of Ed448 private keys. + PrivateKeySize = 114 + // SignatureSize is the length in bytes of signatures. + SignatureSize = 114 + // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. + SeedSize = 57 +) + +const ( + paramB = 456 / 8 // Size of keys in bytes. + hashSize = 2 * paramB // Size of the hash function's output. +) + +// SignerOptions implements crypto.SignerOpts and augments with parameters +// that are specific to the Ed448 signature schemes. +type SignerOptions struct { + // Hash must be crypto.Hash(0) for both Ed448 and Ed448Ph. + crypto.Hash + + // Context is an optional domain separation string for signing. + // Its length must be less or equal than 255 bytes. + Context string + + // Scheme is an identifier for choosing a signature scheme. + Scheme SchemeID +} + +// SchemeID is an identifier for each signature scheme. +type SchemeID uint + +const ( + ED448 SchemeID = iota + ED448Ph +) + +// PublicKey is the type of Ed448 public keys. +type PublicKey []byte + +// Equal reports whether pub and x have the same value. +func (pub PublicKey) Equal(x crypto.PublicKey) bool { + xx, ok := x.(PublicKey) + return ok && bytes.Equal(pub, xx) +} + +// PrivateKey is the type of Ed448 private keys. It implements crypto.Signer. +type PrivateKey []byte + +// Equal reports whether priv and x have the same value. +func (priv PrivateKey) Equal(x crypto.PrivateKey) bool { + xx, ok := x.(PrivateKey) + return ok && subtle.ConstantTimeCompare(priv, xx) == 1 +} + +// Public returns the PublicKey corresponding to priv. +func (priv PrivateKey) Public() crypto.PublicKey { + publicKey := make([]byte, PublicKeySize) + copy(publicKey, priv[SeedSize:]) + return PublicKey(publicKey) +} + +// Seed returns the private key seed corresponding to priv. It is provided for +// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds +// in this package. +func (priv PrivateKey) Seed() []byte { + seed := make([]byte, SeedSize) + copy(seed, priv[:SeedSize]) + return seed +} + +func (priv PrivateKey) Scheme() sign.Scheme { return sch } + +func (pub PublicKey) Scheme() sign.Scheme { return sch } + +func (priv PrivateKey) MarshalBinary() (data []byte, err error) { + privateKey := make(PrivateKey, PrivateKeySize) + copy(privateKey, priv) + return privateKey, nil +} + +func (pub PublicKey) MarshalBinary() (data []byte, err error) { + publicKey := make(PublicKey, PublicKeySize) + copy(publicKey, pub) + return publicKey, nil +} + +// Sign creates a signature of a message given a key pair. +// This function supports all the two signature variants defined in RFC-8032, +// namely Ed448 (or pure EdDSA) and Ed448Ph. +// The opts.HashFunc() must return zero to the specify Ed448 variant. This can +// be achieved by passing crypto.Hash(0) as the value for opts. +// Use an Options struct to pass a bool indicating that the ed448Ph variant +// should be used. +// The struct can also be optionally used to pass a context string for signing. +func (priv PrivateKey) Sign( + rand io.Reader, + message []byte, + opts crypto.SignerOpts, +) (signature []byte, err error) { + var ctx string + var scheme SchemeID + + if o, ok := opts.(SignerOptions); ok { + ctx = o.Context + scheme = o.Scheme + } + + switch true { + case scheme == ED448 && opts.HashFunc() == crypto.Hash(0): + return Sign(priv, message, ctx), nil + case scheme == ED448Ph && opts.HashFunc() == crypto.Hash(0): + return SignPh(priv, message, ctx), nil + default: + return nil, errors.New("ed448: bad hash algorithm") + } +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { + if rand == nil { + rand = cryptoRand.Reader + } + + seed := make(PrivateKey, SeedSize) + if _, err := io.ReadFull(rand, seed); err != nil { + return nil, nil, err + } + + privateKey := NewKeyFromSeed(seed) + publicKey := make([]byte, PublicKeySize) + copy(publicKey, privateKey[SeedSize:]) + + return publicKey, privateKey, nil +} + +// NewKeyFromSeed calculates a private key from a seed. It will panic if +// len(seed) is not SeedSize. This function is provided for interoperability +// with RFC 8032. RFC 8032's private keys correspond to seeds in this +// package. +func NewKeyFromSeed(seed []byte) PrivateKey { + privateKey := make([]byte, PrivateKeySize) + newKeyFromSeed(privateKey, seed) + return privateKey +} + +func newKeyFromSeed(privateKey, seed []byte) { + if l := len(seed); l != SeedSize { + panic("ed448: bad seed length: " + strconv.Itoa(l)) + } + + var h [hashSize]byte + H := sha3.NewShake256() + _, _ = H.Write(seed) + _, _ = H.Read(h[:]) + s := &goldilocks.Scalar{} + deriveSecretScalar(s, h[:paramB]) + + copy(privateKey[:SeedSize], seed) + _ = goldilocks.Curve{}.ScalarBaseMult(s).ToBytes(privateKey[SeedSize:]) +} + +func signAll(signature []byte, privateKey PrivateKey, message, ctx []byte, preHash bool) { + if len(ctx) > ContextMaxSize { + panic(fmt.Errorf("ed448: bad context length: %v", len(ctx))) + } + + H := sha3.NewShake256() + var PHM []byte + + if preHash { + var h [64]byte + _, _ = H.Write(message) + _, _ = H.Read(h[:]) + PHM = h[:] + H.Reset() + } else { + PHM = message + } + + // 1. Hash the 57-byte private key using SHAKE256(x, 114). + var h [hashSize]byte + _, _ = H.Write(privateKey[:SeedSize]) + _, _ = H.Read(h[:]) + s := &goldilocks.Scalar{} + deriveSecretScalar(s, h[:paramB]) + prefix := h[paramB:] + + // 2. Compute SHAKE256(dom4(F, C) || prefix || PH(M), 114). + var rPM [hashSize]byte + H.Reset() + + writeDom(&H, ctx, preHash) + + _, _ = H.Write(prefix) + _, _ = H.Write(PHM) + _, _ = H.Read(rPM[:]) + + // 3. Compute the point [r]B. + r := &goldilocks.Scalar{} + r.FromBytes(rPM[:]) + R := (&[paramB]byte{})[:] + if err := (goldilocks.Curve{}.ScalarBaseMult(r).ToBytes(R)); err != nil { + panic(err) + } + // 4. Compute SHAKE256(dom4(F, C) || R || A || PH(M), 114) + var hRAM [hashSize]byte + H.Reset() + + writeDom(&H, ctx, preHash) + + _, _ = H.Write(R) + _, _ = H.Write(privateKey[SeedSize:]) + _, _ = H.Write(PHM) + _, _ = H.Read(hRAM[:]) + + // 5. Compute S = (r + k * s) mod order. + k := &goldilocks.Scalar{} + k.FromBytes(hRAM[:]) + S := &goldilocks.Scalar{} + S.Mul(k, s) + S.Add(S, r) + + // 6. The signature is the concatenation of R and S. + copy(signature[:paramB], R[:]) + copy(signature[paramB:], S[:]) +} + +// Sign signs the message with privateKey and returns a signature. +// This function supports the signature variant defined in RFC-8032: Ed448, +// also known as the pure version of EdDSA. +// It will panic if len(privateKey) is not PrivateKeySize. +func Sign(priv PrivateKey, message []byte, ctx string) []byte { + signature := make([]byte, SignatureSize) + signAll(signature, priv, message, []byte(ctx), false) + return signature +} + +// SignPh creates a signature of a message given a keypair. +// This function supports the signature variant defined in RFC-8032: Ed448ph, +// meaning it internally hashes the message using SHAKE-256. +// Context could be passed to this function, which length should be no more than +// 255. It can be empty. +func SignPh(priv PrivateKey, message []byte, ctx string) []byte { + signature := make([]byte, SignatureSize) + signAll(signature, priv, message, []byte(ctx), true) + return signature +} + +func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool { + if len(public) != PublicKeySize || + len(signature) != SignatureSize || + len(ctx) > ContextMaxSize || + !isLessThanOrder(signature[paramB:]) { + return false + } + + P, err := goldilocks.FromBytes(public) + if err != nil { + return false + } + + H := sha3.NewShake256() + var PHM []byte + + if preHash { + var h [64]byte + _, _ = H.Write(message) + _, _ = H.Read(h[:]) + PHM = h[:] + H.Reset() + } else { + PHM = message + } + + var hRAM [hashSize]byte + R := signature[:paramB] + + writeDom(&H, ctx, preHash) + + _, _ = H.Write(R) + _, _ = H.Write(public) + _, _ = H.Write(PHM) + _, _ = H.Read(hRAM[:]) + + k := &goldilocks.Scalar{} + k.FromBytes(hRAM[:]) + S := &goldilocks.Scalar{} + S.FromBytes(signature[paramB:]) + + encR := (&[paramB]byte{})[:] + P.Neg() + _ = goldilocks.Curve{}.CombinedMult(S, k, P).ToBytes(encR) + return bytes.Equal(R, encR) +} + +// VerifyAny returns true if the signature is valid. Failure cases are invalid +// signature, or when the public key cannot be decoded. +// This function supports all the two signature variants defined in RFC-8032, +// namely Ed448 (or pure EdDSA) and Ed448Ph. +// The opts.HashFunc() must return zero, this can be achieved by passing +// crypto.Hash(0) as the value for opts. +// Use a SignerOptions struct to pass a context string for signing. +func VerifyAny(public PublicKey, message, signature []byte, opts crypto.SignerOpts) bool { + var ctx string + var scheme SchemeID + if o, ok := opts.(SignerOptions); ok { + ctx = o.Context + scheme = o.Scheme + } + + switch true { + case scheme == ED448 && opts.HashFunc() == crypto.Hash(0): + return Verify(public, message, signature, ctx) + case scheme == ED448Ph && opts.HashFunc() == crypto.Hash(0): + return VerifyPh(public, message, signature, ctx) + default: + return false + } +} + +// Verify returns true if the signature is valid. Failure cases are invalid +// signature, or when the public key cannot be decoded. +// This function supports the signature variant defined in RFC-8032: Ed448, +// also known as the pure version of EdDSA. +func Verify(public PublicKey, message, signature []byte, ctx string) bool { + return verify(public, message, signature, []byte(ctx), false) +} + +// VerifyPh returns true if the signature is valid. Failure cases are invalid +// signature, or when the public key cannot be decoded. +// This function supports the signature variant defined in RFC-8032: Ed448ph, +// meaning it internally hashes the message using SHAKE-256. +// Context could be passed to this function, which length should be no more than +// 255. It can be empty. +func VerifyPh(public PublicKey, message, signature []byte, ctx string) bool { + return verify(public, message, signature, []byte(ctx), true) +} + +func deriveSecretScalar(s *goldilocks.Scalar, h []byte) { + h[0] &= 0xFC // The two least significant bits of the first octet are cleared, + h[paramB-1] = 0x00 // all eight bits the last octet are cleared, and + h[paramB-2] |= 0x80 // the highest bit of the second to last octet is set. + s.FromBytes(h[:paramB]) +} + +// isLessThanOrder returns true if 0 <= x < order and if the last byte of x is zero. +func isLessThanOrder(x []byte) bool { + order := goldilocks.Curve{}.Order() + i := len(order) - 1 + for i > 0 && x[i] == order[i] { + i-- + } + return x[paramB-1] == 0 && x[i] < order[i] +} + +func writeDom(h io.Writer, ctx []byte, preHash bool) { + dom4 := "SigEd448" + _, _ = h.Write([]byte(dom4)) + + if preHash { + _, _ = h.Write([]byte{byte(0x01), byte(len(ctx))}) + } else { + _, _ = h.Write([]byte{byte(0x00), byte(len(ctx))}) + } + _, _ = h.Write(ctx) +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go b/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go new file mode 100644 index 00000000..22da8bc0 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go @@ -0,0 +1,87 @@ +package ed448 + +import ( + "crypto/rand" + "encoding/asn1" + + "github.com/cloudflare/circl/sign" +) + +var sch sign.Scheme = &scheme{} + +// Scheme returns a signature interface. +func Scheme() sign.Scheme { return sch } + +type scheme struct{} + +func (*scheme) Name() string { return "Ed448" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } +func (*scheme) TLSIdentifier() uint { return 0x0808 } +func (*scheme) SupportsContext() bool { return true } +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{1, 3, 101, 113} +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(rand.Reader) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + message []byte, + opts *sign.SignatureOpts, +) []byte { + priv, ok := sk.(PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + ctx := "" + if opts != nil { + ctx = opts.Context + } + return Sign(priv, message, ctx) +} + +func (*scheme) Verify( + pk sign.PublicKey, + message, signature []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + ctx := "" + if opts != nil { + ctx = opts.Context + } + return Verify(pub, message, signature, ctx) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + privateKey := NewKeyFromSeed(seed) + publicKey := make(PublicKey, PublicKeySize) + copy(publicKey, privateKey[SeedSize:]) + return publicKey, privateKey +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) < PublicKeySize { + return nil, sign.ErrPubKeySize + } + pub := make(PublicKey, PublicKeySize) + copy(pub, buf[:PublicKeySize]) + return pub, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) < PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + priv := make(PrivateKey, PrivateKeySize) + copy(priv, buf[:PrivateKeySize]) + return priv, nil +} diff --git a/vendor/github.com/cloudflare/circl/sign/eddilithium2/eddilithium.go b/vendor/github.com/cloudflare/circl/sign/eddilithium2/eddilithium.go new file mode 100644 index 00000000..9ab44019 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/eddilithium2/eddilithium.go @@ -0,0 +1,239 @@ +// Package eddilithium2 implements the hybrid signature scheme Ed25519-Dilithium2. +package eddilithium2 + +import ( + "crypto" + cryptoRand "crypto/rand" + "errors" + "io" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/dilithium/mode2" + "github.com/cloudflare/circl/sign/ed25519" +) + +const ( + // SeedSize is the length of the seed for NewKeyFromSeed + SeedSize = mode2.SeedSize // = ed25519.SeedSize = 32 + + // PublicKeySize is the length in bytes of the packed public key. + PublicKeySize = mode2.PublicKeySize + ed25519.PublicKeySize + + // PrivateKeySize is the length in bytes of the packed public key. + PrivateKeySize = mode2.PrivateKeySize + ed25519.SeedSize + + // SignatureSize is the length in bytes of the signatures. + SignatureSize = mode2.SignatureSize + ed25519.SignatureSize +) + +// PublicKey is the type of an EdDilithium2 public key. +type PublicKey struct { + e ed25519.PublicKey + d mode2.PublicKey +} + +// PrivateKey is the type of an EdDilithium2 private key. +type PrivateKey struct { + e ed25519.PrivateKey + d mode2.PrivateKey +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [SeedSize]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + var seed1 [32]byte + var seed2 [ed25519.SeedSize]byte + + // Internally, Ed25519 and Dilithium hash the seeds they are passed again + // with different hash functions, so it would be safe to use exactly the + // same seed for Ed25519 and Dilithium here. However, in general, when + // combining any two signature schemes it might not be the case that this + // is safe. Setting a bad example here isn't worth the tiny gain in + // performance. + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(seed1[:]) + _, _ = h.Read(seed2[:]) + dpk, dsk := mode2.NewKeyFromSeed(&seed1) + esk := ed25519.NewKeyFromSeed(seed2[:]) + + return &PublicKey{esk.Public().(ed25519.PublicKey), *dpk}, &PrivateKey{esk, *dsk} +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +func SignTo(sk *PrivateKey, msg []byte, signature []byte) { + mode2.SignTo( + &sk.d, + msg, + signature[:mode2.SignatureSize], + ) + esig := ed25519.Sign( + sk.e, + msg, + ) + copy(signature[mode2.SignatureSize:], esig[:]) +} + +// Verify checks whether the given signature by pk on msg is valid. +func Verify(pk *PublicKey, msg []byte, signature []byte) bool { + if !mode2.Verify( + &pk.d, + msg, + signature[:mode2.SignatureSize], + ) { + return false + } + if !ed25519.Verify( + pk.e, + msg, + signature[mode2.SignatureSize:], + ) { + return false + } + return true +} + +// Unpack unpacks pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + var tmp [mode2.PublicKeySize]byte + copy(tmp[:], buf[:mode2.PublicKeySize]) + pk.d.Unpack(&tmp) + pk.e = make([]byte, ed25519.PublicKeySize) + copy(pk.e, buf[mode2.PublicKeySize:]) +} + +// Unpack sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + var tmp [mode2.PrivateKeySize]byte + copy(tmp[:], buf[:mode2.PrivateKeySize]) + sk.d.Unpack(&tmp) + sk.e = ed25519.NewKeyFromSeed(buf[mode2.PrivateKeySize:]) +} + +// Pack packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + var tmp [mode2.PublicKeySize]byte + pk.d.Pack(&tmp) + copy(buf[:mode2.PublicKeySize], tmp[:]) + copy(buf[mode2.PublicKeySize:], pk.e) +} + +// Pack packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + var tmp [mode2.PrivateKeySize]byte + sk.d.Pack(&tmp) + copy(buf[:mode2.PrivateKeySize], tmp[:]) + copy(buf[mode2.PrivateKeySize:], sk.e.Seed()) +} + +// Bytes packs the public key. +func (pk *PublicKey) Bytes() []byte { + return append(pk.d.Bytes(), pk.e...) +} + +// Bytes packs the private key. +func (sk *PrivateKey) Bytes() []byte { + return append(sk.d.Bytes(), sk.e.Seed()...) +} + +// MarshalBinary packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// MarshalBinary packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// UnmarshalBinary the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of eddilithium2.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// UnmarshalBinary unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of eddilithium2.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { return sch } +func (pk *PublicKey) Scheme() sign.Scheme { return sch } + +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return castOther.e.Equal(sk.e) && castOther.d.Equal(&sk.d) +} + +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return castOther.e.Equal(pk.e) && castOther.d.Equal(&pk.d) +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign( + rand io.Reader, msg []byte, opts crypto.SignerOpts, +) (signature []byte, err error) { + var sig [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("eddilithium2: cannot sign hashed message") + } + + SignTo(sk, msg, sig[:]) + return sig[:], nil +} + +// Public computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return &PublicKey{ + sk.e.Public().(ed25519.PublicKey), + *sk.d.Public().(*mode2.PublicKey), + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/eddilithium2/signapi.go b/vendor/github.com/cloudflare/circl/sign/eddilithium2/signapi.go new file mode 100644 index 00000000..0339243e --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/eddilithium2/signapi.go @@ -0,0 +1,93 @@ +package eddilithium2 + +import ( + "crypto/rand" + "encoding/asn1" + + "github.com/cloudflare/circl/sign" +) + +var sch sign.Scheme = &scheme{} + +// Scheme returns a signature interface. +func Scheme() sign.Scheme { return sch } + +type scheme struct{} + +func (*scheme) Name() string { return "Ed25519-Dilithium2" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } +func (*scheme) TLSIdentifier() uint { return 0xfe61 /* temp*/ } +func (*scheme) SupportsContext() bool { return false } +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 45, 9} +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(rand.Reader) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + message []byte, + opts *sign.SignatureOpts, +) []byte { + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + var sig [SignatureSize]byte + SignTo(priv, message, sig[:]) + return sig[:] +} + +func (*scheme) Verify( + pk sign.PublicKey, + message, signature []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, message, signature) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var tmp [SeedSize]byte + copy(tmp[:], seed) + return NewKeyFromSeed(&tmp) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + var tmp [PublicKeySize]byte + copy(tmp[:], buf) + var ret PublicKey + ret.Unpack(&tmp) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + var tmp [PrivateKeySize]byte + copy(tmp[:], buf) + var ret PrivateKey + ret.Unpack(&tmp) + return &ret, nil +} diff --git a/vendor/github.com/cloudflare/circl/sign/eddilithium3/eddilithium.go b/vendor/github.com/cloudflare/circl/sign/eddilithium3/eddilithium.go new file mode 100644 index 00000000..aa05c689 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/eddilithium3/eddilithium.go @@ -0,0 +1,234 @@ +// Package eddilithium3 implements the hybrid signature scheme Ed448-Dilithium3. +package eddilithium3 + +import ( + "crypto" + cryptoRand "crypto/rand" + "errors" + "io" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/dilithium/mode3" + "github.com/cloudflare/circl/sign/ed448" +) + +const ( + // SeedSize is the length of the seed for NewKeyFromSeed + SeedSize = ed448.SeedSize // > mode3.SeedSize + + // PublicKeySize is the length in bytes of the packed public key. + PublicKeySize = mode3.PublicKeySize + ed448.PublicKeySize + + // PrivateKeySize is the length in bytes of the packed public key. + PrivateKeySize = mode3.PrivateKeySize + ed448.SeedSize + + // SignatureSize is the length in bytes of the signatures. + SignatureSize = mode3.SignatureSize + ed448.SignatureSize +) + +// PublicKey is the type of an EdDilithium3 public key. +type PublicKey struct { + e ed448.PublicKey + d mode3.PublicKey +} + +// PrivateKey is the type of an EdDilithium3 private key. +type PrivateKey struct { + e ed448.PrivateKey + d mode3.PrivateKey +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [SeedSize]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + var seed1 [32]byte + var seed2 [ed448.SeedSize]byte + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(seed1[:]) + _, _ = h.Read(seed2[:]) + dpk, dsk := mode3.NewKeyFromSeed(&seed1) + esk := ed448.NewKeyFromSeed(seed2[:]) + + return &PublicKey{esk.Public().(ed448.PublicKey), *dpk}, &PrivateKey{esk, *dsk} +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +func SignTo(sk *PrivateKey, msg []byte, signature []byte) { + mode3.SignTo( + &sk.d, + msg, + signature[:mode3.SignatureSize], + ) + esig := ed448.Sign( + sk.e, + msg, + "", + ) + copy(signature[mode3.SignatureSize:], esig[:]) +} + +// Verify checks whether the given signature by pk on msg is valid. +func Verify(pk *PublicKey, msg []byte, signature []byte) bool { + if !mode3.Verify( + &pk.d, + msg, + signature[:mode3.SignatureSize], + ) { + return false + } + if !ed448.Verify( + pk.e, + msg, + signature[mode3.SignatureSize:], + "", + ) { + return false + } + return true +} + +// Unpack unpacks pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + var tmp [mode3.PublicKeySize]byte + copy(tmp[:], buf[:mode3.PublicKeySize]) + pk.d.Unpack(&tmp) + pk.e = make([]byte, ed448.PublicKeySize) + copy(pk.e, buf[mode3.PublicKeySize:]) +} + +// Unpack sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + var tmp [mode3.PrivateKeySize]byte + copy(tmp[:], buf[:mode3.PrivateKeySize]) + sk.d.Unpack(&tmp) + sk.e = ed448.NewKeyFromSeed(buf[mode3.PrivateKeySize:]) +} + +// Pack packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + var tmp [mode3.PublicKeySize]byte + pk.d.Pack(&tmp) + copy(buf[:mode3.PublicKeySize], tmp[:]) + copy(buf[mode3.PublicKeySize:], pk.e) +} + +// Pack packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + var tmp [mode3.PrivateKeySize]byte + sk.d.Pack(&tmp) + copy(buf[:mode3.PrivateKeySize], tmp[:]) + copy(buf[mode3.PrivateKeySize:], sk.e.Seed()) +} + +// Bytes packs the public key. +func (pk *PublicKey) Bytes() []byte { + return append(pk.d.Bytes(), pk.e...) +} + +// Bytes packs the private key. +func (sk *PrivateKey) Bytes() []byte { + return append(sk.d.Bytes(), sk.e.Seed()...) +} + +// MarshalBinary packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// MarshalBinary packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// UnmarshalBinary the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of eddilithium3.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// UnmarshalBinary unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of eddilithium3.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { return sch } +func (pk *PublicKey) Scheme() sign.Scheme { return sch } + +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return castOther.e.Equal(sk.e) && castOther.d.Equal(&sk.d) +} + +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return castOther.e.Equal(pk.e) && castOther.d.Equal(&pk.d) +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign( + rand io.Reader, msg []byte, opts crypto.SignerOpts, +) (signature []byte, err error) { + var sig [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("eddilithium3: cannot sign hashed message") + } + + SignTo(sk, msg, sig[:]) + return sig[:], nil +} + +// Public computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return &PublicKey{ + sk.e.Public().(ed448.PublicKey), + *sk.d.Public().(*mode3.PublicKey), + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/eddilithium3/signapi.go b/vendor/github.com/cloudflare/circl/sign/eddilithium3/signapi.go new file mode 100644 index 00000000..1c345cfb --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/eddilithium3/signapi.go @@ -0,0 +1,93 @@ +package eddilithium3 + +import ( + "crypto/rand" + "encoding/asn1" + + "github.com/cloudflare/circl/sign" +) + +var sch sign.Scheme = &scheme{} + +// Scheme returns a signature interface. +func Scheme() sign.Scheme { return sch } + +type scheme struct{} + +func (*scheme) Name() string { return "Ed448-Dilithium3" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } +func (*scheme) TLSIdentifier() uint { return 0xfe62 /* temp */ } +func (*scheme) SupportsContext() bool { return false } +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 45, 10} +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(rand.Reader) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + message []byte, + opts *sign.SignatureOpts, +) []byte { + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + var sig [SignatureSize]byte + SignTo(priv, message, sig[:]) + return sig[:] +} + +func (*scheme) Verify( + pk sign.PublicKey, + message, signature []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, message, signature) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var tmp [SeedSize]byte + copy(tmp[:], seed) + return NewKeyFromSeed(&tmp) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + var tmp [PublicKeySize]byte + copy(tmp[:], buf) + var ret PublicKey + ret.Unpack(&tmp) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + var tmp [PrivateKeySize]byte + copy(tmp[:], buf) + var ret PrivateKey + ret.Unpack(&tmp) + return &ret, nil +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go new file mode 100644 index 00000000..d5d224ee --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go @@ -0,0 +1,154 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package dilithium + +import ( + "golang.org/x/sys/cpu" +) + +// Execute an in-place forward NTT on as. +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation, +// but are only bounded bt 18*Q. +func (p *Poly) NTT() { + if cpu.X86.HasAVX2 { + nttAVX2( + (*[N]uint32)(p), + ) + } else { + p.nttGeneric() + } +} + +// Execute an in-place inverse NTT and multiply by Montgomery factor R +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation +// and bounded by 2*Q. +func (p *Poly) InvNTT() { + if cpu.X86.HasAVX2 { + invNttAVX2( + (*[N]uint32)(p), + ) + } else { + p.invNttGeneric() + } +} + +// Sets p to the polynomial whose coefficients are the pointwise multiplication +// of those of a and b. The coefficients of p are bounded by 2q. +// +// Assumes a and b are in Montgomery form and that the pointwise product +// of each coefficient is below 2³² q. +func (p *Poly) MulHat(a, b *Poly) { + if cpu.X86.HasAVX2 { + mulHatAVX2( + (*[N]uint32)(p), + (*[N]uint32)(a), + (*[N]uint32)(b), + ) + } else { + p.mulHatGeneric(a, b) + } +} + +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Add(a, b *Poly) { + if cpu.X86.HasAVX2 { + addAVX2( + (*[N]uint32)(p), + (*[N]uint32)(a), + (*[N]uint32)(b), + ) + } else { + p.addGeneric(a, b) + } +} + +// Sets p to a - b. +// +// Warning: assumes coefficients of b are less than 2q. +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Sub(a, b *Poly) { + if cpu.X86.HasAVX2 { + subAVX2( + (*[N]uint32)(p), + (*[N]uint32)(a), + (*[N]uint32)(b), + ) + } else { + p.subGeneric(a, b) + } +} + +// Writes p whose coefficients are in [0, 16) to buf, which must be of +// length N/2. +func (p *Poly) PackLe16(buf []byte) { + if cpu.X86.HasAVX2 { + if len(buf) < PolyLe16Size { + panic("buf too small") + } + packLe16AVX2( + (*[N]uint32)(p), + &buf[0], + ) + } else { + p.packLe16Generic(buf) + } +} + +// Reduces each of the coefficients to <2q. +func (p *Poly) ReduceLe2Q() { + if cpu.X86.HasAVX2 { + reduceLe2QAVX2((*[N]uint32)(p)) + } else { + p.reduceLe2QGeneric() + } +} + +// Reduce each of the coefficients to > 23 + x2 := x & 0x7FFFFF // 2²³-1 + return x2 + (x1 << 13) - x1 +} + +// Returns x mod q. +func modQ(x uint32) uint32 { + return le2qModQ(ReduceLe2Q(x)) +} + +// For x R ≤ q 2³², find y ≤ 2q with y = x mod q. +func montReduceLe2Q(x uint64) uint32 { + // Qinv = 4236238847 = -(q⁻¹) mod 2³² + m := (x * Qinv) & 0xffffffff + return uint32((x + m*uint64(Q)) >> 32) +} + +// Returns x mod q for 0 ≤ x < 2q. +func le2qModQ(x uint32) uint32 { + x -= Q + mask := uint32(int32(x) >> 31) // mask is 2³²-1 if x was neg.; 0 otherwise + return x + (mask & Q) +} + +// Splits 0 ≤ a < Q into a0 and a1 with a = a1*2ᴰ + a0 +// and -2ᴰ⁻¹ < a0 < 2ᴰ⁻¹. Returns a0 + Q and a1. +func power2round(a uint32) (a0plusQ, a1 uint32) { + // We effectively compute a0 = a mod± 2ᵈ + // and a1 = (a - a0) / 2ᵈ. + a0 := a & ((1 << D) - 1) // a mod 2ᵈ + + // a0 is one of 0, 1, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹, 2ᵈ⁻¹+1, ..., 2ᵈ-1 + a0 -= (1 << (D - 1)) + 1 + // now a0 is -2ᵈ⁻¹-1, -2ᵈ⁻¹, ..., -2, -1, 0, ..., 2ᵈ⁻¹-2 + // Next, we add 2ᴰ to those a0 that are negative (seen as int32). + a0 += uint32(int32(a0)>>31) & (1 << D) + // now a0 is 2ᵈ⁻¹-1, 2ᵈ⁻¹, ..., 2ᵈ-2, 2ᵈ-1, 0, ..., 2ᵈ⁻¹-2 + a0 -= (1 << (D - 1)) - 1 + // now a0 id 0, 1, 2, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹-1, -2ᵈ⁻¹-1, ... + // which is what we want. + a0plusQ = Q + a0 + a1 = (a - a0) >> D + return +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go new file mode 100644 index 00000000..25321f5d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go @@ -0,0 +1,81 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +package dilithium + +// Execute an in-place forward NTT on as. +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation, +// but are only bounded bt 18*Q. +func (p *Poly) NTT() { + p.nttGeneric() +} + +// Execute an in-place inverse NTT and multiply by Montgomery factor R +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation +// and bounded by 2*Q. +func (p *Poly) InvNTT() { + p.invNttGeneric() +} + +// Sets p to the polynomial whose coefficients are the pointwise multiplication +// of those of a and b. The coefficients of p are bounded by 2q. +// +// Assumes a and b are in Montgomery form and that the pointwise product +// of each coefficient is below 2³² q. +func (p *Poly) MulHat(a, b *Poly) { + p.mulHatGeneric(a, b) +} + +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Add(a, b *Poly) { + p.addGeneric(a, b) +} + +// Sets p to a - b. +// +// Warning: assumes coefficients of b are less than 2q. +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Sub(a, b *Poly) { + p.subGeneric(a, b) +} + +// Writes p whose coefficients are in [0, 16) to buf, which must be of +// length N/2. +func (p *Poly) PackLe16(buf []byte) { + p.packLe16Generic(buf) +} + +// Reduces each of the coefficients to <2q. +func (p *Poly) ReduceLe2Q() { + p.reduceLe2QGeneric() +} + +// Reduce each of the coefficients to 0; l >>= 1 { + // On the n-th iteration of the l-loop, the coefficients start off + // bounded by n*2*Q. + // + // offset effectively loops over the row groups in this column; it + // is the first row in the row group. + for offset := uint(0); offset < N-l; offset += 2 * l { + k++ + zeta := uint64(Zetas[k]) + + // j loops over each butterfly in the row group. + for j := offset; j < offset+l; j++ { + t := montReduceLe2Q(zeta * uint64(p[j+l])) + p[j+l] = p[j] + (2*Q - t) // Cooley--Tukey butterfly + p[j] += t + } + } + } +} + +// Execute an in-place inverse NTT and multiply by Montgomery factor R +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation +// and bounded by 2*Q. +func (p *Poly) invNttGeneric() { + k := 0 // Index into InvZetas + + // We basically do the opposite of NTT, but postpone dividing by 2 in the + // inverse of the Cooley--Tukey butterfly and accumulate that to a big + // division by 2⁸ at the end. See comments in the NTT() function. + + for l := uint(1); l < N; l <<= 1 { + // On the n-th iteration of the l-loop, the coefficients start off + // bounded by 2ⁿ⁻¹*2*Q, so by 256*Q on the last. + for offset := uint(0); offset < N-l; offset += 2 * l { + zeta := uint64(InvZetas[k]) + k++ + for j := offset; j < offset+l; j++ { + t := p[j] // Gentleman--Sande butterfly + p[j] = t + p[j+l] + t += 256*Q - p[j+l] + p[j+l] = montReduceLe2Q(zeta * uint64(t)) + } + } + } + + for j := uint(0); j < N; j++ { + // ROver256 = 41978 = (256)⁻¹ R² + p[j] = montReduceLe2Q(ROver256 * uint64(p[j])) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go new file mode 100644 index 00000000..4b952a00 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go @@ -0,0 +1,160 @@ +package dilithium + +// Sets p to the polynomial whose coefficients are less than 1024 encoded +// into buf (which must be of size PolyT1Size). +// +// p will be normalized. +func (p *Poly) UnpackT1(buf []byte) { + j := 0 + for i := 0; i < PolyT1Size; i += 5 { + p[j] = (uint32(buf[i]) | (uint32(buf[i+1]) << 8)) & 0x3ff + p[j+1] = (uint32(buf[i+1]>>2) | (uint32(buf[i+2]) << 6)) & 0x3ff + p[j+2] = (uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4)) & 0x3ff + p[j+3] = (uint32(buf[i+3]>>6) | (uint32(buf[i+4]) << 2)) & 0x3ff + j += 4 + } +} + +// Writes p whose coefficients are in (-2ᵈ⁻¹, 2ᵈ⁻¹] into buf which +// has to be of length at least PolyT0Size. +// +// Assumes that the coefficients are not normalized, but lie in the +// range (q-2ᵈ⁻¹, q+2ᵈ⁻¹]. +func (p *Poly) PackT0(buf []byte) { + j := 0 + for i := 0; i < PolyT0Size; i += 13 { + p0 := Q + (1 << (D - 1)) - p[j] + p1 := Q + (1 << (D - 1)) - p[j+1] + p2 := Q + (1 << (D - 1)) - p[j+2] + p3 := Q + (1 << (D - 1)) - p[j+3] + p4 := Q + (1 << (D - 1)) - p[j+4] + p5 := Q + (1 << (D - 1)) - p[j+5] + p6 := Q + (1 << (D - 1)) - p[j+6] + p7 := Q + (1 << (D - 1)) - p[j+7] + + buf[i] = byte(p0 >> 0) + buf[i+1] = byte(p0>>8) | byte(p1<<5) + buf[i+2] = byte(p1 >> 3) + buf[i+3] = byte(p1>>11) | byte(p2<<2) + buf[i+4] = byte(p2>>6) | byte(p3<<7) + buf[i+5] = byte(p3 >> 1) + buf[i+6] = byte(p3>>9) | byte(p4<<4) + buf[i+7] = byte(p4 >> 4) + buf[i+8] = byte(p4>>12) | byte(p5<<1) + buf[i+9] = byte(p5>>7) | byte(p6<<6) + buf[i+10] = byte(p6 >> 2) + buf[i+11] = byte(p6>>10) | byte(p7<<3) + buf[i+12] = byte(p7 >> 5) + j += 8 + } +} + +// Sets p to the polynomial packed into buf by PackT0. +// +// The coefficients of p will not be normalized, but will lie +// in (-2ᵈ⁻¹, 2ᵈ⁻¹]. +func (p *Poly) UnpackT0(buf []byte) { + j := 0 + for i := 0; i < PolyT0Size; i += 13 { + p[j] = Q + (1 << (D - 1)) - ((uint32(buf[i]) | + (uint32(buf[i+1]) << 8)) & 0x1fff) + p[j+1] = Q + (1 << (D - 1)) - (((uint32(buf[i+1]) >> 5) | + (uint32(buf[i+2]) << 3) | + (uint32(buf[i+3]) << 11)) & 0x1fff) + p[j+2] = Q + (1 << (D - 1)) - (((uint32(buf[i+3]) >> 2) | + (uint32(buf[i+4]) << 6)) & 0x1fff) + p[j+3] = Q + (1 << (D - 1)) - (((uint32(buf[i+4]) >> 7) | + (uint32(buf[i+5]) << 1) | + (uint32(buf[i+6]) << 9)) & 0x1fff) + p[j+4] = Q + (1 << (D - 1)) - (((uint32(buf[i+6]) >> 4) | + (uint32(buf[i+7]) << 4) | + (uint32(buf[i+8]) << 12)) & 0x1fff) + p[j+5] = Q + (1 << (D - 1)) - (((uint32(buf[i+8]) >> 1) | + (uint32(buf[i+9]) << 7)) & 0x1fff) + p[j+6] = Q + (1 << (D - 1)) - (((uint32(buf[i+9]) >> 6) | + (uint32(buf[i+10]) << 2) | + (uint32(buf[i+11]) << 10)) & 0x1fff) + p[j+7] = Q + (1 << (D - 1)) - ((uint32(buf[i+11]) >> 3) | + (uint32(buf[i+12]) << 5)) + + j += 8 + } +} + +// Writes p whose coefficients are less than 1024 into buf, which must be +// of size at least PolyT1Size . +// +// Assumes coefficients of p are normalized. +func (p *Poly) PackT1(buf []byte) { + j := 0 + for i := 0; i < PolyT1Size; i += 5 { + buf[i] = byte(p[j]) + buf[i+1] = byte(p[j]>>8) | byte(p[j+1]<<2) + buf[i+2] = byte(p[j+1]>>6) | byte(p[j+2]<<4) + buf[i+3] = byte(p[j+2]>>4) | byte(p[j+3]<<6) + buf[i+4] = byte(p[j+3] >> 2) + j += 4 + } +} + +// Writes p whose coefficients are in [0, 16) to buf, which must be of +// length N/2. +func (p *Poly) packLe16Generic(buf []byte) { + j := 0 + for i := 0; i < PolyLe16Size; i++ { + buf[i] = byte(p[j]) | byte(p[j+1]<<4) + j += 2 + } +} + +// Writes p with 60 non-zero coefficients {-1,1} to buf, which must have +// length 40. +func (p *Poly) PackB60(buf []byte) { + // We start with a mask of the non-zero positions of p (which is 32 bytes) + // and then append 60 packed bits, where a one indicates a negative + // coefficients. + var signs uint64 + mask := uint64(1) + for i := 0; i < 32; i++ { + buf[i] = 0 + for j := 0; j < 8; j++ { + if p[8*i+j] != 0 { + buf[i] |= 1 << uint(j) + if p[8*i+j] == Q-1 { + signs |= mask + } + mask <<= 1 + } + } + } + for i := uint64(0); i < 8; i++ { + buf[i+32] = uint8(signs >> (8 * i)) + } +} + +// UnpackB60 sets p to the polynomial packed into buf with Poly.PackB60(). +// +// Returns whether unpacking was successful. +func (p *Poly) UnpackB60(buf []byte) bool { + *p = Poly{} // zero p + signs := (uint64(buf[32]) | (uint64(buf[33]) << 8) | + (uint64(buf[34]) << 16) | (uint64(buf[35]) << 24) | + (uint64(buf[36]) << 32) | (uint64(buf[37]) << 40) | + (uint64(buf[38]) << 48) | (uint64(buf[39]) << 56)) + if signs>>60 != 0 { + return false // ensure unused bits are zero for strong unforgeability + } + + for i := 0; i < 32; i++ { + for j := 0; j < 8; j++ { + if (buf[i]>>uint(j))&1 == 1 { + p[8*i+j] = 1 + // Note 1 ^ (1 | (Q-1)) = Q-1 and (-1)&x = x + p[8*i+j] ^= uint32(-(signs & 1)) & (1 | (Q - 1)) + signs >>= 1 + } + } + } + + return true +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go new file mode 100644 index 00000000..f423217f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go @@ -0,0 +1,18 @@ +package dilithium + +import ( + "github.com/cloudflare/circl/sign/internal/dilithium/params" +) + +const ( + SeedSize = params.SeedSize + N = params.N + Q = params.Q + QBits = params.QBits + Qinv = params.Qinv + ROver256 = params.ROver256 + D = params.D + PolyT1Size = params.PolyT1Size + PolyT0Size = params.PolyT0Size + PolyLe16Size = params.PolyLe16Size +) diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go new file mode 100644 index 00000000..2df20e3a --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go @@ -0,0 +1,25 @@ +package params + +// We put these parameters in a separate package so that the Go code, +// such as ntt_amd64_src.go, that generates assembler can import it. + +const ( + SeedSize = 32 + N = 256 + Q = 8380417 // 2²³ - 2¹³ + 1 + QBits = 23 + Qinv = 4236238847 // = -(q^-1) mod 2³² + ROver256 = 41978 // = (256)⁻¹ R² mod q, where R=2³² + D = 13 + + // Size of T1 packed. (Note that the formula is not valid in general, + // but it is for the parameters used in the modes of Dilithium.) + PolyT1Size = (N * (QBits - D)) / 8 + + // Size of T0 packed. (Note that the formula is not valid in general, + // but it is for the parameters used in the modes of Dilithium.) + PolyT0Size = (N * D) / 8 + + // Size of a packed polynomial whose coefficients are in [0,16). + PolyLe16Size = N / 2 +) diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go new file mode 100644 index 00000000..96c0551b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go @@ -0,0 +1,101 @@ +package dilithium + +// An element of our base ring R which are polynomials over Z_q modulo +// the equation Xᴺ = -1, where q=2²³ - 2¹³ + 1 and N=256. +// +// Coefficients aren't always reduced. See Normalize(). +type Poly [N]uint32 + +// Reduces each of the coefficients to <2q. +func (p *Poly) reduceLe2QGeneric() { + for i := uint(0); i < N; i++ { + p[i] = ReduceLe2Q(p[i]) + } +} + +// Reduce each of the coefficients to > 31) + // Sets x to {0, 1, ..., (Q-1)/2, (Q-1)/2, ..., 1} + x = int32((Q-1)/2) - x + if uint32(x) >= bound { + return true + } + } + return false +} + +// Splits p into p1 and p0 such that [i]p1 * 2ᴰ + [i]p0 = [i]p +// with -2ᴰ⁻¹ < [i]p0 ≤ 2ᴰ⁻¹. Returns p0 + Q and p1. +// +// Requires the coefficients of p to be normalized. +func (p *Poly) Power2Round(p0PlusQ, p1 *Poly) { + for i := 0; i < N; i++ { + p0PlusQ[i], p1[i] = power2round(p[i]) + } +} + +// Sets p to the polynomial whose coefficients are the pointwise multiplication +// of those of a and b. The coefficients of p are bounded by 2q. +// +// Assumes a and b are in Montgomery form and that the pointwise product +// of each coefficient is below 2³² q. +func (p *Poly) mulHatGeneric(a, b *Poly) { + for i := 0; i < N; i++ { + p[i] = montReduceLe2Q(uint64(a[i]) * uint64(b[i])) + } +} + +// Sets p to 2ᵈ q without reducing. +// +// So it requires the coefficients of p to be less than 2³²⁻ᴰ. +func (p *Poly) mulBy2toDGeneric(q *Poly) { + for i := 0; i < N; i++ { + p[i] = q[i] << D + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go new file mode 100644 index 00000000..ca92f15e --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go @@ -0,0 +1,35 @@ +// Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg dilithium. DO NOT EDIT. + +//go:build amd64 && !purego + +package dilithium + +//go:noescape +func nttAVX2(p *[256]uint32) + +//go:noescape +func invNttAVX2(p *[256]uint32) + +//go:noescape +func mulHatAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) + +//go:noescape +func addAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) + +//go:noescape +func subAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) + +//go:noescape +func packLe16AVX2(p *[256]uint32, buf *byte) + +//go:noescape +func reduceLe2QAVX2(p *[256]uint32) + +//go:noescape +func le2qModQAVX2(p *[256]uint32) + +//go:noescape +func exceedsAVX2(p *[256]uint32, bound uint32) uint8 + +//go:noescape +func mulBy2toDAVX2(p *[256]uint32, q *[256]uint32) diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/dilithium.go new file mode 100644 index 00000000..4b640f0c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/dilithium.go @@ -0,0 +1,361 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mldsa44 implements NIST signature scheme ML-DSA-44 as defined in FIPS204. +package mldsa44 + +import ( + "crypto" + cryptoRand "crypto/rand" + "encoding/asn1" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa44/internal" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of ML-DSA-44 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of ML-DSA-44 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, + ) + return nil +} + +// Do not use. Implements ML-DSA.Sign_internal used for compatibility tests. +func (sk *PrivateKey) unsafeSignInternal(msg []byte, rnd [32]byte) []byte { + var ret [SignatureSize]byte + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + rnd, + ret[:], + ) + return ret[:] +} + +// Do not use. Implements ML-DSA.Verify_internal used for compatibility tests. +func unsafeVerifyInternal(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mldsa44.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mldsa44.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-44. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-44" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 17} +} + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/dilithium.go new file mode 100644 index 00000000..8f1c8e5c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/dilithium.go @@ -0,0 +1,491 @@ +// Code generated from mode3/internal/dilithium.go by gen.go + +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr *[TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + if len(buf) < SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + pk.tr = new([TRSize]byte) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = &sk.tr + + return &pk, &sk +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: &sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/mat.go new file mode 100644 index 00000000..ceaf634f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/mat.go @@ -0,0 +1,59 @@ +// Code generated from mode3/internal/mat.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/pack.go new file mode 100644 index 00000000..1854b419 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/pack.go @@ -0,0 +1,270 @@ +// Code generated from mode3/internal/pack.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/params.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/params.go new file mode 100644 index 00000000..0485ff0c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "ML-DSA-44" + K = 4 + L = 4 + Eta = 2 + DoubleEtaBits = 3 + Omega = 80 + Tau = 39 + Gamma1Bits = 17 + Gamma2 = 95232 + NIST = true + TRSize = 64 + CTildeSize = 32 +) diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/rounding.go new file mode 100644 index 00000000..58123c09 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/rounding.go @@ -0,0 +1,142 @@ +// Code generated from mode3/internal/rounding.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/sample.go new file mode 100644 index 00000000..b37370a4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/sample.go @@ -0,0 +1,339 @@ +// Code generated from mode3/internal/sample.go by gen.go + +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/vec.go new file mode 100644 index 00000000..d07d3b24 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa44/internal/vec.go @@ -0,0 +1,281 @@ +// Code generated from mode3/internal/vec.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go new file mode 100644 index 00000000..23a7b9a1 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go @@ -0,0 +1,361 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mldsa65 implements NIST signature scheme ML-DSA-65 as defined in FIPS204. +package mldsa65 + +import ( + "crypto" + cryptoRand "crypto/rand" + "encoding/asn1" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa65/internal" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of ML-DSA-65 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of ML-DSA-65 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, + ) + return nil +} + +// Do not use. Implements ML-DSA.Sign_internal used for compatibility tests. +func (sk *PrivateKey) unsafeSignInternal(msg []byte, rnd [32]byte) []byte { + var ret [SignatureSize]byte + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + rnd, + ret[:], + ) + return ret[:] +} + +// Do not use. Implements ML-DSA.Verify_internal used for compatibility tests. +func unsafeVerifyInternal(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mldsa65.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mldsa65.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-65. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-65" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 18} +} + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go new file mode 100644 index 00000000..8f1c8e5c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go @@ -0,0 +1,491 @@ +// Code generated from mode3/internal/dilithium.go by gen.go + +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr *[TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + if len(buf) < SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + pk.tr = new([TRSize]byte) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = &sk.tr + + return &pk, &sk +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: &sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go new file mode 100644 index 00000000..ceaf634f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go @@ -0,0 +1,59 @@ +// Code generated from mode3/internal/mat.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go new file mode 100644 index 00000000..1854b419 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go @@ -0,0 +1,270 @@ +// Code generated from mode3/internal/pack.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go new file mode 100644 index 00000000..8a1f866e --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "ML-DSA-65" + K = 6 + L = 5 + Eta = 4 + DoubleEtaBits = 4 + Omega = 55 + Tau = 49 + Gamma1Bits = 19 + Gamma2 = 261888 + NIST = true + TRSize = 64 + CTildeSize = 48 +) diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go new file mode 100644 index 00000000..58123c09 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go @@ -0,0 +1,142 @@ +// Code generated from mode3/internal/rounding.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go new file mode 100644 index 00000000..b37370a4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go @@ -0,0 +1,339 @@ +// Code generated from mode3/internal/sample.go by gen.go + +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go new file mode 100644 index 00000000..d07d3b24 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go @@ -0,0 +1,281 @@ +// Code generated from mode3/internal/vec.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go new file mode 100644 index 00000000..cb016e73 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go @@ -0,0 +1,361 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mldsa87 implements NIST signature scheme ML-DSA-87 as defined in FIPS204. +package mldsa87 + +import ( + "crypto" + cryptoRand "crypto/rand" + "encoding/asn1" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa87/internal" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of ML-DSA-87 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of ML-DSA-87 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, + ) + return nil +} + +// Do not use. Implements ML-DSA.Sign_internal used for compatibility tests. +func (sk *PrivateKey) unsafeSignInternal(msg []byte, rnd [32]byte) []byte { + var ret [SignatureSize]byte + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + rnd, + ret[:], + ) + return ret[:] +} + +// Do not use. Implements ML-DSA.Verify_internal used for compatibility tests. +func unsafeVerifyInternal(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mldsa87.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mldsa87.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-87. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-87" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 19} +} + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go new file mode 100644 index 00000000..8f1c8e5c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go @@ -0,0 +1,491 @@ +// Code generated from mode3/internal/dilithium.go by gen.go + +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr *[TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + if len(buf) < SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + pk.tr = new([TRSize]byte) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = &sk.tr + + return &pk, &sk +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: &sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go new file mode 100644 index 00000000..ceaf634f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go @@ -0,0 +1,59 @@ +// Code generated from mode3/internal/mat.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go new file mode 100644 index 00000000..1854b419 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go @@ -0,0 +1,270 @@ +// Code generated from mode3/internal/pack.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go new file mode 100644 index 00000000..b5dc669c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "ML-DSA-87" + K = 8 + L = 7 + Eta = 2 + DoubleEtaBits = 3 + Omega = 75 + Tau = 60 + Gamma1Bits = 19 + Gamma2 = 261888 + NIST = true + TRSize = 64 + CTildeSize = 64 +) diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go new file mode 100644 index 00000000..58123c09 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go @@ -0,0 +1,142 @@ +// Code generated from mode3/internal/rounding.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go new file mode 100644 index 00000000..b37370a4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go @@ -0,0 +1,339 @@ +// Code generated from mode3/internal/sample.go by gen.go + +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go new file mode 100644 index 00000000..d07d3b24 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go @@ -0,0 +1,281 @@ +// Code generated from mode3/internal/vec.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/schemes/schemes.go b/vendor/github.com/cloudflare/circl/sign/schemes/schemes.go new file mode 100644 index 00000000..d01d8ca2 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/schemes/schemes.go @@ -0,0 +1,59 @@ +// Package schemes contains a register of signature algorithms. +// +// Implemented schemes: +// +// Ed25519 +// Ed448 +// Ed25519-Dilithium2 +// Ed448-Dilithium3 +package schemes + +import ( + "strings" + + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/ed25519" + "github.com/cloudflare/circl/sign/ed448" + "github.com/cloudflare/circl/sign/eddilithium2" + "github.com/cloudflare/circl/sign/eddilithium3" + + dilithium2 "github.com/cloudflare/circl/sign/dilithium/mode2" + dilithium3 "github.com/cloudflare/circl/sign/dilithium/mode3" + dilithium5 "github.com/cloudflare/circl/sign/dilithium/mode5" + "github.com/cloudflare/circl/sign/mldsa/mldsa44" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/cloudflare/circl/sign/mldsa/mldsa87" +) + +var allSchemes = [...]sign.Scheme{ + ed25519.Scheme(), + ed448.Scheme(), + eddilithium2.Scheme(), + eddilithium3.Scheme(), + dilithium2.Scheme(), + dilithium3.Scheme(), + dilithium5.Scheme(), + mldsa44.Scheme(), + mldsa65.Scheme(), + mldsa87.Scheme(), +} + +var allSchemeNames map[string]sign.Scheme + +func init() { + allSchemeNames = make(map[string]sign.Scheme) + for _, scheme := range allSchemes { + allSchemeNames[strings.ToLower(scheme.Name())] = scheme + } +} + +// ByName returns the scheme with the given name and nil if it is not +// supported. +// +// Names are case insensitive. +func ByName(name string) sign.Scheme { + return allSchemeNames[strings.ToLower(name)] +} + +// All returns all signature schemes supported. +func All() []sign.Scheme { a := allSchemes; return a[:] } diff --git a/vendor/github.com/cloudflare/circl/sign/sign.go b/vendor/github.com/cloudflare/circl/sign/sign.go new file mode 100644 index 00000000..557d6f09 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/sign.go @@ -0,0 +1,113 @@ +// Package sign provides unified interfaces for signature schemes. +// +// A register of schemes is available in the package +// +// github.com/cloudflare/circl/sign/schemes +package sign + +import ( + "crypto" + "encoding" + "errors" +) + +type SignatureOpts struct { + // If non-empty, includes the given context in the signature if supported + // and will cause an error during signing otherwise. + Context string +} + +// A public key is used to verify a signature set by the corresponding private +// key. +type PublicKey interface { + // Returns the signature scheme for this public key. + Scheme() Scheme + Equal(crypto.PublicKey) bool + encoding.BinaryMarshaler + crypto.PublicKey +} + +// A private key allows one to create signatures. +type PrivateKey interface { + // Returns the signature scheme for this private key. + Scheme() Scheme + Equal(crypto.PrivateKey) bool + // For compatibility with Go standard library + crypto.Signer + crypto.PrivateKey + encoding.BinaryMarshaler +} + +// A Scheme represents a specific instance of a signature scheme. +type Scheme interface { + // Name of the scheme. + Name() string + + // GenerateKey creates a new key-pair. + GenerateKey() (PublicKey, PrivateKey, error) + + // Creates a signature using the PrivateKey on the given message and + // returns the signature. opts are additional options which can be nil. + // + // Panics if key is nil or wrong type or opts context is not supported. + Sign(sk PrivateKey, message []byte, opts *SignatureOpts) []byte + + // Checks whether the given signature is a valid signature set by + // the private key corresponding to the given public key on the + // given message. opts are additional options which can be nil. + // + // Panics if key is nil or wrong type or opts context is not supported. + Verify(pk PublicKey, message []byte, signature []byte, opts *SignatureOpts) bool + + // Deterministically derives a keypair from a seed. If you're unsure, + // you're better off using GenerateKey(). + // + // Panics if seed is not of length SeedSize(). + DeriveKey(seed []byte) (PublicKey, PrivateKey) + + // Unmarshals a PublicKey from the provided buffer. + UnmarshalBinaryPublicKey([]byte) (PublicKey, error) + + // Unmarshals a PublicKey from the provided buffer. + UnmarshalBinaryPrivateKey([]byte) (PrivateKey, error) + + // Size of binary marshalled public keys. + PublicKeySize() int + + // Size of binary marshalled public keys. + PrivateKeySize() int + + // Size of signatures. + SignatureSize() int + + // Size of seeds. + SeedSize() int + + // Returns whether contexts are supported. + SupportsContext() bool +} + +var ( + // ErrTypeMismatch is the error used if types of, for instance, private + // and public keys don't match. + ErrTypeMismatch = errors.New("types mismatch") + + // ErrSeedSize is the error used if the provided seed is of the wrong + // size. + ErrSeedSize = errors.New("wrong seed size") + + // ErrPubKeySize is the error used if the provided public key is of + // the wrong size. + ErrPubKeySize = errors.New("wrong size for public key") + + // ErrPrivKeySize is the error used if the provided private key is of + // the wrong size. + ErrPrivKeySize = errors.New("wrong size for private key") + + // ErrContextNotSupported is the error used if a context is not + // supported. + ErrContextNotSupported = errors.New("context not supported") + + // ErrContextTooLong is the error used if the context string is too long. + ErrContextTooLong = errors.New("context string too long") +) diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go new file mode 100644 index 00000000..20ac96f0 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go @@ -0,0 +1,163 @@ +// Package keccakf1600 provides a two and four-way Keccak-f[1600] permutation in parallel. +// +// Keccak-f[1600] is the permutation underlying several algorithms such as +// Keccak, SHA3 and SHAKE. Running two or four permutations in parallel is +// useful in some scenarios like in hash-based signatures. +// +// # Limitations +// +// Note that not all the architectures support SIMD instructions. This package +// uses AVX2 instructions that are available in some AMD64 architectures +// and NEON instructions that are available in some ARM64 architectures. +// +// For those systems not supporting these, the package still provides the +// expected functionality by means of a generic and slow implementation. +// The recommendation is to beforehand verify IsEnabledX4() and IsEnabledX2() +// to determine if the current system supports the SIMD implementation. +package keccakf1600 + +import ( + "runtime" + "unsafe" + + "github.com/cloudflare/circl/internal/sha3" + "golang.org/x/sys/cpu" +) + +// StateX4 contains state for the four-way permutation including the four +// interleaved [25]uint64 buffers. Call Initialize() before use to initialize +// and get a pointer to the interleaved buffer. +type StateX4 struct { + // Go guarantees a to be aligned on 8 bytes, whereas we need it to be + // aligned on 32 bytes for bet performance. Thus we leave some headroom + // to be able to move the start of the state. + + // 4 x 25 uint64s for the interleaved states and three uint64s headroom + // to fix alignment. + a [103]uint64 + + // Offset into a that is 32 byte aligned. + offset int + + // If true, permute will use 12-round keccak instead of 24-round keccak + turbo bool +} + +// StateX2 contains state for the two-way permutation including the two +// interleaved [25]uint64 buffers. Call Initialize() before use to initialize +// and get a pointer to the interleaved buffer. +type StateX2 struct { + // Go guarantees a to be aligned on 8 bytes, whereas we need it to be + // aligned on 32 bytes for bet performance. Thus we leave some headroom + // to be able to move the start of the state. + + // 2 x 25 uint64s for the interleaved states and three uint64s headroom + // to fix alignment. + a [53]uint64 + + // Offset into a that is 32 byte aligned. + offset int + + // If true, permute will use 12-round keccak instead of 24-round keccak + turbo bool +} + +// IsEnabledX4 returns true if the architecture supports a four-way SIMD +// implementation provided in this package. +func IsEnabledX4() bool { return cpu.X86.HasAVX2 } + +// IsEnabledX2 returns true if the architecture supports a two-way SIMD +// implementation provided in this package. +func IsEnabledX2() bool { return enabledX2 } + +// Initialize the state and returns the buffer on which the four permutations +// will act: a uint64 slice of length 100. The first permutation will act +// on {a[0], a[4], ..., a[96]}, the second on {a[1], a[5], ..., a[97]}, etc. +// If turbo is true, applies 12-round variant instead of the usual 24. +func (s *StateX4) Initialize(turbo bool) []uint64 { + s.turbo = turbo + rp := unsafe.Pointer(&s.a[0]) + + // uint64s are always aligned by a multiple of 8. Compute the remainder + // of the address modulo 32 divided by 8. + rem := (int(uintptr(rp)&31) >> 3) + + if rem != 0 { + s.offset = 4 - rem + } + + // The slice we return will be aligned on 32 byte boundary. + return s.a[s.offset : s.offset+100] +} + +// Initialize the state and returns the buffer on which the two permutations +// will act: a uint64 slice of length 50. The first permutation will act +// on {a[0], a[2], ..., a[48]} and the second on {a[1], a[3], ..., a[49]}. +// If turbo is true, applies 12-round variant instead of the usual 24. +func (s *StateX2) Initialize(turbo bool) []uint64 { + s.turbo = turbo + rp := unsafe.Pointer(&s.a[0]) + + // uint64s are always aligned by a multiple of 8. Compute the remainder + // of the address modulo 32 divided by 8. + rem := (int(uintptr(rp)&31) >> 3) + + if rem != 0 { + s.offset = 4 - rem + } + + // The slice we return will be aligned on 32 byte boundary. + return s.a[s.offset : s.offset+50] +} + +// Permute performs the four parallel Keccak-f[1600]s interleaved on the slice +// returned from Initialize(). +func (s *StateX4) Permute() { + if IsEnabledX4() { + permuteSIMDx4(s.a[s.offset:], s.turbo) + } else { + permuteScalarX4(s.a[s.offset:], s.turbo) // A slower generic implementation. + } +} + +// Permute performs the two parallel Keccak-f[1600]s interleaved on the slice +// returned from Initialize(). +func (s *StateX2) Permute() { + if IsEnabledX2() { + permuteSIMDx2(s.a[s.offset:], s.turbo) + } else { + permuteScalarX2(s.a[s.offset:], s.turbo) // A slower generic implementation. + } +} + +func permuteScalarX4(a []uint64, turbo bool) { + var buf [25]uint64 + for i := 0; i < 4; i++ { + for j := 0; j < 25; j++ { + buf[j] = a[4*j+i] + } + sha3.KeccakF1600(&buf, turbo) + for j := 0; j < 25; j++ { + a[4*j+i] = buf[j] + } + } +} + +func permuteScalarX2(a []uint64, turbo bool) { + var buf [25]uint64 + for i := 0; i < 2; i++ { + for j := 0; j < 25; j++ { + buf[j] = a[2*j+i] + } + sha3.KeccakF1600(&buf, turbo) + for j := 0; j < 25; j++ { + a[2*j+i] = buf[j] + } + } +} + +var enabledX2 bool + +func init() { + enabledX2 = runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" +} diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go new file mode 100644 index 00000000..0cb9692c --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go @@ -0,0 +1,13 @@ +//go:build arm64 && go1.16 && !purego +// +build arm64,go1.16,!purego + +package keccakf1600 + +import "github.com/cloudflare/circl/internal/sha3" + +func permuteSIMDx2(state []uint64, turbo bool) { f1600x2ARM(&state[0], &sha3.RC, turbo) } + +func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } + +//go:noescape +func f1600x2ARM(state *uint64, rc *[24]uint64, turbo bool) diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s new file mode 100644 index 00000000..998aeca5 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s @@ -0,0 +1,136 @@ +// +build arm64,go1.16,!purego + +// Taken from https://github.com/bwesterb/armed-keccak + +#include "textflag.h" + +// func f1600x2ARM(state *uint64, rc *[24]uint64, turbo bool) +TEXT ·f1600x2ARM(SB), NOSPLIT, $0-17 + MOVD state+0(FP), R0 + MOVD rc+8(FP), R1 + MOVD R0, R2 + MOVD $24, R3 + + VLD1.P 64(R0), [ V0.B16, V1.B16, V2.B16, V3.B16] + VLD1.P 64(R0), [ V4.B16, V5.B16, V6.B16, V7.B16] + VLD1.P 64(R0), [ V8.B16, V9.B16, V10.B16, V11.B16] + VLD1.P 64(R0), [V12.B16, V13.B16, V14.B16, V15.B16] + VLD1.P 64(R0), [V16.B16, V17.B16, V18.B16, V19.B16] + VLD1.P 64(R0), [V20.B16, V21.B16, V22.B16, V23.B16] + VLD1.P (R0), [V24.B16] + + MOVBU turbo+16(FP), R4 + CBZ R4, loop + + SUB $12, R3, R3 + ADD $96, R1, R1 + +loop: + // Execute theta but without xorring into the state yet. + VEOR3 V10.B16, V5.B16, V0.B16, V25.B16 + VEOR3 V11.B16, V6.B16, V1.B16, V26.B16 + VEOR3 V12.B16, V7.B16, V2.B16, V27.B16 + VEOR3 V13.B16, V8.B16, V3.B16, V28.B16 + VEOR3 V14.B16, V9.B16, V4.B16, V29.B16 + + VEOR3 V20.B16, V15.B16, V25.B16, V25.B16 + VEOR3 V21.B16, V16.B16, V26.B16, V26.B16 + VEOR3 V22.B16, V17.B16, V27.B16, V27.B16 + VEOR3 V23.B16, V18.B16, V28.B16, V28.B16 + VEOR3 V24.B16, V19.B16, V29.B16, V29.B16 + + // Xor parities from step theta into the state at the same time as + // exeuting rho and pi. + VRAX1 V26.D2, V29.D2, V30.D2 + VRAX1 V29.D2, V27.D2, V29.D2 + VRAX1 V27.D2, V25.D2, V27.D2 + VRAX1 V25.D2, V28.D2, V25.D2 + VRAX1 V28.D2, V26.D2, V28.D2 + + VEOR V30.B16, V0.B16, V0.B16 + VMOV V1.B16, V31.B16 + + VXAR $20, V27.D2, V6.D2, V1.D2 + VXAR $44, V25.D2, V9.D2, V6.D2 + VXAR $3 , V28.D2, V22.D2, V9.D2 + VXAR $25, V25.D2, V14.D2, V22.D2 + VXAR $46, V30.D2, V20.D2, V14.D2 + VXAR $2 , V28.D2, V2.D2, V20.D2 + VXAR $21, V28.D2, V12.D2, V2.D2 + VXAR $39, V29.D2, V13.D2, V12.D2 + VXAR $56, V25.D2, V19.D2, V13.D2 + VXAR $8 , V29.D2, V23.D2, V19.D2 + VXAR $23, V30.D2, V15.D2, V23.D2 + VXAR $37, V25.D2, V4.D2, V15.D2 + VXAR $50, V25.D2, V24.D2, V4.D2 + VXAR $62, V27.D2, V21.D2, V24.D2 + VXAR $9 , V29.D2, V8.D2, V21.D2 + VXAR $19, V27.D2, V16.D2, V8.D2 + VXAR $28, V30.D2, V5.D2, V16.D2 + VXAR $36, V29.D2, V3.D2, V5.D2 + VXAR $43, V29.D2, V18.D2, V3.D2 + VXAR $49, V28.D2, V17.D2, V18.D2 + VXAR $54, V27.D2, V11.D2, V17.D2 + VXAR $58, V28.D2, V7.D2, V11.D2 + VXAR $61, V30.D2, V10.D2, V7.D2 + VXAR $63, V27.D2, V31.D2, V10.D2 + + // Chi + VBCAX V1.B16, V2.B16, V0.B16, V25.B16 + VBCAX V2.B16, V3.B16, V1.B16, V26.B16 + VBCAX V3.B16, V4.B16, V2.B16, V2.B16 + VBCAX V4.B16, V0.B16, V3.B16, V3.B16 + VBCAX V0.B16, V1.B16, V4.B16, V4.B16 + VMOV V25.B16, V0.B16 + VMOV V26.B16, V1.B16 + + VBCAX V6.B16, V7.B16, V5.B16, V25.B16 + VBCAX V7.B16, V8.B16, V6.B16, V26.B16 + VBCAX V8.B16, V9.B16, V7.B16, V7.B16 + VBCAX V9.B16, V5.B16, V8.B16, V8.B16 + VBCAX V5.B16, V6.B16, V9.B16, V9.B16 + VMOV V25.B16, V5.B16 + VMOV V26.B16, V6.B16 + + VBCAX V11.B16, V12.B16, V10.B16, V25.B16 + VBCAX V12.B16, V13.B16, V11.B16, V26.B16 + VBCAX V13.B16, V14.B16, V12.B16, V12.B16 + VBCAX V14.B16, V10.B16, V13.B16, V13.B16 + VBCAX V10.B16, V11.B16, V14.B16, V14.B16 + VMOV V25.B16, V10.B16 + VMOV V26.B16, V11.B16 + + VBCAX V16.B16, V17.B16, V15.B16, V25.B16 + VBCAX V17.B16, V18.B16, V16.B16, V26.B16 + VBCAX V18.B16, V19.B16, V17.B16, V17.B16 + VBCAX V19.B16, V15.B16, V18.B16, V18.B16 + VBCAX V15.B16, V16.B16, V19.B16, V19.B16 + VMOV V25.B16, V15.B16 + VMOV V26.B16, V16.B16 + + VBCAX V21.B16, V22.B16, V20.B16, V25.B16 + VBCAX V22.B16, V23.B16, V21.B16, V26.B16 + VBCAX V23.B16, V24.B16, V22.B16, V22.B16 + VBCAX V24.B16, V20.B16, V23.B16, V23.B16 + VBCAX V20.B16, V21.B16, V24.B16, V24.B16 + VMOV V25.B16, V20.B16 + VMOV V26.B16, V21.B16 + + // Iota + VLD1R.P 8(R1), [V25.D2] + VEOR V25.B16, V0.B16, V0.B16 + + SUBS $1, R3, R3 + CBNZ R3, loop + + MOVD R2, R0 + + VST1.P [ V0.B16, V1.B16, V2.B16, V3.B16], 64(R0) + VST1.P [ V4.B16, V5.B16, V6.B16, V7.B16], 64(R0) + VST1.P [ V8.B16, V9.B16, V10.B16, V11.B16], 64(R0) + VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R0) + VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R0) + VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R0) + VST1.P [V24.B16], (R0) + + RET diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go new file mode 100644 index 00000000..bf5b865d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go @@ -0,0 +1,10 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package keccakf1600 + +import "github.com/cloudflare/circl/internal/sha3" + +func permuteSIMDx4(state []uint64, turbo bool) { f1600x4AVX2(&state[0], &sha3.RC, turbo) } + +func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s new file mode 100644 index 00000000..67b64550 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s @@ -0,0 +1,899 @@ +// Code generated by command: go run src.go -out ../../f1600x4_amd64.s -stubs ../../f1600x4stubs_amd64.go -pkg keccakf1600. DO NOT EDIT. + +//go:build amd64 && !purego + +#include "textflag.h" + +// func f1600x4AVX2(state *uint64, rc *[24]uint64, turbo bool) +// Requires: AVX, AVX2 +TEXT ·f1600x4AVX2(SB), NOSPLIT, $0-17 + MOVQ state+0(FP), AX + MOVQ rc+8(FP), CX + MOVQ $0x0000000000000006, DX + MOVBQZX turbo+16(FP), BX + TESTQ BX, BX + JZ loop + MOVQ $0x0000000000000003, DX + ADDQ $0x60, CX + +loop: + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 192(AX), Y11, Y1 + VPXOR 384(AX), Y12, Y2 + VPXOR 576(AX), Y13, Y3 + VPXOR 768(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ (CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 768(AX) + VPXOR 96(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 320(AX), Y10, Y2 + VPXOR 512(AX), Y11, Y3 + VPXOR 704(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 288(AX) + VPXOR 32(AX), Y11, Y0 + VPXOR 224(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 608(AX), Y14, Y3 + VPXOR 640(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 608(AX) + VPXOR 128(AX), Y14, Y0 + VPXOR 160(AX), Y10, Y1 + VPXOR 352(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 736(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 128(AX) + VPXOR 64(AX), Y12, Y0 + VPXOR 256(AX), Y13, Y1 + VPXOR 448(AX), Y14, Y2 + VPXOR 480(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 448(AX) + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 512(AX), Y11, Y1 + VPXOR 224(AX), Y12, Y2 + VPXOR 736(AX), Y13, Y3 + VPXOR 448(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ 8(CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 448(AX) + VPXOR 576(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 640(AX), Y10, Y2 + VPXOR 352(AX), Y11, Y3 + VPXOR 64(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 288(AX) + VPXOR 192(AX), Y11, Y0 + VPXOR 704(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 128(AX), Y14, Y3 + VPXOR 480(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 128(AX) + VPXOR 768(AX), Y14, Y0 + VPXOR 320(AX), Y10, Y1 + VPXOR 32(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 256(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 768(AX) + VPXOR 384(AX), Y12, Y0 + VPXOR 96(AX), Y13, Y1 + VPXOR 608(AX), Y14, Y2 + VPXOR 160(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 608(AX) + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 352(AX), Y11, Y1 + VPXOR 704(AX), Y12, Y2 + VPXOR 256(AX), Y13, Y3 + VPXOR 608(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ 16(CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 608(AX) + VPXOR 736(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 480(AX), Y10, Y2 + VPXOR 32(AX), Y11, Y3 + VPXOR 384(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 288(AX) + VPXOR 512(AX), Y11, Y0 + VPXOR 64(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 768(AX), Y14, Y3 + VPXOR 160(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 768(AX) + VPXOR 448(AX), Y14, Y0 + VPXOR 640(AX), Y10, Y1 + VPXOR 192(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 96(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 448(AX) + VPXOR 224(AX), Y12, Y0 + VPXOR 576(AX), Y13, Y1 + VPXOR 128(AX), Y14, Y2 + VPXOR 320(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 128(AX) + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 32(AX), Y11, Y1 + VPXOR 64(AX), Y12, Y2 + VPXOR 96(AX), Y13, Y3 + VPXOR 128(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ 24(CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 128(AX) + VPXOR 256(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 160(AX), Y10, Y2 + VPXOR 192(AX), Y11, Y3 + VPXOR 224(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 288(AX) + VPXOR 352(AX), Y11, Y0 + VPXOR 384(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 448(AX), Y14, Y3 + VPXOR 320(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 448(AX) + VPXOR 608(AX), Y14, Y0 + VPXOR 480(AX), Y10, Y1 + VPXOR 512(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 576(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 608(AX) + VPXOR 704(AX), Y12, Y0 + VPXOR 736(AX), Y13, Y1 + VPXOR 768(AX), Y14, Y2 + VPXOR 640(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 768(AX) + ADDQ $0x20, CX + SUBQ $0x00000001, DX + JNZ loop + RET diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go new file mode 100644 index 00000000..102fdd04 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go @@ -0,0 +1,8 @@ +// Code generated by command: go run src.go -out ../../f1600x4_amd64.s -stubs ../../f1600x4stubs_amd64.go -pkg keccakf1600. DO NOT EDIT. + +//go:build amd64 && !purego + +package keccakf1600 + +//go:noescape +func f1600x4AVX2(state *uint64, rc *[24]uint64, turbo bool) diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go new file mode 100644 index 00000000..0da75e9b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go @@ -0,0 +1,8 @@ +//go:build (!amd64 && !arm64) || (arm64 && !go1.16) || purego +// +build !amd64,!arm64 arm64,!go1.16 purego + +package keccakf1600 + +func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } + +func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1.go new file mode 100644 index 00000000..d25979d9 --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/asn1.go @@ -0,0 +1,825 @@ +// Copyright 2017 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 cryptobyte + +import ( + encoding_asn1 "encoding/asn1" + "fmt" + "math/big" + "reflect" + "time" + + "golang.org/x/crypto/cryptobyte/asn1" +) + +// This file contains ASN.1-related methods for String and Builder. + +// Builder + +// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Int64(v int64) { + b.addASN1Signed(asn1.INTEGER, v) +} + +// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the +// given tag. +func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) { + b.addASN1Signed(tag, v) +} + +// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION. +func (b *Builder) AddASN1Enum(v int64) { + b.addASN1Signed(asn1.ENUM, v) +} + +func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) { + b.AddASN1(tag, func(c *Builder) { + length := 1 + for i := v; i >= 0x80 || i < -0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Uint64(v uint64) { + b.AddASN1(asn1.INTEGER, func(c *Builder) { + length := 1 + for i := v; i >= 0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1BigInt(n *big.Int) { + if b.err != nil { + return + } + + b.AddASN1(asn1.INTEGER, func(c *Builder) { + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement form. So we + // invert and subtract 1. If the most-significant-bit isn't set then + // we'll need to pad the beginning with 0xff in order to keep the number + // negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if len(bytes) == 0 || bytes[0]&0x80 == 0 { + c.add(0xff) + } + c.add(bytes...) + } else if n.Sign() == 0 { + c.add(0) + } else { + bytes := n.Bytes() + if bytes[0]&0x80 != 0 { + c.add(0) + } + c.add(bytes...) + } + }) +} + +// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING. +func (b *Builder) AddASN1OctetString(bytes []byte) { + b.AddASN1(asn1.OCTET_STRING, func(c *Builder) { + c.AddBytes(bytes) + }) +} + +const generalizedTimeFormatStr = "20060102150405Z0700" + +// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME. +func (b *Builder) AddASN1GeneralizedTime(t time.Time) { + if t.Year() < 0 || t.Year() > 9999 { + b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t) + return + } + b.AddASN1(asn1.GeneralizedTime, func(c *Builder) { + c.AddBytes([]byte(t.Format(generalizedTimeFormatStr))) + }) +} + +// AddASN1UTCTime appends a DER-encoded ASN.1 UTCTime. +func (b *Builder) AddASN1UTCTime(t time.Time) { + b.AddASN1(asn1.UTCTime, func(c *Builder) { + // As utilized by the X.509 profile, UTCTime can only + // represent the years 1950 through 2049. + if t.Year() < 1950 || t.Year() >= 2050 { + b.err = fmt.Errorf("cryptobyte: cannot represent %v as a UTCTime", t) + return + } + c.AddBytes([]byte(t.Format(defaultUTCTimeFormatStr))) + }) +} + +// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not +// support BIT STRINGs that are not a whole number of bytes. +func (b *Builder) AddASN1BitString(data []byte) { + b.AddASN1(asn1.BIT_STRING, func(b *Builder) { + b.AddUint8(0) + b.AddBytes(data) + }) +} + +func (b *Builder) addBase128Int(n int64) { + var length int + if n == 0 { + length = 1 + } else { + for i := n; i > 0; i >>= 7 { + length++ + } + } + + for i := length - 1; i >= 0; i-- { + o := byte(n >> uint(i*7)) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + + b.add(o) + } +} + +func isValidOID(oid encoding_asn1.ObjectIdentifier) bool { + if len(oid) < 2 { + return false + } + + if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) { + return false + } + + for _, v := range oid { + if v < 0 { + return false + } + } + + return true +} + +func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) { + b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) { + if !isValidOID(oid) { + b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid) + return + } + + b.addBase128Int(int64(oid[0])*40 + int64(oid[1])) + for _, v := range oid[2:] { + b.addBase128Int(int64(v)) + } + }) +} + +func (b *Builder) AddASN1Boolean(v bool) { + b.AddASN1(asn1.BOOLEAN, func(b *Builder) { + if v { + b.AddUint8(0xff) + } else { + b.AddUint8(0) + } + }) +} + +func (b *Builder) AddASN1NULL() { + b.add(uint8(asn1.NULL), 0) +} + +// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if +// successful or records an error if one occurred. +func (b *Builder) MarshalASN1(v interface{}) { + // NOTE(martinkr): This is somewhat of a hack to allow propagation of + // encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a + // value embedded into a struct, its tag information is lost. + if b.err != nil { + return + } + bytes, err := encoding_asn1.Marshal(v) + if err != nil { + b.err = err + return + } + b.AddBytes(bytes) +} + +// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag. +// Tags greater than 30 are not supported and result in an error (i.e. +// low-tag-number form only). The child builder passed to the +// BuilderContinuation can be used to build the content of the ASN.1 object. +func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) { + if b.err != nil { + return + } + // Identifiers with the low five bits set indicate high-tag-number format + // (two or more octets), which we don't support. + if tag&0x1f == 0x1f { + b.err = fmt.Errorf("cryptobyte: high-tag number identifier octets not supported: 0x%x", tag) + return + } + b.AddUint8(uint8(tag)) + b.addLengthPrefixed(1, true, f) +} + +// String + +// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean +// representation into out and advances. It reports whether the read +// was successful. +func (s *String) ReadASN1Boolean(out *bool) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.BOOLEAN) || len(bytes) != 1 { + return false + } + + switch bytes[0] { + case 0: + *out = false + case 0xff: + *out = true + default: + return false + } + + return true +} + +// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does +// not point to an integer, to a big.Int, or to a []byte it panics. Only +// positive and zero values can be decoded into []byte, and they are returned as +// big-endian binary values that share memory with s. Positive values will have +// no leading zeroes, and zero will be returned as a single zero byte. +// ReadASN1Integer reports whether the read was successful. +func (s *String) ReadASN1Integer(out interface{}) bool { + switch out := out.(type) { + case *int, *int8, *int16, *int32, *int64: + var i int64 + if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) { + return false + } + reflect.ValueOf(out).Elem().SetInt(i) + return true + case *uint, *uint8, *uint16, *uint32, *uint64: + var u uint64 + if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) { + return false + } + reflect.ValueOf(out).Elem().SetUint(u) + return true + case *big.Int: + return s.readASN1BigInt(out) + case *[]byte: + return s.readASN1Bytes(out) + default: + panic("out does not point to an integer type") + } +} + +func checkASN1Integer(bytes []byte) bool { + if len(bytes) == 0 { + // An INTEGER is encoded with at least one octet. + return false + } + if len(bytes) == 1 { + return true + } + if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 { + // Value is not minimally encoded. + return false + } + return true +} + +var bigOne = big.NewInt(1) + +func (s *String) readASN1BigInt(out *big.Int) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) { + return false + } + if bytes[0]&0x80 == 0x80 { + // Negative number. + neg := make([]byte, len(bytes)) + for i, b := range bytes { + neg[i] = ^b + } + out.SetBytes(neg) + out.Add(out, bigOne) + out.Neg(out) + } else { + out.SetBytes(bytes) + } + return true +} + +func (s *String) readASN1Bytes(out *[]byte) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) { + return false + } + if bytes[0]&0x80 == 0x80 { + return false + } + for len(bytes) > 1 && bytes[0] == 0 { + bytes = bytes[1:] + } + *out = bytes + return true +} + +func (s *String) readASN1Int64(out *int64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) { + return false + } + return true +} + +func asn1Signed(out *int64, n []byte) bool { + length := len(n) + if length > 8 { + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= int64(n[i]) + } + // Shift up and down in order to sign extend the result. + *out <<= 64 - uint8(length)*8 + *out >>= 64 - uint8(length)*8 + return true +} + +func (s *String) readASN1Uint64(out *uint64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) { + return false + } + return true +} + +func asn1Unsigned(out *uint64, n []byte) bool { + length := len(n) + if length > 9 || length == 9 && n[0] != 0 { + // Too large for uint64. + return false + } + if n[0]&0x80 != 0 { + // Negative number. + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= uint64(n[i]) + } + return true +} + +// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out +// and advances. It reports whether the read was successful and resulted in a +// value that can be represented in an int64. +func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool { + var bytes String + return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes) +} + +// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports +// whether the read was successful. +func (s *String) ReadASN1Enum(out *int) bool { + var bytes String + var i int64 + if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) { + return false + } + if int64(int(i)) != i { + return false + } + *out = int(i) + return true +} + +func (s *String) readBase128Int(out *int) bool { + ret := 0 + for i := 0; len(*s) > 0; i++ { + if i == 5 { + return false + } + // Avoid overflowing int on a 32-bit platform. + // We don't want different behavior based on the architecture. + if ret >= 1<<(31-7) { + return false + } + ret <<= 7 + b := s.read(1)[0] + + // ITU-T X.690, section 8.19.2: + // The subidentifier shall be encoded in the fewest possible octets, + // that is, the leading octet of the subidentifier shall not have the value 0x80. + if i == 0 && b == 0x80 { + return false + } + + ret |= int(b & 0x7f) + if b&0x80 == 0 { + *out = ret + return true + } + } + return false // truncated +} + +// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and +// advances. It reports whether the read was successful. +func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 { + return false + } + + // In the worst case, we get two elements from the first byte (which is + // encoded differently) and then every varint is a single byte long. + components := make([]int, len(bytes)+1) + + // The first varint is 40*value1 + value2: + // According to this packing, value1 can take the values 0, 1 and 2 only. + // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2, + // then there are no restrictions on value2. + var v int + if !bytes.readBase128Int(&v) { + return false + } + if v < 80 { + components[0] = v / 40 + components[1] = v % 40 + } else { + components[0] = 2 + components[1] = v - 80 + } + + i := 2 + for ; len(bytes) > 0; i++ { + if !bytes.readBase128Int(&v) { + return false + } + components[i] = v + } + *out = components[:i] + return true +} + +// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and +// advances. It reports whether the read was successful. +func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.GeneralizedTime) { + return false + } + t := string(bytes) + res, err := time.Parse(generalizedTimeFormatStr, t) + if err != nil { + return false + } + if serialized := res.Format(generalizedTimeFormatStr); serialized != t { + return false + } + *out = res + return true +} + +const defaultUTCTimeFormatStr = "060102150405Z0700" + +// ReadASN1UTCTime decodes an ASN.1 UTCTime into out and advances. +// It reports whether the read was successful. +func (s *String) ReadASN1UTCTime(out *time.Time) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.UTCTime) { + return false + } + t := string(bytes) + + formatStr := defaultUTCTimeFormatStr + var err error + res, err := time.Parse(formatStr, t) + if err != nil { + // Fallback to minute precision if we can't parse second + // precision. If we are following X.509 or X.690 we shouldn't + // support this, but we do. + formatStr = "0601021504Z0700" + res, err = time.Parse(formatStr, t) + } + if err != nil { + return false + } + + if serialized := res.Format(formatStr); serialized != t { + return false + } + + if res.Year() >= 2050 { + // UTCTime interprets the low order digits 50-99 as 1950-99. + // This only applies to its use in the X.509 profile. + // See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 + res = res.AddDate(-100, 0, 0) + } + *out = res + return true +} + +// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. +// It reports whether the read was successful. +func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 || + len(bytes)*8/8 != len(bytes) { + return false + } + + paddingBits := bytes[0] + bytes = bytes[1:] + if paddingBits > 7 || + len(bytes) == 0 && paddingBits != 0 || + len(bytes) > 0 && bytes[len(bytes)-1]&(1< 4 || len(*s) < int(2+lenLen) { + return false + } + + lenBytes := String((*s)[2 : 2+lenLen]) + if !lenBytes.readUnsigned(&len32, int(lenLen)) { + return false + } + + // ITU-T X.690 section 10.1 (DER length forms) requires encoding the length + // with the minimum number of octets. + if len32 < 128 { + // Length should have used short-form encoding. + return false + } + if len32>>((lenLen-1)*8) == 0 { + // Leading octet is 0. Length should have been at least one byte shorter. + return false + } + + headerLen = 2 + uint32(lenLen) + if headerLen+len32 < len32 { + // Overflow. + return false + } + length = headerLen + len32 + } + + if int(length) < 0 || !s.ReadBytes((*[]byte)(out), int(length)) { + return false + } + if skipHeader && !out.Skip(int(headerLen)) { + panic("cryptobyte: internal error") + } + + return true +} diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go new file mode 100644 index 00000000..90ef6a24 --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go @@ -0,0 +1,46 @@ +// Copyright 2017 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 asn1 contains supporting types for parsing and building ASN.1 +// messages with the cryptobyte package. +package asn1 + +// Tag represents an ASN.1 identifier octet, consisting of a tag number +// (indicating a type) and class (such as context-specific or constructed). +// +// Methods in the cryptobyte package only support the low-tag-number form, i.e. +// a single identifier octet with bits 7-8 encoding the class and bits 1-6 +// encoding the tag number. +type Tag uint8 + +const ( + classConstructed = 0x20 + classContextSpecific = 0x80 +) + +// Constructed returns t with the constructed class bit set. +func (t Tag) Constructed() Tag { return t | classConstructed } + +// ContextSpecific returns t with the context-specific class bit set. +func (t Tag) ContextSpecific() Tag { return t | classContextSpecific } + +// The following is a list of standard tag and class combinations. +const ( + BOOLEAN = Tag(1) + INTEGER = Tag(2) + BIT_STRING = Tag(3) + OCTET_STRING = Tag(4) + NULL = Tag(5) + OBJECT_IDENTIFIER = Tag(6) + ENUM = Tag(10) + UTF8String = Tag(12) + SEQUENCE = Tag(16 | classConstructed) + SET = Tag(17 | classConstructed) + PrintableString = Tag(19) + T61String = Tag(20) + IA5String = Tag(22) + UTCTime = Tag(23) + GeneralizedTime = Tag(24) + GeneralString = Tag(27) +) diff --git a/vendor/golang.org/x/crypto/cryptobyte/builder.go b/vendor/golang.org/x/crypto/cryptobyte/builder.go new file mode 100644 index 00000000..cf254f5f --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/builder.go @@ -0,0 +1,350 @@ +// Copyright 2017 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 cryptobyte + +import ( + "errors" + "fmt" +) + +// A Builder builds byte strings from fixed-length and length-prefixed values. +// Builders either allocate space as needed, or are ‘fixed’, which means that +// they write into a given buffer and produce an error if it's exhausted. +// +// The zero value is a usable Builder that allocates space as needed. +// +// Simple values are marshaled and appended to a Builder using methods on the +// Builder. Length-prefixed values are marshaled by providing a +// BuilderContinuation, which is a function that writes the inner contents of +// the value to a given Builder. See the documentation for BuilderContinuation +// for details. +type Builder struct { + err error + result []byte + fixedSize bool + child *Builder + offset int + pendingLenLen int + pendingIsASN1 bool + inContinuation *bool +} + +// NewBuilder creates a Builder that appends its output to the given buffer. +// Like append(), the slice will be reallocated if its capacity is exceeded. +// Use Bytes to get the final buffer. +func NewBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + } +} + +// NewFixedBuilder creates a Builder that appends its output into the given +// buffer. This builder does not reallocate the output buffer. Writes that +// would exceed the buffer's capacity are treated as an error. +func NewFixedBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + fixedSize: true, + } +} + +// SetError sets the value to be returned as the error from Bytes. Writes +// performed after calling SetError are ignored. +func (b *Builder) SetError(err error) { + b.err = err +} + +// Bytes returns the bytes written by the builder or an error if one has +// occurred during building. +func (b *Builder) Bytes() ([]byte, error) { + if b.err != nil { + return nil, b.err + } + return b.result[b.offset:], nil +} + +// BytesOrPanic returns the bytes written by the builder or panics if an error +// has occurred during building. +func (b *Builder) BytesOrPanic() []byte { + if b.err != nil { + panic(b.err) + } + return b.result[b.offset:] +} + +// AddUint8 appends an 8-bit value to the byte string. +func (b *Builder) AddUint8(v uint8) { + b.add(byte(v)) +} + +// AddUint16 appends a big-endian, 16-bit value to the byte string. +func (b *Builder) AddUint16(v uint16) { + b.add(byte(v>>8), byte(v)) +} + +// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest +// byte of the 32-bit input value is silently truncated. +func (b *Builder) AddUint24(v uint32) { + b.add(byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint32 appends a big-endian, 32-bit value to the byte string. +func (b *Builder) AddUint32(v uint32) { + b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint48 appends a big-endian, 48-bit value to the byte string. +func (b *Builder) AddUint48(v uint64) { + b.add(byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint64 appends a big-endian, 64-bit value to the byte string. +func (b *Builder) AddUint64(v uint64) { + b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddBytes appends a sequence of bytes to the byte string. +func (b *Builder) AddBytes(v []byte) { + b.add(v...) +} + +// BuilderContinuation is a continuation-passing interface for building +// length-prefixed byte sequences. Builder methods for length-prefixed +// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation +// supplied to them. The child builder passed to the continuation can be used +// to build the content of the length-prefixed sequence. For example: +// +// parent := cryptobyte.NewBuilder() +// parent.AddUint8LengthPrefixed(func (child *Builder) { +// child.AddUint8(42) +// child.AddUint8LengthPrefixed(func (grandchild *Builder) { +// grandchild.AddUint8(5) +// }) +// }) +// +// It is an error to write more bytes to the child than allowed by the reserved +// length prefix. After the continuation returns, the child must be considered +// invalid, i.e. users must not store any copies or references of the child +// that outlive the continuation. +// +// If the continuation panics with a value of type BuildError then the inner +// error will be returned as the error from Bytes. If the child panics +// otherwise then Bytes will repanic with the same value. +type BuilderContinuation func(child *Builder) + +// BuildError wraps an error. If a BuilderContinuation panics with this value, +// the panic will be recovered and the inner error will be returned from +// Builder.Bytes. +type BuildError struct { + Err error +} + +// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence. +func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(1, false, f) +} + +// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence. +func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(2, false, f) +} + +// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence. +func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(3, false, f) +} + +// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence. +func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(4, false, f) +} + +func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) { + if !*b.inContinuation { + *b.inContinuation = true + + defer func() { + *b.inContinuation = false + + r := recover() + if r == nil { + return + } + + if buildError, ok := r.(BuildError); ok { + b.err = buildError.Err + } else { + panic(r) + } + }() + } + + f(arg) +} + +func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) { + // Subsequent writes can be ignored if the builder has encountered an error. + if b.err != nil { + return + } + + offset := len(b.result) + b.add(make([]byte, lenLen)...) + + if b.inContinuation == nil { + b.inContinuation = new(bool) + } + + b.child = &Builder{ + result: b.result, + fixedSize: b.fixedSize, + offset: offset, + pendingLenLen: lenLen, + pendingIsASN1: isASN1, + inContinuation: b.inContinuation, + } + + b.callContinuation(f, b.child) + b.flushChild() + if b.child != nil { + panic("cryptobyte: internal error") + } +} + +func (b *Builder) flushChild() { + if b.child == nil { + return + } + b.child.flushChild() + child := b.child + b.child = nil + + if child.err != nil { + b.err = child.err + return + } + + length := len(child.result) - child.pendingLenLen - child.offset + + if length < 0 { + panic("cryptobyte: internal error") // result unexpectedly shrunk + } + + if child.pendingIsASN1 { + // For ASN.1, we reserved a single byte for the length. If that turned out + // to be incorrect, we have to move the contents along in order to make + // space. + if child.pendingLenLen != 1 { + panic("cryptobyte: internal error") + } + var lenLen, lenByte uint8 + if int64(length) > 0xfffffffe { + b.err = errors.New("pending ASN.1 child too long") + return + } else if length > 0xffffff { + lenLen = 5 + lenByte = 0x80 | 4 + } else if length > 0xffff { + lenLen = 4 + lenByte = 0x80 | 3 + } else if length > 0xff { + lenLen = 3 + lenByte = 0x80 | 2 + } else if length > 0x7f { + lenLen = 2 + lenByte = 0x80 | 1 + } else { + lenLen = 1 + lenByte = uint8(length) + length = 0 + } + + // Insert the initial length byte, make space for successive length bytes, + // and adjust the offset. + child.result[child.offset] = lenByte + extraBytes := int(lenLen - 1) + if extraBytes != 0 { + child.add(make([]byte, extraBytes)...) + childStart := child.offset + child.pendingLenLen + copy(child.result[childStart+extraBytes:], child.result[childStart:]) + } + child.offset++ + child.pendingLenLen = extraBytes + } + + l := length + for i := child.pendingLenLen - 1; i >= 0; i-- { + child.result[child.offset+i] = uint8(l) + l >>= 8 + } + if l != 0 { + b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen) + return + } + + if b.fixedSize && &b.result[0] != &child.result[0] { + panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer") + } + + b.result = child.result +} + +func (b *Builder) add(bytes ...byte) { + if b.err != nil { + return + } + if b.child != nil { + panic("cryptobyte: attempted write while child is pending") + } + if len(b.result)+len(bytes) < len(bytes) { + b.err = errors.New("cryptobyte: length overflow") + } + if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) { + b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer") + return + } + b.result = append(b.result, bytes...) +} + +// Unwrite rolls back non-negative n bytes written directly to the Builder. +// An attempt by a child builder passed to a continuation to unwrite bytes +// from its parent will panic. +func (b *Builder) Unwrite(n int) { + if b.err != nil { + return + } + if b.child != nil { + panic("cryptobyte: attempted unwrite while child is pending") + } + length := len(b.result) - b.pendingLenLen - b.offset + if length < 0 { + panic("cryptobyte: internal error") + } + if n < 0 { + panic("cryptobyte: attempted to unwrite negative number of bytes") + } + if n > length { + panic("cryptobyte: attempted to unwrite more than was written") + } + b.result = b.result[:len(b.result)-n] +} + +// A MarshalingValue marshals itself into a Builder. +type MarshalingValue interface { + // Marshal is called by Builder.AddValue. It receives a pointer to a builder + // to marshal itself into. It may return an error that occurred during + // marshaling, such as unset or invalid values. + Marshal(b *Builder) error +} + +// AddValue calls Marshal on v, passing a pointer to the builder to append to. +// If Marshal returns an error, it is set on the Builder so that subsequent +// appends don't have an effect. +func (b *Builder) AddValue(v MarshalingValue) { + err := v.Marshal(b) + if err != nil { + b.err = err + } +} diff --git a/vendor/golang.org/x/crypto/cryptobyte/string.go b/vendor/golang.org/x/crypto/cryptobyte/string.go new file mode 100644 index 00000000..4b0f8097 --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/string.go @@ -0,0 +1,183 @@ +// Copyright 2017 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 cryptobyte contains types that help with parsing and constructing +// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage +// contains useful ASN.1 constants.) +// +// The String type is for parsing. It wraps a []byte slice and provides helper +// functions for consuming structures, value by value. +// +// The Builder type is for constructing messages. It providers helper functions +// for appending values and also for appending length-prefixed submessages – +// without having to worry about calculating the length prefix ahead of time. +// +// See the documentation and examples for the Builder and String types to get +// started. +package cryptobyte + +// String represents a string of bytes. It provides methods for parsing +// fixed-length and length-prefixed values from it. +type String []byte + +// read advances a String by n bytes and returns them. If less than n bytes +// remain, it returns nil. +func (s *String) read(n int) []byte { + if len(*s) < n || n < 0 { + return nil + } + v := (*s)[:n] + *s = (*s)[n:] + return v +} + +// Skip advances the String by n byte and reports whether it was successful. +func (s *String) Skip(n int) bool { + return s.read(n) != nil +} + +// ReadUint8 decodes an 8-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint8(out *uint8) bool { + v := s.read(1) + if v == nil { + return false + } + *out = uint8(v[0]) + return true +} + +// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint16(out *uint16) bool { + v := s.read(2) + if v == nil { + return false + } + *out = uint16(v[0])<<8 | uint16(v[1]) + return true +} + +// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint24(out *uint32) bool { + v := s.read(3) + if v == nil { + return false + } + *out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2]) + return true +} + +// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint32(out *uint32) bool { + v := s.read(4) + if v == nil { + return false + } + *out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3]) + return true +} + +// ReadUint48 decodes a big-endian, 48-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint48(out *uint64) bool { + v := s.read(6) + if v == nil { + return false + } + *out = uint64(v[0])<<40 | uint64(v[1])<<32 | uint64(v[2])<<24 | uint64(v[3])<<16 | uint64(v[4])<<8 | uint64(v[5]) + return true +} + +// ReadUint64 decodes a big-endian, 64-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint64(out *uint64) bool { + v := s.read(8) + if v == nil { + return false + } + *out = uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7]) + return true +} + +func (s *String) readUnsigned(out *uint32, length int) bool { + v := s.read(length) + if v == nil { + return false + } + var result uint32 + for i := 0; i < length; i++ { + result <<= 8 + result |= uint32(v[i]) + } + *out = result + return true +} + +func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool { + lenBytes := s.read(lenLen) + if lenBytes == nil { + return false + } + var length uint32 + for _, b := range lenBytes { + length = length << 8 + length = length | uint32(b) + } + v := s.read(int(length)) + if v == nil { + return false + } + *outChild = v + return true +} + +// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value +// into out and advances over it. It reports whether the read was successful. +func (s *String) ReadUint8LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(1, out) +} + +// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit +// length-prefixed value into out and advances over it. It reports whether the +// read was successful. +func (s *String) ReadUint16LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(2, out) +} + +// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit +// length-prefixed value into out and advances over it. It reports whether +// the read was successful. +func (s *String) ReadUint24LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(3, out) +} + +// ReadBytes reads n bytes into out and advances over them. It reports +// whether the read was successful. +func (s *String) ReadBytes(out *[]byte, n int) bool { + v := s.read(n) + if v == nil { + return false + } + *out = v + return true +} + +// CopyBytes copies len(out) bytes into out and advances over them. It reports +// whether the copy operation was successful +func (s *String) CopyBytes(out []byte) bool { + n := len(out) + v := s.read(n) + if v == nil { + return false + } + return copy(out, v) == n +} + +// Empty reports whether the string does not contain any bytes. +func (s String) Empty() bool { + return len(s) == 0 +} diff --git a/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s new file mode 100644 index 00000000..269e173c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s @@ -0,0 +1,17 @@ +// Copyright 2018 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 gc + +#include "textflag.h" + +// +// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go +// + +TEXT ·syscall6(SB),NOSPLIT,$0-88 + JMP syscall·syscall6(SB) + +TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s b/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s new file mode 100644 index 00000000..ec2acfe5 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && amd64 && gc + +#include "textflag.h" + +TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) +GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) + +TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sysctlbyname(SB) +GLOBL ·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB) diff --git a/vendor/golang.org/x/sys/cpu/byteorder.go b/vendor/golang.org/x/sys/cpu/byteorder.go new file mode 100644 index 00000000..271055be --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/byteorder.go @@ -0,0 +1,66 @@ +// Copyright 2019 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 cpu + +import ( + "runtime" +) + +// byteOrder is a subset of encoding/binary.ByteOrder. +type byteOrder interface { + Uint32([]byte) uint32 + Uint64([]byte) uint64 +} + +type littleEndian struct{} +type bigEndian struct{} + +func (littleEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func (littleEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func (bigEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func (bigEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + +// hostByteOrder returns littleEndian on little-endian machines and +// bigEndian on big-endian machines. +func hostByteOrder() byteOrder { + switch runtime.GOARCH { + case "386", "amd64", "amd64p32", + "alpha", + "arm", "arm64", + "loong64", + "mipsle", "mips64le", "mips64p32le", + "nios2", + "ppc64le", + "riscv", "riscv64", + "sh": + return littleEndian{} + case "armbe", "arm64be", + "m68k", + "mips", "mips64", "mips64p32", + "ppc", "ppc64", + "s390", "s390x", + "shbe", + "sparc", "sparc64": + return bigEndian{} + } + panic("unknown architecture") +} diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 00000000..63541994 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,338 @@ +// Copyright 2018 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 cpu implements processor feature detection for +// various CPU architectures. +package cpu + +import ( + "os" + "strings" +) + +// Initialized reports whether the CPU features were initialized. +// +// For some GOOS/GOARCH combinations initialization of the CPU features depends +// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm +// Initialized will report false if reading the file fails. +var Initialized bool + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasAVX512 bool // Advanced vector extension 512 + HasAVX512F bool // Advanced vector extension 512 Foundation Instructions + HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions + HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions + HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions + HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions + HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions + HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions + HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add + HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions + HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision + HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision + HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions + HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations + HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions + HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions + HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions + HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 + HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms + HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions + HasAMXTile bool // Advanced Matrix Extension Tile instructions + HasAMXInt8 bool // Advanced Matrix Extension Int8 instructions + HasAMXBF16 bool // Advanced Matrix Extension BFloat16 instructions + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasCX16 bool // Compare and exchange 16 Bytes + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasRDRAND bool // RDRAND instruction (on-chip random number generator) + HasRDSEED bool // RDSEED instruction (on-chip random number generator) + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + HasAVXIFMA bool // Advanced vector extension Integer Fused Multiply Add + HasAVXVNNI bool // Advanced vector extension Vector Neural Network Instructions + HasAVXVNNIInt8 bool // Advanced vector extension Vector Neural Network Int8 instructions + _ CacheLinePad +} + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasSVE2 bool // Scalable Vector Extensions 2 + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + HasDIT bool // Data Independent Timing support + HasI8MM bool // Advanced SIMD Int8 matrix multiplication instructions + _ CacheLinePad +} + +// ARM contains the supported CPU features of the current ARM (32-bit) platform. +// All feature flags are false if: +// 1. the current platform is not arm, or +// 2. the current operating system is not Linux. +var ARM struct { + _ CacheLinePad + HasSWP bool // SWP instruction support + HasHALF bool // Half-word load and store support + HasTHUMB bool // ARM Thumb instruction set + Has26BIT bool // Address space limited to 26-bits + HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support + HasFPA bool // Floating point arithmetic support + HasVFP bool // Vector floating point support + HasEDSP bool // DSP Extensions support + HasJAVA bool // Java instruction set + HasIWMMXT bool // Intel Wireless MMX technology support + HasCRUNCH bool // MaverickCrunch context switching and handling + HasTHUMBEE bool // Thumb EE instruction set + HasNEON bool // NEON instruction set + HasVFPv3 bool // Vector floating point version 3 support + HasVFPv3D16 bool // Vector floating point version 3 D8-D15 + HasTLS bool // Thread local storage support + HasVFPv4 bool // Vector floating point version 4 support + HasIDIVA bool // Integer divide instruction support in ARM mode + HasIDIVT bool // Integer divide instruction support in Thumb mode + HasVFPD32 bool // Vector floating point version 3 D15-D31 + HasLPAE bool // Large Physical Address Extensions + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + _ CacheLinePad +} + +// The booleans in Loong64 contain the correspondingly named cpu feature bit. +// The struct is padded to avoid false sharing. +var Loong64 struct { + _ CacheLinePad + HasLSX bool // support 128-bit vector extension + HasLASX bool // support 256-bit vector extension + HasCRC32 bool // support CRC instruction + HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction + HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} instruction + _ CacheLinePad +} + +// MIPS64X contains the supported CPU features of the current mips64/mips64le +// platforms. If the current platform is not mips64/mips64le or the current +// operating system is not Linux then all feature flags are false. +var MIPS64X struct { + _ CacheLinePad + HasMSA bool // MIPS SIMD architecture + _ CacheLinePad +} + +// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. +// If the current platform is not ppc64/ppc64le then all feature flags are false. +// +// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (DARN, SCV), so there are feature bits for +// those as well. The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8 + _ CacheLinePad +} + +// S390X contains the supported CPU features of the current IBM Z +// (s390x) platform. If the current platform is not IBM Z then all +// feature flags are false. +// +// S390X is padded to avoid false sharing. Further HasVX is only set +// if the OS supports vector registers in addition to the STFLE +// feature bit being set. +var S390X struct { + _ CacheLinePad + HasZARCH bool // z/Architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended + HasLDISP bool // long (20-bit) displacements + HasEIMM bool // 32-bit immediates + HasDFP bool // decimal floating point + HasETF3EH bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions + HasVX bool // vector facility + HasVXE bool // vector-enhancements facility 1 + _ CacheLinePad +} + +// RISCV64 contains the supported CPU features and performance characteristics for riscv64 +// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate +// the presence of RISC-V extensions. +// +// It is safe to assume that all the RV64G extensions are supported and so they are omitted from +// this structure. As riscv64 Go programs require at least RV64G, the code that populates +// this structure cannot run successfully if some of the RV64G extensions are missing. +// The struct is padded to avoid false sharing. +var RISCV64 struct { + _ CacheLinePad + HasFastMisaligned bool // Fast misaligned accesses + HasC bool // Compressed instruction-set extension + HasV bool // Vector extension compatible with RVV 1.0 + HasZba bool // Address generation instructions extension + HasZbb bool // Basic bit-manipulation extension + HasZbs bool // Single-bit instructions extension + HasZvbb bool // Vector Basic Bit-manipulation + HasZvbc bool // Vector Carryless Multiplication + HasZvkb bool // Vector Cryptography Bit-manipulation + HasZvkt bool // Vector Data-Independent Execution Latency + HasZvkg bool // Vector GCM/GMAC + HasZvkn bool // NIST Algorithm Suite (AES/SHA256/SHA512) + HasZvknc bool // NIST Algorithm Suite with carryless multiply + HasZvkng bool // NIST Algorithm Suite with GCM + HasZvks bool // ShangMi Algorithm Suite + HasZvksc bool // ShangMi Algorithm Suite with carryless multiplication + HasZvksg bool // ShangMi Algorithm Suite with GCM + _ CacheLinePad +} + +func init() { + archInit() + initOptions() + processOptions() +} + +// options contains the cpu debug options that can be used in GODEBUG. +// Options are arch dependent and are added by the arch specific initOptions functions. +// Features that are mandatory for the specific GOARCH should have the Required field set +// (e.g. SSE2 on amd64). +var options []option + +// Option names should be lower case. e.g. avx instead of AVX. +type option struct { + Name string + Feature *bool + Specified bool // whether feature value was specified in GODEBUG + Enable bool // whether feature should be enabled + Required bool // whether feature is mandatory and can not be disabled +} + +func processOptions() { + env := os.Getenv("GODEBUG") +field: + for env != "" { + field := "" + i := strings.IndexByte(env, ',') + if i < 0 { + field, env = env, "" + } else { + field, env = env[:i], env[i+1:] + } + if len(field) < 4 || field[:4] != "cpu." { + continue + } + i = strings.IndexByte(field, '=') + if i < 0 { + print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") + continue + } + key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" + + var enable bool + switch value { + case "on": + enable = true + case "off": + enable = false + default: + print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") + continue field + } + + if key == "all" { + for i := range options { + options[i].Specified = true + options[i].Enable = enable || options[i].Required + } + continue field + } + + for i := range options { + if options[i].Name == key { + options[i].Specified = true + options[i].Enable = enable + continue field + } + } + + print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") + } + + for _, o := range options { + if !o.Specified { + continue + } + + if o.Enable && !*o.Feature { + print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") + continue + } + + if !o.Enable && o.Required { + print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") + continue + } + + *o.Feature = o.Enable + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_aix.go b/vendor/golang.org/x/sys/cpu/cpu_aix.go new file mode 100644 index 00000000..9bf0c32e --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_aix.go @@ -0,0 +1,33 @@ +// Copyright 2019 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 aix + +package cpu + +const ( + // getsystemcfg constants + _SC_IMPL = 2 + _IMPL_POWER8 = 0x10000 + _IMPL_POWER9 = 0x20000 +) + +func archInit() { + impl := getsystemcfg(_SC_IMPL) + if impl&_IMPL_POWER8 != 0 { + PPC64.IsPOWER8 = true + } + if impl&_IMPL_POWER9 != 0 { + PPC64.IsPOWER8 = true + PPC64.IsPOWER9 = true + } + + Initialized = true +} + +func getsystemcfg(label int) (n uint64) { + r0, _ := callgetsystemcfg(label) + n = uint64(r0) + return +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 00000000..301b752e --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,73 @@ +// Copyright 2018 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 cpu + +const cacheLineSize = 32 + +// HWCAP/HWCAP2 bits. +// These are specific to Linux. +const ( + hwcap_SWP = 1 << 0 + hwcap_HALF = 1 << 1 + hwcap_THUMB = 1 << 2 + hwcap_26BIT = 1 << 3 + hwcap_FAST_MULT = 1 << 4 + hwcap_FPA = 1 << 5 + hwcap_VFP = 1 << 6 + hwcap_EDSP = 1 << 7 + hwcap_JAVA = 1 << 8 + hwcap_IWMMXT = 1 << 9 + hwcap_CRUNCH = 1 << 10 + hwcap_THUMBEE = 1 << 11 + hwcap_NEON = 1 << 12 + hwcap_VFPv3 = 1 << 13 + hwcap_VFPv3D16 = 1 << 14 + hwcap_TLS = 1 << 15 + hwcap_VFPv4 = 1 << 16 + hwcap_IDIVA = 1 << 17 + hwcap_IDIVT = 1 << 18 + hwcap_VFPD32 = 1 << 19 + hwcap_LPAE = 1 << 20 + hwcap_EVTSTRM = 1 << 21 + + hwcap2_AES = 1 << 0 + hwcap2_PMULL = 1 << 1 + hwcap2_SHA1 = 1 << 2 + hwcap2_SHA2 = 1 << 3 + hwcap2_CRC32 = 1 << 4 +) + +func initOptions() { + options = []option{ + {Name: "pmull", Feature: &ARM.HasPMULL}, + {Name: "sha1", Feature: &ARM.HasSHA1}, + {Name: "sha2", Feature: &ARM.HasSHA2}, + {Name: "swp", Feature: &ARM.HasSWP}, + {Name: "thumb", Feature: &ARM.HasTHUMB}, + {Name: "thumbee", Feature: &ARM.HasTHUMBEE}, + {Name: "tls", Feature: &ARM.HasTLS}, + {Name: "vfp", Feature: &ARM.HasVFP}, + {Name: "vfpd32", Feature: &ARM.HasVFPD32}, + {Name: "vfpv3", Feature: &ARM.HasVFPv3}, + {Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16}, + {Name: "vfpv4", Feature: &ARM.HasVFPv4}, + {Name: "half", Feature: &ARM.HasHALF}, + {Name: "26bit", Feature: &ARM.Has26BIT}, + {Name: "fastmul", Feature: &ARM.HasFASTMUL}, + {Name: "fpa", Feature: &ARM.HasFPA}, + {Name: "edsp", Feature: &ARM.HasEDSP}, + {Name: "java", Feature: &ARM.HasJAVA}, + {Name: "iwmmxt", Feature: &ARM.HasIWMMXT}, + {Name: "crunch", Feature: &ARM.HasCRUNCH}, + {Name: "neon", Feature: &ARM.HasNEON}, + {Name: "idivt", Feature: &ARM.HasIDIVT}, + {Name: "idiva", Feature: &ARM.HasIDIVA}, + {Name: "lpae", Feature: &ARM.HasLPAE}, + {Name: "evtstrm", Feature: &ARM.HasEVTSTRM}, + {Name: "aes", Feature: &ARM.HasAES}, + {Name: "crc32", Feature: &ARM.HasCRC32}, + } + +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_arm64.go new file mode 100644 index 00000000..af2aa99f --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -0,0 +1,194 @@ +// Copyright 2019 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 cpu + +import "runtime" + +// cacheLineSize is used to prevent false sharing of cache lines. +// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size. +// It doesn't cost much and is much more future-proof. +const cacheLineSize = 128 + +func initOptions() { + options = []option{ + {Name: "fp", Feature: &ARM64.HasFP}, + {Name: "asimd", Feature: &ARM64.HasASIMD}, + {Name: "evstrm", Feature: &ARM64.HasEVTSTRM}, + {Name: "aes", Feature: &ARM64.HasAES}, + {Name: "fphp", Feature: &ARM64.HasFPHP}, + {Name: "jscvt", Feature: &ARM64.HasJSCVT}, + {Name: "lrcpc", Feature: &ARM64.HasLRCPC}, + {Name: "pmull", Feature: &ARM64.HasPMULL}, + {Name: "sha1", Feature: &ARM64.HasSHA1}, + {Name: "sha2", Feature: &ARM64.HasSHA2}, + {Name: "sha3", Feature: &ARM64.HasSHA3}, + {Name: "sha512", Feature: &ARM64.HasSHA512}, + {Name: "sm3", Feature: &ARM64.HasSM3}, + {Name: "sm4", Feature: &ARM64.HasSM4}, + {Name: "sve", Feature: &ARM64.HasSVE}, + {Name: "sve2", Feature: &ARM64.HasSVE2}, + {Name: "crc32", Feature: &ARM64.HasCRC32}, + {Name: "atomics", Feature: &ARM64.HasATOMICS}, + {Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, + {Name: "cpuid", Feature: &ARM64.HasCPUID}, + {Name: "asimrdm", Feature: &ARM64.HasASIMDRDM}, + {Name: "fcma", Feature: &ARM64.HasFCMA}, + {Name: "dcpop", Feature: &ARM64.HasDCPOP}, + {Name: "asimddp", Feature: &ARM64.HasASIMDDP}, + {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM}, + {Name: "dit", Feature: &ARM64.HasDIT}, + {Name: "i8mm", Feature: &ARM64.HasI8MM}, + } +} + +func archInit() { + switch runtime.GOOS { + case "freebsd": + readARM64Registers() + case "linux", "netbsd", "openbsd": + doinit() + default: + // Many platforms don't seem to allow reading these registers. + setMinimalFeatures() + } +} + +// setMinimalFeatures fakes the minimal ARM64 features expected by +// TestARM64minimalFeatures. +func setMinimalFeatures() { + ARM64.HasASIMD = true + ARM64.HasFP = true +} + +func readARM64Registers() { + Initialized = true + + parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0()) +} + +func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { + // ID_AA64ISAR0_EL1 + switch extractBits(isar0, 4, 7) { + case 1: + ARM64.HasAES = true + case 2: + ARM64.HasAES = true + ARM64.HasPMULL = true + } + + switch extractBits(isar0, 8, 11) { + case 1: + ARM64.HasSHA1 = true + } + + switch extractBits(isar0, 12, 15) { + case 1: + ARM64.HasSHA2 = true + case 2: + ARM64.HasSHA2 = true + ARM64.HasSHA512 = true + } + + switch extractBits(isar0, 16, 19) { + case 1: + ARM64.HasCRC32 = true + } + + switch extractBits(isar0, 20, 23) { + case 2: + ARM64.HasATOMICS = true + } + + switch extractBits(isar0, 28, 31) { + case 1: + ARM64.HasASIMDRDM = true + } + + switch extractBits(isar0, 32, 35) { + case 1: + ARM64.HasSHA3 = true + } + + switch extractBits(isar0, 36, 39) { + case 1: + ARM64.HasSM3 = true + } + + switch extractBits(isar0, 40, 43) { + case 1: + ARM64.HasSM4 = true + } + + switch extractBits(isar0, 44, 47) { + case 1: + ARM64.HasASIMDDP = true + } + + // ID_AA64ISAR1_EL1 + switch extractBits(isar1, 0, 3) { + case 1: + ARM64.HasDCPOP = true + } + + switch extractBits(isar1, 12, 15) { + case 1: + ARM64.HasJSCVT = true + } + + switch extractBits(isar1, 16, 19) { + case 1: + ARM64.HasFCMA = true + } + + switch extractBits(isar1, 20, 23) { + case 1: + ARM64.HasLRCPC = true + } + + switch extractBits(isar1, 52, 55) { + case 1: + ARM64.HasI8MM = true + } + + // ID_AA64PFR0_EL1 + switch extractBits(pfr0, 16, 19) { + case 0: + ARM64.HasFP = true + case 1: + ARM64.HasFP = true + ARM64.HasFPHP = true + } + + switch extractBits(pfr0, 20, 23) { + case 0: + ARM64.HasASIMD = true + case 1: + ARM64.HasASIMD = true + ARM64.HasASIMDHP = true + } + + switch extractBits(pfr0, 32, 35) { + case 1: + ARM64.HasSVE = true + + parseARM64SVERegister(getzfr0()) + } + + switch extractBits(pfr0, 48, 51) { + case 1: + ARM64.HasDIT = true + } +} + +func parseARM64SVERegister(zfr0 uint64) { + switch extractBits(zfr0, 0, 3) { + case 1: + ARM64.HasSVE2 = true + } +} + +func extractBits(data uint64, start, end uint) uint { + return (uint)(data>>start) & ((1 << (end - start + 1)) - 1) +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.s b/vendor/golang.org/x/sys/cpu/cpu_arm64.s new file mode 100644 index 00000000..22cc9984 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.s @@ -0,0 +1,39 @@ +// Copyright 2019 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 gc + +#include "textflag.h" + +// func getisar0() uint64 +TEXT ·getisar0(SB),NOSPLIT,$0-8 + // get Instruction Set Attributes 0 into x0 + // mrs x0, ID_AA64ISAR0_EL1 = d5380600 + WORD $0xd5380600 + MOVD R0, ret+0(FP) + RET + +// func getisar1() uint64 +TEXT ·getisar1(SB),NOSPLIT,$0-8 + // get Instruction Set Attributes 1 into x0 + // mrs x0, ID_AA64ISAR1_EL1 = d5380620 + WORD $0xd5380620 + MOVD R0, ret+0(FP) + RET + +// func getpfr0() uint64 +TEXT ·getpfr0(SB),NOSPLIT,$0-8 + // get Processor Feature Register 0 into x0 + // mrs x0, ID_AA64PFR0_EL1 = d5380400 + WORD $0xd5380400 + MOVD R0, ret+0(FP) + RET + +// func getzfr0() uint64 +TEXT ·getzfr0(SB),NOSPLIT,$0-8 + // get SVE Feature Register 0 into x0 + // mrs x0, ID_AA64ZFR0_EL1 = d5380480 + WORD $0xd5380480 + MOVD R0, ret+0(FP) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go b/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go new file mode 100644 index 00000000..b838cb9e --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go @@ -0,0 +1,61 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && amd64 && gc + +package cpu + +// darwinSupportsAVX512 checks Darwin kernel for AVX512 support via sysctl +// call (see issue 43089). It also restricts AVX512 support for Darwin to +// kernel version 21.3.0 (MacOS 12.2.0) or later (see issue 49233). +// +// Background: +// Darwin implements a special mechanism to economize on thread state when +// AVX512 specific registers are not in use. This scheme minimizes state when +// preempting threads that haven't yet used any AVX512 instructions, but adds +// special requirements to check for AVX512 hardware support at runtime (e.g. +// via sysctl call or commpage inspection). See issue 43089 and link below for +// full background: +// https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.1.10/osfmk/i386/fpu.c#L214-L240 +// +// Additionally, all versions of the Darwin kernel from 19.6.0 through 21.2.0 +// (corresponding to MacOS 10.15.6 - 12.1) have a bug that can cause corruption +// of the AVX512 mask registers (K0-K7) upon signal return. For this reason +// AVX512 is considered unsafe to use on Darwin for kernel versions prior to +// 21.3.0, where a fix has been confirmed. See issue 49233 for full background. +func darwinSupportsAVX512() bool { + return darwinSysctlEnabled([]byte("hw.optional.avx512f\x00")) && darwinKernelVersionCheck(21, 3, 0) +} + +// Ensure Darwin kernel version is at least major.minor.patch, avoiding dependencies +func darwinKernelVersionCheck(major, minor, patch int) bool { + var release [256]byte + err := darwinOSRelease(&release) + if err != nil { + return false + } + + var mmp [3]int + c := 0 +Loop: + for _, b := range release[:] { + switch { + case b >= '0' && b <= '9': + mmp[c] = 10*mmp[c] + int(b-'0') + case b == '.': + c++ + if c > 2 { + return false + } + case b == 0: + break Loop + default: + return false + } + } + if c != 2 { + return false + } + return mmp[0] > major || mmp[0] == major && (mmp[1] > minor || mmp[1] == minor && mmp[2] >= patch) +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go new file mode 100644 index 00000000..6ac6e1ef --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go @@ -0,0 +1,12 @@ +// Copyright 2019 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 gc + +package cpu + +func getisar0() uint64 +func getisar1() uint64 +func getpfr0() uint64 +func getzfr0() uint64 diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go new file mode 100644 index 00000000..c8ae6ddc --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go @@ -0,0 +1,21 @@ +// Copyright 2019 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 gc + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return true } + +// The following feature detection functions are defined in cpu_s390x.s. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList +func kmQuery() queryResult +func kmcQuery() queryResult +func kmctrQuery() queryResult +func kmaQuery() queryResult +func kimdQuery() queryResult +func klmdQuery() queryResult diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go new file mode 100644 index 00000000..32a44514 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -0,0 +1,15 @@ +// Copyright 2018 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 (386 || amd64 || amd64p32) && gc + +package cpu + +// cpuid is implemented in cpu_gc_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) + +// xgetbv with ecx = 0 is implemented in cpu_gc_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.s b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.s new file mode 100644 index 00000000..ce208ce6 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.s @@ -0,0 +1,26 @@ +// Copyright 2018 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 (386 || amd64 || amd64p32) && gc + +#include "textflag.h" + +// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) +TEXT ·cpuid(SB), NOSPLIT, $0-24 + MOVL eaxArg+0(FP), AX + MOVL ecxArg+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func xgetbv() (eax, edx uint32) +TEXT ·xgetbv(SB), NOSPLIT, $0-8 + MOVL $0, CX + XGETBV + MOVL AX, eax+0(FP) + MOVL DX, edx+4(FP) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go new file mode 100644 index 00000000..7f194678 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go @@ -0,0 +1,11 @@ +// Copyright 2019 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 gccgo + +package cpu + +func getisar0() uint64 { return 0 } +func getisar1() uint64 { return 0 } +func getpfr0() uint64 { return 0 } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go new file mode 100644 index 00000000..9526d2ce --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go @@ -0,0 +1,22 @@ +// Copyright 2019 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 gccgo + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return false } + +// TODO(mundaym): the following feature detection functions are currently +// stubs. See https://golang.org/cl/162887 for how to fix this. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList { panic("not implemented for gccgo") } +func kmQuery() queryResult { panic("not implemented for gccgo") } +func kmcQuery() queryResult { panic("not implemented for gccgo") } +func kmctrQuery() queryResult { panic("not implemented for gccgo") } +func kmaQuery() queryResult { panic("not implemented for gccgo") } +func kimdQuery() queryResult { panic("not implemented for gccgo") } +func klmdQuery() queryResult { panic("not implemented for gccgo") } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c new file mode 100644 index 00000000..3f73a05d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c @@ -0,0 +1,37 @@ +// Copyright 2018 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 (386 || amd64 || amd64p32) && gccgo + +#include +#include +#include + +// Need to wrap __get_cpuid_count because it's declared as static. +int +gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); +} + +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC push_options +#pragma GCC target("xsave") +#pragma clang attribute push (__attribute__((target("xsave"))), apply_to=function) + +// xgetbv reads the contents of an XCR (Extended Control Register) +// specified in the ECX register into registers EDX:EAX. +// Currently, the only supported value for XCR is 0. +void +gccgoXgetbv(uint32_t *eax, uint32_t *edx) +{ + uint64_t v = _xgetbv(0); + *eax = v & 0xffffffff; + *edx = v >> 32; +} + +#pragma clang attribute pop +#pragma GCC pop_options diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go new file mode 100644 index 00000000..170d21dd --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go @@ -0,0 +1,25 @@ +// Copyright 2018 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 (386 || amd64 || amd64p32) && gccgo + +package cpu + +//extern gccgoGetCpuidCount +func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) + +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { + var a, b, c, d uint32 + gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) + return a, b, c, d +} + +//extern gccgoXgetbv +func gccgoXgetbv(eax, edx *uint32) + +func xgetbv() (eax, edx uint32) { + var a, d uint32 + gccgoXgetbv(&a, &d) + return a, d +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux.go b/vendor/golang.org/x/sys/cpu/cpu_linux.go new file mode 100644 index 00000000..743eb543 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux.go @@ -0,0 +1,15 @@ +// Copyright 2018 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 !386 && !amd64 && !amd64p32 && !arm64 + +package cpu + +func archInit() { + if err := readHWCAP(); err != nil { + return + } + doinit() + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go new file mode 100644 index 00000000..2057006d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go @@ -0,0 +1,39 @@ +// Copyright 2019 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 cpu + +func doinit() { + ARM.HasSWP = isSet(hwCap, hwcap_SWP) + ARM.HasHALF = isSet(hwCap, hwcap_HALF) + ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB) + ARM.Has26BIT = isSet(hwCap, hwcap_26BIT) + ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT) + ARM.HasFPA = isSet(hwCap, hwcap_FPA) + ARM.HasVFP = isSet(hwCap, hwcap_VFP) + ARM.HasEDSP = isSet(hwCap, hwcap_EDSP) + ARM.HasJAVA = isSet(hwCap, hwcap_JAVA) + ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT) + ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH) + ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE) + ARM.HasNEON = isSet(hwCap, hwcap_NEON) + ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3) + ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16) + ARM.HasTLS = isSet(hwCap, hwcap_TLS) + ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4) + ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA) + ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT) + ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32) + ARM.HasLPAE = isSet(hwCap, hwcap_LPAE) + ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM.HasAES = isSet(hwCap2, hwcap2_AES) + ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL) + ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1) + ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2) + ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go new file mode 100644 index 00000000..f1caf0f7 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -0,0 +1,120 @@ +// Copyright 2018 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 cpu + +import ( + "strings" + "syscall" +) + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + hwcap_FP = 1 << 0 + hwcap_ASIMD = 1 << 1 + hwcap_EVTSTRM = 1 << 2 + hwcap_AES = 1 << 3 + hwcap_PMULL = 1 << 4 + hwcap_SHA1 = 1 << 5 + hwcap_SHA2 = 1 << 6 + hwcap_CRC32 = 1 << 7 + hwcap_ATOMICS = 1 << 8 + hwcap_FPHP = 1 << 9 + hwcap_ASIMDHP = 1 << 10 + hwcap_CPUID = 1 << 11 + hwcap_ASIMDRDM = 1 << 12 + hwcap_JSCVT = 1 << 13 + hwcap_FCMA = 1 << 14 + hwcap_LRCPC = 1 << 15 + hwcap_DCPOP = 1 << 16 + hwcap_SHA3 = 1 << 17 + hwcap_SM3 = 1 << 18 + hwcap_SM4 = 1 << 19 + hwcap_ASIMDDP = 1 << 20 + hwcap_SHA512 = 1 << 21 + hwcap_SVE = 1 << 22 + hwcap_ASIMDFHM = 1 << 23 + hwcap_DIT = 1 << 24 + + hwcap2_SVE2 = 1 << 1 + hwcap2_I8MM = 1 << 13 +) + +// linuxKernelCanEmulateCPUID reports whether we're running +// on Linux 4.11+. Ideally we'd like to ask the question about +// whether the current kernel contains +// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=77c97b4ee21290f5f083173d957843b615abbff2 +// but the version number will have to do. +func linuxKernelCanEmulateCPUID() bool { + var un syscall.Utsname + syscall.Uname(&un) + var sb strings.Builder + for _, b := range un.Release[:] { + if b == 0 { + break + } + sb.WriteByte(byte(b)) + } + major, minor, _, ok := parseRelease(sb.String()) + return ok && (major > 4 || major == 4 && minor >= 11) +} + +func doinit() { + if err := readHWCAP(); err != nil { + // We failed to read /proc/self/auxv. This can happen if the binary has + // been given extra capabilities(7) with /bin/setcap. + // + // When this happens, we have two options. If the Linux kernel is new + // enough (4.11+), we can read the arm64 registers directly which'll + // trap into the kernel and then return back to userspace. + // + // But on older kernels, such as Linux 4.4.180 as used on many Synology + // devices, calling readARM64Registers (specifically getisar0) will + // cause a SIGILL and we'll die. So for older kernels, parse /proc/cpuinfo + // instead. + // + // See golang/go#57336. + if linuxKernelCanEmulateCPUID() { + readARM64Registers() + } else { + readLinuxProcCPUInfo() + } + return + } + + // HWCAP feature bits + ARM64.HasFP = isSet(hwCap, hwcap_FP) + ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD) + ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM64.HasAES = isSet(hwCap, hwcap_AES) + ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL) + ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1) + ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2) + ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32) + ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS) + ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP) + ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP) + ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID) + ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM) + ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT) + ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA) + ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC) + ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP) + ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3) + ARM64.HasSM3 = isSet(hwCap, hwcap_SM3) + ARM64.HasSM4 = isSet(hwCap, hwcap_SM4) + ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP) + ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) + ARM64.HasSVE = isSet(hwCap, hwcap_SVE) + ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) + ARM64.HasDIT = isSet(hwCap, hwcap_DIT) + + // HWCAP2 feature bits + ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2) + ARM64.HasI8MM = isSet(hwCap2, hwcap2_I8MM) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go new file mode 100644 index 00000000..4f341143 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go @@ -0,0 +1,22 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +// HWCAP bits. These are exposed by the Linux kernel. +const ( + hwcap_LOONGARCH_LSX = 1 << 4 + hwcap_LOONGARCH_LASX = 1 << 5 +) + +func doinit() { + // TODO: Features that require kernel support like LSX and LASX can + // be detected here once needed in std library or by the compiler. + Loong64.HasLSX = hwcIsSet(hwCap, hwcap_LOONGARCH_LSX) + Loong64.HasLASX = hwcIsSet(hwCap, hwcap_LOONGARCH_LASX) +} + +func hwcIsSet(hwc uint, val uint) bool { + return hwc&val != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go new file mode 100644 index 00000000..4686c1d5 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go @@ -0,0 +1,22 @@ +// Copyright 2020 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 linux && (mips64 || mips64le) + +package cpu + +// HWCAP bits. These are exposed by the Linux kernel 5.4. +const ( + // CPU features + hwcap_MIPS_MSA = 1 << 1 +) + +func doinit() { + // HWCAP feature bits + MIPS64X.HasMSA = isSet(hwCap, hwcap_MIPS_MSA) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go new file mode 100644 index 00000000..a428dec9 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go @@ -0,0 +1,9 @@ +// Copyright 2019 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 linux && !arm && !arm64 && !loong64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64 + +package cpu + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go new file mode 100644 index 00000000..197188e6 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go @@ -0,0 +1,30 @@ +// Copyright 2018 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 linux && (ppc64 || ppc64le) + +package cpu + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func doinit() { + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go new file mode 100644 index 00000000..ad741536 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go @@ -0,0 +1,160 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "syscall" + "unsafe" +) + +// RISC-V extension discovery code for Linux. The approach here is to first try the riscv_hwprobe +// syscall falling back to HWCAP to check for the C extension if riscv_hwprobe is not available. +// +// A note on detection of the Vector extension using HWCAP. +// +// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5. +// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe +// syscall is not available then neither is the Vector extension (which needs kernel support). +// The riscv_hwprobe syscall should then be all we need to detect the Vector extension. +// However, some RISC-V board manufacturers ship boards with an older kernel on top of which +// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe +// patches. These kernels advertise support for the Vector extension using HWCAP. Falling +// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not +// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option. +// +// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by +// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board +// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified +// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use +// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector +// extension are binary incompatible. HWCAP can then not be used in isolation to populate the +// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0. +// +// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector +// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype +// register. This check would allow us to safely detect version 1.0 of the Vector extension +// with HWCAP, if riscv_hwprobe were not available. However, the check cannot +// be added until the assembler supports the Vector instructions. +// +// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the +// extensions it advertises support for are explicitly versioned. It's also worth noting that +// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zba. +// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority +// of RISC-V extensions. +// +// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information. + +// golang.org/x/sys/cpu is not allowed to depend on golang.org/x/sys/unix so we must +// reproduce the constants, types and functions needed to make the riscv_hwprobe syscall +// here. + +const ( + // Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. + riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4 + riscv_HWPROBE_IMA_C = 0x2 + riscv_HWPROBE_IMA_V = 0x4 + riscv_HWPROBE_EXT_ZBA = 0x8 + riscv_HWPROBE_EXT_ZBB = 0x10 + riscv_HWPROBE_EXT_ZBS = 0x20 + riscv_HWPROBE_EXT_ZVBB = 0x20000 + riscv_HWPROBE_EXT_ZVBC = 0x40000 + riscv_HWPROBE_EXT_ZVKB = 0x80000 + riscv_HWPROBE_EXT_ZVKG = 0x100000 + riscv_HWPROBE_EXT_ZVKNED = 0x200000 + riscv_HWPROBE_EXT_ZVKNHB = 0x800000 + riscv_HWPROBE_EXT_ZVKSED = 0x1000000 + riscv_HWPROBE_EXT_ZVKSH = 0x2000000 + riscv_HWPROBE_EXT_ZVKT = 0x4000000 + riscv_HWPROBE_KEY_CPUPERF_0 = 0x5 + riscv_HWPROBE_MISALIGNED_FAST = 0x3 + riscv_HWPROBE_MISALIGNED_MASK = 0x7 +) + +const ( + // sys_RISCV_HWPROBE is copied from golang.org/x/sys/unix/zsysnum_linux_riscv64.go. + sys_RISCV_HWPROBE = 258 +) + +// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. +type riscvHWProbePairs struct { + key int64 + value uint64 +} + +const ( + // CPU features + hwcap_RISCV_ISA_C = 1 << ('C' - 'A') +) + +func doinit() { + // A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key + // field should be initialised with one of the key constants defined above, e.g., + // RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value. + // If the kernel does not recognise a key it will set the key field to -1 and the value field to 0. + + pairs := []riscvHWProbePairs{ + {riscv_HWPROBE_KEY_IMA_EXT_0, 0}, + {riscv_HWPROBE_KEY_CPUPERF_0, 0}, + } + + // This call only indicates that extensions are supported if they are implemented on all cores. + if riscvHWProbe(pairs, 0) { + if pairs[0].key != -1 { + v := uint(pairs[0].value) + RISCV64.HasC = isSet(v, riscv_HWPROBE_IMA_C) + RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V) + RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA) + RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB) + RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS) + RISCV64.HasZvbb = isSet(v, riscv_HWPROBE_EXT_ZVBB) + RISCV64.HasZvbc = isSet(v, riscv_HWPROBE_EXT_ZVBC) + RISCV64.HasZvkb = isSet(v, riscv_HWPROBE_EXT_ZVKB) + RISCV64.HasZvkg = isSet(v, riscv_HWPROBE_EXT_ZVKG) + RISCV64.HasZvkt = isSet(v, riscv_HWPROBE_EXT_ZVKT) + // Cryptography shorthand extensions + RISCV64.HasZvkn = isSet(v, riscv_HWPROBE_EXT_ZVKNED) && + isSet(v, riscv_HWPROBE_EXT_ZVKNHB) && RISCV64.HasZvkb && RISCV64.HasZvkt + RISCV64.HasZvknc = RISCV64.HasZvkn && RISCV64.HasZvbc + RISCV64.HasZvkng = RISCV64.HasZvkn && RISCV64.HasZvkg + RISCV64.HasZvks = isSet(v, riscv_HWPROBE_EXT_ZVKSED) && + isSet(v, riscv_HWPROBE_EXT_ZVKSH) && RISCV64.HasZvkb && RISCV64.HasZvkt + RISCV64.HasZvksc = RISCV64.HasZvks && RISCV64.HasZvbc + RISCV64.HasZvksg = RISCV64.HasZvks && RISCV64.HasZvkg + } + if pairs[1].key != -1 { + v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK + RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST + } + } + + // Let's double check with HWCAP if the C extension does not appear to be supported. + // This may happen if we're running on a kernel older than 6.4. + + if !RISCV64.HasC { + RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C) + } +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} + +// riscvHWProbe is a simplified version of the generated wrapper function found in +// golang.org/x/sys/unix/zsyscall_linux_riscv64.go. We simplify it by removing the +// cpuCount and cpus parameters which we do not need. We always want to pass 0 for +// these parameters here so the kernel only reports the extensions that are present +// on all cores. +func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool { + var _zero uintptr + var p0 unsafe.Pointer + if len(pairs) > 0 { + p0 = unsafe.Pointer(&pairs[0]) + } else { + p0 = unsafe.Pointer(&_zero) + } + + _, _, e1 := syscall.Syscall6(sys_RISCV_HWPROBE, uintptr(p0), uintptr(len(pairs)), uintptr(0), uintptr(0), uintptr(flags), 0) + return e1 == 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go new file mode 100644 index 00000000..1517ac61 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go @@ -0,0 +1,40 @@ +// Copyright 2019 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 cpu + +const ( + // bit mask values from /usr/include/bits/hwcap.h + hwcap_ZARCH = 2 + hwcap_STFLE = 4 + hwcap_MSA = 8 + hwcap_LDISP = 16 + hwcap_EIMM = 32 + hwcap_DFP = 64 + hwcap_ETF3EH = 256 + hwcap_VX = 2048 + hwcap_VXE = 8192 +) + +func initS390Xbase() { + // test HWCAP bit vector + has := func(featureMask uint) bool { + return hwCap&featureMask == featureMask + } + + // mandatory + S390X.HasZARCH = has(hwcap_ZARCH) + + // optional + S390X.HasSTFLE = has(hwcap_STFLE) + S390X.HasLDISP = has(hwcap_LDISP) + S390X.HasEIMM = has(hwcap_EIMM) + S390X.HasETF3EH = has(hwcap_ETF3EH) + S390X.HasDFP = has(hwcap_DFP) + S390X.HasMSA = has(hwcap_MSA) + S390X.HasVX = has(hwcap_VX) + if S390X.HasVX { + S390X.HasVXE = has(hwcap_VXE) + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/vendor/golang.org/x/sys/cpu/cpu_loong64.go new file mode 100644 index 00000000..45ecb29a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_loong64.go @@ -0,0 +1,50 @@ +// 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. + +//go:build loong64 + +package cpu + +const cacheLineSize = 64 + +// Bit fields for CPUCFG registers, Related reference documents: +// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg +const ( + // CPUCFG1 bits + cpucfg1_CRC32 = 1 << 25 + + // CPUCFG2 bits + cpucfg2_LAM_BH = 1 << 27 + cpucfg2_LAMCAS = 1 << 28 +) + +func initOptions() { + options = []option{ + {Name: "lsx", Feature: &Loong64.HasLSX}, + {Name: "lasx", Feature: &Loong64.HasLASX}, + {Name: "crc32", Feature: &Loong64.HasCRC32}, + {Name: "lam_bh", Feature: &Loong64.HasLAM_BH}, + {Name: "lamcas", Feature: &Loong64.HasLAMCAS}, + } + + // The CPUCFG data on Loong64 only reflects the hardware capabilities, + // not the kernel support status, so features such as LSX and LASX that + // require kernel support cannot be obtained from the CPUCFG data. + // + // These features only require hardware capability support and do not + // require kernel specific support, so they can be obtained directly + // through CPUCFG + cfg1 := get_cpucfg(1) + cfg2 := get_cpucfg(2) + + Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32) + Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS) + Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH) +} + +func get_cpucfg(reg uint32) uint32 + +func cfgIsSet(cfg uint32, val uint32) bool { + return cfg&val != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_loong64.s b/vendor/golang.org/x/sys/cpu/cpu_loong64.s new file mode 100644 index 00000000..71cbaf1c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_loong64.s @@ -0,0 +1,13 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +// func get_cpucfg(reg uint32) uint32 +TEXT ·get_cpucfg(SB), NOSPLIT|NOFRAME, $0 + MOVW reg+0(FP), R5 + // CPUCFG R5, R4 = 0x00006ca4 + WORD $0x00006ca4 + MOVW R4, ret+8(FP) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 00000000..fedb00cc --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,15 @@ +// Copyright 2018 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 mips64 || mips64le + +package cpu + +const cacheLineSize = 32 + +func initOptions() { + options = []option{ + {Name: "msa", Feature: &MIPS64X.HasMSA}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 00000000..ffb4ec7e --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,11 @@ +// Copyright 2018 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 mips || mipsle + +package cpu + +const cacheLineSize = 32 + +func initOptions() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go new file mode 100644 index 00000000..ebfb3fc8 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go @@ -0,0 +1,173 @@ +// Copyright 2020 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 cpu + +import ( + "syscall" + "unsafe" +) + +// Minimal copy of functionality from x/sys/unix so the cpu package can call +// sysctl without depending on x/sys/unix. + +const ( + _CTL_QUERY = -2 + + _SYSCTL_VERS_1 = 0x1000000 +) + +var _zero uintptr + +func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, errno := syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(_p0), + uintptr(len(mib)), + uintptr(unsafe.Pointer(old)), + uintptr(unsafe.Pointer(oldlen)), + uintptr(unsafe.Pointer(new)), + uintptr(newlen)) + if errno != 0 { + return errno + } + return nil +} + +type sysctlNode struct { + Flags uint32 + Num int32 + Name [32]int8 + Ver uint32 + __rsvd uint32 + Un [16]byte + _sysctl_size [8]byte + _sysctl_func [8]byte + _sysctl_parent [8]byte + _sysctl_desc [8]byte +} + +func sysctlNodes(mib []int32) ([]sysctlNode, error) { + var olen uintptr + + // Get a list of all sysctl nodes below the given MIB by performing + // a sysctl for the given MIB with CTL_QUERY appended. + mib = append(mib, _CTL_QUERY) + qnode := sysctlNode{Flags: _SYSCTL_VERS_1} + qp := (*byte)(unsafe.Pointer(&qnode)) + sz := unsafe.Sizeof(qnode) + if err := sysctl(mib, nil, &olen, qp, sz); err != nil { + return nil, err + } + + // Now that we know the size, get the actual nodes. + nodes := make([]sysctlNode, olen/sz) + np := (*byte)(unsafe.Pointer(&nodes[0])) + if err := sysctl(mib, np, &olen, qp, sz); err != nil { + return nil, err + } + + return nodes, nil +} + +func nametomib(name string) ([]int32, error) { + // Split name into components. + var parts []string + last := 0 + for i := 0; i < len(name); i++ { + if name[i] == '.' { + parts = append(parts, name[last:i]) + last = i + 1 + } + } + parts = append(parts, name[last:]) + + mib := []int32{} + // Discover the nodes and construct the MIB OID. + for partno, part := range parts { + nodes, err := sysctlNodes(mib) + if err != nil { + return nil, err + } + for _, node := range nodes { + n := make([]byte, 0) + for i := range node.Name { + if node.Name[i] != 0 { + n = append(n, byte(node.Name[i])) + } + } + if string(n) == part { + mib = append(mib, int32(node.Num)) + break + } + } + if len(mib) != partno+1 { + return nil, err + } + } + + return mib, nil +} + +// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's +type aarch64SysctlCPUID struct { + midr uint64 /* Main ID Register */ + revidr uint64 /* Revision ID Register */ + mpidr uint64 /* Multiprocessor Affinity Register */ + aa64dfr0 uint64 /* A64 Debug Feature Register 0 */ + aa64dfr1 uint64 /* A64 Debug Feature Register 1 */ + aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */ + aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */ + aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */ + aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */ + aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */ + aa64pfr0 uint64 /* A64 Processor Feature Register 0 */ + aa64pfr1 uint64 /* A64 Processor Feature Register 1 */ + aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */ + mvfr0 uint32 /* Media and VFP Feature Register 0 */ + mvfr1 uint32 /* Media and VFP Feature Register 1 */ + mvfr2 uint32 /* Media and VFP Feature Register 2 */ + pad uint32 + clidr uint64 /* Cache Level ID Register */ + ctr uint64 /* Cache Type Register */ +} + +func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) { + mib, err := nametomib(name) + if err != nil { + return nil, err + } + + out := aarch64SysctlCPUID{} + n := unsafe.Sizeof(out) + _, _, errno := syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(len(mib)), + uintptr(unsafe.Pointer(&out)), + uintptr(unsafe.Pointer(&n)), + uintptr(0), + uintptr(0)) + if errno != 0 { + return nil, errno + } + return &out, nil +} + +func doinit() { + cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id") + if err != nil { + setMinimalFeatures() + return + } + parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0) + + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go new file mode 100644 index 00000000..85b64d5c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go @@ -0,0 +1,65 @@ +// 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 cpu + +import ( + "syscall" + "unsafe" +) + +// Minimal copy of functionality from x/sys/unix so the cpu package can call +// sysctl without depending on x/sys/unix. + +const ( + // From OpenBSD's sys/sysctl.h. + _CTL_MACHDEP = 7 + + // From OpenBSD's machine/cpu.h. + _CPU_ID_AA64ISAR0 = 2 + _CPU_ID_AA64ISAR1 = 3 +) + +// Implemented in the runtime package (runtime/sys_openbsd3.go) +func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + +//go:linkname syscall_syscall6 syscall.syscall6 + +func sysctl(mib []uint32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + _, _, errno := syscall_syscall6(libc_sysctl_trampoline_addr, uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if errno != 0 { + return errno + } + return nil +} + +var libc_sysctl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_sysctl sysctl "libc.so" + +func sysctlUint64(mib []uint32) (uint64, bool) { + var out uint64 + nout := unsafe.Sizeof(out) + if err := sysctl(mib, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); err != nil { + return 0, false + } + return out, true +} + +func doinit() { + setMinimalFeatures() + + // Get ID_AA64ISAR0 and ID_AA64ISAR1 from sysctl. + isar0, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR0}) + if !ok { + return + } + isar1, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR1}) + if !ok { + return + } + parseARM64SystemRegisters(isar0, isar1, 0) + + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s new file mode 100644 index 00000000..054ba05d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s @@ -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. + +#include "textflag.h" + +TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) + +GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm.go new file mode 100644 index 00000000..e9ecf2a4 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm.go @@ -0,0 +1,9 @@ +// Copyright 2020 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 !linux && arm + +package cpu + +func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go new file mode 100644 index 00000000..5341e7f8 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go @@ -0,0 +1,9 @@ +// Copyright 2019 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 !linux && !netbsd && !openbsd && arm64 + +package cpu + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go new file mode 100644 index 00000000..5f8f2419 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go @@ -0,0 +1,11 @@ +// Copyright 2020 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 !linux && (mips64 || mips64le) + +package cpu + +func archInit() { + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go new file mode 100644 index 00000000..89608fba --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go @@ -0,0 +1,12 @@ +// 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. + +//go:build !aix && !linux && (ppc64 || ppc64le) + +package cpu + +func archInit() { + PPC64.IsPOWER8 = true + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go new file mode 100644 index 00000000..5ab87808 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go @@ -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. + +//go:build !linux && riscv64 + +package cpu + +func archInit() { + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_x86.go b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go new file mode 100644 index 00000000..a0fd7e2f --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go @@ -0,0 +1,11 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build 386 || amd64p32 || (amd64 && (!darwin || !gc)) + +package cpu + +func darwinSupportsAVX512() bool { + panic("only implemented for gc && amd64 && darwin") +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go new file mode 100644 index 00000000..c14f12b1 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go @@ -0,0 +1,16 @@ +// Copyright 2020 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 ppc64 || ppc64le + +package cpu + +const cacheLineSize = 128 + +func initOptions() { + options = []option{ + {Name: "darn", Feature: &PPC64.HasDARN}, + {Name: "scv", Feature: &PPC64.HasSCV}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go new file mode 100644 index 00000000..0f617aef --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go @@ -0,0 +1,32 @@ +// Copyright 2019 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 riscv64 + +package cpu + +const cacheLineSize = 64 + +func initOptions() { + options = []option{ + {Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned}, + {Name: "c", Feature: &RISCV64.HasC}, + {Name: "v", Feature: &RISCV64.HasV}, + {Name: "zba", Feature: &RISCV64.HasZba}, + {Name: "zbb", Feature: &RISCV64.HasZbb}, + {Name: "zbs", Feature: &RISCV64.HasZbs}, + // RISC-V Cryptography Extensions + {Name: "zvbb", Feature: &RISCV64.HasZvbb}, + {Name: "zvbc", Feature: &RISCV64.HasZvbc}, + {Name: "zvkb", Feature: &RISCV64.HasZvkb}, + {Name: "zvkg", Feature: &RISCV64.HasZvkg}, + {Name: "zvkt", Feature: &RISCV64.HasZvkt}, + {Name: "zvkn", Feature: &RISCV64.HasZvkn}, + {Name: "zvknc", Feature: &RISCV64.HasZvknc}, + {Name: "zvkng", Feature: &RISCV64.HasZvkng}, + {Name: "zvks", Feature: &RISCV64.HasZvks}, + {Name: "zvksc", Feature: &RISCV64.HasZvksc}, + {Name: "zvksg", Feature: &RISCV64.HasZvksg}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_s390x.go new file mode 100644 index 00000000..5881b883 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.go @@ -0,0 +1,172 @@ +// Copyright 2020 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 cpu + +const cacheLineSize = 256 + +func initOptions() { + options = []option{ + {Name: "zarch", Feature: &S390X.HasZARCH, Required: true}, + {Name: "stfle", Feature: &S390X.HasSTFLE, Required: true}, + {Name: "ldisp", Feature: &S390X.HasLDISP, Required: true}, + {Name: "eimm", Feature: &S390X.HasEIMM, Required: true}, + {Name: "dfp", Feature: &S390X.HasDFP}, + {Name: "etf3eh", Feature: &S390X.HasETF3EH}, + {Name: "msa", Feature: &S390X.HasMSA}, + {Name: "aes", Feature: &S390X.HasAES}, + {Name: "aescbc", Feature: &S390X.HasAESCBC}, + {Name: "aesctr", Feature: &S390X.HasAESCTR}, + {Name: "aesgcm", Feature: &S390X.HasAESGCM}, + {Name: "ghash", Feature: &S390X.HasGHASH}, + {Name: "sha1", Feature: &S390X.HasSHA1}, + {Name: "sha256", Feature: &S390X.HasSHA256}, + {Name: "sha3", Feature: &S390X.HasSHA3}, + {Name: "sha512", Feature: &S390X.HasSHA512}, + {Name: "vx", Feature: &S390X.HasVX}, + {Name: "vxe", Feature: &S390X.HasVXE}, + } +} + +// bitIsSet reports whether the bit at index is set. The bit index +// is in big endian order, so bit index 0 is the leftmost bit. +func bitIsSet(bits []uint64, index uint) bool { + return bits[index/64]&((1<<63)>>(index%64)) != 0 +} + +// facility is a bit index for the named facility. +type facility uint8 + +const ( + // mandatory facilities + zarch facility = 1 // z architecture mode is active + stflef facility = 7 // store-facility-list-extended + ldisp facility = 18 // long-displacement + eimm facility = 21 // extended-immediate + + // miscellaneous facilities + dfp facility = 42 // decimal-floating-point + etf3eh facility = 30 // extended-translation 3 enhancement + + // cryptography facilities + msa facility = 17 // message-security-assist + msa3 facility = 76 // message-security-assist extension 3 + msa4 facility = 77 // message-security-assist extension 4 + msa5 facility = 57 // message-security-assist extension 5 + msa8 facility = 146 // message-security-assist extension 8 + msa9 facility = 155 // message-security-assist extension 9 + + // vector facilities + vx facility = 129 // vector facility + vxe facility = 135 // vector-enhancements 1 + vxe2 facility = 148 // vector-enhancements 2 +) + +// facilityList contains the result of an STFLE call. +// Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type facilityList struct { + bits [4]uint64 +} + +// Has reports whether the given facilities are present. +func (s *facilityList) Has(fs ...facility) bool { + if len(fs) == 0 { + panic("no facility bits provided") + } + for _, f := range fs { + if !bitIsSet(s.bits[:], uint(f)) { + return false + } + } + return true +} + +// function is the code for the named cryptographic function. +type function uint8 + +const ( + // KM{,A,C,CTR} function codes + aes128 function = 18 // AES-128 + aes192 function = 19 // AES-192 + aes256 function = 20 // AES-256 + + // K{I,L}MD function codes + sha1 function = 1 // SHA-1 + sha256 function = 2 // SHA-256 + sha512 function = 3 // SHA-512 + sha3_224 function = 32 // SHA3-224 + sha3_256 function = 33 // SHA3-256 + sha3_384 function = 34 // SHA3-384 + sha3_512 function = 35 // SHA3-512 + shake128 function = 36 // SHAKE-128 + shake256 function = 37 // SHAKE-256 + + // KLMD function codes + ghash function = 65 // GHASH +) + +// queryResult contains the result of a Query function +// call. Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type queryResult struct { + bits [2]uint64 +} + +// Has reports whether the given functions are present. +func (q *queryResult) Has(fns ...function) bool { + if len(fns) == 0 { + panic("no function codes provided") + } + for _, f := range fns { + if !bitIsSet(q.bits[:], uint(f)) { + return false + } + } + return true +} + +func doinit() { + initS390Xbase() + + // We need implementations of stfle, km and so on + // to detect cryptographic features. + if !haveAsmFunctions() { + return + } + + // optional cryptographic functions + if S390X.HasMSA { + aes := []function{aes128, aes192, aes256} + + // cipher message + km, kmc := kmQuery(), kmcQuery() + S390X.HasAES = km.Has(aes...) + S390X.HasAESCBC = kmc.Has(aes...) + if S390X.HasSTFLE { + facilities := stfle() + if facilities.Has(msa4) { + kmctr := kmctrQuery() + S390X.HasAESCTR = kmctr.Has(aes...) + } + if facilities.Has(msa8) { + kma := kmaQuery() + S390X.HasAESGCM = kma.Has(aes...) + } + } + + // compute message digest + kimd := kimdQuery() // intermediate (no padding) + klmd := klmdQuery() // last (padding) + S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) + S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) + S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) + S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist + sha3 := []function{ + sha3_224, sha3_256, sha3_384, sha3_512, + shake128, shake256, + } + S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/vendor/golang.org/x/sys/cpu/cpu_s390x.s new file mode 100644 index 00000000..1fb4b701 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.s @@ -0,0 +1,57 @@ +// Copyright 2019 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 gc + +#include "textflag.h" + +// func stfle() facilityList +TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 + MOVD $ret+0(FP), R1 + MOVD $3, R0 // last doubleword index to store + XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) + WORD $0xb2b01000 // store facility list extended (STFLE) + RET + +// func kmQuery() queryResult +TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KM-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92E0024 // cipher message (KM) + RET + +// func kmcQuery() queryResult +TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMC-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92F0024 // cipher message with chaining (KMC) + RET + +// func kmctrQuery() queryResult +TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMCTR-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92D4024 // cipher message with counter (KMCTR) + RET + +// func kmaQuery() queryResult +TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMA-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xb9296024 // cipher message with authentication (KMA) + RET + +// func kimdQuery() queryResult +TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KIMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93E0024 // compute intermediate message digest (KIMD) + RET + +// func klmdQuery() queryResult +TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KLMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93F0024 // compute last message digest (KLMD) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_wasm.go b/vendor/golang.org/x/sys/cpu/cpu_wasm.go new file mode 100644 index 00000000..384787ea --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_wasm.go @@ -0,0 +1,17 @@ +// Copyright 2019 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 wasm + +package cpu + +// We're compiling the cpu package for an unknown (software-abstracted) CPU. +// Make CacheLinePad an empty struct and hope that the usual struct alignment +// rules are good enough. + +const cacheLineSize = 0 + +func initOptions() {} + +func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go new file mode 100644 index 00000000..1e642f33 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -0,0 +1,162 @@ +// Copyright 2018 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 386 || amd64 || amd64p32 + +package cpu + +import "runtime" + +const cacheLineSize = 64 + +func initOptions() { + options = []option{ + {Name: "adx", Feature: &X86.HasADX}, + {Name: "aes", Feature: &X86.HasAES}, + {Name: "avx", Feature: &X86.HasAVX}, + {Name: "avx2", Feature: &X86.HasAVX2}, + {Name: "avx512", Feature: &X86.HasAVX512}, + {Name: "avx512f", Feature: &X86.HasAVX512F}, + {Name: "avx512cd", Feature: &X86.HasAVX512CD}, + {Name: "avx512er", Feature: &X86.HasAVX512ER}, + {Name: "avx512pf", Feature: &X86.HasAVX512PF}, + {Name: "avx512vl", Feature: &X86.HasAVX512VL}, + {Name: "avx512bw", Feature: &X86.HasAVX512BW}, + {Name: "avx512dq", Feature: &X86.HasAVX512DQ}, + {Name: "avx512ifma", Feature: &X86.HasAVX512IFMA}, + {Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI}, + {Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW}, + {Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS}, + {Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ}, + {Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ}, + {Name: "avx512vnni", Feature: &X86.HasAVX512VNNI}, + {Name: "avx512gfni", Feature: &X86.HasAVX512GFNI}, + {Name: "avx512vaes", Feature: &X86.HasAVX512VAES}, + {Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2}, + {Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG}, + {Name: "avx512bf16", Feature: &X86.HasAVX512BF16}, + {Name: "amxtile", Feature: &X86.HasAMXTile}, + {Name: "amxint8", Feature: &X86.HasAMXInt8}, + {Name: "amxbf16", Feature: &X86.HasAMXBF16}, + {Name: "bmi1", Feature: &X86.HasBMI1}, + {Name: "bmi2", Feature: &X86.HasBMI2}, + {Name: "cx16", Feature: &X86.HasCX16}, + {Name: "erms", Feature: &X86.HasERMS}, + {Name: "fma", Feature: &X86.HasFMA}, + {Name: "osxsave", Feature: &X86.HasOSXSAVE}, + {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, + {Name: "popcnt", Feature: &X86.HasPOPCNT}, + {Name: "rdrand", Feature: &X86.HasRDRAND}, + {Name: "rdseed", Feature: &X86.HasRDSEED}, + {Name: "sse3", Feature: &X86.HasSSE3}, + {Name: "sse41", Feature: &X86.HasSSE41}, + {Name: "sse42", Feature: &X86.HasSSE42}, + {Name: "ssse3", Feature: &X86.HasSSSE3}, + {Name: "avxifma", Feature: &X86.HasAVXIFMA}, + {Name: "avxvnni", Feature: &X86.HasAVXVNNI}, + {Name: "avxvnniint8", Feature: &X86.HasAVXVNNIInt8}, + + // These capabilities should always be enabled on amd64: + {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, + } +} + +func archInit() { + + Initialized = true + + maxID, _, _, _ := cpuid(0, 0) + + if maxID < 1 { + return + } + + _, _, ecx1, edx1 := cpuid(1, 0) + X86.HasSSE2 = isSet(26, edx1) + + X86.HasSSE3 = isSet(0, ecx1) + X86.HasPCLMULQDQ = isSet(1, ecx1) + X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) + X86.HasCX16 = isSet(13, ecx1) + X86.HasSSE41 = isSet(19, ecx1) + X86.HasSSE42 = isSet(20, ecx1) + X86.HasPOPCNT = isSet(23, ecx1) + X86.HasAES = isSet(25, ecx1) + X86.HasOSXSAVE = isSet(27, ecx1) + X86.HasRDRAND = isSet(30, ecx1) + + var osSupportsAVX, osSupportsAVX512 bool + // For XGETBV, OSXSAVE bit is required and sufficient. + if X86.HasOSXSAVE { + eax, _ := xgetbv() + // Check if XMM and YMM registers have OS support. + osSupportsAVX = isSet(1, eax) && isSet(2, eax) + + if runtime.GOOS == "darwin" { + // Darwin requires special AVX512 checks, see cpu_darwin_x86.go + osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512() + } else { + // Check if OPMASK and ZMM registers have OS support. + osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) + } + } + + X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + + if maxID < 7 { + return + } + + eax7, ebx7, ecx7, edx7 := cpuid(7, 0) + X86.HasBMI1 = isSet(3, ebx7) + X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX + X86.HasBMI2 = isSet(8, ebx7) + X86.HasERMS = isSet(9, ebx7) + X86.HasRDSEED = isSet(18, ebx7) + X86.HasADX = isSet(19, ebx7) + + X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension + if X86.HasAVX512 { + X86.HasAVX512F = true + X86.HasAVX512CD = isSet(28, ebx7) + X86.HasAVX512ER = isSet(27, ebx7) + X86.HasAVX512PF = isSet(26, ebx7) + X86.HasAVX512VL = isSet(31, ebx7) + X86.HasAVX512BW = isSet(30, ebx7) + X86.HasAVX512DQ = isSet(17, ebx7) + X86.HasAVX512IFMA = isSet(21, ebx7) + X86.HasAVX512VBMI = isSet(1, ecx7) + X86.HasAVX5124VNNIW = isSet(2, edx7) + X86.HasAVX5124FMAPS = isSet(3, edx7) + X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) + X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) + X86.HasAVX512VNNI = isSet(11, ecx7) + X86.HasAVX512GFNI = isSet(8, ecx7) + X86.HasAVX512VAES = isSet(9, ecx7) + X86.HasAVX512VBMI2 = isSet(6, ecx7) + X86.HasAVX512BITALG = isSet(12, ecx7) + } + + X86.HasAMXTile = isSet(24, edx7) + X86.HasAMXInt8 = isSet(25, edx7) + X86.HasAMXBF16 = isSet(22, edx7) + + // These features depend on the second level of extended features. + if eax7 >= 1 { + eax71, _, _, edx71 := cpuid(7, 1) + if X86.HasAVX512 { + X86.HasAVX512BF16 = isSet(5, eax71) + } + if X86.HasAVX { + X86.HasAVXIFMA = isSet(23, eax71) + X86.HasAVXVNNI = isSet(4, eax71) + X86.HasAVXVNNIInt8 = isSet(4, edx71) + } + } +} + +func isSet(bitpos uint, value uint32) bool { + return value&(1<> 63)) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var hwCap uint +var hwCap2 uint + +func readHWCAP() error { + // For Go 1.21+, get auxv from the Go runtime. + if a := getAuxv(); len(a) > 0 { + for len(a) >= 2 { + tag, val := a[0], uint(a[1]) + a = a[2:] + switch tag { + case _AT_HWCAP: + hwCap = val + case _AT_HWCAP2: + hwCap2 = val + } + } + return nil + } + + buf, err := os.ReadFile(procAuxv) + if err != nil { + // e.g. on android /proc/self/auxv is not accessible, so silently + // ignore the error and leave Initialized = false. On some + // architectures (e.g. arm64) doinit() implements a fallback + // readout and will set Initialized = true again. + return err + } + bo := hostByteOrder() + for len(buf) >= 2*(uintSize/8) { + var tag, val uint + switch uintSize { + case 32: + tag = uint(bo.Uint32(buf[0:])) + val = uint(bo.Uint32(buf[4:])) + buf = buf[8:] + case 64: + tag = uint(bo.Uint64(buf[0:])) + val = uint(bo.Uint64(buf[8:])) + buf = buf[16:] + } + switch tag { + case _AT_HWCAP: + hwCap = val + case _AT_HWCAP2: + hwCap2 = val + } + } + return nil +} diff --git a/vendor/golang.org/x/sys/cpu/parse.go b/vendor/golang.org/x/sys/cpu/parse.go new file mode 100644 index 00000000..56a7e1a1 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/parse.go @@ -0,0 +1,43 @@ +// 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 cpu + +import "strconv" + +// parseRelease parses a dot-separated version number. It follows the semver +// syntax, but allows the minor and patch versions to be elided. +// +// This is a copy of the Go runtime's parseRelease from +// https://golang.org/cl/209597. +func parseRelease(rel string) (major, minor, patch int, ok bool) { + // Strip anything after a dash or plus. + for i := range len(rel) { + if rel[i] == '-' || rel[i] == '+' { + rel = rel[:i] + break + } + } + + next := func() (int, bool) { + for i := range len(rel) { + if rel[i] == '.' { + ver, err := strconv.Atoi(rel[:i]) + rel = rel[i+1:] + return ver, err == nil + } + } + ver, err := strconv.Atoi(rel) + rel = "" + return ver, err == nil + } + if major, ok = next(); !ok || rel == "" { + return + } + if minor, ok = next(); !ok || rel == "" { + return + } + patch, ok = next() + return +} diff --git a/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go b/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go new file mode 100644 index 00000000..4cd64c70 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go @@ -0,0 +1,53 @@ +// 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. + +//go:build linux && arm64 + +package cpu + +import ( + "errors" + "io" + "os" + "strings" +) + +func readLinuxProcCPUInfo() error { + f, err := os.Open("/proc/cpuinfo") + if err != nil { + return err + } + defer f.Close() + + var buf [1 << 10]byte // enough for first CPU + n, err := io.ReadFull(f, buf[:]) + if err != nil && err != io.ErrUnexpectedEOF { + return err + } + in := string(buf[:n]) + const features = "\nFeatures : " + i := strings.Index(in, features) + if i == -1 { + return errors.New("no CPU features found") + } + in = in[i+len(features):] + if i := strings.Index(in, "\n"); i != -1 { + in = in[:i] + } + m := map[string]*bool{} + + initOptions() // need it early here; it's harmless to call twice + for _, o := range options { + m[o.Name] = o.Feature + } + // The EVTSTRM field has alias "evstrm" in Go, but Linux calls it "evtstrm". + m["evtstrm"] = &ARM64.HasEVTSTRM + + for _, f := range strings.Fields(in) { + if p, ok := m[f]; ok { + *p = true + } + } + return nil +} diff --git a/vendor/golang.org/x/sys/cpu/runtime_auxv.go b/vendor/golang.org/x/sys/cpu/runtime_auxv.go new file mode 100644 index 00000000..5f92ac9a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/runtime_auxv.go @@ -0,0 +1,16 @@ +// Copyright 2023 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 cpu + +// getAuxvFn is non-nil on Go 1.21+ (via runtime_auxv_go121.go init) +// on platforms that use auxv. +var getAuxvFn func() []uintptr + +func getAuxv() []uintptr { + if getAuxvFn == nil { + return nil + } + return getAuxvFn() +} diff --git a/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go b/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go new file mode 100644 index 00000000..4c9788ea --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go @@ -0,0 +1,18 @@ +// Copyright 2023 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 go1.21 + +package cpu + +import ( + _ "unsafe" // for linkname +) + +//go:linkname runtime_getAuxv runtime.getAuxv +func runtime_getAuxv() []uintptr + +func init() { + getAuxvFn = runtime_getAuxv +} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go b/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go new file mode 100644 index 00000000..1b9ccb09 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go @@ -0,0 +1,26 @@ +// Copyright 2020 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. + +// Recreate a getsystemcfg syscall handler instead of +// using the one provided by x/sys/unix to avoid having +// the dependency between them. (See golang.org/issue/32102) +// Moreover, this file will be used during the building of +// gccgo's libgo and thus must not used a CGo method. + +//go:build aix && gccgo + +package cpu + +import ( + "syscall" +) + +//extern getsystemcfg +func gccgoGetsystemcfg(label uint32) (r uint64) + +func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) { + r1 = uintptr(gccgoGetsystemcfg(uint32(label))) + e1 = syscall.GetErrno() + return +} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go new file mode 100644 index 00000000..e8b6cdbe --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go @@ -0,0 +1,35 @@ +// Copyright 2019 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. + +// Minimal copy of x/sys/unix so the cpu package can make a +// system call on AIX without depending on x/sys/unix. +// (See golang.org/issue/32102) + +//go:build aix && ppc64 && gc + +package cpu + +import ( + "syscall" + "unsafe" +) + +//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o" + +//go:linkname libc_getsystemcfg libc_getsystemcfg + +type syscallFunc uintptr + +var libc_getsystemcfg syscallFunc + +type errno = syscall.Errno + +// Implemented in runtime/syscall_aix.go. +func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) +func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) + +func callgetsystemcfg(label int) (r1 uintptr, e1 errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0) + return +} diff --git a/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go b/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go new file mode 100644 index 00000000..4d0888b0 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go @@ -0,0 +1,98 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Minimal copy of x/sys/unix so the cpu package can make a +// system call on Darwin without depending on x/sys/unix. + +//go:build darwin && amd64 && gc + +package cpu + +import ( + "syscall" + "unsafe" +) + +type _C_int int32 + +// adapted from unix.Uname() at x/sys/unix/syscall_darwin.go L419 +func darwinOSRelease(release *[256]byte) error { + // from x/sys/unix/zerrors_openbsd_amd64.go + const ( + CTL_KERN = 0x1 + KERN_OSRELEASE = 0x2 + ) + + mib := []_C_int{CTL_KERN, KERN_OSRELEASE} + n := unsafe.Sizeof(*release) + + return sysctl(mib, &release[0], &n, nil, 0) +} + +type Errno = syscall.Errno + +var _zero uintptr // Single-word zero for use when we need a valid pointer to 0 bytes. + +// from x/sys/unix/zsyscall_darwin_amd64.go L791-807 +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + if _, _, err := syscall_syscall6( + libc_sysctl_trampoline_addr, + uintptr(_p0), + uintptr(len(mib)), + uintptr(unsafe.Pointer(old)), + uintptr(unsafe.Pointer(oldlen)), + uintptr(unsafe.Pointer(new)), + uintptr(newlen), + ); err != 0 { + return err + } + + return nil +} + +var libc_sysctl_trampoline_addr uintptr + +// adapted from internal/cpu/cpu_arm64_darwin.go +func darwinSysctlEnabled(name []byte) bool { + out := int32(0) + nout := unsafe.Sizeof(out) + if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil { + return false + } + return out > 0 +} + +//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" + +var libc_sysctlbyname_trampoline_addr uintptr + +// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix +func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + if _, _, err := syscall_syscall6( + libc_sysctlbyname_trampoline_addr, + uintptr(unsafe.Pointer(name)), + uintptr(unsafe.Pointer(old)), + uintptr(unsafe.Pointer(oldlen)), + uintptr(unsafe.Pointer(new)), + uintptr(newlen), + 0, + ); err != 0 { + return err + } + + return nil +} + +//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib" + +// Implemented in the runtime package (runtime/sys_darwin.go) +func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) + +//go:linkname syscall_syscall6 syscall.syscall6 diff --git a/vendor/modules.txt b/vendor/modules.txt index 721faaaf..f256bd48 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,3 +1,34 @@ +# github.com/cloudflare/circl v1.6.1 +## explicit; go 1.22.0 +github.com/cloudflare/circl/ecc/goldilocks +github.com/cloudflare/circl/internal/conv +github.com/cloudflare/circl/internal/sha3 +github.com/cloudflare/circl/math +github.com/cloudflare/circl/math/fp25519 +github.com/cloudflare/circl/math/fp448 +github.com/cloudflare/circl/math/mlsbset +github.com/cloudflare/circl/pki +github.com/cloudflare/circl/sign +github.com/cloudflare/circl/sign/dilithium/mode2 +github.com/cloudflare/circl/sign/dilithium/mode2/internal +github.com/cloudflare/circl/sign/dilithium/mode3 +github.com/cloudflare/circl/sign/dilithium/mode3/internal +github.com/cloudflare/circl/sign/dilithium/mode5 +github.com/cloudflare/circl/sign/dilithium/mode5/internal +github.com/cloudflare/circl/sign/ed25519 +github.com/cloudflare/circl/sign/ed448 +github.com/cloudflare/circl/sign/eddilithium2 +github.com/cloudflare/circl/sign/eddilithium3 +github.com/cloudflare/circl/sign/internal/dilithium +github.com/cloudflare/circl/sign/internal/dilithium/params +github.com/cloudflare/circl/sign/mldsa/mldsa44 +github.com/cloudflare/circl/sign/mldsa/mldsa44/internal +github.com/cloudflare/circl/sign/mldsa/mldsa65 +github.com/cloudflare/circl/sign/mldsa/mldsa65/internal +github.com/cloudflare/circl/sign/mldsa/mldsa87 +github.com/cloudflare/circl/sign/mldsa/mldsa87/internal +github.com/cloudflare/circl/sign/schemes +github.com/cloudflare/circl/simd/keccakf1600 # github.com/go-jose/go-jose/v4 v4.1.2 ## explicit; go 1.23.0 github.com/go-jose/go-jose/v4 @@ -11,6 +42,8 @@ github.com/letsencrypt/challtestsrv github.com/miekg/dns # golang.org/x/crypto v0.39.0 ## explicit; go 1.23.0 +golang.org/x/crypto/cryptobyte +golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/pbkdf2 # golang.org/x/mod v0.24.0 ## explicit; go 1.23.0 @@ -27,6 +60,7 @@ golang.org/x/net/ipv6 golang.org/x/sync/errgroup # golang.org/x/sys v0.33.0 ## explicit; go 1.23.0 +golang.org/x/sys/cpu golang.org/x/sys/unix golang.org/x/sys/windows # golang.org/x/tools v0.33.0 From 494da50abe1c30ff960668a14e571e65c859a624 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Thu, 2 Oct 2025 12:15:32 -0700 Subject: [PATCH 4/5] Allow generating ML-DSA roots and intermediates --- ca/ca.go | 38 +++++++++++++++++++++----------------- ca/ca_test.go | 5 +++-- cmd/pebble/main.go | 2 +- core/types.go | 3 ++- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/ca/ca.go b/ca/ca.go index e4489e1a..577374eb 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -7,8 +7,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" - "crypto/sha1" - "crypto/x509" + "crypto/sha256" "crypto/x509/pkix" "encoding/asn1" "encoding/hex" @@ -21,7 +20,10 @@ import ( "strings" "time" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/letsencrypt/pebble/v2/acme" + "github.com/letsencrypt/pebble/v2/ca/x509pq" "github.com/letsencrypt/pebble/v2/core" "github.com/letsencrypt/pebble/v2/db" ) @@ -79,7 +81,7 @@ func makeSerial() *big.Int { // Taken from https://github.com/cloudflare/cfssl/blob/b94e044bb51ec8f5a7232c71b1ed05dbe4da96ce/signer/signer.go#L221-L244 func makeSubjectKeyID(key crypto.PublicKey) ([]byte, error) { // Marshal the public key as ASN.1 - pubAsDER, err := x509.MarshalPKIXPublicKey(key) + pubAsDER, err := x509pq.MarshalPKIXPublicKey(key) if err != nil { return nil, err } @@ -94,9 +96,9 @@ func makeSubjectKeyID(key crypto.PublicKey) ([]byte, error) { return nil, err } - // Hash it according to https://tools.ietf.org/html/rfc5280#section-4.2.1.2 Method #1: - ski := sha1.Sum(pubInfo.SubjectPublicKey.Bytes) - return ski[:], nil + // Hash it according to https://datatracker.ietf.org/doc/html/rfc7093#section-2 Method #1: + skid := sha256.Sum256(pubInfo.SubjectPublicKey.Bytes) + return skid[0:20:20], nil } // makeKey and makeRootCert are adapted from MiniCA: @@ -112,6 +114,8 @@ func makeKey(keyAlg string) (crypto.Signer, []byte, error) { key, err = rsa.GenerateKey(rand.Reader, 2048) case "ecdsa": key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + case "mldsa": + _, key, err = mldsa65.GenerateKey(rand.Reader) } if err != nil { return nil, nil, err @@ -130,21 +134,21 @@ func (ca *CAImpl) makeCACert( signer *issuer, ) (*core.Certificate, error) { serial := makeSerial() - template := &x509.Certificate{ + template := &x509pq.Certificate{ Subject: subject, SerialNumber: serial, NotBefore: time.Now(), NotAfter: time.Now().AddDate(30, 0, 0), - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + KeyUsage: x509pq.KeyUsageDigitalSignature | x509pq.KeyUsageCertSign, + ExtKeyUsage: []x509pq.ExtKeyUsage{x509pq.ExtKeyUsageServerAuth}, SubjectKeyId: subjectKeyID, BasicConstraintsValid: true, IsCA: true, } var signerKey crypto.Signer - var parent *x509.Certificate + var parent *x509pq.Certificate if signer != nil && signer.key != nil && signer.cert != nil && signer.cert.Cert != nil { signerKey = signer.key parent = signer.cert.Cert @@ -153,12 +157,12 @@ func (ca *CAImpl) makeCACert( parent = template } - der, err := x509.CreateCertificate(rand.Reader, template, parent, subjectKey.Public(), signerKey) + der, err := x509pq.CreateCertificate(rand.Reader, template, parent, subjectKey.Public(), signerKey) if err != nil { return nil, err } - cert, err := x509.ParseCertificate(der) + cert, err := x509pq.ParseCertificate(der) if err != nil { return nil, err } @@ -306,15 +310,15 @@ func (ca *CAImpl) newCertificate(domains []string, ips []net.IP, key crypto.Publ } serial := makeSerial() - template := &x509.Certificate{ + template := &x509pq.Certificate{ DNSNames: domains, IPAddresses: ips, SerialNumber: serial, NotBefore: certNotBefore, NotAfter: certNotAfter, - KeyUsage: x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + KeyUsage: x509pq.KeyUsageDigitalSignature, + ExtKeyUsage: []x509pq.ExtKeyUsage{x509pq.ExtKeyUsageServerAuth}, ExtraExtensions: extensions, BasicConstraintsValid: true, IsCA: false, @@ -340,11 +344,11 @@ func (ca *CAImpl) newCertificate(domains []string, ips []net.IP, key crypto.Publ template.OCSPServer = []string{ca.ocspResponderURL} } - der, err := x509.CreateCertificate(rand.Reader, template, issuer.cert.Cert, key, issuer.key) + der, err := x509pq.CreateCertificate(rand.Reader, template, issuer.cert.Cert, key, issuer.key) if err != nil { return nil, err } - cert, err := x509.ParseCertificate(der) + cert, err := x509pq.ParseCertificate(der) if err != nil { return nil, err } diff --git a/ca/ca_test.go b/ca/ca_test.go index 970bf85b..121aee5c 100644 --- a/ca/ca_test.go +++ b/ca/ca_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/letsencrypt/pebble/v2/acme" + x509pq "github.com/letsencrypt/pebble/v2/ca/x509pq" "github.com/letsencrypt/pebble/v2/core" "github.com/letsencrypt/pebble/v2/db" ) @@ -27,7 +28,7 @@ var ( func makeCa() *CAImpl { logger := log.New(os.Stdout, "Pebble ", log.LstdFlags) db := db.NewMemoryStore() - return New(logger, db, "", "ecdsa", 0, 1, map[string]Profile{"default": {}}) + return New(logger, db, "", "mldsa", 0, 1, map[string]Profile{"default": {}}) } func makeCertOrderWithExtensions(extensions []pkix.Extension) core.Order { @@ -58,7 +59,7 @@ func makeCertOrderWithExtensions(extensions []pkix.Extension) core.Order { } } -func getOCSPMustStapleExtension(cert *x509.Certificate) *pkix.Extension { +func getOCSPMustStapleExtension(cert *x509pq.Certificate) *pkix.Extension { for _, ext := range cert.Extensions { if ext.Id.Equal(ocspID) && bytes.Equal(ext.Value, ocspValue) { return &ext diff --git a/cmd/pebble/main.go b/cmd/pebble/main.go index 5c86247c..ada6ae06 100644 --- a/cmd/pebble/main.go +++ b/cmd/pebble/main.go @@ -109,7 +109,7 @@ func main() { if keyAlg == "" { keyAlg = "rsa" } - acceptableKeyAlgs := []string{"rsa", "ecdsa"} + acceptableKeyAlgs := []string{"rsa", "ecdsa", "mldsa"} if !slices.Contains(acceptableKeyAlgs, keyAlg) { cmd.FailOnError(fmt.Errorf("%q is not one of %#v", keyAlg, acceptableKeyAlgs), "invalid key algorithm") } diff --git a/core/types.go b/core/types.go index a6a5b4a0..a46fdab0 100644 --- a/core/types.go +++ b/core/types.go @@ -16,6 +16,7 @@ import ( "github.com/go-jose/go-jose/v4" "github.com/letsencrypt/pebble/v2/acme" + x509pq "github.com/letsencrypt/pebble/v2/ca/x509pq" ) type Order struct { @@ -145,7 +146,7 @@ func (ch *Challenge) ExpectedKeyAuthorization(key *jose.JSONWebKey) string { type Certificate struct { ID string - Cert *x509.Certificate + Cert *x509pq.Certificate DER []byte IssuerChains [][]*Certificate AccountID string From 1b269a31a2ca0e5dce49bdbeb59f27bfdb208579 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Tue, 7 Oct 2025 14:09:27 -0700 Subject: [PATCH 5/5] Don't lint forked files --- .golangci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.golangci.yaml b/.golangci.yaml index ca8c9718..72b6c0cb 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -81,3 +81,5 @@ issues: linters: - goconst text: 'string `Incorrect validation certificate for %s challenge. ` has \d occurrences, make it a constant' + exclude-dirs: + - ca/x509pq