Skip to content

Commit 6649cfc

Browse files
authored
Merge pull request #408 from bsv-blockchain/fix/tob-7
Fix/tob 7
2 parents 2285482 + efa0789 commit 6649cfc

File tree

7 files changed

+118
-38
lines changed

7 files changed

+118
-38
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. The format
55
## Table of Contents
66

77
- [Unreleased](#unreleased)
8+
- [1.9.22 - 2025-12-04](#1922---2025-12-04)
89
- [1.9.21 - 2025-12-04](#1921---2025-12-04)
910
- [1.9.20 - 2025-12-02](#1920---2025-12-02)
1011
- [1.9.19 - 2025-12-02](#1919---2025-12-02)
@@ -191,6 +192,16 @@ All notable changes to this project will be documented in this file. The format
191192
### Fixed
192193

193194
### Security
195+
196+
---
197+
198+
### [1.9.22] - 2025-12-04
199+
200+
### Changed
201+
202+
- Removed the export of DRBG from the package.
203+
- Added disclaimer to DRBG documentation.
204+
194205
---
195206

196207
### [1.9.21] - 2025-12-04

docs/reference/auth.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ export class MasterCertificate extends Certificate {
502502
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>>
503503
static async issueCertificateForSubject(certifierWallet: ProtoWallet, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (_serial: string): Promise<string> => {
504504
void _serial;
505-
return "Certificate revocation not tracked.";
505+
return "00".repeat(32);
506506
}, serialNumber?: string): Promise<MasterCertificate>
507507
static async decryptFields(subjectOrCertifierWallet: ProtoWallet, masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, counterparty: WalletCounterparty, privileged?: boolean, privilegedReason?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
508508
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.
634634
```ts
635635
static async issueCertificateForSubject(certifierWallet: ProtoWallet, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (_serial: string): Promise<string> => {
636636
void _serial;
637-
return "Certificate revocation not tracked.";
637+
return "00".repeat(32);
638638
}, serialNumber?: string): Promise<MasterCertificate>
639639
```
640640
See also: [CertificateFieldNameUnder50Bytes](./wallet.md#type-certificatefieldnameunder50bytes), [MasterCertificate](./auth.md#class-mastercertificate), [ProtoWallet](./wallet.md#class-protowallet), [WalletCounterparty](./wallet.md#type-walletcounterparty)

docs/reference/primitives.md

Lines changed: 90 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,17 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
829829
---
830830
### Class: DRBG
831831

832-
This class behaves as a HMAC-based deterministic random bit generator (DRBG). It implements a deterministic random number generator using SHA256HMAC HASH function. It takes an initial entropy and nonce when instantiated for seeding purpose.
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.
833843

834844
Example
835845

@@ -4953,8 +4963,10 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
49534963
| [AES](#function-aes) |
49544964
| [AESGCM](#function-aesgcm) |
49554965
| [AESGCMDecrypt](#function-aesgcmdecrypt) |
4966+
| [assertValidHex](#function-assertvalidhex) |
49564967
| [base64ToArray](#function-base64toarray) |
49574968
| [ghash](#function-ghash) |
4969+
| [normalizeHex](#function-normalizehex) |
49584970
| [pbkdf2](#function-pbkdf2) |
49594971
| [red](#function-red) |
49604972
| [toArray](#function-toarray) |
@@ -4994,6 +5006,15 @@ export function AESGCMDecrypt(cipherText: number[], additionalAuthenticatedData:
49945006

49955007
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
49965008

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+
49975018
---
49985019
### Function: base64ToArray
49995020

@@ -5012,6 +5033,15 @@ export function ghash(input: number[], hashSubKey: number[]): number[]
50125033

50135034
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
50145035

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+
50155045
---
50165046
### Function: pbkdf2
50175047

@@ -5939,7 +5969,7 @@ sign = (msg: BigNumber, key: BigNumber, forceLowS: boolean = false, customK?: Bi
59395969
if (kBN == null)
59405970
throw new Error("k is undefined");
59415971
kBN = truncateToN(kBN, true);
5942-
if (kBN.cmpn(1) <= 0 || kBN.cmp(ns1) >= 0) {
5972+
if (kBN.cmpn(1) < 0 || kBN.cmp(ns1) > 0) {
59435973
if (BigNumber.isBN(customK)) {
59445974
throw new Error("Invalid fixed custom K value (must be >1 and <N\u20111)");
59455975
}
@@ -6090,49 +6120,78 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
60906120
```ts
60916121
toUTF8 = (arr: number[]): string => {
60926122
let result = "";
6093-
let skip = 0;
6123+
const replacementChar = "\uFFFD";
60946124
for (let i = 0; i < arr.length; i++) {
6095-
const byte = arr[i];
6096-
if (skip > 0) {
6097-
skip--;
6125+
const byte1 = arr[i];
6126+
if (byte1 <= 127) {
6127+
result += String.fromCharCode(byte1);
60986128
continue;
60996129
}
6100-
if (byte <= 127) {
6101-
result += String.fromCharCode(byte);
6102-
continue;
6103-
}
6104-
if (byte >= 192 && byte <= 223) {
6105-
const avail = arr.length - (i + 1);
6106-
const byte2 = avail >= 1 ? arr[i + 1] : 0;
6107-
skip = Math.min(1, avail);
6108-
const codePoint = ((byte & 31) << 6) | (byte2 & 63);
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);
61096145
result += String.fromCharCode(codePoint);
6146+
i += 1;
61106147
continue;
61116148
}
6112-
if (byte >= 224 && byte <= 239) {
6113-
const avail = arr.length - (i + 1);
6114-
const byte2 = avail >= 1 ? arr[i + 1] : 0;
6115-
const byte3 = avail >= 2 ? arr[i + 2] : 0;
6116-
skip = Math.min(2, avail);
6117-
const codePoint = ((byte & 15) << 12) | ((byte2 & 63) << 6) | (byte3 & 63);
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);
61186164
result += String.fromCharCode(codePoint);
6165+
i += 2;
61196166
continue;
61206167
}
6121-
if (byte >= 240 && byte <= 247) {
6122-
const avail = arr.length - (i + 1);
6123-
const byte2 = avail >= 1 ? arr[i + 1] : 0;
6124-
const byte3 = avail >= 2 ? arr[i + 2] : 0;
6125-
const byte4 = avail >= 3 ? arr[i + 3] : 0;
6126-
skip = Math.min(3, avail);
6127-
const codePoint = ((byte & 7) << 18) |
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) |
61286184
((byte2 & 63) << 12) |
61296185
((byte3 & 63) << 6) |
61306186
(byte4 & 63);
6131-
const surrogate1 = 55296 + ((codePoint - 65536) >> 10);
6132-
const surrogate2 = 56320 + ((codePoint - 65536) & 1023);
6133-
result += String.fromCharCode(surrogate1, surrogate2);
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;
61346192
continue;
61356193
}
6194+
emitReplacement();
61366195
}
61376196
return result;
61386197
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bsv/sdk",
3-
"version": "1.9.20",
3+
"version": "1.9.22",
44
"type": "module",
55
"description": "BSV Blockchain Software Development Kit",
66
"main": "dist/cjs/mod.js",

src/primitives/DRBG.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@ import { SHA256HMAC } from './Hash.js'
22
import { toHex, toArray } from './utils.js'
33

44
/**
5-
* This class behaves as a HMAC-based deterministic random bit generator (DRBG). It implements a deterministic random number generator using SHA256HMAC HASH function. It takes an initial entropy and nonce when instantiated for seeding purpose.
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+
*
617
* @class DRBG
718
*
819
* @constructor

src/primitives/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export { default as PublicKey } from './PublicKey.js'
55
export { default as Signature } from './Signature.js'
66
export { default as PrivateKey, KeyShares } from './PrivateKey.js'
77
export { default as SymmetricKey } from './SymmetricKey.js'
8-
export { default as DRBG } from './DRBG.js'
98
export * as ECDSA from './ECDSA.js'
109
export * as Utils from './utils.js'
1110
export * as Hash from './Hash.js'

0 commit comments

Comments
 (0)