Add Wallet, Partial Wallet and Payment to and from bytes converstion
This commit is contained in:
@@ -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(¶ms, &instance, &witness, &verification_key, &[rr]);
|
||||
assert!(zk_proof.verify(¶ms, &instance, &verification_key, &[rr]))
|
||||
assert!(zk_proof.verify(¶ms, &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(¶ms, &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;
|
||||
|
||||
Reference in New Issue
Block a user