Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: accept raw values as well as hash #4

Merged
merged 4 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ p3-baby-bear = { git = "https://github.com/argumentcomputer/Plonky3.git", branch
]}
num-bigint = { version = "0.4.6", default-features = false }
serde = "1.0.207"
sha2 = "0.10.8"
hex = "0.4.3"

[lib]
crate-type = ["staticlib"]
Expand All @@ -25,4 +27,3 @@ crate-type = ["staticlib"]
hex = "0.4.3"
home = "0.5.9"
serde_json = "1.0.128"
sha2 = "0.10.8"
5 changes: 5 additions & 0 deletions assets/inclusion_fixture.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"vkey": "0x005835dfcad599fa418a0df2b5ecde903b801f7e0706e9530959119ec75aa9e3",
"publicValues": "0xe0fc9100000000000969ed235cf75d25800ea6845c2584af013c1f9617ad2de87202d7e9b93739c95c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f22002fe30a172d0a479f6add89c63b29dce29b6071b3c7e486b0fb4bc431f88501000000000000002000000000000000290decd9548b62a8ef0d3e6ac11e2d7b95a49e22ecf57fc6044b6f007ca2b2ba010000000000000080",
"proof": "0x19b3db1870a51a91be455ba82d2e39cbe5629abdb0b684133a8f69e43302baed21f64f8c3a017c0c322ee0910ea20fb0deff14ebc9d28b22ae1b65bd049f5fe5068f5e2f1842492c1ec64675c53c7b541923d5ad88f4efafd5535061c06b1ee7107a492104941224643fae9f051fbcef1beb7ac19cb527748ff79ba4f7de2b48193bc9921fb16667289153bb6031a4fe01af87f693235319e6d3fea954ee91ac2440212dec1b6c62ab2cc1d8b61a4b9416e1b0d9237be712bdb8c603013c6b7200fe827e9235aaa8e2bbd3db172e46fff9161193e3a568ad8f6e7af50572a858150e60e282674711b44a801fcfe5bf8692a1feac0be30b6184f0c90987ba38fe02194c1c9c8429d24788e46f75568d03a3191c7e83a6dee6def281c6d36183522cdaa119cf660847b8c29cef6e4435499ef4086238825e9c441c3a28960cfc1b0a647a89d8494b5de2caa394fb59a4381a14a523f364ea302d6a84b32054308900662eaf0058fbc6d436602e672e2eba696e8110cd8d0228129496c1a708f29a291691d639d11a9ae2300a24b9fe7b50ccbc292ec9092ef367b98922afaa33300b02166502f811e1dbc324e0858c6f63b9db42152410aab9a96e5fd1ae5d624e01ea3694a8278162c9d962ca1ef2f6a70590a20a534e973acccee2f01af40fa204ddc41227632b53c764b99b837d32d785987a43f5edf397cd34beb9402b854900000007169c4da2bfc39950f8fe20225faf4da7b46ec38da8d4c22b2e40841ec30ef83e0d6aef7b402e7f0de5cb7f6798328268d2fc5e8759f6f12663ac3bff27c76cb1074224fa19ec12fb01bd95d10f4f53436b3e8441c3e93247d2f21fbe94579d43075306065f6ce1f0c966bd219fb1bc2f7347bcb8f149994d5cf023e0b408f34c0416a6c00e69acd5a402c776c53ee60ad3e3a01dea16621d5f110245e14501cf0e464ef0f83a41ad025dbf85cccffd2af8f2bbcfd0eddc5519e86d1ec362249b0d50b96c17005da5b900fad884a0a85402a07b92e4a746f3273b42f31b0e24e92c3e0ef03c15cfec9d03001e9dd208b257e7932f30780c90b5031206ea38e12d2916661b232cd46be404137b62a5268815cc9915685a5d9dcbcfed7d3e6872fe117973aaa3fcfadfbe2c42cbcf7537a5dc1df78c38e931066b3bc3125078dee7000000012ca60493e5d5edafe7948cbe0e3736b1c59aa29998f216a8d7e4b89c06c536a32129520c5ed2ecce4e9d8263b11b757956d2999f74dac0efc16992d923b94bc3"
}
84 changes: 47 additions & 37 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
use hs_bindgen::*;
use num_bigint::BigUint;
use sha2::{Digest as _, Sha256};
use hex;

use sphinx_recursion_gnark_ffi::ffi;

// Helper function to remove "0x" if present
fn strip_hex_prefix(hex: &str) -> &str {
hex.strip_prefix("0x").unwrap_or(hex)
}

// Facade exposing a bindgen anchor
#[hs_bindgen]
pub fn verify_plonk_bn254(
Expand All @@ -10,12 +18,40 @@ pub fn verify_plonk_bn254(
vkey_hash_str: &str,
committed_values_digest_str: &str,
) -> u32 {
// TODO: sanity-check the inputs by parsing the build_dir_str, vkey_hash_str, and committed_values_digest_str
let proof_str = strip_hex_prefix(proof_str);
let vkey_hash_str = strip_hex_prefix(vkey_hash_str);
let committed_values_digest_str = strip_hex_prefix(committed_values_digest_str);

// Decode the hex-encoded string for public values
let decoded_bytes = hex::decode(committed_values_digest_str).expect("Invalid committed values field");

// Check the bit length (bytes * 8 should be 256 bits), hash if necessary
let bit_length = decoded_bytes.len() * 8;

let public_inputs: String = if bit_length > 256 {
Copy link
Member

@wwared wwared Sep 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better if we always unconditionally did the Sha256 hashing here, since this heuristic would be confusing to callers.

What about removing the if entirely and the assets/fibonacci_fixture.json test case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened #5

// The user has provided the committed values rather than the digest!
// Let's reproduce the digest using the committed values
//
// Hash the value using SHA-256
let mut hash: [u8;32] = Sha256::digest(decoded_bytes).into();
// Truncate to 253 bits by clearing the top 3 bits of the first byte
hash[0] &= 0x1F; // 0x1F is 00011111 in binary, which clears the top 3 bits

// Re-encode the truncated hash in hex
hex::encode(hash)
} else {
committed_values_digest_str.to_string()
};

// Parse the BigNum arguments
let vkey_biguint = BigUint::parse_bytes(vkey_hash_str.as_bytes(), 16).expect("Failed to parse vkey");
let public_values_biguint = BigUint::parse_bytes(public_inputs.as_bytes(), 16).expect("Failed to parse public values");

let res = ffi::verify_plonk_bn254(
build_dir_str,
proof_str,
vkey_hash_str,
committed_values_digest_str,
&vkey_biguint.to_string(),
&public_values_biguint.to_string(),
);

// Call the actual function in sphinx_recursion_gnark_ffi
Expand All @@ -29,10 +65,7 @@ pub fn verify_plonk_bn254(

#[cfg(test)]
mod tests {
use ffi::verify_plonk_bn254;
use num_bigint::BigUint;
use serde::{Deserialize, Serialize};
use sha2::{Digest as _, Sha256};
use std::{
fs,
path::{Path, PathBuf},
Expand All @@ -58,12 +91,6 @@ mod tests {
entry.extension().and_then(|ext| ext.to_str()) == Some("json")
}

pub fn get_vkey_hash(build_dir: &Path) -> [u8; 32] {
let vkey_path = build_dir.join("vk.bin");
let vk_bin_bytes = std::fs::read(vkey_path).unwrap();
Sha256::digest(vk_bin_bytes).into()
}

const MIN_PROOF_LENGTH: usize = 3*64 + 192 + 160 + 64 + 32 + 64 + 64; // 768

#[test]
Expand All @@ -87,16 +114,6 @@ mod tests {
let fixture: SolidityFixture =
serde_json::from_str(&fixture_data).expect("Failed to deserialize fixture");

// Helper function to remove "0x" if present
fn strip_hex_prefix(hex: &str) -> &str {
hex.strip_prefix("0x").unwrap_or(hex)
}

// Parse vkey, public values, and proof after stripping "0x"
let vkey = strip_hex_prefix(&fixture.vkey);
let public_values = strip_hex_prefix(&fixture.public_values);
let proof = strip_hex_prefix(&fixture.proof);

// Sanity-check the proof length
// l_com: 64 bytes,
// r_com: 64 bytes,
Expand All @@ -110,29 +127,22 @@ mod tests {
// opening_at_zeta_omega_proof: 64 bytes,
// selector_commit_api_at_zeta: variable,
// wire_committed_commitments: variable,
assert!(proof.len() >= MIN_PROOF_LENGTH);

// Parse the BigNum arguments
let vkey_biguint = BigUint::parse_bytes(vkey.as_bytes(), 16).expect("Failed to parse vkey");
let public_values_biguint = BigUint::parse_bytes(public_values.as_bytes(), 16).expect("Failed to parse public values");

eprintln!("vkey: {:?}", vkey_biguint);
eprintln!("public_values: {:?}", public_values_biguint);
assert!(strip_hex_prefix(&fixture.proof).len() >= MIN_PROOF_LENGTH);

// Fetch the prover's asset directory
let build_dir = plonk_bn254_artifacts_dev_dir();
let result = verify_plonk_bn254(
let result = super::verify_plonk_bn254(
build_dir.to_str().unwrap(),
&proof,
&vkey_biguint.to_string(),
&public_values_biguint.to_string(),
&fixture.proof,
&fixture.vkey,
&fixture.public_values,
);

// Push the result of this verification to the results list
match result {
Ok(_) => results.push(Ok(())),
Err(e) => {
results.push(Err(format!("Verification failed for {:?}: {:?}", path, e)))
1 => results.push(Ok(())),
_ => {
results.push(Err(format!("Verification failed for {:?}", path)))
}
}

Expand Down
Loading