279 lines
5.4 KiB
Go
279 lines
5.4 KiB
Go
package p256k1
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"hash"
|
|
)
|
|
|
|
// SHA256 represents a SHA-256 hash context
|
|
type SHA256 struct {
|
|
hasher hash.Hash
|
|
}
|
|
|
|
// NewSHA256 creates a new SHA-256 hash context
|
|
func NewSHA256() *SHA256 {
|
|
return &SHA256{
|
|
hasher: sha256.New(),
|
|
}
|
|
}
|
|
|
|
// Initialize initializes the SHA-256 context
|
|
func (h *SHA256) Initialize() {
|
|
h.hasher.Reset()
|
|
}
|
|
|
|
// InitializeTagged initializes the SHA-256 context for tagged hashing (BIP-340)
|
|
func (h *SHA256) InitializeTagged(tag []byte) {
|
|
// Compute SHA256(tag)
|
|
tagHash := sha256.Sum256(tag)
|
|
|
|
// Initialize with SHA256(tag) || SHA256(tag)
|
|
h.hasher.Reset()
|
|
h.hasher.Write(tagHash[:])
|
|
h.hasher.Write(tagHash[:])
|
|
}
|
|
|
|
// Write adds data to the hash
|
|
func (h *SHA256) Write(data []byte) {
|
|
h.hasher.Write(data)
|
|
}
|
|
|
|
// Finalize completes the hash and returns the result
|
|
func (h *SHA256) Finalize(output []byte) {
|
|
if len(output) != 32 {
|
|
panic("SHA-256 output must be 32 bytes")
|
|
}
|
|
|
|
result := h.hasher.Sum(nil)
|
|
copy(output, result[:])
|
|
}
|
|
|
|
// Clear clears the hash context
|
|
func (h *SHA256) Clear() {
|
|
h.hasher.Reset()
|
|
}
|
|
|
|
// TaggedSHA256 computes a tagged hash as defined in BIP-340
|
|
func TaggedSHA256(output []byte, tag []byte, msg []byte) {
|
|
if len(output) != 32 {
|
|
panic("output must be 32 bytes")
|
|
}
|
|
|
|
// Compute SHA256(tag)
|
|
tagHash := sha256.Sum256(tag)
|
|
|
|
// Compute SHA256(SHA256(tag) || SHA256(tag) || msg)
|
|
hasher := sha256.New()
|
|
hasher.Write(tagHash[:])
|
|
hasher.Write(tagHash[:])
|
|
hasher.Write(msg)
|
|
|
|
result := hasher.Sum(nil)
|
|
copy(output, result)
|
|
}
|
|
|
|
// SHA256Simple computes a simple SHA-256 hash
|
|
func SHA256Simple(output []byte, input []byte) {
|
|
if len(output) != 32 {
|
|
panic("output must be 32 bytes")
|
|
}
|
|
|
|
result := sha256.Sum256(input)
|
|
copy(output, result[:])
|
|
}
|
|
|
|
// HMACSHA256 represents an HMAC-SHA256 context for RFC 6979
|
|
type HMACSHA256 struct {
|
|
k [32]byte // HMAC key
|
|
v [32]byte // HMAC value
|
|
init bool
|
|
}
|
|
|
|
// NewHMACSHA256 creates a new HMAC-SHA256 context
|
|
func NewHMACSHA256() *HMACSHA256 {
|
|
return &HMACSHA256{}
|
|
}
|
|
|
|
// Initialize initializes the HMAC context with key data
|
|
func (h *HMACSHA256) Initialize(key []byte) {
|
|
// Initialize V = 0x01 0x01 0x01 ... 0x01
|
|
for i := range h.v {
|
|
h.v[i] = 0x01
|
|
}
|
|
|
|
// Initialize K = 0x00 0x00 0x00 ... 0x00
|
|
for i := range h.k {
|
|
h.k[i] = 0x00
|
|
}
|
|
|
|
// K = HMAC_K(V || 0x00 || key)
|
|
h.updateK(0x00, key)
|
|
|
|
// V = HMAC_K(V)
|
|
h.updateV()
|
|
|
|
// K = HMAC_K(V || 0x01 || key)
|
|
h.updateK(0x01, key)
|
|
|
|
// V = HMAC_K(V)
|
|
h.updateV()
|
|
|
|
h.init = true
|
|
}
|
|
|
|
// updateK updates the K value using HMAC
|
|
func (h *HMACSHA256) updateK(sep byte, data []byte) {
|
|
// Create HMAC with current K
|
|
mac := NewHMACWithKey(h.k[:])
|
|
mac.Write(h.v[:])
|
|
mac.Write([]byte{sep})
|
|
if data != nil {
|
|
mac.Write(data)
|
|
}
|
|
mac.Finalize(h.k[:])
|
|
}
|
|
|
|
// updateV updates the V value using HMAC
|
|
func (h *HMACSHA256) updateV() {
|
|
mac := NewHMACWithKey(h.k[:])
|
|
mac.Write(h.v[:])
|
|
mac.Finalize(h.v[:])
|
|
}
|
|
|
|
// Generate generates pseudorandom bytes
|
|
func (h *HMACSHA256) Generate(output []byte) {
|
|
if !h.init {
|
|
panic("HMAC not initialized")
|
|
}
|
|
|
|
outputLen := len(output)
|
|
generated := 0
|
|
|
|
for generated < outputLen {
|
|
// V = HMAC_K(V)
|
|
h.updateV()
|
|
|
|
// Copy V to output
|
|
toCopy := 32
|
|
if generated+toCopy > outputLen {
|
|
toCopy = outputLen - generated
|
|
}
|
|
copy(output[generated:generated+toCopy], h.v[:toCopy])
|
|
generated += toCopy
|
|
}
|
|
}
|
|
|
|
// Finalize finalizes the HMAC context
|
|
func (h *HMACSHA256) Finalize() {
|
|
// Clear sensitive data
|
|
for i := range h.k {
|
|
h.k[i] = 0
|
|
}
|
|
for i := range h.v {
|
|
h.v[i] = 0
|
|
}
|
|
h.init = false
|
|
}
|
|
|
|
// Clear clears the HMAC context
|
|
func (h *HMACSHA256) Clear() {
|
|
h.Finalize()
|
|
}
|
|
|
|
// HMAC represents an HMAC context
|
|
type HMAC struct {
|
|
inner *SHA256
|
|
outer *SHA256
|
|
keyLen int
|
|
}
|
|
|
|
// NewHMACWithKey creates a new HMAC context with the given key
|
|
func NewHMACWithKey(key []byte) *HMAC {
|
|
h := &HMAC{
|
|
inner: NewSHA256(),
|
|
outer: NewSHA256(),
|
|
keyLen: len(key),
|
|
}
|
|
|
|
// Prepare key
|
|
var k [64]byte
|
|
if len(key) > 64 {
|
|
// Hash long keys
|
|
hasher := sha256.New()
|
|
hasher.Write(key)
|
|
result := hasher.Sum(nil)
|
|
copy(k[:], result)
|
|
} else {
|
|
copy(k[:], key)
|
|
}
|
|
|
|
// Create inner and outer keys
|
|
var ikey, okey [64]byte
|
|
for i := 0; i < 64; i++ {
|
|
ikey[i] = k[i] ^ 0x36
|
|
okey[i] = k[i] ^ 0x5c
|
|
}
|
|
|
|
// Initialize inner hash with inner key
|
|
h.inner.Initialize()
|
|
h.inner.Write(ikey[:])
|
|
|
|
// Initialize outer hash with outer key
|
|
h.outer.Initialize()
|
|
h.outer.Write(okey[:])
|
|
|
|
return h
|
|
}
|
|
|
|
// Write adds data to the HMAC
|
|
func (h *HMAC) Write(data []byte) {
|
|
h.inner.Write(data)
|
|
}
|
|
|
|
// Finalize completes the HMAC and returns the result
|
|
func (h *HMAC) Finalize(output []byte) {
|
|
if len(output) != 32 {
|
|
panic("HMAC output must be 32 bytes")
|
|
}
|
|
|
|
// Get inner hash result
|
|
var innerResult [32]byte
|
|
h.inner.Finalize(innerResult[:])
|
|
|
|
// Complete outer hash
|
|
h.outer.Write(innerResult[:])
|
|
h.outer.Finalize(output)
|
|
}
|
|
|
|
// RFC6979HMACSHA256 implements RFC 6979 deterministic nonce generation
|
|
type RFC6979HMACSHA256 struct {
|
|
hmac *HMACSHA256
|
|
}
|
|
|
|
// NewRFC6979HMACSHA256 creates a new RFC 6979 HMAC context
|
|
func NewRFC6979HMACSHA256() *RFC6979HMACSHA256 {
|
|
return &RFC6979HMACSHA256{
|
|
hmac: NewHMACSHA256(),
|
|
}
|
|
}
|
|
|
|
// Initialize initializes the RFC 6979 context
|
|
func (r *RFC6979HMACSHA256) Initialize(key []byte) {
|
|
r.hmac.Initialize(key)
|
|
}
|
|
|
|
// Generate generates deterministic nonce bytes
|
|
func (r *RFC6979HMACSHA256) Generate(output []byte) {
|
|
r.hmac.Generate(output)
|
|
}
|
|
|
|
// Finalize finalizes the RFC 6979 context
|
|
func (r *RFC6979HMACSHA256) Finalize() {
|
|
r.hmac.Finalize()
|
|
}
|
|
|
|
// Clear clears the RFC 6979 context
|
|
func (r *RFC6979HMACSHA256) Clear() {
|
|
r.hmac.Clear()
|
|
}
|