New features: - ECDSA sign/verify with RFC 6979 deterministic nonce (HMAC-SHA256) - Schnorr BIP-340 sign/verify with tagged hashing & x-only pubkeys - Self-contained SHA-256 (header-only, no deps) - Scalar::inverse (Fermat's theorem), negate(), is_even() Build & tooling: - GitHub Actions CI: Linux (gcc-13/clang-17), Windows (MSVC), macOS - .clang-format + .editorconfig for code style - cmake/version.hpp.in auto-generated version header - CMake VERSION 1.0.0 -> 2.2.0 - Fixed install(TARGETS/EXPORT) — moved to cpu/ where target is defined - MSVC compatibility via SECP256K1_NO_INT128 generator expression - Fixed BUILD_TESTING standalone build Testing & benchmarks: - test_ecdsa_schnorr: 22 checks (SHA-256 NIST, inverse, ECDSA, Schnorr) - bench_ct: CT vs fast comparison for all primitives - 3 libFuzzer harnesses (field, scalar, point) - Desktop CLI example (examples/basic_usage) All 5 CTest targets pass (22/22 ECDSA+Schnorr checks).
96 lines
3.5 KiB
C++
96 lines
3.5 KiB
C++
// ============================================================================
|
|
// UltrafastSecp256k1 — Desktop Quick-Start Example
|
|
// ============================================================================
|
|
// Demonstrates basic usage: key generation, point operations, serialization.
|
|
// Build: cmake --build <build_dir> --target example_basic_usage
|
|
// ============================================================================
|
|
|
|
#include <chrono>
|
|
#include <cstdio>
|
|
#include <cstdint>
|
|
|
|
#include "secp256k1/field.hpp"
|
|
#include "secp256k1/scalar.hpp"
|
|
#include "secp256k1/point.hpp"
|
|
#include "secp256k1/selftest.hpp"
|
|
|
|
using namespace secp256k1::fast;
|
|
|
|
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
static void print_hex(const char* label, const uint8_t* data, size_t len) {
|
|
printf(" %s: ", label);
|
|
for (size_t i = 0; i < len; ++i) printf("%02x", data[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
static double now_us() {
|
|
using clk = std::chrono::high_resolution_clock;
|
|
static auto t0 = clk::now();
|
|
return std::chrono::duration<double, std::micro>(clk::now() - t0).count();
|
|
}
|
|
|
|
// ── main ─────────────────────────────────────────────────────────────────────
|
|
|
|
int main() {
|
|
printf("=== UltrafastSecp256k1 — Basic Usage Example ===\n\n");
|
|
|
|
// 1) Self-test
|
|
printf("[1] Running self-test...\n");
|
|
bool ok = Selftest(false);
|
|
printf(" Result: %s\n\n", ok ? "PASS" : "FAIL");
|
|
if (!ok) return 1;
|
|
|
|
// 2) Create a private key (scalar)
|
|
printf("[2] Key generation\n");
|
|
auto priv = Scalar::from_hex(
|
|
"e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35");
|
|
auto pub = Point::generator().scalar_mul(priv);
|
|
|
|
auto compressed = pub.to_compressed();
|
|
auto uncompressed = pub.to_uncompressed();
|
|
printf(" Private key : %s\n", priv.to_hex().c_str());
|
|
print_hex("Public (comp)", compressed.data(), compressed.size());
|
|
print_hex("Public (uncomp)", uncompressed.data(), uncompressed.size());
|
|
printf("\n");
|
|
|
|
// 3) Point arithmetic
|
|
printf("[3] Point arithmetic\n");
|
|
auto G = Point::generator();
|
|
auto G2 = G.dbl();
|
|
auto G3 = G2.add(G);
|
|
printf(" G x = %s\n", G.x().to_hex().c_str());
|
|
printf(" 2G x = %s\n", G2.x().to_hex().c_str());
|
|
printf(" 3G x = %s\n", G3.x().to_hex().c_str());
|
|
printf("\n");
|
|
|
|
// 4) Scalar arithmetic
|
|
printf("[4] Scalar arithmetic\n");
|
|
auto a = Scalar::from_uint64(7);
|
|
auto b = Scalar::from_uint64(13);
|
|
auto c = a * b;
|
|
printf(" 7 * 13 mod n = %s\n", c.to_hex().c_str());
|
|
printf(" Expected 91 = ...5b (last byte)\n\n");
|
|
|
|
// 5) Micro-benchmark: scalar_mul(k, G)
|
|
printf("[5] Benchmark: k * G (1000 iterations)\n");
|
|
constexpr int ITERS = 1000;
|
|
auto k = Scalar::from_hex(
|
|
"0000000000000000000000000000000000000000000000000000000000000001");
|
|
volatile uint8_t sink = 0;
|
|
|
|
double t0 = now_us();
|
|
for (int i = 0; i < ITERS; ++i) {
|
|
auto P = G.scalar_mul(k);
|
|
sink ^= P.to_compressed()[0];
|
|
k += Scalar::one();
|
|
}
|
|
double elapsed = now_us() - t0;
|
|
printf(" Total : %.1f ms\n", elapsed / 1000.0);
|
|
printf(" Per op: %.1f us\n", elapsed / ITERS);
|
|
printf(" (sink = 0x%02x)\n\n", (unsigned)sink);
|
|
|
|
printf("=== Done ===\n");
|
|
return 0;
|
|
}
|