| Crates.io | bitcoin-hmac-sha256 |
| lib.rs | bitcoin-hmac-sha256 |
| version | 0.1.2 |
| created_at | 2025-12-01 04:07:30.553909+00 |
| updated_at | 2025-12-01 04:07:30.553909+00 |
| description | Low-level, allocation-free HMAC-SHA-256 and RFC6979 deterministic nonce generator with FFI-friendly APIs, tailored for Bitcoin-style cryptography. |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1959260 |
| size | 140,157 |
A minimal, allocation-free implementation of HMAC-SHA-256 and RFC 6979 deterministic nonces tailored for Bitcoin-style cryptography and FFI use.
This crate exposes two tightly scoped primitives:
HmacSha256 – a streaming HMAC-SHA-256 construction over an internal Sha256 implementation.Rfc6979HmacSha256 – a deterministic pseudo-random generator implementing RFC 6979 §3.2 using HMAC-SHA-256.The primary design goals are:
This is a low‑level crate intended for cryptographic libraries and bindings, not for general application-level hashing.
HMAC (Hash-based Message Authentication Code) is defined as
[ \mathrm{HMAC}_k(m) = H\Big((k' \oplus opad) ,\Vert, H((k' \oplus ipad) ,\Vert, m)\Big), ]
where
H is SHA-256,k' is the key normalized to the block size of SHA-256 (64 bytes), either by zero-padding or hashing and then zero-padding,ipad = 0x36 repeated 64 times,opad = 0x5c repeated 64 times.HmacSha256 implements exactly this construction with an inner and outer Sha256 state.
RFC 6979 describes how to derive deterministic ECDSA nonces from a secret key and message hash using an HMAC-based DRBG. This crate:
(K, V, retry) in Rfc6979HmacSha256.initialize, generate, and finalize procedures via C-friendly functions.This is useful in contexts where you must avoid reliance on ambient randomness and instead derive nonces purely from secret key material and the hashed message (e.g., Bitcoin ECDSA signatures).
*const u8, length) or safe slices.write / write_ref calls before finalize_into.The crate provides two layers of API:
HmacSha256, Rfc6979HmacSha256).unsafe FFI-style functions that operate on raw pointers, mirroring the original C implementation.The FFI functions are unsafe from the caller’s perspective because they assume:
If you can, prefer the safe methods; use the FFI-style functions only when integrating with C or C++.
HmacSha256#[derive(Getters, MutGetters, Setters)]
pub struct HmacSha256 {
outer: Sha256,
inner: Sha256,
}
impl HmacSha256 {
/// Construct from a raw pointer + length (FFI-style, unsafe boundary).
pub fn new(key: *const u8, keylen: usize) -> Self { ... }
/// Construct from a Rust byte slice (preferred).
#[inline]
pub fn new_with_key(key: &[u8]) -> Self { ... }
/// Construct directly from a slice.
pub fn from_slice(key: &[u8]) -> Self { ... }
}
from_slice implements the standard HMAC key normalization:
key.len() <= 64, it copies the key into a 64-byte array, zero-padding on the right.key.len() > 64, it hashes the key with Sha256, places the 32-byte digest into the beginning of the 64-byte array, and zero-pads the rest.ipad and opad states and initializes the inner and outer Sha256 contexts.impl HmacSha256 {
/// Write data from a raw pointer + length (unsafe boundary).
pub fn write(&mut self, data: *const u8, len: usize) -> &mut HmacSha256 { ... }
/// Write data from a byte slice (safe, preferred).
#[inline]
pub fn write_ref(&mut self, data: &[u8]) -> &mut HmacSha256 { ... }
/// Finalize into the provided 32-byte output buffer.
pub fn finalize_into(&mut self, out: &mut [u8; HMAC_SHA256_OUTPUT_SIZE]) { ... }
/// Legacy finalize signature, takes `hash` by value.
pub fn finalize(&mut self, mut hash: [u8; HMAC_SHA256_OUTPUT_SIZE]) { ... }
}
Usage pattern:
use bitcoin_hmac_sha256::HmacSha256;
const HMAC_SHA256_OUTPUT_SIZE: usize = 32;
let key = b"my hmac key";
let msg1 = b"hello";
let msg2 = b" world";
let mut hmac = HmacSha256::new_with_key(key);
hmac.write_ref(msg1)
.write_ref(msg2);
let mut tag = [0u8; HMAC_SHA256_OUTPUT_SIZE];
hmac.finalize_into(&mut tag);
// `tag` now holds HMAC-SHA-256(key, msg1 || msg2)
Rfc6979HmacSha256#[derive(Builder, Getters, Setters, MutGetters)]
pub struct Rfc6979HmacSha256 {
v: [u8; 32],
k: [u8; 32],
retry: i32,
}
This struct implements the internal state of the RFC 6979 HMAC-DRBG with SHA-256.
pub fn rfc6979_hmac_sha256_initialize(
rng: *mut Rfc6979HmacSha256,
key: *const u8,
keylen: usize,
) { ... }
This function performs RFC 6979 §3.2 steps (b)–(f):
V to 0x01 repeated.K to 0x00 repeated.key via a sequence of HMAC invocations (K, V, and the input key), using the HmacSha256 primitive.retry to 0.The key argument should be the RFC 6979 “key material” – usually the concatenation of the private key and hashed message, but that combination is handled by higher-level code.
pub fn rfc6979_hmac_sha256_generate(
rng: *mut Rfc6979HmacSha256,
mut out: *mut u8,
mut outlen: usize,
) { ... }
This function implements RFC 6979 §3.2(h):
retry != 0.V value to produce pseudo-random output.outlen bytes into out, possibly across multiple 32-byte blocks.retry = 1 to mark that subsequent calls should do the "extra" update.Typical use in ECDSA:
rfc6979_hmac_sha256_initialize with the concatenated key material.rfc6979_hmac_sha256_generate to obtain enough bytes for a candidate scalar k.generate again.pub fn rfc6979_hmac_sha256_finalize(rng: *mut Rfc6979HmacSha256) { ... }
This function wipes K and V with zeros and resets retry to 0. You should call this once you are done with the nonce generator to reduce key material lifetime in memory.
The crate also provides C-like functions that operate on HmacSha256 via raw pointers. These are useful when exposing the crate to C or C++ or when preserving existing foreign interfaces.
pub fn hmac_sha256_initialize(
hash: *mut HmacSha256,
key: *const u8,
keylen: usize,
) { ... }
pub fn hmac_sha256_write(
hash: *mut HmacSha256,
data: *const u8,
size: usize,
) { ... }
pub fn hmac_sha256_finalize(
hash: *mut HmacSha256,
out32: *mut u8,
) { ... }
use bitcoin_hmac_sha256::{
HmacSha256,
hmac_sha256_initialize,
hmac_sha256_write,
hmac_sha256_finalize,
};
unsafe {
let key = b"secret";
let data = b"message";
// Memory owned on Rust side; passed to FFI-style API
let mut ctx: HmacSha256 = core::mem::zeroed();
let mut out = [0u8; 32];
hmac_sha256_initialize(&mut ctx, key.as_ptr(), key.len());
hmac_sha256_write(&mut ctx, data.as_ptr(), data.len());
hmac_sha256_finalize(&mut ctx, out.as_mut_ptr());
// `out` now contains the HMAC tag
}
Add the dependency:
[dependencies]
bitcoin-hmac-sha256 = "0.1.2"
The crate is licensed under MIT and targets the Rust 2024 edition.
rfc6979_hmac_sha256_finalize to wipe DRBG state once done.For production systems, you should layer these primitives beneath a rigorously audited signing and key-handling framework.
For practical use, you should:
This crate is distributed under the MIT license. See your Cargo.toml or accompanying license file for details.