Add Wallet, Partial Wallet and Payment to and from bytes converstion

This commit is contained in:
aniampio
2023-08-07 11:47:38 +01:00
committed by durch
parent e6bcfb697c
commit f623bfed4c
6 changed files with 679 additions and 10 deletions
@@ -7,7 +7,7 @@ use crate::error::{CompactEcashError, Result};
use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses};
use crate::scheme::keygen::VerificationKeyAuth;
use crate::scheme::setup::Parameters;
use crate::utils::{try_deserialize_g1_projective, try_deserialize_g2_projective};
use crate::utils::{try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar_vec, try_deserialize_scalar};
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
@@ -207,7 +207,7 @@ pub struct SpendWitness {
pub r_k: Vec<Scalar>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct SpendProof {
challenge: Scalar,
response_r: Scalar,
@@ -353,6 +353,7 @@ impl SpendProof {
response_attributes,
}
}
pub fn verify(
&self,
params: &Parameters,
@@ -464,6 +465,210 @@ impl SpendProof {
challenge == self.challenge
}
pub fn to_bytes(&self) -> Vec<u8> {
let challenge_bytes = self.challenge.to_bytes();
let response_r_bytes = self.response_r.to_bytes();
let rrl_len = self.response_r_l.len();
let rrl_len_bytes = rrl_len.to_le_bytes();
let rl_len = self.response_l.len();
let rl_len_bytes = rl_len.to_le_bytes();
let roa_len = self.response_o_a.len();
let roa_len_bytes = roa_len.to_le_bytes();
let roc_bytes = self.response_o_c.to_bytes();
let rmu_len = self.response_mu.len();
let rmu_len_bytes = rmu_len.to_le_bytes();
let romu_len = self.response_o_mu.len();
let romu_len_bytes = romu_len.to_le_bytes();
let rattributes_len = self.response_attributes.len();
let rattributes_len_bytes = rattributes_len.to_le_bytes();
let mut bytes: Vec<u8> = Vec::with_capacity(
96 + (rrl_len + rl_len + roa_len + rmu_len + romu_len + rattributes_len) * 8
+ (rrl_len + rl_len + roa_len + rmu_len + romu_len + rattributes_len) * 32);
bytes.extend_from_slice(&challenge_bytes);
bytes.extend_from_slice(&response_r_bytes);
bytes.extend_from_slice(&roc_bytes);
bytes.extend_from_slice(&rrl_len_bytes);
for rrl in &self.response_r_l {
bytes.extend_from_slice(&rrl.to_bytes());
}
bytes.extend_from_slice(&rl_len_bytes);
for rl in &self.response_l {
bytes.extend_from_slice(&rl.to_bytes());
}
bytes.extend_from_slice(&roa_len_bytes);
for roa in &self.response_o_a {
bytes.extend_from_slice(&roa.to_bytes());
}
bytes.extend_from_slice(&rmu_len_bytes);
for rmu in &self.response_mu {
bytes.extend_from_slice(&rmu.to_bytes());
}
bytes.extend_from_slice(&romu_len_bytes);
for romu in &self.response_o_mu {
bytes.extend_from_slice(&romu.to_bytes());
}
bytes.extend_from_slice(&rattributes_len_bytes);
for rattr in &self.response_attributes {
bytes.extend_from_slice(&rattr.to_bytes());
}
bytes
}
}
impl TryFrom<&[u8]> for SpendProof {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<SpendProof> {
if bytes.len() < 336 || (bytes.len() - 96 - 48) % 32 != 0 {
return Err(CompactEcashError::Deserialization(
"tried to deserialize proof of spending with bytes of invalid length"
.to_string(),
));
}
let mut idx = 0;
let challenge_bytes = bytes[idx..idx + 32].try_into().unwrap();
idx += 32;
let response_r_bytes = bytes[idx..idx + 32].try_into().unwrap();
idx += 32;
let response_o_c_bytes = bytes[idx..idx + 32].try_into().unwrap();
idx += 32;
let challenge = try_deserialize_scalar(
&challenge_bytes,
CompactEcashError::Deserialization("Failed to deserialize challenge".to_string()),
)?;
let response_r = try_deserialize_scalar(
&response_r_bytes,
CompactEcashError::Deserialization("Failed to deserialize response_r".to_string()),
)?;
let response_o_c = try_deserialize_scalar(
&response_o_c_bytes,
CompactEcashError::Deserialization("Failed to deserialize response_o_c".to_string()),
)?;
let rrl_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap());
idx += 8;
if bytes[idx..].len() < rrl_len as usize * 32 {
return Err(
CompactEcashError::Deserialization(
"tried to deserialize response_r_l".to_string()),
);
}
let rrl_end = idx + rrl_len as usize * 32;
let response_r_l = try_deserialize_scalar_vec(
rrl_len,
&bytes[idx..rrl_end],
CompactEcashError::Deserialization("Failed to deserialize response_r_l".to_string()),
)?;
let rl_len = u64::from_le_bytes(bytes[rrl_end..rrl_end + 8].try_into().unwrap());
let response_l_start = rrl_end + 8;
if bytes[response_l_start..].len() < rl_len as usize * 32 {
return Err(CompactEcashError::Deserialization(
"tried to deserialize response_l".to_string(),
));
}
let rl_end = response_l_start + rl_len as usize * 32;
let response_l = try_deserialize_scalar_vec(
rl_len,
&bytes[response_l_start..rl_end],
CompactEcashError::Deserialization("Failed to deserialize response_l".to_string()),
)?;
let roa_len = u64::from_le_bytes(bytes[rl_end..rl_end + 8].try_into().unwrap());
let roa_end = rl_end + 8;
if bytes[roa_end..].len() < roa_len as usize * 32 {
return Err(CompactEcashError::Deserialization(
"tried to deserialize response_o_a".to_string(),
));
}
let roa_end = roa_end + roa_len as usize * 32;
let response_o_a = try_deserialize_scalar_vec(
roa_len,
&bytes[rl_end + 8..roa_end],
CompactEcashError::Deserialization("Failed to deserialize response_o_a".to_string()),
)?;
let response_mu_len = u64::from_le_bytes(bytes[roa_end..roa_end + 8].try_into().unwrap());
let response_mu_end = roa_end + 8;
if bytes[response_mu_end..].len() < response_mu_len as usize * 32 {
return Err(CompactEcashError::Deserialization(
"tried to deserialize response_mu".to_string(),
));
}
let response_mu_end = response_mu_end + response_mu_len as usize * 32;
let response_mu = try_deserialize_scalar_vec(
response_mu_len,
&bytes[roa_end + 8..response_mu_end],
CompactEcashError::Deserialization("Failed to deserialize response_mu".to_string()),
)?;
let response_o_mu_len = u64::from_le_bytes(bytes[response_mu_end..response_mu_end + 8].try_into().unwrap());
let response_o_mu_end = response_mu_end + 8;
if bytes[response_o_mu_end..].len() < response_o_mu_len as usize * 32 {
return Err(CompactEcashError::Deserialization(
"tried to deserialize response_o_mu".to_string(),
));
}
let response_o_mu_end = response_o_mu_end + response_o_mu_len as usize * 32;
let response_o_mu = try_deserialize_scalar_vec(
response_o_mu_len,
&bytes[response_mu_end + 8..response_o_mu_end],
CompactEcashError::Deserialization("Failed to deserialize response_o_mu".to_string()),
)?;
let response_attributes_len = u64::from_le_bytes(bytes[response_o_mu_end..response_o_mu_end + 8].try_into().unwrap());
let response_attributes_end = response_o_mu_end + 8;
if bytes[response_attributes_end..].len() < response_attributes_len as usize * 32 {
return Err(CompactEcashError::Deserialization(
"tried to deserialize response_attributes".to_string(),
));
}
let response_attributes_end = response_attributes_end + response_attributes_len as usize * 32;
let response_attributes = try_deserialize_scalar_vec(
response_attributes_len,
&bytes[response_o_mu_end + 8..response_attributes_end],
CompactEcashError::Deserialization("Failed to deserialize response_attributes".to_string()),
)?;
// Construct the SpendProof struct from the deserialized data
let spend_proof = SpendProof {
challenge,
response_r,
response_o_c,
response_r_l,
response_l,
response_o_a,
response_mu,
response_o_mu,
response_attributes,
};
Ok(spend_proof)
}
}
#[cfg(test)]
@@ -563,6 +768,10 @@ mod tests {
};
let zk_proof = SpendProof::construct(&params, &instance, &witness, &verification_key, &[rr]);
assert!(zk_proof.verify(&params, &instance, &verification_key, &[rr]))
assert!(zk_proof.verify(&params, &instance, &verification_key, &[rr]));
let zk_proof_bytes = zk_proof.to_bytes();
let zk_proof2 = SpendProof::try_from(zk_proof_bytes.as_slice()).unwrap();
assert_eq!(zk_proof, zk_proof2);
}
}
@@ -8,7 +8,7 @@ use crate::error::{CompactEcashError, Result};
use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses};
use crate::scheme::keygen::PublicKeyUser;
use crate::scheme::setup::GroupParameters;
use crate::utils::try_deserialize_g1_projective;
use crate::utils::{try_deserialize_g1_projective, try_deserialize_scalar_vec, try_deserialize_scalar};
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
@@ -115,6 +115,7 @@ pub struct WithdrawalReqWitness {
pub pc_coms_openings: Vec<Scalar>,
}
#[derive(Debug, PartialEq)]
pub struct WithdrawalReqProof {
challenge: Scalar,
response_opening: Scalar,
@@ -244,8 +245,89 @@ impl WithdrawalReqProof {
challenge == self.challenge
}
pub fn to_bytes(&self) -> Vec<u8>{
let challenge_bytes = self.challenge.to_bytes();
let response_opening_bytes = self.response_opening.to_bytes();
let ro_len = self.response_openings.len() as u64;
let ra_len = self.response_attributes.len() as u64;
let mut bytes = Vec::with_capacity(32 + 32 + 8 + ro_len as usize * 32 + 8 + ra_len as usize * 32);
bytes.extend_from_slice(&challenge_bytes);
bytes.extend_from_slice(&response_opening_bytes);
bytes.extend_from_slice(&ro_len.to_le_bytes());
for ro in &self.response_openings {
bytes.extend_from_slice(&ro.to_bytes());
}
bytes.extend_from_slice(&ra_len.to_le_bytes());
for ra in &self.response_attributes {
bytes.extend_from_slice(&ra.to_bytes());
}
bytes
}
}
impl TryFrom<&[u8]> for WithdrawalReqProof {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<WithdrawalReqProof> {
if bytes.len() < 32 + 32 + 16 + 32 + 32 || (bytes.len() - 16) % 32 != 0 {
return Err(CompactEcashError::Deserialization(
"tried to deserialize proof of withdrawal with bytes of invalid length"
.to_string(),
));
}
let mut idx = 0;
let challenge_bytes = bytes[idx..idx + 32].try_into().unwrap();
idx += 32;
let response_opening_bytes = bytes[idx..idx + 32].try_into().unwrap();
idx += 32;
let challenge = try_deserialize_scalar(
&challenge_bytes,
CompactEcashError::Deserialization("Failed to deserialize challenge".to_string()),
)?;
let response_opening = try_deserialize_scalar(
&response_opening_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize the response to the random".to_string(),
),
)?;
let ro_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap());
idx += 8;
if bytes[idx..].len() < ro_len as usize * 32 + 8 {
return Err(
CompactEcashError::Deserialization(
"tried to deserialize response openings".to_string()),
);
}
let ro_end = idx + ro_len as usize * 32;
let response_openings = try_deserialize_scalar_vec(
ro_len,
&bytes[idx..ro_end],
CompactEcashError::Deserialization("Failed to deserialize openings response".to_string()),
)?;
let ra_len = u64::from_le_bytes(bytes[ro_end..ro_end + 8].try_into().unwrap());
let response_attributes = try_deserialize_scalar_vec(
ra_len,
&bytes[ro_end + 8..],
CompactEcashError::Deserialization("Failed to deserialize attributes response".to_string()),
)?;
Ok(WithdrawalReqProof{
challenge,
response_opening,
response_openings,
response_attributes,
})
}
}
#[cfg(test)]
mod tests {
use group::Group;
@@ -10,6 +10,7 @@ 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, try_deserialize_scalar, try_deserialize_g2_projective,
};
pub mod aggregation;
@@ -18,6 +19,7 @@ pub mod keygen;
pub mod setup;
pub mod withdrawal;
#[derive(Debug, Clone, PartialEq)]
pub struct PartialWallet {
sig: Signature,
v: Scalar,
@@ -34,8 +36,49 @@ impl PartialWallet {
pub fn index(&self) -> Option<SignerIndex> {
self.idx
}
pub fn to_bytes(&self) -> [u8; 136]{
let mut bytes = [0u8; 136];
bytes[0..96].copy_from_slice(&self.sig.to_bytes());
bytes[96..128].copy_from_slice(&self.v.to_bytes());
// Check if idx is Some and copy its bytes if it exists
if let Some(idx) = &self.idx {
bytes[128..136].copy_from_slice(&idx.to_le_bytes());
}
bytes
}
}
impl TryFrom<&[u8]> for PartialWallet {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<PartialWallet> {
if bytes.len() != 136 {
return Err(CompactEcashError::Deserialization(format!(
"PartialWallet should be exactly 136 bytes, got {}",
bytes.len()
)));
}
let sig_bytes: &[u8; 96] = &bytes[..96].try_into().expect("Slice size != 96");
let v_bytes: &[u8; 32] = &bytes[96..128].try_into().expect("Slice size != 32");
let idx_bytes: &[u8; 8] = &bytes[128..136].try_into().expect("Slice size != 8");
let sig = Signature::try_from(sig_bytes.as_slice()).unwrap();
let v = Scalar::from_bytes(&v_bytes).unwrap();
let idx = None;
if !idx_bytes.iter().all(|&x| x == 0){
let idx = Some(u64::from_le_bytes(*idx_bytes));
}
Ok(PartialWallet{
sig,
v,
idx,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Wallet {
sig: Signature,
v: Scalar,
@@ -46,13 +89,22 @@ impl Wallet {
pub fn signature(&self) -> &Signature {
&self.sig
}
pub fn v(&self) -> Scalar {
self.v
}
pub fn l(&self) -> u64 {
self.l.get()
}
pub fn to_bytes(&self) -> [u8; 136]{
let mut bytes = [0u8; 136];
bytes[0..96].copy_from_slice(&self.sig.to_bytes());
bytes[96..128].copy_from_slice(&self.v.to_bytes());
bytes[128..136].copy_from_slice(&self.l.get().to_le_bytes());
bytes
}
fn up(&self) {
self.l.set(self.l.get() + 1);
}
@@ -203,6 +255,33 @@ impl Wallet {
}
}
impl TryFrom<&[u8]> for Wallet {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<Wallet> {
if bytes.len() != 136 {
return Err(CompactEcashError::Deserialization(format!(
"Wallet should be exactly 136 bytes, got {}",
bytes.len()
)));
}
let sig_bytes: &[u8; 96] = &bytes[..96].try_into().expect("Slice size != 96");
let v_bytes: &[u8; 32] = &bytes[96..128].try_into().expect("Slice size != 32");
let l_bytes: &[u8; 8] = &bytes[128..136].try_into().expect("Slice size != 8");
let sig = Signature::try_from(sig_bytes.as_slice()).unwrap();
let v = Scalar::from_bytes(&v_bytes).unwrap();
let l = Cell::new(u64::from_le_bytes(*l_bytes));
Ok(Wallet{
sig,
v,
l
})
}
}
pub fn pseudorandom_f_delta_v(params: &GroupParameters, v: Scalar, l: u64) -> G1Projective {
let pow = (v + Scalar::from(l) + Scalar::from(1)).invert().unwrap();
params.delta() * pow
@@ -233,7 +312,7 @@ pub struct PayInfo {
pub info: [u8; 32],
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Payment {
pub kappa: G2Projective,
pub sig: Signature,
@@ -320,4 +399,195 @@ impl Payment {
Ok(true)
}
pub fn to_bytes(&self) -> Vec<u8>{
let kappa_bytes = self.kappa.to_affine().to_compressed();
let sig_bytes = self.sig.to_bytes();
let cc_bytes = self.cc.to_affine().to_compressed();
let vv_bytes: [u8; 8] = self.vv.to_le_bytes();
let ss_len = self.ss.len() as u64;
let tt_len = self.tt.len() as u64;
let aa_len = self.aa.len() as u64;
let rr_len = self.rr.len() as u64;
let kappa_k_len = self.kappa_k.len() as u64;
let sig_lk_len = self.sig_lk.len() as u64;
let zk_proof_bytes = self.zk_proof.to_bytes();
let zk_proof_bytes_len = self.zk_proof.to_bytes().len() as u64;
let mut bytes: Vec<u8> = Vec::with_capacity(
(96 + 96 + 48 + 8 + ss_len * 48 + 8 + tt_len * 48 + 8 + aa_len * 48 + 8 + rr_len * 32 + 8 + kappa_k_len * 96 + 8 + sig_lk_len * 96 + zk_proof_bytes_len) as usize);
bytes.extend_from_slice(&kappa_bytes);
bytes.extend_from_slice(&sig_bytes);
bytes.extend_from_slice(&cc_bytes);
bytes.extend_from_slice(&vv_bytes);
let ss_len_bytes = ss_len.to_le_bytes();
bytes.extend_from_slice(&ss_len_bytes);
for s in &self.ss {
bytes.extend_from_slice(&s.to_affine().to_compressed());
}
let tt_len_bytes = tt_len.to_le_bytes();
bytes.extend_from_slice(&tt_len_bytes);
for t in &self.tt {
bytes.extend_from_slice(&t.to_affine().to_compressed());
}
let aa_len_bytes = aa_len.to_le_bytes();
bytes.extend_from_slice(&aa_len_bytes);
for a in &self.aa {
bytes.extend_from_slice(&a.to_affine().to_compressed());
}
let rr_len_bytes = rr_len.to_le_bytes();
bytes.extend_from_slice(&rr_len_bytes);
for r in &self.rr {
bytes.extend_from_slice(&r.to_bytes());
}
let kappa_k_len_bytes = kappa_k_len.to_le_bytes();
bytes.extend_from_slice(&kappa_k_len_bytes);
for kk in &self.kappa_k {
bytes.extend_from_slice(&kk.to_affine().to_compressed());
}
let sig_lk_len_bytes = sig_lk_len.to_le_bytes();
bytes.extend_from_slice(&sig_lk_len_bytes);
for sig in &self.sig_lk {
bytes.extend_from_slice(&sig.to_bytes());
}
bytes.extend_from_slice(&zk_proof_bytes);
bytes
}
}
impl TryFrom<&[u8]> for Payment {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<Payment> {
if bytes.len() < 656 {
return Err(CompactEcashError::Deserialization(
"Invalid byte array for Payment deserialization".to_string(),
));
}
let kappa_bytes: [u8; 96] = bytes[..96].try_into().unwrap();
let sig_bytes: [u8; 96] = bytes[96..192].try_into().unwrap();
let cc_bytes: [u8; 48] = bytes[192..240].try_into().unwrap();
let vv_bytes: [u8; 8] = bytes[240..248].try_into().unwrap();
let ss_len = u64::from_le_bytes(bytes[248..256].try_into().unwrap()) as usize;
// Convert the byte arrays back into their respective types
let kappa = try_deserialize_g2_projective(
&kappa_bytes,
CompactEcashError::Deserialization("Failed to deserialize kappa".to_string()),
)?;
let sig = Signature::try_from(sig_bytes.as_slice())?;
let cc = try_deserialize_g1_projective(
&cc_bytes,
CompactEcashError::Deserialization("Failed to deserialize cc".to_string()),
)?;
let vv = u64::from_le_bytes(vv_bytes);
let mut idx = 256;
let mut ss = Vec::with_capacity(ss_len);
for _ in 0..ss_len {
let ss_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
let ss_elem = try_deserialize_g1_projective(
&ss_bytes,
CompactEcashError::Deserialization("Failed to deserialize ss element".to_string()),
)?;
ss.push(ss_elem);
idx += 48;
}
let tt_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
idx += 8;
let mut tt = Vec::with_capacity(tt_len);
for _ in 0..tt_len {
let tt_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
let tt_elem = try_deserialize_g1_projective(
&tt_bytes,
CompactEcashError::Deserialization("Failed to deserialize tt element".to_string()),
)?;
tt.push(tt_elem);
idx += 48;
}
let aa_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
idx += 8;
let mut aa = Vec::with_capacity(aa_len);
for _ in 0..aa_len {
let aa_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
let aa_elem = try_deserialize_g1_projective(
&aa_bytes,
CompactEcashError::Deserialization("Failed to deserialize aa element".to_string()),
)?;
aa.push(aa_elem);
idx += 48;
}
let rr_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
idx += 8;
let mut rr = Vec::with_capacity(rr_len);
for _ in 0..rr_len {
let rr_bytes: [u8; 32] = bytes[idx..idx + 32].try_into().unwrap();
let rr_elem = try_deserialize_scalar(
&rr_bytes,
CompactEcashError::Deserialization("Failed to deserialize rr element".to_string()),
)?;
rr.push(rr_elem);
idx += 32;
}
let kappa_k_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
idx += 8;
let mut kappa_k = Vec::with_capacity(kappa_k_len);
for _ in 0..kappa_k_len {
let kappa_k_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
let kappa_k_elem = try_deserialize_g2_projective(
&kappa_k_bytes,
CompactEcashError::Deserialization("Failed to deserialize kappa_k element".to_string()),
)?;
kappa_k.push(kappa_k_elem);
idx += 96;
}
// sig_lk
let sig_lk_len = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap()) as usize;
idx += 8;
let mut sig_lk = Vec::with_capacity(sig_lk_len);
for _ in 0..sig_lk_len {
let sig_lk_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
let sig_lk_elem = Signature::try_from(sig_lk_bytes.as_slice())?;
sig_lk.push(sig_lk_elem);
idx += 96;
}
// Deserialize the SpendProof struct
let zk_proof_bytes = &bytes[idx..];
let zk_proof = SpendProof::try_from(zk_proof_bytes)?;
// Construct the Payment struct from the deserialized data
let payment = Payment {
kappa,
sig,
ss,
tt,
aa,
rr,
kappa_k,
sig_lk,
cc,
zk_proof,
vv,
};
Ok(payment)
}
}
@@ -8,9 +8,10 @@ use crate::proofs::proof_withdrawal::{
use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser, VerificationKeyAuth};
use crate::scheme::PartialWallet;
use crate::scheme::setup::GroupParameters;
use crate::utils::{check_bilinear_pairing, hash_g1};
use crate::utils::{check_bilinear_pairing, hash_g1, try_deserialize_g1_projective};
use crate::utils::{BlindedSignature, Signature};
#[derive(Debug, PartialEq)]
pub struct WithdrawalRequest {
com_hash: G1Projective,
com: G1Projective,
@@ -18,6 +19,96 @@ pub struct WithdrawalRequest {
zk_proof: WithdrawalReqProof,
}
impl WithdrawalRequest {
pub fn to_bytes(&self) -> Vec<u8>{
let com_hash_bytes = self.com_hash.to_affine().to_compressed();
let com_bytes = self.com.to_affine().to_compressed();
let pr_coms_len = self.pc_coms.len() as u64;
let zk_proof_bytes = self.zk_proof.to_bytes();
let mut bytes = Vec::with_capacity(48 + 48 + 8 + pr_coms_len as usize * 48 + zk_proof_bytes.len());
bytes.extend_from_slice(&com_hash_bytes);
bytes.extend_from_slice(&com_bytes);
bytes.extend_from_slice(&pr_coms_len.to_le_bytes());
for c in &self.pc_coms {
bytes.extend_from_slice(&c.to_affine().to_compressed());
}
bytes.extend_from_slice(&zk_proof_bytes);
bytes
}
}
impl TryFrom<&[u8]> for WithdrawalRequest {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<WithdrawalRequest> {
if bytes.len() < 48 + 48 + 8 + 48{
return Err(CompactEcashError::DeserializationMinLength {
min: 48 + 48 + 8 + 48,
actual: bytes.len(),
});
}
let mut j = 0;
let commitment_hash_bytes_len = 48;
let commitment_bytes_len = 48;
let com_hash_bytes = bytes[..j + commitment_hash_bytes_len].try_into().unwrap();
let com_hash = try_deserialize_g1_projective(
&com_hash_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize compressed commitment hash".to_string(),
),
)?;
j += commitment_hash_bytes_len;
let com_bytes = bytes[j..j + commitment_bytes_len].try_into().unwrap();
let com = try_deserialize_g1_projective(
&com_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize compressed commitment".to_string(),
),
)?;
j += commitment_bytes_len;
let pc_len = u64::from_le_bytes(bytes[j..j + 8].try_into().unwrap());
j += 8;
if bytes[j..].len() < pc_len as usize * 48 {
return Err(CompactEcashError::DeserializationMinLength {
min: pc_len as usize * 48,
actual: bytes[56..].len(),
});
}
let mut pc_coms = Vec::with_capacity(pc_len as usize);
for i in 0..pc_len as usize {
let start = j + i * 48;
let end = start + 48;
let pc_com_bytes = bytes[start..end].try_into().unwrap();
let pc_com = try_deserialize_g1_projective(
&pc_com_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize compressed Pedersen commitment".to_string(),
),
)?;
pc_coms.push(pc_com)
}
let zk_proof = WithdrawalReqProof::try_from(&bytes[j + pc_len as usize * 48..])?;
Ok(WithdrawalRequest{
com_hash,
com,
pc_coms,
zk_proof,
})
}
}
pub struct RequestInfo {
com_hash: G1Projective,
com_opening: Scalar,
@@ -7,10 +7,10 @@ use crate::scheme::aggregation::{
use crate::scheme::keygen::{
generate_keypair_user, ttp_keygen, VerificationKeyAuth,
};
use crate::scheme::PartialWallet;
use crate::scheme::{Wallet, PartialWallet, Payment};
use crate::scheme::PayInfo;
use crate::scheme::setup::setup;
use crate::scheme::withdrawal::{issue_verify, issue_wallet, withdrawal_request};
use crate::scheme::withdrawal::{issue_verify, issue_wallet, withdrawal_request, WithdrawalRequest};
#[test]
fn main() -> Result<(), CompactEcashError> {
@@ -20,6 +20,10 @@ fn main() -> Result<(), CompactEcashError> {
let user_keypair = generate_keypair_user(&grparams);
let (req, req_info) = withdrawal_request(grparams, &user_keypair.secret_key()).unwrap();
let req_bytes = req.to_bytes();
let req2 = WithdrawalRequest::try_from(req_bytes.as_slice()).unwrap();
assert_eq!(req, req2);
let authorities_keypairs = ttp_keygen(&grparams, 2, 3).unwrap();
let verification_keys_auth: Vec<VerificationKeyAuth> = authorities_keypairs
@@ -47,6 +51,11 @@ fn main() -> Result<(), CompactEcashError> {
.map(|(w, vk)| issue_verify(&grparams, vk, &user_keypair.secret_key(), w, &req_info).unwrap())
.collect();
let partial_wallet = unblinded_wallet_shares.get(0).unwrap().clone();
let partial_wallet_bytes = partial_wallet.to_bytes();
let partial_wallet2 = PartialWallet::try_from(&partial_wallet_bytes[..]).unwrap();
assert_eq!(partial_wallet, partial_wallet2);
// Aggregate partial wallets
let aggr_wallet = aggregate_wallets(
&grparams,
@@ -56,6 +65,10 @@ fn main() -> Result<(), CompactEcashError> {
&req_info,
)?;
let wallet_bytes = aggr_wallet.to_bytes();
let wallet = Wallet::try_from(&wallet_bytes[..]).unwrap();
assert_eq!(aggr_wallet, wallet);
// Let's try to spend some coins
let pay_info = PayInfo { info: [6u8; 32] };
let spend_vv = 1;
@@ -73,6 +86,10 @@ fn main() -> Result<(), CompactEcashError> {
.spend_verify(&params, &verification_key, &pay_info)
.unwrap());
let payment_bytes = payment.to_bytes();
println!("{:?}", payment_bytes.len());
let payment2 = Payment::try_from(&payment_bytes[..]).unwrap();
assert_eq!(payment, payment2);
Ok(())
}
@@ -199,8 +199,8 @@ pub fn check_bilinear_pairing(p: &G1Affine, q: &G2Prepared, r: &G1Affine, s: &G2
pub type SignerIndex = u64;
#[derive(Debug, Clone, Copy)]
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug, Clone, Copy, PartialEq)]
// #[cfg_attr(test, derive(PartialEq))]
pub struct Signature(pub(crate) G1Projective, pub(crate) G1Projective);
pub type PartialSignature = Signature;