|
| 1 | +// mod bb_params; |
| 2 | +// mod credential; |
| 3 | +// mod commitment; |
| 4 | +// mod witness; |
| 5 | + |
| 6 | + |
| 7 | +use ark_bls12_381::{ |
| 8 | + Bls12_381, |
| 9 | + Fr, |
| 10 | + g1::{G1_GENERATOR_X, G1_GENERATOR_Y}, |
| 11 | + g2::{G2_GENERATOR_X, G2_GENERATOR_Y}, |
| 12 | + G1Affine, G2Affine, G1Projective, G2Projective |
| 13 | +}; |
| 14 | +use ark_serialize::CanonicalSerialize; |
| 15 | +use bbs_plus::prelude::SignatureParamsG1; |
| 16 | +use bbs_plus::prelude::SecretKey; |
| 17 | +use bbs_plus::signature::SignatureG1; |
| 18 | +use ark_ec::{pairing::Pairing}; |
| 19 | +use ark_ec::CurveGroup; |
| 20 | +use ark_ff::{PrimeField, UniformRand}; |
| 21 | +use num_bigint::{BigUint, RandBigInt}; |
| 22 | +use rand::thread_rng; |
| 23 | +use ark_ec::AffineRepr; |
| 24 | +use ark_ff::BigInteger; |
| 25 | +// use ark_ec::pairing::PairingOutput; |
| 26 | +use ark_ff::Field; |
| 27 | +use std::ops::Mul; |
| 28 | +use sha2::Sha256; |
| 29 | +use sha2::Digest; |
| 30 | +use std::collections::HashMap; // Added import |
| 31 | + |
| 32 | + |
| 33 | +use crate::bb_params::*; |
| 34 | +use crate::credential::*; |
| 35 | +use crate::commitment::*; |
| 36 | +use crate::witness::*; |
| 37 | + |
| 38 | + |
| 39 | +/// Generate bilinear group parameters: (g ∈ G1, g2 ∈ G2, gt = e(g, g2), q = |Fr|) |
| 40 | +pub fn bi_linear_generator() -> BBParams { |
| 41 | + // MODULUS is a BigInt, convert to BigUint |
| 42 | + let q = BigUint::from(Fr::MODULUS); |
| 43 | + |
| 44 | + // G1: Create point from (x, y) |
| 45 | + let g1_affine = G1Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y); |
| 46 | + let g = g1_affine.into_group(); // Into G1Projective |
| 47 | + |
| 48 | + // G2: Create point from (x, y) |
| 49 | + let g2_affine = G2Affine::new_unchecked(G2_GENERATOR_X, G2_GENERATOR_Y); |
| 50 | + let g2 = g2_affine.into_group(); // Into G2Projective |
| 51 | + |
| 52 | + let gt = Bls12_381::pairing(&g, &g2); |
| 53 | + |
| 54 | + BBParams { q, g, g2, gt } |
| 55 | +} |
| 56 | + |
| 57 | +// Implement the Perdersent commitment for hidding data |
| 58 | +fn commit_to_x(x: &Fr, h: &G1Projective) -> Commitment { |
| 59 | + let mut rng = thread_rng(); |
| 60 | + let r = Fr::rand(&mut rng); |
| 61 | + let g = G1Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y).into_group(); // assumes G is public |
| 62 | + let commitment = g.mul(x) + h.mul(r); // g^x * h^r (g, h in G1) <x is the messae, r for the randomess> |
| 63 | + |
| 64 | + Commitment { |
| 65 | + value: commitment, |
| 66 | + blinding: r, |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | + |
| 71 | +/// Accumulator struct |
| 72 | +pub struct Accumulator { |
| 73 | + pub acc_val: G1Projective, |
| 74 | + pub parameter: Option<BBParams>, |
| 75 | + pub j_pub: Option<G2Projective>, |
| 76 | + pub issued_x: HashMap<String, Fr>, // Maps a credential ID to its x value (in actual this was a database) |
| 77 | +} |
| 78 | + |
| 79 | +impl Accumulator { |
| 80 | + pub fn new() -> Self { // the constructor - but not for use |
| 81 | + let g1_affine = G1Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y); |
| 82 | + let g = g1_affine.into_group(); // Into G1Projective |
| 83 | + Self { |
| 84 | + |
| 85 | + acc_val: g, |
| 86 | + parameter: None, |
| 87 | + j_pub: None, |
| 88 | + issued_x: HashMap::new(), |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + pub fn acc_gen(&mut self, sk: Fr, _n: usize) { // Initialize the acc_gen to actual use |
| 93 | + let bp_para = bi_linear_generator(); |
| 94 | + self.parameter = Some(bp_para); |
| 95 | + |
| 96 | + let mut rng = thread_rng(); |
| 97 | + |
| 98 | + // j_pub = g2^sk ∈ G2 |
| 99 | + let g2 = self.parameter.as_ref().unwrap().g2; |
| 100 | + let j = g2 * sk; |
| 101 | + |
| 102 | + // Sample u_0 ∈ [0, q) |
| 103 | + let u_0 = rng.gen_biguint_below(&self.parameter.as_ref().unwrap().q); |
| 104 | + let u_0_fr = Fr::from_le_bytes_mod_order(&u_0.to_bytes_le()); |
| 105 | + |
| 106 | + // acc = g^u_0 ∈ G1 |
| 107 | + let g = self.parameter.as_ref().unwrap().g; |
| 108 | + self.acc_val = g * u_0_fr; |
| 109 | + |
| 110 | + self.j_pub = Some(j); |
| 111 | + } |
| 112 | + |
| 113 | + pub fn gen_wit(&mut self, sk: &SecretKey<Fr>, credential: Credential, h: &G1Projective) |
| 114 | + -> Witness { |
| 115 | + // (a) Sample x ∈ D / sk |
| 116 | + let mut rng = thread_rng(); |
| 117 | + let x = loop { |
| 118 | + let candidate = Fr::rand(&mut rng); |
| 119 | + let sum = candidate + sk.0; |
| 120 | + if !sum.0.is_zero() { |
| 121 | + break candidate; |
| 122 | + } |
| 123 | + // else continue looping |
| 124 | + }; |
| 125 | + |
| 126 | + // (b) Commit to x |
| 127 | + let commitment = commit_to_x(&x, h); |
| 128 | + let c_x = commitment.value; |
| 129 | + |
| 130 | + // (c) Gen non-membership witness w_{x|t} |
| 131 | + let sum = x + sk.0; |
| 132 | + let inv = sum.inverse().unwrap(); |
| 133 | + let w_x_t = self.acc_val.mul(inv); |
| 134 | + |
| 135 | + // // (d) Sign over messages || c_x |
| 136 | + let mut combined_msgs = credential.messages.clone(); // Vec<BigUnit> |
| 137 | + let c_x_bytes = c_x.into_affine().x.0.to_bytes_be(); |
| 138 | + let c_x_fr = Fr::from_be_bytes_mod_order(&c_x_bytes); |
| 139 | + combined_msgs.push(c_x_fr); |
| 140 | + |
| 141 | + let message_count = combined_msgs.len() as u32; |
| 142 | + let params = SignatureParamsG1::<Bls12_381>::generate_using_rng(&mut rng, message_count).try_into().unwrap(); |
| 143 | + let sig = SignatureG1::new(&mut rng, &combined_msgs, sk, ¶ms).unwrap(); |
| 144 | + |
| 145 | + // Example: associate x with a credential ID = hash(sig) |
| 146 | + let mut hasher = Sha256::new(); |
| 147 | + let mut sig_bytes = vec![]; |
| 148 | + credential.signature.serialize_compressed(&mut sig_bytes).unwrap(); |
| 149 | + hasher.update(sig_bytes); |
| 150 | + let hash = hasher.finalize(); |
| 151 | + let cred_id = format!( |
| 152 | + "cred_{}", |
| 153 | + hash[..4].iter().map(|b| format!("{:02x}", b)).collect::<String>() |
| 154 | + ); |
| 155 | + self.issued_x.insert(cred_id, x); |
| 156 | + |
| 157 | + // // (e) Return the witness |
| 158 | + let witness = Witness{ |
| 159 | + x: x, |
| 160 | + c_x: commitment, |
| 161 | + w_x_t: w_x_t, |
| 162 | + sig: sig.clone() |
| 163 | + }; |
| 164 | + |
| 165 | + return witness |
| 166 | + } |
| 167 | + |
| 168 | + |
| 169 | + // remove an accumulated values - send the updated message for each holder to re-calculate their witness |
| 170 | + |
| 171 | + pub fn del(&mut self, sk: &SecretKey<Fr>, revoke_cred: Credential) -> Fr { |
| 172 | + |
| 173 | + // Serialize the signature |
| 174 | + let mut hasher = Sha256::new(); |
| 175 | + let mut sig_bytes = vec![]; |
| 176 | + revoke_cred.signature.serialize_compressed(&mut sig_bytes).unwrap(); |
| 177 | + hasher.update(sig_bytes); |
| 178 | + let hash = hasher.finalize(); |
| 179 | + let cred_id = format!( |
| 180 | + "cred_{}", |
| 181 | + hash[..4].iter().map(|b| format!("{:02x}", b)).collect::<String>() |
| 182 | + ); |
| 183 | + |
| 184 | + // Get x associated with this credential |
| 185 | + let delta = *self.get_x_by_id(&cred_id).unwrap(); |
| 186 | + // let delta = self.issued_x.get(&cred_id).unwrap(); // Option<&Fr> |
| 187 | + // the delta shall be stored in some-where for all un-update valid holder still work |
| 188 | + let sum = delta + sk.0; |
| 189 | + let inv = sum.inverse().unwrap(); |
| 190 | + |
| 191 | + // Update accumulator |
| 192 | + self.acc_val = self.acc_val.mul(inv); |
| 193 | + |
| 194 | + return delta; |
| 195 | + } |
| 196 | + |
| 197 | + fn get_x_by_id(&self, cred_id: &str) -> Option<&Fr> { |
| 198 | + self.issued_x.get(cred_id) |
| 199 | + } |
| 200 | + |
| 201 | + pub fn get_acc_val(&self) -> G1Projective { |
| 202 | + self.acc_val |
| 203 | + } |
| 204 | + |
| 205 | + pub fn get_j_pub(&self) -> G2Projective { |
| 206 | + self.j_pub.expect("j_pub is not initialized") |
| 207 | + } |
| 208 | + |
| 209 | + pub fn get_parameter(&self) -> BBParams { |
| 210 | + self.parameter.clone().expect("Parameter of accumulator not been setup") |
| 211 | + } |
| 212 | + |
| 213 | + |
| 214 | + } |
| 215 | + |
0 commit comments