rangeproof.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. //! A module to transform range statements about `Scalar`s into
  2. //! statements about linear combinations of `Point`s.
  3. //!
  4. //! A range statement looks like `(a..b).contains(x-8)`, where `a` and
  5. //! `b` are expressions involving only _public_ `Scalar`s and constants
  6. //! and `x-8` is a private `Scalar`, possibly offset by a public
  7. //! `Scalar` or constant. At this time, none of the variables can be
  8. //! vector variables.
  9. //!
  10. //! As usual for Rust notation, the range `a..b` includes `a` but
  11. //! _excludes_ `b`. You can also write `a..=b` to include both
  12. //! endpoints. It is allowed for the range to "wrap around" 0, so
  13. //! that `L-50..100` is a valid range, and equivalent to `-50..100`,
  14. //! where `L` is the order of the group you are using.
  15. //!
  16. //! The size of the range (`b-a`) will be known at run time, but not
  17. //! necessarily at compile time. The size must fit in an [`i128`] and
  18. //! must be strictly greater than 1. Note that the range (and its size)
  19. //! are public, but the value you are stating is in the range will be
  20. //! private.
  21. use super::codegen::CodeGen;
  22. use super::pedersen::{
  23. convert_commitment, convert_randomness, random_scalars, recognize_linscalar,
  24. recognize_pedersen_assignment, recognize_pubscalar, LinScalar, PedersenAssignment,
  25. };
  26. use super::sigma::combiners::*;
  27. use super::sigma::types::{expr_type_tokens, VarDict};
  28. use super::syntax::{collect_cind_points, taggedvardict_to_vardict};
  29. use super::transform::paren_if_needed;
  30. use super::TaggedVarDict;
  31. use quote::{format_ident, quote};
  32. use std::collections::HashMap;
  33. use syn::spanned::Spanned;
  34. use syn::{parse_quote, Error, Expr, Ident, Result};
  35. /// A struct representing a normalized parsed range statement.
  36. ///
  37. /// Here, "normalized" means that the range is adjusted so that the
  38. /// lower bound is 0. This is accomplished by subtracting the stated
  39. /// lower bound from both the upper bound and the expression that is
  40. /// being asserting that it is in the range.
  41. #[derive(Clone, Debug, PartialEq, Eq)]
  42. struct RangeStatement {
  43. /// The upper bound of the range (exclusive). This must evaluate to
  44. /// a public Scalar.
  45. upper: Expr,
  46. /// The expression that is being asserted that it is in the range.
  47. /// This must be a [`LinScalar`]
  48. linscalar: LinScalar,
  49. }
  50. /// Subtract the Expr `lower` (with constant value `lowerval`, if
  51. /// present) from the Expr `expr` (with constant value `exprval`, if
  52. /// present). Return the resulting expression, as well as its constant
  53. /// value, if there is one. Do the subtraction numerically if possible,
  54. /// but otherwise symbolically.
  55. fn subtract_expr(
  56. expr: Option<&Expr>,
  57. exprval: Option<i128>,
  58. lower: &Expr,
  59. lowerval: Option<i128>,
  60. ) -> (Expr, Option<i128>) {
  61. // Note that if expr is None, then exprval is Some(0)
  62. if let (Some(ev), Some(lv)) = (exprval, lowerval) {
  63. if let Some(diffv) = ev.checked_sub(lv) {
  64. // We can do the subtraction numerically
  65. return (parse_quote! { #diffv }, Some(diffv));
  66. }
  67. }
  68. let paren_lower = paren_if_needed(lower.clone());
  69. // Return the difference symbolically
  70. (
  71. if let Some(e) = expr {
  72. parse_quote! { #e - #paren_lower }
  73. } else {
  74. parse_quote! { -#paren_lower }
  75. },
  76. None,
  77. )
  78. }
  79. /// Try to parse the given `Expr` as a range statement
  80. fn parse(vars: &TaggedVarDict, vardict: &VarDict, expr: &Expr) -> Option<RangeStatement> {
  81. // The expression needs to be of the form
  82. // (lower..upper).contains(expr)
  83. // The "top level" must be the method call ".contains"
  84. if let Expr::MethodCall(syn::ExprMethodCall {
  85. receiver,
  86. method,
  87. turbofish: None,
  88. args,
  89. ..
  90. }) = expr
  91. {
  92. if &method.to_string() != "contains" {
  93. // Wasn't ".contains"
  94. return None;
  95. }
  96. // Remove parens around the range, if present
  97. let mut range_expr = receiver.as_ref();
  98. if let Expr::Paren(syn::ExprParen {
  99. expr: parened_expr, ..
  100. }) = range_expr
  101. {
  102. range_expr = parened_expr;
  103. }
  104. // Parse the range
  105. if let Expr::Range(syn::ExprRange {
  106. start, limits, end, ..
  107. }) = range_expr
  108. {
  109. // The endpoints of the range need to be non-vector public
  110. // Scalar expressions
  111. // The first as_ref() turns &Option<Box<Expr>> into
  112. // Option<&Box<Expr>>. The ? removes the Option, and the
  113. // second as_ref() turns &Box<Expr> into &Expr.
  114. let lower = start.as_ref()?.as_ref().clone();
  115. let mut upper = end.as_ref()?.as_ref().clone();
  116. let Some((false, lowerval)) = recognize_pubscalar(vars, vardict, &lower) else {
  117. return None;
  118. };
  119. let Some((false, mut upperval)) = recognize_pubscalar(vars, vardict, &upper) else {
  120. return None;
  121. };
  122. let inclusive_upper = matches!(limits, syn::RangeLimits::Closed(_));
  123. // There needs to be exactly one argument of .contains()
  124. if args.len() != 1 {
  125. return None;
  126. }
  127. // The private expression needs to be a LinScalar
  128. let priv_expr = args.first().unwrap();
  129. let mut linscalar = recognize_linscalar(vars, vardict, priv_expr)?;
  130. // It is. See if the pub_scalar_expr in the LinScalar has a
  131. // constant value
  132. let linscalar_pubscalar_val = if let Some(ref pse) = linscalar.pub_scalar_expr {
  133. let Some((false, pubscalar_val)) = recognize_pubscalar(vars, vardict, pse) else {
  134. return None;
  135. };
  136. pubscalar_val
  137. } else {
  138. Some(0)
  139. };
  140. // We have a valid range statement. Normalize it by forcing
  141. // the upper bound to be exclusive, and the lower bound to
  142. // be 0.
  143. // If the range was inclusive of the upper bound (e.g.,
  144. // `0..=100`), add 1 to the upper bound to make it exclusive
  145. // (e.g., `0..101`).
  146. if inclusive_upper {
  147. // Add 1 to the upper bound, numerically if possible,
  148. // but otherwise symbolically
  149. let mut added_numerically = false;
  150. if let Some(uv) = upperval {
  151. if let Some(new_uv) = uv.checked_add(1) {
  152. upper = parse_quote! { #new_uv };
  153. upperval = Some(new_uv);
  154. added_numerically = true;
  155. }
  156. }
  157. if !added_numerically {
  158. upper = parse_quote! { #upper + 1 };
  159. upperval = None;
  160. }
  161. }
  162. // If the lower bound is not 0, subtract it from both the
  163. // upper bound and the pubscalar_expr in the LinScalar. Do
  164. // this numericaly if possibly, but otherwise symbolically.
  165. if lowerval != Some(0) {
  166. (upper, _) = subtract_expr(Some(&upper), upperval, &lower, lowerval);
  167. let pubscalar_expr;
  168. (pubscalar_expr, _) = subtract_expr(
  169. linscalar.pub_scalar_expr.as_ref(),
  170. linscalar_pubscalar_val,
  171. &lower,
  172. lowerval,
  173. );
  174. linscalar.pub_scalar_expr = Some(pubscalar_expr);
  175. }
  176. return Some(RangeStatement { upper, linscalar });
  177. }
  178. }
  179. None
  180. }
  181. /// Look for, and transform, range statements specified in the
  182. /// [`StatementTree`] into basic statements about linear combinations of
  183. /// `Point`s.
  184. #[allow(non_snake_case)] // so that Points can be capital letters
  185. pub fn transform(
  186. codegen: &mut CodeGen,
  187. st: &mut StatementTree,
  188. vars: &mut TaggedVarDict,
  189. ) -> Result<()> {
  190. // Make the VarDict version of the variable dictionary
  191. let mut vardict = taggedvardict_to_vardict(vars);
  192. // A HashSet of the random Scalars in the macro input
  193. let mut randoms = random_scalars(vars, st);
  194. // Gather mutable references to all of the leaves of the
  195. // StatementTree. Note that this ignores the combiner structure in
  196. // the StatementTree, but that's fine.
  197. let mut leaves = st.leaves_st_mut();
  198. // A list of the computationally independent (non-vector) Points in
  199. // the macro input. There must be at least two of them in order to
  200. // handle range statements, so that we can make Pedersen
  201. // commitments.
  202. let cind_points = collect_cind_points(vars);
  203. // Find any statements that look like Pedersen commitments in the
  204. // StatementTree, and make a HashMap mapping the committed private
  205. // variable to the parsed commitment.
  206. let pedersens: HashMap<Ident, PedersenAssignment> = leaves
  207. .iter()
  208. .filter_map(|leaf| {
  209. // See if we recognize this leaf expression as a
  210. // PedersenAssignment, and if so, make a pair mapping its
  211. // variable to the PedersenAssignment. (The "collect()"
  212. // will turn the list of pairs into a HashMap.)
  213. if let StatementTree::Leaf(leafexpr) = leaf {
  214. recognize_pedersen_assignment(vars, &randoms, &vardict, leafexpr)
  215. .map(|ped_assign| (ped_assign.var(), ped_assign))
  216. } else {
  217. None
  218. }
  219. })
  220. .collect();
  221. // Count how many range statements we've seen
  222. let mut range_stmt_index = 0usize;
  223. // The generated variable name for the rng
  224. let rng_var = codegen.gen_ident(&format_ident!("rng"));
  225. for leaf in leaves.iter_mut() {
  226. // For each leaf expression, see if it looks like a range statement
  227. let StatementTree::Leaf(leafexpr) = leaf else {
  228. continue;
  229. };
  230. let Some(range_stmt) = parse(vars, &vardict, leafexpr) else {
  231. continue;
  232. };
  233. range_stmt_index += 1;
  234. // The variable in the range statement must not be tagged "rand"
  235. if let Some(super::TaggedIdent::Scalar(super::TaggedScalar {
  236. is_pub: false,
  237. is_rand: true,
  238. ..
  239. })) = vars.get(&range_stmt.linscalar.id.to_string())
  240. {
  241. return Err(Error::new(
  242. leafexpr.span(),
  243. "target of range expression cannot be rand",
  244. ));
  245. }
  246. // We will transform the range statement into a list of basic
  247. // linear combination statements that will be ANDed together to
  248. // replace the range statement in the StatementTree. This
  249. // vector holds the list of basic statements.
  250. let mut basic_statements: Vec<Expr> = Vec::new();
  251. // We'll need a Pedersen commitment to the variable in the range
  252. // statement. See if there already is one.
  253. let range_id = &range_stmt.linscalar.id;
  254. let ped_assign = if let Some(ped_assign) = pedersens.get(range_id) {
  255. ped_assign.clone()
  256. } else {
  257. // We'll need to create a new one. First find two
  258. // computationally independent Points.
  259. if cind_points.len() < 2 {
  260. return Err(Error::new(
  261. proc_macro2::Span::call_site(),
  262. "At least two cind Points must be declared to support range statements",
  263. ));
  264. }
  265. let cind_A = &cind_points[0];
  266. let cind_B = &cind_points[1];
  267. // Create new variables for the Pedersen commitment and its
  268. // random Scalar.
  269. let commitment_var = codegen.gen_point(
  270. vars,
  271. &format_ident!("range{}_{}_genC", range_stmt_index, range_id),
  272. false, // is_vec
  273. true, // send_to_verifier
  274. );
  275. let rand_var = codegen.gen_scalar(
  276. vars,
  277. &format_ident!("range{}_{}_genr", range_stmt_index, range_id),
  278. true, // is_rand
  279. false, // is_vec
  280. );
  281. // Update vardict and randoms with the new vars
  282. vardict = taggedvardict_to_vardict(vars);
  283. randoms.insert(rand_var.to_string());
  284. let ped_assign_expr: Expr = parse_quote! {
  285. #commitment_var = #range_id * #cind_A + #rand_var * #cind_B
  286. };
  287. let ped_assign =
  288. recognize_pedersen_assignment(vars, &randoms, &vardict, &ped_assign_expr).unwrap();
  289. codegen.prove_append(quote! {
  290. let #rand_var = Scalar::random(#rng_var);
  291. let #ped_assign_expr;
  292. });
  293. basic_statements.push(ped_assign_expr);
  294. ped_assign
  295. };
  296. // At this point, we have a Pedersen commitment for some linear
  297. // function of range_id (given by
  298. // ped_assign.pedersen.var_term.coeff), using some linear
  299. // function of rand_var (given by
  300. // ped_assign.pedersen.rand_term.coeff) as the randomness. But
  301. // what we need is a Pedersen commitment for a possibly
  302. // different linear function of range_id (given by
  303. // range_stmt.linscalar). So we output runtime code for the
  304. // verifier that converts the commitment, and code for the
  305. // prover that converts the randomness.
  306. // Make a new runtime variable to hold the converted commitment
  307. let commitment_var =
  308. codegen.gen_ident(&format_ident!("range{}_{}_C", range_stmt_index, range_id));
  309. let rand_var =
  310. codegen.gen_ident(&format_ident!("range{}_{}_r", range_stmt_index, range_id));
  311. // Update vardict and randoms with the new vars
  312. vardict = taggedvardict_to_vardict(vars);
  313. randoms.insert(rand_var.to_string());
  314. codegen.verify_append(convert_commitment(
  315. &commitment_var,
  316. &ped_assign,
  317. &range_stmt.linscalar,
  318. &vardict,
  319. )?);
  320. codegen.prove_append(convert_randomness(
  321. &rand_var,
  322. &ped_assign,
  323. &range_stmt.linscalar,
  324. &vardict,
  325. )?);
  326. // Have both the prover and verifier compute the upper bound of
  327. // the range, and generate the bitrep_scalar vector based on
  328. // that upper bound. The key to the range proof is that this
  329. // bitrep_scalar vector has the property that you can write a
  330. // Scalar x as a sum of (different) elements of this vector if
  331. // and only if 0 <= x < upper. The prover and verifier both
  332. // know this vector (it depends only on upper, which is public).
  333. // Then the prover will generate private bits that indicate
  334. // which elements of the vector add up to x, and output
  335. // commitments to those bits, along with proofs that each of
  336. // those commitments indeed commits to a bit (0 or 1). The
  337. // verifier will check that the linear combination of the
  338. // commitments to those bits with the elements of the
  339. // bitrep_scalar vector yields the known commitment to x.
  340. //
  341. // As a small optimization, the commitment to the first bit
  342. // (which always has a bitrep_scalar entry of 1) is not actually
  343. // sent; instead of the verifier checking that the linear
  344. // combination of the commitments equals the known commitment to
  345. // x, it _computes_ the missing commitment to the first bit as
  346. // the difference between the known commitment to x and the
  347. // linear combination of the remaining commitments. The prover
  348. // still needs to prove that the value committed in that
  349. // computed commitment is a bit, but does not need to send the
  350. // commitment itself, saving a small bit of communication.
  351. let upper_var = codegen.gen_ident(&format_ident!(
  352. "range{}_{}_upper",
  353. range_stmt_index,
  354. range_id
  355. ));
  356. let upper_code = expr_type_tokens(&vardict, &range_stmt.upper)?.1;
  357. let bitrep_scalars_var = codegen.gen_ident(&format_ident!(
  358. "range{}_{}_bitrep_scalars",
  359. range_stmt_index,
  360. range_id
  361. ));
  362. let nbits_var = codegen.gen_ident(&format_ident!(
  363. "range{}_{}_nbits",
  364. range_stmt_index,
  365. range_id
  366. ));
  367. codegen.prove_verify_pre_instance_append(quote! {
  368. let #upper_var = #upper_code;
  369. let #bitrep_scalars_var =
  370. sigma_compiler::rangeutils::bitrep_scalars_vartime(#upper_var)?;
  371. if #bitrep_scalars_var.is_empty() {
  372. // The upper bound was either less than 2, or more than
  373. // i128::MAX
  374. return Err(SigmaError::VerificationFailure);
  375. }
  376. let #nbits_var = #bitrep_scalars_var.len();
  377. });
  378. // The prover will compute the bit representation (which
  379. // elements of the bitrep_scalars vector add up to x). This
  380. // should be done (in the prover code at runtime) in constant
  381. // time.
  382. let x_var = codegen.gen_ident(&format_ident!("range{}_{}_var", range_stmt_index, range_id));
  383. let bitrep_var = codegen.gen_ident(&format_ident!(
  384. "range{}_{}_bitrep",
  385. range_stmt_index,
  386. range_id
  387. ));
  388. let x_code = expr_type_tokens(&vardict, &range_stmt.linscalar.to_expr())?.1;
  389. codegen.prove_append(quote! {
  390. let #x_var = #x_code;
  391. let #bitrep_var =
  392. sigma_compiler::rangeutils::compute_bitrep(#x_var, &#bitrep_scalars_var);
  393. });
  394. // As mentioned above, we treat the first bit specially. Make a
  395. // vector of commitments to the rest of the bits to send to the
  396. // verifier, and also a vector of the committed bits and a
  397. // vector of randomnesses for the commitments, both for the
  398. // witness, again not putting those for the first bit into the
  399. // vectors. Do make separate witness elements for the committed
  400. // first bit and the randomness for it.
  401. let bitcomm_var = codegen.gen_point(
  402. vars,
  403. &format_ident!("range{}_{}_bitC", range_stmt_index, range_id),
  404. true, // is_vec
  405. true, // send_to_verifier
  406. );
  407. let bits_var = codegen.gen_scalar(
  408. vars,
  409. &format_ident!("range{}_{}_bit", range_stmt_index, range_id),
  410. false, // is_rand
  411. true, // is_vec
  412. );
  413. let bitrand_var = codegen.gen_scalar(
  414. vars,
  415. &format_ident!("range{}_{}_bitrand", range_stmt_index, range_id),
  416. false, // is_rand is false because this value might get reused in bitrandsq
  417. true, // is_vec
  418. );
  419. let bitrandsq_var = codegen.gen_scalar(
  420. vars,
  421. &format_ident!("range{}_{}_bitrandsq", range_stmt_index, range_id),
  422. false, // is_rand
  423. true, // is_vec
  424. );
  425. let firstbitcomm_var = codegen.gen_point(
  426. vars,
  427. &format_ident!("range{}_{}_firstbitC", range_stmt_index, range_id),
  428. false, // is_vec
  429. false, // send_to_verifier
  430. );
  431. let firstbit_var = codegen.gen_scalar(
  432. vars,
  433. &format_ident!("range{}_{}_firstbit", range_stmt_index, range_id),
  434. false, // is_rand
  435. false, // is_vec
  436. );
  437. let firstbitrand_var = codegen.gen_scalar(
  438. vars,
  439. &format_ident!("range{}_{}_firstbitrand", range_stmt_index, range_id),
  440. false, // is_rand
  441. false, // is_vec
  442. );
  443. let firstbitrandsq_var = codegen.gen_scalar(
  444. vars,
  445. &format_ident!("range{}_{}_firstbitrandsq", range_stmt_index, range_id),
  446. false, // is_rand
  447. false, // is_vec
  448. );
  449. // Update vardict and randoms with the new vars
  450. vardict = taggedvardict_to_vardict(vars);
  451. randoms.insert(bitrand_var.to_string());
  452. randoms.insert(firstbitrand_var.to_string());
  453. // The generators used in the Pedersen commitment
  454. let commit_generator = &ped_assign.pedersen.var_term.id;
  455. let rand_generator = &ped_assign.pedersen.rand_term.id;
  456. codegen.verify_pre_instance_append(quote! {
  457. let mut #bitcomm_var = Vec::<Point>::new();
  458. #bitcomm_var.resize(#nbits_var - 1, Point::default());
  459. });
  460. // The prover code
  461. codegen.prove_append(quote! {
  462. // The main strategy is to prove that each commitment is to
  463. // a bit (0 or 1), and we do this by showing that the
  464. // committed value equals its own square. That is, we show
  465. // that C = b*A + r*B and also that C = b*C + s*B. If both
  466. // of those are true (and A and B are computationally
  467. // independent), then C = b*(b*A + r*B) + s*B = b^2*A +
  468. // (r*b+s)*B, so b=b^2 and r=r*b+s. Therefore either b=0
  469. // and s=r or b=1 and s=0.
  470. // Map the bit representation to a vector of Scalar(0) and
  471. // Scalar(1), but skip the first bit, as described above.
  472. let #bits_var: Vec<Scalar> =
  473. #bitrep_var
  474. .iter()
  475. .skip(1)
  476. .map(|b| Scalar::conditional_select(
  477. &Scalar::ZERO,
  478. &Scalar::ONE,
  479. *b,
  480. ))
  481. .collect();
  482. // Choose randomizers r for the commitments randomly
  483. let #bitrand_var: Vec<Scalar> =
  484. (0..(#nbits_var-1))
  485. .map(|_| Scalar::random(#rng_var))
  486. .collect();
  487. // The randomizers s for the commitments to the squares are
  488. // chosen as above: s=r if b=0 and s=0 if b=1.
  489. let #bitrandsq_var: Vec<Scalar> =
  490. (0..(#nbits_var-1))
  491. .map(|i| Scalar::conditional_select(
  492. &#bitrand_var[i],
  493. &Scalar::ZERO,
  494. #bitrep_var[i+1],
  495. ))
  496. .collect();
  497. // Compute the commitments
  498. let #bitcomm_var: Vec<Point> =
  499. (0..(#nbits_var-1))
  500. .map(|i| #bits_var[i] * #commit_generator +
  501. #bitrand_var[i] * #rand_generator)
  502. .collect();
  503. // The same as above, for for the first bit
  504. let #firstbit_var =
  505. Scalar::conditional_select(
  506. &Scalar::ZERO,
  507. &Scalar::ONE,
  508. #bitrep_var[0],
  509. );
  510. // Compute the randomness that would be needed in the first
  511. // bit commitment so that the linear combination of all the
  512. // bit commitments (with the scalars in bitrep_scalars) adds
  513. // up to commitment_var.
  514. let mut #firstbitrand_var = #rand_var;
  515. for i in 0..(#nbits_var-1) {
  516. #firstbitrand_var -=
  517. #bitrand_var[i] * #bitrep_scalars_var[i+1];
  518. }
  519. // And the randomization for the first square is as above
  520. let #firstbitrandsq_var = Scalar::conditional_select(
  521. &#firstbitrand_var,
  522. &Scalar::ZERO,
  523. #bitrep_var[0],
  524. );
  525. // Compute the first bit commitment
  526. let #firstbitcomm_var =
  527. #firstbit_var * #commit_generator +
  528. #firstbitrand_var * #rand_generator;
  529. });
  530. // The verifier also needs to compute the first commitment
  531. codegen.verify_append(quote! {
  532. let mut #firstbitcomm_var = #commitment_var;
  533. for i in 0..(#nbits_var-1) {
  534. #firstbitcomm_var -=
  535. #bitcomm_var[i] * #bitrep_scalars_var[i+1];
  536. }
  537. });
  538. basic_statements.push(parse_quote! {
  539. #bitcomm_var = #bits_var * #commit_generator
  540. + #bitrand_var * #rand_generator
  541. });
  542. basic_statements.push(parse_quote! {
  543. #bitcomm_var = #bits_var * #bitcomm_var
  544. + #bitrandsq_var * #rand_generator
  545. });
  546. basic_statements.push(parse_quote! {
  547. #firstbitcomm_var = #firstbit_var * #commit_generator
  548. + #firstbitrand_var * #rand_generator
  549. });
  550. basic_statements.push(parse_quote! {
  551. #firstbitcomm_var = #firstbit_var * #firstbitcomm_var
  552. + #firstbitrandsq_var * #rand_generator
  553. });
  554. // Now replace the range statement with an And of the
  555. // basic_statements
  556. let range_st = StatementTree::And(
  557. basic_statements
  558. .into_iter()
  559. .map(StatementTree::Leaf)
  560. .collect(),
  561. );
  562. **leaf = range_st;
  563. }
  564. Ok(())
  565. }
  566. #[cfg(test)]
  567. mod tests {
  568. use super::super::syntax::taggedvardict_from_strs;
  569. use super::*;
  570. fn parse_tester(vars: (&[&str], &[&str]), expr: Expr, expect: Option<RangeStatement>) {
  571. let taggedvardict = taggedvardict_from_strs(vars);
  572. let vardict = taggedvardict_to_vardict(&taggedvardict);
  573. let output = parse(&taggedvardict, &vardict, &expr);
  574. assert_eq!(output, expect);
  575. }
  576. #[test]
  577. fn parse_test() {
  578. let vars = (
  579. [
  580. "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
  581. ]
  582. .as_slice(),
  583. ["C", "cind A", "cind B"].as_slice(),
  584. );
  585. parse_tester(
  586. vars,
  587. parse_quote! {
  588. (0..100).contains(x)
  589. },
  590. Some(RangeStatement {
  591. upper: parse_quote! { 100 },
  592. linscalar: LinScalar {
  593. coeff: 1,
  594. pub_scalar_expr: None,
  595. id: parse_quote! {x},
  596. is_vec: false,
  597. },
  598. }),
  599. );
  600. parse_tester(
  601. vars,
  602. parse_quote! {
  603. (0..=100).contains(x)
  604. },
  605. Some(RangeStatement {
  606. upper: parse_quote! { 101i128 },
  607. linscalar: LinScalar {
  608. coeff: 1,
  609. pub_scalar_expr: None,
  610. id: parse_quote! {x},
  611. is_vec: false,
  612. },
  613. }),
  614. );
  615. parse_tester(
  616. vars,
  617. parse_quote! {
  618. (-12..100).contains(x)
  619. },
  620. Some(RangeStatement {
  621. upper: parse_quote! { 112i128 },
  622. linscalar: LinScalar {
  623. coeff: 1,
  624. pub_scalar_expr: Some(parse_quote! { 12i128 }),
  625. id: parse_quote! {x},
  626. is_vec: false,
  627. },
  628. }),
  629. );
  630. parse_tester(
  631. vars,
  632. parse_quote! {
  633. (-12..(1<<20)).contains(x)
  634. },
  635. Some(RangeStatement {
  636. upper: parse_quote! { 1048588i128 },
  637. linscalar: LinScalar {
  638. coeff: 1,
  639. pub_scalar_expr: Some(parse_quote! { 12i128 }),
  640. id: parse_quote! {x},
  641. is_vec: false,
  642. },
  643. }),
  644. );
  645. parse_tester(
  646. vars,
  647. parse_quote! {
  648. (12..(1<<20)).contains(x+7)
  649. },
  650. Some(RangeStatement {
  651. upper: parse_quote! { 1048564i128 },
  652. linscalar: LinScalar {
  653. coeff: 1,
  654. pub_scalar_expr: Some(parse_quote! { -5i128 }),
  655. id: parse_quote! {x},
  656. is_vec: false,
  657. },
  658. }),
  659. );
  660. parse_tester(
  661. vars,
  662. parse_quote! {
  663. (12..(1<<20)).contains(2*x+7)
  664. },
  665. Some(RangeStatement {
  666. upper: parse_quote! { 1048564i128 },
  667. linscalar: LinScalar {
  668. coeff: 2,
  669. pub_scalar_expr: Some(parse_quote! { -5i128 }),
  670. id: parse_quote! {x},
  671. is_vec: false,
  672. },
  673. }),
  674. );
  675. parse_tester(
  676. vars,
  677. parse_quote! {
  678. (-1..(((1<<126)-1)*2)).contains(x)
  679. },
  680. Some(RangeStatement {
  681. upper: parse_quote! { 170141183460469231731687303715884105727i128 },
  682. linscalar: LinScalar {
  683. coeff: 1,
  684. pub_scalar_expr: Some(parse_quote! { 1i128 }),
  685. id: parse_quote! {x},
  686. is_vec: false,
  687. },
  688. }),
  689. );
  690. parse_tester(
  691. vars,
  692. parse_quote! {
  693. (-2..(((1<<126)-1)*2)).contains(x)
  694. },
  695. Some(RangeStatement {
  696. upper: parse_quote! { (((1<<126)-1)*2)-(-2) },
  697. linscalar: LinScalar {
  698. coeff: 1,
  699. pub_scalar_expr: Some(parse_quote! { 2i128 }),
  700. id: parse_quote! {x},
  701. is_vec: false,
  702. },
  703. }),
  704. );
  705. parse_tester(
  706. vars,
  707. parse_quote! {
  708. (a*b..b+c*c+7).contains(3*x+c*(a+b+2))
  709. },
  710. Some(RangeStatement {
  711. upper: parse_quote! { b+c*c+7-(a*b) },
  712. linscalar: LinScalar {
  713. coeff: 3,
  714. pub_scalar_expr: Some(parse_quote! { c*(a+b+2i128)-(a*b) }),
  715. id: parse_quote! {x},
  716. is_vec: false,
  717. },
  718. }),
  719. );
  720. }
  721. }