@bsv/sdk 1.9.20 → 1.9.23
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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/primitives/DRBG.js +12 -1
- package/dist/cjs/src/primitives/DRBG.js.map +1 -1
- package/dist/cjs/src/primitives/JacobianPoint.js +15 -1
- package/dist/cjs/src/primitives/JacobianPoint.js.map +1 -1
- package/dist/cjs/src/primitives/Point.js +5 -0
- package/dist/cjs/src/primitives/Point.js.map +1 -1
- package/dist/cjs/src/primitives/index.js +1 -3
- package/dist/cjs/src/primitives/index.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/primitives/DRBG.js +12 -1
- package/dist/esm/src/primitives/DRBG.js.map +1 -1
- package/dist/esm/src/primitives/JacobianPoint.js +15 -1
- package/dist/esm/src/primitives/JacobianPoint.js.map +1 -1
- package/dist/esm/src/primitives/Point.js +5 -0
- package/dist/esm/src/primitives/Point.js.map +1 -1
- package/dist/esm/src/primitives/index.js +0 -1
- package/dist/esm/src/primitives/index.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/primitives/DRBG.d.ts +12 -1
- package/dist/types/src/primitives/DRBG.d.ts.map +1 -1
- package/dist/types/src/primitives/JacobianPoint.d.ts.map +1 -1
- package/dist/types/src/primitives/Point.d.ts.map +1 -1
- package/dist/types/src/primitives/index.d.ts +0 -1
- package/dist/types/src/primitives/index.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/dist/umd/bundle.js.map +1 -1
- package/docs/reference/auth.md +2 -2
- package/docs/reference/primitives.md +90 -31
- package/package.json +1 -1
- package/src/primitives/DRBG.ts +12 -1
- package/src/primitives/JacobianPoint.ts +18 -1
- package/src/primitives/Point.ts +4 -0
- package/src/primitives/__tests/Curve.unit.test.ts +63 -0
- package/src/primitives/__tests/utils.test.ts +17 -0
- package/src/primitives/index.ts +0 -1
package/docs/reference/auth.md
CHANGED
|
@@ -502,7 +502,7 @@ export class MasterCertificate extends Certificate {
|
|
|
502
502
|
static async createKeyringForVerifier(subjectWallet: ProtoWallet, certifier: WalletCounterparty, verifier: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, fieldsToReveal: string[], masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, serialNumber: Base64String, privileged?: boolean, privilegedReason?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
503
503
|
static async issueCertificateForSubject(certifierWallet: ProtoWallet, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (_serial: string): Promise<string> => {
|
|
504
504
|
void _serial;
|
|
505
|
-
return "
|
|
505
|
+
return "00".repeat(32);
|
|
506
506
|
}, serialNumber?: string): Promise<MasterCertificate>
|
|
507
507
|
static async decryptFields(subjectOrCertifierWallet: ProtoWallet, masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, counterparty: WalletCounterparty, privileged?: boolean, privilegedReason?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
508
508
|
static async decryptField(subjectOrCertifierWallet: ProtoWallet, masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, fieldName: Base64String, fieldValue: Base64String, counterparty: WalletCounterparty, privileged?: boolean, privilegedReason?: string): Promise<{
|
|
@@ -634,7 +634,7 @@ can also includes a revocation outpoint to manage potential revocation.
|
|
|
634
634
|
```ts
|
|
635
635
|
static async issueCertificateForSubject(certifierWallet: ProtoWallet, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (_serial: string): Promise<string> => {
|
|
636
636
|
void _serial;
|
|
637
|
-
return "
|
|
637
|
+
return "00".repeat(32);
|
|
638
638
|
}, serialNumber?: string): Promise<MasterCertificate>
|
|
639
639
|
```
|
|
640
640
|
See also: [CertificateFieldNameUnder50Bytes](./wallet.md#type-certificatefieldnameunder50bytes), [MasterCertificate](./auth.md#class-mastercertificate), [ProtoWallet](./wallet.md#class-protowallet), [WalletCounterparty](./wallet.md#type-walletcounterparty)
|
|
@@ -829,7 +829,17 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
|
|
|
829
829
|
---
|
|
830
830
|
### Class: DRBG
|
|
831
831
|
|
|
832
|
-
|
|
832
|
+
HMAC-DRBG used **only** for deterministic ECDSA nonce generation.
|
|
833
|
+
|
|
834
|
+
This implementation follows the RFC 6979-style HMAC-DRBG construction for secp256k1
|
|
835
|
+
and is wired internally into the ECDSA signing code. It is **not forward-secure**
|
|
836
|
+
and MUST NOT be used as a general-purpose DRBG, key generator, or randomness source.
|
|
837
|
+
|
|
838
|
+
Security note:
|
|
839
|
+
- Intended scope: internal ECDSA nonce generation with fixed-size inputs.
|
|
840
|
+
- Out-of-scope: generic randomness, long-lived session keys, or any context
|
|
841
|
+
where forward secrecy is required.
|
|
842
|
+
- API stability: this class is internal.
|
|
833
843
|
|
|
834
844
|
Example
|
|
835
845
|
|
|
@@ -4953,8 +4963,10 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
|
|
|
4953
4963
|
| [AES](#function-aes) |
|
|
4954
4964
|
| [AESGCM](#function-aesgcm) |
|
|
4955
4965
|
| [AESGCMDecrypt](#function-aesgcmdecrypt) |
|
|
4966
|
+
| [assertValidHex](#function-assertvalidhex) |
|
|
4956
4967
|
| [base64ToArray](#function-base64toarray) |
|
|
4957
4968
|
| [ghash](#function-ghash) |
|
|
4969
|
+
| [normalizeHex](#function-normalizehex) |
|
|
4958
4970
|
| [pbkdf2](#function-pbkdf2) |
|
|
4959
4971
|
| [red](#function-red) |
|
|
4960
4972
|
| [toArray](#function-toarray) |
|
|
@@ -4994,6 +5006,15 @@ export function AESGCMDecrypt(cipherText: number[], additionalAuthenticatedData:
|
|
|
4994
5006
|
|
|
4995
5007
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
|
|
4996
5008
|
|
|
5009
|
+
---
|
|
5010
|
+
### Function: assertValidHex
|
|
5011
|
+
|
|
5012
|
+
```ts
|
|
5013
|
+
export function assertValidHex(msg: string): void
|
|
5014
|
+
```
|
|
5015
|
+
|
|
5016
|
+
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
|
|
5017
|
+
|
|
4997
5018
|
---
|
|
4998
5019
|
### Function: base64ToArray
|
|
4999
5020
|
|
|
@@ -5012,6 +5033,15 @@ export function ghash(input: number[], hashSubKey: number[]): number[]
|
|
|
5012
5033
|
|
|
5013
5034
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
|
|
5014
5035
|
|
|
5036
|
+
---
|
|
5037
|
+
### Function: normalizeHex
|
|
5038
|
+
|
|
5039
|
+
```ts
|
|
5040
|
+
export function normalizeHex(msg: string): string
|
|
5041
|
+
```
|
|
5042
|
+
|
|
5043
|
+
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
|
|
5044
|
+
|
|
5015
5045
|
---
|
|
5016
5046
|
### Function: pbkdf2
|
|
5017
5047
|
|
|
@@ -5939,7 +5969,7 @@ sign = (msg: BigNumber, key: BigNumber, forceLowS: boolean = false, customK?: Bi
|
|
|
5939
5969
|
if (kBN == null)
|
|
5940
5970
|
throw new Error("k is undefined");
|
|
5941
5971
|
kBN = truncateToN(kBN, true);
|
|
5942
|
-
if (kBN.cmpn(1)
|
|
5972
|
+
if (kBN.cmpn(1) < 0 || kBN.cmp(ns1) > 0) {
|
|
5943
5973
|
if (BigNumber.isBN(customK)) {
|
|
5944
5974
|
throw new Error("Invalid fixed custom K value (must be >1 and <N\u20111)");
|
|
5945
5975
|
}
|
|
@@ -6090,49 +6120,78 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
|
|
|
6090
6120
|
```ts
|
|
6091
6121
|
toUTF8 = (arr: number[]): string => {
|
|
6092
6122
|
let result = "";
|
|
6093
|
-
|
|
6123
|
+
const replacementChar = "\uFFFD";
|
|
6094
6124
|
for (let i = 0; i < arr.length; i++) {
|
|
6095
|
-
const
|
|
6096
|
-
if (
|
|
6097
|
-
|
|
6125
|
+
const byte1 = arr[i];
|
|
6126
|
+
if (byte1 <= 127) {
|
|
6127
|
+
result += String.fromCharCode(byte1);
|
|
6098
6128
|
continue;
|
|
6099
6129
|
}
|
|
6100
|
-
|
|
6101
|
-
result +=
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
const
|
|
6130
|
+
const emitReplacement = (): void => {
|
|
6131
|
+
result += replacementChar;
|
|
6132
|
+
};
|
|
6133
|
+
if (byte1 >= 192 && byte1 <= 223) {
|
|
6134
|
+
if (i + 1 >= arr.length) {
|
|
6135
|
+
emitReplacement();
|
|
6136
|
+
continue;
|
|
6137
|
+
}
|
|
6138
|
+
const byte2 = arr[i + 1];
|
|
6139
|
+
if ((byte2 & 192) !== 128) {
|
|
6140
|
+
emitReplacement();
|
|
6141
|
+
i += 1;
|
|
6142
|
+
continue;
|
|
6143
|
+
}
|
|
6144
|
+
const codePoint = ((byte1 & 31) << 6) | (byte2 & 63);
|
|
6109
6145
|
result += String.fromCharCode(codePoint);
|
|
6146
|
+
i += 1;
|
|
6110
6147
|
continue;
|
|
6111
6148
|
}
|
|
6112
|
-
if (
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
const
|
|
6149
|
+
if (byte1 >= 224 && byte1 <= 239) {
|
|
6150
|
+
if (i + 2 >= arr.length) {
|
|
6151
|
+
emitReplacement();
|
|
6152
|
+
continue;
|
|
6153
|
+
}
|
|
6154
|
+
const byte2 = arr[i + 1];
|
|
6155
|
+
const byte3 = arr[i + 2];
|
|
6156
|
+
if ((byte2 & 192) !== 128 || (byte3 & 192) !== 128) {
|
|
6157
|
+
emitReplacement();
|
|
6158
|
+
i += 2;
|
|
6159
|
+
continue;
|
|
6160
|
+
}
|
|
6161
|
+
const codePoint = ((byte1 & 15) << 12) |
|
|
6162
|
+
((byte2 & 63) << 6) |
|
|
6163
|
+
(byte3 & 63);
|
|
6118
6164
|
result += String.fromCharCode(codePoint);
|
|
6165
|
+
i += 2;
|
|
6119
6166
|
continue;
|
|
6120
6167
|
}
|
|
6121
|
-
if (
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
const
|
|
6168
|
+
if (byte1 >= 240 && byte1 <= 247) {
|
|
6169
|
+
if (i + 3 >= arr.length) {
|
|
6170
|
+
emitReplacement();
|
|
6171
|
+
continue;
|
|
6172
|
+
}
|
|
6173
|
+
const byte2 = arr[i + 1];
|
|
6174
|
+
const byte3 = arr[i + 2];
|
|
6175
|
+
const byte4 = arr[i + 3];
|
|
6176
|
+
if ((byte2 & 192) !== 128 ||
|
|
6177
|
+
(byte3 & 192) !== 128 ||
|
|
6178
|
+
(byte4 & 192) !== 128) {
|
|
6179
|
+
emitReplacement();
|
|
6180
|
+
i += 3;
|
|
6181
|
+
continue;
|
|
6182
|
+
}
|
|
6183
|
+
const codePoint = ((byte1 & 7) << 18) |
|
|
6128
6184
|
((byte2 & 63) << 12) |
|
|
6129
6185
|
((byte3 & 63) << 6) |
|
|
6130
6186
|
(byte4 & 63);
|
|
6131
|
-
const
|
|
6132
|
-
const
|
|
6133
|
-
|
|
6187
|
+
const offset = codePoint - 65536;
|
|
6188
|
+
const highSurrogate = 55296 + (offset >> 10);
|
|
6189
|
+
const lowSurrogate = 56320 + (offset & 1023);
|
|
6190
|
+
result += String.fromCharCode(highSurrogate, lowSurrogate);
|
|
6191
|
+
i += 3;
|
|
6134
6192
|
continue;
|
|
6135
6193
|
}
|
|
6194
|
+
emitReplacement();
|
|
6136
6195
|
}
|
|
6137
6196
|
return result;
|
|
6138
6197
|
}
|
package/package.json
CHANGED
package/src/primitives/DRBG.ts
CHANGED
|
@@ -2,7 +2,18 @@ import { SHA256HMAC } from './Hash.js'
|
|
|
2
2
|
import { toHex, toArray } from './utils.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* HMAC-DRBG used **only** for deterministic ECDSA nonce generation.
|
|
6
|
+
*
|
|
7
|
+
* This implementation follows the RFC 6979-style HMAC-DRBG construction for secp256k1
|
|
8
|
+
* and is wired internally into the ECDSA signing code. It is **not forward-secure**
|
|
9
|
+
* and MUST NOT be used as a general-purpose DRBG, key generator, or randomness source.
|
|
10
|
+
*
|
|
11
|
+
* Security note:
|
|
12
|
+
* - Intended scope: internal ECDSA nonce generation with fixed-size inputs.
|
|
13
|
+
* - Out-of-scope: generic randomness, long-lived session keys, or any context
|
|
14
|
+
* where forward secrecy is required.
|
|
15
|
+
* - API stability: this class is internal.
|
|
16
|
+
*
|
|
6
17
|
* @class DRBG
|
|
7
18
|
*
|
|
8
19
|
* @constructor
|
|
@@ -73,6 +73,14 @@ export default class JacobianPoint extends BasePoint {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
this.zOne = this.z === this.curve.one
|
|
76
|
+
|
|
77
|
+
// --- Canonicalize point at infinity ---
|
|
78
|
+
if (this.isInfinity()) {
|
|
79
|
+
this.x = this.curve.one
|
|
80
|
+
this.y = this.curve.one
|
|
81
|
+
this.z = new BigNumber(0).toRed(this.curve.red)
|
|
82
|
+
this.zOne = false
|
|
83
|
+
}
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
/**
|
|
@@ -361,9 +369,18 @@ export default class JacobianPoint extends BasePoint {
|
|
|
361
369
|
return true
|
|
362
370
|
}
|
|
363
371
|
|
|
372
|
+
p = p as JacobianPoint
|
|
373
|
+
|
|
374
|
+
// --- Infinity handling ---
|
|
375
|
+
if (this.isInfinity() && p.isInfinity()) {
|
|
376
|
+
return true
|
|
377
|
+
}
|
|
378
|
+
if (this.isInfinity() !== p.isInfinity()) {
|
|
379
|
+
return false
|
|
380
|
+
}
|
|
381
|
+
|
|
364
382
|
// x1 * z2^2 == x2 * z1^2
|
|
365
383
|
const z2 = this.z.redSqr()
|
|
366
|
-
p = p as JacobianPoint
|
|
367
384
|
const pz2 = p.z.redSqr()
|
|
368
385
|
if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) {
|
|
369
386
|
return false
|
package/src/primitives/Point.ts
CHANGED
|
@@ -445,6 +445,10 @@ export default class Point extends BasePoint {
|
|
|
445
445
|
* const encodedPointHex = aPoint.encode(true, 'hex');
|
|
446
446
|
*/
|
|
447
447
|
encode (compact: boolean = true, enc?: 'hex'): number[] | string {
|
|
448
|
+
if (this.inf) {
|
|
449
|
+
if (enc === 'hex') return '00'
|
|
450
|
+
return [0x00]
|
|
451
|
+
}
|
|
448
452
|
const len = this.curve.p.byteLength()
|
|
449
453
|
const x = this.getX().toArray('be', len)
|
|
450
454
|
let res: number[]
|
|
@@ -212,3 +212,66 @@ describe('Point codec', () => {
|
|
|
212
212
|
makeShortTest(shortPointOddY)
|
|
213
213
|
)
|
|
214
214
|
})
|
|
215
|
+
|
|
216
|
+
describe('JacobianPoint – Infinity handling and equality (TOB-18)', () => {
|
|
217
|
+
function J(x: any, y: any, z: any) {
|
|
218
|
+
return new JPoint(x, y, z)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
it('Multiple infinity representations are canonicalized and equal', () => {
|
|
222
|
+
const inf1 = J(null, null, null)
|
|
223
|
+
const inf2 = J('0', '0', '0')
|
|
224
|
+
const inf3 = J(new BigNumber(0), new BigNumber(0), new BigNumber(0))
|
|
225
|
+
|
|
226
|
+
expect(inf1.isInfinity()).toBe(true)
|
|
227
|
+
expect(inf2.isInfinity()).toBe(true)
|
|
228
|
+
expect(inf3.isInfinity()).toBe(true)
|
|
229
|
+
|
|
230
|
+
expect(inf1.eq(inf2)).toBe(true)
|
|
231
|
+
expect(inf2.eq(inf3)).toBe(true)
|
|
232
|
+
expect(inf1.eq(inf3)).toBe(true)
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
it('Infinity must not equal a finite point', () => {
|
|
236
|
+
const inf = J(null, null, null)
|
|
237
|
+
|
|
238
|
+
const good = J(
|
|
239
|
+
new BigNumber('e7789226', 16),
|
|
240
|
+
new BigNumber('4b76b191', 16),
|
|
241
|
+
new BigNumber('cbf8d990', 16)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
expect(inf.eq(good)).toBe(false)
|
|
245
|
+
expect(good.eq(inf)).toBe(false)
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it('Infinity equals infinity (canonicalized)', () => {
|
|
249
|
+
const inf1 = J(null, null, null)
|
|
250
|
+
const inf2 = J('0', '0', '0')
|
|
251
|
+
|
|
252
|
+
expect(inf1.eq(inf2)).toBe(true)
|
|
253
|
+
expect(inf2.eq(inf1)).toBe(true)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('Infinity is detected when z is zero in RED form', () => {
|
|
257
|
+
const redZero = new BigNumber(0).toRed(new Curve().red)
|
|
258
|
+
const p = J('1', '2', redZero)
|
|
259
|
+
|
|
260
|
+
expect(p.isInfinity()).toBe(true)
|
|
261
|
+
|
|
262
|
+
const clean = J(null, null, null)
|
|
263
|
+
expect(p.eq(clean)).toBe(true)
|
|
264
|
+
expect(clean.eq(p)).toBe(true)
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('eq() must handle mixed canonical and non-canonical infinity cases', () => {
|
|
268
|
+
const canonical = J(null, null, null)
|
|
269
|
+
const messy = J('1', '1', new BigNumber(0))
|
|
270
|
+
|
|
271
|
+
expect(messy.isInfinity()).toBe(true)
|
|
272
|
+
expect(canonical.eq(messy)).toBe(true)
|
|
273
|
+
expect(messy.eq(canonical)).toBe(true)
|
|
274
|
+
})
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
toBase58Check,
|
|
12
12
|
verifyNotNull
|
|
13
13
|
} from '../../primitives/utils'
|
|
14
|
+
import Point from '../../primitives/Point'
|
|
14
15
|
|
|
15
16
|
describe('utils', () => {
|
|
16
17
|
it('should convert to array', () => {
|
|
@@ -359,3 +360,19 @@ describe('toUTF8 strict UTF-8 decoding (TOB-21)', () => {
|
|
|
359
360
|
|
|
360
361
|
})
|
|
361
362
|
|
|
363
|
+
describe('Point.encode infinity handling', () => {
|
|
364
|
+
it('encodes infinity as 00 (array)', () => {
|
|
365
|
+
const p = new Point(null, null)
|
|
366
|
+
expect(p.encode()).toEqual([0x00])
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
it('encodes infinity as 00 (hex)', () => {
|
|
370
|
+
const p = new Point(null, null)
|
|
371
|
+
expect(p.encode(true, 'hex')).toBe('00')
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
it('does not throw for infinity', () => {
|
|
375
|
+
const p = new Point(null, null)
|
|
376
|
+
expect(() => p.encode()).not.toThrow()
|
|
377
|
+
})
|
|
378
|
+
})
|
package/src/primitives/index.ts
CHANGED
|
@@ -5,7 +5,6 @@ export { default as PublicKey } from './PublicKey.js'
|
|
|
5
5
|
export { default as Signature } from './Signature.js'
|
|
6
6
|
export { default as PrivateKey, KeyShares } from './PrivateKey.js'
|
|
7
7
|
export { default as SymmetricKey } from './SymmetricKey.js'
|
|
8
|
-
export { default as DRBG } from './DRBG.js'
|
|
9
8
|
export * as ECDSA from './ECDSA.js'
|
|
10
9
|
export * as Utils from './utils.js'
|
|
11
10
|
export * as Hash from './Hash.js'
|