Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

feat!: Add Keccak constraints #150

Merged
merged 6 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 13 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ license = "MIT OR Apache-2.0"
acvm = { version = "0.10.3", features = ["bn254"] }

blake2 = "0.9.1"
sha3 = "0.9.1"
dirs = { version = "3.0", optional = true }
reqwest = { version = "0.11.16", optional = true, default-features = false, features = ["stream", "rustls-tls"] }
reqwest = { version = "0.11.16", optional = true, default-features = false, features = [
"stream",
"rustls-tls",
] }
tokio = { version = "1.0", optional = true }
futures-util = { version = "0.3.14", optional = true }
indicatif = { version = "0.17.3", optional = true }
Expand All @@ -23,7 +27,11 @@ barretenberg-sys = { version = "0.1.2", optional = true }

# Wasm
wasmer = { version = "*", optional = true, default-features = false }
rust-embed = { version = "6.6.0", optional = true, features = ["debug-embed", "interpolate-folder-path", "include-exclude"] }
rust-embed = { version = "6.6.0", optional = true, features = [
"debug-embed",
"interpolate-folder-path",
"include-exclude",
] }
getrandom = { version = "0.2", optional = true }

[build-dependencies]
Expand All @@ -41,7 +49,7 @@ native = [
"dep:tokio",
"dep:futures-util",
"dep:dirs",
"dep:indicatif"
"dep:indicatif",
]
wasm = [
"wasmer",
Expand All @@ -56,11 +64,6 @@ wasm = [
"dep:tokio",
"dep:futures-util",
"dep:dirs",
"dep:indicatif"
]
js = [
"wasmer",
"dep:rust-embed",
"dep:getrandom",
"wasmer/js-default",
"dep:indicatif",
]
js = ["wasmer", "dep:rust-embed", "dep:getrandom", "wasmer/js-default"]
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/acvm_interop/proof_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ impl ProofSystemCompiler for Barretenberg {
| BlackBoxFunc::RANGE
| BlackBoxFunc::SHA256
| BlackBoxFunc::Blake2s
| BlackBoxFunc::Keccak256
| BlackBoxFunc::ComputeMerkleRoot
| BlackBoxFunc::SchnorrVerify
| BlackBoxFunc::Pedersen
| BlackBoxFunc::HashToField128Security
| BlackBoxFunc::EcdsaSecp256k1
| BlackBoxFunc::FixedBaseScalarMul => true,

BlackBoxFunc::AES | BlackBoxFunc::Keccak256 => false,
BlackBoxFunc::AES => false,
}
}

Expand Down
63 changes: 60 additions & 3 deletions src/acvm_interop/pwg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ impl PartialWitnessGenerator for Barretenberg {
match func_call.name {
BlackBoxFunc::SHA256 => hash::sha256(initial_witness, func_call),
BlackBoxFunc::Blake2s => hash::blake2s(initial_witness, func_call),
BlackBoxFunc::Keccak256 => keccak256(initial_witness, func_call),
BlackBoxFunc::EcdsaSecp256k1 => {
signature::ecdsa::secp256k1_prehashed(initial_witness, func_call)
}
Expand All @@ -32,9 +33,9 @@ impl PartialWitnessGenerator for Barretenberg {
logic::solve_logic_opcode(initial_witness, func_call)
}
BlackBoxFunc::RANGE => range::solve_range_opcode(initial_witness, func_call),
BlackBoxFunc::AES | BlackBoxFunc::Keccak256 => Err(
OpcodeResolutionError::UnsupportedBlackBoxFunc(func_call.name),
),
BlackBoxFunc::AES => Err(OpcodeResolutionError::UnsupportedBlackBoxFunc(
func_call.name,
)),
BlackBoxFunc::ComputeMerkleRoot => {
let mut inputs_iter = func_call.inputs.iter();

Expand Down Expand Up @@ -160,3 +161,59 @@ impl PartialWitnessGenerator for Barretenberg {
}
}
}

// All of the code below can be removed once we update to acvm 0.11 or greater.
use sha3::Keccak256;
fn keccak256(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let hash = generic_hash_256::<Keccak256>(initial_witness, func_call)?;

for (output_witness, value) in func_call.outputs.iter().zip(hash.iter()) {
insert_value(
output_witness,
FieldElement::from_be_bytes_reduce(&[*value]),
initial_witness,
)?;
}

Ok(OpcodeResolution::Solved)
}
fn insert_value(
witness: &Witness,
value_to_insert: FieldElement,
initial_witness: &mut BTreeMap<Witness, FieldElement>,
) -> Result<(), OpcodeResolutionError> {
let optional_old_value = initial_witness.insert(*witness, value_to_insert);

let old_value = match optional_old_value {
Some(old_value) => old_value,
None => return Ok(()),
};

if old_value != value_to_insert {
return Err(OpcodeResolutionError::UnsatisfiedConstrain);
}

Ok(())
}
fn generic_hash_256<D: Digest>(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
) -> Result<[u8; 32], OpcodeResolutionError> {
let mut hasher = D::new();

// Read witness assignments into hasher.
for input in func_call.inputs.iter() {
let witness = input.witness;
let num_bits = input.num_bits as usize;

let witness_assignment = witness_to_value(initial_witness, witness)?;
let bytes = witness_assignment.fetch_nearest_bytes(num_bits);
hasher.update(bytes);
}

let result = hasher.finalize().as_slice().try_into().unwrap();
Ok(result)
}
68 changes: 67 additions & 1 deletion src/barretenberg_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,34 @@ impl HashToFieldConstraint {
buffer
}
}

#[derive(Clone, Hash, Debug)]
pub(crate) struct Keccak256Constraint {
pub(crate) inputs: Vec<(i32, i32)>,
pub(crate) result: [i32; 32],
}

impl Keccak256Constraint {
fn to_bytes(&self) -> Vec<u8> {
let mut buffer = Vec::new();

let inputs_len = self.inputs.len() as u32;
buffer.extend_from_slice(&inputs_len.to_be_bytes());
for constraint in self.inputs.iter() {
buffer.extend_from_slice(&constraint.0.to_be_bytes());
buffer.extend_from_slice(&constraint.1.to_be_bytes());
}

let result_len = self.result.len() as u32;
buffer.extend_from_slice(&result_len.to_be_bytes());
for constraint in self.result.iter() {
buffer.extend_from_slice(&constraint.to_be_bytes());
}

buffer
}
}

#[derive(Clone, Hash, Debug)]
pub(crate) struct PedersenConstraint {
pub(crate) inputs: Vec<i32>,
Expand Down Expand Up @@ -396,6 +424,7 @@ pub(crate) struct ConstraintSystem {
schnorr_constraints: Vec<SchnorrConstraint>,
ecdsa_secp256k1_constraints: Vec<EcdsaConstraint>,
blake2s_constraints: Vec<Blake2sConstraint>,
keccak_constraints: Vec<Keccak256Constraint>,
pedersen_constraints: Vec<PedersenConstraint>,
hash_to_field_constraints: Vec<HashToFieldConstraint>,
fixed_base_scalar_mul_constraints: Vec<FixedBaseScalarMulConstraint>,
Expand Down Expand Up @@ -567,6 +596,13 @@ impl ConstraintSystem {
buffer.extend(&constraint.to_bytes());
}

// Serialize each Keccak constraint
let keccak_len = self.keccak_constraints.len() as u32;
buffer.extend_from_slice(&keccak_len.to_be_bytes());
for constraint in self.keccak_constraints.iter() {
buffer.extend(&constraint.to_bytes());
}

// Serialize each Pedersen constraint
let pedersen_len = self.pedersen_constraints.len() as u32;
buffer.extend_from_slice(&pedersen_len.to_be_bytes());
Expand Down Expand Up @@ -608,6 +644,7 @@ impl From<&Circuit> for ConstraintSystem {
let mut logic_constraints: Vec<LogicConstraint> = Vec::new();
let mut sha256_constraints: Vec<Sha256Constraint> = Vec::new();
let mut blake2s_constraints: Vec<Blake2sConstraint> = Vec::new();
let mut keccak_constraints: Vec<Keccak256Constraint> = Vec::new();
let mut pedersen_constraints: Vec<PedersenConstraint> = Vec::new();
let mut compute_merkle_root_constraints: Vec<ComputeMerkleRootConstraint> = Vec::new();
let mut schnorr_constraints: Vec<SchnorrConstraint> = Vec::new();
Expand Down Expand Up @@ -923,7 +960,35 @@ impl From<&Circuit> for ConstraintSystem {

fixed_base_scalar_mul_constraints.push(fixed_base_scalar_mul);
}
BlackBoxFunc::Keccak256 => panic!("Keccak256 has not yet been implemented"),
BlackBoxFunc::Keccak256 => {
let mut keccak_inputs: Vec<(i32, i32)> = Vec::new();
for input in gadget_call.inputs.iter() {
let witness_index = input.witness.witness_index() as i32;
let num_bits = input.num_bits as i32;
keccak_inputs.push((witness_index, num_bits));
}

assert_eq!(gadget_call.outputs.len(), 32);

let mut outputs_iter = gadget_call.outputs.iter();
let mut result = [0i32; 32];
for (i, res) in result.iter_mut().enumerate() {
let out_byte = outputs_iter.next().unwrap_or_else(|| {
panic!(
"missing rest of output. Tried to get byte {i} but failed"
)
});

let out_byte_index = out_byte.witness_index() as i32;
*res = out_byte_index
}
let keccak_constraint = Keccak256Constraint {
inputs: keccak_inputs,
result,
};

keccak_constraints.push(keccak_constraint);
}
BlackBoxFunc::AES => panic!("AES has not yet been implemented"),
};
}
Expand All @@ -948,6 +1013,7 @@ impl From<&Circuit> for ConstraintSystem {
schnorr_constraints,
ecdsa_secp256k1_constraints,
blake2s_constraints,
keccak_constraints,
hash_to_field_constraints,
constraints,
fixed_base_scalar_mul_constraints,
Expand Down