Documentation
¶
Overview ¶
Package ripemd160mb computes RIPEMD-160 hashes, with a multi-buffer fixed-32-byte fast path designed for Bitcoin-style Hash160 pipelines.
The package offers two layers of API:
- General purpose: New returns a streaming hash.Hash, and Sum hashes a single message of any length. Both are byte-for-byte compatible with golang.org/x/crypto/ripemd160.
- Fast path: Hash32 hashes many independent 32-byte messages in one call, and HashEach is a convenience wrapper for a slice of arbitrary messages.
Hash32 buffer layout ¶
Hash32 reads n messages of exactly 32 bytes from a single contiguous source buffer and writes n digests of exactly Size (20) bytes to a single contiguous destination buffer. Message i occupies src[i*32:(i+1)*32] and its digest occupies dst[i*Size:(i+1)*Size]:
src: | msg 0 (32B) | msg 1 (32B) | ... | msg n-1 (32B) | dst: | dig 0 (20B) | dig 1 (20B) | ... | dig n-1 (20B) |
Hash32 does not allocate, holds no state between calls, and is safe for concurrent use by multiple goroutines.
Panics ¶
Hash32 panics if n is negative, if len(src) < n*32, or if len(dst) < n*Size. HashEach panics if len(dst) != len(src). These conditions indicate a caller bug rather than a runtime error, so they are not reported via error values.
Backend selection ¶
At package initialization the implementation selects the fastest backend available in this build for the current architecture. The scalar backend is a pure-Go implementation that also serves as the correctness oracle for the vector backends. Backend reports the active backend name and Lanes reports how many messages it processes in parallel.
Two backends are implemented today: a hand-tuned 4-lane arm64 NEON kernel (the default on arm64, several times faster than scalar) and the portable scalar fallback (the default everywhere else). amd64 SIMD kernels are planned but not yet implemented, so amd64 currently runs the scalar backend.
The environment variable GORIPEMD160MB_FORCE may be set to scalar or neon to pin a specific backend. An unknown value, or a backend not implemented for the current architecture, falls back to scalar rather than failing; the value reported by Backend always names the kernel that actually runs.
Example (Hash160HotPath) ¶
Example_hash160HotPath shows the recommended high-throughput HASH160 pattern, the one a Bitcoin-style brute-force pipeline should use: compute the SHA-256 digests yourself (here with crypto/sha256, but typically a vectorized SHA-256) into a single reusable n*32 buffer, then call Hash32 once. Hash32 allocates nothing and is safe to call from many worker goroutines, so the only work per batch is the hashing itself.
const (
n = 8
width = 33 // compressed public keys
)
keys := make([]byte, n*width)
for i := range keys {
keys[i] = byte(i)
}
// Reused across batches in a real worker; shown once here.
digests := make([]byte, n*32) // SHA-256 outputs, contiguous
out := make([]byte, n*ripemd160mb.Size)
for i := 0; i < n; i++ {
sum := sha256.Sum256(keys[i*width : (i+1)*width])
copy(digests[i*32:], sum[:])
}
ripemd160mb.Hash32(out, digests, n)
ok := true
for i := 0; i < n; i++ {
sum := sha256.Sum256(keys[i*width : (i+1)*width])
want := ripemd160mb.Sum(sum[:])
if !bytes.Equal(out[i*ripemd160mb.Size:(i+1)*ripemd160mb.Size], want[:]) {
ok = false
}
}
fmt.Println(ok)
Output: true
Index ¶
Examples ¶
Constants ¶
const ( // Size is the size, in bytes, of a RIPEMD-160 digest. Size = 20 // BlockSize is RIPEMD-160's internal block size in bytes. BlockSize = 64 )
Variables ¶
This section is empty.
Functions ¶
func Backend ¶
func Backend() string
Backend returns the active backend name.
Example ¶
ExampleBackend reports which kernel is active and how many messages it hashes per call. A diagnostic banner like this lets a caller confirm at startup whether it is running the SIMD or the scalar path.
// In real code: log.Printf("ripemd160mb backend=%s lanes=%d", ...)
_ = ripemd160mb.Backend() // e.g. "neon" on arm64, "scalar" elsewhere
lanes := ripemd160mb.Lanes()
fmt.Println(lanes >= 1)
Output: true
func Hash32 ¶
Hash32 hashes n independent 32-byte messages from src into dst.
The buffers are contiguous: message i is src[i*32:(i+1)*32] and its digest is written to dst[i*Size:(i+1)*Size]. src must contain at least n*32 bytes and dst at least n*Size bytes. Hash32 does not allocate and is safe for concurrent use by multiple goroutines.
Hash32 panics if n is negative, if len(src) < n*32, or if len(dst) < n*Size. A count of zero is a no-op and tolerates nil buffers.
Example ¶
ExampleHash32 shows the multi-buffer fast path: several 32-byte messages are laid out contiguously and hashed in a single call. Each 20-byte output lane equals the single-message Sum of the matching input slice.
const n = 3
src := make([]byte, n*32)
for i := range src {
src[i] = byte(i)
}
dst := make([]byte, n*ripemd160mb.Size)
ripemd160mb.Hash32(dst, src, n)
consistent := true
for i := 0; i < n; i++ {
want := ripemd160mb.Sum(src[i*32 : (i+1)*32])
if !bytes.Equal(dst[i*ripemd160mb.Size:(i+1)*ripemd160mb.Size], want[:]) {
consistent = false
}
}
fmt.Println(consistent)
Output: true
func HashEach ¶
HashEach hashes each source message independently into the corresponding dst element, where dst[i] = Sum(src[i]). Unlike Hash32, the messages may have arbitrary lengths.
HashEach panics if len(dst) != len(src).
func Lanes ¶
func Lanes() int
Lanes returns the number of messages processed in parallel by the active backend. It returns 1 for the scalar backend.
func New ¶
New returns a new RIPEMD-160 hash.Hash.
Example ¶
ExampleNew uses the streaming hash.Hash interface, which accepts arbitrary messages written in any number of chunks.
h := ripemd160mb.New()
io.WriteString(h, "ab")
io.WriteString(h, "c")
fmt.Printf("%x\n", h.Sum(nil))
Output: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
Types ¶
This section is empty.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
hash160
command
|
|
|
Package hash160 combines SHA-256 and ripemd160mb.Hash32 for Bitcoin-style HASH160 pipelines.
|
Package hash160 combines SHA-256 and ripemd160mb.Hash32 for Bitcoin-style HASH160 pipelines. |
|
internal
|
|
|
neongen
command
Command neongen emits the arm64 NEON kernel block_arm64.s.
|
Command neongen emits the arm64 NEON kernel block_arm64.s. |