Add byte calculation for divisible ecash

This commit is contained in:
aniampio
2023-08-07 21:19:25 +01:00
committed by durch
parent f623bfed4c
commit a09dc8e462
6 changed files with 322 additions and 8 deletions
@@ -400,7 +400,7 @@ impl Payment {
Ok(true)
}
pub fn to_bytes(&self) -> Vec<u8>{
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();
@@ -87,7 +87,6 @@ fn main() -> Result<(), CompactEcashError> {
.unwrap());
let payment_bytes = payment.to_bytes();
println!("{:?}", payment_bytes.len());
let payment2 = Payment::try_from(&payment_bytes[..]).unwrap();
assert_eq!(payment, payment2);
@@ -8,6 +8,8 @@ use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produc
use crate::scheme::{Phi, VarPhi, Wallet};
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::Parameters;
use crate::error::{DivisibleEcashError, Result};
use crate::utils::{try_deserialize_scalar};
pub struct SpendInstance {
pub kappa: G2Projective,
@@ -84,7 +86,7 @@ pub struct SpendWitness {
pub rho3: Scalar,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct SpendProof {
challenge: Scalar,
response_r: Scalar,
@@ -106,6 +108,29 @@ pub struct SpendProof {
}
impl SpendProof {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::with_capacity(32 * 17); // 17 fields, each 32 bytes
bytes.extend_from_slice(&self.challenge.to_bytes());
bytes.extend_from_slice(&self.response_r.to_bytes());
bytes.extend_from_slice(&self.response_r_sk_u.to_bytes());
bytes.extend_from_slice(&self.response_r_v.to_bytes());
bytes.extend_from_slice(&self.response_r_r.to_bytes());
bytes.extend_from_slice(&self.response_r_r1.to_bytes());
bytes.extend_from_slice(&self.response_r_r2.to_bytes());
bytes.extend_from_slice(&self.response_r_varsig1.to_bytes());
bytes.extend_from_slice(&self.response_r_theta1.to_bytes());
bytes.extend_from_slice(&self.response_r_varsig2.to_bytes());
bytes.extend_from_slice(&self.response_r_theta2.to_bytes());
bytes.extend_from_slice(&self.response_r_rr.to_bytes());
bytes.extend_from_slice(&self.response_r_ss.to_bytes());
bytes.extend_from_slice(&self.response_r_tt.to_bytes());
bytes.extend_from_slice(&self.response_r_rho1.to_bytes());
bytes.extend_from_slice(&self.response_r_rho2.to_bytes());
bytes.extend_from_slice(&self.response_r_rho3.to_bytes());
bytes
}
pub fn construct(
params: &Parameters,
instance: &SpendInstance,
@@ -279,6 +304,142 @@ impl SpendProof {
}
}
impl TryFrom<&[u8]> for SpendProof {
type Error = DivisibleEcashError;
fn try_from(bytes: &[u8]) -> Result<Self> {
const FIELD_SIZE: usize = 32; // Each Scalar field is 32 bytes
if bytes.len() != FIELD_SIZE * 17 {
return Err(DivisibleEcashError::Deserialization(
"Invalid byte array for SpendProof deserialization".to_string(),
));
}
let challenge_bytes = bytes[0..FIELD_SIZE].try_into().unwrap();
let challenge = try_deserialize_scalar(
&challenge_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize challenge".to_string()),
)?;
let response_r_bytes = bytes[FIELD_SIZE..FIELD_SIZE * 2].try_into().unwrap();
let response_r = try_deserialize_scalar(
&response_r_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r".to_string()),
)?;
let response_r_sk_u_bytes = bytes[FIELD_SIZE * 2..FIELD_SIZE * 3].try_into().unwrap();
let response_r_sk_u = try_deserialize_scalar(
&response_r_sk_u_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_sk_u".to_string()),
)?;
let response_r_v_bytes = bytes[FIELD_SIZE * 3..FIELD_SIZE * 4].try_into().unwrap();
let response_r_v = try_deserialize_scalar(
&response_r_v_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_v".to_string()),
)?;
let response_r_r_bytes = bytes[FIELD_SIZE * 4..FIELD_SIZE * 5].try_into().unwrap();
let response_r_r = try_deserialize_scalar(
&response_r_r_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_r".to_string()),
)?;
let response_r_r1_bytes = bytes[FIELD_SIZE * 5..FIELD_SIZE * 6].try_into().unwrap();
let response_r_r1 = try_deserialize_scalar(
&response_r_r1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_r1".to_string()),
)?;
let response_r_r2_bytes = bytes[FIELD_SIZE * 6..FIELD_SIZE * 7].try_into().unwrap();
let response_r_r2 = try_deserialize_scalar(
&response_r_r2_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_r2".to_string()),
)?;
let response_r_varsig1_bytes = bytes[FIELD_SIZE * 7..FIELD_SIZE * 8].try_into().unwrap();
let response_r_varsig1 = try_deserialize_scalar(
response_r_varsig1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_varsig1".to_string()),
)?;
let response_r_theta1_bytes = bytes[FIELD_SIZE * 8..FIELD_SIZE * 9].try_into().unwrap();
let response_r_theta1 = try_deserialize_scalar(
&response_r_theta1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_theta1".to_string()),
)?;
let response_r_varsig2_bytes = bytes[FIELD_SIZE * 9..FIELD_SIZE * 10].try_into().unwrap();
let response_r_varsig2 = try_deserialize_scalar(
&response_r_varsig2_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_varsig2".to_string()),
)?;
let response_r_theta2_bytes = bytes[FIELD_SIZE * 10..FIELD_SIZE * 11].try_into().unwrap();
let response_r_theta2 = try_deserialize_scalar(
&response_r_theta2_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_theta2".to_string()),
)?;
let response_r_rr_bytes = bytes[FIELD_SIZE * 11..FIELD_SIZE * 12].try_into().unwrap();
let response_r_rr = try_deserialize_scalar(
&response_r_rr_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_rr".to_string()),
)?;
let response_r_ss_bytes = bytes[FIELD_SIZE * 12..FIELD_SIZE * 13].try_into().unwrap();
let response_r_ss = try_deserialize_scalar(
&response_r_ss_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_ss".to_string()),
)?;
let response_r_tt_bytes = bytes[FIELD_SIZE * 13..FIELD_SIZE * 14].try_into().unwrap();
let response_r_tt = try_deserialize_scalar(
&response_r_tt_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_tt".to_string()),
)?;
let response_r_rho1_bytes = bytes[FIELD_SIZE * 14..FIELD_SIZE * 15].try_into().unwrap();
let response_r_rho1 = try_deserialize_scalar(
&response_r_rho1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_rho1".to_string()),
)?;
let response_r_rho2_bytes = bytes[FIELD_SIZE * 15..FIELD_SIZE * 16].try_into().unwrap();
let response_r_rho2 = try_deserialize_scalar(
&response_r_rho2_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_rho2".to_string()),
)?;
let response_r_rho3_bytes = bytes[FIELD_SIZE * 16..FIELD_SIZE * 17].try_into().unwrap();
let response_r_rho3 = try_deserialize_scalar(
&response_r_rho3_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize response_r_rho3".to_string()),
)?;
Ok(SpendProof {
challenge,
response_r,
response_r_sk_u,
response_r_v,
response_r_r,
response_r_r1,
response_r_r2,
response_r_varsig1,
response_r_theta1,
response_r_varsig2,
response_r_theta2,
response_r_rr,
response_r_ss,
response_r_tt,
response_r_rho1,
response_r_rho2,
response_r_rho3,
})
}
}
#[cfg(test)]
mod tests {
use std::ops::Neg;
@@ -439,7 +600,13 @@ mod tests {
// compute the zk proof
let zk_proof = SpendProof::construct(&params, &instance, &witness, &verification_key, vv);
assert!(zk_proof.verify(&params, &instance, &verification_key, vv))
assert!(zk_proof.verify(&params, &instance, &verification_key, vv));
// do a to and from bytes check
let zk_proof_bytes = zk_proof.to_bytes();
let zk_proof2 = SpendProof::try_from(&zk_proof_bytes[..]).unwrap();
assert_eq!(zk_proof, zk_proof2);
}
}
@@ -11,7 +11,7 @@ use crate::error::{DivisibleEcashError, 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};
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;
pub mod keygen;
@@ -116,7 +116,7 @@ pub struct PayInfo {
pub info: [u8; 32],
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Payment {
pub kappa: G2Projective,
pub sig: Signature,
@@ -149,6 +149,152 @@ impl Payment {
pub fn get_rr(&self) -> Scalar { self.rr }
pub fn get_zk_proof(&self) -> SpendProof { self.zk_proof.clone() }
pub fn get_vv(&self) -> u64 { self.vv }
pub fn to_bytes(&self) -> Vec<u8>{
let kappa_bytes = self.kappa.to_affine().to_compressed();
let sig_bytes = self.sig.to_bytes();
let phi_bytes = self.phi.to_bytes();
let varphi_bytes = self.varphi.to_bytes();
let varsig_prime1_bytes = self.varsig_prime1.to_affine().to_compressed();
let varsig_prime2_bytes = self.varsig_prime2.to_affine().to_compressed();
let theta_prime1_bytes = self.theta_prime1.to_affine().to_compressed();
let theta_prime2 = self.theta_prime2.to_affine().to_compressed();
let rr_prime_bytes = self.rr_prime.to_affine().to_compressed();
let ss_prime_bytes = self.ss_prime.to_affine().to_compressed();
let tt_prime_bytes = self.tt_prime.to_affine().to_compressed();
let rr_bytes = self.rr.to_bytes();
let zk_proof_bytes = self.zk_proof.to_bytes();
let vv_bytes = self.vv.to_le_bytes();
let mut bytes: Vec<u8> = Vec::with_capacity(760);
bytes.extend_from_slice(&kappa_bytes);
bytes.extend_from_slice(&sig_bytes);
bytes.extend_from_slice(&phi_bytes);
bytes.extend_from_slice(&varphi_bytes);
bytes.extend_from_slice(&varsig_prime1_bytes);
bytes.extend_from_slice(&varsig_prime2_bytes);
bytes.extend_from_slice(&theta_prime1_bytes);
bytes.extend_from_slice(&theta_prime2);
bytes.extend_from_slice(&rr_prime_bytes);
bytes.extend_from_slice(&ss_prime_bytes);
bytes.extend_from_slice(&tt_prime_bytes);
bytes.extend_from_slice(&rr_bytes);
bytes.extend_from_slice(&vv_bytes);
bytes.extend_from_slice(&zk_proof_bytes);
bytes
}
}
impl TryFrom<&[u8]> for Payment {
type Error = DivisibleEcashError;
fn try_from(bytes: &[u8]) -> Result<Self> {
if bytes.len() < 760 {
return Err(DivisibleEcashError::Deserialization(
"Invalid byte array for Payment deserialization".to_string(),
));
}
let mut idx = 0;
let kappa_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
let kappa = try_deserialize_g2_projective(
&kappa_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize kappa".to_string()),
)?;
idx += 96;
let sig_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
let sig = Signature::try_from(sig_bytes.as_slice())?;
idx += 96;
let phi_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
let phi = Phi::from_bytes(&phi_bytes).unwrap();
idx += 96;
let varphi_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
let varphi = VarPhi::from_bytes(&varphi_bytes).unwrap();
idx += 96;
let varsig_prime1_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
let varsig_prime1 = try_deserialize_g1_projective(
&varsig_prime1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize varsig_prime1".to_string()),
)?;
idx += 48;
let varsig_prime2_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
let varsig_prime2 = try_deserialize_g1_projective(
&varsig_prime2_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize varsig_prime2".to_string()),
)?;
idx += 48;
let theta_prime1_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
let theta_prime1 = try_deserialize_g1_projective(
&theta_prime1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize theta_prime1".to_string()),
)?;
idx += 48;
let theta_prime2_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
let theta_prime2 = try_deserialize_g1_projective(
&theta_prime2_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize theta_prime2".to_string()),
)?;
idx += 48;
let rr_prime_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
let rr_prime = try_deserialize_g1_projective(
&rr_prime_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize rr_prime".to_string()),
)?;
idx += 48;
let ss_prime_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
let ss_prime = try_deserialize_g1_projective(
&ss_prime_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize ss_prime".to_string()),
)?;
idx += 48;
let tt_prime_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
let tt_prime = try_deserialize_g2_projective(
&tt_prime_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize tt_prime".to_string()),
)?;
idx += 96;
let rr_bytes: [u8; 32] = bytes[idx..idx+32].try_into().unwrap();
let rr = try_deserialize_scalar(
&rr_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize rr element".to_string()),
)?;
idx += 32;
let vv = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap());
idx += 8;
// Deserialize the SpendProof struct
let zk_proof_bytes = &bytes[idx..];
let zk_proof = SpendProof::try_from(zk_proof_bytes)?;
Ok(Payment{
kappa,
sig,
phi,
varphi,
varsig_prime1,
varsig_prime2,
theta_prime1,
theta_prime2,
rr_prime,
ss_prime,
tt_prime,
rr,
zk_proof,
vv,
})
}
}
pub struct PartialWallet {
@@ -55,6 +55,9 @@ fn main() -> Result<(), DivisibleEcashError> {
// SPEND VERIFICATION
assert!(payment.spend_verify(&params, &verification_key, &pay_info).unwrap());
let payment_bytes = payment.to_bytes();
let payment2 = Payment::try_from(&payment_bytes[..]).unwrap();
assert_eq!(payment, payment2);
Ok(())
}
@@ -206,8 +206,7 @@ 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)]
pub struct Signature(pub(crate) G1Projective, pub(crate) G1Projective);
pub type PartialSignature = Signature;