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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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",