| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- //! A module for parsing the syntax of the macro
- use super::sigma::combiners::StatementTree;
- use super::sigma::types::*;
- use quote::format_ident;
- use std::collections::HashMap;
- use syn::ext::IdentExt;
- use syn::parse::{Parse, ParseStream, Result};
- use syn::punctuated::Punctuated;
- use syn::{parenthesized, Error, Expr, Ident, Token};
- /// A [`TaggedScalar`] is an [`struct@Ident`] representing a `Scalar`,
- /// preceded by zero or more of the following tags: `pub`, `rand`, `vec`
- ///
- /// The following combinations are valid:
- /// - (nothing)
- /// - `pub`
- /// - `rand`
- /// - `vec`
- /// - `pub vec`
- /// - `rand vec`
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub struct TaggedScalar {
- pub id: Ident,
- pub is_pub: bool,
- pub is_rand: bool,
- pub is_vec: bool,
- }
- impl Parse for TaggedScalar {
- fn parse(input: ParseStream) -> Result<Self> {
- let (mut is_pub, mut is_rand, mut is_vec) = (false, false, false);
- loop {
- let id = input.call(Ident::parse_any)?;
- match id.to_string().as_str() {
- // pub and rand are mutually exclusive
- "pub" if !is_rand => {
- is_pub = true;
- }
- "rand" if !is_pub => {
- is_rand = true;
- }
- // any other use of the tagging keywords is not allowed
- "pub" | "rand" | "cind" | "const" => {
- return Err(Error::new(id.span(), "tag not allowed in this position"));
- }
- // vec is allowed with any other tag
- "vec" => {
- is_vec = true;
- }
- _ => {
- return Ok(TaggedScalar {
- id,
- is_pub,
- is_rand,
- is_vec,
- });
- }
- }
- }
- }
- }
- /// A [`TaggedPoint`] is an [`struct@Ident`] representing a `Point`,
- /// preceded by zero or more of the following tags: `cind`, `const`,
- /// `vec`
- ///
- /// All combinations are valid:
- /// - (nothing)
- /// - `cind`
- /// - `const`
- /// - `cind const`
- /// - `vec`
- /// - `cind vec`
- /// - `const vec`
- /// - `cind const vec`
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub struct TaggedPoint {
- pub id: Ident,
- pub is_cind: bool,
- pub is_const: bool,
- pub is_vec: bool,
- }
- impl Parse for TaggedPoint {
- fn parse(input: ParseStream) -> Result<Self> {
- // Points are always pub
- let (mut is_cind, mut is_const, mut is_vec) = (false, false, false);
- loop {
- let id = input.call(Ident::parse_any)?;
- match id.to_string().as_str() {
- "cind" => {
- is_cind = true;
- }
- "const" => {
- is_const = true;
- }
- // any other use of the tagging keywords is not allowed
- "pub" | "rand" => {
- return Err(Error::new(id.span(), "tag not allowed in this position"));
- }
- "vec" => {
- is_vec = true;
- }
- _ => {
- return Ok(TaggedPoint {
- id,
- is_cind,
- is_const,
- is_vec,
- });
- }
- }
- }
- }
- }
- /// A [`TaggedIdent`] can be either a [`TaggedScalar`] or a
- /// [`TaggedPoint`]
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub enum TaggedIdent {
- Scalar(TaggedScalar),
- Point(TaggedPoint),
- }
- /// Convert a [`TaggedIdent`] to its underlying [`AExprType`]
- impl From<&TaggedIdent> for AExprType {
- fn from(ti: &TaggedIdent) -> Self {
- match ti {
- TaggedIdent::Scalar(ts) => Self::Scalar {
- is_pub: ts.is_pub,
- is_vec: ts.is_vec,
- val: None,
- },
- TaggedIdent::Point(tp) => Self::Point {
- is_pub: true,
- is_vec: tp.is_vec,
- },
- }
- }
- }
- /// A [`TaggedVarDict`] is a dictionary of the available variables,
- /// mapping the string version of [`struct@Ident`]s to [`TaggedIdent`],
- /// which includes their type ([`Scalar`](TaggedIdent::Scalar) or
- /// [`Point`](TaggedIdent::Point))
- pub type TaggedVarDict = HashMap<String, TaggedIdent>;
- /// Convert a [`TaggedVarDict`] (a map from [`String`] to
- /// [`TaggedIdent`]) into the equivalent [`VarDict`] (a map from
- /// [`String`] to [`AExprType`])
- pub fn taggedvardict_to_vardict(vd: &TaggedVarDict) -> VarDict {
- vd.iter()
- .map(|(k, v)| (k.clone(), AExprType::from(v)))
- .collect()
- }
- #[cfg(test)]
- /// Convert a list of strings describing `Scalar`s and a list of strings
- /// describing `Point`s into a [`TaggedVarDict`]
- pub fn taggedvardict_from_strs((scalar_strs, point_strs): (&[&str], &[&str])) -> TaggedVarDict {
- let mut vars = HashMap::new();
- for scalar in scalar_strs {
- let ts: TaggedScalar = syn::parse_str(scalar).unwrap();
- vars.insert(ts.id.to_string(), TaggedIdent::Scalar(ts));
- }
- for point in point_strs {
- let tp: TaggedPoint = syn::parse_str(point).unwrap();
- vars.insert(tp.id.to_string(), TaggedIdent::Point(tp));
- }
- vars
- }
- /// The [`SigmaCompSpec`] struct is the result of parsing the macro
- /// input.
- #[derive(Debug)]
- pub struct SigmaCompSpec {
- /// An identifier for the name of the zero-knowledge protocol being
- /// defined
- pub proto_name: Ident,
- /// An identifier for the mathematical
- /// [`PrimeGroup`](https://docs.rs/group/latest/group/prime/trait.PrimeGroup.html)
- /// being used (if none is specified, it is assumed there is a
- /// default type called `G` in scope that implements the
- /// [`PrimeGroup`](https://docs.rs/group/latest/group/prime/trait.PrimeGroup.html)
- /// trait)
- pub group_name: Ident,
- /// A [`TaggedVarDict`] mapping variable names to their types
- /// (`Scalar` or `Point`) and tags (e.g., `rand`, `pub`, `vec`,
- /// `cind`, `const`)
- pub vars: TaggedVarDict,
- /// A [`StatementTree`] representing the statements provided in the
- /// macro invocation that are to be proved true in zero knowledge
- pub statements: StatementTree,
- }
- // T is TaggedScalar or TaggedPoint
- fn paren_taggedidents<T: Parse>(input: ParseStream) -> Result<Vec<T>> {
- let content;
- parenthesized!(content in input);
- let punc: Punctuated<T, Token![,]> = content.parse_terminated(T::parse, Token![,])?;
- Ok(punc.into_iter().collect())
- }
- impl Parse for SigmaCompSpec {
- fn parse(input: ParseStream) -> Result<Self> {
- let proto_name: Ident = input.parse()?;
- // See if a group was specified
- let group_name = if input.peek(Token![<]) {
- input.parse::<Token![<]>()?;
- let gr: Ident = input.parse()?;
- input.parse::<Token![>]>()?;
- gr
- } else {
- format_ident!("G")
- };
- input.parse::<Token![,]>()?;
- let mut vars: TaggedVarDict = HashMap::new();
- let scalars = paren_taggedidents::<TaggedScalar>(input)?;
- vars.extend(
- scalars
- .into_iter()
- .map(|ts| (ts.id.to_string(), TaggedIdent::Scalar(ts))),
- );
- input.parse::<Token![,]>()?;
- let points = paren_taggedidents::<TaggedPoint>(input)?;
- vars.extend(
- points
- .into_iter()
- .map(|tp| (tp.id.to_string(), TaggedIdent::Point(tp))),
- );
- input.parse::<Token![,]>()?;
- let statementpunc: Punctuated<Expr, Token![,]> =
- input.parse_terminated(Expr::parse, Token![,])?;
- let statementlist: Vec<Expr> = statementpunc.into_iter().collect();
- let statements = StatementTree::parse_andlist(&statementlist)?;
- let vardict = taggedvardict_to_vardict(&vars);
- statements.check_disjunction_invariant(&vardict)?;
- Ok(SigmaCompSpec {
- proto_name,
- group_name,
- vars,
- statements,
- })
- }
- }
|