208 lines
3.7 KiB
Go
208 lines
3.7 KiB
Go
package chain
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"sort"
|
|
|
|
"github.com/filecoin-project/go-lotus/chain/address"
|
|
"github.com/filecoin-project/go-lotus/lib/bls-signatures"
|
|
"github.com/filecoin-project/go-lotus/lib/crypto"
|
|
|
|
"github.com/minio/blake2b-simd"
|
|
)
|
|
|
|
const (
|
|
KTSecp256k1 = "secp256k1"
|
|
KTBLS = "bls"
|
|
)
|
|
|
|
type Wallet struct {
|
|
keys map[address.Address]*KeyInfo
|
|
}
|
|
|
|
func NewWallet() *Wallet {
|
|
return &Wallet{keys: make(map[address.Address]*KeyInfo)}
|
|
}
|
|
|
|
type Signature struct {
|
|
Type string
|
|
Data []byte
|
|
}
|
|
|
|
func SignatureFromBytes(x []byte) (Signature, error) {
|
|
val, nr := binary.Uvarint(x)
|
|
if nr != 1 {
|
|
return Signature{}, fmt.Errorf("signatures with type field longer than one byte are invalid")
|
|
}
|
|
var ts string
|
|
switch val {
|
|
case 1:
|
|
ts = KTSecp256k1
|
|
default:
|
|
return Signature{}, fmt.Errorf("unsupported signature type: %d", val)
|
|
}
|
|
|
|
return Signature{
|
|
Type: ts,
|
|
Data: x[1:],
|
|
}, nil
|
|
}
|
|
|
|
func (s *Signature) Verify(addr address.Address, msg []byte) error {
|
|
b2sum := blake2b.Sum256(msg)
|
|
|
|
switch s.Type {
|
|
case KTSecp256k1:
|
|
pubk, err := crypto.EcRecover(b2sum[:], s.Data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
maybeaddr, err := address.NewSecp256k1Address(pubk)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if addr != maybeaddr {
|
|
return fmt.Errorf("signature did not match")
|
|
}
|
|
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("cannot verify signature of unsupported type: %s", s.Type)
|
|
}
|
|
}
|
|
|
|
func (s *Signature) TypeCode() int {
|
|
switch s.Type {
|
|
case KTSecp256k1:
|
|
return 1
|
|
case KTBLS:
|
|
return 2
|
|
default:
|
|
panic("unsupported signature type")
|
|
}
|
|
}
|
|
|
|
func (w *Wallet) Sign(addr address.Address, msg []byte) (*Signature, error) {
|
|
ki, err := w.findKey(addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch ki.Type {
|
|
case KTSecp256k1:
|
|
b2sum := blake2b.Sum256(msg)
|
|
sig, err := crypto.Sign(ki.PrivateKey, b2sum[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Signature{
|
|
Type: KTSecp256k1,
|
|
Data: sig,
|
|
}, nil
|
|
case KTBLS:
|
|
var pk bls.PrivateKey
|
|
copy(pk[:], ki.PrivateKey)
|
|
sig := bls.PrivateKeySign(pk, msg)
|
|
|
|
return &Signature{
|
|
Type: KTBLS,
|
|
Data: sig[:],
|
|
}, nil
|
|
|
|
default:
|
|
panic("cant do it sir")
|
|
}
|
|
}
|
|
|
|
func (w *Wallet) findKey(addr address.Address) (*KeyInfo, error) {
|
|
ki, ok := w.keys[addr]
|
|
if !ok {
|
|
return nil, fmt.Errorf("key not for given address not found in wallet")
|
|
}
|
|
return ki, nil
|
|
}
|
|
|
|
func (w *Wallet) Export(addr address.Address) ([]byte, error) {
|
|
panic("nyi")
|
|
}
|
|
|
|
func (w *Wallet) Import(kdata []byte) (address.Address, error) {
|
|
panic("nyi")
|
|
}
|
|
|
|
func (w *Wallet) ListAddrs() []address.Address {
|
|
var out []address.Address
|
|
for a := range w.keys {
|
|
out = append(out, a)
|
|
}
|
|
sort.Slice(out, func(i, j int) bool {
|
|
return out[i].String() < out[j].String()
|
|
})
|
|
return out
|
|
}
|
|
|
|
func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
|
|
switch typ {
|
|
case KTSecp256k1:
|
|
k, err := crypto.GenerateKey()
|
|
if err != nil {
|
|
return address.Undef, err
|
|
}
|
|
ki := &KeyInfo{
|
|
PrivateKey: k,
|
|
Type: typ,
|
|
}
|
|
|
|
addr := ki.Address()
|
|
w.keys[addr] = ki
|
|
return addr, nil
|
|
case KTBLS:
|
|
priv := bls.PrivateKeyGenerate()
|
|
|
|
ki := &KeyInfo{
|
|
PrivateKey: priv[:],
|
|
Type: KTBLS,
|
|
}
|
|
|
|
addr := ki.Address()
|
|
w.keys[addr] = ki
|
|
return addr, nil
|
|
default:
|
|
return address.Undef, fmt.Errorf("invalid key type: %s", typ)
|
|
}
|
|
}
|
|
|
|
type KeyInfo struct {
|
|
PrivateKey []byte
|
|
|
|
Type string
|
|
}
|
|
|
|
func (ki *KeyInfo) Address() address.Address {
|
|
switch ki.Type {
|
|
case KTSecp256k1:
|
|
pub := crypto.PublicKey(ki.PrivateKey)
|
|
addr, err := address.NewSecp256k1Address(pub)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return addr
|
|
case KTBLS:
|
|
var pk bls.PrivateKey
|
|
copy(pk[:], ki.PrivateKey)
|
|
pub := bls.PrivateKeyPublicKey(pk)
|
|
a, err := address.NewBLSAddress(pub[:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return a
|
|
default:
|
|
panic("unsupported key type")
|
|
}
|
|
}
|