bip352

package module
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: May 26, 2024 License: MIT Imports: 16 Imported by: 5

README

GOBip352

This library provides the basic functions for working with BIP352. It takes care of the elliptic curve computations and some periphery around creating outputs and scanning. This library is not a full wallet.

Todo

Priority 1
  • Sending vectors passing
  • Receiving vectors passing
  • Include vin checking module (include functionality that allows for checking whether inputs are eligible according to the BIP)
    • should be on par with the reference implementation now
Priority 2
  • Add error logging option
  • Consider using fixed length byte arrays instead of slice, will help with "type-safety" of keys, hashes, compressed, x-only, scalars
  • Standardize errors as types
  • Rename package on GitHub to go-bip352 and import as bip352
  • Benchmark a map of labels against looping over the slice of labels in matching

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	AddressHRPError = errors.New("hrp did not match network")

	DecodingLimitExceeded = errors.New("exceeds BIP0352 recommended 1023 character limit")

	ErrVinsEmpty = errors.New("vins were empty")

	ErrNoEligibleVins = errors.New("no eligible vins")
)
View Source
var NumsH = []byte{80, 146, 155, 116, 193, 160, 73, 84, 183, 139, 75, 96, 53, 233, 122, 94, 7, 138, 90, 15, 40, 236, 150, 213, 71, 191, 238, 154, 206, 128, 58, 192}

NumsH = 0x50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0

Functions

func AddPrivateKeys

func AddPrivateKeys(secKey1, secKey2 [32]byte) [32]byte

func AddPublicKeys

func AddPublicKeys(publicKeyBytes1, publicKeyBytes2 [33]byte) ([33]byte, error)

func ComputeInputHash

func ComputeInputHash(vins []*Vin, publicKeySum [33]byte) ([32]byte, error)

ComputeInputHash computes the input_hash for a transaction as per the specification. vins: does not need to contain public key or secret key, only needs the txid and vout; txid has to be in the normal human-readable format sumPublicKeys: 33 byte compressed public key sum of the inputs for shared derivation https://github.com/josibake/bips/blob/silent-payments-bip/bip-0352.mediawiki#inputs-for-shared-secret-derivation

func ComputeTK

func ComputeTK(sharedSecret [33]byte, k uint32) ([32]byte, error)

func ConvertPointsToPublicKey

func ConvertPointsToPublicKey(x, y *big.Int) (*btcec.PublicKey, error)

func ConvertToFixedLength32

func ConvertToFixedLength32(input []byte) [32]byte

func ConvertToFixedLength33

func ConvertToFixedLength33(input []byte) [33]byte

func CreateAddress

func CreateAddress(scanPubKeyBytes, bMKeyBytes [33]byte, mainnet bool, version uint8) (string, error)

func CreateLabelPublicKey

func CreateLabelPublicKey(labelTweak [32]byte) [33]byte

func CreateLabelTweak

func CreateLabelTweak(scanSecKey [32]byte, m uint32) ([32]byte, error)

func CreateLabeledAddress

func CreateLabeledAddress(scanPubKeyBytes, spendPubKeyBytes [33]byte, mainnet bool, version uint8, scanSecKey [32]byte, m uint32) (string, error)

func CreateLabelledSpendPubKey

func CreateLabelledSpendPubKey(spendPubKey, labelPubKey [33]byte) ([33]byte, error)

CreateLabelledSpendPubKey Returns the labeled spend pub key

B_m = B_spend + label

func CreateOutputPubKey

func CreateOutputPubKey(sharedSecret [33]byte, receiverSpendPubKey [33]byte, k uint32) ([32]byte, error)

CreateOutputPubKey returns 32 byte x-only pubKey

func CreateOutputPubKeyTweak

func CreateOutputPubKeyTweak(sharedSecret [33]byte, receiverSpendPubKey [33]byte, k uint32) ([32]byte, [32]byte, error)

CreateOutputPubKeyTweak same as CreateOutputPubKey but this also returns the tweak of the output and the 33 byte compressed output

func CreateSharedSecret

func CreateSharedSecret(publicComponent [33]byte, secretComponent [32]byte, inputHash *[32]byte) ([33]byte, error)

CreateSharedSecret The public component is dependent on whether this function is called from the sender or receiver side. The input_hash is the same for both sides. The input_hash can be nil if the publicComponent already incorporates the inputHash in case of a tweak as it would be for light clients

For the sender publicComponent is B_scan and secretComponent is a_sum

shared_secret = (a_sum * input_hash) * B_scan [Sender]

For the receiver publicComponent is A_sum and the secretComponent is b_scan

shared_secret = (b_scan * input_hash) * A_sum [Receiver, Full node scenario]

shared_secret = b_scan * A_tweaked [Receiver, Light client scenario]

func DecodeSilentPaymentAddress

func DecodeSilentPaymentAddress(address string, mainnet bool) (string, []byte, uint8, error)

DecodeSilentPaymentAddress Returns: 1. hrp 2. the raw byte data that was encoded 3. the version 4. the error, if one occurs

func DecodeSilentPaymentAddressToKeys

func DecodeSilentPaymentAddressToKeys(address string, mainnet bool) (scanPubKeyBytes, spendPubKeyBytes [33]byte, err error)

func FindSmallestOutpoint

func FindSmallestOutpoint(vins []*Vin) ([]byte, error)

FindSmallestOutpoint txid has to be in the normal human-readable format

func Hash160

func Hash160(data []byte) []byte

Hash160 performs a RIPEMD160(SHA256(data)) hash on the given data

func MultPrivateKeys

func MultPrivateKeys(secKey1, secKey2 [32]byte) [32]byte

func NegatePublicKey

func NegatePublicKey(pk [33]byte) ([33]byte, error)

func NegateSecretKey added in v0.1.6

func NegateSecretKey(secretKey [32]byte) [32]byte

func ParseWitnessScript

func ParseWitnessScript(data []byte) ([][]byte, error)

ParseWitnessScript parses a hex-encoded witness script and returns the actual witness data as a list

func RecursiveAddPrivateKeys

func RecursiveAddPrivateKeys(secretKeys [][32]byte) [32]byte

RecursiveAddPrivateKeys this is a simple addition of given privateKeys Keep in mind that this function does not negate privateKeys this has to be done before calling this function

func ReverseBytes

func ReverseBytes(bytes []byte) []byte

ReverseBytes reverses the byte slice and returns that same byte slice

func ReverseBytesCopy

func ReverseBytesCopy(bytes []byte) []byte

ReverseBytesCopy returns a new reversed byte slice

func SenderCreateOutputs

func SenderCreateOutputs(recipients []*Recipient, vins []*Vin, mainnet bool, checkVins bool) error

SenderCreateOutputs recipients: must include result will be stored in the recipients. vins: has to include the txids, vouts and secretKeys

NOTE: if checkVins is set to true the vins should include the necessary data in order to categorise them i.e. (scriptpubkey andOr witness andOr scriptSig)

func SerU32

func SerU32(num uint32) ([]byte, error)

func SumPublicKeys

func SumPublicKeys(pubKeys [][33]byte) ([33]byte, error)

func TaggedHash

func TaggedHash(tag string, msg []byte) [32]byte

Types

type FoundOutput

type FoundOutput struct {
	Output      [32]byte // x-only pubKey
	SecKeyTweak [32]byte // tweak for the output
	Label       *Label   // the label that was matched if there was a label to match
}

func ReceiverScanTransaction

func ReceiverScanTransaction(scanKey [32]byte, receiverSpendPubKey [33]byte, labels []*Label, txOutputs [][32]byte, publicComponent [33]byte, inputHash *[32]byte) ([]*FoundOutput, error)

ReceiverScanTransaction scanKey: scanning secretKey of the receiver receiverSpendPubKey: spend pubKey of the receiver txOutputs: x-only outputs of the specific transaction labels: existing label public keys as bytes [wallets should always check for the change label] publicComponent: either A_sum or tweaked (A_sum * input_hash) if tweaked inputHash should be nil or the computation will be flawed inputHash: 32 byte can be nil if publicComponent is a tweak and already includes the input_hash

type FullTestCase

type FullTestCase struct {
	Comment string `json:"comment"`
	Sending []struct {
		Given struct {
			Vin []struct {
				Txid        string `json:"txid"`
				Vout        uint32 `json:"vout"`
				ScriptSig   string `json:"scriptSig"`
				Txinwitness string `json:"txinwitness"`
				Prevout     struct {
					ScriptPubKey struct {
						Hex  string `json:"hex"`
						Type string `json:"type"`
					} `json:"scriptPubKey"`
				} `json:"prevout"`
				PrivateKey string `json:"private_key"`
			} `json:"vin"`
			Recipients []string `json:"recipients"`
		} `json:"given"`
		Expected struct {
			Outputs []string `json:"outputs"`
		} `json:"expected"`
	} `json:"sending"`
	Receiving []struct {
		Given struct {
			Vin         []VinReceiveTestCase `json:"vin"`
			Outputs     []string             `json:"outputs"`
			KeyMaterial struct {
				SpendPrivKey string `json:"spend_priv_key"`
				ScanPrivKey  string `json:"scan_priv_key"`
			} `json:"key_material"`
			Labels []uint32 `json:"labels"`
		} `json:"given"`
		Expected struct {
			Addresses []string `json:"addresses"`
			Outputs   []struct {
				PubKey       string `json:"pub_key"`
				PrivKeyTweak string `json:"priv_key_tweak"`
				Signature    string `json:"signature"`
			} `json:"outputs"`
			Tweak string `json:"tweak"`
		} `json:"expected"`
	} `json:"receiving"`
}

func LoadFullCaseData

func LoadFullCaseData(t *testing.T) ([]FullTestCase, error)

type Label

type Label struct {
	PubKey  [33]byte `json:"pub_key"` // compressed pubKey of the label
	Tweak   [32]byte `json:"tweak"`   // tweak/secKey to produce the labels pubKey
	Address string   `json:"address"` // todo the corresponding address for the label, still needs a good API for instantiating with this data
	M       uint32   `json:"m"`
}

func CreateLabel

func CreateLabel(scanSecKey [32]byte, m uint32) (Label, error)

func MatchLabels

func MatchLabels(txOutput, pk [33]byte, labels []*Label) (*Label, error)

type Recipient

type Recipient struct {
	SilentPaymentAddress string
	ScanPubKey           *btcec.PublicKey
	SpendPubKey          *btcec.PublicKey
	Output               [32]byte // the resulting taproot x-only output
	Amount               uint64
	Data                 map[string]any // in order to allocate data to a recipient that needs to be known after handling
}

type TypeUTXO

type TypeUTXO int8
const (
	Unknown TypeUTXO = iota - 1
	P2TR
	P2WPKH
	P2PKH
	P2SH
)

func ExtractPubKey

func ExtractPubKey(vin *Vin) ([]byte, TypeUTXO)

ExtractPubKey this routine is not optimised yet and might not be able to parse all edge cases. NOTE: Does not throw any errors, check the utxo type or the byte slice to see whether a public key could be extracted

type Vin

type Vin struct {
	Txid         [32]byte  // txid has to be in the normal human-readable format
	Vout         uint32    // output index of the input
	Amount       uint64    // value of the utxo in satoshi (100_000_000 sat = 1 Bitcoin)
	PublicKey    *[33]byte // 33 byte compressed public key or 32 byte taproot x-only key
	SecretKey    *[32]byte // 32 byte secret key
	Taproot      bool      // indicates whether input is taproot or not. taproot outputs have to be even hence the flag has to be set, so we can check for negation
	Witness      [][]byte  // witness data for the input
	ScriptPubKey []byte    // the scriptPubKey of the input
	ScriptSig    []byte    // used for p2pkh
}

func ExtractEligibleVins

func ExtractEligibleVins(vins []*Vin) ([]*Vin, error)

ExtractEligibleVins returns a slice of vins which are eligible as inputs for the shared derivation NOTE: Returns a deep copy of the vins this will also set the taproot bool flag in the vins of the new returned slice

func (*Vin) DeepCopy

func (v *Vin) DeepCopy() *Vin

func (Vin) Hash

func (v Vin) Hash() *chainhash.Hash

func (Vin) Index

func (v Vin) Index() uint32

func (Vin) NumConfs

func (v Vin) NumConfs() int64

NumConfs not implemented

func (Vin) PkScript

func (v Vin) PkScript() []byte

func (Vin) Value

func (v Vin) Value() btcutil.Amount

func (Vin) ValueAge

func (v Vin) ValueAge() int64

ValueAge not implemented

type VinReceiveTestCase

type VinReceiveTestCase struct {
	Txid        string `json:"txid"`
	Vout        uint32 `json:"vout"`
	ScriptSig   string `json:"scriptSig"`
	Txinwitness string `json:"txinwitness"`
	Prevout     struct {
		ScriptPubKey struct {
			Hex  string `json:"hex"`
			Type string `json:"type"`
		} `json:"scriptPubKey"`
	} `json:"prevout"`
}

Jump to

Keyboard shortcuts

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