- Introduction
- Usage
- Definitions
- Elliptic Curve Parameters
- Ring Signature
- Borromean Ring Signature
- Asset ID Commitment
- Encrypted Asset ID
- Asset ID Descriptor
- Asset Range Proof
- Value Commitment
- Encrypted Value
- Value Descriptor
- Excess Factor
- Excess Commitment
- Value Proof
- Value Range Proof
- Record Encryption Key
- Intermediate Encryption Key
- Asset ID Encryption Key
- Value Encryption Key
- Asset ID Blinding Factor
- Value Blinding Factor
- Issuance Asset Range Proof
- Core algorithms
- Create Ring Signature
- Verify Ring Signature
- Create Borromean Ring Signature
- Verify Borromean Ring Signature
- Recover Payload From Borromean Ring Signature
- Encrypt Payload
- Decrypt Payload
- Create Nonblinded Asset ID Commitment
- Create Blinded Asset ID Commitment
- Encrypt Asset ID
- Decrypt Asset ID
- Create Asset Range Proof
- Verify Asset Range Proof
- Create Nonblinded Value Commitment
- Create Blinded Value Commitment
- Balance Blinding Factors
- Encrypt Value
- Decrypt Value
- Create Value Proof
- Verify Value Proof
- Create Value Range Proof
- Verify Value Range Proof
- Recover Payload From Value Range Proof
- Create Excess Commitment
- Verify Excess Commitment
- Verify Value Commitments Balance
- Create Transient Issuance Key
- Create Issuance Asset Range Proof
- Verify Issuance Asset Range Proof
- High-level procedures
- Integration
In Chain Protocol 2, asset IDs and amounts in transaction inputs and outputs can be kept private. These details are encrypted homomorphically: the network can verify that transactions are balanced (and, consequently, that the ledger is consistent) without learning exact asset IDs or amounts. Designated recipients and auditors share the encryption key that gives them “read access” to the asset ID and amount of a particular output.
Blinded amounts can be selectively revealed to the network in order to make them visible to smart contracts. The asset ID and the amount can be hidden or revealed independently enabling fine-grained privacy control.
Amounts can have absolute privacy, independent of the structure and history of any given transaction. Asset IDs are relatively private, meaning their privacy set is the union of the sets of possible asset IDs committed to by transaction inputs.
[[NOTES: Define absolute privacy. Define privacy set.]]
Cryptographic proofs for blinded asset IDs and blinded amounts require relatively large amounts of data (typically 3 to 5 KB). However, almost 80% of that space can be reused to encrypt a confidential message addressed to a designated recipient of the transaction output. The protocol specifies algorithms for encrypting and decrypting this data, along with parameters that allow the user creating the transaction to tune the size of the proofs trading off some of the privacy for lower bandwidth requirements (e.g. blinding a 32-bit amount requires half as much data compared to blinding a full-resolution 64-bit integer).
This scheme provides information-theoretic privacy, meaning that amounts and asset IDs would remain private even against an adversary with unbounded computational power, or a quantum computer that can efficiently solve the elliptic curve discrete logarithm problem (ECDLP). In other words, the scheme is perfectly hiding. As a necessary consequence, however, the scheme is not perfectly binding — if the ECDLP ceases to be computationally hard, a party could, in effect, freely change the asset ID or amount of blinded outputs. To protect against this possibility, the protocol defines provisional hash-based commitments to both asset ID and amount. If elliptic curve cryptography ceases to be secure, a protocol rule could be introduced (via a soft fork) that requires that transactions spending blinded outputs also publicly reveal values satisfying these hash-based commitments. The scheme allows keeping the encrypted message private even if the asset ID and amount are revealed.
In this section we will provide a brief overview of various ways to use confidential assets.
- Issuer chooses asset ID and an amount to issue.
- Issuer generates issuance REK unique for this issuance.
- Issuer chooses a set of other asset IDs to add into the issuance anonymity set.
- Issuer sorts the union of the issuance asset ID and anonymity set lexicographically.
- For each asset ID, where issuance program does not check an issuance key, issuer creates a transient issuance key.
- Issuer provides arguments for each issuance program of each asset ID.
- Issuer encrypts issuance: generates asset ID and value commitments and provides necessary range proofs.
- Issuer remembers values
(H,c,f)
to help complete the transaction. Once outputs are fully or partially specified, these values can be discarded. - Issuer proceeds with the rest of the transaction creation. See simple transfer and multi-party transaction for details.
- Recipient generates the following parameters and sends them privately to the sender:
- amount and asset ID to be sent,
- control program,
- REK1.
- Sender composes a transaction with an unencrypted output with a given control program.
- Sender adds necessary amount of inputs to satisfy the output:
- For each unspent output, sender pulls values
(assetid,value,H,c,f)
from its DB. - If the unspent output is not confidential, then:
H=8*Decode(SHA3(assetid))
, unblinded asset id commitmentc=0
f=0
- Values
(aek,vek)
can be discarded once the output is spent on the blockchain. These are kept for PQ event in case the spender will have to prove hash-based commitments toc
andf
blinding factors.
- For each unspent output, sender pulls values
- If sender needs to add a change output:
- Sender encrypts the first output.
- Sender balances blinding factors to create an excess factor
q
. - Sender adds unencrypted change output.
- Sender generates a REK2 for the change output.
- Sender encrypts the change output with an additional excess factor
q
.
- If sender does not need a change output:
- Sender balances blinding factors of the inputs to create an excess factor
q
. - Sender encrypts the first output with an additional excess factor
q
.
- Sender balances blinding factors of the inputs to create an excess factor
- Sender stores values
(assetid,value,H,c,f,aek,vek)
in its DB with its change output for later spending. - Sender publishes the transaction.
- Recipient receives the transaction and identifies its output via its control program.
- Recipient uses its REK1 to decrypt output.
- Recipient stores resulting
(assetid,value,H,c,f,aek,vek)
in its DB with its change output for later spending. - Recipient separately stores decrypted plaintext payload with the rest of the reference data. It is not necessary for spending.
- All parties communicate out-of-band payment details (how much is being paid for what), but not cryptographic material or control programs.
- Each party:
- Generates cleartext outputs: (amount, asset ID, control program, REK). These include both requested payment ("I want to receive €10") and the change ("I send back to myself $142").
- Encrypts each output.
- Balances blinding factors to create an excess factor
q[i]
. - For each output, stores values
(assetid,value,H,c,f,aek,vek)
associated with that output in its DB for later spending. - Sends
q[i]
to the party that finalizes transaction.
- Party that finalizes transaction:
- Receives
{q[i]}
values from all other parties (including itself). - Sums all excess factors:
qsum = ∑q[i]
- Creates excess commitment out of
qsum
:Q = qsum·G
and signs it. - Finalizes transaction by placing the excess commitment to the Common Fields.
- Publishes the transaction.
- Receives
- If the amounts and blinding factors are balanced, transaction is valid and included in the blockchain. Parties can not see each other’s outputs, but only their own.
The elliptic curve is edwards25519 as defined by [RFC7748].
Elliptic curve point operations A+B
, A-B
and scalar multiplication a·B
are defined as in [CFRG1].
Encoding for 32-byte scalars and public keys is defined as in [CFRG1].
L
is the order of edwards25519 as defined by [CFRG1] (i.e. 2252+27742317777372353535851937790883648493).
G
is the standard generator point on the elliptic curve specified as "B" in Section 5.1 of [CFRG1].
Ring signature is a variable-length string representing a signature of knowledge of a one private key among an ordered set of public keys (specified separately). In other words, ring signature implements an OR function of the public keys: “I know the private key for A, or B or C”. Ring signatures are used in asset range proofs.
The ring signature is encoded as a string of n+1
32-byte elements where n
is the number of public keys provided separately (typically stored or imputed from the data structure containing the ring signature):
{e, s[0], s[1], ..., s[n-1]}
Each 32-byte element is an integer coded using little endian convention. I.e., a 32-byte string x
x[0],...,x[31]
represents the integer x[0] + 2^8 · x[1] + ... + 2^248 · x[31]
.
Borromean ring signature ([Maxwell2015]) is a data structure representing several ring signatures compactly joined with an AND function of the ring signatures: “I know the private key for (A or B) and (C or D)”. Borromean ring signatures are used in value range proofs that prove the range of multiple digits at once.
The borromean ring signature is encoded as a sequence of 32-byte elements.
{e, s[i,j]...}
Where:
i
is in range0..n
wheren
is the number of rings.j
is in range0..m
wherem
is the number of signatures per ring.
Example: a value range proof for a 4-bit mantissa has 9 elements in its borromean ring signature:
{
e,
s[0,0], s[0,1], s[0,2], s[0,3], # base-4 digit at position 0 (proof for the lower two bits)
s[1,0], s[1,1], s[1,2], s[1,3], # base-4 digit at position 1 (proof for the higher two bits)
}
An asset ID commitment H
is a point on Curve25519 encoded as a 32-byte string as specified in [CFRG1].
The asset ID commitment can either be nonblinded (clear) or blinded (confidential):
Note: even if the asset ID is provided in the clear, the corresponding nonblinded asset ID commitment is necessary for algorithms that validate the transaction as a whole.
Asset ID commitments are pedersen commitments as described in [[CITATION]].
A 64-byte string consisting of two encrypted elements: asset ID and its blinding factor (32 bytes each).
These values are present in the output commitment along with the asset range proof. The encrypted asset ID can be decrypted and verified by the recipient against the declared asset ID commitment. It also serves as an additional hash-based commitment in case ECDLP ceases to be computationally infeasible.
Asset ID Descriptor is a data structure that contains either a cleartext asset ID, or a pair of asset ID commitment with encrypted asset ID. Asset ID Descriptors represent asset ID in outputs and issuance inputs.
Asset ID Descriptor may contain nonblinded, blinded or blinded+encrypted asset ID as indicated by its 1-byte field type
.
Field | Type | Description |
---|---|---|
Type | byte | Contains value 0x00 if asset ID is not blinded. |
Asset ID | sha3-256 | Cleartext asset ID. |
Field | Type | Description |
---|---|---|
Type | byte | Contains value 0x01 if asset ID is blinded, but encrypted portion is not stored (used in issuance inputs). |
Asset ID Commitment | Asset ID Commitment | 32-byte public key representing asset ID commitment. |
Field | Type | Description |
---|---|---|
Type | byte | Contains value 0x03 if asset ID is both blinded and encrypted. |
Asset ID Commitment | Asset ID Commitment | 32-byte public key representing asset ID commitment. |
Encrypted Asset ID | Encrypted Asset ID | 64-byte sequence representing encrypted asset ID (32 bytes) and its blinding factor (32 bytes). |
The asset range proof demonstrates that a given asset ID commitment commits to one of the asset IDs specified in the transaction inputs. A separate validation procedure makes sure that all of the declared asset ID commitments in fact belong to the transaction inputs.
Field | Type | Description |
---|---|---|
Asset ID Commitments Count | varint31 | Number of input asset ID commitments used in the range proof. |
Asset ID Commitments | [Asset ID Commitment] | List of asset ID commitments from the transaction inputs. |
Asset Ring Signature | Ring Signature | A ring signature proving that the asset ID committed in the output belongs to the set of declared input commitments. |
Value pedersen commitment is a point on Curve25519 encoded as a 32-byte string as specified in [CFRG1].
Cleartext value commitment is simply a value multiplied by the asset ID commitment:
V = value·H
Confidential value commitment also contains a blinding factor f
:
V = value·H + f·G
Where:
V
is the value commitment,value
is the 64-bit integer representing the amount,H
is an asset ID commitment,f
is a value blinding factor (could be different from the blinding integer in the asset ID commitment),G
is the standard generator point on the elliptic curve specified as "B" in Section 5.1 of [CFRG1].
Blinded value commitments in transaction outputs created individually using Create Blinded Value Commitment algorithm. Balancing excess commitment is created using Balance Blinding Factors algorithm.
A 40-byte string consisting of two encrypted elements: amount (8 bytes) and value blinding factor (32 bytes).
These values are present in the output commitment along with the value range proof. Encrypted value can be decrypted and verified by the recipient against the value commitment. It also serves as an additional hash-based commitment in case ECDLP ceases to be computationally infeasible.
Value Descriptor is a data structure that contains either a cleartext asset ID, or a pair of value commitment with encrypted value. Value Descriptors represent amounts in outputs and issuance inputs.
Value Descriptor may contain nonblinded, blinded or blinded+encrypted value as indicated by its 1-byte field type
.
Field | Type | Description |
---|---|---|
Type | byte | Contains value 0x00 if amount is not blinded. |
Amount | varint63 | Cleartext amount. |
Field | Type | Description |
---|---|---|
Type | byte | Contains value 0x01 if the amount is blinded, but encrypted portion is not stored (used in issuance inputs). |
Value Commitment | Value Commitment | 32-byte public key representing value commitment. |
Field | Type | Description |
---|---|---|
Type | byte | Contains value 0x03 if the amount is both blinded and encrypted. |
Value Commitment | Value Commitment | 32-byte public key representing value commitment. |
Encrypted Value | Encrypted Value | 40-byte sequence representing encrypted value (8 bytes) and its blinding factor (32 bytes). |
Excess factor is a scalar value representing a net difference between input and output blinding factors. It is computed using Balance Blinding Factors and used to create an Excess Commitment.
Excess commitment is a 96-byte string encoding 3 elements: a public key Q = q·G
and two 32-byte elements comprising a Schnorr signature (e, s)
: s = nonce + q·e; e = SHA3-256(Q || nonce·G)
.
Excess public key Q
is used to verify balance of value commitments while the associated signature proves that Q
does not contain a factor affecting the amount of any asset (see Verify Excess Commitment).
Value proof demonstrates that a given value commitment encodes a specific value and asset ID. It is used to privately prove the contents of an output without revealing blinding factors.
Value range proof demonstrates that a value commitment encodes a value between 0 and 263–1. The 63-bit limit is chosen for consistency with the numeric limits defined for the asset version 1 outputs and VM version 1 numbers.
For the most compact encoding, value range proof uses base-4 digits represented by 4-key ring signatures proving the value of each pair of bits. If the number of bits is odd, the last ring signature contains only 2 elements proving the value of the highest-order bit. All ring signatures share the same e-value (see below) forming a so-called "borromean ring signature".
Value range proof allows a space-privacy tradeoff by making a smaller number of bits confidential while exposing a "minimum value" and a decimal exponent. The complete value is broken down in the following components:
value = vmin + (10^exp)·(d[0]·(4^0) + ... + d[m-1]·(4^(m-1)))
Where di is the i’th digit in a m-digit mantissa (that has either 2·m–1 or 2·m bits). Exponent exp
and the minimum value vmin
are public and by default set to zero by the user creating the transaction.
Field | Type | Description |
---|---|---|
Number of bits | byte | Integer n indicating number of confidential mantissa bits between 1 and 63. |
Exponent | byte | Integer exp indicating the decimal exponent from 0 to 10. |
Minimum value | varint63 | Minimum value vmin from 0 to 263–1. |
Digit commitments | [pubkey] | List of (n+1)/2 – 1 individual digit pedersen commitments where n is the number of mantissa bits. |
Borromean Ring Signature | Borromean Ring Signature | List of all 32-byte elements comprising all ring signatures proving the value of each digit. |
The total number of elements in the Borromean Ring Signature is 1 + 4·n/2
where n
is number of bits and n/2
is a number of rings.
Record encryption key (REK or rek
) is a cryptographically-random 32-byte string unique to a given transaction output.
It is used to decrypt the payload data from the value range proof, and derive asset ID encryption key and value encryption key.
Intermediate encryption key (IEK or iek
) allows decrypting the asset ID and the value in the output commitment. It is derived from the record encryption key as follows:
iek = SHA3-256(0x00 || rek)
Asset ID encryption key (AEK or aek
) allows decrypting the asset ID in the output commitment. It is derived from the intermediate encryption key as follows:
aek = SHA3-256(0x00 || iek)
Value encryption key (VEK or vek
) allows decrypting the amount in the output commitment. It is derived from the intermediate encryption key as follows:
vek = SHA3-256(0x01 || iek)
An integer c
used to produce a blinded asset ID commitment out of a cleartext asset ID commitment:
H = A + c·G
The asset ID blinding factor is created by Create Blinded Asset ID Commitment.
An integer f
used to produce a value commitment out of the asset ID commitment:
V = value·H + f·G
The value blinding factors are created by Create Blinded Value Commitment algorithm.
The issuance asset range proof demonstrates that a given confidential issuance commits to one of the asset IDs specified in the transaction inputs. It contains a ring signature. The other inputs to the verification procedure are computed from other elements in the confidential issuance witness, as part of the validation procedure.
The size of the ring signature (n+1
32-byte elements) and the number of issuance keys (n
) are derived from n
asset issuance choices specified outside the range proof.
Field | Type | Description |
---|---|---|
Issuance Ring Signature | Ring Signature | A ring signature proving that the issuer of an encrypted asset ID approved the issuance. |
Issuance Keys | [Public Key] | Keys to be used to calculate the public key for the corresponding index in the ring signature. |
VM Version | varint63 | Version of the VM that executes the issuance signature program. |
Issuance Signature Program | varstring31 | Predicate committed to by the issuance asset range proof, which is evaluated to ensure that the transaction is authorized. |
Program Arguments Count | varint31 | Number of program arguments that follow. |
Program Arguments | [varstring31] | Data passed to the issuance signature program. |
Inputs:
msg
: the 32-byte string to be signed.{P[i]}
:n
public keys, points on the elliptic curve.j
: the index of the designated public key, so thatP[j] == p·G
.p
: the private key for the public keyP[j]
.
Output: {e0, s[0], ..., s[n-1]}
: the ring signature, n+1
32-byte elements.
Algorithm:
- Let
counter = 0
. - Calculate a sequence of:
n-1
32-byte random values, 64-bytenonce
and 1-bytemask
:{r[i], nonce, mask} = SHAKE256(counter || msg || p || j || P[0] || ... || P[n-1], 8·(32·(n-1) + 64 + 1))
, where:counter
is encoded as a 64-bit little-endian integer,p
is encoded as a 256-bit little-endian integer,j
is encoded as a 64-bit little-endian integer,- points
P[i]
are encoded as public keys.
- Calculate
k = nonce mod L
, wherenonce
is interpreted as a 64-byte little-endian integer and reduced modulo subgroup orderL
. - Calculate the initial e-value, let
i = j+1 mod n
:- Calculate
R[i]
as the pointk·G
and encode it as a 32-byte public key. - Define
w[j]
asmask
with lower 4 bits set to zero:w[j] = mask & 0xf0
. - Calculate
e[i] = SHA3-512(R[i] || msg || i || w[j])
wherei
is encoded as a 64-bit little-endian integer. Interprete[i]
as a little-endian integer reduced moduloL
.
- Calculate
- For
step
from1
ton-1
(these steps are skipped ifn
equals 1):- Let
i = (j + step) mod n
. - Calculate the forged s-value
s[i] = r[step-1]
, wherer[j]
is interpreted as a 64-byte little-endian integer and reduced moduloL
. - Define
z[i]
ass[i]
with the most significant 4 bits set to zero. - Define
w[i]
as a most significant byte ofs[i]
with lower 4 bits set to zero:w[i] = s[i][31] & 0xf0
. - Let
i’ = i+1 mod n
. - Calculate
R[i’] = z[i]·G - e[i]·P[i]
and encode it as a 32-byte public key. - Calculate
e[i’] = SHA3-512(R[i’] || msg || i’ || w[i])
wherei’
is encoded as a 64-bit little-endian integer. Interprete[i’]
as a little-endian integer reduced moduloL
.
- Let
- Calculate the non-forged
z[j] = k + p·e[j] mod L
and encode it as a 32-byte little-endian integer. - If
z[j]
is greater than 2252–1, then increment thecounter
and try again from the beginning. The chance of this happening is below 1 in 2124. - Define
s[j]
asz[j]
with 4 high bits set to high 4 bits of themask
. - Return the ring signature
{e[0], s[0], ..., s[n-1]}
, totaln+1
32-byte elements.
Inputs:
msg
: the 32-byte string being signed.e[0], s[0], ... s[n-1]
: ring signature consisting ofn+1
32-byte little-endian integers.{P[i]}
:n
public keys, points on the elliptic curve.
Output: true
if the verification succeeded, false
otherwise.
Algorithm:
- For each
i
from0
ton-1
:- Define
z[i]
ass[i]
with the most significant 4 bits set to zero (see note below). - Define
w[i]
as a most significant byte ofs[i]
with lower 4 bits set to zero:w[i] = s[i][31] & 0xf0
. - Calculate
R[i+1] = z[i]·G - e[i]·P[i]
and encode it as a 32-byte public key. - Calculate
e[i+1] = SHA3-512(R[i+1] || msg || i+1 || w[i])
wherei+1
is encoded as a 64-bit little-endian integer. - Interpret
e[i+1]
as a little-endian integer reduced modulo subgroup orderL
.
- Define
- Return true if
e[0]
equalse[n]
, otherwise return false.
Note: When the s-values are decoded as little-endian integers we must set their 4 most significant bits to zero in order to restore the original scalar as produced while creating the range proof. During signing the non-forged s-value has its 4 most significant bits set to random bits to make it indistinguishable from the forged s-values.
Inputs:
msg
: the 32-byte string to be signed.n
: number of rings.m
: number of signatures in each ring.{P[i,j]}
:n·m
public keys, points on the elliptic curve.{p[i]}
: the list ofn
scalars representing private keys.{j[i]}
: the list ofn
indexes of the designated public keys within each ring, so thatP[i,j] == p[i]·G
.{payload[i]}
: sequence ofn·m
random 32-byte elements.
Output: {e0, s[0,0], ..., s[i,j], ..., s[n-1,m-1]}
: the borromean ring signature, n·m+1
32-byte elements.
Algorithm:
- Let
counter = 0
. - Let
cnt
byte contain lower 4 bits ofcounter
:cnt = counter & 0x0f
. - Calculate a sequence of
n·m
32-byte random overlay values:{o[i]} = SHAKE256(counter || msg || {p[i]} || {j[i]} || {P[i,j]}, 8·(32·n·m))
, where:counter
is encoded as a 64-bit little-endian integer,- private keys
{p[i]}
are encoded as concatenation of 256-bit little-endian integers, - secret indexes
{j[i]}
are encoded as concatenation of 64-bit little-endian integers, - points
{P[i]}
are encoded as concatenation of public keys.
- Define
r[i] = payload[i] XOR o[i]
for alli
from 0 ton·m - 1
. - For
t
from0
ton-1
(each ring):- Let
j = j[t]
- Let
x = r[m·t + j]
interpreted as a little-endian integer. - Define
k[t]
as the lower 252 bits ofx
. - Define
mask[t]
as the higher 4 bits ofx
. - Define
w[t,j]
as a byte with lower 4 bits set to zero and higher 4 bits equalmask[t]
. - Calculate the initial e-value for the ring:
- Let
j’ = j+1 mod m
. - Calculate
R[t,j’]
as the pointk[t]·G
and encode it as a 32-byte public key. - Calculate
e[t,j’] = SHA3-512(cnt, R[t, j’] || msg || t || j’ || w[t,j])
wheret
andj’
are encoded as 64-bit little-endian integers. Interprete[t,j’]
as a little-endian integer reduced moduloL
.
- Let
- If
j ≠ m-1
, then fori
fromj+1
tom-1
:- Calculate the forged s-value:
s[t,i] = r[m·t + i]
. - Define
z[t,i]
ass[t,i]
with 4 most significant bits set to zero. - Define
w[t,i]
as a most significant byte ofs[t,i]
with lower 4 bits set to zero:w[t,i] = s[t,i][31] & 0xf0
. - Let
i’ = i+1 mod m
. - Calculate point
R[t,i’] = z[t,i]·G - e[t,i]·P[t,i]
and encode it as a 32-byte public key. - Calculate
e[t,i’] = SHA3-512(cnt, R[t,i’] || msg || t || i’ || w[t,i])
wheret
andi’
are encoded as 64-bit little-endian integers. Interprete[t,i’]
as a little-endian integer reduced moduloL
.
- Calculate the forged s-value:
- Let
- Calculate the shared e-value
e0
for all the rings:- Calculate
E
as concatenation of alle[t,0]
values encoded as 32-byte little-endian integers:E = e[0,0] || ... || e[n-1,0]
. - Calculate
e0 = SHA3-512(E)
. Interprete0
as a little-endian integer reduced moduloL
. - If
e0
is greater than 2252–1, then increment thecounter
and try again from step 2. The chance of this happening is below 1 in 2124.
- Calculate
- For
t
from0
ton-1
(each ring):- Let
j = j[t]
. - Let
e[t,0] = e0
. - If
j
is not zero, then fori
from0
toj-1
:- Calculate the forged s-value:
s[t,i] = r[m·t + i]
. - Define
z[t,i]
ass[t,i]
with 4 most significant bits set to zero. - Define
w[t,i]
as a most significant byte ofs[t,i]
with lower 4 bits set to zero:w[t,i] = s[t,i][31] & 0xf0
. - Let
i’ = i+1 mod m
. - Calculate point
R[t,i’] = z[t,i]·G - e[t,i]·P[t,i]
and encode it as a 32-byte public key. Ifi
is zero, usee0
in place ofe[t,0]
. - Calculate
e[t,i’] = SHA3-512(cnt, R[t,i’] || msg || t || i’ || w[t,i])
wheret
andi’
are encoded as 64-bit little-endian integers. Interprete[t,i’]
as a little-endian integer reduced modulo subgroup orderL
.
- Calculate the forged s-value:
- Calculate the non-forged
z[t,j] = k[t] + p[t]·e[t,j] mod L
and encode it as a 32-byte little-endian integer. - If
z[t,j]
is greater than 2252–1, then increment thecounter
and try again from step 2. The chance of this happening is below 1 in 2124. - Define
s[t,j]
asz[t,j]
with 4 high bits set tomask[t]
bits.
- Let
- Set lower 4 bits of
counter
to top 4 bits ofe0
. - Return the borromean ring signature:
{e,s[t,j]}
:n·m+1
32-byte elements.
Inputs:
msg
: the 32-byte string to be signed.n
: number of rings.m
: number of signatures in each ring.{P[i,j]}
:n·m
public keys, points on the elliptic curve.{e0, s[0,0], ..., s[i,j], ..., s[n-1,m-1]}
: the borromean ring signature,n·m+1
32-byte elements.
Output: true
if the verification succeeded, false
otherwise.
Algorithm:
- Define
E
to be an empty binary string. - Set
cnt
byte to the value of top 4 bits ofe0
:cnt = e0[31] >> 4
. - Set top 4 bits of
e0
to zero. - For
t
from0
ton-1
(each ring):- Let
e[t,0] = e0
. - For
i
from0
tom-1
(each item):- Calculate
z[t,i]
ass[t,i]
with the most significant 4 bits set to zero. - Calculate
w[t,i]
as a most significant byte ofs[t,i]
with lower 4 bits set to zero:w[t,i] = s[t,i][31] & 0xf0
. - Let
i’ = i+1 mod m
. - Calculate point
R[t,i’] = z[t,i]·G - e[t,i]·P[t,i]
and encode it as a 32-byte public key. Usee0
instead ofe[t,0]
in each ring. - Calculate
e[t,i’] = SHA3-512(cnt || R[t,i’] || msg || t || i’ || w[t,i])
wheret
andi’
are encoded as 64-bit little-endian integers. - Interpret
e[t,i’]
as a little-endian integer reduced modulo subgroup orderL
.
- Calculate
- Append
e[t,0]
toE
:E = E || e[t,0]
, wheree[t,0]
is encoded as a 32-byte little-endian integer.
- Let
- Calculate
e’ = SHA3-512(E)
and interpret it as a little-endian integer reduced modulo subgroup orderL
, and then encoded as a little-endian 32-byte integer. - Return
true
ife’
equals toe0
. Otherwise, returnfalse
.
Inputs:
msg
: the 32-byte string to be signed.n
: number of rings.m
: number of signatures in each ring.{P[i,j]}
:n·m
public keys, points on the elliptic curve.{p[i]}
: the list ofn
scalars representing private keys.{j[i]}
: the list ofn
indexes of the designated public keys within each ring, so thatP[i,j] == p[i]·G
.{e0, s[0,0], ..., s[i,j], ..., s[n-1,m-1]}
: the borromean ring signature,n·m+1
32-byte elements.
Output: {payload[i]}
list of n·m
random 32-byte elements or nil
if signature verification failed.
Algorithm:
- Define
E
to be an empty binary string. - Set
cnt
byte to the value of top 4 bits ofe0
:cnt = e0[31] >> 4
. - Let
counter
integer equalcnt
. - Calculate a sequence of
n·m
32-byte random overlay values:{o[i]} = SHAKE256(counter || msg || {p[i]} || {j[i]} || {P[i,j]}, 8·(32·n·m))
, where:counter
is encoded as a 64-bit little-endian integer,- private keys
{p[i]}
are encoded as concatenation of 256-bit little-endian integers, - secret indexes
{j[i]}
are encoded as concatenation of 64-bit little-endian integers, - points
{P[i]}
are encoded as concatenation of public keys.
- Set top 4 bits of
e0
to zero. - For
t
from0
ton-1
(each ring):- Let
e[t,0] = e0
. - For
i
from0
tom-1
(each item):- Calculate
z[t,i]
ass[t,i]
with the most significant 4 bits set to zero. - Calculate
w[t,i]
as a most significant byte ofs[t,i]
with lower 4 bits set to zero:w[t,i] = s[t,i][31] & 0xf0
. - If
i
is equal toj[t]
:- Calculate
k[t] = z[t,i] - p[t]·e[t,i] mod L
. - Set top 4 bits of
k[t]
to the top 4 bits ofw[t,i]
:k[t][31] |= w[t,i]
. - Set
payload[m·t + i] = o[m·t + i] XOR k[t]
.
- Calculate
- If
i
is not equal toj[t]
:- Set
payload[m·t + i] = o[m·t + i] XOR s[t,i]
.
- Set
- Let
i’ = i+1 mod m
. - Calculate point
R[t,i’] = z[t,i]·G - e[t,i]·P[t,i]
and encode it as a 32-byte public key. Usee0
instead ofe[t,0]
in each ring. - Calculate
e[t,i’] = SHA3-512(cnt || R[t,i’] || msg || t || i’ || w[t,i])
wheret
andi’
are encoded as 64-bit little-endian integers. - Interpret
e[t,i’]
as a little-endian integer reduced modulo subgroup orderL
.
- Calculate
- Append
e[t,0]
toE
:E = E || e[t,0]
, wheree[t,0]
is encoded as a 32-byte little-endian integer.
- Let
- Calculate
e’ = SHA3-512(E)
and interpret it as a little-endian integer reduced modulo subgroup orderL
, and then encoded as a little-endian 32-byte integer. - Return
payload
ife’
equals toe0
. Otherwise, returnnil
.
Inputs:
n
: number of 32-byte elements in the plaintext to be encrypted.{pt[i]}
: list ofn
32-byte elements of plaintext data.ek
: the encryption/authentication key unique to this payload.
Output: the {ct[i]}
: list of n
32-byte ciphertext elements, where the last one is a 32-byte MAC.
Algorithm:
- Calculate a keystream, a sequence of 32-byte random values:
{keystream[i]} = SHAKE256(ek, 8·(32·n))
. - Encrypt the plaintext payload:
{ct[i]} = {pt[i] XOR keystream[i]}
. - Calculate MAC:
mac = SHA3-256(ek || ct[0] || ... || ct[n-1])
. - Return a sequence of
n+1
32-byte elements:{ct[0], ..., ct[n-1], mac}
.
Inputs:
n
: number of 32-byte elements in the ciphertext to be decrypted.{ct[i]}
: list ofn+1
32-byte ciphertext elements, where the last one is MAC (32 bytes).ek
: the encryption/authentication key.
Output: the {pt[i]}
or nil
, if authentication failed.
Algorithm:
- Calculate MAC’:
mac’ = SHA3-256(ek || ct[0] || ... || ct[n-1])
. - Extract the transmitted MAC:
mac = ct[n]
. - Compare calculated
mac’
with the receivedmac
. If they are not equal, returnnil
. - Calculate a keystream, a sequence of 32-byte random values:
{keystream[i]} = SHAKE256(ek, 8·(32·n))
. - Decrypt the plaintext payload:
{pt[i]} = {ct[i] XOR keystream[i]}
. - Return
{pt[i]}
.
Input: the cleartext asset ID assetID
.
Output: the asset ID commitment encoded as a public key.
Algorithm:
- Let
counter = 0
. - Calculate
SHA3-256(assetID || counter)
wherecounter
is encoded as a 64-bit unsigned integer using little-endian convention. - Decode the resulting hash as a point
P
on the elliptic curve. - If the point is invalid, increment
counter
and go back to step 2. This will happen on average for half of the asset IDs. - Calculate point
A = 8·P
(8 is a cofactor in edwards25519) which belongs to a subgroup ofG
with orderL
. - Return
A
.
Inputs:
assetID
: the cleartext asset ID.aek
: the asset ID encryption key.
Outputs: (H,c)
: the new asset ID commitment and its blinding factor such that H == A + c·G
.
Algorithm:
- Created non-blinded asset ID commitment:
A = 8·SHA3-256(assetID || counter)
. - Calculate
secret = SHA3-512(assetID || aek)
. - Calculate asset ID blinding factor
c
by reducing thesecret
modulo subgroup orderL
:c = secret mod L
. - Calculate blinded asset ID commitment:
H = A + c·G
and encode it as public key. - Return
(H,c)
.
Inputs:
assetID
: the asset ID.H
: the asset ID commitment hiding theassetID
.c
: the asset ID blinding factor for the commitmentH
such thatH == 8·SHA3-256(assetID || counter) + c·G
.aek
: the asset ID encryption key.
Output: (ea,ec)
, the encrypted asset ID including the encrypted blinding factor for H
.
Algorithm:
- Expand the encryption key:
ek = SHA3-512(aek || H)
, split the resulting hash in two halves. - Encrypt the asset ID using the first half:
ea = assetID XOR ek[0,32]
. - Encrypt the blinding factor using the second half:
ec = c XOR ek[32,32]
wherec
is encoded as a 256-bit little-endian integer. - Return
(ea,ec)
.
Note: the encrypted pair also acts as a hash-based commitment to plaintext values (provided hash function is collision-resistant).
Inputs:
H
: the asset ID commitment that obfuscates the asset ID.(ea,ec)
: the encrypted asset ID including the encrypted blinding factor forH
.aek
: the asset ID encryption key.
First two inputs must be proven to be committed to a well-formed transaction.
Outputs: (assetID,c)
: decrypted and verified asset ID with its blinding factor, or nil
if verification failed.
Algorithm:
- Expand the encryption key:
ek = SHA3-512(aek || H)
, split the resulting hash in two halves. - Decrypt the asset ID using the first half:
assetID = ea XOR ek[0,32]
. - Decrypt the blinding factor using the second half:
c = ec XOR ek[32,32]
. - Calculate
A
as a nonblinded asset ID commitment: an elliptic curve point8·decode(SHA3-256(assetID || counter))
. - Calculate point
P = A + c·G
wherec
is interpreted as a little-endian 256-bit integer. - Verify that
P
equals target commitmentH
. If not, halt and returnnil
. - Return
(assetID, c)
.
Inputs:
H’
: the output asset ID commitment for which the range proof is being created.(ea,ec)
: the encrypted asset ID including the encrypted blinding factor forH’
.{H[i]}
:n
candidate asset ID commitments.j
: the index of the designated commitment among the input asset ID commitments, so thatH’ == H[j] + (c’ - c)·G
.c’
: the blinding factor for the commitmentH’
.c
: the blinding factor for the candidate commitmentH[j]
.
Output: an asset range proof consisting of a list of input asset ID commitments and a ring signature.
Algorithm:
- Calculate the message to sign:
msg = SHA3-256(0x55 || H’ || H[0] || ... || H[n-1] || ea || ec)
. - Calculate the set of public keys for the ring signature from the set of input asset ID commitments:
P[i] = H’ - H[i]
. - Calculate the private key:
p = c’ - c mod L
. - Create a ring signature using
msg
,{P[i]}
,j
, andp
. - Return the list of asset ID commitments
{H[i]}
and the ring signaturee[0], s[0], ... s[n-1]
.
Note: unlike the value range proof, this ring signature is not used to store encrypted payload data because decrypting it would reveal the asset ID of one of the inputs to the recipient.
Inputs:
H’
: the target asset ID commitment.(ea,ec)
: the encrypted asset ID including the encrypted blinding factor forH’
.- The to-be-verified asset range proof consisting of:
{H[i]}
:n
input asset ID commitments.e[0], s[0], ... s[n-1]
: the ring signature.
Output: true
if the verification succeeded, false
otherwise.
Algorithm:
- Calculate
msg = SHA3-256(0x55 || H’ || H[0] || ... || H[n-1] || ea || ec)
. - Calculate the set of public keys for the ring signature from the set of input asset ID commitments:
P[i] = H’ - H[i]
. - Verify the ring signature
e[0], s[0], ... s[n-1]
withmsg
and{P[i]}
. - Return true if verification was successful, and false otherwise.
Inputs:
value
: the cleartext amount,H
: the asset ID commitment.
Output: the commitment V
encoded as public key.
Algorithm:
- Calculate
V = value·H
. - Return
V
.
Inputs:
vek
: the value encryption key for the given output,value
: the amount to be blinded in the output,H
: the asset ID commitment in the output,
Output: (V, f)
: the tuple of a value commitment and its blinding factor.
Algorithm:
- Calculate
fbuf = SHA3-512(0xbf || vek)
. - Calculate
f
asfbuf
interpreted as a little-endian integer reduced modulo subgroup orderL
:f = fbuf mod L
. - Calculate point
V = value·H + f·G
. - Return
(V, f)
, whereV
is encoded as a public key and the blinding factorf
is encoded as a 256-bit little-endian integer.
Inputs:
- The list of
n
input tuples{(value[j], c[j], f[j])}
, where:value[j]
: the amount blinded in the j-th input,c[j]
: the blinding factor in the j-th input (so thatH[j] = A[j] + c[j]·G
),f[j]
: the value blinding factor used in the j-th input (so thatV[j] = value[j]·H[j] + f[j]·G
).
- The list of
m
output tuples{(value’[i], c’[i], f’[i])}
, where:value’[i]
: the amount blinded in the i-th output,c’[i]
: the blinding factor in the i-th output (so thatH’[i] = A’[i] + c’[i]·G
),f’[i]
: the value blinding factor used in the i-th output (so thatV’[i] = value’[i]·H’[i] + f’[i]·G
).
Output: q
: the excess blinding factor that must be added to the output blinding factors in order to balance inputs and outputs.
Algorithm:
- Calculate the sum of input blinding factors:
Finput = ∑(value[j]·c[j]+f[j], j from 0 to n-1) mod L
. - Calculate the sum of output blinding factors:
Foutput = ∑(value’[i]·c’[i]+f’[i], i from 0 to m-1) mod L
. - Calculate excess blinding factor as difference between input and output sums:
q = Finput - Foutput mod L
. - Return
q
.
Inputs:
V
: the value commitment.value
: the 64-bit amount being encrypted and blinded.f
: the value blinding factor.vek
: the value encryption key.
Output: (ev,ef)
, the encrypted value including its blinding factor.
Algorithm:
- Expand the encryption key:
ek = SHA3-512(vek || V)
, split the resulting hash in two halves. - Encrypt the value using the first half:
ev = value XOR ek[0,8]
. - Encrypt the value blinding factor using the second half:
ef = f XOR ek[8,32]
wheref
is encoded as 256-bit little-endian integer. - Return
(ev, ef)
.
Inputs:
V
: the full value commitment.H’
: the target asset ID commitment that obfuscates the asset ID.(ev,ef)
: the encrypted value including its blinding factor.vek
: the value encryption key.
First three inputs must be proven to be committed to a well-formed transaction.
Output: (value, f)
: decrypted and verified amount and the value blinding factor; or nil
if verification did not succeed.
Algorithm:
- Expand the encryption key:
ek = SHA3-512(vek || V)
, split the resulting hash in two halves. - Decrypt the value using the first half:
value = ev XOR ek[0,8]
. - Decrypt the value blinding factor using the second half:
f = ef XOR ek[8,32]
wheref
is encoded as 256-bit little-endian integer. - Calculate
P = value·H’ + f·G
. - Verify that
P
equalsV
. If not, halt and returnnil
. - Return
(value, f)
.
TBD.
- Take
value, assetid, c, f
. - Compute
q = value*c + f
- Compute excess commitment
(Q,e,s)
fromq
(pubkey with signature). - Return
value, assetid, Q,e,s
.
TBD.
- Take
value,assetid,Q,e,s
. - Verify excess commitment
Q,e,s
. - Compute nonblinded asset commitment:
A = 8*Decode(SHA3(assetid))
. - Compute nonblinded value commitment:
V’ = value*A
. - Add point
Q
toV’
:V’ = V’+Q
. - Verify that
V’
equalsV
in the given output.
Inputs:
H’
: the asset ID commitment.V
: the value commitment.(ev,ef)
: the encrypted value including its blinding factor.N
: the number of bits to be blinded.value
: the 64-bit amount being encrypted and blinded.{pt[i]}
: plaintext payload string consisting of2·N - 1
32-byte elements.f
: the value blinding factor.rek
: the record encryption key.
Note: this version of the signing algorithm does not use decimal exponent or minimum value and sets them both to zero.
Output: the value range proof consisting of:
N
: number of blinded bits (equals to2·n
),exp
: exponent (zero),vmin
: minimum value (zero),{D[t]}
:n-1
digit commitments encoded as public keys (excluding last digit commitment),{e,s[t,j]}
:1 + 4·n
32-byte elements representing a borromean ring signature,
In case of failure, returns nil
instead of the range proof.
Algorithm:
- Check that
N
belongs to the set{8,16,32,48,64}
; if not, halt and return nil. - Check that
value
is less than2^N
; if not, halt and return nil. - Define
vmin = 0
. - Define
exp = 0
. - Define
base = 4
. - Calculate payload encryption key unique to this payload and the value:
pek = SHA3-256(0xec || rek || f || V)
. - Calculate the message to sign:
msg = SHA3-256(H’ || V || N || exp || vmin || ev || ef)
whereN
,exp
,vmin
are encoded as 64-bit little-endian integers. - Let number of digits
n = N/2
. - Encrypt the payload using
pek
as a key and2·N-1
32-byte plaintext elements to get2·N
32-byte ciphertext elements:{ct[i]} = EncryptPayload({pt[i]}, pek)
. - Calculate 64-byte digit blinding factors for all but last digit:
{b[t]} = SHAKE256(0xbf || msg || f, 8·64·(n-1))
. - Interpret each 64-byte
b[t]
(t
from 0 ton-2
) is interpreted as a little-endian integer and reduce moduloL
to a 32-byte scalar. - Calculate the last digit blinding factor:
b[n-1] = f - ∑b[t] mod L
, wheret
is from 0 ton-2
. - For
t
from0
ton-1
(each digit):- Calculate
digit[t] = value & (0x03 << 2·t)
where<<
denotes a bitwise left shift. - Calculate
D[t] = digit[t]·H + b[t]·G
. - Calculate
j[t] = digit[t] >> 2·t
where>>
denotes a bitwise right shift. - For
i
from0
tobase-1
(each digit’s value):- Calculate point
P[t,i] = D[t] - i·(base^t)·H’
.
- Calculate point
- Calculate
- Create Borromean Ring Signature
brs
with the following inputs:msg
as the message to sign.n
: number of rings.m = base
: number of signatures per ring.{P[i,j]}
:n·m
public keys, points on the elliptic curve.{b[i]}
: the list ofn
blinding factors as private keys.{j[i]}
: the list ofn
indexes of the designated public keys within each ring, so thatP[i,j] == b[i]·G
.{r[i]} = {ct[i]}
: random string consisting ofn·m
32-byte ciphertext elements.
- If failed to create borromean ring signature
brs
, return nil. The chance of this happening is below 1 in 2124. In case of failure, retry creating blinded value commitments with incremented counter. This would yield a new blinding factorf
that will produce different digit blinding keys in this algorithm. - Return the value range proof:
N
: number of blinded bits (equals to2·n
),exp
: exponent (zero),vmin
: minimum value (zero),{D[t]}
:n-1
digit commitments encoded as public keys (excluding the last digit commitment),{e,s[t,j]}
:1 + n·4
32-byte elements representing a borromean ring signature,
Inputs:
H’
: the verified asset ID commitment.V
: the value commitment.(ev,ef)
: the encrypted value including its blinding factor.VRP
: the value range proof consisting of:N
: the number of bits in blinded mantissa (8-bit integer,N = 2·n
).exp
: the decimal exponent (8-bit integer).vmin
: the minimum amount (64-bit integer).{D[t]}
: the list ofn-1
digit pedersen commitments encoded as public keys.{e0, s[i,j]...}
: the borromean ring signature encoded as a sequence of1 + 4·n
32-byte integers.
Output: true
if the verification succeeded, false
otherwise.
Algorithm:
- Perform limit checks one by one. If any one fails, halt and return
false
:- Check that
exp
is less or equal to 10. - Check that
vmin
is less than 263. - Check that
N
is divisible by 2. - Check that
N
is equal or less than 64. - Check that
N + exp·4
is less or equal to 64. - Check that
(10^exp)·(2^N - 1)
is less than 263. - Check that
vmin + (10^exp)·(2^N - 1)
is less than 263.
- Check that
- Let
n = N/2
. - Calculate the message to verify:
msg = SHA3-256(H’ || V || N || exp || vmin || ev || ef)
whereN
,exp
,vmin
are encoded as 64-bit little-endian integers. - Calculate last digit commitment
D[n-1] = (10^(-exp))·(V - vmin·H) - ∑(D[t])
, where∑(D[t])
is a sum of all but the last digit commitment specified in the input to this algorithm. - For
t
from0
ton-1
(each ring):- Define
base = 4
. - For
i
from0
tobase-1
(each digit’s value):- Calculate point
P[t,i] = D[t] - i·(base^t)·H
.
- Calculate point
- Define
- Verify Borromean Ring Signature with the following inputs:
msg
: the 32-byte string being verified.n
: number of rings.m=base
: number of signatures in each ring.{P[i,j]}
:n·m
public keys, points on the elliptic curve.{e0, s[0,0], ..., s[i,j], ..., s[n-1,m-1]}
: the borromean ring signature,n·m+1
32-byte elements.
- Return
true
if verification succeeded, orfalse
otherwise.
Inputs:
H
: the verified asset ID commitment.V
: the value commitment.(ev,ef)
: the encrypted value including its blinding factor.- Value range proof consisting of:
N
: the number of bits in blinded mantissa (8-bit integer,N = 2·n
).exp
: the decimal exponent (8-bit integer).vmin
: the minimum amount (64-bit integer).{D[t]}
: the list ofn-1
digit pedersen commitments encoded as public keys.{e0, s[i,j]...}
: the borromean ring signature encoded as a sequence of1 + 4·n
32-byte integers.
value
: the 64-bit amount being encrypted and blinded.f
: the value blinding factor.rek
: the record encryption key.
Output: {pt[i]}
: an array of 32-bytes of plaintext data if recovery succeeded, nil
otherwise.
Algorithm:
- Perform limit checks one by one. If any one fails, halt and return
false
:- Check that
exp
is less or equal to 10. - Check that
vmin
is less than 263. - Check that
N
is divisible by 2. - Check that
N
is equal or less than 64. - Check that
N + exp·4
is less or equal to 64. - Check that
(10^exp)·(2^N - 1)
is less than 263. - Check that
vmin + (10^exp)·(2^N - 1)
is less than 263.
- Check that
- Let
n = N/2
. - Calculate the message to verify:
msg = SHA3-256(H || V || N || exp || vmin || ev || ef)
whereN
,exp
,vmin
are encoded as 64-bit little-endian integers. - Calculate last digit commitment
D[n-1] = (10^(-exp))·(V - vmin·H) - ∑(D[t])
, where∑(D[t])
is a sum of all but the last digit commitment specified in the input to this algorithm. - Calculate 64-byte digit blinding factors for all but last digit:
{b[t]} = SHAKE256(0xbf || msg || f, 8·64·(n-1))
. - Interpret each 64-byte
b[t]
(t
from 0 ton-2
) is interpreted as a little-endian integer and reduce moduloL
to a 32-byte scalar. - Calculate the last digit blinding factor:
b[n-1] = f - ∑b[t] mod L
, wheret
is from 0 ton-2
. - For
t
from0
ton-1
(each digit):- Calculate
digit[t] = value & (0x03 << 2·t)
where<<
denotes a bitwise left shift. - Calculate
j[t] = digit[t] >> 2·t
where>>
denotes a bitwise right shift. - Define
base = 4
. - For
i
from0
tobase-1
(each digit’s value):- Calculate point
P[t,i] = D[t] - i·(base^t)·H
.
- Calculate point
- Calculate
- Recover Payload From Borromean Ring Signature: compute an array of
2·N
32-byte chunks{ct[i]}
using the following inputs (halt and returnnil
if decryption fails):msg
: the 32-byte string to be signed.n=N/2
: number of rings.m=base
: number of signatures in each ring.{P[i,j]}
:n·m
public keys, points on the elliptic curve.{b[i]}
: the list ofn
blinding factors as private keys.{j[i]}
: the list ofn
indexes of the designated public keys within each ring, so thatP[i,j] == b[i]·G
.{e0, s[0,0], ..., s[i,j], ..., s[n-1,m-1]}
: the borromean ring signature,n·m+1
32-byte elements.
- Derive payload encryption key unique to this payload and the value:
pek = SHA3-256(0xec || rek || f || V)
. - Decrypt payload: compute an array of
2·N-1
32-byte chunks:{pt[i]} = DecryptPayload({ct[i]}, pek)
. If decryption fails, halt and returnnil
. - Return
{pt[i]}
, a plaintext array of2·N-1
32-byte elements.
Inputs:
q
: the excess blinding factor (an integer in range between 0 andL-1
).
Output:
Q
: the public key corresponding to the integerq
.(e,s)
: the Schnorr signature proving thatQ
does not affect asset amounts.
Algorithm:
- Calculate point
Q = q·G
and encode it as a 32-byte public key. - Calculate
k = SHA3-512(q)
whereq
is encoded as a 256-bit integer using little-endian notation. Interpretk
as a little-endian integer reduced moduloL
. - Calculate point
R = k·G
and encode it as a 32-byte public key. - Calculate
e = SHA3-512(Q || R)
whereQ||R
is a concatenation of public keysQ
andR
. - Interpret
e
as a little-endian integer reduced moduloL
. - Calculate
s = k + q·e mod L
. - Encode
s
ande
as 256-bit little-endian integers. - Return
(s,e)
encoded as a concatenation of two 256-bit integers (as a single 64-byte string).
Inputs:
Q
: the public key for the excess commitment (32-byte string)(e,s)
: the Schnorr signature (two 32-byte strings).
Output: true
if the verification succeeded, false
otherwise.
Algorithm:
- Calculate point
R = s·G - e·Q
and encode it as a 32-byte public key. - Calculate
e’ = SHA3-512(Q || R)
whereQ||R
is a concatenation of public keysQ
andR
. - Interpret
e’
as a little-endian integer reduced moduloL
. - Return
true
ife’ == e
, otherwise returnfalse
.
Inputs:
- The list of
n
input value commitments{V[i]}
. - The list of
m
output value commitments{V’[i]}
. - The list of
k
excess commitments{(Q[i], s[i], e[i])}
.
Output: true
if the verification succeeded, false
otherwise.
Algorithm:
- Verify each of
k
excess commitments; if any is not valid, halt and returnfalse
. - Calculate the sum of input value commitments:
Pi = ∑(V[i], j from 0 to n-1)
. - Calculate the sum of output value commitments:
Po = ∑(V’[i], i from 0 to m-1)
. - Calculate the sum of excess commitments:
Pq = ∑(Q[i], i from 0 to k-1)
. - Return
true
ifPi == Po + Pq
, otherwise returnfalse
.
Inputs:
assetid
: asset ID for which the issuance key is being generated.aek
: asset ID encryption key.
Output: (y,Y)
: a pair of private and public keys.
Algorithm:
- Calculate
secret = SHA3-512(0xa1 || assetid || aek)
. - Calculate scalar
y
by reducing thesecret
modulo subgroup orderL
:y = secret mod L
. - Calculate point
Y
by multiplying base point byy
:Y = y·G
. - Return key pair
(y,Y)
.
When creating a confidential issuance, the first step is to construct the rest of the input commitment and input witness, including an asset issuance choice for each asset that one wants to include in the anonymity set. The issuance key for each asset should be extracted from the issuance programs. (Issuance programs that support confidential issuance should have a branch that uses CHECKISSUANCE
to check for a confidential issuance key.)
Inputs:
H
: the asset ID commitment.c
: the blinding factor for commitmentH
such that:H = A + c·G
.{a[i]}
:n
32-byte unencrypted asset IDs.{Y[i]}
:n
issuance keys (each a 32-byte public key.vmver
: VM version for the issuance signature program.program
: issuance signature program.j
: the index of the asset being issued.y
: the private key for the issuance key corresponding to the asset being issued:Y[j] = y·G
.
Output: an issuance asset range proof consisting of:
e[0], s[0], ... s[n-1]
: the issuance ring signature,{Y[i]}
:n
issuance keys,vmver
: VM version for the issuance signature program,program
: issuance signature program,[]
: empty list of program arguments (to be filled in by the issuer).
Algorithm:
- Calculate nonblinded asset commitments for the values in
a
:A[i] = 8·Decode(SHA3(a[i]))
. - Calculate a 96-byte commitment string:
commit = SHAKE256(0x66 || H || A[0] || ... || A[n-1] || Y[0] || ... || Y[n-1] || vmver || program, 8·96)
, wherevmver
is encoded as a 64-bit unsigned little-endian integer. - Calculate message to sign as first 32 bytes of the commitment string:
msg = commit[0:32]
. - Calculate the coefficient
h
from the remaining 64 bytes of the commitment string:h = commit[32:96]
. Interpreth
as a 64-byte little-endian integer and reduce modulo subgroup orderL
. - Calculate
n
public keys{P[i]}
:P[i] = H - A[i] + h·Y[i]
. - Calculate private key
p = c + h·y
. - Create a ring signature with:
- message
msg
, n
public keys{P[i]}
,- index
j
, - private key
p
.
- message
- Return an issuance range proof consisting of
(e0,{s[i]}, {Y[i]}, vmver, program, [])
.
Inputs:
IARP
: the to-be-verified issuance asset range proof consisting of:e[0], s[0], ... s[n-1]
: the issuance ring signature,{Y[i]}
:n
issuance keys,vmver
: VM version for the issuance signature program,program
: issuance signature program,
H
: the asset ID commitment.{a[i]}
:n
32-byte unencrypted asset IDs.
Output: true
if the verification succeeded, false
otherwise.
Algorithm:
- Calculate nonblinded asset commitments for the values in
a
:A[i] = 8·Decode(SHA3(a[i]))
. - Calculate a 96-byte commitment string:
commit = SHAKE256(0x66 || H || A[0] || ... || A[n-1] || Y[0] || ... || Y[n-1] || vmver || program, 8·96)
, wherevmver
is encoded as a 64-bit unsigned little-endian integer. - Calculate message to sign as first 32 bytes of the commitment string:
msg = commit[0:32]
. - Calculate the coefficient
h
from the remaining 64 bytes of the commitment string:h = commit[32:96]
. Interpreth
as a 64-byte little-endian integer and reduce modulo subgroup orderL
. - Calculate the
n
public keys{P[i]}
:P[i] = H - A[i] + h·Y[i]
. - Verify the ring signature
e[0], s[0], ... s[n-1]
with messagemsg
and public keys{P[i]}
.
Inputs:
AD
: the asset ID descriptor.VD
: the value commitment.ARP
: the asset range proof or an empty string.VRP
: the value range proof or an empty string.
Output: true
if verification succeeded, false
otherwise.
Algorithm:
- If
ARP
is not empty andAD
is blinded:- Verify asset range proof using
(AD.H,AD.(ea,ec),ARP)
. If verification failed, halt and returnfalse
.
- Verify asset range proof using
- If
VRP
is not empty andVD
is blinded:- Verify value range proof using
(AD.H,VD.V,VD.(ev,ef),VRP)
. If verification failed, halt and returnfalse
.
- Verify value range proof using
- Return
true
.
Inputs:
AD
: the asset ID descriptor.VD
: the value descriptor.{a[i]}
:n
32-byte unencrypted asset IDs.IARP
: the issuance asset ID range proof.VRP
: the value range proof.
Output: true
if verification succeeded, false
otherwise.
Algorithm:
- If
IARP
is not empty andAD
is blinded:- Verify issuance asset range proof using
(IARP,AD.H,{a[i]})
. If verification failed, halt and returnfalse
.
- Verify issuance asset range proof using
- If
VRP
is not empty andVD
is blinded:- Verify value range proof using
(AD.H, VD.V, evef=(0x00...,0x00...),VRP)
. If verification failed, halt and returnfalse
.
- Verify value range proof using
- Return
true
.
Inputs:
- List of issuances, each input consisting of:
AD
: the asset ID descriptor.VD
: the value descriptor.{a[i]}
:n
32-byte unencrypted asset IDs.IARP
: the issuance asset ID range proof.VRP
: the value range proof.
- List of inputs, each input consisting of:
AD
: the asset ID descriptor.VD
: the value descriptor.
- List of outputs, each output consisting of:
AD
: the asset ID descriptor.VD
: the value descriptor.ARP
: the asset range proof or empty string.VRP
: the value range proof or empty string.
- The list of excess commitments:
{(Q[i], s[i], e[i])}
.
Output: true
if verification succeeded, false
otherwise.
Algorithm:
- Verify each issuance. If verification failed, halt and return
false
. - For each output:
- If
AD
is blinded andARP
is an empty string, or an ARP with zero keys, verify thatAD.H
equals one of the asset ID commitments in the inputs or issuances. If not, halt and returnfalse
. - If
AD
is blinded andARP
is not empty, verify that each asset ID commitment in theARP
belongs to the set of the asset ID commitments on the inputs and issuances. If not, halt and returnfalse
. - If there are more than one output and the output’s value descriptor is blinded:
- Verify that the value range proof is not empty. Otherwise, halt and return
false
.
- Verify that the value range proof is not empty. Otherwise, halt and return
- Verify output. If verification failed, halt and return
false
.
- If
- Verify value commitments balance using a union of issuance and input value commitments as input commitments. If verification failed, halt and return
false
. - Return
true
.
Inputs:
rek
: the record encryption key unique to this issuance.assetID
: the output asset ID.value
: the output amount.N
: number of bits to encrypt (value
must fit withinN
bits).{(assetIDs[i], Y[i])}
:n
input asset IDs and corresponding issuance public keys.y
: issuance key forassetID
such thatY[j] = y·G
wherej
is the index of the issued asset:assetIDs[j] == assetID
.(vmver’,program’)
: the signature program and its VM version to be signed by the issuance proof.
Outputs:
AD
: the asset ID descriptor.VD
: the value descriptor.IARP
: the issuance asset ID range proof.VRP
: the value range proof.c
: the asset ID blinding factor for the asset ID commitmentAD.H
.f
: the value blinding factor.
In case of failure, returns nil
instead of the items listed above.
Algorithm:
- Derive asset encryption key
aek
fromrek
. - Derive value encryption key
vek
fromrek
. - Create nonblinded asset ID commitment for all values in
{assetIDs[i]}
:A[i] = 8·Decode(SHA3(assetIDs[i]))
. - Find
j
index of theassetID
among{assetIDs[i]}
. If not found, halt and returnnil
. - Create blinded asset ID commitment: compute
(H,c)
from(A, 0, aek)
. - Create blinded value commitment: compute
(V,f)
from(vek, value, H, c)
. - Create issuance asset range proof: compute
IARP
from(H, c, {A[i]}, {Y[i]}, vmver’, program’, j, y)
. - Create Value Range Proof: compute
VRP
from(H, V, (0x00...,0x00...), N, value, {0x00...}, f, rek)
. - Create blinded asset ID descriptor
AD
containingH
and all-zero encrypted asset ID. - Create blinded value descriptor
VD
containingV
and all-zero encrypted value. - Return
(AD, VD, IARP, VRP, c, f)
.
This algorithm encrypts the amount and asset ID of a given output and creates value range proof with encrypted payload. If the excess factor is provided, it is used to compute a matching blinding factor to cancel it out.
This algorithm does not create asset range proof (ARP), since it requires knowledge about the input descriptors and one of their blinding factors. ARP can be added separately using Create Asset Range Proof.
Inputs:
rek
: the record encryption key.assetID
: the output asset ID.value
: the output amount.N
: number of bits to encrypt (value
must fit withinN
bits).plaintext
: binary string that has length of less than32·(2·N-1)
bytes when encoded as varstring31.- Optional
q
: the excess factor to have this output balance with the transaction. If omitted, blinding factor is generated at random.
Outputs:
AD
: the asset ID descriptor.VD
: the value descriptor.VRP
: the value range proof.c’
: the output asset ID blinding factor for the asset ID commitmentH’
.f’
: the output value blinding factor.
In case of failure, returns nil
instead of the items listed above.
Algorithm:
- Encode
plaintext
using varstring31 encoding and split the string in 32-byte chunks{pt[i]}
(last chunk padded with zero bytes if needed). - If the number of chunks
{pt[i]}
exceeds2·N-1
, halt and returnnil
. - If the number of chunks
{pt[i]}
is less than2·N-1
, pad the array with all-zero 32-byte chunks. - If
value ≥ 2^N
, halt and returnnil
. - Derive asset encryption key
aek
fromrek
. - Derive value encryption key
vek
fromrek
. - Create blinded asset ID commitment: compute
(H’,c’)
from(assetID, aek)
. - Encrypt asset ID: compute
(ea,ec)
from(assetID, H’, c’, aek)
. - Create blinded value commitment: compute
(V’,f’)
from(vek, value, H’)
. - If
q
is provided:- Compute
extra
scalar:extra = q - f’ - value·c’
. - Add
extra
to the value blinding factor:f’ = f’ + extra
. - Adjust the value commitment too:
V = V + extra·G
. - Note: as a result, the total blinding factor of the output will be equal to
q
.
- Compute
- Encrypt Value: compute
(ev,ef)
from(V’, value, f’, vek)
. - Create Value Range Proof: compute
VRP
from(H’, V’, (ev,ef), N, value, {pt[i]}, f’, rek)
. - Create encrypted asset ID descriptor
AD
containingH’
and(ea,ec)
. - Create encrypted value descriptor
VD
containingV’
and(ev,ef)
. - Return
(AD, VD, VRP, c’, f’)
.
This algorithm decrypts fully encrypted amount and asset ID for a given output.
Inputs:
rek
: the record encryption key.AD
: the asset ID descriptor.VD
: the value descriptor.VRP
: the value range proof or an empty string.
Outputs:
assetID
: the output asset ID.value
: the output amount.c
: the output asset ID blinding factor for the asset ID commitmentH
.f
: the output value blinding factor.plaintext
: the binary string that has length of less than32·(2·N-1)
bytes when encoded as varstring31.
In case of failure, returns nil
instead of the items listed above.
Algorithm:
- Derive asset encryption key
aek
fromrek
. - Derive value encryption key
vek
fromrek
. - Decrypt asset ID:
- If
AD
is nonblinded: setassetID
to the one stored inAD
, setc
to zero. - If
AD
is blinded and not encrypted, halt and return nil. - If
AD
is encrypted, Decrypt Asset ID: compute(assetID,c)
from(H,(ea,ec),aek)
. If verification failed, halt and returnnil
.
- If
- Decrypt value:
- If
VD
is nonblinded: setvalue
to the one stored inVD
, setf
to zero. - If
VD
is blinded and not encrypted, halt and return nil. - If
VD
is encrypted, Decrypt Value: compute(value, f)
from(H,V,(ev,ef),vek)
. If verification failed, halt and returnnil
.
- If
- If value range proof
VRP
is not empty:- Recover payload from Value Range Proof: compute a list of 32-byte chunks
{pt[i]}
from(H,V,(ev,ef),VRP,value,f,rek)
. If verification failed, halt and returnnil
. - Flatten the array
{pt[i]}
in a binary string and decode it using varstring31 encoding. If decoding fails, halt and returnnil
.
- Recover payload from Value Range Proof: compute a list of 32-byte chunks
- If value range proof
VRP
is empty, setplaintext
to an empty string. - Return
(assetID, value, c, f, plaintext)
.
This section provides an overview for protocol changes in the VM1 and blockchain validation logic necessary to support Confidential Assets.
- CHECKOUTPUT: accepts commitments (encoded as 32-byte public keys) for both asset ID and amount arguments. Fails execution if commitment is provided when the corresponding field is nonblinded. Fails execution if raw value is provided, but the field is blinded.
- ASSET: fails execution if asset ID is blinded.
- AMOUNT: fails execution if amount is blinded.
- ASSETCOMMITMENT: returns asset ID commitment, if asset ID is blinded. Fails execution otherwise.
- VALUECOMMITMENT: returns value commitment, if amount is blinded. Fails execution otherwise.
- ISSUANCEKEY: returns public key declared in the issuance choice context.
- TBD
- TBD
- TBD
- TBD
- List of excess commitments (point and a signature).
- Verify block version = 2.
- Verify tx version = 2.
- Verify tx balances.
- Verify range proofs.
- Verify issuance range proof.