@smartledger/bsv 9.7.0 → 9.9.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/CHANGELOG.md +217 -0
- package/README.md +19 -19
- package/bsv-gdaf.min.js +59 -59
- package/bsv-smartcontract.min.js +1 -1
- package/bsv.bundle.js +59 -59
- package/bsv.d.ts +642 -55
- package/bsv.min.js +59 -59
- package/docs/AUDIT_SCOPE.md +40 -14
- package/docs/BRC220_BATCH_LEAF_AMENDMENT.md +16 -6
- package/docs/BRC220_ENCODING_AMENDMENT.md +30 -91
- package/docs/BRC220_PLAN.md +39 -34
- package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/audit-rfq/cure53.txt +24 -10
- package/docs/audit-rfq/ncc-group.txt +24 -10
- package/docs/audit-rfq/trail-of-bits.txt +24 -10
- package/docs/getting-started/INSTALLATION.md +23 -23
- package/docs/getting-started/QUICK_START.md +7 -7
- package/docs/migration/FROM_BSV_1_5_6.md +5 -5
- package/docs/preimage.md +151 -87
- package/lib/notaryhash/certificate.js +524 -79
- package/lib/notaryhash/index.js +100 -71
- package/lib/notaryhash/merkle.js +94 -0
- package/lib/notaryhash/script.js +8 -1
- package/lib/notaryhash/suites.js +17 -14
- package/package.json +7 -3
- package/tools/gen-brc220-batch-vector.js +7 -3
- package/version.js +1 -1
package/bsv.d.ts
CHANGED
|
@@ -12,7 +12,96 @@
|
|
|
12
12
|
declare module '@smartledger/bsv' {
|
|
13
13
|
|
|
14
14
|
export namespace crypto {
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* bn.js, extended with Bitcoin's script-number and sign-magnitude codecs.
|
|
17
|
+
*
|
|
18
|
+
* This was `class BN { }` — an empty declaration — so `new BN(0)` was a
|
|
19
|
+
* compile error and every BN-typed value in the public API widened to `{}`.
|
|
20
|
+
* That made the whole Interpreter surface unusable from TypeScript, since a
|
|
21
|
+
* satoshi amount is a BN.
|
|
22
|
+
*
|
|
23
|
+
* The arithmetic below is bn.js's own; only the codecs are Bitcoin's. The
|
|
24
|
+
* bn.js internals (`red`, `mont`, `iushrn` and friends) are deliberately not
|
|
25
|
+
* enumerated — they are inherited, not part of this library's contract.
|
|
26
|
+
*/
|
|
27
|
+
class BN {
|
|
28
|
+
constructor(
|
|
29
|
+
number?: number | string | number[] | Buffer | BN,
|
|
30
|
+
base?: number | 'hex',
|
|
31
|
+
endian?: 'le' | 'be'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
static Zero: BN;
|
|
35
|
+
static One: BN;
|
|
36
|
+
static Minus1: BN;
|
|
37
|
+
static isBN(b: any): boolean;
|
|
38
|
+
static max(a: BN, b: BN): BN;
|
|
39
|
+
static min(a: BN, b: BN): BN;
|
|
40
|
+
|
|
41
|
+
static fromNumber(n: number): BN;
|
|
42
|
+
static fromString(str: string, base?: number): BN;
|
|
43
|
+
static fromHex(hex: string, opts?: { endian?: 'little' | 'big' }): BN;
|
|
44
|
+
static fromBuffer(buf: Buffer, opts?: { endian?: 'little' | 'big' | 'le' | 'be'; size?: number }): BN;
|
|
45
|
+
/** Sign-magnitude, as Bitcoin serialises signed values. */
|
|
46
|
+
static fromSM(buf: Buffer, opts?: { endian?: 'little' | 'big' }): BN;
|
|
47
|
+
/**
|
|
48
|
+
* Decode a script number. `size` is the era's width — 4 before Genesis,
|
|
49
|
+
* 750,000 after it, 32,000,000 after Chronicle. Ask the interpreter for it
|
|
50
|
+
* with `maxScriptNumLength()` rather than passing a constant.
|
|
51
|
+
*/
|
|
52
|
+
static fromScriptNumBuffer(buf: Buffer, fRequireMinimal?: boolean, size?: number): BN;
|
|
53
|
+
|
|
54
|
+
toNumber(): number;
|
|
55
|
+
toString(base?: number | 'hex', length?: number): string;
|
|
56
|
+
toHex(opts?: { endian?: 'little' | 'big'; size?: number }): string;
|
|
57
|
+
toBuffer(opts?: { endian?: 'little' | 'big' | 'le' | 'be'; size?: number }): Buffer;
|
|
58
|
+
toSM(opts?: { endian?: 'little' | 'big' }): Buffer;
|
|
59
|
+
toSMBigEndian(): Buffer;
|
|
60
|
+
/** Minimal little-endian script number, sign in the high bit of the last byte. */
|
|
61
|
+
toScriptNumBuffer(): Buffer;
|
|
62
|
+
toJSON(): string;
|
|
63
|
+
toArray(endian?: 'le' | 'be', length?: number): number[];
|
|
64
|
+
|
|
65
|
+
clone(): BN;
|
|
66
|
+
copy(dest: BN): void;
|
|
67
|
+
neg(): BN;
|
|
68
|
+
abs(): BN;
|
|
69
|
+
add(b: BN): BN;
|
|
70
|
+
sub(b: BN): BN;
|
|
71
|
+
mul(b: BN): BN;
|
|
72
|
+
div(b: BN): BN;
|
|
73
|
+
mod(b: BN): BN;
|
|
74
|
+
umod(b: BN): BN;
|
|
75
|
+
sqr(): BN;
|
|
76
|
+
pow(b: BN): BN;
|
|
77
|
+
invm(b: BN): BN;
|
|
78
|
+
gcd(b: BN): BN;
|
|
79
|
+
and(b: BN): BN;
|
|
80
|
+
or(b: BN): BN;
|
|
81
|
+
xor(b: BN): BN;
|
|
82
|
+
shln(bits: number): BN;
|
|
83
|
+
shrn(bits: number): BN;
|
|
84
|
+
addn(n: number): BN;
|
|
85
|
+
subn(n: number): BN;
|
|
86
|
+
muln(n: number): BN;
|
|
87
|
+
divn(n: number): BN;
|
|
88
|
+
modn(n: number): number;
|
|
89
|
+
|
|
90
|
+
cmp(b: BN): -1 | 0 | 1;
|
|
91
|
+
ucmp(b: BN): -1 | 0 | 1;
|
|
92
|
+
eq(b: BN): boolean;
|
|
93
|
+
lt(b: BN): boolean;
|
|
94
|
+
lte(b: BN): boolean;
|
|
95
|
+
gt(b: BN): boolean;
|
|
96
|
+
gte(b: BN): boolean;
|
|
97
|
+
isZero(): boolean;
|
|
98
|
+
isNeg(): boolean;
|
|
99
|
+
isEven(): boolean;
|
|
100
|
+
isOdd(): boolean;
|
|
101
|
+
bitLength(): number;
|
|
102
|
+
byteLength(): number;
|
|
103
|
+
testn(bit: number): boolean;
|
|
104
|
+
}
|
|
16
105
|
|
|
17
106
|
class ECDSA {
|
|
18
107
|
hashbuf?: Buffer;
|
|
@@ -363,69 +452,227 @@ declare module '@smartledger/bsv' {
|
|
|
363
452
|
function fromAddress(address: string | Address): Script;
|
|
364
453
|
|
|
365
454
|
function empty(): Script;
|
|
366
|
-
|
|
367
|
-
|
|
455
|
+
/** The four caps `getLimits()`/`setLimits()` move, in the spelling THEY use. */
|
|
456
|
+
interface InterpreterLimits {
|
|
457
|
+
maxScriptElementSize: number;
|
|
458
|
+
maximumElementSize: number;
|
|
459
|
+
maxOpsPerScript: number;
|
|
460
|
+
maxScriptSize: number;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* A step handed to `stepListener`, before the stacks are mutated.
|
|
465
|
+
*
|
|
466
|
+
* `opcode` is typed structurally rather than as an Opcode: this file does not
|
|
467
|
+
* declare that class yet, and inventing a name here would be worse than
|
|
468
|
+
* describing what the object actually carries.
|
|
469
|
+
*/
|
|
470
|
+
interface InterpreterStep {
|
|
471
|
+
pc: number;
|
|
472
|
+
opcode: { num: number; toString(): string };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** A partial snapshot of evaluation state, applied over the defaults. */
|
|
476
|
+
interface InterpreterState {
|
|
477
|
+
stack?: Buffer[];
|
|
478
|
+
altstack?: Buffer[];
|
|
479
|
+
pc?: number;
|
|
480
|
+
pbegincodehash?: number;
|
|
481
|
+
nOpCount?: number;
|
|
482
|
+
vfExec?: boolean[];
|
|
483
|
+
errstr?: string;
|
|
484
|
+
flags?: number;
|
|
485
|
+
script?: Script;
|
|
486
|
+
tx?: Transaction;
|
|
487
|
+
nin?: number;
|
|
488
|
+
satoshisBN?: crypto.BN;
|
|
489
|
+
stepListener?: (step: InterpreterStep, stack: Buffer[], altstack: Buffer[]) => void;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
interface Interpreter {
|
|
493
|
+
stack: Buffer[];
|
|
494
|
+
altstack: Buffer[];
|
|
495
|
+
pc: number;
|
|
496
|
+
pbegincodehash: number;
|
|
497
|
+
nOpCount: number;
|
|
498
|
+
vfExec: boolean[];
|
|
499
|
+
/** The node's error code for the last failure, or '' if none. */
|
|
500
|
+
errstr: string;
|
|
501
|
+
flags: number;
|
|
502
|
+
script?: Script;
|
|
503
|
+
tx?: Transaction;
|
|
504
|
+
nin?: number;
|
|
505
|
+
satoshisBN?: crypto.BN;
|
|
506
|
+
/** Debugging hook, invoked after each step with clones of the stacks. */
|
|
507
|
+
stepListener?: (step: InterpreterStep, stack: Buffer[], altstack: Buffer[]) => void;
|
|
508
|
+
|
|
509
|
+
initialize(obj?: InterpreterState): void;
|
|
510
|
+
set(obj: InterpreterState): void;
|
|
368
511
|
/**
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
512
|
+
* Verify an unlocking script against a locking script.
|
|
513
|
+
*
|
|
514
|
+
* Omitting `flags` resolves to `currentConsensusFlags()`. Passing a
|
|
515
|
+
* hand-assembled set is how a validator silently ends up pre-Genesis:
|
|
516
|
+
* without an era flag the interpreter applies the 2019 caps whatever
|
|
517
|
+
* feature opcodes are enabled. Prefer `mainnetFlags()` or no argument.
|
|
372
518
|
*/
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
519
|
+
verify(
|
|
520
|
+
scriptSig: Script,
|
|
521
|
+
scriptPubkey: Script,
|
|
522
|
+
tx?: Transaction,
|
|
523
|
+
nin?: number,
|
|
524
|
+
flags?: number,
|
|
525
|
+
satoshisBN?: crypto.BN
|
|
526
|
+
): boolean;
|
|
527
|
+
evaluate(): boolean;
|
|
528
|
+
step(): boolean;
|
|
529
|
+
checkSignatureEncoding(buf: Buffer): boolean;
|
|
530
|
+
checkPubkeyEncoding(buf: Buffer): boolean;
|
|
531
|
+
checkLockTime(nLockTime: crypto.BN): boolean;
|
|
532
|
+
checkSequence(nSequence: crypto.BN): boolean;
|
|
533
|
+
|
|
376
534
|
/**
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
535
|
+
* Which consensus era this evaluation belongs to, and the limits that
|
|
536
|
+
* follow from it. These read the SCRIPT_UTXO_AFTER_* flags on the
|
|
537
|
+
* instance, because the node decides almost everything by the era of the
|
|
538
|
+
* OUTPUT BEING SPENT — an output made before an upgrade is spent under
|
|
539
|
+
* the old rules forever.
|
|
540
|
+
*/
|
|
541
|
+
isAfterGenesis(): boolean;
|
|
542
|
+
isAfterChronicle(): boolean;
|
|
543
|
+
/** 520 before Genesis, UNLIMITED after. */
|
|
544
|
+
maxScriptElementSize(): number;
|
|
545
|
+
/** 10,000 before Genesis, UNLIMITED after. */
|
|
546
|
+
maxScriptSize(): number;
|
|
547
|
+
/** 500 before Genesis (not Core's 201), UNLIMITED after. */
|
|
548
|
+
maxOpsPerScript(): number;
|
|
549
|
+
/** 4 bytes before Genesis, 750,000 after it, 32,000,000 after Chronicle. */
|
|
550
|
+
maxScriptNumLength(): number;
|
|
551
|
+
/** 20 before Genesis, UINT32_MAX after. */
|
|
552
|
+
maxPubKeysPerMultisig(): number;
|
|
553
|
+
/** 1000 elements before Genesis, UNLIMITED after. */
|
|
554
|
+
maxStackSize(): number;
|
|
555
|
+
/** UNLIMITED unless a caller sets MAX_STACK_MEMORY_USAGE_AFTER_GENESIS. */
|
|
556
|
+
maxStackMemoryUsage(): number;
|
|
557
|
+
/** Bytes across both stacks, each element charged STACK_ELEMENT_OVERHEAD. */
|
|
558
|
+
stackMemoryUsage(): number;
|
|
559
|
+
/** The stack limits, applied where the node applies them: after every opcode. */
|
|
560
|
+
checkStackLimits(): string | null;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
interface InterpreterConstructor {
|
|
564
|
+
(obj?: InterpreterState): Interpreter;
|
|
565
|
+
new(obj?: InterpreterState): Interpreter;
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Script-verification flags matching BSV mainnet consensus, including the
|
|
569
|
+
* ERA flags — without those the interpreter falls back to the pre-Genesis
|
|
570
|
+
* statics, so a validator named after mainnet applies 2019 limits.
|
|
382
571
|
*
|
|
383
|
-
* `afterChronicle` defaults to true; pass false
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
572
|
+
* `afterChronicle` defaults to true; pass false for a pre-activation UTXO,
|
|
573
|
+
* which is the distinction the node makes per input. CLTV and CSV are
|
|
574
|
+
* deliberately absent: Genesis reverted both to NOPs, and including them
|
|
575
|
+
* yields a validator stricter than consensus.
|
|
387
576
|
*/
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
577
|
+
mainnetFlags(opts?: { afterChronicle?: boolean }): number;
|
|
578
|
+
/**
|
|
579
|
+
* What `verify()` uses when given no flags. Every bit here is also in
|
|
580
|
+
* `mainnetFlags()`; a test asserts that, because the two drifting apart
|
|
581
|
+
* once made the default silently resolve to the weaker of two answers.
|
|
582
|
+
*/
|
|
583
|
+
currentConsensusFlags(): number;
|
|
584
|
+
/** Applies Genesis limits AND returns mainnet flags. Mutates process state. */
|
|
585
|
+
useMainnetConsensus(opts?: { afterChronicle?: boolean; max?: number }): number;
|
|
586
|
+
/**
|
|
587
|
+
* Opt into post-Genesis limits process-wide. Prefer asking for the era via
|
|
588
|
+
* flags; this exists for callers managing the caps by hand. Pass an
|
|
589
|
+
* explicit `max` when verifying scripts from untrusted sources.
|
|
590
|
+
*/
|
|
591
|
+
useGenesisLimits(max?: number): InterpreterConstructor;
|
|
592
|
+
getLimits(): InterpreterLimits;
|
|
593
|
+
setLimits(limits?: Partial<InterpreterLimits>): InterpreterConstructor;
|
|
594
|
+
castToBool(buf: Buffer): boolean;
|
|
404
595
|
|
|
596
|
+
/** Block height at which Chronicle activated on BSV mainnet (2026-04-07). */
|
|
597
|
+
CHRONICLE_ACTIVATION_HEIGHT: number;
|
|
598
|
+
/** What a limit reads as once the era removed it. */
|
|
599
|
+
UNLIMITED: number;
|
|
600
|
+
|
|
601
|
+
// PRE-Genesis caps. Since the limits became era-derived these are the
|
|
602
|
+
// fallback for a caller that sets no era flag, not the answer for every
|
|
603
|
+
// script. Mutable, so useGenesisLimits()/setLimits() still work.
|
|
604
|
+
MAX_SCRIPT_ELEMENT_SIZE: number;
|
|
605
|
+
MAXIMUM_ELEMENT_SIZE: number;
|
|
606
|
+
MAX_OPS_PER_SCRIPT: number;
|
|
607
|
+
MAX_SCRIPT_SIZE: number;
|
|
608
|
+
MAX_STACK_SIZE: number;
|
|
609
|
+
|
|
610
|
+
MAX_SCRIPT_NUM_LENGTH_AFTER_GENESIS: number;
|
|
611
|
+
MAX_SCRIPT_NUM_LENGTH_AFTER_CHRONICLE: number;
|
|
612
|
+
MAX_PUBKEYS_PER_MULTISIG_AFTER_GENESIS: number;
|
|
613
|
+
/**
|
|
614
|
+
* UNLIMITED, because post-Genesis consensus does not bound stack memory.
|
|
615
|
+
* Assign STACK_MEMORY_USAGE_POLICY to validate against relay rules, or any
|
|
616
|
+
* ceiling to harden against untrusted input.
|
|
617
|
+
*/
|
|
618
|
+
MAX_STACK_MEMORY_USAGE_AFTER_GENESIS: number;
|
|
619
|
+
/** The node's -maxstackmemoryusagepolicy default. Relay policy, not consensus. */
|
|
620
|
+
STACK_MEMORY_USAGE_POLICY: number;
|
|
621
|
+
/** Charged per element on top of its bytes; the container is not free either. */
|
|
622
|
+
STACK_ELEMENT_OVERHEAD: number;
|
|
623
|
+
|
|
624
|
+
LOCKTIME_THRESHOLD: number;
|
|
625
|
+
LOCKTIME_THRESHOLD_BN: crypto.BN;
|
|
626
|
+
SEQUENCE_LOCKTIME_DISABLE_FLAG: number;
|
|
627
|
+
SEQUENCE_LOCKTIME_MASK: number;
|
|
628
|
+
SEQUENCE_LOCKTIME_TYPE_FLAG: number;
|
|
629
|
+
|
|
630
|
+
SCRIPT_VERIFY_NONE: number;
|
|
631
|
+
SCRIPT_VERIFY_P2SH: number;
|
|
632
|
+
SCRIPT_VERIFY_STRICTENC: number;
|
|
633
|
+
SCRIPT_VERIFY_DERSIG: number;
|
|
634
|
+
SCRIPT_VERIFY_LOW_S: number;
|
|
635
|
+
SCRIPT_VERIFY_NULLDUMMY: number;
|
|
636
|
+
SCRIPT_VERIFY_SIGPUSHONLY: number;
|
|
637
|
+
SCRIPT_VERIFY_MINIMALDATA: number;
|
|
638
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: number;
|
|
639
|
+
SCRIPT_VERIFY_CLEANSTACK: number;
|
|
640
|
+
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: number;
|
|
641
|
+
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: number;
|
|
642
|
+
SCRIPT_VERIFY_MINIMALIF: number;
|
|
643
|
+
SCRIPT_VERIFY_NULLFAIL: number;
|
|
644
|
+
SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE: number;
|
|
645
|
+
SCRIPT_ENABLE_SIGHASH_FORKID: number;
|
|
646
|
+
SCRIPT_ENABLE_REPLAY_PROTECTION: number;
|
|
647
|
+
SCRIPT_ENABLE_MONOLITH_OPCODES: number;
|
|
648
|
+
SCRIPT_ENABLE_MAGNETIC_OPCODES: number;
|
|
649
|
+
|
|
650
|
+
// The era flags. SCRIPT_UTXO_AFTER_* describes the OUTPUT BEING SPENT and
|
|
651
|
+
// governs almost every rule; SCRIPT_GENESIS and SCRIPT_CHRONICLE describe
|
|
652
|
+
// the block the spending transaction is in.
|
|
653
|
+
SCRIPT_GENESIS: number;
|
|
654
|
+
SCRIPT_UTXO_AFTER_GENESIS: number;
|
|
405
655
|
/**
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* size). Mutates Interpreter-wide static state — call once at app
|
|
409
|
-
* startup. Pass an explicit `max` (e.g. 64 KB) when verifying
|
|
410
|
-
* scripts from untrusted sources.
|
|
656
|
+
* Chronicle: restores OP_2MUL/OP_2DIV, gives OP_VER/OP_VERIF/OP_VERNOTIF
|
|
657
|
+
* meaning, and lets SIGHASH_CHRONICLE select the original digest.
|
|
411
658
|
*/
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
satoshisBN: crypto.BN
|
|
427
|
-
) => boolean
|
|
659
|
+
SCRIPT_ENABLE_CHRONICLE: number;
|
|
660
|
+
/** The node's name for the SCRIPT_ENABLE_CHRONICLE bit. */
|
|
661
|
+
SCRIPT_CHRONICLE: number;
|
|
662
|
+
SCRIPT_UTXO_AFTER_CHRONICLE: number;
|
|
663
|
+
/** Every era bit, for masking one off a flag word. */
|
|
664
|
+
ERA_FLAGS: number;
|
|
665
|
+
|
|
666
|
+
/** Errors whose meaning depends on the era, keyed by node error code. */
|
|
667
|
+
ERA_SENSITIVE_ERRORS: Record<string, { what: string; lifts: string }>;
|
|
668
|
+
/** Set false (or BSV_NO_ERA_HINT=1) to silence the era diagnostic. */
|
|
669
|
+
eraDiagnostics: boolean;
|
|
670
|
+
|
|
671
|
+
true: Buffer;
|
|
672
|
+
false: Buffer;
|
|
428
673
|
}
|
|
674
|
+
|
|
675
|
+
const Interpreter: InterpreterConstructor;
|
|
429
676
|
}
|
|
430
677
|
|
|
431
678
|
export class Script {
|
|
@@ -1145,6 +1392,346 @@ declare module '@smartledger/bsv' {
|
|
|
1145
1392
|
}
|
|
1146
1393
|
}
|
|
1147
1394
|
|
|
1395
|
+
// -------- NotaryHash (BRC-220) --------------------------------------
|
|
1396
|
+
|
|
1397
|
+
/**
|
|
1398
|
+
* BRC-220 NotaryHash: build, anchor and verify detached-signature proofs.
|
|
1399
|
+
*
|
|
1400
|
+
* Certificates are in the BRC-220 reference implementation's JSON format.
|
|
1401
|
+
* Certificates written by 8.3.0–9.8.0 (`version: 1`, numeric `mode`) are still
|
|
1402
|
+
* read — `verify()` reports them as `legacy` — and never written.
|
|
1403
|
+
*/
|
|
1404
|
+
export namespace NotaryHash {
|
|
1405
|
+
/**
|
|
1406
|
+
* The ON-CHAIN record's mode byte. A certificate's `mode` is 'full' | 'hybrid';
|
|
1407
|
+
* a batch is marked by `anchor.type`, not by the mode.
|
|
1408
|
+
*/
|
|
1409
|
+
const MODE: { readonly FULL: 0; readonly HYBRID: 1; readonly BATCH: 2 };
|
|
1410
|
+
|
|
1411
|
+
type CertificateMode = 'full' | 'hybrid';
|
|
1412
|
+
/** How `publicKey` and `signature` are written. Not the signature's byte format. */
|
|
1413
|
+
type CertificateEncoding = 'hex' | 'base64';
|
|
1414
|
+
type AnchorType = 'direct' | 'batch';
|
|
1415
|
+
type Side = 'left' | 'right';
|
|
1416
|
+
|
|
1417
|
+
/** One audit-path sibling, leaf upward; `side` is its place relative to the running hash. */
|
|
1418
|
+
interface AuditPathNode<H = string> { hash: H; side: Side; }
|
|
1419
|
+
|
|
1420
|
+
interface Anchor {
|
|
1421
|
+
type: AnchorType;
|
|
1422
|
+
network: string;
|
|
1423
|
+
txid: string;
|
|
1424
|
+
vout: number;
|
|
1425
|
+
blockHeight: number | null;
|
|
1426
|
+
blockTime: number | null;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
interface MerkleProof {
|
|
1430
|
+
root: string;
|
|
1431
|
+
leafIndex: number;
|
|
1432
|
+
leafCount: number;
|
|
1433
|
+
path: AuditPathNode[];
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
interface SPVEnvelope {
|
|
1437
|
+
rawTx: string;
|
|
1438
|
+
blockHash: string;
|
|
1439
|
+
blockHeight: number;
|
|
1440
|
+
merkleProof: { index: number; nodes: string[] };
|
|
1441
|
+
/** Defaults to 'TSC'. */
|
|
1442
|
+
format?: string;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/** A BRC-220 certificate, as the reference implementation writes it. */
|
|
1446
|
+
interface Certificate {
|
|
1447
|
+
protocol: 'NotaryHash';
|
|
1448
|
+
version: '1.0';
|
|
1449
|
+
mode: CertificateMode;
|
|
1450
|
+
algorithm: string;
|
|
1451
|
+
hashAlgorithm: string;
|
|
1452
|
+
/** Always hex. */
|
|
1453
|
+
payloadHash: string;
|
|
1454
|
+
/** The FULL key, in every mode, written per `encoding`. */
|
|
1455
|
+
publicKey: string;
|
|
1456
|
+
/** The FULL signature, in every mode, written per `encoding`. */
|
|
1457
|
+
signature: string;
|
|
1458
|
+
encoding: CertificateEncoding;
|
|
1459
|
+
/** Always hex. SHA-256 of the canonical proof bytes, not of this JSON. */
|
|
1460
|
+
proofHash: string;
|
|
1461
|
+
/** ISO 8601, whole seconds — the value inside proofHash. */
|
|
1462
|
+
createdAt: string;
|
|
1463
|
+
anchor: Anchor;
|
|
1464
|
+
/** Present when `anchor.type` is 'batch'. */
|
|
1465
|
+
merkle?: MerkleProof;
|
|
1466
|
+
spv?: SPVEnvelope;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
/** The raw proof fields a certificate's strings decode to. */
|
|
1470
|
+
interface ProofFields {
|
|
1471
|
+
algorithm: string;
|
|
1472
|
+
hashAlgorithm: string;
|
|
1473
|
+
payloadHash: Buffer;
|
|
1474
|
+
publicKey: Buffer;
|
|
1475
|
+
signature: Buffer;
|
|
1476
|
+
createdAtUnix: number;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
interface BuildParams {
|
|
1480
|
+
mode: CertificateMode;
|
|
1481
|
+
algorithm: string;
|
|
1482
|
+
/** 'SHA-256' for every algorithm BRC-220 lists. */
|
|
1483
|
+
hashAlgorithm: string;
|
|
1484
|
+
payloadHash: Buffer;
|
|
1485
|
+
/** Raw bytes, FULL even in hybrid mode. */
|
|
1486
|
+
publicKey: Buffer;
|
|
1487
|
+
/** Raw bytes as the signer produced them. */
|
|
1488
|
+
signature: Buffer;
|
|
1489
|
+
/** Defaults to 'hex'. */
|
|
1490
|
+
encoding?: CertificateEncoding;
|
|
1491
|
+
/** Defaults to now. */
|
|
1492
|
+
createdAt?: string | Date;
|
|
1493
|
+
/** Whole seconds; an alternative to `createdAt`. */
|
|
1494
|
+
createdAtUnix?: number;
|
|
1495
|
+
anchor: {
|
|
1496
|
+
txid: string;
|
|
1497
|
+
/** Inferred from whether `merkle` is given. */
|
|
1498
|
+
type?: AnchorType;
|
|
1499
|
+
network?: string;
|
|
1500
|
+
vout?: number;
|
|
1501
|
+
blockHeight?: number | null;
|
|
1502
|
+
blockTime?: number | null;
|
|
1503
|
+
};
|
|
1504
|
+
/** Makes the certificate batch-anchored. Bare Merkle.path() hashes are converted. */
|
|
1505
|
+
merkle?: {
|
|
1506
|
+
root: Buffer | string;
|
|
1507
|
+
leafIndex: number;
|
|
1508
|
+
leafCount: number;
|
|
1509
|
+
path: Array<AuditPathNode<Buffer | string> | Buffer | string>;
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* A certificate in the 8.3.0–9.8.0 format — what `build()` writes when `format` is
|
|
1515
|
+
* omitted, through 9.x. No other BRC-220 implementation reads it.
|
|
1516
|
+
*/
|
|
1517
|
+
interface LegacyCertificate {
|
|
1518
|
+
protocol: 'NotaryHash';
|
|
1519
|
+
version: 1;
|
|
1520
|
+
/** The on-chain mode byte. */
|
|
1521
|
+
mode: 0 | 1 | 2;
|
|
1522
|
+
algorithm: string;
|
|
1523
|
+
hashAlgorithm: string;
|
|
1524
|
+
payloadHash: string;
|
|
1525
|
+
publicKey: string;
|
|
1526
|
+
signature: string;
|
|
1527
|
+
/** Hex either way; named for the signature's byte form. */
|
|
1528
|
+
encoding: 'raw' | 'der';
|
|
1529
|
+
proofHash: string;
|
|
1530
|
+
createdAt: string;
|
|
1531
|
+
anchor: { txid: string; blockHeight?: number };
|
|
1532
|
+
/** Mode 2 only; the path is bare hex hashes. */
|
|
1533
|
+
merkle?: { root: string; leafIndex: number; leafCount: number; path: string[] };
|
|
1534
|
+
spv?: SPVEnvelope;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
interface LegacyBuildParams {
|
|
1538
|
+
/** Omitted: the 9.x default, which warns once. 'legacy' pins it without the notice. */
|
|
1539
|
+
format?: 'legacy';
|
|
1540
|
+
mode: 0 | 1 | 2;
|
|
1541
|
+
algorithm: string;
|
|
1542
|
+
hashAlgorithm: string;
|
|
1543
|
+
payloadHash: Buffer;
|
|
1544
|
+
publicKey: Buffer;
|
|
1545
|
+
signature: Buffer;
|
|
1546
|
+
/** Defaults to 'raw'. */
|
|
1547
|
+
encoding?: 'raw' | 'der';
|
|
1548
|
+
/** Defaults to now. Written as supplied. */
|
|
1549
|
+
createdAt?: string | Date;
|
|
1550
|
+
anchor: { txid: string; blockHeight?: number };
|
|
1551
|
+
/** Required for mode 2. */
|
|
1552
|
+
merkle?: { root: string; leafIndex: number; leafCount: number; path: string[] };
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
namespace Certificate {
|
|
1556
|
+
const PROTOCOL: 'NotaryHash';
|
|
1557
|
+
/** What the 9.x default format writes. Becomes '1.0' in 10.0.0, with the default. */
|
|
1558
|
+
const VERSION: 1;
|
|
1559
|
+
/** What the reference format writes. */
|
|
1560
|
+
const REFERENCE_VERSION: '1.0';
|
|
1561
|
+
const FORMAT: { readonly REFERENCE: 'reference'; readonly LEGACY: 'legacy' };
|
|
1562
|
+
const MODE: { readonly FULL: 'full'; readonly HYBRID: 'hybrid' };
|
|
1563
|
+
/** HEX and BASE64 are the reference format's; RAW and DER the legacy format's. */
|
|
1564
|
+
const ENCODING: { readonly HEX: 'hex'; readonly BASE64: 'base64'; readonly RAW: 'raw'; readonly DER: 'der' };
|
|
1565
|
+
const ANCHOR_TYPE: { readonly DIRECT: 'direct'; readonly BATCH: 'batch' };
|
|
1566
|
+
/** 'bsv-mainnet'. */
|
|
1567
|
+
const DEFAULT_NETWORK: string;
|
|
1568
|
+
const REQUIRED_FIELDS: string[];
|
|
1569
|
+
/**
|
|
1570
|
+
* Build a certificate in the BRC-220 reference format. proofHash is computed
|
|
1571
|
+
* here, never accepted.
|
|
1572
|
+
*/
|
|
1573
|
+
function build(params: BuildParams & { format: 'reference' }): Certificate;
|
|
1574
|
+
/**
|
|
1575
|
+
* Build a certificate in the 8.3.0–9.8.0 format. Omitting `format` selects this
|
|
1576
|
+
* and warns once; the default becomes 'reference' in 10.0.0.
|
|
1577
|
+
*/
|
|
1578
|
+
function build(params: LegacyBuildParams): LegacyCertificate;
|
|
1579
|
+
/** True for a certificate in the 8.3.0–9.8.0 format. */
|
|
1580
|
+
function isLegacy(certificate: object | null | undefined): boolean;
|
|
1581
|
+
/**
|
|
1582
|
+
* Map an 8.3.0–9.8.0 certificate onto the reference format. Anything else is
|
|
1583
|
+
* returned as given, for validateShape to judge.
|
|
1584
|
+
*/
|
|
1585
|
+
function normalize(certificate: object): Certificate;
|
|
1586
|
+
/** Decode a string field. Hex may carry `0x`; base64 may be URL-safe or unpadded. */
|
|
1587
|
+
function decodeBytes(value: string, encoding: CertificateEncoding, name?: string): Buffer;
|
|
1588
|
+
function toProofInput(certificate: object): ProofFields;
|
|
1589
|
+
function recomputeProofHash(certificate: object): Buffer;
|
|
1590
|
+
/** Validity check 2. Strict boolean; false on anything malformed. */
|
|
1591
|
+
function proofHashMatches(certificate: object | null | undefined): boolean;
|
|
1592
|
+
/** Shape only — NOT verification. Empty means well-formed. */
|
|
1593
|
+
function validateShape(certificate: object | null | undefined): string[];
|
|
1594
|
+
/** A new certificate with the envelope attached; proofHash never changes. */
|
|
1595
|
+
function attachSPV<C extends Certificate | LegacyCertificate>(certificate: C, spv: SPVEnvelope): C & { spv: SPVEnvelope };
|
|
1596
|
+
/** RFC 8785 JSON of the certificate. Not what proofHash is computed over. */
|
|
1597
|
+
function canonicalize(certificate: object): string;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
namespace Encoding {
|
|
1601
|
+
/** 'NotaryHash/1.0', the domain prefix inside the canonical bytes. */
|
|
1602
|
+
const PROTOCOL_PREFIX: string;
|
|
1603
|
+
const VERSION: number;
|
|
1604
|
+
/** `u32be(len(x)) || x`. A string is encoded as UTF-8. */
|
|
1605
|
+
function lp(value: Buffer | string): Buffer;
|
|
1606
|
+
function u64be(seconds: number): Buffer;
|
|
1607
|
+
function toUnixSeconds(createdAt: string | Date): number;
|
|
1608
|
+
function canonicalBytes(fields: ProofFields): Buffer;
|
|
1609
|
+
/** SHA-256 of canonicalBytes. */
|
|
1610
|
+
function proofHash(fields: ProofFields): Buffer;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
interface DirectRecord {
|
|
1614
|
+
mode: 0 | 1;
|
|
1615
|
+
version: number;
|
|
1616
|
+
algorithm: string;
|
|
1617
|
+
hashAlgorithm: string;
|
|
1618
|
+
payloadHash: Buffer;
|
|
1619
|
+
proofHash: Buffer;
|
|
1620
|
+
/** Full mode. */
|
|
1621
|
+
publicKey?: Buffer;
|
|
1622
|
+
signature?: Buffer;
|
|
1623
|
+
/** Hybrid mode: SHA-256 of each. */
|
|
1624
|
+
publicKeyHash?: Buffer;
|
|
1625
|
+
signatureHash?: Buffer;
|
|
1626
|
+
}
|
|
1627
|
+
interface BatchRecord {
|
|
1628
|
+
mode: 2;
|
|
1629
|
+
version: number;
|
|
1630
|
+
merkleRoot: Buffer;
|
|
1631
|
+
leafCount: number;
|
|
1632
|
+
}
|
|
1633
|
+
type OnChainRecord = DirectRecord | BatchRecord;
|
|
1634
|
+
|
|
1635
|
+
interface RecordParams {
|
|
1636
|
+
mode: 'full' | 'hybrid' | 'batch' | 0 | 1 | 2;
|
|
1637
|
+
algorithm?: string;
|
|
1638
|
+
hashAlgorithm?: string;
|
|
1639
|
+
payloadHash?: Buffer;
|
|
1640
|
+
proofHash?: Buffer;
|
|
1641
|
+
/** FULL form in every mode; hybrid puts its digest on chain. */
|
|
1642
|
+
publicKey?: Buffer;
|
|
1643
|
+
signature?: Buffer;
|
|
1644
|
+
merkleRoot?: Buffer;
|
|
1645
|
+
leafCount?: number;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
/** The OP_FALSE OP_RETURN record. */
|
|
1649
|
+
namespace Script {
|
|
1650
|
+
const PREFIX: 'NOTARYHASH';
|
|
1651
|
+
const VERSION: number;
|
|
1652
|
+
const MODE: { readonly FULL: 0; readonly HYBRID: 1; readonly BATCH: 2 };
|
|
1653
|
+
function build(record: RecordParams): import('@smartledger/bsv').Script;
|
|
1654
|
+
/** Throws, naming the problem, rather than returning a partial record. */
|
|
1655
|
+
function parse(script: import('@smartledger/bsv').Script | string): OnChainRecord;
|
|
1656
|
+
/** A cheap filter: true means parse() is worth attempting, not that it will succeed. */
|
|
1657
|
+
function isNotaryHash(script: import('@smartledger/bsv').Script | string): boolean;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
/** RFC 6962 — NOT the Bitcoin Merkle tree. Leaf datum is proofHash. */
|
|
1661
|
+
namespace Merkle {
|
|
1662
|
+
const LEAF_PREFIX: number;
|
|
1663
|
+
const NODE_PREFIX: number;
|
|
1664
|
+
function hashLeaf(d: Buffer): Buffer;
|
|
1665
|
+
function hashNode(left: Buffer, right: Buffer): Buffer;
|
|
1666
|
+
function largestPowerOfTwoBelow(n: number): number;
|
|
1667
|
+
function root(leaves: Buffer[]): Buffer;
|
|
1668
|
+
/** Bare sibling hashes, leaf upward. Folding them needs index and leafCount. */
|
|
1669
|
+
function path(leaves: Buffer[], index: number): Buffer[];
|
|
1670
|
+
function foldPath(leafData: Buffer, index: number, leafCount: number, path: Buffer[]): Buffer;
|
|
1671
|
+
function verifyInclusion(leafData: Buffer, index: number, leafCount: number, path: Buffer[], expectedRoot: Buffer): boolean;
|
|
1672
|
+
function pathSides(index: number, leafCount: number): Side[];
|
|
1673
|
+
/** The path as certificates carry it: { hash, side }, leaf upward. */
|
|
1674
|
+
function auditPath(leaves: Buffer[], index: number): Array<AuditPathNode<Buffer>>;
|
|
1675
|
+
function rootFromPath(leafData: Buffer, path: Array<AuditPathNode<Buffer | string>>): Buffer;
|
|
1676
|
+
/** Strict boolean; false on anything malformed. */
|
|
1677
|
+
function verifyAuditPath(leafData: Buffer, path: Array<AuditPathNode<Buffer | string>>, expectedRoot: Buffer): boolean;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
/** A signature suite. `verify` must return a strict boolean; anything else counts as false. */
|
|
1681
|
+
interface Suite {
|
|
1682
|
+
verify(payloadHash: Buffer, signature: Buffer, publicKey: Buffer): boolean;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
namespace Suites {
|
|
1686
|
+
function register(algorithm: string, suite: Suite): typeof Suites;
|
|
1687
|
+
function get(algorithm: string): Suite | undefined;
|
|
1688
|
+
function list(): string[];
|
|
1689
|
+
function unregister(algorithm: string): typeof Suites;
|
|
1690
|
+
/** An unregistered algorithm is false, never a fallback to ECDSA. */
|
|
1691
|
+
function verify(algorithm: string, payloadHash: Buffer, signature: Buffer, publicKey: Buffer): boolean;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
interface AnchorOptions {
|
|
1695
|
+
/** An independently obtained block header: a bsv BlockHeader, 80 bytes, or 80-byte hex. */
|
|
1696
|
+
header?: string | Buffer | object;
|
|
1697
|
+
/** Pass false only for test fixtures. Defaults to true. */
|
|
1698
|
+
requirePow?: boolean;
|
|
1699
|
+
}
|
|
1700
|
+
interface VerifyOptions extends AnchorOptions {
|
|
1701
|
+
/** Checks 1 and 2 only. The result is never `valid`. */
|
|
1702
|
+
skipAnchor?: boolean;
|
|
1703
|
+
}
|
|
1704
|
+
interface CheckResult { valid: boolean; errors: string[]; }
|
|
1705
|
+
interface VerifyReport {
|
|
1706
|
+
/** The verdict. The report itself is always truthy — read this. */
|
|
1707
|
+
valid: boolean;
|
|
1708
|
+
shape: string[];
|
|
1709
|
+
signature: boolean;
|
|
1710
|
+
proofIntegrity: boolean;
|
|
1711
|
+
anchor: boolean;
|
|
1712
|
+
/** Set once the anchor has been checked. */
|
|
1713
|
+
batchInclusion?: boolean;
|
|
1714
|
+
/** True for a certificate written by 8.3.0–9.8.0. */
|
|
1715
|
+
legacy: boolean;
|
|
1716
|
+
errors: string[];
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
function registerSuite(algorithm: string, suite: Suite): typeof Suites;
|
|
1720
|
+
/** Check 1, offline. */
|
|
1721
|
+
function verifySignature(certificate: object): boolean;
|
|
1722
|
+
/** `reverse(SHA256(SHA256(rawTx)))`, as displayed. */
|
|
1723
|
+
function txidFromRawTx(rawTx: Buffer | string): string;
|
|
1724
|
+
function recordFromRawTx(rawTx: Buffer | string): OnChainRecord | null;
|
|
1725
|
+
function recordMatchesCertificate(record: OnChainRecord, certificate: object): boolean;
|
|
1726
|
+
/** Check 3. Without a header this is never valid. */
|
|
1727
|
+
function verifyAnchorSPV(certificate: object, opts?: AnchorOptions): CheckResult;
|
|
1728
|
+
function verifyBatchInclusion(certificate: object): CheckResult;
|
|
1729
|
+
/** All three checks, reported separately. */
|
|
1730
|
+
function verify(certificate: object, opts?: VerifyOptions): VerifyReport;
|
|
1731
|
+
/** Strict boolean verdict, for `if (...)`. */
|
|
1732
|
+
function isValid(certificate: object, opts?: VerifyOptions): boolean;
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1148
1735
|
// -------- Ordinals (1Sat Ordinals inscriptions + marketplace) -------
|
|
1149
1736
|
|
|
1150
1737
|
export namespace Ordinals {
|