Skip to content

Commit

Permalink
Improve encoding, closes echovl#37
Browse files Browse the repository at this point in the history
* expose bech32 module for easy marshalling
* added convinient method to build stake credential from key hash

Signed-off-by: Marco Bardelli <[email protected]>
  • Loading branch information
safanaj committed Dec 5, 2022
1 parent 5d486b0 commit 8011af7
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 0 deletions.
122 changes: 122 additions & 0 deletions bech32/bech32.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package bech32

import (
"fmt"

"github.com/echovl/cardano-go/bech32/prefixes"
"github.com/echovl/cardano-go/internal/bech32"
)

type Bech32Prefix = prefixes.Bech32Prefix

var (
EncodeWithPrefix = bech32.Encode
Decode = bech32.Decode
DecodeNoLimit = bech32.DecodeNoLimit

EncodeFromBase256WithPrefix = bech32.EncodeFromBase256
DecodeToBase256 = bech32.DecodeToBase256
)

type (
Bech32Codec interface {
Prefix() string
Bytes() []byte
SetBytes([]byte)
Len() int
}
Bech32Encoder interface {
Prefix() string
Bytes() []byte
}
)

func Encode(args ...any) (string, error) {
var hrp string
var data []byte
switch len(args) {
case 1:
// the argument have to be a Bech32Codec
if c, ok := args[0].(Bech32Encoder); !ok {
return "", fmt.Errorf("Wrong parameter: %T is not a Bech32Encoder", c)
}
hrp = args[0].(Bech32Encoder).Prefix()
data = args[0].(Bech32Encoder).Bytes()
case 2:
// the argument haave to be a Bech32Codec or a string, and the second have to be a []byte
a1 := args[0]
a2 := args[1]

switch a1.(type) {
case Bech32Encoder:
hrp = a1.(Bech32Codec).Prefix()
case string:
hrp = a1.(string)
default:
return "", fmt.Errorf("Wrong 1st parameter: %T is not a string or Bech32Codec", a1)
}

if _, ok := a2.([]byte); !ok {
return "", fmt.Errorf("Wrong 2nd parameter: %T is not a []byte", a2)
}
data = a2.([]byte)
}
return bech32.Encode(hrp, data)
}

func EncodeFromBase256(args ...any) (string, error) {
var hrp string
var data []byte
switch len(args) {
case 1:
// the argument have to be a Bech32Codec
if c, ok := args[0].(Bech32Encoder); !ok {
return "", fmt.Errorf("Wrong parameter: %T is not a Bech32Encoder", c)
}
hrp = args[0].(Bech32Encoder).Prefix()
if converted, err := bech32.ConvertBits(args[0].(Bech32Encoder).Bytes(), 8, 5, true); err != nil {
return "", err
} else {
data = converted
}
case 2:
// the argument haave to be a Bech32Codec or a string, and the second have to be a []byte
a1 := args[0]
a2 := args[1]

switch a1.(type) {
case Bech32Encoder:
hrp = a1.(Bech32Encoder).Prefix()
case string:
hrp = a1.(string)
default:
return "", fmt.Errorf("Wrong 1st parameter: %T is not a string or Bech32Codec", a1)
}

if _, ok := a2.([]byte); !ok {
return "", fmt.Errorf("Wrong 2nd parameter: %T is not a []byte", a2)
}
if converted, err := bech32.ConvertBits(a2.([]byte), 8, 5, true); err != nil {
} else {
data = converted
}
}
return bech32.Encode(hrp, data)
}

func DecodeInto(be32 string, codec Bech32Codec) error {
expectedLen := codec.Len()
expectedPrefix := codec.Prefix()
hrp, data, err := bech32.DecodeToBase256(be32)
if err != nil {
return err
}
if hrp != expectedPrefix {
return fmt.Errorf("Wrong prefix: want %s got %s", expectedPrefix, hrp)
}
codec.SetBytes(data)
if len(codec.Bytes()) != expectedLen || string(codec.Bytes()) != string(data) {
return fmt.Errorf("Set bytes failed")
}
return nil
}
91 changes: 91 additions & 0 deletions bech32/prefixes/cip5.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package prefixes

// As specified in [CIP-5](https://github.com/cardano-foundation/CIPs/tree/master/CIP5)
//
// copied from cardano-addresses core/lib/Cardano/Codec/Bech32/Prefixes.hs

type Bech32Prefix = string

const (
// -- * Addresses

Addr Bech32Prefix = "addr"
AddrTest Bech32Prefix = "addr_test"
Script Bech32Prefix = "script"
Stake Bech32Prefix = "stake"
StakeTest Bech32Prefix = "stake_test"

// -- * Hashes

AddrPublicKeyHash Bech32Prefix = "addr_vkh"
StakePublicKeyHash Bech32Prefix = "stake_vkh"
AddrSharedPublicKeyHash Bech32Prefix = "addr_shared_vkh"
StakeSharedPublicKeyHash Bech32Prefix = "stake_shared_vkh"

// -- * Keys for 1852H
AddrPublicKey Bech32Prefix = "addr_vk"
AddrPrivateKey Bech32Prefix = "addr_sk"
AddrXPub Bech32Prefix = "addr_xvk"
AddrXPrv Bech32Prefix = "addr_xsk"
AddrExtendedPublicKey = AddrXPub
AddrExtendedPrivateKey = AddrXPrv

AcctPublicKey Bech32Prefix = "acct_vk"
AcctPrivateKey Bech32Prefix = "acct_sk"
AcctXPub Bech32Prefix = "acct_xvk"
AcctXPrv Bech32Prefix = "acct_xsk"
AcctExtendedPublicKey = AcctXPub
AcctExtendedPrivateKey = AcctXPrv

RootPublicKey Bech32Prefix = "root_vk"
RootPrivateKey Bech32Prefix = "root_sk"
RootXPub Bech32Prefix = "root_xvk"
RootXPrv Bech32Prefix = "root_xsk"
RootExtendedPublicKey = RootXPub
RootExtendedPrivateKey = RootXPrv

StakePublicKey Bech32Prefix = "stake_vk"
StakePrivateKey Bech32Prefix = "stake_sk"
StakeXPub Bech32Prefix = "stake_xvk"
StakeXPrv Bech32Prefix = "stake_xsk"
StakeExtendedPublicKey = StakeXPub
StakeExtendedPrivateKey = StakeXPrv

// -- * Keys for 1854H

AddrSharedPublicKey Bech32Prefix = "addr_shared_vk"
AddrSharedPrivateKey Bech32Prefix = "addr_shared_sk"
AddrSharedXPub Bech32Prefix = "addr_shared_xvk"
AddrSharedXPrv Bech32Prefix = "addr_shared_xsk"
AddrSharedExtendedPublicKey = AddrSharedXPub
AddrSharedExtendedPrivateKey = AddrSharedXPrv

AcctSharedPublicKey Bech32Prefix = "acct_shared_vk"
AcctSharedPrivateKey Bech32Prefix = "acct_shared_sk"
AcctSharedXPub Bech32Prefix = "acct_shared_xvk"
AcctSharedXPrv Bech32Prefix = "acct_shared_xsk"
AcctSharedExtendedPublicKey = AcctSharedXPub
AcctSharedExtendedPrivateKey = AcctSharedXPrv

RootSharedPublicKey Bech32Prefix = "root_shared_vk"
RootSharedPrivateKey Bech32Prefix = "root_shared_sk"
RootSharedXPub Bech32Prefix = "root_shared_xvk"
RootSharedXPrv Bech32Prefix = "root_shared_xsk"
RootSharedExtendedPublicKey = RootSharedXPub
RootSharedExtendedPrivateKey = RootSharedXPrv

StakeSharedPublicKey Bech32Prefix = "stake_shared_vk"
StakeSharedPrivateKey Bech32Prefix = "stake_shared_sk"
StakeSharedXPub Bech32Prefix = "stake_shared_xvk"
StakeSharedXPrv Bech32Prefix = "stake_shared_xsk"
StakeSharedExtendedPublicKey = StakeSharedXPub
StakeSharedExtendedPrivateKey = StakeSharedXPrv

// -- * Keys for 1855H
PolicyPublicKey Bech32Prefix = "policy_vk"
PolicyPrivateKey Bech32Prefix = "policy_sk"
PolicyXPub Bech32Prefix = "policy_xvk"
PolicyXPrv Bech32Prefix = "policy_xsk"
PolicyExtendedPublicKey = PolicyXPub
PolicyExtendedPrivateKey = PolicyXPrv
)
8 changes: 8 additions & 0 deletions credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ func NewKeyCredential(publicKey crypto.PubKey) (StakeCredential, error) {
return StakeCredential{Type: KeyCredential, KeyHash: keyHash}, nil
}

// NewKeyCredential creates a Key Credential from an AddrKeyHash (28 bytes key hash).
func NewKeyCredentialFromHash(keyHash AddrKeyHash) (StakeCredential, error) {
if len(keyHash) < 28 {
return StakeCredential{}, fmt.Errorf("Wrong argument: expected 28 bytes key hash")
}
return StakeCredential{Type: KeyCredential, KeyHash: keyHash[:28]}, nil
}

// NewKeyCredential creates a Script Credential.
func NewScriptCredential(script []byte) (StakeCredential, error) {
scriptHash, err := Blake224Hash(script)
Expand Down

0 comments on commit 8011af7

Please sign in to comment.