From 4ff6ea801e355375ce4bc959d3c59fe9f1a756c2 Mon Sep 17 00:00:00 2001 From: Nikolay Kostadinov Date: Mon, 15 Jan 2024 18:25:44 +0200 Subject: [PATCH 1/3] feat(gnark-plonky2): Add gnark verifier for plonky2 circuits --- .gitignore | 3 + beacon-light-client/plonky2/README.md | 4 +- ...d_commitment_mapper_first_level_circuit.rs | 207 +- .../circuits/src/build_final_circuit.rs | 46 +- .../plonky2/circuits/src/hash_tree_root.rs | 355 +-- .../plonky2/circuits/src/utils.rs | 93 +- .../src/validator_commitment_mapper.rs | 198 +- .../circuits/src/validator_hash_tree_root.rs | 196 +- .../plonky2/circuits_executables/Cargo.lock | 109 +- .../plonky2/circuits_executables/Cargo.toml | 7 + .../circuits_executables/bin/final_layer.rs | 34 +- .../circuits_executables/bin/wrapper.rs | 114 + .../examples/read_circuit_data_example.rs | 99 +- .../plonky2/circuits_executables/src/crud.rs | 22 +- .../plonky2/circuits_executables/src/lib.rs | 4 + .../src/poseidon_bn128.rs | 266 +++ .../src/poseidon_bn128_config.rs | 239 ++ .../src/poseidon_constants.rs | 2087 +++++++++++++++++ .../circuits_executables/src/provers.rs | 33 +- .../plonky2/circuits_executables/src/utils.rs | 7 + .../circuits_executables/src/validator.rs | 60 +- .../circuits_executables/verifier/circuit.go | 303 +++ .../circuits_executables/verifier/go.mod | 33 + .../circuits_executables/verifier/go.sum | 73 + .../circuits_executables/verifier/main.go | 93 + .../get_changed_validators.ts | 68 +- relay/implementations/redis.ts | 27 +- 27 files changed, 3866 insertions(+), 914 deletions(-) create mode 100644 beacon-light-client/plonky2/circuits_executables/bin/wrapper.rs create mode 100644 beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128.rs create mode 100644 beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128_config.rs create mode 100644 beacon-light-client/plonky2/circuits_executables/src/poseidon_constants.rs create mode 100644 beacon-light-client/plonky2/circuits_executables/src/utils.rs create mode 100644 beacon-light-client/plonky2/circuits_executables/verifier/circuit.go create mode 100644 beacon-light-client/plonky2/circuits_executables/verifier/go.mod create mode 100644 beacon-light-client/plonky2/circuits_executables/verifier/go.sum create mode 100644 beacon-light-client/plonky2/circuits_executables/verifier/main.go diff --git a/.gitignore b/.gitignore index 7f6caa00a..dd2bf1f9f 100644 --- a/.gitignore +++ b/.gitignore @@ -174,4 +174,7 @@ redis-server/ *.plonky2_targets *.plonky2_circuit +beacon-light-client/plonky2/circuits_executables/verifier/circuit/ +beacon-light-client/plonky2/circuits_executables/verifier/data/ + .DS_Store diff --git a/beacon-light-client/plonky2/README.md b/beacon-light-client/plonky2/README.md index a3484fa39..d0a222f8f 100644 --- a/beacon-light-client/plonky2/README.md +++ b/beacon-light-client/plonky2/README.md @@ -1,6 +1,6 @@ -# Beacon Light Client Task Execution and Data Flow +# The Balance Verification Task Execution and Data Flow -The Beacon Light Client relies heavily on a Redis instance to handle task management. This document provides an overview of the technical structure of the system, including how tasks are produced, consumed, and executed. +The Balance Verification relies heavily on a Redis instance to handle task management. This document provides an overview of the technical structure of the system, including how tasks are produced, consumed, and executed. ## Commitment Mapper diff --git a/beacon-light-client/plonky2/circuits/src/build_commitment_mapper_first_level_circuit.rs b/beacon-light-client/plonky2/circuits/src/build_commitment_mapper_first_level_circuit.rs index 46357ba4c..afd720e53 100644 --- a/beacon-light-client/plonky2/circuits/src/build_commitment_mapper_first_level_circuit.rs +++ b/beacon-light-client/plonky2/circuits/src/build_commitment_mapper_first_level_circuit.rs @@ -108,11 +108,11 @@ pub fn build_commitment_mapper_first_level_circuit() -> ( #[cfg(test)] mod test { use anyhow::Result; - use plonky2::iop::witness::{PartialWitness, WitnessWrite}; + use plonky2::iop::witness::{PartialWitness}; use crate::{ build_commitment_mapper_first_level_circuit::build_commitment_mapper_first_level_circuit, - utils::ETH_SHA256_BIT_SIZE, + utils::{SetBytesArray, ETH_SHA256_BIT_SIZE}, }; #[test] @@ -121,126 +121,34 @@ mod test { let mut pw = PartialWitness::new(); - let validator_pubkey = [ - "1", "0", "0", "1", "0", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "0", "1", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", "0", "0", - "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", - "0", "0", "1", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "1", "1", "0", "1", - "0", "0", "0", "0", "0", "1", "1", "0", "0", "1", "0", "1", "1", "0", "1", "1", "0", - "1", "0", "1", "0", "1", "1", "0", "0", "0", "0", "0", "1", "1", "0", "1", "0", "0", - "1", "0", "0", "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", - "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "1", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "0", "1", "0", "1", "1", "0", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", "1", - "1", "0", "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "1", "1", - "0", "1", "1", "1", "0", "0", "1", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", - "0", "0", "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", - "0", "0", "1", "1", "1", "1", "0", "1", "0", "0", "0", "1", "1", "1", "1", "0", "1", - "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", - "0", "0", "1", "1", "0", "0", "1", "1", "1", "1", "0", "1", "0", "1", "0", "0", "0", - "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "1", "1", "1", "0", "0", "0", - "0", "1", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "0", "0", - "1", "0", "1", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "0", "1", "1", "0", - "0", "0", "1", "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "0", - "0", "0", "0", "1", "0", "0", "1", "1", "0", "1", "0", "0", "0", "0", "1", "0", "1", - "0", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", "0", "0", "1", "1", - "0", "0", "1", "0", "0", "1", "0", "1", "0", "1", - ]; + let validator_pubkey =hex::decode("933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95").unwrap(); + let withdrawal_credentials = + hex::decode("0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50") + .unwrap(); - let withdraw_credentials = [ - "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "1", "0", "1", - "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "0", "0", "1", "1", "1", "1", "0", - "1", "1", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "0", "0", "0", "1", "0", - "0", "0", "0", "0", "0", "0", "0", "1", "1", "1", "1", "1", "1", "0", "1", "0", "0", - "1", "1", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "1", "0", "1", "0", "1", - "0", "1", "0", "0", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", - "1", "0", "1", "1", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "0", "1", "1", "0", "1", "0", "1", "0", "1", "0", "0", "0", - "0", - ]; + let effective_balance = + hex::decode("0040597307000000000000000000000000000000000000000000000000000000") + .unwrap(); - let effective_balance = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", - "0", "0", "0", "1", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let slashed = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let slashed = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_eligibility_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let activation_eligibility_epoch = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let withdrawable_epoch = [ - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let exit_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); + + let withdrawable_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); let validator_hash_tree_root = [ "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "1", "1", "1", "0", @@ -261,43 +169,36 @@ mod test { "1", ]; - for i in 0..384 { - pw.set_bool_target( - validator_commitment.validator.pubkey[i], - validator_pubkey[i] == "1", - ); - } + pw.set_bytes_array(&validator_commitment.validator.pubkey, &validator_pubkey); - for i in 0..ETH_SHA256_BIT_SIZE { - pw.set_bool_target( - validator_commitment.validator.withdrawal_credentials[i], - withdraw_credentials[i] == "1", - ); - - pw.set_bool_target( - validator_commitment.validator.effective_balance[i], - effective_balance[i] == "1", - ); - - pw.set_bool_target(validator_commitment.validator.slashed[i], slashed[i] == "1"); - - pw.set_bool_target( - validator_commitment.validator.activation_eligibility_epoch[i], - activation_eligibility_epoch[i] == "1", - ); - - pw.set_bool_target(validator_commitment.validator.activation_epoch[i], false); - - pw.set_bool_target( - validator_commitment.validator.exit_epoch[i], - if i < 64 { true } else { false }, - ); - - pw.set_bool_target( - validator_commitment.validator.withdrawable_epoch[i], - withdrawable_epoch[i] == "1", - ); - } + pw.set_bytes_array( + &validator_commitment.validator.withdrawal_credentials, + &withdrawal_credentials, + ); + + pw.set_bytes_array( + &validator_commitment.validator.effective_balance, + &effective_balance, + ); + + pw.set_bytes_array(&validator_commitment.validator.slashed, &slashed); + + pw.set_bytes_array( + &validator_commitment.validator.activation_eligibility_epoch, + &activation_eligibility_epoch, + ); + + pw.set_bytes_array( + &validator_commitment.validator.activation_epoch, + &activation_epoch, + ); + + pw.set_bytes_array(&validator_commitment.validator.exit_epoch, &exit_epoch); + + pw.set_bytes_array( + &validator_commitment.validator.withdrawable_epoch, + &withdrawable_epoch, + ); let proof = data.prove(pw).unwrap(); diff --git a/beacon-light-client/plonky2/circuits/src/build_final_circuit.rs b/beacon-light-client/plonky2/circuits/src/build_final_circuit.rs index b3c3d060e..6cec746a8 100644 --- a/beacon-light-client/plonky2/circuits/src/build_final_circuit.rs +++ b/beacon-light-client/plonky2/circuits/src/build_final_circuit.rs @@ -7,7 +7,7 @@ use plonky2::{ }, fri::{reduction_strategies::FriReductionStrategy, FriConfig}, hash::hash_types::HashOutTarget, - iop::target::{BoolTarget, Target}, + iop::target::BoolTarget, plonk::{ circuit_builder::CircuitBuilder, circuit_data::{CircuitConfig, CircuitData, VerifierCircuitTarget}, @@ -22,7 +22,9 @@ use crate::{ build_validator_balance_circuit::ValidatorBalanceProofTargetsExt, is_valid_merkle_branch::{is_valid_merkle_branch, IsValidMerkleBranchTargets}, sha256::make_circuits, - utils::{create_bool_target_array, ssz_num_to_bits, ETH_SHA256_BIT_SIZE}, + utils::{ + biguint_to_bits_target, create_bool_target_array, ssz_num_to_bits, ETH_SHA256_BIT_SIZE, + }, }; pub struct BalanceFinalLayerTargets { @@ -181,17 +183,38 @@ pub fn build_final_circuit( let slot_merkle_branch = create_and_connect_merkle_branch(&mut builder, 34, &slot_bits, &state_root); - builder.register_public_inputs(&state_root.iter().map(|x| x.target).collect::>()); + let public_inputs_hasher = make_circuits(&mut builder, 3 * ETH_SHA256_BIT_SIZE as u64); - builder.register_public_inputs( - &withdrawal_credentials - .limbs - .iter() - .map(|x| x.0) - .collect_vec(), - ); + let withdrawal_credentials_bits = + biguint_to_bits_target::(&mut builder, &withdrawal_credentials); + + let final_sum_bits = ssz_num_to_bits(&mut builder, &balance_sum, 64); + + for i in 0..ETH_SHA256_BIT_SIZE { + builder.connect(public_inputs_hasher.message[i].target, state_root[i].target); + builder.connect( + public_inputs_hasher.message[ETH_SHA256_BIT_SIZE + i].target, + withdrawal_credentials_bits[i].target, + ); + builder.connect( + public_inputs_hasher.message[2 * ETH_SHA256_BIT_SIZE + i].target, + final_sum_bits[i].target, + ); + } + + let mut sha256_hash = public_inputs_hasher.digest; + + // Mask the last 3 bits in big endian as zero + sha256_hash[0] = builder._false(); + sha256_hash[1] = builder._false(); + sha256_hash[2] = builder._false(); + + let tokens = sha256_hash[0..256] + .chunks(8) + .map(|x| builder.le_sum(x.iter().rev())) + .collect_vec(); - builder.register_public_inputs(&balance_sum.limbs.iter().map(|x| x.0).collect_vec()); + builder.register_public_inputs(&tokens); let data = builder.build::(); @@ -331,6 +354,7 @@ fn create_and_connect_merkle_branch( merkle_branch } +#[allow(dead_code)] fn create_final_config() -> CircuitConfig { let standard_recursion_config = CircuitConfig::standard_recursion_config(); diff --git a/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs b/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs index 845ffc45c..b2e5b35d4 100644 --- a/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs +++ b/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs @@ -64,7 +64,7 @@ mod tests { use anyhow::Result; use plonky2::{ field::goldilocks_field::GoldilocksField, - iop::witness::{PartialWitness, WitnessWrite}, + iop::witness::{PartialWitness}, plonk::{ circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, config::PoseidonGoldilocksConfig, @@ -73,7 +73,7 @@ mod tests { use crate::{ hash_tree_root::hash_tree_root, - utils::{hash_bit_array, ETH_SHA256_BIT_SIZE}, + utils::{hash_bytes, SetBytesArray, ETH_SHA256_BIT_SIZE}, }; #[test] @@ -88,81 +88,19 @@ mod tests { let mut pw: PartialWitness = PartialWitness::new(); - let first = vec![ - "0", "1", "1", "0", "0", "1", "1", "1", "0", "0", "1", "1", "0", "1", "0", "1", "0", - "0", "0", "0", "1", "1", "1", "1", "1", "0", "0", "0", "0", "1", "0", "1", "1", "1", - "0", "0", "0", "1", "1", "0", "1", "0", "0", "0", "0", "0", "1", "1", "0", "1", "1", - "1", "0", "1", "1", "1", "0", "1", "1", "1", "1", "1", "1", "0", "0", "1", "0", "1", - "1", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "0", "1", "1", "0", - "1", "1", "1", "1", "1", "0", "0", "1", "1", "0", "0", "1", "1", "1", "0", "0", "0", - "0", "1", "1", "1", "1", "1", "0", "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", - "1", "0", "0", "1", "0", "0", "0", "1", "1", "0", "0", "0", "0", "0", "0", "1", "0", - "0", "1", "1", "1", "0", "1", "1", "0", "1", "0", "0", "0", "1", "1", "0", "0", "0", - "0", "1", "0", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "1", "0", - "1", "1", "1", "0", "0", "0", "0", "1", "0", "1", "1", "1", "0", "0", "0", "1", "1", - "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "1", "1", "0", "0", "0", "1", - "1", "1", "0", "0", "0", "1", "0", "0", "0", "1", "0", "0", "1", "0", "1", "1", "0", - "1", "1", "0", "0", "1", "1", "1", "1", "1", "1", "1", "1", "0", "0", "1", "1", "0", - "0", "0", "0", "0", "0", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", - "1", - ]; + let first = hex::decode("67350f85c683777e5ec537cce1f6652302768c2636b85c6d8b1c44b67f981d2d") + .unwrap(); - let second = vec![ - "0", "0", "1", "1", "0", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "1", "1", - "0", "0", "1", "0", "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", - "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "0", "1", "1", "1", - "1", "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", - "0", "0", "1", "0", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", "1", "0", "1", - "0", "0", "0", "0", "0", "1", "1", "1", "0", "1", "0", "0", "1", "1", "1", "1", "0", - "1", "0", "1", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "1", "0", "0", "1", - "0", "1", "0", "1", "1", "1", "0", "1", "1", "0", "0", "1", "1", "1", "1", "1", "1", - "0", "1", "0", "1", "1", "0", "1", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0", - "0", "1", "0", "0", "1", "0", "1", "0", "0", "0", "0", "1", "0", "0", "0", "1", "0", - "1", "1", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "1", "1", "1", - "1", "1", "0", "0", "1", "0", "1", "1", "1", "1", "0", "1", "1", "1", "1", "1", "0", - "1", "0", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "1", "1", "0", "1", - "0", "0", "1", "1", "1", "1", "0", "1", "0", "1", "1", "0", "0", "0", "0", "0", "0", - "1", "1", "1", "1", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", "1", - "0", - ]; + let second = + hex::decode("35cd95976b68fad8d270a83a7a8092bb3f5a622508b3b6f97be8ede9eb03ddb2") + .unwrap(); - let third = vec![ - "1", "0", "0", "1", "1", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", "0", - "0", "0", "0", "0", "0", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", - "1", "1", "0", "0", "0", "0", "0", "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", - "0", "1", "0", "1", "0", "1", "1", "1", "1", "1", "1", "0", "0", "1", "0", "0", "1", - "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "0", "1", "0", "0", "0", "0", "1", - "1", "1", "0", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "0", "1", "0", - "1", "0", "1", "1", "1", "1", "1", "1", "1", "1", "0", "1", "1", "0", "0", "1", "0", - "0", "1", "1", "1", "1", "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "1", - "1", "0", "0", "0", "1", "1", "0", "0", "1", "1", "0", "1", "1", "1", "0", "0", "1", - "0", "0", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "0", "1", - "1", "0", "0", "1", "1", "1", "1", "1", "0", "0", "0", "1", "1", "1", "0", "1", "0", - "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "0", "0", "0", "1", "1", - "1", "0", "1", "0", "0", "1", "1", "1", "1", "0", "0", "0", "0", "0", "1", "1", "0", - "1", "1", "0", "0", "0", "1", "0", "0", "1", "1", "1", "0", "1", "0", "0", "0", "0", - "0", "0", "0", "1", "0", "0", "0", "1", "1", "1", "0", "0", "1", "1", "0", "1", "0", - "0", - ]; + let third = hex::decode("9dcc025d70596afc98d90e2aeaff64fb2f8cdc8cba67c743143a783627404734") + .unwrap(); - let fourth = vec![ - "1", "1", "0", "0", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", "0", - "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", "1", "1", "0", "1", "0", - "0", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", - "1", "0", "1", "1", "1", "1", "0", "0", "1", "0", "0", "1", "0", "1", "0", "1", "1", - "0", "1", "0", "0", "1", "1", "0", "1", "0", "0", "1", "0", "0", "0", "1", "1", "0", - "0", "1", "0", "0", "0", "0", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", - "1", "1", "1", "0", "1", "1", "0", "1", "0", "1", "1", "0", "1", "1", "1", "1", "1", - "0", "1", "1", "1", "0", "1", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", - "0", "0", "0", "0", "1", "0", "1", "1", "0", "0", "1", "0", "0", "1", "0", "0", "0", - "0", "1", "1", "0", "1", "1", "1", "1", "1", "0", "1", "0", "0", "0", "1", "0", "1", - "0", "0", "0", "0", "1", "1", "1", "1", "1", "0", "0", "1", "1", "1", "0", "1", "0", - "1", "1", "0", "1", "1", "0", "1", "1", "1", "1", "0", "1", "0", "0", "1", "1", "1", - "0", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", "0", "1", "0", "0", - "0", "0", "0", "1", "1", "0", "1", "1", "1", "1", "0", "1", "0", "0", "0", "0", "0", - "1", - ]; + let fourth = + hex::decode("c3b6594b1b1343b69bc95a69190b85dadf776205921be8a1f3adbd39cc906f41") + .unwrap(); let hash_tree_root = vec![ "1", "0", "0", "1", "0", "1", "0", "0", "0", "0", "1", "1", "1", "1", "0", "0", "1", @@ -183,12 +121,10 @@ mod tests { "0", ]; - for i in 0..256 { - pw.set_bool_target(targets.leaves[0][i], first[i] == "1"); - pw.set_bool_target(targets.leaves[1][i], second[i] == "1"); - pw.set_bool_target(targets.leaves[2][i], third[i] == "1"); - pw.set_bool_target(targets.leaves[3][i], fourth[i] == "1"); - } + pw.set_bytes_array(&targets.leaves[0], &first); + pw.set_bytes_array(&targets.leaves[1], &second); + pw.set_bytes_array(&targets.leaves[2], &third); + pw.set_bytes_array(&targets.leaves[3], &fourth); for i in 0..256 { if hash_tree_root[i] == "1" { @@ -206,126 +142,36 @@ mod tests { #[test] fn validators_hash_tree_root() -> Result<()> { - let validator_pubkey = [ - "1", "0", "0", "1", "0", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "0", "1", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", "0", "0", - "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", - "0", "0", "1", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "1", "1", "0", "1", - "0", "0", "0", "0", "0", "1", "1", "0", "0", "1", "0", "1", "1", "0", "1", "1", "0", - "1", "0", "1", "0", "1", "1", "0", "0", "0", "0", "0", "1", "1", "0", "1", "0", "0", - "1", "0", "0", "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", - "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "1", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "0", "1", "0", "1", "1", "0", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", "1", - "1", "0", "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "1", "1", - "0", "1", "1", "1", "0", "0", "1", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", - "0", "0", "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", - "0", "0", "1", "1", "1", "1", "0", "1", "0", "0", "0", "1", "1", "1", "1", "0", "1", - "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", - "0", "0", "1", "1", "0", "0", "1", "1", "1", "1", "0", "1", "0", "1", "0", "0", "0", - "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "1", "1", "1", "0", "0", "0", - "0", "1", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "0", "0", - "1", "0", "1", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "0", "1", "1", "0", - "0", "0", "1", "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "0", - "0", "0", "0", "1", "0", "0", "1", "1", "0", "1", "0", "0", "0", "0", "1", "0", "1", - "0", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", "0", "0", "1", "1", - "0", "0", "1", "0", "0", "1", "0", "1", "0", "1", - ]; + let validator_pubkey =hex::decode("933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c9500000000000000000000000000000000").unwrap(); + let validator_pubkey = hash_bytes(&validator_pubkey); - let withdraw_credentials = [ - "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "1", "0", "1", - "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "0", "0", "1", "1", "1", "1", "0", - "1", "1", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "0", "0", "0", "1", "0", - "0", "0", "0", "0", "0", "0", "0", "1", "1", "1", "1", "1", "1", "0", "1", "0", "0", - "1", "1", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "1", "0", "1", "0", "1", - "0", "1", "0", "0", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", - "1", "0", "1", "1", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "0", "1", "1", "0", "1", "0", "1", "0", "1", "0", "0", "0", - "0", - ]; + let withdrawal_credentials = + hex::decode("0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50") + .unwrap(); - let effective_balance = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", - "0", "0", "0", "1", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let effective_balance = + hex::decode("0040597307000000000000000000000000000000000000000000000000000000") + .unwrap(); - let slashed = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let slashed = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let activation_eligibility_epoch = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_eligibility_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let withdrawable_epoch = [ - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); + + let exit_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); + + let withdrawable_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); let validator_hash_tree_root = [ "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "1", "1", "1", "0", @@ -350,24 +196,27 @@ mod tests { type C = PoseidonGoldilocksConfig; type F = GoldilocksField; - let pubkey_binary_result = hash_bit_array(validator_pubkey.to_vec()); - let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); let targets = hash_tree_root(&mut builder, 8); let mut pw: PartialWitness = PartialWitness::new(); - for i in 0..ETH_SHA256_BIT_SIZE { - pw.set_bool_target(targets.leaves[0][i], pubkey_binary_result[i] == "1"); - pw.set_bool_target(targets.leaves[1][i], withdraw_credentials[i] == "1"); - pw.set_bool_target(targets.leaves[2][i], effective_balance[i] == "1"); - pw.set_bool_target(targets.leaves[3][i], slashed[i] == "1"); - pw.set_bool_target(targets.leaves[4][i], activation_eligibility_epoch[i] == "1"); - pw.set_bool_target(targets.leaves[5][i], false); - pw.set_bool_target(targets.leaves[6][i], if i < 64 { true } else { false }); - pw.set_bool_target(targets.leaves[7][i], withdrawable_epoch[i] == "1"); - } + pw.set_bytes_array(&targets.leaves[0], &validator_pubkey); + + pw.set_bytes_array(&targets.leaves[1], &withdrawal_credentials); + + pw.set_bytes_array(&targets.leaves[2], &effective_balance); + + pw.set_bytes_array(&targets.leaves[3], &slashed); + + pw.set_bytes_array(&targets.leaves[4], &activation_eligibility_epoch); + + pw.set_bytes_array(&targets.leaves[5], &activation_epoch); + + pw.set_bytes_array(&targets.leaves[6], &exit_epoch); + + pw.set_bytes_array(&targets.leaves[7], &withdrawable_epoch); for i in 0..ETH_SHA256_BIT_SIZE { if validator_hash_tree_root[i] == "1" { @@ -396,81 +245,19 @@ mod tests { let mut pw: PartialWitness = PartialWitness::new(); - let first = vec![ - "0", "1", "1", "0", "0", "1", "1", "1", "0", "0", "1", "1", "0", "1", "0", "1", "0", - "0", "0", "0", "1", "1", "1", "1", "1", "0", "0", "0", "0", "1", "0", "1", "1", "1", - "0", "0", "0", "1", "1", "0", "1", "0", "0", "0", "0", "0", "1", "1", "0", "1", "1", - "1", "0", "1", "1", "1", "0", "1", "1", "1", "1", "1", "1", "0", "0", "1", "0", "1", - "1", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "0", "1", "1", "0", - "1", "1", "1", "1", "1", "0", "0", "1", "1", "0", "0", "1", "1", "1", "0", "0", "0", - "0", "1", "1", "1", "1", "1", "0", "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", - "1", "0", "0", "1", "0", "0", "0", "1", "1", "0", "0", "0", "0", "0", "0", "1", "0", - "0", "1", "1", "1", "0", "1", "1", "0", "1", "0", "0", "0", "1", "1", "0", "0", "0", - "0", "1", "0", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "1", "0", - "1", "1", "1", "0", "0", "0", "0", "1", "0", "1", "1", "1", "0", "0", "0", "1", "1", - "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "1", "1", "0", "0", "0", "1", - "1", "1", "0", "0", "0", "1", "0", "0", "0", "1", "0", "0", "1", "0", "1", "1", "0", - "1", "1", "0", "0", "1", "1", "1", "1", "1", "1", "1", "1", "0", "0", "1", "1", "0", - "0", "0", "0", "0", "0", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", - "1", - ]; + let first = hex::decode("67350f85c683777e5ec537cce1f6652302768c2636b85c6d8b1c44b67f981d2d") + .unwrap(); - let second = vec![ - "0", "0", "1", "1", "0", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "1", "1", - "0", "0", "1", "0", "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", - "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "0", "1", "1", "1", - "1", "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", - "0", "0", "1", "0", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", "1", "0", "1", - "0", "0", "0", "0", "0", "1", "1", "1", "0", "1", "0", "0", "1", "1", "1", "1", "0", - "1", "0", "1", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "1", "0", "0", "1", - "0", "1", "0", "1", "1", "1", "0", "1", "1", "0", "0", "1", "1", "1", "1", "1", "1", - "0", "1", "0", "1", "1", "0", "1", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0", - "0", "1", "0", "0", "1", "0", "1", "0", "0", "0", "0", "1", "0", "0", "0", "1", "0", - "1", "1", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "1", "1", "1", - "1", "1", "0", "0", "1", "0", "1", "1", "1", "1", "0", "1", "1", "1", "1", "1", "0", - "1", "0", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "1", "1", "0", "1", - "0", "0", "1", "1", "1", "1", "0", "1", "0", "1", "1", "0", "0", "0", "0", "0", "0", - "1", "1", "1", "1", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", "1", - "0", - ]; + let second = + hex::decode("35cd95976b68fad8d270a83a7a8092bb3f5a622508b3b6f97be8ede9eb03ddb2") + .unwrap(); - let third = vec![ - "1", "0", "0", "1", "1", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", "0", - "0", "0", "0", "0", "0", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", - "1", "1", "0", "0", "0", "0", "0", "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", - "0", "1", "0", "1", "0", "1", "1", "1", "1", "1", "1", "0", "0", "1", "0", "0", "1", - "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "0", "1", "0", "0", "0", "0", "1", - "1", "1", "0", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "0", "1", "0", - "1", "0", "1", "1", "1", "1", "1", "1", "1", "1", "0", "1", "1", "0", "0", "1", "0", - "0", "1", "1", "1", "1", "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "1", - "1", "0", "0", "0", "1", "1", "0", "0", "1", "1", "0", "1", "1", "1", "0", "0", "1", - "0", "0", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "0", "1", - "1", "0", "0", "1", "1", "1", "1", "1", "0", "0", "0", "1", "1", "1", "0", "1", "0", - "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "0", "0", "0", "1", "1", - "1", "0", "1", "0", "0", "1", "1", "1", "1", "0", "0", "0", "0", "0", "1", "1", "0", - "1", "1", "0", "0", "0", "1", "0", "0", "1", "1", "1", "0", "1", "0", "0", "0", "0", - "0", "0", "0", "1", "0", "0", "0", "1", "1", "1", "0", "0", "1", "1", "0", "1", "0", - "0", - ]; + let third = hex::decode("9dcc025d70596afc98d90e2aeaff64fb2f8cdc8cba67c743143a783627404734") + .unwrap(); - let fourth = vec![ - "1", "1", "0", "0", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", "0", - "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", "1", "1", "0", "1", "0", - "0", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", - "1", "0", "1", "1", "1", "1", "0", "0", "1", "0", "0", "1", "0", "1", "0", "1", "1", - "0", "1", "0", "0", "1", "1", "0", "1", "0", "0", "1", "0", "0", "0", "1", "1", "0", - "0", "1", "0", "0", "0", "0", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", - "1", "1", "1", "0", "1", "1", "0", "1", "0", "1", "1", "0", "1", "1", "1", "1", "1", - "0", "1", "1", "1", "0", "1", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", - "0", "0", "0", "0", "1", "0", "1", "1", "0", "0", "1", "0", "0", "1", "0", "0", "0", - "0", "1", "1", "0", "1", "1", "1", "1", "1", "0", "1", "0", "0", "0", "1", "0", "1", - "0", "0", "0", "0", "1", "1", "1", "1", "1", "0", "0", "1", "1", "1", "0", "1", "0", - "1", "1", "0", "1", "1", "0", "1", "1", "1", "1", "0", "1", "0", "0", "1", "1", "1", - "0", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", "0", "1", "0", "0", - "0", "0", "0", "1", "1", "0", "1", "1", "1", "1", "0", "1", "0", "0", "0", "0", "0", - "1", - ]; + let fourth = + hex::decode("c3b6594b1b1343b69bc95a69190b85dadf776205921be8a1f3adbd39cc906f41") + .unwrap(); let hash_tree_root = vec![ "1", "0", "0", "1", "0", "1", "0", "0", "0", "0", "1", "1", "1", "1", "0", "0", "1", @@ -491,12 +278,10 @@ mod tests { "1", ]; - for i in 0..ETH_SHA256_BIT_SIZE { - pw.set_bool_target(targets.leaves[0][i], first[i] == "1"); - pw.set_bool_target(targets.leaves[1][i], second[i] == "1"); - pw.set_bool_target(targets.leaves[2][i], third[i] == "1"); - pw.set_bool_target(targets.leaves[3][i], fourth[i] == "1"); - } + pw.set_bytes_array(&targets.leaves[0], &first); + pw.set_bytes_array(&targets.leaves[1], &second); + pw.set_bytes_array(&targets.leaves[2], &third); + pw.set_bytes_array(&targets.leaves[3], &fourth); for i in 0..ETH_SHA256_BIT_SIZE { if hash_tree_root[i] == "1" { diff --git a/beacon-light-client/plonky2/circuits/src/utils.rs b/beacon-light-client/plonky2/circuits/src/utils.rs index c17db665c..786de5e5c 100644 --- a/beacon-light-client/plonky2/circuits/src/utils.rs +++ b/beacon-light-client/plonky2/circuits/src/utils.rs @@ -1,5 +1,10 @@ use plonky2::{ - field::extension::Extendable, hash::hash_types::RichField, iop::target::BoolTarget, + field::{extension::Extendable, types::Field}, + hash::hash_types::RichField, + iop::{ + target::BoolTarget, + witness::{PartialWitness, WitnessWrite}, + }, plonk::circuit_builder::CircuitBuilder, }; use plonky2_u32::gadgets::arithmetic_u32::U32Target; @@ -10,39 +15,10 @@ use crate::biguint::{BigUintTarget, CircuitBuilderBiguint}; pub const ETH_SHA256_BIT_SIZE: usize = 256; pub const POSEIDON_HASH_SIZE: usize = 4; -pub fn hash_bit_array(validator_pubkey: Vec<&str>) -> Vec { - // Concatenate the array into a single binary string - let binary_string: String = validator_pubkey.join(""); - - // Convert binary string to bytes - let mut byte_string: Vec = binary_string - .as_str() - .chars() - .collect::>() - .chunks(8) - .map(|chunk| { - let byte_str: String = chunk.into_iter().collect(); - u8::from_str_radix(&byte_str, 2).unwrap() - }) - .collect(); - - byte_string.resize(64, 0); - +pub fn hash_bytes(bytes: &[u8]) -> Vec { let mut hasher = Sha256::new(); - hasher.update(byte_string); - let result = hasher.finalize(); - - let pubkey_binary_result: Vec = result - .iter() - .map(|byte| { - format!("{:08b}", byte) - .chars() - .map(|ch| ch.to_string()) - .collect::>() - }) - .flatten() - .collect(); - pubkey_binary_result + hasher.update(bytes); + hasher.finalize().to_vec() } pub fn biguint_is_equal, const D: usize>( @@ -187,6 +163,57 @@ pub fn if_biguint, const D: usize>( result } +pub fn bytes_to_bools(bytes: &[u8]) -> Vec { + let mut bool_values = Vec::new(); + + for value in bytes { + for i in (0..8).rev() { + let mask = 1 << i; + bool_values.push(value & mask != 0); + } + } + + bool_values +} + +pub fn bools_to_bytes(bools: &[bool]) -> Vec { + let mut bytes = Vec::new(); + let mut byte = 0u8; + + for (index, bit) in bools.iter().enumerate() { + if *bit { + byte |= 1 << (7 - (index % 8)); + } + + if index % 8 == 7 { + bytes.push(byte); + byte = 0; + } + } + + if bools.len() % 8 != 0 { + bytes.push(byte); + } + + bytes +} + +pub trait SetBytesArray { + fn set_bytes_array(&mut self, targets: &[BoolTarget], values: &[u8]); +} + +impl SetBytesArray for PartialWitness { + fn set_bytes_array(&mut self, targets: &[BoolTarget], values: &[u8]) { + assert!(targets.len() == values.len() * 8); + + let bool_values = bytes_to_bools(values); + + for i in 0..targets.len() { + self.set_bool_target(targets[i], bool_values[i]); + } + } +} + #[cfg(test)] mod test_ssz_num_from_bits { use anyhow::Result; diff --git a/beacon-light-client/plonky2/circuits/src/validator_commitment_mapper.rs b/beacon-light-client/plonky2/circuits/src/validator_commitment_mapper.rs index ccbecb785..265334662 100644 --- a/beacon-light-client/plonky2/circuits/src/validator_commitment_mapper.rs +++ b/beacon-light-client/plonky2/circuits/src/validator_commitment_mapper.rs @@ -123,7 +123,9 @@ mod test { use anyhow::Result; use plonky2::{ field::goldilocks_field::GoldilocksField, - iop::witness::{PartialWitness, WitnessWrite}, + iop::{ + witness::{PartialWitness}, + }, plonk::{ circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, config::PoseidonGoldilocksConfig, @@ -131,7 +133,8 @@ mod test { }; use crate::{ - utils::ETH_SHA256_BIT_SIZE, validator_commitment_mapper::validator_commitment_mapper, + utils::{SetBytesArray, ETH_SHA256_BIT_SIZE}, + validator_commitment_mapper::validator_commitment_mapper, }; #[test] @@ -146,126 +149,34 @@ mod test { let mut pw = PartialWitness::new(); - let validator_pubkey = [ - "1", "0", "0", "1", "0", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "0", "1", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", "0", "0", - "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", - "0", "0", "1", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "1", "1", "0", "1", - "0", "0", "0", "0", "0", "1", "1", "0", "0", "1", "0", "1", "1", "0", "1", "1", "0", - "1", "0", "1", "0", "1", "1", "0", "0", "0", "0", "0", "1", "1", "0", "1", "0", "0", - "1", "0", "0", "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", - "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "1", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "0", "1", "0", "1", "1", "0", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", "1", - "1", "0", "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "1", "1", - "0", "1", "1", "1", "0", "0", "1", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", - "0", "0", "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", - "0", "0", "1", "1", "1", "1", "0", "1", "0", "0", "0", "1", "1", "1", "1", "0", "1", - "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", - "0", "0", "1", "1", "0", "0", "1", "1", "1", "1", "0", "1", "0", "1", "0", "0", "0", - "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "1", "1", "1", "0", "0", "0", - "0", "1", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "0", "0", - "1", "0", "1", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "0", "1", "1", "0", - "0", "0", "1", "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "0", - "0", "0", "0", "1", "0", "0", "1", "1", "0", "1", "0", "0", "0", "0", "1", "0", "1", - "0", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", "0", "0", "1", "1", - "0", "0", "1", "0", "0", "1", "0", "1", "0", "1", - ]; + let validator_pubkey =hex::decode("933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95").unwrap(); + let withdrawal_credentials = + hex::decode("0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50") + .unwrap(); - let withdraw_credentials = [ - "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "1", "0", "1", - "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "0", "0", "1", "1", "1", "1", "0", - "1", "1", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "0", "0", "0", "1", "0", - "0", "0", "0", "0", "0", "0", "0", "1", "1", "1", "1", "1", "1", "0", "1", "0", "0", - "1", "1", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "1", "0", "1", "0", "1", - "0", "1", "0", "0", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", - "1", "0", "1", "1", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "0", "1", "1", "0", "1", "0", "1", "0", "1", "0", "0", "0", - "0", - ]; + let effective_balance = + hex::decode("0040597307000000000000000000000000000000000000000000000000000000") + .unwrap(); - let effective_balance = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", - "0", "0", "0", "1", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let slashed = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let slashed = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_eligibility_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let activation_eligibility_epoch = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let withdrawable_epoch = [ - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let exit_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); + + let withdrawable_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); let validator_hash_tree_root = [ "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "1", "1", "1", "0", @@ -286,40 +197,27 @@ mod test { "1", ]; - for i in 0..384 { - pw.set_bool_target(targets.validator.pubkey[i], validator_pubkey[i] == "1"); - } + pw.set_bytes_array(&targets.validator.pubkey, &validator_pubkey); - for i in 0..ETH_SHA256_BIT_SIZE { - pw.set_bool_target( - targets.validator.withdrawal_credentials[i], - withdraw_credentials[i] == "1", - ); - - pw.set_bool_target( - targets.validator.effective_balance[i], - effective_balance[i] == "1", - ); - - pw.set_bool_target(targets.validator.slashed[i], slashed[i] == "1"); - - pw.set_bool_target( - targets.validator.activation_eligibility_epoch[i], - activation_eligibility_epoch[i] == "1", - ); - - pw.set_bool_target(targets.validator.activation_epoch[i], false); - - pw.set_bool_target( - targets.validator.exit_epoch[i], - if i < 64 { true } else { false }, - ); - - pw.set_bool_target( - targets.validator.withdrawable_epoch[i], - withdrawable_epoch[i] == "1", - ); - } + pw.set_bytes_array( + &targets.validator.withdrawal_credentials, + &withdrawal_credentials, + ); + + pw.set_bytes_array( + &targets.validator.activation_eligibility_epoch, + &activation_eligibility_epoch, + ); + + pw.set_bytes_array(&targets.validator.activation_epoch, &activation_epoch); + + pw.set_bytes_array(&targets.validator.slashed, &slashed); + + pw.set_bytes_array(&targets.validator.effective_balance, &effective_balance); + + pw.set_bytes_array(&targets.validator.exit_epoch, &exit_epoch); + + pw.set_bytes_array(&targets.validator.withdrawable_epoch, &withdrawable_epoch); for i in 0..ETH_SHA256_BIT_SIZE { if validator_hash_tree_root[i] == "1" { diff --git a/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs b/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs index 805103b6d..d5379a250 100644 --- a/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs +++ b/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs @@ -146,7 +146,7 @@ mod test { use anyhow::Result; use plonky2::{ field::goldilocks_field::GoldilocksField, - iop::witness::{PartialWitness, WitnessWrite}, + iop::witness::{PartialWitness}, plonk::{ circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, config::PoseidonGoldilocksConfig, @@ -154,7 +154,7 @@ mod test { }; use crate::{ - utils::ETH_SHA256_BIT_SIZE, validator_hash_tree_root::hash_tree_root_validator_sha256, + utils::{ETH_SHA256_BIT_SIZE, SetBytesArray}, validator_hash_tree_root::hash_tree_root_validator_sha256, }; #[test] @@ -169,126 +169,34 @@ mod test { let mut pw = PartialWitness::new(); - let validator_pubkey = [ - "1", "0", "0", "1", "0", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "0", "1", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", "0", "0", - "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", - "0", "0", "1", "0", "1", "1", "0", "0", "1", "1", "1", "0", "1", "1", "1", "0", "1", - "0", "0", "0", "0", "0", "1", "1", "0", "0", "1", "0", "1", "1", "0", "1", "1", "0", - "1", "0", "1", "0", "1", "1", "0", "0", "0", "0", "0", "1", "1", "0", "1", "0", "0", - "1", "0", "0", "1", "0", "1", "0", "1", "1", "0", "1", "1", "0", "1", "1", "0", "0", - "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "1", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "0", "1", "0", "1", "1", "0", "0", "1", "1", "0", "0", "0", "1", "1", "0", "1", "1", - "1", "0", "1", "0", "0", "0", "1", "1", "0", "1", "1", "0", "0", "0", "1", "1", "1", - "0", "1", "1", "1", "0", "0", "1", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", - "0", "0", "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "0", - "0", "0", "1", "1", "1", "1", "0", "1", "0", "0", "0", "1", "1", "1", "1", "0", "1", - "1", "1", "0", "0", "1", "1", "0", "0", "1", "0", "1", "0", "0", "1", "0", "0", "1", - "0", "0", "1", "1", "0", "0", "1", "1", "1", "1", "0", "1", "0", "1", "0", "0", "0", - "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "1", "1", "1", "0", "0", "0", - "0", "1", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "0", "0", - "1", "0", "1", "0", "0", "1", "1", "1", "0", "1", "1", "0", "1", "0", "1", "1", "0", - "0", "0", "1", "0", "1", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", "1", "0", - "0", "0", "0", "1", "0", "0", "1", "1", "0", "1", "0", "0", "0", "0", "1", "0", "1", - "0", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "1", "0", "0", "0", "1", "1", - "0", "0", "1", "0", "0", "1", "0", "1", "0", "1", - ]; + let validator_pubkey =hex::decode("933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95").unwrap(); + let withdrawal_credentials = + hex::decode("0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50") + .unwrap(); - let withdraw_credentials = [ - "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "1", "0", "1", - "1", "1", "0", "1", "1", "0", "1", "0", "0", "1", "0", "0", "1", "1", "1", "1", "0", - "1", "1", "1", "1", "1", "0", "1", "0", "0", "1", "0", "1", "0", "0", "0", "1", "0", - "0", "0", "0", "0", "0", "0", "0", "1", "1", "1", "1", "1", "1", "0", "1", "0", "0", - "1", "1", "1", "0", "1", "1", "1", "0", "0", "0", "0", "1", "1", "0", "1", "0", "1", - "0", "1", "0", "0", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", "0", "1", "0", - "1", "0", "0", "0", "1", "1", "0", "0", "0", "1", "0", "1", "0", "1", "0", "1", "1", - "1", "0", "1", "1", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "1", "1", - "0", "1", "0", "0", "1", "0", "1", "1", "0", "1", "0", "1", "0", "1", "0", "0", "0", - "0", - ]; + let effective_balance = + hex::decode("0040597307000000000000000000000000000000000000000000000000000000") + .unwrap(); - let effective_balance = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", - "1", "0", "1", "1", "0", "0", "1", "0", "1", "1", "1", "0", "0", "1", "1", "0", "0", - "0", "0", "0", "1", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let slashed = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let slashed = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_eligibility_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let activation_eligibility_epoch = [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let activation_epoch = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let withdrawable_epoch = [ - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", - ]; + let exit_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); + + let withdrawable_epoch = + hex::decode("ffffffffffffffff000000000000000000000000000000000000000000000000") + .unwrap(); let validator_hash_tree_root = [ "0", "0", "1", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "1", "1", "1", "0", @@ -309,40 +217,28 @@ mod test { "1", ]; - for i in 0..384 { - pw.set_bool_target(targets.validator.pubkey[i], validator_pubkey[i] == "1"); - } + pw.set_bytes_array(&targets.validator.pubkey, &validator_pubkey); + + pw.set_bytes_array( + &targets.validator.withdrawal_credentials, + &withdrawal_credentials, + ); + + pw.set_bytes_array( + &targets.validator.activation_eligibility_epoch, + &activation_eligibility_epoch, + ); + + pw.set_bytes_array(&targets.validator.activation_epoch, &activation_epoch); + + pw.set_bytes_array(&targets.validator.slashed, &slashed); + + pw.set_bytes_array(&targets.validator.effective_balance, &effective_balance); + + pw.set_bytes_array(&targets.validator.exit_epoch, &exit_epoch); + + pw.set_bytes_array(&targets.validator.withdrawable_epoch, &withdrawable_epoch); - for i in 0..ETH_SHA256_BIT_SIZE { - pw.set_bool_target( - targets.validator.withdrawal_credentials[i], - withdraw_credentials[i] == "1", - ); - - pw.set_bool_target( - targets.validator.effective_balance[i], - effective_balance[i] == "1", - ); - - pw.set_bool_target(targets.validator.slashed[i], slashed[i] == "1"); - - pw.set_bool_target( - targets.validator.activation_eligibility_epoch[i], - activation_eligibility_epoch[i] == "1", - ); - - pw.set_bool_target(targets.validator.activation_epoch[i], false); - - pw.set_bool_target( - targets.validator.exit_epoch[i], - if i < 64 { true } else { false }, - ); - - pw.set_bool_target( - targets.validator.withdrawable_epoch[i], - withdrawable_epoch[i] == "1", - ); - } for i in 0..ETH_SHA256_BIT_SIZE { if validator_hash_tree_root[i] == "1" { diff --git a/beacon-light-client/plonky2/circuits_executables/Cargo.lock b/beacon-light-client/plonky2/circuits_executables/Cargo.lock index 359c5c383..7d91645a6 100644 --- a/beacon-light-client/plonky2/circuits_executables/Cargo.lock +++ b/beacon-light-client/plonky2/circuits_executables/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addchain" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" +dependencies = [ + "num-bigint 0.3.3", + "num-integer", + "num-traits", +] + [[package]] name = "addr2line" version = "0.20.0" @@ -197,6 +208,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -281,8 +304,11 @@ dependencies = [ "anyhow", "circuits", "clap", + "ff", "futures-lite", + "hex", "jemallocator", + "lazy_static", "num", "plonky2", "redis", @@ -475,6 +501,35 @@ dependencies = [ "instant", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "byteorder", + "ff_derive", + "rand_core", + "subtle", +] + +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "fixed-hash" version = "0.7.0" @@ -493,6 +548,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.28" @@ -807,6 +868,12 @@ dependencies = [ "log", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.147" @@ -869,7 +936,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" dependencies = [ - "num-bigint", + "num-bigint 0.4.3", "num-complex", "num-integer", "num-iter", @@ -877,6 +944,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -929,7 +1007,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint", + "num-bigint 0.4.3", "num-integer", "num-traits", "serde", @@ -1127,6 +1205,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -1341,6 +1425,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1363,6 +1453,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "termcolor" version = "1.2.0" @@ -1736,3 +1832,12 @@ name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/beacon-light-client/plonky2/circuits_executables/Cargo.toml b/beacon-light-client/plonky2/circuits_executables/Cargo.toml index 7fab6acd5..653a3f598 100644 --- a/beacon-light-client/plonky2/circuits_executables/Cargo.toml +++ b/beacon-light-client/plonky2/circuits_executables/Cargo.toml @@ -13,10 +13,13 @@ redis = "0.22" serde = "1.0.164" serde_json = "1.0.96" anyhow = "1.0.71" +hex = "0.4.3" redis-work-queue = "0.1.3" futures-lite = "1" jemallocator = "0.5.0" clap = "3.0" +lazy_static = "1.4.0" +ff = { package = "ff", version = "0.13", features = ["derive"] } [[bin]] name = "balance_verification" @@ -34,6 +37,10 @@ path = "bin/balance_verification_circuit_data_generation.rs" name = "final_layer" path = "bin/final_layer.rs" +[[bin]] +name = "wrapper" +path = "bin/wrapper.rs" + [[bin]] name = "commitment_mapper_circuit_data_generation" path = "bin/commitment_mapper_circuit_data_generation.rs" diff --git a/beacon-light-client/plonky2/circuits_executables/bin/final_layer.rs b/beacon-light-client/plonky2/circuits_executables/bin/final_layer.rs index 86e979db0..d75b07cc9 100644 --- a/beacon-light-client/plonky2/circuits_executables/bin/final_layer.rs +++ b/beacon-light-client/plonky2/circuits_executables/bin/final_layer.rs @@ -1,7 +1,10 @@ -use std::{println, time::Instant}; +use std::{fs, marker::PhantomData, println, time::Instant}; use anyhow::Result; -use circuits::build_final_circuit::build_final_circuit; +use circuits::{ + build_final_circuit::build_final_circuit, + generator_serializer::{DendrETHGateSerializer, DendrETHGeneratorSerializer}, +}; use circuits_executables::{ crud::{ fetch_final_layer_input, fetch_proof, load_circuit_data, save_final_proof, BalanceProof, @@ -115,10 +118,35 @@ async fn async_main() -> Result<()> { let proof = circuit_data.prove(pw)?; - save_final_proof(&mut con, &proof).await?; + save_final_proof( + &mut con, + &proof, + final_input_data + .state_root + .iter() + .map(|x| *x as u64) + .collect::>(), + balance_proof.withdrawal_credentials, + balance_proof.range_total_value, + ) + .await?; println!("Proof size: {}", proof.to_bytes().len()); + fs::write("final_layer_proof", proof.to_bytes()).unwrap(); + + let gate_serializer = DendrETHGateSerializer; + + let generator_serializer = DendrETHGeneratorSerializer { + _phantom: PhantomData::, + }; + + let circuit_data_bytes = circuit_data + .to_bytes(&gate_serializer, &generator_serializer) + .unwrap(); + + fs::write("final_layer.plonky2_circuit", circuit_data_bytes).unwrap(); + println!("Final proof saved!"); Ok(()) diff --git a/beacon-light-client/plonky2/circuits_executables/bin/wrapper.rs b/beacon-light-client/plonky2/circuits_executables/bin/wrapper.rs new file mode 100644 index 000000000..13c543c8b --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/bin/wrapper.rs @@ -0,0 +1,114 @@ +use std::{fs, println, time::Instant}; + +use anyhow::Result; +use circuits_executables::{ + crud::{load_circuit_data, FinalProof}, + poseidon_bn128_config::PoseidonBN128GoldilocksConfig, + validator_commitment_constants::get_validator_commitment_constants, +}; +use clap::{App, Arg}; +use futures_lite::future; +use plonky2::{ + field::goldilocks_field::GoldilocksField, + fri::{reduction_strategies::FriReductionStrategy, FriConfig}, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::{ + circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, + config::PoseidonGoldilocksConfig, proof::ProofWithPublicInputs, + }, +}; +use redis::AsyncCommands; + +fn main() -> Result<()> { + future::block_on(async_main()) +} + +async fn async_main() -> Result<()> { + let matches = App::new("") + .arg( + Arg::with_name("redis_connection") + .short('r') + .long("redis") + .value_name("Redis Connection") + .help("Sets a custom Redis connection") + .takes_value(true) + .default_value("redis://127.0.0.1:6379/"), + ) + .get_matches(); + + let redis_connection = matches.value_of("redis_connection").unwrap(); + + let start = Instant::now(); + let client = redis::Client::open(redis_connection)?; + let mut con = client.get_async_connection().await?; + + let elapsed = start.elapsed(); + + println!("Redis connection took: {:?}", elapsed); + + let final_layer_circuit = load_circuit_data("final_layer").unwrap(); + + let standard_recursion_config = CircuitConfig::standard_recursion_config(); + + let config = CircuitConfig { + fri_config: FriConfig { + rate_bits: 6, + cap_height: 4, + proof_of_work_bits: 16, + reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5), + num_query_rounds: 14, + }, + ..standard_recursion_config + }; + + let mut builder = CircuitBuilder::::new(config); + + let verifier_target = builder.constant_verifier_data(&final_layer_circuit.verifier_only); + + let proof_target = builder.add_virtual_proof_with_pis(&final_layer_circuit.common); + + builder.verify_proof::( + &proof_target.clone(), + &verifier_target, + &final_layer_circuit.common, + ); + + builder.register_public_inputs(&proof_target.public_inputs); + + let proof_str: String = con + .get(get_validator_commitment_constants().final_layer_proof_key) + .await?; + + let final_layer_proof: FinalProof = serde_json::from_str(&proof_str)?; + let final_layer_proof = final_layer_proof.proof; + + let final_proof: ProofWithPublicInputs = + ProofWithPublicInputs::from_bytes(final_layer_proof, &final_layer_circuit.common)?; + + let mut pw = PartialWitness::new(); + + pw.set_proof_with_pis_target(&proof_target, &final_proof); + + let circuit_data = builder.build::(); + + let proof = circuit_data.prove(pw)?; + + let proof_json = serde_json::to_string(&proof).unwrap(); + + fs::write("proof_with_public_inputs.json", proof_json).unwrap(); + + let common_circuit_data = circuit_data.common; + let common_circuit_data = serde_json::to_string(&common_circuit_data).unwrap(); + + fs::write("common_circuit_data.json", common_circuit_data).unwrap(); + + let verifier_only_circuit_data = serde_json::to_string(&circuit_data.verifier_only).unwrap(); + + fs::write( + "verifier_only_circuit_data.json", + verifier_only_circuit_data, + ) + .unwrap(); + + Ok(()) +} diff --git a/beacon-light-client/plonky2/circuits_executables/examples/read_circuit_data_example.rs b/beacon-light-client/plonky2/circuits_executables/examples/read_circuit_data_example.rs index 4b4c9c6d6..d77156b2b 100644 --- a/beacon-light-client/plonky2/circuits_executables/examples/read_circuit_data_example.rs +++ b/beacon-light-client/plonky2/circuits_executables/examples/read_circuit_data_example.rs @@ -1,21 +1,28 @@ -use std::{marker::PhantomData, println, time::Instant}; +use std::{fs, marker::PhantomData, println, time::Instant}; use anyhow::{Ok, Result}; use circuits::{ generator_serializer::{DendrETHGateSerializer, DendrETHGeneratorSerializer}, targets_serialization::ReadTargets, validator_balance_circuit::ValidatorBalanceVerificationTargets, + validator_commitment_mapper::ValidatorCommitmentTargets, }; use circuits_executables::{ - crud::{fetch_validator_balance_input, read_from_file}, + crud::{fetch_validator, fetch_validator_balance_input, read_from_file}, + poseidon_bn128_config::PoseidonBN128GoldilocksConfig, provers::SetPWValues, }; use futures_lite::future; use plonky2::{ field::goldilocks_field::GoldilocksField, - iop::{witness::PartialWitness}, - plonk::{circuit_data::CircuitData, config::PoseidonGoldilocksConfig}, - util::serialization::{Buffer}, + fri::{reduction_strategies::FriReductionStrategy, FriConfig}, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::{ + circuit_builder::CircuitBuilder, + circuit_data::{CircuitConfig, CircuitData}, + config::PoseidonGoldilocksConfig, + }, + util::serialization::Buffer, }; use jemallocator::Jemalloc; @@ -30,13 +37,12 @@ fn main() -> Result<()> { async fn async_main() -> Result<()> { let start = Instant::now(); - let target_bytes = read_from_file("targets")?; + let target_bytes = read_from_file("commitment_mapper_0.plonky2_targets")?; let mut target_buffer = Buffer::new(&target_bytes); - let validator_targets = - ValidatorBalanceVerificationTargets::read_targets(&mut target_buffer).unwrap(); + let validator_targets = ValidatorCommitmentTargets::read_targets(&mut target_buffer).unwrap(); - let circuit_data_bytes = read_from_file("validator_balance_circuit")?; + let circuit_data_bytes = read_from_file("commitment_mapper_0.plonky2_circuit")?; let gate_serializer = DendrETHGateSerializer; @@ -64,7 +70,7 @@ async fn async_main() -> Result<()> { println!("Redis connection took: {:?}", elapsed); let start = Instant::now(); - let validator_balance_input = fetch_validator_balance_input(&mut con, 0).await?; + let validator_balance_input = fetch_validator(&mut con, 0).await?; let elapsed = start.elapsed(); @@ -73,7 +79,9 @@ async fn async_main() -> Result<()> { let start = Instant::now(); let mut pw = PartialWitness::new(); - validator_targets.set_pw_values(&mut pw, &validator_balance_input); + validator_targets + .validator + .set_pw_values(&mut pw, &validator_balance_input); let proof = data.prove(pw)?; @@ -82,5 +90,74 @@ async fn async_main() -> Result<()> { println!("Proof generation took: {:?}", elapsed); println!("Public inputs: {:?}", proof.public_inputs); + let standard_recursion_config = CircuitConfig::standard_recursion_config(); + + let config = CircuitConfig { + fri_config: FriConfig { + rate_bits: 6, + cap_height: 4, + proof_of_work_bits: 16, + reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5), + num_query_rounds: 14, + }, + ..standard_recursion_config + }; + + let mut builder = CircuitBuilder::::new(config); + + let verifier_target = builder.constant_verifier_data(&data.verifier_only); + + let proof_target = builder.add_virtual_proof_with_pis(&data.common); + + builder.verify_proof::( + &proof_target.clone(), + &verifier_target, + &data.common, + ); + + let public_inputs_inner_proof = proof_target.public_inputs.clone(); + + builder.register_public_inputs(&public_inputs_inner_proof); + + println!("Starting building final proof"); + let start = Instant::now(); + + let data = builder.build::(); + + let elapsed = start.elapsed(); + + println!("Building took: {:?}", elapsed); + + let mut pw = PartialWitness::new(); + + pw.set_proof_with_pis_target(&proof_target, &proof); + + println!("Starting proofing final proof"); + + let start = Instant::now(); + + let proof = data.prove(pw).unwrap(); + + let elapsed = start.elapsed(); + + println!("Proving took: {:?}", elapsed); + + let json = serde_json::to_string(&proof).unwrap(); + + fs::write("proof_with_public_inputs.json", json).unwrap(); + + let common_circuit_data = data.common; + let common_circuit_data = serde_json::to_string(&common_circuit_data).unwrap(); + + fs::write("common_circuit_data.json", common_circuit_data).unwrap(); + + let verifier_only_circuit_data = serde_json::to_string(&data.verifier_only).unwrap(); + + fs::write( + "verifier_only_circuit_data.json", + verifier_only_circuit_data, + ) + .unwrap(); + Ok(()) } diff --git a/beacon-light-client/plonky2/circuits_executables/src/crud.rs b/beacon-light-client/plonky2/circuits_executables/src/crud.rs index 90d7f6898..335ca651a 100644 --- a/beacon-light-client/plonky2/circuits_executables/src/crud.rs +++ b/beacon-light-client/plonky2/circuits_executables/src/crud.rs @@ -11,15 +11,12 @@ use crate::{ use anyhow::Result; use circuits::{ build_commitment_mapper_first_level_circuit::CommitmentMapperProofExt, - build_final_circuit::FinalCircuitProofExt, - build_validator_balance_circuit::{ - ValidatorBalanceProofExt, - }, + build_validator_balance_circuit::ValidatorBalanceProofExt, generator_serializer::{DendrETHGateSerializer, DendrETHGeneratorSerializer}, }; use num::BigUint; use plonky2::{ - field::{goldilocks_field::GoldilocksField}, + field::goldilocks_field::GoldilocksField, plonk::{ circuit_data::CircuitData, config::PoseidonGoldilocksConfig, proof::ProofWithPublicInputs, }, @@ -94,7 +91,9 @@ pub struct FinalCircuitInput { pub struct FinalProof { pub needs_change: bool, pub state_root: Vec, + #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] pub withdrawal_credentials: BigUint, + #[serde(serialize_with = "biguint_to_str", deserialize_with = "parse_biguint")] pub balance_sum: BigUint, pub proof: Vec, } @@ -208,12 +207,15 @@ pub async fn save_balance_proof( pub async fn save_final_proof( con: &mut redis::aio::Connection, proof: &ProofWithPublicInputs, + state_root: Vec, + withdrawal_credentials: BigUint, + balance_sum: BigUint, ) -> Result<()> { let final_proof = serde_json::to_string(&FinalProof { needs_change: false, - state_root: proof.get_final_circuit_state_root().to_vec(), - withdrawal_credentials: proof.get_final_circuit_withdrawal_credentials(), - balance_sum: proof.get_final_circuit_balance_sum(), + state_root: state_root, + withdrawal_credentials: withdrawal_credentials, + balance_sum: balance_sum, proof: proof.to_bytes(), })?; @@ -250,7 +252,9 @@ pub async fn save_validator_proof( index: usize, ) -> Result<()> { let validator_proof = serde_json::to_string(&ValidatorProof { - poseidon_hash: proof.get_commitment_mapper_poseidon_hash_tree_root().to_vec(), + poseidon_hash: proof + .get_commitment_mapper_poseidon_hash_tree_root() + .to_vec(), sha256_hash: proof.get_commitment_mapper_sha256_hash_tree_root().to_vec(), proof: proof.to_bytes(), needs_change: false, diff --git a/beacon-light-client/plonky2/circuits_executables/src/lib.rs b/beacon-light-client/plonky2/circuits_executables/src/lib.rs index 26e5dc6b5..8811fd5ec 100644 --- a/beacon-light-client/plonky2/circuits_executables/src/lib.rs +++ b/beacon-light-client/plonky2/circuits_executables/src/lib.rs @@ -3,3 +3,7 @@ pub mod provers; pub mod validator; pub mod validator_balances_input; pub mod validator_commitment_constants; +pub mod utils; +pub mod poseidon_constants; +pub mod poseidon_bn128_config; +pub mod poseidon_bn128; diff --git a/beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128.rs b/beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128.rs new file mode 100644 index 000000000..a010a9dd6 --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128.rs @@ -0,0 +1,266 @@ +use std::ops::{AddAssign, MulAssign}; + +use ff::Field; + +use crate::{poseidon_constants::{C_CONSTANTS, P_MATRIX, M_MATRIX, S_CONSTANTS}, utils::Fr}; + +pub const RATE: usize = 3; +pub const WIDTH: usize = 4; +const FULL_ROUNDS: usize = 8; +const PARTIAL_ROUNDS: usize = 56; +pub const GOLDILOCKS_ELEMENTS: usize = 3; + +pub type PoseidonState = [Fr; WIDTH]; + +// This poseidon BN128 implementation is based on the following implementation: +// https://github.com/iden3/go-iden3-crypto/blob/e5cf066b8be3da9a3df9544c65818df189fdbebe/poseidon/poseidon.go +pub fn permution(state: &mut PoseidonState) { + ark(state, 0); + full_rounds(state, true); + partial_rounds(state); + full_rounds(state, false); +} + +fn ark(state: &mut PoseidonState, it: usize) { + for i in 0..WIDTH { + state[i].add_assign(&C_CONSTANTS[it + i]); + } +} + +fn exp5(mut x: Fr) -> Fr { + let aux = x; + x = x.square(); + x = x.square(); + x.mul_assign(&aux); + + x +} + +fn exp5_state(state: &mut PoseidonState) { + for state_element in state.iter_mut().take(WIDTH) { + *state_element = exp5(*state_element); + } +} + +fn full_rounds(state: &mut PoseidonState, first: bool) { + for i in 0..FULL_ROUNDS / 2 - 1 { + exp5_state(state); + if first { + ark(state, (i + 1) * WIDTH); + } else { + ark( + state, + (FULL_ROUNDS / 2 + 1) * WIDTH + PARTIAL_ROUNDS + i * WIDTH, + ); + } + mix(state, &M_MATRIX); + } + + exp5_state(state); + if first { + ark(state, (FULL_ROUNDS / 2) * WIDTH); + mix(state, &P_MATRIX); + } else { + mix(state, &M_MATRIX); + } +} + +fn partial_rounds(state: &mut PoseidonState) { + for i in 0..PARTIAL_ROUNDS { + state[0] = exp5(state[0]); + state[0].add_assign(&C_CONSTANTS[(FULL_ROUNDS / 2 + 1) * WIDTH + i]); + + let mut mul; + let mut new_state0 = Fr::ZERO; + for j in 0..WIDTH { + mul = Fr::ZERO; + mul.add_assign(&S_CONSTANTS[(WIDTH * 2 - 1) * i + j]); + mul.mul_assign(&state[j]); + new_state0.add_assign(&mul); + } + + for k in 1..WIDTH { + mul = Fr::ZERO; + mul.add_assign(&state[0]); + mul.mul_assign(&S_CONSTANTS[(WIDTH * 2 - 1) * i + WIDTH + k - 1]); + state[k].add_assign(&mul); + } + + state[0] = new_state0; + } +} + +fn mix(state: &mut PoseidonState, constant_matrix: &[Vec]) { + let mut result: PoseidonState = [Fr::ZERO; WIDTH]; + + let mut mul; + for (i, result_element) in result.iter_mut().enumerate().take(WIDTH) { + for j in 0..WIDTH { + mul = Fr::ZERO; + mul.add_assign(&constant_matrix[j][i]); + mul.mul_assign(&state[j]); + result_element.add_assign(&mul); + } + } + + state[..WIDTH].copy_from_slice(&result[..WIDTH]); +} + +#[cfg(test)] +mod permutation_tests { + use anyhow::Ok; + use ff::{Field, PrimeField}; + + use crate::utils::Fr; + + use super::{permution, WIDTH}; + + #[test] + fn test_permuation() -> Result<(), anyhow::Error> { + // Test inputs are: + // 1. all zeros + // 2. range 0..WIDTH + // 3. all max BN128 values + // 4. random elements of BN128. + // Expected output calculated from this poseidon implementation: https://github.com/iden3/go-iden3-crypto/blob/master/poseidon/poseidon.go#L65 + + let max_value: Fr = Fr::from_str_vartime( + "21888242871839275222246405745257275088548364400416034343698204186575808495616", + ) + .unwrap(); + + let test_vectors: Vec<([Fr; 4], [Fr; 4])> = vec![ + ( + [Fr::ZERO; 4], + [ + Fr::from_str_vartime("5317387130258456662214331362918410991734007599705406860481038345552731150762").unwrap(), + Fr::from_str_vartime("17768273200467269691696191901389126520069745877826494955630904743826040320364").unwrap(), + Fr::from_str_vartime("19413739268543925182080121099097652227979760828059217876810647045303340666757").unwrap(), + Fr::from_str_vartime("3717738800218482999400886888123026296874264026760636028937972004600663725187").unwrap(), + ] + ), + ( + [ + Fr::from_str_vartime("0").unwrap(), + Fr::from_str_vartime("1").unwrap(), + Fr::from_str_vartime("2").unwrap(), + Fr::from_str_vartime("3").unwrap(), + ], + [ + Fr::from_str_vartime("6542985608222806190361240322586112750744169038454362455181422643027100751666").unwrap(), + Fr::from_str_vartime("3478427836468552423396868478117894008061261013954248157992395910462939736589").unwrap(), + Fr::from_str_vartime("1904980799580062506738911865015687096398867595589699208837816975692422464009").unwrap(), + Fr::from_str_vartime("11971464497515232077059236682405357499403220967704831154657374522418385384151").unwrap(), + ] + ), + ( + [max_value; 4], + [ + Fr::from_str_vartime("13055670547682322550638362580666986963569035646873545133474324633020685301274").unwrap(), + Fr::from_str_vartime("19087936485076376314486368416882351797015004625427655501762827988254486144933").unwrap(), + Fr::from_str_vartime("10391468779200270580383536396630001155994223659670674913170907401637624483385").unwrap(), + Fr::from_str_vartime("17202557688472898583549180366140168198092766974201433936205272956998081177816").unwrap(), + ] + ), + ( + [ + Fr::from_str_vartime("6542985608222806190361240322586112750744169038454362455181422643027100751666").unwrap(), + Fr::from_str_vartime("3478427836468552423396868478117894008061261013954248157992395910462939736589").unwrap(), + Fr::from_str_vartime("1904980799580062506738911865015687096398867595589699208837816975692422464009").unwrap(), + Fr::from_str_vartime("11971464497515232077059236682405357499403220967704831154657374522418385384151").unwrap(), + ], + [ + Fr::from_str_vartime("21792249080447013894140672594027696524030291802493510986509431008224624594361").unwrap(), + Fr::from_str_vartime("3536096706123550619294332177231935214243656967137545251021848527424156573335").unwrap(), + Fr::from_str_vartime("14869351042206255711434675256184369368509719143073814271302931417334356905217").unwrap(), + Fr::from_str_vartime("5027523131326906886284185656868809493297314443444919363729302983434650240523").unwrap(), + ] + ), + ]; + + for (mut input, expected_output) in test_vectors.into_iter() { + permution(&mut input); + for i in 0..WIDTH { + assert_eq!(input[i], expected_output[i]); + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod merkle_tree_tests { + use anyhow::Result; + use plonky2::field::extension::Extendable; + use plonky2::hash::hash_types::RichField; + use plonky2::hash::merkle_proofs::verify_merkle_proof_to_cap; + use plonky2::hash::merkle_tree::MerkleTree; + use plonky2::plonk::config::GenericConfig; + + use crate::poseidon_bn128_config::PoseidonBN128GoldilocksConfig; + + fn random_data(n: usize, k: usize) -> Vec> { + (0..n).map(|_| F::rand_vec(k)).collect() + } + + fn verify_all_leaves< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, + >( + leaves: Vec>, + cap_height: usize, + ) -> Result<()> { + let tree = MerkleTree::::new(leaves.clone(), cap_height); + for (i, leaf) in leaves.into_iter().enumerate() { + let proof = tree.prove(i); + verify_merkle_proof_to_cap(leaf, i, &tree.cap, &proof)?; + } + Ok(()) + } + + #[test] + #[should_panic] + fn test_cap_height_too_big() { + const D: usize = 2; + type C = PoseidonBN128GoldilocksConfig; + type F = >::F; + + let log_n = 8; + let cap_height = log_n + 1; // Should panic if `cap_height > len_n`. + + let leaves = random_data::(1 << log_n, 7); + let _ = MerkleTree::>::Hasher>::new(leaves, cap_height); + } + + #[test] + fn test_cap_height_eq_log2_len() -> Result<()> { + const D: usize = 2; + type C = PoseidonBN128GoldilocksConfig; + type F = >::F; + + let log_n = 8; + let n = 1 << log_n; + let leaves = random_data::(n, 7); + + verify_all_leaves::(leaves, log_n)?; + + Ok(()) + } + + #[test] + fn test_merkle_trees() -> Result<()> { + const D: usize = 2; + type C = PoseidonBN128GoldilocksConfig; + type F = >::F; + + let log_n = 8; + let n = 1 << log_n; + let leaves = random_data::(n, 7); + + verify_all_leaves::(leaves, 1)?; + + Ok(()) + } +} diff --git a/beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128_config.rs b/beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128_config.rs new file mode 100644 index 000000000..efd45f163 --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/src/poseidon_bn128_config.rs @@ -0,0 +1,239 @@ +use core::fmt; +use std::error::Error; +use std::marker::PhantomData; + +use ff::{Field as ff_Field, PrimeField}; +use num::BigUint; +use plonky2::field::extension::quadratic::QuadraticExtension; +use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::RichField; +use plonky2::hash::poseidon::{PoseidonHash, PoseidonPermutation}; +use plonky2::plonk::config::{GenericConfig, GenericHashOut, Hasher}; +use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::poseidon_bn128::{permution, RATE, GOLDILOCKS_ELEMENTS}; +use crate::utils::{FrRepr, Fr}; + + +/// Configuration using Poseidon BN128 over the Goldilocks field. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize)] +pub struct PoseidonBN128GoldilocksConfig; +impl GenericConfig<2> for PoseidonBN128GoldilocksConfig { + type F = GoldilocksField; + type FE = QuadraticExtension; + type Hasher = PoseidonBN128Hash; + type InnerHasher = PoseidonHash; +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct PoseidonBN128HashOut { + value: Fr, + _phantom: PhantomData, +} + +fn hash_out_to_bytes(hash: PoseidonBN128HashOut) -> Vec { + let binding = hash.value.to_repr(); + let limbs = binding.as_ref(); + limbs.to_vec() +} + +impl GenericHashOut for PoseidonBN128HashOut { + fn to_bytes(&self) -> Vec { + hash_out_to_bytes(*self) + } + + fn from_bytes(bytes: &[u8]) -> Self { + let sized_bytes: [u8; 32] = bytes.try_into().unwrap(); + let fr_repr = FrRepr(sized_bytes); + let fr = Fr::from_repr(fr_repr).unwrap(); + + Self { + value: fr, + _phantom: PhantomData, + } + } + + fn to_vec(&self) -> Vec { + let bytes = hash_out_to_bytes(*self); + bytes + // Chunks of 7 bytes since 8 bytes would allow collisions. + .chunks(7) + .map(|bytes| { + let mut arr = [0; 8]; + arr[..bytes.len()].copy_from_slice(bytes); + F::from_canonical_u64(u64::from_le_bytes(arr)) + }) + .collect() + } +} + +impl Serialize for PoseidonBN128HashOut { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // Output the hash as a bigint string. + let binding = self.value.to_repr(); + let limbs = binding.as_ref(); + + let big_int = BigUint::from_bytes_le(limbs); + serializer.serialize_str(big_int.to_str_radix(10).as_str()) + } +} + +impl<'de, F: RichField> Deserialize<'de> for PoseidonBN128HashOut { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PoseidonBN128HashOutVisitor; + + impl<'a> Visitor<'a> for PoseidonBN128HashOutVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string with integer value within BN128 scalar field") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(v.to_string()) + } + } + + let deserialized_str = deserializer + .deserialize_str(PoseidonBN128HashOutVisitor) + .unwrap(); + let big_int = BigUint::parse_bytes(deserialized_str.as_bytes(), 10).unwrap(); + + let mut bytes = big_int.to_bytes_le(); + for _i in bytes.len()..32 { + bytes.push(0); + } + + let sized_bytes: [u8; 32] = bytes.try_into().unwrap(); + let fr_repr = FrRepr(sized_bytes); + let fr = Fr::from_repr(fr_repr).unwrap(); + + Ok(Self { + value: fr, + _phantom: PhantomData, + }) + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct PoseidonBN128Hash; +impl Hasher for PoseidonBN128Hash { + const HASH_SIZE: usize = 32; // Hash output is 4 limbs of u64 + type Hash = PoseidonBN128HashOut; + type Permutation = PoseidonPermutation; + + fn hash_no_pad(input: &[F]) -> Self::Hash { + let mut state = [::ZERO; 4]; + + state[0] = ::ZERO; + for rate_chunk in input.chunks(RATE * 3) { + for (j, bn128_chunk) in rate_chunk.chunks(3).enumerate() { + let mut bytes = bn128_chunk[0].to_canonical_u64().to_le_bytes().to_vec(); + + for gl_element in bn128_chunk.iter().skip(1) { + let chunk_bytes = gl_element.to_canonical_u64().to_le_bytes(); + bytes.extend_from_slice(&chunk_bytes); + } + + for _i in bytes.len()..32 { + bytes.push(0); + } + + let sized_bytes: [u8; 32] = bytes.try_into().unwrap(); + let fr_repr = FrRepr(sized_bytes); + state[j + 1] = Fr::from_repr(fr_repr).unwrap(); + } + permution(&mut state); + } + + PoseidonBN128HashOut { + value: state[0], + _phantom: PhantomData, + } + } + + fn hash_pad(input: &[F]) -> Self::Hash { + let mut padded_input = input.to_vec(); + padded_input.push(F::ONE); + while (padded_input.len() + 1) % (RATE * GOLDILOCKS_ELEMENTS) != 0 { + padded_input.push(F::ZERO); + } + padded_input.push(F::ONE); + Self::hash_no_pad(&padded_input) + } + + fn hash_or_noop(inputs: &[F]) -> Self::Hash { + if inputs.len() * 8 <= GOLDILOCKS_ELEMENTS * 8 { + let mut inputs_bytes = vec![0u8; 32]; + for i in 0..inputs.len() { + inputs_bytes[i * 8..(i + 1) * 8] + .copy_from_slice(&inputs[i].to_canonical_u64().to_le_bytes()); + } + Self::Hash::from_bytes(&inputs_bytes) + } else { + Self::hash_no_pad(inputs) + } + } + + fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash { + let mut state = [Fr::ZERO, Fr::ZERO, left.value, right.value]; + permution(&mut state); + + PoseidonBN128HashOut { + value: state[0], + _phantom: PhantomData, + } + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + + #[test] + fn test_byte_methods() { + type F = GoldilocksField; + + let fr = Fr::from_str_vartime( + "11575173631114898451293296430061690731976535592475236587664058405912382527658", + ) + .unwrap(); + let hash = PoseidonBN128HashOut:: { + value: fr, + _phantom: PhantomData, + }; + + let bytes = hash.to_bytes(); + + let hash_from_bytes = PoseidonBN128HashOut::::from_bytes(&bytes); + assert_eq!(hash, hash_from_bytes); + } + + #[test] + fn test_serialization() { + let fr = Fr::from_str_vartime( + "11575173631114898451293296430061690731976535592475236587664058405912382527658", + ) + .unwrap(); + let hash = PoseidonBN128HashOut:: { + value: fr, + _phantom: PhantomData, + }; + + let serialized = serde_json::to_string(&hash).unwrap(); + let deserialized: PoseidonBN128HashOut = + serde_json::from_str(&serialized).unwrap(); + assert_eq!(hash, deserialized); + } +} diff --git a/beacon-light-client/plonky2/circuits_executables/src/poseidon_constants.rs b/beacon-light-client/plonky2/circuits_executables/src/poseidon_constants.rs new file mode 100644 index 000000000..7b37b76c1 --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/src/poseidon_constants.rs @@ -0,0 +1,2087 @@ +use ff::{Field, PrimeField}; +use lazy_static::lazy_static; + +use crate::utils::Fr; + +lazy_static! { + pub static ref C_CONSTANTS: Vec = load_c_constants(); + pub static ref S_CONSTANTS: Vec = load_s_constants(); + pub static ref M_MATRIX: Vec> = load_m_matrix(); + pub static ref P_MATRIX: Vec> = load_p_matrix(); +} + +fn load_c_constants() -> Vec { + let mut c_constants = vec![Fr::ZERO; 88]; + + c_constants[0] = Fr::from_str_vartime( + "11633431549750490989983886834189948010834808234699737327785600195936805266405", + ) + .unwrap(); + c_constants[1] = Fr::from_str_vartime( + "17353750182810071758476407404624088842693631054828301270920107619055744005334", + ) + .unwrap(); + c_constants[2] = Fr::from_str_vartime( + "11575173631114898451293296430061690731976535592475236587664058405912382527658", + ) + .unwrap(); + c_constants[3] = Fr::from_str_vartime( + "9724643380371653925020965751082872123058642683375812487991079305063678725624", + ) + .unwrap(); + c_constants[4] = Fr::from_str_vartime( + "12239673881776349871068957838196514517245834187939809998544709168112271341816", + ) + .unwrap(); + c_constants[5] = Fr::from_str_vartime( + "8213756851595907076282161124887805623974269954849888814703174589291971114278", + ) + .unwrap(); + c_constants[6] = Fr::from_str_vartime( + "10700856158409047630150108954036764855084229282872224809993001752389888794123", + ) + .unwrap(); + c_constants[7] = Fr::from_str_vartime( + "4309412763160017434705250214903006191171337994199861518317363388963372067759", + ) + .unwrap(); + c_constants[8] = Fr::from_str_vartime( + "13621360205860636764861614843016050680668828136032459556937427803817198955108", + ) + .unwrap(); + c_constants[9] = Fr::from_str_vartime( + "18132744072298259781740650630118713682311962872833394850644922000343506947506", + ) + .unwrap(); + c_constants[10] = Fr::from_str_vartime( + "10497941627597965031241580959233976924443640728463059894693130666064841012508", + ) + .unwrap(); + c_constants[11] = Fr::from_str_vartime( + "6417221626367515719470057497947343409306030587855174225463612195298058047522", + ) + .unwrap(); + c_constants[12] = Fr::from_str_vartime( + "4674983908670004491400354631773389862914788156614497726528237310334040582090", + ) + .unwrap(); + c_constants[13] = Fr::from_str_vartime( + "873340198155297459771531732108476825755499970277106398541966195153210717293", + ) + .unwrap(); + c_constants[14] = Fr::from_str_vartime( + "9133482302270339304679323394649165596260136537041379860642176850815828132593", + ) + .unwrap(); + c_constants[15] = Fr::from_str_vartime( + "19667464340426349564507575767837635537801536066735594705258884488718315050710", + ) + .unwrap(); + c_constants[16] = Fr::from_str_vartime( + "331000697881161076911287227440410522823531125482651243929873545789686252480", + ) + .unwrap(); + c_constants[17] = Fr::from_str_vartime( + "2272743329483520819389104778389979623160875907321267447635586085241433137026", + ) + .unwrap(); + c_constants[18] = Fr::from_str_vartime( + "20056061746422267419826865443608176291944892343638717421077672390127627926748", + ) + .unwrap(); + c_constants[19] = Fr::from_str_vartime( + "21689171326367195475219251979604515804697103534428737460300868676042327355863", + ) + .unwrap(); + c_constants[20] = Fr::from_str_vartime( + "7810259695400914964411387917274296266504340291833964145271847716091273468172", + ) + .unwrap(); + c_constants[21] = Fr::from_str_vartime( + "14020998353215410538067420885522582505027736982810754116099481711825941220642", + ) + .unwrap(); + c_constants[22] = Fr::from_str_vartime( + "9245012796693900213810598954108273676196337302084957472786966340245263275743", + ) + .unwrap(); + c_constants[23] = Fr::from_str_vartime( + "8962981905074764319938168719738488892057352527537684271935935864821273084600", + ) + .unwrap(); + c_constants[24] = Fr::from_str_vartime( + "17332843516965697478516240137711403804881134130964557790940490781033584077729", + ) + .unwrap(); + c_constants[25] = Fr::from_str_vartime( + "2962481512633005781617177153208165597038681617596047875933934580338169170271", + ) + .unwrap(); + c_constants[26] = Fr::from_str_vartime( + "3545583524837641414415308887998349399894575957283448040799889114001300580510", + ) + .unwrap(); + c_constants[27] = Fr::from_str_vartime( + "9825748584719861837046057557518727684444343953070352817632834283853645430055", + ) + .unwrap(); + c_constants[28] = Fr::from_str_vartime( + "17858606226144476516342911398749600850253621768390773635294560290497927852949", + ) + .unwrap(); + c_constants[29] = Fr::from_str_vartime( + "19407543101519936976076786599565778993379293656069417288311522496519916759844", + ) + .unwrap(); + c_constants[30] = Fr::from_str_vartime( + "21548305854518815463471937514130615108218483277778620473090880308362072806993", + ) + .unwrap(); + c_constants[31] = Fr::from_str_vartime( + "5027201548230124209007202023859059041801516590630988556095211824751904956552", + ) + .unwrap(); + c_constants[32] = Fr::from_str_vartime( + "1278320788183053034261211126815207721315633476390581364649595040979423239088", + ) + .unwrap(); + c_constants[33] = Fr::from_str_vartime( + "21021340095589643000573495115924922630807303076545481383969066202975724043976", + ) + .unwrap(); + c_constants[34] = Fr::from_str_vartime( + "918385069628188207001966014851379853961258262104472252966637722307728618311", + ) + .unwrap(); + c_constants[35] = Fr::from_str_vartime( + "7965072539100037475925090906281896901763370093075915840665305317760262942154", + ) + .unwrap(); + c_constants[36] = Fr::from_str_vartime( + "7378267415483811789102866201206786220747449921553565182362543937740633252433", + ) + .unwrap(); + c_constants[37] = Fr::from_str_vartime( + "21420063039401631492872969377050715448026482027341082733718950945529081119315", + ) + .unwrap(); + c_constants[38] = Fr::from_str_vartime( + "6984186848935723943941543006673172228872682933412337752165652636767411415446", + ) + .unwrap(); + c_constants[39] = Fr::from_str_vartime( + "12107134736452640457370020100579770521541376434013671407419563526253119375027", + ) + .unwrap(); + c_constants[40] = Fr::from_str_vartime( + "8454625495310558663140928634608422027208548557279385097066005785045755903417", + ) + .unwrap(); + c_constants[41] = Fr::from_str_vartime( + "8017631723660250252193376543593224884977313136061388836952991492888330231080", + ) + .unwrap(); + c_constants[42] = Fr::from_str_vartime( + "19995498935394919030796805510514577077319475365066948284951310616396837691603", + ) + .unwrap(); + c_constants[43] = Fr::from_str_vartime( + "10247653874740427181312035102426523630476005333120089103526343619029364327967", + ) + .unwrap(); + c_constants[44] = Fr::from_str_vartime( + "13160967777591563201117493157286130579932067039961943416358165521611018318814", + ) + .unwrap(); + c_constants[45] = Fr::from_str_vartime( + "5676293694146750080963041160092533338992482128392885932218516813947476623756", + ) + .unwrap(); + c_constants[46] = Fr::from_str_vartime( + "11945330020489343984352429388118756789915736454422495317728221749575540363130", + ) + .unwrap(); + c_constants[47] = Fr::from_str_vartime( + "16575755931296600565681989782918578103656201270919325693721999523168590365097", + ) + .unwrap(); + c_constants[48] = Fr::from_str_vartime( + "6507448101913175376269537672277524478400652962306200709943614250998845221975", + ) + .unwrap(); + c_constants[49] = Fr::from_str_vartime( + "20000756050339437189232666465591830538666897533492662864197332257508545696504", + ) + .unwrap(); + c_constants[50] = Fr::from_str_vartime( + "2538139500492919467696560596150779916859394629326537877502980743087004819534", + ) + .unwrap(); + c_constants[51] = Fr::from_str_vartime( + "7871037999774788273525866585990542333245923983722339125599991222477852815605", + ) + .unwrap(); + c_constants[52] = Fr::from_str_vartime( + "8368558409504001796987467259514778517606739110778427183378433173780120985763", + ) + .unwrap(); + c_constants[53] = Fr::from_str_vartime( + "10459885623117973980697126416757555084518174957115744579590957904857119054380", + ) + .unwrap(); + c_constants[54] = Fr::from_str_vartime( + "3384626976854176329065296334831532874977246373363627584425356985964639685936", + ) + .unwrap(); + c_constants[55] = Fr::from_str_vartime( + "14737139139809423972873213065253246598075451131478157534053817909649707346105", + ) + .unwrap(); + c_constants[56] = Fr::from_str_vartime( + "5793030407008346395600962336988545239125310160053522248574303463872647020425", + ) + .unwrap(); + c_constants[57] = Fr::from_str_vartime( + "161797721038773165886882501305032811420344793568022002686671602943345085701", + ) + .unwrap(); + c_constants[58] = Fr::from_str_vartime( + "16804762399165090393770239542398927686244163302041099831597167085216405440289", + ) + .unwrap(); + c_constants[59] = Fr::from_str_vartime( + "15440431301017924367171251352865716677435047477418739126248587843926419339250", + ) + .unwrap(); + c_constants[60] = Fr::from_str_vartime( + "15570353803062363582500010627498291625214012654155408601153435169223922455380", + ) + .unwrap(); + c_constants[61] = Fr::from_str_vartime( + "15115601269705628455987152258857868396524812969878723314685224929600383566277", + ) + .unwrap(); + c_constants[62] = Fr::from_str_vartime( + "6356053248039389904799735666848118481514593163165587256076018940751965212118", + ) + .unwrap(); + c_constants[63] = Fr::from_str_vartime( + "16309790196305846370580640353745827882351273732480869449701807093685497609128", + ) + .unwrap(); + c_constants[64] = Fr::from_str_vartime( + "18447296906230039277288210321788736138216936478488032824595044533456671231353", + ) + .unwrap(); + c_constants[65] = Fr::from_str_vartime( + "6105351805879633605209308509080121925171118411225835503106175078539279138153", + ) + .unwrap(); + c_constants[66] = Fr::from_str_vartime( + "19852645406205681222287243787651048897744424465454177194550461625744671602479", + ) + .unwrap(); + c_constants[67] = Fr::from_str_vartime( + "9007786282651237028773725177593860474523832555275407287854317958939412791659", + ) + .unwrap(); + c_constants[68] = Fr::from_str_vartime( + "18947127426470143546676956069733014228119216644326548862881450999285087652129", + ) + .unwrap(); + c_constants[69] = Fr::from_str_vartime( + "4006307826238987763983990462011007258305618881936961734589789440938853470615", + ) + .unwrap(); + c_constants[70] = Fr::from_str_vartime( + "6924385845051163089352800210788743599810236082363643773698057309137019167115", + ) + .unwrap(); + c_constants[71] = Fr::from_str_vartime( + "2561599182344380405085465588284140808385687895597384476955417835636116225821", + ) + .unwrap(); + c_constants[72] = Fr::from_str_vartime( + "18225048309586676741223646736155757525087799474840323150729701492173705507839", + ) + .unwrap(); + c_constants[73] = Fr::from_str_vartime( + "16007480414415489869989133828107467718966566156219711380836971295459227141818", + ) + .unwrap(); + c_constants[74] = Fr::from_str_vartime( + "1248906006044888441798838825685606393060257012284188943868730340563960780866", + ) + .unwrap(); + c_constants[75] = Fr::from_str_vartime( + "20912864018050627133842158245163422113261374878008212512322853267715626252916", + ) + .unwrap(); + c_constants[76] = Fr::from_str_vartime( + "13216486202690474504584820948167785518004498504229717602814280132903612841969", + ) + .unwrap(); + c_constants[77] = Fr::from_str_vartime( + "17416264900059210810716133407170753459272974595675494034944092509584936747655", + ) + .unwrap(); + c_constants[78] = Fr::from_str_vartime( + "15395940772659312642272628762657023074462358708226101085466723152641135097674", + ) + .unwrap(); + c_constants[79] = Fr::from_str_vartime( + "4690442806047481777095177614992497363041188209965731514747362442612318535595", + ) + .unwrap(); + c_constants[80] = Fr::from_str_vartime( + "12980185426778583997022610696582563821013078583440402121868121411086576741088", + ) + .unwrap(); + c_constants[81] = Fr::from_str_vartime( + "19436953581443472871973830882428624449045305494959438365629984120779166561614", + ) + .unwrap(); + c_constants[82] = Fr::from_str_vartime( + "7021128259021787032633332177524933222338330182720924079777325144523649322812", + ) + .unwrap(); + c_constants[83] = Fr::from_str_vartime( + "18561291417991436986590120557027289864572049192245689357046574683519049533637", + ) + .unwrap(); + c_constants[84] = Fr::from_str_vartime( + "12019749240411640852887001467406069824508276240179427493437313074459156379732", + ) + .unwrap(); + c_constants[85] = Fr::from_str_vartime( + "19007581091212404202795325684108744075320879284650517772195719617120941682734", + ) + .unwrap(); + c_constants[86] = Fr::from_str_vartime( + "8172766643075822491744127151779052248074930479661223662192995838879026989201", + ) + .unwrap(); + c_constants[87] = Fr::from_str_vartime( + "1885998770792872998306340529689960371653339961062025442813774917754800650781", + ) + .unwrap(); + + c_constants +} + +fn load_s_constants() -> Vec { + let mut s_constants = vec![Fr::ZERO; 392]; + + s_constants[0] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[1] = Fr::from_str_vartime( + "20198106103550706280267600199190750325504745188750640438654177959939538483777", + ) + .unwrap(); + s_constants[2] = Fr::from_str_vartime( + "20760367756622597472566835313508896628444391801225538453375145392828630013190", + ) + .unwrap(); + s_constants[3] = Fr::from_str_vartime( + "4560321026325826558577463029506577497226940849420215249948019116691014248443", + ) + .unwrap(); + s_constants[4] = Fr::from_str_vartime( + "14542348742554217629977259301175635295381723358917389768274600005636270665372", + ) + .unwrap(); + s_constants[5] = Fr::from_str_vartime( + "15896375770890915929312334597144922470201903000282577832977222171710825960733", + ) + .unwrap(); + s_constants[6] = Fr::from_str_vartime( + "12252597347102015743878803847985560878912969150828000392862427919235870760323", + ) + .unwrap(); + s_constants[7] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[8] = Fr::from_str_vartime( + "7179342059755701265188463641990689102412444920238824560515276276968272417627", + ) + .unwrap(); + s_constants[9] = Fr::from_str_vartime( + "4291630597779640477035256747339007105528129889017831542003293220100844273045", + ) + .unwrap(); + s_constants[10] = Fr::from_str_vartime( + "7155591457893668398581213488670279080694237456746471479962759104308162960346", + ) + .unwrap(); + s_constants[11] = Fr::from_str_vartime( + "18018059843853960571576693455761079306078638316240126846230125992269221919628", + ) + .unwrap(); + s_constants[12] = Fr::from_str_vartime( + "17192953047291854075450899126062621814148699654417386994738494022353693631044", + ) + .unwrap(); + s_constants[13] = Fr::from_str_vartime( + "21569358698233938087179836388127293183598397710122666685148766859224500701833", + ) + .unwrap(); + s_constants[14] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[15] = Fr::from_str_vartime( + "767999929530270249383649002937499906068820748885293476546946323828660462871", + ) + .unwrap(); + s_constants[16] = Fr::from_str_vartime( + "5621566033978712522450054985133362876999740181849707666504220417128301048308", + ) + .unwrap(); + s_constants[17] = Fr::from_str_vartime( + "7047587043137472855909285569331719962122602952080655968507950635506526200417", + ) + .unwrap(); + s_constants[18] = Fr::from_str_vartime( + "4106788926932251085789923064963212794107963499320782851030491954062548275037", + ) + .unwrap(); + s_constants[19] = Fr::from_str_vartime( + "4545465201904739898734767265726940896371623586331600641370124254775978068067", + ) + .unwrap(); + s_constants[20] = Fr::from_str_vartime( + "10998902844068831181439895790460185435489188976722435541316954293463196661627", + ) + .unwrap(); + s_constants[21] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[22] = Fr::from_str_vartime( + "4376836298206152573581217002448306554373223213053980459591637689821900483336", + ) + .unwrap(); + s_constants[23] = Fr::from_str_vartime( + "5063873841797552329477290331693185729765297320248590815860571737190009344755", + ) + .unwrap(); + s_constants[24] = Fr::from_str_vartime( + "17220054068062949177158788546035218460663984286240089601095376499170326046885", + ) + .unwrap(); + s_constants[25] = Fr::from_str_vartime( + "6096091793679274146365056037005290512891839764898244154356695047489211507312", + ) + .unwrap(); + s_constants[26] = Fr::from_str_vartime( + "20208154436430351332345105187219062318903703844357504892008088901754085119783", + ) + .unwrap(); + s_constants[27] = Fr::from_str_vartime( + "20838511199557042422189066592494164230774524176144133560311285338373104325885", + ) + .unwrap(); + s_constants[28] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[29] = Fr::from_str_vartime( + "16227720862704770803579874423899491820268073980006154670796744520986650305964", + ) + .unwrap(); + s_constants[30] = Fr::from_str_vartime( + "3929921339874032224077598341189960169422821598221170533707987779964278253429", + ) + .unwrap(); + s_constants[31] = Fr::from_str_vartime( + "11676522033799786037262769984406232796495555956069794755879715792396951198318", + ) + .unwrap(); + s_constants[32] = Fr::from_str_vartime( + "7762519209385193303450585425818218327021377088446472105589371562364474259645", + ) + .unwrap(); + s_constants[33] = Fr::from_str_vartime( + "12228816136730871104506419752649367119045148103237539623130531869347941136043", + ) + .unwrap(); + s_constants[34] = Fr::from_str_vartime( + "5506740114091186508725306313701186842841118936086047703119202768266996591645", + ) + .unwrap(); + s_constants[35] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[36] = Fr::from_str_vartime( + "14813919600103919291484875851986720548476220511386386518354061356196294952105", + ) + .unwrap(); + s_constants[37] = Fr::from_str_vartime( + "19412665928425989269357649645392922518929142728556361947563991549129986237680", + ) + .unwrap(); + s_constants[38] = Fr::from_str_vartime( + "7745252322635388376641759428229975035032852732127464661605110457073217385072", + ) + .unwrap(); + s_constants[39] = Fr::from_str_vartime( + "12066184602104703003390387343585316865507822321930012054206126015745471356816", + ) + .unwrap(); + s_constants[40] = Fr::from_str_vartime( + "12620273762884289038844321186080149434615909817652953074992148689167338466281", + ) + .unwrap(); + s_constants[41] = Fr::from_str_vartime( + "11751773042154924867322926561716263630089863992083485679779160826117120630730", + ) + .unwrap(); + s_constants[42] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[43] = Fr::from_str_vartime( + "5787863126296931978637454491180421506307265052288386136386997720537089333357", + ) + .unwrap(); + s_constants[44] = Fr::from_str_vartime( + "4359270971608384879625804007684881130504862820820494966964908818477035866962", + ) + .unwrap(); + s_constants[45] = Fr::from_str_vartime( + "19213956561377299828591097862016633994148464565683346498602915228516385038972", + ) + .unwrap(); + s_constants[46] = Fr::from_str_vartime( + "10661554072824488477243358897537934080796136449622029441506710580786939692047", + ) + .unwrap(); + s_constants[47] = Fr::from_str_vartime( + "3607791084285905641943446462342879718459787316113396877697968017015606720718", + ) + .unwrap(); + s_constants[48] = Fr::from_str_vartime( + "21380267103954285713588504655257961830793460465329761560308765483331070823566", + ) + .unwrap(); + s_constants[49] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[50] = Fr::from_str_vartime( + "16335017324810170896233622441986531365208293021101073775522004006769586788569", + ) + .unwrap(); + s_constants[51] = Fr::from_str_vartime( + "8596452296160802102282257210844234154821630615259613589128211738647312221536", + ) + .unwrap(); + s_constants[52] = Fr::from_str_vartime( + "16301372420970040998092568156060757300799008373690279794165397142889066306513", + ) + .unwrap(); + s_constants[53] = Fr::from_str_vartime( + "11903327405072234929619206491534763321300297227799575111355508350177812704304", + ) + .unwrap(); + s_constants[54] = Fr::from_str_vartime( + "14821948344368180716550312221723948572649473361813001292505502225087596775887", + ) + .unwrap(); + s_constants[55] = Fr::from_str_vartime( + "5285692778454746827266147532131677990565304365953070750869571432820529495914", + ) + .unwrap(); + s_constants[56] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[57] = Fr::from_str_vartime( + "10012872528823706988605864950067342792516562023507005612462537243496467566252", + ) + .unwrap(); + s_constants[58] = Fr::from_str_vartime( + "21446538914812609684138720355481253195782233393805940184895189253411195275222", + ) + .unwrap(); + s_constants[59] = Fr::from_str_vartime( + "6967738095634646257690113616580876555259467406702097184326306034350680240041", + ) + .unwrap(); + s_constants[60] = Fr::from_str_vartime( + "4106908293164276270299730590107104728631886925545072356564726466348010934176", + ) + .unwrap(); + s_constants[61] = Fr::from_str_vartime( + "20927688665665429774877287472467937369033546230576320387423016374665584172634", + ) + .unwrap(); + s_constants[62] = Fr::from_str_vartime( + "9961827048684904093454156105462119035870307939873087416648411282423867596401", + ) + .unwrap(); + s_constants[63] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[64] = Fr::from_str_vartime( + "17625964999746898246984332334222740240090489215775011285534890391099108738991", + ) + .unwrap(); + s_constants[65] = Fr::from_str_vartime( + "6756403122817134101960922940971569987994537470470008333055210502063290961967", + ) + .unwrap(); + s_constants[66] = Fr::from_str_vartime( + "18209952059360034384023720860507712662310034604843833483955548867331649086618", + ) + .unwrap(); + s_constants[67] = Fr::from_str_vartime( + "8749953392298305294875888962184156769810429880914465959429873281709868501522", + ) + .unwrap(); + s_constants[68] = Fr::from_str_vartime( + "13903906876414887303860424108888965657645488675119946001291096608021846549241", + ) + .unwrap(); + s_constants[69] = Fr::from_str_vartime( + "8884215530056835002390372161442569149992192407996136723184495322116314590715", + ) + .unwrap(); + s_constants[70] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[71] = Fr::from_str_vartime( + "15368493359884894356742361670810465111377869951487306983186672135817808040059", + ) + .unwrap(); + s_constants[72] = Fr::from_str_vartime( + "16469301592941427332568429408115015498659452810956369922459344407975076653255", + ) + .unwrap(); + s_constants[73] = Fr::from_str_vartime( + "11953776125042477689669753843214783238996317490452913722906886945106240528752", + ) + .unwrap(); + s_constants[74] = Fr::from_str_vartime( + "4850027575321262255650746466350338325012270813222547784484958365303358175196", + ) + .unwrap(); + s_constants[75] = Fr::from_str_vartime( + "7167191208528939112939986630484202425436947674819310704476597678688297314160", + ) + .unwrap(); + s_constants[76] = Fr::from_str_vartime( + "14743993805036761996537001252852408745345655735519736268834200732992754437162", + ) + .unwrap(); + s_constants[77] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[78] = Fr::from_str_vartime( + "2193200656642352685118935602989839715339339245164998181015765438900681320425", + ) + .unwrap(); + s_constants[79] = Fr::from_str_vartime( + "4952431971730605970338760580694476897050208114543185599136664869372496356437", + ) + .unwrap(); + s_constants[80] = Fr::from_str_vartime( + "11345335340256434787038072013242069397625261572269911025596723263652849081076", + ) + .unwrap(); + s_constants[81] = Fr::from_str_vartime( + "19160419866562146325212161338497565927215049171520418417356683157217751672139", + ) + .unwrap(); + s_constants[82] = Fr::from_str_vartime( + "1906154907657701464044944280274832161539842850674948965456024456273947429115", + ) + .unwrap(); + s_constants[83] = Fr::from_str_vartime( + "16149082223365808325093364716798557120316343643236068373217398223890421952409", + ) + .unwrap(); + s_constants[84] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[85] = Fr::from_str_vartime( + "15043765472887378252850447725400426753906560153686308918666838116627815818554", + ) + .unwrap(); + s_constants[86] = Fr::from_str_vartime( + "12358170975909062301667468450513761096746838254885629802196667786117625700681", + ) + .unwrap(); + s_constants[87] = Fr::from_str_vartime( + "8976079215643004959353142348700280485976874920070539486194110584442767827768", + ) + .unwrap(); + s_constants[88] = Fr::from_str_vartime( + "16076674040958582640238476383964669465698501606063044308184974525408139269248", + ) + .unwrap(); + s_constants[89] = Fr::from_str_vartime( + "21647594485928619120181355125322770225837180985764869124047447620451714635371", + ) + .unwrap(); + s_constants[90] = Fr::from_str_vartime( + "21615565593822404396628787247811190031843657706885317097074400292994831686718", + ) + .unwrap(); + s_constants[91] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[92] = Fr::from_str_vartime( + "7285489402319904168831455790041657959272324796876172356990227907987038622155", + ) + .unwrap(); + s_constants[93] = Fr::from_str_vartime( + "8211470967679835460786450636871651606756811185450731546421075600179331665168", + ) + .unwrap(); + s_constants[94] = Fr::from_str_vartime( + "13120324752637151731834041425113532499273467426551390593296677993139082244188", + ) + .unwrap(); + s_constants[95] = Fr::from_str_vartime( + "6490061383110696131545774076292741528427005211177990719476969041145673265422", + ) + .unwrap(); + s_constants[96] = Fr::from_str_vartime( + "21671644951532628690769713999772810624944081525303128765668379478511313095702", + ) + .unwrap(); + s_constants[97] = Fr::from_str_vartime( + "17491948871201042934988514071862478178478080786921680019735540941776855947714", + ) + .unwrap(); + s_constants[98] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[99] = Fr::from_str_vartime( + "20875198681143976093301585336441600786893116178926266185909922467347281090330", + ) + .unwrap(); + s_constants[100] = Fr::from_str_vartime( + "3598136009866557326049002438338730052625336381410025235713569185700458778346", + ) + .unwrap(); + s_constants[101] = Fr::from_str_vartime( + "10257854050179821094359263633511835293496268374135163743255999829573090463793", + ) + .unwrap(); + s_constants[102] = Fr::from_str_vartime( + "8709186608235401140998284233255708538357614560705220346211132868280137795418", + ) + .unwrap(); + s_constants[103] = Fr::from_str_vartime( + "1259589977644258611864841556278758814462356863769029941139050408715640323060", + ) + .unwrap(); + s_constants[104] = Fr::from_str_vartime( + "4938787097541166466238757186525276546940957932147842294635573194784914432374", + ) + .unwrap(); + s_constants[105] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[106] = Fr::from_str_vartime( + "16717728254520320964463545682641729805489575123710417403982868570393738171908", + ) + .unwrap(); + s_constants[107] = Fr::from_str_vartime( + "9748879216547249587937312403683718221531596047715540576918379577191876140829", + ) + .unwrap(); + s_constants[108] = Fr::from_str_vartime( + "14944874834710321794079457580123143945012638912293883509561999360499542827539", + ) + .unwrap(); + s_constants[109] = Fr::from_str_vartime( + "18031584503513589779232867929321541667009512801047020067337884181460183159789", + ) + .unwrap(); + s_constants[110] = Fr::from_str_vartime( + "18414164542389736964053830253126595155017280572430646030445262089460883013232", + ) + .unwrap(); + s_constants[111] = Fr::from_str_vartime( + "2610402018952962996318994974332047870945223376199918653423836750745739531230", + ) + .unwrap(); + s_constants[112] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[113] = Fr::from_str_vartime( + "14009467204580838343058201541088761048498359505808795311724314678689480323211", + ) + .unwrap(); + s_constants[114] = Fr::from_str_vartime( + "21469776223413224601890303218554639233147301494161934252153679844173746974667", + ) + .unwrap(); + s_constants[115] = Fr::from_str_vartime( + "20647680658876691843280356403387803136370174824153696476894283712779784940833", + ) + .unwrap(); + s_constants[116] = Fr::from_str_vartime( + "7936850548423967572066326867280341951424312865893525326890769023431047320991", + ) + .unwrap(); + s_constants[117] = Fr::from_str_vartime( + "12722969395702657985023075505830677750286440950878333627607092139722193056708", + ) + .unwrap(); + s_constants[118] = Fr::from_str_vartime( + "11321152935530907374770739017822060871862163756958501641453518139130228537202", + ) + .unwrap(); + s_constants[119] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[120] = Fr::from_str_vartime( + "4094512680835093637766266255807831961532213986166871807693377951477711786051", + ) + .unwrap(); + s_constants[121] = Fr::from_str_vartime( + "18178389385096689665303225717280896610765865274508135228632006790574677752293", + ) + .unwrap(); + s_constants[122] = Fr::from_str_vartime( + "5003815887613767774717115773943502417144707145760897577207221259749678760892", + ) + .unwrap(); + s_constants[123] = Fr::from_str_vartime( + "11395014411676120154590806918236444089801092874462769558428488274754488682814", + ) + .unwrap(); + s_constants[124] = Fr::from_str_vartime( + "5043626533165824802355651303240938472427342475587368271803664178703751133184", + ) + .unwrap(); + s_constants[125] = Fr::from_str_vartime( + "20737661798231456194286427103806996346683878567029159134024210934417745289241", + ) + .unwrap(); + s_constants[126] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[127] = Fr::from_str_vartime( + "17885807983183478128547293344015669882824716934567927629992464147210758449961", + ) + .unwrap(); + s_constants[128] = Fr::from_str_vartime( + "4491530859611985170204284394599169523531547745924230349900720023555385570566", + ) + .unwrap(); + s_constants[129] = Fr::from_str_vartime( + "10590405810993997824904026910850308084431468206425947323744908163083992870845", + ) + .unwrap(); + s_constants[130] = Fr::from_str_vartime( + "14773696309507449928652967351151268377421083281901294044684766706170272145134", + ) + .unwrap(); + s_constants[131] = Fr::from_str_vartime( + "8012817909803347753036095373079065441540540870790316296905616948358031128489", + ) + .unwrap(); + s_constants[132] = Fr::from_str_vartime( + "15953294845538540694147122390548121234862217402440162841644474763770065752954", + ) + .unwrap(); + s_constants[133] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[134] = Fr::from_str_vartime( + "19330308615634016202275470394593918283291746889176278663184951919223544096896", + ) + .unwrap(); + s_constants[135] = Fr::from_str_vartime( + "15105179537685942573078046208371583063999793255578601214915887961329652398190", + ) + .unwrap(); + s_constants[136] = Fr::from_str_vartime( + "21709064542465141520669973714950919003335169451362947708974082912187480247791", + ) + .unwrap(); + s_constants[137] = Fr::from_str_vartime( + "460683998482756280912187509737431365362650506162063605585420395591986395093", + ) + .unwrap(); + s_constants[138] = Fr::from_str_vartime( + "8528936230636059063848306774318500923209521695610089597282351580188192653610", + ) + .unwrap(); + s_constants[139] = Fr::from_str_vartime( + "8893687738651874055934077641258880070065696892648906132887857010931807062812", + ) + .unwrap(); + s_constants[140] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[141] = Fr::from_str_vartime( + "9353521397201520020163669559110959732855095088196767785130221250369398534266", + ) + .unwrap(); + s_constants[142] = Fr::from_str_vartime( + "16613542657585137487151470980837461302153210762614545024991732555481490683814", + ) + .unwrap(); + s_constants[143] = Fr::from_str_vartime( + "2204502375207887950205548277458704596225935813112150868324282564135082293291", + ) + .unwrap(); + s_constants[144] = Fr::from_str_vartime( + "21254675318867619388160936117044327276221059873039333971338260709002243972836", + ) + .unwrap(); + s_constants[145] = Fr::from_str_vartime( + "16665573707712654499163134682677891418056405526644611110898762937899356502949", + ) + .unwrap(); + s_constants[146] = Fr::from_str_vartime( + "14267552583056171982269630733147008270458243455399509417719716681547925602990", + ) + .unwrap(); + s_constants[147] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[148] = Fr::from_str_vartime( + "16367942369253394098422648739247412041658904846897825274155468251740735622582", + ) + .unwrap(); + s_constants[149] = Fr::from_str_vartime( + "3109601755423487827090460933116495844768178403907542635843078881599579349417", + ) + .unwrap(); + s_constants[150] = Fr::from_str_vartime( + "13070881723095523414228674713428974685755915412664044005891151350338033029052", + ) + .unwrap(); + s_constants[151] = Fr::from_str_vartime( + "10259475086157775344414603146661739080464638100961174958014154428063344142346", + ) + .unwrap(); + s_constants[152] = Fr::from_str_vartime( + "14392919515768311705876085292469557682647137722466492884286386263408604670613", + ) + .unwrap(); + s_constants[153] = Fr::from_str_vartime( + "517834877649467900881483483632287988070398657044896986690867428743067995638", + ) + .unwrap(); + s_constants[154] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[155] = Fr::from_str_vartime( + "19776116368291396730046653100175352607868202157614878715709943043429632352654", + ) + .unwrap(); + s_constants[156] = Fr::from_str_vartime( + "5905125865653916927083238886025287246947738553282644091380121061742003257962", + ) + .unwrap(); + s_constants[157] = Fr::from_str_vartime( + "21028910015562338297173802587144293023870505593218986935232089708700866548848", + ) + .unwrap(); + s_constants[158] = Fr::from_str_vartime( + "13395944831564259671405922878791909538223635993323846275946092882663526594615", + ) + .unwrap(); + s_constants[159] = Fr::from_str_vartime( + "7995249236543262914206397633444491535498682241246319919218592002459454218505", + ) + .unwrap(); + s_constants[160] = Fr::from_str_vartime( + "20437702676708041916002540544749140197744801315911882559568865094949905456106", + ) + .unwrap(); + s_constants[161] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[162] = Fr::from_str_vartime( + "18122990859780045886774524690965061785055534365091244948379358057402402367696", + ) + .unwrap(); + s_constants[163] = Fr::from_str_vartime( + "7828598613589603783167146853068200035787559469554903457639957531866407371355", + ) + .unwrap(); + s_constants[164] = Fr::from_str_vartime( + "9332650099915404377420203417011695963084742503430897569811042552155208487972", + ) + .unwrap(); + s_constants[165] = Fr::from_str_vartime( + "10307617695590426797520999316292503894130404130453293663650538793774250723792", + ) + .unwrap(); + s_constants[166] = Fr::from_str_vartime( + "8835502107624355497501451075768318888448783969087607217992442118675676473235", + ) + .unwrap(); + s_constants[167] = Fr::from_str_vartime( + "19120067314041132936628146578356142975011085061134316893491148167766430272263", + ) + .unwrap(); + s_constants[168] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[169] = Fr::from_str_vartime( + "14131158550284047904306566770309132813679338145017696511713416041803712831947", + ) + .unwrap(); + s_constants[170] = Fr::from_str_vartime( + "18278505503803771900469477275449664281120609236542416293497549235136781566441", + ) + .unwrap(); + s_constants[171] = Fr::from_str_vartime( + "17153958308999151990078644296244213778962356073179462336659818419962234105847", + ) + .unwrap(); + s_constants[172] = Fr::from_str_vartime( + "16626758607046130451896378742113613353140534310327816824141377148817543345317", + ) + .unwrap(); + s_constants[173] = Fr::from_str_vartime( + "3253978674468876751813289588828587424582893573659628257653601068985274811195", + ) + .unwrap(); + s_constants[174] = Fr::from_str_vartime( + "15124684821333452470068683925631859150599113099371600515189799092190905862045", + ) + .unwrap(); + s_constants[175] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[176] = Fr::from_str_vartime( + "17554798861971373266763024346102515996719053781651720018946226608652696029966", + ) + .unwrap(); + s_constants[177] = Fr::from_str_vartime( + "4673377481212178482442054929782481181148885179378220577674849430151263814812", + ) + .unwrap(); + s_constants[178] = Fr::from_str_vartime( + "12802184117569856558550257245216015988375556783492060695287038701794605413493", + ) + .unwrap(); + s_constants[179] = Fr::from_str_vartime( + "9519514614359898302883682133832551410294990399516042521409471023087274168403", + ) + .unwrap(); + s_constants[180] = Fr::from_str_vartime( + "16836659443451056297630548550595506972721716824013972318987309735084892491057", + ) + .unwrap(); + s_constants[181] = Fr::from_str_vartime( + "7395214083924359580241425985340483333597901523044123868756997584036793198254", + ) + .unwrap(); + s_constants[182] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[183] = Fr::from_str_vartime( + "14399322858803900772257678181955451734179272552912056546775770413858440530384", + ) + .unwrap(); + s_constants[184] = Fr::from_str_vartime( + "1909978450171978853529623580362647076357052571231552147289256161279685882392", + ) + .unwrap(); + s_constants[185] = Fr::from_str_vartime( + "13281885756205124109513999931355079980393369422935519271174043924199138273390", + ) + .unwrap(); + s_constants[186] = Fr::from_str_vartime( + "164209740719129725777909013206421786172977937257506729867551471718043494039", + ) + .unwrap(); + s_constants[187] = Fr::from_str_vartime( + "16705691420580567376788433299746618119784690539139871305988345805972046012457", + ) + .unwrap(); + s_constants[188] = Fr::from_str_vartime( + "5826800399196629549123275187565614318381497389323145097682684583838285855788", + ) + .unwrap(); + s_constants[189] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[190] = Fr::from_str_vartime( + "8745700306539329869259196731866071878870577472742983713396535761464344570296", + ) + .unwrap(); + s_constants[191] = Fr::from_str_vartime( + "508475125028636547085017721909144447367158867634347790363605834249994548305", + ) + .unwrap(); + s_constants[192] = Fr::from_str_vartime( + "13308065070657129846765808536411368840800238227915085241160671109842614736069", + ) + .unwrap(); + s_constants[193] = Fr::from_str_vartime( + "10019712566526881174916627302365233202635409302600998712624311257405295555967", + ) + .unwrap(); + s_constants[194] = Fr::from_str_vartime( + "14948048658262145603596652021141019702423717894287496732011428902097682702613", + ) + .unwrap(); + s_constants[195] = Fr::from_str_vartime( + "15039086326216274046991605161343057988750627388067276180888219462568845064229", + ) + .unwrap(); + s_constants[196] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[197] = Fr::from_str_vartime( + "21096491705236217573638753819195066035854753372393176304524423503032224425998", + ) + .unwrap(); + s_constants[198] = Fr::from_str_vartime( + "20540136431631199250453995588480387143164544354370046506703506396812372935282", + ) + .unwrap(); + s_constants[199] = Fr::from_str_vartime( + "21186849459525281586750729801174049327027230971997759985511944731378352524720", + ) + .unwrap(); + s_constants[200] = Fr::from_str_vartime( + "6848121885117228161216817594905430814981258429233967407187604355908721328558", + ) + .unwrap(); + s_constants[201] = Fr::from_str_vartime( + "13037575047232910005715065472416622419305037510557664085418549453156900385456", + ) + .unwrap(); + s_constants[202] = Fr::from_str_vartime( + "17833625863119365031315208055152981164942897924758710427636399886811449556740", + ) + .unwrap(); + s_constants[203] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[204] = Fr::from_str_vartime( + "647623368236351122220409431799139859876095524525221664162752495435482065515", + ) + .unwrap(); + s_constants[205] = Fr::from_str_vartime( + "12974365649211231492520765559798270821958589291536737829547558404742935791527", + ) + .unwrap(); + s_constants[206] = Fr::from_str_vartime( + "15547534600512764170410743968922508315745715132682752278457116429781298799438", + ) + .unwrap(); + s_constants[207] = Fr::from_str_vartime( + "20584726236425418677723102941610547182735385166462720350906478152233407640408", + ) + .unwrap(); + s_constants[208] = Fr::from_str_vartime( + "14300225354615797067692544691787701642123233971394030871903066287215191118747", + ) + .unwrap(); + s_constants[209] = Fr::from_str_vartime( + "16295678001265781880580526410222599033811623386008655132827551618100838695276", + ) + .unwrap(); + s_constants[210] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[211] = Fr::from_str_vartime( + "20381043379079252254800770843787089884660790822955671220847236480297529336205", + ) + .unwrap(); + s_constants[212] = Fr::from_str_vartime( + "9108894275082870067933192903079574663897324502580109505768620424181024287163", + ) + .unwrap(); + s_constants[213] = Fr::from_str_vartime( + "5680820607864330888516377287072858105818590744368374152569440046457757684320", + ) + .unwrap(); + s_constants[214] = Fr::from_str_vartime( + "11053473350105919249170169199500210854013326531260083017794490958609880379672", + ) + .unwrap(); + s_constants[215] = Fr::from_str_vartime( + "12769075511883530146865321202033588214490414269703513464106497906236932124198", + ) + .unwrap(); + s_constants[216] = Fr::from_str_vartime( + "18759973693942567196361351599844723429910867650807109887961315229008339652628", + ) + .unwrap(); + s_constants[217] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[218] = Fr::from_str_vartime( + "16425700741812211675363235647687005029399366301071410733155116166884856887679", + ) + .unwrap(); + s_constants[219] = Fr::from_str_vartime( + "19869702808216677847758761872487163621387473209265033304520824036210441934818", + ) + .unwrap(); + s_constants[220] = Fr::from_str_vartime( + "14073988039965881048079447010526118226047246598254103612590470558684258186244", + ) + .unwrap(); + s_constants[221] = Fr::from_str_vartime( + "886202035735213563046862324816018035210995137716997070920200120700003967134", + ) + .unwrap(); + s_constants[222] = Fr::from_str_vartime( + "12027565694895224474791802234109034039772984880014776210441706322417559146489", + ) + .unwrap(); + s_constants[223] = Fr::from_str_vartime( + "11972498202326440163586176809543524758264680802074662372615568024949824595702", + ) + .unwrap(); + s_constants[224] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[225] = Fr::from_str_vartime( + "1348630117144789003644452314839072329750068133934739562703659359268389747985", + ) + .unwrap(); + s_constants[226] = Fr::from_str_vartime( + "1396107425439796908939750972938223221605778648225762567016308314789520339962", + ) + .unwrap(); + s_constants[227] = Fr::from_str_vartime( + "6173001858003427802042546706782122098835769939275305980271183297728965316942", + ) + .unwrap(); + s_constants[228] = Fr::from_str_vartime( + "16943717877001499284920880255048707490719574351604140426529143119277836403129", + ) + .unwrap(); + s_constants[229] = Fr::from_str_vartime( + "14254637476176032842487152448677962929592936990526843481247886860454775633326", + ) + .unwrap(); + s_constants[230] = Fr::from_str_vartime( + "20112551263640702643495202387764478482489841288043250651308711396213637765954", + ) + .unwrap(); + s_constants[231] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[232] = Fr::from_str_vartime( + "14580210729080456657697439135745213807214996922877431278225104041221322283144", + ) + .unwrap(); + s_constants[233] = Fr::from_str_vartime( + "17944065522218783686971981171223808953317623885825040885897493399216933397441", + ) + .unwrap(); + s_constants[234] = Fr::from_str_vartime( + "21672476111949246523929453701335722206799241314728447223788259504904156987147", + ) + .unwrap(); + s_constants[235] = Fr::from_str_vartime( + "16427849329831493218262402566840933522542577642557896988530799384419530862522", + ) + .unwrap(); + s_constants[236] = Fr::from_str_vartime( + "10752733058291453323011452726707429118120906743416692984681703374550581513882", + ) + .unwrap(); + s_constants[237] = Fr::from_str_vartime( + "1120153114481280927826334009363750761062539786064908406397864613779304433308", + ) + .unwrap(); + s_constants[238] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[239] = Fr::from_str_vartime( + "6657045611436002337943867733574742655960423094099745811786819937865742754593", + ) + .unwrap(); + s_constants[240] = Fr::from_str_vartime( + "4548688566209049346950516871294343401334051071109430534058854346117866744739", + ) + .unwrap(); + s_constants[241] = Fr::from_str_vartime( + "12004873649650240122663793814044887628092046288070805572287428956807094282568", + ) + .unwrap(); + s_constants[242] = Fr::from_str_vartime( + "10376720357183386406622952185756280165877227546938927619561389051210153106592", + ) + .unwrap(); + s_constants[243] = Fr::from_str_vartime( + "17932525558731721856340352992169746291760530992792261472641282908501604446811", + ) + .unwrap(); + s_constants[244] = Fr::from_str_vartime( + "17590757077464321402178239743669088074723578712251925458853962272816312109152", + ) + .unwrap(); + s_constants[245] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[246] = Fr::from_str_vartime( + "3209081991282167870383195969354868449640899668458993044016055038297543518657", + ) + .unwrap(); + s_constants[247] = Fr::from_str_vartime( + "5864786650128394026837230220022650012182783025931675255391916679281913080366", + ) + .unwrap(); + s_constants[248] = Fr::from_str_vartime( + "12439377586247860055183624555830288546667346442629775929405362799390541279515", + ) + .unwrap(); + s_constants[249] = Fr::from_str_vartime( + "20249169533694211243074917072193953326307543430194777911574824077740409867889", + ) + .unwrap(); + s_constants[250] = Fr::from_str_vartime( + "11955292991025510476129504480910338468553857092582960824101774602100105865508", + ) + .unwrap(); + s_constants[251] = Fr::from_str_vartime( + "21233753658809258463246874948160331522087646774375604829374717282611108497353", + ) + .unwrap(); + s_constants[252] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[253] = Fr::from_str_vartime( + "5299619631018824922731916064083443097684549422797706633258895684420281864108", + ) + .unwrap(); + s_constants[254] = Fr::from_str_vartime( + "16213823392220550809755333072267867447553466481133861809088541225502993792933", + ) + .unwrap(); + s_constants[255] = Fr::from_str_vartime( + "21774021022385158712853171484065240472428767308361650780051834129571232443113", + ) + .unwrap(); + s_constants[256] = Fr::from_str_vartime( + "19519712983460247626783700627305949599146930344376818640048505866722051236075", + ) + .unwrap(); + s_constants[257] = Fr::from_str_vartime( + "19201631020677948940033345574241839698570728570677190746232685184366085684755", + ) + .unwrap(); + s_constants[258] = Fr::from_str_vartime( + "16950719963293537936274035069294977251884656006132028465274842882566872316866", + ) + .unwrap(); + s_constants[259] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[260] = Fr::from_str_vartime( + "19155409025424437690664522806909434551970754598652921692474864449826455337216", + ) + .unwrap(); + s_constants[261] = Fr::from_str_vartime( + "7680332789706498740282955823359712103361665361365018131178757219206780037124", + ) + .unwrap(); + s_constants[262] = Fr::from_str_vartime( + "21076561076080209150759527181245666654056099483239360146471339739637030537201", + ) + .unwrap(); + s_constants[263] = Fr::from_str_vartime( + "497501917138640900716963445320097032971939272734057482481699619406679852072", + ) + .unwrap(); + s_constants[264] = Fr::from_str_vartime( + "219804352410528064548663406794875692377819157777555527292379890517994310898", + ) + .unwrap(); + s_constants[265] = Fr::from_str_vartime( + "20650062109272119754567889432541551183228545711882667368558930819623066285550", + ) + .unwrap(); + s_constants[266] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[267] = Fr::from_str_vartime( + "11946781549111733342374437686417901919881339755720725189559112628795817706603", + ) + .unwrap(); + s_constants[268] = Fr::from_str_vartime( + "2484460820642436269798549252737235980435448156526237726927772714161779556117", + ) + .unwrap(); + s_constants[269] = Fr::from_str_vartime( + "9131896045016416748829978568219748930005109068654516264093181558753767987250", + ) + .unwrap(); + s_constants[270] = Fr::from_str_vartime( + "17539690836656056361902215257263592451628414553660709391600001441653830206065", + ) + .unwrap(); + s_constants[271] = Fr::from_str_vartime( + "18680327085533119384849399232368527875194911756927197995064579410845089235626", + ) + .unwrap(); + s_constants[272] = Fr::from_str_vartime( + "3733704884118300721043768874060062456481930803626613247865795986430463043840", + ) + .unwrap(); + s_constants[273] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[274] = Fr::from_str_vartime( + "10869324612517034722196547288387911568763853980957190569709459262556333259802", + ) + .unwrap(); + s_constants[275] = Fr::from_str_vartime( + "13541129633400691168270375425224652251629428845905913714872674429516061703834", + ) + .unwrap(); + s_constants[276] = Fr::from_str_vartime( + "19566585716231282658157065399746041623123586124594568018338142400023247847175", + ) + .unwrap(); + s_constants[277] = Fr::from_str_vartime( + "11129427786234676461186088751699468257665219195861018218716326589482169235738", + ) + .unwrap(); + s_constants[278] = Fr::from_str_vartime( + "12587809912397784737743829505557561200040529463438352967575388905004140998345", + ) + .unwrap(); + s_constants[279] = Fr::from_str_vartime( + "19808473521007223175388701036440740142351657866781216113100022591252318502799", + ) + .unwrap(); + s_constants[280] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[281] = Fr::from_str_vartime( + "5873853271511157388891218086625116841039294307138994311967890057520246823262", + ) + .unwrap(); + s_constants[282] = Fr::from_str_vartime( + "13003486326245606952057355171036271201855738149044785151305974666902939676968", + ) + .unwrap(); + s_constants[283] = Fr::from_str_vartime( + "317822617317373237216981618014479686465697065761329030109475447686164721451", + ) + .unwrap(); + s_constants[284] = Fr::from_str_vartime( + "10813741057848680550002438472132336318708520104631920434881565279665858338767", + ) + .unwrap(); + s_constants[285] = Fr::from_str_vartime( + "1407947600055243217568670010193019554033099296398850283939346444151815545565", + ) + .unwrap(); + s_constants[286] = Fr::from_str_vartime( + "10748165363652029592490593406190797442361550791106744394554436667603982640562", + ) + .unwrap(); + s_constants[287] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[288] = Fr::from_str_vartime( + "3799831132390157900444549796610450353874750090914089848349537541361771448668", + ) + .unwrap(); + s_constants[289] = Fr::from_str_vartime( + "1236474870532132985977600728058617189131963342170879994970972386547660462416", + ) + .unwrap(); + s_constants[290] = Fr::from_str_vartime( + "12129114991304316197801712028291571747667685822200300686411158807713612068935", + ) + .unwrap(); + s_constants[291] = Fr::from_str_vartime( + "12452782504819389866332384374641397209636135503933026692197899235338769218420", + ) + .unwrap(); + s_constants[292] = Fr::from_str_vartime( + "17177375615846222421363183777625422826542711334348976790999247784204226247153", + ) + .unwrap(); + s_constants[293] = Fr::from_str_vartime( + "14724993254182752446999797852163908134432351958415665363281656992462126774682", + ) + .unwrap(); + s_constants[294] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[295] = Fr::from_str_vartime( + "5334385037080506459192079464304402035717161708938461991741391759156701759962", + ) + .unwrap(); + s_constants[296] = Fr::from_str_vartime( + "5839603057106324284245920895643629522252067410986057849259994788753287208289", + ) + .unwrap(); + s_constants[297] = Fr::from_str_vartime( + "14326608902192980988016963288619186073396385273801977982209424374836032185437", + ) + .unwrap(); + s_constants[298] = Fr::from_str_vartime( + "3833013442414862082598619907743002206819313202476167703686360031484342083849", + ) + .unwrap(); + s_constants[299] = Fr::from_str_vartime( + "5782627886836397242604493658841762433123584410931373681442076300374639175204", + ) + .unwrap(); + s_constants[300] = Fr::from_str_vartime( + "19713051315944380534324352563108780835417447391745041989823306798607010582122", + ) + .unwrap(); + s_constants[301] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[302] = Fr::from_str_vartime( + "18432899792379962331910523191119990280606783016109716227581834102469679493864", + ) + .unwrap(); + s_constants[303] = Fr::from_str_vartime( + "10114179315138932736747722408239325460537042542506605453447755151962569740761", + ) + .unwrap(); + s_constants[304] = Fr::from_str_vartime( + "5821210875734924302116104693653963583724566141160222647210211530317113743846", + ) + .unwrap(); + s_constants[305] = Fr::from_str_vartime( + "7272434816631750120284299385293876240257916908609412315349255596053274406936", + ) + .unwrap(); + s_constants[306] = Fr::from_str_vartime( + "4212296281436173015983236952207520516627835095278776445938770899997037368424", + ) + .unwrap(); + s_constants[307] = Fr::from_str_vartime( + "6955140567497387214231321978484207887660637811874868846921238176118501620416", + ) + .unwrap(); + s_constants[308] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[309] = Fr::from_str_vartime( + "16897957031536287824842741409118604269531477953952068130977839056875990315078", + ) + .unwrap(); + s_constants[310] = Fr::from_str_vartime( + "13928891481908488754724298520914059676632551457225054691072093686516662594704", + ) + .unwrap(); + s_constants[311] = Fr::from_str_vartime( + "18609207589312797911981956932131451830029990404869237009695385065926468947990", + ) + .unwrap(); + s_constants[312] = Fr::from_str_vartime( + "5536380863513150280191401661180648941427892275212253324640352848339521760494", + ) + .unwrap(); + s_constants[313] = Fr::from_str_vartime( + "5599225957062546984064803248700291456577900100660883438352062938121375670876", + ) + .unwrap(); + s_constants[314] = Fr::from_str_vartime( + "12727467597196655197125834858597394259624613129696376281662301390743901689826", + ) + .unwrap(); + s_constants[315] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[316] = Fr::from_str_vartime( + "19163832296523160821274196616772872907137958231822436470531902352232904941115", + ) + .unwrap(); + s_constants[317] = Fr::from_str_vartime( + "10312950311908120735753698174433012744274520178660214256070764297181492311529", + ) + .unwrap(); + s_constants[318] = Fr::from_str_vartime( + "20378282857854630279466471430783739929226973027333858163427244408490964366943", + ) + .unwrap(); + s_constants[319] = Fr::from_str_vartime( + "10377180064239448654317729091272064413356995963412409612959212677629982453181", + ) + .unwrap(); + s_constants[320] = Fr::from_str_vartime( + "2933414924716564156600257176308187931324021696634706744075039747567264729208", + ) + .unwrap(); + s_constants[321] = Fr::from_str_vartime( + "8493086687568016258498608482327521077256426060613869678446606139457160557731", + ) + .unwrap(); + s_constants[322] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[323] = Fr::from_str_vartime( + "19381450024835411599145851239904096365633900646004460102189421850759351066697", + ) + .unwrap(); + s_constants[324] = Fr::from_str_vartime( + "11953019744947469552190875928518181787128546459454153390773097887154577772396", + ) + .unwrap(); + s_constants[325] = Fr::from_str_vartime( + "13376491371023193271031127665379748375688991534278974638471913598784726444357", + ) + .unwrap(); + s_constants[326] = Fr::from_str_vartime( + "7542871725069391080270213343389444722683777408103033554143042828340526643887", + ) + .unwrap(); + s_constants[327] = Fr::from_str_vartime( + "9502363618190826927264503377951186073033660324604374823531489866751694300021", + ) + .unwrap(); + s_constants[328] = Fr::from_str_vartime( + "8942475100033900568271185100922618012810524607209352225513012701802010622336", + ) + .unwrap(); + s_constants[329] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[330] = Fr::from_str_vartime( + "21672484879307704998081070986668301291593477229230485880081317733634466423656", + ) + .unwrap(); + s_constants[331] = Fr::from_str_vartime( + "12560411374852110641761658167591216057124945743772728716943960683160724056822", + ) + .unwrap(); + s_constants[332] = Fr::from_str_vartime( + "3722997355103511782752507300407310792223403249171458092438045493962181025019", + ) + .unwrap(); + s_constants[333] = Fr::from_str_vartime( + "14433522510308019912373989177241241296955315520711007204668297246004835289367", + ) + .unwrap(); + s_constants[334] = Fr::from_str_vartime( + "21074332145955362315628041254977693445345960799533333435986322886475303250112", + ) + .unwrap(); + s_constants[335] = Fr::from_str_vartime( + "11688037814420019994761430124416432916208455640936309232737398596294520128684", + ) + .unwrap(); + s_constants[336] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[337] = Fr::from_str_vartime( + "8413591227751150541157599965184931267423827079669402000298235589329872211968", + ) + .unwrap(); + s_constants[338] = Fr::from_str_vartime( + "17650123658569960265162949890832225475263279247059954604797491790529432356321", + ) + .unwrap(); + s_constants[339] = Fr::from_str_vartime( + "7032368326020336746840339437615845824739080336621780283569419873917360702928", + ) + .unwrap(); + s_constants[340] = Fr::from_str_vartime( + "7385147306527643945794759599270778258162448657029306136967713046400437047254", + ) + .unwrap(); + s_constants[341] = Fr::from_str_vartime( + "9164511581583407790134635624183479582650863721435788581639986518157210097971", + ) + .unwrap(); + s_constants[342] = Fr::from_str_vartime( + "21232697956642675538653913718380508229639927919821094050264990131998515480363", + ) + .unwrap(); + s_constants[343] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[344] = Fr::from_str_vartime( + "18766563503966172098056598342132389632908065386663557822565991028183540018003", + ) + .unwrap(); + s_constants[345] = Fr::from_str_vartime( + "19588227650050881742478712753831458567447756852853785637599026881217455808917", + ) + .unwrap(); + s_constants[346] = Fr::from_str_vartime( + "1397562335684000327360763239099474090628194083907387149001776134346855210172", + ) + .unwrap(); + s_constants[347] = Fr::from_str_vartime( + "10198846647447159506242448434572704392281982267842998844531477628631237977793", + ) + .unwrap(); + s_constants[348] = Fr::from_str_vartime( + "4082126476185956308289516001173247963427942564076732012191115788827109604670", + ) + .unwrap(); + s_constants[349] = Fr::from_str_vartime( + "1259882007354573001457197686554861546488356012943826286439775962762529569759", + ) + .unwrap(); + s_constants[350] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[351] = Fr::from_str_vartime( + "7716815769035341534093079824074304698185682494514188549310576878173077130022", + ) + .unwrap(); + s_constants[352] = Fr::from_str_vartime( + "2044076383384167496824768664485547753134864604656664348421025061131743608977", + ) + .unwrap(); + s_constants[353] = Fr::from_str_vartime( + "7774223140652128981941948651155326068745393941932597512012824767919719875428", + ) + .unwrap(); + s_constants[354] = Fr::from_str_vartime( + "6679985805196174386295848216686508579276442390463151307353623646770660788584", + ) + .unwrap(); + s_constants[355] = Fr::from_str_vartime( + "6774793209384233535964197412993868564894958211307656732015443437790617825766", + ) + .unwrap(); + s_constants[356] = Fr::from_str_vartime( + "17867078843395024616403441485600115396944676013587205981831608189485186004136", + ) + .unwrap(); + s_constants[357] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[358] = Fr::from_str_vartime( + "6918083713687670289412597323877415882006094844653186686554461196053948517650", + ) + .unwrap(); + s_constants[359] = Fr::from_str_vartime( + "14794244995142016109988120927552904368673513765173156992855465350554201454520", + ) + .unwrap(); + s_constants[360] = Fr::from_str_vartime( + "9469895491505210921132335959822444547950761948532088884408658386318765611458", + ) + .unwrap(); + s_constants[361] = Fr::from_str_vartime( + "12410499443680346161671381257661336704947211959564338473797332912666796028788", + ) + .unwrap(); + s_constants[362] = Fr::from_str_vartime( + "7926578664199378339557308917160770386201454695092254922901982085502190339711", + ) + .unwrap(); + s_constants[363] = Fr::from_str_vartime( + "1074389802911575405482398726791994815320889352331411931514923735327800497648", + ) + .unwrap(); + s_constants[364] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[365] = Fr::from_str_vartime( + "12660721219055881159942064421460786460560697520809352389013840987393603997135", + ) + .unwrap(); + s_constants[366] = Fr::from_str_vartime( + "4257759001257681685309102971805195284424999843809187868418076529498991787195", + ) + .unwrap(); + s_constants[367] = Fr::from_str_vartime( + "8970798405382398224814171740357247330369162836256360293947332566119181156885", + ) + .unwrap(); + s_constants[368] = Fr::from_str_vartime( + "17958544420119383745643163073564878224834088412686597346123856987725643531187", + ) + .unwrap(); + s_constants[369] = Fr::from_str_vartime( + "17738189036503307406862818984242172707709553320980438963253190315183389070671", + ) + .unwrap(); + s_constants[370] = Fr::from_str_vartime( + "14287766641051399433873731520879849723607926081596701974021064214044740995654", + ) + .unwrap(); + s_constants[371] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[372] = Fr::from_str_vartime( + "21558827418411379216994978187086694912014548431326761389965315489378942066021", + ) + .unwrap(); + s_constants[373] = Fr::from_str_vartime( + "7136882485367499209618511242521887384194879969153189708025876500490677483273", + ) + .unwrap(); + s_constants[374] = Fr::from_str_vartime( + "17220467566610801825959292161481147144970669500227722755203417787632930011521", + ) + .unwrap(); + s_constants[375] = Fr::from_str_vartime( + "15644351871844947578414272909094033689340289967910075614127700893758848906931", + ) + .unwrap(); + s_constants[376] = Fr::from_str_vartime( + "21741724266010931381264164854372691714176988715532516896804407315923532276434", + ) + .unwrap(); + s_constants[377] = Fr::from_str_vartime( + "2419785684404332928492315984637322970326738862445167379156610994774664059995", + ) + .unwrap(); + s_constants[378] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[379] = Fr::from_str_vartime( + "10339805366850086548361875185109456315271528882904249869004576409152632926693", + ) + .unwrap(); + s_constants[380] = Fr::from_str_vartime( + "19066576437237017989921605377017982206044010175904765960860923934443601514592", + ) + .unwrap(); + s_constants[381] = Fr::from_str_vartime( + "13822379132369217064164395859669265238386142106084498781870935216496751999075", + ) + .unwrap(); + s_constants[382] = Fr::from_str_vartime( + "21216485273531618687167053274106121432450196094331038082541464436433083018343", + ) + .unwrap(); + s_constants[383] = Fr::from_str_vartime( + "1540326880060266517508750499666125605454874001382251434794459985013783734049", + ) + .unwrap(); + s_constants[384] = Fr::from_str_vartime( + "10979571635040509905158742852019305039752888804051338348133671756054719250675", + ) + .unwrap(); + s_constants[385] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + s_constants[386] = Fr::from_str_vartime( + "17817950236968355275450565661453279500832679749582869473068209804712565393928", + ) + .unwrap(); + s_constants[387] = Fr::from_str_vartime( + "4057227004326267443894866444790295439173752231112985308059870347643133047427", + ) + .unwrap(); + s_constants[388] = Fr::from_str_vartime( + "9481547255077304194865834384522710415757401332737060279379100936057225542025", + ) + .unwrap(); + s_constants[389] = Fr::from_str_vartime( + "19204974983793400699898444372535256207646557857575315905278218870961389967884", + ) + .unwrap(); + s_constants[390] = Fr::from_str_vartime( + "14672613178263529785795301930884172260797190868602674472542654261498546023746", + ) + .unwrap(); + s_constants[391] = Fr::from_str_vartime( + "21407770160218607278833379114951608489910182969042472165261557405353704846967", + ) + .unwrap(); + + s_constants +} + +fn load_m_matrix() -> Vec> { + let mut m_matrix = vec![vec![Fr::ZERO; 4]; 4]; + + m_matrix[0][0] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + m_matrix[0][1] = Fr::from_str_vartime( + "19204974983793400699898444372535256207646557857575315905278218870961389967884", + ) + .unwrap(); + m_matrix[0][2] = Fr::from_str_vartime( + "14672613178263529785795301930884172260797190868602674472542654261498546023746", + ) + .unwrap(); + m_matrix[0][3] = Fr::from_str_vartime( + "21407770160218607278833379114951608489910182969042472165261557405353704846967", + ) + .unwrap(); + m_matrix[1][0] = Fr::from_str_vartime( + "17849615858846139011678879517964683507928512741474025695659909954675835121177", + ) + .unwrap(); + m_matrix[1][1] = Fr::from_str_vartime( + "3722304780857845144568029505892077496425786544014166938942516810831732569870", + ) + .unwrap(); + m_matrix[1][2] = Fr::from_str_vartime( + "20850178060552184587113773087797340350525370429749200838012809627359404457643", + ) + .unwrap(); + m_matrix[1][3] = Fr::from_str_vartime( + "16058955581309173858487265533260133430557379878452348481750737813742488209262", + ) + .unwrap(); + m_matrix[2][0] = Fr::from_str_vartime( + "1013663139540921998616312712475594638459213772728467613870351821911056489570", + ) + .unwrap(); + m_matrix[2][1] = Fr::from_str_vartime( + "11920634922168932145084219049241528148129057802067880076377897257847125830511", + ) + .unwrap(); + m_matrix[2][2] = Fr::from_str_vartime( + "7082289538076771741936674361200789891432311337766695368327626572220036527624", + ) + .unwrap(); + m_matrix[2][3] = Fr::from_str_vartime( + "593311177550138061601452020934455734040559402531605836278498327468203888086", + ) + .unwrap(); + m_matrix[3][0] = Fr::from_str_vartime( + "13211800058103802189838759488224684841774731021206389709687693993627918500545", + ) + .unwrap(); + m_matrix[3][1] = Fr::from_str_vartime( + "6085682566123812000257211683010755099394491689511511633947011263229442977967", + ) + .unwrap(); + m_matrix[3][2] = Fr::from_str_vartime( + "1787876543469562003404632310460227730887431311758627706450615128255538398187", + ) + .unwrap(); + m_matrix[3][3] = Fr::from_str_vartime( + "341662423637860635938968460722645910313598807845686354625820505885069260074", + ) + .unwrap(); + + m_matrix +} + +fn load_p_matrix() -> Vec> { + let mut p_matrix = vec![vec![Fr::ZERO; 4]; 4]; + + p_matrix[0][0] = Fr::from_str_vartime( + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + ) + .unwrap(); + p_matrix[0][1] = Fr::from_str_vartime( + "1219730950550419355108306775069417768387360853368230473071077119306046675572", + ) + .unwrap(); + p_matrix[0][2] = Fr::from_str_vartime( + "15510244717642334318966561950951002886323209693558586261457615423770062424603", + ) + .unwrap(); + p_matrix[0][3] = Fr::from_str_vartime( + "11219946567517274434615160614700308041943360069146893241486574665265822013129", + ) + .unwrap(); + p_matrix[1][0] = Fr::from_str_vartime( + "17849615858846139011678879517964683507928512741474025695659909954675835121177", + ) + .unwrap(); + p_matrix[1][1] = Fr::from_str_vartime( + "17895496371927328657913965415733510282704230821151428152183928968046205671575", + ) + .unwrap(); + p_matrix[1][2] = Fr::from_str_vartime( + "12435993608134323226059776526130103965669300982573338632451717852485169465950", + ) + .unwrap(); + p_matrix[1][3] = Fr::from_str_vartime( + "19939917978926080723093316474977996505935743392066675936804030819065420290084", + ) + .unwrap(); + p_matrix[2][0] = Fr::from_str_vartime( + "1013663139540921998616312712475594638459213772728467613870351821911056489570", + ) + .unwrap(); + p_matrix[2][1] = Fr::from_str_vartime( + "1028374094780216331619466080637054051304375033009771928288419347940821888279", + ) + .unwrap(); + p_matrix[2][2] = Fr::from_str_vartime( + "5643605551164490740833629634586387123466682387363311974272188018328439695366", + ) + .unwrap(); + p_matrix[2][3] = Fr::from_str_vartime( + "3961412593815053600853163531157674011892719679065160984658051723455387746952", + ) + .unwrap(); + p_matrix[3][0] = Fr::from_str_vartime( + "13211800058103802189838759488224684841774731021206389709687693993627918500545", + ) + .unwrap(); + p_matrix[3][1] = Fr::from_str_vartime( + "16436452107226347557423995353975118393704571960279031780622882419612847031696", + ) + .unwrap(); + p_matrix[3][2] = Fr::from_str_vartime( + "11841890240732656097844244837012648335708695431011214021127380678644769978309", + ) + .unwrap(); + p_matrix[3][3] = Fr::from_str_vartime( + "10936049757440664316304266313740303505981633272820388610540392640560764966725", + ) + .unwrap(); + + p_matrix +} diff --git a/beacon-light-client/plonky2/circuits_executables/src/provers.rs b/beacon-light-client/plonky2/circuits_executables/src/provers.rs index 2d43015fe..a15023bc8 100644 --- a/beacon-light-client/plonky2/circuits_executables/src/provers.rs +++ b/beacon-light-client/plonky2/circuits_executables/src/provers.rs @@ -1,7 +1,7 @@ use circuits::{ biguint::WitnessBigUint, build_balance_inner_level_circuit::BalanceInnerCircuitTargets, build_commitment_mapper_inner_level_circuit::CommitmentMapperInnerCircuitTargets, - build_final_circuit::FinalCircuitTargets, + build_final_circuit::FinalCircuitTargets, utils::SetBytesArray, validator_balance_circuit::ValidatorBalanceVerificationTargets, validator_hash_tree_root::ValidatorShaTargets, validator_hash_tree_root_poseidon::ValidatorPoseidonTargets, @@ -179,29 +179,36 @@ impl SetPWValues for ValidatorBalanceVerificationTargets impl SetPWValues for ValidatorShaTargets { fn set_pw_values(&self, pw: &mut PartialWitness, source: &ValidatorShaInput) { - set_boolean_pw_values(pw, &self.pubkey, &source.pubkey); + pw.set_bytes_array(&self.pubkey, &hex::decode(&source.pubkey).unwrap()); - set_boolean_pw_values( - pw, + pw.set_bytes_array( &self.withdrawal_credentials, - &source.withdrawal_credentials, + &hex::decode(&source.withdrawal_credentials).unwrap(), ); - set_boolean_pw_values(pw, &self.effective_balance, &source.effective_balance); + pw.set_bytes_array( + &self.effective_balance, + &hex::decode(&source.effective_balance).unwrap(), + ); - set_boolean_pw_values(pw, &self.slashed, &source.slashed); + pw.set_bytes_array(&self.slashed, &hex::decode(&source.slashed).unwrap()); - set_boolean_pw_values( - pw, + pw.set_bytes_array( &self.activation_eligibility_epoch, - &source.activation_eligibility_epoch, + &hex::decode(&source.activation_eligibility_epoch).unwrap(), ); - set_boolean_pw_values(pw, &self.activation_epoch, &source.activation_epoch); + pw.set_bytes_array( + &self.activation_epoch, + &hex::decode(&source.activation_epoch).unwrap(), + ); - set_boolean_pw_values(pw, &self.exit_epoch, &source.exit_epoch); + pw.set_bytes_array(&self.exit_epoch, &hex::decode(&source.exit_epoch).unwrap()); - set_boolean_pw_values(pw, &self.withdrawable_epoch, &source.withdrawable_epoch); + pw.set_bytes_array( + &self.withdrawable_epoch, + &hex::decode(&source.withdrawable_epoch).unwrap(), + ); } } diff --git a/beacon-light-client/plonky2/circuits_executables/src/utils.rs b/beacon-light-client/plonky2/circuits_executables/src/utils.rs new file mode 100644 index 000000000..535403f6a --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/src/utils.rs @@ -0,0 +1,7 @@ +use ff::PrimeField; + +#[derive(PrimeField)] +#[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"] +#[PrimeFieldGenerator = "7"] +#[PrimeFieldReprEndianness = "little"] +pub struct Fr([u64; 4]); diff --git a/beacon-light-client/plonky2/circuits_executables/src/validator.rs b/beacon-light-client/plonky2/circuits_executables/src/validator.rs index 7309dbda1..b63b50f2f 100644 --- a/beacon-light-client/plonky2/circuits_executables/src/validator.rs +++ b/beacon-light-client/plonky2/circuits_executables/src/validator.rs @@ -128,22 +128,14 @@ pub const VALIDATOR_REGISTRY_LIMIT: usize = 1099511627776; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct ValidatorShaInput { - #[serde(with = "bool_vec_as_int_vec")] - pub pubkey: Vec, - #[serde(with = "bool_vec_as_int_vec")] - pub withdrawal_credentials: Vec, - #[serde(with = "bool_vec_as_int_vec")] - pub effective_balance: Vec, - #[serde(with = "bool_vec_as_int_vec")] - pub slashed: Vec, - #[serde(with = "bool_vec_as_int_vec")] - pub activation_eligibility_epoch: Vec, - #[serde(with = "bool_vec_as_int_vec")] - pub activation_epoch: Vec, - #[serde(with = "bool_vec_as_int_vec")] - pub exit_epoch: Vec, - #[serde(with = "bool_vec_as_int_vec")] - pub withdrawable_epoch: Vec, + pub pubkey: String, + pub withdrawal_credentials: String, + pub effective_balance: String, + pub slashed: String, + pub activation_eligibility_epoch: String, + pub activation_epoch: String, + pub exit_epoch: String, + pub withdrawable_epoch: String, } #[cfg(test)] @@ -154,38 +146,38 @@ mod tests { #[test] fn test_serialize() { let validator = ValidatorShaInput { - pubkey: vec![true, false, true], - withdrawal_credentials: vec![false, false, true], - effective_balance: vec![true, true, false], - slashed: vec![false, true, false], - activation_eligibility_epoch: vec![true, false, true], - activation_epoch: vec![true, false, false], - exit_epoch: vec![false, true, true], - withdrawable_epoch: vec![true, true, true], + pubkey: "933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95".to_string(), + withdrawal_credentials: "0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50".to_string(), + effective_balance: "0040597307000000000000000000000000000000000000000000000000000000".to_string(), + slashed: "0000000000000000000000000000000000000000000000000000000000000000".to_string(), + activation_eligibility_epoch: "0000000000000000000000000000000000000000000000000000000000000000".to_string(), + activation_epoch: "0000000000000000000000000000000000000000000000000000000000000000".to_string(), + exit_epoch: "ffffffffffffffff000000000000000000000000000000000000000000000000".to_string(), + withdrawable_epoch: "ffffffffffffffff000000000000000000000000000000000000000000000000".to_string(), }; let serialized = serde_json::to_string(&validator).unwrap(); - assert_eq!(serialized, "{\"pubkey\":[1,0,1],\"withdrawalCredentials\":[0,0,1],\"effectiveBalance\":[1,1,0],\"slashed\":[0,1,0],\"activationEligibilityEpoch\":[1,0,1],\"activationEpoch\":[1,0,0],\"exitEpoch\":[0,1,1],\"withdrawableEpoch\":[1,1,1]}"); + assert_eq!(serialized, "{\"pubkey\":\"933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95\",\"withdrawalCredentials\":\"0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50\",\"effectiveBalance\":\"0040597307000000000000000000000000000000000000000000000000000000\",\"slashed\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"activationEligibilityEpoch\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"activationEpoch\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"exitEpoch\":\"ffffffffffffffff000000000000000000000000000000000000000000000000\",\"withdrawableEpoch\":\"ffffffffffffffff000000000000000000000000000000000000000000000000\"}"); } #[test] fn test_deserialize() { - let data = "{\"pubkey\":[1,0,1],\"withdrawalCredentials\":[0,0,1],\"effectiveBalance\":[1,1,0],\"slashed\":[0,1,0],\"activationEligibilityEpoch\":[1,0,1],\"activationEpoch\":[1,0,0],\"exitEpoch\":[0,1,1],\"withdrawableEpoch\":[1,1,1]}"; + let data = "{\"pubkey\":\"933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95\",\"withdrawalCredentials\":\"0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50\",\"effectiveBalance\":\"0040597307000000000000000000000000000000000000000000000000000000\",\"slashed\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"activationEligibilityEpoch\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"activationEpoch\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"exitEpoch\":\"ffffffffffffffff000000000000000000000000000000000000000000000000\",\"withdrawableEpoch\":\"ffffffffffffffff000000000000000000000000000000000000000000000000\"}"; let deserialized: ValidatorShaInput = serde_json::from_str(data).unwrap(); - assert_eq!(deserialized.pubkey, vec![true, false, true]); + assert_eq!(deserialized.pubkey, "933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95"); assert_eq!( deserialized.withdrawal_credentials, - vec![false, false, true] + "0100000000000000000000000d369bb49efa5100fd3b86a9f828c55da04d2d50" ); - assert_eq!(deserialized.effective_balance, vec![true, true, false]); - assert_eq!(deserialized.slashed, vec![false, true, false]); + assert_eq!(deserialized.effective_balance, "0040597307000000000000000000000000000000000000000000000000000000"); + assert_eq!(deserialized.slashed, "0000000000000000000000000000000000000000000000000000000000000000"); assert_eq!( deserialized.activation_eligibility_epoch, - vec![true, false, true] + "0000000000000000000000000000000000000000000000000000000000000000" ); - assert_eq!(deserialized.activation_epoch, vec![true, false, false]); - assert_eq!(deserialized.exit_epoch, vec![false, true, true]); - assert_eq!(deserialized.withdrawable_epoch, vec![true, true, true]); + assert_eq!(deserialized.activation_epoch, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_eq!(deserialized.exit_epoch, "ffffffffffffffff000000000000000000000000000000000000000000000000"); + assert_eq!(deserialized.withdrawable_epoch, "ffffffffffffffff000000000000000000000000000000000000000000000000"); } } diff --git a/beacon-light-client/plonky2/circuits_executables/verifier/circuit.go b/beacon-light-client/plonky2/circuits_executables/verifier/circuit.go new file mode 100644 index 000000000..98c318d4c --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/verifier/circuit.go @@ -0,0 +1,303 @@ +package main + +import ( + "fmt" + "math/big" + "os" + "time" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/kzg" + "github.com/consensys/gnark/backend/plonk" + plonk_bn254 "github.com/consensys/gnark/backend/plonk/bn254" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/gnark/logger" + "github.com/rs/zerolog/log" + "github.com/succinctlabs/gnark-plonky2-verifier/trusted_setup" + "github.com/succinctlabs/gnark-plonky2-verifier/types" + "github.com/succinctlabs/gnark-plonky2-verifier/variables" + "github.com/succinctlabs/gnark-plonky2-verifier/verifier" +) + +type Plonky2VerifierCircuit struct { + // Public inputs to the circuit + VerifierDigest frontend.Variable `gnark:"verifierDigest,public"` + + PublicInputHash frontend.Variable `gnark:"publicInputHash,public"` + + // Private inputs to the circuit + ProofWithPis variables.ProofWithPublicInputs + VerifierData variables.VerifierOnlyCircuitData + + // Circuit configuration + CommonCircuitData types.CommonCircuitData `gnark:"-"` +} + +func (c *Plonky2VerifierCircuit) Define(api frontend.API) error { + // initialize the verifier chip + verifierChip := verifier.NewVerifierChip(api, c.CommonCircuitData) + // verify the plonky2 proof + verifierChip.Verify(c.ProofWithPis.Proof, c.ProofWithPis.PublicInputs, c.VerifierData) + + // Public inputs should be 32 bytes + // big-endian representation of SHA256 hash that has been truncated to 253 bits + publicInputs := c.ProofWithPis.PublicInputs + + if len(publicInputs) != 32 { + return fmt.Errorf("expected 32 public inputs, got %d", len(publicInputs)) + } + + inputDigest := frontend.Variable(0) + + for i := 0; i < 32; i++ { + pubByte := publicInputs[31-i].Limb + inputDigest = api.Add(inputDigest, api.Mul(pubByte, frontend.Variable(new(big.Int).Lsh(big.NewInt(1), uint(8*i))))) + } + + api.AssertIsEqual(c.PublicInputHash, inputDigest) + + // We have to assert that the VerifierData we verified the proof with + // matches the VerifierDigest public input + api.AssertIsEqual(c.VerifierDigest, c.VerifierData.CircuitDigest) + + return nil +} + +func CompileVerifierCircuit(circuitPath string) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey, error) { + log := logger.Logger() + + verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData(circuitPath + "/verifier_only_circuit_data.json")) + + proofWithPis := variables.DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs(circuitPath + "/proof_with_public_inputs.json")) + + commonCircuitData := types.ReadCommonCircuitData(circuitPath + "/common_circuit_data.json") + + circuit := Plonky2VerifierCircuit{ + ProofWithPis: proofWithPis, + VerifierData: verifierOnlyCircuitData, + PublicInputHash: new(frontend.Variable), + VerifierDigest: new(frontend.Variable), + CommonCircuitData: commonCircuitData, + } + + r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &circuit) + + if err != nil { + return nil, nil, nil, err + } + + log.Info().Msg("Loading SRS setup") + start := time.Now() + + filePath := circuitPath + "/" + "srs_setup" + + if _, err := os.Stat(filePath); os.IsNotExist(err) { + trusted_setup.DownloadAndSaveAztecIgnitionSrs(174, filePath) + } + + srs := kzg.NewSRS(ecc.BN254) + + fSrs, _ := os.Open(filePath) + + _, err = srs.ReadFrom(fSrs) + + fSrs.Close() + + if err != nil { + return nil, nil, nil, err + } + + elapsed := time.Since(start) + log.Info().Msg("Successfully loaded SRS setup time: " + elapsed.String()) + + log.Info().Msg("Running circuit setup") + + start = time.Now() + + pk, vk, err := plonk.Setup(r1cs, srs) + + if err != nil { + return nil, nil, nil, err + } + + elapsed = time.Since(start) + + log.Info().Msg("Successfully ran circuit setup, time: " + elapsed.String()) + + return r1cs, pk, vk, nil +} + +func SaveVerifierCircuit(path string, r1cs constraint.ConstraintSystem, pk plonk.ProvingKey, vk plonk.VerifyingKey) { + log := logger.Logger() + + err := os.MkdirAll(path, 0777) + + if err != nil { + log.Error().Msg("Failed to create directory: " + err.Error()) + os.Exit(1) + } + + log.Info().Msg("Saving r1cs to " + path) + + r1csFile, err := os.Create(path + "/r1cs.bin") + r1cs.WriteTo(r1csFile) + r1csFile.Close() + + if err != nil { + log.Error().Msg("Failed to save r1cs: " + err.Error()) + os.Exit(1) + } + + log.Info().Msg("Successfully saved r1cs") + + log.Info().Msg("Saving pk and vk to " + path) + + pkFile, err := os.Create(path + "/pk.bin") + pk.WriteRawTo(pkFile) + pkFile.Close() + + if err != nil { + log.Error().Msg("Failed to save pk: " + err.Error()) + os.Exit(1) + } + + vkFile, err := os.Create(path + "/vk.bin") + vk.WriteRawTo(vkFile) + vkFile.Close() + + if err != nil { + log.Error().Msg("Failed to save vk: " + err.Error()) + os.Exit(1) + } + + log.Info().Msg("Successfully saved pk and vk") +} + +func LoadCircuitData(path string) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey, error) { + r1csFile, err := os.Open(path + "/r1cs.bin") + if err != nil { + return nil, nil, nil, err + } + r1cs := plonk.NewCS(ecc.BN254) + start := time.Now() + _, err = r1cs.ReadFrom(r1csFile) + if err != nil { + return nil, nil, nil, err + } + elapsed := time.Since(start) + r1csFile.Close() + log.Debug().Msg("Successfully loaded r1cs, time: " + elapsed.String()) + + pkFile, err := os.Open(path + "/pk.bin") + if err != nil { + return nil, nil, nil, err + } + pk := plonk.NewProvingKey(ecc.BN254) + start = time.Now() + if err != nil { + return nil, nil, nil, err + } + _, err = pk.ReadFrom(pkFile) + if err != nil { + return nil, nil, nil, err + } + pkFile.Close() + elapsed = time.Since(start) + log.Debug().Msg("Successfully loaded pk, time: " + elapsed.String()) + + vkFile, err := os.Open(path + "/vk.bin") + if err != nil { + return nil, nil, nil, err + } + vk := plonk.NewVerifyingKey(ecc.BN254) + start = time.Now() + _, err = vk.ReadFrom(vkFile) + if err != nil { + return nil, nil, nil, err + } + vkFile.Close() + elapsed = time.Since(start) + log.Debug().Msg("Successfully loaded vk, time: " + elapsed.String()) + + return r1cs, pk, vk, nil +} + +func GetPublicInputHash(publicInputs []uint64) frontend.Variable { + if len(publicInputs) != 32 { + panic("publicInputs must be 32 bytes") + } + publicInputsBytes := make([]byte, 32) + for i, v := range publicInputs { + publicInputsBytes[i] = byte(v & 0xFF) + } + publicInputHash := new(big.Int).SetBytes(publicInputsBytes[0:32]) + log.Debug().Msg("Public input hash len: " + fmt.Sprintf("%d", publicInputHash.BitLen())) + if publicInputHash.BitLen() > 253 { + panic("inputHash must be at most 253 bits") + } + return publicInputHash +} + +func Prove(circuitPath string, r1cs constraint.ConstraintSystem, pk plonk.ProvingKey) (plonk.Proof, witness.Witness, error) { + verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData(circuitPath + "/verifier_only_circuit_data.json")) + + proofWithPisRaw := types.ReadProofWithPublicInputs(circuitPath + "/proof_with_public_inputs.json") + proofWithPisVariable := variables.DeserializeProofWithPublicInputs(proofWithPisRaw) + + publicInputHash := GetPublicInputHash(proofWithPisRaw.PublicInputs) + + assignment := Plonky2VerifierCircuit{ + ProofWithPis: proofWithPisVariable, + VerifierData: verifierOnlyCircuitData, + VerifierDigest: verifierOnlyCircuitData.CircuitDigest, + PublicInputHash: publicInputHash, + } + + log.Debug().Msg("Generating witness") + + start := time.Now() + + witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + if err != nil { + return nil, nil, fmt.Errorf("failed to generate witness: %w", err) + } + elapsed := time.Since(start) + log.Debug().Msg("Successfully generated witness, time: " + elapsed.String()) + + log.Debug().Msg("Creating proof") + start = time.Now() + proof, err := plonk.Prove(r1cs, pk, witness) + if err != nil { + return nil, nil, fmt.Errorf("failed to create proof: %w", err) + } + elapsed = time.Since(start) + log.Info().Msg("Successfully created proof, time: " + elapsed.String()) + + log.Info().Msg("Saving proof to proof.json") + + _proof := proof.(*plonk_bn254.Proof) + solidityBytes := _proof.MarshalSolidity() + proofFile, _ := os.Create(circuitPath + "/solidity_bytes.bin") + proofFile.Write(solidityBytes) + proofFile.Close() + + log.Info().Msg("Successfully saved proof") + + publicWitness, err := witness.Public() + log.Info().Msg("Saving public witness to public_witness.bin") + witnessFile, err := os.Create("public_witness.bin") + publicWitness.WriteTo(witnessFile) + witnessFile.Close() + log.Info().Msg("Successfully saved public witness") + + return proof, publicWitness, nil +} + +func ExportSolidityContract(path string, vk plonk.VerifyingKey) { + contractFile, _ := os.Create(path + "/verifier.sol") + vk.ExportSolidity(contractFile) + contractFile.Close() +} diff --git a/beacon-light-client/plonky2/circuits_executables/verifier/go.mod b/beacon-light-client/plonky2/circuits_executables/verifier/go.mod new file mode 100644 index 000000000..21a4ba8f4 --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/verifier/go.mod @@ -0,0 +1,33 @@ +module github.com/metacraft-labs/DendrETH + +go 1.19 + +require ( + github.com/consensys/gnark v0.9.0 + github.com/consensys/gnark-crypto v0.11.2 + github.com/rs/zerolog v1.30.0 + github.com/succinctlabs/gnark-plonky2-verifier v0.0.0-20240104215613-c01f530fe1d0 +) + +require ( + github.com/bits-and-blooms/bitset v1.8.0 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-ignition-verifier v0.0.0-20230527014722-10693546ab33 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fxamacker/cbor/v2 v2.5.0 // indirect + github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + golang.org/x/sys v0.11.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect +) + +replace github.com/succinctlabs/gnark-plonky2-verifier => "//home/dimo/code/repos/metacraft-labs/gnark-plonky2-verifier" diff --git a/beacon-light-client/plonky2/circuits_executables/verifier/go.sum b/beacon-light-client/plonky2/circuits_executables/verifier/go.sum new file mode 100644 index 000000000..d52da3efa --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/verifier/go.sum @@ -0,0 +1,73 @@ +github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= +github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= +github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark v0.9.0 h1:OoOr0Q771mQINVdP3s1AF2Rs1y8gtXhWVkadz/9KmZc= +github.com/consensys/gnark v0.9.0/go.mod h1:Sy9jJjIaGJFfNeupyNOR9Ei2IbAB6cfCO78DfG27YvM= +github.com/consensys/gnark v0.9.1 h1:aTwBp5469MY/2jNrf4ABrqHRW3+JytfkADdw4ZBY7T0= +github.com/consensys/gnark v0.9.1/go.mod h1:udWvWGXnfBE7mn7BsNoGAvZDnUhcONBEtNijvVjfY80= +github.com/consensys/gnark-crypto v0.11.2 h1:GJjjtWJ+db1xGao7vTsOgAOGgjfPe7eRGPL+xxMX0qE= +github.com/consensys/gnark-crypto v0.11.2/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc= +github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark-ignition-verifier v0.0.0-20230527014722-10693546ab33 h1:z42ewLaLxoTYeQ17arcF4WExZc/eSaN3YVlF7eEaPt4= +github.com/consensys/gnark-ignition-verifier v0.0.0-20230527014722-10693546ab33/go.mod h1:JdKor28c/KR4BbznP88bz8AAvnCgovzrB3KWsiR7lwk= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= +github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= +github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/succinctlabs/gnark-plonky2-verifier v0.0.0-20231013210054-89b5a01e4b4b h1:kcqBBMCEhDG6cNKAosD+7OG97jkyih9/G7GuNMrW6A8= +github.com/succinctlabs/gnark-plonky2-verifier v0.0.0-20231013210054-89b5a01e4b4b/go.mod h1:33fqngzJywBvG2tiETIPCFUCnRGkyTOybblVB9M7aOs= +github.com/succinctlabs/gnark-plonky2-verifier v0.0.0-20240104215613-c01f530fe1d0 h1:5dZC0f1lV/y0b3hJ+XtO2Gbaim8wfPwWb0YCAPjusNU= +github.com/succinctlabs/gnark-plonky2-verifier v0.0.0-20240104215613-c01f530fe1d0/go.mod h1:33fqngzJywBvG2tiETIPCFUCnRGkyTOybblVB9M7aOs= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/beacon-light-client/plonky2/circuits_executables/verifier/main.go b/beacon-light-client/plonky2/circuits_executables/verifier/main.go new file mode 100644 index 000000000..2172e6c32 --- /dev/null +++ b/beacon-light-client/plonky2/circuits_executables/verifier/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/logger" +) + +func main() { + circuitPath := flag.String("circuit", "", "path to the circuit") + dataPath := flag.String("data", "", "path to the data") + saveProvingKey := flag.Bool("savepk", false, "save the proving key") + loadProvingKey := flag.Bool("loadpk", false, "load the proving key") + proofFlag := flag.Bool("proof", false, "create the proof") + compileFlag := flag.Bool("compile", false, "compile the circuit") + contractFlag := flag.Bool("contract", false, "Generate solidity contract") + flag.Parse() + + log := logger.Logger() + + log.Debug().Msg("Circuit path: " + *circuitPath) + log.Debug().Msg("Data path: " + *dataPath) + log.Debug().Msg("Save proving key: " + fmt.Sprintf("%t", *saveProvingKey)) + log.Debug().Msg("Load proving key: " + fmt.Sprintf("%t", *loadProvingKey)) + log.Debug().Msg("Create proof: " + fmt.Sprintf("%t", *proofFlag)) + log.Debug().Msg("Compile circuit: " + fmt.Sprintf("%t", *compileFlag)) + log.Debug().Msg("Generate solidity contract: " + fmt.Sprintf("%t", *contractFlag)) + + if *compileFlag { + log.Info().Msg("Compiling circuit") + + r1cs, pk, vk, err := CompileVerifierCircuit(*circuitPath) + + if err != nil { + log.Error().Msg("Failed to compile circuit: " + err.Error()) + os.Exit(1) + } + + if *saveProvingKey { + SaveVerifierCircuit(*dataPath, r1cs, pk, vk) + } + + if *contractFlag { + log.Info().Msg("Generating solidity contract") + ExportSolidityContract(*dataPath, vk) + } + } + + if *proofFlag { + log.Info().Msg("loading the plonk proving key, circuit data and verifying key") + + var r1cs constraint.ConstraintSystem + var pk plonk.ProvingKey + var vk plonk.VerifyingKey + var err error + + if *loadProvingKey { + r1cs, pk, vk, err = LoadCircuitData(*dataPath) + + if err != nil { + log.Error().Msg("Failed to load circuit data: " + err.Error()) + os.Exit(1) + } + } else { + r1cs, pk, vk, err = CompileVerifierCircuit(*circuitPath) + + if err != nil { + log.Error().Msg("Failed to compile circuit: " + err.Error()) + os.Exit(1) + } + } + + log.Info().Msg("Generating proof") + proof, publicWitness, err := Prove(*circuitPath, r1cs, pk) + if err != nil { + log.Error().Msg("Failed to generate proof: " + err.Error()) + os.Exit(1) + } + + log.Info().Msg("Verifying proof") + err = plonk.Verify(proof, vk, publicWitness) + if err != nil { + log.Error().Msg("Failed to verify proof: " + err.Error()) + os.Exit(1) + } + + log.Info().Msg("Successfully verified proof") + } +} diff --git a/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts b/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts index ff5b595ab..398361ac8 100644 --- a/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts +++ b/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts @@ -76,14 +76,14 @@ let TAKE: number | undefined; { index: Number(validator_commitment_constants.validatorRegistryLimit), validator: JSON.stringify({ - pubkey: Array(384).fill(0), - withdrawalCredentials: Array(256).fill(0), - effectiveBalance: Array(256).fill(0), - slashed: Array(256).fill(0), - activationEligibilityEpoch: Array(256).fill(0), - activationEpoch: Array(256).fill(0), - exitEpoch: Array(256).fill(0), - withdrawableEpoch: Array(256).fill(0), + pubkey: ''.padEnd(96, '0'), + withdrawalCredentials: ''.padEnd(64, '0'), + effectiveBalance: ''.padEnd(64, '0'), + slashed: ''.padEnd(64, '0'), + activationEligibilityEpoch: ''.padEnd(64, '0'), + activationEpoch: ''.padEnd(64, '0'), + exitEpoch: ''.padEnd(64, '0'), + withdrawableEpoch: ''.padEnd(64, '0'), }), }, ]); @@ -261,48 +261,32 @@ let TAKE: number | undefined; function convertValidatorToProof(validator: Validator): string { return JSON.stringify({ - pubkey: hexToBits(bytesToHex(validator.pubkey), 381), - withdrawalCredentials: hexToBits( - bytesToHex(validator.withdrawalCredentials), - ), - effectiveBalance: hexToBits( - bytesToHex( - ssz.phase0.Validator.fields.effectiveBalance.hashTreeRoot( - validator.effectiveBalance, - ), + pubkey: bytesToHex(validator.pubkey), + withdrawalCredentials: bytesToHex(validator.withdrawalCredentials), + effectiveBalance: bytesToHex( + ssz.phase0.Validator.fields.effectiveBalance.hashTreeRoot( + validator.effectiveBalance, ), ), - slashed: hexToBits( - bytesToHex( - ssz.phase0.Validator.fields.slashed.hashTreeRoot(validator.slashed), - ), + slashed: bytesToHex( + ssz.phase0.Validator.fields.slashed.hashTreeRoot(validator.slashed), ), - activationEligibilityEpoch: hexToBits( - bytesToHex( - ssz.phase0.Validator.fields.activationEligibilityEpoch.hashTreeRoot( - validator.activationEligibilityEpoch, - ), + activationEligibilityEpoch: bytesToHex( + ssz.phase0.Validator.fields.activationEligibilityEpoch.hashTreeRoot( + validator.activationEligibilityEpoch, ), ), - activationEpoch: hexToBits( - bytesToHex( - ssz.phase0.Validator.fields.activationEpoch.hashTreeRoot( - validator.activationEpoch, - ), + activationEpoch: bytesToHex( + ssz.phase0.Validator.fields.activationEpoch.hashTreeRoot( + validator.activationEpoch, ), ), - exitEpoch: hexToBits( - bytesToHex( - ssz.phase0.Validator.fields.exitEpoch.hashTreeRoot( - validator.exitEpoch, - ), - ), + exitEpoch: bytesToHex( + ssz.phase0.Validator.fields.exitEpoch.hashTreeRoot(validator.exitEpoch), ), - withdrawableEpoch: hexToBits( - bytesToHex( - ssz.phase0.Validator.fields.withdrawableEpoch.hashTreeRoot( - validator.withdrawableEpoch, - ), + withdrawableEpoch: bytesToHex( + ssz.phase0.Validator.fields.withdrawableEpoch.hashTreeRoot( + validator.withdrawableEpoch, ), ), }); diff --git a/relay/implementations/redis.ts b/relay/implementations/redis.ts index 0027a4472..c95f1f861 100644 --- a/relay/implementations/redis.ts +++ b/relay/implementations/redis.ts @@ -49,40 +49,35 @@ export class Redis implements IRedis { const redisValidatorJSON = JSON.parse(batchValidators[j]!); try { let validatorJSON: Validator = { - pubkey: hexToBytes(bitsToBytes(redisValidatorJSON.pubkey)), + pubkey: hexToBytes(redisValidatorJSON.pubkey), withdrawalCredentials: hexToBytes( - bitsToBytes(redisValidatorJSON.withdrawalCredentials), + redisValidatorJSON.withdrawalCredentials, ), effectiveBalance: ssz.phase0.Validator.fields.effectiveBalance.deserialize( - hexToBytes( - bitsToBytes(redisValidatorJSON.effectiveBalance), - ).slice(0, 8), + hexToBytes(redisValidatorJSON.effectiveBalance).slice(0, 8), ), slashed: ssz.phase0.Validator.fields.slashed.deserialize( - hexToBytes(bitsToBytes(redisValidatorJSON.slashed)).slice(0, 1), + hexToBytes(redisValidatorJSON.slashed).slice(0, 1), ), activationEligibilityEpoch: ssz.phase0.Validator.fields.activationEligibilityEpoch.deserialize( - hexToBytes( - bitsToBytes(redisValidatorJSON.activationEligibilityEpoch), - ).slice(0, 8), + hexToBytes(redisValidatorJSON.activationEligibilityEpoch).slice( + 0, + 8, + ), ), activationEpoch: ssz.phase0.Validator.fields.activationEpoch.deserialize( - hexToBytes( - bitsToBytes(redisValidatorJSON.activationEpoch), - ).slice(0, 8), + hexToBytes(redisValidatorJSON.activationEpoch).slice(0, 8), ), exitEpoch: ssz.phase0.Validator.fields.exitEpoch.deserialize( - hexToBytes(bitsToBytes(redisValidatorJSON.exitEpoch)).slice(0, 8), + hexToBytes(redisValidatorJSON.exitEpoch).slice(0, 8), ), withdrawableEpoch: ssz.phase0.Validator.fields.withdrawableEpoch.deserialize( - hexToBytes( - bitsToBytes(redisValidatorJSON.withdrawableEpoch), - ).slice(0, 8), + hexToBytes(redisValidatorJSON.withdrawableEpoch).slice(0, 8), ), }; From 6a4c730eb6600142bf9f5506f5aca06582ff2bfa Mon Sep 17 00:00:00 2001 From: Martin Ivanov Date: Wed, 7 Feb 2024 19:17:10 +0200 Subject: [PATCH 2/3] feat(gnark-verifier): implement an http proving server --- .../circuits_executables/verifier/main.go | 83 +++++++++++++++++-- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/beacon-light-client/plonky2/circuits_executables/verifier/main.go b/beacon-light-client/plonky2/circuits_executables/verifier/main.go index 2172e6c32..4cbe5c010 100644 --- a/beacon-light-client/plonky2/circuits_executables/verifier/main.go +++ b/beacon-light-client/plonky2/circuits_executables/verifier/main.go @@ -1,13 +1,26 @@ package main import ( + "encoding/json" + "errors" "flag" "fmt" + "net/http" "os" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/plonk" + plonk_bn254 "github.com/consensys/gnark/backend/plonk/bn254" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/logger" + "github.com/consensys/gnark/frontend" + "github.com/rs/zerolog/log" + "github.com/succinctlabs/gnark-plonky2-verifier/types" + "github.com/succinctlabs/gnark-plonky2-verifier/variables" +) + +var ( + r1cs constraint.ConstraintSystem + pk plonk.ProvingKey ) func main() { @@ -18,10 +31,9 @@ func main() { proofFlag := flag.Bool("proof", false, "create the proof") compileFlag := flag.Bool("compile", false, "compile the circuit") contractFlag := flag.Bool("contract", false, "Generate solidity contract") + startServerFlag := flag.Bool("server", false, "Start an http proving server") flag.Parse() - log := logger.Logger() - log.Debug().Msg("Circuit path: " + *circuitPath) log.Debug().Msg("Data path: " + *dataPath) log.Debug().Msg("Save proving key: " + fmt.Sprintf("%t", *saveProvingKey)) @@ -29,6 +41,25 @@ func main() { log.Debug().Msg("Create proof: " + fmt.Sprintf("%t", *proofFlag)) log.Debug().Msg("Compile circuit: " + fmt.Sprintf("%t", *compileFlag)) log.Debug().Msg("Generate solidity contract: " + fmt.Sprintf("%t", *contractFlag)) + log.Debug().Msg("Start an http proving server: " + fmt.Sprintf("%t", *startServerFlag)) + + defer func() { + if !*startServerFlag { + return + } + + http.HandleFunc("/genProof", generateProof) + const PORT = 3333 + log.Log().Msg(fmt.Sprintf("Listening on port: %v", PORT)) + if err := http.ListenAndServe(fmt.Sprintf(":%v", PORT), nil); err != nil { + if errors.Is(err, http.ErrServerClosed) { + log.Log().Msg("Server closed") + } else if err != nil { + log.Error().Msg(fmt.Sprintf("Error starting server: %s", err.Error())) + os.Exit(1) + } + } + }() if *compileFlag { log.Info().Msg("Compiling circuit") @@ -53,8 +84,6 @@ func main() { if *proofFlag { log.Info().Msg("loading the plonk proving key, circuit data and verifying key") - var r1cs constraint.ConstraintSystem - var pk plonk.ProvingKey var vk plonk.VerifyingKey var err error @@ -91,3 +120,47 @@ func main() { log.Info().Msg("Successfully verified proof") } } + +type GenerateProofDTO struct { + VerifierOnlyCircuitData types.VerifierOnlyCircuitDataRaw `json:"verifier_only_circuit_data"` + ProofWithPublicInputs types.ProofWithPublicInputsRaw `json:"proof_with_public_inputs"` +} + +func generateProof(res http.ResponseWriter, req *http.Request) { + var dto GenerateProofDTO + if err := json.NewDecoder(req.Body).Decode(&dto); err != nil { + http.Error(res, fmt.Sprintf("Error while parsing request body: %s", err.Error()), 400) + return + } + + verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(dto.VerifierOnlyCircuitData) + proofWithPisVariable := variables.DeserializeProofWithPublicInputs(dto.ProofWithPublicInputs) + publicInputHash := GetPublicInputHash(dto.ProofWithPublicInputs.PublicInputs) + + assignment := Plonky2VerifierCircuit{ + ProofWithPis: proofWithPisVariable, + VerifierData: verifierOnlyCircuitData, + VerifierDigest: verifierOnlyCircuitData.CircuitDigest, + PublicInputHash: publicInputHash, + } + log.Debug().Msg("Generating witness") + witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + if err != nil { + http.Error(res, fmt.Sprintf("failed to generate witness: %s", err.Error()), 400) + return + } + + log.Debug().Msg("Successfully generated witness") + log.Debug().Msg("Creating proof") + + proof, err := plonk.Prove(r1cs, pk, witness) + if err != nil { + http.Error(res, fmt.Sprintf("failed to create proof: %s", err.Error()), 400) + return + } + + log.Info().Msg("Successfully created proof") + + res.Header().Add("Content-Type", "octet-stream") + res.Write(proof.(*plonk_bn254.Proof).MarshalSolidity()) +} From 05a264a0c707a992ff0c67412a0c2253af90fb4d Mon Sep 17 00:00:00 2001 From: Martin Ivanov Date: Thu, 8 Feb 2024 18:42:27 +0200 Subject: [PATCH 3/3] feat(gnark-verifier): Implement proof generation queue --- .../circuits_executables/verifier/circuit.go | 8 +- .../circuits_executables/verifier/main.go | 78 +++++++++++++------ 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/beacon-light-client/plonky2/circuits_executables/verifier/circuit.go b/beacon-light-client/plonky2/circuits_executables/verifier/circuit.go index 98c318d4c..4f295d9fb 100644 --- a/beacon-light-client/plonky2/circuits_executables/verifier/circuit.go +++ b/beacon-light-client/plonky2/circuits_executables/verifier/circuit.go @@ -67,8 +67,6 @@ func (c *Plonky2VerifierCircuit) Define(api frontend.API) error { } func CompileVerifierCircuit(circuitPath string) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey, error) { - log := logger.Logger() - verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData(circuitPath + "/verifier_only_circuit_data.json")) proofWithPis := variables.DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs(circuitPath + "/proof_with_public_inputs.json")) @@ -89,6 +87,7 @@ func CompileVerifierCircuit(circuitPath string) (constraint.ConstraintSystem, pl return nil, nil, nil, err } + log := logger.Logger() log.Info().Msg("Loading SRS setup") start := time.Now() @@ -177,6 +176,8 @@ func SaveVerifierCircuit(path string, r1cs constraint.ConstraintSystem, pk plonk } func LoadCircuitData(path string) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey, error) { + log := logger.Logger() + r1csFile, err := os.Open(path + "/r1cs.bin") if err != nil { return nil, nil, nil, err @@ -234,6 +235,8 @@ func GetPublicInputHash(publicInputs []uint64) frontend.Variable { publicInputsBytes[i] = byte(v & 0xFF) } publicInputHash := new(big.Int).SetBytes(publicInputsBytes[0:32]) + + log := logger.Logger() log.Debug().Msg("Public input hash len: " + fmt.Sprintf("%d", publicInputHash.BitLen())) if publicInputHash.BitLen() > 253 { panic("inputHash must be at most 253 bits") @@ -256,6 +259,7 @@ func Prove(circuitPath string, r1cs constraint.ConstraintSystem, pk plonk.Provin PublicInputHash: publicInputHash, } + log := logger.Logger() log.Debug().Msg("Generating witness") start := time.Now() diff --git a/beacon-light-client/plonky2/circuits_executables/verifier/main.go b/beacon-light-client/plonky2/circuits_executables/verifier/main.go index 4cbe5c010..e0d2c7770 100644 --- a/beacon-light-client/plonky2/circuits_executables/verifier/main.go +++ b/beacon-light-client/plonky2/circuits_executables/verifier/main.go @@ -7,17 +7,20 @@ import ( "fmt" "net/http" "os" + "sync" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/plonk" plonk_bn254 "github.com/consensys/gnark/backend/plonk/bn254" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/rs/zerolog/log" + "github.com/consensys/gnark/logger" "github.com/succinctlabs/gnark-plonky2-verifier/types" "github.com/succinctlabs/gnark-plonky2-verifier/variables" ) +const PORT = 3333 + var ( r1cs constraint.ConstraintSystem pk plonk.ProvingKey @@ -34,6 +37,7 @@ func main() { startServerFlag := flag.Bool("server", false, "Start an http proving server") flag.Parse() + log := logger.Logger() log.Debug().Msg("Circuit path: " + *circuitPath) log.Debug().Msg("Data path: " + *dataPath) log.Debug().Msg("Save proving key: " + fmt.Sprintf("%t", *saveProvingKey)) @@ -48,12 +52,11 @@ func main() { return } - http.HandleFunc("/genProof", generateProof) - const PORT = 3333 - log.Log().Msg(fmt.Sprintf("Listening on port: %v", PORT)) + http.Handle("/genProof", newGenerateProofHandler()) + log.Info().Msg(fmt.Sprintf("Listening on port: %v", PORT)) if err := http.ListenAndServe(fmt.Sprintf(":%v", PORT), nil); err != nil { if errors.Is(err, http.ErrServerClosed) { - log.Log().Msg("Server closed") + log.Info().Msg("Server closed") } else if err != nil { log.Error().Msg(fmt.Sprintf("Error starting server: %s", err.Error())) os.Exit(1) @@ -81,27 +84,28 @@ func main() { } } - if *proofFlag { - log.Info().Msg("loading the plonk proving key, circuit data and verifying key") + var vk plonk.VerifyingKey - var vk plonk.VerifyingKey + if *loadProvingKey { var err error + r1cs, pk, vk, err = LoadCircuitData(*dataPath) - if *loadProvingKey { - r1cs, pk, vk, err = LoadCircuitData(*dataPath) - - if err != nil { - log.Error().Msg("Failed to load circuit data: " + err.Error()) - os.Exit(1) - } - } else { - r1cs, pk, vk, err = CompileVerifierCircuit(*circuitPath) + if err != nil { + log.Error().Msg("Failed to load circuit data: " + err.Error()) + os.Exit(1) + } + } else { + var err error + r1cs, pk, vk, err = CompileVerifierCircuit(*circuitPath) - if err != nil { - log.Error().Msg("Failed to compile circuit: " + err.Error()) - os.Exit(1) - } + if err != nil { + log.Error().Msg("Failed to compile circuit: " + err.Error()) + os.Exit(1) } + } + + if *proofFlag { + log.Info().Msg("loading the plonk proving key, circuit data and verifying key") log.Info().Msg("Generating proof") proof, publicWitness, err := Prove(*circuitPath, r1cs, pk) @@ -126,7 +130,37 @@ type GenerateProofDTO struct { ProofWithPublicInputs types.ProofWithPublicInputsRaw `json:"proof_with_public_inputs"` } -func generateProof(res http.ResponseWriter, req *http.Request) { +type GenerateProofHandler struct { + waitingForJobCV *sync.Cond + waitingForJob *bool +} + +func newGenerateProofHandler() GenerateProofHandler { + return GenerateProofHandler{ + waitingForJobCV: sync.NewCond(&sync.Mutex{}), + waitingForJob: func() *bool { + flag := true + return &flag + }(), + } +} + +func (handler GenerateProofHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) { + log := logger.Logger() + + handler.waitingForJobCV.L.Lock() + for !*handler.waitingForJob { + handler.waitingForJobCV.Wait() + } + + *handler.waitingForJob = false + + defer func() { + *handler.waitingForJob = true + handler.waitingForJobCV.L.Unlock() + handler.waitingForJobCV.Signal() + }() + var dto GenerateProofDTO if err := json.NewDecoder(req.Body).Decode(&dto); err != nil { http.Error(res, fmt.Sprintf("Error while parsing request body: %s", err.Error()), 400)