Skip to content

Commit

Permalink
feat: serde for rev_list and calc rev_list state
Browse files Browse the repository at this point in the history
Signed-off-by: bwty <[email protected]>
  • Loading branch information
whalelephant committed Jan 3, 2023
1 parent 0f331b9 commit 124dc34
Show file tree
Hide file tree
Showing 17 changed files with 229 additions and 36 deletions.
Binary file added .tmp/.tmpYtxwf1
Binary file not shown.
Binary file added .tmp/.tmpm00t8T
Binary file not shown.
Binary file added .tmp/2qxJm1HasDk8ydBJToifu3MhM2VdGT1muGrApPExaQXi
Binary file not shown.
Binary file added .tmp/3ihh9JWQKrYgW2N9zrFa9MhvvoeRZYWf36utggLmTacm
Binary file not shown.
Binary file added .tmp/4SDkFYbhNoCRha5fLBvgzP26vhjERXFWyfWWNoJNpetn
Binary file not shown.
Binary file added .tmp/574xmaMjXnvqufaGnkRwC2dDQqdMZ4wGaDB2hqgMCiPK
Binary file not shown.
Binary file added .tmp/6wT833GbcqGbEd3wgHvEpebqrcFkB1XaE4JzhtqZkRYa
Binary file not shown.
Binary file added .tmp/DLtaWoozsJZNceWuzQaSzXT98ZWdcoYiY21jebwVnYuL
Binary file not shown.
Binary file added .tmp/F2CCN8zbYtvFw6KG58zQLrnuo5sb2uhTiL6vVxhEBHtT
Binary file not shown.
Binary file added .tmp/FPMhxK1ZjNZKcWxdJETgg6ixr93YHW4NXdYtneXRDzdE
Binary file not shown.
Binary file added .tmp/HrPXS3xTVh3gsrJbmGP1n11jZmzRk8qPb3CZpsQa4rjs
Binary file not shown.
Binary file added .tmp/HuUbZPdyMQKAD2LtvMzneA2AheFS8fzjenPkDkmPL1MF
Binary file not shown.
3 changes: 2 additions & 1 deletion anoncreds/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ once_cell = "1.9"
rand = "0.8.5"
regex = "1.2.1"
serde = { version = "1.0", features = ["derive"] }
bitvec = { version = "1.0.1", features = ["serde"] }
serde_json = { version = "1.0", features = ["raw_value"]}
sha2 = "0.10"
tempfile = "3.1.0"
thiserror = "1.0"
ursa = { version = "=0.3.6", default-features = false, features = ["cl_native", "serde"] }
ursa = { path = "../../../ursa/libursa", default-features = false, features = ["cl_native", "serde"] }
zeroize = { version = "1.3", optional = true, features = ["zeroize_derive"] }
# We add the openssl dependency here because ursa does not expose a vendored openssl feature
# Since we use "cl_native" as a feature, which uses openssl, we can add a vendored build with
Expand Down
132 changes: 132 additions & 0 deletions anoncreds/src/data_types/anoncreds/rev_reg.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
use bitvec::vec::BitVec;
use serde::{
de::{Deserializer, Error as DeError, SeqAccess, Visitor},
ser::{SerializeSeq, Serializer},
};
use std::collections::HashSet;

use crate::{data_types::Validatable, impl_anoncreds_object_identifier};
use ursa::cl::Accumulator;

impl_anoncreds_object_identifier!(RevocationRegistryId);

Expand Down Expand Up @@ -47,3 +53,129 @@ impl Validatable for RevocationRegistryDelta {}
pub struct RevocationRegistryDeltaV1 {
pub value: ursa::cl::RevocationRegistryDelta,
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RevocationList {
rev_reg_id: RevocationRegistryId,
#[serde(with = "serde_revocation_list")]
revocation_list: bitvec::vec::BitVec,
current_accum: Accumulator,
timestamp: u64,
}

impl From<&RevocationList> for ursa::cl::RevocationRegistry {
fn from(rev_reg_list: &RevocationList) -> ursa::cl::RevocationRegistry {
ursa::cl::RevocationRegistry::from_accum(rev_reg_list.current_accum)
}
}

impl RevocationList {
pub(crate) fn timestamp(&self) -> u64 {
self.timestamp
}

pub(crate) fn state(&self) -> &bitvec::vec::BitVec {
&self.revocation_list
}

pub(crate) fn state_owned(&self) -> bitvec::vec::BitVec {
self.revocation_list.clone()
}

#[cfg(test)]
fn new(
rev_reg_id: &str,
revocation_list: bitvec::vec::BitVec,
current_accum: Accumulator,
timestamp: u64,
) -> Self {
Self {
rev_reg_id: rev_reg_id.into(),
revocation_list,
current_accum,
timestamp,
}
}
}

pub mod serde_revocation_list {
use super::*;
pub fn serialize<S>(state: &bitvec::vec::BitVec, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = s.serialize_seq(Some(state.len()))?;
for element in state {
let e = match element.as_ref() {
&true => 1,
&false => 0,
};
seq.serialize_element(&e)?;
}
seq.end()
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<bitvec::vec::BitVec, D::Error>
where
D: Deserializer<'de>,
{
struct JsonBitStringVisitor;

impl<'de> Visitor<'de> for JsonBitStringVisitor {
type Value = bitvec::vec::BitVec;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a seq containing revoation state, i.e. [1, 0, 1]")
}

fn visit_seq<S>(self, mut v: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
// TODO: do we have a min size for this?
let mut bv = BitVec::with_capacity(v.size_hint().unwrap_or_default());
while let Some(ele) = v.next_element()? {
match ele {
0 => bv.push(false),
1 => bv.push(true),
_ => {
return Err(S::Error::custom("invalid revocation state"));
}
}
}
Ok(bv)
}
}
deserializer.deserialize_seq(JsonBitStringVisitor)
}
}

#[cfg(test)]
mod tests {
use super::*;
use bitvec::prelude::*;

const REVOCATION_LIST: &str = "{\"revRegId\":\"reg\",\"revocationList\":[1,1,1,1],\"currentAccum\":\"1 1379509F4D411630D308A5ABB4F422FCE6737B330B1C5FD286AA5C26F2061E60 1 235535CC45D4816C7686C5A402A230B35A62DDE82B4A652E384FD31912C4E4BB 1 0C94B61595FCAEFC892BB98A27D524C97ED0B7ED1CC49AD6F178A59D4199C9A4 1 172482285606DEE8500FC8A13E6A35EC071F8B84F0EB4CD3DD091C0B4CD30E5E 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000\",\"timestamp\":1234}";

#[test]
fn json_rev_list_can_be_deserialized() {
let des = serde_json::from_str::<RevocationList>(REVOCATION_LIST).unwrap();
let expected_state = bitvec![1;4];
println!("des state {:?}", des.state());
println!("exp state {:?}", expected_state);
assert_eq!(des.state(), &expected_state);
}

#[test]
fn test_revocation_list_roundtrip_serde() {
let state = bitvec![1;4];
let accum = Accumulator::new().expect("Should be able to create Accumulator");
let list = RevocationList::new("reg", state, accum, 1234u64);
let ser = serde_json::to_string(&list).unwrap();
let des = serde_json::from_str::<RevocationList>(&ser).unwrap();
let ser2 = serde_json::to_string(&des).unwrap();
let list_des = serde_json::from_str::<RevocationList>(&ser2).unwrap();
assert_eq!(list, list_des)
}
}
19 changes: 12 additions & 7 deletions anoncreds/src/ffi/revocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::services::{
prover::create_or_update_revocation_state,
tails::{TailsFileReader, TailsFileWriter},
types::{
CredentialRevocationState, IssuanceType, RegistryType, RevocationRegistry,
CredentialRevocationState, IssuanceType, RegistryType, RevocationList, RevocationRegistry,
RevocationRegistryDefinition, RevocationRegistryDefinitionPrivate, RevocationRegistryDelta,
},
};
Expand Down Expand Up @@ -239,19 +239,23 @@ impl_anoncreds_object_from_json!(
anoncreds_revocation_registry_delta_from_json
);

impl_anoncreds_object!(RevocationList, "RevocationList");
impl_anoncreds_object_from_json!(RevocationList, anoncreds_revocation_list_from_json);

#[no_mangle]
pub extern "C" fn anoncreds_create_or_update_revocation_state(
rev_reg_def: ObjectHandle,
rev_reg_delta: ObjectHandle,
rev_reg_list: ObjectHandle,
rev_reg_index: i64,
timestamp: i64,
tails_path: FfiStr,
rev_state: ObjectHandle,
old_rev_reg_list: ObjectHandle,
rev_state_p: *mut ObjectHandle,
) -> ErrorCode {
catch_error(|| {
check_useful_c_ptr!(rev_state_p);
let prev_rev_state = rev_state.opt_load()?;
let prev_rev_reg_list = old_rev_reg_list.opt_load()?;
let tails_reader = TailsFileReader::new_tails_reader(
tails_path
.as_opt_str()
Expand All @@ -260,17 +264,18 @@ pub extern "C" fn anoncreds_create_or_update_revocation_state(
let rev_state = create_or_update_revocation_state(
tails_reader,
rev_reg_def.load()?.cast_ref()?,
rev_reg_delta.load()?.cast_ref()?,
rev_reg_list.load()?.cast_ref()?,
rev_reg_index
.try_into()
.map_err(|_| err_msg!("Invalid credential revocation index"))?,
timestamp
.try_into()
.map_err(|_| err_msg!("Invalid timestamp"))?,
prev_rev_state
.as_ref()
.map(AnonCredsObject::cast_ref)
.transpose()?,
prev_rev_reg_list
.as_ref()
.map(AnonCredsObject::cast_ref)
.transpose()?,
)?;
let rev_state = ObjectHandle::create(rev_state)?;
unsafe { *rev_state_p = rev_state };
Expand Down
109 changes: 82 additions & 27 deletions anoncreds/src/services/prover.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use std::collections::{HashMap, HashSet};
use bitvec::bitvec;
use std::{
collections::{HashMap, HashSet},
convert::TryFrom,
ops::BitXor,
};

use super::types::*;
use crate::data_types::anoncreds::{
Expand All @@ -9,14 +14,15 @@ use crate::data_types::anoncreds::{
AttributeValue, Identifier, RequestedProof, RevealedAttributeGroupInfo,
RevealedAttributeInfo, SubProofReferent,
},
rev_reg::RevocationList,
schema::SchemaId,
};
use crate::error::Result;
use crate::error::{Error, Result};
use crate::services::helpers::*;
use crate::ursa::cl::{
issuer::Issuer as CryptoIssuer, prover::Prover as CryptoProver,
verifier::Verifier as CryptoVerifier, CredentialPublicKey,
RevocationRegistry as CryptoRevocationRegistry, SubProofRequest, Witness,
verifier::Verifier as CryptoVerifier, CredentialPublicKey, RevocationRegistryDelta,
SubProofRequest, Witness,
};
use indy_utils::Validatable;

Expand Down Expand Up @@ -252,52 +258,101 @@ pub fn create_presentation(
pub fn create_or_update_revocation_state(
tails_reader: TailsReader,
revoc_reg_def: &RevocationRegistryDefinition,
rev_reg_delta: &RevocationRegistryDelta,
rev_reg_list: &RevocationList,
rev_reg_idx: u32,
timestamp: u64,
rev_state: Option<&CredentialRevocationState>,
rev_state: Option<&CredentialRevocationState>, // for witness update
old_rev_reg_list: Option<&RevocationList>, // for witness update
) -> Result<CredentialRevocationState> {
trace!(
"create_or_update_revocation_state >>> , tails_reader: {:?}, revoc_reg_def: {:?}, \
rev_reg_delta: {:?}, rev_reg_idx: {}, timestamp: {:?}, rev_state: {:?}",
rev_reg_list: {:?}, rev_reg_idx: {}, rev_state: {:?}, old_rev_reg_list {:?}",
tails_reader,
revoc_reg_def,
rev_reg_delta,
rev_reg_list,
rev_reg_idx,
timestamp,
rev_state
rev_state,
old_rev_reg_list,
);

let RevocationRegistryDefinition::RevocationRegistryDefinitionV1(revoc_reg_def) = revoc_reg_def;
let RevocationRegistryDelta::RevocationRegistryDeltaV1(rev_reg_delta) = rev_reg_delta;

let witness = match rev_state {
None => Witness::new(
rev_reg_idx,
revoc_reg_def.value.max_cred_num,
revoc_reg_def.value.issuance_type.to_bool(),
&rev_reg_delta.value,
&tails_reader,
)?,
Some(source_rev_state) => {
let mut issued = HashSet::<u32>::new();
let mut revoked = HashSet::<u32>::new();
let witness =
if let (Some(source_rev_state), Some(source_rev_list)) = (rev_state, old_rev_reg_list) {
_create_index_deltas(
rev_reg_list.state_owned().bitxor(source_rev_list.state()),
rev_reg_list.state(),
&mut issued,
&mut revoked,
);

let rev_reg_delta = RevocationRegistryDelta::from_parts(
Some(&source_rev_list.into()),
&rev_reg_list.into(),
&issued,
&revoked,
);
let mut witness = source_rev_state.witness.clone();
witness.update(
rev_reg_idx,
revoc_reg_def.value.max_cred_num,
&rev_reg_delta.value,
&rev_reg_delta,
&tails_reader,
)?;
witness
}
};
} else {
let list_size = usize::try_from(revoc_reg_def.value.max_cred_num)
.map_err(|e| Error::from_msg(crate::ErrorKind::InvalidState, e.to_string()))?;
let list = match revoc_reg_def.value.issuance_type {
// All cred are revoked by default
IssuanceType::ISSUANCE_ON_DEMAND => {
bitvec![1; list_size]
}
IssuanceType::ISSUANCE_BY_DEFAULT => {
bitvec![0; list_size]
}
};
_create_index_deltas(
rev_reg_list.state_owned().bitxor(list),
rev_reg_list.state(),
&mut issued,
&mut revoked,
);
let rev_reg_delta =
RevocationRegistryDelta::from_parts(None, &rev_reg_list.into(), &issued, &revoked);
Witness::new(
rev_reg_idx,
revoc_reg_def.value.max_cred_num,
revoc_reg_def.value.issuance_type.to_bool(),
&rev_reg_delta,
&tails_reader,
)?
};

Ok(CredentialRevocationState {
witness,
rev_reg: CryptoRevocationRegistry::from(rev_reg_delta.value.clone()),
timestamp,
rev_reg: rev_reg_list.into(),
timestamp: rev_reg_list.timestamp(),
})
}

fn _create_index_deltas(
delta: bitvec::vec::BitVec,
list: &bitvec::vec::BitVec,
issued: &mut HashSet<u32>,
revoked: &mut HashSet<u32>,
) {
for i in delta.iter_ones() {
if list[i] == true {
// true means cred has been revoked
revoked.insert(i as u32);
} else {
// false means cred has not been
issued.insert(i as u32);
}
}
}

fn prepare_credential_for_proving(
requested_attributes: HashSet<(String, bool)>,
requested_predicates: HashSet<String>,
Expand Down
2 changes: 1 addition & 1 deletion anoncreds/src/services/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use crate::data_types::anoncreds::{
master_secret::MasterSecret,
pres_request::PresentationRequest,
presentation::Presentation,
rev_reg::{RevocationRegistry, RevocationRegistryDelta},
rev_reg::{RevocationList, RevocationRegistry, RevocationRegistryDelta},
rev_reg_def::{
IssuanceType, RegistryType, RevocationRegistryDefinition,
RevocationRegistryDefinitionPrivate,
Expand Down

0 comments on commit 124dc34

Please sign in to comment.