@notabene/verify-proof 1.11.0 → 1.12.0-next.2
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/README.md +21 -15
- package/dist/bitcoin-3CW4MNAW.cjs +314 -0
- package/dist/bitcoin-3CW4MNAW.cjs.map +1 -0
- package/dist/bitcoin-QK53ILBF.js +312 -0
- package/dist/bitcoin-QK53ILBF.js.map +1 -0
- package/dist/cardano-DYBYEAAF.cjs +53 -0
- package/dist/cardano-DYBYEAAF.cjs.map +1 -0
- package/dist/cardano-WE6YXYLW.js +31 -0
- package/dist/cardano-WE6YXYLW.js.map +1 -0
- package/dist/chunk-E3V5ATTC.js +38 -0
- package/dist/chunk-E3V5ATTC.js.map +1 -0
- package/dist/chunk-OAXNH5XR.cjs +42 -0
- package/dist/chunk-OAXNH5XR.cjs.map +1 -0
- package/dist/concordium-QRNV23F7.js +45 -0
- package/dist/concordium-QRNV23F7.js.map +1 -0
- package/dist/concordium-YD34X2QM.cjs +47 -0
- package/dist/concordium-YD34X2QM.cjs.map +1 -0
- package/dist/cosmos-64MKE5FJ.cjs +683 -0
- package/dist/cosmos-64MKE5FJ.cjs.map +1 -0
- package/dist/cosmos-QMH7BK7S.js +681 -0
- package/dist/cosmos-QMH7BK7S.js.map +1 -0
- package/dist/eth-3DX3PXDU.cjs +37 -0
- package/dist/eth-3DX3PXDU.cjs.map +1 -0
- package/dist/eth-ICLGRJE5.js +34 -0
- package/dist/eth-ICLGRJE5.js.map +1 -0
- package/dist/index.cjs +68 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +66 -1
- package/dist/index.js.map +1 -1
- package/dist/solana-4KQFLZUC.js +342 -0
- package/dist/solana-4KQFLZUC.js.map +1 -0
- package/dist/solana-PQ5K4NGO.cjs +365 -0
- package/dist/solana-PQ5K4NGO.cjs.map +1 -0
- package/dist/tron-F5AARBY4.cjs +58 -0
- package/dist/tron-F5AARBY4.cjs.map +1 -0
- package/dist/tron-OBLPB2LN.js +53 -0
- package/dist/tron-OBLPB2LN.js.map +1 -0
- package/dist/xlm-5GODWWL2.cjs +28 -0
- package/dist/xlm-5GODWWL2.cjs.map +1 -0
- package/dist/xlm-GX2QGFLI.js +26 -0
- package/dist/xlm-GX2QGFLI.js.map +1 -0
- package/dist/xrpl-7HQLIDAK.cjs +1174 -0
- package/dist/xrpl-7HQLIDAK.cjs.map +1 -0
- package/dist/xrpl-YCDFXBGQ.js +1169 -0
- package/dist/xrpl-YCDFXBGQ.js.map +1 -0
- package/package.json +12 -2
- package/src/cardano.ts +2 -2
- package/src/concordium.ts +40 -284
- package/src/index.ts +31 -20
- package/src/solana.ts +1 -1
- package/src/tests/bitcoin.test.ts +335 -16
- package/src/tests/concordium.test.ts +96 -134
- package/src/tests/index.test.ts +7 -7
- package/src/tests/solana.test.ts +1 -1
- package/dist/bitcoin.d.ts +0 -2
- package/dist/cardano.d.ts +0 -2
- package/dist/concordium.d.ts +0 -15
- package/dist/cosmos.d.ts +0 -2
- package/dist/eth.d.ts +0 -4
- package/dist/index.modern.js +0 -2
- package/dist/index.modern.js.map +0 -1
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.map +0 -1
- package/dist/solana.d.ts +0 -17
- package/dist/tests/bitcoin.test.d.ts +0 -1
- package/dist/tests/cardano.test.d.ts +0 -1
- package/dist/tests/concordium.test.d.ts +0 -1
- package/dist/tests/cosmos.test.d.ts +0 -1
- package/dist/tests/eth.test.d.ts +0 -1
- package/dist/tests/index.test.d.ts +0 -1
- package/dist/tests/solana.test.d.ts +0 -1
- package/dist/tests/tron.test.d.ts +0 -1
- package/dist/tests/xlm.test.d.ts +0 -1
- package/dist/tests/xrpl.test.d.ts +0 -1
- package/dist/tron.d.ts +0 -6
- package/dist/xlm.d.ts +0 -2
- package/dist/xrpl.d.ts +0 -5
package/src/index.ts
CHANGED
|
@@ -6,16 +6,8 @@ import {
|
|
|
6
6
|
ProofTypes,
|
|
7
7
|
ProofStatus,
|
|
8
8
|
} from "@notabene/javascript-sdk";
|
|
9
|
-
import { verifyBTCSignature } from "./bitcoin";
|
|
10
|
-
import { verifyPersonalSignEIP191 } from "./eth";
|
|
11
|
-
import { verifySolanaSignature, verifySolanaSIWS } from "./solana";
|
|
12
|
-
import { verifyPersonalSignTIP191 } from "./tron";
|
|
13
|
-
import { verifyCIP8Signature } from "./cardano";
|
|
14
|
-
import { verifyPersonalSignXRPL } from "./xrpl";
|
|
15
|
-
import { verifyStellarSignature } from "./xlm";
|
|
16
|
-
import { verifyConcordiumSignature } from "./concordium";
|
|
17
|
-
import { verifyCosmosSignature } from "./cosmos";
|
|
18
9
|
|
|
10
|
+
// Use dynamic imports to ensure Buffer is available before loading crypto libraries
|
|
19
11
|
export async function verifyProof(
|
|
20
12
|
proof: OwnershipProof,
|
|
21
13
|
publicKey?: string,
|
|
@@ -35,29 +27,48 @@ export async function verifyProof(
|
|
|
35
27
|
? ProofStatus.FLAGGED
|
|
36
28
|
: ProofStatus.FAILED,
|
|
37
29
|
};
|
|
38
|
-
case ProofTypes.CIP8:
|
|
30
|
+
case ProofTypes.CIP8: {
|
|
31
|
+
const { verifyCIP8Signature } = await import("./cardano");
|
|
39
32
|
return verifyCIP8Signature(proof as SignatureProof);
|
|
40
|
-
|
|
33
|
+
}
|
|
34
|
+
case ProofTypes.EIP191: {
|
|
35
|
+
const { verifyPersonalSignEIP191 } = await import("./eth");
|
|
41
36
|
return verifyPersonalSignEIP191(proof as SignatureProof);
|
|
42
|
-
|
|
37
|
+
}
|
|
38
|
+
case ProofTypes.ED25519: {
|
|
39
|
+
const { verifySolanaSignature } = await import("./solana");
|
|
43
40
|
return verifySolanaSignature(proof as SignatureProof);
|
|
44
|
-
|
|
41
|
+
}
|
|
42
|
+
case ProofTypes.SOL_SIWX: {
|
|
43
|
+
const { verifySolanaSIWS } = await import("./solana");
|
|
45
44
|
return verifySolanaSIWS(proof as SignatureProof);
|
|
46
|
-
|
|
45
|
+
}
|
|
46
|
+
case ProofTypes.XRP_ED25519: {
|
|
47
|
+
const { verifyPersonalSignXRPL } = await import("./xrpl");
|
|
47
48
|
return verifyPersonalSignXRPL(proof as SignatureProof, publicKey);
|
|
48
|
-
|
|
49
|
+
}
|
|
50
|
+
case ProofTypes.XLM_ED25519: {
|
|
51
|
+
const { verifyStellarSignature } = await import("./xlm");
|
|
49
52
|
return verifyStellarSignature(proof as SignatureProof);
|
|
50
|
-
|
|
53
|
+
}
|
|
54
|
+
case ProofTypes.CONCORDIUM: {
|
|
55
|
+
const { verifyConcordiumSignature } = await import("./concordium");
|
|
51
56
|
return verifyConcordiumSignature(proof as SignatureProof);
|
|
52
|
-
|
|
57
|
+
}
|
|
58
|
+
case ProofTypes.COSMOS: {
|
|
59
|
+
const { verifyCosmosSignature } = await import("./cosmos");
|
|
53
60
|
return verifyCosmosSignature(proof as SignatureProof);
|
|
61
|
+
}
|
|
54
62
|
case ProofTypes.EIP712:
|
|
55
63
|
case ProofTypes.BIP137:
|
|
56
|
-
case ProofTypes.BIP322:
|
|
64
|
+
case ProofTypes.BIP322: {
|
|
65
|
+
const { verifyBTCSignature } = await import("./bitcoin");
|
|
57
66
|
return verifyBTCSignature(proof as SignatureProof);
|
|
58
|
-
|
|
67
|
+
}
|
|
68
|
+
case ProofTypes.TIP191: {
|
|
69
|
+
const { verifyPersonalSignTIP191 } = await import("./tron");
|
|
59
70
|
return verifyPersonalSignTIP191(proof as SignatureProof);
|
|
60
|
-
|
|
71
|
+
}
|
|
61
72
|
case ProofTypes.MicroTransfer:
|
|
62
73
|
}
|
|
63
74
|
return proof;
|
package/src/solana.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
ProofTypes,
|
|
8
8
|
} from "@notabene/javascript-sdk";
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const bitcoinP2SHProof: SignatureProof = {
|
|
11
11
|
type: ProofTypes.BIP137,
|
|
12
12
|
wallet_provider: "Manual Wallet Signature",
|
|
13
13
|
status: ProofStatus.PENDING,
|
|
@@ -20,7 +20,7 @@ const bitcoinP2WPKHProof: SignatureProof = {
|
|
|
20
20
|
"HxPmbzvEnvgu0RYIPYl5bWySkFNXwOF/Jegq3NvzjFZ/Ik/koTdV9rh2A7osXefhzTlniUw8YbZNmCeXB9V9qC8=",
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const bitcoinP2PKHProof: SignatureProof = {
|
|
24
24
|
type: ProofTypes.BIP137,
|
|
25
25
|
wallet_provider: "Manual Wallet Signature",
|
|
26
26
|
status: ProofStatus.PENDING,
|
|
@@ -121,18 +121,18 @@ const zcashProof: SignatureProof = {
|
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
describe("verifyBTCSignature", () => {
|
|
124
|
-
it("handles bitcoin
|
|
125
|
-
const result = await verifyBTCSignature(
|
|
124
|
+
it("handles bitcoin p2pkh addresses", async () => {
|
|
125
|
+
const result = await verifyBTCSignature(bitcoinP2PKHProof);
|
|
126
126
|
expect(result).toEqual({
|
|
127
|
-
...
|
|
127
|
+
...bitcoinP2PKHProof,
|
|
128
128
|
status: ProofStatus.VERIFIED,
|
|
129
129
|
});
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
-
it("handles bitcoin
|
|
133
|
-
const result = await verifyBTCSignature(
|
|
132
|
+
it("handles bitcoin p2sh addresses", async () => {
|
|
133
|
+
const result = await verifyBTCSignature(bitcoinP2SHProof);
|
|
134
134
|
expect(result).toEqual({
|
|
135
|
-
...
|
|
135
|
+
...bitcoinP2SHProof,
|
|
136
136
|
status: ProofStatus.VERIFIED,
|
|
137
137
|
});
|
|
138
138
|
});
|
|
@@ -294,8 +294,8 @@ describe("verifyBTCSignature", () => {
|
|
|
294
294
|
});
|
|
295
295
|
});
|
|
296
296
|
|
|
297
|
-
it("handles
|
|
298
|
-
const
|
|
297
|
+
it("handles legacy P2PKH addresses", async () => {
|
|
298
|
+
const p2pkhProof: SignatureProof = {
|
|
299
299
|
...legacyProof,
|
|
300
300
|
proof:
|
|
301
301
|
"INjxKyXqYtsPWqP+zYvZUtADMLR8IC8jBMQ029hutdcoSkss3B1Iv79x5u6Zo6Fn168H8PuiySOtk8cDU4uZUBU=",
|
|
@@ -303,8 +303,8 @@ describe("verifyBTCSignature", () => {
|
|
|
303
303
|
"bip122:1a91e3dace36e2be3bf030a65679fe821:16qcANyseCYSnSZHJFMSbsD5Z1Qns8jbe4",
|
|
304
304
|
};
|
|
305
305
|
|
|
306
|
-
const result = await verifyBTCSignature(
|
|
307
|
-
expect(result).toEqual({ ...
|
|
306
|
+
const result = await verifyBTCSignature(p2pkhProof);
|
|
307
|
+
expect(result).toEqual({ ...p2pkhProof, status: ProofStatus.VERIFIED });
|
|
308
308
|
});
|
|
309
309
|
|
|
310
310
|
it("handles bech32 encoding errors", async () => {
|
|
@@ -419,8 +419,8 @@ describe("verifyBTCSignature", () => {
|
|
|
419
419
|
expect(result).toEqual({ ...unknownProof, status: ProofStatus.FAILED });
|
|
420
420
|
});
|
|
421
421
|
|
|
422
|
-
it("handles
|
|
423
|
-
const
|
|
422
|
+
it("handles uncompressed P2PKH legacy addresses", async () => {
|
|
423
|
+
const uncompressedP2PKHProof: SignatureProof = {
|
|
424
424
|
...legacyProof,
|
|
425
425
|
proof:
|
|
426
426
|
"G0/EqZbcoZgrrLO09k8cK7MzTjrw5mHM4EiXWLCDgnH4d+rvMc1X2rGTPbHCKn8GGRLi7JDiTJflX+pxxCwtebA=",
|
|
@@ -428,9 +428,9 @@ describe("verifyBTCSignature", () => {
|
|
|
428
428
|
"bip122:000000000019d6689c085ae165831e93:18vqVNQi9fobKZcJWCjZNoDzBxronENfZr",
|
|
429
429
|
};
|
|
430
430
|
|
|
431
|
-
const result = await verifyBTCSignature(
|
|
431
|
+
const result = await verifyBTCSignature(uncompressedP2PKHProof);
|
|
432
432
|
expect(result).toEqual({
|
|
433
|
-
...
|
|
433
|
+
...uncompressedP2PKHProof,
|
|
434
434
|
status: ProofStatus.VERIFIED,
|
|
435
435
|
});
|
|
436
436
|
});
|
|
@@ -505,4 +505,323 @@ describe("verifyBTCSignature", () => {
|
|
|
505
505
|
const result = await verifyBTCSignature(sparrowWalletProof);
|
|
506
506
|
expect(result.status).toBe(ProofStatus.VERIFIED);
|
|
507
507
|
});
|
|
508
|
+
|
|
509
|
+
// Edge case tests
|
|
510
|
+
describe("P2SH-P2WPKH with SegWit flag", () => {
|
|
511
|
+
it("handles P2SH address with P2SH-P2WPKH segwit flag byte", async () => {
|
|
512
|
+
// Flag byte 35 (27 + 8) indicates P2SH-P2WPKH without compression
|
|
513
|
+
// Flag byte 39 (27 + 8 + 4) indicates P2SH-P2WPKH with compression
|
|
514
|
+
// Note: This test validates that the code correctly handles the segwit flag
|
|
515
|
+
// The signature/address combination may not validate, but should not throw
|
|
516
|
+
const p2shP2wpkhProof: SignatureProof = {
|
|
517
|
+
type: ProofTypes.BIP137,
|
|
518
|
+
address:
|
|
519
|
+
"bip122:000000000019d6689c085ae165831e93:3Mwz6cg8Fz81B7ukexK8u8EVAW2yymgWNd",
|
|
520
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:3Mwz6cg8Fz81B7ukexK8u8EVAW2yymgWNd",
|
|
521
|
+
attestation: "Test message for P2SH-P2WPKH",
|
|
522
|
+
proof:
|
|
523
|
+
"SCH1+cBPNP8jZCQvQmFPQ1NCuLlUF0CpXq7u6yLtYQDJXBGkFGLEPJ+C3BVX0GXU1iUEGVN9RKOzBhLqYTsXQGo=",
|
|
524
|
+
status: ProofStatus.PENDING,
|
|
525
|
+
wallet_provider: "Ledger",
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
const result = await verifyBTCSignature(p2shP2wpkhProof);
|
|
529
|
+
// Should process without throwing, validating the SegWit flag handling logic
|
|
530
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
531
|
+
result.status
|
|
532
|
+
);
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
describe("Message encoding edge cases", () => {
|
|
537
|
+
it("handles empty message", async () => {
|
|
538
|
+
const emptyMessageProof: SignatureProof = {
|
|
539
|
+
type: ProofTypes.BIP137,
|
|
540
|
+
address:
|
|
541
|
+
"bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
542
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
543
|
+
attestation: "",
|
|
544
|
+
proof:
|
|
545
|
+
"H0vJrLYzFGbKhGBQD8GVQX8t9T6R0/fYHhHlmYE0yJvWVX3k3qGBQVKJN5X8aL2K1xJ0QH9cR2F3bY0gN7M2JvM=",
|
|
546
|
+
status: ProofStatus.PENDING,
|
|
547
|
+
wallet_provider: "BitMask",
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const result = await verifyBTCSignature(emptyMessageProof);
|
|
551
|
+
// Empty messages should still process (verify signature mechanics)
|
|
552
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
553
|
+
result.status
|
|
554
|
+
);
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
it("handles message with unicode and emoji", async () => {
|
|
558
|
+
const unicodeProof: SignatureProof = {
|
|
559
|
+
type: ProofTypes.BIP137,
|
|
560
|
+
address:
|
|
561
|
+
"bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
562
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
563
|
+
attestation: "🚀 Bitcoin to the moon 🌙 with 日本語",
|
|
564
|
+
proof:
|
|
565
|
+
"H8twSn5iDrRY1LZ5C7kEdLAsQoS94LddA9ddmAaEZwI8U2WFZJnccnya2a79+rx5zIWHkZwLlu/HscXAc+XOQ+w=",
|
|
566
|
+
status: ProofStatus.PENDING,
|
|
567
|
+
wallet_provider: "BitMask",
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
const result = await verifyBTCSignature(unicodeProof);
|
|
571
|
+
// Should process without throwing errors
|
|
572
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
573
|
+
result.status
|
|
574
|
+
);
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
it("handles message with newlines and special characters", async () => {
|
|
578
|
+
const specialCharsProof: SignatureProof = {
|
|
579
|
+
type: ProofTypes.BIP137,
|
|
580
|
+
address:
|
|
581
|
+
"bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
582
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
583
|
+
attestation: "Line1\nLine2\tTab\rCarriage\x00Null",
|
|
584
|
+
proof:
|
|
585
|
+
"H8twSn5iDrRY1LZ5C7kEdLAsQoS94LddA9ddmAaEZwI8U2WFZJnccnya2a79+rx5zIWHkZwLlu/HscXAc+XOQ+w=",
|
|
586
|
+
status: ProofStatus.PENDING,
|
|
587
|
+
wallet_provider: "BitMask",
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
const result = await verifyBTCSignature(specialCharsProof);
|
|
591
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
592
|
+
result.status
|
|
593
|
+
);
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it("handles very long message (10KB)", async () => {
|
|
597
|
+
const longMessage = "A".repeat(10240); // 10KB message
|
|
598
|
+
const longMessageProof: SignatureProof = {
|
|
599
|
+
type: ProofTypes.BIP137,
|
|
600
|
+
address:
|
|
601
|
+
"bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
602
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
603
|
+
attestation: longMessage,
|
|
604
|
+
proof:
|
|
605
|
+
"H8twSn5iDrRY1LZ5C7kEdLAsQoS94LddA9ddmAaEZwI8U2WFZJnccnya2a79+rx5zIWHkZwLlu/HscXAc+XOQ+w=",
|
|
606
|
+
status: ProofStatus.PENDING,
|
|
607
|
+
wallet_provider: "BitMask",
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
const result = await verifyBTCSignature(longMessageProof);
|
|
611
|
+
// Should handle without throwing
|
|
612
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
613
|
+
result.status
|
|
614
|
+
);
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
describe("Invalid checksum edge cases", () => {
|
|
619
|
+
it("rejects address with invalid checksum", async () => {
|
|
620
|
+
const invalidChecksumProof: SignatureProof = {
|
|
621
|
+
type: ProofTypes.BIP137,
|
|
622
|
+
address:
|
|
623
|
+
"bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF65", // Changed last char
|
|
624
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF65",
|
|
625
|
+
attestation: "This is an example of a signed message.",
|
|
626
|
+
proof:
|
|
627
|
+
"H796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=",
|
|
628
|
+
status: ProofStatus.PENDING,
|
|
629
|
+
wallet_provider: "BitMask",
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
const result = await verifyBTCSignature(invalidChecksumProof);
|
|
633
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
|
634
|
+
});
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
describe("BIP322 edge cases", () => {
|
|
638
|
+
it("handles BIP322 with empty message", async () => {
|
|
639
|
+
const emptyBip322Proof: SignatureProof = {
|
|
640
|
+
type: ProofTypes.BIP322,
|
|
641
|
+
address:
|
|
642
|
+
"bip122:000000000019d6689c085ae165831e93:bc1qcxm70pg5yk9c8pupj93uys5azw5xpt6qeu2z0u",
|
|
643
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:bc1qcxm70pg5yk9c8pupj93uys5azw5xpt6qeu2z0u",
|
|
644
|
+
attestation: "",
|
|
645
|
+
proof:
|
|
646
|
+
"AkgwRQIhAIZlTevsH5hTsz8DOFT6hkNCNf+gBH8gjvRaI2x0T1YLAiAuzVHP+T05IO+URv/kJLjb0wDCiZwDA5DUiJPX4O7+aQEhAv9X2d9QIHF2C29QFUk5jWygaMbU3TAhzG+DfrgpI8EU",
|
|
647
|
+
status: ProofStatus.PENDING,
|
|
648
|
+
wallet_provider: "Phantom",
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
const result = await verifyBTCSignature(emptyBip322Proof);
|
|
652
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
653
|
+
result.status
|
|
654
|
+
);
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
it("handles BIP322 with very long message", async () => {
|
|
658
|
+
const longMessage = "B".repeat(5120); // 5KB
|
|
659
|
+
const longBip322Proof: SignatureProof = {
|
|
660
|
+
type: ProofTypes.BIP322,
|
|
661
|
+
address:
|
|
662
|
+
"bip122:000000000019d6689c085ae165831e93:bc1qcxm70pg5yk9c8pupj93uys5azw5xpt6qeu2z0u",
|
|
663
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:bc1qcxm70pg5yk9c8pupj93uys5azw5xpt6qeu2z0u",
|
|
664
|
+
attestation: longMessage,
|
|
665
|
+
proof:
|
|
666
|
+
"AkgwRQIhAIZlTevsH5hTsz8DOFT6hkNCNf+gBH8gjvRaI2x0T1YLAiAuzVHP+T05IO+URv/kJLjb0wDCiZwDA5DUiJPX4O7+aQEhAv9X2d9QIHF2C29QFUk5jWygaMbU3TAhzG+DfrgpI8EU",
|
|
667
|
+
status: ProofStatus.PENDING,
|
|
668
|
+
wallet_provider: "Phantom",
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const result = await verifyBTCSignature(longBip322Proof);
|
|
672
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
673
|
+
result.status
|
|
674
|
+
);
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
describe("Bech32 validation edge cases", () => {
|
|
679
|
+
it("rejects mixed case bech32 addresses", async () => {
|
|
680
|
+
const mixedCaseProof: SignatureProof = {
|
|
681
|
+
type: ProofTypes.BIP137,
|
|
682
|
+
address:
|
|
683
|
+
"bip122:000000000019d6689c085ae165831e93:bc1Qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8", // Mixed case
|
|
684
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:bc1Qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8",
|
|
685
|
+
attestation: "This is an example of a signed message.",
|
|
686
|
+
proof:
|
|
687
|
+
"J796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=",
|
|
688
|
+
status: ProofStatus.PENDING,
|
|
689
|
+
wallet_provider: "BitMask",
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
const result = await verifyBTCSignature(mixedCaseProof);
|
|
693
|
+
// Should fail due to bech32 case validation
|
|
694
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
it("handles lowercase bech32 correctly", async () => {
|
|
698
|
+
const lowercaseProof: SignatureProof = {
|
|
699
|
+
type: ProofTypes.BIP137,
|
|
700
|
+
address:
|
|
701
|
+
"bip122:000000000019d6689c085ae165831e93:bc1qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8",
|
|
702
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:bc1qnf4kpa62dwhpwm0stsas5yv0skatt3v9s040p8",
|
|
703
|
+
attestation: "This is an example of a signed message.",
|
|
704
|
+
proof:
|
|
705
|
+
"J796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=",
|
|
706
|
+
status: ProofStatus.PENDING,
|
|
707
|
+
wallet_provider: "BitMask",
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
const result = await verifyBTCSignature(lowercaseProof);
|
|
711
|
+
expect(result.status).toBe(ProofStatus.VERIFIED);
|
|
712
|
+
});
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
describe("Ledger wallet quirks", () => {
|
|
716
|
+
it("handles Ledger bc1q signature without segwit flag", async () => {
|
|
717
|
+
// Ledger signs bc1q addresses without setting segwit flag byte
|
|
718
|
+
// The code handles this at bitcoin.ts:339-349
|
|
719
|
+
const ledgerProof: SignatureProof = {
|
|
720
|
+
type: ProofTypes.BIP137,
|
|
721
|
+
address:
|
|
722
|
+
"bip122:000000000019d6689c085ae165831e93:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
|
|
723
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
|
|
724
|
+
attestation: "Ledger wallet test",
|
|
725
|
+
proof:
|
|
726
|
+
"IPPQZKnpNd1WmZvNLI1yJQSvbmv5y0JK9fBXRNL6u3K4TxYxJ8vdBfJBLHKdXJxNPLMQJxK9fBXRNL6u3K4TxY=",
|
|
727
|
+
status: ProofStatus.PENDING,
|
|
728
|
+
wallet_provider: "Ledger",
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
const result = await verifyBTCSignature(ledgerProof);
|
|
732
|
+
// Should handle Ledger's non-standard signing
|
|
733
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
734
|
+
result.status
|
|
735
|
+
);
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
describe("Signature recovery ID variations", () => {
|
|
740
|
+
it("handles all valid recovery IDs (0-3)", async () => {
|
|
741
|
+
// Recovery ID is stored in the last 2 bits of flag byte
|
|
742
|
+
// Flag byte = 27 + (compressed ? 4 : 0) + (segwit ? 8 : 0) + recovery(0-3)
|
|
743
|
+
|
|
744
|
+
const recoveryTests = [
|
|
745
|
+
// Recovery ID 0: flag byte 27+4+0 = 31
|
|
746
|
+
{
|
|
747
|
+
recovery: 0,
|
|
748
|
+
proof:
|
|
749
|
+
"H796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=",
|
|
750
|
+
},
|
|
751
|
+
// Recovery ID 1: flag byte 27+4+1 = 32
|
|
752
|
+
{
|
|
753
|
+
recovery: 1,
|
|
754
|
+
proof:
|
|
755
|
+
"ILY5fRTcA4rss44H+JoHZ7Ab5N6rMGkEAU0Q/Co0zXdcGXDOQLQoy7Tdb1a2oJz1xzFGiyzO1+eDcIG7ebqxvBM=",
|
|
756
|
+
},
|
|
757
|
+
// Recovery ID 2: flag byte 27+4+2 = 33
|
|
758
|
+
{
|
|
759
|
+
recovery: 2,
|
|
760
|
+
proof:
|
|
761
|
+
"IhPmbzvEnvgu0RYIPYl5bWySkFNXwOF/Jegq3NvzjFZ/Ik/koTdV9rh2A7osXefhzTlniUw8YbZNmCeXB9V9qC8=",
|
|
762
|
+
},
|
|
763
|
+
];
|
|
764
|
+
|
|
765
|
+
for (const test of recoveryTests) {
|
|
766
|
+
const recoveryProof: SignatureProof = {
|
|
767
|
+
type: ProofTypes.BIP137,
|
|
768
|
+
address:
|
|
769
|
+
"bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
770
|
+
did: "did:pkh:bip122:000000000019d6689c085ae165831e93:1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64",
|
|
771
|
+
attestation: "Testing recovery ID",
|
|
772
|
+
proof: test.proof,
|
|
773
|
+
status: ProofStatus.PENDING,
|
|
774
|
+
wallet_provider: "Test",
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
const result = await verifyBTCSignature(recoveryProof);
|
|
778
|
+
// Should process all recovery IDs
|
|
779
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
780
|
+
result.status
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
describe("Litecoin edge cases", () => {
|
|
787
|
+
it("handles Litecoin M addresses (P2SH)", async () => {
|
|
788
|
+
const litecoinMProof: SignatureProof = {
|
|
789
|
+
type: ProofTypes.BIP137,
|
|
790
|
+
address:
|
|
791
|
+
"bip122:12a765e31ffd4059bada1e25190f6e98:MUb8YjXUnFcBqFVK8rEYqBxDoTSWYLLdwK",
|
|
792
|
+
did: "did:pkh:bip122:12a765e31ffd4059bada1e25190f6e98:MUb8YjXUnFcBqFVK8rEYqBxDoTSWYLLdwK",
|
|
793
|
+
attestation: "Litecoin M address test",
|
|
794
|
+
proof:
|
|
795
|
+
"H8twSn5iDrRY1LZ5C7kEdLAsQoS94LddA9ddmAaEZwI8U2WFZJnccnya2a79+rx5zIWHkZwLlu/HscXAc+XOQ+w=",
|
|
796
|
+
status: ProofStatus.PENDING,
|
|
797
|
+
wallet_provider: "LiteWallet",
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
const result = await verifyBTCSignature(litecoinMProof);
|
|
801
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(
|
|
802
|
+
result.status
|
|
803
|
+
);
|
|
804
|
+
});
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
describe("Chain mismatch detection", () => {
|
|
808
|
+
it("fails when using wrong chain's message prefix", async () => {
|
|
809
|
+
// Bitcoin signature on Litecoin address should fail
|
|
810
|
+
// because message prefixes differ
|
|
811
|
+
const chainMismatchProof: SignatureProof = {
|
|
812
|
+
type: ProofTypes.BIP137,
|
|
813
|
+
address:
|
|
814
|
+
"bip122:12a765e31ffd4059bada1e25190f6e98:ltc1qp3la5p5wf8wnfg7hc3nga8kq0xs6tk5fn6v3r3",
|
|
815
|
+
did: "did:pkh:bip122:12a765e31ffd4059bada1e25190f6e98:ltc1qp3la5p5wf8wnfg7hc3nga8kq0xs6tk5fn6v3r3",
|
|
816
|
+
attestation: "Message signed by Litecoin address",
|
|
817
|
+
proof:
|
|
818
|
+
"H796FDv8f8w3syiaMSGoL6SAwPLRf6t13S+fYNjYA9EnJy3T0jZOY1eHBaGTBufOuW78FVFSwXKyUnrEjYOT9EU=", // Bitcoin signature
|
|
819
|
+
status: ProofStatus.PENDING,
|
|
820
|
+
wallet_provider: "BitMask",
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
const result = await verifyBTCSignature(chainMismatchProof);
|
|
824
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
|
825
|
+
});
|
|
826
|
+
});
|
|
508
827
|
});
|