mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
sdk/python: Perform full code cleanup and make everything work.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "darkfi-sdk-py"
|
||||
description = "Python bindings for Darkfi SDK"
|
||||
description = "Python bindings for the DarkFi SDK"
|
||||
version = "0.4.1"
|
||||
edition = "2021"
|
||||
authors = ["Dyne.org foundation <foundation@dyne.org>"]
|
||||
@@ -8,14 +8,13 @@ license = "AGPL-3.0-only"
|
||||
homepage = "https://dark.fi"
|
||||
repository = "https://github.com/darkrenaissance/darkfi"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
name = "darkfi_sdk_py"
|
||||
name = "darkfi_sdk"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
darkfi = { path = "../../../", features = ["zk", "zkas"] }
|
||||
darkfi-sdk = { path = "../" }
|
||||
darkfi = {path = "../../../", features = ["zk", "zkas"]}
|
||||
darkfi-sdk = {path = "../"}
|
||||
halo2_gadgets = "0.3.0"
|
||||
pyo3 = "0.19.2"
|
||||
rand = "0.8.5"
|
||||
|
||||
@@ -9,5 +9,4 @@ all:
|
||||
dev:
|
||||
$(MATURIN) develop --release
|
||||
|
||||
|
||||
.PHONY: all
|
||||
|
||||
@@ -22,14 +22,14 @@ $ source venv/bin/activate
|
||||
|
||||
```
|
||||
$ python
|
||||
>>> import darkfi_sdk_py
|
||||
>>> from darkfi_sdk_py.base import Base
|
||||
>>> a = Base.from_u64(42)
|
||||
>>> b = Base.from_u64(69)
|
||||
>>> a + b == Base.from_u64(111)
|
||||
>>> import darkfi_sdk
|
||||
>>> from darkfi_sdk.pasta import Fp
|
||||
>>> a = Fp.from_u64(42)
|
||||
>>> b = Fp.from_u64(69)
|
||||
>>> a + b == Fp.from_u64(111)
|
||||
```
|
||||
|
||||
### Randomness
|
||||
## Randomness
|
||||
|
||||
Note that the `random` methods take randomness
|
||||
from the OS on the Rust side.
|
||||
|
||||
@@ -3,14 +3,13 @@ requires = ["maturin>=1.0,<2.0"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "darkfi-sdk-py"
|
||||
requires-python = ">=3.8"
|
||||
name = "darkfi-sdk"
|
||||
requires-python = ">=3.9"
|
||||
classifiers = [
|
||||
"Programming Language :: Rust",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
]
|
||||
|
||||
|
||||
[tool.maturin]
|
||||
features = ["pyo3/extension-module"]
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use darkfi_sdk::pasta::{arithmetic::CurveAffine, pallas};
|
||||
use pyo3::prelude::*;
|
||||
|
||||
use super::base::Base;
|
||||
|
||||
/// A Pallas point in the affine coordinate space (or the point at infinity).
|
||||
#[pyclass]
|
||||
pub struct Affine(pub(crate) pallas::Affine);
|
||||
|
||||
#[pymethods]
|
||||
impl Affine {
|
||||
fn __str__(&self) -> String {
|
||||
format!("Affine({:?})", self.0)
|
||||
}
|
||||
|
||||
fn coordinates(&self) -> (Base, Base) {
|
||||
let coords = self.0.coordinates().unwrap();
|
||||
(Base(*coords.x()), Base(*coords.y()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "affine")?;
|
||||
submod.add_class::<Affine>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi_sdk::{
|
||||
bridgetree::Hashable,
|
||||
crypto::{poseidon_hash, MerkleNode},
|
||||
pasta::{
|
||||
group::ff::{Field, FromUniformBytes, PrimeField},
|
||||
pallas,
|
||||
},
|
||||
};
|
||||
use pyo3::{basic::CompareOp, prelude::*};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
/// The base field of the Pallas and iso-Pallas curves.
|
||||
/// Randomness is provided by the OS and on the Rust side.
|
||||
#[pyclass]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Base(pub(crate) pallas::Base);
|
||||
|
||||
#[pymethods]
|
||||
impl Base {
|
||||
// Why is this not callable?
|
||||
#[staticmethod]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
Self(pallas::Base::from(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_u128(v: u128) -> Self {
|
||||
Self(pallas::Base::from_u128(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_raw(v: [u64; 4]) -> Self {
|
||||
Self(pallas::Base::from_raw(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_uniform_bytes(bytes: [u8; 64]) -> Self {
|
||||
Self(pallas::Base::from_uniform_bytes(&bytes))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn random() -> Self {
|
||||
Self(pallas::Base::random(&mut OsRng))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn modulus() -> String {
|
||||
pallas::Base::MODULUS.to_string()
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn zero() -> Self {
|
||||
Self(pallas::Base::zero())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn one() -> Self {
|
||||
Self(pallas::Base::one())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn poseidon_hash(messages: Vec<&PyCell<Self>>) -> Self {
|
||||
let l = messages.len();
|
||||
let messages: Vec<pallas::Base> = messages.iter().map(|m| m.borrow().deref().0).collect();
|
||||
if l == 1 {
|
||||
let m: [pallas::Base; 1] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 2 {
|
||||
let m: [pallas::Base; 2] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 3 {
|
||||
let m: [pallas::Base; 3] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 4 {
|
||||
let m: [pallas::Base; 4] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 5 {
|
||||
let m: [pallas::Base; 5] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 6 {
|
||||
let m: [pallas::Base; 6] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 7 {
|
||||
let m: [pallas::Base; 7] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 8 {
|
||||
let m: [pallas::Base; 8] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 9 {
|
||||
let m: [pallas::Base; 9] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 10 {
|
||||
let m: [pallas::Base; 10] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 11 {
|
||||
let m: [pallas::Base; 11] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 12 {
|
||||
let m: [pallas::Base; 12] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 13 {
|
||||
let m: [pallas::Base; 13] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 14 {
|
||||
let m: [pallas::Base; 14] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 15 {
|
||||
let m: [pallas::Base; 15] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else if l == 16 {
|
||||
let m: [pallas::Base; 16] = messages.try_into().unwrap();
|
||||
Self(poseidon_hash(m))
|
||||
} else {
|
||||
panic!("Messages length violation, must be: 1 <= len <= 16");
|
||||
}
|
||||
}
|
||||
|
||||
/// pos(ition) encodes the left/right position on each level
|
||||
/// path is the the silbling on each level
|
||||
#[staticmethod]
|
||||
fn merkle_root(i: u64, p: Vec<&PyCell<Base>>, a: &Base) -> Self {
|
||||
// TOOD: consider adding length check, for i and path, for extra defensiness
|
||||
let mut current = MerkleNode::new(a.0);
|
||||
for (level, sibling) in p.iter().enumerate() {
|
||||
let level = level as u8;
|
||||
let sibling = MerkleNode::new(sibling.borrow().deref().0);
|
||||
current = if i & (1 << level) == 0 {
|
||||
MerkleNode::combine(level.into(), ¤t, &sibling)
|
||||
} else {
|
||||
MerkleNode::combine(level.into(), &sibling, ¤t)
|
||||
};
|
||||
}
|
||||
let root = current.inner();
|
||||
Self(root)
|
||||
}
|
||||
|
||||
fn __str__(&self) -> String {
|
||||
format!("{:?}", self.0)
|
||||
}
|
||||
|
||||
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
|
||||
let class_name: &str = slf.get_type().name()?;
|
||||
Ok(format!("{}({:?})", class_name, slf.borrow().0))
|
||||
}
|
||||
|
||||
fn __add__(&self, other: &Self) -> Self {
|
||||
Self(self.0 + other.0)
|
||||
}
|
||||
|
||||
fn __sub__(&self, other: &Self) -> Self {
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
|
||||
fn __mul__(&self, other: &Self) -> Self {
|
||||
Self(self.0 * other.0)
|
||||
}
|
||||
|
||||
fn __neg__(&self) -> Self {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
|
||||
match op {
|
||||
CompareOp::Lt => Ok(self.0 < other.0),
|
||||
CompareOp::Le => Ok(self.0 <= other.0),
|
||||
CompareOp::Eq => Ok(self.0 == other.0),
|
||||
CompareOp::Ne => Ok(self.0 != other.0),
|
||||
CompareOp::Gt => Ok(self.0 > other.0),
|
||||
CompareOp::Ge => Ok(self.0 >= other.0),
|
||||
}
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
Self(self.0.double())
|
||||
}
|
||||
|
||||
fn square(&self) -> Self {
|
||||
Self(self.0.square())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "base")?;
|
||||
submod.add_class::<Base>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
73
src/sdk/python/src/crypto.rs
Normal file
73
src/sdk/python/src/crypto.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi_sdk::{crypto, pasta::pallas};
|
||||
use pyo3::{pyfunction, types::PyModule, wrap_pyfunction, PyCell, PyResult, Python};
|
||||
|
||||
use super::pasta::{Ep, Fp, Fq};
|
||||
|
||||
/// Calculate the Poseidon hash of given `Fp` elements.
|
||||
#[pyfunction]
|
||||
pub fn poseidon_hash(messages: Vec<&PyCell<Fp>>) -> Fp {
|
||||
let messages: Vec<pallas::Base> = messages.iter().map(|x| x.borrow().deref().0).collect();
|
||||
match messages.len() {
|
||||
1 => Fp(crypto::util::poseidon_hash::<1>(messages.try_into().unwrap())),
|
||||
2 => Fp(crypto::util::poseidon_hash::<2>(messages.try_into().unwrap())),
|
||||
3 => Fp(crypto::util::poseidon_hash::<3>(messages.try_into().unwrap())),
|
||||
4 => Fp(crypto::util::poseidon_hash::<4>(messages.try_into().unwrap())),
|
||||
5 => Fp(crypto::util::poseidon_hash::<5>(messages.try_into().unwrap())),
|
||||
6 => Fp(crypto::util::poseidon_hash::<6>(messages.try_into().unwrap())),
|
||||
7 => Fp(crypto::util::poseidon_hash::<7>(messages.try_into().unwrap())),
|
||||
8 => Fp(crypto::util::poseidon_hash::<8>(messages.try_into().unwrap())),
|
||||
9 => Fp(crypto::util::poseidon_hash::<9>(messages.try_into().unwrap())),
|
||||
10 => Fp(crypto::util::poseidon_hash::<10>(messages.try_into().unwrap())),
|
||||
11 => Fp(crypto::util::poseidon_hash::<11>(messages.try_into().unwrap())),
|
||||
12 => Fp(crypto::util::poseidon_hash::<12>(messages.try_into().unwrap())),
|
||||
13 => Fp(crypto::util::poseidon_hash::<13>(messages.try_into().unwrap())),
|
||||
14 => Fp(crypto::util::poseidon_hash::<14>(messages.try_into().unwrap())),
|
||||
15 => Fp(crypto::util::poseidon_hash::<15>(messages.try_into().unwrap())),
|
||||
16 => Fp(crypto::util::poseidon_hash::<16>(messages.try_into().unwrap())),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate a Pedersen commitment with an u64 value.
|
||||
#[pyfunction]
|
||||
pub fn pedersen_commitment_u64(value: u64, blind: &PyCell<Fq>) -> Ep {
|
||||
Ep(crypto::pedersen::pedersen_commitment_u64(value, blind.borrow().deref().0))
|
||||
}
|
||||
|
||||
/// Calculate a Pedersen commitment with an Fp value.
|
||||
#[pyfunction]
|
||||
pub fn pedersen_commitment_base(value: &PyCell<Fp>, blind: &PyCell<Fq>) -> Ep {
|
||||
Ep(crypto::pedersen::pedersen_commitment_base(
|
||||
value.borrow().deref().0,
|
||||
blind.borrow().deref().0,
|
||||
))
|
||||
}
|
||||
|
||||
/// Wrapper function for creating this Python module.
|
||||
pub(crate) fn create_module(py: Python<'_>) -> PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "crypto")?;
|
||||
submod.add_function(wrap_pyfunction!(poseidon_hash, submod)?)?;
|
||||
submod.add_function(wrap_pyfunction!(pedersen_commitment_u64, submod)?)?;
|
||||
submod.add_function(wrap_pyfunction!(pedersen_commitment_base, submod)?)?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -16,71 +16,35 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// Pallas point in affine space
|
||||
mod affine;
|
||||
/// Pallas base field element
|
||||
mod base;
|
||||
/// Pallas point in projective space
|
||||
mod point;
|
||||
/// Pallas scalar field element
|
||||
mod scalar;
|
||||
/// Pallas and Vesta curves
|
||||
mod pasta;
|
||||
|
||||
/// ZK proof creation
|
||||
mod proof;
|
||||
/// Proving key creation
|
||||
mod proving_key;
|
||||
/// Verifying key creation
|
||||
mod verifying_key;
|
||||
/// zkas ZkBinary wrappers
|
||||
mod zk_binary;
|
||||
/// zkvm wrappers
|
||||
mod zk_circuit;
|
||||
/// Merkle tree utilities
|
||||
mod merkle;
|
||||
|
||||
/// Cryptographic utilities
|
||||
mod crypto;
|
||||
|
||||
/// zkas definitions
|
||||
mod zkas;
|
||||
|
||||
#[pyo3::prelude::pymodule]
|
||||
fn darkfi_sdk_py(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> {
|
||||
let submodule = affine::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.affine'] = submodule");
|
||||
fn darkfi_sdk(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> {
|
||||
let submodule = pasta::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk.pasta'] = submodule");
|
||||
m.add_submodule(submodule)?;
|
||||
|
||||
let submodule = base::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.base'] = submodule");
|
||||
let submodule = merkle::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk.merkle'] = submodule");
|
||||
m.add_submodule(submodule)?;
|
||||
|
||||
let submodule = scalar::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.scalar'] = submodule");
|
||||
m.add_submodule(scalar::create_module(py)?)?;
|
||||
let submodule = crypto::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk.crypto'] = submodule");
|
||||
m.add_submodule(submodule)?;
|
||||
|
||||
let submodule = point::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.point'] = submodule");
|
||||
m.add_submodule(point::create_module(py)?)?;
|
||||
|
||||
let submodule = proof::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.proof'] = submodule");
|
||||
m.add_submodule(proof::create_module(py)?)?;
|
||||
|
||||
let submodule = proving_key::create_module(py)?;
|
||||
pyo3::py_run!(
|
||||
py,
|
||||
submodule,
|
||||
"import sys; sys.modules['darkfi_sdk_py.proving_key'] = submodule"
|
||||
);
|
||||
m.add_submodule(proving_key::create_module(py)?)?;
|
||||
|
||||
let submodule = verifying_key::create_module(py)?;
|
||||
pyo3::py_run!(
|
||||
py,
|
||||
submodule,
|
||||
"import sys; sys.modules['darkfi_sdk_py.verifying_key'] = submodule"
|
||||
);
|
||||
m.add_submodule(verifying_key::create_module(py)?)?;
|
||||
|
||||
let submodule = zk_binary::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.zk_binary'] = submodule");
|
||||
m.add_submodule(zk_binary::create_module(py)?)?;
|
||||
|
||||
let submodule = zk_circuit::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.zk_circuit'] = submodule");
|
||||
m.add_submodule(zk_circuit::create_module(py)?)?;
|
||||
let submodule = zkas::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk.zkas'] = submodule");
|
||||
m.add_submodule(submodule)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
60
src/sdk/python/src/merkle.rs
Normal file
60
src/sdk/python/src/merkle.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi_sdk::crypto::{merkle_node, MerkleNode};
|
||||
use pyo3::{pyclass, pymethods, types::PyModule, PyCell, PyResult};
|
||||
|
||||
use super::pasta::Fp;
|
||||
|
||||
#[pyclass]
|
||||
/// Class representing a bridgetree
|
||||
pub struct MerkleTree(merkle_node::MerkleTree);
|
||||
|
||||
#[pymethods]
|
||||
impl MerkleTree {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
Self(merkle_node::MerkleTree::new(100))
|
||||
}
|
||||
|
||||
fn append(&mut self, node: &PyCell<Fp>) -> PyResult<bool> {
|
||||
Ok(self.0.append(MerkleNode::from(node.borrow().deref().0)))
|
||||
}
|
||||
|
||||
fn mark(&mut self) -> PyResult<u32> {
|
||||
Ok(u64::from(self.0.mark().unwrap()) as u32)
|
||||
}
|
||||
|
||||
fn root(&self, checkpoint_depth: usize) -> PyResult<Fp> {
|
||||
let root = self.0.root(checkpoint_depth).unwrap();
|
||||
Ok(Fp(root.inner()))
|
||||
}
|
||||
|
||||
fn witness(&self, position: u32, checkpoint_depth: usize) -> PyResult<Vec<Fp>> {
|
||||
let path = self.0.witness((position as u64).into(), checkpoint_depth).unwrap();
|
||||
Ok(path.iter().map(|x| Fp(x.inner())).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper function for creating this Python module.
|
||||
pub(crate) fn create_module(py: pyo3::Python<'_>) -> PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "merkle")?;
|
||||
submod.add_class::<MerkleTree>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
316
src/sdk/python/src/pasta.rs
Normal file
316
src/sdk/python/src/pasta.rs
Normal file
@@ -0,0 +1,316 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi_sdk::{
|
||||
crypto::{constants::NullifierK, pasta_prelude::*, util},
|
||||
pasta::{group::ff::FromUniformBytes, pallas, vesta},
|
||||
};
|
||||
use halo2_gadgets::ecc::chip::FixedPoint;
|
||||
use pyo3::{
|
||||
basic::CompareOp, pyclass, pyfunction, pymethods, types::PyModule, wrap_pyfunction, PyCell,
|
||||
PyResult,
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
macro_rules! impl_elem {
|
||||
($x:ty, $inner:ty) => {
|
||||
#[pymethods]
|
||||
impl $x {
|
||||
#[new]
|
||||
fn new(v: &str) -> PyResult<Self> {
|
||||
assert!(v.starts_with("0x") && v.len() == 66);
|
||||
let v = v.trim_start_matches("0x");
|
||||
let (a, b) = v.split_at(32);
|
||||
let (le_1, le_0) = b.split_at(16);
|
||||
let (le_3, le_2) = a.split_at(16);
|
||||
|
||||
let le_0 = u64::from_str_radix(le_0, 16)?;
|
||||
let le_1 = u64::from_str_radix(le_1, 16)?;
|
||||
let le_2 = u64::from_str_radix(le_2, 16)?;
|
||||
let le_3 = u64::from_str_radix(le_3, 16)?;
|
||||
|
||||
Ok(Self(<$inner>::from_raw([le_0, le_1, le_2, le_3])))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
Self(<$inner>::from(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_u128(v: u128) -> Self {
|
||||
Self(<$inner>::from_u128(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
const fn from_raw(v: [u64; 4]) -> Self {
|
||||
Self(<$inner>::from_raw(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_uniform_bytes(bytes: [u8; 64]) -> Self {
|
||||
Self(<$inner>::from_uniform_bytes(&bytes))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn random() -> Self {
|
||||
Self(<$inner>::random(&mut OsRng))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn modulus() -> &'static str {
|
||||
<$inner>::MODULUS
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn zero() -> Self {
|
||||
Self(<$inner>::ZERO)
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn one() -> Self {
|
||||
Self(<$inner>::ONE)
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
Self(self.0.double())
|
||||
}
|
||||
|
||||
fn square(&self) -> Self {
|
||||
Self(self.0.square())
|
||||
}
|
||||
|
||||
fn __str__(&self) -> PyResult<String> {
|
||||
Ok(format!("{:?}", self.0))
|
||||
}
|
||||
|
||||
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
|
||||
let class_name: &str = slf.get_type().name()?;
|
||||
Ok(format!("{}({:?})", class_name, slf.borrow().0))
|
||||
}
|
||||
|
||||
fn __add__(&self, other: &Self) -> Self {
|
||||
Self(self.0 + other.0)
|
||||
}
|
||||
|
||||
fn __sub__(&self, other: &Self) -> Self {
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
|
||||
fn __mul__(&self, other: &Self) -> Self {
|
||||
Self(self.0 * other.0)
|
||||
}
|
||||
|
||||
fn __neg__(&self) -> Self {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
|
||||
match op {
|
||||
CompareOp::Lt => Ok(self.0 < other.0),
|
||||
CompareOp::Le => Ok(self.0 <= other.0),
|
||||
CompareOp::Eq => Ok(self.0 == other.0),
|
||||
CompareOp::Ne => Ok(self.0 != other.0),
|
||||
CompareOp::Gt => Ok(self.0 > other.0),
|
||||
CompareOp::Ge => Ok(self.0 >= other.0),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_json(&self) -> PyResult<String> {
|
||||
self.__str__()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_affine {
|
||||
($x:ty, $inner:ty, $base:ident, $projective:ty) => {
|
||||
#[pymethods]
|
||||
impl $x {
|
||||
fn coordinates(&self) -> ($base, $base) {
|
||||
let coords = self.0.coordinates().unwrap();
|
||||
($base(*coords.x()), $base(*coords.y()))
|
||||
}
|
||||
|
||||
fn coordinates_str(&self) -> PyResult<Vec<String>> {
|
||||
let coords = self.0.coordinates().unwrap();
|
||||
let x = $base(*coords.x()).__str__()?;
|
||||
let y = $base(*coords.y()).__str__()?;
|
||||
Ok(vec![x, y])
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_xy(x: &PyCell<$base>, y: &PyCell<$base>) -> PyResult<Self> {
|
||||
let affine_point =
|
||||
<$inner>::from_xy(x.borrow().deref().0, y.borrow().deref().0).unwrap();
|
||||
Ok(Self(affine_point))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_projective(x: &PyCell<$projective>) -> Self {
|
||||
Self(<$inner>::from(x.borrow().deref().0))
|
||||
}
|
||||
|
||||
fn __str__(&self) -> String {
|
||||
format!("{:?}", self.0)
|
||||
}
|
||||
|
||||
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
|
||||
let class_name: &str = slf.get_type().name()?;
|
||||
Ok(format!("{}({:?})", class_name, slf.borrow().0))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_point {
|
||||
($x:ty, $inner:ty, $base:ty, $scalar:ty, $affine:ty) => {
|
||||
#[pymethods]
|
||||
impl $x {
|
||||
#[new]
|
||||
fn new(x: &PyCell<$base>, y: &PyCell<$base>) -> PyResult<Self> {
|
||||
let affine_point = <$affine>::from_xy(x, y).unwrap();
|
||||
Ok(Self::from_affine(affine_point))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn identity() -> Self {
|
||||
Self(<$inner>::identity())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn generator() -> Self {
|
||||
Self(<$inner>::generator())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn random() -> Self {
|
||||
Self(<$inner>::random(&mut OsRng))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_affine(p: $affine) -> Self {
|
||||
Self(<$inner>::from(p.0))
|
||||
}
|
||||
|
||||
fn __str__(slf: &PyCell<Self>) -> PyResult<String> {
|
||||
let affine = <$affine>::from_projective(slf);
|
||||
let (x, y) = affine.coordinates();
|
||||
Ok(format!("[{}, {}]", x.__str__()?, y.__str__()?))
|
||||
}
|
||||
|
||||
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
|
||||
let class_name: &str = slf.get_type().name()?;
|
||||
Ok(format!("{}({:?})", class_name, slf.borrow().0))
|
||||
}
|
||||
|
||||
fn __add__(&self, rhs: &Self) -> Self {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
|
||||
fn __sub__(&self, rhs: &Self) -> Self {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
|
||||
fn __mul__(&self, scalar: &$scalar) -> Self {
|
||||
Self(self.0 * scalar.0)
|
||||
}
|
||||
|
||||
fn __neg__(&self) -> Self {
|
||||
Self(-self.0)
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
|
||||
match op {
|
||||
CompareOp::Eq => Ok(self.0 == other.0),
|
||||
CompareOp::Ne => Ok(self.0 != other.0),
|
||||
CompareOp::Lt => unimplemented!(),
|
||||
CompareOp::Le => unimplemented!(),
|
||||
CompareOp::Gt => unimplemented!(),
|
||||
CompareOp::Ge => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// The base field of the Pallas curve and the scalar field of the Vesta curve.
|
||||
#[pyclass(dict)]
|
||||
#[derive(Copy, Clone, PartialEq, std::cmp::Eq, Ord, PartialOrd, Debug)]
|
||||
pub struct Fp(pub(crate) pallas::Base);
|
||||
impl_elem!(Fp, pallas::Base);
|
||||
|
||||
/// The scalar field of the Pallas curve and the base field of the Vesta curve.
|
||||
#[pyclass]
|
||||
#[derive(Copy, Clone, PartialEq, std::cmp::Eq, Ord, PartialOrd, Debug)]
|
||||
pub struct Fq(pub(crate) pallas::Scalar);
|
||||
impl_elem!(Fq, pallas::Scalar);
|
||||
|
||||
/// A Pallas curve point in the projective space
|
||||
#[pyclass]
|
||||
#[derive(Copy, Clone, PartialEq, std::cmp::Eq, Debug)]
|
||||
pub struct Ep(pub(crate) pallas::Point);
|
||||
impl_point!(Ep, pallas::Point, Fp, Fq, EpAffine);
|
||||
|
||||
/// A Pallas curve point in the affine space
|
||||
#[pyclass]
|
||||
#[derive(Copy, Clone, PartialEq, std::cmp::Eq, Debug)]
|
||||
pub struct EpAffine(pub(crate) pallas::Affine);
|
||||
impl_affine!(EpAffine, pallas::Affine, Fp, Ep);
|
||||
|
||||
/// A Vesta curve point in the projective space
|
||||
#[pyclass]
|
||||
#[derive(Copy, Clone, PartialEq, std::cmp::Eq, Debug)]
|
||||
pub struct Eq(pub(crate) vesta::Point);
|
||||
impl_point!(Eq, vesta::Point, Fq, Fp, EqAffine);
|
||||
|
||||
/// A Vesta curve point in the affine space
|
||||
#[pyclass]
|
||||
#[derive(Copy, Clone, PartialEq, std::cmp::Eq, Debug)]
|
||||
pub struct EqAffine(pub(crate) vesta::Affine);
|
||||
impl_affine!(EqAffine, vesta::Affine, Fq, Eq);
|
||||
|
||||
#[pyfunction]
|
||||
/// Return the NullifierK generator point as EpAffine.
|
||||
pub fn nullifier_k() -> EpAffine {
|
||||
EpAffine(NullifierK.generator())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
/// Convert Fp to Fq safely.
|
||||
pub fn mod_r_p(x: &PyCell<Fp>) -> PyResult<Fq> {
|
||||
Ok(Fq(util::mod_r_p(x.borrow().deref().0)))
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "pasta")?;
|
||||
|
||||
submod.add_class::<Fp>()?;
|
||||
submod.add_class::<Fq>()?;
|
||||
submod.add_class::<Ep>()?;
|
||||
submod.add_class::<EpAffine>()?;
|
||||
submod.add_class::<Eq>()?;
|
||||
submod.add_class::<EqAffine>()?;
|
||||
|
||||
submod.add_function(wrap_pyfunction!(nullifier_k, submod)?)?;
|
||||
submod.add_function(wrap_pyfunction!(mod_r_p, submod)?)?;
|
||||
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
constants::fixed_bases::{
|
||||
NullifierK, VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES,
|
||||
VALUE_COMMITMENT_V_BYTES,
|
||||
},
|
||||
util::mod_r_p,
|
||||
},
|
||||
pasta::{
|
||||
arithmetic::CurveExt,
|
||||
group::{Curve, Group},
|
||||
pallas,
|
||||
},
|
||||
};
|
||||
use halo2_gadgets::ecc::chip::FixedPoint;
|
||||
use pyo3::{basic::CompareOp, prelude::*};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use super::{affine::Affine, base::Base, scalar::Scalar};
|
||||
|
||||
/// A Pallas point in the projective coordinate space.
|
||||
#[pyclass]
|
||||
pub struct Point(pub(crate) pallas::Point);
|
||||
|
||||
#[pymethods]
|
||||
impl Point {
|
||||
#[staticmethod]
|
||||
fn identity() -> Self {
|
||||
Self(pallas::Point::identity())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn generator() -> Self {
|
||||
Self(pallas::Point::generator())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn mul_short(value: &Base) -> Self {
|
||||
let hasher = pallas::Point::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
|
||||
let v = hasher(&VALUE_COMMITMENT_V_BYTES);
|
||||
Self(v * mod_r_p(value.0))
|
||||
}
|
||||
|
||||
// Why value doesn't need to be a Pycell?
|
||||
#[staticmethod]
|
||||
fn mul_base(value: &Base) -> Self {
|
||||
let v = NullifierK.generator();
|
||||
Self(v * mod_r_p(value.0))
|
||||
}
|
||||
|
||||
// Why not a pycell?
|
||||
#[staticmethod]
|
||||
fn mul_r_generator(blind: &Scalar) -> Self {
|
||||
let hasher = pallas::Point::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
|
||||
let r = hasher(&VALUE_COMMITMENT_R_BYTES);
|
||||
let r = Self(r);
|
||||
Self(r.0 * blind.0)
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn random() -> Self {
|
||||
Self(pallas::Point::random(&mut OsRng))
|
||||
}
|
||||
|
||||
fn __str__(&self) -> String {
|
||||
format!("{:?}", self.0)
|
||||
}
|
||||
|
||||
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
|
||||
let class_name: &str = slf.get_type().name()?;
|
||||
Ok(format!("{}({:?})", class_name, slf.borrow().0))
|
||||
}
|
||||
|
||||
fn to_affine(&self) -> Affine {
|
||||
Affine(self.0.to_affine())
|
||||
}
|
||||
|
||||
fn __add__(&self, rhs: &Self) -> Self {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
|
||||
fn __sub__(&self, rhs: &Self) -> Self {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
|
||||
fn __mul__(&self, scalar: &Scalar) -> Self {
|
||||
Self(self.0 * scalar.0)
|
||||
}
|
||||
|
||||
fn __neg__(&self) -> Self {
|
||||
Self(-self.0)
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
|
||||
match op {
|
||||
CompareOp::Eq => Ok(self.0 == other.0),
|
||||
CompareOp::Ne => Ok(self.0 != other.0),
|
||||
CompareOp::Lt => todo!(),
|
||||
CompareOp::Le => todo!(),
|
||||
CompareOp::Gt => todo!(),
|
||||
CompareOp::Ge => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "point")?;
|
||||
submod.add_class::<Point>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi::zk::{proof, vm};
|
||||
use darkfi_sdk::pasta::pallas;
|
||||
use pyo3::prelude::*;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use super::{
|
||||
base::Base, proving_key::ProvingKey, verifying_key::VerifyingKey, zk_circuit::ZkCircuit,
|
||||
};
|
||||
|
||||
#[pyclass]
|
||||
pub struct Proof(pub(crate) proof::Proof);
|
||||
|
||||
#[pymethods]
|
||||
impl Proof {
|
||||
#[staticmethod]
|
||||
fn create(
|
||||
pk: &PyCell<ProvingKey>,
|
||||
circuits: Vec<&PyCell<ZkCircuit>>,
|
||||
instances: Vec<&PyCell<Base>>,
|
||||
) -> Self {
|
||||
let pk = pk.borrow().deref().0.clone();
|
||||
let circuits: Vec<vm::ZkCircuit> =
|
||||
circuits.iter().map(|c| c.borrow().deref().0.clone()).collect();
|
||||
let instances: Vec<pallas::Base> = instances.iter().map(|i| i.borrow().deref().0).collect();
|
||||
let proof =
|
||||
proof::Proof::create(&pk, circuits.as_slice(), instances.as_slice(), &mut OsRng);
|
||||
let proof = proof.unwrap();
|
||||
Self(proof)
|
||||
}
|
||||
|
||||
fn verify(&self, vk: &PyCell<VerifyingKey>, instances: Vec<&PyCell<Base>>) {
|
||||
let vk = vk.borrow().deref().0.clone();
|
||||
let proof = self.0.clone();
|
||||
let instances: Vec<pallas::Base> = instances.iter().map(|i| i.borrow().deref().0).collect();
|
||||
proof.verify(&vk, instances.as_slice()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "proof")?;
|
||||
submod.add_class::<Proof>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi::zk::{proof, vm};
|
||||
use pyo3::prelude::*;
|
||||
|
||||
use super::zk_circuit::ZkCircuit;
|
||||
|
||||
#[pyclass]
|
||||
pub struct ProvingKey(pub(crate) proof::ProvingKey);
|
||||
|
||||
#[pymethods]
|
||||
impl ProvingKey {
|
||||
#[staticmethod]
|
||||
fn build(k: u32, circuit: &PyCell<ZkCircuit>) -> Self {
|
||||
let circuit_ref = circuit.borrow();
|
||||
let circuit: &vm::ZkCircuit = &circuit_ref.deref().0;
|
||||
let proving_key = proof::ProvingKey::build(k, circuit);
|
||||
Self(proving_key)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "proving_key")?;
|
||||
submod.add_class::<ProvingKey>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use darkfi_sdk::{
|
||||
crypto::pasta_prelude::{Field, PrimeField},
|
||||
pasta::{group::ff::FromUniformBytes, pallas},
|
||||
};
|
||||
use pyo3::{basic::CompareOp, prelude::*};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
/// The scalar field of the Pallas and iso-Pallas curves.
|
||||
#[pyclass]
|
||||
pub struct Scalar(pub(crate) pallas::Scalar);
|
||||
|
||||
#[pymethods]
|
||||
impl Scalar {
|
||||
#[staticmethod]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
Self(pallas::Scalar::from(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_u128(v: u128) -> Self {
|
||||
Self(pallas::Scalar::from_u128(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_raw(v: [u64; 4]) -> Self {
|
||||
Self(pallas::Scalar::from_raw(v))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn from_uniform_bytes(bytes: [u8; 64]) -> Self {
|
||||
Self(pallas::Scalar::from_uniform_bytes(&bytes))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn random() -> Self {
|
||||
Self(pallas::Scalar::random(&mut OsRng))
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn modulus() -> String {
|
||||
pallas::Scalar::MODULUS.to_string()
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn zero() -> Self {
|
||||
Self(pallas::Scalar::zero())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn one() -> Self {
|
||||
Self(pallas::Scalar::one())
|
||||
}
|
||||
|
||||
fn __str__(&self) -> String {
|
||||
format!("{:?}", self.0)
|
||||
}
|
||||
|
||||
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
|
||||
let class_name: &str = slf.get_type().name()?;
|
||||
Ok(format!("{}({:?})", class_name, slf.borrow().0))
|
||||
}
|
||||
|
||||
fn __add__(&self, other: &Self) -> Self {
|
||||
Self(self.0 + other.0)
|
||||
}
|
||||
|
||||
fn __sub__(&self, other: &Self) -> Self {
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
|
||||
fn __mul__(&self, other: &Self) -> Self {
|
||||
Self(self.0 * other.0)
|
||||
}
|
||||
|
||||
fn __neg__(&self) -> Self {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
|
||||
match op {
|
||||
CompareOp::Lt => Ok(self.0 < other.0),
|
||||
CompareOp::Le => Ok(self.0 <= other.0),
|
||||
CompareOp::Eq => Ok(self.0 == other.0),
|
||||
CompareOp::Ne => Ok(self.0 != other.0),
|
||||
CompareOp::Gt => Ok(self.0 > other.0),
|
||||
CompareOp::Ge => Ok(self.0 >= other.0),
|
||||
}
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
Self(self.0.double())
|
||||
}
|
||||
|
||||
fn square(&self) -> Self {
|
||||
Self(self.0.square())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "scalar")?;
|
||||
submod.add_class::<Scalar>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi::zk::proof;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
use super::zk_circuit::ZkCircuit;
|
||||
|
||||
#[pyclass]
|
||||
pub struct VerifyingKey(pub(crate) proof::VerifyingKey);
|
||||
|
||||
#[pymethods]
|
||||
impl VerifyingKey {
|
||||
#[staticmethod]
|
||||
fn build(k: u32, circuit: &PyCell<ZkCircuit>) -> Self {
|
||||
let circuit_ref = circuit.borrow();
|
||||
let circuit = &circuit_ref.deref().0;
|
||||
let proving_key = proof::VerifyingKey::build(k, circuit);
|
||||
Self(proving_key)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "verifying_key")?;
|
||||
submod.add_class::<VerifyingKey>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use darkfi::zkas::decoder;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[pyclass]
|
||||
pub struct ZkBinary(pub(crate) decoder::ZkBinary);
|
||||
|
||||
/// There is no need for constants, as bindings for ec_mul_short and ec_mul_base
|
||||
/// don't actually take the constants.
|
||||
/// The constants are hardcoded on the Rust side.
|
||||
#[pymethods]
|
||||
impl ZkBinary {
|
||||
#[staticmethod]
|
||||
fn decode(bytes: Vec<u8>) -> Self {
|
||||
let bincode = decoder::ZkBinary::decode(bytes.as_slice()).unwrap();
|
||||
Self(bincode)
|
||||
}
|
||||
|
||||
fn namespace(&self) -> String {
|
||||
self.0.namespace.clone()
|
||||
}
|
||||
|
||||
fn literals(&self) -> Vec<(String, String)> {
|
||||
let l = self.0.literals.clone();
|
||||
l.iter().map(|(lit, value)| (format!("{lit:?}"), value.clone())).collect()
|
||||
}
|
||||
|
||||
fn witnesses(&self) -> Vec<String> {
|
||||
let w = self.0.witnesses.clone();
|
||||
w.iter().map(|v| format!("{v:?}")).collect()
|
||||
}
|
||||
|
||||
fn constant_count(&self) -> usize {
|
||||
self.0.constants.len()
|
||||
}
|
||||
|
||||
fn opcodes(&self) -> Vec<(String, Vec<(String, usize)>)> {
|
||||
let o = self.0.opcodes.clone();
|
||||
o.iter()
|
||||
.map(|(opcode_, args_)| {
|
||||
let opcode = format!("{opcode_:?}");
|
||||
let args = args_
|
||||
.iter()
|
||||
.map(|(heap_type, heap_idx)| (format!("{heap_type:?}"), *heap_idx))
|
||||
.collect();
|
||||
(opcode, args)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn k(&self) -> u32 {
|
||||
self.0.k
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "zk_binary")?;
|
||||
submod.add_class::<ZkBinary>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi::zk::{halo2::Value, vm, vm_heap::empty_witnesses};
|
||||
use darkfi_sdk::crypto::MerkleNode;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
use super::{base::Base, point::Point, scalar::Scalar, zk_binary::ZkBinary};
|
||||
|
||||
#[pyclass]
|
||||
pub struct ZkCircuit(pub(crate) vm::ZkCircuit, pub(crate) Vec<vm::Witness>);
|
||||
|
||||
/// Like Builder Object
|
||||
#[pymethods]
|
||||
impl ZkCircuit {
|
||||
#[new]
|
||||
fn new(circuit_code: &PyCell<ZkBinary>) -> Self {
|
||||
let circuit_code = circuit_code.borrow().deref().0.clone();
|
||||
// DUMMY CIRCUIT
|
||||
let circuit = vm::ZkCircuit::new(vec![], &circuit_code);
|
||||
Self(circuit, vec![])
|
||||
}
|
||||
|
||||
fn build(&self, circuit_code: &PyCell<ZkBinary>) -> Self {
|
||||
let circuit_code = circuit_code.borrow().deref().0.clone();
|
||||
let circuit = vm::ZkCircuit::new(self.1.clone(), &circuit_code);
|
||||
Self(circuit, self.1.clone())
|
||||
}
|
||||
|
||||
fn verifier_build(&self, circuit_code: &PyCell<ZkBinary>) -> Self {
|
||||
let circuit_code = circuit_code.borrow().deref().0.clone();
|
||||
let circuit = vm::ZkCircuit::new(empty_witnesses(&circuit_code).unwrap(), &circuit_code);
|
||||
Self(circuit, self.1.clone())
|
||||
}
|
||||
|
||||
fn witness_point(&mut self, v: &PyCell<Point>) {
|
||||
let v = v.borrow();
|
||||
let v = v.deref();
|
||||
self.1.push(vm::Witness::EcPoint(Value::known(v.0)));
|
||||
}
|
||||
|
||||
fn witness_ni_point(&mut self, v: &PyCell<Point>) {
|
||||
let v = v.borrow();
|
||||
let v = v.deref();
|
||||
self.1.push(vm::Witness::EcNiPoint(Value::known(v.0)));
|
||||
}
|
||||
|
||||
fn witness_fixed_point(&mut self, v: &PyCell<Point>) {
|
||||
let v = v.borrow();
|
||||
let v = v.deref();
|
||||
self.1.push(vm::Witness::EcFixedPoint(Value::known(v.0)));
|
||||
}
|
||||
|
||||
fn witness_scalar(&mut self, v: &PyCell<Scalar>) {
|
||||
let v = v.borrow();
|
||||
let v = v.deref();
|
||||
self.1.push(vm::Witness::Scalar(Value::known(v.0)));
|
||||
}
|
||||
|
||||
fn witness_base(&mut self, v: &PyCell<Base>) {
|
||||
let v = v.borrow();
|
||||
let v = v.deref();
|
||||
self.1.push(vm::Witness::Base(Value::known(v.0)));
|
||||
}
|
||||
|
||||
fn witness_merkle_path(&mut self, v: Vec<&PyCell<Base>>) {
|
||||
let v: Vec<MerkleNode> = v.iter().map(|v| MerkleNode::new(v.borrow().deref().0)).collect();
|
||||
let v: [MerkleNode; 32] = v.try_into().unwrap();
|
||||
let v = Value::known(v);
|
||||
self.1.push(vm::Witness::MerklePath(v));
|
||||
}
|
||||
|
||||
fn witness_u32(&mut self, v: u32) {
|
||||
self.1.push(vm::Witness::Uint32(Value::known(v)));
|
||||
}
|
||||
|
||||
fn witness_u64(&mut self, v: u64) {
|
||||
self.1.push(vm::Witness::Uint64(Value::known(v)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "zk_circuit")?;
|
||||
submod.add_class::<ZkCircuit>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
209
src/sdk/python/src/zkas.rs
Normal file
209
src/sdk/python/src/zkas.rs
Normal file
@@ -0,0 +1,209 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use darkfi::{
|
||||
zk::{self, empty_witnesses, halo2::Value},
|
||||
zkas::decoder,
|
||||
};
|
||||
use darkfi_sdk::{crypto::MerkleNode, pasta::pallas};
|
||||
use pyo3::{pyclass, pymethods, types::PyModule, PyCell, PyResult, Python};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use super::pasta::{Ep, Fp, Fq};
|
||||
|
||||
#[pyclass]
|
||||
/// Decoded zkas bincode
|
||||
pub struct ZkBinary(decoder::ZkBinary);
|
||||
|
||||
#[pymethods]
|
||||
impl ZkBinary {
|
||||
#[new]
|
||||
fn new(bytes: Vec<u8>) -> Self {
|
||||
Self::decode(bytes)
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn decode(bytes: Vec<u8>) -> Self {
|
||||
let bincode = decoder::ZkBinary::decode(bytes.as_slice()).unwrap();
|
||||
Self(bincode)
|
||||
}
|
||||
|
||||
fn k(&self) -> u32 {
|
||||
self.0.k
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
/// Class representing a zkVM circuit, the witness values, and the zkas binary
|
||||
/// defining the circuit code path.
|
||||
pub struct ZkCircuit(zk::vm::ZkCircuit, Vec<zk::vm::Witness>, decoder::ZkBinary);
|
||||
|
||||
#[pymethods]
|
||||
impl ZkCircuit {
|
||||
#[new]
|
||||
fn new(zkbin: &PyCell<ZkBinary>) -> Self {
|
||||
let zkbin = zkbin.borrow().deref().0.clone();
|
||||
let circuit = zk::vm::ZkCircuit::new(vec![], &zkbin);
|
||||
Self(circuit, vec![], zkbin)
|
||||
}
|
||||
|
||||
fn prover_build(&self) -> Self {
|
||||
let circuit = zk::vm::ZkCircuit::new(self.1.clone(), &self.2);
|
||||
Self(circuit, self.1.clone(), self.2.clone())
|
||||
}
|
||||
|
||||
fn verifier_build(&self) -> Self {
|
||||
let witnesses = empty_witnesses(&self.2).unwrap();
|
||||
let circuit = zk::vm::ZkCircuit::new(witnesses.clone(), &self.2);
|
||||
Self(circuit, witnesses, self.2.clone())
|
||||
}
|
||||
|
||||
fn witness_ecpoint(&mut self, w: &PyCell<Ep>) {
|
||||
let w = w.borrow();
|
||||
let w = w.deref();
|
||||
self.1.push(zk::vm::Witness::EcPoint(Value::known(w.0)));
|
||||
}
|
||||
|
||||
fn witness_ecnipoint(&mut self, w: &PyCell<Ep>) {
|
||||
let w = w.borrow();
|
||||
let w = w.deref();
|
||||
self.1.push(zk::vm::Witness::EcNiPoint(Value::known(w.0)));
|
||||
}
|
||||
|
||||
fn witness_base(&mut self, w: &PyCell<Fp>) {
|
||||
let w = w.borrow();
|
||||
let w = w.deref();
|
||||
self.1.push(zk::vm::Witness::Base(Value::known(w.0)));
|
||||
}
|
||||
|
||||
fn witness_scalar(&mut self, w: &PyCell<Fq>) {
|
||||
let w = w.borrow();
|
||||
let w = w.deref();
|
||||
self.1.push(zk::vm::Witness::Scalar(Value::known(w.0)));
|
||||
}
|
||||
|
||||
fn witness_merklepath(&mut self, w: Vec<&PyCell<Fp>>) {
|
||||
assert!(w.len() == 32);
|
||||
let path: Vec<MerkleNode> =
|
||||
w.iter().map(|x| MerkleNode::from(x.borrow().deref().0)).collect();
|
||||
self.1.push(zk::vm::Witness::MerklePath(Value::known(path.try_into().unwrap())));
|
||||
}
|
||||
|
||||
fn witness_uint32(&mut self, w: u32) {
|
||||
self.1.push(zk::vm::Witness::Uint32(Value::known(w)));
|
||||
}
|
||||
|
||||
fn witness_uint64(&mut self, w: u64) {
|
||||
self.1.push(zk::vm::Witness::Uint64(Value::known(w)));
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
/// Verifying key for a zkVM proof
|
||||
pub struct VerifyingKey(zk::proof::VerifyingKey);
|
||||
|
||||
#[pymethods]
|
||||
impl VerifyingKey {
|
||||
#[staticmethod]
|
||||
fn build(k: u32, circuit: &PyCell<ZkCircuit>) -> Self {
|
||||
let circuit_ref = circuit.borrow();
|
||||
let circuit = &circuit_ref.deref().0;
|
||||
let vk = zk::proof::VerifyingKey::build(k, circuit);
|
||||
Self(vk)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
/// Proving key for a zkVM proof
|
||||
pub struct ProvingKey(zk::proof::ProvingKey);
|
||||
|
||||
#[pymethods]
|
||||
impl ProvingKey {
|
||||
#[staticmethod]
|
||||
fn build(k: u32, circuit: &PyCell<ZkCircuit>) -> Self {
|
||||
let circuit_ref = circuit.borrow();
|
||||
let circuit = &circuit_ref.deref().0;
|
||||
let pk = zk::proof::ProvingKey::build(k, circuit);
|
||||
Self(pk)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
/// A zkVM proof
|
||||
pub struct Proof(zk::proof::Proof);
|
||||
|
||||
#[pymethods]
|
||||
impl Proof {
|
||||
#[staticmethod]
|
||||
fn create(
|
||||
pk: &PyCell<ProvingKey>,
|
||||
circuits: Vec<&PyCell<ZkCircuit>>,
|
||||
instances: Vec<&PyCell<Fp>>,
|
||||
) -> Self {
|
||||
let pk = pk.borrow().deref().0.clone();
|
||||
let circuits: Vec<zk::vm::ZkCircuit> =
|
||||
circuits.iter().map(|c| c.borrow().deref().0.clone()).collect();
|
||||
let instances: Vec<pallas::Base> = instances.iter().map(|i| i.borrow().deref().0).collect();
|
||||
|
||||
let proof =
|
||||
zk::proof::Proof::create(&pk, circuits.as_slice(), instances.as_slice(), &mut OsRng)
|
||||
.unwrap();
|
||||
Self(proof)
|
||||
}
|
||||
|
||||
fn verify(&self, vk: &PyCell<VerifyingKey>, instances: Vec<&PyCell<Fp>>) {
|
||||
let vk = vk.borrow().deref().0.clone();
|
||||
let instances: Vec<pallas::Base> = instances.iter().map(|i| i.borrow().deref().0).collect();
|
||||
self.0.verify(&vk, instances.as_slice()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
/// MockProver class used for fast proof creation and verification.
|
||||
/// Doesn't offer any security and should not be used in production.
|
||||
pub struct MockProver(zk::halo2::dev::MockProver<pallas::Base>);
|
||||
|
||||
#[pymethods]
|
||||
impl MockProver {
|
||||
#[staticmethod]
|
||||
fn run(k: u32, circuit: &PyCell<ZkCircuit>, instances: Vec<&PyCell<Fp>>) -> Self {
|
||||
let circuit = circuit.borrow().deref().0.clone();
|
||||
let instances: Vec<pallas::Base> = instances.iter().map(|i| i.borrow().deref().0).collect();
|
||||
let prover = zk::halo2::dev::MockProver::run(k, &circuit, vec![instances]).unwrap();
|
||||
Self(prover)
|
||||
}
|
||||
|
||||
fn verify(&self) {
|
||||
self.0.assert_satisfied();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: Python<'_>) -> PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "zkas")?;
|
||||
|
||||
submod.add_class::<ZkBinary>()?;
|
||||
submod.add_class::<ZkCircuit>()?;
|
||||
submod.add_class::<VerifyingKey>()?;
|
||||
submod.add_class::<ProvingKey>()?;
|
||||
submod.add_class::<Proof>()?;
|
||||
submod.add_class::<MockProver>()?;
|
||||
|
||||
Ok(submod)
|
||||
}
|
||||
Reference in New Issue
Block a user