diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go new file mode 100644 index 0000000..9bc97d1 --- /dev/null +++ b/blockchain/blockchain.go @@ -0,0 +1,44 @@ +package blockchain + +import ( + "crypto/sha256" + "encoding/binary" +) + +type BlockHeader struct { + blockNumber uint32 + lastBlock Hash + miner Wallet +} + +func (bh *BlockHeader) Marshal() []byte { + buf := []byte{} + binary.LittleEndian.PutUint32(buf, bh.blockNumber) + buf = append(buf, bh.lastBlock...) + buf = append(buf, bh.miner.Marshal()...) + return buf +} + +type Block struct { + BlockHeader + transactions []Transaction +} + +func (b *Block) Marshal() []byte { + buf := b.BlockHeader.Marshal() + for _, t := range b.transactions { + buf = append(buf, t.Marshal()...) + } + return buf +} + +func (b *Block) Hash() []byte { + sum := sha256.Sum256(b.Marshal()) + return sum[:] +} + +type BlockChain []Block + +func (bc BlockChain) Verify(b *Block) { + +} diff --git a/blockchain/transaction.go b/blockchain/transaction.go new file mode 100644 index 0000000..847d250 --- /dev/null +++ b/blockchain/transaction.go @@ -0,0 +1,50 @@ +package blockchain + +import ( + "encoding/binary" +) + +// TxHashPointer is a reference to a transaction on the blockchain. +type TxHashPointer struct { + blockNumber uint32 + hash []byte +} + +func (thp TxHashPointer) Marshal() []byte { + buf := []byte{} + binary.LittleEndian.PutUint32(buf, thp.blockNumber) + return append(buf, thp.hash...) +} + +// TxBody contains all relevant information about a transaction. +type TxBody struct { + sender Wallet + inputs []TxHashPointer + outputs []TxHashPointer +} + +func (tb *TxBody) Marshal() []byte { + buf := tb.sender.Marshal() + for _, input := range tb.inputs { + buf = append(buf, input.Marshal()...) + } + for _, output := range tb.outputs { + buf = append(buf, output.Marshal()...) + } + return buf +} + +// Transaction contains a TxBody and a signature verifying it. +type Transaction struct { + TxBody + hash Hash + sig Signature +} + +func (t *Transaction) Marshal() []byte { + buf := t.TxBody.Marshal() + buf = append(buf, t.hash...) + buf = append(buf, t.sig.X.Bytes()...) + buf = append(buf, t.sig.Y.Bytes()...) + return buf +} diff --git a/blockchain/wallet.go b/blockchain/wallet.go new file mode 100644 index 0000000..0f99636 --- /dev/null +++ b/blockchain/wallet.go @@ -0,0 +1,50 @@ +package blockchain + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "fmt" + "math/big" +) + +var curve = elliptic.P256() + +// Wallet represents a Cumulus wallet address in the blockchain. +type Wallet ecdsa.PublicKey + +// Hash represents a hash of a transaction. +type Hash []byte + +// Signature represents a signature of a transaction. +type Signature struct { + X big.Int + Y big.Int +} + +// New creates a new Wallet backed by a ECC key pair. Uses system entropy. +func NewWallet() (*Wallet, error) { + k, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, err + } + pk := Wallet(k.PublicKey) + return &pk, nil +} + +func (w *Wallet) String() string { + return fmt.Sprintf("%x-%x", w.X, w.Y) +} + +func (w *Wallet) Marshal() []byte { + return elliptic.Marshal(curve, w.X, w.Y) +} + +func (w *Wallet) Equals(other *Wallet) bool { + return w.X.Cmp(other.X) == 0 && w.Y.Cmp(other.Y) == 0 +} + +func Unmarshal(wallet []byte) *Wallet { + x, y := elliptic.Unmarshal(curve, wallet) + return &Wallet{curve, x, y} +} diff --git a/blockchain/wallet_test.go b/blockchain/wallet_test.go new file mode 100644 index 0000000..76f922d --- /dev/null +++ b/blockchain/wallet_test.go @@ -0,0 +1,20 @@ +package blockchain + +import ( + "fmt" + "testing" +) + +func TestUnmarshal(t *testing.T) { + w, err := NewWallet() + if err != nil { + t.Fail() + } + + unmarshalled := Unmarshal(w.Marshal()) + fmt.Println("w", w.X, w.Y) + fmt.Println("u", unmarshalled.X, unmarshalled.Y) + if !w.Equals(unmarshalled) { + t.Fatal("Unmarshal produced a different wallet") + } +}