zkas: Implement EcNiPoint type and EcMulVarBase opcode.

This commit is contained in:
parazyd
2022-12-16 14:11:23 +01:00
parent f918aab7e2
commit 1c8feadcb6
9 changed files with 105 additions and 15 deletions

View File

@@ -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',

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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>>);

View File

@@ -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]),

View File

@@ -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(),

View File

@@ -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),

View File

@@ -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);