package nkeys
import (
"bytes"
"encoding/base32"
"encoding/binary"
)
type PrefixByte byte
const (
PrefixByteSeed PrefixByte = 18 << 3
PrefixBytePrivate PrefixByte = 15 << 3
PrefixByteServer PrefixByte = 13 << 3
PrefixByteCluster PrefixByte = 2 << 3
PrefixByteOperator PrefixByte = 14 << 3
PrefixByteAccount PrefixByte = 0
PrefixByteUser PrefixByte = 20 << 3
PrefixByteCurve PrefixByte = 23 << 3
PrefixByteUnknown PrefixByte = 25 << 3
)
var b32Enc = base32 .StdEncoding .WithPadding (base32 .NoPadding )
func Encode (prefix PrefixByte , src []byte ) ([]byte , error ) {
if err := checkValidPrefixByte (prefix ); err != nil {
return nil , err
}
var raw bytes .Buffer
if err := raw .WriteByte (byte (prefix )); err != nil {
return nil , err
}
if _ , err := raw .Write (src ); err != nil {
return nil , err
}
err := binary .Write (&raw , binary .LittleEndian , crc16 (raw .Bytes ()))
if err != nil {
return nil , err
}
data := raw .Bytes ()
buf := make ([]byte , b32Enc .EncodedLen (len (data )))
b32Enc .Encode (buf , data )
return buf [:], nil
}
func EncodeSeed (public PrefixByte , src []byte ) ([]byte , error ) {
if err := checkValidPublicPrefixByte (public ); err != nil {
return nil , err
}
if len (src ) != seedLen {
return nil , ErrInvalidSeedLen
}
b1 := byte (PrefixByteSeed ) | (byte (public ) >> 5 )
b2 := (byte (public ) & 31 ) << 3
var raw bytes .Buffer
raw .WriteByte (b1 )
raw .WriteByte (b2 )
if _ , err := raw .Write (src ); err != nil {
return nil , err
}
err := binary .Write (&raw , binary .LittleEndian , crc16 (raw .Bytes ()))
if err != nil {
return nil , err
}
data := raw .Bytes ()
buf := make ([]byte , b32Enc .EncodedLen (len (data )))
b32Enc .Encode (buf , data )
return buf , nil
}
func IsValidEncoding (src []byte ) bool {
_ , err := decode (src )
return err == nil
}
func decode(src []byte ) ([]byte , error ) {
raw := make ([]byte , b32Enc .DecodedLen (len (src )))
n , err := b32Enc .Decode (raw , src )
if err != nil {
return nil , err
}
raw = raw [:n ]
if n < 4 {
return nil , ErrInvalidEncoding
}
crc := binary .LittleEndian .Uint16 (raw [n -2 :])
if err := validate (raw [0 :n -2 ], crc ); err != nil {
return nil , err
}
return raw [:n -2 ], nil
}
func Decode (expectedPrefix PrefixByte , src []byte ) ([]byte , error ) {
if err := checkValidPrefixByte (expectedPrefix ); err != nil {
return nil , err
}
raw , err := decode (src )
if err != nil {
return nil , err
}
b1 := raw [0 ] & 248
if prefix := PrefixByte (b1 ); prefix != expectedPrefix {
return nil , ErrInvalidPrefixByte
}
return raw [1 :], nil
}
func DecodeSeed (src []byte ) (PrefixByte , []byte , error ) {
raw , err := decode (src )
if err != nil {
return PrefixByteSeed , nil , err
}
b1 := raw [0 ] & 248
b2 := (raw [0 ]&7 )<<5 | ((raw [1 ] & 248 ) >> 3 )
if PrefixByte (b1 ) != PrefixByteSeed {
return PrefixByteSeed , nil , ErrInvalidSeed
}
if checkValidPublicPrefixByte (PrefixByte (b2 )) != nil {
return PrefixByteSeed , nil , ErrInvalidSeed
}
return PrefixByte (b2 ), raw [2 :], nil
}
func Prefix (src string ) PrefixByte {
b , err := decode ([]byte (src ))
if err != nil {
return PrefixByteUnknown
}
prefix := PrefixByte (b [0 ])
err = checkValidPrefixByte (prefix )
if err == nil {
return prefix
}
b1 := b [0 ] & 248
if PrefixByte (b1 ) == PrefixByteSeed {
return PrefixByteSeed
}
return PrefixByteUnknown
}
func IsValidPublicKey (src string ) bool {
b , err := decode ([]byte (src ))
if err != nil {
return false
}
if prefix := PrefixByte (b [0 ]); checkValidPublicPrefixByte (prefix ) != nil {
return false
}
return true
}
func IsValidPublicUserKey (src string ) bool {
_ , err := Decode (PrefixByteUser , []byte (src ))
return err == nil
}
func IsValidPublicAccountKey (src string ) bool {
_ , err := Decode (PrefixByteAccount , []byte (src ))
return err == nil
}
func IsValidPublicServerKey (src string ) bool {
_ , err := Decode (PrefixByteServer , []byte (src ))
return err == nil
}
func IsValidPublicClusterKey (src string ) bool {
_ , err := Decode (PrefixByteCluster , []byte (src ))
return err == nil
}
func IsValidPublicOperatorKey (src string ) bool {
_ , err := Decode (PrefixByteOperator , []byte (src ))
return err == nil
}
func IsValidPublicCurveKey (src string ) bool {
_ , err := Decode (PrefixByteCurve , []byte (src ))
return err == nil
}
func checkValidPrefixByte(prefix PrefixByte ) error {
switch prefix {
case PrefixByteOperator , PrefixByteServer , PrefixByteCluster ,
PrefixByteAccount , PrefixByteUser , PrefixByteSeed , PrefixBytePrivate , PrefixByteCurve :
return nil
}
return ErrInvalidPrefixByte
}
func checkValidPublicPrefixByte(prefix PrefixByte ) error {
switch prefix {
case PrefixByteOperator , PrefixByteServer , PrefixByteCluster , PrefixByteAccount , PrefixByteUser , PrefixByteCurve :
return nil
}
return ErrInvalidPrefixByte
}
func (p PrefixByte ) String () string {
switch p {
case PrefixByteOperator :
return "operator"
case PrefixByteServer :
return "server"
case PrefixByteCluster :
return "cluster"
case PrefixByteAccount :
return "account"
case PrefixByteUser :
return "user"
case PrefixByteSeed :
return "seed"
case PrefixBytePrivate :
return "private"
case PrefixByteCurve :
return "x25519"
}
return "unknown"
}
func CompatibleKeyPair (kp KeyPair , expected ...PrefixByte ) error {
pk , err := kp .PublicKey ()
if err != nil {
return err
}
pkType := Prefix (pk )
for _ , k := range expected {
if pkType == k {
return nil
}
}
return ErrIncompatibleKey
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .