Libgcrypt in the Bitcoin ecosystem

12.09.2026

Libgcrypt in the Bitcoin ecosystem

Wallet application boundaries, participation in ECDSA transaction signing and private key generation: analysis of documentation, source code, and project history. Field:  Applied cryptography / Bitcoin. Method:  source code audit + standards analysis.

Annotation

Libgcrypt is a general-purpose GNU cryptographic library, but is not a component of the Bitcoin protocol.  It supports SHA-256, RIPEMD-160, HMAC, PBKDF2, CSPRNG, MPI/ECC, ECDSA, and the named curve secp256k1, so a single wallet can build a significant portion of the cryptographic circuit on it. [1]  However, Bitcoin Core does not use Libgcrypt for key generation, signing, or consensus signature verification: these operations are performed by a specialized  libsecp256k1. [11] [12]

Direct widespread use is confirmed in the experimental C project  wall_e_t . Historical limited use was found in  Bitcoin Toolkit 2.0.x , where Libgcrypt supported SHA-256/RIPEMD-160 but not ECDSA; the dependency was removed from the code in 2023. The claim of widespread adoption of Libgcrypt in popular production wallets is not confirmed.

Short answer

In Bitcoin, it can be used by the implementation, but the protocol does not require it.

ECDSA technically Yes: Libgcrypt can do secp256k1/ECDSA and  gcry_pk_sign.

In Bitcoin Core No: Core uses  libsecp256k1.

Key generation Yes in some wallets; no as a required part of Bitcoin .

  1. Subject and methodology
  2. Libgcrypt Capabilities
  3. Bitcoin’s Cryptographic Layers
  4. What projects are used?
  5. Bitcoin Core
  6. ECDSA signing
  7. Private key generation
  8. Taproot and Schnorr
  9. Security audit
  10. Recommendations
  11. Conclusions
  12. Sources

Subject and methodology

The study distinguishes four layers: (1) protocol and consensus rules; (2) node implementation; (3) wallet implementation; (4) indirect system dependencies. Installing  libgcrypt on Linux, using GnuPG to test the release, or being present  guile-gcrypt in a reproducible build environment does not mean that this library processes Bitcoin private keys.

For each open source project, build files, includes  <gcrypt.h>, calls  gcry_*, crypto call graph, and Git history were checked. The current snapshot was separated from older releases. A negative result is interpreted with caution: it confirms the absence of a direct dependency in the checked open source snapshot, but does not rule out closed source applications, forks, or older versions.

Proof criterion.  The project name in the README is not sufficient. Reliable proof requires direct linking and API calls in the code that actually performs key generation, hashing, signing, or wallet encryption.

Libgcrypt Capabilities

The official manual calls Libgcrypt a GNU library of cryptographic building blocks with an extensible API. [1]  The public-key module supports ECDSA/ECDH/EdDSA, and the list of curves includes  secp256k1; the flag  rfc6979 is for the deterministic parameter  k in DSA/ECDSA. [2]

Keys and signatures are passed as S-expressions.  gcry_pk_sign returns the ECDSA components  r and  s, and  gcry_pk_verify verifies them. [2]  Additionally, hashing, HMAC, PBKDF2, CSPRNG, multi-precision integers, symmetric encryption, and secure memory are available. [3]

Functional sufficiency does not equal protocol compatibility.  Libgcrypt does not build Bitcoin sighash, serialize transactions, execute Bitcoin Script, or implement BIP-66/BIP-340 as a complete Bitcoin stack. These responsibilities lie with the application.

Bitcoin Layers

LayerOperationLibgcrypt CapabilityLimitation
EntropyRandom bytesYesCorrect quality level and error checking are required.
Private keyScalar 1 ≤ d < nYesUnbiased display/rejection sampling is required.
Public keyQ = dG on secp256k1YesBitcoin-compatible coding is required
AddressesSHA-256, RIPEMD-160, HMACYesBase58Check/Bech32 implements the application
HD walletBIP-39/BIP-32 primitivesYesThe application implements standards and derivation path
Legacy/SegWit v0ECDSA sign/verifyYesNeed sighash, DER, low-S, witness/script
TaprootBIP-340 SchnorrNot confirmed by a ready APIGeneric ECDSA/EdDSA does not replace BIP-340
StorageKDF + AEAD/AESYesThis is a wallet policy, not a consensus.
ConsensusScript, sighash rules, soft forksThere is no ready stackA Bitcoin implementation is needed

Nodes don’t know which library created the signature. They accept or reject the byte transaction according to Bitcoin consensus and policy. Therefore, the same valid ECDSA signature can be calculated by Libgcrypt, OpenSSL, a hardware wallet, or  libsecp256k1.

Projects and wallets

wall_e_t: direct example

In the currently examined commit  of the Rubberazer/wall_e_te63602b  project  ,  the Makefile links to  , and the code includes  . This is an experimental GNU/Linux C wallet, not a widely used audited production wallet.-lgcrypt<gcrypt.h>

  • gcry_random_bytes(..., GCRY_STRONG_RANDOM) — entropy mnemonics;
  • gcry_md_hash_buffer(SHA256) — BIP-39 checksum;
  • gcry_kdf_derive(PBKDF2, SHA512, 2048) — mnemonic-to-seed;
  • HMAC-SHA512 и MPI modulo n — master/child key derivation;
  • gcry_mpi_ec_new, gcry_pubkey_get_sexp — public key from private;
  • gcry_pk_sign,  gcry_pk_verify — ECDSA on secp256k1;
  • AES-256-GCM-SIV, PBKDF2, secure allocations — protection of wallet records.

Therefore, in wall_e_t, Libgcrypt is directly linked to both private key origins and ECDSA. However,  sign_ECDSA it is called from crypto-test; no call to it was detected in the production path for constructing and signing Bitcoin input. The presence of an ECDSA function, but an incomplete Bitcoin transaction signer, is proven.

Bitcoin Toolkit: A Historical Example

The Git history of  bartobri/bitcoin-toolkit  shows that releases 2.0.1–2.0.2 linked  -lgcrypt and called  gcry_md_* for SHA-256/RIPEMD-160. This handled hashing, Base58Check, and addresses, but not ECDSA or private key generation.

37f84b7 The February 14, 2023,  commit  removed gcry_* and  -lgcrypt. The README for versions 3.x also mentioned the library—an example of why documentation needs to be verified with build graph. The current version, 4.0, uses  libsecp256k1, and gets randomness via  getentropy(2) or  /dev/urandom.

Summary matrix

ProjectSliceLibgcryptECDSA through itKeygen through itQualification
wall_e_te63602bYesThere is a functionYes, via entropy/HD pipelineExperimental wallet
Bitcoin Toolkit2.0.xHistoricalNoNoSHA-256/RIPEMD-160 only
Bitcoin Toolkit4.0Nolibsecp256k1OS CSPRNGCLI toolkit, не stored wallet
Bitcoin CorecurrentNolibsecp256k1Core RNG + validationReference node/wallet
ElectrumcurrentNot confirmedlibsecp256k1/electrum-eccNo Libgcrypt dependenciesA popular SPV wallet
Wasabi / btcwallet / Bitcoin Wallet Androidtested open cutsNot confirmedOther stacksOther stacksThere is no reason to include it in the list

Bitcoin Core

The modern Bitcoin Core includes headers  secp256k1.h, calls  secp256k1_ecdsa_sign,  secp256k1_ecdsa_verifyand  secp256k1_keypair_create the Schnorr API. The new secret key receives random bytes through a custom RNG pipeline and verifies it as a scalar secp256k1. The API  libsecp256k1 considers the secret valid when  0 < d < n and strict ECDSA verification accepts lower-S. [12]

Historically, Bitcoin Core 0.10 switched signing from OpenSSL to  libsecp256k1 constant-time and deterministic signatures; version 0.12 switched ECDSA verification to it, reducing the attack surface and speeding up verification. [10] [11]

Why is libgcrypt listed in the Core tree?  The table  guile-gcrypt → libgcrypt-dev in the Guix documentation refers to reproducible build tools. It’s not a runtime crypto wallet backend or a consensus dependency.

Electrum also explicitly lists  libsecp256k1 ECC as a dependency and a package  cryptography for symmetric ciphers; it does not acknowledge Libgcrypt in the signing path. [13]

ECDSA signing

Mathematical scheme

For a private scalar  d, a message hash  z, a base point  G, its order  n , and a one-time secret  k:

Q = dG R = kG r = x(R) mod n s = k⁻¹(z + r·d) mod n signature = (r, s)

The secp256k1 curve is standardized by SEC 2 as a 256-bit Koblitz curve over a prime field; parameters include  p,  a=0,  b=7,  G,  n and the cofactor 1. [4]

Bitcoin-specific context

In Bitcoin, ECDSA signs not a “transaction as a file,” but a special digest for a specific input. Its preimage and covered fields depend on the script type, witness version, and SIGHASH flags. The signature is then placed in  scriptSig the witness and verified against the public key and the conditions of the spent output. [7]

Transaction + prevout→Sighash preimage→32-byte digest→ECDSA(digest,d)→low-S + strict DER→scriptSig / witness

The role of Libgcrypt

Libgcrypt can perform the central mathematical step: deriving  (r,s) via  gcry_pk_sign for a secp256k1 key. The documented RFC 6979 mode is specified by a flag  rfc6979 and a hash algorithm. [2]  RFC 6979 makes the nonce a deterministic function of the private key and message hash, maintaining compatibility with the standard ECDSA verifier. [5]

But the library does not exempt the calling code from Bitcoin rules. BIP-66 requires strict DER for ECDSA signatures in the corresponding opcodes. [8]  Lower-S eliminates substitutability  (r,s) for  (r,n−s); specialized  libsecp256k1 has explicit normalization and lower-S verification. [9] [12]

What the adapter must do

  • Build exact legacy, SegWit v0 or other applicable sighash.
  • Pass the digest itself, and don’t re-hash/mis-hash it.
  • Provide RFC 6979 or other secure nonce mechanism.
  • Normalize  s = min(s, n−s).
  • Serialize  r,s to minimal positive strict DER.
  • Add Bitcoin SIGHASH byte where required.
  • Generate a correct  scriptSig/witness.
  • For P2TR use BIP-340, not ECDSA.

Key generation

A Bitcoin private key is an integer:

d ∈ {1, 2, …, n − 1} Q = dG

NIST describes the ECDSA private key as being  d in the range  [1,n−1], derived from the DRBG, and the public key as being  Q=[d]G. [6]  Therefore, Libgcrypt may be directly related to the keygen if the application uses its CSPRNG and ECC arithmetic. However, neither the WIF format, nor the address, nor the descriptor are the private key itself.

Two typical paths

Independent key:  The CSPRNG produces sufficient entropy; the application receives an unbiased scalar and rejects 0 or a value ≥  n.  HD wallet:  The entropy is converted to a mnemonic and seed, then BIP-32 deterministically creates a key tree.

CSPRNG entropy→BIP-39 mnemonic→PBKDF2-HMAC-SHA512 seed→BIP-32 master key→child d

BIP-39 encodes 128–256 bits of entropy by appending the first  ENT/32 bits of the SHA-256 checksum and breaking the result into 11-bit word indices. [15]  BIP-32 defines a tree of normal and hardened keys from a single seed. [14]  Libgcrypt is capable of handling the primitive layer—RNG, SHA-256, PBKDF2-HMAC-SHA512, HMAC-SHA512, and ECC—but BIP compliance is ensured by the wallet code.

Don’t confuse d, k, and seed

ObjectPurposeLifespanRelationship with RFC 6979
dBitcoin private keyLong-termEnter RFC 6979
kECDSA secret nonceOne signatureIt is precisely this that is defined by RFC 6979.
seedHD Wallet Root SecretLong-termNot being created RFC 6979
chain codeBIP-32 derivation parameterНа extended keyNot an ECDSA nonce

RFC 6979 explicitly states that the key-pair generation does not change. [5]  Therefore, the presence of the flag in Libgcrypt  rfc6979 applies to signing, not to the creation of a new wallet private key.

Taproot and Schnorr

After Taproot, it cannot be claimed that every Bitcoin signature is ECDSA. BIP-340 defines 64-byte Schnorr signatures over the same secp256k1. [16]  P2TR uses x-only public keys, tagged hashes, and separate signature message rules.

Libgcrypt documentation confirms ECDSA and EdDSA, but EdDSA is not BIP-340. Generic ECC arithmetic theoretically allows for a native implementation of BIP-340, but this is not equivalent to a ready-made audited BIP-340 API. Therefore,  gcry_pk_sign Taproot spend does not sign in ECDSA mode.

Security audit

wall_e_t: risks found

A static analysis of the function  sign_ECDSA shows why the presence of a cryptographic backend does not necessarily mean the presence of a secure Bitcoin signer.

ObservationRiskRating
It is used  (flags raw), not explicit rfc6979Nonce policy depends on the backend/RNG and is not fixed by the interface.High
No lower-S normalizationBitcoin policy/compatibility, malleabilityHigh
The homemade DER takes sign-padding into account only for rNon-canonical/incorrect signatures for some values r,sCritical
Condition  r[0] > 0x80, not a check of whether the high bit is setBoundary error at 0x80High
One-shot SHA-256 of a random bufferNon-universal Bitcoin sighashCritical
No SIGHASH byteIncomplete Bitcoin signature serializationCritical
The function was found only in a test call.Production transaction signing not confirmedAverage

These are the results of a static analysis of a specific slice, not a claim of compromised funds. Before deployment with real assets, patches, official test vectors, differential testing against Bitcoin Core, and an independent audit are required.

The wall_e_tinternal Libgcrypt function _gcry_ecc_ecdsa_sign()is applied indirectly when sign_ECDSA().

The code itself wall_e_tdoesn’t call it _gcry_ecc_ecdsa_sign()directly—it’s an internal Libgcrypt symbol, not intended for external use. Instead, wall_e_tit generates a private ECC key on the curve secp256k1as an S-expression and calls the public API:

cgcry_pk_sign(&s_sign, s_data, s_key);

For such an ECC key, Libgcrypt directs execution along the internal chain:

text:

wall_e_t::sign_ECDSA()
→ gcry_pk_sign()
→ внутренний ECC/ECDSA dispatcher Libgcrypt
→ _gcry_ecc_ecdsa_sign() [cipher/ecc-ecdsa.c]
→ _gcry_mpi_ec_mul_point()

Therefore, the precise professional wording is: wall_e_t it doesn’t have a direct source-level call _gcry_ecc_ecdsa_sign , but its ECDSA signing via [libgcrypt] gcry_pk_sign()results in this function being executed within the dynamically linked Libgcrypt. The repository explicitly lists Libgcrypt as a fundamental dependency and uses it for cryptographic operations. [gnupg+2]

What does the function do?

_gcry_ecc_ecdsa_sign()— the internal implementation of ECDSA signature calculation. For the Bitcoin secp256k1 curve, it is involved in the calculation of:

Q=dG,R=kG,r=x(R) mthed n,Q=dG,R=kG,r=x(R)modn,

s=k−1(With+rd) mthed n.s=k−1(z+rd)modn.

Here:

  • d— private scalar;
  • Q— the corresponding public key;
  • k— one-time ECDSA nonce;
  • With— hash of the message being signed;
  • n— base point order secp256k1;
  • (r,s)— the final ECDSA signature.

Libgcrypt is documented to support ECDSA secp256k1and RFC 6979 deterministic nonce mode . gnupg

Important limitation of wall_e_t

The presence of a challenge _gcry_ecc_ecdsa_sign() does not prove that it wall_e_talready correctly signs real Bitcoin transactions in production mode.

Its function sign_ECDSA()has been found to have significant limitations:

Bitcoin signature componentCondition inwall_e_t::sign_ECDSA()Risk
ECDSA on secp256k1Yes, throughgcry_pk_sign()The basic cryptographic step works
Bitcoin sighashNot confirmedThe function simply applies a single SHA-256 to the input buffer.
RFC 6979Not explicitly specifiedUsed (flags raw), not documented(flags rfc6979)
low-S normalizationNot foundPossible incompatibility with Bitcoin policy/SegWit rules
BIP-66 strict DERNot fully implementedDER encoding is manual and incomplete
Padding forsNot processed similarlyrPossible invalid ASN.1 INTEGER
SIGHASH-byteNot addedIncomplete serialization of Bitcoin ECDSA signature
Integration into transaction pathNot confirmedREADME marks transaction/transfer as not ready yet

BIP-66 requires strict DER representation of ECDSA signatures, and BIP-146 requires lower-S for relevant scenarios. The repository itself warns that the project is in early stages and is not intended for serious use; transaction and transfer operations are marked as not yet ready.

Other Bitcoin wallets

Confirmed answer

For any wallet that uses Libgcrypt for ECDSA signatures on secp256k1 gcry_pk_sign(), _gcry_ecc_ecdsa_sign()this will be called indirectly. This is an internal feature of Libgcrypt, not a unique feature wall_e_t.

But among the widely known Bitcoin wallets, there are few publicly confirmed examples:

ProjectUses _gcry_ecc_ecdsa_sign()via Libgcrypt?Justification
wall_e_tYes, indirectlysign_ECDSA()calls gcry_pk_sign()with(curve "secp256k1")
Bitcoin CoreNoUses libsecp256k1ECDSA for signing and verification
ElectrumNot confirmed; no dependenciesFor ECC specified libsecp256k1/electrum-ecc
Bitcoin Toolkit 2.0.xNo for ECDSALibgcrypt has been used historically for SHA-256 and RIPEMD-160
Bitcoin Toolkit 4.0NoUseslibsecp256k1
Wasabi, btcwallet, Bitcoin Wallet AndroidNot confirmedThere is no reliable evidence that they use Libgcrypt ECDSA backend.

Bitcoin Core historically replaced OpenSSL with [unclear] libsecp256k1: first for signing, then for validation. The goal was constant-time operations, a smaller attack surface, and faster signature verification. Electrum also specifies [unclear] libsecp256k1for elliptic operations in its dependencies, rather than Libgcrypt.cryptobook.nakov+4.

Safety_gcry_ecc_ecdsa_sign

This internal function is also important from a cryptanalytic perspective. It has been addressed, in particular:

  • CVE-2018-0495 / ROHNP : Cache side-channel in ECDSA signing on older Libgcrypt, potentially allowing private key recovery in a local or cross-VM scenario; fix related to blinding in _gcry_ecc_ecdsa_sign().security-tracker.debian+1
  • CVE-2019-13627 : Changes to nonce and scalar multiplication handling to reduce timing leaks. openembedded

Therefore, the outdated Libgcrypt cannot be used for research or application builds wall_e_t. However, even the current library does not fix the Bitcoin framework’s bugs: sighash, DER, low-S, nonce policy, serialization, and Script/witness must be implemented separately and verified with test vectors.

Practical test

For your own debug build, you can confirm the dynamic path:

bash:


# Проверить наличие runtime-зависимости
ldd ./wall_e_t | grep -i gcrypt

# Найти публичную функцию
nm -D /usr/lib/*/libgcrypt.so* 2>/dev/null | grep ' gcry_pk_sign$'

# При наличии debug-symbols Libgcrypt
gdb --args ./test_crypto

B GDB:

textset breakpoint pending on
break _gcry_ecc_ecdsa_sign
run
bt

If an internal symbol is hidden or stripped in a release package, the breakpoint may not be set. This does not invalidate the call; reliable tracing requires a debug build of Libgcrypt or the debug symbols package installed.


Systemic threats

  • Weak entropy:  bias or seed duplication compromises the entire key tree.
  • Nonce failure:  retry, bias, or leakage  k allows recovery  d.
  • Side channels:  secure memory does not guarantee constant-time scalar arithmetic.
  • Fault injection:  For sensitive devices, hedged deterministic signatures with additional randomness are useful. [17]
  • Encoding errors:  DER, MPI, endianness and leading zeros often create incompatibilities.
  • Protocol confusion:  generic  sign(data) cannot be substituted for Bitcoin sighash layer.

Recommendations

For a new wallet

  1. Use OS CSPRNG or hardware TRNG to seed entropy.
  2. Use a mature BIP-32/BIP-39/descriptor implementation with official vectors.
  3. Use  libsecp256k1 for key validation, public keys, ECDSA and BIP-340.
  4. Separate the crypto primitive layer and the Bitcoin transaction/sighash/script layer.
  5. Store keys using AEAD and a modern password-based KDF; if possible, isolate them in a hardware wallet/HSM.
  6. Добавить fuzzing, sanitizers, differential tests, regtest integration и reproducible builds.

If Libgcrypt is required

  • Explicitly set RFC 6979 or documented hedged nonce mode.
  • Normalize lower-S after signature.
  • Do not write your own DER encoder without comprehensive BIP-66 tests.
  • Verify each generated ECDSA signature independently  libsecp256k1 in tests.
  • Check zero/out-of-range private scalars and all API return codes.
  • Do not announce P2TR support without a definitive BIP-340 implementation and official test vectors.
  • Conduct an audit of S-expression/MPI conversions, secure-memory lifetime, and error paths.

Conclusions

  1. Libgcrypt is not part of the Bitcoin protocol or consensus.  Neither transactions nor nodes contain the library’s identifier.
  2. Bitcoin Core does not use it for keygen/ECDSA.  The main backend is  libsecp256k1.
  3. There is a technical connection to ECDSA.  Libgcrypt supports secp256k1, ECDSA, and RFC6979-oriented mode; a wallet can sign using it if it correctly implements the Bitcoin bindings.
  4. The connection to private key generation is conditional.  It’s direct if the wallet uses Libgcrypt CSPRNG/KDF/ECC, like wall_e_t; other wallets may not.
  5. Confirmed examples are rare.  wall_e_t is a current experimental example; Bitcoin Toolkit is a historical hash-only example.
  6. Generic ECDSA is not sufficient.  Sighash, strict DER, low-S, SIGHASH byte, and a valid script/witness are required; Taproot requires BIP-340 Schnorr.

The final formula:  “The Bitcoin protocol uses Libgcrypt” is incorrect. “An individual Bitcoin wallet can use Libgcrypt for entropy, HD derivation, and ECDSA” is correct. “Any Libgcrypt signature is automatically a valid Bitcoin signature” is incorrect.

Sources

  1. GNU Privacy Guard. The Libgcrypt Reference Manual.
  2. GNU Privacy Guard. Cryptographic Functions: ECDSA, rfc6979, gcry_pk_sign.
  3. GNU Privacy Guard. Key Derivation: gcry_kdf_derive, PBKDF2.
  4. SECG. SEC 2, Recommended Elliptic Curve Domain Parameters, secp256k1.
  5. T. Pornin. RFC 6979: Deterministic Usage of DSA and ECDSA, 2013.
  6. NIST. FIPS 186-5 Digital Signature Standard, 2023.
  7. Bitcoin Developer Documentation. Transactions.
  8. P. Wuille. BIP 66: Strict DER signatures.
  9. Bitcoin Core libsecp256k1. ECDSA lower-S normalization documentation.
  10. Bitcoin Core 0.10 release notes. Improved signing security / libsecp256k1.
  11. Bitcoin Core. Bitcoin Core 0.12.0: libsecp256k1 verification.
  12. Bitcoin Core. libsecp256k1 API: secret-key validity and ECDSA verification.
  13. Electrum. Repository and dependency documentation.
  14. P. Wuille. BIP 32: Hierarchical Deterministic Wallets.
  15. M. Palatinus et al. BIP 39: Mnemonic code for generating deterministic keys.
  16. P. Wuille, J. Nick, T. Ruffing. BIP 340: Schnorr Signatures for secp256k1.
  17. IETF CFRG draft. Deterministic signatures with additional randomness.
  18. Rubberazer. wall_e_t source repository, audited commit e63602bb88a9fce65e5af522255ad0f5b8749063.
  19. Brian Barto. Bitcoin Toolkit source repository; commit removing Libgcrypt.
  20. Bitcoin Core. Source repository, audited commit f3fec67c3eeb27d5be1bc9d57ca737b74fcd762d.