https://github.com/paritytech/arkworks-extensions
Arkworks extensions enabling customizable hooks for EC operations
https://github.com/paritytech/arkworks-extensions
arkworks cryptography elliptic-curves
Last synced: 5 months ago
JSON representation
Arkworks extensions enabling customizable hooks for EC operations
- Host: GitHub
- URL: https://github.com/paritytech/arkworks-extensions
- Owner: paritytech
- License: apache-2.0
- Created: 2022-12-08T15:20:18.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2025-03-14T10:58:11.000Z (7 months ago)
- Last Synced: 2025-05-08T00:12:57.457Z (5 months ago)
- Topics: arkworks, cryptography, elliptic-curves
- Language: Rust
- Homepage:
- Size: 118 MB
- Stars: 50
- Watchers: 5
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE-APACHE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# Arkworks Extensions
## Overview
This library extends [arkworks-rs/algebra](https://github.com/arkworks-rs/algebra).
We fork the popular elliptic curves `BLS12_381`, `BLS12_377`, `BW6_761`,
`ED_ON_BLS12_381_BANDERSNATCH`, `Pallas`, `Vesta`, `SECP256K1` and `ED_ON_BLS12_377` in a way which allows
delegating some of the most computationally expensive operations to some user
defined hooks.We also provide forks of the models `BW6` and `BLS12` to avoid the point
preparation before the hooks calls during pairing operations. Therefore, we
redefine the elliptic curve sub-groups `G2` for both models as thin wrappers
around the affine points and move the point preparation procedure to the
user defined hook.## Usage
The following usage example is extracted from the hooks provided by
[substrate-curves](https://github.com/paritytech/substrate-curves) project.The project provides a set of ready to use `CurveHooks` implementations compatible with
[Substrate](https://github.com/paritytech/polkadot-sdk/primitives/crypto/ec-utils)
host functions to jump from *wasm32* computational domain into the native host.The motivation is:
- native target is typically more efficient that *wasm32*.
- *wasm32* is single thread while in the native target we can hopefully leverage
the Arkworks `parallel` feature.Note that Substrate elliptic curves host functions take and return raw byte arrays
representing SCALE encoded values.### BLS12-377
```rust
use ark_bls12_377_ext::CurveHooks;
use ark_ec::{pairing::Pairing, CurveConfig}
use ark_scale::{
ark_serialize::{Compress, Validate},
scale::{Decode, Encode},
};
use sp_crypto_ec_utils::bls12_377_ops;const SCALE_USAGE: u8 = ark_scale::make_usage(Compress::No, Validate::No);
type ArkScale = ark_scale::ArkScale;o
type ArkScaleProjective = ark_scale::hazmat::ArkScaleProjective;#[derive(Copy, Clone)]
pub struct HostHooks;type Bls12_377 = ark_bls12_377_ext::Bls12_377;
type G1Affine = ark_bls12_377_ext::g1::G1Affine;
type G1Config = ark_bls12_377_ext::g1::Config;
type G2Affine = ark_bls12_377_ext::g2::G2Affine;
type G2Config = ark_bls12_377_ext::g2::Config;impl CurveHooks for HostHooks {
fn bls12_377_multi_miller_loop(
g1: impl Iterator::G1Prepared>,
g2: impl Iterator::G2Prepared>,
) -> Result<::TargetField, ()> {
// Encode to SCALE to call into Substrate HF
let g1 = ArkScale::from(g1.collect::>()).encode();
let g2 = ArkScale::from(g2.collect::>()).encode();
// Call into native host function
let res = bls12_377_ops::bls12_377_multi_miller_loop(g1, g2).unwrap_or_default();
// Decode from SCALE
let res = ArkScale::<::TargetField>::decode(&mut res.as_slice());
res.map(|v| v.0).map_err(|_| ())
}fn bls12_377_final_exponentiation(
target: ::TargetField,
) -> Result<::TargetField, ()> {
let target = ArkScale::from(target).encode();
let res = bls12_377_ops::bls12_377_final_exponentiation(target).unwrap_or_default();
let res = ArkScale::<::TargetField>::decode(&mut res.as_slice());
res.map(|v| v.0).map_err(|_| ())
}fn bls12_377_msm_g1(
bases: &[G1Affine],
scalars: &[::ScalarField],
) -> Result {
let bases = ArkScale::from(bases).encode();
let scalars = ArkScale::from(scalars).encode();
let res = bls12_377_ops::bls12_377_msm_g1(bases, scalars).unwrap_or_default();
let res = ArkScaleProjective::::decode(&mut res.as_slice());
res.map(|v| v.0).map_err(|_| ())
}fn bls12_377_msm_g2(
bases: &[G2Affine],
scalars: &[::ScalarField],
) -> Result {
let bases = ArkScale::from(bases).encode();
let scalars = ArkScale::from(scalars).encode();
let res = bls12_377_ops::bls12_377_msm_g2(bases, scalars).unwrap_or_default();
let res = ArkScaleProjective::::decode(&mut res.as_slice());
res.map(|v| v.0).map_err(|_| ())
}fn bls12_377_mul_projective_g1(
base: &G1Projective,
scalar: &[u64],
) -> Result {
let base = ArkScaleProjective::from(base).encode();
let scalar = ArkScale::from(scalar).encode();
let res = bls12_377_ops::bls12_377_mul_projective_g1(base, scalar).unwrap_or_default();
let res = ArkScaleProjective::::decode(&mut res.as_slice());
res.map(|v| v.0).map_err(|_| ())
}fn bls12_377_mul_projective_g2(
base: &G2Projective,
scalar: &[u64],
) -> Result {
let base = ArkScaleProjective::from(base).encode();
let scalar = ArkScale::from(scalar).encode();
let res = bls12_377_ops::bls12_377_mul_projective_g2(base, scalar).unwrap_or_default();
let res = ArkScaleProjective::::decode(&mut res.as_slice());
res.map(|v| v.0).map_err(|_| ())
}o
}
```For more working examples refer to [Ark Substrate](https://github.com/davxy/ark-substrate-examples).
## ⚠️ Known Limitations ⚠️
Be aware that, while in the hook context, any usage of functions which may
re-enter into the same hook with the same value, may cause an infinite loop.We are aware of hooks re-entrancy issues when using **point checked
deserialization** in projective multiplication hooks.In particular, if you serialize and deserialize (**with point checking**) the
input point in one of the projective multiplication hooks then we end up
re-entering the multiplication hook with the same value as a consequence of the
internally performed check.The following invocation flow applies:
1. [Validation of deserialized value](https://github.com/arkworks-rs/algebra/blob/c0666a81190dbcade1b735ffd383a5f577dd33d5/ec/src/models/twisted_edwards/mod.rs#L145-L147).
2. [Check if point is in the correct subgroup](https://github.com/arkworks-rs/algebra/blob/c0666a81190dbcade1b735ffd383a5f577dd33d5/ec/src/models/twisted_edwards/affine.rs#L321).
3. [Jump into the `TECurveConfig` for the check](https://github.com/arkworks-rs/algebra/blob/c0666a81190dbcade1b735ffd383a5f577dd33d5/ec/src/models/twisted_edwards/affine.rs#L159).
4. Calls the "custom" (defined by this crate) implementation of `mul_affine` which calls `mul_projective`.
5. Goto 1So pay special attention to the actions in your `CurveHooks` implementations.
If you encounter any other way to trigger the open, please file an issue.