secp256k1

package module
v8.0.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2022 License: ISC Imports: 21 Imported by: 5

README

secp256k1

Build Status ISC License GoDoc

Package dcrec implements elliptic curve cryptography needed for working with Decred (secp256k1 only for now). It is designed so that it may be used with the standard crypto/ecdsa packages provided with go. A comprehensive suite of test is provided to ensure proper functionality. Package dcrec was originally based on work from ThePiachu which is licensed under the same terms as Go, but it has signficantly diverged since then. The Decred developers original is licensed under the liberal ISC license.

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 secp256k1 elliptic curve cryptography.

Installation and Updating

$ go get -u github.com/Decred-Next/dcrnd/dcrec/v8

Examples

  • Sign Message Demonstrates signing a message with a secp256k1 private key that is first parsed form raw bytes and serializing the generated signature.

  • Verify Signature Demonstrates verifying a secp256k1 signature against a public key that is first parsed from raw bytes. The signature is also parsed from raw bytes.

  • Encryption Demonstrates encrypting a message for a public key that is first parsed from raw bytes, then decrypting it using the corresponding private key.

  • Decryption Demonstrates decrypting a message using a private key that is first parsed from raw bytes.

License

Package dcrec is licensed under the copyfree ISC License except for dcrec.go and dcrec_test.go which is under the same license as Go.

Documentation

Overview

Package secp256k1 implements support for the elliptic curves needed for Decred.

Decred uses elliptic curve cryptography using koblitz curves (specifically secp256k1) for cryptographic functions. See https://www.secg.org/sec2-v2.pdf for details on the standard.

This package provides the data structures and functions implementing the crypto/elliptic Curve interface in order to permit using these curves with the standard crypto/ecdsa package provided with go. Helper functionality is provided to parse signatures and public keys from standard formats. It was designed for use with dcrd, but should be general enough for other uses of elliptic curve crypto. It was originally based on some initial work by ThePiachu, but has significantly diverged since then.

Example (DecryptMessage)

This example demonstrates decrypting a message using a private key that is first parsed from raw bytes.

// Decode the hex-encoded private key.
pkBytes, err := hex.DecodeString("a11b0a4e1a132305652ee7a8eb7848f6ad" +
	"5ea381e3ce20a2c086a2e388230811")
if err != nil {
	fmt.Println(err)
	return
}
privKey := secp256k1.PrivKeyFromBytes(pkBytes)

ciphertext, err := hex.DecodeString("35f644fbfb208bc71e57684c3c8b437402ca" +
	"002047a2f1b38aa1a8f1d5121778378414f708fe13ebf7b4a7bb74407288c1958969" +
	"00207cf4ac6057406e40f79961c973309a892732ae7a74ee96cd89823913b8b8d650" +
	"a44166dc61ea1c419d47077b748a9c06b8d57af72deb2819d98a9d503efc59fc8307" +
	"d14174f8b83354fac3ff56075162")
if err != nil {
	fmt.Println(err)
	return
}

// Try decrypting the message.
plaintext, err := secp256k1.Decrypt(privKey, ciphertext)
if err != nil {
	fmt.Println(err)
	return
}

fmt.Println(string(plaintext))
Output:

test message
Example (EncryptMessage)

This example demonstrates encrypting a message for a public key that is first parsed from raw bytes, then decrypting it using the corresponding private key.

// Decode the hex-encoded pubkey of the recipient.
pubKeyBytes, err := hex.DecodeString("04115c42e757b2efb7671c578530ec191a1" +
	"359381e6a71127a9d37c486fd30dae57e76dc58f693bd7e7010358ce6b165e483a29" +
	"21010db67ac11b1b51b651953d2") // uncompressed pubkey
if err != nil {
	fmt.Println(err)
	return
}
pubKey, err := secp256k1.ParsePubKey(pubKeyBytes)
if err != nil {
	fmt.Println(err)
	return
}

// Encrypt a message decryptable by the private key corresponding to pubKey
message := "test message"
ciphertext, err := secp256k1.Encrypt(pubKey, []byte(message))
if err != nil {
	fmt.Println(err)
	return
}

// Decode the hex-encoded private key.
pkBytes, err := hex.DecodeString("a11b0a4e1a132305652ee7a8eb7848f6ad" +
	"5ea381e3ce20a2c086a2e388230811")
if err != nil {
	fmt.Println(err)
	return
}
privKey := secp256k1.PrivKeyFromBytes(pkBytes)

// Try decrypting and verify if it's the same message.
plaintext, err := secp256k1.Decrypt(privKey, ciphertext)
if err != nil {
	fmt.Println(err)
	return
}

fmt.Println(string(plaintext))
Output:

test message
Example (SignMessage)

This example demonstrates signing a message with a secp256k1 private key that is first parsed form raw bytes and serializing the generated signature.

// Decode a hex-encoded private key.
pkBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2d4f87" +
	"20ee63e502ee2869afab7de234b80c")
if err != nil {
	fmt.Println(err)
	return
}
privKey := secp256k1.PrivKeyFromBytes(pkBytes)

// Sign a message using the private key.
message := "test message"
messageHash := chainhash.HashB([]byte(message))
signature := privKey.Sign(messageHash)

// Serialize and display the signature.
fmt.Printf("Serialized Signature: %x\n", signature.Serialize())

// Verify the signature for the message using the public key.
pubKey := privKey.PubKey()
verified := signature.Verify(messageHash, pubKey)
fmt.Printf("Signature Verified? %v\n", verified)
Output:

Serialized Signature: 3045022100fcc0a8768cfbcefcf2cadd7cfb0fb18ed08dd2e2ae84bef1a474a3d351b26f0302200fc1a350b45f46fa00101391302818d748c2b22615511a3ffd5bb638bd777207
Signature Verified? true
Example (VerifySignature)

This example demonstrates verifying a secp256k1 signature against a public key that is first parsed from raw bytes. The signature is also parsed from raw bytes.

// Decode hex-encoded serialized public key.
pubKeyBytes, err := hex.DecodeString("02a673638cb9587cb68ea08dbef685c" +
	"6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5")
if err != nil {
	fmt.Println(err)
	return
}
pubKey, err := secp256k1.ParsePubKey(pubKeyBytes)
if err != nil {
	fmt.Println(err)
	return
}

// Decode hex-encoded serialized signature.
sigBytes, err := hex.DecodeString("3045022100fcc0a8768cfbcefcf2cadd7cfb0" +
	"fb18ed08dd2e2ae84bef1a474a3d351b26f0302200fc1a350b45f46fa0010139130" +
	"2818d748c2b22615511a3ffd5bb638bd777207")

if err != nil {
	fmt.Println(err)
	return
}
signature, err := secp256k1.ParseDERSignature(sigBytes)
if err != nil {
	fmt.Println(err)
	return
}

// Verify the signature for the message using the public key.
message := "test message"
messageHash := chainhash.HashB([]byte(message))
verified := signature.Verify(messageHash, pubKey)
fmt.Println("Signature Verified?", verified)
Output:

Signature Verified? true

Index

Examples

Constants

View Source
const (
	PubKeyBytesLenCompressed   = 33
	PubKeyBytesLenUncompressed = 65
)

These constants define the lengths of serialized public keys.

View Source
const PrivKeyBytesLen = 32

PrivKeyBytesLen defines the length in bytes of a serialized private key.

Variables

View Source
var (
	// ErrInvalidMAC occurs when Message Authentication Check (MAC) fails
	// during decryption. This happens because of either invalid private key or
	// corrupt ciphertext.
	ErrInvalidMAC = errors.New("invalid mac hash")
)

Functions

func Decrypt

func Decrypt(priv *PrivateKey, in []byte) ([]byte, error)

Decrypt decrypts data that was encrypted using the Encrypt function.

func Encrypt

func Encrypt(pubkey *PublicKey, in []byte) ([]byte, error)

Encrypt encrypts data for the target public key using AES-256-CBC. It also generates a private key (the pubkey of which is also in the output). The only supported curve is secp256k1. The `structure' that it encodes everything into is:

struct {
	// Initialization Vector used for AES-256-CBC
	IV [16]byte
	// Public Key: curve(2) + len_of_pubkeyX(2) + pubkeyX +
	// len_of_pubkeyY(2) + pubkeyY (curve = 714)
	PublicKey [70]byte
	// Cipher text
	Data []byte
	// HMAC-SHA-256 Message Authentication Code
	HMAC [32]byte
}

The primary aim is to ensure byte compatibility with Pyelliptic. Also, refer to section 5.8.1 of ANSI X9.63 for rationale on this format.

func GenerateSharedSecret

func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte

GenerateSharedSecret generates a shared secret based on a private key and a public key using Diffie-Hellman key exchange (ECDH) (RFC 4753). RFC5903 Section 9 states we should only return x.

func NonceRFC6979

func NonceRFC6979(privKey *big.Int, hash []byte, extra []byte, version []byte, extraIterations uint32) *big.Int

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 SignCompact

func SignCompact(key *PrivateKey, hash []byte, isCompressedKey bool) ([]byte, error)

SignCompact produces a compact signature of the data in hash with the given private key on the secp256k1 curve. The isCompressed parameter should be used to detail if the given signature should reference a compressed public key or not. If successful the bytes of the compact signature will be returned in the format: <(byte of 27+public key solution)+4 if compressed >< padded bytes for signature R><padded bytes for signature S> where the R and S parameters are padded up to the bitlength of the curve.

Types

type CurveParams

type CurveParams struct {
	*elliptic.CurveParams

	H int // cofactor of the curve.
	// contains filtered or unexported fields
}

CurveParams contains the parameters for the secp256k1 curve.

func Params

func Params() *CurveParams

Params returns the secp256k1 curve parameters for convenience.

type KoblitzCurve

type KoblitzCurve struct {
	*CurveParams
	// contains filtered or unexported fields
}

KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve interface from crypto/elliptic.

func S256

func S256() *KoblitzCurve

S256 returns a Curve which implements secp256k1.

func (*KoblitzCurve) Add

func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int)

Add returns the sum of (x1,y1) and (x2,y2).

This is part of the elliptic.Curve interface implementation.

func (*KoblitzCurve) Double

func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int)

Double returns 2*(x1,y1).

This is part of the elliptic.Curve interface implementation.

func (*KoblitzCurve) IsOnCurve

func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool

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 (*KoblitzCurve) Params

func (curve *KoblitzCurve) Params() *elliptic.CurveParams

Params returns the parameters for the curve.

This is part of the elliptic.Curve interface implementation.

func (*KoblitzCurve) ScalarBaseMult

func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int)

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 (*KoblitzCurve) ScalarMult

func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int)

ScalarMult returns k*(Bx, By) where k is a big endian integer.

This is part of the elliptic.Curve interface implementation.

type PrivateKey

type PrivateKey struct {
	D *big.Int
}

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.

func GeneratePrivateKey

func GeneratePrivateKey() (*PrivateKey, error)

GeneratePrivateKey returns a private key that is suitable for use with secp256k1.

func NewPrivateKey

func NewPrivateKey(d *big.Int) *PrivateKey

NewPrivateKey instantiates a new private key from a scalar encoded as a big integer.

func PrivKeyFromBytes

func PrivKeyFromBytes(pk []byte) *PrivateKey

PrivKeyFromBytes returns a private and public key for `curve' based on the private key passed as an argument as a byte slice.

func (*PrivateKey) PubKey

func (p *PrivateKey) PubKey() *PublicKey

PubKey computes and returns the public key corresponding to this private key. PubKey returns the PublicKey corresponding to this private key.

func (PrivateKey) Serialize

func (p PrivateKey) Serialize() []byte

Serialize returns the private key as a big-endian binary-encoded number, padded to a length of 32 bytes.

func (*PrivateKey) Sign

func (p *PrivateKey) Sign(hash []byte) *Signature

Sign generates an ECDSA signature for the provided hash (which should be the result of hashing a larger message) using the private key. Produced signature is deterministic (same message and same key yield the same signature) and canonical in accordance with RFC6979 and BIP0062.

func (*PrivateKey) ToECDSA

func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey

ToECDSA returns the private key as a *ecdsa.PrivateKey.

type PublicKey

type PublicKey struct {
	X *big.Int
	Y *big.Int
}

PublicKey provides facilities for efficiently working with secp256k1 private keys within this package and includes functions to serialize in both uncompressed and compressed SEC (Standards for Efficient Cryptography) formats.

func NewPublicKey

func NewPublicKey(x *big.Int, y *big.Int) *PublicKey

NewPublicKey instantiates a new public key with the given X,Y coordinates.

func ParsePubKey

func ParsePubKey(pubKeyStr []byte) (key *PublicKey, err error)

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 RecoverCompact

func RecoverCompact(signature, hash []byte) (*PublicKey, bool, error)

RecoverCompact attempts to recover the secp256k1 public key from the provided 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 (*PublicKey) IsEqual

func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool

IsEqual compares this PublicKey instance to the one passed, returning true if both PublicKeys are equivalent. A PublicKey is equivalent to another, if they both have the same X and Y coordinate.

func (PublicKey) SerializeCompressed

func (p PublicKey) SerializeCompressed() []byte

SerializeCompressed serializes a public key in a 33-byte compressed format.

func (PublicKey) SerializeUncompressed

func (p PublicKey) SerializeUncompressed() []byte

SerializeUncompressed serializes a public key in a 65-byte uncompressed format.

func (PublicKey) ToECDSA

func (p PublicKey) ToECDSA() *ecdsa.PublicKey

ToECDSA returns the public key as a *ecdsa.PublicKey.

type Signature

type Signature struct {
	R *big.Int
	S *big.Int
}

Signature is a type representing an ecdsa signature.

func NewSignature

func NewSignature(r, s *big.Int) *Signature

NewSignature instantiates a new signature given some R,S values.

func ParseDERSignature

func ParseDERSignature(sigStr []byte) (*Signature, error)

ParseDERSignature parses a signature in the Distinguished Encoding Rules (DER) format of the ASN.1 spec into a Signature type. If parsing according to the less strict BER format is needed, use ParseSignature.

func ParseSignature

func ParseSignature(sigStr []byte) (*Signature, error)

ParseSignature parses a signature in the Basic Encoding Rules (BER) format into a Signature type, performing some basic sanity checks. If parsing according to the more strict DER format is needed, use ParseDERSignature.

func (*Signature) IsEqual

func (sig *Signature) IsEqual(otherSig *Signature) bool

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 (*Signature) Serialize

func (sig *Signature) Serialize() []byte

Serialize returns the ECDSA signature in the more strict DER format. Note that the serialized bytes returned do not include the appended hash type used in Decred signature scripts.

0x30 <length> 0x02 <length r> r 0x02 <length s> s

func (*Signature) Verify

func (sig *Signature) Verify(hash []byte, pubKey *PublicKey) bool

Verify returns whether or not the signature is valid for the provided hash and secp256k1 public key.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL