-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from tchataigner/feature/keccak-example
Introducing Keccak example and cleanup
- Loading branch information
Showing
17 changed files
with
1,192 additions
and
500 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
/Cargo.lock | ||
|
||
.vscode/ | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#![allow(clippy::expect_used, clippy::unwrap_used)] | ||
|
||
use bellpepper_core::ConstraintSystem; | ||
use circom_scotia::{calculate_witness, r1cs::CircomConfig, synthesize}; | ||
|
||
use pasta_curves::vesta::Base as Fr; | ||
use std::env::current_dir; | ||
|
||
use bellpepper_core::test_cs::TestConstraintSystem; | ||
use circom_scotia::r1cs::CircomInput; | ||
use pasta_curves::Fq; | ||
|
||
fn main() { | ||
let root = current_dir().unwrap().join("examples/keccak"); | ||
let wtns = root.join("circom_keccak256.wasm"); | ||
let r1cs = root.join("circom_keccak256.r1cs"); | ||
|
||
let mut cs = TestConstraintSystem::<Fr>::new(); | ||
let cfg = CircomConfig::new(wtns, r1cs).unwrap(); | ||
|
||
let input_bytes = [ | ||
116, 101, 115, 116, 0, 0, 0, 0, 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 expected_output = [ | ||
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, 212, | ||
4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, | ||
]; | ||
|
||
let input_bits = bytes_to_bits(&input_bytes); | ||
|
||
let arg_in = CircomInput { | ||
name: "in".into(), | ||
value: input_bits.clone().iter().map(|b| Fr::from(*b)).collect(), | ||
}; | ||
let input = vec![arg_in]; | ||
let witness = calculate_witness(&cfg, input, true).expect("msg"); | ||
|
||
let output = synthesize( | ||
&mut cs.namespace(|| "keccak_circom"), | ||
cfg.r1cs.clone(), | ||
Some(witness), | ||
); | ||
|
||
let state_out_fq = output.unwrap(); | ||
let state_out_bits: Vec<bool> = state_out_fq | ||
.iter() | ||
.map(|an| Fq::one() == an.get_value().unwrap()) | ||
.collect(); | ||
let state_out_bytes = bits_to_bytes(&state_out_bits); | ||
|
||
assert_eq!(state_out_bytes, expected_output); | ||
} | ||
|
||
// Transforms a slice of bits in a slice of bytes. Fills the bytes from least to most significant | ||
// bit. | ||
fn bits_to_bytes(bits: &[bool]) -> Vec<u8> { | ||
let mut bytes = vec![0; (bits.len() + 7) / 8]; // Initialize a vector with zeroes | ||
|
||
for (i, &bit) in bits.iter().enumerate() { | ||
// Iterate over each bit with its index | ||
let byte_index = i / 8; // Calculate the byte index for the current bit | ||
if bit { | ||
// If the current bit is true, | ||
bytes[byte_index] |= 1 << (i % 8); // Set the corresponding bit in the byte | ||
} | ||
} | ||
bytes // Return the array of bytes | ||
} | ||
|
||
// Transforms a slice of bytes to a slice of bits. When dividing one byte in bits, order the bits | ||
// from the least significant to the most significant one. | ||
fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> { | ||
let mut bits = Vec::new(); // Create a new, empty vector to store bits | ||
|
||
for &byte in bytes.iter() { | ||
// Iterate over each byte in the input slice | ||
for j in 0..8 { | ||
// For each bit in the byte | ||
if byte & (1 << j) > 0 { | ||
// Check if the bit is set | ||
bits.push(true); // If the bit is set, push 1 to the vector | ||
} else { | ||
bits.push(false); // If the bit is not set, push 0 | ||
} | ||
} | ||
} | ||
bits // Return the vector of bits | ||
} |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
use thiserror::Error; | ||
|
||
/// Enum related to error happening while reading data from source. | ||
#[derive(Error, Debug)] | ||
pub enum ReaderError { | ||
/// Error if we failed to open the file we want to read. | ||
#[error("Failed to open file \"{filename}\": {source}")] | ||
OpenFileError { | ||
filename: String, | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// High level error returned if we could not read our .bin or .json file. | ||
#[error("Failed to read witness from file \"{filename}\": {source}")] | ||
ReadWitnessError { | ||
filename: String, | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error thrown if the specified filename contains non-unicode characters. | ||
#[error("Could not read provided file path. It most likely contains non-Unicode data.")] | ||
FilenameError, | ||
/// Error if we could not find the magic header 'wtns' in the witness file. | ||
#[error("'witns' header not found.")] | ||
WitnessHeaderError, | ||
/// Error if we could not find the magic header 'r1cs' in the r1cs file. | ||
#[error("'r1cs' header not found.")] | ||
R1CSHeaderError, | ||
/// Error thrown while failing to seek a new position in our buffer. | ||
#[error("Error while seeking in buffer: {source}")] | ||
SeekError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error thrown when we try to read a witness file with a non-supported version. | ||
#[error("Witness version not supported. Version supported is 2.*, found {0}")] | ||
WitnessVersionNotSupported(String), | ||
/// Error thrown when we try to read a r1cs file with a non-supported version. | ||
#[error("R1CS version not supported. Version supported is 1, found {0}")] | ||
R1CSVersionNotSupported(String), | ||
/// Error thrown when we try to read a section from our file and it does not exist. | ||
#[error("Failed to find section {0}")] | ||
SectionNotFound(String), | ||
/// Error if the number of sections in the witness file is not two. | ||
#[error("Invalid number of sections found in witness data. Expected 2 got {0}")] | ||
SectionCountError(String), | ||
/// Error thrown if the section we are reading is not of the type we expected. | ||
#[error("Invalid section type. Expected {0}, got {1}")] | ||
SectionTypeError(String, String), | ||
/// Error thrown if the section we are reading is not of the length we expected. | ||
#[error("Invalid section length. Expected {0}, got {1}")] | ||
SectionLengthError(String, String), | ||
/// Error thrown if the field we are reading is not of the size we expected. | ||
#[error("Invalid field byte size. Expected {0}, got {1}")] | ||
FieldByteSizeError(String, String), | ||
/// Error if we tried to read an integer from the bytes and it failed. | ||
#[error("Failed to read integer from bytes: {source}")] | ||
ReadIntegerError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error if we tried to read a specified amount of bytes and it failed. | ||
#[error("Failed to read bytes: {source}")] | ||
ReadBytesError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error if we tried to read a field element from the bytes and it failed. | ||
#[error("Failed to read field from bytes: {source}")] | ||
ReadFieldError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error thrown if the specified modulus in the r1cs header is not the one we were expecting. | ||
#[error("Mismatched prime field. Expected {expected}, read {value} in the header instead.")] | ||
NonMatchingPrime { expected: String, value: String }, | ||
/// Error thrown when parsing wires in an R1CS file. We expect the first wire to always be mapped to 0. | ||
#[error("Wire 0 should always be mapped to 0")] | ||
WireError, | ||
} | ||
|
||
/// Enum related to witness generatiuon problems. | ||
#[derive(Error, Debug)] | ||
pub enum WitnessError { | ||
/// Error if we could not execute the node command to generate our witness. | ||
#[error("Failed to execute the witness generation: {source}")] | ||
FailedExecutionError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error if we could not read the witness from the generated file. | ||
#[error("Could not load witness from its generated file: {source}")] | ||
LoadWitnessError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error generated while trying to access or alter the file system. | ||
#[error("Could not interact with the file system: {source}")] | ||
FileSystemError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error generated if a panic occurs when trying to access the content of our Mutex. | ||
#[error("Could not acquire the witness calculator mutex lock.")] | ||
MutexError, | ||
/// Error if we could not calculate the witness. | ||
#[error("Failed to calculate the witness: {source}")] | ||
WitnessCalculationError { | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
} | ||
|
||
/// Error related to the Circom configuration | ||
#[derive(Error, Debug)] | ||
pub enum CircomConfigError { | ||
/// Error if we could not instantiate our Witness Calculator. | ||
#[error( | ||
"Could instantiate a witness calculator based on the witness file \"{path}\": {source}" | ||
)] | ||
WitnessCalculatorInstantiationError { | ||
path: String, | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
/// Error if we could not load data from our R1CS file. | ||
#[error("Could load r1cs data from the given file \"{path}\": {source}")] | ||
LoadR1CSError { | ||
path: String, | ||
#[source] | ||
source: Box<dyn std::error::Error + Sync + Send>, | ||
}, | ||
} |
Oops, something went wrong.