Skip to content

Commit 7fbd3e5

Browse files
Merge pull request #44 from skalenetwork/bug/36-dont-use-buffer
Bug/36 dont use buffer
2 parents f785370 + c8f1a4d commit 7fbd3e5

8 files changed

Lines changed: 91 additions & 32 deletions

File tree

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
3333
- name: Run sgx container
3434
run: |
35-
export SGX_WALLET_TAG=1.10.1-develop.3
35+
export SGX_WALLET_TAG=1.10.2-develop.6
3636
echo "SGX_WALLET_TAG=$SGX_WALLET_TAG" >> $GITHUB_ENV
3737
bash ./scripts/run_sgx_container.sh $SGX_WALLET_TAG
3838
echo "Waiting for SGX wallet to be ready..."
@@ -59,7 +59,7 @@ jobs:
5959

6060
- name: Run skaled container
6161
run: |
62-
export SKALED_RELEASE=5.1.0-develop.7-bite2
62+
export SKALED_RELEASE=5.1.0-develop.38-bite
6363
echo "SKALED_RELEASE=$SKALED_RELEASE" >> $GITHUB_ENV
6464
shell: bash
6565

examples/confidential-token-demo/src/encryption.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ethers } from 'ethers';
2-
import { BITE } from '@skalenetwork/bite';
2+
import { BITE, bytesToHex, concatBytes, hexToBytes } from '@skalenetwork/bite';
33
import crypto from 'crypto';
44

55
export async function encryptTokenTransfer(rpcUrl, provider, tokenAddress, recipient, amount) {
@@ -39,16 +39,16 @@ export function decryptBalance(secretKey, encryptedDataHex) {
3939
const cleanSecretKey = secretKey.startsWith('0x') ? secretKey.slice(2) : secretKey;
4040
const cleanEncryptedData = encryptedDataHex.startsWith('0x') ? encryptedDataHex.slice(2) : encryptedDataHex;
4141

42-
const encryptedDataBuffer = Buffer.from(cleanEncryptedData, 'hex');
42+
const encryptedDataBytes = hexToBytes(cleanEncryptedData);
4343

4444
// Extract parts
45-
const iv = encryptedDataBuffer.subarray(0, 16);
46-
const ephemeralPublicKey = encryptedDataBuffer.subarray(16, 16 + 33);
47-
const ciphertext = encryptedDataBuffer.subarray(16 + 33);
45+
const iv = encryptedDataBytes.subarray(0, 16);
46+
const ephemeralPublicKey = encryptedDataBytes.subarray(16, 16 + 33);
47+
const ciphertext = encryptedDataBytes.subarray(16 + 33);
4848

4949
// Derive Shared Secret
5050
const ecdh = crypto.createECDH('secp256k1');
51-
ecdh.setPrivateKey(Buffer.from(cleanSecretKey, 'hex'));
51+
ecdh.setPrivateKey(hexToBytes(cleanSecretKey));
5252

5353
// computeSecret requires the other party's public key
5454
const sharedSecret = ecdh.computeSecret(ephemeralPublicKey);
@@ -61,17 +61,17 @@ export function decryptBalance(secretKey, encryptedDataHex) {
6161
// Decrypt: AES-256-CBC with PKCS7 unpadding (default for createDecipheriv)
6262
const decipher = crypto.createDecipheriv('aes-256-cbc', encryptionKey, iv);
6363
let decrypted = decipher.update(ciphertext);
64-
decrypted = Buffer.concat([decrypted, decipher.final()]);
64+
decrypted = concatBytes(decrypted, decipher.final());
6565

6666
// If the plaintext was stored as a *textual* hex string (e.g. "0x..."), UTF-8 decoding is correct.
6767
// If it was stored as raw bytes, represent it as hex instead.
68-
let decryptedString = decrypted.toString('utf8');
68+
let decryptedString = new TextDecoder().decode(decrypted);
6969

7070
const maybeHex = decryptedString.startsWith('0x') ? decryptedString.slice(2) : decryptedString;
7171
const looksLikeHex = /^[0-9a-fA-F]*$/.test(maybeHex) && maybeHex.length % 2 === 0;
7272

7373
if (!looksLikeHex) {
74-
decryptedString = `0x${decrypted.toString('hex')}`;
74+
decryptedString = `0x${bytesToHex(decrypted)}`;
7575
}
7676

7777
// Convert hex string to decimal if applicable

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@skalenetwork/bite",
3-
"version": "0.8.1",
3+
"version": "0.8.2",
44
"description": "TS Library to interact with BITE protocol",
55
"homepage": "https://github.com/skalenetwork/bite.ts",
66
"license": "LGPL-3.0-or-later",

scripts/endpoint_by_container/data_dir/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@
372372
"flexibleDeploymentPatchTimestamp": 1721826000,
373373
"verifyBlsSyncPatchTimestamp": 1721829600,
374374
"externalGasPatchTimestamp": 1727712000,
375+
"bite2PatchTimestamp": 1735689600,
376+
"singleStateCommitPerBlockPatchTimestamp": 1735689600,
377+
"contractCreationReadOnlyPatchTimestamp": 1735689600,
378+
"currentBlockRandomPatchTimestamp": 1735689600,
375379
"emptyBlockIntervalMs": 1000
376380
}
377381
}

src/core/encrypt.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { encode } from '@ethereumjs/rlp';
3030
import {logger} from "../utils/logger";
3131
import * as utils from '../utils/helper';
3232
import * as constants from '../utils/constants';
33+
import { bytesToHex, hexToBytes } from '../utils/bytes';
3334

3435

3536
export interface Transaction {
@@ -152,14 +153,14 @@ export async function encryptMessage(
152153
const encryptedRawMessage = await encryptRawMessage(data, publicKeyResponse.commonBLSPublicKey, sanitizedAADTE, sanitizedAADAES);
153154

154155
// RLP encode epochID and encrypted message
155-
const rlpEncodedResult = rlpEncodeMessageData([publicKeyResponse.epochId, Buffer.from(encryptedRawMessage, 'hex')]);
156+
const rlpEncodedResult = rlpEncodeMessageData([publicKeyResponse.epochId, hexToBytes(encryptedRawMessage)]);
156157
return `0x${rlpEncodedResult}`;
157158
} else {
158159
const encryptedRawMessage = await encryptRawMessageDualKey(data, committees[0].commonBLSPublicKey,
159160
committees[1].commonBLSPublicKey, sanitizedAADTE, sanitizedAADAES);
160161

161162
// RLP encode epochID and encrypted message
162-
const rlpEncodedResult = rlpEncodeMessageData([committees[0].epochId, Buffer.from(encryptedRawMessage, 'hex')]);
163+
const rlpEncodedResult = rlpEncodeMessageData([committees[0].epochId, hexToBytes(encryptedRawMessage)]);
163164
return `0x${rlpEncodedResult}`;
164165
}
165166
} catch (error) {
@@ -188,7 +189,7 @@ export async function encryptMessageMockup(
188189
const epochId = 0;
189190

190191
// RLP encode epochID and encrypted message
191-
const rlpEncodedResult = rlpEncodeMessageData([epochId, Buffer.from(encryptedRawMessage, 'hex')]);
192+
const rlpEncodedResult = rlpEncodeMessageData([epochId, hexToBytes(encryptedRawMessage)]);
192193
return `0x${rlpEncodedResult}`;
193194
} catch (error) {
194195
logger.error('Error encrypting message:', error);
@@ -234,15 +235,15 @@ function validateAndExtractTransactionFields(tx: Transaction): Transaction {
234235
*/
235236
function rlpEncodeTransactionData(txTo: string, txData: string): string {
236237
try {
237-
// Convert hex strings to Buffer for RLP encoding
238-
const toBuffer = Buffer.from(txTo, 'hex');
239-
const dataBuffer = Buffer.from(txData, 'hex');
238+
// Convert hex strings to bytes for RLP encoding
239+
const toBytes = hexToBytes(txTo);
240+
const dataBytes = hexToBytes(txData);
240241

241242
// RLP encode as array [txData, txTo]
242-
const rlpEncoded = encode([dataBuffer, toBuffer]);
243+
const rlpEncoded = encode([dataBytes, toBytes]);
243244

244245
// Convert back to hex string without 0x prefix
245-
return Buffer.from(rlpEncoded).toString('hex');
246+
return bytesToHex(rlpEncoded);
246247
} catch (error) {
247248
logger.error('Error RLP encoding transaction data:', error);
248249
throw new Error('Failed to RLP encode transaction data');
@@ -251,16 +252,16 @@ function rlpEncodeTransactionData(txTo: string, txData: string): string {
251252

252253
/**
253254
* RLP encodes array of epochId and encrypted message
254-
* @param {(number | Buffer | (number | Buffer)[])[]} data - Array of data to RLP encode
255+
* @param {(number | Uint8Array | (number | Uint8Array)[])[]} data - Array of data to RLP encode
255256
* @returns {string} RLP encoded data as hex string (without 0x prefix)
256257
*/
257-
function rlpEncodeMessageData(data: (number | Buffer | (number | Buffer)[])[]): string {
258+
function rlpEncodeMessageData(data: (number | Uint8Array | (number | Uint8Array)[])[]): string {
258259
try {
259260
// RLP encode the array
260261
const rlpEncoded = encode(data);
261262

262263
// Convert back to hex string without 0x prefix
263-
return Buffer.from(rlpEncoded).toString('hex');
264+
return bytesToHex(rlpEncoded);
264265
} catch (error) {
265266
logger.error('Error RLP encoding message data:', error);
266267
throw new Error('Failed to RLP encode message data');

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@
2222
*/
2323

2424
export * from './core/bite';
25-
export { type Transaction } from './core/encrypt';
25+
export { type Transaction } from './core/encrypt';
26+
export { bytesToHex, concatBytes, hexToBytes } from './utils/bytes';

src/utils/bytes.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license
3+
* SKALE bite.ts
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
/**
20+
* @file bytes.ts
21+
* @copyright SKALE Labs 2026-Present
22+
*/
23+
24+
import { validateHexString } from './helper';
25+
26+
export function hexToBytes(hex: string): Uint8Array {
27+
const sanitizedHex = hex.startsWith('0x') ? hex.slice(2) : hex;
28+
validateHexString(sanitizedHex);
29+
const bytes = new Uint8Array(sanitizedHex.length / 2);
30+
31+
for (let i = 0; i < sanitizedHex.length; i += 2) {
32+
bytes[i / 2] = parseInt(sanitizedHex.slice(i, i + 2), 16);
33+
}
34+
35+
return bytes;
36+
}
37+
38+
export function bytesToHex(bytes: Uint8Array): string {
39+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
40+
}
41+
42+
export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
43+
const totalLength = arrays.reduce((sum, array) => sum + array.length, 0);
44+
const result = new Uint8Array(totalLength);
45+
let offset = 0;
46+
47+
for (const array of arrays) {
48+
result.set(array, offset);
49+
offset += array.length;
50+
}
51+
52+
return result;
53+
}

tests/test_epoch_validation.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22

3-
const { BITE } = require('..');
3+
const { BITE, bytesToHex, hexToBytes } = require('..');
44
const { encode } = require('@ethereumjs/rlp');
55
const ethers = require('ethers');
66

@@ -63,19 +63,19 @@ async function createForgedTransaction(transaction, forgedEpochId, publicKey) {
6363
const txData = transaction.data.startsWith('0x') ? transaction.data.slice(2) : transaction.data;
6464

6565
// RLP encode transaction data (same as in the real encrypt function)
66-
const toBuffer = Buffer.from(txTo, 'hex');
67-
const dataBuffer = Buffer.from(txData, 'hex');
68-
const rlpEncodedTxData = encode([dataBuffer, toBuffer]);
69-
const rlpEncodedTxHex = Buffer.from(rlpEncodedTxData).toString('hex');
66+
const toBytes = hexToBytes(txTo);
67+
const dataBytes = hexToBytes(txData);
68+
const rlpEncodedTxData = encode([dataBytes, toBytes]);
69+
const rlpEncodedTxHex = bytesToHex(rlpEncodedTxData);
7070

7171
// Encrypt the RLP encoded transaction data using the same BLS key
7272
const encryptedRawMessage = await encryptRawMessage(rlpEncodedTxHex, publicKey);
7373

7474
// RLP encode with forged epochId (same structure as real encrypt function)
75-
const encryptedMessageBuffer = Buffer.from(encryptedRawMessage, 'hex');
76-
const forgedRlpEncoded = encode([forgedEpochId, encryptedMessageBuffer]);
75+
const encryptedMessageBytes = hexToBytes(encryptedRawMessage);
76+
const forgedRlpEncoded = encode([forgedEpochId, encryptedMessageBytes]);
7777

78-
return '0x' + Buffer.from(forgedRlpEncoded).toString('hex');
78+
return '0x' + bytesToHex(forgedRlpEncoded);
7979
} catch (error) {
8080
console.error('Error creating forged transaction:', error);
8181
throw error;

0 commit comments

Comments
 (0)