lib.rs 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155
  1. // We want the macros like CMZ14Protocol to be camel case
  2. #![allow(non_snake_case)]
  3. /*! The implementation of the CMZCred derive.
  4. This derive should not be explicitly used by a programmer using a CMZ
  5. credential. Instead, a CMZ credential should be declared with the
  6. `CMZ!{ Name: attr1, attr2, attr3 }`
  7. macro. That macro will internally expand to a struct annotated with
  8. this CMZCred derive. This derive will output the implementation of
  9. the CMZCredential trait for the declared credential.
  10. */
  11. use darling::FromDeriveInput;
  12. use proc_macro::TokenStream;
  13. use proc_macro2::TokenStream as TokenStream2;
  14. use quote::{format_ident, quote, ToTokens};
  15. use std::collections::HashMap;
  16. use syn::parse::{Parse, ParseStream, Result};
  17. use syn::punctuated::Punctuated;
  18. use syn::visit_mut::{self, VisitMut};
  19. use syn::{
  20. braced, bracketed, parse_macro_input, parse_quote, token, Data, DataStruct, DeriveInput, Expr,
  21. Fields, FieldsNamed, Ident, Member, Token, Visibility,
  22. };
  23. fn impl_cmzcred_derive(ast: &syn::DeriveInput, group_ident: &Ident) -> TokenStream {
  24. // Ensure that CMZCred is derived on a struct and not something else
  25. // (like an enum)
  26. let Data::Struct(DataStruct {
  27. struct_token: _,
  28. fields:
  29. Fields::Named(FieldsNamed {
  30. brace_token: _,
  31. ref named,
  32. }),
  33. semi_token: _,
  34. }) = ast.data
  35. else {
  36. panic!("CMZCred derived on a non-struct");
  37. };
  38. // attrs and idents are each vectors of the names of the attributes
  39. // of the credential (not including the MAC and any non-public
  40. // fields). attrs stores the names as Strings, while idents stores
  41. // them as Idents.
  42. let mut attrs = Vec::<String>::new();
  43. let mut idents = Vec::<&Ident>::new();
  44. for n in named {
  45. let Some(ref ident) = n.ident else {
  46. panic!("Missing attribute name in CMZCred");
  47. };
  48. let id_str = ident.to_string();
  49. if let Visibility::Public(_) = n.vis {
  50. if id_str != *"MAC" {
  51. attrs.push(id_str);
  52. idents.push(ident);
  53. }
  54. }
  55. }
  56. let num_attrs = attrs.len();
  57. let attr_index = 0..num_attrs;
  58. let name = &ast.ident;
  59. let errmsg = format!("Invalid attribute name for {} CMZ credential", name);
  60. // Output the CMZCredential trait implementation
  61. let gen = quote! {
  62. impl CMZCredential for #name {
  63. type Scalar = <#group_ident as Group>::Scalar;
  64. type Point = #group_ident;
  65. fn attrs() -> Vec<&'static str> {
  66. vec![
  67. #( #attrs, )*
  68. ]
  69. }
  70. fn num_attrs() -> usize {
  71. return #num_attrs;
  72. }
  73. fn attr_num(attrname: &str) -> usize {
  74. match attrname {
  75. #( #attrs => #attr_index, )*
  76. _ => panic!(#errmsg),
  77. }
  78. }
  79. fn attr(&self, attrname: &str) -> &Option<Self::Scalar> {
  80. match attrname {
  81. #( #attrs => &self.#idents, )*
  82. _ => panic!(#errmsg),
  83. }
  84. }
  85. fn attr_mut(&mut self, attrname: &str) -> &mut Option<Self::Scalar> {
  86. match attrname {
  87. #( #attrs => &mut self.#idents, )*
  88. _ => panic!(#errmsg),
  89. }
  90. }
  91. fn set_pubkey(&mut self, pubkey: &CMZPubkey<Self::Point>) -> &mut Self {
  92. self.pubkey = pubkey.clone();
  93. self
  94. }
  95. fn get_pubkey<'a> (&'a self) -> &'a CMZPubkey<Self::Point> {
  96. &self.pubkey
  97. }
  98. fn set_privkey(&mut self, privkey: &CMZPrivkey<Self::Point>) -> &mut Self {
  99. self.pubkey = cmz_privkey_to_pubkey(&privkey);
  100. self.privkey = privkey.clone();
  101. self
  102. }
  103. fn get_privkey<'a> (&'a self) -> &'a CMZPrivkey<Self::Point> {
  104. &self.privkey
  105. }
  106. fn privkey_x(&self, name: &str) -> Self::Scalar {
  107. self.privkey.x[Self::attr_num(name)]
  108. }
  109. fn pubkey_X(&self, name: &str) -> Self::Point {
  110. self.pubkey.X[Self::attr_num(name)]
  111. }
  112. fn gen_keys(rng: &mut impl RngCore, muCMZ: bool) ->
  113. (CMZPrivkey<Self::Point>, CMZPubkey<Self::Point>) {
  114. // Generate (num_attrs + 2) random scalars as the
  115. // private key
  116. let x0 = <Self::Scalar as ff::Field>::random(&mut *rng);
  117. let xr = <Self::Scalar as ff::Field>::random(&mut *rng);
  118. let x: Vec<Self::Scalar> = (0..Self::num_attrs())
  119. .map(|_| <Self::Scalar as ff::Field>::random(&mut *rng))
  120. .collect();
  121. let privkey = CMZPrivkey { muCMZ, x0, xr, x };
  122. // Convert the private key to a public key
  123. let pubkey = cmz_privkey_to_pubkey(&privkey);
  124. (privkey, pubkey)
  125. }
  126. fn compute_MAC_coeff(&self, privkey: &CMZPrivkey<Self::Point>) -> Result<Self::Scalar, ()> {
  127. if privkey.x.len() != Self::num_attrs() {
  128. return Err(());
  129. }
  130. let mut coeff = privkey.x0;
  131. if privkey.muCMZ {
  132. coeff += privkey.xr;
  133. }
  134. for field in Self::attrs().iter() {
  135. let attr_val = self.attr(field).ok_or(())?;
  136. coeff += attr_val * privkey.x[Self::attr_num(field)];
  137. }
  138. Ok(coeff)
  139. }
  140. fn create_MAC(&mut self, rng: &mut impl RngCore, privkey: &CMZPrivkey<Self::Point>) -> Result<(),()> {
  141. let coeff = self.compute_MAC_coeff(privkey)?;
  142. self.MAC.P = <Self::Point as group::Group>::random(&mut *rng);
  143. self.MAC.Q = coeff * self.MAC.P;
  144. Ok(())
  145. }
  146. fn verify_MAC(&self, privkey: &CMZPrivkey<Self::Point>) ->
  147. Result<(),()> {
  148. let coeff = self.compute_MAC_coeff(privkey)?;
  149. if !bool::from(self.MAC.P.is_identity()) && coeff * self.MAC.P == self.MAC.Q {
  150. Ok(())
  151. } else {
  152. Err(())
  153. }
  154. }
  155. fn fake_MAC(&mut self, rng: &mut impl RngCore) {
  156. self.MAC.P = <Self::Point as group::Group>::random(&mut *rng);
  157. self.MAC.Q = <Self::Point as group::Group>::random(&mut *rng);
  158. }
  159. }
  160. };
  161. gen.into()
  162. }
  163. #[derive(FromDeriveInput)]
  164. #[darling(attributes(cmzcred_group))]
  165. struct GroupIdent {
  166. group: Ident,
  167. }
  168. #[proc_macro_derive(CMZCred, attributes(cmzcred_group))]
  169. pub fn cmzcred_derive(input: TokenStream) -> TokenStream {
  170. // Construct a representation of Rust code as a syntax tree
  171. // that we can manipulate
  172. let ast: DeriveInput = syn::parse(input).unwrap();
  173. // Get the cmzcred_group(group = G) attribute
  174. let group_ident = GroupIdent::from_derive_input(&ast)
  175. .expect("missing group parameter to cmzcred_group attribute");
  176. // Build the trait implementation
  177. impl_cmzcred_derive(&ast, &group_ident.group)
  178. }
  179. /** The CMZ Protocol creation macros.
  180. The format is:
  181. let proto = muCMZProtocol! { proto_name<param1,param2>,
  182. [ A: Cred {
  183. attr1: H,
  184. attr2: R,
  185. },
  186. B?: Cred2 {
  187. attr3: H,
  188. attr4: I,
  189. } ],
  190. C: Cred3 {
  191. attr5: J,
  192. attr6: R,
  193. attr7: H,
  194. attr8: I,
  195. attr9: S,
  196. },
  197. A.attr1 == B.attr3 + param1,
  198. A.attr1 == C.attr7,
  199. };
  200. The parameters are:
  201. - an identifier for the protocol
  202. - an optional angle-bracketed list of parameters (identifiers)
  203. - a list of zero or more specifications for credentials that will be shown
  204. - a list of zero or more specifications for credentials that will be issued
  205. - zero or more statements relating the attributes in the credentials
  206. Each credential specification list can be:
  207. - empty
  208. - a single credential specification
  209. - a square-bracketed list of credential specifications
  210. Each credential specification is:
  211. - an identifier for the credential
  212. - for a shown (not issued) credential, an optional "?". If present,
  213. the validity of this credential will _not_ be proved by default,
  214. and must be explicit (perhaps in only some branches of an "OR"
  215. statement) in the statements; if absent (the default), the validity
  216. of the shown credential will always be proven
  217. - a type for the credential, previously defined with the CMZ! macro
  218. - a braced list of the attributes of the credential (as defined in
  219. the CMZ! macro), annotated with the attribute specification
  220. An attribute specification for a credential to be shown is one of:
  221. - H (hide)
  222. - R (reveal)
  223. - I (implicit)
  224. An attribute specification for a credential to be issued is one of:
  225. - H (hide)
  226. - R (reveal)
  227. - I (implicit)
  228. - S (set by issuer)
  229. - J (joint creation)
  230. */
  231. // The possible attribute specifications for a credential to be shown
  232. #[derive(Copy, Clone, Debug, PartialEq)]
  233. enum ShowSpec {
  234. Hide,
  235. Reveal,
  236. Implicit,
  237. }
  238. impl Parse for ShowSpec {
  239. fn parse(input: ParseStream) -> Result<Self> {
  240. let spec: Ident = input.parse()?;
  241. match spec.to_string().to_uppercase().as_str() {
  242. "H" | "HIDE" => Ok(Self::Hide),
  243. "R" | "REVEAL" => Ok(Self::Reveal),
  244. "I" | "IMPLICIT" => Ok(Self::Implicit),
  245. _ => Err(input.error("Unknown attribute spec for shown credential")),
  246. }
  247. }
  248. }
  249. impl ShowSpec {
  250. fn abbr(&self) -> &'static str {
  251. match self {
  252. Self::Hide => "H",
  253. Self::Reveal => "R",
  254. Self::Implicit => "I",
  255. }
  256. }
  257. }
  258. // The possible attribute specifications for a credential to be issued
  259. #[derive(Copy, Clone, Debug, PartialEq)]
  260. enum IssueSpec {
  261. Hide,
  262. Reveal,
  263. Implicit,
  264. Set,
  265. Joint,
  266. }
  267. impl Parse for IssueSpec {
  268. fn parse(input: ParseStream) -> Result<Self> {
  269. let spec: Ident = input.parse()?;
  270. match spec.to_string().to_uppercase().as_str() {
  271. "H" | "HIDE" => Ok(Self::Hide),
  272. "R" | "REVEAL" => Ok(Self::Reveal),
  273. "I" | "IMPLICIT" => Ok(Self::Implicit),
  274. "S" | "SET" => Ok(Self::Set),
  275. "J" | "JOINT" => Ok(Self::Joint),
  276. _ => Err(input.error("Unknown attribute spec for issued credential")),
  277. }
  278. }
  279. }
  280. impl IssueSpec {
  281. fn abbr(&self) -> &'static str {
  282. match self {
  283. Self::Hide => "H",
  284. Self::Reveal => "R",
  285. Self::Implicit => "I",
  286. Self::Set => "S",
  287. Self::Joint => "J",
  288. }
  289. }
  290. }
  291. // An attribute specification like "attr1: Reveal"
  292. #[derive(Clone)]
  293. struct AttrSpec<ShowOrIssue: Parse> {
  294. attr: Ident,
  295. spec: ShowOrIssue,
  296. }
  297. impl<ShowOrIssue: Parse> Parse for AttrSpec<ShowOrIssue> {
  298. fn parse(input: ParseStream) -> Result<Self> {
  299. let attr: Ident = input.parse()?;
  300. input.parse::<Token![:]>()?;
  301. let spec: ShowOrIssue = input.parse()?;
  302. Ok(Self { attr, spec })
  303. }
  304. }
  305. // A specification of a credential, either to be shown or issued
  306. #[derive(Debug)]
  307. struct CredSpec<ShowOrIssue: Parse, const VALID_OPTIONAL: bool> {
  308. id: Ident,
  309. cred_type: Ident,
  310. // For shown credentials only (not issued credentials): set to true
  311. // if we want to only optionally (for example, in an "OR" clause)
  312. // show that this credential is valid. The default state of false
  313. // means we should always show that the credential is valid.
  314. valid_optional: bool,
  315. attrs: HashMap<Ident, ShowOrIssue>,
  316. }
  317. impl<ShowOrIssue: Parse + Copy, const VALID_OPTIONAL: bool> Parse
  318. for CredSpec<ShowOrIssue, VALID_OPTIONAL>
  319. {
  320. fn parse(input: ParseStream) -> Result<Self> {
  321. let id: Ident = input.parse()?;
  322. let valid_optional = if VALID_OPTIONAL && input.peek(Token![?]) {
  323. input.parse::<Token![?]>()?;
  324. true
  325. } else {
  326. false
  327. };
  328. input.parse::<Token![:]>()?;
  329. let cred_type: Ident = input.parse()?;
  330. let content;
  331. braced!(content in input);
  332. let attrspecs: Punctuated<AttrSpec<ShowOrIssue>, Token![,]> =
  333. content.parse_terminated(AttrSpec::<ShowOrIssue>::parse, Token![,])?;
  334. let mut attrs: HashMap<Ident, ShowOrIssue> = HashMap::new();
  335. for attrspec in attrspecs.iter() {
  336. attrs.insert(attrspec.attr.clone(), attrspec.spec);
  337. }
  338. Ok(Self {
  339. id,
  340. cred_type,
  341. valid_optional,
  342. attrs,
  343. })
  344. }
  345. }
  346. // A vector of credential specifications, which could be empty, a single
  347. // credential specification, or a bracketed list of credential
  348. // specifications. We need a newtype here and not just a Vec so that we
  349. // can implement the Parse trait for it.
  350. struct CredSpecVec<ShowOrIssue: Parse, const VALID_OPTIONAL: bool>(
  351. Vec<CredSpec<ShowOrIssue, VALID_OPTIONAL>>,
  352. );
  353. impl<ShowOrIssue: Parse + Copy, const VALID_OPTIONAL: bool> Parse
  354. for CredSpecVec<ShowOrIssue, VALID_OPTIONAL>
  355. {
  356. fn parse(input: ParseStream) -> Result<Self> {
  357. let specvec: Vec<CredSpec<ShowOrIssue, VALID_OPTIONAL>> = if input.peek(Token![,]) {
  358. // The list is empty
  359. Vec::new()
  360. } else if input.peek(token::Bracket) {
  361. let content;
  362. bracketed!(content in input);
  363. let specs: Punctuated<CredSpec<ShowOrIssue, VALID_OPTIONAL>, Token![,]> = content
  364. .parse_terminated(CredSpec::<ShowOrIssue, VALID_OPTIONAL>::parse, Token![,])?;
  365. specs.into_iter().collect()
  366. } else {
  367. let spec: CredSpec<ShowOrIssue, VALID_OPTIONAL> = input.parse()?;
  368. vec![spec]
  369. };
  370. Ok(Self(specvec))
  371. }
  372. }
  373. // A protocol specification, following the syntax described above.
  374. #[derive(Debug)]
  375. struct ProtoSpec {
  376. proto_name: Ident,
  377. params: Vec<Ident>,
  378. point_params: Vec<Ident>,
  379. show_creds: Vec<CredSpec<ShowSpec, true>>,
  380. issue_creds: Vec<CredSpec<IssueSpec, false>>,
  381. statements: Vec<Expr>,
  382. }
  383. impl Parse for ProtoSpec {
  384. fn parse(input: ParseStream) -> Result<Self> {
  385. let mut params: Vec<Ident> = Vec::new();
  386. let mut point_params: Vec<Ident> = Vec::new();
  387. let proto_name: Ident = input.parse()?;
  388. // See if there are optional parameters; Rust does not provide a
  389. // convenient angle-bracket parser like it does parens, square
  390. // brackets, and braces, so we just roll our own.
  391. if input.peek(Token![<]) {
  392. input.parse::<Token![<]>()?;
  393. loop {
  394. if input.peek(Token![>]) {
  395. break;
  396. }
  397. if input.peek(Token![@]) {
  398. // Param identifiers starting with @ are Points
  399. // rather than Scalars.
  400. input.parse::<Token![@]>()?;
  401. let param: Ident = input.parse()?;
  402. point_params.push(param);
  403. } else {
  404. let param: Ident = input.parse()?;
  405. params.push(param);
  406. }
  407. if input.peek(Token![>]) {
  408. break;
  409. }
  410. input.parse::<Token![,]>()?;
  411. }
  412. input.parse::<Token![>]>()?;
  413. }
  414. input.parse::<Token![,]>()?;
  415. let showvec: CredSpecVec<ShowSpec, true> = input.parse()?;
  416. input.parse::<Token![,]>()?;
  417. let issuevec: CredSpecVec<IssueSpec, false> = input.parse()?;
  418. input.parse::<Token![,]>()?;
  419. let statementpunc: Punctuated<Expr, Token![,]> =
  420. input.parse_terminated(Expr::parse, Token![,])?;
  421. let statements: Vec<Expr> = statementpunc.into_iter().collect();
  422. Ok(ProtoSpec {
  423. proto_name,
  424. params,
  425. point_params,
  426. show_creds: showvec.0,
  427. issue_creds: issuevec.0,
  428. statements,
  429. })
  430. }
  431. }
  432. // Names and types of fields that might end up in a generated struct
  433. enum StructField {
  434. Scalar(Ident),
  435. Point(Ident),
  436. EncPoint(Ident),
  437. Pubkey(Ident),
  438. ByteVec(Ident),
  439. }
  440. // A list of StructField items
  441. #[derive(Default)]
  442. struct StructFieldList {
  443. fields: Vec<StructField>,
  444. }
  445. impl StructFieldList {
  446. pub fn push_scalar(&mut self, s: &Ident) {
  447. self.fields.push(StructField::Scalar(s.clone()));
  448. }
  449. pub fn push_point(&mut self, s: &Ident) {
  450. self.fields.push(StructField::Point(s.clone()));
  451. }
  452. pub fn push_encpoint(&mut self, s: &Ident) {
  453. self.fields.push(StructField::EncPoint(s.clone()));
  454. }
  455. pub fn push_pubkey(&mut self, s: &Ident) {
  456. self.fields.push(StructField::Pubkey(s.clone()));
  457. }
  458. pub fn push_bytevec(&mut self, s: &Ident) {
  459. self.fields.push(StructField::ByteVec(s.clone()));
  460. }
  461. /// Output an iterator consisting of the field names
  462. pub fn field_iter(&self) -> impl Iterator<Item = &Ident> {
  463. self.fields.iter().map(|f| match f {
  464. StructField::Scalar(id) => id,
  465. StructField::Point(id) => id,
  466. StructField::EncPoint(id) => id,
  467. StructField::Pubkey(id) => id,
  468. StructField::ByteVec(id) => id,
  469. })
  470. }
  471. /// Output a ToTokens of the fields as they would appear in a struct
  472. /// definition (including the serde_as annotations)
  473. pub fn field_decls(&self) -> impl ToTokens {
  474. let decls = self.fields.iter().map(|f| match f {
  475. StructField::Scalar(id) => quote! {
  476. #[serde_as(as = "SerdeScalar")]
  477. pub #id: Scalar,
  478. },
  479. StructField::Point(id) => quote! {
  480. #[serde_as(as = "SerdePoint")]
  481. pub #id: Point,
  482. },
  483. StructField::EncPoint(id) => quote! {
  484. #[serde_as(as = "(SerdePoint, SerdePoint)")]
  485. pub #id: (Point, Point),
  486. },
  487. StructField::Pubkey(id) => quote! {
  488. pub #id: CMZPubkey<Point>,
  489. },
  490. StructField::ByteVec(id) => quote! {
  491. #[serde(with = "serde_bytes")]
  492. pub #id: Vec<u8>,
  493. },
  494. });
  495. quote! { #(#decls)* }
  496. }
  497. }
  498. // This is where the main work is done. The six macros in the
  499. // CMZProtocol macro family (below) all call this function, with
  500. // different values for the bools.
  501. fn protocol_macro(
  502. input: TokenStream,
  503. use_muCMZ: bool,
  504. emit_client: bool,
  505. emit_issuer: bool,
  506. ) -> TokenStream {
  507. let proto_spec: ProtoSpec = parse_macro_input!(input as ProtoSpec);
  508. let proto_name = &proto_spec.proto_name;
  509. let has_params = !proto_spec.params.is_empty() || !proto_spec.point_params.is_empty();
  510. let tot_num_creds = proto_spec.show_creds.len() + proto_spec.issue_creds.len();
  511. // Use the group of the first named credential type
  512. let group_types = if !proto_spec.show_creds.is_empty() {
  513. let first_cred_type = &proto_spec.show_creds[0].cred_type;
  514. quote! {
  515. pub type Scalar = <#first_cred_type as CMZCredential>::Scalar;
  516. pub type Point = <#first_cred_type as CMZCredential>::Point;
  517. }
  518. } else if !proto_spec.issue_creds.is_empty() {
  519. let first_cred_type = &proto_spec.issue_creds[0].cred_type;
  520. quote! {
  521. pub type Scalar = <#first_cred_type as CMZCredential>::Scalar;
  522. pub type Point = <#first_cred_type as CMZCredential>::Point;
  523. }
  524. } else {
  525. quote! {}
  526. };
  527. // The structure of the client's ZKP
  528. let mut cli_proof_rand_scalars = Vec::<Ident>::default();
  529. let mut cli_proof_priv_scalars = Vec::<Ident>::default();
  530. let mut cli_proof_pub_scalars = Vec::<Ident>::default();
  531. let mut cli_proof_cind_points = Vec::<Ident>::default();
  532. let mut cli_proof_pub_points = Vec::<Ident>::default();
  533. let mut cli_proof_const_points = Vec::<Ident>::default();
  534. let mut cli_proof_statements = Vec::<TokenStream2>::default();
  535. // A map from the credential name and attribute name (as Strings) to
  536. // the scoped attribute identifier. This map is used to translate
  537. // expressions like `L.id` in the user-provided statements into the
  538. // appropriate identifier.
  539. let mut cli_proof_idmap = HashMap::<(String, String), Ident>::default();
  540. // The structure of the issuer's ZKP
  541. let mut iss_proof_rand_scalars = Vec::<Ident>::default();
  542. let mut iss_proof_priv_scalars = Vec::<Ident>::default();
  543. let mut iss_proof_pub_scalars = Vec::<Ident>::default();
  544. // The issuer has no cind_points
  545. let mut iss_proof_pub_points = Vec::<Ident>::default();
  546. let mut iss_proof_const_points = Vec::<Ident>::default();
  547. let mut iss_proof_statements = Vec::<TokenStream2>::default();
  548. /* Credential issuing
  549. For each attribute of each credential to be issued, handle it
  550. according to its IssueSpec:
  551. */
  552. // The fields that will end up in the ClientState
  553. let mut clientstate_fields = StructFieldList::default();
  554. // The fields that will end up in the Request
  555. let mut request_fields = StructFieldList::default();
  556. // The fields that will end up in the Reply
  557. let mut reply_fields = StructFieldList::default();
  558. // The code that will end up in prepare
  559. let mut prepare_code = quote! {};
  560. // The code that will end up in handle, before the call to
  561. // fill_creds
  562. let mut handle_code_pre_fill = quote! {};
  563. // The code that will end up in handle, after the call to
  564. // fill_creds but before the call to authorize
  565. let mut handle_code_post_fill = quote! {};
  566. // The code that will end up in handle, after the call to
  567. // authorize
  568. let mut handle_code_post_auth = quote! {};
  569. // The code that will end up in finalize
  570. let mut finalize_code = quote! {};
  571. // Are there any Hide or Joint attributes in _any_ credential to be
  572. // issued?
  573. let mut any_hide_joint = false;
  574. let A_ident = format_ident!("A_generator");
  575. let B_ident = format_ident!("B_generator");
  576. let d_ident = format_ident!("d_privkey");
  577. let D_ident = format_ident!("D_pubkey");
  578. let iss_proof_sessid_ident = format_ident!("iss_proof_sessid");
  579. prepare_code = quote! {
  580. #prepare_code
  581. let #A_ident = bp.A();
  582. };
  583. handle_code_pre_fill = quote! {
  584. #handle_code_pre_fill
  585. let #A_ident = bp.A();
  586. };
  587. finalize_code = quote! {
  588. #finalize_code
  589. let #A_ident = bp.A();
  590. };
  591. iss_proof_const_points.push(A_ident.clone());
  592. if !use_muCMZ || !proto_spec.issue_creds.is_empty() {
  593. prepare_code = quote! {
  594. #prepare_code
  595. let #B_ident = bp.B();
  596. };
  597. handle_code_pre_fill = quote! {
  598. #handle_code_pre_fill
  599. let #B_ident = bp.B();
  600. };
  601. finalize_code = quote! {
  602. #finalize_code
  603. let #B_ident = bp.B();
  604. };
  605. iss_proof_const_points.push(B_ident.clone());
  606. }
  607. // Stash the issue proof session id in prepare so that it can be
  608. // used in finalize
  609. clientstate_fields.push_bytevec(&iss_proof_sessid_ident);
  610. for iss_cred in proto_spec.issue_creds.iter() {
  611. // Are there any Hide or Joint attributes in this particular
  612. // credential to be issued?
  613. let mut cred_hide_joint = false;
  614. // The credential being issued
  615. let iss_cred_id = format_ident!("iss_cred_{}", iss_cred.id);
  616. // The public key for the credential
  617. let pubkey_cred = format_ident!("pubkey_iss_cred_{}", iss_cred.id);
  618. // The randomizing factor to generate P
  619. let b_cred = format_ident!("b_iss_cred_{}", iss_cred.id);
  620. // The (revealed part of) the MAC
  621. let P_cred = format_ident!("P_iss_cred_{}", iss_cred.id);
  622. let Q_cred = format_ident!("Q_iss_cred_{}", iss_cred.id);
  623. // Only for CMZ14, not µCMZ:
  624. // The encrypted form of the hidden part of the MAC
  625. let EQ_cred = format_ident!("EQ_iss_cred_{}", iss_cred.id);
  626. let EQ0_cred = format_ident!("EQ0_iss_cred_{}", iss_cred.id);
  627. let EQ1_cred = format_ident!("EQ1_iss_cred_{}", iss_cred.id);
  628. // The ZKP statements that prove the format of EQ_cred
  629. let mut eq0_statement = quote! {};
  630. let mut eq1_statement = quote! {};
  631. // Only for µCMZ, not CMZ14:
  632. // The Pedersen commitment to only the Hide and Joint attributes
  633. let C_cred = format_ident!("C_iss_cred_{}", iss_cred.id);
  634. // The completed Pedersen commitment to the attributes
  635. // (including all kinds of attributes)
  636. let K_cred = format_ident!("K_iss_cred_{}", iss_cred.id);
  637. // The ZKP statement that proves the format of C
  638. let mut C_statement = quote! {};
  639. let iss_cred_type = &iss_cred.cred_type;
  640. // String version of the credential name
  641. let cred_str = iss_cred.id.to_string();
  642. // Check that fill_creds filled in the private key for this
  643. // credential and that it's for the right protocol (CMZ14 or
  644. // µCMZ)
  645. handle_code_post_fill = quote! {
  646. #handle_code_post_fill
  647. if #iss_cred_id.get_privkey().x.len() != #iss_cred_type::num_attrs() {
  648. return Err(CMZError::PrivkeyMissing(#cred_str));
  649. }
  650. if #iss_cred_id.get_privkey().muCMZ != #use_muCMZ {
  651. return Err(CMZError::WrongProtocol(#cred_str));
  652. }
  653. };
  654. // Check that the credential passed to prepare has its public
  655. // key set and that it's for the right protocol (CMZ14 or µCMZ)
  656. prepare_code = quote! {
  657. #prepare_code
  658. if #iss_cred_id.get_pubkey().X.len() != #iss_cred_type::num_attrs() {
  659. return Err(CMZError::PubkeyMissing(#cred_str));
  660. }
  661. if #iss_cred_id.get_pubkey().Xr.is_some() != #use_muCMZ {
  662. return Err(CMZError::WrongProtocol(#cred_str));
  663. }
  664. };
  665. // Stash the public key in prepare and use it to fill in the
  666. // public key of the completed credential in finalize
  667. clientstate_fields.push_pubkey(&pubkey_cred);
  668. prepare_code = quote! {
  669. #prepare_code
  670. let #pubkey_cred = #iss_cred_id.get_pubkey().clone();
  671. };
  672. finalize_code = quote! {
  673. #finalize_code
  674. #iss_cred_id.set_pubkey(&self.#pubkey_cred);
  675. };
  676. for (attr, &spec) in iss_cred.attrs.iter() {
  677. // String version of the attribute name
  678. let attr_str = attr.to_string();
  679. // The scoped attribute name
  680. let scoped_attr = format_ident!("iss_{}attr_{}_{}", spec.abbr(), iss_cred.id, attr);
  681. // Remember the mapping from the credential and attribute
  682. // name to the scoped attribute
  683. cli_proof_idmap.insert(
  684. (iss_cred.id.to_string(), attr.to_string()),
  685. scoped_attr.clone(),
  686. );
  687. // The private and public key for this attribute
  688. let x_attr = format_ident!("x_{}", scoped_attr);
  689. let X_attr = format_ident!("X_{}", scoped_attr);
  690. if spec == IssueSpec::Hide || spec == IssueSpec::Joint {
  691. cred_hide_joint = true;
  692. }
  693. if !use_muCMZ {
  694. // For CMZ14, we prove that the encrypted MAC is
  695. // consistent with all components of the credential's
  696. // public key
  697. handle_code_post_auth = quote! {
  698. #handle_code_post_auth
  699. let #x_attr = #iss_cred_id.privkey_x(#attr_str);
  700. let #X_attr = #iss_cred_id.pubkey_X(#attr_str);
  701. };
  702. finalize_code = quote! {
  703. #finalize_code
  704. let #X_attr = #iss_cred_id.pubkey_X(#attr_str);
  705. };
  706. iss_proof_priv_scalars.push(x_attr.clone());
  707. iss_proof_pub_points.push(X_attr.clone());
  708. iss_proof_statements.push(quote! {
  709. #X_attr = #x_attr * #A_ident,
  710. });
  711. }
  712. if spec == IssueSpec::Hide {
  713. /* For each Hide attribute, the attribute (passed in the
  714. prepare) goes in the ClientState, and from there to
  715. to the generated credential in finalize.
  716. */
  717. clientstate_fields.push_scalar(&scoped_attr);
  718. prepare_code = quote! {
  719. #prepare_code
  720. let #scoped_attr =
  721. #iss_cred_id.#attr.ok_or(CMZError::HideAttrMissing(#cred_str,
  722. #attr_str))?;
  723. };
  724. finalize_code = quote! {
  725. #finalize_code
  726. #iss_cred_id.#attr = Some(self.#scoped_attr);
  727. }
  728. }
  729. if spec == IssueSpec::Joint {
  730. /* For each Joint attribute, the client's part of the
  731. attribute (randomly generated) goes in the
  732. ClientState, and the issuer's part of the attribute
  733. (randomly generated) goes in the Reply.
  734. */
  735. clientstate_fields.push_scalar(&scoped_attr);
  736. reply_fields.push_scalar(&scoped_attr);
  737. prepare_code = quote! {
  738. #prepare_code
  739. let #scoped_attr = <Scalar as ff::Field>::random(&mut *rng);
  740. };
  741. handle_code_pre_fill = quote! {
  742. #handle_code_pre_fill
  743. let #scoped_attr = <Scalar as ff::Field>::random(&mut *rng);
  744. };
  745. finalize_code = quote! {
  746. #finalize_code
  747. let #scoped_attr = reply.#scoped_attr;
  748. #iss_cred_id.#attr = Some(self.#scoped_attr + reply.#scoped_attr);
  749. };
  750. }
  751. if !use_muCMZ && (spec == IssueSpec::Hide || spec == IssueSpec::Joint) {
  752. /* For each Hide and Joint attribute (for CMZ14): Compute an
  753. exponential El Gamal encryption (of the attribute) E_attr =
  754. (r_attr*B, attr*B + r_attr*D) for random r_attr. Include E_attr
  755. in the Request, attr in the ClientState, and attr,
  756. r_attr, and E_attr in the CliProof. Add
  757. b*x_attr*E_attr to E_Q in handle, for the b chosen on
  758. a per-issued-credential basis below. Include x_attr,
  759. X_attr, and t_attr = b*x_attr in IssProof and T_attr
  760. = b*X_attr = t_attr*A in Reply and IssProof.
  761. */
  762. let enc_attr = format_ident!("E_{}", scoped_attr);
  763. let enc0_attr = format_ident!("E0_{}", scoped_attr);
  764. let enc1_attr = format_ident!("E1_{}", scoped_attr);
  765. let r_attr = format_ident!("r_{}", scoped_attr);
  766. let t_attr = format_ident!("t_{}", scoped_attr);
  767. let T_attr = format_ident!("T_{}", scoped_attr);
  768. request_fields.push_encpoint(&enc_attr);
  769. clientstate_fields.push_encpoint(&enc_attr);
  770. reply_fields.push_point(&T_attr);
  771. iss_proof_priv_scalars.push(t_attr.clone());
  772. iss_proof_pub_points.push(T_attr.clone());
  773. iss_proof_pub_points.push(enc0_attr.clone());
  774. iss_proof_pub_points.push(enc1_attr.clone());
  775. iss_proof_statements.push(quote! {
  776. #T_attr = #t_attr * #A_ident,
  777. #T_attr = #b_cred * #X_attr,
  778. });
  779. eq0_statement = quote! {
  780. #eq0_statement + #t_attr * #enc0_attr
  781. };
  782. eq1_statement = quote! {
  783. #eq1_statement + #t_attr * #enc1_attr
  784. };
  785. cli_proof_priv_scalars.push(scoped_attr.clone());
  786. cli_proof_rand_scalars.push(r_attr.clone());
  787. cli_proof_pub_points.push(enc0_attr.clone());
  788. cli_proof_pub_points.push(enc1_attr.clone());
  789. cli_proof_statements.push(quote! {
  790. #enc0_attr = #r_attr * #B_ident,
  791. #enc1_attr = #scoped_attr * #B_ident + #r_attr * #D_ident,
  792. });
  793. prepare_code = quote! {
  794. #prepare_code
  795. let #r_attr = <Scalar as ff::Field>::random(&mut *rng);
  796. let #enc0_attr = bp.mulB(&#r_attr);
  797. let #enc1_attr = bp.mulB(&#scoped_attr) +
  798. #r_attr * #D_ident;
  799. let #enc_attr = (#enc0_attr, #enc1_attr);
  800. };
  801. handle_code_post_fill = quote! {
  802. #handle_code_post_fill
  803. let #enc0_attr = request.#enc_attr.0;
  804. let #enc1_attr = request.#enc_attr.1;
  805. };
  806. handle_code_post_auth = quote! {
  807. #handle_code_post_auth
  808. let #t_attr = #b_cred * #x_attr;
  809. #EQ_cred.0 += #t_attr * #enc0_attr;
  810. #EQ_cred.1 += #t_attr * #enc1_attr;
  811. let #T_attr = bp.mulA(&#t_attr);
  812. };
  813. finalize_code = quote! {
  814. #finalize_code
  815. let #T_attr = reply.#T_attr;
  816. let #enc0_attr = self.#enc_attr.0;
  817. let #enc1_attr = self.#enc_attr.1;
  818. };
  819. }
  820. if use_muCMZ && (spec == IssueSpec::Hide || spec == IssueSpec::Joint) {
  821. /* For each Hide and Joint attribute (for µCMZ): add
  822. attr*X_attr to C.
  823. */
  824. prepare_code = quote! {
  825. #prepare_code
  826. let #X_attr = #pubkey_cred.X[#iss_cred_type::attr_num(#attr_str)];
  827. #C_cred += #scoped_attr * #X_attr;
  828. };
  829. handle_code_post_fill = quote! {
  830. #handle_code_post_fill
  831. let #X_attr = #iss_cred_id.pubkey_X(#attr_str);
  832. };
  833. C_statement = quote! {
  834. #C_statement + #scoped_attr * #X_attr
  835. };
  836. cli_proof_priv_scalars.push(scoped_attr.clone());
  837. cli_proof_cind_points.push(X_attr.clone());
  838. }
  839. /* For each Reveal attribute: include attr in Request (client will
  840. pass the value into prepare). Also store it in the
  841. ClientState.
  842. */
  843. if spec == IssueSpec::Reveal {
  844. request_fields.push_scalar(&scoped_attr);
  845. clientstate_fields.push_scalar(&scoped_attr);
  846. cli_proof_pub_scalars.push(scoped_attr.clone());
  847. prepare_code = quote! {
  848. #prepare_code
  849. let #scoped_attr =
  850. #iss_cred_id.#attr.ok_or(CMZError::RevealAttrMissing(#cred_str,
  851. #attr_str))?;
  852. };
  853. handle_code_pre_fill = quote! {
  854. #handle_code_pre_fill
  855. let #scoped_attr = request.#scoped_attr;
  856. #iss_cred_id.#attr = Some(#scoped_attr);
  857. };
  858. finalize_code = quote! {
  859. #finalize_code
  860. #iss_cred_id.#attr = Some(self.#scoped_attr);
  861. };
  862. }
  863. /* For each Implicit attribute: store it in ClientState
  864. (will be passed into prepare) on the client side, and
  865. will be filled in by fill_creds on the issuer side.
  866. */
  867. if spec == IssueSpec::Implicit {
  868. clientstate_fields.push_scalar(&scoped_attr);
  869. cli_proof_pub_scalars.push(scoped_attr.clone());
  870. prepare_code = quote! {
  871. #prepare_code
  872. let #scoped_attr =
  873. #iss_cred_id.#attr.ok_or(CMZError::ImplicitAttrCliMissing(#cred_str,
  874. #attr_str))?;
  875. };
  876. handle_code_post_fill = quote! {
  877. #handle_code_post_fill
  878. let #scoped_attr =
  879. #iss_cred_id.#attr.ok_or(CMZError::ImplicitAttrIssMissing(#cred_str,
  880. #attr_str))?;
  881. };
  882. finalize_code = quote! {
  883. #finalize_code
  884. #iss_cred_id.#attr = Some(self.#scoped_attr);
  885. };
  886. }
  887. /* For each Set attribute: the issuer's value will be set
  888. by fill_creds. Include the value in Reply.
  889. */
  890. if spec == IssueSpec::Set {
  891. reply_fields.push_scalar(&scoped_attr);
  892. handle_code_post_fill = quote! {
  893. #handle_code_post_fill
  894. let #scoped_attr =
  895. #iss_cred_id.#attr.ok_or(CMZError::SetAttrMissing(#cred_str,
  896. #attr_str))?;
  897. };
  898. finalize_code = quote! {
  899. #finalize_code
  900. #iss_cred_id.#attr = Some(reply.#scoped_attr);
  901. }
  902. }
  903. if spec == IssueSpec::Reveal
  904. || spec == IssueSpec::Implicit
  905. || spec == IssueSpec::Set
  906. || spec == IssueSpec::Joint
  907. {
  908. if use_muCMZ {
  909. /* For each Reveal, Implicit, Set, or Joint attribute, add
  910. attr*X_attr to K in handle and finalize.
  911. */
  912. handle_code_post_fill = quote! {
  913. #handle_code_post_fill
  914. #K_cred += (#scoped_attr *
  915. #iss_cred_id.pubkey_X(#attr_str));
  916. };
  917. // For a Joint attribute, we only want to use the
  918. // issuer's contribution (which is in #scoped_attr),
  919. // not #iss_cred_id.#attr, which is the sum of the
  920. // client's and issuer's contributions
  921. let use_attr = if spec == IssueSpec::Joint {
  922. quote! { #scoped_attr }
  923. } else {
  924. quote! { #iss_cred_id.#attr.unwrap() }
  925. };
  926. finalize_code = quote! {
  927. #finalize_code
  928. #K_cred += (#use_attr *
  929. #iss_cred_id.pubkey_X(#attr_str));
  930. };
  931. } else {
  932. /* For each Reveal, Implicit, Set, or Joint attribute, add
  933. attr*x_attr*P to Q in handle.
  934. */
  935. handle_code_post_auth = quote! {
  936. #handle_code_post_auth
  937. #Q_cred += (#scoped_attr * #x_attr) * #P_cred;
  938. };
  939. // For Joint attributes, we only want to use the
  940. // issuer's contribution. We already set
  941. // #scoped_attr to the issuer's contribution earlier
  942. // on.
  943. if spec != IssueSpec::Joint {
  944. finalize_code = quote! {
  945. #finalize_code
  946. let #scoped_attr = #iss_cred_id.#attr.unwrap();
  947. };
  948. }
  949. eq1_statement = quote! {
  950. #eq1_statement + #x_attr * ( #scoped_attr * #P_cred )
  951. };
  952. iss_proof_pub_scalars.push(scoped_attr.clone());
  953. }
  954. }
  955. }
  956. if !use_muCMZ {
  957. /* For all Hide and Joint attributes of a single credential to be
  958. issued (for CMZ14): the issuer chooses random b and s, computes
  959. P = b*B, E_Q = (s*B,s*D+b*x_0*B) + \sum_{hide,joint}
  960. b*x_attr*E_attr + (0,\sum_{implicit,reveal,set,joint}
  961. b*x_attr*attr*B) (note that E_Q and each E_attr are all
  962. pairs of Points; the scalar multiplication is
  963. componentwise). Include P, E_Q in Reply. The client will
  964. compute Q = E_Q[1] - d*E_Q[0].
  965. */
  966. let s_cred = format_ident!("s_iss_cred_{}", iss_cred.id);
  967. let x0_cred = format_ident!("x0_iss_cred_{}", iss_cred.id);
  968. let xr_cred = format_ident!("xr_cred{}", iss_cred.id);
  969. let X0_cred = format_ident!("X0_iss_cred_{}", iss_cred.id);
  970. reply_fields.push_point(&P_cred);
  971. if cred_hide_joint {
  972. reply_fields.push_encpoint(&EQ_cred);
  973. } else {
  974. reply_fields.push_point(&Q_cred);
  975. }
  976. let EQ_cred_code_pre = if cred_hide_joint {
  977. quote! {
  978. let #s_cred = <Scalar as ff::Field>::random(&mut *rng);
  979. let mut #EQ_cred = (bp.mulB(&#s_cred), #s_cred * #D_ident);
  980. }
  981. } else {
  982. quote! {}
  983. };
  984. let EQ_cred_code_post = if cred_hide_joint {
  985. quote! {
  986. #EQ_cred.1 += #Q_cred;
  987. let #EQ0_cred = #EQ_cred.0;
  988. let #EQ1_cred = #EQ_cred.1;
  989. }
  990. } else {
  991. quote! {}
  992. };
  993. if cred_hide_joint {
  994. iss_proof_pub_points.push(EQ0_cred.clone());
  995. iss_proof_pub_points.push(EQ1_cred.clone());
  996. iss_proof_statements.push(quote! {
  997. #EQ0_cred = #s_cred * #B_ident #eq0_statement,
  998. #EQ1_cred = #s_cred * #D_ident + #x0_cred * #P_cred #eq1_statement,
  999. });
  1000. }
  1001. handle_code_post_auth = quote! {
  1002. let #b_cred = <Scalar as ff::Field>::random(&mut *rng);
  1003. let #P_cred = bp.mulB(&#b_cred);
  1004. let #x0_cred = #iss_cred_id.get_privkey().x0;
  1005. let #xr_cred = #iss_cred_id.get_privkey().xr;
  1006. let #X0_cred = #iss_cred_id.get_pubkey().X0.unwrap();
  1007. let mut #Q_cred = bp.mulB(&(#b_cred * #iss_cred_id.get_privkey().x0));
  1008. #EQ_cred_code_pre
  1009. #handle_code_post_auth
  1010. #EQ_cred_code_post
  1011. };
  1012. let finalize_Q_code = if cred_hide_joint {
  1013. quote! {
  1014. let #EQ0_cred = reply.#EQ_cred.0;
  1015. let #EQ1_cred = reply.#EQ_cred.1;
  1016. #iss_cred_id.MAC.Q = #EQ1_cred - self.#d_ident * #EQ0_cred;
  1017. }
  1018. } else {
  1019. quote! {
  1020. #iss_cred_id.MAC.Q = reply.#Q_cred;
  1021. }
  1022. };
  1023. finalize_code = quote! {
  1024. #finalize_code
  1025. let #P_cred = reply.#P_cred;
  1026. let #X0_cred = #iss_cred_id.get_pubkey().X0.unwrap();
  1027. #iss_cred_id.MAC.P = #P_cred;
  1028. #finalize_Q_code
  1029. };
  1030. if cred_hide_joint {
  1031. iss_proof_rand_scalars.push(s_cred.clone());
  1032. }
  1033. iss_proof_pub_points.push(P_cred.clone());
  1034. iss_proof_priv_scalars.push(x0_cred.clone());
  1035. iss_proof_rand_scalars.push(xr_cred.clone());
  1036. iss_proof_pub_points.push(X0_cred.clone());
  1037. iss_proof_rand_scalars.push(b_cred.clone());
  1038. iss_proof_statements.push(quote! {
  1039. #X0_cred = #x0_cred * #B_ident + #xr_cred * #A_ident,
  1040. });
  1041. }
  1042. if use_muCMZ {
  1043. /* For all Hide and Joint attributes of a single credential to be
  1044. issued (for µCMZ): The client chooses a random s, computes C =
  1045. (\sum_{hide,joint} attr*X_attr) + s*A, where X_attr is the
  1046. public key for that attribute. Include s and C in the
  1047. ClientState, C in the Request, and the attributes, s, and
  1048. C in the CliProof. Hide attributes will be passed into
  1049. prepare on the client side; Joint attributes (client
  1050. contribution) will be generated randomly by prepare on
  1051. the client side. On the issuer side, handle will pick a
  1052. random b, compute P = b*A, K = C + X_r +
  1053. \sum_{implicit,reveal,set,joint} attr*X_attr, R =
  1054. b*(x_0*A + K). Include P and R in Reply, and x_0, b, P,
  1055. R, K in IssProof. For each implicit,reveal,set,joint
  1056. attribute, include x_attr and P_attr = attr*P in
  1057. IssProof. The client will compute K as above, and Q = R
  1058. - s*P.
  1059. */
  1060. let R_cred = format_ident!("R_iss_cred_{}", iss_cred.id);
  1061. let s_cred = format_ident!("s_iss_cred_{}", iss_cred.id);
  1062. let x0_cred = format_ident!("x0_iss_cred_{}", iss_cred.id);
  1063. let X0_cred = format_ident!("X0_iss_cred_{}", iss_cred.id);
  1064. reply_fields.push_point(&P_cred);
  1065. reply_fields.push_point(&R_cred);
  1066. if cred_hide_joint {
  1067. clientstate_fields.push_scalar(&s_cred);
  1068. clientstate_fields.push_point(&C_cred);
  1069. request_fields.push_point(&C_cred);
  1070. cli_proof_pub_points.push(C_cred.clone());
  1071. cli_proof_rand_scalars.push(s_cred.clone());
  1072. prepare_code = quote! {
  1073. let #s_cred = <Scalar as ff::Field>::random(&mut *rng);
  1074. let mut #C_cred = bp.mulA(&#s_cred);
  1075. #prepare_code
  1076. };
  1077. handle_code_post_fill = quote! {
  1078. let #C_cred = request.#C_cred;
  1079. let mut #K_cred = #C_cred + #iss_cred_id.get_pubkey().Xr.unwrap();
  1080. #handle_code_post_fill
  1081. };
  1082. finalize_code = quote! {
  1083. let mut #K_cred = self.#C_cred + self.#pubkey_cred.Xr.unwrap();
  1084. #finalize_code
  1085. };
  1086. // Construct the client proof for this credential
  1087. cli_proof_statements.push(quote! {
  1088. #C_cred = #s_cred * #A_ident #C_statement,
  1089. });
  1090. } else {
  1091. handle_code_post_fill = quote! {
  1092. let mut #K_cred = #iss_cred_id.get_pubkey().Xr.unwrap();
  1093. #handle_code_post_fill
  1094. };
  1095. finalize_code = quote! {
  1096. let mut #K_cred = self.#pubkey_cred.Xr.unwrap();
  1097. #finalize_code
  1098. };
  1099. }
  1100. handle_code_post_auth = quote! {
  1101. #handle_code_post_auth
  1102. let #b_cred = <Scalar as ff::Field>::random(&mut *rng);
  1103. let #P_cred = bp.mulA(&#b_cred);
  1104. let #x0_cred = #iss_cred_id.get_privkey().x0;
  1105. let #X0_cred = #iss_cred_id.get_pubkey().X0.unwrap();
  1106. let #R_cred = #b_cred * (bp.mulA(&#x0_cred) + #K_cred);
  1107. };
  1108. let finalize_Q_code = if cred_hide_joint {
  1109. quote! {
  1110. #iss_cred_id.MAC.Q = reply.#R_cred - self.#s_cred * reply.#P_cred;
  1111. }
  1112. } else {
  1113. quote! {
  1114. #iss_cred_id.MAC.Q = reply.#R_cred;
  1115. }
  1116. };
  1117. finalize_code = quote! {
  1118. #finalize_code
  1119. let #P_cred = reply.#P_cred;
  1120. let #X0_cred = #iss_cred_id.get_pubkey().X0.unwrap();
  1121. let #R_cred = reply.#R_cred;
  1122. #iss_cred_id.MAC.P = #P_cred;
  1123. #finalize_Q_code
  1124. };
  1125. // Construct the issuer proof for this credential
  1126. iss_proof_priv_scalars.push(x0_cred.clone());
  1127. iss_proof_rand_scalars.push(b_cred.clone());
  1128. iss_proof_pub_points.push(P_cred.clone());
  1129. iss_proof_pub_points.push(X0_cred.clone());
  1130. iss_proof_pub_points.push(K_cred.clone());
  1131. iss_proof_pub_points.push(R_cred.clone());
  1132. iss_proof_statements.push(quote! {
  1133. #P_cred = #b_cred * #A_ident,
  1134. #X0_cred = #x0_cred * #B_ident,
  1135. #R_cred = #x0_cred * #P_cred + #b_cred * #K_cred,
  1136. });
  1137. }
  1138. any_hide_joint |= cred_hide_joint;
  1139. }
  1140. /* If there are _any_ Hide or Joint attributes in CMZ14 (as opposed
  1141. to µCMZ), the client generates an El Gamal keypair (d, D=d*B).
  1142. Include d in the ClientState and D in the Request.
  1143. */
  1144. if any_hide_joint && !use_muCMZ {
  1145. clientstate_fields.push_scalar(&d_ident);
  1146. clientstate_fields.push_point(&D_ident);
  1147. cli_proof_rand_scalars.push(d_ident.clone());
  1148. cli_proof_pub_points.push(D_ident.clone());
  1149. request_fields.push_point(&D_ident);
  1150. cli_proof_statements.push(quote! {
  1151. #D_ident = #d_ident * #B_ident,
  1152. });
  1153. prepare_code = quote! {
  1154. let (#d_ident,#D_ident) = bp.keypairB(&mut *rng);
  1155. #prepare_code
  1156. };
  1157. handle_code_post_fill = quote! {
  1158. let #D_ident = request.#D_ident;
  1159. #handle_code_post_fill
  1160. };
  1161. finalize_code = quote! {
  1162. #finalize_code
  1163. let #D_ident = self.#D_ident;
  1164. };
  1165. iss_proof_pub_points.push(D_ident.clone());
  1166. }
  1167. if !proto_spec.issue_creds.is_empty() {
  1168. // The issuer will create a zero-knowledge proof
  1169. let iss_proof_ident = format_ident!("iss_proof");
  1170. reply_fields.push_bytevec(&iss_proof_ident);
  1171. let iss_instance_fields = iss_proof_pub_points
  1172. .iter()
  1173. .chain(iss_proof_const_points.iter())
  1174. .chain(iss_proof_pub_scalars.iter());
  1175. let iss_witness_fields = iss_proof_rand_scalars
  1176. .iter()
  1177. .chain(iss_proof_priv_scalars.iter());
  1178. handle_code_post_auth = quote! {
  1179. #handle_code_post_auth
  1180. let iss_proof_instance = issuer_proof::Instance {
  1181. #(#iss_instance_fields,)*
  1182. };
  1183. let iss_proof_witness = issuer_proof::Witness {
  1184. #(#iss_witness_fields,)*
  1185. };
  1186. // If prove returns Err here, there's an actual bug.
  1187. let #iss_proof_ident =
  1188. issuer_proof::prove(&iss_proof_instance,
  1189. &iss_proof_witness, &iss_proof_sessid, rng).unwrap();
  1190. };
  1191. let cli_iss_instance_fields = iss_proof_pub_points
  1192. .iter()
  1193. .chain(iss_proof_const_points.iter())
  1194. .chain(iss_proof_pub_scalars.iter());
  1195. finalize_code = quote! {
  1196. #finalize_code
  1197. let iss_proof_instance = issuer_proof::Instance {
  1198. #(#cli_iss_instance_fields,)*
  1199. };
  1200. if issuer_proof::verify(&iss_proof_instance,
  1201. &reply.#iss_proof_ident, &self.iss_proof_sessid).is_err() {
  1202. return Err((CMZError::IssProofFailed, self));
  1203. }
  1204. };
  1205. }
  1206. // Validity proofs for shown credentials with valid_optional go here
  1207. let mut validity_proofs: HashMap<String, TokenStream2> = HashMap::new();
  1208. for show_cred in proto_spec.show_creds.iter() {
  1209. // The credential being shown
  1210. let show_cred_id = format_ident!("show_cred_{}", show_cred.id);
  1211. // The rerandomizing factor for the MAC
  1212. let t_cred = format_ident!("t_show_cred_{}", show_cred.id);
  1213. // The rerandomized MAC
  1214. let P_cred = format_ident!("P_show_cred_{}", show_cred.id);
  1215. let Q_cred = format_ident!("Q_show_cred_{}", show_cred.id);
  1216. // The randomness for the Pedersen commitment to Q
  1217. let zQ_cred = format_ident!("zQ_show_cred_{}", show_cred.id);
  1218. // The Pedersen commitment to Q
  1219. let CQ_cred = format_ident!("CQ_show_cred_{}", show_cred.id);
  1220. // The verification point
  1221. let V_cred = format_ident!("V_show_cred_{}", show_cred.id);
  1222. // The coefficient (on P) of the MAC on the Reveal and Implicit
  1223. // attributes, computed by the issuer
  1224. let q_cred = format_ident!("q_show_cred_{}", show_cred.id);
  1225. let show_cred_type = &show_cred.cred_type;
  1226. // String version of the credential name
  1227. let cred_str = show_cred.id.to_string();
  1228. // Check that fill_creds filled in the private key for this
  1229. // credential and that it's for the right protocol (CMZ14 or
  1230. // µCMZ)
  1231. handle_code_post_fill = quote! {
  1232. #handle_code_post_fill
  1233. if #show_cred_id.get_privkey().x.len() != #show_cred_type::num_attrs() {
  1234. return Err(CMZError::PrivkeyMissing(#cred_str));
  1235. }
  1236. if #show_cred_id.get_privkey().muCMZ != #use_muCMZ {
  1237. return Err(CMZError::WrongProtocol(#cred_str));
  1238. }
  1239. };
  1240. // Check that the credential passed to prepare has its public
  1241. // key set and that it's for the right protocol (CMZ14 or µCMZ)
  1242. prepare_code = quote! {
  1243. #prepare_code
  1244. if #show_cred_id.get_pubkey().X.len() != #show_cred_type::num_attrs() {
  1245. return Err(CMZError::PubkeyMissing(#cred_str));
  1246. }
  1247. if #show_cred_id.get_pubkey().Xr.is_some() != #use_muCMZ {
  1248. return Err(CMZError::WrongProtocol(#cred_str));
  1249. }
  1250. };
  1251. // Rerandomize the MAC and construct a Pedersen commitment to Q
  1252. // Also start constructing the client's version of the
  1253. // verification point V (which will be updated with each Hide
  1254. // attribute below)
  1255. prepare_code = quote! {
  1256. #prepare_code
  1257. let #t_cred = <Scalar as ff::Field>::random(&mut *rng);
  1258. let #P_cred = #t_cred * #show_cred_id.MAC.P;
  1259. let #Q_cred = #t_cred * #show_cred_id.MAC.Q;
  1260. let #zQ_cred = <Scalar as ff::Field>::random(&mut *rng);
  1261. let #CQ_cred = #Q_cred - bp.mulB(&#zQ_cred);
  1262. let mut #V_cred = bp.mulB(&#zQ_cred);
  1263. };
  1264. handle_code_post_fill = quote! {
  1265. #handle_code_post_fill
  1266. let #P_cred = request.#P_cred;
  1267. if bool::from(#P_cred.is_identity()) {
  1268. return Err(CMZError::CliProofFailed);
  1269. }
  1270. };
  1271. request_fields.push_point(&P_cred);
  1272. request_fields.push_point(&CQ_cred);
  1273. cli_proof_rand_scalars.push(zQ_cred.clone());
  1274. cli_proof_cind_points.push(P_cred.clone());
  1275. cli_proof_pub_points.push(V_cred.clone());
  1276. // The ZKP statement that proves the format of V
  1277. let mut V_statement = quote! {
  1278. #V_cred = #zQ_cred * #B_ident
  1279. };
  1280. // Start constructing the issuer's version of the verification
  1281. // point Vi (which will be updated with each Hide attribute below)
  1282. // and the MAC on the Reveal and Implicit attributes
  1283. // µCMZ has the extra xr to add in here
  1284. let q_init = if use_muCMZ {
  1285. quote! { #show_cred_id.get_privkey().x0 + #show_cred_id.get_privkey().xr }
  1286. } else {
  1287. quote! { #show_cred_id.get_privkey().x0 }
  1288. };
  1289. handle_code_post_fill = quote! {
  1290. #handle_code_post_fill
  1291. let mut #V_cred = -request.#CQ_cred;
  1292. let mut #q_cred = #q_init;
  1293. };
  1294. for (attr, &spec) in show_cred.attrs.iter() {
  1295. // String version of the attribute name
  1296. let attr_str = attr.to_string();
  1297. // The scoped attribute name
  1298. let scoped_attr = format_ident!("show_{}attr_{}_{}", spec.abbr(), show_cred.id, attr);
  1299. // The public key for this attribute
  1300. let X_attr = format_ident!("X_{}", scoped_attr);
  1301. // Remember the mapping from the credential and attribute
  1302. // name to the scoped attribute
  1303. cli_proof_idmap.insert(
  1304. (show_cred.id.to_string(), attr.to_string()),
  1305. scoped_attr.clone(),
  1306. );
  1307. if spec == ShowSpec::Hide {
  1308. prepare_code = quote! {
  1309. #prepare_code
  1310. let #scoped_attr =
  1311. #show_cred_id.#attr.ok_or(CMZError::HideAttrMissing(#cred_str,
  1312. #attr_str))?;
  1313. };
  1314. // Construct a Pedersen commitment to the Hide attribute
  1315. // and update the verification point
  1316. let z_attr = format_ident!("z_{}", scoped_attr);
  1317. let C_attr = format_ident!("C_{}", scoped_attr);
  1318. request_fields.push_point(&C_attr);
  1319. prepare_code = quote! {
  1320. #prepare_code
  1321. let #z_attr = <Scalar as ff::Field>::random(&mut *rng);
  1322. let #C_attr = #scoped_attr * #P_cred + bp.mulA(&#z_attr);
  1323. let #X_attr = #show_cred_id.pubkey_X(#attr_str);
  1324. #V_cred += #z_attr * #X_attr;
  1325. };
  1326. handle_code_post_fill = quote! {
  1327. #handle_code_post_fill
  1328. let #C_attr = request.#C_attr;
  1329. let #X_attr = #show_cred_id.pubkey_X(#attr_str);
  1330. #V_cred += #show_cred_id.privkey_x(#attr_str)
  1331. * #C_attr;
  1332. };
  1333. cli_proof_priv_scalars.push(scoped_attr.clone());
  1334. cli_proof_rand_scalars.push(z_attr.clone());
  1335. cli_proof_pub_points.push(C_attr.clone());
  1336. cli_proof_cind_points.push(X_attr.clone());
  1337. cli_proof_statements.push(quote! {
  1338. #C_attr = #scoped_attr * #P_cred + #z_attr * #A_ident,
  1339. });
  1340. V_statement = quote! {
  1341. #V_statement + #z_attr * #X_attr
  1342. };
  1343. }
  1344. if spec == ShowSpec::Reveal {
  1345. request_fields.push_scalar(&scoped_attr);
  1346. prepare_code = quote! {
  1347. #prepare_code
  1348. let #scoped_attr =
  1349. #show_cred_id.#attr.ok_or(CMZError::RevealAttrMissing(#cred_str,
  1350. #attr_str))?;
  1351. };
  1352. handle_code_pre_fill = quote! {
  1353. #handle_code_pre_fill
  1354. let #scoped_attr = request.#scoped_attr;
  1355. #show_cred_id.#attr = Some(#scoped_attr);
  1356. };
  1357. // Accumulate the coefficient (of P) on the component of
  1358. // Q due to this attribute
  1359. handle_code_post_fill = quote! {
  1360. #handle_code_post_fill
  1361. #q_cred += #scoped_attr *
  1362. #show_cred_id.privkey_x(#attr_str);
  1363. };
  1364. cli_proof_pub_scalars.push(scoped_attr.clone());
  1365. }
  1366. if spec == ShowSpec::Implicit {
  1367. prepare_code = quote! {
  1368. #prepare_code
  1369. let #scoped_attr =
  1370. #show_cred_id.#attr.ok_or(CMZError::ImplicitAttrCliMissing(#cred_str,
  1371. #attr_str))?;
  1372. };
  1373. handle_code_post_fill = quote! {
  1374. #handle_code_post_fill
  1375. let #scoped_attr =
  1376. #show_cred_id.#attr.ok_or(CMZError::ImplicitAttrIssMissing(#cred_str,
  1377. #attr_str))?;
  1378. };
  1379. // Accumulate the coefficient (of P) on the component of
  1380. // Q due to this attribute
  1381. handle_code_post_fill = quote! {
  1382. #handle_code_post_fill
  1383. #q_cred += #scoped_attr *
  1384. #show_cred_id.privkey_x(#attr_str);
  1385. };
  1386. cli_proof_pub_scalars.push(scoped_attr.clone());
  1387. }
  1388. }
  1389. // Compute the computation of the issuer's version of the
  1390. // Verification point Vi
  1391. handle_code_post_fill = quote! {
  1392. #handle_code_post_fill
  1393. #V_cred += #q_cred * #P_cred;
  1394. };
  1395. if show_cred.valid_optional {
  1396. validity_proofs.insert(
  1397. cred_str,
  1398. quote! {
  1399. #V_statement
  1400. },
  1401. );
  1402. } else {
  1403. cli_proof_statements.push(quote! {
  1404. #V_statement,
  1405. });
  1406. }
  1407. }
  1408. cli_proof_const_points.push(A_ident.clone());
  1409. cli_proof_const_points.push(B_ident.clone());
  1410. for paramid in proto_spec.params.iter() {
  1411. let scoped_param = format_ident!("param_{}", paramid);
  1412. prepare_code = quote! {
  1413. #prepare_code
  1414. let #scoped_param = params.#paramid;
  1415. };
  1416. handle_code_post_fill = quote! {
  1417. #handle_code_post_fill
  1418. let #scoped_param = params.#paramid;
  1419. };
  1420. cli_proof_pub_scalars.push(scoped_param.clone());
  1421. cli_proof_idmap.insert(("".to_string(), paramid.to_string()), scoped_param.clone());
  1422. }
  1423. for paramid in proto_spec.point_params.iter() {
  1424. let scoped_param = format_ident!("param_{}", paramid);
  1425. prepare_code = quote! {
  1426. #prepare_code
  1427. let #scoped_param = params.#paramid;
  1428. };
  1429. handle_code_post_fill = quote! {
  1430. #handle_code_post_fill
  1431. let #scoped_param = params.#paramid;
  1432. };
  1433. cli_proof_pub_points.push(scoped_param.clone());
  1434. cli_proof_idmap.insert(("".to_string(), paramid.to_string()), scoped_param.clone());
  1435. }
  1436. // The client will create a zero-knowledge proof
  1437. let cli_proof_ident = format_ident!("cli_proof");
  1438. request_fields.push_bytevec(&cli_proof_ident);
  1439. let cli_instance_fields = cli_proof_pub_points
  1440. .iter()
  1441. .chain(cli_proof_const_points.iter())
  1442. .chain(cli_proof_cind_points.iter())
  1443. .chain(cli_proof_pub_scalars.iter());
  1444. let cli_witness_fields = cli_proof_rand_scalars
  1445. .iter()
  1446. .chain(cli_proof_priv_scalars.iter());
  1447. prepare_code = quote! {
  1448. #prepare_code
  1449. let cli_proof_instance = client_proof::Instance {
  1450. #(#cli_instance_fields,)*
  1451. };
  1452. let cli_proof_witness = client_proof::Witness {
  1453. #(#cli_witness_fields,)*
  1454. };
  1455. // If prove returns Err here, there's an actual bug.
  1456. let #cli_proof_ident = client_proof::prove(&cli_proof_instance,
  1457. &cli_proof_witness, &cli_proof_sessid, rng).unwrap();
  1458. };
  1459. let iss_cli_instance_fields = cli_proof_pub_points
  1460. .iter()
  1461. .chain(cli_proof_const_points.iter())
  1462. .chain(cli_proof_cind_points.iter())
  1463. .chain(cli_proof_pub_scalars.iter());
  1464. handle_code_post_fill = quote! {
  1465. #handle_code_post_fill
  1466. let cli_proof_instance = client_proof::Instance {
  1467. #(#iss_cli_instance_fields,)*
  1468. };
  1469. if client_proof::verify(&cli_proof_instance,
  1470. &request.#cli_proof_ident, &cli_proof_sessid).is_err() {
  1471. return Err(CMZError::CliProofFailed);
  1472. }
  1473. };
  1474. // Build the Params struct, if we have params
  1475. let params_struct = if has_params {
  1476. let param_list = &proto_spec.params;
  1477. let point_param_list = &proto_spec.point_params;
  1478. quote! {
  1479. pub struct Params {
  1480. #( pub #param_list: Scalar, )*
  1481. #( pub #point_param_list: Point, )*
  1482. }
  1483. }
  1484. } else {
  1485. quote! {}
  1486. };
  1487. // Build the ClientState struct
  1488. let client_state = {
  1489. let decls = clientstate_fields.field_decls();
  1490. quote! {
  1491. #[serde_as]
  1492. #[derive(Clone,Debug,serde::Serialize,serde::Deserialize)]
  1493. pub struct ClientState {
  1494. #decls
  1495. }
  1496. impl TryFrom<&[u8]> for ClientState {
  1497. type Error = bincode::Error;
  1498. fn try_from(bytes: &[u8]) -> bincode::Result<ClientState> {
  1499. bincode::deserialize::<ClientState>(bytes)
  1500. }
  1501. }
  1502. impl From<&ClientState> for Vec<u8> {
  1503. fn from(req: &ClientState) -> Vec<u8> {
  1504. bincode::serialize(req).unwrap()
  1505. }
  1506. }
  1507. impl ClientState {
  1508. pub fn as_bytes(&self) -> Vec<u8> {
  1509. self.into()
  1510. }
  1511. }
  1512. }
  1513. };
  1514. // Build the Request and Reply structs
  1515. let messages = {
  1516. let reqdecls = request_fields.field_decls();
  1517. let repdecls = reply_fields.field_decls();
  1518. quote! {
  1519. #[serde_as]
  1520. #[derive(Clone,Debug,serde::Serialize,serde::Deserialize)]
  1521. pub struct Request {
  1522. #reqdecls
  1523. }
  1524. impl TryFrom<&[u8]> for Request {
  1525. type Error = bincode::Error;
  1526. fn try_from(bytes: &[u8]) -> bincode::Result<Request> {
  1527. bincode::deserialize::<Request>(bytes)
  1528. }
  1529. }
  1530. impl From<&Request> for Vec<u8> {
  1531. fn from(req: &Request) -> Vec<u8> {
  1532. bincode::serialize(req).unwrap()
  1533. }
  1534. }
  1535. impl Request {
  1536. pub fn as_bytes(&self) -> Vec<u8> {
  1537. self.into()
  1538. }
  1539. }
  1540. #[serde_as]
  1541. #[derive(Clone,Debug,serde::Serialize,serde::Deserialize)]
  1542. pub struct Reply {
  1543. #repdecls
  1544. }
  1545. impl TryFrom<&[u8]> for Reply {
  1546. type Error = bincode::Error;
  1547. fn try_from(bytes: &[u8]) -> bincode::Result<Reply> {
  1548. bincode::deserialize::<Reply>(bytes)
  1549. }
  1550. }
  1551. impl From<&Reply> for Vec<u8> {
  1552. fn from(rep: &Reply) -> Vec<u8> {
  1553. bincode::serialize(rep).unwrap()
  1554. }
  1555. }
  1556. impl Reply {
  1557. pub fn as_bytes(&self) -> Vec<u8> {
  1558. self.into()
  1559. }
  1560. }
  1561. }
  1562. };
  1563. // Massage the statements provided in the protocol spec to change
  1564. // any expression of the form "L.id" (a credential name and an
  1565. // attribute name) into the corresponding scoped attribute.
  1566. // Bare identifiers that are protocol parameter names also get
  1567. // modified into the corresponding scoped attribute. These names
  1568. // are stored in the idmap with an empty string for the credential
  1569. // name.
  1570. //
  1571. // The expression "valid(A)" for a shown credential A with
  1572. // valid_optional set expands to the proof of validity for that
  1573. // credential.
  1574. struct StatementScoper<'a> {
  1575. idmap: &'a HashMap<(String, String), Ident>,
  1576. validity_proofs: &'a HashMap<String, TokenStream2>,
  1577. }
  1578. impl<'a> VisitMut for StatementScoper<'a> {
  1579. fn visit_expr_mut(&mut self, node: &mut Expr) {
  1580. if let Expr::Field(exfld) = node {
  1581. let base = *exfld.base.clone();
  1582. if let Expr::Path(basepath) = base {
  1583. if let Member::Named(attrid) = &exfld.member {
  1584. if let Some(credid) = basepath.path.get_ident() {
  1585. if let Some(scopedid) =
  1586. self.idmap.get(&(credid.to_string(), attrid.to_string()))
  1587. {
  1588. *node = parse_quote! { #scopedid };
  1589. return;
  1590. }
  1591. }
  1592. }
  1593. }
  1594. }
  1595. if let Expr::Path(expath) = node {
  1596. if let Some(id) = expath.path.get_ident() {
  1597. if let Some(scopedparam) = self.idmap.get(&("".to_string(), id.to_string())) {
  1598. *node = parse_quote! { #scopedparam };
  1599. return;
  1600. }
  1601. }
  1602. }
  1603. if let Expr::Call(excall) = node {
  1604. let base = *excall.func.clone();
  1605. if let Expr::Path(basepath) = base {
  1606. if let Some(id) = basepath.path.get_ident() {
  1607. if *id == "valid" && excall.args.len() == 1 {
  1608. let mut validity_statement = quote! {};
  1609. let argexpr = excall.args.first().unwrap();
  1610. if let Expr::Path(argpath) = argexpr {
  1611. if let Some(credid) = argpath.path.get_ident() {
  1612. let credstr = credid.to_string();
  1613. match self.validity_proofs.get(&credstr) {
  1614. Some(tokens) => {
  1615. validity_statement = tokens.clone();
  1616. },
  1617. None => panic!("{} is not a shown credential with optional validity proof", credstr),
  1618. }
  1619. }
  1620. }
  1621. *node = parse_quote! { #validity_statement };
  1622. return;
  1623. }
  1624. }
  1625. }
  1626. }
  1627. // Unless we bailed out above, continue with the default
  1628. // traversal
  1629. visit_mut::visit_expr_mut(self, node);
  1630. }
  1631. }
  1632. let mut statement_scoper = StatementScoper {
  1633. idmap: &cli_proof_idmap,
  1634. validity_proofs: &validity_proofs,
  1635. };
  1636. let mut cli_proof_scoped_statements = proto_spec.statements.clone();
  1637. cli_proof_scoped_statements
  1638. .iter_mut()
  1639. .for_each(|expr| statement_scoper.visit_expr_mut(expr));
  1640. // The client's zero-knowledge proof
  1641. let cli_sigma_compiler_macro = if emit_client && emit_issuer {
  1642. quote! { sigma_compiler }
  1643. } else if emit_client {
  1644. quote! { sigma_compiler_prover }
  1645. } else {
  1646. quote! { sigma_compiler_verifier }
  1647. };
  1648. let cli_proof = {
  1649. quote! {
  1650. #cli_sigma_compiler_macro! { client_proof<Point>,
  1651. (#(rand #cli_proof_rand_scalars,)*
  1652. #(#cli_proof_priv_scalars,)*
  1653. #(pub #cli_proof_pub_scalars,)*),
  1654. (#(cind #cli_proof_cind_points,)*
  1655. #(#cli_proof_pub_points,)*
  1656. #(cind const #cli_proof_const_points,)*),
  1657. #(#cli_proof_scoped_statements,)*
  1658. #(#cli_proof_statements)*
  1659. }
  1660. }
  1661. };
  1662. println!("cli_proof = {cli_proof}");
  1663. // The issuer's zero-knowledge proof
  1664. let iss_sigma_compiler_macro = if emit_client && emit_issuer {
  1665. quote! { sigma_compiler }
  1666. } else if emit_issuer {
  1667. quote! { sigma_compiler_prover }
  1668. } else {
  1669. quote! { sigma_compiler_verifier }
  1670. };
  1671. let iss_proof = {
  1672. quote! {
  1673. #iss_sigma_compiler_macro! { issuer_proof<Point>,
  1674. (#(rand #iss_proof_rand_scalars,)*
  1675. #(#iss_proof_priv_scalars,)*
  1676. #(pub #iss_proof_pub_scalars,)*),
  1677. // no cind_points
  1678. (#(#iss_proof_pub_points,)*
  1679. #(cind const #iss_proof_const_points,)*),
  1680. #(#iss_proof_statements)*
  1681. }
  1682. }
  1683. };
  1684. println!("iss_proof = {iss_proof}");
  1685. // The argument list for the client's prepare function. There is an
  1686. // immutable reference for each credential to be shown, and an owned
  1687. // value for each credential to be issued.
  1688. let client_show_args = proto_spec.show_creds.iter().map(|c| {
  1689. let id = format_ident!("show_cred_{}", c.id);
  1690. let cred_type = &c.cred_type;
  1691. quote! { #id: &#cred_type, }
  1692. });
  1693. let client_issue_args = proto_spec.issue_creds.iter().map(|c| {
  1694. let id = format_ident!("iss_cred_{}", c.id);
  1695. let cred_type = &c.cred_type;
  1696. quote! { #id: #cred_type, }
  1697. });
  1698. let client_params_arg = if has_params {
  1699. quote! { params: &Params, }
  1700. } else {
  1701. quote! {}
  1702. };
  1703. // Build the client's prepare function
  1704. let client_func = {
  1705. let reqf = request_fields.field_iter();
  1706. let csf = clientstate_fields.field_iter();
  1707. quote! {
  1708. pub fn prepare(rng: &mut (impl CryptoRng + RngCore),
  1709. session_id: &[u8],
  1710. #(#client_show_args)* #(#client_issue_args)* #client_params_arg)
  1711. -> Result<(Request, ClientState),CMZError> {
  1712. let bp = cmz_basepoints::<Point>();
  1713. let mut cli_proof_sessid: Vec<u8> = Vec::new();
  1714. cli_proof_sessid.extend(b"cli_");
  1715. cli_proof_sessid.extend(session_id);
  1716. let mut iss_proof_sessid: Vec<u8> = Vec::new();
  1717. iss_proof_sessid.extend(b"iss_");
  1718. iss_proof_sessid.extend(session_id);
  1719. #prepare_code
  1720. Ok((Request{#(#reqf,)*}, ClientState{#(#csf,)*}))
  1721. }
  1722. }
  1723. };
  1724. // Build the issuer's handle function
  1725. let issuer_func = {
  1726. // The credential declarations for the issuer's handle function
  1727. let cred_decls = proto_spec
  1728. .show_creds
  1729. .iter()
  1730. .map(|c| {
  1731. let id = format_ident!("show_cred_{}", c.id);
  1732. let cred_type = &c.cred_type;
  1733. quote! { let mut #id = #cred_type::default(); }
  1734. })
  1735. .chain(proto_spec.issue_creds.iter().map(|c| {
  1736. let id = format_ident!("iss_cred_{}", c.id);
  1737. let cred_type = &c.cred_type;
  1738. quote! { let mut #id = #cred_type::default(); }
  1739. }));
  1740. // The type of the returned credentials from handle
  1741. let cred_rettypes = proto_spec
  1742. .show_creds
  1743. .iter()
  1744. .map(|c| {
  1745. let cred_type = &c.cred_type;
  1746. quote! { #cred_type }
  1747. })
  1748. .chain(proto_spec.issue_creds.iter().map(|c| {
  1749. let cred_type = &c.cred_type;
  1750. quote! { #cred_type }
  1751. }));
  1752. // The return type
  1753. let rettype = match tot_num_creds {
  1754. 0 => quote! { Result<Reply,CMZError> },
  1755. 1 => quote! { Result<(Reply, #(#cred_rettypes)*),CMZError> },
  1756. _ => quote! { Result<(Reply, (#(#cred_rettypes),*)),CMZError> },
  1757. };
  1758. // The return value
  1759. let cred_retvals = proto_spec
  1760. .show_creds
  1761. .iter()
  1762. .map(|c| {
  1763. let id = format_ident!("show_cred_{}", c.id);
  1764. quote! { #id }
  1765. })
  1766. .chain(proto_spec.issue_creds.iter().map(|c| {
  1767. let id = format_ident!("iss_cred_{}", c.id);
  1768. quote! { #id }
  1769. }));
  1770. // The argument list for the issuer's fill_creds callback
  1771. let fill_creds_args = proto_spec
  1772. .show_creds
  1773. .iter()
  1774. .map(|c| {
  1775. let cred_type = &c.cred_type;
  1776. quote! { &mut #cred_type, }
  1777. })
  1778. .chain(proto_spec.issue_creds.iter().map(|c| {
  1779. let cred_type = &c.cred_type;
  1780. quote! { &mut #cred_type, }
  1781. }));
  1782. // The parameters for the fill_creds callback
  1783. let fill_creds_params = proto_spec
  1784. .show_creds
  1785. .iter()
  1786. .map(|c| {
  1787. let id = format_ident!("show_cred_{}", c.id);
  1788. quote! { &mut #id, }
  1789. })
  1790. .chain(proto_spec.issue_creds.iter().map(|c| {
  1791. let id = format_ident!("iss_cred_{}", c.id);
  1792. quote! { &mut #id, }
  1793. }));
  1794. // The return value of the callback
  1795. let fill_creds_params_ret = if has_params {
  1796. quote! { Params }
  1797. } else {
  1798. quote! { () }
  1799. };
  1800. // The assignment of the return value of the callback
  1801. let fill_creds_assign = if has_params {
  1802. quote! { let params = }
  1803. } else {
  1804. quote! {}
  1805. };
  1806. // The argument list for the issuer's authorize callback
  1807. let authorize_args = proto_spec
  1808. .show_creds
  1809. .iter()
  1810. .map(|c| {
  1811. let cred_type = &c.cred_type;
  1812. quote! { &#cred_type, }
  1813. })
  1814. .chain(proto_spec.issue_creds.iter().map(|c| {
  1815. let cred_type = &c.cred_type;
  1816. quote! { &#cred_type, }
  1817. }));
  1818. // The parameters for the authorize callback
  1819. let authorize_params = proto_spec
  1820. .show_creds
  1821. .iter()
  1822. .map(|c| {
  1823. let id = format_ident!("show_cred_{}", c.id);
  1824. quote! { &#id, }
  1825. })
  1826. .chain(proto_spec.issue_creds.iter().map(|c| {
  1827. let id = format_ident!("iss_cred_{}", c.id);
  1828. quote! { &#id, }
  1829. }));
  1830. let repf = reply_fields.field_iter();
  1831. let retval = match tot_num_creds {
  1832. 0 => quote! { Ok(Reply{#(#repf,)*}) },
  1833. 1 => quote! { Ok((Reply{#(#repf,)*}, #(#cred_retvals)*)) },
  1834. _ => quote! { Ok((Reply{#(#repf,)*}, (#(#cred_retvals),*))) },
  1835. };
  1836. quote! {
  1837. pub fn handle<F,A>(rng: &mut (impl CryptoRng + RngCore),
  1838. session_id: &[u8],
  1839. request: Request, fill_creds: F, authorize: A)
  1840. -> #rettype
  1841. where
  1842. F: FnOnce(#(#fill_creds_args)*) ->
  1843. Result<#fill_creds_params_ret, CMZError>,
  1844. A: FnOnce(#(#authorize_args)*) ->
  1845. Result<(),CMZError>
  1846. {
  1847. let bp = cmz_basepoints::<Point>();
  1848. let mut cli_proof_sessid: Vec<u8> = Vec::new();
  1849. cli_proof_sessid.extend(b"cli_");
  1850. cli_proof_sessid.extend(session_id);
  1851. let mut iss_proof_sessid: Vec<u8> = Vec::new();
  1852. iss_proof_sessid.extend(b"iss_");
  1853. iss_proof_sessid.extend(session_id);
  1854. #(#cred_decls)*
  1855. #handle_code_pre_fill
  1856. #fill_creds_assign fill_creds(#(#fill_creds_params)*)?;
  1857. #handle_code_post_fill
  1858. authorize(#(#authorize_params)*)?;
  1859. #handle_code_post_auth
  1860. #retval
  1861. }
  1862. }
  1863. };
  1864. // Build the ClientState's finalize function
  1865. let clientstate_finalize_func = {
  1866. // The credential declarations for the client's finalize function
  1867. let cred_decls = proto_spec.issue_creds.iter().map(|c| {
  1868. let id = format_ident!("iss_cred_{}", c.id);
  1869. let cred_type = &c.cred_type;
  1870. quote! { let mut #id = #cred_type::default(); }
  1871. });
  1872. // The type of the returned credentials from finalize
  1873. let cred_rettypes = proto_spec.issue_creds.iter().map(|c| {
  1874. let cred_type = &c.cred_type;
  1875. quote! { #cred_type }
  1876. });
  1877. let rettype = match proto_spec.issue_creds.len() {
  1878. 0 => quote! { Result<(),(CMZError,Self)> },
  1879. 1 => quote! { Result<#(#cred_rettypes)*,(CMZError,Self)> },
  1880. _ => quote! { Result<(#(#cred_rettypes),*),(CMZError,Self)> },
  1881. };
  1882. // Return value for ClientState's finalize function
  1883. let cred_retvals = proto_spec.issue_creds.iter().map(|c| {
  1884. let id = format_ident!("iss_cred_{}", c.id);
  1885. quote! { #id }
  1886. });
  1887. let retval = match proto_spec.issue_creds.len() {
  1888. 0 => quote! { Ok(()) },
  1889. 1 => quote! { Ok(#(#cred_retvals)*) },
  1890. _ => quote! { Ok((#(#cred_retvals),*)) },
  1891. };
  1892. quote! {
  1893. impl ClientState {
  1894. pub fn finalize(
  1895. self,
  1896. reply: Reply,
  1897. ) -> #rettype {
  1898. let bp = cmz_basepoints::<Point>();
  1899. #(#cred_decls)*
  1900. #finalize_code
  1901. #retval
  1902. }
  1903. }
  1904. }
  1905. };
  1906. let client_side = if emit_client {
  1907. quote! { #client_state #client_func #clientstate_finalize_func }
  1908. } else {
  1909. quote! {}
  1910. };
  1911. let issuer_side = if emit_issuer {
  1912. issuer_func
  1913. } else {
  1914. quote! {}
  1915. };
  1916. // Output the generated module for this protocol
  1917. quote! {
  1918. #[allow(non_snake_case)]
  1919. pub mod #proto_name {
  1920. use super::*;
  1921. use group::GroupEncoding;
  1922. #group_types
  1923. #params_struct
  1924. #messages
  1925. #cli_proof
  1926. #iss_proof
  1927. #client_side
  1928. #issuer_side
  1929. }
  1930. }
  1931. .into()
  1932. }
  1933. /** There are six variants of the `CMZProtocol` macro. The ones starting
  1934. with "CMZ14" create protocol implementations using the original CMZ14
  1935. issuing protocol. The ones starting with "muCMZ" using the more
  1936. efficient µCMZ protocol. The ones with "Cli" only create the code
  1937. for the client side of the protocol. The ones with "Iss" only create
  1938. the code for the issuer side of the protocol. (The ones without
  1939. either create the code for both sides of the protocol.)
  1940. */
  1941. #[proc_macro]
  1942. pub fn CMZ14Protocol(input: TokenStream) -> TokenStream {
  1943. protocol_macro(input, false, true, true)
  1944. }
  1945. #[proc_macro]
  1946. pub fn CMZ14CliProtocol(input: TokenStream) -> TokenStream {
  1947. protocol_macro(input, false, true, false)
  1948. }
  1949. #[proc_macro]
  1950. pub fn CMZ14IssProtocol(input: TokenStream) -> TokenStream {
  1951. protocol_macro(input, false, false, true)
  1952. }
  1953. #[proc_macro]
  1954. pub fn muCMZProtocol(input: TokenStream) -> TokenStream {
  1955. protocol_macro(input, true, true, true)
  1956. }
  1957. #[proc_macro]
  1958. pub fn muCMZCliProtocol(input: TokenStream) -> TokenStream {
  1959. protocol_macro(input, true, true, false)
  1960. }
  1961. #[proc_macro]
  1962. pub fn muCMZIssProtocol(input: TokenStream) -> TokenStream {
  1963. protocol_macro(input, true, false, true)
  1964. }