-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
bap.go
130 lines (111 loc) · 3.64 KB
/
bap.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Package bap is a library for working with Bitcoin Attestation Protocol (BAP) in Go
//
// Protocol: https://github.com/icellan/bap
//
// If you have any suggestions or comments, please feel free to open an issue on
// this GitHub repository!
//
// By BitcoinSchema Organization (https://bitcoinschema.org)
package bap
import (
"crypto/sha256"
"errors"
"fmt"
hd "github.com/bitcoin-sv/go-sdk/compat/bip32"
ec "github.com/bitcoin-sv/go-sdk/primitives/ec"
"github.com/bitcoin-sv/go-sdk/transaction"
chaincfg "github.com/bitcoin-sv/go-sdk/transaction/chaincfg"
"github.com/bitcoinschema/go-aip"
)
// Prefix is the bitcom prefix for Bitcoin Attestation Protocol (BAP)
const Prefix = "1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT"
const pipe string = "|"
// AttestationType is an enum for BAP Type Constants
type AttestationType string
// BAP attestation type constants
const (
ATTEST AttestationType = "ATTEST"
ID AttestationType = "ID"
REVOKE AttestationType = "REVOKE"
ALIAS AttestationType = "ALIAS"
)
// CreateIdentity creates an identity from a private key, an id key, and a counter
//
// Source: https://github.com/icellan/bap
func CreateIdentity(xPrivateKey, idKey string, currentCounter uint32) (*transaction.Transaction, error) {
// Test for id key
if len(idKey) == 0 {
return nil, fmt.Errorf("missing required field: %s", "idKey")
}
hdKey, err := hd.NewKeyFromString(xPrivateKey)
if err != nil {
return nil, err
}
signingHdKey, err := hdKey.DeriveChildFromPath(fmt.Sprintf("%d/%d", 0, currentCounter))
if err != nil {
return nil, err
}
signingKey, err := signingHdKey.ECPrivKey()
if err != nil {
return nil, err
}
// Create the identity attestation op_return data
var data [][]byte
data = append(
data,
[]byte(Prefix),
[]byte(ID),
[]byte(idKey),
[]byte(signingHdKey.Address(&chaincfg.MainNet)),
[]byte(pipe),
)
// Generate a signature from this point
var finalOutput [][]byte
if finalOutput, _, err = aip.SignOpReturnData(signingKey, aip.BitcoinECDSA, data); err != nil {
return nil, err
}
// Return the transaction
return returnTx(finalOutput)
}
// CreateAttestation creates an attestation transaction from an id key, signing key, and signing address
//
// Source: https://github.com/icellan/bap
func CreateAttestation(idKey string, attestorSigningKey *ec.PrivateKey, attributeName,
attributeValue, identityAttributeSecret string) (*transaction.Transaction, error) {
// ID key is required
if len(idKey) == 0 {
return nil, errors.New("missing required field: idKey")
}
// Attribute secret and name
if len(attributeName) == 0 {
return nil, errors.New("missing required field: attributeName")
} else if len(identityAttributeSecret) == 0 {
return nil, errors.New("missing required field: identityAttributeSecret")
}
// Attest that an internal wallet address is associated with our identity key
idUrn := fmt.Sprintf("urn:bap:id:%s:%s:%s", attributeName, attributeValue, identityAttributeSecret)
attestationUrn := fmt.Sprintf("urn:bap:attest:%v:%s", sha256.Sum256([]byte(idUrn)), idKey)
attestationHash := sha256.Sum256([]byte(attestationUrn))
// Create op_return attestation
var data [][]byte
data = append(
data,
[]byte(Prefix),
[]byte(ATTEST),
attestationHash[0:],
[]byte(pipe),
)
// Generate a signature from this point
finalOutput, _, err := aip.SignOpReturnData(attestorSigningKey, aip.BitcoinECDSA, data)
if err != nil {
return nil, err
}
// Return the transaction
return returnTx(finalOutput)
}
// returnTx will add the output and return a new tx
func returnTx(outBytes [][]byte) (t *transaction.Transaction, err error) {
t = transaction.NewTransaction()
err = t.AddOpReturnPartsOutput(outBytes)
return
}