lib.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. // We want the macros like CMZProtocol 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::{Span, TokenStream};
  13. use quote::{quote, ToTokens};
  14. use std::collections::HashMap;
  15. use syn::parse::{Parse, ParseStream, Result};
  16. use syn::punctuated::Punctuated;
  17. use syn::{
  18. braced, bracketed, parse_macro_input, token, Data, DataStruct, DeriveInput, Expr, Fields,
  19. FieldsNamed, Ident, Token, Visibility,
  20. };
  21. fn impl_cmzcred_derive(ast: &syn::DeriveInput, group_ident: &Ident) -> TokenStream {
  22. // Ensure that CMZCred is derived on a struct and not something else
  23. // (like an enum)
  24. let Data::Struct(DataStruct {
  25. struct_token: _,
  26. fields:
  27. Fields::Named(FieldsNamed {
  28. brace_token: _,
  29. ref named,
  30. }),
  31. semi_token: _,
  32. }) = ast.data
  33. else {
  34. panic!("CMZCred derived on a non-struct");
  35. };
  36. // attrs and idents are each vectors of the names of the attributes
  37. // of the credential (not including the MAC and any non-public
  38. // fields). attrs stores the names as Strings, while idents stores
  39. // them as Idents.
  40. let mut attrs = Vec::<String>::new();
  41. let mut idents = Vec::<&Ident>::new();
  42. for n in named {
  43. let Some(ref ident) = n.ident else {
  44. panic!("Missing attribute name in CMZCred");
  45. };
  46. let id_str = ident.to_string();
  47. if let Visibility::Public(_) = n.vis {
  48. if id_str != String::from("MAC") {
  49. attrs.push(id_str);
  50. idents.push(ident);
  51. }
  52. }
  53. }
  54. let num_attrs = attrs.len();
  55. let name = &ast.ident;
  56. let errmsg = format!("Invalid attribute name for {} CMZ credential", name);
  57. // Output the CMZCredential trait implementation
  58. let gen = quote! {
  59. impl CMZCredential for #name {
  60. type Scalar = <#group_ident as Group>::Scalar;
  61. type Point = #group_ident;
  62. fn attrs() -> Vec<&'static str> {
  63. vec![
  64. #( #attrs, )*
  65. ]
  66. }
  67. fn num_attrs() -> usize {
  68. return #num_attrs;
  69. }
  70. fn attr(&self, attrname: &str) -> &Option<Self::Scalar> {
  71. match attrname {
  72. #( #attrs => &self.#idents, )*
  73. _ => panic!(#errmsg),
  74. }
  75. }
  76. fn attr_mut(&mut self, attrname: &str) -> &mut Option<Self::Scalar> {
  77. match attrname {
  78. #( #attrs => &mut self.#idents, )*
  79. _ => panic!(#errmsg),
  80. }
  81. }
  82. fn set_pubkey(&mut self, pubkey: &CMZPubkey<Self::Point>) -> &mut Self {
  83. self.pubkey = pubkey.clone();
  84. self
  85. }
  86. fn get_pubkey(&self) -> CMZPubkey<Self::Point> {
  87. self.pubkey.clone()
  88. }
  89. fn set_privkey(&mut self, privkey: &CMZPrivkey<Self::Point>)
  90. -> &mut Self {
  91. self.pubkey = cmz_privkey_to_pubkey(&privkey);
  92. self.privkey = privkey.clone();
  93. self
  94. }
  95. fn get_privkey(&self) -> CMZPrivkey<Self::Point> {
  96. self.privkey.clone()
  97. }
  98. fn gen_keys(rng: &mut impl RngCore, muCMZ: bool) ->
  99. (CMZPrivkey<Self::Point>, CMZPubkey<Self::Point>) {
  100. // Generate (num_attrs + 2) random scalars as the
  101. // private key
  102. let x0tilde: Self::Scalar = if muCMZ {
  103. <Self::Scalar as ff::Field>::ZERO
  104. } else {
  105. <Self::Scalar as ff::Field>::random(&mut *rng)
  106. };
  107. let x0: Self::Scalar =
  108. <Self::Scalar as ff::Field>::random(&mut *rng);
  109. let x: Vec<Self::Scalar> = (0..Self::num_attrs())
  110. .map(|_| <Self::Scalar as ff::Field>::random(&mut *rng))
  111. .collect();
  112. let privkey = CMZPrivkey { x0tilde, x0, x };
  113. // Convert the private key to a public key
  114. let pubkey = cmz_privkey_to_pubkey(&privkey);
  115. (privkey, pubkey)
  116. }
  117. }
  118. };
  119. gen.into()
  120. }
  121. #[derive(FromDeriveInput)]
  122. #[darling(attributes(cmzcred_group))]
  123. struct GroupIdent {
  124. group: Ident,
  125. }
  126. #[proc_macro_derive(CMZCred, attributes(cmzcred_group))]
  127. pub fn cmzcred_derive(input: TokenStream) -> TokenStream {
  128. // Construct a representation of Rust code as a syntax tree
  129. // that we can manipulate
  130. let ast: DeriveInput = syn::parse(input).unwrap();
  131. // Get the cmzcred_group(group = G) attribute
  132. let group_ident = GroupIdent::from_derive_input(&ast)
  133. .expect("missing group parameter to cmzcred_group attribute");
  134. // Build the trait implementation
  135. impl_cmzcred_derive(&ast, &group_ident.group)
  136. }
  137. /** The CMZ Protocol creation macros.
  138. The format is:
  139. let proto = CMZProtocol! { proto_name<param1,param2>,
  140. [ A: Cred {
  141. attr1: H,
  142. attr2: R,
  143. },
  144. B: Cred2 {
  145. attr3: H,
  146. attr4: I,
  147. } ],
  148. C: Cred3 {
  149. attr5: J,
  150. attr6: R,
  151. attr7: H,
  152. attr8: I,
  153. attr9: S,
  154. },
  155. A.attr1 == B.attr3 + param1,
  156. A.attr1 == C.attr7,
  157. };
  158. The parameters are:
  159. - an identifier for the protocol
  160. - an optional angle-bracketed list of parameters (identifiers)
  161. - a list of zero or more specifications for credentials that will be shown
  162. - a list of zero or more specifications for credentials that will be issued
  163. - zero or more statements relating the attributes in the credentials
  164. Each credential specification list can be:
  165. - empty
  166. - a single credential specification
  167. - a square-bracketed list of credential specifications
  168. Each credential specification is:
  169. - an identifier for the credential
  170. - a type for the credential, previously defined with the CMZ! macro
  171. - a braced list of the attributes of the credential (as defined in
  172. the CMZ! macro), annotated with the attribute specification
  173. An attribute specification for a credential to be shown is one of:
  174. - H (hide)
  175. - R (reveal)
  176. - I (implicit)
  177. An attribute specification for a credential to be issued is one of:
  178. - H (hide)
  179. - R (reveal)
  180. - I (implicit)
  181. - S (set by issuer)
  182. - J (joint creation)
  183. */
  184. // The possible attribute specifications for a credential to be shown
  185. #[derive(Copy, Clone, Debug, PartialEq)]
  186. enum ShowSpec {
  187. Hide,
  188. Reveal,
  189. Implicit,
  190. }
  191. impl Parse for ShowSpec {
  192. fn parse(input: ParseStream) -> Result<Self> {
  193. let spec: Ident = input.parse()?;
  194. match spec.to_string().to_uppercase().as_str() {
  195. "H" | "HIDE" => Ok(Self::Hide),
  196. "R" | "REVEAL" => Ok(Self::Reveal),
  197. "I" | "IMPLICIT" => Ok(Self::Implicit),
  198. _ => Err(input.error("Unknown attribute spec for shown credential")),
  199. }
  200. }
  201. }
  202. // The possible attribute specifications for a credential to be issued
  203. #[derive(Copy, Clone, Debug, PartialEq)]
  204. enum IssueSpec {
  205. Hide,
  206. Reveal,
  207. Implicit,
  208. Set,
  209. Joint,
  210. }
  211. impl Parse for IssueSpec {
  212. fn parse(input: ParseStream) -> Result<Self> {
  213. let spec: Ident = input.parse()?;
  214. match spec.to_string().to_uppercase().as_str() {
  215. "H" | "HIDE" => Ok(Self::Hide),
  216. "R" | "REVEAL" => Ok(Self::Reveal),
  217. "I" | "IMPLICIT" => Ok(Self::Implicit),
  218. "S" | "SET" => Ok(Self::Set),
  219. "J" | "JOINT" => Ok(Self::Joint),
  220. _ => Err(input.error("Unknown attribute spec for issued credential")),
  221. }
  222. }
  223. }
  224. // An attribute specification like "attr1: Reveal"
  225. #[derive(Clone)]
  226. struct AttrSpec<ShowOrIssue: Parse> {
  227. attr: Ident,
  228. spec: ShowOrIssue,
  229. }
  230. impl<ShowOrIssue: Parse> Parse for AttrSpec<ShowOrIssue> {
  231. fn parse(input: ParseStream) -> Result<Self> {
  232. let attr: Ident = input.parse()?;
  233. input.parse::<Token![:]>()?;
  234. let spec: ShowOrIssue = input.parse()?;
  235. Ok(Self { attr, spec })
  236. }
  237. }
  238. // A specification of a credential, either to be shown or issued
  239. #[derive(Debug)]
  240. struct CredSpec<ShowOrIssue: Parse> {
  241. id: Ident,
  242. cred_type: Ident,
  243. attrs: HashMap<String, ShowOrIssue>,
  244. }
  245. impl<ShowOrIssue: Parse + Copy> Parse for CredSpec<ShowOrIssue> {
  246. fn parse(input: ParseStream) -> Result<Self> {
  247. let id: Ident = input.parse()?;
  248. input.parse::<Token![:]>()?;
  249. let cred_type: Ident = input.parse()?;
  250. let content;
  251. braced!(content in input);
  252. let attrspecs: Punctuated<AttrSpec<ShowOrIssue>, Token![,]> =
  253. content.parse_terminated(AttrSpec::<ShowOrIssue>::parse, Token![,])?;
  254. let mut attrs: HashMap<String, ShowOrIssue> = HashMap::new();
  255. for attrspec in attrspecs.iter() {
  256. attrs.insert(attrspec.attr.to_string(), attrspec.spec);
  257. }
  258. Ok(Self {
  259. id,
  260. cred_type,
  261. attrs,
  262. })
  263. }
  264. }
  265. // A vector of credential specifications, which could be empty, a single
  266. // credential specification, or a bracketed list of credential
  267. // specifications. We need a newtype here and not just a Vec so that we
  268. // can implement the Parse trait for it.
  269. struct CredSpecVec<ShowOrIssue: Parse>(Vec<CredSpec<ShowOrIssue>>);
  270. impl<ShowOrIssue: Parse + Copy> Parse for CredSpecVec<ShowOrIssue> {
  271. fn parse(input: ParseStream) -> Result<Self> {
  272. let specvec: Vec<CredSpec<ShowOrIssue>> = if input.peek(Token![,]) {
  273. // The list is empty
  274. Vec::new()
  275. } else if input.peek(token::Bracket) {
  276. let content;
  277. bracketed!(content in input);
  278. let specs: Punctuated<CredSpec<ShowOrIssue>, Token![,]> =
  279. content.parse_terminated(CredSpec::<ShowOrIssue>::parse, Token![,])?;
  280. specs.into_iter().collect()
  281. } else {
  282. let spec: CredSpec<ShowOrIssue> = input.parse()?;
  283. vec![spec]
  284. };
  285. Ok(Self(specvec))
  286. }
  287. }
  288. // A protocol specification, following the syntax described above.
  289. #[derive(Debug)]
  290. struct ProtoSpec {
  291. proto_name: Ident,
  292. params: Vec<Ident>,
  293. show_creds: Vec<CredSpec<ShowSpec>>,
  294. issue_creds: Vec<CredSpec<IssueSpec>>,
  295. statements: Vec<Expr>,
  296. }
  297. impl Parse for ProtoSpec {
  298. fn parse(input: ParseStream) -> Result<Self> {
  299. let mut params: Vec<Ident> = Vec::new();
  300. let proto_name: Ident = input.parse()?;
  301. // See if there are optional parameters; Rust does not provide a
  302. // convenient angle-bracket parser like it does parens, square
  303. // brackets, and braces, so we just roll our own.
  304. if input.peek(Token![<]) {
  305. input.parse::<Token![<]>()?;
  306. loop {
  307. if input.peek(Token![>]) {
  308. break;
  309. }
  310. let param: Ident = input.parse()?;
  311. params.push(param);
  312. if input.peek(Token![>]) {
  313. break;
  314. }
  315. input.parse::<Token![,]>()?;
  316. }
  317. input.parse::<Token![>]>()?;
  318. }
  319. input.parse::<Token![,]>()?;
  320. let showvec: CredSpecVec<ShowSpec> = input.parse()?;
  321. input.parse::<Token![,]>()?;
  322. let issuevec: CredSpecVec<IssueSpec> = input.parse()?;
  323. input.parse::<Token![,]>()?;
  324. let statementpunc: Punctuated<Expr, Token![,]> =
  325. input.parse_terminated(Expr::parse, Token![,])?;
  326. let statements: Vec<Expr> = statementpunc.into_iter().collect();
  327. Ok(ProtoSpec {
  328. proto_name,
  329. params,
  330. show_creds: showvec.0,
  331. issue_creds: issuevec.0,
  332. statements,
  333. })
  334. }
  335. }
  336. // Names and types of fields that might end up in a generated struct
  337. enum StructField {
  338. Scalar(Ident),
  339. Point(Ident),
  340. }
  341. // Convenience functions to create StructField items
  342. impl StructField {
  343. pub fn scalar(s: &str) -> Self {
  344. Self::Scalar(Ident::new(s, Span::call_site().into()))
  345. }
  346. pub fn point(s: &str) -> Self {
  347. Self::Point(Ident::new(s, Span::call_site().into()))
  348. }
  349. }
  350. // A list of StructField items
  351. #[derive(Default)]
  352. struct StructFieldList {
  353. fields: Vec<StructField>,
  354. }
  355. impl StructFieldList {
  356. pub fn push_scalar(&mut self, s: &str) {
  357. self.fields.push(StructField::scalar(s));
  358. }
  359. pub fn push_point(&mut self, s: &str) {
  360. self.fields.push(StructField::point(s));
  361. }
  362. /// Output an iterator consisting of the field names
  363. pub fn field_iter<'a>(&'a self) -> impl Iterator<Item = &'a Ident> {
  364. self.fields.iter().map(|f| match f {
  365. StructField::Scalar(id) => id,
  366. StructField::Point(id) => id,
  367. })
  368. }
  369. /// Output a ToTokens of the fields as they would appear in a struct
  370. /// definition (including the serde_as annotations)
  371. pub fn field_decls(&self) -> impl ToTokens {
  372. let decls = self.fields.iter().map(|f| match f {
  373. StructField::Scalar(id) => quote! {
  374. #[serde_as(as = "SerdeScalar")]
  375. pub #id: Scalar,
  376. },
  377. StructField::Point(id) => quote! {
  378. #[serde_as(as = "SerdePoint")]
  379. pub #id: Point,
  380. },
  381. });
  382. quote! { #(#decls)* }
  383. }
  384. }
  385. // This is where the main work is done. The six macros in the
  386. // CMZProtocol macro family (below) all call this function, with
  387. // different values for the bools.
  388. fn protocol_macro(
  389. input: TokenStream,
  390. use_muCMZ: bool,
  391. emit_client: bool,
  392. emit_issuer: bool,
  393. ) -> TokenStream {
  394. let proto_spec: ProtoSpec = parse_macro_input!(input as ProtoSpec);
  395. let proto_name = &proto_spec.proto_name;
  396. let has_params = proto_spec.params.len() > 0;
  397. let tot_num_creds = proto_spec.show_creds.len() + proto_spec.issue_creds.len();
  398. // Use the group of the first named credential type
  399. let group_types = if proto_spec.show_creds.len() > 0 {
  400. let first_cred_type = &proto_spec.show_creds[0].cred_type;
  401. quote! {
  402. pub type Scalar = <#first_cred_type as CMZCredential>::Scalar;
  403. pub type Point = <#first_cred_type as CMZCredential>::Point;
  404. }
  405. } else if proto_spec.issue_creds.len() > 0 {
  406. let first_cred_type = &proto_spec.issue_creds[0].cred_type;
  407. quote! {
  408. pub type Scalar = <#first_cred_type as CMZCredential>::Scalar;
  409. pub type Point = <#first_cred_type as CMZCredential>::Point;
  410. }
  411. } else {
  412. quote! {}
  413. };
  414. /* Credential issuing
  415. For each attribute of each credential to be issued, handle it
  416. according to its IssueSpec:
  417. */
  418. // The fields that will end up in the ClientState
  419. let mut clientstate_fields = StructFieldList::default();
  420. // The fields that will end up in the Request
  421. let mut request_fields = StructFieldList::default();
  422. // The fields that will end up in the Reply
  423. let mut reply_fields = StructFieldList::default();
  424. // The code that will end up in prepare
  425. let mut prepare_code = quote! {};
  426. // Are there any Hide or Joint attributes in _any_ credential to be
  427. // issued?
  428. let mut any_hide_joint = false;
  429. for iss_cred in proto_spec.issue_creds.iter() {
  430. // Are there any Hide or Joint attributes in this particular
  431. // credential to be issued?
  432. let mut cred_hide_joint = false;
  433. for (attr, &spec) in iss_cred.attrs.iter() {
  434. if spec == IssueSpec::Hide || spec == IssueSpec::Joint {
  435. cred_hide_joint = true;
  436. }
  437. /* For each Hide and Joint attribute (for CMZ): Compute an
  438. exponential El Gamal encryption (of the attribute) E_attr =
  439. (r_attr*B, attr*B + r_attr*D) for random r_attr. Include E_attr
  440. in the Request, and attr, r_attr, and E_attr in the CliProof.
  441. Hide attributes will be passed into prepare on the client side;
  442. Joint attributes (client contribution) will be generated randomly
  443. by prepare on the client side, and (issuer contribution) by
  444. handle on the issuer side.
  445. */
  446. /* For all Hide and Joint attributes of a single credential to be
  447. isued (for CMZ): the issuer chooses a random b, computes
  448. P = b*B, E_Q = b*x_0*B + \sum_{hide,joint} b*x_attr*E_attr
  449. + (0,\sum_{implicit,reveal,set,joint} b*x_attr*attr*B)
  450. (note that E_Q and each E_attr are all pairs of Points; the
  451. scalar multiplication is componentwise). Include P, E_Q in
  452. Reply. For each such attribute, include t_attr = b*x_attr and
  453. T_attr = b*X_attr = t_attr*A in Reply and IssProof. The client
  454. will compute Q = E_Q[1] - d*E_Q[0].
  455. */
  456. /* For all Hide and Joint attributes of a single credential to be
  457. issued (for µCMZ): The client chooses a random s, computes C =
  458. (\sum_{hide,joint} attr*X_attr) + s*A, where X_attr is the
  459. public key for that attribute. Include s in the ClientState, C
  460. in the Request, and the attributes, s, and C in the CliProof.
  461. Hide attributes will be passed into prepare on the client side;
  462. Joint attributes (client contribution) will be generated randomly
  463. by prepare on the client side. On the issuer side, handle will
  464. pick a random b, compute P = b*A, R = b*(x_0*A + C) +
  465. \sum_{implicit,reveal,set,joint} x_attr*attr*P. Include P
  466. and R in Reply, and x_0, b, P, R, C in IssProof. For each
  467. implicit,reveal,set,joint attribute, include x_attr and P_attr =
  468. attr*P in IssProof. The client will compute Q = R - s*P.
  469. */
  470. /* For each Reveal attribute: include attr in Request (client will
  471. pass the value into prepare)
  472. */
  473. /* For each Implicit attribute: does not appear (will be filled in
  474. by fill_creds on the issuer side and passed into prepare on the
  475. client side)
  476. */
  477. /* For each Set and Joint attribute: the issuer's value will be set
  478. by fill_creds (for Set) or by handle (for Joint). Include the
  479. value in Reply.
  480. */
  481. }
  482. any_hide_joint |= cred_hide_joint;
  483. }
  484. /* If there are _any_ Hide or Joint attributes in CMZ (as opposed to
  485. µCMZ), the client generates an El Gamal keypair (d, D=d*B).
  486. Include d in the ClientState and D in the Request.
  487. */
  488. if any_hide_joint && !use_muCMZ {
  489. clientstate_fields.push_scalar("d");
  490. request_fields.push_point("D");
  491. prepare_code = quote! {
  492. let (d,D) = bp.keypairB(&mut *rng);
  493. #prepare_code
  494. }
  495. }
  496. // Build the Params struct, if we have params
  497. let params_struct = if has_params {
  498. let param_list = &proto_spec.params;
  499. quote! {
  500. pub struct Params {
  501. #( pub #param_list: Scalar, )*
  502. }
  503. }
  504. } else {
  505. quote! {}
  506. };
  507. // Build the ClientState struct
  508. let client_state = {
  509. let decls = clientstate_fields.field_decls();
  510. quote! {
  511. #[serde_as]
  512. #[derive(Clone,Debug,serde::Serialize,serde::Deserialize)]
  513. pub struct ClientState {
  514. #decls
  515. }
  516. impl TryFrom<&[u8]> for ClientState {
  517. type Error = bincode::Error;
  518. fn try_from(bytes: &[u8]) -> bincode::Result<ClientState> {
  519. bincode::deserialize::<ClientState>(bytes)
  520. }
  521. }
  522. impl From<&ClientState> for Vec<u8> {
  523. fn from(req: &ClientState) -> Vec<u8> {
  524. bincode::serialize(req).unwrap()
  525. }
  526. }
  527. impl ClientState {
  528. pub fn as_bytes(&self) -> Vec<u8> {
  529. self.into()
  530. }
  531. }
  532. }
  533. };
  534. // Build the Request and Reply structs
  535. let messages = {
  536. let reqdecls = request_fields.field_decls();
  537. let repdecls = reply_fields.field_decls();
  538. quote! {
  539. #[serde_as]
  540. #[derive(Clone,Debug,serde::Serialize,serde::Deserialize)]
  541. pub struct Request {
  542. #reqdecls
  543. }
  544. impl TryFrom<&[u8]> for Request {
  545. type Error = bincode::Error;
  546. fn try_from(bytes: &[u8]) -> bincode::Result<Request> {
  547. bincode::deserialize::<Request>(bytes)
  548. }
  549. }
  550. impl From<&Request> for Vec<u8> {
  551. fn from(req: &Request) -> Vec<u8> {
  552. bincode::serialize(req).unwrap()
  553. }
  554. }
  555. impl Request {
  556. pub fn as_bytes(&self) -> Vec<u8> {
  557. self.into()
  558. }
  559. }
  560. #[serde_as]
  561. #[derive(Clone,Debug,serde::Serialize,serde::Deserialize)]
  562. pub struct Reply {
  563. #repdecls
  564. }
  565. impl TryFrom<&[u8]> for Reply {
  566. type Error = bincode::Error;
  567. fn try_from(bytes: &[u8]) -> bincode::Result<Reply> {
  568. bincode::deserialize::<Reply>(bytes)
  569. }
  570. }
  571. impl From<&Reply> for Vec<u8> {
  572. fn from(rep: &Reply) -> Vec<u8> {
  573. bincode::serialize(rep).unwrap()
  574. }
  575. }
  576. impl Reply {
  577. pub fn as_bytes(&self) -> Vec<u8> {
  578. self.into()
  579. }
  580. }
  581. }
  582. };
  583. // The argument list for the client's prepare function. There is an
  584. // immutable reference for each credential to be shown, and an owned
  585. // value for each credential to be issued.
  586. let client_show_args = proto_spec.show_creds.iter().map(|c| {
  587. let id = &c.id;
  588. let cred_type = &c.cred_type;
  589. quote! { #id: &#cred_type, }
  590. });
  591. let client_issue_args = proto_spec.issue_creds.iter().map(|c| {
  592. let id = &c.id;
  593. let cred_type = &c.cred_type;
  594. quote! { #id: #cred_type, }
  595. });
  596. let client_params_arg = if has_params {
  597. quote! { params: &Params, }
  598. } else {
  599. quote! {}
  600. };
  601. // Build the client's prepare function
  602. let client_func = {
  603. let reqf = request_fields.field_iter();
  604. let csf = clientstate_fields.field_iter();
  605. quote! {
  606. pub fn prepare(rng: &mut impl RngCore,
  607. #(#client_show_args)* #(#client_issue_args)* #client_params_arg)
  608. -> Result<(Request, ClientState),CMZError> {
  609. let bp = cmz_basepoints::<Point>();
  610. #prepare_code
  611. Ok((Request{#(#reqf,)*}, ClientState{#(#csf,)*}))
  612. }
  613. }
  614. };
  615. // The argument list for the issuer's fill_creds callback
  616. let issuer_fill_creds_args = proto_spec
  617. .show_creds
  618. .iter()
  619. .map(|c| {
  620. let cred_type = &c.cred_type;
  621. quote! { &mut #cred_type, }
  622. })
  623. .chain(proto_spec.issue_creds.iter().map(|c| {
  624. let cred_type = &c.cred_type;
  625. quote! { &mut #cred_type, }
  626. }));
  627. // The return value of the callback
  628. let issuer_fill_creds_params_ret = if has_params {
  629. quote! { Params }
  630. } else {
  631. quote! { () }
  632. };
  633. // The argument list for the issuer's authorize callback
  634. let issuer_authorize_args = proto_spec
  635. .show_creds
  636. .iter()
  637. .map(|c| {
  638. let cred_type = &c.cred_type;
  639. quote! { &#cred_type, }
  640. })
  641. .chain(proto_spec.issue_creds.iter().map(|c| {
  642. let cred_type = &c.cred_type;
  643. quote! { &#cred_type, }
  644. }));
  645. // The type of the returned credentials from handle
  646. let issuer_handle_cred_rettypes = proto_spec
  647. .show_creds
  648. .iter()
  649. .map(|c| {
  650. let cred_type = &c.cred_type;
  651. quote! { #cred_type }
  652. })
  653. .chain(proto_spec.issue_creds.iter().map(|c| {
  654. let cred_type = &c.cred_type;
  655. quote! { #cred_type }
  656. }));
  657. let issuer_handle_ret = if tot_num_creds > 1 {
  658. quote! { Result<(Reply, (#(#issuer_handle_cred_rettypes),*)),CMZError> }
  659. } else if tot_num_creds == 1 {
  660. quote! { Result<(Reply, #(#issuer_handle_cred_rettypes)*),CMZError> }
  661. } else {
  662. quote! { Result<Reply,CMZError> }
  663. };
  664. // Temporary: null return value for issuer's handle function
  665. let issuer_handle_cred_retvals = proto_spec
  666. .show_creds
  667. .iter()
  668. .map(|c| {
  669. let cred_type = &c.cred_type;
  670. quote! { #cred_type::default() }
  671. })
  672. .chain(proto_spec.issue_creds.iter().map(|c| {
  673. let cred_type = &c.cred_type;
  674. quote! { #cred_type::default() }
  675. }));
  676. let issuer_handle_retval = if tot_num_creds > 1 {
  677. quote! { Ok((Reply{}, (#(#issuer_handle_cred_retvals),*))) }
  678. } else if tot_num_creds == 1 {
  679. quote! { Ok((Reply{}, #(#issuer_handle_cred_retvals)*)) }
  680. } else {
  681. quote! { Ok(Reply{}) }
  682. };
  683. // Build the issuer's handle function
  684. let issuer_func = quote! {
  685. pub fn handle<F,A>(rng: &mut impl RngCore,
  686. request: Request, fill_creds: F, authorize: A)
  687. -> #issuer_handle_ret
  688. where
  689. F: FnOnce(#(#issuer_fill_creds_args)*) ->
  690. Result<#issuer_fill_creds_params_ret, CMZError>,
  691. A: FnOnce(#(#issuer_authorize_args)*) ->
  692. Result<(),CMZError>
  693. {
  694. #issuer_handle_retval
  695. }
  696. };
  697. // The type of the returned credentials from finalize
  698. let clientstate_finalize_cred_rettypes = proto_spec.issue_creds.iter().map(|c| {
  699. let cred_type = &c.cred_type;
  700. quote! { #cred_type }
  701. });
  702. let clientstate_finalize_rettype = if proto_spec.issue_creds.len() > 1 {
  703. quote! { Result<(#(#clientstate_finalize_cred_rettypes),*),(CMZError,Self)> }
  704. } else if proto_spec.issue_creds.len() == 1 {
  705. quote! { Result<#(#clientstate_finalize_cred_rettypes)*,(CMZError,Self)> }
  706. } else {
  707. quote! { Result<(),(CMZError,Self)> }
  708. };
  709. // Temporary: null return value for ClientState's finalize function
  710. let clientstate_finalize_cred_retvals = proto_spec.issue_creds.iter().map(|c| {
  711. let cred_type = &c.cred_type;
  712. quote! { #cred_type::default() }
  713. });
  714. let clientstate_finalize_retval = if proto_spec.issue_creds.len() > 1 {
  715. quote! { Ok((#(#clientstate_finalize_cred_retvals),*)) }
  716. } else if proto_spec.issue_creds.len() == 1 {
  717. quote! { Ok(#(#clientstate_finalize_cred_retvals)*) }
  718. } else {
  719. quote! { Ok(()) }
  720. };
  721. // Build the ClientState's finalize function
  722. let clientstate_finalize_func = quote! {
  723. impl ClientState {
  724. pub fn finalize(self, reply: Reply)
  725. -> #clientstate_finalize_rettype {
  726. #clientstate_finalize_retval
  727. }
  728. }
  729. };
  730. let client_side = if emit_client {
  731. quote! { #client_state #client_func #clientstate_finalize_func }
  732. } else {
  733. quote! {}
  734. };
  735. let issuer_side = if emit_issuer {
  736. issuer_func
  737. } else {
  738. quote! {}
  739. };
  740. // Output the generated module for this protocol
  741. quote! {
  742. pub mod #proto_name {
  743. use super::*;
  744. #group_types
  745. #params_struct
  746. #messages
  747. #client_side
  748. #issuer_side
  749. }
  750. }
  751. .into()
  752. }
  753. /** There are six variants of the CMZProtocol macro. The ones starting
  754. with "CMZ" create protocol implementations using the original CMZ
  755. issuing protocol. The ones starting with "muCMZ" using the more
  756. efficient µCMZ protocol. The ones with "Cli" only create the code
  757. for the client side of the protocol. The ones with "Iss" only create
  758. the code for the issuer side of the protocol. (The ones without
  759. either create the code for both sides of the protocol.)
  760. */
  761. #[proc_macro]
  762. pub fn CMZProtocol(input: TokenStream) -> TokenStream {
  763. protocol_macro(input, false, true, true)
  764. }
  765. #[proc_macro]
  766. pub fn CMZCliProtocol(input: TokenStream) -> TokenStream {
  767. protocol_macro(input, false, true, false)
  768. }
  769. #[proc_macro]
  770. pub fn CMZIssProtocol(input: TokenStream) -> TokenStream {
  771. protocol_macro(input, false, false, true)
  772. }
  773. #[proc_macro]
  774. pub fn muCMZProtocol(input: TokenStream) -> TokenStream {
  775. protocol_macro(input, true, true, true)
  776. }
  777. #[proc_macro]
  778. pub fn muCMZCliProtocol(input: TokenStream) -> TokenStream {
  779. protocol_macro(input, true, true, false)
  780. }
  781. #[proc_macro]
  782. pub fn muCMZIssProtocol(input: TokenStream) -> TokenStream {
  783. protocol_macro(input, true, false, true)
  784. }