UltrafastSecp256k1 3.68.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
address.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_ADDRESS_HPP
2#define SECP256K1_ADDRESS_HPP
3#pragma once
4
5// ============================================================================
6// Bitcoin Address Generation + Encoding for secp256k1
7// ============================================================================
8// Address types:
9// P2PKH -- Pay-to-Public-Key-Hash (1..., legacy, Base58Check)
10// P2WPKH -- Pay-to-Witness-Public-Key-Hash (bc1q..., SegWit v0, Bech32)
11// P2TR -- Pay-to-Taproot (bc1p..., SegWit v1, Bech32m)
12//
13// Encoding:
14// Base58Check -- P2PKH addresses + WIF private keys
15// Bech32 -- SegWit v0 (BIP-173)
16// Bech32m -- SegWit v1+ (BIP-350)
17//
18// BIP-352 Silent Payments:
19// Privacy-preserving addresses. Sender computes unique output from
20// public scan/spend keys; only recipient can detect and spend.
21// ============================================================================
22
23#include <array>
24#include <cstdint>
25#include <cstddef>
26#include <string>
27#include <vector>
28#include <utility>
29#include "secp256k1/scalar.hpp"
30#include "secp256k1/point.hpp"
31
32namespace secp256k1 {
33
34// -- Network ------------------------------------------------------------------
35
36enum class Network : std::uint8_t {
37 Mainnet = 0,
38 Testnet = 1
39};
40
41// -- Base58Check Encoding -----------------------------------------------------
42
43// Encode data with 4-byte SHA256d checksum in Base58
44std::string base58check_encode(const std::uint8_t* data, std::size_t len);
45
46// Decode Base58Check, returns pair of (data, valid)
47std::pair<std::vector<std::uint8_t>, bool>
48base58check_decode(const std::string& encoded);
49
50// -- Bech32 / Bech32m Encoding (BIP-173 / BIP-350) ---------------------------
51
52enum class Bech32Encoding {
53 BECH32, // SegWit v0 (BIP-173)
54 BECH32M // SegWit v1+ (BIP-350)
55};
56
57// Encode a witness program to bech32/bech32m address
58// hrp: "bc" for mainnet, "tb" for testnet
59// witness_version: 0 for P2WPKH, 1 for P2TR
60// witness_program: 20 bytes (v0) or 32 bytes (v1)
61std::string bech32_encode(const std::string& hrp,
62 std::uint8_t witness_version,
63 const std::uint8_t* witness_program,
64 std::size_t prog_len);
65
66// Decode bech32/bech32m address
67// Returns: {hrp, witness_version, witness_program, valid}
69 std::string hrp;
70 int witness_version; // -1 if invalid
71 std::vector<std::uint8_t> witness_program;
72 bool valid;
73};
74Bech32DecodeResult bech32_decode(const std::string& addr);
75
76// -- HASH160 ------------------------------------------------------------------
77
78// HASH160: RIPEMD160 applied to SHA256 digest
79std::array<std::uint8_t, 20> hash160(const std::uint8_t* data, std::size_t len);
80
81// -- Address Derivation -------------------------------------------------------
82
83// P2PKH address from public key (compressed 33 bytes or uncompressed 65 bytes)
84// Returns: "1..." (mainnet) or "m/n..." (testnet)
85std::string address_p2pkh(const fast::Point& pubkey,
87
88// P2WPKH address from public key (native SegWit v0)
89// Returns: "bc1q..." (mainnet) or "tb1q..." (testnet)
90std::string address_p2wpkh(const fast::Point& pubkey,
92
93// P2TR address from x-only public key (Taproot, SegWit v1)
94// Returns: "bc1p..." (mainnet) or "tb1p..." (testnet)
95// If internal_key only (no script tree): uses untwisted key
96std::string address_p2tr(const fast::Point& internal_key,
98
99// P2TR address from x-only output key bytes (32 bytes)
100std::string address_p2tr_raw(const std::array<std::uint8_t, 32>& output_key_x,
102
103// P2SH-P2WPKH address (nested/wrapped SegWit, "3..." on mainnet)
104// Wraps P2WPKH witness program inside P2SH for backward compatibility
105std::string address_p2sh_p2wpkh(const fast::Point& pubkey,
107
108// P2SH address from a 20-byte script hash (generic)
109std::string address_p2sh(const std::array<std::uint8_t, 20>& script_hash,
111
112// P2WSH address from a 32-byte witness script hash (SegWit v0)
113std::string address_p2wsh(const std::array<std::uint8_t, 32>& witness_script_hash,
115
116// -- CashAddr (Bitcoin Cash BIP-0185) -----------------------------------------
117
118// Encode a hash160 as CashAddr address
119// type: 0 = P2PKH, 1 = P2SH
120std::string cashaddr_encode(const std::array<std::uint8_t, 20>& hash,
121 const std::string& prefix,
122 std::uint8_t type = 0);
123
124// CashAddr P2PKH from public key
125std::string address_cashaddr(const fast::Point& pubkey,
126 const std::string& prefix = "bitcoincash");
127
128// -- WIF (Wallet Import Format) -----------------------------------------------
129
130// Encode private key as WIF string
131std::string wif_encode(const fast::Scalar& private_key,
132 bool compressed = true,
134
135// Decode WIF string to private key
136// Returns: {scalar, compressed, network, valid}
143WIFDecodeResult wif_decode(const std::string& wif);
144
145// -- BIP-352 Silent Payments --------------------------------------------------
146
147// Silent payment address: (scan_pubkey, spend_pubkey) pair
151
152 // Encode to sp1q... address (mainnet) or tsp1q... (testnet)
153 std::string encode(Network net = Network::Mainnet) const;
154};
155
156// Generate silent payment address from scan and spend private keys
159 const fast::Scalar& spend_privkey);
160
161// Sender: Compute output public key for a silent payment
162// input_privkeys: sender's input private keys (for ECDH)
163// input_pubkeys: corresponding public keys
164// recipient: recipient's silent payment address
165// k: output index (for multiple outputs to same recipient)
166// Returns: {output_pubkey, output_tweaked_key}
167std::pair<fast::Point, fast::Scalar>
168silent_payment_create_output(const std::vector<fast::Scalar>& input_privkeys,
169 const SilentPaymentAddress& recipient,
170 std::uint32_t k = 0);
171
172// Receiver: Scan transaction to detect silent payment outputs
173// scan_privkey: receiver's scan private key
174// spend_privkey: receiver's spend private key
175// input_pubkeys: all input public keys from the transaction
176// output_pubkeys: all output x-only public keys to check
177// Returns: vector of {output_index, tweaked_privkey} for detected outputs
178std::vector<std::pair<std::uint32_t, fast::Scalar>>
180 const fast::Scalar& spend_privkey,
181 const std::vector<fast::Point>& input_pubkeys,
182 const std::vector<std::array<std::uint8_t, 32>>& output_pubkeys);
183
184// ── Fast batch scanner (wallet-optimised, non-CT) ────────────────────────────
185//
186// For full-blockchain scanning: scan_privkey is constant across millions of txs.
187// This API amortizes four expensive costs:
188// (1) KPlan::from_scalar(scan_privkey): GLV decompose + wNAF — computed ONCE.
189// (2) batch_scalar_mul_fixed_k for Stage 1: shared wNAF loop, 1 field_inv per
190// chunk (chunk_size≈2048). Treats scan as "one execution schedule, N data".
191// (3) batch_to_compressed for Stage 1: single field inversion across all N secrets.
192// (4) batch_x_only_bytes for Stage 2: single field inversion across all N outputs.
193//
194// Compared to N × silent_payment_scan() on i5-14400F (50K txs, 1 thread):
195// silent_payment_scan: ~47K ns/tx (CT Stage 1 + ct::generator_mul per tx)
196// fast_scan_batch: ~23K ns/tx → 2.06× speedup
197//
198// Stage 2 standalone throughput (16T, w=18 table): 1.60 M/s
199// Full pipeline (Stage 1 + Stage 2) at 16T: ~206K tx/s (Stage 1 dominates)
200//
201// Not constant-time: suitable for trusted-environment wallet scanning.
202// For server-side scanning where side-channel matters, use silent_payment_scan().
203
204// One effective input pubkey + its candidate outputs per transaction.
205// a_eff = input_hash × A_sum (caller's responsibility to aggregate inputs).
206// For raw-input aggregation, use ScanTxRaw + compute_a_eff() below.
207struct ScanTx {
208 fast::Point a_eff; // input_hash × A_sum
209 std::vector<std::array<std::uint8_t, 32>> outputs; // x-only output pubkeys to test
210};
211
212// Raw-input variant: caller provides individual input pubkeys per transaction.
213// compute_a_eff() aggregates them into a_eff using Pippenger/Strauss batch MSM
214// (all scalars = 1, so this reduces to batch point addition with one field_inv).
215struct ScanTxRaw {
216 std::vector<fast::Point> input_pubkeys; // all P_j from tx inputs
217 std::array<std::uint8_t, 36> smallest_outpoint; // BIP-352 input hash seed
218 std::vector<std::array<std::uint8_t, 32>> outputs; // x-only output pubkeys
219};
220
221// Aggregate raw inputs into ScanTx.a_eff using batch MSM (scalars all = 1):
222// a_eff = input_hash(outpoint, A_sum) × A_sum
223// where A_sum = Σ input_pubkeys[j]
224// Uses multi_scalar_mul (Strauss GLV + effective-affine) for the summation.
225// Pippenger crossover applies at n_inputs > ~128; Strauss is used for all n < 128.
227
228// One detected match.
229struct ScanMatch {
230 std::uint32_t tx_index; // index into the txs[] vector
231 std::uint32_t output_index; // which output_pubkeys[] entry matched
232 fast::Scalar tweaked_privkey; // spend_privkey + t_k (spendable key)
233};
234
235// Batch scanner: processes txs.size() transactions in one call.
236// Stage 1 uses batch_scalar_mul_fixed_k (shared wNAF schedule, lockstep execution).
237// Stage 2 uses batch_x_only_bytes (one field_inv for all output candidates).
238std::vector<ScanMatch>
239fast_scan_batch(const fast::Scalar& scan_privkey,
240 const fast::Scalar& spend_privkey,
241 const std::vector<ScanTx>& txs);
242
243} // namespace secp256k1
244
245#endif // SECP256K1_ADDRESS_HPP
Bech32DecodeResult bech32_decode(const std::string &addr)
std::string base58check_encode(const std::uint8_t *data, std::size_t len)
std::string address_p2sh(const std::array< std::uint8_t, 20 > &script_hash, Network net=Network::Mainnet)
std::string address_p2tr(const fast::Point &internal_key, Network net=Network::Mainnet)
std::string address_p2wsh(const std::array< std::uint8_t, 32 > &witness_script_hash, Network net=Network::Mainnet)
std::string address_p2tr_raw(const std::array< std::uint8_t, 32 > &output_key_x, Network net=Network::Mainnet)
ScanTx compute_a_eff(const ScanTxRaw &raw)
std::string address_p2sh_p2wpkh(const fast::Point &pubkey, Network net=Network::Mainnet)
std::string address_cashaddr(const fast::Point &pubkey, const std::string &prefix="bitcoincash")
std::pair< fast::Point, fast::Scalar > silent_payment_create_output(const std::vector< fast::Scalar > &input_privkeys, const SilentPaymentAddress &recipient, std::uint32_t k=0)
std::pair< std::vector< std::uint8_t >, bool > base58check_decode(const std::string &encoded)
WIFDecodeResult wif_decode(const std::string &wif)
std::array< std::uint8_t, 20 > hash160(const std::uint8_t *data, std::size_t len)
std::array< std::uint8_t, 32 > witness_script_hash(const std::uint8_t *script, std::size_t script_len) noexcept
std::string address_p2wpkh(const fast::Point &pubkey, Network net=Network::Mainnet)
std::string address_p2pkh(const fast::Point &pubkey, Network net=Network::Mainnet)
std::string bech32_encode(const std::string &hrp, std::uint8_t witness_version, const std::uint8_t *witness_program, std::size_t prog_len)
std::string cashaddr_encode(const std::array< std::uint8_t, 20 > &hash, const std::string &prefix, std::uint8_t type=0)
std::string wif_encode(const fast::Scalar &private_key, bool compressed=true, Network net=Network::Mainnet)
std::vector< std::pair< std::uint32_t, fast::Scalar > > silent_payment_scan(const fast::Scalar &scan_privkey, const fast::Scalar &spend_privkey, const std::vector< fast::Point > &input_pubkeys, const std::vector< std::array< std::uint8_t, 32 > > &output_pubkeys)
std::vector< ScanMatch > fast_scan_batch(const fast::Scalar &scan_privkey, const fast::Scalar &spend_privkey, const std::vector< ScanTx > &txs)
SilentPaymentAddress silent_payment_address(const fast::Scalar &scan_privkey, const fast::Scalar &spend_privkey)
std::vector< std::uint8_t > witness_program
Definition address.hpp:71
fast::Scalar tweaked_privkey
Definition address.hpp:232
std::uint32_t output_index
Definition address.hpp:231
std::uint32_t tx_index
Definition address.hpp:230
std::vector< fast::Point > input_pubkeys
Definition address.hpp:216
std::vector< std::array< std::uint8_t, 32 > > outputs
Definition address.hpp:218
std::array< std::uint8_t, 36 > smallest_outpoint
Definition address.hpp:217
fast::Point a_eff
Definition address.hpp:208
std::vector< std::array< std::uint8_t, 32 > > outputs
Definition address.hpp:209
std::string encode(Network net=Network::Mainnet) const