@nuggetslife/vc 0.1.0 → 0.3.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.
Files changed (70) hide show
  1. package/Cargo.toml +1 -0
  2. package/W3C_CONFORMANCE.md +9 -6
  3. package/bench/frame_compare.mjs +7 -20
  4. package/bench/v2_internals.mjs +3 -5
  5. package/bench/vc_ops.mjs +4 -10
  6. package/index.d.ts +2 -2
  7. package/interop-allowlist.json +3 -0
  8. package/interop-smoke-allowlist.json +3 -0
  9. package/package.json +8 -7
  10. package/src/bls_signatures/bbs_bls_holder_bound_signature_2022/mod.rs +18 -27
  11. package/src/bls_signatures/bbs_bls_holder_bound_signature_proof_2022/mod.rs +9 -10
  12. package/src/bls_signatures/bbs_bls_signature_2020/mod.rs +21 -25
  13. package/src/bls_signatures/bbs_bls_signature_proof_2020/mod.rs +6 -12
  14. package/src/jsonld.rs +40 -75
  15. package/src/ld_signatures.rs +210 -224
  16. package/src/lib.rs +8 -0
  17. package/test-fixtures/interop/README.md +46 -0
  18. package/test-fixtures/interop/_contexts/README.md +51 -0
  19. package/test-fixtures/interop/_contexts/bbs-bound-v1.jsonld +92 -0
  20. package/test-fixtures/interop/_contexts/citizenship-v1.jsonld +58 -0
  21. package/test-fixtures/interop/_contexts/credentials-v1.jsonld +316 -0
  22. package/test-fixtures/interop/_contexts/elm-edc-ap.jsonld +809 -0
  23. package/test-fixtures/interop/_contexts/essif-schemas-vc-2020-v1.jsonld +47 -0
  24. package/test-fixtures/interop/_contexts/identity-v2.jsonld +195 -0
  25. package/test-fixtures/interop/_contexts/nuggets-identity-v1.jsonld +175 -0
  26. package/test-fixtures/interop/_contexts/nuggets-kyb-v1.jsonld +333 -0
  27. package/test-fixtures/interop/_contexts/openbadges-v3.jsonld +445 -0
  28. package/test-fixtures/interop/_contexts/security-bbs-v1.jsonld +93 -0
  29. package/test-fixtures/interop/ebsi/diploma-elm/README.md +29 -0
  30. package/test-fixtures/interop/ebsi/diploma-elm/expected.nq +70 -0
  31. package/test-fixtures/interop/ebsi/diploma-elm/frame.jsonld +24 -0
  32. package/test-fixtures/interop/ebsi/diploma-elm/input.jsonld +444 -0
  33. package/test-fixtures/interop/ebsi/diploma-simple/README.md +19 -0
  34. package/test-fixtures/interop/ebsi/diploma-simple/expected.nq +9 -0
  35. package/test-fixtures/interop/ebsi/diploma-simple/frame.jsonld +13 -0
  36. package/test-fixtures/interop/ebsi/diploma-simple/input.jsonld +24 -0
  37. package/test-fixtures/interop/idv2/full-disclosure/README.md +9 -0
  38. package/test-fixtures/interop/idv2/full-disclosure/expected.nq +59 -0
  39. package/test-fixtures/interop/idv2/full-disclosure/frame.jsonld +9 -0
  40. package/test-fixtures/interop/idv2/full-disclosure/input.jsonld +82 -0
  41. package/test-fixtures/interop/nuggets/identity-v1/README.md +17 -0
  42. package/test-fixtures/interop/nuggets/identity-v1/expected.nq +21 -0
  43. package/test-fixtures/interop/nuggets/identity-v1/frame.jsonld +17 -0
  44. package/test-fixtures/interop/nuggets/identity-v1/input.jsonld +31 -0
  45. package/test-fixtures/interop/nuggets/kyb-v1/README.md +15 -0
  46. package/test-fixtures/interop/nuggets/kyb-v1/expected.nq +18 -0
  47. package/test-fixtures/interop/nuggets/kyb-v1/frame.jsonld +24 -0
  48. package/test-fixtures/interop/nuggets/kyb-v1/input.jsonld +60 -0
  49. package/test-fixtures/interop/openbadges-v3/basic-achievement/README.md +17 -0
  50. package/test-fixtures/interop/openbadges-v3/basic-achievement/expected.nq +12 -0
  51. package/test-fixtures/interop/openbadges-v3/basic-achievement/frame.jsonld +17 -0
  52. package/test-fixtures/interop/openbadges-v3/basic-achievement/input.jsonld +25 -0
  53. package/test-fixtures/interop/openbadges-v3/with-allowed-values/README.md +11 -0
  54. package/test-fixtures/interop/openbadges-v3/with-allowed-values/expected.nq +25 -0
  55. package/test-fixtures/interop/openbadges-v3/with-allowed-values/frame.jsonld +22 -0
  56. package/test-fixtures/interop/openbadges-v3/with-allowed-values/input.jsonld +40 -0
  57. package/test-fixtures/interop/vp/single-vc-wrap/README.md +6 -0
  58. package/test-fixtures/interop/vp/single-vc-wrap/expected.nq +7 -0
  59. package/test-fixtures/interop/vp/single-vc-wrap/frame.jsonld +17 -0
  60. package/test-fixtures/interop/vp/single-vc-wrap/input.jsonld +27 -0
  61. package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/README.md +5 -0
  62. package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/expected.nq +13 -0
  63. package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/frame.jsonld +14 -0
  64. package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/input.jsonld +29 -0
  65. package/test_interop.mjs +184 -0
  66. package/test_interop_smoke.mjs +388 -0
  67. package/test_w3c_conformance.mjs +7 -0
  68. package/tools/regen_expected.mjs +108 -0
  69. package/w3c-baseline.json +63 -74
  70. package/w3c-denylist.json +6 -1
package/Cargo.toml CHANGED
@@ -13,6 +13,7 @@ bs58 = "0.5.1"
13
13
  chrono = "0.4.38"
14
14
  hex = "0.4.3"
15
15
  lru = "0.14.0"
16
+ mimalloc = { version = "0.1", default-features = false }
16
17
  # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
17
18
  napi = { version = "2.16.10", default-features = false, features = ["full"] }
18
19
  napi-derive = "2.16.12"
@@ -1,10 +1,13 @@
1
1
  # W3C Conformance Gate
2
2
 
3
3
  The CI runs the W3C JSON-LD 1.1 API and RDF Dataset Canonicalization (RDFC-1.0)
4
- test suites against the v2 JSON-LD path (`CLIENTFFI_JSONLD_V2=1`) via
5
- `test_w3c_conformance.mjs`. The job fails only when a test that **previously
6
- passed** starts failing — never on tests that were already failing in the
7
- committed baseline.
4
+ test suites against the (sole) V2 JSON-LD path via `test_w3c_conformance.mjs`.
5
+ The job fails only when a test that **previously passed** starts failing —
6
+ never on tests that were already failing in the committed baseline.
7
+
8
+ Note: prior versions of this doc referenced `CLIENTFFI_JSONLD_V2=1`; the V1
9
+ JSON-LD pipeline was retired in v1.13.0 (Sprint 4 close-out) and that env
10
+ var is now a no-op.
8
11
 
9
12
  ## Files
10
13
 
@@ -22,12 +25,12 @@ committed baseline.
22
25
  yarn fetch:w3c-tests
23
26
 
24
27
  # Verify nothing has regressed vs baseline
25
- CLIENTFFI_JSONLD_V2=1 yarn test:w3c
28
+ yarn test:w3c
26
29
 
27
30
  # Re-run the suite and overwrite the baseline. Add `--runs 3` for
28
31
  # fast algos (canonize, fromRdf) to take the intersection of 3 runs
29
32
  # and filter out flaky tests.
30
- CLIENTFFI_JSONLD_V2=1 yarn test:w3c:update
33
+ yarn test:w3c:update
31
34
  ```
32
35
 
33
36
  ## Adding a denylist entry
@@ -1,21 +1,16 @@
1
1
  // Head-to-head frame() bench: jsonld.js (Digital Bazaar reference) vs.
2
- // the three Rust backends behind the NAPI binding.
2
+ // the Rust NAPI binding (V2 native typed-tree walker).
3
3
  //
4
4
  // Usage:
5
5
  // node vc/js/bench/frame_compare.mjs # default 30w + 30t
6
6
  // node vc/js/bench/frame_compare.mjs --warm 20 --timed 100
7
7
  // node vc/js/bench/frame_compare.mjs --json
8
8
  //
9
- // Each backend runs in its own measurement loop. The Rust backends are
10
- // selected via env flags inspected by the NAPI binding (vc/js/src/jsonld.rs):
11
- // CLIENTFFI_JSONLD_V2=1 CLIENTFFI_FRAME_NATIVE=1 → frame_native
12
- // CLIENTFFI_JSONLD_V2=1 CLIENTFFI_FRAME_FAST=1 → frame_v2_fast
13
- // CLIENTFFI_JSONLD_V2=1 → frame_v2 (V1-algo full)
14
- //
15
- // Caveat: the env flags are read by `frame_native::use_native()` (cached
16
- // via OnceLock) and inline `std::env::var` in the binding. We can't toggle
17
- // them within a single Node process, so this script spawns a fresh child
18
- // process per backend.
9
+ // Each backend runs in its own measurement loop. The legacy `frame_v2` /
10
+ // `frame_v2_fast` Rust variants were retired in Sprint 3 Phase D and the
11
+ // V1 JSON-LD pipeline (selected via `CLIENTFFI_JSONLD_V2=0` opt-out) was
12
+ // retired in Sprint 4 V1 retirement (v1.13.0); only the V2 native frame
13
+ // remains.
19
14
 
20
15
  import { readFileSync, existsSync } from 'node:fs';
21
16
  import { resolve, dirname, join } from 'node:path';
@@ -51,17 +46,9 @@ if (!backend) {
51
46
  label: 'jsonld.js',
52
47
  env: { BENCH_BACKEND: 'jsonld_js' },
53
48
  },
54
- {
55
- label: 'frame_v2',
56
- env: { BENCH_BACKEND: 'rust', CLIENTFFI_JSONLD_V2: '1' },
57
- },
58
- {
59
- label: 'frame_v2_fast',
60
- env: { BENCH_BACKEND: 'rust', CLIENTFFI_JSONLD_V2: '1', CLIENTFFI_FRAME_FAST: '1' },
61
- },
62
49
  {
63
50
  label: 'frame_native',
64
- env: { BENCH_BACKEND: 'rust', CLIENTFFI_JSONLD_V2: '1', CLIENTFFI_FRAME_NATIVE: '1' },
51
+ env: { BENCH_BACKEND: 'rust' },
65
52
  },
66
53
  ];
67
54
 
@@ -2,12 +2,11 @@
2
2
  // 166 KB IDv2 credential fixture. 30 warm + 30 timed samples per op.
3
3
  //
4
4
  // Usage:
5
- // node vc/js/bench/v2_internals.mjs # V1 (default jsonld pipeline)
6
- // CLIENTFFI_JSONLD_V2=1 node vc/js/bench/v2_internals.mjs # V2 (vendored crate pipeline)
5
+ // node vc/js/bench/v2_internals.mjs # default V2 pipeline
7
6
  // node vc/js/bench/v2_internals.mjs --json # machine-readable output
8
7
  // node vc/js/bench/v2_internals.mjs --only compact # restrict to one op
9
8
  //
10
- // Compares before/after numbers across Sprint 2 patches.
9
+ // V1 baseline variant retired in Sprint 4 V1 retirement (v1.13.0).
11
10
 
12
11
  import { readFileSync, existsSync } from 'node:fs';
13
12
  import { resolve, dirname, join } from 'node:path';
@@ -84,10 +83,9 @@ if (onlyArg && !ops[onlyArg]) {
84
83
  process.exit(1);
85
84
  }
86
85
 
87
- const variant = process.env.CLIENTFFI_JSONLD_V2 ? 'V2' : 'V1';
88
86
  const results = {
89
87
  meta: {
90
- variant,
88
+ variant: 'V2',
91
89
  commit: gitSha,
92
90
  fixture: idv2Json,
93
91
  fixtureBytes: JSON.stringify(big).length,
package/bench/vc_ops.mjs CHANGED
@@ -1,13 +1,9 @@
1
1
  // End-to-end BBS+ verifiable credential ops bench.
2
2
  //
3
3
  // Times the full sign → verify → derive_proof → verify_derived flow for two
4
- // fixtures, across three pipeline configurations. Spawns one Node child
5
- // process per config so the OnceLock-cached env flags in Rust pick up the
6
- // right path.
7
- //
8
- // v1 : default (V1 jsonld pipeline)
9
- // v2 : CLIENTFFI_JSONLD_V2=1 (V2 pipeline, frame_v2)
10
- // v2_native : CLIENTFFI_JSONLD_V2=1 + CLIENTFFI_FRAME_NATIVE=1
4
+ // fixtures across the Rust V2 pipeline (jsonld.js reference for comparison).
5
+ // V1 + intermediate frame_v2 / frame_v2_fast variants were retired in
6
+ // Sprint 4 V1 retirement (v1.13.0).
11
7
  //
12
8
  // Usage:
13
9
  // node vc/js/bench/vc_ops.mjs
@@ -38,9 +34,7 @@ if (!backend) {
38
34
  // Driver: spawn child per pipeline config.
39
35
  const configs = [
40
36
  { label: 'js_ref', env: { BENCH_PIPELINE: 'js' } },
41
- { label: 'v1', env: {} },
42
- { label: 'v2', env: { CLIENTFFI_JSONLD_V2: '1' } },
43
- { label: 'v2_native', env: { CLIENTFFI_JSONLD_V2: '1', CLIENTFFI_FRAME_NATIVE: '1' } },
37
+ { label: 'v2_native', env: {} },
44
38
  ];
45
39
 
46
40
  const allResults = [];
package/index.d.ts CHANGED
@@ -500,8 +500,8 @@ export declare class BoundBls12381G2KeyPair {
500
500
  /**
501
501
  * JSON-LD processor — drop-in replacement for the jsonld.js API.
502
502
  *
503
- * Holds a `DocumentLoader` and `ContextResolver` internally so they are
504
- * created once and reused across all method calls.
503
+ * Holds a `DocumentLoader` internally so it is created once and reused
504
+ * across all method calls.
505
505
  *
506
506
  * ```js
507
507
  * const jsonld = new JsonLd({ contexts: { "https://example.org/ctx": {...} } });
@@ -0,0 +1,3 @@
1
+ {
2
+ "expect_fail": []
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "expect_fail": []
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuggetslife/vc",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "napi": {
@@ -22,7 +22,8 @@
22
22
  "@mattrglobal/jsonld-signatures-bbs": "^1.2.0",
23
23
  "@napi-rs/cli": "^2.18.3",
24
24
  "@types/node": "^20.14.9",
25
- "jsonld": "^8.3.3"
25
+ "jsonld": "^8.3.3",
26
+ "jsonld-signatures": "^7.0.0"
26
27
  },
27
28
  "engines": {
28
29
  "node": ">= 10"
@@ -41,11 +42,11 @@
41
42
  },
42
43
  "packageManager": "yarn@4.3.1",
43
44
  "optionalDependencies": {
44
- "@nuggetslife/vc-darwin-arm64": "0.1.0",
45
- "@nuggetslife/vc-linux-arm64-gnu": "0.1.0",
46
- "@nuggetslife/vc-linux-arm64-musl": "0.1.0",
47
- "@nuggetslife/vc-linux-x64-gnu": "0.1.0",
48
- "@nuggetslife/vc-linux-x64-musl": "0.1.0"
45
+ "@nuggetslife/vc-darwin-arm64": "0.3.0",
46
+ "@nuggetslife/vc-linux-arm64-gnu": "0.3.0",
47
+ "@nuggetslife/vc-linux-arm64-musl": "0.3.0",
48
+ "@nuggetslife/vc-linux-x64-gnu": "0.3.0",
49
+ "@nuggetslife/vc-linux-x64-musl": "0.3.0"
49
50
  },
50
51
  "dependencies": {}
51
52
  }
@@ -29,14 +29,14 @@ impl BbsBlsHolderBoundSignature2022 {
29
29
  match options {
30
30
  Some(opts) => {
31
31
  let key = match opts.key {
32
- Some(kp_opts) => Bls12381G2KeyPair::new(Some(
33
- super::bls_12381_g2_keypair::types::KeyPairOptions {
32
+ Some(kp_opts) => {
33
+ Bls12381G2KeyPair::new(Some(super::bls_12381_g2_keypair::types::KeyPairOptions {
34
34
  id: kp_opts.id,
35
35
  controller: kp_opts.controller,
36
36
  public_key_base58: kp_opts.public_key_base58,
37
37
  private_key_base58: kp_opts.private_key_base58,
38
- },
39
- )),
38
+ }))
39
+ }
40
40
  None => Bls12381G2KeyPair::new(None),
41
41
  };
42
42
 
@@ -80,7 +80,7 @@ impl BbsBlsHolderBoundSignature2022 {
80
80
  &self,
81
81
  options: BoundCreateProofOptions,
82
82
  ) -> Result<serde_json::Value> {
83
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
83
+ let loader = loader_from_contexts(options.contexts.as_ref());
84
84
 
85
85
  let rust_key = napi_key_to_rust_key(&self.key);
86
86
 
@@ -102,7 +102,7 @@ impl BbsBlsHolderBoundSignature2022 {
102
102
 
103
103
  let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
104
104
  suite
105
- .create_blind_sign_commitment_context(&options.document, &purpose, loader, cr)
105
+ .create_blind_sign_commitment_context(&options.document, &purpose, loader)
106
106
  .await
107
107
  .map_err(|e| {
108
108
  napi::Error::from_reason(format!("createBlindSignCommitmentContext failed: {e}"))
@@ -111,11 +111,8 @@ impl BbsBlsHolderBoundSignature2022 {
111
111
 
112
112
  /// Create a proof for a document using BbsBlsHolderBoundSignature2022 (blind signing).
113
113
  #[napi]
114
- pub async fn create_proof(
115
- &self,
116
- options: BoundCreateProofOptions,
117
- ) -> Result<serde_json::Value> {
118
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
114
+ pub async fn create_proof(&self, options: BoundCreateProofOptions) -> Result<serde_json::Value> {
115
+ let loader = loader_from_contexts(options.contexts.as_ref());
119
116
 
120
117
  let commitment = self
121
118
  .commitment
@@ -145,7 +142,7 @@ impl BbsBlsHolderBoundSignature2022 {
145
142
 
146
143
  let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
147
144
  let signed =
148
- vc::jsonld::signatures::sign_holder_bound(options.document, &suite, &purpose, loader, cr)
145
+ vc::jsonld::signatures::sign_holder_bound(options.document, &suite, &purpose, loader)
149
146
  .await
150
147
  .map_err(|e| napi::Error::from_reason(format!("createProof failed: {e}")))?;
151
148
 
@@ -159,15 +156,15 @@ impl BbsBlsHolderBoundSignature2022 {
159
156
  ///
160
157
  /// Returns `{ verified: boolean, error?: string }`.
161
158
  #[napi]
162
- pub async fn verify_proof(
163
- &self,
164
- options: BoundVerifyProofOptions,
165
- ) -> Result<serde_json::Value> {
166
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
159
+ pub async fn verify_proof(&self, options: BoundVerifyProofOptions) -> Result<serde_json::Value> {
160
+ let loader = loader_from_contexts(options.contexts.as_ref());
167
161
 
168
162
  let blinding_factor = options.blinding_factor.to_vec();
169
- let blinded_messages: Vec<Vec<u8>> =
170
- options.blinded_messages.iter().map(|m| m.to_vec()).collect();
163
+ let blinded_messages: Vec<Vec<u8>> = options
164
+ .blinded_messages
165
+ .iter()
166
+ .map(|m| m.to_vec())
167
+ .collect();
171
168
 
172
169
  let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
173
170
  let result = vc::jsonld::signatures::verify_holder_bound(
@@ -176,7 +173,6 @@ impl BbsBlsHolderBoundSignature2022 {
176
173
  blinded_messages,
177
174
  &purpose,
178
175
  loader,
179
- cr,
180
176
  )
181
177
  .await
182
178
  .map_err(|e| napi::Error::from_reason(format!("verifyProof failed: {e}")))?;
@@ -189,18 +185,13 @@ impl BbsBlsHolderBoundSignature2022 {
189
185
 
190
186
  /// Ensure both BBS and holder-bound suite contexts are present.
191
187
  #[napi]
192
- pub fn ensure_suite_context(
193
- &self,
194
- document: serde_json::Value,
195
- ) -> Result<serde_json::Value> {
188
+ pub fn ensure_suite_context(&self, document: serde_json::Value) -> Result<serde_json::Value> {
196
189
  let mut doc = document;
197
190
 
198
191
  for context_url in &[BBS_CONTEXT_URL, BBS_BOUND_CONTEXT_URL] {
199
192
  let has_context = match doc.get("@context") {
200
193
  Some(serde_json::Value::String(s)) => s == *context_url,
201
- Some(serde_json::Value::Array(arr)) => {
202
- arr.iter().any(|v| v.as_str() == Some(*context_url))
203
- }
194
+ Some(serde_json::Value::Array(arr)) => arr.iter().any(|v| v.as_str() == Some(*context_url)),
204
195
  _ => false,
205
196
  };
206
197
 
@@ -23,15 +23,15 @@ impl BbsBlsHolderBoundSignatureProof2022 {
23
23
 
24
24
  /// Derive a selective disclosure proof from a holder-bound signed document.
25
25
  #[napi]
26
- pub async fn derive_proof(
27
- &self,
28
- options: BoundDeriveProofOptions,
29
- ) -> Result<serde_json::Value> {
30
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
26
+ pub async fn derive_proof(&self, options: BoundDeriveProofOptions) -> Result<serde_json::Value> {
27
+ let loader = loader_from_contexts(options.contexts.as_ref());
31
28
 
32
29
  let blinding_factor = options.blinding_factor.to_vec();
33
- let blinded_messages: Vec<Vec<u8>> =
34
- options.blinded_messages.iter().map(|m| m.to_vec()).collect();
30
+ let blinded_messages: Vec<Vec<u8>> = options
31
+ .blinded_messages
32
+ .iter()
33
+ .map(|m| m.to_vec())
34
+ .collect();
35
35
  let nonce = options.nonce.map(|s| s.as_bytes().to_vec());
36
36
 
37
37
  vc::jsonld::signatures::derive_proof_holder_bound(
@@ -41,7 +41,6 @@ impl BbsBlsHolderBoundSignatureProof2022 {
41
41
  blinded_messages,
42
42
  nonce,
43
43
  loader,
44
- cr,
45
44
  )
46
45
  .await
47
46
  .map_err(|e| napi::Error::from_reason(format!("deriveProof failed: {e}")))
@@ -55,10 +54,10 @@ impl BbsBlsHolderBoundSignatureProof2022 {
55
54
  &self,
56
55
  options: BoundVerifyDerivedProofOptions,
57
56
  ) -> Result<serde_json::Value> {
58
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
57
+ let loader = loader_from_contexts(options.contexts.as_ref());
59
58
 
60
59
  let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
61
- let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader, cr)
60
+ let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader)
62
61
  .await
63
62
  .map_err(|e| napi::Error::from_reason(format!("verifyProof failed: {e}")))?;
64
63
 
@@ -63,14 +63,14 @@ impl BbsBlsSignature2020 {
63
63
  match options {
64
64
  Some(opts) => {
65
65
  let key = match opts.key {
66
- Some(kp_opts) => Bls12381G2KeyPair::new(Some(
67
- super::bls_12381_g2_keypair::types::KeyPairOptions {
66
+ Some(kp_opts) => {
67
+ Bls12381G2KeyPair::new(Some(super::bls_12381_g2_keypair::types::KeyPairOptions {
68
68
  id: kp_opts.id,
69
69
  controller: kp_opts.controller,
70
70
  public_key_base58: kp_opts.public_key_base58,
71
71
  private_key_base58: kp_opts.private_key_base58,
72
- },
73
- )),
72
+ }))
73
+ }
74
74
  None => Bls12381G2KeyPair::new(None),
75
75
  };
76
76
 
@@ -116,15 +116,13 @@ impl BbsBlsSignature2020 {
116
116
  /// Generate a BbsBlsSignature2020 suite from a seed (async key generation).
117
117
  #[napi(factory)]
118
118
  pub async fn generate(options: SignatureSuiteOptions) -> Self {
119
- let key = Bls12381G2KeyPair::generate(
120
- options.key.map(|kp| {
121
- super::bls_12381_g2_keypair::types::GenerateKeyPairOptions {
122
- id: kp.id,
123
- controller: kp.controller,
124
- seed: kp.private_key_base58.map(|s| s.into_bytes().into()),
125
- }
126
- }),
127
- )
119
+ let key = Bls12381G2KeyPair::generate(options.key.map(|kp| {
120
+ super::bls_12381_g2_keypair::types::GenerateKeyPairOptions {
121
+ id: kp.id,
122
+ controller: kp.controller,
123
+ seed: kp.private_key_base58.map(|s| s.into_bytes().into()),
124
+ }
125
+ }))
128
126
  .await;
129
127
 
130
128
  let proof = json!({
@@ -165,7 +163,7 @@ impl BbsBlsSignature2020 {
165
163
  /// Returns just the proof object (matching JS reference behavior).
166
164
  #[napi]
167
165
  pub async fn create_proof(&self, options: CreateProofOptions) -> Result<serde_json::Value> {
168
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
166
+ let loader = loader_from_contexts(options.contexts.as_ref());
169
167
 
170
168
  let rust_key = napi_key_to_rust_key(&self.key);
171
169
  let suite = vc::jsonld::signatures::bbs::BbsBlsSignature2020::new(
@@ -179,7 +177,7 @@ impl BbsBlsSignature2020 {
179
177
  .await;
180
178
 
181
179
  let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
182
- let signed = vc::jsonld::signatures::sign(options.document, &suite, &purpose, loader, cr)
180
+ let signed = vc::jsonld::signatures::sign(options.document, &suite, &purpose, loader)
183
181
  .await
184
182
  .map_err(|e| napi::Error::from_reason(format!("createProof failed: {e}")))?;
185
183
 
@@ -194,10 +192,10 @@ impl BbsBlsSignature2020 {
194
192
  /// Returns `{ verified: boolean, error?: string }`.
195
193
  #[napi]
196
194
  pub async fn verify_proof(&self, options: VerifyProofOptions) -> Result<serde_json::Value> {
197
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
195
+ let loader = loader_from_contexts(options.contexts.as_ref());
198
196
 
199
197
  let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
200
- let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader, cr)
198
+ let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader)
201
199
  .await
202
200
  .map_err(|e| napi::Error::from_reason(format!("verifyProof failed: {e}")))?;
203
201
 
@@ -209,25 +207,23 @@ impl BbsBlsSignature2020 {
209
207
 
210
208
  /// Ensure the BBS suite context is present in the document's @context.
211
209
  #[napi]
212
- pub fn ensure_suite_context(
213
- &self,
214
- document: serde_json::Value,
215
- ) -> Result<serde_json::Value> {
210
+ pub fn ensure_suite_context(&self, document: serde_json::Value) -> Result<serde_json::Value> {
216
211
  let bbs_context = "https://w3id.org/security/bbs/v1";
217
212
  let mut doc = document;
218
213
 
219
214
  // Check if already present
220
215
  let has_context = match doc.get("@context") {
221
216
  Some(serde_json::Value::String(s)) => s == bbs_context,
222
- Some(serde_json::Value::Array(arr)) => {
223
- arr.iter().any(|v| v.as_str() == Some(bbs_context))
224
- }
217
+ Some(serde_json::Value::Array(arr)) => arr.iter().any(|v| v.as_str() == Some(bbs_context)),
225
218
  _ => false,
226
219
  };
227
220
 
228
221
  if !has_context {
229
222
  if let Some(obj) = doc.as_object_mut() {
230
- let existing = obj.get("@context").cloned().unwrap_or(serde_json::Value::Null);
223
+ let existing = obj
224
+ .get("@context")
225
+ .cloned()
226
+ .unwrap_or(serde_json::Value::Null);
231
227
  let mut new_context = match existing {
232
228
  serde_json::Value::Array(arr) => serde_json::Value::Array(arr),
233
229
  other => serde_json::Value::Array(vec![other]),
@@ -24,19 +24,13 @@ impl BbsBlsSignatureProof2020 {
24
24
  /// Derive a selective disclosure proof from a signed document.
25
25
  #[napi]
26
26
  pub async fn derive_proof(&self, options: DeriveProofOptions) -> Result<serde_json::Value> {
27
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
27
+ let loader = loader_from_contexts(options.contexts.as_ref());
28
28
 
29
29
  let nonce = options.nonce.map(|s| s.as_bytes().to_vec());
30
30
 
31
- vc::jsonld::signatures::derive_proof(
32
- &options.document,
33
- &options.reveal_document,
34
- nonce,
35
- loader,
36
- cr,
37
- )
38
- .await
39
- .map_err(|e| napi::Error::from_reason(format!("deriveProof failed: {e}")))
31
+ vc::jsonld::signatures::derive_proof(&options.document, &options.reveal_document, nonce, loader)
32
+ .await
33
+ .map_err(|e| napi::Error::from_reason(format!("deriveProof failed: {e}")))
40
34
  }
41
35
 
42
36
  /// Verify a derived (selective disclosure) proof.
@@ -47,10 +41,10 @@ impl BbsBlsSignatureProof2020 {
47
41
  &self,
48
42
  options: VerifyDerivedProofOptions,
49
43
  ) -> Result<serde_json::Value> {
50
- let (loader, cr) = loader_from_contexts(options.contexts.as_ref());
44
+ let loader = loader_from_contexts(options.contexts.as_ref());
51
45
 
52
46
  let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
53
- let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader, cr)
47
+ let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader)
54
48
  .await
55
49
  .map_err(|e| napi::Error::from_reason(format!("verifyProof failed: {e}")))?;
56
50