eq.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. use bellman::{
  2. gadgets::{
  3. boolean::{AllocatedBit, Boolean},
  4. multipack, num, Assignment,
  5. },
  6. groth16, Circuit, ConstraintSystem, SynthesisError,
  7. };
  8. use bls12_381::Bls12;
  9. use bls12_381::Scalar;
  10. use ff::{Field, PrimeField};
  11. use group::Curve;
  12. use rand::rngs::OsRng;
  13. use std::ops::{Neg, SubAssign};
  14. pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
  15. struct MyCircuit {
  16. quantity: Option<bls12_381::Scalar>,
  17. multiplier: Option<bls12_381::Scalar>,
  18. entry_price: Option<bls12_381::Scalar>,
  19. exit_price: Option<bls12_381::Scalar>,
  20. }
  21. impl Circuit<bls12_381::Scalar> for MyCircuit {
  22. fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
  23. self,
  24. cs: &mut CS,
  25. ) -> Result<(), SynthesisError> {
  26. // Witness variables
  27. let quantity = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
  28. Ok(*self.quantity.get()?)
  29. })?;
  30. let multiplier = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
  31. Ok(*self.multiplier.get()?)
  32. })?;
  33. let entry_price = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
  34. Ok(*self.entry_price.get()?)
  35. })?;
  36. let exit_price = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
  37. Ok(*self.exit_price.get()?)
  38. })?;
  39. // P = mN (1 - 1/R)
  40. // = mN - mN/R
  41. // = mN - mN * S_0 * S_T^-1
  42. // initial_margin = mN
  43. let initial_margin = multiplier.mul(cs.namespace(|| "initial margin"), &quantity)?;
  44. // S_T_inv = S_T^-1
  45. let exit_price_inv =
  46. num::AllocatedNum::alloc(cs.namespace(|| "exit price inverse"), || {
  47. let tmp = *exit_price.get_value().get()?;
  48. if tmp.is_zero() {
  49. Err(SynthesisError::DivisionByZero)
  50. } else {
  51. let inv = tmp.invert().unwrap();
  52. Ok(inv)
  53. }
  54. })?;
  55. // assert S_T * S_T_inv = 1
  56. cs.enforce(
  57. || "constraint inverse exit price",
  58. |lc| lc + exit_price.get_variable(),
  59. |lc| lc + exit_price_inv.get_variable(),
  60. |lc| lc + CS::one(),
  61. );
  62. // ungained = initial_margin * S_0 * S_T_inv
  63. let ungained = initial_margin.mul(cs.namespace(|| "ungained 1"), &entry_price)?;
  64. let ungained = ungained.mul(cs.namespace(|| "ungained 2"), &exit_price_inv)?;
  65. // pnl = initial_margin - ungained
  66. let pnl = num::AllocatedNum::alloc(cs.namespace(|| "exit price inverse"), || {
  67. let mut tmp = *initial_margin.get_value().get()?;
  68. tmp.sub_assign(ungained.get_value().get()?);
  69. Ok(tmp)
  70. })?;
  71. cs.enforce(
  72. || "constraint pnl calc",
  73. |lc| lc + initial_margin.get_variable() - ungained.get_variable(),
  74. |lc| lc + CS::one(),
  75. |lc| lc + pnl.get_variable(),
  76. );
  77. // Apply clamp:
  78. //
  79. // if pnl < -initial_margin:
  80. // pnl = -initial_margin
  81. // if pnl > initial_margin:
  82. // pnl = initial_margin
  83. Ok(())
  84. }
  85. }
  86. fn main() {
  87. let x = Scalar::from(2);
  88. println!("{:?}", x.invert().unwrap());
  89. use std::time::Instant;
  90. let start = Instant::now();
  91. // Create parameters for our circuit. In a production deployment these would
  92. // be generated securely using a multiparty computation.
  93. let params = {
  94. let c = MyCircuit {
  95. quantity: None,
  96. multiplier: None,
  97. entry_price: None,
  98. exit_price: None,
  99. };
  100. groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
  101. };
  102. println!("Setup: [{:?}]", start.elapsed());
  103. // Prepare the verification key (for proof verification).
  104. let pvk = groth16::prepare_verifying_key(&params.vk);
  105. // Pick a preimage and compute its hash.
  106. let quantity = bls12_381::Scalar::from(1);
  107. let multiplier = bls12_381::Scalar::from(1);
  108. let entry_price = bls12_381::Scalar::from(100);
  109. let exit_price = bls12_381::Scalar::from(200);
  110. // Create an instance of our circuit (with the preimage as a witness).
  111. let c = MyCircuit {
  112. quantity: Some(quantity),
  113. multiplier: Some(multiplier),
  114. entry_price: Some(entry_price),
  115. exit_price: Some(exit_price),
  116. };
  117. let start = Instant::now();
  118. // Create a Groth16 proof with our parameters.
  119. let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
  120. println!("Prove: [{:?}]", start.elapsed());
  121. let start = Instant::now();
  122. let mut public_input = [bls12_381::Scalar::zero(); 0];
  123. let start = Instant::now();
  124. // Check the proof!
  125. assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
  126. println!("Verify: [{:?}]", start.elapsed());
  127. }