Explorar el Código

zkas: Implement EcNiPoint type and EcMulVarBase opcode.

parazyd hace 3 años
padre
commit
1c8feadcb6
Se han modificado 9 ficheros con 105 adiciones y 15 borrados
  1. 3 4
      contrib/zk.lua
  2. 3 4
      contrib/zk.vim
  3. 7 0
      proof/opcodes.zk
  4. 34 1
      src/zk/vm.rs
  5. 8 2
      src/zk/vm_stack.rs
  6. 10 1
      src/zkas/opcode.rs
  7. 18 0
      src/zkas/parser.rs
  8. 4 0
      src/zkas/types.rs
  9. 18 3
      tests/zkvm_opcodes.rs

+ 3 - 4
contrib/zk.lua

@@ -32,14 +32,13 @@ local constant = token(l.CONSTANT, word_match{
 -- Types.
 local type = token(l.TYPE, word_match{
   'EcPoint', 'EcFixedPoint', 'EcFixedPointBase', 'EcFixedPointShort',
-  'Base', 'BaseArray', 'Scalar', 'ScalarArray',
-  'MerklePath',
-  'Uint32', 'Uint64',
+  'EcNiPoint', 'Base', 'BaseArray', 'Scalar', 'ScalarArray',
+  'MerklePath', 'Uint32', 'Uint64',
 })
 
 -- Instructions.
 local instruction = token('instruction', word_match{
-  'ec_add', 'ec_mul', 'ec_mul_base', 'ec_mul_short',
+  'ec_add', 'ec_mul', 'ec_mul_base', 'ec_mul_short', 'ec_mul_var_base',
   'ec_get_x', 'ec_get_y',
   'base_add', 'base_mul', 'base_sub',
   'poseidon_hash', 'merkle_root',

+ 3 - 4
contrib/zk.vim

@@ -13,13 +13,12 @@ syn keyword zkasKeyword
     \ circuit
 
 syn keyword zkasType 
-    \ EcPoint EcFixedPoint EcFixedPointBase EcFixedPointShort
+    \ EcPoint EcFixedPoint EcFixedPointBase EcFixedPointShort EcNiPoint
     \ Base BaseArray Scalar ScalarArray
-    \ MerklePath
-    \ Uint32 Uint64
+    \ MerklePath Uint32 Uint64
 
 syn keyword zkasInstruction
-    \ ec_add ec_mul ec_mul_base ec_mul_short
+    \ ec_add ec_mul ec_mul_base ec_mul_short ec_mul_var_base
     \ ec_get_x ec_get_y
     \ base_add base_mul base_sub
     \ poseidon_hash merkle_root

+ 7 - 0
proof/opcodes.zk

@@ -15,6 +15,9 @@ contract "Opcodes" {
 
 	Base secret,
 
+	EcNiPoint pubkey,
+	Base ephem_secret,
+
 	Uint32 leaf_pos,
 	MerklePath path,
 }
@@ -56,4 +59,8 @@ circuit "Opcodes" {
 	constrain_instance(ec_get_y(public));
 
 	bool_check(one);
+
+	ephem_public = ec_mul_var_base(ephem_secret, pubkey);
+	constrain_instance(ec_get_x(ephem_public));
+	constrain_instance(ec_get_y(ephem_public));
 }

+ 34 - 1
src/zk/vm.rs

@@ -24,7 +24,8 @@ use darkfi_sdk::crypto::constants::{
 use halo2_gadgets::{
     ecc::{
         chip::{EccChip, EccConfig},
-        FixedPoint, FixedPointBaseField, FixedPointShort, Point, ScalarFixed, ScalarFixedShort,
+        FixedPoint, FixedPointBaseField, FixedPointShort, NonIdentityPoint, Point, ScalarFixed,
+        ScalarFixedShort, ScalarVar,
     },
     poseidon::{
         primitives as poseidon, Hash as PoseidonHash, Pow5Chip as PoseidonChip,
@@ -414,6 +415,18 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     stack.push(StackVar::EcPoint(point));
                 }
 
+                Witness::EcNiPoint(w) => {
+                    trace!(target: L_TGT, "Witnessing EcNiPoint into circuit");
+                    let point = NonIdentityPoint::new(
+                        ecc_chip.clone(),
+                        layouter.namespace(|| "Witness EcNiPoint"),
+                        w.as_ref().map(|cm| cm.to_affine()),
+                    )?;
+
+                    trace!(target: L_TGT, "Pushing EcNiPoint to stack index {}", stack.len());
+                    stack.push(StackVar::EcNiPoint(point));
+                }
+
                 Witness::EcFixedPoint(_) => {
                     error!(target: L_TGT, "Unable to witness EcFixedPoint, this is unimplemented.");
                     return Err(plonk::Error::Synthesis)
@@ -501,6 +514,26 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     stack.push(StackVar::EcPoint(ret));
                 }
 
+                Opcode::EcMulVarBase => {
+                    trace!(target: L_TGT, "Executing `EcMulVarBase{:?}` opcode", opcode.1);
+                    let args = &opcode.1;
+
+                    let lhs: NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>> =
+                        stack[args[1].1].clone().into();
+
+                    let rhs: AssignedCell<Fp, Fp> = stack[args[0].1].clone().into();
+                    let rhs = ScalarVar::from_base(
+                        ecc_chip.clone(),
+                        layouter.namespace(|| "EcMulVarBase::from_base()"),
+                        &rhs,
+                    )?;
+
+                    let (ret, _) = lhs.mul(layouter.namespace(|| "EcMulVarBase()"), rhs)?;
+
+                    trace!(target: L_TGT, "Pushing result to stack index {}", stack.len());
+                    stack.push(StackVar::EcPoint(ret));
+                }
+
                 Opcode::EcMulBase => {
                     trace!(target: L_TGT, "Executing `EcMulBase{:?}` opcode", opcode.1);
                     let args = &opcode.1;

+ 8 - 2
src/zk/vm_stack.rs

@@ -18,7 +18,9 @@
 
 //! VM stack type abstractions
 use darkfi_sdk::crypto::{constants::OrchardFixedBases, MerkleNode};
-use halo2_gadgets::ecc::{chip::EccChip, FixedPoint, FixedPointBaseField, FixedPointShort, Point};
+use halo2_gadgets::ecc::{
+    chip::EccChip, FixedPoint, FixedPointBaseField, FixedPointShort, NonIdentityPoint, Point,
+};
 use halo2_proofs::{
     circuit::{AssignedCell, Value},
     pasta::pallas,
@@ -31,6 +33,7 @@ use crate::zkas::{decoder::ZkBinary, types::VarType};
 #[derive(Clone)]
 pub enum Witness {
     EcPoint(Value<pallas::Point>),
+    EcNiPoint(Value<pallas::Point>),
     EcFixedPoint(Value<pallas::Point>),
     Base(Value<pallas::Base>),
     Scalar(Value<pallas::Scalar>),
@@ -51,6 +54,7 @@ pub fn empty_witnesses(zkbin: &ZkBinary) -> Vec<Witness> {
     for witness in &zkbin.witnesses {
         match witness {
             VarType::EcPoint => ret.push(Witness::EcPoint(Value::unknown())),
+            VarType::EcNiPoint => ret.push(Witness::EcNiPoint(Value::unknown())),
             VarType::EcFixedPoint => ret.push(Witness::EcFixedPoint(Value::unknown())),
             VarType::Base => ret.push(Witness::Base(Value::unknown())),
             VarType::Scalar => ret.push(Witness::Scalar(Value::unknown())),
@@ -66,9 +70,10 @@ pub fn empty_witnesses(zkbin: &ZkBinary) -> Vec<Witness> {
 
 /// These represent the witness types inside the circuit
 #[allow(clippy::large_enum_variant)]
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub enum StackVar {
     EcPoint(Point<pallas::Affine, EccChip<OrchardFixedBases>>),
+    EcNiPoint(NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
     EcFixedPoint(FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
     EcFixedPointShort(FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>>),
     EcFixedPointBase(FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>>),
@@ -94,6 +99,7 @@ macro_rules! impl_from {
 }
 
 impl_from!(EcPoint, Point<pallas::Affine, EccChip<OrchardFixedBases>>);
+impl_from!(EcNiPoint, NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>>);
 impl_from!(EcFixedPoint, FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>);
 impl_from!(EcFixedPointShort, FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>>);
 impl_from!(EcFixedPointBase, FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>>);

+ 10 - 1
src/zkas/opcode.rs

@@ -28,7 +28,7 @@ pub enum Opcode {
     /// Elliptic curve addition
     EcAdd = 0x01,
 
-    // Elliptic curve multiplication
+    /// Elliptic curve multiplication
     EcMul = 0x02,
 
     /// Elliptic curve multiplication with a Base field element
@@ -37,6 +37,9 @@ pub enum Opcode {
     /// Elliptic curve multiplication with a Base field element of 64bit width
     EcMulShort = 0x04,
 
+    /// Variable Elliptic curve multiplication with a Base field element
+    EcMulVarBase = 0x05,
+
     /// Get the x coordinate of an elliptic curve point
     EcGetX = 0x08,
 
@@ -95,6 +98,7 @@ impl Opcode {
             "ec_mul" => Some(Self::EcMul),
             "ec_mul_base" => Some(Self::EcMulBase),
             "ec_mul_short" => Some(Self::EcMulShort),
+            "ec_mul_var_base" => Some(Self::EcMulVarBase),
             "ec_get_x" => Some(Self::EcGetX),
             "ec_get_y" => Some(Self::EcGetY),
             "poseidon_hash" => Some(Self::PoseidonHash),
@@ -121,6 +125,7 @@ impl Opcode {
             0x02 => Some(Self::EcMul),
             0x03 => Some(Self::EcMulBase),
             0x04 => Some(Self::EcMulShort),
+            0x05 => Some(Self::EcMulVarBase),
             0x08 => Some(Self::EcGetX),
             0x09 => Some(Self::EcGetY),
             0x10 => Some(Self::PoseidonHash),
@@ -159,6 +164,10 @@ impl Opcode {
                 (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcFixedPointShort])
             }
 
+            Opcode::EcMulVarBase => {
+                (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcNiPoint])
+            }
+
             Opcode::EcGetX => (vec![VarType::Base], vec![VarType::EcPoint]),
 
             Opcode::EcGetY => (vec![VarType::Base], vec![VarType::EcPoint]),

+ 18 - 0
src/zkas/parser.rs

@@ -509,6 +509,24 @@ impl Parser {
 
             // Valid witness types
             match v.1.token.as_str() {
+                "EcPoint" => {
+                    ret.push(Witness {
+                        name: k.to_string(),
+                        typ: VarType::EcPoint,
+                        line: v.0.line,
+                        column: v.0.column,
+                    });
+                }
+
+                "EcNiPoint" => {
+                    ret.push(Witness {
+                        name: k.to_string(),
+                        typ: VarType::EcNiPoint,
+                        line: v.0.line,
+                        column: v.0.column,
+                    });
+                }
+
                 "Base" => {
                     ret.push(Witness {
                         name: k.to_string(),

+ 4 - 0
src/zkas/types.rs

@@ -53,6 +53,9 @@ pub enum VarType {
     /// Elliptic curve fixed point in base field
     EcFixedPointBase = 0x04,
 
+    /// Elliptic curve nonidentity point
+    EcNiPoint = 0x05,
+
     /// Base field element
     Base = 0x10,
 
@@ -82,6 +85,7 @@ impl VarType {
             0x02 => Some(Self::EcFixedPoint),
             0x03 => Some(Self::EcFixedPointShort),
             0x04 => Some(Self::EcFixedPointBase),
+            0x05 => Some(Self::EcNiPoint),
             0x10 => Some(Self::Base),
             0x11 => Some(Self::BaseArray),
             0x12 => Some(Self::Scalar),

+ 18 - 3
tests/zkvm_opcodes.rs

@@ -17,7 +17,7 @@
  */
 
 use darkfi_sdk::{
-    crypto::{pedersen::pedersen_commitment_u64, MerkleNode, PublicKey, SecretKey},
+    crypto::{pedersen::pedersen_commitment_u64, util::mod_r_p, MerkleNode, PublicKey, SecretKey},
     incrementalmerkletree::{bridgetree::BridgeTree, Tree},
 };
 use halo2_gadgets::poseidon::{
@@ -80,6 +80,10 @@ fn zkvm_opcodes() -> Result<()> {
     let merkle_path = tree.authentication_path(leaf_pos, &root).unwrap();
     let leaf_pos: u64 = leaf_pos.into();
 
+    let ephem_secret = SecretKey::random(&mut OsRng);
+    let pubkey = PublicKey::from_secret(ephem_secret).inner();
+    let (ephem_x, ephem_y) = PublicKey::from(pubkey * mod_r_p(ephem_secret.inner())).xy();
+
     let prover_witnesses = vec![
         Witness::Base(Value::known(pallas::Base::from(value))),
         Witness::Scalar(Value::known(value_blind)),
@@ -87,6 +91,8 @@ fn zkvm_opcodes() -> Result<()> {
         Witness::Base(Value::known(a)),
         Witness::Base(Value::known(b)),
         Witness::Base(Value::known(secret)),
+        Witness::EcNiPoint(Value::known(pubkey)),
+        Witness::Base(Value::known(ephem_secret.inner())),
         Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
         Witness::MerklePath(Value::known(merkle_path.try_into().unwrap())),
     ];
@@ -100,8 +106,17 @@ fn zkvm_opcodes() -> Result<()> {
     let public = PublicKey::from_secret(SecretKey::from(secret));
     let (pub_x, pub_y) = public.xy();
 
-    let public_inputs =
-        vec![*value_coords.x(), *value_coords.y(), c2, d, root.inner(), pub_x, pub_y];
+    let public_inputs = vec![
+        *value_coords.x(),
+        *value_coords.y(),
+        c2,
+        d,
+        root.inner(),
+        pub_x,
+        pub_y,
+        ephem_x,
+        ephem_y,
+    ];
 
     let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
     let proving_key = ProvingKey::build(13, &circuit);