* fix: CUDA RIPEMD160 r2 table + ECDH y-parity + GPU-side conversion - hash160.cuh: fix transposed r2[46..47] (was 13,4 -> correct 4,13) - ecdh.cuh: compute y-parity for SHA-256(02/03||x) to match CPU ecdh_compute - gpu_backend_cuda.cu: GPU-side Jacobian<->compressed conversion via batch_jac_to_compressed_kernel and batch_compressed_to_jac_kernel; fix bytes_to_scalar/bytes_to_field byte order; add msm_reduce_and_compress_kernel for GPU-side MSM accumulation; remove dead host-side FieldElement code - gpu/CMakeLists.txt: remove gpu_backend_cuda_host.cpp - bindings/rust: add hex dev-dep, fix abi_version() call in smoke test - bindings/nodejs: add koffi-based smoke test (Node 22 compatible) GPU test results: 154 passed, 0 failed gpu_abi_gate: 44/44 gpu_ops_equivalence: 55/55 gpu_host_api_negative: 55/55 Binding tests: Rust (cargo test): 13/13 Node.js (koffi): 12/12 * examples: add 6-language example suite (C, Python, Rust, Node.js, Go, Java) Comprehensive CPU + GPU examples for all supported binding languages: - C: Direct C ABI calls, 16 demo sections (CPU + GPU) - Python: ctypes + Ufsecp wrapper, 14 sections (CPU + GPU) - Rust: Safe ufsecp crate wrapper, 9 sections (CPU only) - Node.js: koffi FFI, 12 sections (CPU + GPU) - Go: Pure cgo, 14 sections (CPU + GPU) - Java: JNA FFI, 14 sections (CPU + GPU) Each example covers: key generation, ECDSA (sign/verify/recover/DER), Schnorr (BIP-340), ECDH, hashing (SHA-256, Hash160), Bitcoin addresses (P2PKH, P2WPKH, P2TR), WIF encoding, BIP-32 HD derivation, and Taproot. GPU examples demonstrate: backend discovery, batch key generation, batch ECDSA verify, batch Hash160, and multi-scalar multiplication. All 6 examples tested and verified against RTX 5060 Ti (CUDA + OpenCL). * examples: add GPU+Pedersen to all 6 languages, expand README - Rust: add GPU sections [10]-[15] + Pedersen, add GPU+Pedersen FFI to ufsecp-sys - Node.js: add BIP-32, Taproot, Pedersen sections [8]-[10], renumber GPU [11]-[15] - Python: add Pedersen section [10] via direct ctypes - Go: add Pedersen section [10] via cgo - Java: add Pedersen JNA declarations + section [10] - Rust safe wrapper: add Context::as_ptr() for GPU FFI access - examples/README.md: comprehensive rewrite with all 6 languages, build/run instructions, feature coverage matrix, embedded platforms, troubleshooting - README.md: add Highlights, Performance, Architecture stack diagram, Hardware Compatibility table (16 platforms), Embedded Targets, Examples index, Use Cases section; expand Architecture with bindings + source tree All 6 examples tested: C 16/16, Rust 15/15, Python 15/15, Node.js 15/15, Go 15/15, Java 15/15 -- all sections pass including GPU operations. * docs: fix GPU backend maturity labels, add docs links, clean repo hygiene - .gitignore: add rules for example build artifacts (binaries, node_modules, target/, Cargo.lock, package-lock.json, .class files) - README.md: fix GPU overclaims -- OpenCL is partial (4/6 ops), Metal is experimental (discovery only); add GPU API, Validation Matrix, Feature Maturity, Supported Guarantees, Examples to Documentation table - FEATURE_MATURITY.md: fix contradictions -- ECDSA/Schnorr verify GPU column corrected from 'all 3' to 'CUDA' (OpenCL UNSUPPORTED per ufsecp_gpu.h); BIP-32 HD GPU corrected from 'all 3' to '-' (no GPU C ABI path) - GPU_VALIDATION_MATRIX.md: add CI and Local Verification table documenting that CUDA/OpenCL tests pass locally (RTX 5060 Ti), GH Actions lacks GPU runners; all 4 GPU C ABI tests (gpu_abi_gate, gpu_ops_equivalence, gpu_host_api_negative, gpu_backend_matrix) confirmed in ctest matrix (49 total) and pass * fix: Metal device index validation + canonical GPU audit presets - Metal backend: reject out-of-range device_index in init() before creating MetalRuntime (fixes gpu_host_api_negative on macOS CI) - CMakePresets.json: add cuda-audit, cuda-audit-5060ti configure/build presets and testPresets for reproducible 49-test GPU verification - docs/BUILDING.md: document canonical GPU audit build path - docs/LOCAL_CI.md: add GPU proof-path quick-reference - docs/README.md: update docs index entry --------- Co-authored-by: shrec <shrec@users.noreply.github.com>
390 lines
18 KiB
Java
390 lines
18 KiB
Java
/**
|
|
* UltrafastSecp256k1 -- Java Example (CPU + GPU)
|
|
*
|
|
* Demonstrates direct JNA FFI to the ufsecp C ABI: key ops, ECDSA, Schnorr,
|
|
* ECDH, hashing, Bitcoin addresses, and GPU batch operations.
|
|
*
|
|
* Build & Run:
|
|
* # Download jna.jar from Maven Central (or use the one in this directory):
|
|
* # https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.14.0/jna-5.14.0.jar
|
|
*
|
|
* javac -cp jna.jar Example.java
|
|
* java -cp .:jna.jar \
|
|
* -Djna.library.path=../../build-linux/include/ufsecp \
|
|
* Example
|
|
*/
|
|
|
|
import com.sun.jna.*;
|
|
import com.sun.jna.ptr.*;
|
|
import java.util.Arrays;
|
|
import java.util.HexFormat;
|
|
|
|
import com.sun.jna.NativeLong;
|
|
|
|
public class Example {
|
|
|
|
// ── Native Library Interface ──────────────────────────────────────
|
|
|
|
public interface Ufsecp extends Library {
|
|
Ufsecp INSTANCE = Native.load("ufsecp", Ufsecp.class);
|
|
|
|
// Context
|
|
int ufsecp_ctx_create(PointerByReference ctx);
|
|
void ufsecp_ctx_destroy(Pointer ctx);
|
|
int ufsecp_abi_version();
|
|
String ufsecp_version_string();
|
|
String ufsecp_error_str(int code);
|
|
|
|
// Keys
|
|
int ufsecp_seckey_verify(Pointer ctx, byte[] k32);
|
|
int ufsecp_pubkey_create(Pointer ctx, byte[] sk32, byte[] pk33);
|
|
int ufsecp_pubkey_create_uncompressed(Pointer ctx, byte[] sk32, byte[] pk65);
|
|
int ufsecp_pubkey_xonly(Pointer ctx, byte[] sk32, byte[] xo32);
|
|
|
|
// ECDSA
|
|
int ufsecp_ecdsa_sign(Pointer ctx, byte[] msg32, byte[] sk32, byte[] sig64);
|
|
int ufsecp_ecdsa_verify(Pointer ctx, byte[] msg32, byte[] sig64, byte[] pk33);
|
|
int ufsecp_ecdsa_sign_recoverable(Pointer ctx, byte[] msg32, byte[] sk32, byte[] sig64, IntByReference recid);
|
|
int ufsecp_ecdsa_recover(Pointer ctx, byte[] msg32, byte[] sig64, int recid, byte[] pk33);
|
|
int ufsecp_ecdsa_sig_to_der(Pointer ctx, byte[] sig64, byte[] der, NativeLongByReference len);
|
|
|
|
// Schnorr
|
|
int ufsecp_schnorr_sign(Pointer ctx, byte[] msg32, byte[] sk32, byte[] aux32, byte[] sig64);
|
|
int ufsecp_schnorr_verify(Pointer ctx, byte[] msg32, byte[] sig64, byte[] xo32);
|
|
|
|
// ECDH
|
|
int ufsecp_ecdh(Pointer ctx, byte[] sk32, byte[] pk33, byte[] secret32);
|
|
|
|
// Hashing
|
|
int ufsecp_sha256(byte[] data, long len, byte[] digest32);
|
|
int ufsecp_hash160(byte[] data, long len, byte[] digest20);
|
|
|
|
// Addresses
|
|
int ufsecp_addr_p2pkh(Pointer ctx, byte[] pk33, int net, byte[] addr, NativeLongByReference len);
|
|
int ufsecp_addr_p2wpkh(Pointer ctx, byte[] pk33, int net, byte[] addr, NativeLongByReference len);
|
|
int ufsecp_addr_p2tr(Pointer ctx, byte[] xo32, int net, byte[] addr, NativeLongByReference len);
|
|
|
|
// WIF
|
|
int ufsecp_wif_encode(Pointer ctx, byte[] sk32, int comp, int net, byte[] wif, NativeLongByReference len);
|
|
|
|
// BIP-32
|
|
int ufsecp_bip32_master(Pointer ctx, byte[] seed, long seedLen, byte[] key82);
|
|
int ufsecp_bip32_derive_path(Pointer ctx, byte[] master82, String path, byte[] key82);
|
|
int ufsecp_bip32_privkey(Pointer ctx, byte[] key82, byte[] priv32);
|
|
int ufsecp_bip32_pubkey(Pointer ctx, byte[] key82, byte[] pub33);
|
|
|
|
// Taproot
|
|
int ufsecp_taproot_output_key(Pointer ctx, byte[] intX32, Pointer mr, byte[] outX32, IntByReference parity);
|
|
int ufsecp_taproot_verify(Pointer ctx, byte[] outX32, int parity, byte[] intX32, Pointer mr, long mrLen);
|
|
|
|
// Pedersen
|
|
int ufsecp_pedersen_commit(Pointer ctx, byte[] value32, byte[] blinding32, byte[] commit33);
|
|
int ufsecp_pedersen_verify(Pointer ctx, byte[] commit33, byte[] value32, byte[] blinding32);
|
|
|
|
// GPU
|
|
int ufsecp_gpu_backend_count(int[] ids, int max);
|
|
String ufsecp_gpu_backend_name(int bid);
|
|
int ufsecp_gpu_is_available(int bid);
|
|
int ufsecp_gpu_device_count(int bid);
|
|
int ufsecp_gpu_ctx_create(PointerByReference ctx, int bid, int dev);
|
|
void ufsecp_gpu_ctx_destroy(Pointer ctx);
|
|
int ufsecp_gpu_generator_mul_batch(Pointer ctx, byte[] s32, long n, byte[] pk33);
|
|
int ufsecp_gpu_ecdsa_verify_batch(Pointer ctx, byte[] msg, byte[] pk, byte[] sig, long n, byte[] res);
|
|
int ufsecp_gpu_hash160_pubkey_batch(Pointer ctx, byte[] pk33, long n, byte[] h20);
|
|
int ufsecp_gpu_msm(Pointer ctx, byte[] s32, byte[] p33, long n, byte[] out33);
|
|
String ufsecp_gpu_error_str(int code);
|
|
}
|
|
|
|
// ── Helpers ───────────────────────────────────────────────────────
|
|
|
|
static final Ufsecp lib = Ufsecp.INSTANCE;
|
|
static final HexFormat HEX = HexFormat.of();
|
|
|
|
static void check(int rc, String op) {
|
|
if (rc != 0) {
|
|
System.err.printf("[FAIL] %s: %s (code %d)%n", op, lib.ufsecp_error_str(rc), rc);
|
|
System.exit(1);
|
|
}
|
|
}
|
|
|
|
static String hexs(byte[] data) { return HEX.formatHex(data); }
|
|
static String hexs(byte[] data, int off, int len) {
|
|
return HEX.formatHex(Arrays.copyOfRange(data, off, off + len));
|
|
}
|
|
|
|
static String getAddr(AddrFn fn, Pointer ctx, byte[] key, int net) {
|
|
byte[] buf = new byte[128];
|
|
NativeLongByReference len = new NativeLongByReference(new NativeLong(128));
|
|
check(fn.call(ctx, key, net, buf, len), "addr");
|
|
return new String(buf, 0, (int) len.getValue().longValue());
|
|
}
|
|
|
|
@FunctionalInterface
|
|
interface AddrFn {
|
|
int call(Pointer ctx, byte[] key, int net, byte[] buf, NativeLongByReference len);
|
|
}
|
|
|
|
// ── Test Keys ────────────────────────────────────────────────────
|
|
|
|
static byte[] privkey() {
|
|
byte[] k = new byte[32];
|
|
k[31] = 1;
|
|
return k;
|
|
}
|
|
|
|
static byte[] privkey2() {
|
|
byte[] k = new byte[32];
|
|
k[31] = 2;
|
|
return k;
|
|
}
|
|
|
|
// ── CPU Demo ─────────────────────────────────────────────────────
|
|
|
|
static void demoCPU(Pointer ctx) {
|
|
System.out.println("=== CPU Operations ===\n");
|
|
byte[] sk = privkey(), sk2 = privkey2();
|
|
|
|
// 1. Key Generation
|
|
System.out.println("[1] Key Generation");
|
|
byte[] pub33 = new byte[33], pub65 = new byte[65], xonly = new byte[32];
|
|
check(lib.ufsecp_pubkey_create(ctx, sk, pub33), "pubkey_create");
|
|
check(lib.ufsecp_pubkey_create_uncompressed(ctx, sk, pub65), "pubkey_uncompressed");
|
|
check(lib.ufsecp_pubkey_xonly(ctx, sk, xonly), "pubkey_xonly");
|
|
System.out.printf(" %-20s %s%n", "Private key:", hexs(sk));
|
|
System.out.printf(" %-20s %s%n", "Compressed (33B):", hexs(pub33));
|
|
System.out.printf(" %-20s %s%n", "Uncompressed (65B):", hexs(pub65));
|
|
System.out.printf(" %-20s %s%n", "X-only (32B):", hexs(xonly));
|
|
System.out.println();
|
|
|
|
// 2. ECDSA
|
|
System.out.println("[2] ECDSA Sign / Verify (RFC 6979)");
|
|
byte[] msg = new byte[32];
|
|
check(lib.ufsecp_sha256("Hello UltrafastSecp256k1!".getBytes(), 24, msg), "sha256");
|
|
System.out.printf(" %-20s %s%n", "Message hash:", hexs(msg));
|
|
|
|
byte[] sig = new byte[64];
|
|
check(lib.ufsecp_ecdsa_sign(ctx, msg, sk, sig), "ecdsa_sign");
|
|
System.out.printf(" %-20s %s%n", "ECDSA signature:", hexs(sig));
|
|
|
|
int vrc = lib.ufsecp_ecdsa_verify(ctx, msg, sig, pub33);
|
|
System.out.printf(" %-20s %s%n", "Verify:", vrc == 0 ? "VALID" : "INVALID");
|
|
|
|
// DER
|
|
byte[] der = new byte[72];
|
|
NativeLongByReference derLen = new NativeLongByReference(new NativeLong(72));
|
|
check(lib.ufsecp_ecdsa_sig_to_der(ctx, sig, der, derLen), "sig_to_der");
|
|
System.out.printf(" %-20s %d bytes%n", "DER length:", derLen.getValue().longValue());
|
|
|
|
// Recovery
|
|
IntByReference recid = new IntByReference();
|
|
byte[] rsig = new byte[64], recovered = new byte[33];
|
|
check(lib.ufsecp_ecdsa_sign_recoverable(ctx, msg, sk, rsig, recid), "sign_recoverable");
|
|
check(lib.ufsecp_ecdsa_recover(ctx, msg, rsig, recid.getValue(), recovered), "recover");
|
|
System.out.printf(" %-20s recid=%d, match=%s%n", "Recovery:",
|
|
recid.getValue(), Arrays.equals(recovered, pub33) ? "YES" : "NO");
|
|
System.out.println();
|
|
|
|
// 3. Schnorr
|
|
System.out.println("[3] Schnorr Sign / Verify (BIP-340)");
|
|
byte[] aux = new byte[32], schnorrSig = new byte[64];
|
|
check(lib.ufsecp_schnorr_sign(ctx, msg, sk, aux, schnorrSig), "schnorr_sign");
|
|
System.out.printf(" %-20s %s%n", "Schnorr signature:", hexs(schnorrSig));
|
|
vrc = lib.ufsecp_schnorr_verify(ctx, msg, schnorrSig, xonly);
|
|
System.out.printf(" %-20s %s%n", "Verify:", vrc == 0 ? "VALID" : "INVALID");
|
|
System.out.println();
|
|
|
|
// 4. ECDH
|
|
System.out.println("[4] ECDH Key Agreement");
|
|
byte[] pub2 = new byte[33];
|
|
check(lib.ufsecp_pubkey_create(ctx, sk2, pub2), "pubkey2");
|
|
byte[] secretA = new byte[32], secretB = new byte[32];
|
|
check(lib.ufsecp_ecdh(ctx, sk, pub2, secretA), "ecdh_a");
|
|
check(lib.ufsecp_ecdh(ctx, sk2, pub33, secretB), "ecdh_b");
|
|
System.out.printf(" %-20s %s%n", "Secret (A->B):", hexs(secretA));
|
|
System.out.printf(" %-20s %s%n", "Secret (B->A):", hexs(secretB));
|
|
System.out.printf(" %-20s %s%n", "Match:", Arrays.equals(secretA, secretB) ? "YES" : "NO");
|
|
System.out.println();
|
|
|
|
// 5. Hashing
|
|
System.out.println("[5] Hashing");
|
|
byte[] sha = new byte[32], h160 = new byte[20];
|
|
check(lib.ufsecp_sha256(pub33, 33, sha), "sha256_pub");
|
|
check(lib.ufsecp_hash160(pub33, 33, h160), "hash160_pub");
|
|
System.out.printf(" %-20s %s%n", "SHA-256(pubkey):", hexs(sha));
|
|
System.out.printf(" %-20s %s%n", "Hash160(pubkey):", hexs(h160));
|
|
System.out.println();
|
|
|
|
// 6. Bitcoin Addresses
|
|
System.out.println("[6] Bitcoin Addresses");
|
|
System.out.printf(" %-20s %s%n", "P2PKH:", getAddr(lib::ufsecp_addr_p2pkh, ctx, pub33, 0));
|
|
System.out.printf(" %-20s %s%n", "P2WPKH:", getAddr(lib::ufsecp_addr_p2wpkh, ctx, pub33, 0));
|
|
System.out.printf(" %-20s %s%n", "P2TR:", getAddr(lib::ufsecp_addr_p2tr, ctx, xonly, 0));
|
|
System.out.println();
|
|
|
|
// 7. WIF
|
|
System.out.println("[7] WIF Encoding");
|
|
byte[] wifBuf = new byte[128];
|
|
NativeLongByReference wifLen = new NativeLongByReference(new NativeLong(128));
|
|
check(lib.ufsecp_wif_encode(ctx, sk, 1, 0, wifBuf, wifLen), "wif_encode");
|
|
System.out.printf(" %-20s %s%n", "WIF:", new String(wifBuf, 0, (int) wifLen.getValue().longValue()));
|
|
System.out.println();
|
|
|
|
// 8. BIP-32
|
|
System.out.println("[8] BIP-32 HD Key Derivation");
|
|
byte[] seed = new byte[64];
|
|
Arrays.fill(seed, (byte) 0x42);
|
|
byte[] master = new byte[82];
|
|
check(lib.ufsecp_bip32_master(ctx, seed, 64, master), "bip32_master");
|
|
byte[] childKey = new byte[82];
|
|
check(lib.ufsecp_bip32_derive_path(ctx, master, "m/44'/0'/0'/0/0", childKey), "bip32_path");
|
|
byte[] childPriv = new byte[32], childPub = new byte[33];
|
|
check(lib.ufsecp_bip32_privkey(ctx, childKey, childPriv), "bip32_privkey");
|
|
check(lib.ufsecp_bip32_pubkey(ctx, childKey, childPub), "bip32_pubkey");
|
|
System.out.printf(" %-20s %s%n", "BIP-32 child priv:", hexs(childPriv));
|
|
System.out.printf(" %-20s %s%n", "BIP-32 child pub:", hexs(childPub));
|
|
System.out.println();
|
|
|
|
// 9. Taproot
|
|
System.out.println("[9] Taproot (BIP-341)");
|
|
byte[] outputX = new byte[32];
|
|
IntByReference parity = new IntByReference();
|
|
check(lib.ufsecp_taproot_output_key(ctx, xonly, null, outputX, parity), "taproot_output_key");
|
|
System.out.printf(" %-20s %s%n", "Output key:", hexs(outputX));
|
|
System.out.printf(" %-20s %d%n", "Parity:", parity.getValue());
|
|
vrc = lib.ufsecp_taproot_verify(ctx, outputX, parity.getValue(), xonly, null, 0);
|
|
System.out.printf(" %-20s %s%n", "Verify:", vrc == 0 ? "VALID" : "INVALID");
|
|
System.out.println();
|
|
|
|
// 10. Pedersen Commitment
|
|
System.out.println("[10] Pedersen Commitment");
|
|
byte[] pedValue = new byte[32]; pedValue[31] = 42;
|
|
byte[] pedBlinding = new byte[32]; pedBlinding[31] = 7;
|
|
byte[] pedCommit = new byte[33];
|
|
check(lib.ufsecp_pedersen_commit(ctx, pedValue, pedBlinding, pedCommit), "pedersen_commit");
|
|
System.out.printf(" %-20s %s%n", "Commitment:", hexs(pedCommit));
|
|
vrc = lib.ufsecp_pedersen_verify(ctx, pedCommit, pedValue, pedBlinding);
|
|
System.out.printf(" %-20s %s%n", "Verify:", vrc == 0 ? "VALID" : "INVALID");
|
|
System.out.println();
|
|
}
|
|
|
|
// ── GPU Demo ─────────────────────────────────────────────────────
|
|
|
|
static void demoGPU(Pointer cpuCtx) {
|
|
System.out.println("=== GPU Operations ===\n");
|
|
|
|
// 10. Backend Discovery
|
|
System.out.println("[10] GPU Backend Discovery");
|
|
int[] bids = new int[4];
|
|
int nBackends = lib.ufsecp_gpu_backend_count(bids, 4);
|
|
System.out.printf(" %-20s %d%n", "Backends compiled:", nBackends);
|
|
|
|
int useBackend = 0;
|
|
for (int i = 0; i < nBackends; i++) {
|
|
int bid = bids[i];
|
|
String name = lib.ufsecp_gpu_backend_name(bid);
|
|
int avail = lib.ufsecp_gpu_is_available(bid);
|
|
int devs = lib.ufsecp_gpu_device_count(bid);
|
|
System.out.printf(" Backend %d: %-8s available=%d devices=%d%n", bid, name, avail, devs);
|
|
if (avail != 0 && useBackend == 0) useBackend = bid;
|
|
}
|
|
|
|
if (useBackend == 0) {
|
|
System.out.println(" No GPU backends available -- skipping GPU demos.\n");
|
|
return;
|
|
}
|
|
|
|
// Create GPU context
|
|
PointerByReference gpuRef = new PointerByReference();
|
|
int rc = lib.ufsecp_gpu_ctx_create(gpuRef, useBackend, 0);
|
|
if (rc != 0) {
|
|
System.out.printf(" GPU context creation failed: %s%n", lib.ufsecp_gpu_error_str(rc));
|
|
return;
|
|
}
|
|
Pointer gpu = gpuRef.getValue();
|
|
|
|
int N = 4;
|
|
|
|
// 11. Batch Key Generation
|
|
System.out.println("\n[11] GPU Batch Key Generation (4 keys)");
|
|
byte[] scalars = new byte[N * 32];
|
|
for (int i = 0; i < N; i++) scalars[i * 32 + 31] = (byte)(i + 1);
|
|
|
|
byte[] pubkeys = new byte[N * 33];
|
|
rc = lib.ufsecp_gpu_generator_mul_batch(gpu, scalars, N, pubkeys);
|
|
if (rc == 0) {
|
|
for (int i = 0; i < N; i++)
|
|
System.out.printf(" GPU pubkey[%d]: %s%n", i, hexs(pubkeys, i*33, 33));
|
|
} else {
|
|
System.out.printf(" gpu_generator_mul_batch: %s%n", lib.ufsecp_gpu_error_str(rc));
|
|
}
|
|
|
|
// 12. ECDSA Batch Verify
|
|
System.out.println("\n[12] GPU ECDSA Batch Verify");
|
|
byte[] msgs = new byte[N * 32], sigs = new byte[N * 64], pubs = new byte[N * 33];
|
|
for (int i = 0; i < N; i++) {
|
|
byte[] msgHash = new byte[32];
|
|
lib.ufsecp_sha256(new byte[]{(byte)i}, 1, msgHash);
|
|
System.arraycopy(msgHash, 0, msgs, i * 32, 32);
|
|
|
|
byte[] sk = new byte[32];
|
|
sk[31] = (byte)(i + 1);
|
|
byte[] sig = new byte[64];
|
|
lib.ufsecp_ecdsa_sign(cpuCtx, msgHash, sk, sig);
|
|
System.arraycopy(sig, 0, sigs, i * 64, 64);
|
|
System.arraycopy(pubkeys, i * 33, pubs, i * 33, 33);
|
|
}
|
|
|
|
byte[] results = new byte[N];
|
|
rc = lib.ufsecp_gpu_ecdsa_verify_batch(gpu, msgs, pubs, sigs, N, results);
|
|
if (rc == 0) {
|
|
StringBuilder sb = new StringBuilder(" Results: ");
|
|
for (int i = 0; i < N; i++) sb.append(String.format("[%d]=%s ", i, results[i] != 0 ? "VALID" : "INVALID"));
|
|
System.out.println(sb);
|
|
} else {
|
|
System.out.printf(" gpu_ecdsa_verify_batch: %s%n", lib.ufsecp_gpu_error_str(rc));
|
|
}
|
|
|
|
// 13. Hash160 Batch
|
|
System.out.println("\n[13] GPU Hash160 Batch");
|
|
byte[] hashes = new byte[N * 20];
|
|
rc = lib.ufsecp_gpu_hash160_pubkey_batch(gpu, pubkeys, N, hashes);
|
|
if (rc == 0) {
|
|
for (int i = 0; i < N; i++)
|
|
System.out.printf(" Hash160[%d]: %s%n", i, hexs(hashes, i*20, 20));
|
|
} else {
|
|
System.out.printf(" gpu_hash160_pubkey_batch: %s%n", lib.ufsecp_gpu_error_str(rc));
|
|
}
|
|
|
|
// 14. MSM
|
|
System.out.println("\n[14] GPU Multi-Scalar Multiplication");
|
|
byte[] msmResult = new byte[33];
|
|
rc = lib.ufsecp_gpu_msm(gpu, scalars, pubkeys, N, msmResult);
|
|
if (rc == 0) {
|
|
System.out.printf(" MSM result: %s%n", hexs(msmResult));
|
|
} else {
|
|
System.out.printf(" gpu_msm: %s%n", lib.ufsecp_gpu_error_str(rc));
|
|
}
|
|
|
|
lib.ufsecp_gpu_ctx_destroy(gpu);
|
|
System.out.println();
|
|
}
|
|
|
|
// ── Main ─────────────────────────────────────────────────────────
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println("UltrafastSecp256k1 -- Java Example");
|
|
System.out.printf("ABI version: %d%n", lib.ufsecp_abi_version());
|
|
System.out.printf("Library: %s%n%n", lib.ufsecp_version_string());
|
|
|
|
PointerByReference ctxRef = new PointerByReference();
|
|
check(lib.ufsecp_ctx_create(ctxRef), "ctx_create");
|
|
Pointer ctx = ctxRef.getValue();
|
|
|
|
demoCPU(ctx);
|
|
demoGPU(ctx);
|
|
|
|
lib.ufsecp_ctx_destroy(ctx);
|
|
System.out.println("All examples completed successfully.");
|
|
}
|
|
}
|