Skip to content

Commit 1e332dc

Browse files
committed
support range proof
1 parent 9024327 commit 1e332dc

File tree

3 files changed

+265
-24
lines changed

3 files changed

+265
-24
lines changed

include/utility/mpt_utility.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ extern "C" {
3131
#define kMPT_SCHNORR_PROOF_SIZE 65
3232
#define kMPT_EQUALITY_PROOF_SIZE 98
3333
#define kMPT_PEDERSEN_LINK_SIZE 195
34+
#define kMPT_SINGLE_BULLETPROOF_SIZE 688
35+
#define kMPT_DOUBLE_BULLETPROOF_SIZE 754
3436

3537
// Field sizes in bytes for context hash
3638
#define kMPT_TYPE_SIZE 2
@@ -199,7 +201,7 @@ mpt_serialize_ec_pair(
199201
/**
200202
* @brief Generates a new Secp256k1 ElGamal keypair.
201203
* @param out_privkey [out] A 32-byte buffer for private key.
202-
* @param out_pubkey [out] A 64-byte buffer for public key.
204+
* @param out_pubkey [out] A 33-byte buffer for public key.
203205
* @return 0 on success, -1 on failure.
204206
*/
205207
int
@@ -216,7 +218,7 @@ mpt_generate_blinding_factor(uint8_t out_factor[kMPT_BLINDING_FACTOR_SIZE]);
216218
/**
217219
* @brief Encrypts an uint64 amount using an ElGamal public key.
218220
* @param amount [in] The integer value to encrypt.
219-
* @param pubkey [in] The 64-byte public key.
221+
* @param pubkey [in] The 33-byte public key.
220222
* @param blinding_factor [in] The 32-byte random blinding factor (scalar r).
221223
* @param out_ciphertext [out] A 66-byte buffer to store the resulting ciphertext (C1, C2).
222224
* @return 0 on success, -1 on failure.
@@ -252,7 +254,7 @@ mpt_decrypt_amount(
252254
* sender possesses the private key associated with the account, binding it
253255
* to the specific transaction via the ctx_hash.
254256
*
255-
* @param pubkey [in] 64-byte public key of the account.
257+
* @param pubkey [in] 33-byte public key of the account.
256258
* @param privkey [in] 32-byte private key of the account.
257259
* @param ctx_hash [in] 32-byte hash of the transaction (challenge).
258260
* @param out_proof [out] 65-byte buffer to store the Schnorr proof.
@@ -269,7 +271,7 @@ mpt_get_convert_proof(
269271
* @brief Computes a Pedersen Commitment point for Confidential MPT.
270272
* @param amount [in] The 64-bit unsigned integer value to commit.
271273
* @param blinding_factor [in] A 32-byte secret scalar (rho) used to hide the amount.
272-
* @param out_commitment [out] A 64-byte buffer to store the commitment
274+
* @param out_commitment [out] A 33-byte buffer to store the commitment
273275
*/
274276
int
275277
mpt_get_pedersen_commitment(
@@ -279,7 +281,7 @@ mpt_get_pedersen_commitment(
279281

280282
/**
281283
* @brief Generates a ZK linkage proof between an ElGamal ciphertext and a Pedersen commitment.
282-
* @param pubkey [in] 64-byte internal format of the sender's public key.
284+
* @param pubkey [in] 33-byte public key of the sender.
283285
* @param blinding_factor [in] 32-byte blinding factor used for the ElGamal encryption.
284286
* @param context_hash [in] 32-byte hash of the transaction context.
285287
* @param params [in] Struct containing commitment, amount, and ciphertext.
@@ -297,7 +299,7 @@ mpt_get_amount_linkage_proof(
297299
/**
298300
* @brief Generates a ZK linkage proof for the sender's balance.
299301
* @param priv [in] 32-byte private key of the sender.
300-
* @param pub [in] 64-byte internal format of the sender's public key.
302+
* @param pub [in] 33-byte public key of the sender.
301303
* @param context_hash [in] 32-byte hash of the transaction context.
302304
* @param params [in] Struct containing commitment, amount, and ciphertext.
303305
* @param out [out] Buffer of exactly 195 bytes to store the proof.
@@ -341,28 +343,30 @@ mpt_get_confidential_send_proof(
341343
/**
342344
* @brief Generates proof for ConfidentialMPTConvertBack.
343345
* @param priv [in] The holder's 32-byte private key.
344-
* @param pub [in] The holder's 64-byte public key (internal format).
346+
* @param pub [in] The holder's 33-byte public key.
345347
* @param context_hash [in] The 32-byte context hash binding the proof to the transaction.
348+
* @param amount [in] The amount to convert back.
346349
* @param params [in] Pedersen commitment parameters.
347-
* @param out_proof [out] The 65-byte buffer to be filled with the Pedersen linkage proof.
350+
* @param out_proof [out] The 883-byte buffer to be filled with the Pedersen linkage proof and range proof.
348351
* @return 0 on success, -1 on failure (e.g., math error or invalid parameters).
349352
*/
350353
int
351354
mpt_get_convert_back_proof(
352355
uint8_t const priv[kMPT_PRIVKEY_SIZE],
353356
uint8_t const pub[kMPT_PUBKEY_SIZE],
354357
uint8_t const context_hash[kMPT_HALF_SHA_SIZE],
358+
uint64_t const amount,
355359
mpt_pedersen_proof_params const* params,
356-
uint8_t out_proof[kMPT_PEDERSEN_LINK_SIZE]);
360+
uint8_t out_proof[kMPT_PEDERSEN_LINK_SIZE + kMPT_SINGLE_BULLETPROOF_SIZE]);
357361

358362
/**
359363
* @brief Generates proof for ConfidentialMPTClawback.
360364
* @param priv [in] The issuer's 32-byte private key.
361-
* @param pub [in] The issuer's 64-byte public key.
365+
* @param pub [in] The issuer's 33-byte public key.
362366
* @param context_hash [in] The 32-byte context hash binding the proof to the transaction.
363367
* @param amount [in] The plaintext amount to be clawed back.
364368
* @param encrypted_amount [in] The 66-byte sfIssuerEncryptedBalance blob from the ledger.
365-
* @param out_proof [out] The 64-byte buffer to be filled with the equality proof.
369+
* @param out_proof [out] The 98-byte buffer to be filled with the equality proof.
366370
* @return 0 on success, -1 on failure (e.g., math error or invalid ciphertext).
367371
*/
368372
int

src/utility/mpt_utility.cpp

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,55 @@
4242
#endif
4343
#endif
4444

45+
46+
/**
47+
* @internal
48+
* Private helper to generate aggregated bulletproofs
49+
*/
50+
static int
51+
mpt_get_bulletproof_agg(
52+
uint64_t const* values,
53+
uint8_t const* const* blinding_ptrs,
54+
size_t m,
55+
uint8_t const context_hash[kMPT_HALF_SHA_SIZE],
56+
uint8_t* out_proof,
57+
size_t* out_len)
58+
{
59+
if ((m != 1 && m != 2) || !values || !blinding_ptrs || !out_proof || !out_len)
60+
return -1;
61+
62+
secp256k1_context const* ctx = mpt_secp256k1_context();
63+
64+
uint8_t blindings_flat[64];
65+
for (size_t i = 0; i < m; ++i) {
66+
if (!blinding_ptrs[i]) return -1;
67+
std::memcpy(blindings_flat + (i * 32), blinding_ptrs[i], 32);
68+
}
69+
70+
secp256k1_pubkey pk_base;
71+
if (secp256k1_mpt_get_h_generator(ctx, &pk_base) != 1)
72+
return -1;
73+
74+
if (secp256k1_bulletproof_prove_agg(
75+
ctx,
76+
out_proof,
77+
out_len,
78+
values,
79+
blindings_flat,
80+
m,
81+
&pk_base,
82+
context_hash) != 1)
83+
{
84+
return -1;
85+
}
86+
87+
size_t const expected = (m == 1) ? kMPT_SINGLE_BULLETPROOF_SIZE : kMPT_DOUBLE_BULLETPROOF_SIZE;
88+
if (*out_len != expected)
89+
return -1;
90+
91+
return 0;
92+
}
93+
4594
/**
4695
* Context for secp256k1 operations.
4796
* Initialized once and reused across all operations to optimize performance
@@ -189,7 +238,7 @@ get_multi_ciphertext_equality_proof_size(size_t n_recipients)
189238
size_t
190239
get_confidential_send_proof_size(size_t n_recipients)
191240
{
192-
return get_multi_ciphertext_equality_proof_size(n_recipients) + (kMPT_PEDERSEN_LINK_SIZE * 2);
241+
return get_multi_ciphertext_equality_proof_size(n_recipients) + (kMPT_PEDERSEN_LINK_SIZE * 2) + kMPT_DOUBLE_BULLETPROOF_SIZE;
193242
}
194243

195244
bool
@@ -640,9 +689,26 @@ mpt_get_confidential_send_proof(
640689
return -1;
641690
}
642691

643-
*out_len = totalRequired;
692+
uint8_t* bp_ptr = bal_ptr + kMPT_PEDERSEN_LINK_SIZE;
693+
694+
// Values to prove: [amount being sent, remaining balance] for range proof
695+
uint64_t const remaining_balance = balance_params->amount - amount;
696+
uint64_t bp_values[2] = { amount, remaining_balance };
697+
698+
// Blinding factors: [rho_amount, rho_balance - rho_amount]
699+
uint8_t rho_rem[32];
700+
uint8_t neg_rho_m[32];
701+
secp256k1_mpt_scalar_negate(neg_rho_m, amount_params->blinding_factor);
702+
secp256k1_mpt_scalar_add(rho_rem, balance_params->blinding_factor, neg_rho_m);
703+
704+
uint8_t const* bp_blinding_ptrs[2] = { amount_params->blinding_factor, rho_rem };
705+
size_t actual_bp_len = kMPT_DOUBLE_BULLETPROOF_SIZE;
706+
707+
if (mpt_get_bulletproof_agg(bp_values, bp_blinding_ptrs, 2, context_hash, bp_ptr, &actual_bp_len) != 0)
708+
return -1;
709+
710+
*out_len = size_equality + (kMPT_PEDERSEN_LINK_SIZE * 2) + actual_bp_len;
644711

645-
// todo: add range proof
646712
return 0;
647713
}
648714

@@ -651,12 +717,27 @@ mpt_get_convert_back_proof(
651717
uint8_t const priv[kMPT_PRIVKEY_SIZE],
652718
uint8_t const pub[kMPT_PUBKEY_SIZE],
653719
uint8_t const context_hash[kMPT_HALF_SHA_SIZE],
720+
uint64_t const amount,
654721
mpt_pedersen_proof_params const* params,
655-
uint8_t out_proof[kMPT_PEDERSEN_LINK_SIZE])
722+
uint8_t out_proof[kMPT_PEDERSEN_LINK_SIZE + kMPT_SINGLE_BULLETPROOF_SIZE])
656723
{
657-
return mpt_get_balance_linkage_proof(priv, pub, context_hash, params, out_proof);
658-
659-
// todo: add range proof
724+
int ret = mpt_get_balance_linkage_proof(priv, pub, context_hash, params, out_proof);
725+
if (ret != 0)
726+
return ret;
727+
728+
uint64_t const remaining_balance = params->amount - amount;
729+
uint8_t* bulletproof_ptr = out_proof + kMPT_PEDERSEN_LINK_SIZE;
730+
size_t proof_len = kMPT_SINGLE_BULLETPROOF_SIZE;
731+
732+
uint8_t const* blinding_ptrs[1] = { params->blinding_factor };
733+
734+
return mpt_get_bulletproof_agg(
735+
&remaining_balance,
736+
blinding_ptrs,
737+
1,
738+
context_hash,
739+
bulletproof_ptr,
740+
&proof_len);
660741
}
661742

662743
int

0 commit comments

Comments
 (0)