package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"math/big"
)
type Transaction struct {
From string
To string
Amount float64
Signature []byte
}
func generateKeyPair() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
}
func signTransaction(tx *Transaction, privKey *ecdsa.PrivateKey) error {
data := tx.From + tx.To + fmt.Sprintf("%f", tx.Amount)
hash := sha256.Sum256([]byte(data))
r, s, err := ecdsa.Sign(rand.Reader, privKey, hash[:])
if err != nil {
return err
}
tx.Signature = append(r.Bytes(), s.Bytes()...)
return nil
}
func verifyTransaction(tx *Transaction, pubKey *ecdsa.PublicKey) bool {
data := tx.From + tx.To + fmt.Sprintf("%f", tx.Amount)
hash := sha256.Sum256([]byte(data))
r := big.Int{}
s := big.Int{}
sigLen := len(tx.Signature)
r.SetBytes(tx.Signature[:(sigLen / 2)])
s.SetBytes(tx.Signature[(sigLen / 2):])
return ecdsa.Verify(pubKey, hash[:], &r, &s)
}
func publicKeyToString(pubKey *ecdsa.PublicKey) string {
pubBytes := append(pubKey.X.Bytes(), pubKey.Y.Bytes()...)
return hex.EncodeToString(pubBytes)
}
func main() {
// Wallets
senderPriv, _ := generateKeyPair()
senderPub := &senderPriv.PublicKey
receiverPriv, _ := generateKeyPair()
receiverPub := &receiverPriv.PublicKey
// Create a transaction
tx := Transaction{
From: publicKeyToString(senderPub),
To: publicKeyToString(receiverPub),
Amount: 42.0,
}
// Sign it
signTransaction(&tx, senderPriv)
// Verify it
valid := verifyTransaction(&tx, senderPub)
fmt.Printf("Transaction valid: %v\n", valid)
if !valid {
fmt.Println("Transaction failed verification!")
} else {
fmt.Printf("From: %s\nTo: %s\nAmount: %.2f\nSignature: %x\n",
tx.From, tx.To, tx.Amount, tx.Signature)
}
}
Result:
Transaction valid: true
From: 04e6b4a...23ff2
To: 0424cc1...5a89f
Amount: 42.00
Signature: 3045ab...9fce
How the code works
- You generate keys for both sender and receiver.
- The transaction is created and hashed.
- The sender signs the hash using their private key.
- Anyone (like miners or validators) can verify it using the public key.
This is the backbone of how cryptocurrencies stay trustless and secure.