From d5e92ed5478ea22df2e4b93c8ad02830098ebbb5 Mon Sep 17 00:00:00 2001 From: Rodrigo Ferreira Date: Mon, 19 Aug 2024 18:49:32 -0300 Subject: [PATCH] Package/wheels distribution via maturin (#153) Co-authored-by: feltroidprime --- .github/workflows/hydra.yml | 3 +- .github/workflows/maturin.yml | 171 ++++++++++++++++++ hydra/garaga/definitions.py | 2 +- hydra/garaga/hints/ecip.py | 3 +- hydra/garaga/hints/multi_miller_witness.py | 3 +- hydra/garaga/poseidon_transcript.py | 2 +- pyproject.toml | 23 +++ tools/garaga_rs/Cargo.toml | 5 +- tools/garaga_rs/src/ecip/core.rs | 193 +++++++-------------- tools/garaga_rs/src/lib.rs | 183 +++++++++++-------- tools/make/setup.sh | 2 - 11 files changed, 375 insertions(+), 215 deletions(-) create mode 100644 .github/workflows/maturin.yml diff --git a/.github/workflows/hydra.yml b/.github/workflows/hydra.yml index d5d0a73d..deb2b216 100644 --- a/.github/workflows/hydra.yml +++ b/.github/workflows/hydra.yml @@ -47,8 +47,7 @@ jobs: - name: Compile Rust bindings with maturin run: | source venv/bin/activate - cd tools/garaga_rs - cargo test + (cd tools/garaga_rs && cargo fmt --check && cargo test) maturin develop --release - name: Run pytest run: | diff --git a/.github/workflows/maturin.yml b/.github/workflows/maturin.yml new file mode 100644 index 00000000..58ccc17b --- /dev/null +++ b/.github/workflows/maturin.yml @@ -0,0 +1,171 @@ +# This file is autogenerated by maturin v1.7.0 +# To update, run +# +# maturin generate-ci github +# +name: CI + +on: + push: + branches: + - main + - master + tags: + - '*' + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + linux: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-latest + target: x86_64 + - runner: ubuntu-latest + target: x86 + - runner: ubuntu-latest + target: aarch64 + - runner: ubuntu-latest + target: armv7 + - runner: ubuntu-latest + target: s390x + - runner: ubuntu-latest + target: ppc64le + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + manylinux: auto + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-linux-${{ matrix.platform.target }} + path: dist + + musllinux: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-latest + target: x86_64 + - runner: ubuntu-latest + target: x86 + - runner: ubuntu-latest + target: aarch64 + - runner: ubuntu-latest + target: armv7 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + manylinux: musllinux_1_2 + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-musllinux-${{ matrix.platform.target }} + path: dist + + windows: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: windows-latest + target: x64 + - runner: windows-latest + target: x86 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + architecture: ${{ matrix.platform.target }} + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-windows-${{ matrix.platform.target }} + path: dist + + macos: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: macos-12 + target: x86_64 + - runner: macos-14 + target: aarch64 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + # Workaround to ensure python 3.10 is available on x86_64 + python-version: ${{ matrix.platform.target == 'x86_64' && '3.10' || '3.x' }} + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-macos-${{ matrix.platform.target }} + path: dist + + sdist: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build sdist + uses: PyO3/maturin-action@v1 + with: + command: sdist + args: --out dist + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: wheels-sdist + path: dist + + release: + name: Release + runs-on: ubuntu-latest + # Note this will only run when a new tag is pushed + if: "startsWith(github.ref, 'refs/tags/')" + needs: [linux, musllinux, windows, macos, sdist] + steps: + - uses: actions/download-artifact@v4 + - name: Publish to PyPI + uses: PyO3/maturin-action@v1 + env: + MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + with: + command: upload + args: --non-interactive --skip-existing wheels-*/* diff --git a/hydra/garaga/definitions.py b/hydra/garaga/definitions.py index c07e8d80..2bf01a95 100644 --- a/hydra/garaga/definitions.py +++ b/hydra/garaga/definitions.py @@ -4,10 +4,10 @@ from enum import Enum from typing import TypeAlias -import garaga_rs from fastecdsa import curvemath from starkware.python.math_utils import EcInfinity, ec_safe_add, ec_safe_mult +from garaga import garaga_rs from garaga.algebra import ( BaseField, BaseFp2Field, diff --git a/hydra/garaga/hints/ecip.py b/hydra/garaga/hints/ecip.py index f000580f..fdaf6d07 100644 --- a/hydra/garaga/hints/ecip.py +++ b/hydra/garaga/hints/ecip.py @@ -4,8 +4,7 @@ import functools from dataclasses import dataclass -import garaga_rs - +from garaga import garaga_rs from garaga.algebra import Fp2, FunctionFelt, Polynomial, PyFelt, RationalFunction, T from garaga.definitions import CURVES, CurveID, G1Point, G2Point, get_base_field from garaga.hints.neg_3 import ( diff --git a/hydra/garaga/hints/multi_miller_witness.py b/hydra/garaga/hints/multi_miller_witness.py index bcab9013..13f228cd 100644 --- a/hydra/garaga/hints/multi_miller_witness.py +++ b/hydra/garaga/hints/multi_miller_witness.py @@ -1,7 +1,6 @@ import math -import garaga_rs - +from garaga import garaga_rs from garaga.algebra import PyFelt from garaga.definitions import CURVES, CurveID, G1G2Pair, G1Point, G2Point from garaga.hints.bls import get_root_and_scaling_factor_bls diff --git a/hydra/garaga/poseidon_transcript.py b/hydra/garaga/poseidon_transcript.py index ff5b0649..ae836898 100644 --- a/hydra/garaga/poseidon_transcript.py +++ b/hydra/garaga/poseidon_transcript.py @@ -1,9 +1,9 @@ -import garaga_rs from starkware.cairo.common.poseidon_utils import PoseidonParams from starkware.cairo.common.poseidon_utils import ( hades_permutation as hades_permutation_slow, # #only for testing times ) +from garaga import garaga_rs from garaga.algebra import ModuloCircuitElement, PyFelt from garaga.definitions import BASE, N_LIMBS, STARK from garaga.hints.io import bigint_split diff --git a/pyproject.toml b/pyproject.toml index 6388799a..fc539055 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,28 @@ +[build-system] +requires = ["maturin>=1.7,<2.0"] +build-backend = "maturin" + [project] +name = "garaga" requires-python = ">=3.10,<3.11" +dependencies = [ + "cairo-lang==0.13.2a0", + "fastecdsa", + "sympy", + "typer", + "web3==5.31.0" +] + +[project.scripts] +garaga = "garaga.starknet.starknet_cli:app" + +[tool.maturin] +features = ["pyo3/extension-module"] +manifest-path = "tools/garaga_rs/Cargo.toml" +# configures rust package as a module under garaga +module-name = "garaga.garaga_rs" +# python source root must be under / +python-source = "hydra" [tool.isort] profile = "black" diff --git a/tools/garaga_rs/Cargo.toml b/tools/garaga_rs/Cargo.toml index 27138806..bf622932 100644 --- a/tools/garaga_rs/Cargo.toml +++ b/tools/garaga_rs/Cargo.toml @@ -4,9 +4,12 @@ version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "garaga_rs" +crate-type = ["cdylib"] [dependencies] -pyo3 = { version = "0.15", features = ["extension-module", "num-bigint"] } +pyo3 = { version = "0.22", features = ["extension-module", "num-bigint"] } num-bigint = "0.4" num-traits = "0.2" ark-bn254 = "0.4" diff --git a/tools/garaga_rs/src/ecip/core.rs b/tools/garaga_rs/src/ecip/core.rs index 73103408..611be8f0 100644 --- a/tools/garaga_rs/src/ecip/core.rs +++ b/tools/garaga_rs/src/ecip/core.rs @@ -12,33 +12,21 @@ use crate::ecip::rational_function::FunctionFelt; use crate::ecip::rational_function::RationalFunction; use num_bigint::{BigInt, BigUint, ToBigInt}; -use pyo3::{prelude::*, types::PyList}; use super::curve::CurveParamsProvider; -#[pyfunction] pub fn zk_ecip_hint( - py: Python, - py_list_1: &PyList, - py_list_2: &PyList, + list_bytes: Vec>, + list_scalars: Vec, curve_id: usize, -) -> PyResult { +) -> Result<[Vec; 5], String> { match curve_id { 0 => { - let list_bytes: Vec<&[u8]> = py_list_1 - .into_iter() - .map(|x| x.extract()) - .collect::, _>>()?; - let list_felts: Vec> = list_bytes .into_iter() .map(|x| { - FieldElement::::from_bytes_be(x).map_err(|e| { - PyErr::new::(format!( - "Byte conversion error: {:?}", - e - )) - }) + FieldElement::::from_bytes_be(&x) + .map_err(|e| format!("Byte conversion error: {:?}", e)) }) .collect::>, _>>()?; @@ -47,24 +35,15 @@ pub fn zk_ecip_hint( .map(|chunk| G1Point::new(chunk[0].clone(), chunk[1].clone())) .collect(); - let scalars: Vec> = extract_scalars::(py_list_2)?; - run_ecip::(py, points, scalars) + let scalars: Vec> = extract_scalars::(list_scalars); + Ok(run_ecip::(points, scalars)) } 1 => { - let list_bytes: Vec<&[u8]> = py_list_1 - .into_iter() - .map(|x| x.extract()) - .collect::, _>>()?; - let list_felts: Vec> = list_bytes .into_iter() .map(|x| { - FieldElement::::from_bytes_be(x).map_err(|e| { - PyErr::new::(format!( - "Byte conversion error: {:?}", - e - )) - }) + FieldElement::::from_bytes_be(&x) + .map_err(|e| format!("Byte conversion error: {:?}", e)) }) .collect::>, _>>()?; @@ -73,24 +52,15 @@ pub fn zk_ecip_hint( .map(|chunk| G1Point::new(chunk[0].clone(), chunk[1].clone())) .collect(); - let scalars: Vec> = extract_scalars::(py_list_2)?; - run_ecip::(py, points, scalars) + let scalars: Vec> = extract_scalars::(list_scalars); + Ok(run_ecip::(points, scalars)) } 2 => { - let list_bytes: Vec<&[u8]> = py_list_1 - .into_iter() - .map(|x| x.extract()) - .collect::, _>>()?; - let list_felts: Vec> = list_bytes .into_iter() .map(|x| { - FieldElement::::from_bytes_be(x).map_err(|e| { - PyErr::new::(format!( - "Byte conversion error: {:?}", - e - )) - }) + FieldElement::::from_bytes_be(&x) + .map_err(|e| format!("Byte conversion error: {:?}", e)) }) .collect::>, _>>()?; @@ -99,24 +69,15 @@ pub fn zk_ecip_hint( .map(|chunk| G1Point::new(chunk[0].clone(), chunk[1].clone())) .collect(); - let scalars: Vec> = extract_scalars::(py_list_2)?; - run_ecip::(py, points, scalars) + let scalars: Vec> = extract_scalars::(list_scalars); + Ok(run_ecip::(points, scalars)) } 3 => { - let list_bytes: Vec<&[u8]> = py_list_1 - .into_iter() - .map(|x| x.extract()) - .collect::, _>>()?; - let list_felts: Vec> = list_bytes .into_iter() .map(|x| { - FieldElement::::from_bytes_be(x).map_err(|e| { - PyErr::new::(format!( - "Byte conversion error: {:?}", - e - )) - }) + FieldElement::::from_bytes_be(&x) + .map_err(|e| format!("Byte conversion error: {:?}", e)) }) .collect::>, _>>()?; @@ -125,24 +86,15 @@ pub fn zk_ecip_hint( .map(|chunk| G1Point::new(chunk[0].clone(), chunk[1].clone())) .collect(); - let scalars: Vec> = extract_scalars::(py_list_2)?; - run_ecip::(py, points, scalars) + let scalars: Vec> = extract_scalars::(list_scalars); + Ok(run_ecip::(points, scalars)) } 4 => { - let list_bytes: Vec<&[u8]> = py_list_1 - .into_iter() - .map(|x| x.extract()) - .collect::, _>>()?; - let list_felts: Vec> = list_bytes .into_iter() .map(|x| { - FieldElement::::from_bytes_be(x).map_err(|e| { - PyErr::new::(format!( - "Byte conversion error: {:?}", - e - )) - }) + FieldElement::::from_bytes_be(&x) + .map_err(|e| format!("Byte conversion error: {:?}", e)) }) .collect::>, _>>()?; @@ -151,22 +103,18 @@ pub fn zk_ecip_hint( .map(|chunk| G1Point::new(chunk[0].clone(), chunk[1].clone())) .collect(); - let scalars: Vec> = extract_scalars::(py_list_2)?; - run_ecip::(py, points, scalars) + let scalars: Vec> = extract_scalars::(list_scalars); + Ok(run_ecip::(points, scalars)) } - _ => Err(PyErr::new::( - "Invalid curve ID", - )), + _ => Err(String::from("Invalid curve ID")), } } -fn extract_scalars>( - py_list: &PyList, -) -> Result>, PyErr> { +fn extract_scalars>(list: Vec) -> Vec> { let mut dss_ = Vec::new(); - for i in 0..py_list.len() { - let scalar_biguint: BigUint = py_list[i].extract()?; + for i in 0..list.len() { + let scalar_biguint = list[i].clone(); let neg_3_digits = neg_3_base_le(scalar_biguint); dss_.push(neg_3_digits); } @@ -185,7 +133,7 @@ fn extract_scalars>( dss.push(ds); } - Ok(dss) + dss } fn neg_3_base_le(scalar: BigUint) -> Vec { @@ -227,7 +175,7 @@ fn floor_division(a: BigInt, b: BigInt) -> BigInt { } } -fn run_ecip(py: Python, points: Vec>, dss: Vec>) -> PyResult +fn run_ecip(points: Vec>, dss: Vec>) -> [Vec; 5] where F: IsPrimeField + CurveParamsProvider, { @@ -246,57 +194,40 @@ where // let sum_dlog = sum_dlog.simplify(); - let q_tuple = PyList::new( - py, - [ - q.x.representative().to_string(), - q.y.representative().to_string(), - ], - ); - - let a_num_list = PyList::new( - py, - sum_dlog - .a - .numerator - .coefficients - .iter() - .map(|c| c.representative().to_string()), - ); - let a_den_list = PyList::new( - py, - sum_dlog - .a - .denominator - .coefficients - .iter() - .map(|c| c.representative().to_string()), - ); - let b_num_list = PyList::new( - py, - sum_dlog - .b - .numerator - .coefficients - .iter() - .map(|c| c.representative().to_string()), - ); - let b_den_list = PyList::new( - py, - sum_dlog - .b - .denominator - .coefficients - .iter() - .map(|c| c.representative().to_string()), - ); - - let result_tuple = PyList::new( - py, - [q_tuple, a_num_list, a_den_list, b_num_list, b_den_list], - ); + let q_tuple = vec![ + q.x.representative().to_string(), + q.y.representative().to_string(), + ]; + let a_num_list = sum_dlog + .a + .numerator + .coefficients + .iter() + .map(|c| c.representative().to_string()) + .collect(); + let a_den_list = sum_dlog + .a + .denominator + .coefficients + .iter() + .map(|c| c.representative().to_string()) + .collect(); + let b_num_list = sum_dlog + .b + .numerator + .coefficients + .iter() + .map(|c| c.representative().to_string()) + .collect(); + let b_den_list = sum_dlog + .b + .denominator + .coefficients + .iter() + .map(|c| c.representative().to_string()) + .collect(); - Ok(result_tuple.into()) + [q_tuple, a_num_list, a_den_list, b_num_list, b_den_list] } fn line>(p: G1Point, q: G1Point) -> FF { diff --git a/tools/garaga_rs/src/lib.rs b/tools/garaga_rs/src/lib.rs index 4e9292f1..ceb4a2ef 100644 --- a/tools/garaga_rs/src/lib.rs +++ b/tools/garaga_rs/src/lib.rs @@ -17,10 +17,8 @@ use pyo3::{ {prelude::*, wrap_pyfunction}, }; -use crate::ecip::core::__pyo3_get_function_zk_ecip_hint; - #[pymodule] -fn garaga_rs(_py: Python, m: &PyModule) -> PyResult<()> { +fn garaga_rs(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(g2_add, m)?)?; m.add_function(wrap_pyfunction!(g2_scalar_mul, m)?)?; m.add_function(wrap_pyfunction!(multi_pairing, m)?)?; @@ -38,17 +36,17 @@ const CURVE_BLS12_381: usize = 1; fn g2_add( py: Python, curve_id: usize, - py_tuple_1: &PyTuple, - py_tuple_2: &PyTuple, + py_tuple_1: &Bound<'_, PyTuple>, + py_tuple_2: &Bound<'_, PyTuple>, ) -> PyResult { - let a_0: BigUint = py_tuple_1[0].extract()?; - let a_1: BigUint = py_tuple_1[1].extract()?; - let a_2: BigUint = py_tuple_1[2].extract()?; - let a_3: BigUint = py_tuple_1[3].extract()?; - let b_0: BigUint = py_tuple_2[0].extract()?; - let b_1: BigUint = py_tuple_2[1].extract()?; - let b_2: BigUint = py_tuple_2[2].extract()?; - let b_3: BigUint = py_tuple_2[3].extract()?; + let a_0: BigUint = py_tuple_1.get_item(0)?.extract()?; + let a_1: BigUint = py_tuple_1.get_item(1)?.extract()?; + let a_2: BigUint = py_tuple_1.get_item(2)?.extract()?; + let a_3: BigUint = py_tuple_1.get_item(3)?.extract()?; + let b_0: BigUint = py_tuple_2.get_item(0)?.extract()?; + let b_1: BigUint = py_tuple_2.get_item(1)?.extract()?; + let b_2: BigUint = py_tuple_2.get_item(2)?.extract()?; + let b_3: BigUint = py_tuple_2.get_item(3)?.extract()?; if curve_id == CURVE_BN254 { use ark_bn254::{Fq, Fq2, G2Affine}; @@ -61,7 +59,7 @@ fn g2_add( Fq2::new(Fq::from(b_2), Fq::from(b_3)), ); let c: G2Affine = (a + b).into(); - let py_tuple = PyTuple::new( + let py_tuple = PyTuple::new_bound( py, [ BigUint::from(c.x.c0.into_bigint()), @@ -84,7 +82,7 @@ fn g2_add( Fq2::new(Fq::from(b_2), Fq::from(b_3)), ); let c: G2Affine = (a + b).into(); - let py_tuple = PyTuple::new( + let py_tuple = PyTuple::new_bound( py, [ BigUint::from(c.x.c0.into_bigint()), @@ -103,13 +101,13 @@ fn g2_add( fn g2_scalar_mul( py: Python, curve_id: usize, - py_tuple_1: &PyTuple, - py_int_2: &PyInt, + py_tuple_1: &Bound<'_, PyTuple>, + py_int_2: &Bound<'_, PyInt>, ) -> PyResult { - let a_0: BigUint = py_tuple_1[0].extract()?; - let a_1: BigUint = py_tuple_1[1].extract()?; - let a_2: BigUint = py_tuple_1[2].extract()?; - let a_3: BigUint = py_tuple_1[3].extract()?; + let a_0: BigUint = py_tuple_1.get_item(0)?.extract()?; + let a_1: BigUint = py_tuple_1.get_item(1)?.extract()?; + let a_2: BigUint = py_tuple_1.get_item(2)?.extract()?; + let a_3: BigUint = py_tuple_1.get_item(3)?.extract()?; let k: BigUint = py_int_2.extract()?; if curve_id == CURVE_BN254 { @@ -119,7 +117,7 @@ fn g2_scalar_mul( Fq2::new(Fq::from(a_2), Fq::from(a_3)), ); let c: G2Affine = a.mul_bigint(k.to_u64_digits()).into(); - let py_tuple = PyTuple::new( + let py_tuple = PyTuple::new_bound( py, [ BigUint::from(c.x.c0.into_bigint()), @@ -138,7 +136,7 @@ fn g2_scalar_mul( Fq2::new(Fq::from(a_2), Fq::from(a_3)), ); let c: G2Affine = a.mul_bigint(k.to_u64_digits()).into(); - let py_tuple = PyTuple::new( + let py_tuple = PyTuple::new_bound( py, [ BigUint::from(c.x.c0.into_bigint()), @@ -154,7 +152,7 @@ fn g2_scalar_mul( } #[pyfunction] -fn multi_pairing(py: Python, curve_id: usize, py_list_1: &PyList) -> PyResult { +fn multi_pairing(py: Python, curve_id: usize, py_list_1: &Bound<'_, PyList>) -> PyResult { assert!(py_list_1.len() % 6 == 0, "invalid length"); if curve_id == CURVE_BN254 { @@ -162,12 +160,12 @@ fn multi_pairing(py: Python, curve_id: usize, py_list_1: &PyList) -> PyResult PyResult PyResult PyResult PyResult PyResult { +fn multi_miller_loop( + py: Python, + curve_id: usize, + py_list_1: &Bound<'_, PyList>, +) -> PyResult { assert!(py_list_1.len() % 6 == 0, "invalid length"); if curve_id == CURVE_BN254 { @@ -249,12 +251,12 @@ fn multi_miller_loop(py: Python, curve_id: usize, py_list_1: &PyList) -> PyResul let mut a_list = Vec::new(); let mut b_list = Vec::new(); for i in (0..py_list_1.len()).step_by(6) { - let a_0: BigUint = py_list_1[i].extract()?; - let a_1: BigUint = py_list_1[i + 1].extract()?; - let b_0: BigUint = py_list_1[i + 2].extract()?; - let b_1: BigUint = py_list_1[i + 3].extract()?; - let b_2: BigUint = py_list_1[i + 4].extract()?; - let b_3: BigUint = py_list_1[i + 5].extract()?; + let a_0: BigUint = py_list_1.get_item(i + 0)?.extract()?; + let a_1: BigUint = py_list_1.get_item(i + 1)?.extract()?; + let b_0: BigUint = py_list_1.get_item(i + 2)?.extract()?; + let b_1: BigUint = py_list_1.get_item(i + 3)?.extract()?; + let b_2: BigUint = py_list_1.get_item(i + 4)?.extract()?; + let b_3: BigUint = py_list_1.get_item(i + 5)?.extract()?; let a = G1Affine::new(Fq::from(a_0), Fq::from(a_1)); let b = G2Affine::new( Fq2::new(Fq::from(b_0), Fq::from(b_1)), @@ -280,7 +282,7 @@ fn multi_miller_loop(py: Python, curve_id: usize, py_list_1: &PyList) -> PyResul BigUint::from(v.c1.c2.c1.into_bigint()), ] } - let py_list = PyList::new(py, to(c.0)); + let py_list = PyList::new_bound(py, to(c.0)); return Ok(py_list.into()); } @@ -289,12 +291,12 @@ fn multi_miller_loop(py: Python, curve_id: usize, py_list_1: &PyList) -> PyResul let mut a_list = Vec::new(); let mut b_list = Vec::new(); for i in (0..py_list_1.len()).step_by(6) { - let a_0: BigUint = py_list_1[i].extract()?; - let a_1: BigUint = py_list_1[i + 1].extract()?; - let b_0: BigUint = py_list_1[i + 2].extract()?; - let b_1: BigUint = py_list_1[i + 3].extract()?; - let b_2: BigUint = py_list_1[i + 4].extract()?; - let b_3: BigUint = py_list_1[i + 5].extract()?; + let a_0: BigUint = py_list_1.get_item(i + 0)?.extract()?; + let a_1: BigUint = py_list_1.get_item(i + 1)?.extract()?; + let b_0: BigUint = py_list_1.get_item(i + 2)?.extract()?; + let b_1: BigUint = py_list_1.get_item(i + 3)?.extract()?; + let b_2: BigUint = py_list_1.get_item(i + 4)?.extract()?; + let b_3: BigUint = py_list_1.get_item(i + 5)?.extract()?; let a = G1Affine::new(Fq::from(a_0), Fq::from(a_1)); let b = G2Affine::new( Fq2::new(Fq::from(b_0), Fq::from(b_1)), @@ -320,7 +322,7 @@ fn multi_miller_loop(py: Python, curve_id: usize, py_list_1: &PyList) -> PyResul BigUint::from(v.c1.c2.c1.into_bigint()), ] } - let py_list = PyList::new(py, to(c.0)); + let py_list = PyList::new_bound(py, to(c.0)); return Ok(py_list.into()); } @@ -328,19 +330,23 @@ fn multi_miller_loop(py: Python, curve_id: usize, py_list_1: &PyList) -> PyResul } #[pyfunction] -fn get_final_exp_witness(py: Python, curve_id: usize, py_list: &PyList) -> PyResult { - let f_0: BigUint = py_list[0].extract()?; - let f_1: BigUint = py_list[1].extract()?; - let f_2: BigUint = py_list[2].extract()?; - let f_3: BigUint = py_list[3].extract()?; - let f_4: BigUint = py_list[4].extract()?; - let f_5: BigUint = py_list[5].extract()?; - let f_6: BigUint = py_list[6].extract()?; - let f_7: BigUint = py_list[7].extract()?; - let f_8: BigUint = py_list[8].extract()?; - let f_9: BigUint = py_list[9].extract()?; - let f_10: BigUint = py_list[10].extract()?; - let f_11: BigUint = py_list[11].extract()?; +fn get_final_exp_witness( + py: Python, + curve_id: usize, + py_list: &Bound<'_, PyList>, +) -> PyResult { + let f_0: BigUint = py_list.get_item(0)?.extract()?; + let f_1: BigUint = py_list.get_item(1)?.extract()?; + let f_2: BigUint = py_list.get_item(2)?.extract()?; + let f_3: BigUint = py_list.get_item(3)?.extract()?; + let f_4: BigUint = py_list.get_item(4)?.extract()?; + let f_5: BigUint = py_list.get_item(5)?.extract()?; + let f_6: BigUint = py_list.get_item(6)?.extract()?; + let f_7: BigUint = py_list.get_item(7)?.extract()?; + let f_8: BigUint = py_list.get_item(8)?.extract()?; + let f_9: BigUint = py_list.get_item(9)?.extract()?; + let f_10: BigUint = py_list.get_item(10)?.extract()?; + let f_11: BigUint = py_list.get_item(11)?.extract()?; if curve_id == CURVE_BN254 { use ark_bn254::{Fq, Fq12, Fq2, Fq6}; @@ -373,7 +379,10 @@ fn get_final_exp_witness(py: Python, curve_id: usize, py_list: &PyList) -> PyRes BigUint::from(v.c1.c2.c1.into_bigint()), ] } - let py_tuple = PyTuple::new(py, [PyList::new(py, to(c)), PyList::new(py, to(wi))]); + let py_tuple = PyTuple::new_bound( + py, + [PyList::new_bound(py, to(c)), PyList::new_bound(py, to(wi))], + ); return Ok(py_tuple.into()); } @@ -408,7 +417,10 @@ fn get_final_exp_witness(py: Python, curve_id: usize, py_list: &PyList) -> PyRes BigUint::from(v.c1.c2.c1.into_bigint()), ] } - let py_tuple = PyTuple::new(py, [PyList::new(py, to(c)), PyList::new(py, to(wi))]); + let py_tuple = PyTuple::new_bound( + py, + [PyList::new_bound(py, to(c)), PyList::new_bound(py, to(wi))], + ); return Ok(py_tuple.into()); } @@ -418,9 +430,9 @@ fn get_final_exp_witness(py: Python, curve_id: usize, py_list: &PyList) -> PyRes #[pyfunction] fn hades_permutation( py: Python, - py_value_1: &PyBytes, - py_value_2: &PyBytes, - py_value_3: &PyBytes, + py_value_1: &Bound<'_, PyBytes>, + py_value_2: &Bound<'_, PyBytes>, + py_value_3: &Bound<'_, PyBytes>, ) -> PyResult { let byte_slice_1: &[u8] = py_value_1.as_bytes(); let byte_slice_2: &[u8] = py_value_2.as_bytes(); @@ -437,13 +449,38 @@ fn hades_permutation( PoseidonCairoStark252::hades_permutation(&mut state); - let py_tuple = PyTuple::new( + let py_tuple = PyTuple::new_bound( py, state.iter().map(|fe| { let fe_bytes = fe.to_bytes_be(); - PyBytes::new(py, &fe_bytes) + PyBytes::new_bound(py, &fe_bytes) }), ); Ok(py_tuple.into()) } + +#[pyfunction] +fn zk_ecip_hint( + py: Python, + py_list_1: &Bound<'_, PyList>, + py_list_2: &Bound<'_, PyList>, + curve_id: usize, +) -> PyResult { + let list_values = py_list_1 + .into_iter() + .map(|x| x.extract()) + .collect::>, _>>()?; + + let list_scalars = py_list_2 + .into_iter() + .map(|x| x.extract()) + .collect::, _>>()?; + + let v = ecip::core::zk_ecip_hint(list_values, list_scalars, curve_id) + .map_err(|e| PyErr::new::(e))?; + + let py_list = PyList::new_bound(py, v.into_iter().map(|x| PyList::new_bound(py, x))); + + Ok(py_list.into()) +} diff --git a/tools/make/setup.sh b/tools/make/setup.sh index 7629de47..f039bb47 100755 --- a/tools/make/setup.sh +++ b/tools/make/setup.sh @@ -96,9 +96,7 @@ echo "Applying patch to instances.py..." patch venv/lib/python3.10/site-packages/starkware/cairo/lang/instances.py < tools/make/instances.patch echo "Compiling garaga_rs Rust extension..." -cd tools/garaga_rs maturin develop --release -cd ../../ echo "Generating input files for test_pairing.cairo..." source venv/bin/activate && python3.10 tests/gen_inputs.py