Skip to content

Commit

Permalink
calculate substrate address from public key
Browse files Browse the repository at this point in the history
  • Loading branch information
robdefeo committed Oct 16, 2019
1 parent 8fbbf77 commit c523ce3
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 0 deletions.
36 changes: 36 additions & 0 deletions internal/protocols/substrate/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package substrate

import (
"github.com/minio/blake2b-simd"
"github.com/pkg/errors"
)

func SS58AddressFormat(network string, publicKey []byte) ([]byte, error) {
if len(publicKey) != 32 {
return nil, errors.Errorf("public key must be 32 bytes")
}
prefixedKey, err := prefixWithNetwork(network, publicKey)
if err != nil {
return nil, errors.WithStack(err)
}
hash := blake2b.Sum512(addSS58Prefix(prefixedKey))

// take first 2 bytes of hash since public key
return append(prefixedKey, hash[:2]...), nil
}

func addSS58Prefix(pubKey []byte) []byte {
prefix := []byte("SS58PRE")
return append(prefix, pubKey...)
}

func prefixWithNetwork(network string, publicKey []byte) ([]byte, error) {
// https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)#address-type defines different prefixes by network
switch network {
case EdgewareTestnet:
// 42 = 0x2a
return append([]byte{0x2a}, publicKey...), nil
default:
return nil, errors.Errorf("unknown address prefix for %q", network)
}
}
134 changes: 134 additions & 0 deletions internal/protocols/substrate/address_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package substrate

import (
"testing"

"github.com/mailchain/mailchain/internal/testutil"
"github.com/stretchr/testify/assert"
)

func Test_prefixWithNetwork(t *testing.T) {
assert := assert.New(t)
type args struct {
network string
publicKey []byte
}
tests := []struct {
name string
args args
want []byte
wantErr bool
}{
{
"edgeware-testnet",
args{
"edgeware-testnet",
testutil.MustHexDecodeString("b14d4c84eedf30aabd53ae71286b392f1caaf77597c5a525ea7cc856f91de4a3"),
},
[]byte{0x2a, 0xb1, 0x4d, 0x4c, 0x84, 0xee, 0xdf, 0x30, 0xaa, 0xbd, 0x53, 0xae, 0x71, 0x28, 0x6b, 0x39, 0x2f, 0x1c, 0xaa, 0xf7, 0x75, 0x97, 0xc5, 0xa5, 0x25, 0xea, 0x7c, 0xc8, 0x56, 0xf9, 0x1d, 0xe4, 0xa3},
false,
},
{
"invalid",
args{
"invalid",
testutil.MustHexDecodeString("b14d4c84eedf30aabd53ae71286b392f1caaf77597c5a525ea7cc856f91de4a3"),
},
nil,
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := prefixWithNetwork(tt.args.network, tt.args.publicKey)
if (err != nil) != tt.wantErr {
t.Errorf("prefixWithNetwork() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !assert.Equal(tt.want, got) {
t.Errorf("prefixWithNetwork() = %v, want %v", got, tt.want)
}
})
}
}

func Test_addSS58Prefix(t *testing.T) {
assert := assert.New(t)
type args struct {
pubKey []byte
}
tests := []struct {
name string
args args
want []byte
}{
{
"success",
args{
testutil.MustHexDecodeString("b14d"),
},
[]byte{0x53, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45, 0xb1, 0x4d},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := addSS58Prefix(tt.args.pubKey); !assert.Equal(tt.want, got) {
t.Errorf("addSS58Prefix() = %v, want %v", got, tt.want)
}
})
}
}

func TestSS58AddressFormat(t *testing.T) {
assert := assert.New(t)
type args struct {
network string
publicKey []byte
}
tests := []struct {
name string
args args
want []byte
wantErr bool
}{
{
"success",
args{
"edgeware-testnet",
testutil.MustHexDecodeString("b14d4c84eedf30aabd53ae71286b392f1caaf77597c5a525ea7cc856f91de4a3"),
},
[]byte{0x2a, 0xb1, 0x4d, 0x4c, 0x84, 0xee, 0xdf, 0x30, 0xaa, 0xbd, 0x53, 0xae, 0x71, 0x28, 0x6b, 0x39, 0x2f, 0x1c, 0xaa, 0xf7, 0x75, 0x97, 0xc5, 0xa5, 0x25, 0xea, 0x7c, 0xc8, 0x56, 0xf9, 0x1d, 0xe4, 0xa3, 0x83, 0x20},
false,
},
{
"err-network",
args{
"invalid",
testutil.MustHexDecodeString("b14d4c84eedf30aabd53ae71286b392f1caaf77597c5a525ea7cc856f91de4a3"),
},
nil,
true,
},
{
"err-key-length",
args{
"edgeware-testnet",
testutil.MustHexDecodeString("b14d"),
},
nil,
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := SS58AddressFormat(tt.args.network, tt.args.publicKey)
if (err != nil) != tt.wantErr {
t.Errorf("SS58AddressFormat() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !assert.Equal(tt.want, got) {
t.Errorf("SS58AddressFormat() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit c523ce3

Please sign in to comment.