跳转到内容

confidential_balance - [devnet]

此内容尚不支持你的语言。

Balance types for the confidential asset protocol.

A balances aa is chunked into vectors of bb-bit chunks [a0,a1,,an1][a_0, a_1, \ldots, a_{n-1}] such that a=i=0n1aiBia = \sum_{i = 0}^{n-1} a_i B^i where B=2bB = 2^b. Then, each chunk ii is encrypted as a tuple (Pi=aiG+riH,Ri=riek)(P_i = a_i G + r_i H, R_i = r_i \mathsf{ek}) under an encryption key ek\mathsf{ek}.

The pending balance has nn chunks while the available balance has \ell such chunks. For Aptos, we need bn=64b n = 64 and b=128b \ell = 128.

CompressedBalance<T> and Balance<T> are parameterized by phantom markers Pending and Available.

use 0x1::option;
use 0x1::ristretto255;
use 0x1::vector;

Constants

The number of chunks \ell in an available balance.

const AVAILABLE_BALANCE_CHUNKS: u64 = 8;

The number of bits bb in a single chunk.

const CHUNK_SIZE_BITS: u64 = 16;

All chunks are < than this value

const CHUNK_UPPER_BOUND: u64 = 65536;

Expected the P or R components to have the wrong number of chunks.

const E_WRONG_NUM_CHUNKS: u64 = 1;

Expected the auditor R-component to be either empty or have the correct number of chunks.

const E_WRONG_NUM_CHUNKS_FOR_AUDITOR: u64 = 2;

The number of chunks nn in a pending balance.

const PENDING_BALANCE_CHUNKS: u64 = 4;

Structs

Pending

struct Pending has drop
Fields
dummy_field: bool

Available

struct Available has drop
Fields
dummy_field: bool

Functions

get_P

public(friend) fun get_P<T>(self: &confidential_balance::Balance<T>): &vector<ristretto255::RistrettoPoint>
Implementation
public(friend) fun get_P<T>(self: &Balance<T>): &vector<RistrettoPoint> { &self.P }

get_R

public(friend) fun get_R<T>(self: &confidential_balance::Balance<T>): &vector<ristretto255::RistrettoPoint>
Implementation
public(friend) fun get_R<T>(self: &Balance<T>): &vector<RistrettoPoint> { &self.R }

get_R_aud

public(friend) fun get_R_aud<T>(self: &confidential_balance::Balance<T>): &vector<ristretto255::RistrettoPoint>
Implementation
public(friend) fun get_R_aud<T>(self: &Balance<T>): &vector<RistrettoPoint> { &self.R_aud }

get_compressed_P

public(friend) fun get_compressed_P<T>(self: &confidential_balance::CompressedBalance<T>): &vector<ristretto255::CompressedRistretto>
Implementation
public(friend) fun get_compressed_P<T>(self: &CompressedBalance<T>): &vector<CompressedRistretto> { &self.P }

get_compressed_R

public(friend) fun get_compressed_R<T>(self: &confidential_balance::CompressedBalance<T>): &vector<ristretto255::CompressedRistretto>
Implementation
public(friend) fun get_compressed_R<T>(self: &CompressedBalance<T>): &vector<CompressedRistretto> { &self.R }

get_compressed_R_aud

public(friend) fun get_compressed_R_aud<T>(self: &confidential_balance::CompressedBalance<T>): &vector<ristretto255::CompressedRistretto>
Implementation
public(friend) fun get_compressed_R_aud<T>(self: &CompressedBalance<T>): &vector<CompressedRistretto> { &self.R_aud }

compress

public(friend) fun compress<T>(self: &confidential_balance::Balance<T>): confidential_balance::CompressedBalance<T>
Implementation
public(friend) fun compress<T>(self: &Balance<T>): CompressedBalance<T> {
CompressedBalance::V1 {
P: self.P.map_ref(|p| p.point_compress()),
R: self.R.map_ref(|r| r.point_compress()),
R_aud: self.R_aud.map_ref(|r| r.point_compress()),
}
}

decompress

public(friend) fun decompress<T>(self: &confidential_balance::CompressedBalance<T>): confidential_balance::Balance<T>
Implementation
public(friend) fun decompress<T>(self: &CompressedBalance<T>): Balance<T> {
Balance::V1 {
P: self.P.map_ref(|p| p.point_decompress()),
R: self.R.map_ref(|r| r.point_decompress()),
R_aud: self.R_aud.map_ref(|r| r.point_decompress()),
}
}

is_zero

public(friend) fun is_zero<T>(self: &confidential_balance::CompressedBalance<T>): bool
Implementation
public(friend) fun is_zero<T>(self: &CompressedBalance<T>): bool {
self.P.all(|p| p.is_identity()) &&
self.R.all(|r| r.is_identity())
}

add_mut_base

Element-wise P and R addition. R_aud is NOT touched.

public(friend) fun add_mut_base<T>(self: &mut confidential_balance::Balance<T>, rhs_P: &vector<ristretto255::RistrettoPoint>, rhs_R: &vector<ristretto255::RistrettoPoint>)
Implementation
public(friend) fun add_mut_base<T>(self: &mut Balance<T>, rhs_P: &vector<RistrettoPoint>, rhs_R: &vector<RistrettoPoint>) {
vector::range(0, rhs_P.length()).for_each(|i| {
self.P[i].point_add_assign(&rhs_P[i]);
self.R[i].point_add_assign(&rhs_R[i]);
});
}

new_balance

fun new_balance<T>(p: vector<ristretto255::RistrettoPoint>, r: vector<ristretto255::RistrettoPoint>, r_aud: vector<ristretto255::RistrettoPoint>, expected_chunks: u64): confidential_balance::Balance<T>
Implementation
fun new_balance<T>(
p: vector<RistrettoPoint>, r: vector<RistrettoPoint>, r_aud: vector<RistrettoPoint>,
expected_chunks: u64,
): Balance<T> {
assert_correct_num_chunks(&p, &r, &r_aud, expected_chunks);
Balance::V1 { P: p, R: r, R_aud: r_aud }
}

new_compressed_balance

fun new_compressed_balance<T>(p: vector<ristretto255::CompressedRistretto>, r: vector<ristretto255::CompressedRistretto>, r_aud: vector<ristretto255::CompressedRistretto>, expected_chunks: u64): confidential_balance::CompressedBalance<T>
Implementation
fun new_compressed_balance<T>(
p: vector<CompressedRistretto>, r: vector<CompressedRistretto>, r_aud: vector<CompressedRistretto>,
expected_chunks: u64,
): CompressedBalance<T> {
assert_correct_num_chunks(&p, &r, &r_aud, expected_chunks);
CompressedBalance::V1 { P: p, R: r, R_aud: r_aud }
}

new_zero_compressed

fun new_zero_compressed<T>(num_chunks: u64): confidential_balance::CompressedBalance<T>
Implementation
fun new_zero_compressed<T>(num_chunks: u64): CompressedBalance<T> {
let identity = point_identity_compressed();
new_compressed_balance<T>(
vector::range(0, num_chunks).map(|_| identity),
vector::range(0, num_chunks).map(|_| identity),
vector[],
num_chunks
)
}

new_pending_from_p_and_r

public(friend) fun new_pending_from_p_and_r(p: vector<ristretto255::RistrettoPoint>, r: vector<ristretto255::RistrettoPoint>): confidential_balance::Balance<confidential_balance::Pending>
Implementation
public(friend) fun new_pending_from_p_and_r(p: vector<RistrettoPoint>, r: vector<RistrettoPoint>): Balance<Pending> {
new_balance(p, r, vector[], PENDING_BALANCE_CHUNKS)
}

new_zero_pending_compressed

public(friend) fun new_zero_pending_compressed(): confidential_balance::CompressedBalance<confidential_balance::Pending>
Implementation
public(friend) fun new_zero_pending_compressed(): CompressedBalance<Pending> {
new_zero_compressed(PENDING_BALANCE_CHUNKS)
}

new_pending_u64_no_randomness

Creates a pending balance from a 64-bit amount with no randomness (R = identity).

public(friend) fun new_pending_u64_no_randomness(amount: u64): confidential_balance::Balance<confidential_balance::Pending>
Implementation
public(friend) fun new_pending_u64_no_randomness(amount: u64): Balance<Pending> {
let identity = point_identity();
new_pending_from_p_and_r(
split_into_chunks((amount as u128), PENDING_BALANCE_CHUNKS).map(|chunk| chunk.basepoint_mul()),
vector::range(0, PENDING_BALANCE_CHUNKS).map(|_| identity.point_clone()),
)
}

add_assign_pending

Adds a pending balance to a compressed pending balance in place.

public(friend) fun add_assign_pending(balance: &mut confidential_balance::CompressedBalance<confidential_balance::Pending>, rhs: &confidential_balance::Balance<confidential_balance::Pending>): confidential_balance::CompressedBalance<confidential_balance::Pending>
Implementation
public(friend) fun add_assign_pending(balance: &mut CompressedBalance<Pending>, rhs: &Balance<Pending>): CompressedBalance<Pending> {
let decompressed = balance.decompress();
decompressed.add_mut_base(rhs.get_P(), rhs.get_R());
*balance = decompressed.compress();
*balance
}

get_num_pending_chunks

#[view]
public fun get_num_pending_chunks(): u64
Implementation
public fun get_num_pending_chunks(): u64 { PENDING_BALANCE_CHUNKS }

new_available_from_p_r_r_aud

public(friend) fun new_available_from_p_r_r_aud(p: vector<ristretto255::RistrettoPoint>, r: vector<ristretto255::RistrettoPoint>, r_aud: vector<ristretto255::RistrettoPoint>): confidential_balance::Balance<confidential_balance::Available>
Implementation
public(friend) fun new_available_from_p_r_r_aud(
p: vector<RistrettoPoint>, r: vector<RistrettoPoint>, r_aud: vector<RistrettoPoint>
): Balance<Available> {
new_balance(p, r, r_aud, AVAILABLE_BALANCE_CHUNKS)
}

new_compressed_available_from_p_r_r_aud

public(friend) fun new_compressed_available_from_p_r_r_aud(p: vector<ristretto255::CompressedRistretto>, r: vector<ristretto255::CompressedRistretto>, r_aud: vector<ristretto255::CompressedRistretto>): confidential_balance::CompressedBalance<confidential_balance::Available>
Implementation
public(friend) fun new_compressed_available_from_p_r_r_aud(
p: vector<CompressedRistretto>, r: vector<CompressedRistretto>, r_aud: vector<CompressedRistretto>
): CompressedBalance<Available> {
new_compressed_balance(p, r, r_aud, AVAILABLE_BALANCE_CHUNKS)
}

new_zero_available_compressed

public(friend) fun new_zero_available_compressed(): confidential_balance::CompressedBalance<confidential_balance::Available>
Implementation
public(friend) fun new_zero_available_compressed(): CompressedBalance<Available> {
new_zero_compressed(AVAILABLE_BALANCE_CHUNKS)
}

new_compressed_available_from_bytes

Deserializes raw byte vectors into a CompressedBalance (without decompressing).

public(friend) fun new_compressed_available_from_bytes(p_bytes: vector<vector<u8>>, r_bytes: vector<vector<u8>>, r_aud_bytes: vector<vector<u8>>): confidential_balance::CompressedBalance<confidential_balance::Available>
Implementation
public(friend) fun new_compressed_available_from_bytes(
p_bytes: vector<vector<u8>>,
r_bytes: vector<vector<u8>>,
r_aud_bytes: vector<vector<u8>>,
): CompressedBalance<Available> {
new_compressed_available_from_p_r_r_aud(
deserialize_compressed_points(p_bytes),
deserialize_compressed_points(r_bytes),
deserialize_compressed_points(r_aud_bytes),
)
}

set_available_R

Sets only the R component (EK component) of a compressed available balance.

public(friend) fun set_available_R(balance: &mut confidential_balance::CompressedBalance<confidential_balance::Available>, new_R: vector<ristretto255::CompressedRistretto>)
Implementation
public(friend) fun set_available_R(balance: &mut CompressedBalance<Available>, new_R: vector<CompressedRistretto>) {
assert!(new_R.length() == AVAILABLE_BALANCE_CHUNKS, error::invalid_argument(E_WRONG_NUM_CHUNKS));
balance.R = new_R;
}

add_assign_available_excluding_auditor

Adds a pending balance to an available balance in place. R_aud is NOT touched (stale after rollover).

public(friend) fun add_assign_available_excluding_auditor(self: &mut confidential_balance::CompressedBalance<confidential_balance::Available>, rhs: &confidential_balance::CompressedBalance<confidential_balance::Pending>)
Implementation
public(friend) fun add_assign_available_excluding_auditor(self: &mut CompressedBalance<Available>, rhs: &CompressedBalance<Pending>) {
let lhs_P = self.P.map_ref(|p| p.point_decompress());
let lhs_R = self.R.map_ref(|r| r.point_decompress());
let rhs_P = rhs.P.map_ref(|p| p.point_decompress());
let rhs_R = rhs.R.map_ref(|r| r.point_decompress());
vector::range(0, rhs_P.length()).for_each(|i| {
lhs_P[i].point_add_assign(&rhs_P[i]);
lhs_R[i].point_add_assign(&rhs_R[i]);
});
self.P = lhs_P.map_ref(|p| p.point_compress());
self.R = lhs_R.map_ref(|r| r.point_compress());
}

get_num_available_chunks

#[view]
public fun get_num_available_chunks(): u64
Implementation
public fun get_num_available_chunks(): u64 { AVAILABLE_BALANCE_CHUNKS }

get_chunk_size_bits

public(friend) fun get_chunk_size_bits(): u64
Implementation
public(friend) fun get_chunk_size_bits(): u64 { CHUNK_SIZE_BITS }

get_chunk_upper_bound

Every balance chunk is << than this bound (i.e., <216< 2^{16}).

public(friend) fun get_chunk_upper_bound(): u64
Implementation
public(friend) fun get_chunk_upper_bound(): u64 { CHUNK_UPPER_BOUND }

split_into_chunks

Splits amount into num_chunks 16-bit chunks as Scalar values.

fun split_into_chunks(amount: u128, num_chunks: u64): vector<ristretto255::Scalar>
Implementation
fun split_into_chunks(amount: u128, num_chunks: u64): vector<Scalar> {
vector::range(0, num_chunks).map(|i| {
new_scalar_from_u128(amount >> (i * CHUNK_SIZE_BITS as u8) & 0xffff)
})
}

get_b_powers

Returns [B^0, B^1, …, B^{count-1}] where B = 2^chunk_size_bits.

public(friend) fun get_b_powers(count: u64): vector<ristretto255::Scalar>
Implementation
public(friend) fun get_b_powers(count: u64): vector<Scalar> {
let b = new_scalar_from_u128((CHUNK_UPPER_BOUND as u128));
let powers = vector[scalar_one()];
let prev = scalar_one();
for (i in 1..count) {
prev = prev.scalar_mul(&b);
powers.push_back(prev);
};
powers
}

get_encryption_key_basepoint_compressed

Returns the compressed generator H used to derive the encryption key as EK = DK^(-1) * H.

public(friend) fun get_encryption_key_basepoint_compressed(): ristretto255::CompressedRistretto
Implementation
public(friend) fun get_encryption_key_basepoint_compressed(): CompressedRistretto {
ristretto255::basepoint_H_compressed()
}

assert_correct_num_chunks

fun assert_correct_num_chunks<T>(p: &vector<T>, r: &vector<T>, r_aud: &vector<T>, expected_chunks: u64)
Implementation
fun assert_correct_num_chunks<T>(p: &vector<T>, r: &vector<T>, r_aud: &vector<T>, expected_chunks: u64) {
assert!(p.length() == expected_chunks, error::invalid_argument(E_WRONG_NUM_CHUNKS));
assert!(r.length() == expected_chunks, error::invalid_argument(E_WRONG_NUM_CHUNKS));
assert!(r_aud.is_empty() || r_aud.length() == expected_chunks, error::invalid_argument(
E_WRONG_NUM_CHUNKS_FOR_AUDITOR
));
}

Enum CompressedBalance

enum CompressedBalance<T> has copy, drop, store
Variants
V1
Fields
P: vector<ristretto255::CompressedRistretto>
R: vector<ristretto255::CompressedRistretto>
R_aud: vector<ristretto255::CompressedRistretto>

Enum Balance

enum Balance<T> has drop
Variants
V1
Fields
P: vector<ristretto255::RistrettoPoint>
R: vector<ristretto255::RistrettoPoint>
R_aud: vector<ristretto255::RistrettoPoint>