use super::secret_sharing::Threshold;
pub use crate::common::types::{AccountAddress, ACCOUNT_ADDRESS_SIZE};
use crate::{
bulletproofs::{range_proof::RangeProof, utils::Generators},
common::{
types::{CredentialIndex, KeyIndex, KeyPair, Signature},
*,
},
curve_arithmetic::*,
dodis_yampolskiy_prf as prf,
elgamal::{ChunkSize, Cipher, Message, SecretKey as ElgamalSecretKey},
pedersen_commitment::{
Commitment as PedersenCommitment, CommitmentKey as PedersenKey,
Randomness as PedersenRandomness, Value as PedersenValue,
},
random_oracle::Challenge,
sigma_protocols::{
com_enc_eq, com_eq, com_eq_different_groups, com_eq_sig, com_mult,
common::{ReplicateAdapter, ReplicateResponse},
dlog,
},
};
use anyhow::{anyhow, bail};
use byteorder::ReadBytesExt;
use concordium_contracts_common as concordium_std;
pub use concordium_contracts_common::SignatureThreshold;
use concordium_contracts_common::{AccountThreshold, ZeroSignatureThreshold};
use derive_more::*;
use ed25519_dalek as ed25519;
use ed25519_dalek::Verifier;
use either::Either;
use ff::Field;
use hex::{decode, encode};
use serde::{
de, de::Visitor, ser::SerializeMap, Deserialize as SerdeDeserialize, Deserializer,
Serialize as SerdeSerialize, Serializer,
};
use sha2::{Digest, Sha256};
use std::{
cmp::Ordering,
collections::{btree_map::BTreeMap, hash_map::HashMap, BTreeSet},
convert::{TryFrom, TryInto},
fmt,
io::{Cursor, Read},
str::FromStr,
};
use thiserror::Error;
pub static PI_DIGITS: &[u8] = include_bytes!("../../data/pi-1000-digits.dat");
pub const NUM_BULLETPROOF_GENERATORS: usize = 32 * 8;
pub const CHUNK_SIZE: ChunkSize = ChunkSize::ThirtyTwo;
pub fn account_address_from_registration_id(reg_id: &impl Curve) -> AccountAddress {
let mut hasher = Sha256::new();
reg_id.serial(&mut hasher);
AccountAddress(hasher.finalize().into())
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, SerdeBase16Serialize)]
pub struct IpCdiSignature(ed25519::Signature);
impl std::ops::Deref for IpCdiSignature {
type Target = ed25519::Signature;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl From<ed25519::Signature> for IpCdiSignature {
fn from(sig: ed25519::Signature) -> Self { IpCdiSignature(sig) }
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, SerdeBase16Serialize)]
pub struct AccountOwnershipSignature(ed25519::Signature);
impl std::ops::Deref for AccountOwnershipSignature {
type Target = ed25519::Signature;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl From<ed25519::Signature> for AccountOwnershipSignature {
fn from(sig: ed25519::Signature) -> Self { AccountOwnershipSignature(sig) }
}
#[derive(Debug, PartialEq, Eq)]
#[derive(SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(transparent)]
pub struct AccountOwnershipProof {
pub sigs: BTreeMap<KeyIndex, AccountOwnershipSignature>,
}
impl Serial for AccountOwnershipProof {
fn serial<B: Buffer>(&self, out: &mut B) {
let len = self.sigs.len() as u8;
out.put(&len);
serial_map_no_length(&self.sigs, out)
}
}
impl Deserial for AccountOwnershipProof {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let len: u8 = source.get()?;
if len == 0 {
bail!("Need at least one proof.")
}
let sigs = deserial_map_no_length(source, usize::from(len))?;
Ok(AccountOwnershipProof { sigs })
}
}
impl AccountOwnershipProof {
pub fn num_proofs(&self) -> Result<SignatureThreshold, ZeroSignatureThreshold> {
SignatureThreshold::try_from(self.sigs.len() as u8)
}
}
#[derive(
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Copy,
Hash,
From,
Serialize,
SerdeSerialize,
SerdeDeserialize,
FromStr,
)]
#[repr(transparent)]
#[serde(transparent)]
pub struct IpIdentity(pub u32);
impl fmt::Display for IpIdentity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) }
}
#[derive(
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Copy,
Hash,
Serial,
SerdeSerialize,
SerdeDeserialize,
)]
#[serde(into = "u32", try_from = "u32")]
pub struct ArIdentity(u32);
impl Deserial for ArIdentity {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let x = source.get()?;
if x == 0 {
bail!("ArIdentity must be non-zero.")
} else {
Ok(ArIdentity(x))
}
}
}
impl fmt::Display for ArIdentity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) }
}
impl From<ArIdentity> for u32 {
fn from(x: ArIdentity) -> Self { x.0 }
}
impl From<ArIdentity> for u64 {
fn from(x: ArIdentity) -> Self { x.0.into() }
}
impl TryFrom<u32> for ArIdentity {
type Error = &'static str;
fn try_from(value: u32) -> Result<Self, Self::Error> {
if value == 0 {
Err("Zero is not a valid ArIdentity.")
} else {
Ok(ArIdentity(value))
}
}
}
impl FromStr for ArIdentity {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let x = u32::from_str(s).map_err(|_| "Could not read u32.")?;
ArIdentity::try_from(x)
}
}
impl ArIdentity {
pub fn to_scalar<C: Curve>(self) -> C::Scalar { C::scalar_from_u64(u64::from(self.0)) }
#[cfg(any(test, feature = "internal-test-helpers"))]
pub fn new(x: u32) -> Self {
assert_ne!(x, 0, "Trying to construct ArIdentity 0.");
ArIdentity(x)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Serialize, Into)]
#[repr(transparent)]
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(try_from = "AttributeStringTag", into = "AttributeStringTag")]
pub struct AttributeTag(pub u8);
impl std::borrow::Borrow<u8> for AttributeTag {
fn borrow(&self) -> &u8 { &self.0 }
}
pub const ATTRIBUTE_NAMES: [&str; 14] = [
"firstName",
"lastName",
"sex",
"dob",
"countryOfResidence",
"nationality",
"idDocType",
"idDocNo",
"idDocIssuer",
"idDocIssuedAt",
"idDocExpiresAt",
"nationalIdNo",
"taxIdNo",
"lei",
];
pub const ATTRIBUTE_TAG_LEI: AttributeTag = AttributeTag(13);
#[derive(Debug, PartialEq, Eq, Clone)]
#[repr(transparent)]
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(transparent)]
pub struct AttributeStringTag(String);
impl fmt::Display for AttributeStringTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) }
}
impl TryFrom<AttributeStringTag> for AttributeTag {
type Error = anyhow::Error;
fn try_from(v: AttributeStringTag) -> Result<Self, Self::Error> {
if let Some(idx) = ATTRIBUTE_NAMES.iter().position(|&x| x == v.0) {
Ok(AttributeTag(idx as u8))
} else {
match v.0.strip_prefix("UNNAMED#").and_then(|x| x.parse().ok()) {
Some(num) if num < 254 => Ok(AttributeTag(num)), _ => Err(anyhow!("Unrecognized attribute tag.")),
}
}
}
}
impl std::convert::From<AttributeTag> for AttributeStringTag {
fn from(v: AttributeTag) -> Self {
let v_usize: usize = v.into();
if v_usize < ATTRIBUTE_NAMES.len() {
AttributeStringTag(ATTRIBUTE_NAMES[v_usize].to_owned())
} else {
AttributeStringTag(format!("UNNAMED#{}", v.0))
}
}
}
impl fmt::Display for AttributeTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let l: usize = (*self).into();
if l < ATTRIBUTE_NAMES.len() {
f.write_str(ATTRIBUTE_NAMES[l])
} else {
write!(f, "UNNAMED#{}", l)
}
}
}
impl std::str::FromStr for AttributeTag {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(idx) = ATTRIBUTE_NAMES.iter().position(|&x| x == s) {
Ok(AttributeTag(idx as u8))
} else {
match s.strip_prefix("UNNAMED#").and_then(|x| x.parse().ok()) {
Some(num) if num < 254 => Ok(AttributeTag(num)), _ => Err(anyhow!("Unrecognized attribute tag.")),
}
}
}
}
impl From<AttributeTag> for usize {
fn from(tag: AttributeTag) -> Self { tag.0.into() }
}
impl From<u8> for AttributeTag {
fn from(tag: u8) -> Self { AttributeTag(tag) }
}
pub trait Attribute<F: Field>:
Clone + Sized + Send + Sync + fmt::Display + Serialize + Ord {
fn to_field_element(&self) -> F;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct YearMonth {
pub year: u16,
pub month: u8,
}
impl YearMonth {
pub fn lower(self) -> Option<chrono::DateTime<chrono::Utc>> {
let date = chrono::NaiveDate::from_ymd_opt(self.year.into(), self.month.into(), 1)?;
let time = chrono::NaiveTime::from_hms_opt(0, 0, 0)?;
let dt = date.and_time(time);
Some(chrono::DateTime::from_utc(dt, chrono::Utc))
}
pub fn upper(self) -> Option<chrono::DateTime<chrono::Utc>> {
let date = chrono::NaiveDate::from_ymd_opt(self.year.into(), self.month.into(), 1)?;
let time = chrono::NaiveTime::from_hms_opt(0, 0, 0)?;
let date = date.checked_add_months(chrono::Months::new(1))?;
let dt = date.and_time(time);
Some(chrono::DateTime::from_utc(dt, chrono::Utc))
}
}
impl ToString for YearMonth {
fn to_string(&self) -> String { format!("{:04}{:02}", self.year, self.month) }
}
impl SerdeSerialize for YearMonth {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer, {
let s = format!("{}{:0>2}", self.year, self.month);
serializer.serialize_str(&s)
}
}
impl<'de> SerdeDeserialize<'de> for YearMonth {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>, {
deserializer.deserialize_str(YearMonthVisitor)
}
}
struct YearMonthVisitor;
impl<'de> Visitor<'de> for YearMonthVisitor {
type Value = YearMonth;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a year and month in format YYYYMM")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: de::Error, {
YearMonth::from_str(s).map_err(de::Error::custom)
}
}
impl Serial for YearMonth {
fn serial<B: Buffer>(&self, out: &mut B) {
out.put(&self.year);
out.put(&self.month);
}
}
impl Deserial for YearMonth {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let year = source.get()?;
let month = source.get()?;
YearMonth::new(year, month).ok_or_else(|| anyhow!("Invalid year/month."))
}
}
impl std::str::FromStr for YearMonth {
type Err = anyhow::Error;
fn from_str(s: &str) -> ParseResult<Self> {
if !s.chars().all(|c| c.is_ascii() && c.is_numeric()) {
bail!("Unsupported date in format YYYYMM")
}
if s.len() != 6 {
bail!("Invalid length of YYYYMM.")
}
let (s_year, s_month) = s.split_at(4);
let year = s_year.parse::<u16>()?;
let month = s_month.parse::<u8>()?;
if let Some(ym) = YearMonth::new(year, month) {
Ok(ym)
} else {
bail!("Year or month out of range.")
}
}
}
impl YearMonth {
pub fn new(year: u16, month: u8) -> Option<Self> {
if (1000..10000).contains(&year) && (1..=12).contains(&month) {
Some(YearMonth { year, month })
} else {
None
}
}
pub fn now() -> YearMonth {
use chrono::Datelike;
let now = chrono::Utc::now();
YearMonth {
year: now.year() as u16,
month: now.month() as u8,
}
}
pub fn from_timestamp(unix_seconds: i64) -> Option<YearMonth> {
use chrono::{Datelike, TimeZone};
let date = chrono::Utc.timestamp_opt(unix_seconds, 0).earliest()?;
let year = date.year().try_into().ok()?;
let month = date.month().try_into().ok()?;
Self::new(year, month)
}
}
impl TryFrom<u64> for YearMonth {
type Error = ();
fn try_from(v: u64) -> Result<Self, Self::Error> {
let month = (v & 0xFF) as u8;
let year = ((v >> 8) & 0xFFFF) as u16;
YearMonth::new(year, month).ok_or(())
}
}
impl From<YearMonth> for u64 {
fn from(v: YearMonth) -> Self { u64::from(v.month) | (u64::from(v.year) << 8) }
}
impl From<&YearMonth> for u64 {
fn from(v: &YearMonth) -> Self { u64::from(v.month) | (u64::from(v.year) << 8) }
}
impl From<&YearMonth> for u32 {
fn from(v: &YearMonth) -> Self { u32::from(v.month) | (u32::from(v.year) << 8) }
}
impl From<YearMonth> for u32 {
fn from(v: YearMonth) -> Self { u32::from(v.month) | (u32::from(v.year) << 8) }
}
#[derive(Clone, Debug, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "F: Field, AttributeType: Attribute<F> + SerdeSerialize",
deserialize = "F: Field, AttributeType: Attribute<F> + SerdeDeserialize<'de>"
))]
pub struct AttributeList<F: Field, AttributeType: Attribute<F>> {
#[serde(rename = "validTo")]
pub valid_to: YearMonth,
#[serde(rename = "createdAt")]
pub created_at: YearMonth,
#[serde(rename = "maxAccounts")]
pub max_accounts: u8,
#[serde(rename = "chosenAttributes")]
#[map_size_length = 2]
pub alist: BTreeMap<AttributeTag, AttributeType>,
#[serde(skip)]
pub _phantom: std::marker::PhantomData<F>,
}
impl<F: Field, AttributeType: Attribute<F>> HasAttributeValues<F, AttributeTag, AttributeType>
for AttributeList<F, AttributeType>
{
fn get_attribute_value(&self, attribute_tag: &AttributeTag) -> Option<&AttributeType> {
self.alist.get(attribute_tag)
}
}
#[derive(Debug, Serialize)]
#[derive(SerdeBase16Serialize, From, Into)]
pub struct IdCredentials<C: Curve> {
pub id_cred_sec: PedersenValue<C>,
}
impl<C: Curve> IdCredentials<C> {
pub fn generate<R: rand::Rng>(csprng: &mut R) -> Self {
IdCredentials {
id_cred_sec: PedersenValue::generate(csprng),
}
}
}
#[derive(Debug, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct CredentialHolderInfo<C: Curve> {
#[serde(rename = "idCredSecret")]
pub id_cred: IdCredentials<C>,
}
#[derive(Debug, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct AccCredentialInfo<C: Curve> {
#[serde(rename = "credentialHolderInformation")]
pub cred_holder_info: CredentialHolderInfo<C>,
#[serde(rename = "prfKey")]
pub prf_key: prf::SecretKey<C>,
}
#[derive(Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct IpArData<C: Curve> {
#[serde(
rename = "encPrfKeyShare",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub enc_prf_key_share: [Cipher<C>; 8],
#[serde(rename = "proofComEncEq")]
pub proof_com_enc_eq: com_enc_eq::Response<C>,
}
#[derive(Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct IpArDecryptedData<C: Curve> {
#[serde(rename = "arIdentity")]
pub ar_identity: ArIdentity,
#[serde(rename = "prfKeyShare")]
pub prf_key_share: Value<C>,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct ChainArData<C: Curve> {
#[serde(rename = "encIdCredPubShare")]
pub enc_id_cred_pub_share: Cipher<C>,
}
#[derive(Debug, PartialEq, Eq, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct ChainArDecryptedData<C: Curve> {
#[serde(rename = "arIdentity")]
pub ar_identity: ArIdentity,
#[serde(rename = "idCredPubShare")]
pub id_cred_pub_share: Message<C>,
}
#[derive(Debug, Clone, SerdeSerialize, SerdeDeserialize, Serialize)]
pub struct ChoiceArParameters {
#[serde(rename = "arIdentities")]
#[set_size_length = 2]
pub ar_identities: BTreeSet<ArIdentity>,
#[serde(rename = "threshold")]
pub threshold: Threshold,
}
#[derive(Debug, Clone)]
pub struct PreIdentityProof<P: Pairing, C: Curve<Scalar = P::ScalarField>> {
pub common_proof_fields: CommonPioProofFields<P, C>,
pub prf_regid_proof: com_eq::Response<C>,
pub proof_acc_sk: AccountOwnershipProof,
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>> Serial for PreIdentityProof<P, C> {
fn serial<B: Buffer>(&self, out: &mut B) {
out.put(&self.common_proof_fields.challenge);
out.put(&self.common_proof_fields.id_cred_sec_response);
out.put(&self.common_proof_fields.commitments_same_proof);
out.put(&self.common_proof_fields.commitments_prf_same);
out.put(&self.prf_regid_proof);
out.put(&self.proof_acc_sk);
out.put(&self.common_proof_fields.bulletproofs);
}
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>> Deserial for PreIdentityProof<P, C> {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let challenge: Challenge = source.get()?;
let id_cred_sec_response: dlog::Response<C> = source.get()?;
let commitments_same_proof: com_eq::Response<C> = source.get()?;
let commitments_prf_same: com_eq_different_groups::Response<P::G1, C> = source.get()?;
let prf_regid_proof: com_eq::Response<C> = source.get()?;
let proof_acc_sk: AccountOwnershipProof = source.get()?;
let bulletproofs: Vec<RangeProof<C>> = source.get()?;
let common_proof_fields = CommonPioProofFields {
challenge,
id_cred_sec_response,
commitments_same_proof,
commitments_prf_same,
bulletproofs,
};
Ok(PreIdentityProof {
common_proof_fields,
prf_regid_proof,
proof_acc_sk,
})
}
}
#[derive(Debug, Clone, Serialize)]
pub struct CommonPioProofFields<P: Pairing, C: Curve<Scalar = P::ScalarField>> {
pub challenge: Challenge,
pub id_cred_sec_response: dlog::Response<C>,
pub commitments_same_proof: com_eq::Response<C>,
pub commitments_prf_same: com_eq_different_groups::Response<P::G1, C>,
pub bulletproofs: Vec<RangeProof<C>>,
}
pub type IdCredPubVerifiers<C> = (
ReplicateAdapter<com_enc_eq::ComEncEq<C>>,
ReplicateResponse<com_enc_eq::Response<C>>,
);
#[derive(Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>",
deserialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>"
))]
pub struct PreIdentityObject<P: Pairing, C: Curve<Scalar = P::ScalarField>> {
#[serde(rename = "pubInfoForIp")]
pub pub_info_for_ip: PublicInformationForIp<C>,
#[serde(rename = "ipArData")]
#[map_size_length = 4]
pub ip_ar_data: BTreeMap<ArIdentity, IpArData<C>>,
#[serde(rename = "choiceArData")]
pub choice_ar_parameters: ChoiceArParameters,
#[serde(rename = "idCredSecCommitment")]
pub cmm_sc: PedersenCommitment<P::G1>,
#[serde(rename = "prfKeyCommitmentWithIP")]
pub cmm_prf: PedersenCommitment<P::G1>,
#[serde(rename = "prfKeySharingCoeffCommitments")]
pub cmm_prf_sharing_coeff: Vec<PedersenCommitment<C>>,
#[serde(
rename = "proofsOfKnowledge",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub poks: PreIdentityProof<P, C>,
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>> PreIdentityObject<P, C> {
pub fn get_common_pio_fields(&self) -> CommonPioFields<P, C> {
CommonPioFields {
ip_ar_data: &self.ip_ar_data,
choice_ar_parameters: &self.choice_ar_parameters,
cmm_sc: &self.cmm_sc,
cmm_prf: &self.cmm_prf,
cmm_prf_sharing_coeff: &self.cmm_prf_sharing_coeff,
}
}
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>> PreIdentityObjectV1<P, C> {
pub fn get_common_pio_fields(&self) -> CommonPioFields<P, C> {
CommonPioFields {
ip_ar_data: &self.ip_ar_data,
choice_ar_parameters: &self.choice_ar_parameters,
cmm_sc: &self.cmm_sc,
cmm_prf: &self.cmm_prf,
cmm_prf_sharing_coeff: &self.cmm_prf_sharing_coeff,
}
}
}
#[derive(Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>",
deserialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>"
))]
pub struct PreIdentityObjectV1<P: Pairing, C: Curve<Scalar = P::ScalarField>> {
#[serde(
rename = "idCredPub",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub id_cred_pub: C,
#[serde(rename = "ipArData")]
#[map_size_length = 4]
pub ip_ar_data: BTreeMap<ArIdentity, IpArData<C>>,
#[serde(rename = "choiceArData")]
pub choice_ar_parameters: ChoiceArParameters,
#[serde(rename = "idCredSecCommitment")]
pub cmm_sc: PedersenCommitment<P::G1>,
#[serde(rename = "prfKeyCommitmentWithIP")]
pub cmm_prf: PedersenCommitment<P::G1>,
#[serde(rename = "prfKeySharingCoeffCommitments")]
pub cmm_prf_sharing_coeff: Vec<PedersenCommitment<C>>,
#[serde(
rename = "proofsOfKnowledge",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub poks: CommonPioProofFields<P, C>,
}
pub struct CommonPioFields<'a, P: Pairing, C: Curve<Scalar = P::ScalarField>> {
pub ip_ar_data: &'a BTreeMap<ArIdentity, IpArData<C>>,
pub choice_ar_parameters: &'a ChoiceArParameters,
pub cmm_sc: &'a PedersenCommitment<P::G1>,
pub cmm_prf: &'a PedersenCommitment<P::G1>,
pub cmm_prf_sharing_coeff: &'a Vec<PedersenCommitment<C>>,
}
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>, AttributeType: Attribute<C::Scalar> \
+ SerdeSerialize",
deserialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct IdentityObject<
P: Pairing,
C: Curve<Scalar = P::ScalarField>,
AttributeType: Attribute<C::Scalar>,
> {
#[serde(rename = "preIdentityObject")]
pub pre_identity_object: PreIdentityObject<P, C>,
#[serde(rename = "attributeList")]
pub alist: AttributeList<C::Scalar, AttributeType>,
#[serde(
rename = "signature",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub signature: crate::ps_sig::Signature<P>,
}
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>, AttributeType: Attribute<C::Scalar> \
+ SerdeSerialize",
deserialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct IdentityObjectV1<
P: Pairing,
C: Curve<Scalar = P::ScalarField>,
AttributeType: Attribute<C::Scalar>,
> {
#[serde(rename = "preIdentityObject")]
pub pre_identity_object: PreIdentityObjectV1<P, C>,
#[serde(rename = "attributeList")]
pub alist: AttributeList<C::Scalar, AttributeType>,
#[serde(
rename = "signature",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub signature: crate::ps_sig::Signature<P>,
}
pub trait HasIdentityObjectFields<
P: Pairing,
C: Curve<Scalar = P::ScalarField>,
AttributeType: Attribute<C::Scalar>,
> {
fn get_common_pio_fields(&self) -> CommonPioFields<P, C>;
fn get_attribute_list(&self) -> &AttributeList<C::Scalar, AttributeType>;
fn get_signature(&self) -> &crate::ps_sig::Signature<P>;
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: Attribute<C::Scalar>>
HasIdentityObjectFields<P, C, AttributeType> for IdentityObject<P, C, AttributeType>
{
fn get_common_pio_fields(&self) -> CommonPioFields<P, C> {
self.pre_identity_object.get_common_pio_fields()
}
fn get_attribute_list(&self) -> &AttributeList<C::Scalar, AttributeType> { &self.alist }
fn get_signature(&self) -> &crate::ps_sig::Signature<P> { &self.signature }
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: Attribute<C::Scalar>>
HasIdentityObjectFields<P, C, AttributeType> for IdentityObjectV1<P, C, AttributeType>
{
fn get_common_pio_fields(&self) -> CommonPioFields<P, C> {
self.pre_identity_object.get_common_pio_fields()
}
fn get_attribute_list(&self) -> &AttributeList<C::Scalar, AttributeType> { &self.alist }
fn get_signature(&self) -> &crate::ps_sig::Signature<P> { &self.signature }
}
#[derive(Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct IpAnonymityRevokers<C: Curve> {
#[serde(rename = "anonymityRevokers")]
pub ars: Vec<ArInfo<C>>,
#[serde(rename = "arCommitmentKey")]
pub ar_cmm_key: PedersenKey<C>,
#[serde(serialize_with = "base16_encode")]
#[serde(deserialize_with = "base16_decode")]
#[serde(rename = "arBase")]
pub ar_base: C,
}
#[derive(PartialEq, Eq, Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
pub struct Description {
#[string_size_length = 4]
#[serde(rename = "name")]
pub name: String,
#[string_size_length = 4]
#[serde(rename = "url")]
pub url: String,
#[string_size_length = 4]
#[serde(rename = "description")]
pub description: String,
}
pub fn mk_dummy_description(name: String) -> Description {
Description {
name,
url: "".to_owned(),
description: "".to_owned(),
}
}
#[derive(Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "P: Pairing", deserialize = "P: Pairing"))]
pub struct IpInfo<P: Pairing> {
#[serde(rename = "ipIdentity")]
pub ip_identity: IpIdentity,
#[serde(rename = "ipDescription")]
pub ip_description: Description,
#[serde(rename = "ipVerifyKey")]
pub ip_verify_key: crate::ps_sig::PublicKey<P>,
#[serde(
rename = "ipCdiVerifyKey",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub ip_cdi_verify_key: ed25519::PublicKey,
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "P: Pairing", deserialize = "P: Pairing"))]
#[serde(transparent)]
pub struct IpInfos<P: Pairing> {
#[serde(rename = "idps")]
pub identity_providers: BTreeMap<IpIdentity, IpInfo<P>>,
}
pub type ArPublicKey<C> = crate::elgamal::PublicKey<C>;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct ArInfo<C: Curve> {
#[serde(rename = "arIdentity")]
pub ar_identity: ArIdentity,
#[serde(rename = "arDescription")]
pub ar_description: Description,
#[serde(rename = "arPublicKey")]
pub ar_public_key: ArPublicKey<C>,
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
#[serde(transparent)]
pub struct ArInfos<C: Curve> {
pub anonymity_revokers: BTreeMap<ArIdentity, ArInfo<C>>,
}
pub trait HasArPublicKey<C: Curve> {
fn get_public_key(&self) -> &ArPublicKey<C>;
}
impl<C: Curve> HasArPublicKey<C> for ArInfo<C> {
fn get_public_key(&self) -> &ArPublicKey<C> { &self.ar_public_key }
}
impl<C: Curve> HasArPublicKey<C> for ArPublicKey<C> {
fn get_public_key(&self) -> &ArPublicKey<C> { self }
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct CredentialDeploymentCommitments<C: Curve> {
#[serde(rename = "cmmPrf")]
pub cmm_prf: PedersenCommitment<C>,
#[serde(rename = "cmmCredCounter")]
pub cmm_cred_counter: PedersenCommitment<C>,
#[serde(rename = "cmmMaxAccounts")]
pub cmm_max_accounts: PedersenCommitment<C>,
#[map_size_length = 2]
#[serde(rename = "cmmAttributes")]
pub cmm_attributes: BTreeMap<AttributeTag, PedersenCommitment<C>>,
#[serde(rename = "cmmIdCredSecSharingCoeff")]
pub cmm_id_cred_sec_sharing_coeff: Vec<PedersenCommitment<C>>,
}
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct CommitmentsRandomness<C: Curve> {
#[serde(rename = "idCredSecRand")]
pub id_cred_sec_rand: PedersenRandomness<C>,
#[serde(rename = "prfRand")]
pub prf_rand: PedersenRandomness<C>,
#[serde(rename = "credCounterRand")]
pub cred_counter_rand: PedersenRandomness<C>,
#[serde(rename = "maxAccountsRand")]
pub max_accounts_rand: PedersenRandomness<C>,
#[serde(rename = "attributesRand")]
pub attributes_rand: HashMap<AttributeTag, PedersenRandomness<C>>,
}
#[derive(Debug, SerdeBase16IgnoreLengthSerialize, Clone)]
pub struct CredDeploymentProofs<P: Pairing, C: Curve<Scalar = P::ScalarField>> {
pub id_proofs: IdOwnershipProofs<P, C>,
pub proof_acc_sk: AccountOwnershipProof,
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>> Serial for CredDeploymentProofs<P, C> {
fn serial<B: Buffer>(&self, out: &mut B) {
let mut tmp_out = Vec::new();
tmp_out.put(&self.id_proofs.sig);
tmp_out.put(&self.id_proofs.commitments);
tmp_out.put(&self.id_proofs.challenge);
tmp_out.put(&(self.id_proofs.proof_id_cred_pub.len() as u32));
serial_map_no_length(&self.id_proofs.proof_id_cred_pub, &mut tmp_out);
tmp_out.put(&self.id_proofs.proof_ip_sig);
tmp_out.put(&self.id_proofs.proof_reg_id);
tmp_out.put(&self.proof_acc_sk);
tmp_out.put(&self.id_proofs.cred_counter_less_than_max_accounts);
let len: u32 = tmp_out.len() as u32; out.put(&len);
out.write_all(&tmp_out).expect("Writing to buffer is safe.");
}
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>> Deserial for CredDeploymentProofs<P, C> {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let len: u32 = source.get()?;
let mut limited = source.take(u64::from(len));
let sig = limited.get()?;
let commitments = limited.get()?;
let challenge = limited.get()?;
let proof_id_cred_pub_len: u32 = limited.get()?;
let proof_id_cred_pub =
deserial_map_no_length(&mut limited, proof_id_cred_pub_len as usize)?;
let proof_ip_sig = limited.get()?;
let proof_reg_id = limited.get()?;
let proof_acc_sk = limited.get()?;
let cred_counter_less_than_max_accounts = limited.get()?;
if limited.limit() == 0 {
Ok(CredDeploymentProofs {
id_proofs: IdOwnershipProofs {
sig,
commitments,
challenge,
proof_id_cred_pub,
proof_ip_sig,
proof_reg_id,
cred_counter_less_than_max_accounts,
},
proof_acc_sk,
})
} else {
bail!("Length information is inaccurate. Credential proofs not valid.")
}
}
}
#[derive(Debug, Serialize, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>",
deserialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>"
))]
pub struct IdOwnershipProofs<P: Pairing, C: Curve<Scalar = P::ScalarField>> {
#[serde(
rename = "sig",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub sig: crate::ps_sig::BlindedSignature<P>,
#[serde(
rename = "commitments",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub commitments: CredentialDeploymentCommitments<C>,
#[serde(
rename = "challenge",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub challenge: Challenge,
#[serde(rename = "proofIdCredPub")]
#[map_size_length = 4]
pub proof_id_cred_pub: BTreeMap<ArIdentity, com_enc_eq::Response<C>>,
#[serde(
rename = "proofIpSig",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub proof_ip_sig: com_eq_sig::Response<P, C>,
#[serde(
rename = "proofRegId",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub proof_reg_id: com_mult::Response<C>,
#[serde(
rename = "credCounterLessThanMaxAccounts",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub cred_counter_less_than_max_accounts: RangeProof<C>,
}
#[derive(Debug, PartialEq, Eq, Clone, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeSerialize",
deserialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct Policy<C: Curve, AttributeType: Attribute<C::Scalar>> {
#[serde(rename = "validTo")]
pub valid_to: YearMonth,
#[serde(rename = "createdAt")]
pub created_at: YearMonth,
#[serde(rename = "revealedAttributes")]
pub policy_vec: BTreeMap<AttributeTag, AttributeType>,
#[serde(skip)]
pub _phantom: std::marker::PhantomData<C>,
}
impl<C: Curve, AttributeType: Attribute<C::Scalar>> Serial for Policy<C, AttributeType> {
fn serial<B: Buffer>(&self, out: &mut B) {
out.put(&self.valid_to);
out.put(&self.created_at);
out.put(&(self.policy_vec.len() as u16));
serial_map_no_length(&self.policy_vec, out)
}
}
impl<C: Curve, AttributeType: Attribute<C::Scalar>> Deserial for Policy<C, AttributeType> {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let valid_to = source.get()?;
let created_at = source.get()?;
let len: u16 = source.get()?;
let policy_vec = deserial_map_no_length(source, usize::from(len))?;
Ok(Policy {
valid_to,
created_at,
policy_vec,
_phantom: Default::default(),
})
}
}
#[derive(Debug, PartialEq, Eq, concordium_std::Serialize)]
pub enum SchemeId {
Ed25519,
}
#[derive(Debug, Eq, Clone)]
pub enum VerifyKey {
Ed25519VerifyKey(ed25519::PublicKey),
}
impl concordium_std::Serial for VerifyKey {
fn serial<W: concordium_std::Write>(&self, out: &mut W) -> Result<(), W::Err> {
match self {
VerifyKey::Ed25519VerifyKey(key) => {
concordium_std::Serial::serial(&0u8, out)?;
concordium_std::Serial::serial(&key.as_bytes(), out)
}
}
}
}
impl concordium_std::Deserial for VerifyKey {
fn deserial<R: concordium_std::Read>(source: &mut R) -> concordium_std::ParseResult<Self> {
let tag: u8 = concordium_std::Deserial::deserial(source)?;
if tag == 0 {
let bytes: [u8; ed25519::PUBLIC_KEY_LENGTH] =
concordium_std::Deserial::deserial(source)?;
let pk = ed25519::PublicKey::from_bytes(&bytes)
.map_err(|_| concordium_std::ParseError {})?;
Ok(Self::Ed25519VerifyKey(pk))
} else {
Err(concordium_std::ParseError {})
}
}
}
impl SerdeSerialize for VerifyKey {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let mut map = ser.serialize_map(Some(2))?;
match self {
VerifyKey::Ed25519VerifyKey(ref key) => {
map.serialize_entry("schemeId", "Ed25519")?;
map.serialize_entry("verifyKey", &encode(to_bytes(key)))?;
}
}
map.end()
}
}
impl<'de> SerdeDeserialize<'de> for VerifyKey {
fn deserialize<D: Deserializer<'de>>(des: D) -> Result<Self, D::Error> {
struct VerifyKeyVisitor;
impl<'de> Visitor<'de> for VerifyKeyVisitor {
type Value = VerifyKey;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Either a string or a map with verification key.")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let bytes = decode(v).map_err(de::Error::custom)?;
let key = from_bytes(&mut Cursor::new(&bytes)).map_err(de::Error::custom)?;
Ok(VerifyKey::Ed25519VerifyKey(key))
}
fn visit_map<A: de::MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
let mut map = map;
let mut tmp_map: BTreeMap<String, String> = BTreeMap::new();
while tmp_map.len() < 2 {
if let Some((k, v)) = map.next_entry()? {
if k == "schemeId" {
if v != "Ed25519" {
return Err(de::Error::custom(format!(
"Unknown signature scheme type {}",
v
)));
}
if tmp_map.insert(k, v).is_some() {
return Err(de::Error::custom("Duplicate schemeId."));
}
} else if k == "verifyKey" {
tmp_map.insert(k, v);
}
} else {
return Err(de::Error::custom(
"At least the two keys 'schemeId' and 'verifyKey' are expected.",
));
}
}
let vf_key_str = tmp_map.get("verifyKey").ok_or_else(|| {
de::Error::custom("Could not find verifyKey, should not happen.")
})?;
let bytes = decode(vf_key_str).map_err(de::Error::custom)?;
let key = from_bytes(&mut Cursor::new(&bytes)).map_err(de::Error::custom)?;
Ok(VerifyKey::Ed25519VerifyKey(key))
}
}
des.deserialize_any(VerifyKeyVisitor)
}
}
impl From<ed25519::PublicKey> for VerifyKey {
fn from(pk: ed25519::PublicKey) -> Self { VerifyKey::Ed25519VerifyKey(pk) }
}
impl From<&ed25519::Keypair> for VerifyKey {
fn from(kp: &ed25519::Keypair) -> Self { VerifyKey::Ed25519VerifyKey(kp.public) }
}
impl From<&KeyPair> for VerifyKey {
fn from(kp: &KeyPair) -> Self { VerifyKey::Ed25519VerifyKey(kp.public) }
}
impl Ord for VerifyKey {
fn cmp(&self, other: &VerifyKey) -> Ordering {
let VerifyKey::Ed25519VerifyKey(ref self_key) = self;
let VerifyKey::Ed25519VerifyKey(ref other_key) = other;
self_key.as_ref().cmp(other_key.as_ref())
}
}
impl PartialOrd for VerifyKey {
fn partial_cmp(&self, other: &VerifyKey) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl PartialEq for VerifyKey {
fn eq(&self, other: &VerifyKey) -> bool { self.cmp(other) == Ordering::Equal }
}
impl Serial for VerifyKey {
fn serial<B: Buffer>(&self, out: &mut B) {
use VerifyKey::*;
match self {
Ed25519VerifyKey(ref key) => {
out.put(&SchemeId::Ed25519);
out.put(key);
}
}
}
}
impl Deserial for VerifyKey {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
use VerifyKey::*;
match source.get()? {
SchemeId::Ed25519 => {
let key = source.get()?;
Ok(Ed25519VerifyKey(key))
}
}
}
}
impl VerifyKey {
pub fn verify(&self, msg: impl AsRef<[u8]>, sig: &crate::common::types::Signature) -> bool {
match self {
VerifyKey::Ed25519VerifyKey(pk) => {
let sig: ed25519_dalek::Signature = {
if let Ok(x) = sig.as_ref().try_into() {
x
} else {
return false;
}
};
pk.verify(msg.as_ref(), &sig).is_ok()
}
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(bound(
serialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeSerialize",
deserialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct CredentialDeploymentValues<C: Curve, AttributeType: Attribute<C::Scalar>> {
#[serde(rename = "credentialPublicKeys")]
pub cred_key_info: CredentialPublicKeys,
#[serde(
rename = "credId",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub cred_id: CredId<C>,
#[serde(rename = "ipIdentity")]
pub ip_identity: IpIdentity,
#[serde(rename = "revocationThreshold")]
pub threshold: Threshold,
#[map_size_length = 2]
#[serde(rename = "arData", deserialize_with = "deserialize_ar_data")]
pub ar_data: BTreeMap<ArIdentity, ChainArData<C>>,
#[serde(rename = "policy")]
pub policy: Policy<C, AttributeType>,
}
#[derive(Debug, PartialEq, Eq, Serialize, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(bound(
serialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeSerialize",
deserialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct InitialCredentialDeploymentValues<C: Curve, AttributeType: Attribute<C::Scalar>> {
#[serde(rename = "credentialPublicKeys")]
pub cred_account: CredentialPublicKeys,
#[serde(
rename = "regId",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub reg_id: CredId<C>,
#[serde(rename = "ipIdentity")]
pub ip_identity: IpIdentity,
#[serde(rename = "policy")]
pub policy: Policy<C, AttributeType>,
}
fn deserialize_ar_data<'de, D: de::Deserializer<'de>, C: Curve>(
des: D,
) -> Result<BTreeMap<ArIdentity, ChainArData<C>>, D::Error> {
#[derive(Default)]
struct ArIdentityVisitor<C>(std::marker::PhantomData<C>);
impl<'de, C: Curve> Visitor<'de> for ArIdentityVisitor<C> {
type Value = BTreeMap<ArIdentity, ChainArData<C>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"An object with integer keys and ChainArData values."
)
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>, {
let mut map = map;
let mut res = BTreeMap::new();
while let Some((k, v)) = map.next_entry::<String, _>()? {
let k = ArIdentity::from_str(&k)
.map_err(|_| de::Error::custom("Cannot read ArIdentity key."))?;
res.insert(k, v);
}
Ok(res)
}
}
des.deserialize_map(ArIdentityVisitor(std::default::Default::default()))
}
#[derive(Debug, Serialize, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeSerialize",
deserialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct CredentialDeploymentInfo<
P: Pairing,
C: Curve<Scalar = P::ScalarField>,
AttributeType: Attribute<C::Scalar>,
> {
#[serde(flatten)]
pub values: CredentialDeploymentValues<C, AttributeType>,
#[serde(rename = "proofs")] pub proofs: CredDeploymentProofs<P, C>,
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum CredentialType {
Initial,
Normal,
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, PartialEq, Eq)]
#[serde(tag = "type", content = "contents")]
#[serde(bound(
serialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeSerialize",
deserialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub enum AccountCredentialWithoutProofs<C: Curve, AttributeType: Attribute<C::Scalar>> {
#[serde(rename = "initial")]
Initial {
#[serde(flatten)]
icdv: InitialCredentialDeploymentValues<C, AttributeType>,
},
#[serde(rename = "normal")]
Normal {
#[serde(flatten)]
cdv: CredentialDeploymentValues<C, AttributeType>,
#[serde(rename = "commitments")]
commitments: CredentialDeploymentCommitments<C>,
},
}
impl<C: Curve, AttributeType: Attribute<C::Scalar>>
AccountCredentialWithoutProofs<C, AttributeType>
{
pub fn policy(&self) -> &Policy<C, AttributeType> {
match self {
AccountCredentialWithoutProofs::Initial { icdv } => &icdv.policy,
AccountCredentialWithoutProofs::Normal { cdv, .. } => &cdv.policy,
}
}
pub fn issuer(&self) -> IpIdentity {
match self {
AccountCredentialWithoutProofs::Initial { icdv } => icdv.ip_identity,
AccountCredentialWithoutProofs::Normal { cdv, .. } => cdv.ip_identity,
}
}
}
impl<C: Curve, AttributeType: Serial + Attribute<C::Scalar>> Serial
for AccountCredentialWithoutProofs<C, AttributeType>
{
fn serial<B: Buffer>(&self, out: &mut B) {
match self {
AccountCredentialWithoutProofs::Initial { icdv } => {
0u8.serial(out);
icdv.serial(out);
}
AccountCredentialWithoutProofs::Normal { cdv, commitments } => {
1u8.serial(out);
cdv.serial(out);
commitments.serial(out);
}
}
}
}
impl<C: Curve, AttributeType: Deserial + Attribute<C::Scalar>> Deserial
for AccountCredentialWithoutProofs<C, AttributeType>
{
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let tag = u8::deserial(source)?;
match tag {
0u8 => {
let icdv = source.get()?;
Ok(Self::Initial { icdv })
}
1u8 => {
let cdv = source.get()?;
let commitments = source.get()?;
Ok(Self::Normal { cdv, commitments })
}
_ => bail!("Unsupported credential tag: {}", tag),
}
}
}
pub type CredId<C> = C;
impl<C: Curve, AttributeType: Attribute<C::Scalar>>
AccountCredentialWithoutProofs<C, AttributeType>
{
pub fn cred_id(&self) -> &CredId<C> {
match self {
AccountCredentialWithoutProofs::Initial { icdv } => &icdv.reg_id,
AccountCredentialWithoutProofs::Normal { cdv, .. } => &cdv.cred_id,
}
}
}
#[derive(Debug, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeSerialize",
deserialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct UnsignedCredentialDeploymentInfo<
P: Pairing,
C: Curve<Scalar = P::ScalarField>,
AttributeType: Attribute<C::Scalar>,
> {
#[serde(flatten)]
pub values: CredentialDeploymentValues<C, AttributeType>,
pub proofs: IdOwnershipProofs<P, C>,
}
#[derive(Debug, Serialize, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(bound(
serialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeSerialize",
deserialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct InitialCredentialDeploymentInfo<
C: Curve, AttributeType: Attribute<C::Scalar>,
> {
#[serde(flatten)]
pub values: InitialCredentialDeploymentValues<C, AttributeType>,
#[serde(rename = "sig")]
pub sig: IpCdiSignature,
}
#[derive(Debug, Serialize, Clone, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct PublicInformationForIp<C: Curve> {
#[serde(
rename = "idCredPub",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub id_cred_pub: C,
#[serde(
rename = "regId",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub reg_id: C,
#[serde(rename = "publicKeys")]
pub vk_acc: CredentialPublicKeys,
}
#[derive(Clone)]
pub struct IpContext<'a, P: Pairing, C: Curve<Scalar = P::ScalarField>> {
pub ip_info: &'a IpInfo<P>,
pub ars_infos: &'a BTreeMap<ArIdentity, ArInfo<C>>,
pub global_context: &'a GlobalContext<C>,
}
impl<'a, P: Pairing, C: Curve<Scalar = P::ScalarField>> Copy for IpContext<'a, P, C> {}
#[derive(Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct GlobalContext<C: Curve> {
#[serde(rename = "onChainCommitmentKey")]
pub on_chain_commitment_key: PedersenKey<C>,
#[serde(rename = "bulletproofGenerators")]
pub bulletproof_generators: Generators<C>,
#[string_size_length = 4]
#[serde(rename = "genesisString")]
pub genesis_string: String,
}
impl<C: Curve> GlobalContext<C> {
pub fn generate(genesis_string: String) -> Self {
Self::generate_size(genesis_string, NUM_BULLETPROOF_GENERATORS)
}
pub fn generate_from_seed(genesis_string: String, n: usize, seed: &[u8]) -> Self {
let g = C::hash_to_group(seed);
let h = C::hash_to_group(&to_bytes(&g));
let cmm_key = PedersenKey { g, h };
let mut generators = Vec::with_capacity(n);
let mut generator = h;
for _ in 0..n {
generator = C::hash_to_group(&to_bytes(&generator));
let g = generator;
generator = C::hash_to_group(&to_bytes(&generator));
let h = generator;
generators.push((g, h));
}
GlobalContext {
on_chain_commitment_key: cmm_key,
bulletproof_generators: Generators { G_H: generators },
genesis_string,
}
}
pub fn generate_size(genesis_string: String, n: usize) -> Self {
Self::generate_from_seed(genesis_string, n, &PI_DIGITS[0..1000])
}
pub fn encryption_in_exponent_generator(&self) -> &C { &self.on_chain_commitment_key.h }
pub fn elgamal_generator(&self) -> &C { &self.on_chain_commitment_key.g }
pub fn vector_commitment_base(&self) -> (&C, usize, impl Iterator<Item = &C>) {
let base_size = self.bulletproof_generators.G_H.len();
let iter = self.bulletproof_generators.G_H.iter().map(|x| &x.0);
(&self.on_chain_commitment_key.h, base_size, iter)
}
pub fn bulletproof_generators(&self) -> &Generators<C> { &self.bulletproof_generators }
}
impl<'a, P: Pairing, C: Curve<Scalar = P::ScalarField>> IpContext<'a, P, C> {
pub fn new(
ip_info: &'a IpInfo<P>, ars_infos: &'a BTreeMap<ArIdentity, ArInfo<C>>, global_context: &'a GlobalContext<C>,
) -> Self {
IpContext {
ip_info,
ars_infos,
global_context,
}
}
}
pub trait PublicInitialAccountData {
fn get_public_keys(&self) -> BTreeMap<KeyIndex, VerifyKey>;
fn get_threshold(&self) -> SignatureThreshold;
fn get_cred_key_info(&self) -> CredentialPublicKeys {
CredentialPublicKeys {
keys: self.get_public_keys(),
threshold: self.get_threshold(),
}
}
}
pub trait InitialAccountDataWithSigning: PublicInitialAccountData {
fn sign_public_information_for_ip<C: Curve>(
&self,
info: &PublicInformationForIp<C>,
) -> BTreeMap<KeyIndex, AccountOwnershipSignature>;
}
pub trait PublicCredentialData {
fn get_public_keys(&self) -> BTreeMap<KeyIndex, VerifyKey>;
fn get_threshold(&self) -> SignatureThreshold;
fn get_cred_key_info(&self) -> CredentialPublicKeys {
CredentialPublicKeys {
keys: self.get_public_keys(),
threshold: self.get_threshold(),
}
}
}
pub trait CredentialDataWithSigning: PublicCredentialData {
fn sign<P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: Attribute<C::Scalar>>(
&self,
message_expiry: &Either<types::TransactionTime, AccountAddress>,
unsigned_cred_info: &UnsignedCredentialDeploymentInfo<P, C, AttributeType>,
) -> BTreeMap<KeyIndex, AccountOwnershipSignature>;
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize)]
pub struct AccountKeys {
#[serde(rename = "keys")]
pub keys: BTreeMap<CredentialIndex, CredentialData>,
#[serde(rename = "threshold")]
pub threshold: AccountThreshold,
}
impl From<CredentialData> for AccountKeys {
fn from(cd: CredentialData) -> Self { Self::from((CredentialIndex { index: 0 }, cd)) }
}
impl From<(CredentialIndex, CredentialData)> for AccountKeys {
fn from((ki, cd): (CredentialIndex, CredentialData)) -> Self {
let mut keys = BTreeMap::new();
keys.insert(ki, cd);
Self {
keys,
threshold: AccountThreshold::ONE,
}
}
}
impl From<InitialAccountData> for AccountKeys {
fn from(cd: InitialAccountData) -> Self {
let mut keys = BTreeMap::new();
keys.insert(CredentialIndex { index: 0 }, CredentialData {
keys: cd.keys,
threshold: cd.threshold,
});
Self {
keys,
threshold: AccountThreshold::ONE,
}
}
}
impl AccountKeys {
pub fn sign_data(
&self,
msg: &[u8],
) -> BTreeMap<CredentialIndex, BTreeMap<KeyIndex, Signature>> {
let mut signatures = BTreeMap::<CredentialIndex, BTreeMap<KeyIndex, _>>::new();
for (ci, cred_keys) in self.keys.iter() {
let cred_sigs = cred_keys
.keys
.iter()
.map(|(ki, kp)| (*ki, kp.sign(msg)))
.collect::<BTreeMap<_, _>>();
signatures.insert(*ci, cred_sigs);
}
signatures
}
}
impl AccountKeys {
pub fn generate<R: rand::CryptoRng + rand::Rng>(
account_threshold: AccountThreshold,
indices: &[(CredentialIndex, SignatureThreshold, &[KeyIndex])],
csprng: &mut R,
) -> Self {
let keys = indices.iter().map(|(ci, threshold, kis)| {
(*ci, CredentialData {
keys: kis
.iter()
.map(|ki| (*ki, KeyPair::generate(csprng)))
.collect(),
threshold: *threshold,
})
});
Self {
keys: keys.collect(),
threshold: account_threshold,
}
}
pub fn singleton<R: rand::CryptoRng + rand::Rng>(csprng: &mut R) -> Self {
Self::generate(
AccountThreshold::ONE,
&[(0.into(), SignatureThreshold::ONE, &[0.into()])],
csprng,
)
}
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize)]
pub struct CredentialData {
#[serde(rename = "keys")]
pub keys: BTreeMap<KeyIndex, crate::common::types::KeyPair>,
#[serde(rename = "threshold")]
pub threshold: SignatureThreshold,
}
impl PublicCredentialData for CredentialData {
fn get_threshold(&self) -> SignatureThreshold { self.threshold }
fn get_public_keys(&self) -> BTreeMap<KeyIndex, VerifyKey> {
self.keys
.iter()
.map(|(&idx, kp)| (idx, VerifyKey::Ed25519VerifyKey(kp.public)))
.collect()
}
}
impl CredentialDataWithSigning for CredentialData {
fn sign<P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: Attribute<C::Scalar>>(
&self,
new_or_existing: &Either<types::TransactionTime, AccountAddress>,
unsigned_cred_info: &UnsignedCredentialDeploymentInfo<P, C, AttributeType>,
) -> BTreeMap<KeyIndex, AccountOwnershipSignature> {
let to_sign = super::utils::credential_hash_to_sign(
&unsigned_cred_info.values,
&unsigned_cred_info.proofs,
new_or_existing,
);
self.keys
.iter()
.map(|(&idx, kp)| {
let expanded_sk = ed25519::ExpandedSecretKey::from(&kp.secret);
(idx, expanded_sk.sign(&to_sign, &kp.public).into())
})
.collect()
}
}
#[derive(SerdeSerialize, SerdeDeserialize)]
pub struct InitialAccountData {
#[serde(rename = "keys")]
pub keys: BTreeMap<KeyIndex, crate::common::types::KeyPair>,
#[serde(rename = "threshold")]
pub threshold: SignatureThreshold,
}
impl PublicInitialAccountData for InitialAccountData {
fn get_threshold(&self) -> SignatureThreshold { self.threshold }
fn get_public_keys(&self) -> BTreeMap<KeyIndex, VerifyKey> {
self.keys
.iter()
.map(|(&idx, kp)| (idx, VerifyKey::Ed25519VerifyKey(kp.public)))
.collect()
}
}
impl InitialAccountDataWithSigning for InitialAccountData {
fn sign_public_information_for_ip<C: Curve>(
&self,
pub_info_for_ip: &PublicInformationForIp<C>,
) -> BTreeMap<KeyIndex, AccountOwnershipSignature> {
let to_sign = Sha256::digest(to_bytes(pub_info_for_ip));
self.keys
.iter()
.map(|(&idx, kp)| {
let expanded_sk = ed25519::ExpandedSecretKey::from(&kp.secret);
(idx, expanded_sk.sign(&to_sign, &kp.public).into())
})
.collect()
}
}
#[derive(
Debug, PartialEq, Eq, SerdeSerialize, SerdeDeserialize, Clone, concordium_std::Serialize,
)]
pub struct CredentialPublicKeys {
#[serde(rename = "keys")]
#[concordium(size_length = 1)]
pub keys: BTreeMap<KeyIndex, VerifyKey>,
#[serde(rename = "threshold")]
pub threshold: SignatureThreshold,
}
impl Serial for CredentialPublicKeys {
fn serial<B: Buffer>(&self, out: &mut B) {
let len = self.keys.len() as u8;
out.put(&len);
serial_map_no_length(&self.keys, out);
out.put(&self.threshold);
}
}
impl Deserial for CredentialPublicKeys {
fn deserial<R: ReadBytesExt>(cur: &mut R) -> ParseResult<Self> {
let len = cur.read_u8()?;
if len == 0 {
bail!(anyhow!("At least one key must be present."));
}
let keys = deserial_map_no_length(cur, usize::from(len))?;
let threshold = cur.get()?;
Ok(CredentialPublicKeys { keys, threshold })
}
}
impl CredentialPublicKeys {
pub fn get(&self, idx: KeyIndex) -> Option<&VerifyKey> { self.keys.get(&idx) }
}
impl Serial for SchemeId {
fn serial<B: Buffer>(&self, out: &mut B) {
match self {
SchemeId::Ed25519 => out.write_u8(0).expect("Writing to buffer is safe."),
}
}
}
impl Deserial for SchemeId {
fn deserial<R: ReadBytesExt>(cur: &mut R) -> ParseResult<Self> {
match cur.read_u8()? {
0 => Ok(SchemeId::Ed25519),
_ => bail!("Only Ed25519 signature scheme supported."),
}
}
}
#[derive(SerdeSerialize, SerdeDeserialize, Serialize, Default)]
pub struct IpMetadata {
#[string_size_length = 4]
#[serde(rename = "issuanceStart")]
pub issuance_start: String,
#[string_size_length = 4]
#[serde(rename = "icon")]
pub icon: String,
}
#[derive(SerdeSerialize, SerdeDeserialize, Serialize)]
#[serde(bound(serialize = "P: Pairing", deserialize = "P: Pairing"))]
pub struct IpData<P: Pairing> {
#[serde(rename = "ipInfo")]
pub public_ip_info: IpInfo<P>,
#[serde(
rename = "ipSecretKey",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub ip_secret_key: crate::ps_sig::SecretKey<P>,
#[serde(
rename = "ipCdiSecretKey",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub ip_cdi_secret_key: ed25519::SecretKey,
}
#[derive(SerdeSerialize, SerdeDeserialize, Serialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct ArData<C: Curve> {
#[serde(rename = "arInfo")]
pub public_ar_info: ArInfo<C>,
#[serde(
rename = "arSecretKey",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub ar_secret_key: ElgamalSecretKey<C>,
}
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>",
deserialize = "P: Pairing, C: Curve<Scalar=P::ScalarField>"
))]
pub struct IdObjectUseData<P: Pairing, C: Curve<Scalar = P::ScalarField>> {
#[serde(rename = "aci")]
pub aci: AccCredentialInfo<C>,
#[serde(
rename = "randomness",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub randomness: crate::ps_sig::SigRetrievalRandomness<P>,
}
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct AnonymityRevocationRecord<C: Curve> {
#[serde(
rename = "idCredPub",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub id_cred_pub: C,
#[serde(rename = "arData")]
pub ar_data: BTreeMap<ArIdentity, IpArData<C>>,
#[serde(rename = "maxAccounts")]
pub max_accounts: u8,
#[serde(rename = "revocationThreshold")]
pub threshold: Threshold,
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone)]
#[serde(tag = "type", content = "contents")]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeSerialize",
deserialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub enum AccountCredential<
P: Pairing,
C: Curve<Scalar = P::ScalarField>,
AttributeType: Attribute<C::Scalar>,
> {
#[serde(rename = "initial")]
Initial {
#[serde(flatten)]
icdi: InitialCredentialDeploymentInfo<C, AttributeType>,
},
#[serde(rename = "normal")]
Normal {
#[serde(flatten)]
cdi: CredentialDeploymentInfo<P, C, AttributeType>,
},
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: Attribute<C::Scalar>> Serial
for AccountCredential<P, C, AttributeType>
{
fn serial<B: Buffer>(&self, out: &mut B) {
match self {
AccountCredential::Initial { icdi } => {
0u8.serial(out);
icdi.serial(out)
}
AccountCredential::Normal { cdi } => {
1u8.serial(out);
cdi.serial(out)
}
}
}
}
impl<P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: Attribute<C::Scalar>> Deserial
for AccountCredential<P, C, AttributeType>
{
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
match source.get()? {
0u8 => {
let icdi = source.get()?;
Ok(AccountCredential::Initial { icdi })
}
1u8 => {
let cdi = source.get()?;
Ok(AccountCredential::Normal { cdi })
}
n => bail!("AccountCredential::deserial: Unsupported tag {}.", n),
}
}
}
#[derive(SerdeSerialize, SerdeDeserialize, Serialize, Debug, Clone)]
#[serde(bound(
serialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeSerialize",
deserialize = "P: Pairing, C: Curve<Scalar = P::ScalarField>, AttributeType: \
Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub struct AccountCredentialMessage<
P: Pairing,
C: Curve<Scalar = P::ScalarField>,
AttributeType: Attribute<C::Scalar>,
> {
#[serde(rename = "messageExpiry")]
pub message_expiry: types::TransactionTime,
#[serde(rename = "credential")]
pub credential: AccountCredential<P, C, AttributeType>,
}
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(tag = "type", content = "contents")]
#[serde(bound(
serialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeSerialize",
deserialize = "C: Curve, AttributeType: Attribute<C::Scalar> + SerdeDeserialize<'de>"
))]
pub enum AccountCredentialValues<C: Curve, AttributeType: Attribute<C::Scalar>> {
#[serde(rename = "initial")]
Initial {
#[serde(flatten)]
icdi: InitialCredentialDeploymentValues<C, AttributeType>,
},
#[serde(rename = "normal")]
Normal {
#[serde(flatten)]
cdi: CredentialDeploymentValues<C, AttributeType>,
},
}
pub trait HasAttributeRandomness<C: Curve, TagType = AttributeTag> {
type ErrorType: 'static + Send + Sync + std::error::Error;
fn get_attribute_commitment_randomness(
&self,
attribute_tag: &TagType,
) -> Result<PedersenRandomness<C>, Self::ErrorType>;
}
#[derive(thiserror::Error, Debug)]
#[error("The randomness for attribute {tag} is missing.")]
pub struct MissingAttributeRandomnessError<TagType> {
tag: TagType,
}
impl<
C: Curve,
TagType: Ord + Clone + std::fmt::Display + std::fmt::Debug + Send + Sync + 'static,
> HasAttributeRandomness<C, TagType> for BTreeMap<TagType, PedersenRandomness<C>>
{
type ErrorType = MissingAttributeRandomnessError<TagType>;
fn get_attribute_commitment_randomness(
&self,
attribute_tag: &TagType,
) -> Result<PedersenRandomness<C>, Self::ErrorType> {
self.get(attribute_tag)
.cloned()
.ok_or(MissingAttributeRandomnessError {
tag: attribute_tag.clone(),
})
}
}
impl<
C: Curve,
TagType: Ord + Clone + std::fmt::Display + std::fmt::Debug + Send + Sync + 'static,
> HasAttributeRandomness<C, TagType> for BTreeMap<TagType, Value<C>>
{
type ErrorType = MissingAttributeRandomnessError<TagType>;
fn get_attribute_commitment_randomness(
&self,
attribute_tag: &TagType,
) -> Result<PedersenRandomness<C>, Self::ErrorType> {
self.get(attribute_tag)
.map(PedersenRandomness::from_value)
.ok_or(MissingAttributeRandomnessError {
tag: attribute_tag.clone(),
})
}
}
pub trait HasAttributeValues<F: Field, TagType, AttributeType: Attribute<F>> {
fn get_attribute_value(&self, attribute_tag: &TagType) -> Option<&AttributeType>;
}
impl<F: Field, TagType: Serialize + std::cmp::Ord, AttributeType: Attribute<F>>
HasAttributeValues<F, TagType, AttributeType> for BTreeMap<TagType, AttributeType>
{
fn get_attribute_value(&self, attribute_tag: &TagType) -> Option<&AttributeType> {
self.get(attribute_tag)
}
}
#[derive(Debug, Error)]
pub enum ImpossibleError {}
pub struct SystemAttributeRandomness;
impl<C: Curve> HasAttributeRandomness<C> for SystemAttributeRandomness {
type ErrorType = ImpossibleError;
fn get_attribute_commitment_randomness(
&self,
_attribute_tag: &AttributeTag,
) -> Result<PedersenRandomness<C>, Self::ErrorType> {
let mut csprng = rand::thread_rng();
Ok(PedersenRandomness::generate(&mut csprng))
}
}
#[derive(SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
pub struct IdRecoveryRequest<C: Curve> {
#[serde(
rename = "idCredPub",
serialize_with = "base16_encode",
deserialize_with = "base16_decode"
)]
pub id_cred_pub: C,
#[serde(rename = "timestamp")]
pub timestamp: u64,
#[serde(rename = "proof")]
pub proof: dlog::Proof<C>,
}
#[cfg(test)]
mod tests {
use super::*;
use ed25519::Signer;
#[test]
fn test_serde_sig() {
use rand::thread_rng;
let mut csprng = thread_rng();
let keypair = ed25519::Keypair::generate(&mut csprng);
for _ in 0..1000 {
let message: &[u8] = b"test";
let signature: AccountOwnershipSignature = keypair.sign(message).into();
let serialized = serde_json::to_string(&signature).unwrap();
let deserialized: AccountOwnershipSignature =
serde_json::from_str(&serialized).unwrap();
assert_eq!(signature, deserialized);
}
}
#[test]
fn test_yearmonth_serialization() {
let ym1 = YearMonth::new(2020, 2).unwrap();
let ym2 = YearMonth::new(2020, 2).unwrap();
assert_eq!(ym1, ym2);
let mut buf = Vec::new();
buf.put(&ym1);
let mut cursor = std::io::Cursor::new(buf);
let ym1_parsed = cursor.get().unwrap();
assert_eq!(ym1, ym1_parsed);
let json = serde_json::to_string(&ym1).unwrap();
assert_eq!("\"202002\"", json);
let ym1_parsed = serde_json::from_str(&json).unwrap();
assert_eq!(ym1, ym1_parsed);
let num: u64 = u64::from(ym1);
assert_eq!(num, 517122);
let ym1_parsed = YearMonth::try_from(num).unwrap();
assert_eq!(ym1, ym1_parsed);
}
#[test]
fn test_aliases() -> anyhow::Result<()> {
use rand::{thread_rng, Rng};
let base = AccountAddress(thread_rng().gen());
for i in 0..(1 << 24) {
let alias = base
.get_alias(i)
.expect("Counter < 2^24, so alias should exist.");
anyhow::ensure!(
alias.is_alias(&base),
"Generated alias {:?} is not an alias of the base address {:?}.",
alias,
base
)
}
anyhow::ensure!(base.get_alias(1 << 24).is_none());
Ok(())
}
#[test]
fn test_timestamp_lower_upper() {
use chrono::Datelike;
for year in 1000..=9999 {
for month in 1..=12 {
if month == 12 && year == 9999 {
continue;
}
let ym = YearMonth::new(year, month).unwrap();
let lower = ym.lower().unwrap();
let upper = ym.upper().unwrap();
assert_eq!(lower.year(), year as i32);
assert_eq!(lower.month(), month as u32);
assert_eq!(
upper.year(),
if month == 12 { year + 1 } else { year } as i32
);
assert_eq!(
upper.month(),
if month == 12 { 1 } else { (month + 1) as u32 }
);
let lower_from_ts = YearMonth::from_timestamp(lower.timestamp()).unwrap();
assert_eq!(ym, lower_from_ts);
}
}
}
}