@@ -186,15 +186,40 @@ ElGamalPedersenLinkProof balanceLinkageProof = linkProofGen.generateProof(
186186);
187187```
188188
189- ** Step 7: Combine proofs**
189+ ** Step 7: Generate Bulletproof Range Proof**
190+
191+ The bulletproof proves that both the send amount and remaining balance are non-negative (in range [ 0, 2^64)).
192+
193+ ``` java
194+ // Compute remaining balance: senderCurrentBalance - sendAmount
195+ UnsignedLong remainingBalance = UnsignedLong . valueOf(
196+ senderCurrentBalance. longValue() - sendAmount. longValue()
197+ );
198+
199+ // Compute blinding factor for remaining balance: rho_rem = rho_balance - rho_amount
200+ byte [] negAmountBlinding = Secp256k1Operations . scalarNegate(amountBlindingFactorForSend. toBytes());
201+ byte [] rhoRemBytes = Secp256k1Operations . scalarAdd(balanceBlindingFactorForSend. toBytes(), negAmountBlinding);
202+ BlindingFactor rhoRem = BlindingFactor . fromBytes(rhoRemBytes);
203+
204+ // Generate aggregated bulletproof for {amount, remainingBalance}
205+ BulletproofRangeProofGenerator bulletproofGen = new JavaBulletproofRangeProofGenerator ();
206+ BulletproofRangeProof bulletproof = bulletproofGen. generateProof(
207+ Arrays . asList(sendAmount, remainingBalance), // List of values
208+ Arrays . asList(amountBlindingFactorForSend, rhoRem), // List of blinding factors
209+ sendContext
210+ );
211+ ```
212+
213+ ** Step 8: Combine all proofs**
190214
191215``` java
192- String fullZkProofHex = ZKProofUtils . combineSendProofsHex(
193- samePlaintextProof, amountLinkageProof, balanceLinkageProof
216+ // SamePlaintextMultiProof (359) + Amount Linkage (195) + Balance Linkage (195) + Bulletproof (754) = 1503 bytes
217+ String fullZkProofHex = ZKProofUtils . combineSendProofsWithBulletproofHex(
218+ samePlaintextProof, amountLinkageProof, balanceLinkageProof, bulletproof
194219);
195220
196- String amountCommitmentHex = amountCommitment. toReversedHex64 ();
197- String balanceCommitmentHex = balanceCommitment. toReversedHex64 ();
221+ String amountCommitmentHex = amountCommitment. hexValue ();
222+ String balanceCommitmentHex = balanceCommitment. hexValue ();
198223```
199224
200225---
@@ -253,9 +278,36 @@ ElGamalPedersenLinkProof balanceLinkageProof = linkProofGen.generateProof(
253278 convertBackBalanceBlindingFactor,
254279 context
255280);
281+ ```
256282
257- String zkProofHex = balanceLinkageProof. hexValue();
258- String balanceCommitmentHex = balanceCommitment. toReversedHex64();
283+ ** Step 5: Generate Bulletproof Range Proof**
284+
285+ The bulletproof proves the remaining balance after conversion is non-negative.
286+
287+ ``` java
288+ // Compute remaining balance: currentBalance - convertBackAmount
289+ UnsignedLong remainingBalance = UnsignedLong . valueOf(
290+ currentBalance. longValue() - convertBackAmount. longValue()
291+ );
292+
293+ // Generate bulletproof for remaining balance (single value)
294+ BulletproofRangeProofGenerator bulletproofGen = new JavaBulletproofRangeProofGenerator ();
295+ BulletproofRangeProof bulletproof = bulletproofGen. generateProof(
296+ Collections . singletonList(remainingBalance),
297+ Collections . singletonList(convertBackBalanceBlindingFactor), // Same blinding factor as balance commitment
298+ context
299+ );
300+ ```
301+
302+ ** Step 6: Combine proofs**
303+
304+ ``` java
305+ // Pedersen linkage proof (195 bytes) + Bulletproof (688 bytes) = 883 bytes total
306+ String zkProofHex = ZKProofUtils . combineConvertBackProofsHex(
307+ balanceLinkageProof, bulletproof
308+ );
309+
310+ String balanceCommitmentHex = balanceCommitment. hexValue();
259311```
260312
261313---
@@ -288,17 +340,16 @@ ConfidentialMPTClawbackContext context = ConfidentialMPTClawbackContext.generate
288340``` java
289341JavaEqualityPlaintextProofGenerator equalityProofGen = new JavaEqualityPlaintextProofGenerator ();
290342
343+ // The nonce is generated internally by the proof generator
291344BlindingFactor issuerPrivateKeyAsBlindingFactor = BlindingFactor . fromBytes(
292345 issuerElGamalKeyPair. privateKey(). naturalBytes(). toByteArray()
293346);
294- BlindingFactor clawbackNonce = BlindingFactor . generate();
295347
296348EqualityPlaintextProof clawbackProof = equalityProofGen. generateProof(
297349 issuerBalanceCiphertext, // ElGamalCiphertext - from MPToken.issuerEncryptedBalance
298350 issuerElGamalKeyPair. publicKey(), // ElGamalPublicKey
299351 clawbackAmount, // UnsignedLong
300352 issuerPrivateKeyAsBlindingFactor, // BlindingFactor - issuer's PRIVATE KEY
301- clawbackNonce, // BlindingFactor
302353 context // ConfidentialMPTClawbackContext
303354);
304355
@@ -315,7 +366,10 @@ JavaElGamalBalanceDecryptor decryptor = new JavaElGamalBalanceDecryptor();
315366ElGamalCiphertext ciphertext = ElGamalCiphertext . fromBytes(
316367 BaseEncoding . base16(). decode(encryptedHex)
317368);
318- long decryptedAmount = decryptor. decrypt(ciphertext, privateKey);
369+
370+ // Decrypt with search range [minAmount, maxAmount]
371+ // The decryptor uses baby-step giant-step algorithm to find the plaintext
372+ long decryptedAmount = decryptor. decrypt(ciphertext, privateKey, 0 , 1_000_000 );
319373```
320374
321375---
0 commit comments