-
Notifications
You must be signed in to change notification settings - Fork 10
/
principal.go
77 lines (67 loc) · 2 KB
/
principal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package principal
import (
"crypto/sha256"
"encoding/base32"
"encoding/binary"
"fmt"
"github.com/fxamacker/cbor/v2"
"hash/crc32"
"strings"
)
// AnonymousID is used for the anonymous caller. It can be used in call and query requests without a signature.
var AnonymousID = Principal{[]byte{0x04}}
var encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
// Principal are generic identifiers for canisters, users and possibly other concepts in the future.
type Principal struct {
Raw []byte
}
// Decode converts a textual representation into a principal.
func Decode(s string) (Principal, error) {
s = strings.ReplaceAll(s, "-", "")
s = strings.ToUpper(s)
b32, err := encoding.DecodeString(s)
if err != nil {
return Principal{}, err
}
if len(b32) < 4 {
return Principal{}, fmt.Errorf("invalid length: %s", b32)
}
if crc32.ChecksumIEEE(b32[4:]) != binary.BigEndian.Uint32(b32[:4]) {
return Principal{}, fmt.Errorf("invalid checksum: %s", b32)
}
return Principal{b32[4:]}, err
}
// NewSelfAuthenticating returns a self authenticating principal identifier based on the given public key.
func NewSelfAuthenticating(pub []byte) Principal {
hash := sha256.Sum224(pub)
return Principal{
Raw: append(hash[:], 0x02),
}
}
// Encode converts the principal to its textual representation.
func (p Principal) Encode() string {
cs := make([]byte, 4)
binary.BigEndian.PutUint32(cs, crc32.ChecksumIEEE(p.Raw))
b32 := encoding.EncodeToString(append(cs, p.Raw...))
b32 = strings.ToLower(b32)
var str string
for i, c := range b32 {
if i != 0 && i%5 == 0 {
str += "-"
}
str += string(c)
}
return str
}
// MarshalCBOR converts the principal to its CBOR representation.
func (p Principal) MarshalCBOR() ([]byte, error) {
return cbor.Marshal(p.Raw)
}
// String implements the Stringer interface.
func (p Principal) String() string {
return p.Encode()
}
// UnmarshalCBOR converts a CBOR representation into a principal.
func (p *Principal) UnmarshalCBOR(bytes []byte) error {
return cbor.Unmarshal(bytes, &p.Raw)
}