-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial Plonky2 Plugin #14
base: main
Are you sure you want to change the base?
Changes from all commits
7ce3d34
52e395f
b119db6
b0df886
a17f960
f717323
2bd4b08
8cc4f45
4a32873
7fbefd7
ce54cc6
8f07581
e2f76b4
79cfe47
2d1c99c
dc1cef3
e290048
1fbb5c8
16b729b
69805e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
[workspace] | ||
members = ["eclair", "openzl", "openzl-*", "plugins/*"] | ||
members = ["eclair", "examples/*", "openzl", "openzl-*", "plugins/*"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "ecdsa-wasm" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib", "lib"] | ||
|
||
[dependencies] | ||
getrandom = { version = "0.2.8", features = ["js"] } | ||
openzl-plugin-plonky2 = { path = "../../plugins/plonky2", default-features = false, features = ["ecdsa"] } | ||
wasm-bindgen = { version = "0.2.83" } | ||
|
||
[dev-dependencies] | ||
instant = { version = "0.1.12", default-features = false, features = ["wasm-bindgen"] } | ||
wasm-bindgen-test = { version = "0.3.33", default-features = false } | ||
web-sys = { version = "0.3.59", default-features = false, features = ["console"] } |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,103 @@ | ||||||
//! ECDSA WASM | ||||||
|
||||||
use openzl_plugin_plonky2::base::{ | ||||||
ecdsa::{ | ||||||
curve::{ | ||||||
curve_types::{Curve, CurveScalar}, | ||||||
ecdsa::{sign_message, ECDSAPublicKey, ECDSASecretKey}, | ||||||
secp256k1::Secp256K1, | ||||||
}, | ||||||
gadgets::{ | ||||||
curve::CircuitBuilderCurve, | ||||||
ecdsa::{verify_message_circuit, ECDSAPublicKeyTarget, ECDSASignatureTarget}, | ||||||
nonnative::CircuitBuilderNonNative, | ||||||
}, | ||||||
}, | ||||||
field::{secp256k1_scalar::Secp256K1Scalar, types::Sample}, | ||||||
iop::witness::PartialWitness, | ||||||
plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, config::GenericConfig}, | ||||||
}; | ||||||
|
||||||
/// Tests the proving and verification of the ECDSA signature circuit. | ||||||
#[inline] | ||||||
pub fn test_ecdsa_circuit<C, const D: usize>(config: CircuitConfig) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't use the eclair interface at all for this circuit. If the eclair creator doesn't use it in a simple signature scheme example, who will? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This stuff was copied directly from plonky2, I haven't converted it over yet. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we do change this let's allocate the pieces appropriately as public/private inputs, rather than all being constants as they are here. |
||||||
where | ||||||
C: GenericConfig<D>, | ||||||
{ | ||||||
let pw = PartialWitness::new(); | ||||||
let mut builder = CircuitBuilder::<C::F, D>::new(config); | ||||||
Comment on lines
+27
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally we'd interact with plonky2 through the plugin structs and not their native ones. |
||||||
|
||||||
let msg = Secp256K1Scalar::rand(); | ||||||
let msg_target = builder.constant_nonnative(msg); | ||||||
|
||||||
let sk = ECDSASecretKey::<Secp256K1>(Secp256K1Scalar::rand()); | ||||||
|
||||||
let pk = ECDSAPublicKey((CurveScalar(sk.0) * Secp256K1::GENERATOR_PROJECTIVE).to_affine()); | ||||||
let pk_target = ECDSAPublicKeyTarget(builder.constant_affine_point(pk.0)); | ||||||
|
||||||
let sig = sign_message(msg, sk); | ||||||
let sig_target = ECDSASignatureTarget { | ||||||
r: builder.constant_nonnative(sig.r), | ||||||
s: builder.constant_nonnative(sig.s), | ||||||
}; | ||||||
|
||||||
verify_message_circuit(&mut builder, msg_target, sig_target, pk_target); | ||||||
|
||||||
let data = builder.build::<C>(); | ||||||
let proof = data.prove(pw).expect("Proving failed."); | ||||||
data.verify(proof).expect("Verification failed."); | ||||||
} | ||||||
|
||||||
/// Testing Module | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Time for |
||||||
#[cfg(test)] | ||||||
pub mod test { | ||||||
use super::*; | ||||||
use openzl_plugin_plonky2::base::plonk::config::PoseidonGoldilocksConfig; | ||||||
use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure}; | ||||||
use web_sys::console; | ||||||
|
||||||
wasm_bindgen_test_configure!(run_in_browser); | ||||||
|
||||||
/// Defines a benchmark over `f` with `REPEAT` repetitions. | ||||||
#[inline] | ||||||
fn bench<F, const REPEAT: usize>(mut f: F, label: &str) | ||||||
where | ||||||
F: FnMut(), | ||||||
{ | ||||||
let start_time = instant::Instant::now(); | ||||||
for _ in 0..REPEAT { | ||||||
f(); | ||||||
} | ||||||
let end_time = instant::Instant::now(); | ||||||
console::log_1( | ||||||
&format!( | ||||||
"{:?} Performance: {:?}", | ||||||
label, | ||||||
((end_time - start_time) / REPEAT as u32) | ||||||
) | ||||||
.into(), | ||||||
); | ||||||
} | ||||||
|
||||||
/// Runs the ECDSA benchmark for a narrow circuit configuration. | ||||||
#[wasm_bindgen_test] | ||||||
pub fn bench_ecdsa_circuit_narrow() { | ||||||
bench::<_, 3>( | ||||||
|| { | ||||||
test_ecdsa_circuit::<PoseidonGoldilocksConfig, 2>( | ||||||
CircuitConfig::standard_ecc_config(), | ||||||
) | ||||||
}, | ||||||
"Bench ECDSA Narrow", | ||||||
) | ||||||
} | ||||||
|
||||||
/// Runs the ECDSA benchmark for a narrow circuit configuration. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
#[wasm_bindgen_test] | ||||||
pub fn bench_ecdsa_circuit_wide() { | ||||||
bench::<_, 3>( | ||||||
|| test_ecdsa_circuit::<PoseidonGoldilocksConfig, 2>(CircuitConfig::wide_ecc_config()), | ||||||
"Bench ECDSA Wide", | ||||||
) | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,13 +85,13 @@ where | |
where | ||
F: FieldGeneration, | ||
{ | ||
let ys: Vec<F> = (t as u64..2 * t as u64).map(F::from_u64).collect(); | ||
let ys: Vec<F> = (t as u32..2 * t as u32).map(F::from_u32).collect(); // TODO: Change u64 to integer mod order(F) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this change because of the smaller size of the Goldilocks field? |
||
SquareMatrix::new_unchecked(Matrix::new_unchecked( | ||
(0..t as u64) | ||
(0..t as u32) | ||
.map(|x| { | ||
ys.iter() | ||
.map(|y| { | ||
F::add(&F::from_u64(x), y) | ||
F::add(&F::from_u32(x), y) | ||
.inverse() | ||
.expect("`x+y` is invertible.") | ||
}) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,8 +66,8 @@ pub trait FieldGeneration { | |
/// Number of bits of modulus of the field. | ||
const MODULUS_BITS: usize; | ||
|
||
/// Converts a `u64` value to a field element. | ||
fn from_u64(elem: u64) -> Self; | ||
/// Converts a `u32` value to a field element. | ||
fn from_u32(elem: u32) -> Self; | ||
Comment on lines
+69
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not an associated type |
||
|
||
/// Converts from `bits` into a field element in big endian order, returning `None` if `bits` | ||
/// are out of range. | ||
|
@@ -112,6 +112,16 @@ pub trait Constants { | |
const ADDITIVE_ROUND_KEYS_COUNT: usize = Self::ROUNDS * Self::WIDTH; | ||
} | ||
|
||
/// Poseidon S-Box Exponent | ||
/// | ||
/// For Poseidon implementations that use an `x^n` s-box with `n > 0`, this helper `trait` can be | ||
/// used to mark the exponent `n` for convenience. For `n = -1` the s-box "power" needs to be | ||
/// specified in the [`Specification::apply_sbox`] method. | ||
pub trait SBoxExponent { | ||
/// S-Box Exponent Value | ||
const SBOX_EXPONENT: u64; | ||
} | ||
|
||
/// Parameter Field Type | ||
#[component] | ||
pub type ParameterField; | ||
|
@@ -140,7 +150,7 @@ pub trait Field<COM = ()>: ParameterFieldType { | |
fn add_const_assign(lhs: &mut Self::Field, rhs: &Self::ParameterField, compiler: &mut COM); | ||
|
||
/// Converts a constant parameter `point` for permutation state. | ||
fn from_parameter(point: Self::ParameterField) -> Self::Field; | ||
fn from_parameter(point: Self::ParameterField, compiler: &mut COM) -> Self::Field; | ||
} | ||
|
||
/// Poseidon Permutation Specification | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,8 +9,9 @@ use core::marker::PhantomData; | |
use eclair::alloc::Constant; | ||
use openzl_crypto::poseidon::{ | ||
self, encryption::BlockElement, hash::DomainTag, Constants, FieldGeneration, NativeField, | ||
ParameterFieldType, | ||
ParameterFieldType, SBoxExponent, | ||
}; | ||
use openzl_util::derivative; | ||
|
||
#[cfg(test)] | ||
pub mod test; | ||
|
@@ -19,12 +20,9 @@ pub mod test; | |
type Compiler<S> = R1CS<<S as Specification>::Field>; | ||
|
||
/// Poseidon Permutation Specification. | ||
pub trait Specification: Constants { | ||
pub trait Specification: Constants + SBoxExponent { | ||
/// Field Type | ||
type Field: PrimeField; | ||
|
||
/// S-BOX Exponenet | ||
const SBOX_EXPONENT: u64; | ||
} | ||
|
||
impl<F> NativeField for Fp<F> | ||
|
@@ -84,7 +82,7 @@ where | |
} | ||
|
||
#[inline] | ||
fn from_u64(elem: u64) -> Self { | ||
fn from_u32(elem: u32) -> Self { | ||
Self(F::from(elem)) | ||
} | ||
} | ||
|
@@ -143,19 +141,16 @@ where | |
} | ||
|
||
/// Poseidon Specification Configuration | ||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] | ||
pub struct Spec<F, const ARITY: usize>(PhantomData<F>) | ||
where | ||
F: PrimeField; | ||
#[derive(derivative::Derivative)] | ||
#[derivative(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] | ||
pub struct Spec<F, const ARITY: usize>(PhantomData<F>); | ||
|
||
impl<F, const ARITY: usize> Specification for Spec<F, ARITY> | ||
where | ||
F: PrimeField, | ||
Self: poseidon::Constants, | ||
Self: poseidon::Constants + SBoxExponent, | ||
{ | ||
type Field = F; | ||
|
||
const SBOX_EXPONENT: u64 = 5; | ||
} | ||
|
||
impl<F, const ARITY: usize, COM> Constant<COM> for Spec<F, ARITY> | ||
|
@@ -217,7 +212,7 @@ where | |
} | ||
|
||
#[inline] | ||
fn from_parameter(point: Self::ParameterField) -> Self::Field { | ||
fn from_parameter(point: Self::ParameterField, _: &mut ()) -> Self::Field { | ||
point | ||
} | ||
} | ||
|
@@ -268,7 +263,7 @@ where | |
} | ||
|
||
#[inline] | ||
fn from_parameter(point: Self::ParameterField) -> Self::Field { | ||
fn from_parameter(point: Self::ParameterField, _: &mut Compiler<Self>) -> Self::Field { | ||
FpVar::Constant(point.0) | ||
} | ||
} | ||
|
@@ -297,6 +292,10 @@ where | |
} | ||
} | ||
|
||
impl<const ARITY: usize> SBoxExponent for Spec<bn254::Fr, ARITY> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why only bn254 implementation? |
||
const SBOX_EXPONENT: u64 = 5; | ||
} | ||
|
||
impl poseidon::Constants for Spec<bn254::Fr, 2> { | ||
const WIDTH: usize = 3; | ||
const FULL_ROUNDS: usize = 8; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why these changes? Is there something wrong with the stable CI?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use stable with plonky2 because it uses unstable features.