@nuggetslife/vc 0.0.5 → 0.0.7
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/index.d.ts +81 -0
- package/index.js +3 -1
- package/package.json +2 -2
- package/src/lib.rs +133 -27
- package/src/types.rs +154 -0
- package/src/validators.rs +68 -0
- package/test.mjs +78 -0
package/index.d.ts
CHANGED
|
@@ -9,11 +9,83 @@ export interface KeyPairOptions {
|
|
|
9
9
|
privateKeyBase58?: string
|
|
10
10
|
publicKeyBase58?: string
|
|
11
11
|
}
|
|
12
|
+
export interface JwkKeyPairOptions {
|
|
13
|
+
id?: string
|
|
14
|
+
controller?: string
|
|
15
|
+
privateKeyJwk?: JsonWebKey
|
|
16
|
+
publicKeyJwk?: JsonWebKey
|
|
17
|
+
}
|
|
18
|
+
export interface JsonWebKey {
|
|
19
|
+
/**
|
|
20
|
+
* Indicates the key type used
|
|
21
|
+
* For BLS12381_G1 and BLS12381_G2 the string "EC" MUST be used
|
|
22
|
+
* @see https://tools.ietf.org/html/rfc7517#section-4.1
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
kty: string
|
|
26
|
+
/**
|
|
27
|
+
* Indicates the curve this key is associated with
|
|
28
|
+
* In the case of BLS12-381, the curve will also indicate if it's a G1 or G2 point
|
|
29
|
+
* For a G1 point, use the string "BLS12381_G1"
|
|
30
|
+
* For a G2 point, use the string "BLS12381_G2"
|
|
31
|
+
*/
|
|
32
|
+
crv: string
|
|
33
|
+
/**
|
|
34
|
+
* This is a compression of the public key point
|
|
35
|
+
* For a G1 public key, X is a 384bit base64url encoding of the octet string representation of the coordinate
|
|
36
|
+
* For a G2 public key, X is a 768bit made up of the concatenation of two 384 bit x coordinates known as
|
|
37
|
+
* x_a and x_b in the following form (x_a || x_b) as a base64url encoding of the octet string representation of the two coordinates
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
x: string
|
|
41
|
+
/** @see https://tools.ietf.org/html/rfc7517#section-4.2 */
|
|
42
|
+
use?: string
|
|
43
|
+
/**
|
|
44
|
+
* @see https://tools.ietf.org/html/rfc7517#section-4.3
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
keyOps?: Array<string>
|
|
48
|
+
/**
|
|
49
|
+
* @see https://tools.ietf.org/html/rfc7517#section-4.4
|
|
50
|
+
*
|
|
51
|
+
*/
|
|
52
|
+
alg?: string
|
|
53
|
+
/**
|
|
54
|
+
* @see https://tools.ietf.org/html/rfc7517#section-4.5
|
|
55
|
+
* TODO: Add note about referencing did-jose-extensions when ready
|
|
56
|
+
*
|
|
57
|
+
*/
|
|
58
|
+
kid?: string
|
|
59
|
+
/**
|
|
60
|
+
* IMPORTANT NOTE: d represents the private key value and should not be shared
|
|
61
|
+
* IT IS HIGHLY SENSITIVE DATA AND IF NOT SECURED PROPERLY CONSIDER THE KEY COMPROMISED
|
|
62
|
+
* @see https://tools.ietf.org/html/rfc7517#section-9.2
|
|
63
|
+
*
|
|
64
|
+
*/
|
|
65
|
+
d?: string
|
|
66
|
+
/**
|
|
67
|
+
* This coordinate is not used for BLS Keys, but is kept here to make the interface more standard
|
|
68
|
+
*
|
|
69
|
+
*/
|
|
70
|
+
y?: string
|
|
71
|
+
/**
|
|
72
|
+
* @see https://www.w3.org/TR/WebCryptoAPI/#cryptokey-interface-members
|
|
73
|
+
*
|
|
74
|
+
*/
|
|
75
|
+
ext?: boolean
|
|
76
|
+
}
|
|
12
77
|
export interface GenerateKeyPairOptions {
|
|
13
78
|
id?: string
|
|
14
79
|
controller?: string
|
|
15
80
|
seed?: Buffer
|
|
16
81
|
}
|
|
82
|
+
export interface KeyPairSignerOptions {
|
|
83
|
+
data: Array<Uint8Array>
|
|
84
|
+
}
|
|
85
|
+
export interface KeyPairVerifierOptions {
|
|
86
|
+
data: Array<Uint8Array>
|
|
87
|
+
signature: Uint8Array
|
|
88
|
+
}
|
|
17
89
|
export class Bls12381G2KeyPair {
|
|
18
90
|
id?: string
|
|
19
91
|
controller?: string
|
|
@@ -23,6 +95,15 @@ export class Bls12381G2KeyPair {
|
|
|
23
95
|
constructor(options?: KeyPairOptions | undefined | null)
|
|
24
96
|
static generate(options?: GenerateKeyPairOptions | undefined | null): Promise<Bls12381G2KeyPair>
|
|
25
97
|
static from(options: KeyPairOptions): Promise<Bls12381G2KeyPair>
|
|
98
|
+
static fromJwk(options: JwkKeyPairOptions): Promise<Bls12381G2KeyPair>
|
|
26
99
|
get publicKey(): string | null
|
|
27
100
|
get privateKey(): string | null
|
|
101
|
+
signer(): KeyPairSigner
|
|
102
|
+
verifier(): KeyPairVerifier
|
|
103
|
+
}
|
|
104
|
+
export class KeyPairSigner {
|
|
105
|
+
sign(options: KeyPairSignerOptions): Promise<Uint8Array>
|
|
106
|
+
}
|
|
107
|
+
export class KeyPairVerifier {
|
|
108
|
+
verify(options: KeyPairVerifierOptions): Promise<boolean>
|
|
28
109
|
}
|
package/index.js
CHANGED
|
@@ -310,6 +310,8 @@ if (!nativeBinding) {
|
|
|
310
310
|
throw new Error(`Failed to load native binding`)
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
const { Bls12381G2KeyPair } = nativeBinding
|
|
313
|
+
const { Bls12381G2KeyPair, KeyPairSigner, KeyPairVerifier } = nativeBinding
|
|
314
314
|
|
|
315
315
|
module.exports.Bls12381G2KeyPair = Bls12381G2KeyPair
|
|
316
|
+
module.exports.KeyPairSigner = KeyPairSigner
|
|
317
|
+
module.exports.KeyPairVerifier = KeyPairVerifier
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuggetslife/vc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -38,6 +38,6 @@
|
|
|
38
38
|
},
|
|
39
39
|
"packageManager": "yarn@4.3.1",
|
|
40
40
|
"optionalDependencies": {
|
|
41
|
-
"@nuggetslife/vc-darwin-arm64": "0.0.
|
|
41
|
+
"@nuggetslife/vc-darwin-arm64": "0.0.7"
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/lib.rs
CHANGED
|
@@ -3,34 +3,16 @@
|
|
|
3
3
|
#[macro_use]
|
|
4
4
|
extern crate napi_derive;
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
use base64::{engine::general_purpose::URL_SAFE, Engine as _};
|
|
7
7
|
use napi::bindgen_prelude::*;
|
|
8
|
-
use
|
|
8
|
+
use types::{Bls12381G2KeyPair, GenerateKeyPairOptions, JwkKeyPairOptions, KeyPairOptions};
|
|
9
|
+
use validators::{assert_bls_12381_g2_private_jwk, assert_bls_12381_g2_public_jwk};
|
|
10
|
+
use vc::bbs_signatures::bls12381::{
|
|
11
|
+
bls_generate_g2_key, bls_sign, bls_verify, BlsBbsSignRequest, BlsBbsVerifyRequest, BlsKeyPair,
|
|
12
|
+
};
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
pub
|
|
12
|
-
pub id: Option<String>,
|
|
13
|
-
pub controller: Option<String>,
|
|
14
|
-
pub private_key_buffer: Option<Vec<u8>>,
|
|
15
|
-
pub public_key_buffer: Option<Vec<u8>>,
|
|
16
|
-
#[napi(js_name = "type")]
|
|
17
|
-
pub type_: String,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
#[napi(object)]
|
|
21
|
-
pub struct KeyPairOptions {
|
|
22
|
-
pub id: Option<String>,
|
|
23
|
-
pub controller: Option<String>,
|
|
24
|
-
pub private_key_base58: Option<String>,
|
|
25
|
-
pub public_key_base58: Option<String>,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
#[napi(object)]
|
|
29
|
-
pub struct GenerateKeyPairOptions {
|
|
30
|
-
pub id: Option<String>,
|
|
31
|
-
pub controller: Option<String>,
|
|
32
|
-
pub seed: Option<Buffer>,
|
|
33
|
-
}
|
|
14
|
+
pub mod types;
|
|
15
|
+
pub mod validators;
|
|
34
16
|
|
|
35
17
|
#[napi]
|
|
36
18
|
impl Bls12381G2KeyPair {
|
|
@@ -126,6 +108,49 @@ impl Bls12381G2KeyPair {
|
|
|
126
108
|
Bls12381G2KeyPair::new(Some(options)).await
|
|
127
109
|
}
|
|
128
110
|
|
|
111
|
+
#[napi(factory)]
|
|
112
|
+
pub async fn from_jwk(options: JwkKeyPairOptions) -> Result<Bls12381G2KeyPair> {
|
|
113
|
+
let JwkKeyPairOptions {
|
|
114
|
+
id,
|
|
115
|
+
controller,
|
|
116
|
+
private_key_jwk,
|
|
117
|
+
public_key_jwk,
|
|
118
|
+
} = options;
|
|
119
|
+
|
|
120
|
+
if let Some(jwk) = private_key_jwk {
|
|
121
|
+
assert_bls_12381_g2_private_jwk(&jwk)?;
|
|
122
|
+
let public_key_base58 = Some(convert_base64_url_to_base58(jwk.x)?);
|
|
123
|
+
let d = jwk
|
|
124
|
+
.d
|
|
125
|
+
.ok_or(napi::Error::from_reason("jwk.d value is none"))?;
|
|
126
|
+
let private_key_base58 = Some(convert_base64_url_to_base58(d)?);
|
|
127
|
+
|
|
128
|
+
let kp = Bls12381G2KeyPair::new(Some(KeyPairOptions {
|
|
129
|
+
id,
|
|
130
|
+
controller,
|
|
131
|
+
public_key_base58,
|
|
132
|
+
private_key_base58,
|
|
133
|
+
}))
|
|
134
|
+
.await;
|
|
135
|
+
|
|
136
|
+
Ok(kp)
|
|
137
|
+
} else if let Some(jwk) = public_key_jwk {
|
|
138
|
+
assert_bls_12381_g2_public_jwk(&jwk)?;
|
|
139
|
+
let public_key_base58 = Some(convert_base64_url_to_base58(jwk.x)?);
|
|
140
|
+
let kp = Bls12381G2KeyPair::new(Some(KeyPairOptions {
|
|
141
|
+
id,
|
|
142
|
+
controller,
|
|
143
|
+
public_key_base58,
|
|
144
|
+
private_key_base58: None,
|
|
145
|
+
}))
|
|
146
|
+
.await;
|
|
147
|
+
|
|
148
|
+
Ok(kp)
|
|
149
|
+
} else {
|
|
150
|
+
Err(napi::Error::from_reason("The JWK provided is not a valid"))
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
129
154
|
#[napi(getter)]
|
|
130
155
|
pub fn public_key(&self) -> Option<String> {
|
|
131
156
|
self
|
|
@@ -141,6 +166,87 @@ impl Bls12381G2KeyPair {
|
|
|
141
166
|
.clone()
|
|
142
167
|
.map(|b| bs58::encode(b).into_string())
|
|
143
168
|
}
|
|
169
|
+
|
|
170
|
+
#[napi]
|
|
171
|
+
pub fn signer(&self) -> KeyPairSigner {
|
|
172
|
+
KeyPairSigner { key: self.clone() }
|
|
173
|
+
}
|
|
174
|
+
#[napi]
|
|
175
|
+
pub fn verifier(&self) -> KeyPairVerifier {
|
|
176
|
+
KeyPairVerifier { key: self.clone() }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
pub fn convert_base64_url_to_base58(value: String) -> Result<String> {
|
|
181
|
+
let decoded = URL_SAFE.decode(value).map_err(|err| {
|
|
182
|
+
napi::Error::from_reason(format!("failed to decode base64 url_safe. error {err}"))
|
|
183
|
+
})?;
|
|
184
|
+
Ok(bs58::encode(decoded).into_string())
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
#[napi]
|
|
188
|
+
pub struct KeyPairSigner {
|
|
189
|
+
key: Bls12381G2KeyPair,
|
|
144
190
|
}
|
|
145
191
|
|
|
146
|
-
|
|
192
|
+
#[napi(object)]
|
|
193
|
+
pub struct KeyPairSignerOptions {
|
|
194
|
+
pub data: Vec<Uint8Array>,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
#[napi]
|
|
198
|
+
impl KeyPairSigner {
|
|
199
|
+
#[napi]
|
|
200
|
+
pub async fn sign(&self, options: KeyPairSignerOptions) -> Result<Uint8Array> {
|
|
201
|
+
if self.key.private_key_buffer.is_none() {
|
|
202
|
+
return Err(napi::Error::from_reason("No private key to sign with."));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let messages: Vec<Vec<u8>> = options.data.into_iter().map(|x| x.to_vec()).collect();
|
|
206
|
+
let key_pair = BlsKeyPair {
|
|
207
|
+
public_key: self.key.public_key_buffer.clone(),
|
|
208
|
+
secret_key: self.key.private_key_buffer.clone(),
|
|
209
|
+
};
|
|
210
|
+
let sig = bls_sign(BlsBbsSignRequest { messages, key_pair })
|
|
211
|
+
.await
|
|
212
|
+
.map_err(|err| napi::Error::from_reason(format!("bls_signed failed: {err}")))?;
|
|
213
|
+
|
|
214
|
+
Ok(Uint8Array::from(sig))
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
#[napi]
|
|
219
|
+
pub struct KeyPairVerifier {
|
|
220
|
+
key: Bls12381G2KeyPair,
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
#[napi(object)]
|
|
224
|
+
pub struct KeyPairVerifierOptions {
|
|
225
|
+
pub data: Vec<Uint8Array>,
|
|
226
|
+
pub signature: Uint8Array,
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#[napi]
|
|
230
|
+
impl KeyPairVerifier {
|
|
231
|
+
#[napi]
|
|
232
|
+
pub async fn verify(&self, options: KeyPairVerifierOptions) -> Result<bool> {
|
|
233
|
+
let KeyPairVerifierOptions { data, signature } = options;
|
|
234
|
+
let Some(public_key) = self.key.public_key_buffer.clone() else {
|
|
235
|
+
return Err(napi::Error::from_reason(
|
|
236
|
+
"key.public_key is required for verify",
|
|
237
|
+
));
|
|
238
|
+
};
|
|
239
|
+
let signature = signature.to_vec();
|
|
240
|
+
let messages = data.into_iter().map(|a| a.to_vec()).collect::<Vec<_>>();
|
|
241
|
+
|
|
242
|
+
let verified = bls_verify(BlsBbsVerifyRequest {
|
|
243
|
+
public_key,
|
|
244
|
+
signature,
|
|
245
|
+
messages,
|
|
246
|
+
})
|
|
247
|
+
.await
|
|
248
|
+
.map_err(|err| napi::Error::from_reason(format!("bls_verify failed: {err}")))?;
|
|
249
|
+
|
|
250
|
+
Ok(verified)
|
|
251
|
+
}
|
|
252
|
+
}
|
package/src/types.rs
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
use napi::bindgen_prelude::*;
|
|
2
|
+
|
|
3
|
+
#[derive(Clone)]
|
|
4
|
+
#[napi]
|
|
5
|
+
pub struct Bls12381G2KeyPair {
|
|
6
|
+
pub id: Option<String>,
|
|
7
|
+
pub controller: Option<String>,
|
|
8
|
+
pub private_key_buffer: Option<Vec<u8>>,
|
|
9
|
+
pub public_key_buffer: Option<Vec<u8>>,
|
|
10
|
+
#[napi(js_name = "type")]
|
|
11
|
+
pub type_: String,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[napi(object)]
|
|
15
|
+
pub struct KeyPairOptions {
|
|
16
|
+
pub id: Option<String>,
|
|
17
|
+
pub controller: Option<String>,
|
|
18
|
+
pub private_key_base58: Option<String>,
|
|
19
|
+
pub public_key_base58: Option<String>,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#[napi(object)]
|
|
23
|
+
pub struct JwkKeyPairOptions {
|
|
24
|
+
pub id: Option<String>,
|
|
25
|
+
pub controller: Option<String>,
|
|
26
|
+
pub private_key_jwk: Option<JsonWebKey>,
|
|
27
|
+
pub public_key_jwk: Option<JsonWebKey>,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[napi(object)]
|
|
31
|
+
pub struct JsonWebKey {
|
|
32
|
+
/////
|
|
33
|
+
/// Indicates the key type used
|
|
34
|
+
/// For BLS12381_G1 and BLS12381_G2 the string "EC" MUST be used
|
|
35
|
+
//
|
|
36
|
+
/// @see https://tools.ietf.org/html/rfc7517#section-4.1
|
|
37
|
+
///
|
|
38
|
+
pub kty: String,
|
|
39
|
+
|
|
40
|
+
/////
|
|
41
|
+
/// Indicates the curve this key is associated with
|
|
42
|
+
/// In the case of BLS12-381, the curve will also indicate if it's a G1 or G2 point
|
|
43
|
+
//
|
|
44
|
+
/// For a G1 point, use the string "BLS12381_G1"
|
|
45
|
+
/// For a G2 point, use the string "BLS12381_G2"
|
|
46
|
+
//
|
|
47
|
+
pub crv: String,
|
|
48
|
+
|
|
49
|
+
/////
|
|
50
|
+
/// This is a compression of the public key point
|
|
51
|
+
//
|
|
52
|
+
/// For a G1 public key, X is a 384bit base64url encoding of the octet string representation of the coordinate
|
|
53
|
+
/// For a G2 public key, X is a 768bit made up of the concatenation of two 384 bit x coordinates known as
|
|
54
|
+
/// x_a and x_b in the following form (x_a || x_b) as a base64url encoding of the octet string representation of the two coordinates
|
|
55
|
+
///
|
|
56
|
+
pub x: String,
|
|
57
|
+
|
|
58
|
+
/////
|
|
59
|
+
/// @see https://tools.ietf.org/html/rfc7517#section-4.2
|
|
60
|
+
//
|
|
61
|
+
#[napi(js_name = "use")]
|
|
62
|
+
pub use_: Option<String>,
|
|
63
|
+
|
|
64
|
+
/////
|
|
65
|
+
/// @see https://tools.ietf.org/html/rfc7517#section-4.3
|
|
66
|
+
///
|
|
67
|
+
pub key_ops: Option<Vec<String>>,
|
|
68
|
+
|
|
69
|
+
/////
|
|
70
|
+
/// @see https://tools.ietf.org/html/rfc7517#section-4.4
|
|
71
|
+
///
|
|
72
|
+
pub alg: Option<String>,
|
|
73
|
+
|
|
74
|
+
/////
|
|
75
|
+
/// @see https://tools.ietf.org/html/rfc7517#section-4.5
|
|
76
|
+
//
|
|
77
|
+
/// TODO: Add note about referencing did-jose-extensions when ready
|
|
78
|
+
///
|
|
79
|
+
pub kid: Option<String>,
|
|
80
|
+
|
|
81
|
+
/////
|
|
82
|
+
//
|
|
83
|
+
/// IMPORTANT NOTE: d represents the private key value and should not be shared
|
|
84
|
+
/// IT IS HIGHLY SENSITIVE DATA AND IF NOT SECURED PROPERLY CONSIDER THE KEY COMPROMISED
|
|
85
|
+
//
|
|
86
|
+
/// @see https://tools.ietf.org/html/rfc7517#section-9.2
|
|
87
|
+
///
|
|
88
|
+
pub d: Option<String>,
|
|
89
|
+
|
|
90
|
+
/////
|
|
91
|
+
/// This coordinate is not used for BLS Keys, but is kept here to make the interface more standard
|
|
92
|
+
///
|
|
93
|
+
pub y: Option<String>,
|
|
94
|
+
|
|
95
|
+
/////
|
|
96
|
+
/// @see https://www.w3.org/TR/WebCryptoAPI/#cryptokey-interface-members
|
|
97
|
+
///
|
|
98
|
+
pub ext: Option<bool>,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
#[napi(object)]
|
|
102
|
+
pub struct GenerateKeyPairOptions {
|
|
103
|
+
pub id: Option<String>,
|
|
104
|
+
pub controller: Option<String>,
|
|
105
|
+
pub seed: Option<Buffer>,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#[derive(PartialEq)]
|
|
109
|
+
pub enum BlsCurveName {
|
|
110
|
+
DeprecatedG1,
|
|
111
|
+
DeprecatedG2,
|
|
112
|
+
G1,
|
|
113
|
+
G2,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
impl TryFrom<&str> for BlsCurveName {
|
|
117
|
+
type Error = napi::Error;
|
|
118
|
+
|
|
119
|
+
fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
|
120
|
+
match value {
|
|
121
|
+
"BLS12381_G1" => Ok(BlsCurveName::DeprecatedG1),
|
|
122
|
+
"BLS12381_G2" => Ok(BlsCurveName::DeprecatedG2),
|
|
123
|
+
"Bls12381G1" => Ok(BlsCurveName::G1),
|
|
124
|
+
"Bls12381G2" => Ok(BlsCurveName::G2),
|
|
125
|
+
_ => Err(napi::Error::from_reason(format!(
|
|
126
|
+
"no matching BlsNamedCurve for value: {}",
|
|
127
|
+
value
|
|
128
|
+
))),
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#[derive(PartialEq)]
|
|
134
|
+
pub enum JwkKty {
|
|
135
|
+
OctetKeyPair,
|
|
136
|
+
EC,
|
|
137
|
+
RSA,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
impl TryFrom<&str> for JwkKty {
|
|
141
|
+
type Error = napi::Error;
|
|
142
|
+
|
|
143
|
+
fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
|
144
|
+
match value {
|
|
145
|
+
"OKP" => Ok(JwkKty::OctetKeyPair),
|
|
146
|
+
"EC" => Ok(JwkKty::EC),
|
|
147
|
+
"RSA" => Ok(JwkKty::RSA),
|
|
148
|
+
_ => Err(napi::Error::from_reason(format!(
|
|
149
|
+
"no matching JwkKty for value: {}",
|
|
150
|
+
value
|
|
151
|
+
))),
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
use crate::types::{BlsCurveName, JsonWebKey, JwkKty};
|
|
2
|
+
|
|
3
|
+
pub fn check_common_bls_jwk_values(jwk: &JsonWebKey) -> napi::Result<()> {
|
|
4
|
+
BlsCurveName::try_from(jwk.crv.as_str())?;
|
|
5
|
+
let kty = JwkKty::try_from(jwk.kty.as_str())?;
|
|
6
|
+
if kty == JwkKty::EC || kty == JwkKty::OctetKeyPair {
|
|
7
|
+
Ok(())
|
|
8
|
+
} else {
|
|
9
|
+
Err(napi::Error::from_reason(format!(
|
|
10
|
+
"kty value: {} not allowed",
|
|
11
|
+
jwk.kty
|
|
12
|
+
)))
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
pub fn assert_public_bls_jwk(jwk: &JsonWebKey) -> napi::Result<()> {
|
|
17
|
+
check_common_bls_jwk_values(jwk)?;
|
|
18
|
+
if jwk.d.is_none() {
|
|
19
|
+
Ok(())
|
|
20
|
+
} else {
|
|
21
|
+
Err(napi::Error::from_reason(
|
|
22
|
+
"expected jwk.d to be none, found some value",
|
|
23
|
+
))
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn assert_private_bls_jwk(jwk: &JsonWebKey) -> napi::Result<()> {
|
|
28
|
+
check_common_bls_jwk_values(jwk)?;
|
|
29
|
+
Ok(())
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pub fn assert_bls_12381_g2_public_jwk(jwk: &JsonWebKey) -> napi::Result<()> {
|
|
33
|
+
let curve = BlsCurveName::try_from(jwk.crv.as_str())?;
|
|
34
|
+
if curve != BlsCurveName::DeprecatedG2 || curve != BlsCurveName::G2 {
|
|
35
|
+
return Err(napi::Error::from_reason(format!(
|
|
36
|
+
"curve value: {} not allowed",
|
|
37
|
+
jwk.crv
|
|
38
|
+
)));
|
|
39
|
+
}
|
|
40
|
+
assert_public_bls_jwk(jwk)?;
|
|
41
|
+
if jwk.x.len() != 128 {
|
|
42
|
+
Err(napi::Error::from_reason(format!(
|
|
43
|
+
"jwk.x expected length 128, got {}",
|
|
44
|
+
jwk.x.len()
|
|
45
|
+
)))
|
|
46
|
+
} else {
|
|
47
|
+
Ok(())
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub fn assert_bls_12381_g2_private_jwk(jwk: &JsonWebKey) -> napi::Result<()> {
|
|
52
|
+
let curve = BlsCurveName::try_from(jwk.crv.as_str())?;
|
|
53
|
+
if curve != BlsCurveName::DeprecatedG2 || curve != BlsCurveName::G2 {
|
|
54
|
+
return Err(napi::Error::from_reason(format!(
|
|
55
|
+
"curve value: {} not allowed",
|
|
56
|
+
jwk.crv
|
|
57
|
+
)));
|
|
58
|
+
}
|
|
59
|
+
assert_private_bls_jwk(jwk)?;
|
|
60
|
+
if jwk.x.len() != 128 {
|
|
61
|
+
Err(napi::Error::from_reason(format!(
|
|
62
|
+
"jwk.x expected length 128, got {}",
|
|
63
|
+
jwk.x.len()
|
|
64
|
+
)))
|
|
65
|
+
} else {
|
|
66
|
+
Ok(())
|
|
67
|
+
}
|
|
68
|
+
}
|
package/test.mjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { Bls12381G2KeyPair } from '@mattrglobal/bls12381-key-pair';
|
|
4
|
+
import { Bls12381G2KeyPair as NewKeyPairClass } from './index.js'
|
|
5
|
+
import bs58 from 'bs58'
|
|
6
|
+
import bbs from '@nuggetslife/ffi-bbs-signatures'
|
|
7
|
+
|
|
8
|
+
const seed = Buffer.alloc(32, 0)
|
|
9
|
+
const address = '0x581510277Bc56802dE75BA021b66873437e0169f'
|
|
10
|
+
const addressBase58 = bs58.encode(Buffer.from(address.slice(2), 'hex'))
|
|
11
|
+
|
|
12
|
+
//Set of messages we wish to sign
|
|
13
|
+
const messages = [
|
|
14
|
+
Uint8Array.from(Buffer.from("message1", "utf8")),
|
|
15
|
+
Uint8Array.from(Buffer.from("message2", "utf8")),
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
test('gen keypair for same seed', async () => {
|
|
19
|
+
const mattr = await Bls12381G2KeyPair.generate({ seed, });
|
|
20
|
+
const harry = await NewKeyPairClass.generate({ seed })
|
|
21
|
+
const ffi = await bbs.generateBls12381G2KeyPair(seed)
|
|
22
|
+
const ffi_sec_key = bs58.encode(Buffer.from(ffi.secretKey))
|
|
23
|
+
const ffi_pub_key = bs58.encode(Buffer.from(ffi.publicKey))
|
|
24
|
+
|
|
25
|
+
// private keys match
|
|
26
|
+
assert.equal(mattr.privateKey, harry.privateKey)
|
|
27
|
+
assert.equal(ffi_sec_key, harry.privateKey)
|
|
28
|
+
|
|
29
|
+
// public keys match
|
|
30
|
+
assert.equal(mattr.publicKey, harry.publicKey)
|
|
31
|
+
assert.equal(ffi_pub_key, harry.publicKey)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
test('keypair from keypair', async () => {
|
|
36
|
+
const mattr = await Bls12381G2KeyPair.generate({ seed, });
|
|
37
|
+
const harry = await NewKeyPairClass.from({
|
|
38
|
+
id: mattr.id,
|
|
39
|
+
controller: mattr.controller,
|
|
40
|
+
publicKeyBase58: mattr.publicKey,
|
|
41
|
+
privateKeyBase58: mattr.privateKey
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// private keys match
|
|
45
|
+
assert.equal(mattr.id, harry.id)
|
|
46
|
+
assert.equal(mattr.controller, harry.controller)
|
|
47
|
+
assert.equal(mattr.publicKey, harry.publicKey)
|
|
48
|
+
assert.equal(mattr.privateKey, harry.privateKey)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
test('sign and verify', async () => {
|
|
53
|
+
const mattr = await Bls12381G2KeyPair.generate({ seed, });
|
|
54
|
+
const harry = await NewKeyPairClass.generate({ seed })
|
|
55
|
+
|
|
56
|
+
const ms = mattr.signer();
|
|
57
|
+
const hs = harry.signer();
|
|
58
|
+
|
|
59
|
+
const sign_opts = { data: messages }
|
|
60
|
+
|
|
61
|
+
let ms_sig = await ms.sign(sign_opts);
|
|
62
|
+
let hs_sig = await hs.sign(sign_opts);
|
|
63
|
+
|
|
64
|
+
assert.equal(ms_sig.length, hs_sig.length)
|
|
65
|
+
|
|
66
|
+
const hsv = harry.verifier();
|
|
67
|
+
const msv = mattr.verifier();
|
|
68
|
+
|
|
69
|
+
let hs_verify_hs_sig = await hsv.verify({ data: messages, signature: hs_sig })
|
|
70
|
+
let hs_verify_ms_sig = await hsv.verify({ data: messages, signature: ms_sig })
|
|
71
|
+
let ms_verify_ms_sig = await msv.verify({ data: messages, signature: ms_sig })
|
|
72
|
+
let ms_verify_hs_sig = await msv.verify({ data: messages, signature: hs_sig })
|
|
73
|
+
|
|
74
|
+
assert.equal(hs_verify_hs_sig, true)
|
|
75
|
+
assert.equal(hs_verify_ms_sig, true)
|
|
76
|
+
assert.equal(ms_verify_ms_sig, true)
|
|
77
|
+
assert.equal(ms_verify_hs_sig, true)
|
|
78
|
+
})
|