mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
sdk-py: Move to src/sdk/python
This commit is contained in:
72
src/sdk/python/.gitignore
vendored
Normal file
72
src/sdk/python/.gitignore
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/target
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
.venv/
|
||||
env/
|
||||
bin/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
include/
|
||||
man/
|
||||
venv/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
pip-selfcheck.json
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# Rope
|
||||
.ropeproject
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
*.pot
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyCharm
|
||||
.idea/
|
||||
|
||||
# VSCode
|
||||
.vscode/
|
||||
|
||||
# Pyenv
|
||||
.python-version
|
||||
22
src/sdk/python/Cargo.toml
Normal file
22
src/sdk/python/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "darkfi-sdk-py"
|
||||
description = "Python bindings for Darkfi SDK"
|
||||
version = "0.4.1"
|
||||
edition = "2021"
|
||||
authors = ["Dyne.org foundation <foundation@dyne.org>"]
|
||||
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"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
darkfi = { path = "../../../", features = ["zk", "zkas"] }
|
||||
darkfi-sdk = { path = "../" }
|
||||
halo2_gadgets = "0.3.0"
|
||||
pasta_curves = "0.5.1"
|
||||
pyo3 = "0.19.0"
|
||||
rand = "0.8.5"
|
||||
3
src/sdk/python/README.md
Normal file
3
src/sdk/python/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Installation
|
||||
|
||||
Follow virtualenv and pyo3 setup guide: https://pyo3.rs/v0.15.1/#using-rust-from-python
|
||||
16
src/sdk/python/pyproject.toml
Normal file
16
src/sdk/python/pyproject.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[build-system]
|
||||
requires = ["maturin>=1.0,<2.0"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "darkfi-sdk-py"
|
||||
requires-python = ">=3.8"
|
||||
classifiers = [
|
||||
"Programming Language :: Rust",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
]
|
||||
|
||||
|
||||
[tool.maturin]
|
||||
features = ["pyo3/extension-module"]
|
||||
43
src/sdk/python/src/affine.rs
Normal file
43
src/sdk/python/src/affine.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
/* 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 crate::base::Base;
|
||||
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
||||
use pyo3::prelude::*;
|
||||
|
||||
/// 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)
|
||||
}
|
||||
195
src/sdk/python/src/base.rs
Normal file
195
src/sdk/python/src/base.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
/* 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::{
|
||||
bridgetree::Hashable,
|
||||
crypto::{poseidon_hash, MerkleNode},
|
||||
};
|
||||
use pasta_curves::{
|
||||
group::ff::{Field, FromUniformBytes, PrimeField},
|
||||
pallas,
|
||||
};
|
||||
use pyo3::prelude::*;
|
||||
use rand::rngs::OsRng;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// The base field of the Pallas and iso-Pallas curves.
|
||||
/// Randomness is provided by the OS and on the Rust side.
|
||||
#[pyclass]
|
||||
pub struct Base(pub(crate) pallas::Base);
|
||||
|
||||
#[pymethods]
|
||||
impl Base {
|
||||
// Why is this not callable?
|
||||
#[new]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
Self(pallas::Base::from(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)
|
||||
}
|
||||
|
||||
// For some reason, the name needs to be explictely stated
|
||||
// for Python to correctly implement
|
||||
#[pyo3(name = "__str__")]
|
||||
fn __str_(&self) -> String {
|
||||
format!("Base({:?})", self.0)
|
||||
}
|
||||
|
||||
#[pyo3(name = "__repr__")]
|
||||
fn __repr_(&self) -> String {
|
||||
format!("Base({:?})", self.0)
|
||||
}
|
||||
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
self.0.eq(&rhs.0)
|
||||
}
|
||||
|
||||
fn add(&self, rhs: &Self) -> Self {
|
||||
Self(self.0.add(&rhs.0))
|
||||
}
|
||||
|
||||
fn sub(&self, rhs: &Self) -> Self {
|
||||
Self(self.0.sub(&rhs.0))
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
Self(self.0.double())
|
||||
}
|
||||
|
||||
fn mul(&self, rhs: &Self) -> Self {
|
||||
Self(self.0.mul(&rhs.0))
|
||||
}
|
||||
|
||||
fn neg(&self) -> Self {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
76
src/sdk/python/src/lib.rs
Normal file
76
src/sdk/python/src/lib.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
|
||||
mod affine;
|
||||
mod base;
|
||||
mod point;
|
||||
mod proof;
|
||||
mod proving_key;
|
||||
mod scalar;
|
||||
mod verifying_key;
|
||||
mod zk_binary;
|
||||
mod zk_circuit;
|
||||
|
||||
#[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");
|
||||
m.add_submodule(submodule)?;
|
||||
|
||||
let submodule = base::create_module(py)?;
|
||||
pyo3::py_run!(py, submodule, "import sys; sys.modules['darkfi_sdk_py.base'] = 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 = 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)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
100
src/sdk/python/src/point.rs
Normal file
100
src/sdk/python/src/point.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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 crate::{affine::Affine, base::Base, scalar::Scalar};
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
constants::fixed_bases::{
|
||||
NullifierK, VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES,
|
||||
VALUE_COMMITMENT_V_BYTES,
|
||||
},
|
||||
util::mod_r_p,
|
||||
ValueCommit,
|
||||
},
|
||||
pasta::{
|
||||
arithmetic::CurveExt,
|
||||
group::{Curve, Group},
|
||||
},
|
||||
};
|
||||
use halo2_gadgets::ecc::chip::FixedPoint;
|
||||
use pasta_curves::pallas;
|
||||
use pyo3::prelude::*;
|
||||
use std::ops::{Add, Mul};
|
||||
|
||||
/// 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 = ValueCommit::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 = ValueCommit::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
|
||||
let r = hasher(&VALUE_COMMITMENT_R_BYTES);
|
||||
let r = Self(r);
|
||||
r.mul(blind)
|
||||
}
|
||||
|
||||
#[pyo3(name = "__str__")]
|
||||
fn __str__(&self) -> String {
|
||||
format!("Point({:?})", self.0)
|
||||
}
|
||||
|
||||
fn to_affine(&self) -> Affine {
|
||||
Affine(self.0.to_affine())
|
||||
}
|
||||
|
||||
fn add(&self, rhs: &Self) -> Self {
|
||||
Self(self.0.add(rhs.0))
|
||||
}
|
||||
|
||||
fn mul(&self, scalar: &Scalar) -> Self {
|
||||
Self(self.0.mul(scalar.0))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "point")?;
|
||||
submod.add_class::<Point>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
61
src/sdk/python/src/proof.rs
Normal file
61
src/sdk/python/src/proof.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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 crate::{
|
||||
base::Base, proving_key::ProvingKey, verifying_key::VerifyingKey, zk_circuit::ZkCircuit,
|
||||
};
|
||||
use darkfi::zk::{proof, vm};
|
||||
use pasta_curves::pallas;
|
||||
use pyo3::prelude::*;
|
||||
use rand::rngs::OsRng;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[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)
|
||||
}
|
||||
42
src/sdk/python/src/proving_key.rs
Normal file
42
src/sdk/python/src/proving_key.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 crate::zk_circuit::ZkCircuit;
|
||||
use darkfi::zk::{proof, vm};
|
||||
use pyo3::prelude::*;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[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)
|
||||
}
|
||||
99
src/sdk/python/src/scalar.rs
Normal file
99
src/sdk/python/src/scalar.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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};
|
||||
use pasta_curves::pallas;
|
||||
use pyo3::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 {
|
||||
#[new]
|
||||
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 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())
|
||||
}
|
||||
|
||||
#[pyo3(name = "__str__")]
|
||||
fn __str__(&self) -> String {
|
||||
format!("Scalar({:?})", self.0)
|
||||
}
|
||||
|
||||
#[pyo3(name = "__repr__")]
|
||||
fn __repr__(&self) -> String {
|
||||
format!("Scalar({:?})", self.0)
|
||||
}
|
||||
|
||||
fn add(&self, rhs: &Self) -> Self {
|
||||
Self(self.0.add(&rhs.0))
|
||||
}
|
||||
|
||||
fn sub(&self, rhs: &Self) -> Self {
|
||||
Self(self.0.sub(&rhs.0))
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
Self(self.0.double())
|
||||
}
|
||||
|
||||
fn mul(&self, rhs: &Self) -> Self {
|
||||
Self(self.0.mul(&rhs.0))
|
||||
}
|
||||
|
||||
fn neg(&self) -> Self {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
42
src/sdk/python/src/verifying_key.rs
Normal file
42
src/sdk/python/src/verifying_key.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 crate::zk_circuit::ZkCircuit;
|
||||
use darkfi::zk::proof;
|
||||
use pyo3::prelude::*;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[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)
|
||||
}
|
||||
73
src/sdk/python/src/zk_binary.rs
Normal file
73
src/sdk/python/src/zk_binary.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 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()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&PyModule> {
|
||||
let submod = PyModule::new(py, "zk_binary")?;
|
||||
submod.add_class::<ZkBinary>()?;
|
||||
Ok(submod)
|
||||
}
|
||||
101
src/sdk/python/src/zk_circuit.rs
Normal file
101
src/sdk/python/src/zk_circuit.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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 crate::{base::Base, point::Point, scalar::Scalar, zk_binary::ZkBinary};
|
||||
use darkfi::zk::{halo2::Value, vm, vm_heap::empty_witnesses};
|
||||
use darkfi_sdk::crypto::MerkleNode;
|
||||
use pyo3::prelude::*;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[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), circuit_code.clone());
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user