@nuggetslife/vc 0.0.9 → 0.0.15
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/Cargo.toml +5 -2
- package/index.d.ts +303 -3
- package/index.js +15 -1
- package/package.json +16 -8
- package/prepublish.sh +7 -0
- package/src/bls_signatures/bbs_bls_holder_bound_signature_2022/mod.rs +268 -0
- package/src/bls_signatures/bbs_bls_holder_bound_signature_2022/types.rs +26 -0
- package/src/bls_signatures/bbs_bls_holder_bound_signature_proof_2022/mod.rs +100 -0
- package/src/bls_signatures/bbs_bls_holder_bound_signature_proof_2022/types.rs +17 -0
- package/src/bls_signatures/bbs_bls_signature_2020/mod.rs +329 -0
- package/src/bls_signatures/bbs_bls_signature_2020/types.rs +37 -0
- package/src/bls_signatures/bbs_bls_signature_proof_2020/mod.rs +92 -0
- package/src/bls_signatures/bbs_bls_signature_proof_2020/types.rs +13 -0
- package/src/bls_signatures/bls_12381_g2_keypair/mod.rs +470 -0
- package/src/{types.rs → bls_signatures/bls_12381_g2_keypair/types.rs} +0 -11
- package/src/{validators.rs → bls_signatures/bls_12381_g2_keypair/validators.rs} +1 -1
- package/src/bls_signatures/bound_bls_12381_g2_keypair/mod.rs +70 -0
- package/src/bls_signatures/bound_bls_12381_g2_keypair/types.rs +11 -0
- package/src/bls_signatures/mod.rs +6 -0
- package/src/jsonld.rs +200 -0
- package/src/ld_signatures.rs +311 -0
- package/src/lib.rs +3 -463
- package/test-data/bbs.json +92 -0
- package/test-data/citizenVocab.json +57 -0
- package/test-data/controllerDocument.json +5 -0
- package/test-data/credentialsContext.json +315 -0
- package/test-data/deriveProofFrame.json +15 -0
- package/test-data/inputDocument.json +29 -0
- package/test-data/keyPair.json +6 -0
- package/test-data/suiteContext.json +82 -0
- package/test.mjs +1088 -22
- package/test_jsonld_crossverify.mjs +256 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
use napi::bindgen_prelude::*;
|
|
2
|
+
|
|
3
|
+
use crate::bls_signatures::bls_12381_g2_keypair::types::KeyPairOptions;
|
|
4
|
+
|
|
5
|
+
#[napi(object)]
|
|
6
|
+
pub struct BoundSignatureSuiteOptions {
|
|
7
|
+
pub key: Option<KeyPairOptions>,
|
|
8
|
+
pub verification_method: Option<String>,
|
|
9
|
+
pub date: Option<String>,
|
|
10
|
+
pub commitment: Option<Uint8Array>,
|
|
11
|
+
pub blinded: Option<Vec<u32>>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[napi(object)]
|
|
15
|
+
pub struct BoundCreateProofOptions {
|
|
16
|
+
pub document: serde_json::Value,
|
|
17
|
+
pub contexts: Option<serde_json::Value>,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[napi(object)]
|
|
21
|
+
pub struct BoundVerifyProofOptions {
|
|
22
|
+
pub document: serde_json::Value,
|
|
23
|
+
pub blinding_factor: Uint8Array,
|
|
24
|
+
pub blinded_messages: Vec<Uint8Array>,
|
|
25
|
+
pub contexts: Option<serde_json::Value>,
|
|
26
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
use napi::bindgen_prelude::*;
|
|
2
|
+
use serde_json::json;
|
|
3
|
+
use types::{BoundDeriveProofOptions, BoundVerifyDerivedProofOptions};
|
|
4
|
+
|
|
5
|
+
use crate::ld_signatures::{create_document_loader, parse_contexts};
|
|
6
|
+
|
|
7
|
+
pub mod types;
|
|
8
|
+
|
|
9
|
+
#[napi]
|
|
10
|
+
pub struct BbsBlsHolderBoundSignatureProof2022 {
|
|
11
|
+
#[napi(js_name = "type")]
|
|
12
|
+
pub type_: String,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#[napi]
|
|
16
|
+
impl BbsBlsHolderBoundSignatureProof2022 {
|
|
17
|
+
#[napi(constructor)]
|
|
18
|
+
pub fn new() -> Self {
|
|
19
|
+
Self {
|
|
20
|
+
type_: String::from("sec:BbsBlsHolderBoundSignatureProof2022"),
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// Derive a selective disclosure proof from a holder-bound signed document.
|
|
25
|
+
#[napi]
|
|
26
|
+
pub async fn derive_proof(
|
|
27
|
+
&self,
|
|
28
|
+
options: BoundDeriveProofOptions,
|
|
29
|
+
) -> Result<serde_json::Value> {
|
|
30
|
+
let additional_contexts = options
|
|
31
|
+
.contexts
|
|
32
|
+
.as_ref()
|
|
33
|
+
.map(|v| parse_contexts(&json!({ "contexts": v })))
|
|
34
|
+
.unwrap_or_default();
|
|
35
|
+
let (loader, cr) = create_document_loader(additional_contexts);
|
|
36
|
+
|
|
37
|
+
let blinding_factor = options.blinding_factor.to_vec();
|
|
38
|
+
let blinded_messages: Vec<Vec<u8>> =
|
|
39
|
+
options.blinded_messages.iter().map(|m| m.to_vec()).collect();
|
|
40
|
+
let nonce = options.nonce.map(|s| s.as_bytes().to_vec());
|
|
41
|
+
|
|
42
|
+
vc::jsonld::signatures::derive_proof_holder_bound(
|
|
43
|
+
&options.document,
|
|
44
|
+
&options.reveal_document,
|
|
45
|
+
blinding_factor,
|
|
46
|
+
blinded_messages,
|
|
47
|
+
nonce,
|
|
48
|
+
loader,
|
|
49
|
+
cr,
|
|
50
|
+
)
|
|
51
|
+
.await
|
|
52
|
+
.map_err(|e| napi::Error::from_reason(format!("deriveProof failed: {e}")))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// Verify a derived (selective disclosure) holder-bound proof.
|
|
56
|
+
///
|
|
57
|
+
/// Returns `{ verified: boolean, error?: string }`.
|
|
58
|
+
#[napi]
|
|
59
|
+
pub async fn verify_proof(
|
|
60
|
+
&self,
|
|
61
|
+
options: BoundVerifyDerivedProofOptions,
|
|
62
|
+
) -> Result<serde_json::Value> {
|
|
63
|
+
let additional_contexts = options
|
|
64
|
+
.contexts
|
|
65
|
+
.as_ref()
|
|
66
|
+
.map(|v| parse_contexts(&json!({ "contexts": v })))
|
|
67
|
+
.unwrap_or_default();
|
|
68
|
+
let (loader, cr) = create_document_loader(additional_contexts);
|
|
69
|
+
|
|
70
|
+
let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
|
|
71
|
+
let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader, cr)
|
|
72
|
+
.await
|
|
73
|
+
.map_err(|e| napi::Error::from_reason(format!("verifyProof failed: {e}")))?;
|
|
74
|
+
|
|
75
|
+
Ok(json!({
|
|
76
|
+
"verified": result.verified,
|
|
77
|
+
"error": result.error,
|
|
78
|
+
}))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Returns the proof types this suite produces.
|
|
82
|
+
#[napi(getter)]
|
|
83
|
+
pub fn proof_type(&self) -> Vec<String> {
|
|
84
|
+
vec![
|
|
85
|
+
"BbsBlsHolderBoundSignatureProof2022".to_string(),
|
|
86
|
+
"sec:BbsBlsHolderBoundSignatureProof2022".to_string(),
|
|
87
|
+
"https://w3id.org/security#BbsBlsHolderBoundSignatureProof2022".to_string(),
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// Returns the proof types from which this suite can derive.
|
|
92
|
+
#[napi(getter)]
|
|
93
|
+
pub fn supported_derived_proof_type(&self) -> Vec<String> {
|
|
94
|
+
vec![
|
|
95
|
+
"BbsBlsHolderBoundSignature2022".to_string(),
|
|
96
|
+
"sec:BbsBlsHolderBoundSignature2022".to_string(),
|
|
97
|
+
"https://w3id.org/security#BbsBlsHolderBoundSignature2022".to_string(),
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
use napi::bindgen_prelude::*;
|
|
2
|
+
|
|
3
|
+
#[napi(object)]
|
|
4
|
+
pub struct BoundDeriveProofOptions {
|
|
5
|
+
pub document: serde_json::Value,
|
|
6
|
+
pub reveal_document: serde_json::Value,
|
|
7
|
+
pub blinding_factor: Uint8Array,
|
|
8
|
+
pub blinded_messages: Vec<Uint8Array>,
|
|
9
|
+
pub contexts: Option<serde_json::Value>,
|
|
10
|
+
pub nonce: Option<String>,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#[napi(object)]
|
|
14
|
+
pub struct BoundVerifyDerivedProofOptions {
|
|
15
|
+
pub document: serde_json::Value,
|
|
16
|
+
pub contexts: Option<serde_json::Value>,
|
|
17
|
+
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#![allow(dead_code)]
|
|
2
|
+
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
|
3
|
+
use chrono::Utc;
|
|
4
|
+
use napi::bindgen_prelude::*;
|
|
5
|
+
use serde_json::json;
|
|
6
|
+
use types::{
|
|
7
|
+
CreateProofOptions, SignatureSuiteOptions, SuiteSignOptions, VerifyProofOptions,
|
|
8
|
+
VerifySignatureOptions,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
use super::bls_12381_g2_keypair::{
|
|
12
|
+
Bls12381G2KeyPair, KeyPairSigner, KeyPairSignerOptions, KeyPairVerifier, KeyPairVerifierOptions,
|
|
13
|
+
};
|
|
14
|
+
use crate::ld_signatures::{create_document_loader, parse_contexts};
|
|
15
|
+
|
|
16
|
+
pub mod types;
|
|
17
|
+
|
|
18
|
+
/// Convert a NAPI Bls12381G2KeyPair to a Rust core Bls12381G2KeyPair.
|
|
19
|
+
fn napi_key_to_rust_key(
|
|
20
|
+
napi_key: &Bls12381G2KeyPair,
|
|
21
|
+
) -> vc::jsonld::signatures::bbs::bls_12381_g2_keypair::Bls12381G2KeyPair {
|
|
22
|
+
vc::jsonld::signatures::bbs::bls_12381_g2_keypair::Bls12381G2KeyPair::new(Some(
|
|
23
|
+
vc::jsonld::signatures::bbs::bls_12381_g2_keypair::types::KeyPairOptions {
|
|
24
|
+
id: napi_key.id.clone(),
|
|
25
|
+
controller: napi_key.controller.clone(),
|
|
26
|
+
public_key_base58: napi_key.public_key(),
|
|
27
|
+
private_key_base58: napi_key.private_key(),
|
|
28
|
+
},
|
|
29
|
+
))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[napi]
|
|
33
|
+
pub struct BbsBlsSignature2020 {
|
|
34
|
+
proof: serde_json::Value,
|
|
35
|
+
signer: Option<KeyPairSigner>,
|
|
36
|
+
verifier: KeyPairVerifier,
|
|
37
|
+
key: Bls12381G2KeyPair,
|
|
38
|
+
verification_method: Option<String>,
|
|
39
|
+
proof_signature_key: String,
|
|
40
|
+
date: String,
|
|
41
|
+
#[napi(js_name = "type")]
|
|
42
|
+
pub type_: String,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#[napi]
|
|
46
|
+
impl BbsBlsSignature2020 {
|
|
47
|
+
#[napi(constructor)]
|
|
48
|
+
pub fn new(options: Option<SignatureSuiteOptions>) -> Self {
|
|
49
|
+
let proof = json!({
|
|
50
|
+
"@context": [
|
|
51
|
+
{
|
|
52
|
+
"sec": "https://w3id.org/security#",
|
|
53
|
+
"proof": {
|
|
54
|
+
"@id": "sec:proof",
|
|
55
|
+
"@type": "@id",
|
|
56
|
+
"@container": "@graph",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
"https://w3id.org/security/bbs/v1",
|
|
60
|
+
],
|
|
61
|
+
"type": "BbsBlsSignature2020",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
match options {
|
|
65
|
+
Some(opts) => {
|
|
66
|
+
let key = match opts.key {
|
|
67
|
+
Some(kp_opts) => Bls12381G2KeyPair::new(Some(
|
|
68
|
+
super::bls_12381_g2_keypair::types::KeyPairOptions {
|
|
69
|
+
id: kp_opts.id,
|
|
70
|
+
controller: kp_opts.controller,
|
|
71
|
+
public_key_base58: kp_opts.public_key_base58,
|
|
72
|
+
private_key_base58: kp_opts.private_key_base58,
|
|
73
|
+
},
|
|
74
|
+
)),
|
|
75
|
+
None => Bls12381G2KeyPair::new(None),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
let signer = if key.private_key_inner.is_some() {
|
|
79
|
+
Some(key.signer())
|
|
80
|
+
} else {
|
|
81
|
+
None
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
Self {
|
|
85
|
+
proof,
|
|
86
|
+
signer,
|
|
87
|
+
verifier: key.verifier(),
|
|
88
|
+
verification_method: match opts.verification_method {
|
|
89
|
+
Some(vm) => Some(vm),
|
|
90
|
+
None => key.id.clone(),
|
|
91
|
+
},
|
|
92
|
+
key,
|
|
93
|
+
date: match opts.date {
|
|
94
|
+
Some(d) => d,
|
|
95
|
+
None => Utc::now().to_rfc3339(),
|
|
96
|
+
},
|
|
97
|
+
proof_signature_key: String::from("proofValue"),
|
|
98
|
+
type_: String::from("sec:BbsBlsSignature2020"),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
None => {
|
|
102
|
+
let key = Bls12381G2KeyPair::new(None);
|
|
103
|
+
Self {
|
|
104
|
+
proof,
|
|
105
|
+
signer: None,
|
|
106
|
+
verifier: key.verifier(),
|
|
107
|
+
verification_method: None,
|
|
108
|
+
key,
|
|
109
|
+
date: Utc::now().to_rfc3339(),
|
|
110
|
+
proof_signature_key: String::from("proofValue"),
|
|
111
|
+
type_: String::from("sec:BbsBlsSignature2020"),
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Generate a BbsBlsSignature2020 suite from a seed (async key generation).
|
|
118
|
+
#[napi(factory)]
|
|
119
|
+
pub async fn generate(options: SignatureSuiteOptions) -> Self {
|
|
120
|
+
let key = Bls12381G2KeyPair::generate(
|
|
121
|
+
options.key.map(|kp| {
|
|
122
|
+
super::bls_12381_g2_keypair::types::GenerateKeyPairOptions {
|
|
123
|
+
id: kp.id,
|
|
124
|
+
controller: kp.controller,
|
|
125
|
+
seed: kp.private_key_base58.map(|s| s.into_bytes().into()),
|
|
126
|
+
}
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
.await;
|
|
130
|
+
|
|
131
|
+
let proof = json!({
|
|
132
|
+
"@context": [
|
|
133
|
+
{
|
|
134
|
+
"sec": "https://w3id.org/security#",
|
|
135
|
+
"proof": {
|
|
136
|
+
"@id": "sec:proof",
|
|
137
|
+
"@type": "@id",
|
|
138
|
+
"@container": "@graph",
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
"https://w3id.org/security/bbs/v1",
|
|
142
|
+
],
|
|
143
|
+
"type": "BbsBlsSignature2020",
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
Self {
|
|
147
|
+
proof,
|
|
148
|
+
signer: Some(key.signer()),
|
|
149
|
+
verifier: key.verifier(),
|
|
150
|
+
verification_method: match options.verification_method {
|
|
151
|
+
Some(vm) => Some(vm),
|
|
152
|
+
None => key.id.clone(),
|
|
153
|
+
},
|
|
154
|
+
key,
|
|
155
|
+
date: match options.date {
|
|
156
|
+
Some(d) => d,
|
|
157
|
+
None => Utc::now().to_rfc3339(),
|
|
158
|
+
},
|
|
159
|
+
proof_signature_key: String::from("proofValue"),
|
|
160
|
+
type_: String::from("sec:BbsBlsSignature2020"),
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/// Create a proof for a document using BbsBlsSignature2020.
|
|
165
|
+
///
|
|
166
|
+
/// Returns just the proof object (matching JS reference behavior).
|
|
167
|
+
#[napi]
|
|
168
|
+
pub async fn create_proof(&self, options: CreateProofOptions) -> Result<serde_json::Value> {
|
|
169
|
+
let additional_contexts = options
|
|
170
|
+
.contexts
|
|
171
|
+
.as_ref()
|
|
172
|
+
.map(|v| parse_contexts(&json!({ "contexts": v })))
|
|
173
|
+
.unwrap_or_default();
|
|
174
|
+
let (loader, cr) = create_document_loader(additional_contexts);
|
|
175
|
+
|
|
176
|
+
let rust_key = napi_key_to_rust_key(&self.key);
|
|
177
|
+
let suite = vc::jsonld::signatures::bbs::BbsBlsSignature2020::new(
|
|
178
|
+
vc::jsonld::signatures::bbs::SignatureSuiteOptions {
|
|
179
|
+
key: rust_key,
|
|
180
|
+
verification_method: self.verification_method.clone(),
|
|
181
|
+
date: None,
|
|
182
|
+
canonize_options: None,
|
|
183
|
+
},
|
|
184
|
+
)
|
|
185
|
+
.await;
|
|
186
|
+
|
|
187
|
+
let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
|
|
188
|
+
let signed = vc::jsonld::signatures::sign(options.document, &suite, &purpose, loader, cr)
|
|
189
|
+
.await
|
|
190
|
+
.map_err(|e| napi::Error::from_reason(format!("createProof failed: {e}")))?;
|
|
191
|
+
|
|
192
|
+
signed
|
|
193
|
+
.get("proof")
|
|
194
|
+
.cloned()
|
|
195
|
+
.ok_or_else(|| napi::Error::from_reason("createProof: no proof in signed document"))
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/// Verify a document with an embedded proof.
|
|
199
|
+
///
|
|
200
|
+
/// Returns `{ verified: boolean, error?: string }`.
|
|
201
|
+
#[napi]
|
|
202
|
+
pub async fn verify_proof(&self, options: VerifyProofOptions) -> Result<serde_json::Value> {
|
|
203
|
+
let additional_contexts = options
|
|
204
|
+
.contexts
|
|
205
|
+
.as_ref()
|
|
206
|
+
.map(|v| parse_contexts(&json!({ "contexts": v })))
|
|
207
|
+
.unwrap_or_default();
|
|
208
|
+
let (loader, cr) = create_document_loader(additional_contexts);
|
|
209
|
+
|
|
210
|
+
let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
|
|
211
|
+
let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader, cr)
|
|
212
|
+
.await
|
|
213
|
+
.map_err(|e| napi::Error::from_reason(format!("verifyProof failed: {e}")))?;
|
|
214
|
+
|
|
215
|
+
Ok(json!({
|
|
216
|
+
"verified": result.verified,
|
|
217
|
+
"error": result.error,
|
|
218
|
+
}))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/// Ensure the BBS suite context is present in the document's @context.
|
|
222
|
+
#[napi]
|
|
223
|
+
pub fn ensure_suite_context(
|
|
224
|
+
&self,
|
|
225
|
+
document: serde_json::Value,
|
|
226
|
+
) -> Result<serde_json::Value> {
|
|
227
|
+
let bbs_context = "https://w3id.org/security/bbs/v1";
|
|
228
|
+
let mut doc = document;
|
|
229
|
+
|
|
230
|
+
// Check if already present
|
|
231
|
+
let has_context = match doc.get("@context") {
|
|
232
|
+
Some(serde_json::Value::String(s)) => s == bbs_context,
|
|
233
|
+
Some(serde_json::Value::Array(arr)) => {
|
|
234
|
+
arr.iter().any(|v| v.as_str() == Some(bbs_context))
|
|
235
|
+
}
|
|
236
|
+
_ => false,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
if !has_context {
|
|
240
|
+
if let Some(obj) = doc.as_object_mut() {
|
|
241
|
+
let existing = obj.get("@context").cloned().unwrap_or(serde_json::Value::Null);
|
|
242
|
+
let mut new_context = match existing {
|
|
243
|
+
serde_json::Value::Array(arr) => serde_json::Value::Array(arr),
|
|
244
|
+
other => serde_json::Value::Array(vec![other]),
|
|
245
|
+
};
|
|
246
|
+
if let serde_json::Value::Array(arr) = &mut new_context {
|
|
247
|
+
arr.push(serde_json::Value::String(bbs_context.to_string()));
|
|
248
|
+
}
|
|
249
|
+
obj.insert("@context".to_string(), new_context);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
Ok(doc)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
#[napi]
|
|
257
|
+
pub async fn sign(&self, options: SuiteSignOptions) -> Result<serde_json::Value> {
|
|
258
|
+
let signer = self
|
|
259
|
+
.signer
|
|
260
|
+
.as_ref()
|
|
261
|
+
.ok_or_else(|| napi::Error::from_reason("No signer available (no private key)"))?;
|
|
262
|
+
|
|
263
|
+
let mut proof_mut = options.proof.clone();
|
|
264
|
+
let Some(proof_obj) = proof_mut.as_object_mut() else {
|
|
265
|
+
return Err(napi::Error::from_reason("proof is not a json object"));
|
|
266
|
+
};
|
|
267
|
+
let proof_value = signer
|
|
268
|
+
.sign(KeyPairSignerOptions {
|
|
269
|
+
data: options.verify_data,
|
|
270
|
+
})
|
|
271
|
+
.await?;
|
|
272
|
+
let proof_value = STANDARD.encode(proof_value.to_vec());
|
|
273
|
+
|
|
274
|
+
proof_obj.insert(
|
|
275
|
+
self.proof_signature_key.clone(),
|
|
276
|
+
serde_json::Value::String(proof_value),
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
Ok(proof_mut)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
#[napi]
|
|
283
|
+
pub async fn verify_signature(&self, options: VerifySignatureOptions) -> Result<bool> {
|
|
284
|
+
let Some(serde_json::Value::String(proof_value)) = options.proof.get(&self.proof_signature_key)
|
|
285
|
+
else {
|
|
286
|
+
return Err(napi::Error::from_reason(format!(
|
|
287
|
+
"key: {} is missing from proof",
|
|
288
|
+
self.proof_signature_key
|
|
289
|
+
)));
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
let signature = STANDARD.decode(proof_value).map_err(|err| {
|
|
293
|
+
napi::Error::from_reason(format!(
|
|
294
|
+
"failed to decode proof_value from base64 string. error: {err}"
|
|
295
|
+
))
|
|
296
|
+
})?;
|
|
297
|
+
|
|
298
|
+
let signature = Uint8Array::from(signature);
|
|
299
|
+
let verified = self
|
|
300
|
+
.verifier
|
|
301
|
+
.verify(KeyPairVerifierOptions {
|
|
302
|
+
data: options.verify_data,
|
|
303
|
+
signature,
|
|
304
|
+
})
|
|
305
|
+
.await
|
|
306
|
+
.map_err(|err| napi::Error::from_reason(format!("verifySignature failed: {err}")))?;
|
|
307
|
+
|
|
308
|
+
Ok(verified)
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
#[cfg(test)]
|
|
313
|
+
mod tests {
|
|
314
|
+
|
|
315
|
+
use super::*;
|
|
316
|
+
#[test]
|
|
317
|
+
pub fn it_works() {
|
|
318
|
+
let mut j = json!({});
|
|
319
|
+
|
|
320
|
+
let Some(obj) = j.as_object_mut() else {
|
|
321
|
+
return ();
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
obj.insert(String::from("hello"), "there".into());
|
|
325
|
+
let _x = STANDARD.decode("hello");
|
|
326
|
+
|
|
327
|
+
println!("{j}")
|
|
328
|
+
}
|
|
329
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#![allow(dead_code)]
|
|
2
|
+
use napi::bindgen_prelude::Uint8Array;
|
|
3
|
+
|
|
4
|
+
use crate::bls_signatures::bls_12381_g2_keypair::types::KeyPairOptions;
|
|
5
|
+
|
|
6
|
+
#[napi(object)]
|
|
7
|
+
pub struct SignatureSuiteOptions {
|
|
8
|
+
pub key: Option<KeyPairOptions>,
|
|
9
|
+
pub verification_method: Option<String>,
|
|
10
|
+
pub date: Option<String>,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#[napi(object)]
|
|
14
|
+
pub struct CreateProofOptions {
|
|
15
|
+
pub document: serde_json::Value,
|
|
16
|
+
pub contexts: Option<serde_json::Value>,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#[napi(object)]
|
|
20
|
+
pub struct VerifyProofOptions {
|
|
21
|
+
pub document: serde_json::Value,
|
|
22
|
+
pub contexts: Option<serde_json::Value>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[napi(object)]
|
|
26
|
+
pub struct SuiteSignOptions {
|
|
27
|
+
pub document: serde_json::Value,
|
|
28
|
+
pub proof: serde_json::Value,
|
|
29
|
+
pub verify_data: Vec<Uint8Array>,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[napi(object)]
|
|
33
|
+
pub struct VerifySignatureOptions {
|
|
34
|
+
pub document: serde_json::Value,
|
|
35
|
+
pub proof: serde_json::Value,
|
|
36
|
+
pub verify_data: Vec<Uint8Array>,
|
|
37
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
use napi::bindgen_prelude::*;
|
|
2
|
+
use serde_json::json;
|
|
3
|
+
use types::{DeriveProofOptions, VerifyDerivedProofOptions};
|
|
4
|
+
|
|
5
|
+
use crate::ld_signatures::{create_document_loader, parse_contexts};
|
|
6
|
+
|
|
7
|
+
pub mod types;
|
|
8
|
+
|
|
9
|
+
#[napi]
|
|
10
|
+
pub struct BbsBlsSignatureProof2020 {
|
|
11
|
+
#[napi(js_name = "type")]
|
|
12
|
+
pub type_: String,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#[napi]
|
|
16
|
+
impl BbsBlsSignatureProof2020 {
|
|
17
|
+
#[napi(constructor)]
|
|
18
|
+
pub fn new() -> Self {
|
|
19
|
+
Self {
|
|
20
|
+
type_: String::from("sec:BbsBlsSignatureProof2020"),
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// Derive a selective disclosure proof from a signed document.
|
|
25
|
+
#[napi]
|
|
26
|
+
pub async fn derive_proof(&self, options: DeriveProofOptions) -> Result<serde_json::Value> {
|
|
27
|
+
let additional_contexts = options
|
|
28
|
+
.contexts
|
|
29
|
+
.as_ref()
|
|
30
|
+
.map(|v| parse_contexts(&json!({ "contexts": v })))
|
|
31
|
+
.unwrap_or_default();
|
|
32
|
+
let (loader, cr) = create_document_loader(additional_contexts);
|
|
33
|
+
|
|
34
|
+
let nonce = options.nonce.map(|s| s.as_bytes().to_vec());
|
|
35
|
+
|
|
36
|
+
vc::jsonld::signatures::derive_proof(
|
|
37
|
+
&options.document,
|
|
38
|
+
&options.reveal_document,
|
|
39
|
+
nonce,
|
|
40
|
+
loader,
|
|
41
|
+
cr,
|
|
42
|
+
)
|
|
43
|
+
.await
|
|
44
|
+
.map_err(|e| napi::Error::from_reason(format!("deriveProof failed: {e}")))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Verify a derived (selective disclosure) proof.
|
|
48
|
+
///
|
|
49
|
+
/// Returns `{ verified: boolean, error?: string }`.
|
|
50
|
+
#[napi]
|
|
51
|
+
pub async fn verify_proof(
|
|
52
|
+
&self,
|
|
53
|
+
options: VerifyDerivedProofOptions,
|
|
54
|
+
) -> Result<serde_json::Value> {
|
|
55
|
+
let additional_contexts = options
|
|
56
|
+
.contexts
|
|
57
|
+
.as_ref()
|
|
58
|
+
.map(|v| parse_contexts(&json!({ "contexts": v })))
|
|
59
|
+
.unwrap_or_default();
|
|
60
|
+
let (loader, cr) = create_document_loader(additional_contexts);
|
|
61
|
+
|
|
62
|
+
let purpose = vc::jsonld::signatures::AssertionProofPurpose::new();
|
|
63
|
+
let result = vc::jsonld::signatures::verify(&options.document, &purpose, loader, cr)
|
|
64
|
+
.await
|
|
65
|
+
.map_err(|e| napi::Error::from_reason(format!("verifyProof failed: {e}")))?;
|
|
66
|
+
|
|
67
|
+
Ok(json!({
|
|
68
|
+
"verified": result.verified,
|
|
69
|
+
"error": result.error,
|
|
70
|
+
}))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// Returns the proof types this suite produces.
|
|
74
|
+
#[napi(getter)]
|
|
75
|
+
pub fn proof_type(&self) -> Vec<String> {
|
|
76
|
+
vec![
|
|
77
|
+
"BbsBlsSignatureProof2020".to_string(),
|
|
78
|
+
"sec:BbsBlsSignatureProof2020".to_string(),
|
|
79
|
+
"https://w3id.org/security#BbsBlsSignatureProof2020".to_string(),
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// Returns the proof types from which this suite can derive.
|
|
84
|
+
#[napi(getter)]
|
|
85
|
+
pub fn supported_derived_proof_type(&self) -> Vec<String> {
|
|
86
|
+
vec![
|
|
87
|
+
"BbsBlsSignature2020".to_string(),
|
|
88
|
+
"sec:BbsBlsSignature2020".to_string(),
|
|
89
|
+
"https://w3id.org/security#BbsBlsSignature2020".to_string(),
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#[napi(object)]
|
|
2
|
+
pub struct DeriveProofOptions {
|
|
3
|
+
pub document: serde_json::Value,
|
|
4
|
+
pub reveal_document: serde_json::Value,
|
|
5
|
+
pub contexts: Option<serde_json::Value>,
|
|
6
|
+
pub nonce: Option<String>,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
#[napi(object)]
|
|
10
|
+
pub struct VerifyDerivedProofOptions {
|
|
11
|
+
pub document: serde_json::Value,
|
|
12
|
+
pub contexts: Option<serde_json::Value>,
|
|
13
|
+
}
|