pedersen.rs 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857
  1. //! A module for finding and manipulating Pedersen commitments in a
  2. //! [`StatementTree`].
  3. //!
  4. //! A Pedersen commitment to a private `Scalar` `x` looks like
  5. //!
  6. //! `C = (a*x+b)*A + (c*r+d)*B`
  7. //!
  8. //! Where `a` and `c` are a constant non-zero `Scalar`s (defaults to
  9. //! [`Scalar::ONE`](https://docs.rs/ff/0.13.1/ff/trait.Field.html#associatedconstant.ONE)),
  10. //! `b`, and `d` are public `Scalar`s or constants (or combinations of
  11. //! those), `r` is a random private `Scalar` that appears nowhere else
  12. //! in the [`StatementTree`], `C` is a public `Point`, and `A` and `B`
  13. //! are computationally independent public `Point`s.
  14. use super::sigma::combiners::*;
  15. use super::sigma::types::*;
  16. use super::syntax::*;
  17. use super::transform::paren_if_needed;
  18. use proc_macro2::TokenStream;
  19. use quote::quote;
  20. use std::collections::{HashMap, HashSet};
  21. use syn::parse::Result;
  22. use syn::visit::Visit;
  23. use syn::{parse_quote, Error, Expr, Ident};
  24. /// Find all random private `Scalar`s (according to the
  25. /// [`TaggedVarDict`]) that appear exactly once in the
  26. /// [`StatementTree`].
  27. pub fn unique_random_scalars(vars: &TaggedVarDict, st: &StatementTree) -> HashSet<String> {
  28. // Filter the TaggedVarDict so that it only contains the private
  29. // _random_ Scalars
  30. let random_private_scalars: VarDict = vars
  31. .iter()
  32. .filter(|(_, v)| {
  33. matches!(
  34. v,
  35. TaggedIdent::Scalar(TaggedScalar {
  36. is_pub: false,
  37. is_rand: true,
  38. ..
  39. })
  40. )
  41. })
  42. .map(|(k, v)| (k.clone(), AExprType::from(v)))
  43. .collect();
  44. let mut seen_randoms: HashMap<String, usize> = HashMap::new();
  45. // Create a PrivScalarMap that will call the given closure for each
  46. // private Scalar (listed in the VarDict) in a supplied expression
  47. let mut var_map = PrivScalarMap {
  48. vars: &random_private_scalars,
  49. // The closure counts how many times each private random Scalar
  50. // in the VarDict appears in total
  51. closure: &mut |ident| {
  52. let id_str = ident.to_string();
  53. let val = seen_randoms.get(&id_str);
  54. let newval = match val {
  55. Some(n) => n + 1,
  56. None => 1,
  57. };
  58. seen_randoms.insert(id_str, newval);
  59. Ok(())
  60. },
  61. result: Ok(()),
  62. };
  63. // Call the PrivScalarMap for each leaf expression in the
  64. // StatementTree
  65. for e in st.leaves() {
  66. var_map.visit_expr(e);
  67. }
  68. // Return a HashSet of the ones that we saw exactly once
  69. seen_randoms
  70. .into_iter()
  71. .filter_map(|(k, v)| if v == 1 { Some(k) } else { None })
  72. .collect()
  73. }
  74. /// A representation of `a*x + b` where `a` is a constant `Scalar`, `b`
  75. /// is a public `Scalar` [arithmetic expression], and `x` is a private
  76. /// `Scalar` variable. `a` is optional, and defaults to `1`. `b` is
  77. /// optional, and defaults to `0`
  78. ///
  79. /// [arithmetic expression]: expr_type
  80. #[derive(Clone, Debug, PartialEq, Eq)]
  81. pub struct LinScalar {
  82. /// The coefficient `a`
  83. pub coeff: i128,
  84. /// The public `Scalar` expression `b`, if present
  85. pub pub_scalar_expr: Option<Expr>,
  86. /// The private `Scalar` `x`
  87. pub id: Ident,
  88. /// Whether `x` is a vector variable
  89. pub is_vec: bool,
  90. }
  91. impl LinScalar {
  92. /// Negate a [`LinScalar`]
  93. pub fn negate(self) -> Result<Self> {
  94. Ok(Self {
  95. coeff: self.coeff.checked_neg().ok_or(Error::new(
  96. proc_macro2::Span::call_site(),
  97. "i128 neg overflow",
  98. ))?,
  99. pub_scalar_expr: if let Some(expr) = self.pub_scalar_expr {
  100. let pexpr = paren_if_needed(expr);
  101. Some(parse_quote! { -#pexpr })
  102. } else {
  103. None
  104. },
  105. ..self
  106. })
  107. }
  108. /// Add a public `Scalar` expression to a [`LinScalar`]
  109. pub fn add_opt_pub_scalar_expr(self, opsexpr: Option<Expr>) -> Result<Self> {
  110. if let Some(psexpr) = opsexpr {
  111. Ok(Self {
  112. pub_scalar_expr: if let Some(expr) = self.pub_scalar_expr {
  113. let ppsexpr = paren_if_needed(psexpr);
  114. Some(parse_quote! { #expr + #ppsexpr })
  115. } else {
  116. Some(psexpr)
  117. },
  118. ..self
  119. })
  120. } else {
  121. Ok(self)
  122. }
  123. }
  124. /// Add a [`LinScalar`] to a [`LinScalar`].
  125. ///
  126. /// The private variables must match.
  127. pub fn add_linscalar(self, arg: Self) -> Result<Self> {
  128. if self.id != arg.id {
  129. return Err(Error::new(
  130. proc_macro2::Span::call_site(),
  131. "private variables in added LinScalars do not match",
  132. ));
  133. }
  134. Self {
  135. coeff: self.coeff.checked_add(arg.coeff).ok_or(Error::new(
  136. proc_macro2::Span::call_site(),
  137. "i128 add overflow",
  138. ))?,
  139. ..self
  140. }
  141. .add_opt_pub_scalar_expr(arg.pub_scalar_expr)
  142. }
  143. /// Multiply a [`LinScalar`] by a constant
  144. pub fn mul_const(self, arg: i128) -> Result<Self> {
  145. Ok(Self {
  146. coeff: self.coeff.checked_mul(arg).ok_or(Error::new(
  147. proc_macro2::Span::call_site(),
  148. "i128 mul overflow",
  149. ))?,
  150. pub_scalar_expr: if let Some(expr) = self.pub_scalar_expr {
  151. if arg == 1 {
  152. Some(expr)
  153. } else {
  154. let pexpr = paren_if_needed(expr);
  155. Some(parse_quote! { #pexpr * #arg })
  156. }
  157. } else {
  158. None
  159. },
  160. ..self
  161. })
  162. }
  163. /// Output a [`LinScalar`] as an [`Expr`]
  164. pub fn to_expr(&self) -> Expr {
  165. let coeff = self.coeff;
  166. let id = &self.id;
  167. // If there's a non-1 coefficient, multiply it by the id
  168. let coeff_var_term: Expr = if coeff == 1 {
  169. parse_quote! { #id }
  170. } else {
  171. parse_quote! { #coeff * #id }
  172. };
  173. // If there's a pub_scalar_expr, add it to the result
  174. if let Some(ref pse) = self.pub_scalar_expr {
  175. let ppse = paren_if_needed(pse.clone());
  176. parse_quote! { #coeff_var_term + #ppse }
  177. } else {
  178. coeff_var_term
  179. }
  180. }
  181. }
  182. /// A representation of `b*A` where `b` is a public `Scalar` [arithmetic
  183. /// expression] (default to `1`) and `A` is a computationally
  184. /// independent `Point`.
  185. ///
  186. /// [arithmetic expression]: expr_type
  187. #[derive(Clone, Debug, PartialEq, Eq)]
  188. pub struct CIndPoint {
  189. /// The public `Scalar` expression `b`
  190. pub coeff: Option<Expr>,
  191. /// The value of the coeff, if it's a constant
  192. pub coeff_val: Option<i128>,
  193. /// The public `Point` `A`
  194. pub id: Ident,
  195. }
  196. impl CIndPoint {
  197. /// Negate a [`CIndPoint`]
  198. pub fn negate(self) -> Result<Self> {
  199. Ok(Self {
  200. coeff: Some(if let Some(expr) = self.coeff {
  201. let pexpr = paren_if_needed(expr);
  202. parse_quote! { -#pexpr }
  203. } else {
  204. parse_quote! { -1 }
  205. }),
  206. coeff_val: if let Some(val) = self.coeff_val {
  207. val.checked_neg()
  208. } else {
  209. None
  210. },
  211. ..self
  212. })
  213. }
  214. /// Add a [`CIndPoint`] to a [`CIndPoint`]
  215. pub fn add_cind(self, arg: CIndPoint) -> Result<Self> {
  216. if self.id != arg.id {
  217. return Err(Error::new(
  218. proc_macro2::Span::call_site(),
  219. "public points in added CIndPoints do not match",
  220. ));
  221. }
  222. let lexpr = if let Some(expr) = self.coeff {
  223. expr
  224. } else {
  225. parse_quote! { 1 }
  226. };
  227. let rexpr = if let Some(expr) = arg.coeff {
  228. paren_if_needed(expr)
  229. } else {
  230. parse_quote! { 1 }
  231. };
  232. let coeff_val = if let (Some(lval), Some(rval)) = (self.coeff_val, arg.coeff_val) {
  233. lval.checked_add(rval)
  234. } else {
  235. None
  236. };
  237. Ok(Self {
  238. coeff: Some(parse_quote! { #lexpr + #rexpr }),
  239. coeff_val,
  240. ..self
  241. })
  242. }
  243. /// Multiply a public Scalar [`Expr`] by a [`CIndPoint`]. val is
  244. /// Some(v) if the Expr is the constant v.
  245. pub fn mul_pub_scalar_expr(self, expr: Expr, val: Option<i128>) -> Result<Self> {
  246. let coeff = match self.coeff {
  247. None => Some(expr),
  248. Some(selfexpr) => {
  249. let pleft = paren_if_needed(selfexpr);
  250. let pright = paren_if_needed(expr);
  251. Some(parse_quote! { #pleft * #pright })
  252. }
  253. };
  254. let coeff_val = match (self.coeff_val, val) {
  255. (Some(leftval), Some(rightval)) => leftval.checked_mul(rightval),
  256. _ => None,
  257. };
  258. Ok(Self {
  259. coeff,
  260. coeff_val,
  261. ..self
  262. })
  263. }
  264. }
  265. /// A representation of `(a*x + b)*A` where `a` is a constant `Scalar`
  266. /// (default to `1`), `b` is a public `Scalar` [arithmetic expression]
  267. /// (default to `0`), `x` is a private `Scalar` variable, and `A` is a
  268. /// computationally independent `Point`
  269. #[derive(Clone, Debug, PartialEq, Eq)]
  270. pub struct Term {
  271. /// The `Scalar` expression `a*x + b`
  272. pub coeff: LinScalar,
  273. /// The public `Point` `A`
  274. pub id: Ident,
  275. }
  276. impl Term {
  277. /// Negate a [`Term`]
  278. pub fn negate(self) -> Result<Self> {
  279. Ok(Self {
  280. coeff: self.coeff.negate()?,
  281. ..self
  282. })
  283. }
  284. /// Add a [`CIndPoint`] to a [`Term`]
  285. pub fn add_cind(self, arg: CIndPoint) -> Result<Self> {
  286. if self.id != arg.id {
  287. return Err(Error::new(
  288. proc_macro2::Span::call_site(),
  289. "public points in added CIndPoint and Term do not match",
  290. ));
  291. }
  292. Ok(Self {
  293. coeff: self.coeff.add_opt_pub_scalar_expr(arg.coeff)?,
  294. ..self
  295. })
  296. }
  297. /// Add a [`Term`] to a [`Term`]
  298. pub fn add_term(self, arg: Term) -> Result<Self> {
  299. if self.id != arg.id {
  300. return Err(Error::new(
  301. proc_macro2::Span::call_site(),
  302. "public points in added Terms do not match",
  303. ));
  304. }
  305. Ok(Self {
  306. coeff: self.coeff.add_linscalar(arg.coeff)?,
  307. ..self
  308. })
  309. }
  310. /// Multiply a [`Term`] by a constant
  311. pub fn mul_const(self, arg: i128) -> Result<Self> {
  312. Ok(Self {
  313. coeff: self.coeff.mul_const(arg)?,
  314. ..self
  315. })
  316. }
  317. }
  318. /// A representation of `(a*x+b)*A + (c*r+d)*B` where `a` and `c` are a
  319. /// constant non-zero `Scalar`s (default to `1`), `b`, and `d` are
  320. /// public `Scalar`s or constants or combinations of those (default to
  321. /// `0`), `x` is a private `Scalar`, `r` is a random private `Scalar`
  322. /// that appears nowhere else in the [`StatementTree`], and `A` and `B`
  323. /// are computationally independent public `Point`s.
  324. #[derive(Clone, Debug, PartialEq, Eq)]
  325. pub struct Pedersen {
  326. /// The term containing the variable being committed to (`x` above)
  327. pub var_term: Term,
  328. /// The term containing the random variable (`r` above)
  329. pub rand_term: Term,
  330. }
  331. impl Pedersen {
  332. /// Get the `Ident` for the committed private `Scalar` in a [`Pedersen`]
  333. pub fn var(&self) -> Ident {
  334. self.var_term.coeff.id.clone()
  335. }
  336. /// Negate a [`Pedersen`]
  337. pub fn negate(self) -> Result<Self> {
  338. Ok(Self {
  339. var_term: self.var_term.negate()?,
  340. rand_term: self.rand_term.negate()?,
  341. })
  342. }
  343. /// Add a [`CIndPoint`] to a [`Pedersen`]
  344. pub fn add_cind(self, arg: CIndPoint) -> Result<Self> {
  345. if self.var_term.id == arg.id {
  346. Ok(Self {
  347. var_term: self.var_term.add_cind(arg)?,
  348. ..self
  349. })
  350. } else if self.rand_term.id == arg.id {
  351. // This branch actually can't happen, since the private
  352. // random Scalar variable can only appear once in the
  353. // StatementTree.
  354. Ok(Self {
  355. rand_term: self.rand_term.add_cind(arg)?,
  356. ..self
  357. })
  358. } else {
  359. Err(Error::new(
  360. proc_macro2::Span::call_site(),
  361. "public points in added Pedersen and CIndPoint do not match",
  362. ))
  363. }
  364. }
  365. /// Add a [`Term`] to a [`Pedersen`]
  366. pub fn add_term(self, arg: Term) -> Result<Self> {
  367. if self.var_term.id == arg.id {
  368. Ok(Self {
  369. var_term: self.var_term.add_term(arg)?,
  370. ..self
  371. })
  372. } else if self.rand_term.id == arg.id {
  373. // This branch actually can't happen, since the private
  374. // random Scalar variable can only appear once in the
  375. // StatementTree.
  376. Ok(Self {
  377. rand_term: self.rand_term.add_term(arg)?,
  378. ..self
  379. })
  380. } else {
  381. Err(Error::new(
  382. proc_macro2::Span::call_site(),
  383. "public points in added Pedersen and CIndPoint do not match",
  384. ))
  385. }
  386. }
  387. /// Multiply a [`Pedersen`] by a constant
  388. pub fn mul_const(self, arg: i128) -> Result<Self> {
  389. Ok(Self {
  390. var_term: self.var_term.mul_const(arg)?,
  391. rand_term: self.rand_term.mul_const(arg)?,
  392. })
  393. }
  394. }
  395. /// Components of a Pedersen commitment
  396. #[derive(Clone, Debug, PartialEq, Eq)]
  397. pub enum PedersenExpr {
  398. PubScalarExpr(Expr),
  399. LinScalar(LinScalar),
  400. CIndPoint(CIndPoint),
  401. Term(Term),
  402. Pedersen(Pedersen),
  403. }
  404. /// A struct that implements [`AExprFold`] in service of
  405. /// [`recognize_pedersen`], [`recognize_linscalar`], and
  406. /// [`recognize_pubscalar`]
  407. struct RecognizeFold<'a> {
  408. /// The [`TaggedVarDict`] that maps variable names to their types
  409. vars: &'a TaggedVarDict,
  410. /// The HashSet of random variables that appear exactly once in the
  411. /// parent [`StatementTree`]
  412. randoms: &'a HashSet<String>,
  413. }
  414. impl<'a> AExprFold<PedersenExpr> for RecognizeFold<'a> {
  415. /// Called when an identifier found in the [`VarDict`] is
  416. /// encountered in the [`Expr`]
  417. fn ident(&mut self, id: &Ident, _restype: AExprType) -> Result<PedersenExpr> {
  418. let Some(vartype) = self.vars.get(&id.to_string()) else {
  419. return Err(Error::new(id.span(), "unknown identifier"));
  420. };
  421. match vartype {
  422. TaggedIdent::Scalar(TaggedScalar { is_pub: true, .. }) => {
  423. // A bare public Scalar is a simple PubScalarExpr
  424. Ok(PedersenExpr::PubScalarExpr(parse_quote! { #id }))
  425. }
  426. TaggedIdent::Scalar(TaggedScalar {
  427. is_pub: false,
  428. is_vec,
  429. ..
  430. }) => {
  431. // A bare private Scalar is a simple LinScalar
  432. Ok(PedersenExpr::LinScalar(LinScalar {
  433. coeff: 1i128,
  434. pub_scalar_expr: None,
  435. id: id.clone(),
  436. is_vec: *is_vec,
  437. }))
  438. }
  439. TaggedIdent::Point(TaggedPoint { is_cind: true, .. }) => {
  440. // A bare cind Point is a CIndPoint
  441. Ok(PedersenExpr::CIndPoint(CIndPoint {
  442. coeff: None,
  443. coeff_val: Some(1),
  444. id: id.clone(),
  445. }))
  446. }
  447. TaggedIdent::Point(TaggedPoint { is_cind: false, .. }) => {
  448. // Not a part of a valid Pedersen expression
  449. Err(Error::new(id.span(), "non-cind Point"))
  450. }
  451. }
  452. }
  453. /// Called when the arithmetic expression evaluates to a constant
  454. /// [`i128`] value.
  455. fn const_i128(&mut self, restype: AExprType) -> Result<PedersenExpr> {
  456. let AExprType::Scalar { val: Some(val), .. } = restype else {
  457. return Err(Error::new(
  458. proc_macro2::Span::call_site(),
  459. "BUG: it should not happen that const_i128 is called without a value",
  460. ));
  461. };
  462. Ok(PedersenExpr::PubScalarExpr(parse_quote! { #val }))
  463. }
  464. /// Called for unary negation
  465. fn neg(&mut self, arg: (AExprType, PedersenExpr), _restype: AExprType) -> Result<PedersenExpr> {
  466. match arg.1 {
  467. PedersenExpr::PubScalarExpr(expr) => {
  468. Ok(PedersenExpr::PubScalarExpr(parse_quote! { -#expr }))
  469. }
  470. PedersenExpr::LinScalar(linscalar) => Ok(PedersenExpr::LinScalar(linscalar.negate()?)),
  471. PedersenExpr::CIndPoint(cind) => Ok(PedersenExpr::CIndPoint(cind.negate()?)),
  472. PedersenExpr::Term(term) => Ok(PedersenExpr::Term(term.negate()?)),
  473. PedersenExpr::Pedersen(pedersen) => Ok(PedersenExpr::Pedersen(pedersen.negate()?)),
  474. }
  475. }
  476. /// Called for a parenthesized expression
  477. fn paren(
  478. &mut self,
  479. arg: (AExprType, PedersenExpr),
  480. _restype: AExprType,
  481. ) -> Result<PedersenExpr> {
  482. match arg.1 {
  483. PedersenExpr::PubScalarExpr(expr) => {
  484. Ok(PedersenExpr::PubScalarExpr(parse_quote! { (#expr) }))
  485. }
  486. _ => Ok(arg.1),
  487. }
  488. }
  489. /// Called when adding two `Scalar`s
  490. fn add_scalars(
  491. &mut self,
  492. larg: (AExprType, PedersenExpr),
  493. rarg: (AExprType, PedersenExpr),
  494. _restype: AExprType,
  495. ) -> Result<PedersenExpr> {
  496. match (larg.1, rarg.1) {
  497. // Adding two PubScalarExprs yields a PubScalarExpr
  498. (PedersenExpr::PubScalarExpr(lexpr), PedersenExpr::PubScalarExpr(rexpr)) => Ok(
  499. PedersenExpr::PubScalarExpr(parse_quote! { #lexpr + #rexpr }),
  500. ),
  501. // Adding a PubScalarExpr and a LinScalar yields a LinScalar
  502. (PedersenExpr::PubScalarExpr(psexpr), PedersenExpr::LinScalar(linscalar))
  503. | (PedersenExpr::LinScalar(linscalar), PedersenExpr::PubScalarExpr(psexpr)) => Ok(
  504. PedersenExpr::LinScalar(linscalar.add_opt_pub_scalar_expr(Some(psexpr))?),
  505. ),
  506. // Adding two LinScalars yields a LinScalar if they're for
  507. // the same private Scalar
  508. (PedersenExpr::LinScalar(llinscalar), PedersenExpr::LinScalar(rlinscalar)) => Ok(
  509. PedersenExpr::LinScalar(llinscalar.add_linscalar(rlinscalar)?),
  510. ),
  511. // Nothing else is valid
  512. _ => Err(Error::new(
  513. proc_macro2::Span::call_site(),
  514. "not a component of a Pedersen commitment",
  515. )),
  516. }
  517. }
  518. /// Called when adding two `Point`s
  519. fn add_points(
  520. &mut self,
  521. larg: (AExprType, PedersenExpr),
  522. rarg: (AExprType, PedersenExpr),
  523. _restype: AExprType,
  524. ) -> Result<PedersenExpr> {
  525. match (larg.1, rarg.1) {
  526. // Adding two CIndPoints yields a CIndPoint if they're for
  527. // the same public Point
  528. (PedersenExpr::CIndPoint(lcind), PedersenExpr::CIndPoint(rcind)) => {
  529. Ok(PedersenExpr::CIndPoint(lcind.add_cind(rcind)?))
  530. }
  531. // Adding a CIndPoint to a Term yields a Term if they're for
  532. // the same public Point
  533. (PedersenExpr::CIndPoint(cind), PedersenExpr::Term(term))
  534. | (PedersenExpr::Term(term), PedersenExpr::CIndPoint(cind)) => {
  535. Ok(PedersenExpr::Term(term.add_cind(cind)?))
  536. }
  537. // Adding a Term to a Term yields a Term if they're for the
  538. // same public Point and private Scalar, or a Pedersen if
  539. // they're different, but one is for a private random Scalar
  540. // that only appears once in the [`StatementTree`]
  541. (PedersenExpr::Term(lterm), PedersenExpr::Term(rterm)) => {
  542. if lterm.id == rterm.id {
  543. Ok(PedersenExpr::Term(lterm.add_term(rterm)?))
  544. } else if self.randoms.contains(&rterm.coeff.id.to_string()) {
  545. Ok(PedersenExpr::Pedersen(Pedersen {
  546. var_term: lterm,
  547. rand_term: rterm,
  548. }))
  549. } else if self.randoms.contains(&lterm.coeff.id.to_string()) {
  550. Ok(PedersenExpr::Pedersen(Pedersen {
  551. var_term: rterm,
  552. rand_term: lterm,
  553. }))
  554. } else {
  555. Err(Error::new(
  556. proc_macro2::Span::call_site(),
  557. "public points in added Terms do not form a Pedersen commitment",
  558. ))
  559. }
  560. }
  561. // Adding a CIndPoint to a Pedersen yields a Pedersen if one
  562. // of the two public Points in the Pedersen matches the one
  563. // in the CIndPoint
  564. (PedersenExpr::CIndPoint(cind), PedersenExpr::Pedersen(pedersen))
  565. | (PedersenExpr::Pedersen(pedersen), PedersenExpr::CIndPoint(cind)) => {
  566. Ok(PedersenExpr::Pedersen(pedersen.add_cind(cind)?))
  567. }
  568. // Adding a Term to a Pedersen yields a Pedersen if one of
  569. // the two public Points in the Pedersen matches the one
  570. // in the Term
  571. (PedersenExpr::Term(term), PedersenExpr::Pedersen(pedersen))
  572. | (PedersenExpr::Pedersen(pedersen), PedersenExpr::Term(term)) => {
  573. Ok(PedersenExpr::Pedersen(pedersen.add_term(term)?))
  574. }
  575. // Note that it's impossible to add a Pedersen to a
  576. // Pedersen, since the private random Scalar only appears
  577. // once in the StatementTree.
  578. // Nothing else is valid
  579. _ => Err(Error::new(
  580. proc_macro2::Span::call_site(),
  581. "not a component of a Pedersen commitment",
  582. )),
  583. }
  584. }
  585. /// Called when summing a vector of `Scalar`s
  586. fn sum_scalars(
  587. &mut self,
  588. _arg: (AExprType, PedersenExpr),
  589. _restype: AExprType,
  590. ) -> Result<PedersenExpr> {
  591. // Sums are never recognized as components of Pedersen
  592. // commitments
  593. Err(Error::new(
  594. proc_macro2::Span::call_site(),
  595. "not a component of a Pedersen commitment",
  596. ))
  597. }
  598. /// Called when summing a vector of `Point`s
  599. fn sum_points(
  600. &mut self,
  601. _arg: (AExprType, PedersenExpr),
  602. _restype: AExprType,
  603. ) -> Result<PedersenExpr> {
  604. // Sums are never recognized as components of Pedersen
  605. // commitments
  606. Err(Error::new(
  607. proc_macro2::Span::call_site(),
  608. "not a component of a Pedersen commitment",
  609. ))
  610. }
  611. /// Called when subtracting two `Scalar`s
  612. fn sub_scalars(
  613. &mut self,
  614. (largtype, larg): (AExprType, PedersenExpr),
  615. (rargtype, rarg): (AExprType, PedersenExpr),
  616. restype: AExprType,
  617. ) -> Result<PedersenExpr> {
  618. if let PedersenExpr::PubScalarExpr(ref lexpr) = larg {
  619. if let PedersenExpr::PubScalarExpr(ref rexpr) = rarg {
  620. // Subtracting two PubScalarExprs yields a PubScalarExpr
  621. return Ok(PedersenExpr::PubScalarExpr(
  622. parse_quote! { #lexpr - #rexpr },
  623. ));
  624. }
  625. }
  626. // Anything else gets the default treatment
  627. let negrarg = self.neg((rargtype, rarg), rargtype)?;
  628. self.add_scalars((largtype, larg), (rargtype, negrarg), restype)
  629. }
  630. /// Called when subtracting two `Point`s
  631. fn sub_points(
  632. &mut self,
  633. larg: (AExprType, PedersenExpr),
  634. rarg: (AExprType, PedersenExpr),
  635. restype: AExprType,
  636. ) -> Result<PedersenExpr> {
  637. let rargtype = rarg.0;
  638. let negrarg = self.neg(rarg, rargtype)?;
  639. self.add_points(larg, (rargtype, negrarg), restype)
  640. }
  641. /// Called when multiplying two `Scalar`s
  642. fn mul_scalars(
  643. &mut self,
  644. larg: (AExprType, PedersenExpr),
  645. rarg: (AExprType, PedersenExpr),
  646. _restype: AExprType,
  647. ) -> Result<PedersenExpr> {
  648. match (larg, rarg) {
  649. // Multiplying two PubScalarExprs yields a PubScalarExpr
  650. ((_, PedersenExpr::PubScalarExpr(lexpr)), (_, PedersenExpr::PubScalarExpr(rexpr))) => {
  651. Ok(PedersenExpr::PubScalarExpr(
  652. parse_quote! { #lexpr * #rexpr },
  653. ))
  654. }
  655. // Multiplying a PubScalarExpr by a LinScalar yields a
  656. // LinScalar if the PubScalarExpr is actually a constant
  657. // (indicated by the AExprType's val field containing
  658. // Some(val))
  659. (
  660. (
  661. AExprType::Scalar {
  662. val: Some(psval), ..
  663. },
  664. PedersenExpr::PubScalarExpr(_),
  665. ),
  666. (_, PedersenExpr::LinScalar(linscalar)),
  667. )
  668. | (
  669. (_, PedersenExpr::LinScalar(linscalar)),
  670. (
  671. AExprType::Scalar {
  672. val: Some(psval), ..
  673. },
  674. PedersenExpr::PubScalarExpr(_),
  675. ),
  676. ) => Ok(PedersenExpr::LinScalar(linscalar.mul_const(psval)?)),
  677. // Nothing else is valid
  678. _ => Err(Error::new(
  679. proc_macro2::Span::call_site(),
  680. "not a component of a Pedersen commitment",
  681. )),
  682. }
  683. }
  684. /// Called when multiplying a `Scalar` and a `Point` (the `Scalar`
  685. /// will always be passed as the first argument)
  686. fn mul_scalar_point(
  687. &mut self,
  688. sarg: (AExprType, PedersenExpr),
  689. parg: (AExprType, PedersenExpr),
  690. _restype: AExprType,
  691. ) -> Result<PedersenExpr> {
  692. match (sarg.0, sarg.1, parg.1) {
  693. // Multiplying a PubScalarExpr by a CIndPoint yields a
  694. // CIndPoint
  695. (
  696. AExprType::Scalar { val, .. },
  697. PedersenExpr::PubScalarExpr(pub_expr),
  698. PedersenExpr::CIndPoint(cind),
  699. ) => Ok(PedersenExpr::CIndPoint(
  700. cind.mul_pub_scalar_expr(pub_expr, val)?,
  701. )),
  702. // Multiplying a LinScalar by a CIndPoint yields a Term
  703. // if the coefficient in the CIndPoint is a constant
  704. (
  705. _,
  706. PedersenExpr::LinScalar(linscalar),
  707. PedersenExpr::CIndPoint(CIndPoint {
  708. coeff_val: Some(cval),
  709. id,
  710. ..
  711. }),
  712. ) => Ok(PedersenExpr::Term(Term {
  713. coeff: linscalar.mul_const(cval)?,
  714. id,
  715. })),
  716. // Multiplying a PubScalarExpr by a Term yields a Term if
  717. // the PubScalarExpr is a constant
  718. (
  719. AExprType::Scalar {
  720. val: Some(const_val),
  721. ..
  722. },
  723. PedersenExpr::PubScalarExpr(_),
  724. PedersenExpr::Term(term),
  725. ) => Ok(PedersenExpr::Term(term.mul_const(const_val)?)),
  726. // Multiplying a PubScalarExpr by a Pedersen yields a
  727. // Pedersen if the PubScalarExpr is a constant
  728. (
  729. AExprType::Scalar {
  730. val: Some(const_val),
  731. ..
  732. },
  733. PedersenExpr::PubScalarExpr(_),
  734. PedersenExpr::Pedersen(pedersen),
  735. ) => Ok(PedersenExpr::Pedersen(pedersen.mul_const(const_val)?)),
  736. // Nothing else is valid
  737. _ => Err(Error::new(
  738. proc_macro2::Span::call_site(),
  739. "not a component of a Pedersen commitment",
  740. )),
  741. }
  742. }
  743. }
  744. /// Parse the right-hand side of the = in an [`Expr`] to see if we
  745. /// recognize it as a Pedersen commitment
  746. pub fn recognize_pedersen(
  747. vars: &TaggedVarDict,
  748. randoms: &HashSet<String>,
  749. vardict: &VarDict,
  750. expr: &Expr,
  751. ) -> Option<Pedersen> {
  752. let mut fold = RecognizeFold { vars, randoms };
  753. let Ok((aetype, PedersenExpr::Pedersen(pedersen))) = fold.fold(vardict, expr) else {
  754. return None;
  755. };
  756. // It's not allowed for the overall expression to be a vector type,
  757. // but the randomizer variable be a non-vector
  758. if let Some(TaggedIdent::Scalar(TaggedScalar { is_vec: false, .. })) =
  759. vars.get(&pedersen.rand_term.id.to_string())
  760. {
  761. if matches!(aetype, AExprType::Point { is_vec: true, .. }) {
  762. return None;
  763. }
  764. }
  765. // It's not allowed for either the committed variable or the random
  766. // variable to have a 0 coefficient
  767. if pedersen.var_term.coeff.coeff == 0 || pedersen.rand_term.coeff.coeff == 0 {
  768. return None;
  769. }
  770. Some(pedersen)
  771. }
  772. /// Parse an [`Expr`] to see if we recognize it as a [`LinScalar`]
  773. pub fn recognize_linscalar(
  774. vars: &TaggedVarDict,
  775. vardict: &VarDict,
  776. expr: &Expr,
  777. ) -> Option<LinScalar> {
  778. let mut fold = RecognizeFold {
  779. vars,
  780. randoms: &HashSet::new(),
  781. };
  782. let Ok((_, PedersenExpr::LinScalar(linscalar))) = fold.fold(vardict, expr) else {
  783. return None;
  784. };
  785. // A 0 coefficient is not allowed
  786. if linscalar.coeff == 0 {
  787. return None;
  788. }
  789. Some(linscalar)
  790. }
  791. /// Parse an [`Expr`] to see if we recognize it as an expression that
  792. /// evaluates to a public `Scalar`.
  793. ///
  794. /// The returned [`bool`] is true if the expression evaluates to a
  795. /// vector. The [`i128`] is the value of the expression if it is a
  796. /// constant.
  797. pub fn recognize_pubscalar(
  798. vars: &TaggedVarDict,
  799. vardict: &VarDict,
  800. expr: &Expr,
  801. ) -> Option<(bool, Option<i128>)> {
  802. let mut fold = RecognizeFold {
  803. vars,
  804. randoms: &HashSet::new(),
  805. };
  806. let Ok((AExprType::Scalar { is_vec, val, .. }, PedersenExpr::PubScalarExpr(_))) =
  807. fold.fold(vardict, expr)
  808. else {
  809. return None;
  810. };
  811. Some((is_vec, val))
  812. }
  813. /// A representation of an assignment [`Expr`] assigning a [Pedersen
  814. /// expression](Pedersen) to a public `Point`.
  815. #[derive(Clone, Debug, PartialEq, Eq)]
  816. pub struct PedersenAssignment {
  817. /// The public `Point` being assigned to
  818. pub id: Ident,
  819. /// The Pedersen expression being assigned
  820. pub pedersen: Pedersen,
  821. }
  822. impl PedersenAssignment {
  823. /// Get the `Ident` for the committed private `Scalar` in a
  824. /// [`PedersenAssignment`]
  825. pub fn var(&self) -> Ident {
  826. self.pedersen.var()
  827. }
  828. }
  829. /// Parse an [`Expr`] to see if we recognize it as an assignment
  830. /// statement assigning a [Pedersen expression](Pedersen) to an
  831. /// [`struct@Ident`] for a public `Point`.
  832. pub fn recognize_pedersen_assignment(
  833. vars: &TaggedVarDict,
  834. randoms: &HashSet<String>,
  835. vardict: &VarDict,
  836. expr: &Expr,
  837. ) -> Option<PedersenAssignment> {
  838. let Expr::Assign(syn::ExprAssign { left, right, .. }) = expr else {
  839. return None;
  840. };
  841. let Expr::Path(syn::ExprPath { path, .. }) = left.as_ref() else {
  842. return None;
  843. };
  844. let id = path.get_ident()?;
  845. let pedersen = recognize_pedersen(vars, randoms, vardict, right)?;
  846. Some(PedersenAssignment {
  847. id: id.clone(),
  848. pedersen,
  849. })
  850. }
  851. /// Output code to convert a commitment given by a
  852. /// [`PedersenAssignment`] into one for a different [`LinScalar`] of the
  853. /// same variable.
  854. pub fn convert_commitment(
  855. output_commitment: &Ident,
  856. ped_assign: &PedersenAssignment,
  857. new_linscalar: &LinScalar,
  858. vardict: &VarDict,
  859. ) -> Result<TokenStream> {
  860. let orig_commitment = &ped_assign.id;
  861. let mut is_vec = matches!(
  862. vardict.get(&orig_commitment.to_string()),
  863. Some(AExprType::Point { is_vec: true, .. })
  864. );
  865. let mut needs_clone = is_vec;
  866. let ped_assign_linscalar = &ped_assign.pedersen.var_term.coeff;
  867. let generator = &ped_assign.pedersen.var_term.id;
  868. let generator_is_vec = matches!(
  869. vardict.get(&generator.to_string()),
  870. Some(AExprType::Point { is_vec: true, .. })
  871. );
  872. let mut generated_code = quote! { #orig_commitment };
  873. // Subtract the pub_scalar_expr in ped_assign_linscalar (if present)
  874. // times the generator
  875. if let Some(ref pse) = ped_assign_linscalar.pub_scalar_expr {
  876. let (ppse_type, ppse_tokens) = expr_type_tokens(vardict, &paren_if_needed(pse.clone()))?;
  877. let ppse_is_vec = matches!(ppse_type, AExprType::Scalar { is_vec: true, .. });
  878. generated_code = tokens_sub_maybe_vec(
  879. generated_code,
  880. is_vec,
  881. tokens_mul_maybe_vec(
  882. ppse_tokens,
  883. ppse_is_vec,
  884. quote! { #generator },
  885. generator_is_vec,
  886. ),
  887. ppse_is_vec | generator_is_vec,
  888. );
  889. is_vec |= ppse_is_vec | generator_is_vec;
  890. needs_clone = false;
  891. }
  892. // Divide by the coeff in ped_assign_linscalar, if present (noting
  893. // it also cannot be 0, so will have an inverse)
  894. if ped_assign_linscalar.coeff != 1 {
  895. let coeff_tokens = const_i128_tokens(ped_assign_linscalar.coeff);
  896. generated_code = tokens_mul_maybe_vec(
  897. quote! { <Scalar as Field>::invert(&#coeff_tokens).unwrap() },
  898. false,
  899. generated_code,
  900. is_vec,
  901. );
  902. needs_clone = false;
  903. }
  904. // Now multiply by the coeff in new_linscalar, if present
  905. if new_linscalar.coeff != 1 {
  906. let coeff_tokens = const_i128_tokens(new_linscalar.coeff);
  907. generated_code = tokens_mul_maybe_vec(coeff_tokens, false, generated_code, is_vec);
  908. needs_clone = false;
  909. }
  910. // And add the pub_scalar_expr in new_linscalar (if present) times
  911. // the generator
  912. if let Some(ref pse) = new_linscalar.pub_scalar_expr {
  913. let (ppse_type, ppse_tokens) = expr_type_tokens(vardict, &paren_if_needed(pse.clone()))?;
  914. let ppse_is_vec = matches!(ppse_type, AExprType::Scalar { is_vec: true, .. });
  915. generated_code = tokens_add_maybe_vec(
  916. generated_code,
  917. is_vec,
  918. tokens_mul_maybe_vec(
  919. ppse_tokens,
  920. ppse_is_vec,
  921. quote! { #generator },
  922. generator_is_vec,
  923. ),
  924. ppse_is_vec | generator_is_vec,
  925. );
  926. needs_clone = false;
  927. }
  928. if needs_clone {
  929. generated_code = quote! { #generated_code.clone() };
  930. }
  931. Ok(quote! { let #output_commitment = #generated_code; })
  932. }
  933. /// Output code to convert the randomness given by a
  934. /// [`PedersenAssignment`] into that resulting from the conversion in
  935. /// [`convert_commitment`].
  936. pub fn convert_randomness(
  937. output_randomness: &Ident,
  938. ped_assign: &PedersenAssignment,
  939. new_linscalar: &LinScalar,
  940. vardict: &VarDict,
  941. ) -> Result<TokenStream> {
  942. let ped_assign_linscalar = &ped_assign.pedersen.var_term.coeff;
  943. // Start with the LinScalar in ped_assign.pedersen.rand_term
  944. let (coeff_type, mut generated_code) = expr_type_tokens(
  945. vardict,
  946. &paren_if_needed(ped_assign.pedersen.rand_term.coeff.to_expr()),
  947. )?;
  948. let is_vec = matches!(coeff_type, AExprType::Scalar { is_vec: true, .. });
  949. let mut needs_clone = is_vec;
  950. // Divide by the coeff in ped_assign_linscalar, if present (noting
  951. // it also cannot be 0, so will have an inverse)
  952. if ped_assign_linscalar.coeff != 1 {
  953. let coeff_tokens = const_i128_tokens(ped_assign_linscalar.coeff);
  954. generated_code = tokens_mul_maybe_vec(
  955. quote! { <Scalar as Field>::invert(&#coeff_tokens).unwrap() },
  956. false,
  957. generated_code,
  958. is_vec,
  959. );
  960. needs_clone = false;
  961. }
  962. // Now multiply by the coeff in new_linscalar, if present
  963. if new_linscalar.coeff != 1 {
  964. let coeff_tokens = const_i128_tokens(new_linscalar.coeff);
  965. generated_code = tokens_mul_maybe_vec(coeff_tokens, false, generated_code, is_vec);
  966. needs_clone = false;
  967. }
  968. if needs_clone {
  969. generated_code = quote! { #generated_code.clone() };
  970. }
  971. Ok(quote! { let #output_randomness = #generated_code; })
  972. }
  973. #[cfg(test)]
  974. mod test {
  975. use super::*;
  976. use quote::format_ident;
  977. use syn::{parse_quote, Expr};
  978. fn unique_random_scalars_tester(vars: (&[&str], &[&str]), e: Expr, expected: &[&str]) {
  979. let taggedvardict = taggedvardict_from_strs(vars);
  980. let st = StatementTree::parse(&e).unwrap();
  981. let expected_out = expected.iter().map(|s| s.to_string()).collect();
  982. let output = unique_random_scalars(&taggedvardict, &st);
  983. assert_eq!(output, expected_out);
  984. }
  985. #[test]
  986. fn unique_random_scalars_test() {
  987. let vars = (
  988. ["x", "y", "z", "rand r", "rand s", "rand t"].as_slice(),
  989. ["C", "cind A", "cind B"].as_slice(),
  990. );
  991. unique_random_scalars_tester(
  992. vars,
  993. parse_quote! {
  994. C = x*A + r*B
  995. },
  996. ["r"].as_slice(),
  997. );
  998. unique_random_scalars_tester(
  999. vars,
  1000. parse_quote! {
  1001. AND (
  1002. C = x*A + r*B,
  1003. D = y*A + s*B,
  1004. )
  1005. },
  1006. ["r", "s"].as_slice(),
  1007. );
  1008. unique_random_scalars_tester(
  1009. vars,
  1010. parse_quote! {
  1011. AND (
  1012. C = x*A + r*B,
  1013. OR (
  1014. D = y*A + s*B,
  1015. E = y*A + t*B,
  1016. ),
  1017. E = z*A + r*B,
  1018. )
  1019. },
  1020. ["s", "t"].as_slice(),
  1021. );
  1022. }
  1023. fn fold_tester(
  1024. vars: (&[&str], &[&str]),
  1025. randoms: &[&str],
  1026. e: Expr,
  1027. expected_out: Option<PedersenExpr>,
  1028. ) {
  1029. let taggedvardict = taggedvardict_from_strs(vars);
  1030. let vardict = taggedvardict_to_vardict(&taggedvardict);
  1031. let mut randoms_hash = HashSet::new();
  1032. for r in randoms {
  1033. randoms_hash.insert(r.to_string());
  1034. }
  1035. let mut fold = RecognizeFold {
  1036. vars: &taggedvardict,
  1037. randoms: &randoms_hash,
  1038. };
  1039. let output = if let Ok((_, pe)) = fold.fold(&vardict, &e) {
  1040. Some(pe)
  1041. } else {
  1042. None
  1043. };
  1044. assert_eq!(output, expected_out);
  1045. }
  1046. #[test]
  1047. fn fold_test() {
  1048. let vars = (
  1049. [
  1050. "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
  1051. ]
  1052. .as_slice(),
  1053. ["C", "cind A", "cind B"].as_slice(),
  1054. );
  1055. let randoms = ["r", "s", "t"].as_slice();
  1056. fold_tester(
  1057. vars,
  1058. randoms,
  1059. parse_quote! {
  1060. 1
  1061. },
  1062. Some(PedersenExpr::PubScalarExpr(parse_quote! { 1i128 })),
  1063. );
  1064. fold_tester(
  1065. vars,
  1066. randoms,
  1067. parse_quote! {
  1068. 1 + 2
  1069. },
  1070. Some(PedersenExpr::PubScalarExpr(parse_quote! { 3i128 })),
  1071. );
  1072. fold_tester(
  1073. vars,
  1074. randoms,
  1075. parse_quote! {
  1076. 1 - 2
  1077. },
  1078. Some(PedersenExpr::PubScalarExpr(parse_quote! { -1i128 })),
  1079. );
  1080. fold_tester(
  1081. vars,
  1082. randoms,
  1083. parse_quote! {
  1084. a
  1085. },
  1086. Some(PedersenExpr::PubScalarExpr(parse_quote! { a })),
  1087. );
  1088. fold_tester(
  1089. vars,
  1090. randoms,
  1091. parse_quote! {
  1092. a + 1
  1093. },
  1094. Some(PedersenExpr::PubScalarExpr(parse_quote! { a + 1i128 })),
  1095. );
  1096. fold_tester(
  1097. vars,
  1098. randoms,
  1099. parse_quote! {
  1100. a + b + 1
  1101. },
  1102. Some(PedersenExpr::PubScalarExpr(parse_quote! { a + b + 1i128 })),
  1103. );
  1104. fold_tester(
  1105. vars,
  1106. randoms,
  1107. parse_quote! {
  1108. a + 2*b + 1
  1109. },
  1110. Some(PedersenExpr::PubScalarExpr(
  1111. parse_quote! { a + 2i128 * b + 1i128 },
  1112. )),
  1113. );
  1114. fold_tester(
  1115. vars,
  1116. randoms,
  1117. parse_quote! {
  1118. a - 2*b + 1
  1119. },
  1120. Some(PedersenExpr::PubScalarExpr(
  1121. parse_quote! { a - 2i128 * b + 1i128 },
  1122. )),
  1123. );
  1124. fold_tester(
  1125. vars,
  1126. randoms,
  1127. parse_quote! {
  1128. a - (2*b + 1)
  1129. },
  1130. Some(PedersenExpr::PubScalarExpr(
  1131. parse_quote! { a - (2i128 * b + 1i128) },
  1132. )),
  1133. );
  1134. fold_tester(
  1135. vars,
  1136. randoms,
  1137. parse_quote! {
  1138. x
  1139. },
  1140. Some(PedersenExpr::LinScalar(LinScalar {
  1141. coeff: 1,
  1142. pub_scalar_expr: None,
  1143. id: parse_quote! {x},
  1144. is_vec: false,
  1145. })),
  1146. );
  1147. fold_tester(
  1148. vars,
  1149. randoms,
  1150. parse_quote! {
  1151. x + 2
  1152. },
  1153. Some(PedersenExpr::LinScalar(LinScalar {
  1154. coeff: 1,
  1155. pub_scalar_expr: Some(parse_quote! { 2i128 }),
  1156. id: parse_quote! {x},
  1157. is_vec: false,
  1158. })),
  1159. );
  1160. fold_tester(
  1161. vars,
  1162. randoms,
  1163. parse_quote! {
  1164. 3*x + 2
  1165. },
  1166. Some(PedersenExpr::LinScalar(LinScalar {
  1167. coeff: 3,
  1168. pub_scalar_expr: Some(parse_quote! { 2i128 }),
  1169. id: parse_quote! {x},
  1170. is_vec: false,
  1171. })),
  1172. );
  1173. fold_tester(
  1174. vars,
  1175. randoms,
  1176. parse_quote! {
  1177. 3*(x + 2)
  1178. },
  1179. Some(PedersenExpr::LinScalar(LinScalar {
  1180. coeff: 3,
  1181. pub_scalar_expr: Some(parse_quote! { 2i128 * 3i128 }),
  1182. id: parse_quote! {x},
  1183. is_vec: false,
  1184. })),
  1185. );
  1186. fold_tester(
  1187. vars,
  1188. randoms,
  1189. parse_quote! {
  1190. 3*(x - 2)
  1191. },
  1192. Some(PedersenExpr::LinScalar(LinScalar {
  1193. coeff: 3,
  1194. pub_scalar_expr: Some(parse_quote! { (-2i128) * 3i128 }),
  1195. id: parse_quote! {x},
  1196. is_vec: false,
  1197. })),
  1198. );
  1199. fold_tester(
  1200. vars,
  1201. randoms,
  1202. parse_quote! {
  1203. 3*(x + a)
  1204. },
  1205. Some(PedersenExpr::LinScalar(LinScalar {
  1206. coeff: 3,
  1207. pub_scalar_expr: Some(parse_quote! { a * 3i128 }),
  1208. id: parse_quote! {x},
  1209. is_vec: false,
  1210. })),
  1211. );
  1212. // Adding two private Scalars
  1213. fold_tester(
  1214. vars,
  1215. randoms,
  1216. parse_quote! {
  1217. 3*(x + y)
  1218. },
  1219. None,
  1220. );
  1221. fold_tester(
  1222. vars,
  1223. randoms,
  1224. parse_quote! {
  1225. a * A
  1226. },
  1227. Some(PedersenExpr::CIndPoint(CIndPoint {
  1228. coeff: Some(parse_quote! { a }),
  1229. coeff_val: None,
  1230. id: parse_quote! {A},
  1231. })),
  1232. );
  1233. fold_tester(
  1234. vars,
  1235. randoms,
  1236. parse_quote! {
  1237. a * A * b
  1238. },
  1239. Some(PedersenExpr::CIndPoint(CIndPoint {
  1240. coeff: Some(parse_quote! { a * b }),
  1241. coeff_val: None,
  1242. id: parse_quote! {A},
  1243. })),
  1244. );
  1245. fold_tester(
  1246. vars,
  1247. randoms,
  1248. parse_quote! {
  1249. A * b * (c+1)
  1250. },
  1251. Some(PedersenExpr::CIndPoint(CIndPoint {
  1252. coeff: Some(parse_quote! { b * (c + 1i128) }),
  1253. coeff_val: None,
  1254. id: parse_quote! {A},
  1255. })),
  1256. );
  1257. fold_tester(
  1258. vars,
  1259. randoms,
  1260. parse_quote! {
  1261. 3*(x + a) * A
  1262. },
  1263. Some(PedersenExpr::Term(Term {
  1264. coeff: LinScalar {
  1265. coeff: 3,
  1266. pub_scalar_expr: Some(parse_quote! { a * 3i128 }),
  1267. id: parse_quote! {x},
  1268. is_vec: false,
  1269. },
  1270. id: parse_quote! {A},
  1271. })),
  1272. );
  1273. fold_tester(
  1274. vars,
  1275. randoms,
  1276. parse_quote! {
  1277. 3*(x + a) * A + A * b
  1278. },
  1279. Some(PedersenExpr::Term(Term {
  1280. coeff: LinScalar {
  1281. coeff: 3,
  1282. pub_scalar_expr: Some(parse_quote! { a * 3i128 + b }),
  1283. id: parse_quote! {x},
  1284. is_vec: false,
  1285. },
  1286. id: parse_quote! {A},
  1287. })),
  1288. );
  1289. fold_tester(
  1290. vars,
  1291. randoms,
  1292. parse_quote! {
  1293. 3*(x + a) * A + A * b * (c + 1)
  1294. },
  1295. Some(PedersenExpr::Term(Term {
  1296. coeff: LinScalar {
  1297. coeff: 3,
  1298. pub_scalar_expr: Some(parse_quote! { a * 3i128 + (b*(c+1i128)) }),
  1299. id: parse_quote! {x},
  1300. is_vec: false,
  1301. },
  1302. id: parse_quote! {A},
  1303. })),
  1304. );
  1305. fold_tester(
  1306. vars,
  1307. randoms,
  1308. parse_quote! {
  1309. 3*(x + a) * A + A * b * (c + 1) + r * B
  1310. },
  1311. Some(PedersenExpr::Pedersen(Pedersen {
  1312. var_term: Term {
  1313. coeff: LinScalar {
  1314. coeff: 3,
  1315. pub_scalar_expr: Some(parse_quote! { a * 3i128 + (b * (c + 1i128)) }),
  1316. id: parse_quote! {x},
  1317. is_vec: false,
  1318. },
  1319. id: parse_quote! {A},
  1320. },
  1321. rand_term: Term {
  1322. coeff: LinScalar {
  1323. coeff: 1,
  1324. pub_scalar_expr: None,
  1325. id: parse_quote! {r},
  1326. is_vec: false,
  1327. },
  1328. id: parse_quote! {B},
  1329. },
  1330. })),
  1331. );
  1332. }
  1333. fn recognize_tester(
  1334. vars: (&[&str], &[&str]),
  1335. randoms: &[&str],
  1336. e: Expr,
  1337. expected_out: Option<Pedersen>,
  1338. ) {
  1339. let taggedvardict = taggedvardict_from_strs(vars);
  1340. let vardict = taggedvardict_to_vardict(&taggedvardict);
  1341. let mut randoms_hash = HashSet::new();
  1342. for r in randoms {
  1343. randoms_hash.insert(r.to_string());
  1344. }
  1345. let output = recognize_pedersen(&taggedvardict, &randoms_hash, &vardict, &e);
  1346. assert_eq!(output, expected_out);
  1347. }
  1348. #[test]
  1349. fn recognize_pedersen_test() {
  1350. let vars = (
  1351. [
  1352. "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
  1353. ]
  1354. .as_slice(),
  1355. ["C", "cind A", "cind B"].as_slice(),
  1356. );
  1357. let randoms = ["r", "s", "t"].as_slice();
  1358. recognize_tester(
  1359. vars,
  1360. randoms,
  1361. parse_quote! {
  1362. 3*(x + a) * A + A * b * (c + 1) + r * B
  1363. },
  1364. Some(Pedersen {
  1365. var_term: Term {
  1366. coeff: LinScalar {
  1367. coeff: 3,
  1368. pub_scalar_expr: Some(parse_quote! { a * 3i128 + (b * (c + 1i128)) }),
  1369. id: parse_quote! {x},
  1370. is_vec: false,
  1371. },
  1372. id: parse_quote! {A},
  1373. },
  1374. rand_term: Term {
  1375. coeff: LinScalar {
  1376. coeff: 1,
  1377. pub_scalar_expr: None,
  1378. id: parse_quote! {r},
  1379. is_vec: false,
  1380. },
  1381. id: parse_quote! {B},
  1382. },
  1383. }),
  1384. );
  1385. recognize_tester(
  1386. vars,
  1387. randoms,
  1388. parse_quote! {
  1389. 3 * (2*x + a*b) * A + B * (3 * r - 7)
  1390. },
  1391. Some(Pedersen {
  1392. var_term: Term {
  1393. coeff: LinScalar {
  1394. coeff: 6,
  1395. pub_scalar_expr: Some(parse_quote! { (a * b) * 3i128 }),
  1396. id: parse_quote! {x},
  1397. is_vec: false,
  1398. },
  1399. id: parse_quote! {A},
  1400. },
  1401. rand_term: Term {
  1402. coeff: LinScalar {
  1403. coeff: 3,
  1404. pub_scalar_expr: Some(parse_quote! { -7i128 }),
  1405. id: parse_quote! {r},
  1406. is_vec: false,
  1407. },
  1408. id: parse_quote! {B},
  1409. },
  1410. }),
  1411. );
  1412. recognize_tester(
  1413. vars,
  1414. randoms,
  1415. parse_quote! {
  1416. (3 * (2*x + a*b) * A + B * (3 * r - 7))* (7-2)
  1417. },
  1418. Some(Pedersen {
  1419. var_term: Term {
  1420. coeff: LinScalar {
  1421. coeff: 30,
  1422. pub_scalar_expr: Some(parse_quote! { ((a * b) * 3i128) * 5i128 }),
  1423. id: parse_quote! {x},
  1424. is_vec: false,
  1425. },
  1426. id: parse_quote! {A},
  1427. },
  1428. rand_term: Term {
  1429. coeff: LinScalar {
  1430. coeff: 15,
  1431. pub_scalar_expr: Some(parse_quote! { (-7i128) * 5i128 }),
  1432. id: parse_quote! {r},
  1433. is_vec: false,
  1434. },
  1435. id: parse_quote! {B},
  1436. },
  1437. }),
  1438. );
  1439. }
  1440. fn recognize_linscalar_tester(
  1441. vars: (&[&str], &[&str]),
  1442. e: Expr,
  1443. expected_out: Option<LinScalar>,
  1444. expected_expr: Option<Expr>,
  1445. ) {
  1446. let taggedvardict = taggedvardict_from_strs(vars);
  1447. let vardict = taggedvardict_to_vardict(&taggedvardict);
  1448. let output = recognize_linscalar(&taggedvardict, &vardict, &e);
  1449. assert_eq!(output, expected_out);
  1450. if output.is_some() {
  1451. assert_eq!(output.unwrap().to_expr(), expected_expr.unwrap());
  1452. }
  1453. }
  1454. #[test]
  1455. fn recognize_linscalar_test() {
  1456. let vars = (
  1457. [
  1458. "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
  1459. ]
  1460. .as_slice(),
  1461. ["C", "cind A", "cind B"].as_slice(),
  1462. );
  1463. recognize_linscalar_tester(
  1464. vars,
  1465. parse_quote! {
  1466. x
  1467. },
  1468. Some(LinScalar {
  1469. coeff: 1,
  1470. pub_scalar_expr: None,
  1471. id: parse_quote! {x},
  1472. is_vec: false,
  1473. }),
  1474. Some(parse_quote! { x }),
  1475. );
  1476. recognize_linscalar_tester(
  1477. vars,
  1478. parse_quote! {
  1479. x * 7 - x * 3
  1480. },
  1481. Some(LinScalar {
  1482. coeff: 4,
  1483. pub_scalar_expr: None,
  1484. id: parse_quote! {x},
  1485. is_vec: false,
  1486. }),
  1487. Some(parse_quote! { 4i128 * x }),
  1488. );
  1489. recognize_linscalar_tester(
  1490. vars,
  1491. parse_quote! {
  1492. x - (a + 12)
  1493. },
  1494. Some(LinScalar {
  1495. coeff: 1,
  1496. pub_scalar_expr: Some(parse_quote! {-(a + 12i128)}),
  1497. id: parse_quote! {x},
  1498. is_vec: false,
  1499. }),
  1500. Some(parse_quote! { x + (-(a + 12i128))}),
  1501. );
  1502. recognize_linscalar_tester(
  1503. vars,
  1504. parse_quote! {
  1505. 3*(x + a + 1)
  1506. },
  1507. Some(LinScalar {
  1508. coeff: 3,
  1509. pub_scalar_expr: Some(parse_quote! { ( a + 1i128 ) * 3i128 }),
  1510. id: parse_quote! {x},
  1511. is_vec: false,
  1512. }),
  1513. Some(parse_quote! { 3i128 * x + ((a + 1i128) * 3i128) }),
  1514. );
  1515. recognize_linscalar_tester(
  1516. vars,
  1517. parse_quote! {
  1518. 3*(x + a + 1) - x*4
  1519. },
  1520. Some(LinScalar {
  1521. coeff: -1,
  1522. pub_scalar_expr: Some(parse_quote! { ( a + 1i128 ) * 3i128 }),
  1523. id: parse_quote! {x},
  1524. is_vec: false,
  1525. }),
  1526. Some(parse_quote! { -1i128 * x + ((a + 1i128) * 3i128) }),
  1527. );
  1528. recognize_linscalar_tester(
  1529. vars,
  1530. parse_quote! {
  1531. 3*(x + a + 1) - x*4 + x
  1532. },
  1533. None,
  1534. None,
  1535. );
  1536. }
  1537. fn recognize_pubscalar_tester(
  1538. vars: (&[&str], &[&str]),
  1539. e: Expr,
  1540. expected_out: Option<(bool, Option<i128>)>,
  1541. ) {
  1542. let taggedvardict = taggedvardict_from_strs(vars);
  1543. let vardict = taggedvardict_to_vardict(&taggedvardict);
  1544. let output = recognize_pubscalar(&taggedvardict, &vardict, &e);
  1545. assert_eq!(output, expected_out);
  1546. }
  1547. #[test]
  1548. fn recognize_pubscalar_test() {
  1549. let vars = (
  1550. [
  1551. "x",
  1552. "y",
  1553. "z",
  1554. "pub a",
  1555. "pub vec b",
  1556. "pub c",
  1557. "rand r",
  1558. "rand s",
  1559. "rand t",
  1560. ]
  1561. .as_slice(),
  1562. ["C", "cind A", "cind B"].as_slice(),
  1563. );
  1564. recognize_pubscalar_tester(
  1565. vars,
  1566. parse_quote! {
  1567. 3*(x + a + 1)
  1568. },
  1569. None,
  1570. );
  1571. recognize_pubscalar_tester(
  1572. vars,
  1573. parse_quote! {
  1574. 3
  1575. },
  1576. Some((false, Some(3))),
  1577. );
  1578. recognize_pubscalar_tester(
  1579. vars,
  1580. parse_quote! {
  1581. a
  1582. },
  1583. Some((false, None)),
  1584. );
  1585. recognize_pubscalar_tester(
  1586. vars,
  1587. parse_quote! {
  1588. 3*(a + 1)
  1589. },
  1590. Some((false, None)),
  1591. );
  1592. recognize_pubscalar_tester(
  1593. vars,
  1594. parse_quote! {
  1595. 3*(a + b)
  1596. },
  1597. Some((true, None)),
  1598. );
  1599. }
  1600. fn convert_commitment_randomness_tester(
  1601. vars: (&[&str], &[&str]),
  1602. randoms: &[&str],
  1603. ped_assign_expr: Expr,
  1604. lin_scalar_expr: Expr,
  1605. expect_commitment: TokenStream,
  1606. expect_randomness: TokenStream,
  1607. ) {
  1608. let taggedvardict = taggedvardict_from_strs(vars);
  1609. let vardict = taggedvardict_to_vardict(&taggedvardict);
  1610. let mut randoms_hash = HashSet::new();
  1611. for r in randoms {
  1612. randoms_hash.insert(r.to_string());
  1613. }
  1614. let output_commitment = format_ident! { "out" };
  1615. let output_randomness = format_ident! { "out_rand" };
  1616. let ped_assign = recognize_pedersen_assignment(
  1617. &taggedvardict,
  1618. &randoms_hash,
  1619. &vardict,
  1620. &ped_assign_expr,
  1621. )
  1622. .unwrap();
  1623. let lin_scalar = recognize_linscalar(&taggedvardict, &vardict, &lin_scalar_expr).unwrap();
  1624. assert_eq!(
  1625. convert_commitment(&output_commitment, &ped_assign, &lin_scalar, &vardict)
  1626. .unwrap()
  1627. .to_string(),
  1628. expect_commitment.to_string()
  1629. );
  1630. assert_eq!(
  1631. convert_randomness(&output_randomness, &ped_assign, &lin_scalar, &vardict)
  1632. .unwrap()
  1633. .to_string(),
  1634. expect_randomness.to_string()
  1635. );
  1636. }
  1637. #[test]
  1638. fn convert_commitment_randomness_test() {
  1639. let vars = (
  1640. [
  1641. "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
  1642. ]
  1643. .as_slice(),
  1644. ["C", "cind A", "cind B"].as_slice(),
  1645. );
  1646. let randoms = ["r", "s", "t"].as_slice();
  1647. convert_commitment_randomness_tester(
  1648. vars,
  1649. randoms,
  1650. parse_quote! { C = x*A + r*B },
  1651. parse_quote! { x },
  1652. quote! { let out = C; },
  1653. quote! { let out_rand = r; },
  1654. );
  1655. convert_commitment_randomness_tester(
  1656. vars,
  1657. randoms,
  1658. parse_quote! { C = x*A + r*B },
  1659. parse_quote! { 2 * x },
  1660. quote! { let out = Scalar::from_u128(2u128) * C; },
  1661. quote! { let out_rand = Scalar::from_u128(2u128) * r; },
  1662. );
  1663. convert_commitment_randomness_tester(
  1664. vars,
  1665. randoms,
  1666. parse_quote! { C = x*A + r*B },
  1667. parse_quote! { 2 * x + 12 },
  1668. quote! { let out = (Scalar::from_u128(2u128) * C) +
  1669. (Scalar::from_u128(12u128) * A); },
  1670. quote! { let out_rand = Scalar::from_u128(2u128) * r; },
  1671. );
  1672. convert_commitment_randomness_tester(
  1673. vars,
  1674. randoms,
  1675. parse_quote! { C = x*A + r*B },
  1676. parse_quote! { 2 * x + 12 + a },
  1677. quote! { let out = (Scalar::from_u128(2u128) * C) +
  1678. ((Scalar::from_u128(12u128) + a) * A); },
  1679. quote! { let out_rand = Scalar::from_u128(2u128) * r; },
  1680. );
  1681. convert_commitment_randomness_tester(
  1682. vars,
  1683. randoms,
  1684. parse_quote! { C = 3*x*A + r*B },
  1685. parse_quote! { 2 * x + 12 + a },
  1686. quote! { let out = (Scalar::from_u128(2u128) *
  1687. (<Scalar as Field>::invert(&Scalar::from_u128(3u128)).unwrap() * C)) +
  1688. ((Scalar::from_u128(12u128) + a) * A); },
  1689. quote! { let out_rand = Scalar::from_u128(2u128) *
  1690. (<Scalar as Field>::invert(&Scalar::from_u128(3u128)).unwrap() * r); },
  1691. );
  1692. convert_commitment_randomness_tester(
  1693. vars,
  1694. randoms,
  1695. parse_quote! { C = -3*x*A + r*B },
  1696. parse_quote! { 2 * x + 12 + a },
  1697. quote! { let out = (Scalar::from_u128(2u128) *
  1698. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() * C)) +
  1699. ((Scalar::from_u128(12u128) + a) * A); },
  1700. quote! { let out_rand = Scalar::from_u128(2u128) *
  1701. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() * r); },
  1702. );
  1703. convert_commitment_randomness_tester(
  1704. vars,
  1705. randoms,
  1706. parse_quote! { C = (-3*x+4+b)*A + r*B },
  1707. parse_quote! { 2 * x + 12 + a },
  1708. quote! { let out = (Scalar::from_u128(2u128) *
  1709. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
  1710. (C - ((Scalar::from_u128(4u128) + b) * A)))) +
  1711. ((Scalar::from_u128(12u128) + a) * A); },
  1712. quote! { let out_rand = Scalar::from_u128(2u128) *
  1713. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() * r); },
  1714. );
  1715. convert_commitment_randomness_tester(
  1716. vars,
  1717. randoms,
  1718. parse_quote! { C = (-3*x+4+b)*A + 2*r*B },
  1719. parse_quote! { 2 * x + 12 + a },
  1720. quote! { let out = (Scalar::from_u128(2u128) *
  1721. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
  1722. (C - ((Scalar::from_u128(4u128) + b) * A)))) +
  1723. ((Scalar::from_u128(12u128) + a) * A); },
  1724. quote! { let out_rand = Scalar::from_u128(2u128) *
  1725. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
  1726. (r * Scalar::from_u128(2u128))); },
  1727. );
  1728. convert_commitment_randomness_tester(
  1729. vars,
  1730. randoms,
  1731. parse_quote! { C = (-3*x+4+b)*A + (2*r+c-3)*B },
  1732. parse_quote! { 2 * x + 12 + a },
  1733. quote! { let out = (Scalar::from_u128(2u128) *
  1734. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
  1735. (C - ((Scalar::from_u128(4u128) + b) * A)))) +
  1736. ((Scalar::from_u128(12u128) + a) * A); },
  1737. quote! { let out_rand = Scalar::from_u128(2u128) *
  1738. (<Scalar as Field>::invert(&Scalar::from_u128(3u128).neg()).unwrap() *
  1739. ((r * Scalar::from_u128(2u128)) +
  1740. (c + (Scalar::from_u128(3u128).neg())))); },
  1741. );
  1742. }
  1743. }