rangeproof.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  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(InvalidInstance::new(
  375. "range upper bound has no bit representation",
  376. ).into());
  377. }
  378. let #nbits_var = #bitrep_scalars_var.len();
  379. });
  380. // The prover will compute the bit representation (which
  381. // elements of the bitrep_scalars vector add up to x). This
  382. // should be done (in the prover code at runtime) in constant
  383. // time.
  384. let x_var = codegen.gen_ident(&format_ident!("range{}_{}_var", range_stmt_index, range_id));
  385. let bitrep_var = codegen.gen_ident(&format_ident!(
  386. "range{}_{}_bitrep",
  387. range_stmt_index,
  388. range_id
  389. ));
  390. let x_code = expr_type_tokens(&vardict, &range_stmt.linscalar.to_expr())?.1;
  391. codegen.prove_append(quote! {
  392. let #x_var = #x_code;
  393. let #bitrep_var =
  394. sigma_compiler::rangeutils::compute_bitrep(#x_var, &#bitrep_scalars_var);
  395. });
  396. // As mentioned above, we treat the first bit specially. Make a
  397. // vector of commitments to the rest of the bits to send to the
  398. // verifier, and also a vector of the committed bits and a
  399. // vector of randomnesses for the commitments, both for the
  400. // witness, again not putting those for the first bit into the
  401. // vectors. Do make separate witness elements for the committed
  402. // first bit and the randomness for it.
  403. let bitcomm_var = codegen.gen_point(
  404. vars,
  405. &format_ident!("range{}_{}_bitC", range_stmt_index, range_id),
  406. true, // is_vec
  407. true, // send_to_verifier
  408. );
  409. let bits_var = codegen.gen_scalar(
  410. vars,
  411. &format_ident!("range{}_{}_bit", range_stmt_index, range_id),
  412. false, // is_rand
  413. true, // is_vec
  414. );
  415. let bitrand_var = codegen.gen_scalar(
  416. vars,
  417. &format_ident!("range{}_{}_bitrand", range_stmt_index, range_id),
  418. false, // is_rand is false because this value might get reused in bitrandsq
  419. true, // is_vec
  420. );
  421. let bitrandsq_var = codegen.gen_scalar(
  422. vars,
  423. &format_ident!("range{}_{}_bitrandsq", range_stmt_index, range_id),
  424. false, // is_rand
  425. true, // is_vec
  426. );
  427. let firstbitcomm_var = codegen.gen_point(
  428. vars,
  429. &format_ident!("range{}_{}_firstbitC", range_stmt_index, range_id),
  430. false, // is_vec
  431. false, // send_to_verifier
  432. );
  433. let firstbit_var = codegen.gen_scalar(
  434. vars,
  435. &format_ident!("range{}_{}_firstbit", range_stmt_index, range_id),
  436. false, // is_rand
  437. false, // is_vec
  438. );
  439. let firstbitrand_var = codegen.gen_scalar(
  440. vars,
  441. &format_ident!("range{}_{}_firstbitrand", range_stmt_index, range_id),
  442. false, // is_rand
  443. false, // is_vec
  444. );
  445. let firstbitrandsq_var = codegen.gen_scalar(
  446. vars,
  447. &format_ident!("range{}_{}_firstbitrandsq", range_stmt_index, range_id),
  448. false, // is_rand
  449. false, // is_vec
  450. );
  451. // Update vardict and randoms with the new vars
  452. vardict = taggedvardict_to_vardict(vars);
  453. randoms.insert(bitrand_var.to_string());
  454. randoms.insert(firstbitrand_var.to_string());
  455. // The generators used in the Pedersen commitment
  456. let commit_generator = &ped_assign.pedersen.var_term.id;
  457. let rand_generator = &ped_assign.pedersen.rand_term.id;
  458. codegen.verify_pre_instance_append(quote! {
  459. let mut #bitcomm_var = Vec::<Point>::new();
  460. #bitcomm_var.resize(#nbits_var - 1, Point::default());
  461. });
  462. // The prover code
  463. codegen.prove_append(quote! {
  464. // The main strategy is to prove that each commitment is to
  465. // a bit (0 or 1), and we do this by showing that the
  466. // committed value equals its own square. That is, we show
  467. // that C = b*A + r*B and also that C = b*C + s*B. If both
  468. // of those are true (and A and B are computationally
  469. // independent), then C = b*(b*A + r*B) + s*B = b^2*A +
  470. // (r*b+s)*B, so b=b^2 and r=r*b+s. Therefore either b=0
  471. // and s=r or b=1 and s=0.
  472. // Map the bit representation to a vector of Scalar(0) and
  473. // Scalar(1), but skip the first bit, as described above.
  474. let #bits_var: Vec<Scalar> =
  475. #bitrep_var
  476. .iter()
  477. .skip(1)
  478. .map(|b| Scalar::conditional_select(
  479. &Scalar::ZERO,
  480. &Scalar::ONE,
  481. *b,
  482. ))
  483. .collect();
  484. // Choose randomizers r for the commitments randomly
  485. let #bitrand_var: Vec<Scalar> =
  486. (0..(#nbits_var-1))
  487. .map(|_| Scalar::random(#rng_var))
  488. .collect();
  489. // The randomizers s for the commitments to the squares are
  490. // chosen as above: s=r if b=0 and s=0 if b=1.
  491. let #bitrandsq_var: Vec<Scalar> =
  492. (0..(#nbits_var-1))
  493. .map(|i| Scalar::conditional_select(
  494. &#bitrand_var[i],
  495. &Scalar::ZERO,
  496. #bitrep_var[i+1],
  497. ))
  498. .collect();
  499. // Compute the commitments
  500. let #bitcomm_var: Vec<Point> =
  501. (0..(#nbits_var-1))
  502. .map(|i| #bits_var[i] * #commit_generator +
  503. #bitrand_var[i] * #rand_generator)
  504. .collect();
  505. // The same as above, for for the first bit
  506. let #firstbit_var =
  507. Scalar::conditional_select(
  508. &Scalar::ZERO,
  509. &Scalar::ONE,
  510. #bitrep_var[0],
  511. );
  512. // Compute the randomness that would be needed in the first
  513. // bit commitment so that the linear combination of all the
  514. // bit commitments (with the scalars in bitrep_scalars) adds
  515. // up to commitment_var.
  516. let mut #firstbitrand_var = #rand_var;
  517. for i in 0..(#nbits_var-1) {
  518. #firstbitrand_var -=
  519. #bitrand_var[i] * #bitrep_scalars_var[i+1];
  520. }
  521. // And the randomization for the first square is as above
  522. let #firstbitrandsq_var = Scalar::conditional_select(
  523. &#firstbitrand_var,
  524. &Scalar::ZERO,
  525. #bitrep_var[0],
  526. );
  527. // Compute the first bit commitment
  528. let #firstbitcomm_var =
  529. #firstbit_var * #commit_generator +
  530. #firstbitrand_var * #rand_generator;
  531. });
  532. // The verifier also needs to compute the first commitment
  533. codegen.verify_append(quote! {
  534. let mut #firstbitcomm_var = #commitment_var;
  535. for i in 0..(#nbits_var-1) {
  536. #firstbitcomm_var -=
  537. #bitcomm_var[i] * #bitrep_scalars_var[i+1];
  538. }
  539. });
  540. basic_statements.push(parse_quote! {
  541. #bitcomm_var = #bits_var * #commit_generator
  542. + #bitrand_var * #rand_generator
  543. });
  544. basic_statements.push(parse_quote! {
  545. #bitcomm_var = #bits_var * #bitcomm_var
  546. + #bitrandsq_var * #rand_generator
  547. });
  548. basic_statements.push(parse_quote! {
  549. #firstbitcomm_var = #firstbit_var * #commit_generator
  550. + #firstbitrand_var * #rand_generator
  551. });
  552. basic_statements.push(parse_quote! {
  553. #firstbitcomm_var = #firstbit_var * #firstbitcomm_var
  554. + #firstbitrandsq_var * #rand_generator
  555. });
  556. // Now replace the range statement with an And of the
  557. // basic_statements
  558. let range_st = StatementTree::And(
  559. basic_statements
  560. .into_iter()
  561. .map(StatementTree::Leaf)
  562. .collect(),
  563. );
  564. **leaf = range_st;
  565. }
  566. Ok(())
  567. }
  568. #[cfg(test)]
  569. mod tests {
  570. use super::super::syntax::taggedvardict_from_strs;
  571. use super::*;
  572. fn parse_tester(vars: (&[&str], &[&str]), expr: Expr, expect: Option<RangeStatement>) {
  573. let taggedvardict = taggedvardict_from_strs(vars);
  574. let vardict = taggedvardict_to_vardict(&taggedvardict);
  575. let output = parse(&taggedvardict, &vardict, &expr);
  576. assert_eq!(output, expect);
  577. }
  578. #[test]
  579. fn parse_test() {
  580. let vars = (
  581. [
  582. "x", "y", "z", "pub a", "pub b", "pub c", "rand r", "rand s", "rand t",
  583. ]
  584. .as_slice(),
  585. ["C", "cind A", "cind B"].as_slice(),
  586. );
  587. parse_tester(
  588. vars,
  589. parse_quote! {
  590. (0..100).contains(x)
  591. },
  592. Some(RangeStatement {
  593. upper: parse_quote! { 100 },
  594. linscalar: LinScalar {
  595. coeff: 1,
  596. pub_scalar_expr: None,
  597. id: parse_quote! {x},
  598. is_vec: false,
  599. },
  600. }),
  601. );
  602. parse_tester(
  603. vars,
  604. parse_quote! {
  605. (0..=100).contains(x)
  606. },
  607. Some(RangeStatement {
  608. upper: parse_quote! { 101i128 },
  609. linscalar: LinScalar {
  610. coeff: 1,
  611. pub_scalar_expr: None,
  612. id: parse_quote! {x},
  613. is_vec: false,
  614. },
  615. }),
  616. );
  617. parse_tester(
  618. vars,
  619. parse_quote! {
  620. (-12..100).contains(x)
  621. },
  622. Some(RangeStatement {
  623. upper: parse_quote! { 112i128 },
  624. linscalar: LinScalar {
  625. coeff: 1,
  626. pub_scalar_expr: Some(parse_quote! { 12i128 }),
  627. id: parse_quote! {x},
  628. is_vec: false,
  629. },
  630. }),
  631. );
  632. parse_tester(
  633. vars,
  634. parse_quote! {
  635. (-12..(1<<20)).contains(x)
  636. },
  637. Some(RangeStatement {
  638. upper: parse_quote! { 1048588i128 },
  639. linscalar: LinScalar {
  640. coeff: 1,
  641. pub_scalar_expr: Some(parse_quote! { 12i128 }),
  642. id: parse_quote! {x},
  643. is_vec: false,
  644. },
  645. }),
  646. );
  647. parse_tester(
  648. vars,
  649. parse_quote! {
  650. (12..(1<<20)).contains(x+7)
  651. },
  652. Some(RangeStatement {
  653. upper: parse_quote! { 1048564i128 },
  654. linscalar: LinScalar {
  655. coeff: 1,
  656. pub_scalar_expr: Some(parse_quote! { -5i128 }),
  657. id: parse_quote! {x},
  658. is_vec: false,
  659. },
  660. }),
  661. );
  662. parse_tester(
  663. vars,
  664. parse_quote! {
  665. (12..(1<<20)).contains(2*x+7)
  666. },
  667. Some(RangeStatement {
  668. upper: parse_quote! { 1048564i128 },
  669. linscalar: LinScalar {
  670. coeff: 2,
  671. pub_scalar_expr: Some(parse_quote! { -5i128 }),
  672. id: parse_quote! {x},
  673. is_vec: false,
  674. },
  675. }),
  676. );
  677. parse_tester(
  678. vars,
  679. parse_quote! {
  680. (-1..(((1<<126)-1)*2)).contains(x)
  681. },
  682. Some(RangeStatement {
  683. upper: parse_quote! { 170141183460469231731687303715884105727i128 },
  684. linscalar: LinScalar {
  685. coeff: 1,
  686. pub_scalar_expr: Some(parse_quote! { 1i128 }),
  687. id: parse_quote! {x},
  688. is_vec: false,
  689. },
  690. }),
  691. );
  692. parse_tester(
  693. vars,
  694. parse_quote! {
  695. (-2..(((1<<126)-1)*2)).contains(x)
  696. },
  697. Some(RangeStatement {
  698. upper: parse_quote! { (((1<<126)-1)*2)-(-2) },
  699. linscalar: LinScalar {
  700. coeff: 1,
  701. pub_scalar_expr: Some(parse_quote! { 2i128 }),
  702. id: parse_quote! {x},
  703. is_vec: false,
  704. },
  705. }),
  706. );
  707. parse_tester(
  708. vars,
  709. parse_quote! {
  710. (a*b..b+c*c+7).contains(3*x+c*(a+b+2))
  711. },
  712. Some(RangeStatement {
  713. upper: parse_quote! { b+c*c+7-(a*b) },
  714. linscalar: LinScalar {
  715. coeff: 3,
  716. pub_scalar_expr: Some(parse_quote! { c*(a+b+2i128)-(a*b) }),
  717. id: parse_quote! {x},
  718. is_vec: false,
  719. },
  720. }),
  721. );
  722. }
  723. }