Verify Pedersen Commitment Values

Oracle Blockchain Platform Digital Assets Edition uses Pedersen commitments to ensure both secrecy and immutability. The following APIs can help verify the Pedersen commitments against actual raw text values.

In Oracle Blockchain Platform, data can be persisted in the rich history database by connecting to an Oracle Database. Accounts and transactions, which are stored as key/value pairs in the state database, can be tracked over time in the rich history database. In confidential mode, both accounts and transactions are stored in two parts, private and public, in the history table in the rich history database.

All data, both public and private for the organization, is available in the history table of the rich history database. The table name uses the following format: <obp_instance_name>_<channel_name>_hist. For example, CentralBank_default_hist.

Public Account Data (State Database)
  • Stored under the chaincode ID: <chaincode_name>
  • Accessible to all network participants
  • General account properties such as org_id, token_name, balance/onhold_balance (as Pedersen commitments), and other non-confidential metadata
Private Account Data (Private Data Collection)
  • Stored under the chaincode ID: <chaincode_name>$$_implicit_org_<Oracle_Blockchain_Platform_instance_name>
  • Accessible only to the organization that owns the private data collection
  • Sensitive fields such as balance/onhold_balance (raw values), balanceBlindingFactor, onHoldBalanceBlindingFactor, and daily limits
Public Transaction Data (State Database)
  • Stored under the chaincode ID: <chaincode_name>
  • Accessible to all network participants
  • General account properties such as sender and receiver account IDs, from_account_balance/from_account_onhold_balance/to_account_balance/to_account_onhold_balance/transaction amounts (as Pedersen commitments), and other non-confidential metadata
Private Transaction Data (Private Data Collection)
  • Stored under the chaincode ID: <chaincode_name>$$_implicit_org_<Oracle_Blockchain_Platform_instance_name>
  • Accessible only to the organization that owns the private data collection
  • Sensitive fields such as from_account_balance/from_account_onhold_balance/to_account_balance/to_account_onhold_balance/transaction amounts (raw values), and the corresponding blinding factors

Pedersen Commitment APIs

You can use the following APIs, which are included in the controller file of the chaincode, to verify and work with Pedersen commitments.

generateCommitment
This method generates a Pedersen commitment for a specified value and blinding factor. This method can be called only by a Token Admin or Org Admin.
@Validator(yup.string(), yup.string())
 public async generateCommitment(value: string, blinding_factor: string) {
   await this.Ctx.Auth.checkAuthorization("ACCOUNT.processSendersAndReceivers", "TOKEN");
   const result = await this.Ctx.PedersonCommitments.generateCommitment(value, blinding_factor);
   return result;
 }
Parameters:
  • value: string – The numeric value to generate the Pedersen commitment for.
  • blinding_factor: string – The random number used to generate the Pedersen commitment.
Returns:
  • A hash value, which is the Pedersen commitment for the specified value and blinding factor.
Return Value Example:
"0212f6b676da244eee000a9106060cf3a3a4bb5a9b61be23dd467e557156c40be8"
addCommitment
This method adds two specified Pedersen commitment hash values. Because Pedersen commitments are homomorphic, they support performing mathematical operations such as addition and subtraction on commitments while preserving the relationships between the underlying values. This method can be called only by a Token Admin or Org Admin.
@Validator(yup.string(), yup.string())
 public async addCommitment(value1: string, value2: string) {
  await this.Ctx.Auth.checkAuthorization("ACCOUNT.processSendersAndReceivers", "TOKEN");
  const result = await this.Ctx.PedersonCommitments.add(value1, value2);
  return result;
 }
Parameters:
  • value1: string – The first Pedersen commitment hash value to add.
  • value2: string – The second Pedersen commitment hash value to add.
Returns:
  • A hash value, which is the Pedersen commitment for the sum of the two specified Pedersen commitment values.
Return Value Example:
"03a9c138b76e7d56f799108a46f665f53a42f55008b31e0fec071019aa5c37344a"
subCommitment
This method subtracts the second specified Pedersen commitment hash value from the first. Because Pedersen commitments are homomorphic, they support performing mathematical operations such as addition and subtraction on commitments while preserving the relationships between the underlying values. This method can be called only by a Token Admin or Org Admin.
@Validator(yup.string(), yup.string())
 public async subCommitment(value1: string, value2: string) {
  await this.Ctx.Auth.checkAuthorization("ACCOUNT.processSendersAndReceivers", "TOKEN");
  const result = await this.Ctx.PedersonCommitments.sub(value1, value2);
  return result;
 }
Parameters:
  • value1: string – The first Pedersen commitment hash value in the subtraction (the minuend).
  • value2: string – The second Pedersen commitment hash value to subtract from the first (the subtrahend).
Returns:
  • A hash value, which is the Pedersen commitment for the difference of the two specified Pedersen commitment values.
Return Value Example:
"0212f6b676da244eee000a9106060cf3a3a4bb5a9b61be23dd467e557156c40be8"

Verifying Account and On Hold Balances

  1. Use the following query to get the Pedersen commitment of the balance, which is public data.
    SELECT JSON_VALUE(h."VALUEJSON", '$.balance') AS balance_commitment
    FROM "<OBP_instance_name>_<channel>_hist" h
    WHERE h."CHAINCODEID" = '<chaincode_name>'
      AND h."KEY" = '<account_id>'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    Example query:
    SELECT JSON_VALUE(h."VALUEJSON", '$.balance') AS balance_commitment
    FROM "CentralBank_default_hist" h
    WHERE h."CHAINCODEID" = 'testChaincode'
      AND h."KEY" = 'oaccount~07e1c67205520da256f6edfbe9d1cb763cf13d29a3ec870137251a1344feab84'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    Example response balance_commitment:
    03977a92a07c00234270d41097a35ed2050bcdef02d3908a9a3cc733951b4171dd
  2. Use the following query to get the balance and blinding factor from the private data collection.
    SELECT 
        JSON_VALUE(h."VALUEJSON", '$.balance') AS balance,
        JSON_VALUE(h."VALUEJSON", '$.balanceBlindingFactor') AS blinding_factor
    FROM "<OBP_instance_name>_<channel>_hist" h
    WHERE h."CHAINCODEID" = '<chaincode_name>$$_implicit_org_<OBP_instance_name>'
      AND h."KEY" = '<account_id>'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    Example query:
    SELECT
        JSON_VALUE(h."VALUEJSON", '$.balance') AS balance,
        JSON_VALUE(h."VALUEJSON", '$.balanceBlindingFactor') AS blinding_factor
    FROM "CentralBank_default_hist" h
    WHERE h."CHAINCODEID" = 'testChaincode$$_implicit_org_CentralBank'
      AND h."KEY" = 'oaccount~07e1c67205520da256f6edfbe9d1cb763cf13d29a3ec870137251a1344feab84'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    The following table shows an example response:
    balance blinding_factor
    100 17629824947682234000
  3. Add the generateCommitment method, defined previously, to the controller file located in the src folder (src/controller/<Chaincode_name>.controller.ts).
    Example:
    @Validator(yup.string(), yup.string()) 
    public async generateCommitment(value: string, bf: string) {
        await this. Ctx.Auth.checkAuthorization("ACCOUNT.processSendersAndReceivers", "TOKEN"); 
        const result = await this.Ctx.PedersonCommitments.generateCommitment(value, bf); 
        return result;
    }	
  4. Pass the balance (as value) and blinding_factor (as blinding_factor) values from the second step to the generateCommitment method.
    Example:
    balance_commitment from step 1 :03977a92a07c00234270d41097a35ed2050bcdef02d3908a9a3cc733951b4171dd
    balance from step 2 : 100
    blinding_factor from step 2 : 17629824947682234000
     
    Invoke the method generateCommitment("100", "875628364246182")
    Response: "0212f6b676da244eee000a9106060cf3a3a4bb5a9b61be23dd467e557156c40be8"
  5. Verify that balance_commitment value from the first step matches the output of the generateCommitment method.
    Example:
    balance_commitment from step 1 :03977a92a07c00234270d41097a35ed2050bcdef02d3908a9a3cc733951b4171dd
    Response From Step 4: "03977a92a07c00234270d41097a35ed2050bcdef02d3908a9a3cc733951b4171dd"
     
    balance_commitment from step 1 must equal the generateCommitment response from step 4
    LHS = RHS
    
    This verifies that the Pederson commitment is correct against the raw balance and blindingFactor
  6. To verify an on-hold balance, repeat these steps for the onhold_balance Pedersen commitment and the onhold_balance and onHoldBalanceBlindingFactor values.

Verifying Transaction Quantities

  1. Use the following query to get the Pedersen commitment of the quantity, which is public data.
    SELECT JSON_VALUE(h."VALUEJSON", '$.amount') AS quantity_commitment
    FROM "<OBP_instance_name>_<channel>_hist" h
    WHERE h."CHAINCODEID" = '<chaincode_name>'
      AND h."KEY" = '<transaction_id>'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    The following text shows an example query.
    SELECT JSON_VALUE(h."VALUEJSON", '$.amount') AS quantity_commitment
    FROM "AdamsCentralBank_adams_hist" h
    WHERE h."CHAINCODEID" = 'confDev'
      AND h."KEY" = 'otransaction~d5e08934fd520554162d694476bae8521803e4bf7272e8709fe34dd3eeecbfe4'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    The following text shows an example response.
    quantity_commitment
    036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
  2. Use the following query to get the quantity and blinding factor from the private data collection.
    SELECT
        JSON_VALUE(h."VALUEJSON", '$.amount') AS quantity,
        JSON_VALUE(h."VALUEJSON", '$.blindingFactor') AS blinding_factor
    FROM "<OBP_instance_name>_<channel>_hist" h
    WHERE h."CHAINCODEID" = '<chaincode_name>$$_implicit_org_<OBP_instance_name>'
      AND h."KEY" = '<transaction_id>'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    The following text shows an example query.
    SELECT
        JSON_VALUE(h."VALUEJSON", '$.amount') AS quantity,
        JSON_VALUE(h."VALUEJSON", '$.blindingFactor') AS blinding_factor
    FROM "CentralBank_default_hist" h
    WHERE h."CHAINCODEID" = 'testChaincode$$_implicit_org_CentralBank'
      AND h."KEY" = 'otransaction~d5e08934fd520554162d694476bae8521803e4bf7272e8709fe34dd3eeecbfe4'
    ORDER BY h."BLOCKNO" DESC, h."TXNNO" DESC
    FETCH FIRST 1 ROW ONLY;
    The following text shows an example response.
    quantity blinding_factor
    100 17721346708393996000
  3. Add the generateCommitment method, defined previously, to the controller file located in the src folder (src/controller/<Chaincode_name>.controller.ts).
    Example:
    @Validator(yup.string(), yup.string()) 
    public async generateCommitment(value: string, bf: string) {
        await this. Ctx.Auth.checkAuthorization("ACCOUNT.processSendersAndReceivers", "TOKEN"); 
        const result = await this.Ctx.PedersonCommitments.generateCommitment(value, bf); 
        return result;
    }	
  4. Pass the quantity (as value) and blinding_factor (as blinding_factor) values from the second step to the generateCommitment method.
    Example:
    quantity_commitment from step 1 :036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
    quantity from step 2 : 100
    blinding_factor from step 2 : 17721346708393996000
     
    Invoke the method generateCommitment("100", "17721346708393996000")
    Response: "036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
  5. Verify that quantity_commitment value from the first step matches the output of the generateCommitment method.
    Example:
    quantity_commitment from step 1: 036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
    Response From Step 4: "036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
     
    balance_commitment from step 1 = response from step 4
    LHS = RHS
     
    This verifies that the Pederson commitment is correct against the raw quantity and blindingFactor

Auditing Account Balances

After you get the current actual balance_commitment and balance values and the blinding factor for the account as described previously, you can validate these values against the transaction history.

The example values we're starting with:
balance_commitment for account :036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
balance for account : 4600
blinding_factor for account : 6835208149283572992000
  1. Use the getAccountTransactionHistoryWithFiltersFromRichHistDB method to retrieve all transactions for the account. Each transaction has a unique transaction ID and corresponding entries of quantity_commitment (in the state database), and quantity and blinding factor (in the private data collection).
    The example response:
    [
        {
            "transaction_id": "otransaction~5112f576c94c2d23c342479bfa37e34612414b3258a64b43cf51b920f4ff5868",
            "transacted_amount": 5000,
            "timestamp": "2025-08-12T21:05:02.000Z",
            "token_id": "USD",
            "transacted_account": "oaccount~cea6080858337b1575d6a76ed0bd07a0eacd8871e3f2f7f793729a0e4b0e8e98",
            "transacted_org_id": "CentralBank",
            "transacted_user_id": "cb_retirer_demo",
            "transacted_custom_account_id": "10109999006543",
            "to_account": "oaccount~cea6080858337b1575d6a76ed0bd07a0eacd8871e3f2f7f793729a0e4b0e8e98",
            "to_org_id": "CentralBank",
            "to_user_id": "cb_retirer_demo",
            "to_custom_account_id": "10109999006543",
            "from_account": "oaccount~68d67712f500e9dac8c314c19744003a993250271d960e9b0d25267bb18dfe9a",
            "from_org_id": "CentralBank",
            "from_user_id": "cb_issuer_demo",
            "from_custom_account_id": "10109999001234",
            "transaction_type": "DEBIT",
            "category": "burn",
            "balance": 45000,
            "onhold_balance": 0
        },
        {
            "transaction_id": "otransaction~862aa9d9e877d3ea209b87299ab5b12c13ed5ce43d1cf1b934043c1dd02f58f6",
            "transacted_amount": 50000,
            "timestamp": "2025-08-12T21:04:22.000Z",
            "token_id": "USD",
            "transacted_account": "oaccount~da6e14466a0ba9b48ebc18fa672addb92dffc371bf953c3229a95b2ff2d9cd41",
            "transacted_org_id": "CentralBank",
            "transacted_user_id": "cb__creator_demo",
            "transacted_custom_account_id": "10105678004567",
            "to_account": "oaccount~68d67712f500e9dac8c314c19744003a993250271d960e9b0d25267bb18dfe9a",
            "to_org_id": "CentralBank",
            "to_user_id": "cb_issuer_demo",
            "to_custom_account_id": "10109999001234",
            "from_account": "oaccount~da6e14466a0ba9b48ebc18fa672addb92dffc371bf953c3229a95b2ff2d9cd41",
            "from_org_id": "CentralBank",
            "from_user_id": "cb__creator_demo",
            "from_custom_account_id": "10105678004567",
            "transaction_type": "CREDIT",
            "category": "transfer",
            "balance": 50000,
            "onhold_balance": 0
        },
        {
            "transaction_id": "otransaction~d209ff46dc46f4adb42f0002377507fe995b32bc618ac919eba49141cf1b8008",
            "transacted_amount": 100,
            "timestamp": "2025-08-01T10:59:48.000Z",
            "token_id": "token",
            "category": "category value",
            "description": "description value",
            "holding_id": "ohold~cbdc~token~mint1",
            "to_account_id": "oaccount~da6e14466a0ba9b48ebc18fa672addb92dffc371bf953c3229a95b2ff2d9cd41",
            "to_org_id": "CentralBank",
            "to_user_id": "cb",
            "to_custom_account_id": "10109999001234",
            "transacted_account": "oaccount~3a1b1c307883c0f74473fedfa62894d510b68959c4a21c7abb9d0224151aa573",
            "transaction_type": "APPROVE_MINT",
            "balance": 100,
            "onhold_balance": 0,
            "transacted_org_id": "CentralBank",
            "transacted_user_id": "cb__creator_demo",
            "transacted_custom_account_id": "1234567jh"
        }
    ]
  2. Follow the previous steps to verify each transaction quantity and ensure that the public and private data are synchronized. The following examples show transactions and the values used in the calculations from the previous verification steps.
    Transaction 1
    otransaction~d209ff46dc46f4adb42f0002377507fe995b32bc618ac919eba49141cf1b8008
    Values from the verification steps:
    quantity_commitment from step 1: 036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
    quantity from step 2: 100
    blinding_factor from step 2: 17721346708393996000
     
    Call the method generateCommitment("100", "17721346708393996000")
    Response: "036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
     
    quantity_commitment from step 1: 036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
    response from step 4: "036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
     
    balance_commitment from step 1 = response from step 4
    LHS = RHS
     
    This verifies that the Pedersen commitment is correct against the raw quantity and blindingFactor 
    Transaction 2
    otransaction~862aa9d9e877d3ea209b87299ab5b12c13ed5ce43d1cf1b934043c1dd02f58f6
    Values from the verification steps:
    quantity_commitment from step 1: dd63036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23
    quantity from step 2: 50000
    blinding_factor from step 2: 6789721346708393996000
     
    Call the method generateCommitment("50000", "6789721346708393996000")
    Response: "dd63036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23"
     
    quantity_commitment from step 1: dd63036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23
    Response from step 4: "dd63036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23"
     
    balance_commitment from step 1 = response from step 4
    LHS = RHS
     
    This verifies that the Pedersen commitment is correct against the raw quantity and blindingFactor
    Transaction 3
    otransaction~5112f576c94c2d23c342479bfa37e34612414b3258a64b43cf51b920f4ff5868
    Values from the verification steps:
    quantity_commitment from step 1: d28b5a08889921d71b658b592a4261bc76b17cf553c67de2943d769741f8f23dd63
    quantity from step 2: 5000
    blinding_factor from step 2: 39317721346708996000
     
    Call the method generateCommitment("5000", "39317721346708996000")
    Response: "d28b5a08889921d71b658b592a4261bc76b17cf553c67de2943d769741f8f23dd63"
     
    quantity_commitment from step 1: d28b5a08889921d71b658b592a4261bc76b17cf553c67de2943d769741f8f23dd63
    Response from step 4: "d28b5a08889921d71b658b592a4261bc76b17cf553c67de2943d769741f8f23dd63"
     
    balance_commitment from step 1 = response from step 4
    LHS = RHS
     
    This verifies that the Pedersen commitment is correct against the raw quantity and blindingFactor
  3. Iterate through the ordered list of transactions in the order that they took place and compute running totals for each property. For each transaction, complete the following steps.
    1. If the transaction is a credit (addition), combine the quantity_commitment property by using the addCommitment method. If the transaction is a debit (subtraction), combine the quantity_commitment property by using the subCommitment method.
    2. If the transaction is a credit, add the quantity property. If the transaction is a debit, subtract the quantity property.
    3. If the transaction is a credit, add the blinding_factor property. If the transaction is a debit, subtract the blinding_factor property.
    The following examples show processing the commitments, quantity, and blinding factor.
    Process commitments
    Starting balance_commitment: "2a4261d28b5a08889921d71b658b59bc76b17cf553c67de2943d769741f8f23dd63"
    
        For Transaction 1 using method
        addCommitment(
        "2a4261d28b5a08889921d71b658b59bc76b17cf553c67de2943d769741f8f23dd63", 
        "036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
        ) = "a1d71b658036b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
    
        current balance_commitment: "a1d71b658036b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
        Transaction 2 using method
        addCommitment(
        "a1d71b658036b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63", 
        "dd63036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23"
        ) = "b285a4261dd63036a1d71b658b592bc76da08b17cf553c67de2943d769741f8f23"
    
        current balance_commitment: "b285a4261dd63036a1d71b658b592bc76da08b17cf553c67de2943d769741f8f23"
        Transaction 3 using method
        subCommitment(
        "b285a4261dd63036a1d71b658b592bc76da08b17cf553c67de2943d769741f8f23", 
        "d28b5a08889921d71b658b592a4261bc76b17cf553c67de2943d769741f8f23dd63"
        ) = "036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
    
    Final commitment: "036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63"
    Process quantity
    starting balance: 0
    
        For Transaction 1 
        current_balance = 0 + 100 = 100
        current_balance = 100
        For Transaction 2
        new current_balance = 100 + 5000 = 5100
        current_balance = 5100
        For Transaction 3
        new current_balance = 5100 - 500 = 4600
    
    Final_balance = 4600
    Process blinding factor
    starting blindingFactor: 67083177213493996000
    
        For Transaction 1 
        current_blindingFactor = 67083177213493996000 + 17721346708393996000 = 84804523921887992000
        current_balance = 84804523921887992000
        For Transaction 2
        new current_blindingFactor = 84804523921887992000 + 6789721346708393996000 = 6874525870630281988000
        current_balance = 6874525870630281988000
        For Transaction 3
        new current_blindingFactor = 6874525870630281988000 - 39317721346708996000 = 6835208149283572992000
    
    Final_balance = 6835208149283572992000
  4. After processing all transactions, check that the following statements are true.
    • The quantity_commitment value matches the current Account.balance_commitment value
    • The quantity value matches the current Account.balance value
    • The blinding_factor value matches the current Account.blinding_factor value
    Example:
    Starting balance_commitment: 036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
    balance_commitment from step 3 :036a1d71b658b592a4261bc76d28b5a08b17cf553c67de2943d769741f8f23dd63
     
    Starting balance_commitment =  balance_commitment from step 3
    LHS = RHS
    The balance pederson commitment is verified.
      
    starting balance : 4600
    balance from step 3 : 4600
     
    starting balance =  balance for step 3
    LHS = RHS
    The balance verified. 
     
    starting blinding_factor  : 6835208149283572992000
    blinding_factor from step 3  : 6835208149283572992000
     
    starting blinding_factor =  blinding_factor for step 3
    LHS = RHS
    The blinding_factor is verified.