Update get range proof signature function to return an error
This commit is contained in:
@@ -25,6 +25,9 @@ pub enum CompactEcashError {
|
||||
#[error("Spend Verification related error: {0}")]
|
||||
Spend(String),
|
||||
|
||||
#[error("ZKP Proof related error: {0}")]
|
||||
RangeProofOutOfBound(String),
|
||||
|
||||
#[error("Tried to deserialize {object} with bytes of invalid length. Expected {actual} < {} or {modulus_target} % {modulus} == 0")]
|
||||
DeserializationInvalidLength {
|
||||
actual: usize,
|
||||
|
||||
@@ -3,8 +3,8 @@ use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use bls12_381::{G1Affine, G1Projective, Scalar};
|
||||
use digest::Digest;
|
||||
use digest::generic_array::typenum::Unsigned;
|
||||
use digest::Digest;
|
||||
use group::GroupEncoding;
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -20,10 +20,10 @@ type ChallengeDigest = Sha256;
|
||||
|
||||
/// Generates a Scalar [or Fp] challenge by hashing a number of elliptic curve points.
|
||||
fn compute_challenge<D, I, B>(iter: I) -> Scalar
|
||||
where
|
||||
D: Digest,
|
||||
I: Iterator<Item=B>,
|
||||
B: AsRef<[u8]>,
|
||||
where
|
||||
D: Digest,
|
||||
I: Iterator<Item = B>,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
let mut h = D::new();
|
||||
for point_representation in iter {
|
||||
@@ -51,8 +51,8 @@ fn produce_response(witness_replacement: &Scalar, challenge: &Scalar, secret: &S
|
||||
|
||||
// note: it's caller's responsibility to ensure witnesses.len() = secrets.len()
|
||||
fn produce_responses<S>(witnesses: &[Scalar], challenge: &Scalar, secrets: &[S]) -> Vec<Scalar>
|
||||
where
|
||||
S: Borrow<Scalar>,
|
||||
where
|
||||
S: Borrow<Scalar>,
|
||||
{
|
||||
debug_assert_eq!(witnesses.len(), secrets.len());
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use bls12_381::{G1Projective, G2Projective, Scalar};
|
||||
use group::{Curve, Group, GroupEncoding};
|
||||
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses};
|
||||
use crate::proofs::{compute_challenge, produce_response, produce_responses, ChallengeDigest};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::utils::{try_deserialize_g1_projective, try_deserialize_g2_projective};
|
||||
@@ -14,11 +14,11 @@ use crate::utils::{try_deserialize_g1_projective, try_deserialize_g2_projective}
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct SpendInstance {
|
||||
pub kappa: G2Projective,
|
||||
pub A: G1Projective,
|
||||
pub C: G1Projective,
|
||||
pub D: G1Projective,
|
||||
pub S: G1Projective,
|
||||
pub T: G1Projective,
|
||||
pub aa: G1Projective,
|
||||
pub cc: G1Projective,
|
||||
pub dd: G1Projective,
|
||||
pub ss: G1Projective,
|
||||
pub tt: G1Projective,
|
||||
pub kappa_l: G2Projective,
|
||||
}
|
||||
|
||||
@@ -41,29 +41,29 @@ impl TryFrom<&[u8]> for SpendInstance {
|
||||
&kappa_bytes,
|
||||
CompactEcashError::Deserialization("Failed to deserialize kappa".to_string()),
|
||||
)?;
|
||||
let A_bytes = bytes[96..144].try_into().unwrap();
|
||||
let A = try_deserialize_g1_projective(
|
||||
&A_bytes,
|
||||
let aa_bytes = bytes[96..144].try_into().unwrap();
|
||||
let aa = try_deserialize_g1_projective(
|
||||
&aa_bytes,
|
||||
CompactEcashError::Deserialization("Failed to deserialize A".to_string()),
|
||||
)?;
|
||||
let C_bytes = bytes[144..192].try_into().unwrap();
|
||||
let C = try_deserialize_g1_projective(
|
||||
&C_bytes,
|
||||
let cc_bytes = bytes[144..192].try_into().unwrap();
|
||||
let cc = try_deserialize_g1_projective(
|
||||
&cc_bytes,
|
||||
CompactEcashError::Deserialization("Failed to deserialize C".to_string()),
|
||||
)?;
|
||||
let D_bytes = bytes[192..240].try_into().unwrap();
|
||||
let D = try_deserialize_g1_projective(
|
||||
&D_bytes,
|
||||
let dd_bytes = bytes[192..240].try_into().unwrap();
|
||||
let dd = try_deserialize_g1_projective(
|
||||
&dd_bytes,
|
||||
CompactEcashError::Deserialization("Failed to deserialize D".to_string()),
|
||||
)?;
|
||||
let S_bytes = bytes[240..288].try_into().unwrap();
|
||||
let S = try_deserialize_g1_projective(
|
||||
&S_bytes,
|
||||
let ss_bytes = bytes[240..288].try_into().unwrap();
|
||||
let ss = try_deserialize_g1_projective(
|
||||
&ss_bytes,
|
||||
CompactEcashError::Deserialization("Failed to deserialize S".to_string()),
|
||||
)?;
|
||||
let T_bytes = bytes[288..336].try_into().unwrap();
|
||||
let T = try_deserialize_g1_projective(
|
||||
&T_bytes,
|
||||
let tt_bytes = bytes[288..336].try_into().unwrap();
|
||||
let tt = try_deserialize_g1_projective(
|
||||
&tt_bytes,
|
||||
CompactEcashError::Deserialization("Failed to deserialize T".to_string()),
|
||||
)?;
|
||||
let kappa_l_bytes = bytes[336..432].try_into().unwrap();
|
||||
@@ -74,11 +74,11 @@ impl TryFrom<&[u8]> for SpendInstance {
|
||||
|
||||
Ok(SpendInstance {
|
||||
kappa,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
S,
|
||||
T,
|
||||
aa,
|
||||
cc,
|
||||
dd,
|
||||
ss,
|
||||
tt,
|
||||
kappa_l,
|
||||
})
|
||||
}
|
||||
@@ -88,11 +88,11 @@ impl SpendInstance {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = Vec::with_capacity(2 * 96 + 5 * 48);
|
||||
bytes.extend_from_slice(self.kappa.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.A.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.C.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.D.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.S.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.T.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.aa.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.cc.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.dd.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.ss.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.tt.to_bytes().as_ref());
|
||||
bytes.extend_from_slice(self.kappa_l.to_bytes().as_ref());
|
||||
bytes
|
||||
}
|
||||
@@ -136,7 +136,7 @@ impl SpendProof {
|
||||
instance: &SpendInstance,
|
||||
witness: &SpendWitness,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
R: Scalar,
|
||||
rr: Scalar,
|
||||
) -> Self {
|
||||
let grparams = params.grp();
|
||||
// generate random values to replace each witness
|
||||
@@ -167,21 +167,19 @@ impl SpendProof {
|
||||
let zkcm_kappa = grparams.gen2() * r_r
|
||||
+ verification_key.alpha
|
||||
+ r_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
let zkcm_A = g1 * r_o_a + gamma1 * r_l;
|
||||
let zkcm_C = g1 * r_o_c + gamma1 * r_v;
|
||||
let zkcm_D = g1 * r_o_d + gamma1 * r_t;
|
||||
let zkcm_S = g1 * r_mu;
|
||||
let zkcm_gamma11 = (instance.A + instance.C + gamma1) * r_mu + g1 * r_o_mu;
|
||||
let zkcm_T = g1 * r_sk + (g1 * R) * r_lambda;
|
||||
let zkcm_gamma12 = (instance.A + instance.D + gamma1) * r_lambda + g1 * r_o_lambda;
|
||||
let zkcm_kappa_l = grparams.gen2() * r_r_l
|
||||
+ params.pkRP().alpha
|
||||
+ params.pkRP().beta * r_l;
|
||||
let zkcm_aa = g1 * r_o_a + gamma1 * r_l;
|
||||
let zkcm_cc = g1 * r_o_c + gamma1 * r_v;
|
||||
let zkcm_dd = g1 * r_o_d + gamma1 * r_t;
|
||||
let zkcm_ss = g1 * r_mu;
|
||||
let zkcm_gamma11 = (instance.aa + instance.cc + gamma1) * r_mu + g1 * r_o_mu;
|
||||
let zkcm_tt = g1 * r_sk + (g1 * rr) * r_lambda;
|
||||
let zkcm_gamma12 = (instance.aa + instance.dd + gamma1) * r_lambda + g1 * r_o_lambda;
|
||||
let zkcm_kappa_l = grparams.gen2() * r_r_l + params.pkRP().alpha + params.pkRP().beta * r_l;
|
||||
|
||||
// compute the challenge
|
||||
let challenge = compute_challenge::<ChallengeDigest, _, _>(
|
||||
@@ -191,15 +189,15 @@ impl SpendProof {
|
||||
.chain(beta2_bytes.iter().map(|b| b.as_ref()))
|
||||
.chain(std::iter::once(instance.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_kappa.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_A.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_C.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_D.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_S.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_aa.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_cc.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_dd.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_ss.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_kappa_l.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(
|
||||
zkcm_gamma11.to_affine().to_bytes().as_ref(),
|
||||
))
|
||||
.chain(std::iter::once(zkcm_T.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_tt.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(
|
||||
zkcm_gamma12.to_affine().to_bytes().as_ref(),
|
||||
)),
|
||||
@@ -243,7 +241,7 @@ impl SpendProof {
|
||||
params: &Parameters,
|
||||
instance: &SpendInstance,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
R: Scalar,
|
||||
rr: Scalar,
|
||||
) -> bool {
|
||||
let grparams = params.grp();
|
||||
let g1 = *grparams.gen1();
|
||||
@@ -259,28 +257,28 @@ impl SpendProof {
|
||||
+ grparams.gen2() * self.response_r
|
||||
+ verification_key.alpha * (Scalar::one() - self.challenge)
|
||||
+ self
|
||||
.response_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
.response_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
let zkcm_A =
|
||||
g1 * self.response_o_a + gamma1 * self.response_l + instance.A * self.challenge;
|
||||
let zkcm_C = g1 * self.response_o_c
|
||||
let zkcm_aa =
|
||||
g1 * self.response_o_a + gamma1 * self.response_l + instance.aa * self.challenge;
|
||||
let zkcm_cc = g1 * self.response_o_c
|
||||
+ gamma1 * self.response_attributes[1]
|
||||
+ instance.C * self.challenge;
|
||||
let zkcm_D = g1 * self.response_o_d
|
||||
+ instance.cc * self.challenge;
|
||||
let zkcm_dd = g1 * self.response_o_d
|
||||
+ gamma1 * self.response_attributes[2]
|
||||
+ instance.D * self.challenge;
|
||||
let zkcm_S = g1 * self.response_mu + instance.S * self.challenge;
|
||||
let zkcm_gamma11 = (instance.A + instance.C + gamma1) * self.response_mu
|
||||
+ instance.dd * self.challenge;
|
||||
let zkcm_ss = g1 * self.response_mu + instance.ss * self.challenge;
|
||||
let zkcm_gamma11 = (instance.aa + instance.cc + gamma1) * self.response_mu
|
||||
+ g1 * self.response_o_mu
|
||||
+ gamma1 * self.challenge;
|
||||
let zkcm_T = g1 * self.response_attributes[0]
|
||||
+ (g1 * R) * self.response_lambda
|
||||
+ instance.T * self.challenge;
|
||||
let zkcm_gamma12 = (instance.A + instance.D + gamma1) * self.response_lambda
|
||||
let zkcm_tt = g1 * self.response_attributes[0]
|
||||
+ (g1 * rr) * self.response_lambda
|
||||
+ instance.tt * self.challenge;
|
||||
let zkcm_gamma12 = (instance.aa + instance.dd + gamma1) * self.response_lambda
|
||||
+ g1 * self.response_o_lambda
|
||||
+ gamma1 * self.challenge;
|
||||
|
||||
@@ -297,15 +295,15 @@ impl SpendProof {
|
||||
.chain(beta2_bytes.iter().map(|b| b.as_ref()))
|
||||
.chain(std::iter::once(instance.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_kappa.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_A.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_C.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_D.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_S.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_aa.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_cc.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_dd.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_ss.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_kappa_l.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(
|
||||
zkcm_gamma11.to_affine().to_bytes().as_ref(),
|
||||
))
|
||||
.chain(std::iter::once(zkcm_T.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(zkcm_tt.to_bytes().as_ref()))
|
||||
.chain(std::iter::once(
|
||||
zkcm_gamma12.to_affine().to_bytes().as_ref(),
|
||||
)),
|
||||
@@ -319,14 +317,14 @@ impl SpendProof {
|
||||
mod tests {
|
||||
use bls12_381::{G1Projective, G2Projective, Scalar};
|
||||
use group::Curve;
|
||||
use rand::thread_rng;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::{pseudorandom_fgt, pseudorandom_fgv};
|
||||
use crate::scheme::aggregation::aggregate_verification_keys;
|
||||
use crate::scheme::keygen::{PublicKeyUser, ttp_keygen, VerificationKeyAuth};
|
||||
use crate::scheme::keygen::{ttp_keygen, PublicKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::{setup, GroupParameters};
|
||||
use crate::scheme::PayInfo;
|
||||
use crate::scheme::setup::{GroupParameters, setup};
|
||||
use crate::scheme::{pseudorandom_fgt, pseudorandom_fgv};
|
||||
use crate::utils::hash_to_scalar;
|
||||
|
||||
#[test]
|
||||
@@ -350,6 +348,7 @@ mod tests {
|
||||
let v = grparams.random_scalar();
|
||||
let t = grparams.random_scalar();
|
||||
let attributes = vec![sk, v, t];
|
||||
// the below value must be from range 0 to params.L()
|
||||
let l = 5;
|
||||
let gamma1 = *grparams.gamma1();
|
||||
let g1 = *grparams.gen1();
|
||||
@@ -358,27 +357,27 @@ mod tests {
|
||||
let kappa = grparams.gen2() * r
|
||||
+ verification_key.alpha
|
||||
+ attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>();
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
let o_a = grparams.random_scalar();
|
||||
let o_c = grparams.random_scalar();
|
||||
let o_d = grparams.random_scalar();
|
||||
|
||||
// compute commitments A, C, D
|
||||
let A = g1 * o_a + gamma1 * Scalar::from(l);
|
||||
let C = g1 * o_c + gamma1 * v;
|
||||
let D = g1 * o_d + gamma1 * t;
|
||||
let aa = g1 * o_a + gamma1 * Scalar::from(l);
|
||||
let cc = g1 * o_c + gamma1 * v;
|
||||
let dd = g1 * o_d + gamma1 * t;
|
||||
|
||||
// compute hash of the payment info
|
||||
let payInfo = PayInfo { info: [37u8; 32] };
|
||||
let R = hash_to_scalar(payInfo.info);
|
||||
let pay_info = PayInfo { info: [37u8; 32] };
|
||||
let rr = hash_to_scalar(pay_info.info);
|
||||
|
||||
// evaluate the pseudorandom functions
|
||||
let S = pseudorandom_fgv(&grparams, v, l);
|
||||
let T = g1 * sk + pseudorandom_fgt(&grparams, t, l) * R;
|
||||
let ss = pseudorandom_fgv(&grparams, v, l);
|
||||
let tt = g1 * sk + pseudorandom_fgt(&grparams, t, l) * rr;
|
||||
|
||||
// compute values mu, o_mu, lambda, o_lambda
|
||||
let mu: Scalar = (v + Scalar::from(l) + Scalar::from(1)).invert().unwrap();
|
||||
@@ -387,21 +386,20 @@ mod tests {
|
||||
let o_lambda = ((o_a + o_d) * lambda).neg();
|
||||
|
||||
// parse the signature associated with value l
|
||||
let sign_l = params.get_sign_by_idx(l);
|
||||
let sign_l = params.get_sign_by_idx(l).unwrap();
|
||||
// randomise the signature associated with value l
|
||||
let (sign_l_prime, r_l) = sign_l.randomise(grparams);
|
||||
// compute kappa_l
|
||||
let kappa_l = grparams.gen2() * r_l
|
||||
+ params.pkRP().alpha
|
||||
+ params.pkRP().beta * Scalar::from(l);
|
||||
let kappa_l =
|
||||
grparams.gen2() * r_l + params.pkRP().alpha + params.pkRP().beta * Scalar::from(l);
|
||||
|
||||
let instance = SpendInstance {
|
||||
kappa,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
S,
|
||||
T,
|
||||
aa,
|
||||
cc,
|
||||
dd,
|
||||
ss,
|
||||
tt,
|
||||
kappa_l,
|
||||
};
|
||||
|
||||
@@ -418,7 +416,7 @@ mod tests {
|
||||
o_mu,
|
||||
o_lambda,
|
||||
};
|
||||
let zk_proof = SpendProof::construct(¶ms, &instance, &witness, &verification_key, R);
|
||||
assert!(zk_proof.verify(¶ms, &instance, &verification_key, R))
|
||||
let zk_proof = SpendProof::construct(¶ms, &instance, &witness, &verification_key, rr);
|
||||
assert!(zk_proof.verify(¶ms, &instance, &verification_key, rr))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use group::GroupEncoding;
|
||||
use itertools::izip;
|
||||
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses};
|
||||
use crate::proofs::{compute_challenge, produce_response, produce_responses, ChallengeDigest};
|
||||
use crate::scheme::keygen::PublicKeyUser;
|
||||
use crate::scheme::setup::GroupParameters;
|
||||
use crate::utils::try_deserialize_g1_projective;
|
||||
@@ -136,10 +136,10 @@ impl WithdrawalReqProof {
|
||||
// compute zkp commitments for each instance
|
||||
let zkcm_com = params.gen1() * r_com_opening
|
||||
+ r_attributes
|
||||
.iter()
|
||||
.zip(params.gammas().iter())
|
||||
.map(|(rm_i, gamma_i)| gamma_i * rm_i)
|
||||
.sum::<G1Projective>();
|
||||
.iter()
|
||||
.zip(params.gammas().iter())
|
||||
.map(|(rm_i, gamma_i)| gamma_i * rm_i)
|
||||
.sum::<G1Projective>();
|
||||
|
||||
let zkcm_pedcom = r_pedcom_openings
|
||||
.iter()
|
||||
@@ -192,26 +192,30 @@ impl WithdrawalReqProof {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn verify(&self, params: &GroupParameters, instance: &WithdrawalReqInstance) -> bool {
|
||||
pub(crate) fn verify(
|
||||
&self,
|
||||
params: &GroupParameters,
|
||||
instance: &WithdrawalReqInstance,
|
||||
) -> bool {
|
||||
// recompute zk commitments for each instance
|
||||
let zkcm_com = instance.com * self.challenge
|
||||
+ params.gen1() * self.response_opening
|
||||
+ self
|
||||
.response_attributes
|
||||
.iter()
|
||||
.zip(params.gammas().iter())
|
||||
.map(|(m_i, gamma_i)| gamma_i * m_i)
|
||||
.sum::<G1Projective>();
|
||||
.response_attributes
|
||||
.iter()
|
||||
.zip(params.gammas().iter())
|
||||
.map(|(m_i, gamma_i)| gamma_i * m_i)
|
||||
.sum::<G1Projective>();
|
||||
|
||||
let zkcm_pedcom = izip!(
|
||||
instance.pc_coms.iter(),
|
||||
self.response_openings.iter(),
|
||||
self.response_attributes.iter()
|
||||
)
|
||||
.map(|(cm_j, resp_o_j, resp_m_j)| {
|
||||
cm_j * self.challenge + params.gen1() * resp_o_j + instance.h * resp_m_j
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.map(|(cm_j, resp_o_j, resp_m_j)| {
|
||||
cm_j * self.challenge + params.gen1() * resp_o_j + instance.h * resp_m_j
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let zk_commitment_user_sk =
|
||||
instance.pk_user.pk * self.challenge + params.gen1() * self.response_attributes[0];
|
||||
@@ -288,10 +292,10 @@ mod tests {
|
||||
let com_opening = params.random_scalar();
|
||||
let com = params.gen1() * com_opening
|
||||
+ attr
|
||||
.iter()
|
||||
.zip(params.gammas())
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
.iter()
|
||||
.zip(params.gammas())
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
let h = hash_g1(com.to_bytes());
|
||||
|
||||
let pc_openings = params.n_random_scalars(attr.len());
|
||||
|
||||
@@ -6,16 +6,16 @@ use bls12_381::{G2Prepared, G2Projective, Scalar};
|
||||
use group::Curve;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::Attribute;
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::scheme::{PartialWallet, Wallet};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::GroupParameters;
|
||||
use crate::scheme::withdrawal::RequestInfo;
|
||||
use crate::scheme::{PartialWallet, Wallet};
|
||||
use crate::utils::{
|
||||
check_bilinear_pairing, PartialSignature, perform_lagrangian_interpolation_at_origin,
|
||||
check_bilinear_pairing, perform_lagrangian_interpolation_at_origin, PartialSignature,
|
||||
Signature, SignatureShare, SignerIndex,
|
||||
};
|
||||
use crate::Attribute;
|
||||
|
||||
pub(crate) trait Aggregatable: Sized {
|
||||
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
|
||||
@@ -27,10 +27,10 @@ pub(crate) trait Aggregatable: Sized {
|
||||
}
|
||||
|
||||
impl<T> Aggregatable for T
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> T: Sum<&'a T>,
|
||||
for<'a> &'a T: Mul<Scalar, Output=T>,
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> T: Sum<&'a T>,
|
||||
for<'a> &'a T: Mul<Scalar, Output = T>,
|
||||
{
|
||||
fn aggregate(aggregatable: &[T], indices: Option<&[u64]>) -> Result<T> {
|
||||
if aggregatable.is_empty() {
|
||||
@@ -145,9 +145,9 @@ pub fn aggregate_signatures(
|
||||
pub fn aggregate_wallets(
|
||||
params: &GroupParameters,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
skUser: &SecretKeyUser,
|
||||
sk_user: &SecretKeyUser,
|
||||
wallets: &[PartialWallet],
|
||||
reqInfo: &RequestInfo,
|
||||
req_info: &RequestInfo,
|
||||
) -> Result<Wallet> {
|
||||
// Aggregate partial wallets
|
||||
let signature_shares: Vec<SignatureShare> = wallets
|
||||
@@ -156,14 +156,14 @@ pub fn aggregate_wallets(
|
||||
.map(|(idx, wallet)| SignatureShare::new(*wallet.signature(), (idx + 1) as u64))
|
||||
.collect();
|
||||
|
||||
let attributes = vec![skUser.sk, reqInfo.get_v(), reqInfo.get_t()];
|
||||
let attributes = vec![sk_user.sk, req_info.get_v(), req_info.get_t()];
|
||||
let aggregated_signature =
|
||||
aggregate_signature_shares(¶ms, &verification_key, &attributes, &signature_shares)?;
|
||||
|
||||
Ok(Wallet {
|
||||
sig: aggregated_signature,
|
||||
v: reqInfo.get_v(),
|
||||
t: reqInfo.get_t(),
|
||||
v: req_info.get_v(),
|
||||
t: req_info.get_t(),
|
||||
l: Cell::new(0),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,11 +2,8 @@ use crate::error::Result;
|
||||
use crate::scheme::keygen::PublicKeyUser;
|
||||
use crate::scheme::Payment;
|
||||
|
||||
pub fn identify(
|
||||
pay1: Payment,
|
||||
pay2: Payment,
|
||||
) -> Result<PublicKeyUser> {
|
||||
pub fn identify(pay1: Payment, pay2: Payment) -> Result<PublicKeyUser> {
|
||||
// TODO: We should include here the check for S and payInfo
|
||||
let pkUser = (pay2.T * pay1.R - pay1.T * pay2.R) * ((pay1.R - pay2.R).invert().unwrap());
|
||||
Ok(PublicKeyUser { pk: pkUser })
|
||||
let pk_user = (pay2.tt * pay1.rr - pay1.tt * pay2.rr) * ((pay1.rr - pay2.rr).invert().unwrap());
|
||||
Ok(PublicKeyUser { pk: pk_user })
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ use crate::error::{CompactEcashError, Result};
|
||||
use crate::scheme::aggregation::aggregate_verification_keys;
|
||||
use crate::scheme::setup::GroupParameters;
|
||||
use crate::scheme::SignerIndex;
|
||||
use crate::utils::Polynomial;
|
||||
use crate::utils::{
|
||||
try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar,
|
||||
try_deserialize_scalar_vec,
|
||||
};
|
||||
use crate::utils::Polynomial;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SecretKeyAuth {
|
||||
@@ -242,13 +242,13 @@ impl<'a> Mul<Scalar> for &'a VerificationKeyAuth {
|
||||
}
|
||||
|
||||
impl<T> Sum<T> for VerificationKeyAuth
|
||||
where
|
||||
T: Borrow<VerificationKeyAuth>,
|
||||
where
|
||||
T: Borrow<VerificationKeyAuth>,
|
||||
{
|
||||
#[inline]
|
||||
fn sum<I>(iter: I) -> Self
|
||||
where
|
||||
I: Iterator<Item=T>,
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
{
|
||||
let mut peekable = iter.peekable();
|
||||
let head_attributes = match peekable.peek() {
|
||||
@@ -440,4 +440,3 @@ pub fn ttp_keygen(
|
||||
|
||||
Ok(keypairs)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@ use std::convert::TryInto;
|
||||
use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
|
||||
use group::{Curve, Group};
|
||||
|
||||
use crate::Attribute;
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::utils::{
|
||||
check_bilinear_pairing, hash_to_scalar, Signature, SignerIndex, try_deserialize_g1_projective,
|
||||
check_bilinear_pairing, hash_to_scalar, try_deserialize_g1_projective, Signature, SignerIndex,
|
||||
};
|
||||
use crate::Attribute;
|
||||
|
||||
pub mod aggregation;
|
||||
pub mod identify;
|
||||
@@ -71,8 +71,8 @@ impl Wallet {
|
||||
&self,
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
skUser: &SecretKeyUser,
|
||||
payInfo: &PayInfo,
|
||||
sk_user: &SecretKeyUser,
|
||||
pay_info: &PayInfo,
|
||||
) -> Result<(Payment, &Self)> {
|
||||
if self.l() > params.L() {
|
||||
return Err(CompactEcashError::Spend(
|
||||
@@ -84,7 +84,7 @@ impl Wallet {
|
||||
// randomize signature in the wallet
|
||||
let (signature_prime, sign_blinding_factor) = self.signature().randomise(grparams);
|
||||
// construct kappa i.e., blinded attributes for show
|
||||
let attributes = vec![skUser.sk, self.v(), self.t()];
|
||||
let attributes = vec![sk_user.sk, self.v(), self.t()];
|
||||
// compute kappa
|
||||
let kappa = compute_kappa(
|
||||
&grparams,
|
||||
@@ -99,16 +99,17 @@ impl Wallet {
|
||||
let o_d = grparams.random_scalar();
|
||||
|
||||
// compute commitments A, C, D
|
||||
let A = grparams.gen1() * o_a + grparams.gamma1() * Scalar::from(self.l());
|
||||
let C = grparams.gen1() * o_c + grparams.gamma1() * self.v();
|
||||
let D = grparams.gen1() * o_d + grparams.gamma1() * self.t();
|
||||
let aa = grparams.gen1() * o_a + grparams.gamma1() * Scalar::from(self.l());
|
||||
let cc = grparams.gen1() * o_c + grparams.gamma1() * self.v();
|
||||
let dd = grparams.gen1() * o_d + grparams.gamma1() * self.t();
|
||||
|
||||
// compute hash of the payment info
|
||||
let R = hash_to_scalar(payInfo.info);
|
||||
let rr = hash_to_scalar(pay_info.info);
|
||||
|
||||
// evaluate the pseudorandom functions
|
||||
let S = pseudorandom_fgv(&grparams, self.v(), self.l());
|
||||
let T = grparams.gen1() * skUser.sk + pseudorandom_fgt(&grparams, self.t(), self.l()) * R;
|
||||
let ss = pseudorandom_fgv(&grparams, self.v(), self.l());
|
||||
let tt =
|
||||
grparams.gen1() * sk_user.sk + pseudorandom_fgt(&grparams, self.t(), self.l()) * rr;
|
||||
|
||||
// compute values mu, o_mu, lambda, o_lambda
|
||||
let mu: Scalar = (self.v() + Scalar::from(self.l()) + Scalar::from(1))
|
||||
@@ -121,7 +122,7 @@ impl Wallet {
|
||||
let o_lambda = ((o_a + o_d) * lambda).neg();
|
||||
|
||||
// parse the signature associated with value l
|
||||
let sign_l = params.get_sign_by_idx(self.l());
|
||||
let sign_l = params.get_sign_by_idx(self.l())?;
|
||||
// randomise the signature associated with value l
|
||||
let (sign_l_prime, sign_l_blinding_factor) = sign_l.randomise(grparams);
|
||||
// compute kappa_l
|
||||
@@ -130,16 +131,16 @@ impl Wallet {
|
||||
+ params.pkRP().beta * Scalar::from(self.l());
|
||||
|
||||
// construct the zkp proof
|
||||
let spendInstance = SpendInstance {
|
||||
let spend_instance = SpendInstance {
|
||||
kappa,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
S,
|
||||
T,
|
||||
aa,
|
||||
cc,
|
||||
dd,
|
||||
ss,
|
||||
tt,
|
||||
kappa_l,
|
||||
};
|
||||
let spendWitness = SpendWitness {
|
||||
let spend_witness = SpendWitness {
|
||||
attributes,
|
||||
r: sign_blinding_factor,
|
||||
r_l: sign_l_blinding_factor,
|
||||
@@ -152,19 +153,24 @@ impl Wallet {
|
||||
o_mu,
|
||||
o_lambda,
|
||||
};
|
||||
let zk_proof =
|
||||
SpendProof::construct(¶ms, &spendInstance, &spendWitness, &verification_key, R);
|
||||
let zk_proof = SpendProof::construct(
|
||||
¶ms,
|
||||
&spend_instance,
|
||||
&spend_witness,
|
||||
&verification_key,
|
||||
rr,
|
||||
);
|
||||
|
||||
// output pay and updated wallet
|
||||
let pay = Payment {
|
||||
kappa,
|
||||
sig: signature_prime,
|
||||
S,
|
||||
T,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
R,
|
||||
ss,
|
||||
tt,
|
||||
aa,
|
||||
cc,
|
||||
dd,
|
||||
rr,
|
||||
kappa_l,
|
||||
sig_l: sign_l_prime,
|
||||
zk_proof,
|
||||
@@ -195,10 +201,10 @@ pub fn compute_kappa(
|
||||
params.gen2() * blinding_factor
|
||||
+ verification_key.alpha
|
||||
+ attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>()
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>()
|
||||
}
|
||||
|
||||
pub struct PayInfo {
|
||||
@@ -209,12 +215,12 @@ pub struct PayInfo {
|
||||
pub struct Payment {
|
||||
pub kappa: G2Projective,
|
||||
pub sig: Signature,
|
||||
pub S: G1Projective,
|
||||
pub T: G1Projective,
|
||||
pub A: G1Projective,
|
||||
pub C: G1Projective,
|
||||
pub D: G1Projective,
|
||||
pub R: Scalar,
|
||||
pub ss: G1Projective,
|
||||
pub tt: G1Projective,
|
||||
pub aa: G1Projective,
|
||||
pub cc: G1Projective,
|
||||
pub dd: G1Projective,
|
||||
pub rr: Scalar,
|
||||
pub kappa_l: G2Projective,
|
||||
pub sig_l: Signature,
|
||||
pub zk_proof: SpendProof,
|
||||
@@ -225,7 +231,7 @@ impl Payment {
|
||||
&self,
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
payinfo: &PayInfo,
|
||||
pay_info: &PayInfo,
|
||||
) -> Result<bool> {
|
||||
if bool::from(self.sig.0.is_identity()) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
@@ -244,8 +250,25 @@ impl Payment {
|
||||
));
|
||||
}
|
||||
|
||||
if bool::from(self.sig_l.0.is_identity()) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The element h of the signature on l equals the identity".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !check_bilinear_pairing(
|
||||
&self.sig_l.0.to_affine(),
|
||||
&G2Prepared::from(self.kappa_l.to_affine()),
|
||||
&self.sig_l.1.to_affine(),
|
||||
params.grp().prepared_miller_g2(),
|
||||
) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The bilinear check for kappa_l failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// verify integrity of R
|
||||
if !(self.R == hash_to_scalar(payinfo.info)) {
|
||||
if !(self.rr == hash_to_scalar(pay_info.info)) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"Integrity of R does not hold".to_string(),
|
||||
));
|
||||
@@ -256,17 +279,17 @@ impl Payment {
|
||||
// verify the zk proof
|
||||
let instance = SpendInstance {
|
||||
kappa: self.kappa,
|
||||
A: self.A,
|
||||
C: self.C,
|
||||
D: self.D,
|
||||
S: self.S,
|
||||
T: self.T,
|
||||
aa: self.aa,
|
||||
cc: self.cc,
|
||||
dd: self.dd,
|
||||
ss: self.ss,
|
||||
tt: self.tt,
|
||||
kappa_l: self.kappa_l,
|
||||
};
|
||||
|
||||
if !self
|
||||
.zk_proof
|
||||
.verify(¶ms, &instance, &verification_key, self.R)
|
||||
.verify(¶ms, &instance, &verification_key, self.rr)
|
||||
{
|
||||
return Err(CompactEcashError::Spend(
|
||||
"ZkProof verification failed".to_string(),
|
||||
|
||||
@@ -5,7 +5,7 @@ use ff::Field;
|
||||
use group::{Curve, GroupEncoding};
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::utils::{hash_g1, Signature};
|
||||
|
||||
const ATTRIBUTES_LEN: usize = 3;
|
||||
@@ -28,13 +28,11 @@ impl GroupParameters {
|
||||
.map(|i| hash_g1(format!("gamma{}", i)))
|
||||
.collect();
|
||||
|
||||
|
||||
Ok(GroupParameters {
|
||||
g1: G1Affine::generator(),
|
||||
g2: G2Affine::generator(),
|
||||
gammas,
|
||||
_g2_prepared_miller: G2Prepared::from(G2Affine::generator()),
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,7 +75,6 @@ impl GroupParameters {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SecretKeyRP {
|
||||
pub(crate) x: Scalar,
|
||||
@@ -86,7 +83,10 @@ pub struct SecretKeyRP {
|
||||
|
||||
impl SecretKeyRP {
|
||||
pub fn public_key(&self, params: &GroupParameters) -> PublicKeyRP {
|
||||
PublicKeyRP { alpha: params.gen2() * self.x, beta: params.gen2() * self.y }
|
||||
PublicKeyRP {
|
||||
alpha: params.gen2() * self.x,
|
||||
beta: params.gen2() * self.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,11 +108,30 @@ pub struct Parameters {
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub fn grp(&self) -> &GroupParameters { &self.grp }
|
||||
pub fn pkRP(&self) -> &PublicKeyRP { &self.pkRP }
|
||||
pub fn L(&self) -> u64 { self.L }
|
||||
pub fn signs(&self) -> &HashMap<u64, Signature> { &self.signs }
|
||||
pub fn get_sign_by_idx(&self, idx: u64) -> &Signature { self.signs.get(&idx).unwrap() }
|
||||
pub fn grp(&self) -> &GroupParameters {
|
||||
&self.grp
|
||||
}
|
||||
pub fn pkRP(&self) -> &PublicKeyRP {
|
||||
&self.pkRP
|
||||
}
|
||||
pub fn L(&self) -> u64 {
|
||||
self.L
|
||||
}
|
||||
pub fn signs(&self) -> &HashMap<u64, Signature> {
|
||||
&self.signs
|
||||
}
|
||||
pub fn get_sign_by_idx(&self, idx: u64) -> Result<&Signature> {
|
||||
match self.signs.get(&idx) {
|
||||
Some(val) => return Ok(val),
|
||||
None => {
|
||||
return Err(CompactEcashError::RangeProofOutOfBound(
|
||||
"Cannot find the range proof signature for the given value. \
|
||||
Check if the requested value is within the bound 0..L"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup() -> Parameters {
|
||||
@@ -125,7 +144,13 @@ pub fn setup() -> Parameters {
|
||||
for l in 0..MAX_COIN_VALUE {
|
||||
let r = grp.random_scalar();
|
||||
let h = grp.gen1() * r;
|
||||
signs.insert(l, Signature { 0: h, 1: h * (x + y * Scalar::from(l)) });
|
||||
signs.insert(
|
||||
l,
|
||||
Signature {
|
||||
0: h,
|
||||
1: h * (x + y * Scalar::from(l)),
|
||||
},
|
||||
);
|
||||
}
|
||||
Parameters {
|
||||
grp,
|
||||
@@ -134,5 +159,3 @@ pub fn setup() -> Parameters {
|
||||
signs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ use crate::error::{CompactEcashError, Result};
|
||||
use crate::proofs::proof_withdrawal::{
|
||||
WithdrawalReqInstance, WithdrawalReqProof, WithdrawalReqWitness,
|
||||
};
|
||||
use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::keygen::ttp_keygen;
|
||||
use crate::scheme::PartialWallet;
|
||||
use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::scheme::PartialWallet;
|
||||
use crate::utils::{check_bilinear_pairing, hash_g1};
|
||||
use crate::utils::{BlindedSignature, Signature};
|
||||
|
||||
@@ -57,10 +57,10 @@ pub fn withdrawal_request(
|
||||
let com_opening = params.random_scalar();
|
||||
let com = params.gen1() * com_opening
|
||||
+ attributes
|
||||
.iter()
|
||||
.zip(gammas)
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
.iter()
|
||||
.zip(gammas)
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
|
||||
// Value h in the paper
|
||||
let com_hash = hash_g1(com.to_bytes());
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use itertools::izip;
|
||||
|
||||
use crate::error::CompactEcashError;
|
||||
use crate::scheme::{PartialWallet, Payment, pseudorandom_fgt};
|
||||
use crate::scheme::aggregation::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, aggregate_wallets,
|
||||
};
|
||||
use crate::scheme::identify::identify;
|
||||
use crate::scheme::keygen::{
|
||||
generate_keypair_user, PublicKeyUser, SecretKeyUser, ttp_keygen, VerificationKeyAuth,
|
||||
generate_keypair_user, ttp_keygen, PublicKeyUser, SecretKeyUser, VerificationKeyAuth,
|
||||
};
|
||||
use crate::scheme::PayInfo;
|
||||
use crate::scheme::setup::{GroupParameters, Parameters, setup};
|
||||
use crate::scheme::setup::{setup, GroupParameters, Parameters};
|
||||
use crate::scheme::withdrawal::{issue_verify, issue_wallet, withdrawal_request};
|
||||
use crate::scheme::PayInfo;
|
||||
use crate::scheme::{pseudorandom_fgt, PartialWallet, Payment};
|
||||
use crate::utils::{hash_to_scalar, SignatureShare};
|
||||
|
||||
#[test]
|
||||
@@ -45,8 +45,8 @@ fn main() -> Result<(), CompactEcashError> {
|
||||
wallet_blinded_signatures.iter(),
|
||||
verification_keys_auth.iter()
|
||||
)
|
||||
.map(|(w, vk)| issue_verify(&grparams, vk, &user_keypair.secret_key(), w, &req_info).unwrap())
|
||||
.collect();
|
||||
.map(|(w, vk)| issue_verify(&grparams, vk, &user_keypair.secret_key(), w, &req_info).unwrap())
|
||||
.collect();
|
||||
|
||||
// Aggregate partial wallets
|
||||
let aggr_wallet = aggregate_wallets(
|
||||
@@ -58,40 +58,41 @@ fn main() -> Result<(), CompactEcashError> {
|
||||
)?;
|
||||
|
||||
// Let's try to spend some coins
|
||||
let payInfo = PayInfo { info: [6u8; 32] };
|
||||
let pay_info = PayInfo { info: [6u8; 32] };
|
||||
|
||||
let (payment, upd_wallet) = aggr_wallet.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&user_keypair.secret_key(),
|
||||
&payInfo,
|
||||
&pay_info,
|
||||
)?;
|
||||
|
||||
assert!(payment
|
||||
.spend_verify(¶ms, &verification_key, &payInfo)
|
||||
.spend_verify(¶ms, &verification_key, &pay_info)
|
||||
.unwrap());
|
||||
|
||||
// try to spend twice the same payment with different payInfo.
|
||||
// try to spend twice the same payment with different payInfo
|
||||
let payment1 = payment.clone();
|
||||
let payInfo2 = PayInfo { info: [9u8; 32] };
|
||||
let R2 = hash_to_scalar(payInfo2.info);
|
||||
let pay_info2 = PayInfo { info: [9u8; 32] };
|
||||
let rr2 = hash_to_scalar(pay_info2.info);
|
||||
let l2 = aggr_wallet.l() - 1;
|
||||
let payment2 = Payment {
|
||||
kappa: payment1.kappa.clone(),
|
||||
sig: payment1.sig.clone(),
|
||||
S: payment1.S.clone(),
|
||||
T: grparams.gen1() * user_keypair.secret_key().sk + pseudorandom_fgt(&grparams, aggr_wallet.t(), l2) * R2,
|
||||
A: payment1.A.clone(),
|
||||
C: payment1.C.clone(),
|
||||
D: payment1.D.clone(),
|
||||
R: R2,
|
||||
ss: payment1.ss.clone(),
|
||||
tt: grparams.gen1() * user_keypair.secret_key().sk
|
||||
+ pseudorandom_fgt(&grparams, aggr_wallet.t(), l2) * rr2,
|
||||
aa: payment1.aa.clone(),
|
||||
cc: payment1.cc.clone(),
|
||||
dd: payment1.dd.clone(),
|
||||
rr: rr2,
|
||||
kappa_l: payment1.kappa_l.clone(),
|
||||
sig_l: payment1.sig_l.clone(),
|
||||
zk_proof: payment1.zk_proof.clone(),
|
||||
};
|
||||
|
||||
let identifiedUser = identify(payment1, payment2).unwrap();
|
||||
assert_eq!(user_keypair.public_key().pk, identifiedUser.pk);
|
||||
let identified_user = identify(payment1, payment2).unwrap();
|
||||
assert_eq!(user_keypair.public_key().pk, identified_user.pk);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ use core::ops::Mul;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ops::Neg;
|
||||
|
||||
use bls12_381::{
|
||||
G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, multi_miller_loop, Scalar,
|
||||
};
|
||||
use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField};
|
||||
use bls12_381::{
|
||||
multi_miller_loop, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar,
|
||||
};
|
||||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
|
||||
@@ -85,9 +85,9 @@ pub(crate) fn perform_lagrangian_interpolation_at_origin<T>(
|
||||
points: &[SignerIndex],
|
||||
values: &[T],
|
||||
) -> Result<T>
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> &'a T: Mul<Scalar, Output=T>,
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> &'a T: Mul<Scalar, Output = T>,
|
||||
{
|
||||
if points.is_empty() || values.is_empty() {
|
||||
return Err(CompactEcashError::Interpolation(
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use bls12_381::Scalar;
|
||||
|
||||
mod error;
|
||||
mod proofs;
|
||||
mod scheme;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod error;
|
||||
mod utils;
|
||||
mod traits;
|
||||
mod utils;
|
||||
|
||||
pub type Attribute = Scalar;
|
||||
pub type Attribute = Scalar;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@ pub mod aggregation;
|
||||
pub mod identify;
|
||||
pub mod keygen;
|
||||
pub mod setup;
|
||||
pub mod structure_preserving_signature;
|
||||
pub mod withdrawal;
|
||||
pub mod structure_preserving_signature;
|
||||
@@ -41,7 +41,9 @@ impl GroupParameters {
|
||||
&self._g2_prepared_miller
|
||||
}
|
||||
|
||||
pub(crate) fn getL(&self) -> u64 { self.L }
|
||||
pub(crate) fn getL(&self) -> u64 {
|
||||
self.L
|
||||
}
|
||||
|
||||
pub(crate) fn random_scalar(&self) -> Scalar {
|
||||
// lazily-initialized thread-local random number generator, seeded by the system
|
||||
@@ -60,7 +62,6 @@ pub struct Parameters {
|
||||
paramsAuth: ParametersAuthority,
|
||||
}
|
||||
|
||||
|
||||
impl Parameters {
|
||||
pub fn new(grp: GroupParameters) -> Parameters {
|
||||
let g1 = grp.gen1();
|
||||
@@ -78,10 +79,16 @@ impl Parameters {
|
||||
let sigma = g1 * z;
|
||||
let theta = eta * z;
|
||||
|
||||
let sigmasUser: Vec<G1Projective> = (1..=grp.getL()).map(|i| sigma * (y * Scalar::from(i))).collect();
|
||||
let thetasUser: Vec<G1Projective> = (1..=grp.getL()).map(|i| theta * (y * Scalar::from(i))).collect();
|
||||
let sigmasUser: Vec<G1Projective> = (1..=grp.getL())
|
||||
.map(|i| sigma * (y * Scalar::from(i)))
|
||||
.collect();
|
||||
let thetasUser: Vec<G1Projective> = (1..=grp.getL())
|
||||
.map(|i| theta * (y * Scalar::from(i)))
|
||||
.collect();
|
||||
|
||||
let deltasAuth: Vec<G2Projective> = (0..=grp.getL() - 1).map(|i| g2 * (y * Scalar::from(i))).collect();
|
||||
let deltasAuth: Vec<G2Projective> = (0..=grp.getL() - 1)
|
||||
.map(|i| g2 * (y * Scalar::from(i)))
|
||||
.collect();
|
||||
let etasUser: Vec<G1Projective> = vec_a.iter().map(|x| g1 * x).collect();
|
||||
|
||||
let mut etasAuth: Vec<G2Projective> = Default::default();
|
||||
@@ -137,4 +144,4 @@ pub struct ParametersUser {
|
||||
pub struct ParametersAuthority {
|
||||
deltas: Vec<G2Projective>,
|
||||
etas: Vec<G2Projective>,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ use std::convert::TryFrom;
|
||||
use bls12_381::{G1Projective, G2Projective, Scalar};
|
||||
use group::Curve;
|
||||
|
||||
use crate::Attribute;
|
||||
use crate::scheme::setup::GroupParameters;
|
||||
use crate::Attribute;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct SPSVerificationKey {
|
||||
@@ -24,13 +24,22 @@ pub(crate) struct SPSSecretKey {
|
||||
}
|
||||
|
||||
impl SPSSecretKey {
|
||||
pub fn z(&self) -> Scalar { self.z }
|
||||
pub fn y(&self) -> Scalar { self.y }
|
||||
pub fn z(&self) -> Scalar {
|
||||
self.z
|
||||
}
|
||||
pub fn y(&self) -> Scalar {
|
||||
self.y
|
||||
}
|
||||
pub fn sign(&self, grparams: GroupParameters, attributes: Vec<Attribute>) -> SPSSignature {
|
||||
let r = grparams.random_scalar();
|
||||
let R = grparams.gen1() * r;
|
||||
let prod: Vec<Scalar> = attributes.iter().zip(self.ws.iter()).map(|(w_i, m_i)| m_i * w_i.neg()).collect();
|
||||
let Z = grparams.gen1() * (self.z() - r * self.y()) + prod.iter().fold(1 | acc, x | acc * x);
|
||||
let prod: Vec<Scalar> = attributes
|
||||
.iter()
|
||||
.zip(self.ws.iter())
|
||||
.map(|(w_i, m_i)| m_i * w_i.neg())
|
||||
.collect();
|
||||
let Z =
|
||||
grparams.gen1() * (self.z() - r * self.y()) + prod.iter().fold(1 | acc, x | acc * x);
|
||||
// let sum = a.iter().fold(0, |acc, x| acc + x);
|
||||
// let Z: G1Projective = grparams.gen1() * (self.z() - r * self.y())
|
||||
// + attributes
|
||||
@@ -76,4 +85,3 @@ impl SPSKeyPair {
|
||||
}
|
||||
|
||||
pub struct SPSSignature {}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::error::DivisibleEcashError;
|
||||
|
||||
pub trait Bytable
|
||||
where
|
||||
Self: Sized,
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn to_byte_vec(&self) -> Vec<u8>;
|
||||
|
||||
@@ -10,8 +10,8 @@ pub trait Bytable
|
||||
}
|
||||
|
||||
pub trait Base58
|
||||
where
|
||||
Self: Bytable,
|
||||
where
|
||||
Self: Bytable,
|
||||
{
|
||||
fn try_from_bs58<S: AsRef<str>>(x: S) -> Result<Self, DivisibleEcashError> {
|
||||
Self::try_from_byte_slice(&bs58::decode(x.as_ref()).into_vec().unwrap())
|
||||
|
||||
@@ -6,10 +6,10 @@ use core::ops::Mul;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ops::Neg;
|
||||
|
||||
use bls12_381::{
|
||||
G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, multi_miller_loop, Scalar,
|
||||
};
|
||||
use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField};
|
||||
use bls12_381::{
|
||||
multi_miller_loop, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar,
|
||||
};
|
||||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
|
||||
@@ -85,9 +85,9 @@ pub(crate) fn perform_lagrangian_interpolation_at_origin<T>(
|
||||
points: &[SignerIndex],
|
||||
values: &[T],
|
||||
) -> Result<T>
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> &'a T: Mul<Scalar, Output=T>,
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> &'a T: Mul<Scalar, Output = T>,
|
||||
{
|
||||
if points.is_empty() || values.is_empty() {
|
||||
return Err(DivisibleEcashError::Interpolation(
|
||||
@@ -221,12 +221,16 @@ impl TryFrom<&[u8]> for Signature {
|
||||
|
||||
let sig1 = try_deserialize_g1_projective(
|
||||
sig1_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize compressed sig1".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize compressed sig1".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let sig2 = try_deserialize_g1_projective(
|
||||
sig2_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize compressed sig2".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize compressed sig2".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(Signature(sig1, sig2))
|
||||
|
||||
@@ -27,31 +27,8 @@ pub use scheme::verification::prove_bandwidth_credential;
|
||||
pub use scheme::verification::verify_credential;
|
||||
pub use scheme::verification::Theta;
|
||||
pub use scheme::BlindedSignature;
|
||||
pub use scheme::issuance::blind_sign;
|
||||
pub use scheme::issuance::prepare_blind_sign;
|
||||
pub use scheme::issuance::BlindSignRequest;
|
||||
pub use scheme::keygen::ttp_keygen;
|
||||
pub use scheme::keygen::KeyPair;
|
||||
pub use scheme::keygen::VerificationKey;
|
||||
pub use scheme::setup::setup;
|
||||
pub use scheme::setup::Parameters;
|
||||
pub use scheme::verification::prove_bandwidth_credential;
|
||||
pub use scheme::verification::verify_credential;
|
||||
pub use scheme::verification::Theta;
|
||||
pub use scheme::BlindedSignature;
|
||||
pub use scheme::issuance::blind_sign;
|
||||
pub use scheme::issuance::BlindSignRequest;
|
||||
pub use scheme::issuance::prepare_blind_sign;
|
||||
pub use scheme::keygen::KeyPair;
|
||||
pub use scheme::keygen::ttp_keygen;
|
||||
pub use scheme::keygen::VerificationKey;
|
||||
pub use scheme::setup::Parameters;
|
||||
pub use scheme::setup::setup;
|
||||
pub use scheme::Signature;
|
||||
pub use scheme::SignatureShare;
|
||||
pub use scheme::verification::prove_bandwidth_credential;
|
||||
pub use scheme::verification::Theta;
|
||||
pub use scheme::verification::verify_credential;
|
||||
pub use traits::Base58;
|
||||
pub use utils::hash_to_scalar;
|
||||
|
||||
|
||||
@@ -5,10 +5,9 @@ use core::ops::Neg;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use bls12_381::{G1Affine, G2Prepared, G2Projective, multi_miller_loop, Scalar};
|
||||
use bls12_381::{multi_miller_loop, G1Affine, G2Prepared, G2Projective, Scalar};
|
||||
use group::{Curve, Group};
|
||||
|
||||
use crate::Attribute;
|
||||
use crate::error::{CoconutError, Result};
|
||||
use crate::proofs::ProofKappaZeta;
|
||||
use crate::scheme::double_use::BlindedSerialNumber;
|
||||
@@ -17,6 +16,7 @@ use crate::scheme::Signature;
|
||||
use crate::scheme::VerificationKey;
|
||||
use crate::traits::{Base58, Bytable};
|
||||
use crate::utils::try_deserialize_g2_projective;
|
||||
use crate::Attribute;
|
||||
|
||||
// TODO NAMING: this whole thing
|
||||
// Theta
|
||||
@@ -136,10 +136,10 @@ pub fn compute_kappa(
|
||||
params.gen2() * blinding_factor
|
||||
+ verification_key.alpha
|
||||
+ private_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>()
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>()
|
||||
}
|
||||
|
||||
pub fn compute_zeta(params: &Parameters, serial_number: Attribute) -> G2Projective {
|
||||
@@ -296,11 +296,11 @@ pub fn verify(
|
||||
) -> bool {
|
||||
let kappa = (verification_key.alpha
|
||||
+ public_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(m_i, b_i)| b_i * m_i)
|
||||
.sum::<G2Projective>())
|
||||
.to_affine();
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(m_i, b_i)| b_i * m_i)
|
||||
.sum::<G2Projective>())
|
||||
.to_affine();
|
||||
|
||||
check_bilinear_pairing(
|
||||
&sig.0.to_affine(),
|
||||
@@ -345,7 +345,7 @@ mod tests {
|
||||
serial_number,
|
||||
binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
|
||||
let bytes = theta.to_bytes();
|
||||
assert_eq!(Theta::try_from(bytes.as_slice()).unwrap(), theta);
|
||||
|
||||
Reference in New Issue
Block a user