Skip to content

Commit

Permalink
Add package wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasgeihs committed Oct 6, 2021
1 parent 90b949a commit cdb6657
Show file tree
Hide file tree
Showing 7 changed files with 482 additions and 0 deletions.
37 changes: 37 additions & 0 deletions wallet/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2021 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package wallet

import (
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"perun.network/go-perun/wallet"
)

// Account represents an account held in the HD wallet.
type Account struct {
kr keyring.Keyring
addr *Address
}

// Address returns the address of this account.
func (a *Account) Address() wallet.Address {
return a.addr
}

// SignData is used to sign data with this account.
func (a *Account) SignData(data []byte) ([]byte, error) {
sig, _, err := a.kr.SignByAddress(a.addr.CosmAddr(), data)
return sig, err
}
102 changes: 102 additions & 0 deletions wallet/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2021 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package wallet

import (
"bytes"
"fmt"
"io"

"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
ctypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types"
cio "github.com/perun-network/perun-cosmwasm-backend/pkg/io"
"perun.network/go-perun/wallet"
)

// Address represents an account address.
type Address struct {
ctypes.PubKey
}

// NewAddress creates a new address.
func NewAddress(pk ctypes.PubKey) *Address {
a := Address{pk}
return &a
}

// CosmAddr returns the cosmos address.
func (a *Address) CosmAddr() types.Address {
return types.AccAddress(a.Address().Bytes())
}

// AsAddr attempts to cast a generic address into a specific address.
func AsAddr(addr wallet.Address) (*Address, error) {
a, ok := addr.(*Address)
if !ok {
return nil, fmt.Errorf("invalid type: %T", addr)
}
return a, nil
}

// Encode writes the object to a stream.
func (a *Address) Encode(w io.Writer) error {
pk, ok := a.PubKey.(*secp256k1.PubKey)
if !ok {
panic(fmt.Sprintf("wrong type: %T", a.PubKey))
}
return cio.WriteBytesUint16(w, pk.Key)
}

// Decode reads an object from a stream.
func (a *Address) Decode(r io.Reader) error {
var b []byte
err := cio.ReadBytesUint16(r, &b)
if err != nil {
return fmt.Errorf("reading byte stream: %w", err)
}

pk := secp256k1.PubKey{
Key: b,
}
*a = *NewAddress(&pk)
return nil
}

// Bytes returns the representation of the address as byte slice.
func (a *Address) Bytes() []byte {
return a.PubKey.Bytes()
}

// String converts this address to a string.
func (a *Address) String() string {
return types.AccAddress(a.PubKey.Address().Bytes()).String()
}

// Equals returns whether the two addresses are equal. The implementation
// must be equivalent to checking `Address.Cmp(Address) == 0`.
func (a *Address) Equals(b wallet.Address) bool {
_b, err := AsAddr(b)
if err != nil {
return false
}
return a.PubKey.Equals(_b.PubKey)
}

// Cmp compares the byte representation of two addresses. For `a.Cmp(b)`
// returns -1 if a < b, 0 if a == b, 1 if a > b.
func (a Address) Cmp(b wallet.Address) int {
return bytes.Compare(a.Bytes(), b.Bytes())
}
54 changes: 54 additions & 0 deletions wallet/backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2021 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package wallet

import (
"io"

pio "perun.network/go-perun/pkg/io"
"perun.network/go-perun/wallet"
)

// Backend provides utility functions.
type Backend struct{}

func NewBackend() *Backend {
return &Backend{}
}

// DecodeAddress reads and decodes an address from an io.Writer
func (b *Backend) DecodeAddress(r io.Reader) (wallet.Address, error) {
var a Address
err := a.Decode(r)
return &a, err
}

const SigntuareLength = 64

// DecodeSig reads a signature from the provided stream.
func (b *Backend) DecodeSig(r io.Reader) (wallet.Sig, error) {
sig := make([]byte, SigntuareLength)
return sig, pio.Decode(r, &sig)
}

// VerifySignature verifies if this signature was signed by this address.
func (b *Backend) VerifySignature(msg []byte, sig wallet.Sig, addr wallet.Address) (bool, error) {
a, err := AsAddr(addr)
if err != nil {
return false, err
}

return a.PubKey.VerifySignature(msg, sig), nil
}
52 changes: 52 additions & 0 deletions wallet/test/randomizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2021 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package test

import (
"math/rand"

"perun.network/go-perun/wallet"
wallettest "perun.network/go-perun/wallet/test"
)

// Randomizer provides methods for generating randomized test input.
type Randomizer struct {
w *Wallet
}

func NewRandomizer() *Randomizer {
return &Randomizer{
w: NewWallet(),
}
}

// NewRandomAddress returns a new random address generated from the
// passed rng.
func (r *Randomizer) NewRandomAddress(rng *rand.Rand) wallet.Address {
return r.RandomWallet().NewRandomAccount(rng).Address()
}

// RandomWallet returns a fixed random wallet that is part of the
// randomizer's state. It will be used to generate accounts with
// NewRandomAccount.
func (r *Randomizer) RandomWallet() wallettest.Wallet {
return r.w
}

// NewWallet returns a fresh, temporary Wallet that doesn't hold any
// accounts yet.
func (r *Randomizer) NewWallet() wallettest.Wallet {
return NewWallet()
}
59 changes: 59 additions & 0 deletions wallet/test/wallet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2021 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package test

import (
"fmt"
"math/rand"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
bwallet "github.com/perun-network/perun-cosmwasm-backend/wallet"
"perun.network/go-perun/wallet"
)

// Wallet provides methods for wallet testing.
type Wallet struct {
*bwallet.Wallet
counter int
}

// NewWallet creates a new test wallet.
func NewWallet() *Wallet {
kr := newKeyring()
return &Wallet{
Wallet: bwallet.NewWallet(kr),
counter: 0,
}
}

func newKeyring() keyring.Keyring {
kr, err := keyring.New("", keyring.BackendMemory, "", nil)
if err != nil {
panic(err)
}
return kr
}

// NewRandomAccount generates a new account.
func (w *Wallet) NewRandomAccount(rng *rand.Rand) wallet.Account {
pwd := ""
w.counter++
name := fmt.Sprintf("Account%d", w.counter)
acc, err := w.Wallet.NewAccount(rng, name, pwd)
if err != nil {
panic(err)
}
return acc
}
Loading

0 comments on commit cdb6657

Please sign in to comment.