narodnik 5 лет назад
Родитель
Сommit
ad425c652c
3 измененных файлов с 122 добавлено и 19 удалено
  1. 95 6
      src/eq.rs
  2. 1 1
      src/mint.rs
  3. 26 12
      src/spend.rs

+ 95 - 6
src/eq.rs

@@ -1,20 +1,25 @@
 use bellman::{
     gadgets::{
         boolean::{AllocatedBit, Boolean},
-        multipack,
-        Assignment,
-        num
+        multipack, num, Assignment,
     },
     groth16, Circuit, ConstraintSystem, SynthesisError,
 };
 use bls12_381::Bls12;
+use bls12_381::Scalar;
+use ff::{Field, PrimeField};
 use group::Curve;
 use rand::rngs::OsRng;
+use std::ops::{Neg, SubAssign};
 
 pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
 
 struct MyCircuit {
     value: Option<bls12_381::Scalar>,
+    quantity: Option<bls12_381::Scalar>,
+    multiplier: Option<bls12_381::Scalar>,
+    entry_price: Option<bls12_381::Scalar>,
+    exit_price: Option<bls12_381::Scalar>,
 }
 
 impl Circuit<bls12_381::Scalar> for MyCircuit {
@@ -26,11 +31,81 @@ impl Circuit<bls12_381::Scalar> for MyCircuit {
             Ok(*self.value.get()?)
         })?;
 
+        // Witness variables
+        let quantity = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.quantity.get()?)
+        })?;
+        let multiplier = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.multiplier.get()?)
+        })?;
+        let entry_price = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.entry_price.get()?)
+        })?;
+        let exit_price = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.exit_price.get()?)
+        })?;
+
+        // P = mN (1 - 1/R)
+        //   = mN - mN/R
+        //   = mN - mN * S_0 * S_T^-1
+
+        // initial_margin = mN
+        let initial_margin = multiplier.mul(cs.namespace(|| "initial margin"), &quantity)?;
+
+        // S_T_inv = S_T^-1
+        let exit_price_inv =
+            num::AllocatedNum::alloc(cs.namespace(|| "exit price inverse"), || {
+                let tmp = *exit_price.get_value().get()?;
+
+                if tmp.is_zero() {
+                    Err(SynthesisError::DivisionByZero)
+                } else {
+                    let inv = tmp.invert().unwrap();
+                    Ok(inv)
+                }
+            })?;
+
+        // assert S_T * S_T_inv = 1
+        cs.enforce(
+            || "constraint inverse exit price",
+            |lc| lc + exit_price.get_variable(),
+            |lc| lc + exit_price_inv.get_variable(),
+            |lc| lc + CS::one(),
+        );
+
+        // ungained = initial_margin * S_0 * S_T_inv
+        let ungained = initial_margin.mul(cs.namespace(|| "ungained 1"), &entry_price)?;
+        let ungained = ungained.mul(cs.namespace(|| "ungained 2"), &exit_price_inv)?;
+
+        // pnl = initial_margin - ungained
+        let pnl =
+            num::AllocatedNum::alloc(cs.namespace(|| "exit price inverse"), || {
+                let mut tmp = *initial_margin.get_value().get()?;
+
+                tmp.sub_assign(ungained.get_value().get()?);
+
+                Ok(tmp)
+            })?;
+
+        cs.enforce(
+            || "constraint pnl calc",
+            |lc| lc + initial_margin.get_variable() - ungained.get_variable(),
+            |lc| lc + CS::one(),
+            |lc| lc + pnl.get_variable(),
+        );
+
+        // Apply clamp:
+        //
+        //   if pnl < -initial_margin:
+        //       pnl = -initial_margin
+        //   if pnl > initial_margin:
+        //       pnl = initial_margin
+
         cs.enforce(
             || "conditionally enforce correct root",
             |lc| lc + x.get_variable(),
             |lc| lc + CS::one(),
-            |lc| lc + x.get_variable(),
+            |lc| lc + CS::one(),
         );
 
         Ok(())
@@ -44,7 +119,13 @@ fn main() {
     // Create parameters for our circuit. In a production deployment these would
     // be generated securely using a multiparty computation.
     let params = {
-        let c = MyCircuit { value: None };
+        let c = MyCircuit {
+            value: None,
+            quantity: None,
+            multiplier: None,
+            entry_price: None,
+            exit_price: None,
+        };
         groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
     };
     println!("Setup: [{:?}]", start.elapsed());
@@ -53,11 +134,19 @@ fn main() {
     let pvk = groth16::prepare_verifying_key(&params.vk);
 
     // Pick a preimage and compute its hash.
-    let value = bls12_381::Scalar::one();
+    let value = bls12_381::Scalar::from(1);
+    let quantity = bls12_381::Scalar::from(1);
+    let multiplier = bls12_381::Scalar::from(1);
+    let entry_price = bls12_381::Scalar::from(100);
+    let exit_price = bls12_381::Scalar::from(200);
 
     // Create an instance of our circuit (with the preimage as a witness).
     let c = MyCircuit {
         value: Some(value),
+        quantity: Some(quantity),
+        multiplier: Some(multiplier),
+        entry_price: Some(entry_price),
+        exit_price: Some(exit_price),
     };
 
     let start = Instant::now();

+ 1 - 1
src/mint.rs

@@ -73,8 +73,8 @@ impl MintRevealedValues {
 }
 
 fn main() {
-    use std::time::Instant;
     use rand::rngs::OsRng;
+    use std::time::Instant;
 
     let public = jubjub::SubgroupPoint::random(&mut OsRng);
 

+ 26 - 12
src/spend.rs

@@ -1,16 +1,20 @@
 use bellman::gadgets::multipack;
 use bellman::groth16;
+use bitvec::{order::Lsb0, view::AsBits};
 use blake2s_simd::Params as Blake2sParams;
 use bls12_381::Bls12;
 use ff::{Field, PrimeField};
 use group::{Curve, GroupEncoding};
-use bitvec::{order::Lsb0, view::AsBits};
 
 mod spend_contract;
 use spend_contract::SpendContract;
 
 // This thing is nasty lol
-pub fn merkle_hash(depth: usize, lhs: &bls12_381::Scalar, rhs: &bls12_381::Scalar) -> bls12_381::Scalar {
+pub fn merkle_hash(
+    depth: usize,
+    lhs: &bls12_381::Scalar,
+    rhs: &bls12_381::Scalar,
+) -> bls12_381::Scalar {
     let lhs = {
         let mut tmp = [false; 256];
         for (a, b) in tmp.iter_mut().zip(lhs.to_repr().as_bits::<Lsb0>()) {
@@ -57,7 +61,7 @@ impl SpendRevealedValues {
         serial: &jubjub::Fr,
         randomness_coin: &jubjub::Fr,
         secret: &jubjub::Fr,
-        merkle_path: &[(bls12_381::Scalar, bool)]
+        merkle_path: &[(bls12_381::Scalar, bool)],
     ) -> Self {
         let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
             * jubjub::Fr::from(value))
@@ -92,10 +96,11 @@ impl SpendRevealedValues {
                 .as_bytes(),
         );
 
-        let merkle_root = jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
-            zcash_primitives::pedersen_hash::Personalization::NoteCommitment,
-            multipack::bytes_to_bits_le(&coin)
-        ));
+        let merkle_root =
+            jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
+                zcash_primitives::pedersen_hash::Personalization::NoteCommitment,
+                multipack::bytes_to_bits_le(&coin),
+            ));
         let affine = merkle_root.to_affine();
         let mut merkle_root = affine.get_u();
 
@@ -107,7 +112,11 @@ impl SpendRevealedValues {
             }
         }
 
-        SpendRevealedValues { value_commit, nullifier, merkle_root }
+        SpendRevealedValues {
+            value_commit,
+            nullifier,
+            merkle_root,
+        }
     }
 
     fn make_outputs(&self) -> [bls12_381::Scalar; 5] {
@@ -158,8 +167,8 @@ impl SpendRevealedValues {
 }
 
 fn main() {
-    use std::time::Instant;
     use rand::rngs::OsRng;
+    use std::time::Instant;
 
     let value = 110;
     let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
@@ -175,8 +184,14 @@ fn main() {
         (bls12_381::Scalar::random(&mut OsRng), true),
     ];
 
-    let revealed =
-        SpendRevealedValues::compute(value, &randomness_value, &serial, &randomness_coin, &secret, &merkle_path);
+    let revealed = SpendRevealedValues::compute(
+        value,
+        &randomness_value,
+        &serial,
+        &randomness_coin,
+        &secret,
+        &merkle_path,
+    );
 
     let start = Instant::now();
     let params = {
@@ -228,4 +243,3 @@ fn main() {
     assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
     println!("Verify: [{:?}]", start.elapsed());
 }
-