| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857 |
- //! A module for finding and manipulating Pedersen commitments in a
- //! [`StatementTree`].
- //!
- //! A Pedersen commitment to a private `Scalar` `x` looks like
- //!
- //! `C = (a*x+b)*A + (c*r+d)*B`
- //!
- //! Where `a` and `c` are a constant non-zero `Scalar`s (defaults to
- //! [`Scalar::ONE`](https://docs.rs/ff/0.13.1/ff/trait.Field.html#associatedconstant.ONE)),
- //! `b`, and `d` are public `Scalar`s or constants (or combinations of
- //! those), `r` is a random private `Scalar` that appears nowhere else
- //! in the [`StatementTree`], `C` is a public `Point`, and `A` and `B`
- //! are computationally independent public `Point`s.
- use super::sigma::combiners::*;
- use super::sigma::types::*;
- use super::syntax::*;
- use super::transform::paren_if_needed;
- use proc_macro2::TokenStream;
- use quote::quote;
- use std::collections::{HashMap, HashSet};
- use syn::parse::Result;
- use syn::visit::Visit;
- use syn::{parse_quote, Error, Expr, Ident};
- /// Find all random private `Scalar`s (according to the
- /// [`TaggedVarDict`]) that appear exactly once in the
- /// [`StatementTree`].
- pub fn unique_random_scalars(vars: &TaggedVarDict, st: &StatementTree) -> HashSet<String> {
- // Filter the TaggedVarDict so that it only contains the private
- // _random_ Scalars
- let random_private_scalars: VarDict = vars
- .iter()
- .filter(|(_, v)| {
- matches!(
- v,
- TaggedIdent::Scalar(TaggedScalar {
- is_pub: false,
- is_rand: true,
- ..
- })
- )
- })
- .map(|(k, v)| (k.clone(), AExprType::from(v)))
- .collect();
- let mut seen_randoms: HashMap<String, usize> = HashMap::new();
- // Create a PrivScalarMap that will call the given closure for each
- // private Scalar (listed in the VarDict) in a supplied expression
- let mut var_map = PrivScalarMap {
- vars: &random_private_scalars,
- // The closure counts how many times each private random Scalar
- // in the VarDict appears in total
- closure: &mut |ident| {
- let id_str = ident.to_string();
- let val = seen_randoms.get(&id_str);
- let newval = match val {
- Some(n) => n + 1,
- None => 1,
- };
- seen_randoms.insert(id_str, newval);
- Ok(())
- },
- result: Ok(()),
- };
- // Call the PrivScalarMap for each leaf expression in the
- // StatementTree
- for e in st.leaves() {
- var_map.visit_expr(e);
- }
- // Return a HashSet of the ones that we saw exactly once
- seen_randoms
- .into_iter()
- .filter_map(|(k, v)| if v == 1 { Some(k) } else { None })
- .collect()
- }
- /// A representation of `a*x + b` where `a` is a constant `Scalar`, `b`
- /// is a public `Scalar` [arithmetic expression], and `x` is a private
- /// `Scalar` variable. `a` is optional, and defaults to `1`. `b` is
- /// optional, and defaults to `0`
- ///
- /// [arithmetic expression]: expr_type
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub struct LinScalar {
- /// The coefficient `a`
- pub coeff: i128,
- /// The public `Scalar` expression `b`, if present
- pub pub_scalar_expr: Option<Expr>,
- /// The private `Scalar` `x`
- pub id: Ident,
- /// Whether `x` is a vector variable
- pub is_vec: bool,
- }
- impl LinScalar {
- /// Negate a [`LinScalar`]
- pub fn negate(self) -> Result<Self> {
- Ok(Self {
- coeff: self.coeff.checked_neg().ok_or(Error::new(
- proc_macro2::Span::call_site(),
- "i128 neg overflow",
- ))?,
- pub_scalar_expr: if let Some(expr) = self.pub_scalar_expr {
- let pexpr = paren_if_needed(expr);
- Some(parse_quote! { -#pexpr })
- } else {
- None
- },
- ..self
- })
- }
- /// Add a public `Scalar` expression to a [`LinScalar`]
- pub fn add_opt_pub_scalar_expr(self, opsexpr: Option<Expr>) -> Result<Self> {
- if let Some(psexpr) = opsexpr {
- Ok(Self {
- pub_scalar_expr: if let Some(expr) = self.pub_scalar_expr {
- let ppsexpr = paren_if_needed(psexpr);
- Some(parse_quote! { #expr + #ppsexpr })
- } else {
- Some(psexpr)
- },
- ..self
- })
- } else {
- Ok(self)
- }
- }
- /// Add a [`LinScalar`] to a [`LinScalar`].
- ///
- /// The private variables must match.
- pub fn add_linscalar(self, arg: Self) -> Result<Self> {
- if self.id != arg.id {
- return Err(Error::new(
- proc_macro2::Span::call_site(),
- "private variables in added LinScalars do not match",
- ));
- }
- Self {
- coeff: self.coeff.checked_add(arg.coeff).ok_or(Error::new(
- proc_macro2::Span::call_site(),
- "i128 add overflow",
- ))?,
- ..self
- }
- .add_opt_pub_scalar_expr(arg.pub_scalar_expr)
- }
- /// Multiply a [`LinScalar`] by a constant
- pub fn mul_const(self, arg: i128) -> Result<Self> {
- Ok(Self {
- coeff: self.coeff.checked_mul(arg).ok_or(Error::new(
- proc_macro2::Span::call_site(),
- "i128 mul overflow",
- ))?,
- pub_scalar_expr: if let Some(expr) = self.pub_scalar_expr {
- if arg == 1 {
- Some(expr)
- } else {
- let pexpr = paren_if_needed(expr);
- Some(parse_quote! { #pexpr * #arg })
- }
- } else {
- None
- },
- ..self
- })
- }
- /// Output a [`LinScalar`] as an [`Expr`]
- pub fn to_expr(&self) -> Expr {
- let coeff = self.coeff;
- let id = &self.id;
- // If there's a non-1 coefficient, multiply it by the id
- let coeff_var_term: Expr = if coeff == 1 {
- parse_quote! { #id }
- } else {
- parse_quote! { #coeff * #id }
- };
- // If there's a pub_scalar_expr, add it to the result
- if let Some(ref pse) = self.pub_scalar_expr {
- let ppse = paren_if_needed(pse.clone());
- parse_quote! { #coeff_var_term + #ppse }
- } else {
- coeff_var_term
- }
- }
- }
- /// A representation of `b*A` where `b` is a public `Scalar` [arithmetic
- /// expression] (default to `1`) and `A` is a computationally
- /// independent `Point`.
- ///
- /// [arithmetic expression]: expr_type
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub struct CIndPoint {
- /// The public `Scalar` expression `b`
- pub coeff: Option<Expr>,
- /// The value of the coeff, if it's a constant
- pub coeff_val: Option<i128>,
- /// The public `Point` `A`
- pub id: Ident,
- }
- impl CIndPoint {
- /// Negate a [`CIndPoint`]
- pub fn negate(self) -> Result<Self> {
- Ok(Self {
- coeff: Some(if let Some(expr) = self.coeff {
- let pexpr = paren_if_needed(expr);
- parse_quote! { -#pexpr }
- } else {
- parse_quote! { -1 }
- }),
- coeff_val: if let Some(val) = self.coeff_val {
- val.checked_neg()
- } else {
- None
- },
- ..self
- })
- }
- /// Add a [`CIndPoint`] to a [`CIndPoint`]
- pub fn add_cind(self, arg: CIndPoint) -> Result<Self> {
- if self.id != arg.id {
- return Err(Error::new(
- proc_macro2::Span::call_site(),
- "public points in added CIndPoints do not match",
- ));
- }
- let lexpr = if let Some(expr) = self.coeff {
- expr
- } else {
- parse_quote! { 1 }
- };
- let rexpr = if let Some(expr) = arg.coeff {
- paren_if_needed(expr)
- } else {
- parse_quote! { 1 }
- };
- let coeff_val = if let (Some(lval), Some(rval)) = (self.coeff_val, arg.coeff_val) {
- lval.checked_add(rval)
- } else {
- None
- };
- Ok(Self {
- coeff: Some(parse_quote! { #lexpr + #rexpr }),
- coeff_val,
- ..self
- })
- }
- /// Multiply a public Scalar [`Expr`] by a [`CIndPoint`]. val is
- /// Some(v) if the Expr is the constant v.
- pub fn mul_pub_scalar_expr(self, expr: Expr, val: Option<i128>) -> Result<Self> {
- let coeff = match self.coeff {
- None => Some(expr),
- Some(selfexpr) => {
- let pleft = paren_if_needed(selfexpr);
- let pright = paren_if_needed(expr);
- Some(parse_quote! { #pleft * #pright })
- }
- };
- let coeff_val = match (self.coeff_val, val) {
- (Some(leftval), Some(rightval)) => leftval.checked_mul(rightval),
- _ => None,
- };
- Ok(Self {
- coeff,
- coeff_val,
- ..self
- })
- }
- }
- /// A representation of `(a*x + b)*A` where `a` is a constant `Scalar`
- /// (default to `1`), `b` is a public `Scalar` [arithmetic expression]
- /// (default to `0`), `x` is a private `Scalar` variable, and `A` is a
- /// computationally independent `Point`
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub struct Term {
- /// The `Scalar` expression `a*x + b`
- pub coeff: LinScalar,
- /// The public `Point` `A`
- pub id: Ident,
- }
- impl Term {
- /// Negate a [`Term`]
- pub fn negate(self) -> Result<Self> {
- Ok(Self {
- coeff: self.coeff.negate()?,
- ..self
- })
- }
- /// Add a [`CIndPoint`] to a [`Term`]
- pub fn add_cind(self, arg: CIndPoint) -> Result<Self> {
- if self.id != arg.id {
- return Err(Error::new(
- proc_macro2::Span::call_site(),
- "public points in added CIndPoint and Term do not match",
- ));
- }
- Ok(Self {
- coeff: self.coeff.add_opt_pub_scalar_expr(arg.coeff)?,
- ..self
- })
- }
- /// Add a [`Term`] to a [`Term`]
- pub fn add_term(self, arg: Term) -> Result<Self> {
- if self.id != arg.id {
- return Err(Error::new(
- proc_macro2::Span::call_site(),
- "public points in added Terms do not match",
- ));
- }
- Ok(Self {
- coeff: self.coeff.add_linscalar(arg.coeff)?,
- ..self
- })
- }
- /// Multiply a [`Term`] by a constant
- pub fn mul_const(self, arg: i128) -> Result<Self> {
- Ok(Self {
- coeff: self.coeff.mul_const(arg)?,
- ..self
- })
- }
- }
- /// A representation of `(a*x+b)*A + (c*r+d)*B` where `a` and `c` are a
- /// constant non-zero `Scalar`s (default to `1`), `b`, and `d` are
- /// public `Scalar`s or constants or combinations of those (default to
- /// `0`), `x` is a private `Scalar`, `r` is a random private `Scalar`
- /// that appears nowhere else in the [`StatementTree`], and `A` and `B`
- /// are computationally independent public `Point`s.
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub struct Pedersen {
- /// The term containing the variable being committed to (`x` above)
- pub var_term: Term,
- /// The term containing the random variable (`r` above)
- pub rand_term: Term,
- }
- impl Pedersen {
- /// Get the `Ident` for the committed private `Scalar` in a [`Pedersen`]
- pub fn var(&self) -> Ident {
- self.var_term.coeff.id.clone()
- }
- /// Negate a [`Pedersen`]
- pub fn negate(self) -> Result<Self> {
- Ok(Self {
- var_term: self.var_term.negate()?,
- rand_term: self.rand_term.negate()?,
- })
- }
- /// Add a [`CIndPoint`] to a [`Pedersen`]
- pub fn add_cind(self, arg: CIndPoint) -> Result<Self> {
- if self.var_term.id == arg.id {
- Ok(Self {
- var_term: self.var_term.add_cind(arg)?,
- ..self
- })
- } else if self.rand_term.id == arg.id {
- // This branch actually can't happen, since the private
- // random Scalar variable can only appear once in the
- // StatementTree.
- Ok(Self {
- rand_term: self.rand_term.add_cind(arg)?,
- ..self
- })
- } else {
- Err(Error::new(
- proc_macro2::Span::call_site(),
- "public points in added Pedersen and CIndPoint do not match",
- ))
- }
- }
- /// Add a [`Term`] to a [`Pedersen`]
- pub fn add_term(self, arg: Term) -> Result<Self> {
- if self.var_term.id == arg.id {
- Ok(Self {
- var_term: self.var_term.add_term(arg)?,
- ..self
- })
- } else if self.rand_term.id == arg.id {
- // This branch actually can't happen, since the private
- // random Scalar variable can only appear once in the
- // StatementTree.
- Ok(Self {
- rand_term: self.rand_term.add_term(arg)?,
- ..self
- })
- } else {
- Err(Error::new(
- proc_macro2::Span::call_site(),
- "public points in added Pedersen and CIndPoint do not match",
- ))
- }
- }
- /// Multiply a [`Pedersen`] by a constant
- pub fn mul_const(self, arg: i128) -> Result<Self> {
- Ok(Self {
- var_term: self.var_term.mul_const(arg)?,
- rand_term: self.rand_term.mul_const(arg)?,
- })
- }
- }
- /// Components of a Pedersen commitment
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub enum PedersenExpr {
- PubScalarExpr(Expr),
- LinScalar(LinScalar),
- CIndPoint(CIndPoint),
- Term(Term),
- Pedersen(Pedersen),
- }
- /// A struct that implements [`AExprFold`] in service of
- /// [`recognize_pedersen`], [`recognize_linscalar`], and
- /// [`recognize_pubscalar`]
- struct RecognizeFold<'a> {
- /// The [`TaggedVarDict`] that maps variable names to their types
- vars: &'a TaggedVarDict,
- /// The HashSet of random variables that appear exactly once in the
- /// parent [`StatementTree`]
- randoms: &'a HashSet<String>,
- }
- impl<'a> AExprFold<PedersenExpr> for RecognizeFold<'a> {
- /// Called when an identifier found in the [`VarDict`] is
- /// encountered in the [`Expr`]
- fn ident(&mut self, id: &Ident, _restype: AExprType) -> Result<PedersenExpr> {
- let Some(vartype) = self.vars.get(&id.to_string()) else {
- return Err(Error::new(id.span(), "unknown identifier"));
- };
- match vartype {
- TaggedIdent::Scalar(TaggedScalar { is_pub: true, .. }) => {
- // A bare public Scalar is a simple PubScalarExpr
- Ok(PedersenExpr::PubScalarExpr(parse_quote! { #id }))
- }
- TaggedIdent::Scalar(TaggedScalar {
- is_pub: false,
- is_vec,
- ..
- }) => {
- // A bare private Scalar is a simple LinScalar
- Ok(PedersenExpr::LinScalar(LinScalar {
- coeff: 1i128,
- pub_scalar_expr: None,
- id: id.clone(),
- is_vec: *is_vec,
- }))
- }
- TaggedIdent::Point(TaggedPoint { is_cind: true, .. }) => {
- // A bare cind Point is a CIndPoint
- Ok(PedersenExpr::CIndPoint(CIndPoint {
- coeff: None,
- coeff_val: Some(1),
- id: id.clone(),
- }))
- }
- TaggedIdent::Point(TaggedPoint { is_cind: false, .. }) => {
- // Not a part of a valid Pedersen expression
- Err(Error::new(id.span(), "non-cind Point"))
- }
- }
- }
- /// Called when the arithmetic expression evaluates to a constant
- /// [`i128`] value.
- fn const_i128(&mut self, restype: AExprType) -> Result<PedersenExpr> {
- let AExprType::Scalar { val: Some(val), .. } = restype else {
- return Err(Error::new(
- proc_macro2::Span::call_site(),
- "BUG: it should not happen that const_i128 is called without a value",
- ));
- };
- Ok(PedersenExpr::PubScalarExpr(parse_quote! { #val }))
- }
- /// Called for unary negation
- fn neg(&mut self, arg: (AExprType, PedersenExpr), _restype: AExprType) -> Result<PedersenExpr> {
- match arg.1 {
- PedersenExpr::PubScalarExpr(expr) => {
- Ok(PedersenExpr::PubScalarExpr(parse_quote! { -#expr }))
- }
- PedersenExpr::LinScalar(linscalar) => Ok(PedersenExpr::LinScalar(linscalar.negate()?)),
- PedersenExpr::CIndPoint(cind) => Ok(PedersenExpr::CIndPoint(cind.negate()?)),
- PedersenExpr::Term(term) => Ok(PedersenExpr::Term(term.negate()?)),
- PedersenExpr::Pedersen(pedersen) => Ok(PedersenExpr::Pedersen(pedersen.negate()?)),
- }
- }
- /// Called for a parenthesized expression
- fn paren(
- &mut self,
- arg: (AExprType, PedersenExpr),
- _restype: AExprType,
- ) -> Result<PedersenExpr> {
- match arg.1 {
- PedersenExpr::PubScalarExpr(expr) => {
- Ok(PedersenExpr::PubScalarExpr(parse_quote! { (#expr) }))
- }
- _ => Ok(arg.1),
- }
- }
- /// Called when adding two `Scalar`s
- fn add_scalars(
- &mut self,
- larg: (AExprType, PedersenExpr),
- rarg: (AExprType, PedersenExpr),
- _restype: AExprType,
- ) -> Result<PedersenExpr> {
- match (larg.1, rarg.1) {
- // Adding two PubScalarExprs yields a PubScalarExpr
- (PedersenExpr::PubScalarExpr(lexpr), PedersenExpr::PubScalarExpr(rexpr)) => Ok(
- PedersenExpr::PubScalarExpr(parse_quote! { #lexpr + #rexpr }),
- ),
- // Adding a PubScalarExpr and a LinScalar yields a LinScalar
- (PedersenExpr::PubScalarExpr(psexpr), PedersenExpr::LinScalar(linscalar))
- | (PedersenExpr::LinScalar(linscalar), PedersenExpr::PubScalarExpr(psexpr)) => Ok(
- PedersenExpr::LinScalar(linscalar.add_opt_pub_scalar_expr(Some(psexpr))?),
- ),
- // Adding two LinScalars yields a LinScalar if they're for
- // the same private Scalar
- (PedersenExpr::LinScalar(llinscalar), PedersenExpr::LinScalar(rlinscalar)) => Ok(
- PedersenExpr::LinScalar(llinscalar.add_linscalar(rlinscalar)?),
- ),
- // Nothing else is valid
- _ => Err(Error::new(
- proc_macro2::Span::call_site(),
- "not a component of a Pedersen commitment",
- )),
- }
- }
- /// Called when adding two `Point`s
- fn add_points(
- &mut self,
- larg: (AExprType, PedersenExpr),
- rarg: (AExprType, PedersenExpr),
- _restype: AExprType,
- ) -> Result<PedersenExpr> {
- match (larg.1, rarg.1) {
- // Adding two CIndPoints yields a CIndPoint if they're for
- // the same public Point
- (PedersenExpr::CIndPoint(lcind), PedersenExpr::CIndPoint(rcind)) => {
- Ok(PedersenExpr::CIndPoint(lcind.add_cind(rcind)?))
- }
- // Adding a CIndPoint to a Term yields a Term if they're for
- // the same public Point
- (PedersenExpr::CIndPoint(cind), PedersenExpr::Term(term))
- | (PedersenExpr::Term(term), PedersenExpr::CIndPoint(cind)) => {
- Ok(PedersenExpr::Term(term.add_cind(cind)?))
- }
- // Adding a Term to a Term yields a Term if they're for the
- // same public Point and private Scalar, or a Pedersen if
- // they're different, but one is for a private random Scalar
- // that only appears once in the [`StatementTree`]
- (PedersenExpr::Term(lterm), PedersenExpr::Term(rterm)) => {
- if lterm.id == rterm.id {
- Ok(PedersenExpr::Term(lterm.add_term(rterm)?))
- } else if self.randoms.contains(&rterm.coeff.id.to_string()) {
- Ok(PedersenExpr::Pedersen(Pedersen {
- var_term: lterm,
- rand_term: rterm,
- }))
- } else if self.randoms.contains(<erm.coeff.id.to_string()) {
- Ok(PedersenExpr::Pedersen(Pedersen {
- var_term: rterm,
- rand_term: lterm,
- }))
- } else {
- Err(Error::new(
- proc_macro2::Span::call_site(),
- "public points in added Terms do not form a Pedersen commitment",
- ))
- }
- }
- // Adding a CIndPoint to a Pedersen yields a Pedersen if one
- // of the two public Points in the Pedersen matches the one
- // in the CIndPoint
- (PedersenExpr::CIndPoint(cind), PedersenExpr::Pedersen(pedersen))
- | (PedersenExpr::Pedersen(pedersen), PedersenExpr::CIndPoint(cind)) => {
- Ok(PedersenExpr::Pedersen(pedersen.add_cind(cind)?))
- }
- // Adding a Term to a Pedersen yields a Pedersen if one of
- // the two public Points in the Pedersen matches the one
- // in the Term
- (PedersenExpr::Term(term), PedersenExpr::Pedersen(pedersen))
- | (PedersenExpr::Pedersen(pedersen), PedersenExpr::Term(term)) => {
- Ok(PedersenExpr::Pedersen(pedersen.add_term(term)?))
- }
- // Note that it's impossible to add a Pedersen to a
- // Pedersen, since the private random Scalar only appears
- // once in the StatementTree.
- // Nothing else is valid
- _ => Err(Error::new(
- proc_macro2::Span::call_site(),
- "not a component of a Pedersen commitment",
- )),
- }
- }
- /// Called when summing a vector of `Scalar`s
- fn sum_scalars(
- &mut self,
- _arg: (AExprType, PedersenExpr),
- _restype: AExprType,
- ) -> Result<PedersenExpr> {
- // Sums are never recognized as components of Pedersen
- // commitments
- Err(Error::new(
- proc_macro2::Span::call_site(),
- "not a component of a Pedersen commitment",
- ))
- }
- /// Called when summing a vector of `Point`s
- fn sum_points(
- &mut self,
- _arg: (AExprType, PedersenExpr),
- _restype: AExprType,
- ) -> Result<PedersenExpr> {
- // Sums are never recognized as components of Pedersen
- // commitments
- Err(Error::new(
- proc_macro2::Span::call_site(),
- "not a component of a Pedersen commitment",
- ))
- }
- /// Called when subtracting two `Scalar`s
- fn sub_scalars(
- &mut self,
- (largtype, larg): (AExprType, PedersenExpr),
- (rargtype, rarg): (AExprType, PedersenExpr),
- restype: AExprType,
- ) -> Result<PedersenExpr> {
- if let PedersenExpr::PubScalarExpr(ref lexpr) = larg {
- if let PedersenExpr::PubScalarExpr(ref rexpr) = rarg {
- // Subtracting two PubScalarExprs yields a PubScalarExpr
- return Ok(PedersenExpr::PubScalarExpr(
- parse_quote! { #lexpr - #rexpr },
- ));
- }
- }
- // Anything else gets the default treatment
- let negrarg = self.neg((rargtype, rarg), rargtype)?;
- self.add_scalars((largtype, larg), (rargtype, negrarg), restype)
- }
- /// Called when subtracting two `Point`s
- fn sub_points(
- &mut self,
- larg: (AExprType, PedersenExpr),
- rarg: (AExprType, PedersenExpr),
- restype: AExprType,
- ) -> Result<PedersenExpr> {
- let rargtype = rarg.0;
- let negrarg = self.neg(rarg, rargtype)?;
- self.add_points(larg, (rargtype, negrarg), restype)
- }
- /// Called when multiplying two `Scalar`s
- fn mul_scalars(
- &mut self,
- larg: (AExprType, PedersenExpr),
- rarg: (AExprType, PedersenExpr),
- _restype: AExprType,
- ) -> Result<PedersenExpr> {
- match (larg, rarg) {
- // Multiplying two PubScalarExprs yields a PubScalarExpr
- ((_, PedersenExpr::PubScalarExpr(lexpr)), (_, PedersenExpr::PubScalarExpr(rexpr))) => {
- Ok(PedersenExpr::PubScalarExpr(
- parse_quote! { #lexpr * #rexpr },
- ))
- }
- // Multiplying a PubScalarExpr by a LinScalar yields a
- // LinScalar if the PubScalarExpr is actually a constant
- // (indicated by the AExprType's val field containing
- // Some(val))
- (
- (
- AExprType::Scalar {
- val: Some(psval), ..
- },
- PedersenExpr::PubScalarExpr(_),
- ),
- (_, PedersenExpr::LinScalar(linscalar)),
- )
- | (
- (_, PedersenExpr::LinScalar(linscalar)),
- (
- AExprType::Scalar {
- val: Some(psval), ..
- },
- PedersenExpr::PubScalarExpr(_),
- ),
- ) => Ok(PedersenExpr::LinScalar(linscalar.mul_const(psval)?)),
- // Nothing else is valid
- _ => Err(Error::new(
- proc_macro2::Span::call_site(),
- "not a component of a Pedersen commitment",
- )),
- }
- }
- /// Called when multiplying a `Scalar` and a `Point` (the `Scalar`
- /// will always be passed as the first argument)
- fn mul_scalar_point(
- &mut self,
- sarg: (AExprType, PedersenExpr),
- parg: (AExprType, PedersenExpr),
- _restype: AExprType,
- ) -> Result<PedersenExpr> {
- match (sarg.0, sarg.1, parg.1) {
- // Multiplying a PubScalarExpr by a CIndPoint yields a
- // CIndPoint
- (
- AExprType::Scalar { val, .. },
- PedersenExpr::PubScalarExpr(pub_expr),
- PedersenExpr::CIndPoint(cind),
- ) => Ok(PedersenExpr::CIndPoint(
- cind.mul_pub_scalar_expr(pub_expr, val)?,
- )),
- // Multiplying a LinScalar by a CIndPoint yields a Term
- // if the coefficient in the CIndPoint is a constant
- (
- _,
- PedersenExpr::LinScalar(linscalar),
- PedersenExpr::CIndPoint(CIndPoint {
- coeff_val: Some(cval),
- id,
- ..
- }),
- ) => Ok(PedersenExpr::Term(Term {
- coeff: linscalar.mul_const(cval)?,
- id,
- })),
- // Multiplying a PubScalarExpr by a Term yields a Term if
- // the PubScalarExpr is a constant
- (
- AExprType::Scalar {
- val: Some(const_val),
- ..
- },
- PedersenExpr::PubScalarExpr(_),
- PedersenExpr::Term(term),
- ) => Ok(PedersenExpr::Term(term.mul_const(const_val)?)),
- // Multiplying a PubScalarExpr by a Pedersen yields a
- // Pedersen if the PubScalarExpr is a constant
- (
- AExprType::Scalar {
- val: Some(const_val),
- ..
- },
- PedersenExpr::PubScalarExpr(_),
- PedersenExpr::Pedersen(pedersen),
- ) => Ok(PedersenExpr::Pedersen(pedersen.mul_const(const_val)?)),
- // Nothing else is valid
- _ => Err(Error::new(
- proc_macro2::Span::call_site(),
- "not a component of a Pedersen commitment",
- )),
- }
- }
- }
- /// Parse the right-hand side of the = in an [`Expr`] to see if we
- /// recognize it as a Pedersen commitment
- pub fn recognize_pedersen(
- vars: &TaggedVarDict,
- randoms: &HashSet<String>,
- vardict: &VarDict,
- expr: &Expr,
- ) -> Option<Pedersen> {
- let mut fold = RecognizeFold { vars, randoms };
- let Ok((aetype, PedersenExpr::Pedersen(pedersen))) = fold.fold(vardict, expr) else {
- return None;
- };
- // It's not allowed for the overall expression to be a vector type,
- // but the randomizer variable be a non-vector
- if let Some(TaggedIdent::Scalar(TaggedScalar { is_vec: false, .. })) =
- vars.get(&pedersen.rand_term.id.to_string())
- {
- if matches!(aetype, AExprType::Point { is_vec: true, .. }) {
- return None;
- }
- }
- // It's not allowed for either the committed variable or the random
- // variable to have a 0 coefficient
- if pedersen.var_term.coeff.coeff == 0 || pedersen.rand_term.coeff.coeff == 0 {
- return None;
- }
- Some(pedersen)
- }
- /// Parse an [`Expr`] to see if we recognize it as a [`LinScalar`]
- pub fn recognize_linscalar(
- vars: &TaggedVarDict,
- vardict: &VarDict,
- expr: &Expr,
- ) -> Option<LinScalar> {
- let mut fold = RecognizeFold {
- vars,
- randoms: &HashSet::new(),
- };
- let Ok((_, PedersenExpr::LinScalar(linscalar))) = fold.fold(vardict, expr) else {
- return None;
- };
- // A 0 coefficient is not allowed
- if linscalar.coeff == 0 {
- return None;
- }
- Some(linscalar)
- }
- /// Parse an [`Expr`] to see if we recognize it as an expression that
- /// evaluates to a public `Scalar`.
- ///
- /// The returned [`bool`] is true if the expression evaluates to a
- /// vector. The [`i128`] is the value of the expression if it is a
- /// constant.
- pub fn recognize_pubscalar(
- vars: &TaggedVarDict,
- vardict: &VarDict,
- expr: &Expr,
- ) -> Option<(bool, Option<i128>)> {
- let mut fold = RecognizeFold {
- vars,
- randoms: &HashSet::new(),
- };
- let Ok((AExprType::Scalar { is_vec, val, .. }, PedersenExpr::PubScalarExpr(_))) =
- fold.fold(vardict, expr)
- else {
- return None;
- };
- Some((is_vec, val))
- }
- /// A representation of an assignment [`Expr`] assigning a [Pedersen
- /// expression](Pedersen) to a public `Point`.
- #[derive(Clone, Debug, PartialEq, Eq)]
- pub struct PedersenAssignment {
- /// The public `Point` being assigned to
- pub id: Ident,
- /// The Pedersen expression being assigned
- pub pedersen: Pedersen,
- }
- impl PedersenAssignment {
- /// Get the `Ident` for the committed private `Scalar` in a
- /// [`PedersenAssignment`]
- pub fn var(&self) -> Ident {
- self.pedersen.var()
- }
- }
- /// Parse an [`Expr`] to see if we recognize it as an assignment
- /// statement assigning a [Pedersen expression](Pedersen) to an
- /// [`struct@Ident`] for a public `Point`.
- pub fn recognize_pedersen_assignment(
- vars: &TaggedVarDict,
- randoms: &HashSet<String>,
- vardict: &VarDict,
- expr: &Expr,
- ) -> Option<PedersenAssignment> {
- let Expr::Assign(syn::ExprAssign { left, right, .. }) = expr else {
- return None;
- };
- let Expr::Path(syn::ExprPath { path, .. }) = left.as_ref() else {
- return None;
- };
- let id = path.get_ident()?;
- let pedersen = recognize_pedersen(vars, randoms, vardict, right)?;
- Some(PedersenAssignment {
- id: id.clone(),
- pedersen,
- })
- }
- /// Output code to convert a commitment given by a
- /// [`PedersenAssignment`] into one for a different [`LinScalar`] of the
- /// same variable.
- pub fn convert_commitment(
- output_commitment: &Ident,
- ped_assign: &PedersenAssignment,
- new_linscalar: &LinScalar,
- vardict: &VarDict,
- ) -> Result<TokenStream> {
- let orig_commitment = &ped_assign.id;
- let mut is_vec = matches!(
- vardict.get(&orig_commitment.to_string()),
- Some(AExprType::Point { is_vec: true, .. })
- );
- let mut needs_clone = is_vec;
- let ped_assign_linscalar = &ped_assign.pedersen.var_term.coeff;
- let generator = &ped_assign.pedersen.var_term.id;
- let generator_is_vec = matches!(
- vardict.get(&generator.to_string()),
- Some(AExprType::Point { is_vec: true, .. })
- );
- let mut generated_code = quote! { #orig_commitment };
- // Subtract the pub_scalar_expr in ped_assign_linscalar (if present)
- // times the generator
- if let Some(ref pse) = ped_assign_linscalar.pub_scalar_expr {
- let (ppse_type, ppse_tokens) = expr_type_tokens(vardict, &paren_if_needed(pse.clone()))?;
- let ppse_is_vec = matches!(ppse_type, AExprType::Scalar { is_vec: true, .. });
- generated_code = tokens_sub_maybe_vec(
- generated_code,
- is_vec,
- tokens_mul_maybe_vec(
- ppse_tokens,
- ppse_is_vec,
- quote! { #generator },
- generator_is_vec,
- ),
- ppse_is_vec | generator_is_vec,
- );
- is_vec |= ppse_is_vec | generator_is_vec;
- needs_clone = false;
- }
- // Divide by the coeff in ped_assign_linscalar, if present (noting
- // it also cannot be 0, so will have an inverse)
- if ped_assign_linscalar.coeff != 1 {
- let coeff_tokens = const_i128_tokens(ped_assign_linscalar.coeff);
- generated_code = tokens_mul_maybe_vec(
- quote! { <Scalar as Field>::invert(&#coeff_tokens).unwrap() },
- false,
- generated_code,
- is_vec,
- );
- needs_clone = false;
- }
- // Now multiply by the coeff in new_linscalar, if present
- if new_linscalar.coeff != 1 {
- let coeff_tokens = const_i128_tokens(new_linscalar.coeff);
- generated_code = tokens_mul_maybe_vec(coeff_tokens, false, generated_code, is_vec);
- needs_clone = false;
- }
- // And add the pub_scalar_expr in new_linscalar (if present) times
- // the generator
- if let Some(ref pse) = new_linscalar.pub_scalar_expr {
- let (ppse_type, ppse_tokens) = expr_type_tokens(vardict, &paren_if_needed(pse.clone()))?;
- let ppse_is_vec = matches!(ppse_type, AExprType::Scalar { is_vec: true, .. });
- generated_code = tokens_add_maybe_vec(
- generated_code,
- is_vec,
- tokens_mul_maybe_vec(
- ppse_tokens,
- ppse_is_vec,
- quote! { #generator },
- generator_is_vec,
- ),
- ppse_is_vec | generator_is_vec,
- );
- needs_clone = false;
- }
- if needs_clone {
- generated_code = quote! { #generated_code.clone() };
- }
- Ok(quote! { let #output_commitment = #generated_code; })
- }
- /// Output code to convert the randomness given by a
- /// [`PedersenAssignment`] into that resulting from the conversion in
- /// [`convert_commitment`].
- pub fn convert_randomness(
- output_randomness: &Ident,
- ped_assign: &PedersenAssignment,
- new_linscalar: &LinScalar,
- vardict: &VarDict,
- ) -> Result<TokenStream> {
- let ped_assign_linscalar = &ped_assign.pedersen.var_term.coeff;
- // Start with the LinScalar in ped_assign.pedersen.rand_term
- let (coeff_type, mut generated_code) = expr_type_tokens(
- vardict,
- &paren_if_needed(ped_assign.pedersen.rand_term.coeff.to_expr()),
- )?;
- let is_vec = matches!(coeff_type, AExprType::Scalar { is_vec: true, .. });
- let mut needs_clone = is_vec;
- // Divide by the coeff in ped_assign_linscalar, if present (noting
- // it also cannot be 0, so will have an inverse)
- if ped_assign_linscalar.coeff != 1 {
- let coeff_tokens = const_i128_tokens(ped_assign_linscalar.coeff);
- generated_code = tokens_mul_maybe_vec(
- quote! { <Scalar as Field>::invert(&#coeff_tokens).unwrap() },
- false,
- generated_code,
- is_vec,
- );
- needs_clone = false;
- }
- // Now multiply by the coeff in new_linscalar, if present
- if new_linscalar.coeff != 1 {
- let coeff_tokens = const_i128_tokens(new_linscalar.coeff);
- generated_code = tokens_mul_maybe_vec(coeff_tokens, false, generated_code, is_vec);
- needs_clone = false;
- }
- if needs_clone {
- generated_code = quote! { #generated_code.clone() };
- }
- Ok(quote! { let #output_randomness = #generated_code; })
- }
- #[cfg(test)]
- mod test {
- use super::*;
- use quote::format_ident;
- use syn::{parse_quote, Expr};
- fn unique_random_scalars_tester(vars: (&[&str], &[&str]), e: Expr, expected: &[&str]) {
- let taggedvardict = taggedvardict_from_strs(vars);
- let st = StatementTree::parse(&e).unwrap();
- let expected_out = expected.iter().map(|s| s.to_string()).collect();
- let output = unique_random_scalars(&taggedvardict, &st);
- assert_eq!(output, expected_out);
- }
- #[test]
- fn unique_random_scalars_test() {
- let vars = (
- ["x", "y", "z", "rand r", "rand s", "rand t"].as_slice(),
- ["C", "cind A", "cind B"].as_slice(),
- );
- unique_random_scalars_tester(
- vars,
- parse_quote! {
- C = x*A + r*B
- },
- ["r"].as_slice(),
- );
- unique_random_scalars_tester(
- vars,
- parse_quote! {
- AND (
- C = x*A + r*B,
- D = y*A + s*B,
- )
- },
- ["r", "s"].as_slice(),
- );
- unique_random_scalars_tester(
- vars,
- parse_quote! {
- AND (
- C = x*A + r*B,
- OR (
- D = y*A + s*B,
- E = y*A + t*B,
- ),
- E = z*A + r*B,
- )
- },
- ["s", "t"].as_slice(),
- );
- }
- fn fold_tester(
- vars: (&[&str], &[&str]),
- randoms: &[&str],
- e: Expr,
- expected_out: Option<PedersenExpr>,
- ) {
- let taggedvardict = taggedvardict_from_strs(vars);
- let vardict = taggedvardict_to_vardict(&taggedvardict);
- let mut randoms_hash = HashSet::new();
- for r in randoms {
- randoms_hash.insert(r.to_string());
- }
- let mut fold = RecognizeFold {
- vars: &taggedvardict,
- randoms: &randoms_hash,
- };
- let output = if let Ok((_, pe)) = fold.fold(&vardict, &e) {
- Some(pe)
- } else {
- None
- };
- assert_eq!(output, expected_out);
- }
- #[test]
- fn fold_test() {
- let vars = (
- [
- "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
- ]
- .as_slice(),
- ["C", "cind A", "cind B"].as_slice(),
- );
- let randoms = ["r", "s", "t"].as_slice();
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 1
- },
- Some(PedersenExpr::PubScalarExpr(parse_quote! { 1i128 })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 1 + 2
- },
- Some(PedersenExpr::PubScalarExpr(parse_quote! { 3i128 })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 1 - 2
- },
- Some(PedersenExpr::PubScalarExpr(parse_quote! { -1i128 })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a
- },
- Some(PedersenExpr::PubScalarExpr(parse_quote! { a })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a + 1
- },
- Some(PedersenExpr::PubScalarExpr(parse_quote! { a + 1i128 })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a + b + 1
- },
- Some(PedersenExpr::PubScalarExpr(parse_quote! { a + b + 1i128 })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a + 2*b + 1
- },
- Some(PedersenExpr::PubScalarExpr(
- parse_quote! { a + 2i128 * b + 1i128 },
- )),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a - 2*b + 1
- },
- Some(PedersenExpr::PubScalarExpr(
- parse_quote! { a - 2i128 * b + 1i128 },
- )),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a - (2*b + 1)
- },
- Some(PedersenExpr::PubScalarExpr(
- parse_quote! { a - (2i128 * b + 1i128) },
- )),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- x
- },
- Some(PedersenExpr::LinScalar(LinScalar {
- coeff: 1,
- pub_scalar_expr: None,
- id: parse_quote! {x},
- is_vec: false,
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- x + 2
- },
- Some(PedersenExpr::LinScalar(LinScalar {
- coeff: 1,
- pub_scalar_expr: Some(parse_quote! { 2i128 }),
- id: parse_quote! {x},
- is_vec: false,
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*x + 2
- },
- Some(PedersenExpr::LinScalar(LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { 2i128 }),
- id: parse_quote! {x},
- is_vec: false,
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + 2)
- },
- Some(PedersenExpr::LinScalar(LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { 2i128 * 3i128 }),
- id: parse_quote! {x},
- is_vec: false,
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x - 2)
- },
- Some(PedersenExpr::LinScalar(LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { (-2i128) * 3i128 }),
- id: parse_quote! {x},
- is_vec: false,
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + a)
- },
- Some(PedersenExpr::LinScalar(LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { a * 3i128 }),
- id: parse_quote! {x},
- is_vec: false,
- })),
- );
- // Adding two private Scalars
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + y)
- },
- None,
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a * A
- },
- Some(PedersenExpr::CIndPoint(CIndPoint {
- coeff: Some(parse_quote! { a }),
- coeff_val: None,
- id: parse_quote! {A},
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- a * A * b
- },
- Some(PedersenExpr::CIndPoint(CIndPoint {
- coeff: Some(parse_quote! { a * b }),
- coeff_val: None,
- id: parse_quote! {A},
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- A * b * (c+1)
- },
- Some(PedersenExpr::CIndPoint(CIndPoint {
- coeff: Some(parse_quote! { b * (c + 1i128) }),
- coeff_val: None,
- id: parse_quote! {A},
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + a) * A
- },
- Some(PedersenExpr::Term(Term {
- coeff: LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { a * 3i128 }),
- id: parse_quote! {x},
- is_vec: false,
- },
- id: parse_quote! {A},
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + a) * A + A * b
- },
- Some(PedersenExpr::Term(Term {
- coeff: LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { a * 3i128 + b }),
- id: parse_quote! {x},
- is_vec: false,
- },
- id: parse_quote! {A},
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + a) * A + A * b * (c + 1)
- },
- Some(PedersenExpr::Term(Term {
- coeff: LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { a * 3i128 + (b*(c+1i128)) }),
- id: parse_quote! {x},
- is_vec: false,
- },
- id: parse_quote! {A},
- })),
- );
- fold_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + a) * A + A * b * (c + 1) + r * B
- },
- Some(PedersenExpr::Pedersen(Pedersen {
- var_term: Term {
- coeff: LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { a * 3i128 + (b * (c + 1i128)) }),
- id: parse_quote! {x},
- is_vec: false,
- },
- id: parse_quote! {A},
- },
- rand_term: Term {
- coeff: LinScalar {
- coeff: 1,
- pub_scalar_expr: None,
- id: parse_quote! {r},
- is_vec: false,
- },
- id: parse_quote! {B},
- },
- })),
- );
- }
- fn recognize_tester(
- vars: (&[&str], &[&str]),
- randoms: &[&str],
- e: Expr,
- expected_out: Option<Pedersen>,
- ) {
- let taggedvardict = taggedvardict_from_strs(vars);
- let vardict = taggedvardict_to_vardict(&taggedvardict);
- let mut randoms_hash = HashSet::new();
- for r in randoms {
- randoms_hash.insert(r.to_string());
- }
- let output = recognize_pedersen(&taggedvardict, &randoms_hash, &vardict, &e);
- assert_eq!(output, expected_out);
- }
- #[test]
- fn recognize_pedersen_test() {
- let vars = (
- [
- "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
- ]
- .as_slice(),
- ["C", "cind A", "cind B"].as_slice(),
- );
- let randoms = ["r", "s", "t"].as_slice();
- recognize_tester(
- vars,
- randoms,
- parse_quote! {
- 3*(x + a) * A + A * b * (c + 1) + r * B
- },
- Some(Pedersen {
- var_term: Term {
- coeff: LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { a * 3i128 + (b * (c + 1i128)) }),
- id: parse_quote! {x},
- is_vec: false,
- },
- id: parse_quote! {A},
- },
- rand_term: Term {
- coeff: LinScalar {
- coeff: 1,
- pub_scalar_expr: None,
- id: parse_quote! {r},
- is_vec: false,
- },
- id: parse_quote! {B},
- },
- }),
- );
- recognize_tester(
- vars,
- randoms,
- parse_quote! {
- 3 * (2*x + a*b) * A + B * (3 * r - 7)
- },
- Some(Pedersen {
- var_term: Term {
- coeff: LinScalar {
- coeff: 6,
- pub_scalar_expr: Some(parse_quote! { (a * b) * 3i128 }),
- id: parse_quote! {x},
- is_vec: false,
- },
- id: parse_quote! {A},
- },
- rand_term: Term {
- coeff: LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { -7i128 }),
- id: parse_quote! {r},
- is_vec: false,
- },
- id: parse_quote! {B},
- },
- }),
- );
- recognize_tester(
- vars,
- randoms,
- parse_quote! {
- (3 * (2*x + a*b) * A + B * (3 * r - 7))* (7-2)
- },
- Some(Pedersen {
- var_term: Term {
- coeff: LinScalar {
- coeff: 30,
- pub_scalar_expr: Some(parse_quote! { ((a * b) * 3i128) * 5i128 }),
- id: parse_quote! {x},
- is_vec: false,
- },
- id: parse_quote! {A},
- },
- rand_term: Term {
- coeff: LinScalar {
- coeff: 15,
- pub_scalar_expr: Some(parse_quote! { (-7i128) * 5i128 }),
- id: parse_quote! {r},
- is_vec: false,
- },
- id: parse_quote! {B},
- },
- }),
- );
- }
- fn recognize_linscalar_tester(
- vars: (&[&str], &[&str]),
- e: Expr,
- expected_out: Option<LinScalar>,
- expected_expr: Option<Expr>,
- ) {
- let taggedvardict = taggedvardict_from_strs(vars);
- let vardict = taggedvardict_to_vardict(&taggedvardict);
- let output = recognize_linscalar(&taggedvardict, &vardict, &e);
- assert_eq!(output, expected_out);
- if output.is_some() {
- assert_eq!(output.unwrap().to_expr(), expected_expr.unwrap());
- }
- }
- #[test]
- fn recognize_linscalar_test() {
- let vars = (
- [
- "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
- ]
- .as_slice(),
- ["C", "cind A", "cind B"].as_slice(),
- );
- recognize_linscalar_tester(
- vars,
- parse_quote! {
- x
- },
- Some(LinScalar {
- coeff: 1,
- pub_scalar_expr: None,
- id: parse_quote! {x},
- is_vec: false,
- }),
- Some(parse_quote! { x }),
- );
- recognize_linscalar_tester(
- vars,
- parse_quote! {
- x * 7 - x * 3
- },
- Some(LinScalar {
- coeff: 4,
- pub_scalar_expr: None,
- id: parse_quote! {x},
- is_vec: false,
- }),
- Some(parse_quote! { 4i128 * x }),
- );
- recognize_linscalar_tester(
- vars,
- parse_quote! {
- x - (a + 12)
- },
- Some(LinScalar {
- coeff: 1,
- pub_scalar_expr: Some(parse_quote! {-(a + 12i128)}),
- id: parse_quote! {x},
- is_vec: false,
- }),
- Some(parse_quote! { x + (-(a + 12i128))}),
- );
- recognize_linscalar_tester(
- vars,
- parse_quote! {
- 3*(x + a + 1)
- },
- Some(LinScalar {
- coeff: 3,
- pub_scalar_expr: Some(parse_quote! { ( a + 1i128 ) * 3i128 }),
- id: parse_quote! {x},
- is_vec: false,
- }),
- Some(parse_quote! { 3i128 * x + ((a + 1i128) * 3i128) }),
- );
- recognize_linscalar_tester(
- vars,
- parse_quote! {
- 3*(x + a + 1) - x*4
- },
- Some(LinScalar {
- coeff: -1,
- pub_scalar_expr: Some(parse_quote! { ( a + 1i128 ) * 3i128 }),
- id: parse_quote! {x},
- is_vec: false,
- }),
- Some(parse_quote! { -1i128 * x + ((a + 1i128) * 3i128) }),
- );
- recognize_linscalar_tester(
- vars,
- parse_quote! {
- 3*(x + a + 1) - x*4 + x
- },
- None,
- None,
- );
- }
- fn recognize_pubscalar_tester(
- vars: (&[&str], &[&str]),
- e: Expr,
- expected_out: Option<(bool, Option<i128>)>,
- ) {
- let taggedvardict = taggedvardict_from_strs(vars);
- let vardict = taggedvardict_to_vardict(&taggedvardict);
- let output = recognize_pubscalar(&taggedvardict, &vardict, &e);
- assert_eq!(output, expected_out);
- }
- #[test]
- fn recognize_pubscalar_test() {
- let vars = (
- [
- "x",
- "y",
- "z",
- "pub a",
- "pub vec b",
- "pub c",
- "rand r",
- "rand s",
- "rand t",
- ]
- .as_slice(),
- ["C", "cind A", "cind B"].as_slice(),
- );
- recognize_pubscalar_tester(
- vars,
- parse_quote! {
- 3*(x + a + 1)
- },
- None,
- );
- recognize_pubscalar_tester(
- vars,
- parse_quote! {
- 3
- },
- Some((false, Some(3))),
- );
- recognize_pubscalar_tester(
- vars,
- parse_quote! {
- a
- },
- Some((false, None)),
- );
- recognize_pubscalar_tester(
- vars,
- parse_quote! {
- 3*(a + 1)
- },
- Some((false, None)),
- );
- recognize_pubscalar_tester(
- vars,
- parse_quote! {
- 3*(a + b)
- },
- Some((true, None)),
- );
- }
- fn convert_commitment_randomness_tester(
- vars: (&[&str], &[&str]),
- randoms: &[&str],
- ped_assign_expr: Expr,
- lin_scalar_expr: Expr,
- expect_commitment: TokenStream,
- expect_randomness: TokenStream,
- ) {
- let taggedvardict = taggedvardict_from_strs(vars);
- let vardict = taggedvardict_to_vardict(&taggedvardict);
- let mut randoms_hash = HashSet::new();
- for r in randoms {
- randoms_hash.insert(r.to_string());
- }
- let output_commitment = format_ident! { "out" };
- let output_randomness = format_ident! { "out_rand" };
- let ped_assign = recognize_pedersen_assignment(
- &taggedvardict,
- &randoms_hash,
- &vardict,
- &ped_assign_expr,
- )
- .unwrap();
- let lin_scalar = recognize_linscalar(&taggedvardict, &vardict, &lin_scalar_expr).unwrap();
- assert_eq!(
- convert_commitment(&output_commitment, &ped_assign, &lin_scalar, &vardict)
- .unwrap()
- .to_string(),
- expect_commitment.to_string()
- );
- assert_eq!(
- convert_randomness(&output_randomness, &ped_assign, &lin_scalar, &vardict)
- .unwrap()
- .to_string(),
- expect_randomness.to_string()
- );
- }
- #[test]
- fn convert_commitment_randomness_test() {
- let vars = (
- [
- "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
- ]
- .as_slice(),
- ["C", "cind A", "cind B"].as_slice(),
- );
- let randoms = ["r", "s", "t"].as_slice();
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = x*A + r*B },
- parse_quote! { x },
- quote! { let out = C; },
- quote! { let out_rand = r; },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = x*A + r*B },
- parse_quote! { 2 * x },
- quote! { let out = Scalar::from_u128(2u128) * C; },
- quote! { let out_rand = Scalar::from_u128(2u128) * r; },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = x*A + r*B },
- parse_quote! { 2 * x + 12 },
- quote! { let out = (Scalar::from_u128(2u128) * C) +
- (Scalar::from_u128(12u128) * A); },
- quote! { let out_rand = Scalar::from_u128(2u128) * r; },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = x*A + r*B },
- parse_quote! { 2 * x + 12 + a },
- quote! { let out = (Scalar::from_u128(2u128) * C) +
- ((Scalar::from_u128(12u128) + a) * A); },
- quote! { let out_rand = Scalar::from_u128(2u128) * r; },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = 3*x*A + r*B },
- parse_quote! { 2 * x + 12 + a },
- quote! { let out = (Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128)).unwrap() * C)) +
- ((Scalar::from_u128(12u128) + a) * A); },
- quote! { let out_rand = Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128)).unwrap() * r); },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = -3*x*A + r*B },
- parse_quote! { 2 * x + 12 + a },
- quote! { let out = (Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() * C)) +
- ((Scalar::from_u128(12u128) + a) * A); },
- quote! { let out_rand = Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() * r); },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = (-3*x+4+b)*A + r*B },
- parse_quote! { 2 * x + 12 + a },
- quote! { let out = (Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
- (C - ((Scalar::from_u128(4u128) + b) * A)))) +
- ((Scalar::from_u128(12u128) + a) * A); },
- quote! { let out_rand = Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() * r); },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = (-3*x+4+b)*A + 2*r*B },
- parse_quote! { 2 * x + 12 + a },
- quote! { let out = (Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
- (C - ((Scalar::from_u128(4u128) + b) * A)))) +
- ((Scalar::from_u128(12u128) + a) * A); },
- quote! { let out_rand = Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
- (r * Scalar::from_u128(2u128))); },
- );
- convert_commitment_randomness_tester(
- vars,
- randoms,
- parse_quote! { C = (-3*x+4+b)*A + (2*r+c-3)*B },
- parse_quote! { 2 * x + 12 + a },
- quote! { let out = (Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
- (C - ((Scalar::from_u128(4u128) + b) * A)))) +
- ((Scalar::from_u128(12u128) + a) * A); },
- quote! { let out_rand = Scalar::from_u128(2u128) *
- (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
- ((r * Scalar::from_u128(2u128)) +
- (c + (Scalar::from_u128(3u128).neg())))); },
- );
- }
- }
|