-
Definitions
/// Ciphersuite is a wrapper of u8 pub type Ciphersuite = u8;
-
Methods:
fn check_ciphersuite(Ciphersuite) -> bool
- Input: ciphersuite identifier
- Output: checks if the ciphersuite is supported by the current version of the code.
- Note: currently only support
ciphersuite == 0
-
Definitions
/// the PointproofsG1 and PointproofsG2 can be switched to improve verification speed /// PointproofsG1 represents G1 in the paper, and can be mapped to either bls12-381::G1 or bls12-381::G2 type PointproofsG1 = G1; type PointproofsG2 = G2; type PointproofsG1Affine = G1Affine; type PointproofsG2Affine = G2Affine;
Group switching can be enabled during compiling with a flag. By default, the groups are NOT switched.
features=group_switched
-
Definitions
pub struct ProverParams { pub ciphersuite: Ciphersuite, pub n: usize, pub generators: Vec<PointproofsG1Affine>, pub pp_len: usize, pub precomp: Vec<PointproofsG1Affine>, }
pub struct VerifierParams { ciphersuite: Ciphersuite, pub n: usize, generators: Vec<PointproofsG2Affine>, gt_elt: Fq12, }
-
Methods:
fn paramgen_from_seed<Blob: AsRef<[u8]>>( seed: Blob, ciphersuite: Ciphersuite, ) -> Result<(ProverParams, VerifierParams), String>
- Input: a seed
- Input: ciphersuite identifier
- Input: vector length n
- Output: prover parameter and verifier parameter
- Error: ciphersuite is not supported
- Error: seed is too short
- Error: n is too large
- Note: This function is only used for testing. For deployment, use
pointproofs_paramgen
trait for parameters.
fn serialize<W: Write>(&self, writer: &mut W, compressed: bool) -> Result<()>
- Input: either a
ProverParams
or aVerifierParam
- Input: a writable buffer
- Input: a flag whether to compress the group point or not; must be true
- Output: none
- Error: compression is false
- Error: ciphersuite is not supported
- Error: serialization fails
- Steps: serialize the parameters into a blob
- For
ProverParams
, convert|ciphersuite id | n | generators | pp_len | [pre_compute] |
to bytes - For
VerifierParam
, convert|ciphersuite id | n | generators | pp_len | [pre_compute] | gt_element
to bytes
- For
fn deserialize<R: Read>(reader: &mut R, compressed: bool) -> Result<Self>
- Input: a readeble buffer
- Input: a flag whether the group elements are expected to be compressed or not; must be true
- Output: either a
ProverParams
or aVerifierParam
- Error: compression is false
- Error: ciphersuite is not supported
- Error: encoded buffer has a different compressness than specified
- Error: deserialization fails
- Steps: deserialize the blob into parameters
- For
ProverParams
, convert bytes to|ciphersuite id | n | generators | pp_len | [pre_compute] |
- For
VerifierParam
, convert bytes to|ciphersuite id | n | generators | pp_len | [pre_compute] | gt_element
- For
-
Definitions
pub struct Commitment { ciphersuite: Ciphersuite, commit: G1, }
-
Methods:
fn serialize<W: Write>(&self, writer: &mut W, compressed: bool) -> Result<()>
- Input: a
Commitment
- Input: a writable buffer
- Input: a flag whether to compress the group point or not; must be true
- Output: none
- Error: compression is false
- Error: ciphersuite is not supported
- Error: serialization fails
- Steps: convert
| ciphersuite | commit |
to bytes
fn deserialize<R: Read>(reader: &mut R, compressed: bool) -> Result<Self>
- Input: a readeble buffer
- Input: a flag whether the group elements are expected to be compressed or not; must be true
- Output: a
Commitment
- Error: compression is false
- Error: ciphersuite is not supported
- Error: encoded buffer has a different compressness than specified
- Error: deserialization fails
- Steps: convert bytes to
| ciphersuite | commit |
pub fn new<Blob: AsRef<[u8]>>( prover_params: &ProverParams, values: &[Blob], ) -> Result<Self, String>
- Input: a
ProverParam
- Input: the values to commit to; as a slice of
&[u8]
- Output: a
Commitment
- Error: ciphersuite is not supported
- Error: ciphersuite does not match #elements in parameters
- Error: values.length does not match n
- Steps:
- hash
value
s intoscalar
s commit = \prod prover_params.generators[i]^scalar[i] for i in indices
- hash
pub fn update<Blob: AsRef<[u8]>>( &mut self, prover_params: &ProverParams, changed_index: usize, value_before: Blob, value_after: Blob, ) -> Result<(), String>
- Input: self, a
Commitment
- Input: a
ProverParam
- Input: the
index
to be updated - Input: the original value
- Input: the value updated to
- Output: mutate self to the updated commit
- Error: ciphersuite is not supported
- Error: self.ciphersuite does not match prover_params.ciphersuite
- Error: index out of range
- Steps:
- hash
value_before
intoold_scalar
- hash
value_after
intonew_scalar
commit = commit * prover_params,generators[changed_index]^(new_scalar-old_scalar)
- hash
pub fn batch_update<Blob: AsRef<[u8]>>( &mut self, prover_params: &ProverParams, changed_index: &[usize], value_before: &[Blob], value_after: &[Blob], ) -> Result<(), String>
- Input: self, a
Commitment
- Input: a
ProverParam
- Input: a list of
indices
to be updated - Input: a list of original values
- Input: a list of values updated to
- Output: mutate self to the updated commit
- Error: ciphersuite is not supported
- Error: self.ciphersuite does not match prover_params.ciphersuite
- Error: index out of range
- Error: # of changed_index, value_before or value_after do not match
- Steps:
- for
i
inindices
- hash
value_before[i]
s intoold_scalar[i]
- hash
value_after[i]
s intonew_scalar[i]
commit = commit * \prod prover_params.generators[i]^(new_scalar[i]-old_scalar[i])
for i in indices
- for
- Input: a
-
Definitions
pub struct Proof { ciphersuite: Ciphersuite, proof: PointproofsG1, }
-
Methods
/// generate a new proof pub fn new<Blob: AsRef<[u8]>>( prover_params: &ProverParams, values: &[Blob], index: usize, ) -> Result<Self, String>
- Input: a
ProverParams
- Input: a list of values to commit
- Input: the index for which the proof is generated
- Output: a new proof
- Error: ciphersuite is not supported
- Error: index out of range
- Error: values.length does not match n
- Steps:
- hash the
value
s intoscarlar
s proof = \prod prover_params.generators[n - index + i]^scalar[i]
for i in range(n) except index (in implementation we implement it asfor i in range(n)
without exception, since the corresponding generator was already set to0
)
- hash the
/// generate a list of new proofs pub fn batch_new<Blob: AsRef<[u8]>>( prover_params: &ProverParams, values: &[Blob], indices: &[usize], ) -> Result<Vec<Self>, String>
- Input: a
ProverParam
- Input: a list of values to commit
- Input: a list of indices for which the proofs are generated
- Output: a list of proofs, each corresponding to an index
- Error: ciphersuite is not supported
- Error: index out of range
- Error: values.length does not match n
- Error: indices.length = 0 or indices.length > n
- Steps:
- hash the
value
s intoscarlar
s - for j in 0..indices.len():
proof[j] = \prod prover_params[n - indices[j] + i]^scalar[i]
for i in range(n) except index
(in implementation we implement it asfor i in range(n)
without exception, since the corresponding generator was already set to1
)
- hash the
/// generate a single, aggregated proof pub fn batch_new_aggregated<Blob: AsRef<[u8]>>( prover_params: &ProverParams, commit: &Commitment, values: &[Blob], indices: &[usize], ) -> Result<Self, String>
-
Input: a
ProverParam
-
Input: a list of values to commit
-
Input: a list of indices for which the proofs are generated
-
Output: an aggregated proof for proofs, each corresponding to an index
-
Error: ciphersuite is not supported
-
Error: index out of range
-
Error: values.length does not match n
-
Error: indices.length = 0 or indices.length > n
- hash the
value
s intoscarlar
s proof = 1
- for j in 0..indices.len():
proof[j] = \prod prover_params[n - indices[j] + i]^scalar[i]
for i in range(n) except indices[j] (in implementation we implement it asfor i in range(n)
without exception, since the corresponding generator was already set to1
)proof *= proof[j]
More efficient implementation is via the following
\prod_k prover_params[k]^c[k]
wherec[k]=\sum scalar[k+i-n] * t_i
for i in indices (with scalars at out-of-range indices understood to be 0) - hash the
/// For updating your proof when someone else's value changes /// Not for updating your own proof when your value changes -- because then the proof does not change! pub fn update<Blob: AsRef<[u8]>>( &mut self, prover_params: &ProverParams, proof_index: usize, changed_index: usize, value_before: Blob, value_after: Blob, ) -> Result<(), String>
- Input: self, the proof to be updated
- Input: a
ProverParams
- Input: proof_index, the index for which the proof is generated
- Input: changed_index, the index for which the proof will be updated
- Output: mutate self to a new proof
- Error: ciphersuite is not supported
- Error: index out of range
- Note: This function is used for updating your proof when someone else's value changes. It is not for updating your own proof when your value changes -- because then the proof does not change!
- Steps:
- hash
value_before
intoold_scalar
- hash
value_after
intonew_scalar
proof = proof * prover_params.generators[changed_index + n - proof_index]^(new_scalar-old_scalar)
- hash
/// Verify the proof pub fn verify<Blob: AsRef<[u8]>>( &self, verifier_params: &VerifierParams, com: &Commitment, value: Blob, index: usize, ) -> bool
- Input: self, the proof to be verified
- Input: a
VerifierParams
- Input: the commitment
- Input: the value that proof is generated
- Input: index of the value in the value vector
- Output: if the proof is valid w.r.t. commit/values/index or not
- Steps:
- Compute
t = hash_to_field_pointproofs(value)
- return
e(com^{1/t}, veririer_params.generators[n-index-1]) * e(proof^{-1/t}, generator_of_g2) == gt_elt
- Compute
/// Aggregates a vector of proofs into a single one /// Note: the aggregator does not check the validity of /// individual commits. The caller may need to check them /// if they care for it. pub fn same_commit_aggregate<Blob: AsRef<[u8]>>( commit: &Commitment, proofs: &[Self], set: &[usize], value_sub_vector: &[Blob], n: usize, ) -> Result<Self, String>
- Input: a commitment
- Input: a list of proofs for this commitment
- Input: the set of indices for proofs
- Input: the set of values for proofs
- Input: n - the public parameter
- Output: an aggregated proof
- Error: the lengths do not match
- Error: ciphersuite not supported
- Steps:
- if
commit.len() == 1
, returnproof[0]
- hash to a list of scalars
ti = hash_to_ti(commit, set, value_sub_vector, n)
- return
proof = \prod proofs[i]^ti[i]
- if
/// Aggregate an array of proofs, each is an (aggregated) proof for a /// commit, into a single proof pub fn cross_commit_aggregate_partial<Blob: AsRef<[u8]>>( commits: &[Commitment], proofs: &[Self], set: &[Vec<usize>], value_sub_vector: &[Vec<Blob>], n: usize, ) -> Result<Self, String>
- Input: a vector commitments
- Input: a vector of proofs, each (aggregate) proof belongs to a commitment
- Input: a vector of sets of indices for proofs, each set of indices belongs to a same commitment
- Input: a vector of sets of values for proofs, each set of values belongs to a same commitment
- Output: an aggregated proof
- Error: the lengths do not match
- Error: ciphersuite not supported
- Steps:
- if
commit.len() == 1
, returnaggregate(commits[0], proofs[0], set[0], value_sub_vector[0], n)
- hash to a list of scalars
hash_to_tj(&commits, &set, &value_sub_vector, n)
- return
proof = \prod proofs[i]^tj[i]
- if
/// Aggregate a 2-dim array of proofs, each row corresponding to a /// commit, into a single proof pub fn cross_commit_aggregate_full<Blob: AsRef<[u8]>>( commits: &[Commitment], proofs: &[Vec<Self>], set: &[Vec<usize>], value_sub_vector: &[Vec<Blob>], n: usize, ) -> Result<Self, String>
- Input: a vector commitments
- Input: a vector of vectors of proofs, each vector of proofs belongs to a same commitment
- Input: a vector of sets of indices for proofs, each set of indices belongs to a same commitment
- Input: a vector of sets of values for proofs, each set of values belongs to a same commitment
- Output: an aggregated proof
- Error: the lengths do not match
- Error: ciphersuite not supported
- Steps:
- if
commit.len() == 1
, returnaggregate(commits[0], proofs[0], set[0], value_sub_vector[0], n)
- hash to a list of scalars
hash_to_tj(&commits, &set, &value_sub_vector, n)
- for
0<=i<commit.len
computepi[i] = aggregate(commits[i], proofs[i], set[i], value_sub_vector[i], n)
- return
proof = \prod pi[i]^tj[i]
- if
/// batch verify a proof for a list of values/indices pub fn same_commit_batch_verify<Blob: AsRef<[u8]>>( &self, verifier_params: &VerifierParams, com: &Commitment, set: &[usize], value_sub_vector: &[Blob], ) -> bool
- Input is similar to
aggregate
- Output: if the proof is valid w.r.t. the inputs or not
- Formula:
e(com, g2^{tmp*\sum_{i \in set} \alpha^{N+1-i} t_i})* e(proof^{-tmp}, g2)?= e(g1, g2)^{alpha^N+1}
wheretmp = 1/\sum value_i*t_i
- Steps:
- if
set.len() == 1
, returnself.verify(&verifier_params, &com, value_sub_vector[0].as_ref(), set[0]);
- Set
t_i = hash_to_ti(com, set, value_sub_vector, verifier_params.n)
- Compute
tmp = 1/ \sum value_i*t_i
- Return
e(com, (\Prod verifier_params.generators[n-i-1]^(tmp * t_i)) * e(proof^{-tmp}, g2) == gt_elt
- if
/// verify a proof which was aggregated from 2-dim array of proofs pub fn cross_commit_batch_verify<Blob: AsRef<[u8]>>( &self, verifier_params: &VerifierParams, com: &[Commitment], set: &[Vec<usize>], value_sub_vector: &[Vec<Blob>], ) -> bool
- Input is similar to
cross_commit_aggregate
- Output: if the proof is valid w.r.t. the inputs or not
- Formula:
\prod e(com[j], g2^{\sum alpha^{n + 1 - i} * t_j,i * tj * tmp} ) * e(proof^{-tmp}, g2) == e(g1, g2)^{alpha^{n+1}}
wheretmp = 1/\sum m_j,i * t_j,i * tj
- Steps:
- if
com.len() == 1
, returnself.batch_verify(&verifier_params, &com[0], &set[0], &value_sub_vector[0])
- compute
tmp = 1 / sum_j tj (sum_i m_j,i * t_j,i)
- formulate
g1_vec = [com | (1/proof)^tmp]
- set
g2_vec
as forj \in [num_commit], (\Prod for i in set[j] of verifier_params.generators[n-i-1]^(tmp * t_j,i * t_j))
, g2_vec.push(G2::one())
- return
pairing_multi_product(g1_vec, g2_vec) == verifier_params.gt_elt
- if
fn serialize<W: Write>(&self, writer: &mut W, compressed: bool) -> Result<()>
- Input: a
Commitment
- Input: a writable buffer
- Input: a flag whether to compress the group point or not; must be true
- Output: none
- Error: compression is false
- Error: ciphersuite is not supported
- Error: serialization fails
- Steps: convert
| ciphersuite | proof |
to bytes
fn deserialize<R: Read>(reader: &mut R, compressed: bool) -> Result<Self>
- Input: a readeble buffer
- Input: a flag whether the group elements are expected to be compressed or not; must be true
- Output: a
Commitment
- Error: compression is false
- Error: ciphersuite is not supported
- Error: encoded buffer has a different compressness than specified
- Error: deserialization fails
- Steps: convert bytes to
| ciphersuite | proof |
- Input: a
-
pointproofs' hash to field
// hash_to_field_pointproofs use SHA 512 to hash a blob into a non-zero field element pub fn hash_to_field_pointproofs<Blob: AsRef<[u8]>>(input: Blob) -> Fr
- Steps:
- hash
input
into64
bytes arraydata
- convert
data
into a 512 bits integera = os2ip(data)
t = a mod r
wherer
is the group order- if
t == 0
return 1, else returnt
- hash
- Note: always returns a non-zero field element. The output should be IND from uniform.
- Steps:
-
hash to t_j
pub fn hash_to_tj<Blob: AsRef<[u8]>>( commits: &[Commitment], set: &[Vec<usize>], value_sub_vector: &[Vec<Blob>], n: usize, ) -> Result<Vec<FrRepr>, String>
- Input: a list of k commitments
- Input: a list of k * x indices, for which we need to generate t_j
- Input: Value: a list of k * x messages that is committed to
- Output: a list of k field elements
- Error: ciphersuite id not supported
- Error: lengths do no match
- Steps:
tmp = {C | S | m[S]} for i \in [0 .. commit.len-1]
digest = SHA512(tmp)
- for
0 <= i < commits.len()
,res[i] = hash_to_field_pointproofs(i, digest)
- Note: this procedure is a bit different from the paper, where no intermediate digest is generated. We pre-hash the data into a digest to improve efficiency.
-
hash to t_i
pub fn hash_to_ti_fr<Blob: AsRef<[u8]>>( commit: &Commitment, set: &[usize], value_sub_vector: &[Blob], n: usize, ) -> Result<Vec<Fr>, String>
- Input: the commitment
- Input: a list of indices, for which we need to generate t_i
- Input: Value: the messages that is committed to
- Output: a list of field elements
- Error: ciphersuite id not supported
- Error: lengths do no match
- Steps:
digest = SHA512(C | S | m[S])
- for
0 <= i < set.len()
,res[i] = hash_to_field_pointproofs(i, digest)
- Note: this procedure is a bit different from the paper, where no intermediate digest is generated. We pre-hash the data into a digest to improve efficiency.
Here are a list of minor difference of the spec from the paper. Those differences are either to improve the performance or simplicity of code. They have no impact on the security of the scheme.
-
hash to ti-s and tj-s:
- in the code we hash the inputs into a digest first, and then use this digest (concatenated with an index) to generate a field element.
- in the paper, there is no intermediate digest. the input is concatenated with the index to generated a field element.
-
indexing:
- in the code, the indices start from 0 and end with n-1
- in the paper, the indices start from 1 and end with n