Integrate BACKBEAT SDK and resolve KACHING license validation

Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

View File

@@ -0,0 +1,17 @@
ISC License
Copyright (c) 2013-2017 The btcsuite developers
Copyright (c) 2015-2020 The Decred developers
Copyright (c) 2017 The Lightning Network Developers
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,72 @@
secp256k1
=========
[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4)
Package secp256k1 implements optimized secp256k1 elliptic curve operations.
This package provides an optimized pure Go implementation of elliptic curve
cryptography operations over the secp256k1 curve as well as data structures and
functions for working with public and private secp256k1 keys. See
https://www.secg.org/sec2-v2.pdf for details on the standard.
In addition, sub packages are provided to produce, verify, parse, and serialize
ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme
specific to Decred) signatures. See the README.md files in the relevant sub
packages for more details about those aspects.
An overview of the features provided by this package are as follows:
- Private key generation, serialization, and parsing
- Public key generation, serialization and parsing per ANSI X9.62-1998
- Parses uncompressed, compressed, and hybrid public keys
- Serializes uncompressed and compressed public keys
- Specialized types for performing optimized and constant time field operations
- `FieldVal` type for working modulo the secp256k1 field prime
- `ModNScalar` type for working modulo the secp256k1 group order
- Elliptic curve operations in Jacobian projective coordinates
- Point addition
- Point doubling
- Scalar multiplication with an arbitrary point
- Scalar multiplication with the base point (group generator)
- Point decompression from a given x coordinate
- Nonce generation via RFC6979 with support for extra data and version
information that can be used to prevent nonce reuse between signing algorithms
It also provides an implementation of the Go standard library `crypto/elliptic`
`Curve` interface via the `S256` function so that it may be used with other
packages in the standard library such as `crypto/tls`, `crypto/x509`, and
`crypto/ecdsa`. However, in the case of ECDSA, it is highly recommended to use
the `ecdsa` sub package of this package instead since it is optimized
specifically for secp256k1 and is significantly faster as a result.
Although this package was primarily written for dcrd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use optimized secp256k1 elliptic curve cryptography.
Finally, a comprehensive suite of tests is provided to provide a high level of
quality assurance.
## secp256k1 use in Decred
At the time of this writing, the primary public key cryptography in widespread
use on the Decred network used to secure coins is based on elliptic curves
defined by the secp256k1 domain parameters.
## Installation and Updating
This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module.
Use the standard go tooling for working with modules to incorporate it.
## Examples
* [Encryption](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#example-package-EncryptDecryptMessage)
Demonstrates encrypting and decrypting a message using a shared key derived
through ECDHE.
## License
Package secp256k1 is licensed under the [copyfree](http://copyfree.org) ISC
License.

File diff suppressed because one or more lines are too long

1272
vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package secp256k1 implements optimized secp256k1 elliptic curve operations in
pure Go.
This package provides an optimized pure Go implementation of elliptic curve
cryptography operations over the secp256k1 curve as well as data structures and
functions for working with public and private secp256k1 keys. See
https://www.secg.org/sec2-v2.pdf for details on the standard.
In addition, sub packages are provided to produce, verify, parse, and serialize
ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme
specific to Decred) signatures. See the README.md files in the relevant sub
packages for more details about those aspects.
An overview of the features provided by this package are as follows:
- Private key generation, serialization, and parsing
- Public key generation, serialization and parsing per ANSI X9.62-1998
- Parses uncompressed, compressed, and hybrid public keys
- Serializes uncompressed and compressed public keys
- Specialized types for performing optimized and constant time field operations
- FieldVal type for working modulo the secp256k1 field prime
- ModNScalar type for working modulo the secp256k1 group order
- Elliptic curve operations in Jacobian projective coordinates
- Point addition
- Point doubling
- Scalar multiplication with an arbitrary point
- Scalar multiplication with the base point (group generator)
- Point decompression from a given x coordinate
- Nonce generation via RFC6979 with support for extra data and version
information that can be used to prevent nonce reuse between signing
algorithms
It also provides an implementation of the Go standard library crypto/elliptic
Curve interface via the S256 function so that it may be used with other packages
in the standard library such as crypto/tls, crypto/x509, and crypto/ecdsa.
However, in the case of ECDSA, it is highly recommended to use the ecdsa sub
package of this package instead since it is optimized specifically for secp256k1
and is significantly faster as a result.
Although this package was primarily written for dcrd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use optimized secp256k1 elliptic curve cryptography.
Finally, a comprehensive suite of tests is provided to provide a high level of
quality assurance.
# Use of secp256k1 in Decred
At the time of this writing, the primary public key cryptography in widespread
use on the Decred network used to secure coins is based on elliptic curves
defined by the secp256k1 domain parameters.
*/
package secp256k1

View File

@@ -0,0 +1,21 @@
// Copyright (c) 2015 The btcsuite developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// GenerateSharedSecret generates a shared secret based on a private key and a
// public key using Diffie-Hellman key exchange (ECDH) (RFC 5903).
// RFC5903 Section 9 states we should only return x.
//
// It is recommended to securely hash the result before using as a cryptographic
// key.
func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {
var point, result JacobianPoint
pubkey.AsJacobian(&point)
ScalarMultNonConst(&privkey.Key, &point, &result)
result.ToAffine()
xBytes := result.X.Bytes()
return xBytes[:]
}

View File

@@ -0,0 +1,52 @@
ecdsa
=====
[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa)
Package ecdsa provides secp256k1-optimized ECDSA signing and verification.
This package provides data structures and functions necessary to produce and
verify deterministic canonical signatures in accordance with RFC6979 and
BIP0062, optimized specifically for the secp256k1 curve using the Elliptic Curve
Digital Signature Algorithm (ECDSA), as defined in FIPS 186-3. See
https://www.secg.org/sec2-v2.pdf for details on the secp256k1 standard.
It also provides functions to parse and serialize the ECDSA signatures with the
more strict Distinguished Encoding Rules (DER) of ISO/IEC 8825-1 and some
additional restrictions specific to secp256k1.
In addition, it supports a custom "compact" signature format which allows
efficient recovery of the public key from a given valid signature and message
hash combination.
A comprehensive suite of tests is provided to ensure proper functionality.
## ECDSA use in Decred
At the time of this writing, ECDSA signatures are heavily used for proving coin
ownership in Decred as the vast majority of transactions consist of what is
effectively transferring ownership of coins to a public key associated with a
private key only known to the recipient of the coins along with an encumbrance
that requires an ECDSA signature that proves the new owner possesses the private
key without actually revealing it.
## Installation and Updating
This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module.
Use the standard go tooling for working with modules to incorporate it.
## Examples
* [Sign Message](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa#example-package-SignMessage)
Demonstrates signing a message with a secp256k1 private key that is first
parsed from raw bytes and serializing the generated signature.
* [Verify Signature](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa#example-Signature.Verify)
Demonstrates verifying a secp256k1 signature against a public key that is
first parsed from raw bytes. The signature is also parsed from raw bytes.
## License
Package ecdsa is licensed under the [copyfree](http://copyfree.org) ISC License.

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package ecdsa provides secp256k1-optimized ECDSA signing and verification.
This package provides data structures and functions necessary to produce and
verify deterministic canonical signatures in accordance with RFC6979 and
BIP0062, optimized specifically for the secp256k1 curve using the Elliptic Curve
Digital Signature Algorithm (ECDSA), as defined in FIPS 186-3. See
https://www.secg.org/sec2-v2.pdf for details on the secp256k1 standard.
It also provides functions to parse and serialize the ECDSA signatures with the
more strict Distinguished Encoding Rules (DER) of ISO/IEC 8825-1 and some
additional restrictions specific to secp256k1.
In addition, it supports a custom "compact" signature format which allows
efficient recovery of the public key from a given valid signature and message
hash combination.
A comprehensive suite of tests is provided to ensure proper functionality.
# ECDSA use in Decred
At the time of this writing, ECDSA signatures are heavily used for proving coin
ownership in Decred as the vast majority of transactions consist of what is
effectively transferring ownership of coins to a public key associated with a
private key only known to the recipient of the coins along with an encumbrance
that requires an ECDSA signature that proves the new owner possesses the private
key without actually revealing it.
# Errors
Errors returned by this package are of type ecdsa.Error and fully support the
standard library errors.Is and errors.As functions. This allows the caller to
programmatically determine the specific error by examining the ErrorKind field
of the type asserted ecdsa.Error while still providing rich error messages with
contextual information. See ErrorKind in the package documentation for a full
list.
*/
package ecdsa

View File

@@ -0,0 +1,134 @@
// Copyright (c) 2020-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ecdsa
// ErrorKind identifies a kind of error. It has full support for
// errors.Is and errors.As, so the caller can directly check against
// an error kind when determining the reason for an error.
type ErrorKind string
// These constants are used to identify a specific Error.
const (
// ErrSigTooShort is returned when a signature that should be a DER
// signature is too short.
ErrSigTooShort = ErrorKind("ErrSigTooShort")
// ErrSigTooLong is returned when a signature that should be a DER signature
// is too long.
ErrSigTooLong = ErrorKind("ErrSigTooLong")
// ErrSigInvalidSeqID is returned when a signature that should be a DER
// signature does not have the expected ASN.1 sequence ID.
ErrSigInvalidSeqID = ErrorKind("ErrSigInvalidSeqID")
// ErrSigInvalidDataLen is returned when a signature that should be a DER
// signature does not specify the correct number of remaining bytes for the
// R and S portions.
ErrSigInvalidDataLen = ErrorKind("ErrSigInvalidDataLen")
// ErrSigMissingSTypeID is returned when a signature that should be a DER
// signature does not provide the ASN.1 type ID for S.
ErrSigMissingSTypeID = ErrorKind("ErrSigMissingSTypeID")
// ErrSigMissingSLen is returned when a signature that should be a DER
// signature does not provide the length of S.
ErrSigMissingSLen = ErrorKind("ErrSigMissingSLen")
// ErrSigInvalidSLen is returned when a signature that should be a DER
// signature does not specify the correct number of bytes for the S portion.
ErrSigInvalidSLen = ErrorKind("ErrSigInvalidSLen")
// ErrSigInvalidRIntID is returned when a signature that should be a DER
// signature does not have the expected ASN.1 integer ID for R.
ErrSigInvalidRIntID = ErrorKind("ErrSigInvalidRIntID")
// ErrSigZeroRLen is returned when a signature that should be a DER
// signature has an R length of zero.
ErrSigZeroRLen = ErrorKind("ErrSigZeroRLen")
// ErrSigNegativeR is returned when a signature that should be a DER
// signature has a negative value for R.
ErrSigNegativeR = ErrorKind("ErrSigNegativeR")
// ErrSigTooMuchRPadding is returned when a signature that should be a DER
// signature has too much padding for R.
ErrSigTooMuchRPadding = ErrorKind("ErrSigTooMuchRPadding")
// ErrSigRIsZero is returned when a signature has R set to the value zero.
ErrSigRIsZero = ErrorKind("ErrSigRIsZero")
// ErrSigRTooBig is returned when a signature has R with a value that is
// greater than or equal to the group order.
ErrSigRTooBig = ErrorKind("ErrSigRTooBig")
// ErrSigInvalidSIntID is returned when a signature that should be a DER
// signature does not have the expected ASN.1 integer ID for S.
ErrSigInvalidSIntID = ErrorKind("ErrSigInvalidSIntID")
// ErrSigZeroSLen is returned when a signature that should be a DER
// signature has an S length of zero.
ErrSigZeroSLen = ErrorKind("ErrSigZeroSLen")
// ErrSigNegativeS is returned when a signature that should be a DER
// signature has a negative value for S.
ErrSigNegativeS = ErrorKind("ErrSigNegativeS")
// ErrSigTooMuchSPadding is returned when a signature that should be a DER
// signature has too much padding for S.
ErrSigTooMuchSPadding = ErrorKind("ErrSigTooMuchSPadding")
// ErrSigSIsZero is returned when a signature has S set to the value zero.
ErrSigSIsZero = ErrorKind("ErrSigSIsZero")
// ErrSigSTooBig is returned when a signature has S with a value that is
// greater than or equal to the group order.
ErrSigSTooBig = ErrorKind("ErrSigSTooBig")
// ErrSigInvalidLen is returned when a signature that should be a compact
// signature is not the required length.
ErrSigInvalidLen = ErrorKind("ErrSigInvalidLen")
// ErrSigInvalidRecoveryCode is returned when a signature that should be a
// compact signature has an invalid value for the public key recovery code.
ErrSigInvalidRecoveryCode = ErrorKind("ErrSigInvalidRecoveryCode")
// ErrSigOverflowsPrime is returned when a signature that should be a
// compact signature has the overflow bit set but adding the order to it
// would overflow the underlying field prime.
ErrSigOverflowsPrime = ErrorKind("ErrSigOverflowsPrime")
// ErrPointNotOnCurve is returned when attempting to recover a public key
// from a compact signature results in a point that is not on the elliptic
// curve.
ErrPointNotOnCurve = ErrorKind("ErrPointNotOnCurve")
)
// Error satisfies the error interface and prints human-readable errors.
func (e ErrorKind) Error() string {
return string(e)
}
// Error identifies an error related to an ECDSA signature. It has full
// support for errors.Is and errors.As, so the caller can ascertain the
// specific reason for the error by checking the underlying error.
type Error struct {
Err error
Description string
}
// Error satisfies the error interface and prints human-readable errors.
func (e Error) Error() string {
return e.Description
}
// Unwrap returns the underlying wrapped error.
func (e Error) Unwrap() error {
return e.Err
}
// signatureError creates an Error given a set of arguments.
func signatureError(kind ErrorKind, desc string) Error {
return Error{Err: kind, Description: desc}
}

View File

@@ -0,0 +1,990 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ecdsa
import (
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// References:
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
//
// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules:
// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules
// (CER) and Distinguished Encoding Rules (DER)
//
// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0)
// https://www.secg.org/sec1-v2.pdf
var (
// zero32 is an array of 32 bytes used for the purposes of zeroing and is
// defined here to avoid extra allocations.
zero32 = [32]byte{}
// orderAsFieldVal is the order of the secp256k1 curve group stored as a
// field value. It is provided here to avoid the need to create it multiple
// times.
orderAsFieldVal = func() secp256k1.FieldVal {
var f secp256k1.FieldVal
f.SetByteSlice(secp256k1.Params().N.Bytes())
return f
}()
)
const (
// asn1SequenceID is the ASN.1 identifier for a sequence and is used when
// parsing and serializing signatures encoded with the Distinguished
// Encoding Rules (DER) format per section 10 of [ISO/IEC 8825-1].
asn1SequenceID = 0x30
// asn1IntegerID is the ASN.1 identifier for an integer and is used when
// parsing and serializing signatures encoded with the Distinguished
// Encoding Rules (DER) format per section 10 of [ISO/IEC 8825-1].
asn1IntegerID = 0x02
)
// Signature is a type representing an ECDSA signature.
type Signature struct {
r secp256k1.ModNScalar
s secp256k1.ModNScalar
}
// NewSignature instantiates a new signature given some r and s values.
func NewSignature(r, s *secp256k1.ModNScalar) *Signature {
return &Signature{*r, *s}
}
// Serialize returns the ECDSA signature in the Distinguished Encoding Rules
// (DER) format per section 10 of [ISO/IEC 8825-1] and such that the S component
// of the signature is less than or equal to the half order of the group.
//
// Note that the serialized bytes returned do not include the appended hash type
// used in Decred signature scripts.
func (sig *Signature) Serialize() []byte {
// The format of a DER encoded signature is as follows:
//
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
// - 0x30 is the ASN.1 identifier for a sequence.
// - Total length is 1 byte and specifies length of all remaining data.
// - 0x02 is the ASN.1 identifier that specifies an integer follows.
// - Length of R is 1 byte and specifies how many bytes R occupies.
// - R is the arbitrary length big-endian encoded number which
// represents the R value of the signature. DER encoding dictates
// that the value must be encoded using the minimum possible number
// of bytes. This implies the first byte can only be null if the
// highest bit of the next byte is set in order to prevent it from
// being interpreted as a negative number.
// - 0x02 is once again the ASN.1 integer identifier.
// - Length of S is 1 byte and specifies how many bytes S occupies.
// - S is the arbitrary length big-endian encoded number which
// represents the S value of the signature. The encoding rules are
// identical as those for R.
// Ensure the S component of the signature is less than or equal to the half
// order of the group because both S and its negation are valid signatures
// modulo the order, so this forces a consistent choice to reduce signature
// malleability.
sigS := new(secp256k1.ModNScalar).Set(&sig.s)
if sigS.IsOverHalfOrder() {
sigS.Negate()
}
// Serialize the R and S components of the signature into their fixed
// 32-byte big-endian encoding. Note that the extra leading zero byte is
// used to ensure it is canonical per DER and will be stripped if needed
// below.
var rBuf, sBuf [33]byte
sig.r.PutBytesUnchecked(rBuf[1:33])
sigS.PutBytesUnchecked(sBuf[1:33])
// Ensure the encoded bytes for the R and S components are canonical per DER
// by trimming all leading zero bytes so long as the next byte does not have
// the high bit set and it's not the final byte.
canonR, canonS := rBuf[:], sBuf[:]
for len(canonR) > 1 && canonR[0] == 0x00 && canonR[1]&0x80 == 0 {
canonR = canonR[1:]
}
for len(canonS) > 1 && canonS[0] == 0x00 && canonS[1]&0x80 == 0 {
canonS = canonS[1:]
}
// Total length of returned signature is 1 byte for each magic and length
// (6 total), plus lengths of R and S.
totalLen := 6 + len(canonR) + len(canonS)
b := make([]byte, 0, totalLen)
b = append(b, asn1SequenceID)
b = append(b, byte(totalLen-2))
b = append(b, asn1IntegerID)
b = append(b, byte(len(canonR)))
b = append(b, canonR...)
b = append(b, asn1IntegerID)
b = append(b, byte(len(canonS)))
b = append(b, canonS...)
return b
}
// zeroArray32 zeroes the provided 32-byte buffer.
func zeroArray32(b *[32]byte) {
copy(b[:], zero32[:])
}
// fieldToModNScalar converts a field value to scalar modulo the group order and
// returns the scalar along with either 1 if it was reduced (aka it overflowed)
// or 0 otherwise.
//
// Note that a bool is not used here because it is not possible in Go to convert
// from a bool to numeric value in constant time and many constant-time
// operations require a numeric value.
func fieldToModNScalar(v *secp256k1.FieldVal) (secp256k1.ModNScalar, uint32) {
var buf [32]byte
v.PutBytes(&buf)
var s secp256k1.ModNScalar
overflow := s.SetBytes(&buf)
zeroArray32(&buf)
return s, overflow
}
// modNScalarToField converts a scalar modulo the group order to a field value.
func modNScalarToField(v *secp256k1.ModNScalar) secp256k1.FieldVal {
var buf [32]byte
v.PutBytes(&buf)
var fv secp256k1.FieldVal
fv.SetBytes(&buf)
return fv
}
// Verify returns whether or not the signature is valid for the provided hash
// and secp256k1 public key.
func (sig *Signature) Verify(hash []byte, pubKey *secp256k1.PublicKey) bool {
// The algorithm for verifying an ECDSA signature is given as algorithm 4.30
// in [GECC].
//
// The following is a paraphrased version for reference:
//
// G = curve generator
// N = curve order
// Q = public key
// m = message
// R, S = signature
//
// 1. Fail if R and S are not in [1, N-1]
// 2. e = H(m)
// 3. w = S^-1 mod N
// 4. u1 = e * w mod N
// u2 = R * w mod N
// 5. X = u1G + u2Q
// 6. Fail if X is the point at infinity
// 7. x = X.x mod N (X.x is the x coordinate of X)
// 8. Verified if x == R
//
// However, since all group operations are done internally in Jacobian
// projective space, the algorithm is modified slightly here in order to
// avoid an expensive inversion back into affine coordinates at step 7.
// Credits to Greg Maxwell for originally suggesting this optimization.
//
// Ordinarily, step 7 involves converting the x coordinate to affine by
// calculating x = x / z^2 (mod P) and then calculating the remainder as
// x = x (mod N). Then step 8 compares it to R.
//
// Note that since R is the x coordinate mod N from a random point that was
// originally mod P, and the cofactor of the secp256k1 curve is 1, there are
// only two possible x coordinates that the original random point could have
// been to produce R: x, where x < N, and x+N, where x+N < P.
//
// This implies that the signature is valid if either:
// a) R == X.x / X.z^2 (mod P)
// => R * X.z^2 == X.x (mod P)
// --or--
// b) R + N < P && R + N == X.x / X.z^2 (mod P)
// => R + N < P && (R + N) * X.z^2 == X.x (mod P)
//
// Therefore the following modified algorithm is used:
//
// 1. Fail if R and S are not in [1, N-1]
// 2. e = H(m)
// 3. w = S^-1 mod N
// 4. u1 = e * w mod N
// u2 = R * w mod N
// 5. X = u1G + u2Q
// 6. Fail if X is the point at infinity
// 7. z = (X.z)^2 mod P (X.z is the z coordinate of X)
// 8. Verified if R * z == X.x (mod P)
// 9. Fail if R + N >= P
// 10. Verified if (R + N) * z == X.x (mod P)
// Step 1.
//
// Fail if R and S are not in [1, N-1].
if sig.r.IsZero() || sig.s.IsZero() {
return false
}
// Step 2.
//
// e = H(m)
var e secp256k1.ModNScalar
e.SetByteSlice(hash)
// Step 3.
//
// w = S^-1 mod N
w := new(secp256k1.ModNScalar).InverseValNonConst(&sig.s)
// Step 4.
//
// u1 = e * w mod N
// u2 = R * w mod N
u1 := new(secp256k1.ModNScalar).Mul2(&e, w)
u2 := new(secp256k1.ModNScalar).Mul2(&sig.r, w)
// Step 5.
//
// X = u1G + u2Q
var X, Q, u1G, u2Q secp256k1.JacobianPoint
pubKey.AsJacobian(&Q)
secp256k1.ScalarBaseMultNonConst(u1, &u1G)
secp256k1.ScalarMultNonConst(u2, &Q, &u2Q)
secp256k1.AddNonConst(&u1G, &u2Q, &X)
// Step 6.
//
// Fail if X is the point at infinity
if (X.X.IsZero() && X.Y.IsZero()) || X.Z.IsZero() {
return false
}
// Step 7.
//
// z = (X.z)^2 mod P (X.z is the z coordinate of X)
z := new(secp256k1.FieldVal).SquareVal(&X.Z)
// Step 8.
//
// Verified if R * z == X.x (mod P)
sigRModP := modNScalarToField(&sig.r)
result := new(secp256k1.FieldVal).Mul2(&sigRModP, z).Normalize()
if result.Equals(&X.X) {
return true
}
// Step 9.
//
// Fail if R + N >= P
if sigRModP.IsGtOrEqPrimeMinusOrder() {
return false
}
// Step 10.
//
// Verified if (R + N) * z == X.x (mod P)
sigRModP.Add(&orderAsFieldVal)
result.Mul2(&sigRModP, z).Normalize()
return result.Equals(&X.X)
}
// IsEqual compares this Signature instance to the one passed, returning true if
// both Signatures are equivalent. A signature is equivalent to another, if
// they both have the same scalar value for R and S.
func (sig *Signature) IsEqual(otherSig *Signature) bool {
return sig.r.Equals(&otherSig.r) && sig.s.Equals(&otherSig.s)
}
// ParseDERSignature parses a signature in the Distinguished Encoding Rules
// (DER) format per section 10 of [ISO/IEC 8825-1] and enforces the following
// additional restrictions specific to secp256k1:
//
// - The R and S values must be in the valid range for secp256k1 scalars:
// - Negative values are rejected
// - Zero is rejected
// - Values greater than or equal to the secp256k1 group order are rejected
func ParseDERSignature(sig []byte) (*Signature, error) {
// The format of a DER encoded signature for secp256k1 is as follows:
//
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
// - 0x30 is the ASN.1 identifier for a sequence
// - Total length is 1 byte and specifies length of all remaining data
// - 0x02 is the ASN.1 identifier that specifies an integer follows
// - Length of R is 1 byte and specifies how many bytes R occupies
// - R is the arbitrary length big-endian encoded number which
// represents the R value of the signature. DER encoding dictates
// that the value must be encoded using the minimum possible number
// of bytes. This implies the first byte can only be null if the
// highest bit of the next byte is set in order to prevent it from
// being interpreted as a negative number.
// - 0x02 is once again the ASN.1 integer identifier
// - Length of S is 1 byte and specifies how many bytes S occupies
// - S is the arbitrary length big-endian encoded number which
// represents the S value of the signature. The encoding rules are
// identical as those for R.
//
// NOTE: The DER specification supports specifying lengths that can occupy
// more than 1 byte, however, since this is specific to secp256k1
// signatures, all lengths will be a single byte.
const (
// minSigLen is the minimum length of a DER encoded signature and is
// when both R and S are 1 byte each.
//
// 0x30 + <1-byte> + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
minSigLen = 8
// maxSigLen is the maximum length of a DER encoded signature and is
// when both R and S are 33 bytes each. It is 33 bytes because a
// 256-bit integer requires 32 bytes and an additional leading null byte
// might be required if the high bit is set in the value.
//
// 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes>
maxSigLen = 72
// sequenceOffset is the byte offset within the signature of the
// expected ASN.1 sequence identifier.
sequenceOffset = 0
// dataLenOffset is the byte offset within the signature of the expected
// total length of all remaining data in the signature.
dataLenOffset = 1
// rTypeOffset is the byte offset within the signature of the ASN.1
// identifier for R and is expected to indicate an ASN.1 integer.
rTypeOffset = 2
// rLenOffset is the byte offset within the signature of the length of
// R.
rLenOffset = 3
// rOffset is the byte offset within the signature of R.
rOffset = 4
)
// The signature must adhere to the minimum and maximum allowed length.
sigLen := len(sig)
if sigLen < minSigLen {
str := fmt.Sprintf("malformed signature: too short: %d < %d", sigLen,
minSigLen)
return nil, signatureError(ErrSigTooShort, str)
}
if sigLen > maxSigLen {
str := fmt.Sprintf("malformed signature: too long: %d > %d", sigLen,
maxSigLen)
return nil, signatureError(ErrSigTooLong, str)
}
// The signature must start with the ASN.1 sequence identifier.
if sig[sequenceOffset] != asn1SequenceID {
str := fmt.Sprintf("malformed signature: format has wrong type: %#x",
sig[sequenceOffset])
return nil, signatureError(ErrSigInvalidSeqID, str)
}
// The signature must indicate the correct amount of data for all elements
// related to R and S.
if int(sig[dataLenOffset]) != sigLen-2 {
str := fmt.Sprintf("malformed signature: bad length: %d != %d",
sig[dataLenOffset], sigLen-2)
return nil, signatureError(ErrSigInvalidDataLen, str)
}
// Calculate the offsets of the elements related to S and ensure S is inside
// the signature.
//
// rLen specifies the length of the big-endian encoded number which
// represents the R value of the signature.
//
// sTypeOffset is the offset of the ASN.1 identifier for S and, like its R
// counterpart, is expected to indicate an ASN.1 integer.
//
// sLenOffset and sOffset are the byte offsets within the signature of the
// length of S and S itself, respectively.
rLen := int(sig[rLenOffset])
sTypeOffset := rOffset + rLen
sLenOffset := sTypeOffset + 1
if sTypeOffset >= sigLen {
str := "malformed signature: S type indicator missing"
return nil, signatureError(ErrSigMissingSTypeID, str)
}
if sLenOffset >= sigLen {
str := "malformed signature: S length missing"
return nil, signatureError(ErrSigMissingSLen, str)
}
// The lengths of R and S must match the overall length of the signature.
//
// sLen specifies the length of the big-endian encoded number which
// represents the S value of the signature.
sOffset := sLenOffset + 1
sLen := int(sig[sLenOffset])
if sOffset+sLen != sigLen {
str := "malformed signature: invalid S length"
return nil, signatureError(ErrSigInvalidSLen, str)
}
// R elements must be ASN.1 integers.
if sig[rTypeOffset] != asn1IntegerID {
str := fmt.Sprintf("malformed signature: R integer marker: %#x != %#x",
sig[rTypeOffset], asn1IntegerID)
return nil, signatureError(ErrSigInvalidRIntID, str)
}
// Zero-length integers are not allowed for R.
if rLen == 0 {
str := "malformed signature: R length is zero"
return nil, signatureError(ErrSigZeroRLen, str)
}
// R must not be negative.
if sig[rOffset]&0x80 != 0 {
str := "malformed signature: R is negative"
return nil, signatureError(ErrSigNegativeR, str)
}
// Null bytes at the start of R are not allowed, unless R would otherwise be
// interpreted as a negative number.
if rLen > 1 && sig[rOffset] == 0x00 && sig[rOffset+1]&0x80 == 0 {
str := "malformed signature: R value has too much padding"
return nil, signatureError(ErrSigTooMuchRPadding, str)
}
// S elements must be ASN.1 integers.
if sig[sTypeOffset] != asn1IntegerID {
str := fmt.Sprintf("malformed signature: S integer marker: %#x != %#x",
sig[sTypeOffset], asn1IntegerID)
return nil, signatureError(ErrSigInvalidSIntID, str)
}
// Zero-length integers are not allowed for S.
if sLen == 0 {
str := "malformed signature: S length is zero"
return nil, signatureError(ErrSigZeroSLen, str)
}
// S must not be negative.
if sig[sOffset]&0x80 != 0 {
str := "malformed signature: S is negative"
return nil, signatureError(ErrSigNegativeS, str)
}
// Null bytes at the start of S are not allowed, unless S would otherwise be
// interpreted as a negative number.
if sLen > 1 && sig[sOffset] == 0x00 && sig[sOffset+1]&0x80 == 0 {
str := "malformed signature: S value has too much padding"
return nil, signatureError(ErrSigTooMuchSPadding, str)
}
// The signature is validly encoded per DER at this point, however, enforce
// additional restrictions to ensure R and S are in the range [1, N-1] since
// valid ECDSA signatures are required to be in that range per spec.
//
// Also note that while the overflow checks are required to make use of the
// specialized mod N scalar type, rejecting zero here is not strictly
// required because it is also checked when verifying the signature, but
// there really isn't a good reason not to fail early here on signatures
// that do not conform to the ECDSA spec.
// Strip leading zeroes from R.
rBytes := sig[rOffset : rOffset+rLen]
for len(rBytes) > 0 && rBytes[0] == 0x00 {
rBytes = rBytes[1:]
}
// R must be in the range [1, N-1]. Notice the check for the maximum number
// of bytes is required because SetByteSlice truncates as noted in its
// comment so it could otherwise fail to detect the overflow.
var r secp256k1.ModNScalar
if len(rBytes) > 32 {
str := "invalid signature: R is larger than 256 bits"
return nil, signatureError(ErrSigRTooBig, str)
}
if overflow := r.SetByteSlice(rBytes); overflow {
str := "invalid signature: R >= group order"
return nil, signatureError(ErrSigRTooBig, str)
}
if r.IsZero() {
str := "invalid signature: R is 0"
return nil, signatureError(ErrSigRIsZero, str)
}
// Strip leading zeroes from S.
sBytes := sig[sOffset : sOffset+sLen]
for len(sBytes) > 0 && sBytes[0] == 0x00 {
sBytes = sBytes[1:]
}
// S must be in the range [1, N-1]. Notice the check for the maximum number
// of bytes is required because SetByteSlice truncates as noted in its
// comment so it could otherwise fail to detect the overflow.
var s secp256k1.ModNScalar
if len(sBytes) > 32 {
str := "invalid signature: S is larger than 256 bits"
return nil, signatureError(ErrSigSTooBig, str)
}
if overflow := s.SetByteSlice(sBytes); overflow {
str := "invalid signature: S >= group order"
return nil, signatureError(ErrSigSTooBig, str)
}
if s.IsZero() {
str := "invalid signature: S is 0"
return nil, signatureError(ErrSigSIsZero, str)
}
// Create and return the signature.
return NewSignature(&r, &s), nil
}
// sign generates an ECDSA signature over the secp256k1 curve for the provided
// hash (which should be the result of hashing a larger message) using the given
// nonce and private key and returns it along with an additional public key
// recovery code and success indicator. Upon success, the produced signature is
// deterministic (same message, nonce, and key yield the same signature) and
// canonical in accordance with BIP0062.
//
// Note that signRFC6979 makes use of this function as it is the primary ECDSA
// signing logic. It differs in that it accepts a nonce to use when signing and
// may not successfully produce a valid signature for the given nonce. It is
// primarily separated for testing purposes.
func sign(privKey, nonce *secp256k1.ModNScalar, hash []byte) (*Signature, byte, bool) {
// The algorithm for producing an ECDSA signature is given as algorithm 4.29
// in [GECC].
//
// The following is a paraphrased version for reference:
//
// G = curve generator
// N = curve order
// d = private key
// m = message
// r, s = signature
//
// 1. Select random nonce k in [1, N-1]
// 2. Compute kG
// 3. r = kG.x mod N (kG.x is the x coordinate of the point kG)
// Repeat from step 1 if r = 0
// 4. e = H(m)
// 5. s = k^-1(e + dr) mod N
// Repeat from step 1 if s = 0
// 6. Return (r,s)
//
// This is slightly modified here to conform to RFC6979 and BIP 62 as
// follows:
//
// A. Instead of selecting a random nonce in step 1, use RFC6979 to generate
// a deterministic nonce in [1, N-1] parameterized by the private key,
// message being signed, and an iteration count for the repeat cases
// B. Negate s calculated in step 5 if it is > N/2
// This is done because both s and its negation are valid signatures
// modulo the curve order N, so it forces a consistent choice to reduce
// signature malleability
// NOTE: Step 1 is performed by the caller.
//
// Step 2.
//
// Compute kG
//
// Note that the point must be in affine coordinates.
k := nonce
var kG secp256k1.JacobianPoint
secp256k1.ScalarBaseMultNonConst(k, &kG)
kG.ToAffine()
// Step 3.
//
// r = kG.x mod N
// Repeat from step 1 if r = 0
r, overflow := fieldToModNScalar(&kG.X)
if r.IsZero() {
return nil, 0, false
}
// Since the secp256k1 curve has a cofactor of 1, when recovering a
// public key from an ECDSA signature over it, there are four possible
// candidates corresponding to the following cases:
//
// 1) The X coord of the random point is < N and its Y coord even
// 2) The X coord of the random point is < N and its Y coord is odd
// 3) The X coord of the random point is >= N and its Y coord is even
// 4) The X coord of the random point is >= N and its Y coord is odd
//
// Rather than forcing the recovery procedure to check all possible
// cases, this creates a recovery code that uniquely identifies which of
// the cases apply by making use of 2 bits. Bit 0 identifies the
// oddness case and Bit 1 identifies the overflow case (aka when the X
// coord >= N).
//
// It is also worth noting that making use of Hasse's theorem shows
// there are around log_2((p-n)/p) ~= -127.65 ~= 1 in 2^127 points where
// the X coordinate is >= N. It is not possible to calculate these
// points since that would require breaking the ECDLP, but, in practice
// this strongly implies with extremely high probability that there are
// only a few actual points for which this case is true.
pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.Y.IsOddBit())
// Step 4.
//
// e = H(m)
//
// Note that this actually sets e = H(m) mod N which is correct since
// it is only used in step 5 which itself is mod N.
var e secp256k1.ModNScalar
e.SetByteSlice(hash)
// Step 5 with modification B.
//
// s = k^-1(e + dr) mod N
// Repeat from step 1 if s = 0
// s = -s if s > N/2
kinv := new(secp256k1.ModNScalar).InverseValNonConst(k)
s := new(secp256k1.ModNScalar).Mul2(privKey, &r).Add(&e).Mul(kinv)
if s.IsZero() {
return nil, 0, false
}
if s.IsOverHalfOrder() {
s.Negate()
// Negating s corresponds to the random point that would have been
// generated by -k (mod N), which necessarily has the opposite
// oddness since N is prime, thus flip the pubkey recovery code
// oddness bit accordingly.
pubKeyRecoveryCode ^= 0x01
}
// Step 6.
//
// Return (r,s)
return NewSignature(&r, s), pubKeyRecoveryCode, true
}
// signRFC6979 generates a deterministic ECDSA signature according to RFC 6979
// and BIP0062 and returns it along with an additional public key recovery code
// for efficiently recovering the public key from the signature.
func signRFC6979(privKey *secp256k1.PrivateKey, hash []byte) (*Signature, byte) {
// The algorithm for producing an ECDSA signature is given as algorithm 4.29
// in [GECC].
//
// The following is a paraphrased version for reference:
//
// G = curve generator
// N = curve order
// d = private key
// m = message
// r, s = signature
//
// 1. Select random nonce k in [1, N-1]
// 2. Compute kG
// 3. r = kG.x mod N (kG.x is the x coordinate of the point kG)
// Repeat from step 1 if r = 0
// 4. e = H(m)
// 5. s = k^-1(e + dr) mod N
// Repeat from step 1 if s = 0
// 6. Return (r,s)
//
// This is slightly modified here to conform to RFC6979 and BIP 62 as
// follows:
//
// A. Instead of selecting a random nonce in step 1, use RFC6979 to generate
// a deterministic nonce in [1, N-1] parameterized by the private key,
// message being signed, and an iteration count for the repeat cases
// B. Negate s calculated in step 5 if it is > N/2
// This is done because both s and its negation are valid signatures
// modulo the curve order N, so it forces a consistent choice to reduce
// signature malleability
privKeyScalar := &privKey.Key
var privKeyBytes [32]byte
privKeyScalar.PutBytes(&privKeyBytes)
defer zeroArray32(&privKeyBytes)
for iteration := uint32(0); ; iteration++ {
// Step 1 with modification A.
//
// Generate a deterministic nonce in [1, N-1] parameterized by the
// private key, message being signed, and iteration count.
k := secp256k1.NonceRFC6979(privKeyBytes[:], hash, nil, nil, iteration)
// Steps 2-6.
sig, pubKeyRecoveryCode, success := sign(privKeyScalar, k, hash)
k.Zero()
if !success {
continue
}
return sig, pubKeyRecoveryCode
}
}
// Sign generates an ECDSA signature over the secp256k1 curve for the provided
// hash (which should be the result of hashing a larger message) using the given
// private key. The produced signature is deterministic (same message and same
// key yield the same signature) and canonical in accordance with RFC6979 and
// BIP0062.
func Sign(key *secp256k1.PrivateKey, hash []byte) *Signature {
signature, _ := signRFC6979(key, hash)
return signature
}
const (
// compactSigSize is the size of a compact signature. It consists of a
// compact signature recovery code byte followed by the R and S components
// serialized as 32-byte big-endian values. 1+32*2 = 65.
// for the R and S components. 1+32+32=65.
compactSigSize = 65
// compactSigMagicOffset is a value used when creating the compact signature
// recovery code inherited from Bitcoin and has no meaning, but has been
// retained for compatibility. For historical purposes, it was originally
// picked to avoid a binary representation that would allow compact
// signatures to be mistaken for other components.
compactSigMagicOffset = 27
// compactSigCompPubKey is a value used when creating the compact signature
// recovery code to indicate the original public key was compressed.
compactSigCompPubKey = 4
// pubKeyRecoveryCodeOddnessBit specifies the bit that indicates the oddess
// of the Y coordinate of the random point calculated when creating a
// signature.
pubKeyRecoveryCodeOddnessBit = 1 << 0
// pubKeyRecoveryCodeOverflowBit specifies the bit that indicates the X
// coordinate of the random point calculated when creating a signature was
// >= N, where N is the order of the group.
pubKeyRecoveryCodeOverflowBit = 1 << 1
)
// SignCompact produces a compact ECDSA signature over the secp256k1 curve for
// the provided hash (which should be the result of hashing a larger message)
// using the given private key. The isCompressedKey parameter specifies if the
// produced signature should reference a compressed public key or not.
//
// Compact signature format:
// <1-byte compact sig recovery code><32-byte R><32-byte S>
//
// The compact sig recovery code is the value 27 + public key recovery code + 4
// if the compact signature was created with a compressed public key.
func SignCompact(key *secp256k1.PrivateKey, hash []byte, isCompressedKey bool) []byte {
// Create the signature and associated pubkey recovery code and calculate
// the compact signature recovery code.
sig, pubKeyRecoveryCode := signRFC6979(key, hash)
compactSigRecoveryCode := compactSigMagicOffset + pubKeyRecoveryCode
if isCompressedKey {
compactSigRecoveryCode += compactSigCompPubKey
}
// Output <compactSigRecoveryCode><32-byte R><32-byte S>.
var b [compactSigSize]byte
b[0] = compactSigRecoveryCode
sig.r.PutBytesUnchecked(b[1:33])
sig.s.PutBytesUnchecked(b[33:65])
return b[:]
}
// RecoverCompact attempts to recover the secp256k1 public key from the provided
// compact signature and message hash. It first verifies the signature, and, if
// the signature matches then the recovered public key will be returned as well
// as a boolean indicating whether or not the original key was compressed.
func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) {
// The following is very loosely based on the information and algorithm that
// describes recovering a public key from and ECDSA signature in section
// 4.1.6 of [SEC1].
//
// Given the following parameters:
//
// G = curve generator
// N = group order
// P = field prime
// Q = public key
// m = message
// e = hash of the message
// r, s = signature
// X = random point used when creating signature whose x coordinate is r
//
// The equation to recover a public key candidate from an ECDSA signature
// is:
// Q = r^-1(sX - eG).
//
// This can be verified by plugging it in for Q in the sig verification
// equation:
// X = s^-1(eG + rQ) (mod N)
// => s^-1(eG + r(r^-1(sX - eG))) (mod N)
// => s^-1(eG + sX - eG) (mod N)
// => s^-1(sX) (mod N)
// => X (mod N)
//
// However, note that since r is the x coordinate mod N from a random point
// that was originally mod P, and the cofactor of the secp256k1 curve is 1,
// there are four possible points that the original random point could have
// been to produce r: (r,y), (r,-y), (r+N,y), and (r+N,-y). At least 2 of
// those points will successfully verify, and all 4 will successfully verify
// when the original x coordinate was in the range [N+1, P-1], but in any
// case, only one of them corresponds to the original private key used.
//
// The method described by section 4.1.6 of [SEC1] to determine which one is
// the correct one involves calculating each possibility as a candidate
// public key and comparing the candidate to the authentic public key. It
// also hints that it is possible to generate the signature in a such a
// way that only one of the candidate public keys is viable.
//
// A more efficient approach that is specific to the secp256k1 curve is used
// here instead which is to produce a "pubkey recovery code" when signing
// that uniquely identifies which of the 4 possibilities is correct for the
// original random point and using that to recover the pubkey directly as
// follows:
//
// 1. Fail if r and s are not in [1, N-1]
// 2. Convert r to integer mod P
// 3. If pubkey recovery code overflow bit is set:
// 3.1 Fail if r + N >= P
// 3.2 r = r + N (mod P)
// 4. y = +sqrt(r^3 + 7) (mod P)
// 4.1 Fail if y does not exist
// 4.2 y = -y if needed to match pubkey recovery code oddness bit
// 5. X = (r, y)
// 6. e = H(m) mod N
// 7. w = r^-1 mod N
// 8. u1 = -(e * w) mod N
// u2 = s * w mod N
// 9. Q = u1G + u2X
// 10. Fail if Q is the point at infinity
// A compact signature consists of a recovery byte followed by the R and
// S components serialized as 32-byte big-endian values.
if len(signature) != compactSigSize {
str := fmt.Sprintf("malformed signature: wrong size: %d != %d",
len(signature), compactSigSize)
return nil, false, signatureError(ErrSigInvalidLen, str)
}
// Parse and validate the compact signature recovery code.
const (
minValidCode = compactSigMagicOffset
maxValidCode = compactSigMagicOffset + compactSigCompPubKey + 3
)
sigRecoveryCode := signature[0]
if sigRecoveryCode < minValidCode || sigRecoveryCode > maxValidCode {
str := fmt.Sprintf("invalid signature: public key recovery code %d is "+
"not in the valid range [%d, %d]", sigRecoveryCode, minValidCode,
maxValidCode)
return nil, false, signatureError(ErrSigInvalidRecoveryCode, str)
}
sigRecoveryCode -= compactSigMagicOffset
wasCompressed := sigRecoveryCode&compactSigCompPubKey != 0
pubKeyRecoveryCode := sigRecoveryCode & 3
// Step 1.
//
// Parse and validate the R and S signature components.
//
// Fail if r and s are not in [1, N-1].
var r, s secp256k1.ModNScalar
if overflow := r.SetByteSlice(signature[1:33]); overflow {
str := "invalid signature: R >= group order"
return nil, false, signatureError(ErrSigRTooBig, str)
}
if r.IsZero() {
str := "invalid signature: R is 0"
return nil, false, signatureError(ErrSigRIsZero, str)
}
if overflow := s.SetByteSlice(signature[33:]); overflow {
str := "invalid signature: S >= group order"
return nil, false, signatureError(ErrSigSTooBig, str)
}
if s.IsZero() {
str := "invalid signature: S is 0"
return nil, false, signatureError(ErrSigSIsZero, str)
}
// Step 2.
//
// Convert r to integer mod P.
fieldR := modNScalarToField(&r)
// Step 3.
//
// If pubkey recovery code overflow bit is set:
if pubKeyRecoveryCode&pubKeyRecoveryCodeOverflowBit != 0 {
// Step 3.1.
//
// Fail if r + N >= P
//
// Either the signature or the recovery code must be invalid if the
// recovery code overflow bit is set and adding N to the R component
// would exceed the field prime since R originally came from the X
// coordinate of a random point on the curve.
if fieldR.IsGtOrEqPrimeMinusOrder() {
str := "invalid signature: signature R + N >= P"
return nil, false, signatureError(ErrSigOverflowsPrime, str)
}
// Step 3.2.
//
// r = r + N (mod P)
fieldR.Add(&orderAsFieldVal)
}
// Step 4.
//
// y = +sqrt(r^3 + 7) (mod P)
// Fail if y does not exist.
// y = -y if needed to match pubkey recovery code oddness bit
//
// The signature must be invalid if the calculation fails because the X
// coord originally came from a random point on the curve which means there
// must be a Y coord that satisfies the equation for a valid signature.
oddY := pubKeyRecoveryCode&pubKeyRecoveryCodeOddnessBit != 0
var y secp256k1.FieldVal
if valid := secp256k1.DecompressY(&fieldR, oddY, &y); !valid {
str := "invalid signature: not for a valid curve point"
return nil, false, signatureError(ErrPointNotOnCurve, str)
}
// Step 5.
//
// X = (r, y)
var X secp256k1.JacobianPoint
X.X.Set(fieldR.Normalize())
X.Y.Set(y.Normalize())
X.Z.SetInt(1)
// Step 6.
//
// e = H(m) mod N
var e secp256k1.ModNScalar
e.SetByteSlice(hash)
// Step 7.
//
// w = r^-1 mod N
w := new(secp256k1.ModNScalar).InverseValNonConst(&r)
// Step 8.
//
// u1 = -(e * w) mod N
// u2 = s * w mod N
u1 := new(secp256k1.ModNScalar).Mul2(&e, w).Negate()
u2 := new(secp256k1.ModNScalar).Mul2(&s, w)
// Step 9.
//
// Q = u1G + u2X
var Q, u1G, u2X secp256k1.JacobianPoint
secp256k1.ScalarBaseMultNonConst(u1, &u1G)
secp256k1.ScalarMultNonConst(u2, &X, &u2X)
secp256k1.AddNonConst(&u1G, &u2X, &Q)
// Step 10.
//
// Fail if Q is the point at infinity.
//
// Either the signature or the pubkey recovery code must be invalid if the
// recovered pubkey is the point at infinity.
if (Q.X.IsZero() && Q.Y.IsZero()) || Q.Z.IsZero() {
str := "invalid signature: recovered pubkey is the point at infinity"
return nil, false, signatureError(ErrPointNotOnCurve, str)
}
// Notice that the public key is in affine coordinates.
Q.ToAffine()
pubKey := secp256k1.NewPublicKey(&Q.X, &Q.Y)
return pubKey, wasCompressed, nil
}

View File

@@ -0,0 +1,255 @@
// Copyright 2020-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// References:
// [SECG]: Recommended Elliptic Curve Domain Parameters
// https://www.secg.org/sec2-v2.pdf
//
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
import (
"crypto/ecdsa"
"crypto/elliptic"
"math/big"
)
// CurveParams contains the parameters for the secp256k1 curve.
type CurveParams struct {
// P is the prime used in the secp256k1 field.
P *big.Int
// N is the order of the secp256k1 curve group generated by the base point.
N *big.Int
// Gx and Gy are the x and y coordinate of the base point, respectively.
Gx, Gy *big.Int
// BitSize is the size of the underlying secp256k1 field in bits.
BitSize int
// H is the cofactor of the secp256k1 curve.
H int
// ByteSize is simply the bit size / 8 and is provided for convenience
// since it is calculated repeatedly.
ByteSize int
}
// Curve parameters taken from [SECG] section 2.4.1.
var curveParams = CurveParams{
P: fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
N: fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
Gx: fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
Gy: fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"),
BitSize: 256,
H: 1,
ByteSize: 256 / 8,
}
// Params returns the secp256k1 curve parameters for convenience.
func Params() *CurveParams {
return &curveParams
}
// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve
// interface from crypto/elliptic.
type KoblitzCurve struct {
*elliptic.CurveParams
}
// bigAffineToJacobian takes an affine point (x, y) as big integers and converts
// it to Jacobian point with Z=1.
func bigAffineToJacobian(x, y *big.Int, result *JacobianPoint) {
result.X.SetByteSlice(x.Bytes())
result.Y.SetByteSlice(y.Bytes())
result.Z.SetInt(1)
}
// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and
// converts it to an affine point as big integers.
func jacobianToBigAffine(point *JacobianPoint) (*big.Int, *big.Int) {
point.ToAffine()
// Convert the field values for the now affine point to big.Ints.
x3, y3 := new(big.Int), new(big.Int)
x3.SetBytes(point.X.Bytes()[:])
y3.SetBytes(point.Y.Bytes()[:])
return x3, y3
}
// Params returns the parameters for the curve.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Params() *elliptic.CurveParams {
return curve.CurveParams
}
// IsOnCurve returns whether or not the affine point (x,y) is on the curve.
//
// This is part of the elliptic.Curve interface implementation. This function
// differs from the crypto/elliptic algorithm since a = 0 not -3.
func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool {
// Convert big ints to a Jacobian point for faster arithmetic.
var point JacobianPoint
bigAffineToJacobian(x, y, &point)
return isOnCurve(&point.X, &point.Y)
}
// Add returns the sum of (x1,y1) and (x2,y2).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
// The point at infinity is the identity according to the group law for
// elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P.
if x1.Sign() == 0 && y1.Sign() == 0 {
return x2, y2
}
if x2.Sign() == 0 && y2.Sign() == 0 {
return x1, y1
}
// Convert the affine coordinates from big integers to Jacobian points,
// do the point addition in Jacobian projective space, and convert the
// Jacobian point back to affine big.Ints.
var p1, p2, result JacobianPoint
bigAffineToJacobian(x1, y1, &p1)
bigAffineToJacobian(x2, y2, &p2)
AddNonConst(&p1, &p2, &result)
return jacobianToBigAffine(&result)
}
// Double returns 2*(x1,y1).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
if y1.Sign() == 0 {
return new(big.Int), new(big.Int)
}
// Convert the affine coordinates from big integers to Jacobian points,
// do the point doubling in Jacobian projective space, and convert the
// Jacobian point back to affine big.Ints.
var point, result JacobianPoint
bigAffineToJacobian(x1, y1, &point)
DoubleNonConst(&point, &result)
return jacobianToBigAffine(&result)
}
// moduloReduce reduces k from more than 32 bytes to 32 bytes and under. This
// is done by doing a simple modulo curve.N. We can do this since G^N = 1 and
// thus any other valid point on the elliptic curve has the same order.
func moduloReduce(k []byte) []byte {
// Since the order of G is curve.N, we can use a much smaller number by
// doing modulo curve.N
if len(k) > curveParams.ByteSize {
tmpK := new(big.Int).SetBytes(k)
tmpK.Mod(tmpK, curveParams.N)
return tmpK.Bytes()
}
return k
}
// ScalarMult returns k*(Bx, By) where k is a big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// Convert the affine coordinates from big integers to Jacobian points,
// do the multiplication in Jacobian projective space, and convert the
// Jacobian point back to affine big.Ints.
var kModN ModNScalar
kModN.SetByteSlice(moduloReduce(k))
var point, result JacobianPoint
bigAffineToJacobian(Bx, By, &point)
ScalarMultNonConst(&kModN, &point, &result)
return jacobianToBigAffine(&result)
}
// ScalarBaseMult returns k*G where G is the base point of the group and k is a
// big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// Perform the multiplication and convert the Jacobian point back to affine
// big.Ints.
var kModN ModNScalar
kModN.SetByteSlice(moduloReduce(k))
var result JacobianPoint
ScalarBaseMultNonConst(&kModN, &result)
return jacobianToBigAffine(&result)
}
// X returns the x coordinate of the public key.
func (p *PublicKey) X() *big.Int {
return new(big.Int).SetBytes(p.x.Bytes()[:])
}
// Y returns the y coordinate of the public key.
func (p *PublicKey) Y() *big.Int {
return new(big.Int).SetBytes(p.y.Bytes()[:])
}
// ToECDSA returns the public key as a *ecdsa.PublicKey.
func (p *PublicKey) ToECDSA() *ecdsa.PublicKey {
return &ecdsa.PublicKey{
Curve: S256(),
X: p.X(),
Y: p.Y(),
}
}
// ToECDSA returns the private key as a *ecdsa.PrivateKey.
func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
var privKeyBytes [PrivKeyBytesLen]byte
p.Key.PutBytes(&privKeyBytes)
var result JacobianPoint
ScalarBaseMultNonConst(&p.Key, &result)
x, y := jacobianToBigAffine(&result)
newPrivKey := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: S256(),
X: x,
Y: y,
},
D: new(big.Int).SetBytes(privKeyBytes[:]),
}
zeroArray32(&privKeyBytes)
return newPrivKey
}
// fromHex converts the passed hex string into a big integer pointer and will
// panic is there is an error. This is only provided for the hard-coded
// constants so errors in the source code can bet detected. It will only (and
// must only) be called for initialization purposes.
func fromHex(s string) *big.Int {
if s == "" {
return big.NewInt(0)
}
r, ok := new(big.Int).SetString(s, 16)
if !ok {
panic("invalid hex in source file: " + s)
}
return r
}
// secp256k1 is a global instance of the KoblitzCurve implementation which in
// turn embeds and implements elliptic.CurveParams.
var secp256k1 = &KoblitzCurve{
CurveParams: &elliptic.CurveParams{
P: curveParams.P,
N: curveParams.N,
B: fromHex("0000000000000000000000000000000000000000000000000000000000000007"),
Gx: curveParams.Gx,
Gy: curveParams.Gy,
BitSize: curveParams.BitSize,
Name: "secp256k1",
},
}
// S256 returns an elliptic.Curve which implements secp256k1.
func S256() *KoblitzCurve {
return secp256k1
}

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// ErrorKind identifies a kind of error. It has full support for errors.Is and
// errors.As, so the caller can directly check against an error kind when
// determining the reason for an error.
type ErrorKind string
// These constants are used to identify a specific RuleError.
const (
// ErrPubKeyInvalidLen indicates that the length of a serialized public
// key is not one of the allowed lengths.
ErrPubKeyInvalidLen = ErrorKind("ErrPubKeyInvalidLen")
// ErrPubKeyInvalidFormat indicates an attempt was made to parse a public
// key that does not specify one of the supported formats.
ErrPubKeyInvalidFormat = ErrorKind("ErrPubKeyInvalidFormat")
// ErrPubKeyXTooBig indicates that the x coordinate for a public key
// is greater than or equal to the prime of the field underlying the group.
ErrPubKeyXTooBig = ErrorKind("ErrPubKeyXTooBig")
// ErrPubKeyYTooBig indicates that the y coordinate for a public key is
// greater than or equal to the prime of the field underlying the group.
ErrPubKeyYTooBig = ErrorKind("ErrPubKeyYTooBig")
// ErrPubKeyNotOnCurve indicates that a public key is not a point on the
// secp256k1 curve.
ErrPubKeyNotOnCurve = ErrorKind("ErrPubKeyNotOnCurve")
// ErrPubKeyMismatchedOddness indicates that a hybrid public key specified
// an oddness of the y coordinate that does not match the actual oddness of
// the provided y coordinate.
ErrPubKeyMismatchedOddness = ErrorKind("ErrPubKeyMismatchedOddness")
)
// Error satisfies the error interface and prints human-readable errors.
func (e ErrorKind) Error() string {
return string(e)
}
// Error identifies an error related to public key cryptography using a
// sec256k1 curve. It has full support for errors.Is and errors.As, so the
// caller can ascertain the specific reason for the error by checking
// the underlying error.
type Error struct {
Err error
Description string
}
// Error satisfies the error interface and prints human-readable errors.
func (e Error) Error() string {
return e.Description
}
// Unwrap returns the underlying wrapped error.
func (e Error) Unwrap() error {
return e.Err
}
// makeError creates an Error given a set of arguments.
func makeError(kind ErrorKind, desc string) Error {
return Error{Err: kind, Description: desc}
}

1681
vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
// Copyright 2015 The btcsuite developers
// Copyright (c) 2015-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
"compress/zlib"
"encoding/base64"
"io"
"strings"
"sync"
)
//go:generate go run genprecomps.go
// bytePointTable describes a table used to house pre-computed values for
// accelerating scalar base multiplication.
type bytePointTable [32][256]JacobianPoint
// compressedBytePointsFn is set to a real function by the code generation to
// return the compressed pre-computed values for accelerating scalar base
// multiplication.
var compressedBytePointsFn func() string
// s256BytePoints houses pre-computed values used to accelerate scalar base
// multiplication such that they are only loaded on first use.
var s256BytePoints = func() func() *bytePointTable {
// mustLoadBytePoints decompresses and deserializes the pre-computed byte
// points used to accelerate scalar base multiplication for the secp256k1
// curve.
//
// This approach is used since it allows the compile to use significantly
// less ram and be performed much faster than it is with hard-coding the
// final in-memory data structure. At the same time, it is quite fast to
// generate the in-memory data structure on first use with this approach
// versus computing the table.
//
// It will panic on any errors because the data is hard coded and thus any
// errors means something is wrong in the source code.
var data *bytePointTable
mustLoadBytePoints := func() {
// There will be no byte points to load when generating them.
if compressedBytePointsFn == nil {
return
}
bp := compressedBytePointsFn()
// Decompress the pre-computed table used to accelerate scalar base
// multiplication.
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp))
r, err := zlib.NewReader(decoder)
if err != nil {
panic(err)
}
serialized, err := io.ReadAll(r)
if err != nil {
panic(err)
}
// Deserialize the precomputed byte points and set the memory table to
// them.
offset := 0
var bytePoints bytePointTable
for byteNum := 0; byteNum < len(bytePoints); byteNum++ {
// All points in this window.
for i := 0; i < len(bytePoints[byteNum]); i++ {
p := &bytePoints[byteNum][i]
p.X.SetByteSlice(serialized[offset:])
offset += 32
p.Y.SetByteSlice(serialized[offset:])
offset += 32
p.Z.SetInt(1)
}
}
data = &bytePoints
}
// Return a closure that initializes the data on first access. This is done
// because the table takes a non-trivial amount of memory and initializing
// it unconditionally would cause anything that imports the package, either
// directly, or indirectly via transitive deps, to use that memory even if
// the caller never accesses any parts of the package that actually needs
// access to it.
var loadBytePointsOnce sync.Once
return func() *bytePointTable {
loadBytePointsOnce.Do(mustLoadBytePoints)
return data
}
}()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
"bytes"
"crypto/sha256"
"hash"
)
// References:
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
//
// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules:
// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules
// (CER) and Distinguished Encoding Rules (DER)
//
// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0)
// https://www.secg.org/sec1-v2.pdf
var (
// singleZero is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
singleZero = []byte{0x00}
// zeroInitializer is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize)
// singleOne is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
singleOne = []byte{0x01}
// oneInitializer is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size)
)
// hmacsha256 implements a resettable version of HMAC-SHA256.
type hmacsha256 struct {
inner, outer hash.Hash
ipad, opad [sha256.BlockSize]byte
}
// Write adds data to the running hash.
func (h *hmacsha256) Write(p []byte) {
h.inner.Write(p)
}
// initKey initializes the HMAC-SHA256 instance to the provided key.
func (h *hmacsha256) initKey(key []byte) {
// Hash the key if it is too large.
if len(key) > sha256.BlockSize {
h.outer.Write(key)
key = h.outer.Sum(nil)
}
copy(h.ipad[:], key)
copy(h.opad[:], key)
for i := range h.ipad {
h.ipad[i] ^= 0x36
}
for i := range h.opad {
h.opad[i] ^= 0x5c
}
h.inner.Write(h.ipad[:])
}
// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it
// with the provided key. It is equivalent to creating a new instance with the
// provided key without allocating more memory.
func (h *hmacsha256) ResetKey(key []byte) {
h.inner.Reset()
h.outer.Reset()
copy(h.ipad[:], zeroInitializer)
copy(h.opad[:], zeroInitializer)
h.initKey(key)
}
// Resets the HMAC-SHA256 to its initial state using the current key.
func (h *hmacsha256) Reset() {
h.inner.Reset()
h.inner.Write(h.ipad[:])
}
// Sum returns the hash of the written data.
func (h *hmacsha256) Sum() []byte {
h.outer.Reset()
h.outer.Write(h.opad[:])
h.outer.Write(h.inner.Sum(nil))
return h.outer.Sum(nil)
}
// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key.
func newHMACSHA256(key []byte) *hmacsha256 {
h := new(hmacsha256)
h.inner = sha256.New()
h.outer = sha256.New()
h.initKey(key)
return h
}
// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using
// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input
// and returns a 32-byte nonce to be used for deterministic signing. The extra
// and version arguments are optional, but allow additional data to be added to
// the input of the HMAC. When provided, the extra data must be 32-bytes and
// version must be 16 bytes or they will be ignored.
//
// Finally, the extraIterations parameter provides a method to produce a stream
// of deterministic nonces to ensure the signing code is able to produce a nonce
// that results in a valid signature in the extremely unlikely event the
// original nonce produced results in an invalid signature (e.g. R == 0).
// Signing code should start with 0 and increment it if necessary.
func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar {
// Input to HMAC is the 32-byte private key and the 32-byte hash. In
// addition, it may include the optional 32-byte extra data and 16-byte
// version. Create a fixed-size array to avoid extra allocs and slice it
// properly.
const (
privKeyLen = 32
hashLen = 32
extraLen = 32
versionLen = 16
)
var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte
// Truncate rightmost bytes of private key and hash if they are too long and
// leave left padding of zeros when they're too short.
if len(privKey) > privKeyLen {
privKey = privKey[:privKeyLen]
}
if len(hash) > hashLen {
hash = hash[:hashLen]
}
offset := privKeyLen - len(privKey) // Zero left padding if needed.
offset += copy(keyBuf[offset:], privKey)
offset += hashLen - len(hash) // Zero left padding if needed.
offset += copy(keyBuf[offset:], hash)
if len(extra) == extraLen {
offset += copy(keyBuf[offset:], extra)
if len(version) == versionLen {
offset += copy(keyBuf[offset:], version)
}
} else if len(version) == versionLen {
// When the version was specified, but not the extra data, leave the
// extra data portion all zero.
offset += privKeyLen
offset += copy(keyBuf[offset:], version)
}
key := keyBuf[:offset]
// Step B.
//
// V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is
// equal to 8*ceil(hashLen/8).
//
// Note that since the hash length is a multiple of 8 for the chosen hash
// function in this optimized implementation, the result is just the hash
// length, so avoid the extra calculations. Also, since it isn't modified,
// start with a global value.
v := oneInitializer
// Step C (Go zeroes all allocated memory).
//
// K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is
// equal to 8*ceil(hashLen/8).
//
// As above, since the hash length is a multiple of 8 for the chosen hash
// function in this optimized implementation, the result is just the hash
// length, so avoid the extra calculations.
k := zeroInitializer[:hashLen]
// Step D.
//
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
//
// Note that key is the "int2octets(x) || bits2octets(h1)" portion along
// with potential additional data as described by section 3.6 of the RFC.
hasher := newHMACSHA256(k)
hasher.Write(oneInitializer)
hasher.Write(singleZero[:])
hasher.Write(key)
k = hasher.Sum()
// Step E.
//
// V = HMAC_K(V)
hasher.ResetKey(k)
hasher.Write(v)
v = hasher.Sum()
// Step F.
//
// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
//
// Note that key is the "int2octets(x) || bits2octets(h1)" portion along
// with potential additional data as described by section 3.6 of the RFC.
hasher.Reset()
hasher.Write(v)
hasher.Write(singleOne[:])
hasher.Write(key[:])
k = hasher.Sum()
// Step G.
//
// V = HMAC_K(V)
hasher.ResetKey(k)
hasher.Write(v)
v = hasher.Sum()
// Step H.
//
// Repeat until the value is nonzero and less than the curve order.
var generated uint32
for {
// Step H1 and H2.
//
// Set T to the empty sequence. The length of T (in bits) is denoted
// tlen; thus, at that point, tlen = 0.
//
// While tlen < qlen, do the following:
// V = HMAC_K(V)
// T = T || V
//
// Note that because the hash function output is the same length as the
// private key in this optimized implementation, there is no need to
// loop or create an intermediate T.
hasher.Reset()
hasher.Write(v)
v = hasher.Sum()
// Step H3.
//
// k = bits2int(T)
// If k is within the range [1,q-1], return it.
//
// Otherwise, compute:
// K = HMAC_K(V || 0x00)
// V = HMAC_K(V)
var secret ModNScalar
overflow := secret.SetByteSlice(v)
if !overflow && !secret.IsZero() {
generated++
if generated > extraIterations {
return &secret
}
}
// K = HMAC_K(V || 0x00)
hasher.Reset()
hasher.Write(v)
hasher.Write(singleZero[:])
k = hasher.Sum()
// V = HMAC_K(V)
hasher.ResetKey(k)
hasher.Write(v)
v = hasher.Sum()
}
}

View File

@@ -0,0 +1,111 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
cryptorand "crypto/rand"
"io"
)
// PrivateKey provides facilities for working with secp256k1 private keys within
// this package and includes functionality such as serializing and parsing them
// as well as computing their associated public key.
type PrivateKey struct {
Key ModNScalar
}
// NewPrivateKey instantiates a new private key from a scalar encoded as a
// big integer.
func NewPrivateKey(key *ModNScalar) *PrivateKey {
return &PrivateKey{Key: *key}
}
// PrivKeyFromBytes returns a private based on the provided byte slice which is
// interpreted as an unsigned 256-bit big-endian integer in the range [0, N-1],
// where N is the order of the curve.
//
// WARNING: This means passing a slice with more than 32 bytes is truncated and
// that truncated value is reduced modulo N. Further, 0 is not a valid private
// key. It is up to the caller to provide a value in the appropriate range of
// [1, N-1]. Failure to do so will either result in an invalid private key or
// potentially weak private keys that have bias that could be exploited.
//
// This function primarily exists to provide a mechanism for converting
// serialized private keys that are already known to be good.
//
// Typically callers should make use of GeneratePrivateKey or
// GeneratePrivateKeyFromRand when creating private keys since they properly
// handle generation of appropriate values.
func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey {
var privKey PrivateKey
privKey.Key.SetByteSlice(privKeyBytes)
return &privKey
}
// generatePrivateKey generates and returns a new private key that is suitable
// for use with secp256k1 using the provided reader as a source of entropy. The
// provided reader must be a source of cryptographically secure randomness to
// avoid weak private keys.
func generatePrivateKey(rand io.Reader) (*PrivateKey, error) {
// The group order is close enough to 2^256 that there is only roughly a 1
// in 2^128 chance of generating an invalid private key, so this loop will
// virtually never run more than a single iteration in practice.
var key PrivateKey
var b32 [32]byte
for valid := false; !valid; {
if _, err := io.ReadFull(rand, b32[:]); err != nil {
return nil, err
}
// The private key is only valid when it is in the range [1, N-1], where
// N is the order of the curve.
overflow := key.Key.SetBytes(&b32)
valid = (key.Key.IsZeroBit() | overflow) == 0
}
zeroArray32(&b32)
return &key, nil
}
// GeneratePrivateKey generates and returns a new cryptographically secure
// private key that is suitable for use with secp256k1.
func GeneratePrivateKey() (*PrivateKey, error) {
return generatePrivateKey(cryptorand.Reader)
}
// GeneratePrivateKeyFromRand generates a private key that is suitable for use
// with secp256k1 using the provided reader as a source of entropy. The
// provided reader must be a source of cryptographically secure randomness, such
// as [crypto/rand.Reader], to avoid weak private keys.
func GeneratePrivateKeyFromRand(rand io.Reader) (*PrivateKey, error) {
return generatePrivateKey(rand)
}
// PubKey computes and returns the public key corresponding to this private key.
func (p *PrivateKey) PubKey() *PublicKey {
var result JacobianPoint
ScalarBaseMultNonConst(&p.Key, &result)
result.ToAffine()
return NewPublicKey(&result.X, &result.Y)
}
// Zero manually clears the memory associated with the private key. This can be
// used to explicitly clear key material from memory for enhanced security
// against memory scraping.
func (p *PrivateKey) Zero() {
p.Key.Zero()
}
// PrivKeyBytesLen defines the length in bytes of a serialized private key.
const PrivKeyBytesLen = 32
// Serialize returns the private key as a 256-bit big-endian binary-encoded
// number, padded to a length of 32 bytes.
func (p PrivateKey) Serialize() []byte {
var privKeyBytes [PrivKeyBytesLen]byte
p.Key.PutBytes(&privKeyBytes)
return privKeyBytes[:]
}

View File

@@ -0,0 +1,237 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// References:
// [SEC1] Elliptic Curve Cryptography
// https://www.secg.org/sec1-v2.pdf
//
// [SEC2] Recommended Elliptic Curve Domain Parameters
// https://www.secg.org/sec2-v2.pdf
//
// [ANSI X9.62-1998] Public Key Cryptography For The Financial Services
// Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)
import (
"fmt"
)
const (
// PubKeyBytesLenCompressed is the number of bytes of a serialized
// compressed public key.
PubKeyBytesLenCompressed = 33
// PubKeyBytesLenUncompressed is the number of bytes of a serialized
// uncompressed public key.
PubKeyBytesLenUncompressed = 65
// PubKeyFormatCompressedEven is the identifier prefix byte for a public key
// whose Y coordinate is even when serialized in the compressed format per
// section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4).
PubKeyFormatCompressedEven byte = 0x02
// PubKeyFormatCompressedOdd is the identifier prefix byte for a public key
// whose Y coordinate is odd when serialized in the compressed format per
// section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4).
PubKeyFormatCompressedOdd byte = 0x03
// PubKeyFormatUncompressed is the identifier prefix byte for a public key
// when serialized according in the uncompressed format per section 2.3.3 of
// [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.3).
PubKeyFormatUncompressed byte = 0x04
// PubKeyFormatHybridEven is the identifier prefix byte for a public key
// whose Y coordinate is even when serialized according to the hybrid format
// per section 4.3.6 of [ANSI X9.62-1998].
//
// NOTE: This format makes little sense in practice an therefore this
// package will not produce public keys serialized in this format. However,
// it will parse them since they exist in the wild.
PubKeyFormatHybridEven byte = 0x06
// PubKeyFormatHybridOdd is the identifier prefix byte for a public key
// whose Y coordingate is odd when serialized according to the hybrid format
// per section 4.3.6 of [ANSI X9.62-1998].
//
// NOTE: This format makes little sense in practice an therefore this
// package will not produce public keys serialized in this format. However,
// it will parse them since they exist in the wild.
PubKeyFormatHybridOdd byte = 0x07
)
// PublicKey provides facilities for efficiently working with secp256k1 public
// keys within this package and includes functions to serialize in both
// uncompressed and compressed SEC (Standards for Efficient Cryptography)
// formats.
type PublicKey struct {
x FieldVal
y FieldVal
}
// NewPublicKey instantiates a new public key with the given x and y
// coordinates.
//
// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x
// and y coordinates, it allows creation of public keys that are not valid
// points on the secp256k1 curve. The IsOnCurve method of the returned instance
// can be used to determine validity.
func NewPublicKey(x, y *FieldVal) *PublicKey {
var pubKey PublicKey
pubKey.x.Set(x)
pubKey.y.Set(y)
return &pubKey
}
// ParsePubKey parses a secp256k1 public key encoded according to the format
// specified by ANSI X9.62-1998, which means it is also compatible with the
// SEC (Standards for Efficient Cryptography) specification which is a subset of
// the former. In other words, it supports the uncompressed, compressed, and
// hybrid formats as follows:
//
// Compressed:
//
// <format byte = 0x02/0x03><32-byte X coordinate>
//
// Uncompressed:
//
// <format byte = 0x04><32-byte X coordinate><32-byte Y coordinate>
//
// Hybrid:
//
// <format byte = 0x05/0x06><32-byte X coordinate><32-byte Y coordinate>
//
// NOTE: The hybrid format makes little sense in practice an therefore this
// package will not produce public keys serialized in this format. However,
// this function will properly parse them since they exist in the wild.
func ParsePubKey(serialized []byte) (key *PublicKey, err error) {
var x, y FieldVal
switch len(serialized) {
case PubKeyBytesLenUncompressed:
// Reject unsupported public key formats for the given length.
format := serialized[0]
switch format {
case PubKeyFormatUncompressed:
case PubKeyFormatHybridEven, PubKeyFormatHybridOdd:
default:
str := fmt.Sprintf("invalid public key: unsupported format: %x",
format)
return nil, makeError(ErrPubKeyInvalidFormat, str)
}
// Parse the x and y coordinates while ensuring that they are in the
// allowed range.
if overflow := x.SetByteSlice(serialized[1:33]); overflow {
str := "invalid public key: x >= field prime"
return nil, makeError(ErrPubKeyXTooBig, str)
}
if overflow := y.SetByteSlice(serialized[33:]); overflow {
str := "invalid public key: y >= field prime"
return nil, makeError(ErrPubKeyYTooBig, str)
}
// Ensure the oddness of the y coordinate matches the specified format
// for hybrid public keys.
if format == PubKeyFormatHybridEven || format == PubKeyFormatHybridOdd {
wantOddY := format == PubKeyFormatHybridOdd
if y.IsOdd() != wantOddY {
str := fmt.Sprintf("invalid public key: y oddness does not "+
"match specified value of %v", wantOddY)
return nil, makeError(ErrPubKeyMismatchedOddness, str)
}
}
// Reject public keys that are not on the secp256k1 curve.
if !isOnCurve(&x, &y) {
str := fmt.Sprintf("invalid public key: [%v,%v] not on secp256k1 "+
"curve", x, y)
return nil, makeError(ErrPubKeyNotOnCurve, str)
}
case PubKeyBytesLenCompressed:
// Reject unsupported public key formats for the given length.
format := serialized[0]
switch format {
case PubKeyFormatCompressedEven, PubKeyFormatCompressedOdd:
default:
str := fmt.Sprintf("invalid public key: unsupported format: %x",
format)
return nil, makeError(ErrPubKeyInvalidFormat, str)
}
// Parse the x coordinate while ensuring that it is in the allowed
// range.
if overflow := x.SetByteSlice(serialized[1:33]); overflow {
str := "invalid public key: x >= field prime"
return nil, makeError(ErrPubKeyXTooBig, str)
}
// Attempt to calculate the y coordinate for the given x coordinate such
// that the result pair is a point on the secp256k1 curve and the
// solution with desired oddness is chosen.
wantOddY := format == PubKeyFormatCompressedOdd
if !DecompressY(&x, wantOddY, &y) {
str := fmt.Sprintf("invalid public key: x coordinate %v is not on "+
"the secp256k1 curve", x)
return nil, makeError(ErrPubKeyNotOnCurve, str)
}
y.Normalize()
default:
str := fmt.Sprintf("malformed public key: invalid length: %d",
len(serialized))
return nil, makeError(ErrPubKeyInvalidLen, str)
}
return NewPublicKey(&x, &y), nil
}
// SerializeUncompressed serializes a public key in the 65-byte uncompressed
// format.
func (p PublicKey) SerializeUncompressed() []byte {
// 0x04 || 32-byte x coordinate || 32-byte y coordinate
var b [PubKeyBytesLenUncompressed]byte
b[0] = PubKeyFormatUncompressed
p.x.PutBytesUnchecked(b[1:33])
p.y.PutBytesUnchecked(b[33:65])
return b[:]
}
// SerializeCompressed serializes a public key in the 33-byte compressed format.
func (p PublicKey) SerializeCompressed() []byte {
// Choose the format byte depending on the oddness of the Y coordinate.
format := PubKeyFormatCompressedEven
if p.y.IsOdd() {
format = PubKeyFormatCompressedOdd
}
// 0x02 or 0x03 || 32-byte x coordinate
var b [PubKeyBytesLenCompressed]byte
b[0] = format
p.x.PutBytesUnchecked(b[1:33])
return b[:]
}
// IsEqual compares this public key instance to the one passed, returning true
// if both public keys are equivalent. A public key is equivalent to another,
// if they both have the same X and Y coordinates.
func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool {
return p.x.Equals(&otherPubKey.x) && p.y.Equals(&otherPubKey.y)
}
// AsJacobian converts the public key into a Jacobian point with Z=1 and stores
// the result in the provided result param. This allows the public key to be
// treated a Jacobian point in the secp256k1 group in calculations.
func (p *PublicKey) AsJacobian(result *JacobianPoint) {
result.X.Set(&p.x)
result.Y.Set(&p.y)
result.Z.SetInt(1)
}
// IsOnCurve returns whether or not the public key represents a point on the
// secp256k1 curve.
func (p *PublicKey) IsOnCurve() bool {
return isOnCurve(&p.x, &p.y)
}