Skip to content
Snippets Groups Projects
Commit 82d2b347 authored by Yordan Kinkov's avatar Yordan Kinkov
Browse files

Add JWKS simple service for development

parent caef5b28
No related tags found
No related merge requests found
Showing
with 5219 additions and 0 deletions
......@@ -181,3 +181,14 @@ services:
- "8222:8222"
- "6222:6222"
- "4222:4222"
jwks:
container_name: jwks
build:
dockerfile: Dockerfile
context: jwks/
volumes:
- ./jwks:/jwks:rw
ports:
- "8090:8080"
FROM golang:1.19
WORKDIR /jwks
COPY . .
RUN ls -la
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "./jwks"]
\ No newline at end of file
# JWKS app
The JWKS application exposes an API for issuing JSON Web Token (JWT) and listing JSON Web Key Set (JWKS) in
order to be used for verification of this JWT. **This application must be used only for development purpose!**
### Usage
You can obtain a JWT on the `/token` endpoint. If the application is run in the workspace docker-compose environment,
the endpoint is `localhost:8090/token`.
The JWKS endpoint is `/key`. When you pass the endpoint to a service inside your local docker-compose environment, you
should pass `http://jwks:8080/key` in the environment of the specific service. On you host machine, the endpoint is
`http://localhost:8090/key`.
### License
[Apache 2.0 license](LICENSE)
\ No newline at end of file
module gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/workspace/jwks
go 1.19
require (
github.com/gorilla/mux v1.8.0
github.com/lestrrat-go/jwx/v2 v2.0.6
)
require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.0 // indirect
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
)
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.0.6 h1:RlyYNLV892Ed7+FTfj1ROoF6x7WxL965PGTHso/60G0=
github.com/lestrrat-go/jwx/v2 v2.0.6/go.mod h1:aVrGuwEr3cp2Prw6TtQvr8sQxe+84gruID5C9TxT64Q=
github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
jwks/jwks 0 → 100755
File added
package main
import (
"crypto/rand"
"crypto/rsa"
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jwt"
)
var (
publicKey jwk.RSAPublicKey
privateKey jwk.RSAPrivateKey
)
func main() {
initkeys()
router := mux.NewRouter()
router.HandleFunc("/key", key)
router.HandleFunc("/token", token)
log.Fatal(http.ListenAndServe(":8080", router))
}
func initkeys() {
rawprivkey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("failed to create raw private key: %v", err)
}
privkey, err := jwk.FromRaw(rawprivkey)
if err != nil {
log.Fatalf("failed to create private key: %v", err)
}
pubkey, err := privkey.PublicKey()
if err != nil {
log.Fatalf("failed to create public key: %v", err)
}
privk, ok := privkey.(jwk.RSAPrivateKey)
if !ok {
log.Fatalf("cannot cast private key to RSA private key")
}
privateKey = privk
if err := privateKey.Set(jwk.KeyIDKey, "key1"); err != nil {
log.Fatalf("cannot set kid value to private key: %v", err)
}
pubk, ok := pubkey.(jwk.RSAPublicKey)
if !ok {
log.Fatalf("cannot cast public key to RSA public key")
}
publicKey = pubk
}
func key(w http.ResponseWriter, r *http.Request) {
set := jwk.NewSet()
var raw interface{}
err := publicKey.Raw(&raw)
if err != nil {
log.Fatalf("error getting public key: %v", err)
}
key, err := jwk.FromRaw(raw)
if err != nil {
log.Fatalf("error getting public key: %v", err)
}
err = key.Set(jwk.AlgorithmKey, jwa.RS256)
if err != nil {
log.Fatalf("error getting public key: %v", err)
}
err = key.Set("kid", "key1")
if err != nil {
log.Fatalf("error getting public key: %v", err)
}
err = set.AddKey(key)
if err != nil {
log.Fatalf("error getting public key: %v", err)
}
json.NewEncoder(w).Encode(set)
}
func token(w http.ResponseWriter, r *http.Request) {
token, err := jwt.NewBuilder().
Claim(`claim1`, `value1`).
Claim(`claim2`, `value2`).
Issuer(`https://example.com`).
Subject("terminator").
Audience([]string{"skynet"}).
Build()
if err != nil {
log.Fatalf("failed to build token: %s\n", err)
}
signed, err := jwt.Sign(token, jwt.WithKey(jwa.RS256, privateKey))
if err != nil {
log.Fatalf("failed to sign token: %s\n", err)
}
json.NewEncoder(w).Encode(string(signed))
}
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.
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.
This diff is collapsed.
// 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
// Copyright (c) 2015 The btcsuite developers
// Copyright (c) 2015-2016 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 securily 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[:]
}
// 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
}
// 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}
}
This diff is collapsed.
// 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
}
}()
This diff is collapsed.
This diff is collapsed.
// 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
import (
csprng "crypto/rand"
)
// 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.
//
// Note that this means passing a slice with more than 32 bytes is truncated and
// that truncated value is reduced modulo N. It is up to the caller to either
// provide a value in the appropriate range or choose to accept the described
// behavior.
//
// Typically callers should simply make use of GeneratePrivateKey when creating
// private keys which properly handles generation of appropriate values.
func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey {
var privKey PrivateKey
privKey.Key.SetByteSlice(privKeyBytes)
return &privKey
}
// GeneratePrivateKey generates and returns a new cryptographically secure
// private key that is suitable for use with secp256k1.
func GeneratePrivateKey() (*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 := csprng.Read(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
}
// 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[:]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment