@notabene/verify-proof 1.0.0-preview.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/dist/solana.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { SignatureProof } from "@notabene/javascript-sdk/src/types";
1
+ import { SignatureProof } from "@notabene/javascript-sdk";
2
2
  export declare function verifySolanaSignature(proof: SignatureProof): Promise<SignatureProof>;
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@notabene/verify-proof",
3
- "version": "1.0.0-preview.6",
3
+ "version": "1.0.0",
4
4
  "description": "Verify ownership proofs",
5
5
  "source": "src/index.ts",
6
6
  "type": "module",
7
7
  "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
8
9
  "main": "dist/index.cjs",
9
10
  "author": "Pelle Braendgaard",
10
11
  "license": "Apache-2.0",
@@ -22,25 +23,21 @@
22
23
  "test": "vitest"
23
24
  },
24
25
  "devDependencies": {
25
- "@types/bitcoinjs-lib": "3.4.0",
26
- "@types/node": "^22.9.0",
27
- "bitcoinjs-lib": "^3.2.0",
28
- "buffer": "^6.0.3",
29
- "ecpair": "^3.0.0-rc.0",
30
26
  "eslint": "^9.9.0",
31
27
  "microbundle": "^0.15.1",
32
- "tiny-secp256k1": "^2.2.3",
28
+ "ox": "^0.2.2",
33
29
  "typescript": "^5.5.4",
30
+ "vite": "^5.4.11",
34
31
  "vitest": "^2.0.5"
35
32
  },
36
33
  "dependencies": {
34
+ "@bitauth/libauth": "^3.0.0",
37
35
  "@notabene/javascript-sdk": "^2.0.2",
38
- "@solana/web3.js": "^1.95.4",
39
36
  "@stablelib/base64": "^2.0.0",
37
+ "bech32": "^2.0.0",
40
38
  "bigi": "^1.4.2",
41
- "bitcoinjs-message": "^2.2.0",
42
- "ox": "^0.1.4",
39
+ "bs58": "^6.0.0",
43
40
  "tweetnacl": "^1.0.3",
44
- "viem": "^2.21.44"
41
+ "varuint-bitcoin": "^2.0.0"
45
42
  }
46
43
  }
package/src/bitcoin.ts CHANGED
@@ -1,10 +1,24 @@
1
+ import { ProofStatus, SignatureProof } from "@notabene/javascript-sdk";
2
+ import { bech32 } from "bech32";
3
+
1
4
  import {
2
- ProofStatus,
3
- SignatureProof,
4
- } from "@notabene/javascript-sdk/src/types";
5
- import * as bitcoinMessage from "bitcoinjs-message";
5
+ secp256k1,
6
+ hash160,
7
+ hash256,
8
+ RecoveryId,
9
+ encodeBase58AddressFormat,
10
+ } from "@bitauth/libauth";
11
+ import { encode as encodeLength } from "varuint-bitcoin";
12
+ import { decode as decodeBase64 } from "@stablelib/base64";
13
+
14
+ enum SEGWIT_TYPES {
15
+ P2WPKH = "p2wpkh",
16
+ P2SH_P2WPKH = "p2sh(p2wpkh)",
17
+ }
18
+
19
+ const messagePrefix = "\u0018Bitcoin Signed Message:\n";
6
20
 
7
- export enum DerivationMode {
21
+ enum DerivationMode {
8
22
  LEGACY = "Legacy",
9
23
  NATIVE = "Native SegWit",
10
24
  SEGWIT = "SegWit",
@@ -25,13 +39,7 @@ export async function verifyBTCSignature(
25
39
  const segwit = [DerivationMode.SEGWIT, DerivationMode.NATIVE].includes(
26
40
  getDerivationMode(address),
27
41
  );
28
- const verified = bitcoinMessage.verify(
29
- proof.attestation,
30
- address,
31
- proof.proof,
32
- undefined,
33
- segwit,
34
- );
42
+ const verified = verify(proof.attestation, address, proof.proof, segwit);
35
43
 
36
44
  return {
37
45
  ...proof,
@@ -59,3 +67,98 @@ function getDerivationMode(address: string) {
59
67
  );
60
68
  }
61
69
  }
70
+
71
+ type DecodedSignature = {
72
+ compressed: boolean;
73
+ segwitType?: SEGWIT_TYPES;
74
+ recovery: RecoveryId;
75
+ signature: Uint8Array;
76
+ };
77
+
78
+ function decodeSignature(proof: string): DecodedSignature {
79
+ const signature = decodeBase64(proof);
80
+ if (signature.length !== 65) throw new Error("Invalid signature length");
81
+
82
+ const flagByte = signature[0] - 27;
83
+ if (flagByte > 15 || flagByte < 0) {
84
+ throw new Error("Invalid signature parameter");
85
+ }
86
+
87
+ return {
88
+ compressed: !!(flagByte & 12),
89
+ segwitType: !(flagByte & 8)
90
+ ? undefined
91
+ : !(flagByte & 4)
92
+ ? SEGWIT_TYPES.P2SH_P2WPKH
93
+ : SEGWIT_TYPES.P2WPKH,
94
+ recovery: (flagByte & 3) as RecoveryId,
95
+ signature: signature.slice(1),
96
+ };
97
+ }
98
+
99
+ function verify(
100
+ attestation: string,
101
+ address: string,
102
+ proof: string,
103
+ checkSegwitAlways: boolean,
104
+ ) {
105
+ const { compressed, segwitType, recovery, signature } =
106
+ decodeSignature(proof);
107
+ if (checkSegwitAlways && !compressed) {
108
+ throw new Error(
109
+ "checkSegwitAlways can only be used with a compressed pubkey signature flagbyte",
110
+ );
111
+ }
112
+
113
+ const hash = magicHash(attestation);
114
+ const publicKey: Uint8Array | string = compressed
115
+ ? secp256k1.recoverPublicKeyCompressed(signature, recovery, hash)
116
+ : secp256k1.recoverPublicKeyUncompressed(signature, recovery, hash);
117
+ if (typeof publicKey === "string") throw new Error(publicKey);
118
+ const publicKeyHash = hash160(publicKey);
119
+ let actual: string = "";
120
+
121
+ if (segwitType) {
122
+ if (segwitType === SEGWIT_TYPES.P2SH_P2WPKH) {
123
+ actual = encodeBech32Address(publicKeyHash);
124
+ } else {
125
+ // parsed.segwitType === SEGWIT_TYPES.P2WPKH
126
+ // must be true since we only return null, P2SH_P2WPKH, or P2WPKH
127
+ // from the decodeSignature function.
128
+ actual = encodeBech32Address(publicKeyHash);
129
+ }
130
+ } else {
131
+ if (checkSegwitAlways) {
132
+ try {
133
+ actual = encodeBech32Address(publicKeyHash);
134
+ // if address is bech32 it is not p2sh
135
+ } catch (e) {
136
+ actual = encodeBech32Address(publicKeyHash);
137
+ // base58 can be p2pkh or p2sh-p2wpkh
138
+ }
139
+ } else {
140
+ actual = encodeBase58AddressFormat(0, publicKeyHash);
141
+ }
142
+ }
143
+
144
+ return actual === address;
145
+ }
146
+
147
+ function magicHash(attestation: string) {
148
+ const prefix = new TextEncoder().encode(messagePrefix);
149
+ const message = new TextEncoder().encode(attestation);
150
+ const length = encodeLength(message.length).buffer;
151
+ const buffer = new Uint8Array(
152
+ prefix.length + length.byteLength + message.length,
153
+ );
154
+ buffer.set(prefix);
155
+ buffer.set(new Uint8Array(length), prefix.length);
156
+ buffer.set(message, prefix.length + length.byteLength);
157
+ return hash256(buffer);
158
+ }
159
+
160
+ function encodeBech32Address(publicKeyHash: Uint8Array): string {
161
+ const bwords = bech32.toWords(publicKeyHash);
162
+ bwords.unshift(0);
163
+ return bech32.encode("bc", bwords);
164
+ }
package/src/eth.ts CHANGED
@@ -1,8 +1,22 @@
1
- import {
2
- ProofStatus,
3
- SignatureProof,
4
- } from "@notabene/javascript-sdk/src/types";
5
- import { verifyMessage } from "viem";
1
+ import { ProofStatus, SignatureProof } from "@notabene/javascript-sdk";
2
+
3
+ import { Secp256k1, Hex, PersonalMessage, Signature, Address } from "ox";
4
+
5
+ export function verifyEIP191(
6
+ address: Hex.Hex,
7
+ message: string,
8
+ proof: Hex.Hex,
9
+ ): boolean {
10
+ try {
11
+ const payload = PersonalMessage.getSignPayload(Hex.fromString(message));
12
+ const signature = Signature.fromHex(proof);
13
+ const publicKey = Secp256k1.recoverPublicKey({ payload, signature });
14
+ const recovered = Address.fromPublicKey(publicKey);
15
+ return recovered.toString() === address.toString();
16
+ } catch (error) {
17
+ return false;
18
+ }
19
+ }
6
20
 
7
21
  export async function verifyPersonalSignEIP191(
8
22
  proof: SignatureProof,
@@ -10,11 +24,11 @@ export async function verifyPersonalSignEIP191(
10
24
  const [ns, _, address] = proof.address.split(/:/);
11
25
  if (ns !== "eip155") return { ...proof, status: ProofStatus.FAILED };
12
26
 
13
- const verified = await verifyMessage({
14
- address: address as `0x${string}`,
15
- message: proof.attestation,
16
- signature: proof.proof as `0x${string}`,
17
- });
27
+ const verified = verifyEIP191(
28
+ address as Hex.Hex,
29
+ proof.attestation,
30
+ proof.proof as Hex.Hex,
31
+ );
18
32
  return {
19
33
  ...proof,
20
34
  status: verified ? ProofStatus.VERIFIED : ProofStatus.FAILED,
package/src/index.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  ScreenshotProof,
6
6
  ProofTypes,
7
7
  ProofStatus,
8
- } from "@notabene/javascript-sdk/src/types";
8
+ } from "@notabene/javascript-sdk";
9
9
  import { verifyBTCSignature } from "./bitcoin";
10
10
  import { verifyPersonalSignEIP191 } from "./eth";
11
11
  import { verifySolanaSignature } from "./solana";
package/src/solana.ts CHANGED
@@ -1,10 +1,7 @@
1
- import { PublicKey } from "@solana/web3.js";
2
1
  import nacl from "tweetnacl";
3
- import {
4
- ProofStatus,
5
- SignatureProof,
6
- } from "@notabene/javascript-sdk/src/types";
2
+ import { ProofStatus, SignatureProof } from "@notabene/javascript-sdk";
7
3
  import { decode as decodeBase64 } from "@stablelib/base64";
4
+ import bs58 from "bs58";
8
5
 
9
6
  export async function verifySolanaSignature(
10
7
  proof: SignatureProof,
@@ -12,13 +9,13 @@ export async function verifySolanaSignature(
12
9
  const [ns, _, address] = proof.address.split(/:/);
13
10
  if (ns !== "solana") return { ...proof, status: ProofStatus.FAILED };
14
11
  try {
15
- const publicKey = new PublicKey(address);
12
+ const publicKey = bs58.decode(address);
16
13
  const messageBytes = new TextEncoder().encode(proof.attestation);
17
14
  const signatureBytes = decodeBase64(proof.proof);
18
15
  const verified = nacl.sign.detached.verify(
19
16
  messageBytes,
20
17
  signatureBytes,
21
- publicKey.toBytes(),
18
+ publicKey,
22
19
  );
23
20
 
24
21
  return {
@@ -1,95 +1,61 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import * as bitcoin from "bitcoinjs-lib";
3
- import * as bitcoinMessage from "bitcoinjs-message";
4
- import { Buffer } from "node:buffer";
1
+ import { describe, it, expect } from "vitest";
5
2
 
6
3
  import { verifyBTCSignature } from "../bitcoin";
7
4
  import {
8
5
  type SignatureProof,
9
6
  ProofStatus,
10
7
  ProofTypes,
11
- } from "@notabene/javascript-sdk/src/types";
12
-
13
- function rng() {
14
- return Buffer.from("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
15
- }
16
-
17
- function signMessage(
18
- toAddress: (kp: bitcoin.ECPair) => string,
19
- ): SignatureProof {
20
- const keyPair = bitcoin.ECPair.makeRandom({ rng: rng });
21
- const address = toAddress(keyPair);
22
- const privateKey = keyPair.d.toBuffer(32);
23
- var attestation = "This is an example of a signed message.";
24
- var proof = bitcoinMessage
25
- .sign(attestation, privateKey, keyPair.compressed)
26
- .toString("base64");
27
- // console.log("signMessage", { proof, address });
28
- return {
29
- type: ProofTypes.BIP137,
30
- address: `bip122:000000000019d6689c085ae165831e93:${address}`,
31
- did: `did:pkh:bip122:000000000019d6689c085ae165831e93:${address}`,
32
- attestation,
33
- proof,
34
- status: ProofStatus.PENDING,
35
- wallet_provider: "MetaMask",
36
- };
37
- }
38
-
39
- function signP2PKHMessage(): SignatureProof {
40
- return signMessage((kp) => kp.getAddress());
41
- }
42
-
43
- function signSegWitMessage(): SignatureProof {
44
- return signMessage((kp) =>
45
- bitcoin.address.toBech32(
46
- bitcoin.crypto.hash160(kp.getPublicKeyBuffer()),
47
- 0,
48
- kp.network.bech32 || "bc",
49
- ),
50
- );
51
- }
8
+ } from "@notabene/javascript-sdk";
9
+
10
+ const segwitProof: SignatureProof = {
11
+ type: ProofTypes.BIP137,
12
+ address:
13
+ "bip122:000000000019d6689c085ae165831e93:bc1qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8",
14
+ did: "did:pkh:bip122:000000000019d6689c085ae165831e93:bc1qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8",
15
+ attestation: "This is an example of a signed message.",
16
+ proof:
17
+ "J796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=",
18
+ status: ProofStatus.PENDING,
19
+ wallet_provider: "BitMask",
20
+ };
21
+
22
+ const legacyProof: SignatureProof = {
23
+ type: ProofTypes.BIP137,
24
+ address:
25
+ "bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
26
+ did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
27
+ attestation: "This is an example of a signed message.",
28
+ proof:
29
+ "H796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=",
30
+ status: ProofStatus.PENDING,
31
+ wallet_provider: "BitMask",
32
+ };
52
33
 
53
34
  describe("verifyBTCSignature", () => {
54
35
  it("handles native segwit addresses", async () => {
55
- const proof: SignatureProof = signSegWitMessage();
56
- const result = await verifyBTCSignature(proof);
57
- expect(result.status).toBe(ProofStatus.VERIFIED);
36
+ const result = await verifyBTCSignature(segwitProof);
37
+ expect(result).toEqual({ ...segwitProof, status: ProofStatus.VERIFIED });
58
38
  });
59
39
 
60
40
  it("verifies legacy bitcoin address signature", async () => {
61
- const proof: SignatureProof = signP2PKHMessage();
62
- const result = await verifyBTCSignature(proof);
63
- expect(result.status).toBe(ProofStatus.VERIFIED);
41
+ const result = await verifyBTCSignature(legacyProof);
42
+ expect(result).toEqual({ ...legacyProof, status: ProofStatus.VERIFIED });
64
43
  });
65
44
 
66
45
  it("fails for invalid bitcoin signature", async () => {
67
- const proof: SignatureProof = {
68
- type: ProofTypes.BIP137,
69
- did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
70
- address:
71
- "bip122:000000000019d6689c085ae165831e93:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
72
- attestation: "test message",
73
- proof: "invalid_signature",
74
- status: ProofStatus.PENDING,
75
- };
46
+ const proof: SignatureProof = { ...legacyProof, proof: "invalitd" };
76
47
 
77
48
  const result = await verifyBTCSignature(proof);
78
- expect(result.status).toBe(ProofStatus.FAILED);
49
+ expect(result).toEqual({ ...proof, status: ProofStatus.FAILED });
79
50
  });
80
51
 
81
52
  it("returns failed proof for non-BIP122 address", async () => {
82
53
  const proof: SignatureProof = {
83
- type: ProofTypes.EIP191,
84
- status: ProofStatus.PENDING,
85
- did: "did:example:123",
54
+ ...legacyProof,
86
55
  address: "eip155:1:0x1234567890123456789012345678901234567890",
87
- proof: "0x1234567890",
88
- attestation: "I own this address",
89
- wallet_provider: "MetaMask",
90
56
  };
91
57
 
92
58
  const result = await verifyBTCSignature(proof);
93
- expect(result.status).toBe(ProofStatus.FAILED);
59
+ expect(result).toEqual({ ...proof, status: ProofStatus.FAILED });
94
60
  });
95
61
  });
@@ -1,10 +1,10 @@
1
- import { describe, it, expect, vi } from "vitest";
1
+ import { describe, it, expect } from "vitest";
2
2
  import { verifyPersonalSignEIP191 } from "../eth";
3
3
  import {
4
4
  type SignatureProof,
5
5
  ProofStatus,
6
6
  ProofTypes,
7
- } from "@notabene/javascript-sdk/src/types";
7
+ } from "@notabene/javascript-sdk";
8
8
 
9
9
  import { Hex, Address, PersonalMessage, Secp256k1, Signature } from "ox";
10
10
 
@@ -45,6 +45,7 @@ describe("verifyPersonalSignEIP191", () => {
45
45
  const proof: SignatureProof = {
46
46
  type: ProofTypes.EIP191,
47
47
  did: `did:pkh:bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6`,
48
+ wallet_provider: "metamask",
48
49
  address:
49
50
  "bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6",
50
51
  attestation: "test message",
@@ -1,4 +1,4 @@
1
- import { describe, it, expect, vi } from "vitest";
1
+ import { describe, it, expect } from "vitest";
2
2
  import { verifyProof } from "../index";
3
3
  import {
4
4
  type DeclarationProof,
@@ -6,13 +6,7 @@ import {
6
6
  type SignatureProof,
7
7
  ProofStatus,
8
8
  ProofTypes,
9
- } from "@notabene/javascript-sdk/src/types";
10
- import { verifyMessage } from "viem";
11
-
12
- // Mock viem's verifyMessage function
13
- vi.mock("viem", () => ({
14
- verifyMessage: vi.fn(),
15
- }));
9
+ } from "@notabene/javascript-sdk";
16
10
 
17
11
  describe("verifyProof", () => {
18
12
  it("should verify a confirmed checkbox proof", async () => {
@@ -87,68 +81,86 @@ describe("verifyProof", () => {
87
81
  expect(result).toEqual(proof);
88
82
  });
89
83
 
90
- it("should verify a valid PersonalSignEIP191 proof", async () => {
84
+ describe("eip191", () => {
91
85
  const proof: SignatureProof = {
92
86
  type: ProofTypes.EIP191,
87
+ address: "eip155:1:0x772f226b9cc93a2953dc5868864de72f90441caf",
88
+ did: "did:pkh:eip155:1:0x772f226b9cc93a2953dc5868864de72f90441caf",
89
+ attestation: "I agree",
90
+ proof:
91
+ "0xddd74ca17084728a167b6f99326b50a0ce4a1ce4f80a56da4a60b23b69637c624e6dfb2270de56caece9182200fe38791339cbf097586a4e06a9ef4bd298cc1800",
93
92
  status: ProofStatus.PENDING,
94
- did: "did:example:123",
95
- address: "eip155:1:0x1234567890123456789012345678901234567890",
96
- proof: "0x1234567890",
97
- attestation: "I own this address",
98
93
  wallet_provider: "MetaMask",
99
94
  };
100
95
 
101
- // Mock successful verification
102
- (verifyMessage as jest.Mock).mockResolvedValue(true);
96
+ it("should verify proof", async () => {
97
+ const result = await verifyProof(proof);
98
+ expect(result.status).toBe(ProofStatus.VERIFIED);
99
+ });
103
100
 
104
- const result = await verifyProof(proof);
101
+ it("should fail if not invalid proof", async () => {
102
+ const result = await verifyProof({
103
+ ...proof,
104
+ proof: "0x",
105
+ } as SignatureProof);
105
106
 
106
- expect(result.status).toBe(ProofStatus.VERIFIED);
107
- expect(verifyMessage).toHaveBeenCalledWith({
108
- address: "0x1234567890123456789012345678901234567890",
109
- message: proof.attestation,
110
- signature: proof.proof,
107
+ expect(result.status).toBe(ProofStatus.FAILED);
111
108
  });
112
109
  });
113
110
 
114
- it("should fail an invalid PersonalSignEIP191 proof", async () => {
111
+ describe("solana", () => {
115
112
  const proof: SignatureProof = {
116
- type: ProofTypes.EIP191,
113
+ type: ProofTypes.ED25519,
117
114
  status: ProofStatus.PENDING,
118
- did: "did:example:123",
119
- address: "eip155:1:0x1234567890123456789012345678901234567890",
120
- proof: "0x1234567890",
121
- attestation: "I own this address",
122
- wallet_provider: "MetaMask",
115
+ did: "did:pkh:solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:3GgW39JvdBVCAdiK1mafeBcBKXJq8mee5woVoDARRnPq",
116
+ address:
117
+ "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:3GgW39JvdBVCAdiK1mafeBcBKXJq8mee5woVoDARRnPq",
118
+ attestation: "Test message",
119
+ proof:
120
+ "8dkeX3S+qisPkadV5QkmLWu2gbom/ljqlEwDAVuEV33HWZbSbPol+KV/zET4NLn8JBvSpu6JROJRg45WAIMPAQ==",
121
+ wallet_provider: "Phantom",
123
122
  };
124
123
 
125
- // Mock failed verification
126
- (verifyMessage as jest.Mock).mockResolvedValue(false);
124
+ it("should verify proof", async () => {
125
+ const result = await verifyProof(proof);
126
+ expect(result.status).toBe(ProofStatus.VERIFIED);
127
+ });
127
128
 
128
- const result = await verifyProof(proof);
129
+ it("should fail if not invalid proof", async () => {
130
+ const result = await verifyProof({
131
+ ...proof,
132
+ proof: "0x",
133
+ } as SignatureProof);
129
134
 
130
- expect(result.status).toBe(ProofStatus.FAILED);
131
- expect(verifyMessage).toHaveBeenCalledWith({
132
- address: "0x1234567890123456789012345678901234567890",
133
- message: proof.attestation,
134
- signature: proof.proof,
135
+ expect(result.status).toBe(ProofStatus.FAILED);
135
136
  });
136
137
  });
137
138
 
138
- it("should fail if not eip155 proof", async () => {
139
+ describe("bitcoin", () => {
139
140
  const proof: SignatureProof = {
140
- type: ProofTypes.EIP191,
141
+ type: ProofTypes.BIP137,
141
142
  status: ProofStatus.PENDING,
142
- did: "did:example:123",
143
143
  address:
144
- "bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6",
145
- proof: "0x1234567890",
146
- attestation: "I own this address",
147
- wallet_provider: "MetaMask",
144
+ "bip122:000000000019d6689c085ae165831e93:bc1qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8",
145
+ did: "did:pkh:bip122:000000000019d6689c085ae165831e93:bc1qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8",
146
+ attestation: "This is an example of a signed message.",
147
+ proof:
148
+ "J796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=",
149
+ wallet_provider: "Phantom",
148
150
  };
149
151
 
150
- const result = await verifyProof(proof);
152
+ it("should verify proof", async () => {
153
+ const result = await verifyProof(proof);
154
+ expect(result.status).toBe(ProofStatus.VERIFIED);
155
+ });
151
156
 
152
- expect(result.status).toBe(ProofStatus.FAILED);
157
+ it("should fail if not invalid proof", async () => {
158
+ const result = await verifyProof({
159
+ ...proof,
160
+ proof: "0x",
161
+ } as SignatureProof);
162
+
163
+ expect(result.status).toBe(ProofStatus.FAILED);
164
+ });
153
165
  });
154
166
  });
@@ -1,40 +1,41 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { Keypair } from "@solana/web3.js";
2
+ import bs58 from "bs58";
3
3
  import nacl from "tweetnacl";
4
4
  import {
5
5
  ProofStatus,
6
6
  ProofTypes,
7
7
  SignatureProof,
8
- } from "@notabene/javascript-sdk/src/types";
8
+ } from "@notabene/javascript-sdk";
9
9
  import { verifySolanaSignature } from "../solana";
10
10
 
11
11
  describe("verifySolanaSignature", () => {
12
+ const keypair = nacl.sign.keyPair();
13
+ const address = bs58.encode(keypair.publicKey);
12
14
  it("verifies valid Solana signature", async () => {
13
15
  // Generate a test keypair
14
- const keypair = Keypair.generate();
15
16
  const message = "Test message";
16
17
  const messageBytes = new TextEncoder().encode(message);
17
18
  const signature = nacl.sign.detached(messageBytes, keypair.secretKey);
18
19
  const proof: SignatureProof = {
19
20
  type: ProofTypes.ED25519,
20
21
  status: ProofStatus.PENDING,
21
- did: `did:pkh:solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${keypair.publicKey.toString()}`,
22
- address: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${keypair.publicKey.toString()}`,
22
+ did: `did:pkh:solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${address}`,
23
+ address: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${address}`,
23
24
  attestation: message,
24
25
  proof: Buffer.from(signature).toString("base64"),
25
26
  wallet_provider: "Phantom",
26
27
  };
28
+
27
29
  const result = await verifySolanaSignature(proof);
28
30
  expect(result.status).toBe(ProofStatus.VERIFIED);
29
31
  });
30
32
 
31
33
  it("fails for invalid signature", async () => {
32
- const keypair = Keypair.generate();
33
34
  const proof: SignatureProof = {
34
35
  type: ProofTypes.ED25519,
35
36
  status: ProofStatus.PENDING,
36
- did: `did:pkh:solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${keypair.publicKey.toString()}`,
37
- address: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${keypair.publicKey.toString()}`,
37
+ did: `did:pkh:solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${address}`,
38
+ address: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${address}`,
38
39
  attestation: "Test message",
39
40
  proof: "invalid_signature",
40
41
  wallet_provider: "Phantom",