chainlesschain 0.66.0 → 0.81.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.
@@ -467,4 +467,278 @@ export function _resetState() {
467
467
  _proofs.clear();
468
468
  _verificationKeys.clear();
469
469
  _credentials.clear();
470
+ _maxCircuitsPerCreator = ZKP_DEFAULT_MAX_CIRCUITS_PER_CREATOR;
471
+ _proofExpiryMs = ZKP_DEFAULT_PROOF_EXPIRY_MS;
472
+ }
473
+
474
+ /* ──────────────────────────────────────────────────────────
475
+ * V2 — Phase 88 surface (strictly additive)
476
+ * ────────────────────────────────────────────────────────── */
477
+
478
+ export const PROOF_SCHEME_V2 = PROOF_SCHEME;
479
+ export const CIRCUIT_STATUS_V2 = CIRCUIT_STATUS;
480
+
481
+ export const PROOF_STATUS_V2 = Object.freeze({
482
+ PENDING: "pending",
483
+ VERIFIED: "verified",
484
+ INVALID: "invalid",
485
+ EXPIRED: "expired",
486
+ });
487
+
488
+ export const ZKP_DEFAULT_MAX_CIRCUITS_PER_CREATOR = 10;
489
+ export const ZKP_DEFAULT_PROOF_EXPIRY_MS = 3600_000; // 1h
490
+
491
+ let _maxCircuitsPerCreator = ZKP_DEFAULT_MAX_CIRCUITS_PER_CREATOR;
492
+ let _proofExpiryMs = ZKP_DEFAULT_PROOF_EXPIRY_MS;
493
+
494
+ const CIRCUIT_TRANSITIONS_V2 = new Map([
495
+ ["draft", new Set(["compiled", "failed"])],
496
+ ["compiled", new Set(["verified", "failed"])],
497
+ ]);
498
+ const CIRCUIT_TERMINALS_V2 = new Set(["verified", "failed"]);
499
+
500
+ const PROOF_TRANSITIONS_V2 = new Map([
501
+ ["pending", new Set(["verified", "invalid", "expired"])],
502
+ ]);
503
+ const PROOF_TERMINALS_V2 = new Set(["verified", "invalid", "expired"]);
504
+
505
+ /* ── Config ────────────────────────────────────────────── */
506
+
507
+ export function setMaxCircuitsPerCreator(n) {
508
+ if (typeof n !== "number" || Number.isNaN(n) || n < 1) {
509
+ throw new Error("maxCircuitsPerCreator must be a positive integer");
510
+ }
511
+ _maxCircuitsPerCreator = Math.floor(n);
512
+ }
513
+
514
+ export function getMaxCircuitsPerCreator() {
515
+ return _maxCircuitsPerCreator;
516
+ }
517
+
518
+ export function getCircuitCountByCreator(creator) {
519
+ if (!creator) return 0;
520
+ let count = 0;
521
+ for (const c of _circuits.values()) {
522
+ if (c.creator === creator) count += 1;
523
+ }
524
+ return count;
525
+ }
526
+
527
+ export function setProofExpiryMs(ms) {
528
+ if (typeof ms !== "number" || Number.isNaN(ms) || ms < 1) {
529
+ throw new Error("proofExpiryMs must be a positive integer");
530
+ }
531
+ _proofExpiryMs = Math.floor(ms);
532
+ }
533
+
534
+ export function getProofExpiryMs() {
535
+ return _proofExpiryMs;
536
+ }
537
+
538
+ /* ── Circuit V2 ────────────────────────────────────────── */
539
+
540
+ export function compileCircuitV2(db, { name, definition, creator } = {}) {
541
+ if (!name) throw new Error("name is required");
542
+ if (creator) {
543
+ const count = getCircuitCountByCreator(creator);
544
+ if (count >= _maxCircuitsPerCreator) {
545
+ throw new Error(
546
+ `Max circuits per creator reached (${count}/${_maxCircuitsPerCreator})`,
547
+ );
548
+ }
549
+ }
550
+ const circuit = compileCircuit(db, name, definition);
551
+ if (creator) {
552
+ circuit.creator = creator;
553
+ }
554
+ return { ...circuit };
555
+ }
556
+
557
+ export function setCircuitStatusV2(db, circuitId, newStatus, patch = {}) {
558
+ const circuit = _circuits.get(circuitId);
559
+ if (!circuit) throw new Error(`Circuit not found: ${circuitId}`);
560
+ if (!Object.values(CIRCUIT_STATUS_V2).includes(newStatus)) {
561
+ throw new Error(`Unknown circuit status: ${newStatus}`);
562
+ }
563
+ const allowed = CIRCUIT_TRANSITIONS_V2.get(circuit.status);
564
+ if (!allowed || !allowed.has(newStatus)) {
565
+ throw new Error(`Invalid transition: ${circuit.status} → ${newStatus}`);
566
+ }
567
+ circuit.status = newStatus;
568
+ if (patch.errorMessage !== undefined)
569
+ circuit.errorMessage = patch.errorMessage;
570
+ db.prepare("UPDATE zkp_circuits SET status = ? WHERE id = ?").run(
571
+ newStatus,
572
+ circuitId,
573
+ );
574
+ return { ...circuit };
575
+ }
576
+
577
+ /* ── Proof V2 ──────────────────────────────────────────── */
578
+
579
+ export function generateProofV2(
580
+ db,
581
+ { circuitId, privateInputs, publicInputs, scheme } = {},
582
+ ) {
583
+ if (!circuitId) throw new Error("circuitId is required");
584
+ const circuit = _circuits.get(circuitId);
585
+ if (!circuit) throw new Error(`Circuit not found: ${circuitId}`);
586
+ if (
587
+ circuit.status !== CIRCUIT_STATUS.COMPILED &&
588
+ circuit.status !== CIRCUIT_STATUS.VERIFIED
589
+ ) {
590
+ throw new Error(
591
+ `Circuit not ready (status=${circuit.status}, must be compiled/verified)`,
592
+ );
593
+ }
594
+ const proof = generateProof(db, circuitId, privateInputs, publicInputs, {
595
+ scheme,
596
+ });
597
+ const stored = _proofs.get(proof.id);
598
+ stored.status = PROOF_STATUS_V2.PENDING;
599
+ stored.expiresAt = Date.now() + _proofExpiryMs;
600
+ return { ...stored };
601
+ }
602
+
603
+ export function verifyProofV2(db, proofId) {
604
+ const proof = _proofs.get(proofId);
605
+ if (!proof) throw new Error(`Proof not found: ${proofId}`);
606
+ const current = proof.status || PROOF_STATUS_V2.PENDING;
607
+ if (PROOF_TERMINALS_V2.has(current)) {
608
+ throw new Error(`Invalid transition: ${current} → verify (terminal)`);
609
+ }
610
+ if (proof.expiresAt && Date.now() > proof.expiresAt) {
611
+ proof.status = PROOF_STATUS_V2.EXPIRED;
612
+ db.prepare("UPDATE zkp_proofs SET verified = 0 WHERE id = ?").run(proofId);
613
+ return { ...proof, valid: false, reason: "expired" };
614
+ }
615
+ const result = verifyProof(db, proofId);
616
+ proof.status = result.valid
617
+ ? PROOF_STATUS_V2.VERIFIED
618
+ : PROOF_STATUS_V2.INVALID;
619
+ return { ...proof, valid: result.valid };
620
+ }
621
+
622
+ export function failProof(db, proofId, { reason } = {}) {
623
+ const proof = _proofs.get(proofId);
624
+ if (!proof) throw new Error(`Proof not found: ${proofId}`);
625
+ const current = proof.status || PROOF_STATUS_V2.PENDING;
626
+ if (PROOF_TERMINALS_V2.has(current)) {
627
+ throw new Error(`Invalid transition: ${current} → invalid (terminal)`);
628
+ }
629
+ proof.status = PROOF_STATUS_V2.INVALID;
630
+ proof.verified = false;
631
+ if (reason !== undefined) proof.errorMessage = reason;
632
+ db.prepare("UPDATE zkp_proofs SET verified = 0 WHERE id = ?").run(proofId);
633
+ return { ...proof };
634
+ }
635
+
636
+ export function setProofStatus(db, proofId, newStatus, patch = {}) {
637
+ const proof = _proofs.get(proofId);
638
+ if (!proof) throw new Error(`Proof not found: ${proofId}`);
639
+ if (!Object.values(PROOF_STATUS_V2).includes(newStatus)) {
640
+ throw new Error(`Unknown proof status: ${newStatus}`);
641
+ }
642
+ const current = proof.status || PROOF_STATUS_V2.PENDING;
643
+ const allowed = PROOF_TRANSITIONS_V2.get(current);
644
+ if (!allowed || !allowed.has(newStatus)) {
645
+ throw new Error(`Invalid transition: ${current} → ${newStatus}`);
646
+ }
647
+ proof.status = newStatus;
648
+ if (patch.errorMessage !== undefined) proof.errorMessage = patch.errorMessage;
649
+ if (newStatus === PROOF_STATUS_V2.VERIFIED) {
650
+ proof.verified = true;
651
+ db.prepare("UPDATE zkp_proofs SET verified = 1 WHERE id = ?").run(proofId);
652
+ } else {
653
+ proof.verified = false;
654
+ db.prepare("UPDATE zkp_proofs SET verified = 0 WHERE id = ?").run(proofId);
655
+ }
656
+ return { ...proof };
657
+ }
658
+
659
+ export function autoExpireProofs(db) {
660
+ const now = Date.now();
661
+ const expired = [];
662
+ for (const proof of _proofs.values()) {
663
+ const current = proof.status || PROOF_STATUS_V2.PENDING;
664
+ if (PROOF_TERMINALS_V2.has(current)) continue;
665
+ if (proof.expiresAt && now > proof.expiresAt) {
666
+ proof.status = PROOF_STATUS_V2.EXPIRED;
667
+ proof.verified = false;
668
+ db.prepare("UPDATE zkp_proofs SET verified = 0 WHERE id = ?").run(
669
+ proof.id,
670
+ );
671
+ expired.push({ ...proof });
672
+ }
673
+ }
674
+ return expired;
675
+ }
676
+
677
+ /* ── Selective Disclosure V2 ───────────────────────────── */
678
+
679
+ export function selectiveDiscloseV2(
680
+ db,
681
+ { credentialId, disclosedFields, requiredFields, recipientDid } = {},
682
+ ) {
683
+ if (!credentialId) throw new Error("credentialId is required");
684
+ if (!Array.isArray(disclosedFields)) {
685
+ throw new Error("disclosedFields must be an array");
686
+ }
687
+ const credential = _credentials.get(credentialId);
688
+ if (!credential) throw new Error(`Credential not found: ${credentialId}`);
689
+ if (Array.isArray(requiredFields)) {
690
+ for (const f of requiredFields) {
691
+ if (!disclosedFields.includes(f)) {
692
+ throw new Error(`Required field missing from disclosure: ${f}`);
693
+ }
694
+ if (!(f in credential.claims)) {
695
+ throw new Error(`Required field not in credential: ${f}`);
696
+ }
697
+ }
698
+ }
699
+ return selectiveDisclose(db, credentialId, disclosedFields, recipientDid);
700
+ }
701
+
702
+ /* ── V2 Stats ──────────────────────────────────────────── */
703
+
704
+ export function getZKPStatsV2() {
705
+ const circuitsByStatus = {};
706
+ for (const s of Object.values(CIRCUIT_STATUS_V2)) circuitsByStatus[s] = 0;
707
+ const proofsByStatus = {};
708
+ for (const s of Object.values(PROOF_STATUS_V2)) proofsByStatus[s] = 0;
709
+ const proofsByScheme = {};
710
+ for (const s of Object.values(PROOF_SCHEME_V2)) proofsByScheme[s] = 0;
711
+
712
+ for (const c of _circuits.values()) {
713
+ circuitsByStatus[c.status] = (circuitsByStatus[c.status] || 0) + 1;
714
+ }
715
+ let verifiedCount = 0;
716
+ let pendingCount = 0;
717
+ for (const p of _proofs.values()) {
718
+ const status = p.status || PROOF_STATUS_V2.PENDING;
719
+ proofsByStatus[status] = (proofsByStatus[status] || 0) + 1;
720
+ proofsByScheme[p.scheme] = (proofsByScheme[p.scheme] || 0) + 1;
721
+ if (status === PROOF_STATUS_V2.VERIFIED) verifiedCount += 1;
722
+ if (status === PROOF_STATUS_V2.PENDING) pendingCount += 1;
723
+ }
724
+
725
+ const credentialsByDid = {};
726
+ for (const c of _credentials.values()) {
727
+ const key = c.did || "_anonymous";
728
+ credentialsByDid[key] = (credentialsByDid[key] || 0) + 1;
729
+ }
730
+
731
+ return {
732
+ totalCircuits: _circuits.size,
733
+ totalProofs: _proofs.size,
734
+ totalCredentials: _credentials.size,
735
+ verifiedProofs: verifiedCount,
736
+ pendingProofs: pendingCount,
737
+ maxCircuitsPerCreator: _maxCircuitsPerCreator,
738
+ proofExpiryMs: _proofExpiryMs,
739
+ circuitsByStatus,
740
+ proofsByStatus,
741
+ proofsByScheme,
742
+ credentialsByDid,
743
+ };
470
744
  }