Add benchmark results and performance analysis for ECDSA and ECDH operations
This commit introduces two new files: `BENCHMARK_RESULTS.md` and `benchmark_results.txt`, which document the performance metrics of various cryptographic operations, including ECDSA signing, verification, and ECDH key exchange. The results provide insights into operation times, memory allocations, and comparisons with C implementations. Additionally, new test files for ECDSA and ECDH functionalities have been added, ensuring comprehensive coverage and validation of the implemented algorithms. This enhances the overall robustness and performance understanding of the secp256k1 implementation.
This commit is contained in:
274
hash.go
Normal file
274
hash.go
Normal file
@@ -0,0 +1,274 @@
|
||||
package p256k1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// SHA256 represents a SHA-256 hash context
|
||||
type SHA256 struct {
|
||||
hasher hash.Hash
|
||||
}
|
||||
|
||||
// NewSHA256 creates a new SHA-256 hash context
|
||||
func NewSHA256() *SHA256 {
|
||||
h := &SHA256{}
|
||||
h.hasher = sha256.New()
|
||||
return h
|
||||
}
|
||||
|
||||
// Write writes data to the hash
|
||||
func (h *SHA256) Write(data []byte) {
|
||||
h.hasher.Write(data)
|
||||
}
|
||||
|
||||
// Sum finalizes the hash and returns the 32-byte result
|
||||
func (h *SHA256) Sum(out []byte) []byte {
|
||||
if out == nil {
|
||||
out = make([]byte, 32)
|
||||
}
|
||||
copy(out, h.hasher.Sum(nil))
|
||||
return out
|
||||
}
|
||||
|
||||
// Finalize finalizes the hash and writes the result to out32 (must be 32 bytes)
|
||||
func (h *SHA256) Finalize(out32 []byte) {
|
||||
if len(out32) != 32 {
|
||||
panic("output buffer must be 32 bytes")
|
||||
}
|
||||
sum := h.hasher.Sum(nil)
|
||||
copy(out32, sum)
|
||||
}
|
||||
|
||||
// Clear clears the hash context to prevent leaking sensitive information
|
||||
func (h *SHA256) Clear() {
|
||||
memclear(unsafe.Pointer(h), unsafe.Sizeof(*h))
|
||||
}
|
||||
|
||||
// HMACSHA256 represents an HMAC-SHA256 context
|
||||
type HMACSHA256 struct {
|
||||
inner, outer SHA256
|
||||
}
|
||||
|
||||
// NewHMACSHA256 creates a new HMAC-SHA256 context with the given key
|
||||
func NewHMACSHA256(key []byte) *HMACSHA256 {
|
||||
h := &HMACSHA256{}
|
||||
|
||||
// Prepare key: if keylen > 64, hash it first
|
||||
var rkey [64]byte
|
||||
if len(key) <= 64 {
|
||||
copy(rkey[:], key)
|
||||
// Zero pad the rest
|
||||
for i := len(key); i < 64; i++ {
|
||||
rkey[i] = 0
|
||||
}
|
||||
} else {
|
||||
// Hash the key if it's too long
|
||||
hasher := sha256.New()
|
||||
hasher.Write(key)
|
||||
sum := hasher.Sum(nil)
|
||||
copy(rkey[:32], sum)
|
||||
// Zero pad the rest
|
||||
for i := 32; i < 64; i++ {
|
||||
rkey[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize outer hash with key XOR 0x5c
|
||||
h.outer = SHA256{hasher: sha256.New()}
|
||||
for i := 0; i < 64; i++ {
|
||||
rkey[i] ^= 0x5c
|
||||
}
|
||||
h.outer.hasher.Write(rkey[:])
|
||||
|
||||
// Initialize inner hash with key XOR 0x36
|
||||
h.inner = SHA256{hasher: sha256.New()}
|
||||
for i := 0; i < 64; i++ {
|
||||
rkey[i] ^= 0x5c ^ 0x36
|
||||
}
|
||||
h.inner.hasher.Write(rkey[:])
|
||||
|
||||
// Clear sensitive key material
|
||||
memclear(unsafe.Pointer(&rkey), unsafe.Sizeof(rkey))
|
||||
return h
|
||||
}
|
||||
|
||||
// Write writes data to the inner hash
|
||||
func (h *HMACSHA256) Write(data []byte) {
|
||||
h.inner.Write(data)
|
||||
}
|
||||
|
||||
// Finalize finalizes the HMAC and writes the result to out32 (must be 32 bytes)
|
||||
func (h *HMACSHA256) Finalize(out32 []byte) {
|
||||
if len(out32) != 32 {
|
||||
panic("output buffer must be 32 bytes")
|
||||
}
|
||||
|
||||
// Finalize inner hash
|
||||
var temp [32]byte
|
||||
h.inner.Finalize(temp[:])
|
||||
|
||||
// Feed inner hash result to outer hash
|
||||
h.outer.Write(temp[:])
|
||||
|
||||
// Finalize outer hash
|
||||
h.outer.Finalize(out32)
|
||||
|
||||
// Clear temp
|
||||
memclear(unsafe.Pointer(&temp), unsafe.Sizeof(temp))
|
||||
}
|
||||
|
||||
// Clear clears the HMAC context
|
||||
func (h *HMACSHA256) Clear() {
|
||||
h.inner.Clear()
|
||||
h.outer.Clear()
|
||||
memclear(unsafe.Pointer(h), unsafe.Sizeof(*h))
|
||||
}
|
||||
|
||||
// RFC6979HMACSHA256 implements RFC 6979 deterministic nonce generation
|
||||
type RFC6979HMACSHA256 struct {
|
||||
v [32]byte
|
||||
k [32]byte
|
||||
retry int
|
||||
}
|
||||
|
||||
// NewRFC6979HMACSHA256 initializes a new RFC6979 HMAC-SHA256 context
|
||||
func NewRFC6979HMACSHA256(key []byte) *RFC6979HMACSHA256 {
|
||||
rng := &RFC6979HMACSHA256{}
|
||||
|
||||
// RFC6979 3.2.b: V = 0x01 0x01 0x01 ... 0x01 (32 bytes)
|
||||
for i := 0; i < 32; i++ {
|
||||
rng.v[i] = 0x01
|
||||
}
|
||||
|
||||
// RFC6979 3.2.c: K = 0x00 0x00 0x00 ... 0x00 (32 bytes)
|
||||
for i := 0; i < 32; i++ {
|
||||
rng.k[i] = 0x00
|
||||
}
|
||||
|
||||
// RFC6979 3.2.d: K = HMAC_K(V || 0x00 || key)
|
||||
hmac := NewHMACSHA256(rng.k[:])
|
||||
hmac.Write(rng.v[:])
|
||||
hmac.Write([]byte{0x00})
|
||||
hmac.Write(key)
|
||||
hmac.Finalize(rng.k[:])
|
||||
hmac.Clear()
|
||||
|
||||
// V = HMAC_K(V)
|
||||
hmac = NewHMACSHA256(rng.k[:])
|
||||
hmac.Write(rng.v[:])
|
||||
hmac.Finalize(rng.v[:])
|
||||
hmac.Clear()
|
||||
|
||||
// RFC6979 3.2.f: K = HMAC_K(V || 0x01 || key)
|
||||
hmac = NewHMACSHA256(rng.k[:])
|
||||
hmac.Write(rng.v[:])
|
||||
hmac.Write([]byte{0x01})
|
||||
hmac.Write(key)
|
||||
hmac.Finalize(rng.k[:])
|
||||
hmac.Clear()
|
||||
|
||||
// V = HMAC_K(V)
|
||||
hmac = NewHMACSHA256(rng.k[:])
|
||||
hmac.Write(rng.v[:])
|
||||
hmac.Finalize(rng.v[:])
|
||||
hmac.Clear()
|
||||
|
||||
rng.retry = 0
|
||||
return rng
|
||||
}
|
||||
|
||||
// Generate generates output bytes using RFC6979
|
||||
func (rng *RFC6979HMACSHA256) Generate(out []byte) {
|
||||
// RFC6979 3.2.h: If retry, update K and V
|
||||
if rng.retry != 0 {
|
||||
hmac := NewHMACSHA256(rng.k[:])
|
||||
hmac.Write(rng.v[:])
|
||||
hmac.Write([]byte{0x00})
|
||||
hmac.Finalize(rng.k[:])
|
||||
hmac.Clear()
|
||||
|
||||
hmac = NewHMACSHA256(rng.k[:])
|
||||
hmac.Write(rng.v[:])
|
||||
hmac.Finalize(rng.v[:])
|
||||
hmac.Clear()
|
||||
}
|
||||
|
||||
// Generate output bytes
|
||||
outlen := len(out)
|
||||
for outlen > 0 {
|
||||
hmac := NewHMACSHA256(rng.k[:])
|
||||
hmac.Write(rng.v[:])
|
||||
hmac.Finalize(rng.v[:])
|
||||
hmac.Clear()
|
||||
|
||||
now := outlen
|
||||
if now > 32 {
|
||||
now = 32
|
||||
}
|
||||
copy(out, rng.v[:now])
|
||||
out = out[now:]
|
||||
outlen -= now
|
||||
}
|
||||
|
||||
rng.retry = 1
|
||||
}
|
||||
|
||||
// Finalize finalizes the RFC6979 context
|
||||
func (rng *RFC6979HMACSHA256) Finalize() {
|
||||
// Nothing to do, but matches C API
|
||||
}
|
||||
|
||||
// Clear clears the RFC6979 context
|
||||
func (rng *RFC6979HMACSHA256) Clear() {
|
||||
memclear(unsafe.Pointer(rng), unsafe.Sizeof(*rng))
|
||||
}
|
||||
|
||||
// TaggedHash computes SHA256(SHA256(tag) || SHA256(tag) || data)
|
||||
// This is used in BIP-340 for Schnorr signatures
|
||||
func TaggedHash(tag []byte, data []byte) [32]byte {
|
||||
var result [32]byte
|
||||
|
||||
// First hash: SHA256(tag)
|
||||
h := NewSHA256()
|
||||
h.Write(tag)
|
||||
h.Finalize(result[:])
|
||||
|
||||
// Second hash: SHA256(SHA256(tag) || SHA256(tag) || data)
|
||||
h = NewSHA256()
|
||||
h.Write(result[:]) // SHA256(tag)
|
||||
h.Write(result[:]) // SHA256(tag) again
|
||||
h.Write(data)
|
||||
h.Finalize(result[:])
|
||||
h.Clear()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// HashToScalar converts a 32-byte hash to a scalar value
|
||||
func HashToScalar(hash []byte) (*Scalar, error) {
|
||||
if len(hash) != 32 {
|
||||
return nil, errors.New("hash must be 32 bytes")
|
||||
}
|
||||
|
||||
var scalar Scalar
|
||||
scalar.setB32(hash)
|
||||
return &scalar, nil
|
||||
}
|
||||
|
||||
// HashToField converts a 32-byte hash to a field element
|
||||
func HashToField(hash []byte) (*FieldElement, error) {
|
||||
if len(hash) != 32 {
|
||||
return nil, errors.New("hash must be 32 bytes")
|
||||
}
|
||||
|
||||
var field FieldElement
|
||||
if err := field.setB32(hash); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &field, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user