Jelajahi Sumber

bit decomposition

narodnik 5 tahun lalu
induk
melakukan
cb8851df17
7 mengubah file dengan 162 tambahan dan 16 penghapusan
  1. 4 0
      Cargo.toml
  2. 27 0
      proofs/bits.psm
  3. 5 0
      run_bits.sh
  4. 5 0
      scripts/vm.py
  5. 31 0
      src/bits.rs
  6. 6 13
      src/jubjub.rs
  7. 84 3
      src/vm.rs

+ 4 - 0
Cargo.toml

@@ -72,3 +72,7 @@ path = "src/vmtest.rs"
 name = "jubjub"
 path = "src/jubjub.rs"
 
+[[bin]]
+name = "bits"
+path = "src/bits.rs"
+

+ 27 - 0
proofs/bits.psm

@@ -0,0 +1,27 @@
+constant a 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000
+constant d 0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1
+constant one 0x0000000000000000000000000000000000000000000000000000000000000001
+
+contract input_spend
+    param x
+    {% for n in range(255) %}
+        private b_{{n}}
+    {% endfor %}
+
+    unpack_bits x b_0 b_254
+
+    {% for n in range(255) %}
+        # (1 - b) * b == 0
+        lc0_add_one
+        lc0_sub b_{{n}}
+
+        lc1_add b_{{n}}
+
+        enforce
+    {% endfor %}
+
+    lc0_add_bits b_0
+    lc0_sub x
+    enforce
+end
+

+ 5 - 0
run_bits.sh

@@ -0,0 +1,5 @@
+#!/bin/bash -x
+python scripts/preprocess.py proofs/bits.psm > /tmp/bits.psm
+python scripts/vm.py --rust /tmp/bits.psm > src/bits_contract.rs
+cargo run --release --bin bits
+

+ 5 - 0
scripts/vm.py

@@ -14,6 +14,8 @@ op_commands = {
     "add": 2, 
     "sub": 2,
     "divide": 2,
+    "double": 1,
+    "unpack_bits": 3,
     "load": 2,
     "local": 1,
 }
@@ -31,6 +33,9 @@ constraint_commands = {
     "lc0_add_coeff": 2,
     "lc1_add_coeff": 2,
     "lc2_add_coeff": 2,
+    "lc0_add_bits": 1,
+    "lc1_add_bits": 1,
+    "lc2_add_bits": 1,
     "enforce": 0,
 }
 

+ 31 - 0
src/bits.rs

@@ -0,0 +1,31 @@
+use bls12_381::Scalar;
+
+mod bits_contract;
+mod vm;
+use bits_contract::load_zkvm;
+
+fn main() -> std::result::Result<(), vm::ZKVMError> {
+    let mut vm = load_zkvm();
+
+    vm.setup();
+
+    let params = vec![(
+        0,
+        Scalar::from_raw([
+            0xb981_9dc8_2d90_607e,
+            0xa361_ee3f_d48f_df77,
+            0x52a3_5a8c_1908_dd87,
+            0x15a3_6d1f_0f39_0d88,
+        ]),
+    )];
+    vm.initialize(&params)?;
+
+    let proof = vm.prove();
+
+    let public = vm.public();
+
+    assert_eq!(public.len(), 0);
+
+    assert!(vm.verify(&proof, &public));
+    Ok(())
+}

+ 6 - 13
src/jubjub.rs

@@ -1,7 +1,7 @@
+use bls12_381::Scalar;
 use ff::PrimeField;
 use group::Group;
 use jubjub::SubgroupPoint;
-use bls12_381::Scalar;
 
 fn main() {
     let g = SubgroupPoint::from_raw_unchecked(
@@ -23,17 +23,10 @@ fn main() {
     println!("{:?}", x);
 
     let one = Scalar::from_bytes(&[
-        0x01, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-    ]).unwrap();
+        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00,
+    ])
+    .unwrap();
     assert_eq!(Scalar::one(), one);
 }

+ 84 - 3
src/vm.rs

@@ -10,7 +10,7 @@ use bls12_381::Scalar;
 use ff::{Field, PrimeField};
 use group::Curve;
 use rand::rngs::OsRng;
-use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
+use std::ops::{Add, AddAssign, MulAssign, Neg, SubAssign};
 use std::time::Instant;
 
 pub struct ZKVirtualMachine {
@@ -37,6 +37,8 @@ pub enum CryptoOperation {
     Sub(VariableRef, VariableRef),
     Load(VariableRef, VariableIndex),
     Divide(VariableRef, VariableRef),
+    Double(VariableRef),
+    UnpackBits(VariableRef, VariableRef, VariableRef),
     Local,
 }
 
@@ -60,15 +62,23 @@ pub enum ConstraintInstruction {
     Lc0AddCoeff(VariableIndex, VariableIndex),
     Lc1AddCoeff(VariableIndex, VariableIndex),
     Lc2AddCoeff(VariableIndex, VariableIndex),
+    Lc0AddBits(VariableIndex),
+    Lc1AddBits(VariableIndex),
+    Lc2AddBits(VariableIndex),
     Enforce,
 }
 
+#[derive(Debug)]
 pub enum ZKVMError {
     DivisionByZero,
+    MalformedRange,
 }
 
 impl ZKVirtualMachine {
-    pub fn initialize(&mut self, params: &Vec<(VariableIndex, Scalar)>) -> std::result::Result<(), ZKVMError> {
+    pub fn initialize(
+        &mut self,
+        params: &Vec<(VariableIndex, Scalar)>,
+    ) -> std::result::Result<(), ZKVMError> {
         // Resize array
         self.aux = vec![Scalar::zero(); self.alloc.len()];
 
@@ -149,6 +159,51 @@ impl ZKVirtualMachine {
                         return Err(ZKVMError::DivisionByZero);
                     }
                 }
+                CryptoOperation::Double(self_) => {
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    *self_ = self_.double();
+                }
+                CryptoOperation::UnpackBits(value, start, end) => {
+                    let value = match value {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let (self_, start_index, end_index) = match start {
+                        VariableRef::Aux(start_index) => match end {
+                            VariableRef::Aux(end_index) => (&mut self.aux, start_index, end_index),
+                            VariableRef::Local(end_index) => {
+                                return Err(ZKVMError::MalformedRange);
+                            }
+                        },
+                        VariableRef::Local(start_index) => match end {
+                            VariableRef::Aux(end_index) => {
+                                return Err(ZKVMError::MalformedRange);
+                            }
+                            VariableRef::Local(end_index) => {
+                                (&mut local_stack, start_index, end_index)
+                            }
+                        },
+                    };
+                    if start_index > end_index {
+                        return Err(ZKVMError::MalformedRange);
+                    }
+                    if (end_index + 1) - start_index != Scalar::NUM_BITS as usize {
+                        return Err(ZKVMError::MalformedRange);
+                    }
+                    if *end_index >= self_.len() {
+                        return Err(ZKVMError::MalformedRange);
+                    }
+
+                    for (i, bit) in value.to_le_bits().into_iter().rev().cloned().enumerate() {
+                        match bit {
+                            true => self_[i] = Scalar::one(),
+                            false => self_[i] = Scalar::zero(),
+                        }
+                    }
+                }
                 CryptoOperation::Local => {
                     local_stack.push(Scalar::zero());
                 }
@@ -229,6 +284,24 @@ pub struct ZKVMCircuit {
     constants: Vec<Scalar>,
 }
 
+fn lc_add_bits(
+    mut lc: bellman::LinearCombination<Scalar>,
+    variables: &Vec<bellman::Variable>,
+    start_index: usize,
+) -> std::result::Result<bellman::LinearCombination<Scalar>, SynthesisError> {
+    if variables.len() - start_index > Scalar::NUM_BITS as usize {
+        return Err(SynthesisError::Unsatisfiable);
+    }
+
+    let mut coeff = Scalar::one();
+    for i in 0..Scalar::NUM_BITS as usize {
+        lc = lc + (coeff, variables[start_index + i]);
+
+        coeff = coeff.double();
+    }
+    Ok(lc)
+}
+
 impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
     fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
         self,
@@ -292,6 +365,15 @@ impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
                 ConstraintInstruction::Lc2AddCoeff(const_index, index) => {
                     lc2 = lc2 + (self.constants[const_index], variables[index]);
                 }
+                ConstraintInstruction::Lc0AddBits(start_index) => {
+                    lc0 = lc_add_bits(lc0, &variables, start_index)?;
+                }
+                ConstraintInstruction::Lc1AddBits(start_index) => {
+                    lc1 = lc_add_bits(lc1, &variables, start_index)?;
+                }
+                ConstraintInstruction::Lc2AddBits(start_index) => {
+                    lc2 = lc_add_bits(lc2, &variables, start_index)?;
+                }
                 ConstraintInstruction::Enforce => {
                     cs.enforce(
                         || "constraint",
@@ -309,4 +391,3 @@ impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
         Ok(())
     }
 }
-