Skip to content

Commit 2c3b487

Browse files
Merge pull request #43 from skalenetwork/beta
stable
2 parents 51feab3 + bf83074 commit 2c3b487

8 files changed

Lines changed: 62 additions & 16 deletions

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959

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

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ Encrypts a raw hex-encoded message using the BLS threshold encryption from the c
119119

120120
---
121121

122+
### `bite.encryptMessageForCTX(message, ctxSubmitterAddress)`
123+
124+
Encrypts a raw hex-encoded message specifically for Confidential Transactions (CTX). This is a convenience method that sets the `ctxSubmitterAddress` as `aadTE` - Additional Authentication Data for Threshold Encryption, used to protect user's encrypted data. Address of smart contract that will create CTX with that data should be passed as `ctxSubmitterAddress`. When data is encrypted with `ctxSubmitterAddress` as `aadTE`, only `ctxSubmitterAddress` is allowed to submit CTX to decrypt that data. CTXs submitted by other addresses will be rejected.
125+
126+
- **Parameters**:
127+
- `message`: `string` – A hex string to encrypt (with or without `0x` prefix).
128+
- `ctxSubmitterAddress`: `string` – The Smart Contract Address to be used as `aadTE`.
129+
- **Returns**: `Promise<string>` – An encrypted hex string in RLP format.
130+
131+
---
132+
122133
### `bite.getDecryptedTransactionData(transactionHash)`
123134

124135
Retrieves decrypted transaction data from the configured BITE provider using the `bite_getDecryptedTransactionData` JSON-RPC method.

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.7.2",
3+
"version": "0.8.1",
44
"description": "TS Library to interact with BITE protocol",
55
"homepage": "https://github.com/skalenetwork/bite.ts",
66
"license": "LGPL-3.0-or-later",

src/core/bite.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ export class BITE {
5050
return encrypt.encryptTransaction(tx, committees);
5151
}
5252

53+
/**
54+
* Encrypt a hex-encoded message using BLS public key for CTX.
55+
* @param message - Hex string (with or without 0x).
56+
* @param ctxSubmitterAddress - Smart Contract Address for aadTE.
57+
*/
58+
async encryptMessageForCTX(message: string, ctxSubmitterAddress: string): Promise<string> {
59+
const committees = await biteRpc.getCommitteesInfo(this.providerURL);
60+
return encrypt.encryptMessage(message, committees, ctxSubmitterAddress);
61+
}
62+
5363
/**
5464
* Encrypt a transaction object using BLS public key and provided committees info.
5565
* @param tx - The transaction to encrypt.

src/core/encrypt.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,16 @@ export interface Transaction {
4343
*
4444
* @param {Transaction} tx - The transaction object.
4545
* @param {utils.CommitteeInfo[]} committees - The committees info object.
46+
* @param {string} [aadTE] - Optional TE Additional Authenticated Data.
47+
* @param {string} [aadAES] - Optional AES Additional Authenticated Data.
4648
* @returns {Promise<Transaction>} - A promise with encrypted transaction.
4749
*
4850
*/
4951
export async function encryptTransaction(
5052
tx: Transaction,
51-
committees: utils.CommitteeInfo[]
53+
committees: utils.CommitteeInfo[],
54+
aadTE?: string,
55+
aadAES?: string
5256
): Promise<Transaction> {
5357
try {
5458
const validatedTx = validateAndExtractTransactionFields(tx);
@@ -58,7 +62,13 @@ export async function encryptTransaction(
5862
// RLP encode data and to fields
5963
const rlpEncodedData = rlpEncodeTransactionData(txTo, txData);
6064

61-
const encryptedData = await encryptMessage(rlpEncodedData, committees);
65+
const sanitizedAADAES = aadAES ? utils.remove0xPrefixIfNeeded(aadAES) : undefined;
66+
const sanitizedAADTE = aadTE ? utils.remove0xPrefixIfNeeded(aadTE) : undefined;
67+
68+
if (sanitizedAADAES) utils.validateHexString(sanitizedAADAES);
69+
if (sanitizedAADTE) utils.validateHexString(sanitizedAADTE);
70+
71+
const encryptedData = await encryptMessage(rlpEncodedData, committees, sanitizedAADTE, sanitizedAADAES);
6272

6373
// Set default gasLimit if not set
6474
const biteGasLimit = tx.gasLimit ?? constants.DEFAULT_GAS_LIMIT;
@@ -113,25 +123,40 @@ export async function encryptTransactionMockup(tx: Transaction): Promise<Transac
113123
*
114124
* @param {string} message - The message to encrypt, as a hex string (with or without 0x prefix).
115125
* @param {utils.CommitteeInfo[]} committees - The committees info object.
126+
* @param {string} [aadTE] - Optional TE Additional Authenticated Data, as a hex string.
127+
* @param {string} [aadAES] - Optional AES Additional Authenticated Data, as a hex string.
116128
* @returns {Promise<string>} - The encrypted message.
117129
*/
118130
export async function encryptMessage(
119131
message: string,
120-
committees: utils.CommitteeInfo[]
132+
committees: utils.CommitteeInfo[],
133+
aadTE?: string,
134+
aadAES?: string
121135
): Promise<string> {
122136
try {
123137
const data = utils.remove0xPrefixIfNeeded(message);
124138
utils.validateHexString(data);
125139

140+
const sanitizedAADTE = aadTE ? utils.remove0xPrefixIfNeeded(aadTE) : undefined;
141+
const sanitizedAADAES = aadAES ? utils.remove0xPrefixIfNeeded(aadAES) : undefined;
142+
143+
if (sanitizedAADAES) {
144+
utils.validateHexString(sanitizedAADAES);
145+
}
146+
if (sanitizedAADTE) {
147+
utils.validateHexString(sanitizedAADTE);
148+
}
149+
126150
if (committees.length === 1) {
127151
const publicKeyResponse = committees[0];
128-
const encryptedRawMessage = await encryptRawMessage(data, publicKeyResponse.commonBLSPublicKey);
152+
const encryptedRawMessage = await encryptRawMessage(data, publicKeyResponse.commonBLSPublicKey, sanitizedAADTE, sanitizedAADAES);
129153

130154
// RLP encode epochID and encrypted message
131155
const rlpEncodedResult = rlpEncodeMessageData([publicKeyResponse.epochId, Buffer.from(encryptedRawMessage, 'hex')]);
132156
return `0x${rlpEncodedResult}`;
133157
} else {
134-
const encryptedRawMessage = await encryptRawMessageDualKey(data, committees[0].commonBLSPublicKey, committees[1].commonBLSPublicKey);
158+
const encryptedRawMessage = await encryptRawMessageDualKey(data, committees[0].commonBLSPublicKey,
159+
committees[1].commonBLSPublicKey, sanitizedAADTE, sanitizedAADAES);
135160

136161
// RLP encode epochID and encrypted message
137162
const rlpEncodedResult = rlpEncodeMessageData([committees[0].epochId, Buffer.from(encryptedRawMessage, 'hex')]);

src/types/t-encrypt.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
declare module '@skalenetwork/t-encrypt' {
2-
export function encryptMessage(message: string, publicKey: string): Promise<string>;
3-
export function encryptMessageDualKey(message: string, firstPublicKey: string, secondPublicKey: string): Promise<string>;
2+
export function encryptMessage(message: string, publicKey: string, AADAES?: string, AADTE?: string): Promise<string>;
3+
export function encryptMessageDualKey(message: string, firstPublicKey: string, secondPublicKey: string, AADAES?: string, AADTE?: string): Promise<string>;
44
export function encryptMessageMockup(message: string): Promise<string>;
55
}

tests/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ The test relies on a Solidity contract named `Game`. This contract implements a
2525
* `submitPlaintext(bytes)`: Adds plaintext data to the state.
2626
* `decryptAndExecute()`: Packages the encrypted and plaintext data and performs a `staticcall` to the precompiled `submitCTX` stored at address `0x14`. The `submitCTX` precompile creates a BITE2 Transaction (Confidential Transaction - CTX), which is then added to the next block.
2727
* `onDecrypt(bytes[], bytes[])`: Called as part of the execution flow to process the now-decrypted data. It calculates the sums of the values and determines if the user "won" (difference between sums < 101). Every CTX created via the `submitCTX` precompile is sent to the `onDecrypt(bytes[], bytes[])` function of the same address that initiated the call to `submitCTX`.
28+
* `didUserWin`: Returns the `userWon` flag.
2829

2930
## Test Steps
3031

@@ -36,7 +37,7 @@ The `runSampleBITE2` function performs the following steps:
3637

3738
2. **Encrypted Data Submission**:
3839
* Generates 5 random numbers (range 50-249).
39-
* Encrypts each number using `bite.encryptMessage(hexValue)`.
40+
* Encrypts each number using `bite.encryptMessageForCTX(hexValue, contractAddress)`.
4041
* Calls `submitEncrypted` on the contract to store these values.
4142

4243
3. **Plaintext Data Submission**:

tests/test.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ async function runSampleBITE2( providerUrl, chainID, INSECURE_ETH_PRIVATE_KEY )
131131
for (let i = 0; i < encryptedNumbers.length; i++) {
132132
const hexValue = '0x' + encryptedNumbers[i].toString(16).padStart(64, '0'); // Convert to 32 bytes hex
133133

134-
const encryptedNumber = await bite.encryptMessage(hexValue);
134+
const encryptedNumber = await bite.encryptMessageForCTX(hexValue, contractAddress);
135135

136136
const tx = await contract.submitEncrypted(encryptedNumber);
137137
await tx.wait();
@@ -172,16 +172,15 @@ async function runSampleBITE2( providerUrl, chainID, INSECURE_ETH_PRIVATE_KEY )
172172

173173
// Wait for one more block to be created
174174
console.log("\nStep 7: Waiting for one more block...");
175-
const currentBlock = await provider.getBlockNumber();
175+
let currentBlock = await provider.getBlockNumber();
176176
console.log(`Current block: ${currentBlock}`);
177177

178178
// Poll for next block
179-
let nextBlock = currentBlock;
180-
while (nextBlock <= currentBlock) {
179+
while (currentBlock == decryptReceipt.blockNumber) {
181180
await new Promise(resolve => setTimeout(resolve, 1000));
182-
nextBlock = await provider.getBlockNumber();
181+
currentBlock = await provider.getBlockNumber();
183182
}
184-
console.log(`✓ Next block created: ${nextBlock}`);
183+
console.log(`✓ Next block created: ${currentBlock}`);
185184

186185
// Call getSumDecrypted
187186
console.log("\nStep 8: Calling getSumDecrypted...");

0 commit comments

Comments
 (0)