1package testing
2
3import (
4 "context"
5 "encoding/base64"
6 "encoding/json"
7 "os"
8 "strings"
9 "testing"
10
11 "github.com/bluesky-social/indigo/repo"
12
13 "github.com/ipfs/go-datastore"
14 blockstore "github.com/ipfs/go-ipfs-blockstore"
15 "github.com/stretchr/testify/assert"
16 "github.com/whyrusleeping/go-did"
17 secp "gitlab.com/yawning/secp256k1-voi"
18 "gitlab.com/yawning/secp256k1-voi/secec"
19)
20
21func TestVerification(t *testing.T) {
22 assert := assert.New(t)
23
24 fi, err := os.Open("testdata/divy.repo")
25 if err != nil {
26 t.Fatal(err)
27 }
28
29 bs := blockstore.NewBlockstore(datastore.NewMapDatastore())
30 ctx := context.TODO()
31 c, err := repo.IngestRepo(ctx, bs, fi)
32 if err != nil {
33 t.Fatal(err)
34 }
35
36 r, err := repo.OpenRepo(ctx, bs, c)
37 if err != nil {
38 t.Fatal(err)
39 }
40
41 vmstr := `{
42 "id": "#atproto",
43 "type": "EcdsaSecp256k1VerificationKey2019",
44 "controller": "did:plc:wj5jny4sq4sohwoaxjkjgug6",
45 "publicKeyMultibase": "zQYEBzXeuTM9UR3rfvNag6L3RNAs5pQZyYPsomTsgQhsxLdEgCrPTLgFna8yqCnxPpNT7DBk6Ym3dgPKNu86vt9GR"
46 }`
47 var vm did.VerificationMethod
48
49 if err := json.Unmarshal([]byte(vmstr), &vm); err != nil {
50 t.Fatal(err)
51 }
52
53 pk, err := vm.GetPublicKey()
54 if err != nil {
55 t.Fatal(err)
56 }
57
58 assert.Equal(pk.Type, "EcdsaSecp256k1VerificationKey2019")
59
60 scom := r.SignedCommit()
61
62 msg, err := scom.Unsigned().BytesForSigning()
63 if err != nil {
64 t.Fatal(err)
65 }
66
67 if err := pk.Verify(msg, scom.Sig); err != nil {
68 t.Fatal(err)
69 }
70}
71
72func TestVerificationK256(t *testing.T) {
73 // 2023-03-30T11:18:20.605-0700 WARN indexer indexer/keymgr.go:37 trying to verify sig {"key": {"Raw":"BBKybGcJOMvsIyPaKglHtcocOFN7QrlppYHN3i4fW5PfLmfUFCXNcNKMk/MjT/cnquZS1APwxr6QUR7LE8/bJC8=","Type":"EcdsaSecp256k1VerificationKey2019"}, "sigBytes": "1ZJM8YFVmHJksi+liHFn62GBfUd7zDio0BVej0JTjtJUdYMgmV8Mg4/4RNfL9VFM8bXMhzusJ1qpu2kTyHoliA==", "msgBytes": "pGNkaWR4IGRpZDpwbGM6cHVydnZqNXV0N2hyeGo1ejdtbTZyNGd0ZGRhdGHYKlglAAFxEiAG8t9fbFkSGKBhEXYLZLC5njldpEfHGg2hheTdR9VLi2RwcmV22CpYJQABcRIgtJroXREnp3TZxxf8xZTQC+w4+vnfz1KIkWVitinSPOFndmVyc2lvbgI="}
74
75 assert := assert.New(t)
76 keyBytes, err := base64.StdEncoding.DecodeString("BBKybGcJOMvsIyPaKglHtcocOFN7QrlppYHN3i4fW5PfLmfUFCXNcNKMk/MjT/cnquZS1APwxr6QUR7LE8/bJC8=")
77 assert.NoError(err)
78 msgBytes, err := base64.StdEncoding.DecodeString("pGNkaWR4IGRpZDpwbGM6cHVydnZqNXV0N2hyeGo1ejdtbTZyNGd0ZGRhdGHYKlglAAFxEiAG8t9fbFkSGKBhEXYLZLC5njldpEfHGg2hheTdR9VLi2RwcmV22CpYJQABcRIgtJroXREnp3TZxxf8xZTQC+w4+vnfz1KIkWVitinSPOFndmVyc2lvbgI=")
79 assert.NoError(err)
80 sigBytes, err := base64.StdEncoding.DecodeString("1ZJM8YFVmHJksi+liHFn62GBfUd7zDio0BVej0JTjtJUdYMgmV8Mg4/4RNfL9VFM8bXMhzusJ1qpu2kTyHoliA==")
81 assert.NoError(err)
82
83 pt, err := secp.NewIdentityPoint().SetBytes(keyBytes)
84 if err != nil {
85 t.Fatal(err)
86 }
87
88 k, err := secec.NewPublicKeyFromPoint(pt)
89 if err != nil {
90 t.Fatal(err)
91 }
92
93 key := did.PubKey{
94 Type: "EcdsaSecp256k1VerificationKey2019", // k1 -> K256
95 Raw: k,
96 }
97
98 assert.NoError(key.Verify(msgBytes, sigBytes))
99}
100
101func parseKeyFromMultibase(t *testing.T, s, keyType string) did.PubKey {
102 vm := did.VerificationMethod{
103 Type: keyType,
104 PublicKeyMultibase: &s,
105 }
106
107 pk, err := vm.GetPublicKey()
108 if err != nil {
109 t.Fatal(err)
110 }
111
112 return *pk
113}
114
115func parseDidKey(t *testing.T, s string) *did.PubKey {
116 parts := strings.SplitN(s, ":", 3)
117 k, err := did.PubKeyFromMultibaseString(parts[2])
118 if err != nil {
119 t.Fatal(err)
120 }
121
122 return k
123}
124
125func TestInteropSignatures(t *testing.T) {
126 assert := assert.New(t)
127
128 testTable := []struct {
129 description string
130 keyType string
131 docType string
132 didKey string
133 multibaseKey string
134 msgBase64 string
135 sigBase64 string
136 }{
137 {
138 description: "p256/secp256r1",
139 keyType: "ES256",
140 docType: "EcdsaSecp256r1VerificationKey2019",
141 msgBase64: "oWVoZWxsb2V3b3JsZA",
142 didKey: "did:key:zDnaembgSGUhZULN2Caob4HLJPaxBh92N7rtH21TErzqf8HQo",
143 multibaseKey: "zxdM8dSstjrpZaRUwBmDvjGXweKuEMVN95A9oJBFjkWMh",
144 sigBase64: "2vZNsG3UKvvO/CDlrdvyZRISOFylinBh0Jupc6KcWoJWExHptCfduPleDbG3rko3YZnn9Lw0IjpixVmexJDegg",
145 },
146 {
147 description: "k256/secp256k1",
148 keyType: "ES256K",
149 docType: "EcdsaSecp256k1VerificationKey2019",
150 didKey: "did:key:zQ3shueETAVp1HCdE7pcrUD1wEHNhfaQiDJmWeJgCxZRmDJuy",
151 multibaseKey: "zRvvEWNhRDxCYpkWWKzvrCP5Sca54yhgXjLcSgfJsWW9Jk8Wq79d5h2PTW3BQDmNQv4prqGjRkXiEDwnfpq2tTsmp",
152 msgBase64: "oWVoZWxsb2V3b3JsZA",
153 sigBase64: "FbKI9u/VoY9SFHvtsuYsZULkt3QiNRrPUP3N4bX0xTxfWIUccyoNJ7egTITlaD1xBhXAvDdBnbyC6aOZ0jyjEA",
154 },
155 }
156
157 for _, row := range testTable {
158 pkDid := parseDidKey(t, row.didKey)
159 pkMultibase := parseKeyFromMultibase(t, row.multibaseKey, row.docType)
160 msgBytes, err := base64.RawStdEncoding.DecodeString(row.msgBase64)
161 assert.NoError(err)
162 sigBytes, err := base64.RawStdEncoding.DecodeString(row.sigBase64)
163 assert.NoError(err)
164
165 assert.NoError(pkDid.Verify(msgBytes, sigBytes), "keyType=%v format=%v", row.description, "did:key")
166 assert.NoError(pkMultibase.Verify(msgBytes, sigBytes), "keyType=%v format=%v", row.description, "multibase")
167 assert.Error(pkMultibase.Verify(msgBytes, []byte{1, 2, 3}), "keyType=%v format=%v", row.description, "multibase")
168 assert.Error(pkMultibase.Verify([]byte{1, 2, 3}, sigBytes), "keyType=%v format=%v", row.description, "multibase")
169
170 // TODO: investigate these additional tests, which partially fail, instead of "continue"
171 /*
172 assert.Equal(pkDid, pkMultibase, row.description)
173 assert.NotEqual(pkDid.MultibaseString(), "<invalid key>", "keyType=%v format=%v", row.description, "did:key")
174 assert.NotEqual(pkMultibase.MultibaseString(), "<invalid key>", "keyType=%v format=%v", row.description, "multibase")
175
176 // check that keys round-trip ok
177 assert.Equal(row.didKey, pkDid.DID(), "export keyType=%v format=%v", row.description, "did:key")
178 assert.Equal(row.multibaseKey, pkDid.MultibaseString(), "export keyType=%v format=%v", row.description, "multibase")
179 pkDid = parseDidKey(t, pkDid.DID())
180 pkMultibase = parseKeyFromMultibase(t, pkMultibase.MultibaseString(), row.docType)
181
182 assert.NoError(pkDid.Verify(msgBytes, sigBytes), "round-trip keyType=%v format=%v", row.description, "did:key")
183 assert.NoError(pkMultibase.Verify(msgBytes, sigBytes), "round-trip keyType=%v format=%v", row.description, "multibase")
184 */
185 }
186}