Skip to content
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

Introduce deployment variable limit and cost #2431

Closed
wants to merge 8 commits into from
45 changes: 41 additions & 4 deletions circuit/environment/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Field = <console::MainnetV0 as console::Environment>::Field;

thread_local! {
pub(super) static CONSTRAINT_LIMIT: Cell<Option<u64>> = Cell::new(None);
pub(super) static VARIABLE_LIMIT: Cell<Option<u64>> = Cell::new(None);
pub(super) static CIRCUIT: RefCell<R1CS<Field>> = RefCell::new(R1CS::new());
pub(super) static IN_WITNESS: Cell<bool> = Cell::new(false);
pub(super) static ZERO: LinearCombination<Field> = LinearCombination::zero();
Expand Down Expand Up @@ -53,10 +54,20 @@ impl Environment for Circuit {
IN_WITNESS.with(|in_witness| {
// Ensure we are not in witness mode.
if !in_witness.get() {
CIRCUIT.with(|circuit| match mode {
Mode::Constant => circuit.borrow_mut().new_constant(value),
Mode::Public => circuit.borrow_mut().new_public(value),
Mode::Private => circuit.borrow_mut().new_private(value),
CIRCUIT.with(|circuit| {
// Ensure that we do not surpass the variable limit for the circuit.
VARIABLE_LIMIT.with(|variable_limit| {
if let Some(limit) = variable_limit.get() {
if Self::num_variables() > limit {
Self::halt(format!("Surpassed the variable limit ({limit})"))
}
}
});
match mode {
Mode::Constant => circuit.borrow_mut().new_constant(value),
Mode::Public => circuit.borrow_mut().new_public(value),
Mode::Private => circuit.borrow_mut().new_private(value),
}
})
} else {
Self::halt("Tried to initialize a new variable in witness mode")
Expand Down Expand Up @@ -201,6 +212,11 @@ impl Environment for Circuit {
CIRCUIT.with(|circuit| circuit.borrow().is_satisfied_in_scope())
}

/// Returns the total number of variables in the entire circuit.
fn num_variables() -> u64 {
CIRCUIT.with(|circuit| circuit.borrow().num_variables())
}

/// Returns the number of constants in the entire circuit.
fn num_constants() -> u64 {
CIRCUIT.with(|circuit| circuit.borrow().num_constants())
Expand Down Expand Up @@ -268,20 +284,32 @@ impl Environment for Circuit {
CONSTRAINT_LIMIT.with(|current_limit| current_limit.replace(limit));
}

/// Returns the variable limit for the circuit, if one exists.
fn get_variable_limit() -> Option<u64> {
VARIABLE_LIMIT.with(|current_limit| current_limit.get())
}

/// Sets the variable limit for the circuit.
fn set_variable_limit(limit: Option<u64>) {
VARIABLE_LIMIT.with(|current_limit| current_limit.replace(limit));
}

/// Returns the R1CS circuit, resetting the circuit.
fn inject_r1cs(r1cs: R1CS<Self::BaseField>) {
CIRCUIT.with(|circuit| {
// Ensure the circuit is empty before injecting.
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
// Inject the R1CS instance.
let r1cs = circuit.replace(r1cs);
// Ensure the circuit that was replaced is empty.
assert_eq!(0, r1cs.num_constants());
assert_eq!(1, r1cs.num_public());
assert_eq!(0, r1cs.num_private());
assert_eq!(1, r1cs.num_variables());
assert_eq!(0, r1cs.num_constraints());
})
}
Expand All @@ -293,12 +321,15 @@ impl Environment for Circuit {
IN_WITNESS.with(|in_witness| in_witness.replace(false));
// Reset the constraint limit.
Self::set_constraint_limit(None);
// Reset the variable limit.
Self::set_variable_limit(None);
// Eject the R1CS instance.
let r1cs = circuit.replace(R1CS::<<Self as Environment>::BaseField>::new());
// Ensure the circuit is now empty.
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
// Return the R1CS instance.
r1cs
Expand All @@ -312,11 +343,14 @@ impl Environment for Circuit {
IN_WITNESS.with(|in_witness| in_witness.replace(false));
// Reset the constraint limit.
Self::set_constraint_limit(None);
// Reset the variable limit.
Self::set_variable_limit(None);
// Eject the R1CS instance.
let r1cs = circuit.replace(R1CS::<<Self as Environment>::BaseField>::new());
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
// Convert the R1CS instance to an assignment.
Assignment::from(r1cs)
Expand All @@ -330,11 +364,14 @@ impl Environment for Circuit {
IN_WITNESS.with(|in_witness| in_witness.replace(false));
// Reset the constraint limit.
Self::set_constraint_limit(None);
// Reset the variable limit.
Self::set_variable_limit(None);
// Reset the circuit.
*circuit.borrow_mut() = R1CS::<<Self as Environment>::BaseField>::new();
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
});
}
Expand Down
9 changes: 9 additions & 0 deletions circuit/environment/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ pub trait Environment: 'static + Copy + Clone + fmt::Debug + fmt::Display + Eq +
/// Returns `true` if all constraints in the current scope are satisfied.
fn is_satisfied_in_scope() -> bool;

/// Returns the total number of variables in the entire environment.
fn num_variables() -> u64;

/// Returns the number of constants in the entire environment.
fn num_constants() -> u64;

Expand Down Expand Up @@ -167,6 +170,12 @@ pub trait Environment: 'static + Copy + Clone + fmt::Debug + fmt::Display + Eq +
/// Sets the constraint limit for the circuit.
fn set_constraint_limit(limit: Option<u64>);

/// Returns the variable limit for the circuit, if one exists.
fn get_variable_limit() -> Option<u64>;

/// Sets the variable limit for the circuit.
fn set_variable_limit(limit: Option<u64>);

/// Returns the R1CS circuit, resetting the circuit.
fn inject_r1cs(r1cs: R1CS<Self::BaseField>);

Expand Down
10 changes: 10 additions & 0 deletions circuit/environment/src/helpers/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct R1CS<F: PrimeField> {
private: Vec<Variable<F>>,
constraints: Vec<Rc<Constraint<F>>>,
counter: Counter<F>,
num_variables: u64,
nonzeros: (u64, u64, u64),
}

Expand All @@ -41,6 +42,7 @@ impl<F: PrimeField> R1CS<F> {
private: Default::default(),
constraints: Default::default(),
counter: Default::default(),
num_variables: 1,
nonzeros: (0, 0, 0),
}
}
Expand All @@ -60,6 +62,7 @@ impl<F: PrimeField> R1CS<F> {
let variable = Variable::Constant(Rc::new(value));
self.constants.push(variable.clone());
self.counter.increment_constant();
self.num_variables += 1;
variable
}

Expand All @@ -68,6 +71,7 @@ impl<F: PrimeField> R1CS<F> {
let variable = Variable::Public(Rc::new((self.public.len() as u64, value)));
self.public.push(variable.clone());
self.counter.increment_public();
self.num_variables += 1;
variable
}

Expand All @@ -76,6 +80,7 @@ impl<F: PrimeField> R1CS<F> {
let variable = Variable::Private(Rc::new((self.private.len() as u64, value)));
self.private.push(variable.clone());
self.counter.increment_private();
self.num_variables += 1;
variable
}

Expand Down Expand Up @@ -134,6 +139,11 @@ impl<F: PrimeField> R1CS<F> {
self.counter.scope()
}

/// Returns the total number of variables in the constraint system.
pub fn num_variables(&self) -> u64 {
self.num_variables
}

/// Returns the number of constants in the constraint system.
pub fn num_constants(&self) -> u64 {
self.constants.len() as u64
Expand Down
35 changes: 35 additions & 0 deletions circuit/environment/src/testnet_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Field = <console::TestnetV0 as console::Environment>::Field;

thread_local! {
static CONSTRAINT_LIMIT: Cell<Option<u64>> = Cell::new(None);
static VARIABLE_LIMIT: Cell<Option<u64>> = Cell::new(None);
pub(super) static TESTNET_CIRCUIT: RefCell<R1CS<Field>> = RefCell::new(R1CS::new());
static IN_WITNESS: Cell<bool> = Cell::new(false);
static ZERO: LinearCombination<Field> = LinearCombination::zero();
Expand Down Expand Up @@ -53,6 +54,14 @@ impl Environment for TestnetCircuit {
IN_WITNESS.with(|in_witness| {
// Ensure we are not in witness mode.
if !in_witness.get() {
// Ensure that we do not surpass the variable limit for the circuit.
VARIABLE_LIMIT.with(|variable_limit| {
if let Some(limit) = variable_limit.get() {
if Self::num_variables() > limit {
Self::halt(format!("Surpassed the variable limit ({limit})"))
}
}
});
TESTNET_CIRCUIT.with(|circuit| match mode {
Mode::Constant => circuit.borrow_mut().new_constant(value),
Mode::Public => circuit.borrow_mut().new_public(value),
Expand Down Expand Up @@ -177,6 +186,11 @@ impl Environment for TestnetCircuit {
TESTNET_CIRCUIT.with(|circuit| circuit.borrow().is_satisfied_in_scope())
}

/// Returns the total number of variables in the entire circuit.
fn num_variables() -> u64 {
TESTNET_CIRCUIT.with(|circuit| circuit.borrow().num_variables())
}

/// Returns the number of constants in the entire circuit.
fn num_constants() -> u64 {
TESTNET_CIRCUIT.with(|circuit| circuit.borrow().num_constants())
Expand Down Expand Up @@ -244,20 +258,32 @@ impl Environment for TestnetCircuit {
CONSTRAINT_LIMIT.with(|current_limit| current_limit.replace(limit));
}

/// Returns the variable limit for the circuit, if one exists.
fn get_variable_limit() -> Option<u64> {
VARIABLE_LIMIT.with(|current_limit| current_limit.get())
}

/// Sets the variable limit for the circuit.
fn set_variable_limit(limit: Option<u64>) {
VARIABLE_LIMIT.with(|current_limit| current_limit.replace(limit));
}

/// Returns the R1CS circuit, resetting the circuit.
fn inject_r1cs(r1cs: R1CS<Self::BaseField>) {
TESTNET_CIRCUIT.with(|circuit| {
// Ensure the circuit is empty before injecting.
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
// Inject the R1CS instance.
let r1cs = circuit.replace(r1cs);
// Ensure the circuit that was replaced is empty.
assert_eq!(0, r1cs.num_constants());
assert_eq!(1, r1cs.num_public());
assert_eq!(0, r1cs.num_private());
assert_eq!(1, r1cs.num_variables());
assert_eq!(0, r1cs.num_constraints());
})
}
Expand All @@ -269,12 +295,15 @@ impl Environment for TestnetCircuit {
IN_WITNESS.with(|in_witness| in_witness.replace(false));
// Reset the constraint limit.
Self::set_constraint_limit(None);
// Reset the variable limit.
Self::set_variable_limit(None);
// Eject the R1CS instance.
let r1cs = circuit.replace(R1CS::<<Self as Environment>::BaseField>::new());
// Ensure the circuit is now empty.
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
// Return the R1CS instance.
r1cs
Expand All @@ -288,11 +317,14 @@ impl Environment for TestnetCircuit {
IN_WITNESS.with(|in_witness| in_witness.replace(false));
// Reset the constraint limit.
Self::set_constraint_limit(None);
// Reset the variable limit.
Self::set_variable_limit(None);
// Eject the R1CS instance.
let r1cs = circuit.replace(R1CS::<<Self as Environment>::BaseField>::new());
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
// Convert the R1CS instance to an assignment.
Assignment::from(r1cs)
Expand All @@ -306,11 +338,14 @@ impl Environment for TestnetCircuit {
IN_WITNESS.with(|in_witness| in_witness.replace(false));
// Reset the constraint limit.
Self::set_constraint_limit(None);
// Reset the variable limit.
Self::set_variable_limit(None);
// Reset the circuit.
*circuit.borrow_mut() = R1CS::<<Self as Environment>::BaseField>::new();
assert_eq!(0, circuit.borrow().num_constants());
assert_eq!(1, circuit.borrow().num_public());
assert_eq!(0, circuit.borrow().num_private());
assert_eq!(1, circuit.borrow().num_variables());
assert_eq!(0, circuit.borrow().num_constraints());
});
}
Expand Down
3 changes: 3 additions & 0 deletions circuit/network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ pub trait Aleo: Environment {
/// The maximum number of field elements in data (must not exceed u16::MAX).
const MAX_DATA_SIZE_IN_FIELDS: u32 = <Self::Network as console::Network>::MAX_DATA_SIZE_IN_FIELDS;

/// Initializes all of the constants for the Aleo environment.
fn init_constants();

/// Returns the encryption domain as a constant field element.
fn encryption_domain() -> Field<Self>;

Expand Down
38 changes: 38 additions & 0 deletions circuit/network/src/testnet_v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,29 @@ thread_local! {
pub struct AleoTestnetV0;

impl Aleo for AleoTestnetV0 {
/// Initializes all of the constants for the Aleo environment.
fn init_constants() {
GENERATOR_G.with(|_| ());
ENCRYPTION_DOMAIN.with(|_| ());
GRAPH_KEY_DOMAIN.with(|_| ());
SERIAL_NUMBER_DOMAIN.with(|_| ());
BHP_256.with(|_| ());
BHP_512.with(|_| ());
BHP_768.with(|_| ());
BHP_1024.with(|_| ());
KECCAK_256.with(|_| ());
KECCAK_384.with(|_| ());
KECCAK_512.with(|_| ());
PEDERSEN_64.with(|_| ());
PEDERSEN_128.with(|_| ());
POSEIDON_2.with(|_| ());
POSEIDON_4.with(|_| ());
POSEIDON_8.with(|_| ());
SHA3_256.with(|_| ());
SHA3_384.with(|_| ());
SHA3_512.with(|_| ());
}

/// Returns the encryption domain as a constant field element.
fn encryption_domain() -> Field<Self> {
ENCRYPTION_DOMAIN.with(|domain| domain.clone())
Expand Down Expand Up @@ -411,6 +434,11 @@ impl Environment for AleoTestnetV0 {
E::is_satisfied_in_scope()
}

/// Returns the total number of variables in the entire circuit.
fn num_variables() -> u64 {
E::num_variables()
}

/// Returns the number of constants in the entire circuit.
fn num_constants() -> u64 {
E::num_constants()
Expand Down Expand Up @@ -476,6 +504,16 @@ impl Environment for AleoTestnetV0 {
E::set_constraint_limit(limit)
}

/// Returns the variable limit for the circuit, if one exists.
fn get_variable_limit() -> Option<u64> {
E::get_variable_limit()
}

/// Sets the constraint limit for the circuit.
fn set_variable_limit(limit: Option<u64>) {
E::set_variable_limit(limit)
}

/// Returns the R1CS circuit, resetting the circuit.
fn inject_r1cs(r1cs: R1CS<Self::BaseField>) {
E::inject_r1cs(r1cs)
Expand Down
Loading