Skip to content

Commit

Permalink
feat: sxg verification
Browse files Browse the repository at this point in the history
  • Loading branch information
0xVikasRushi committed Oct 13, 2024
1 parent fdde55a commit 11e7b72
Show file tree
Hide file tree
Showing 8 changed files with 880 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

Binary file modified elf/riscv32im-succinct-zkvm-elf
Binary file not shown.
630 changes: 630 additions & 0 deletions lib/src/constants.rs

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub mod constants;
pub mod sxg;

use alloy_sol_types::sol;
use p256::ecdsa::{signature::Verifier, Signature, VerifyingKey};
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -43,8 +46,31 @@ pub fn verify_ecdsa_p256_signature(
Ok(verifying_key.verify(message, &signature).is_ok())
}

pub fn verify_ecdsa_p256_r_s(
message: &[u8],
r: &[u8; 32],
s: &[u8; 32],
px: &[u8; 32],
py: &[u8; 32],
) -> Result<bool, Box<dyn std::error::Error>> {
let mut signature_bytes = [0u8; 64];
signature_bytes[..32].copy_from_slice(r);
signature_bytes[32..].copy_from_slice(s);
let signature = Signature::from_slice(&signature_bytes)?;

let mut public_key_bytes = [4u8; 65];
public_key_bytes[1..33].copy_from_slice(px);
public_key_bytes[33..].copy_from_slice(py);

let verifying_key = VerifyingKey::from_sec1_bytes(&public_key_bytes)?;

Ok(verifying_key.verify(message, &signature).is_ok())
}

#[cfg(test)]
mod tests {
use constants::FINAL_PAYLOAD;

use super::*;

#[test]
Expand All @@ -57,4 +83,36 @@ mod tests {
let result = verify_ecdsa_p256_signature(message, signature_hex, public_key_hex);
assert!(result.unwrap());
}

#[test]
fn test_verify_ecdsa_p256_r_s() {
let px1 = "45E3943B0705F9EF69B53A4EFB8C668E6A9F90124E9BCF917662CFADEA56C0C1";
let py1 = "F3703834F92F6FE70A004BA4098D079BFB5F927E042991EFD5A1572E8F9D39D6";

let r1 = "9970818CBCA38C196795EEAD295BDED48311702DF7DDB0C2BB448276894C393D";
let s1 = "729B2F9229D545A553F0F7CBC1792E9A6185E539DBF667FE5BC38D673D90C014";

let r: [u8; 32] = hex::decode(r1).unwrap().try_into().unwrap();
let s: [u8; 32] = hex::decode(s1).unwrap().try_into().unwrap();
let px: [u8; 32] = hex::decode(px1).unwrap().try_into().unwrap();
let py: [u8; 32] = hex::decode(py1).unwrap().try_into().unwrap();

let result0 = verify_ecdsa_p256_r_s(FINAL_PAYLOAD, &r, &s, &px, &py).unwrap();
assert!(result0);

let r_hex = "6a7570a91dd49c4ff738efd81ceaadbf89daad02611d184e276906eeb3671225";
let s_hex = "4ff40cda556ed67ef04b3933e2e92830b6cfae684da605f07f779fad78945e22";
let px_hex = "57be97dd389c893d7271a1fe7546aaf09074aba40779d19c21c00832bc3f821a";
let py_hex = "dd286faf7beb2f0722050169d89ae7fe0b02e8b8bea4c5141b188ff678e6d8bf";
let message1 =
b"ECDSA proves knowledge of a secret number in the context of a single message";

let r: [u8; 32] = hex::decode(r_hex).unwrap().try_into().unwrap();
let s: [u8; 32] = hex::decode(s_hex).unwrap().try_into().unwrap();
let px: [u8; 32] = hex::decode(px_hex).unwrap().try_into().unwrap();
let py: [u8; 32] = hex::decode(py_hex).unwrap().try_into().unwrap();

let result1 = verify_ecdsa_p256_r_s(message1, &r, &s, &px, &py).unwrap();
assert!(result1);
}
}
151 changes: 151 additions & 0 deletions lib/src/sxg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use crate::{sha256_hash, verify_ecdsa_p256_r_s};

pub struct SXGInput {
pub final_payload: Vec<u8>,
pub data_to_verify: Vec<u8>,
pub data_to_verify_start_index: usize,
pub integrity_start_index: usize,
pub payload: Vec<u8>,
pub r: [u8; 32],
pub s: [u8; 32],
pub px: [u8; 32],
pub py: [u8; 32],
}

fn calculate_integrity(input: &[u8], record_size: usize) -> [u8; 32] {
if input.is_empty() {
return sha256_hash(&[]);
}

let actual_record_size = record_size.min(input.len());
let mut records: Vec<&[u8]> = Vec::new();
let mut i = 0;

while i < input.len() {
let chunk_size = (i + actual_record_size).min(input.len()) - i;
records.push(&input[i..i + chunk_size]);
i += actual_record_size;
}

let mut proofs: Vec<[u8; 32]> = Vec::new();
for record in records.into_iter().rev() {
let mut to_hash = Vec::from(record);
if !proofs.is_empty() {
to_hash.extend_from_slice(&proofs[0]);
to_hash.push(1);
} else {
to_hash.push(0);
}
let hash_result = sha256_hash(&to_hash);
proofs.insert(0, hash_result);
}

proofs[0]
}

fn base64_encode_mice(input: &[u8]) -> String {
let base64_chars: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let mut result = String::from("mi-sha256-03=");
let mut i = 0;

while i < input.len() {
let n = if i + 3 <= input.len() {
((input[i] as u32) << 16) | ((input[i + 1] as u32) << 8) | (input[i + 2] as u32)
} else if i + 2 == input.len() {
((input[i] as u32) << 16) | ((input[i + 1] as u32) << 8)
} else {
(input[i] as u32) << 16
};

result.push(base64_chars[((n >> 18) & 63) as usize] as char);
result.push(base64_chars[((n >> 12) & 63) as usize] as char);

if i + 1 < input.len() {
result.push(base64_chars[((n >> 6) & 63) as usize] as char);
} else {
result.push('=');
}

if i + 2 < input.len() {
result.push(base64_chars[(n & 63) as usize] as char);
} else {
result.push('=');
}

i += 3;
}

result
}

pub fn sxg_verify(input: SXGInput) -> Result<bool, Box<dyn std::error::Error>> {
let SXGInput {
final_payload,
data_to_verify,
data_to_verify_start_index,
integrity_start_index,
payload,
r,
s,
px,
py,
} = input;

if payload[data_to_verify_start_index..data_to_verify_start_index + data_to_verify.len()]
!= data_to_verify
{
return Ok(false);
}

let mice = base64_encode_mice(&calculate_integrity(&payload, 16384));
let mice_bytes = mice.as_bytes();

if final_payload[integrity_start_index..integrity_start_index + mice_bytes.len()]
!= mice_bytes[..]
{
return Ok(false);
}

Ok(verify_ecdsa_p256_r_s(&final_payload, &r, &s, &px, &py).is_ok())
}

#[cfg(test)]
mod tests {
use crate::constants::{DATA_TO_VERIFY, FINAL_PAYLOAD, PAYLOAD};

#[test]
fn test_sxg() {
let final_payload = FINAL_PAYLOAD;
let data_to_verify = DATA_TO_VERIFY;
let payload = PAYLOAD;

let data_to_verify_start_index = 0;
let integrity_start_index = 694 / 2;

let px = "45E3943B0705F9EF69B53A4EFB8C668E6A9F90124E9BCF917662CFADEA56C0C1";
let py = "F3703834F92F6FE70A004BA4098D079BFB5F927E042991EFD5A1572E8F9D39D6";

let r = "9970818CBCA38C196795EEAD295BDED48311702DF7DDB0C2BB448276894C393D";
let s = "729B2F9229D545A553F0F7CBC1792E9A6185E539DBF667FE5BC38D673D90C014";

let r = hex::decode(r).unwrap();
let s = hex::decode(s).unwrap();

let px = hex::decode(px).unwrap();
let py = hex::decode(py).unwrap();

let input = super::SXGInput {
final_payload: final_payload.to_vec(),
data_to_verify: data_to_verify.to_vec(),
data_to_verify_start_index,
integrity_start_index,
payload: payload.to_vec(),
r: r.try_into().unwrap(),
s: s.try_into().unwrap(),
px: px.try_into().unwrap(),
py: py.try_into().unwrap(),
};

assert!(super::sxg_verify(input).unwrap());
}
}
1 change: 1 addition & 0 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ edition = "2021"
alloy-sol-types = { workspace = true }
sp1-zkvm = "2.0.0"
fibonacci-lib = { path = "../lib" }
hex = "0.4.3"
42 changes: 35 additions & 7 deletions program/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
sp1_zkvm::entrypoint!(main);

use alloy_sol_types::SolType;
use fibonacci_lib::{fibonacci, sha256_hash, verify_ecdsa_p256_signature, PublicValuesStruct};
use fibonacci_lib::constants::{DATA_TO_VERIFY, FINAL_PAYLOAD, PAYLOAD};

use fibonacci_lib::sxg::{sxg_verify, SXGInput};
use fibonacci_lib::{fibonacci, sha256_hash, verify_ecdsa_p256_signature, PublicValuesStruct};
use hex;
pub fn main() {
// Read an input to the program.
//
Expand All @@ -19,15 +22,40 @@ pub fn main() {

let n = sp1_zkvm::io::read::<u32>();

let sha256_hash = sha256_hash(&[1, 11]);
let (a, b) = fibonacci(n);

let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
let public_key_hex = "0457be97dd389c893d7271a1fe7546aaf09074aba40779d19c21c00832bc3f821add286faf7beb2f0722050169d89ae7fe0b02e8b8bea4c5141b188ff678e6d8bf";
let signature_hex = "6a7570a91dd49c4ff738efd81ceaadbf89daad02611d184e276906eeb36712254ff40cda556ed67ef04b3933e2e92830b6cfae684da605f07f779fad78945e22";
let final_payload = FINAL_PAYLOAD;
let data_to_verify = DATA_TO_VERIFY;
let payload = PAYLOAD;

let result = verify_ecdsa_p256_signature(message, signature_hex, public_key_hex);
let data_to_verify_start_index = 0;
let integrity_start_index = 694 / 2;

let (a, b) = fibonacci(n);
let px = "45E3943B0705F9EF69B53A4EFB8C668E6A9F90124E9BCF917662CFADEA56C0C1";
let py = "F3703834F92F6FE70A004BA4098D079BFB5F927E042991EFD5A1572E8F9D39D6";

let r = "9970818CBCA38C196795EEAD295BDED48311702DF7DDB0C2BB448276894C393D";
let s = "729B2F9229D545A553F0F7CBC1792E9A6185E539DBF667FE5BC38D673D90C014";

let r = hex::decode(r).unwrap();
let s = hex::decode(s).unwrap();

let px = hex::decode(px).unwrap();
let py = hex::decode(py).unwrap();

let input = SXGInput {
final_payload: final_payload.to_vec(),
data_to_verify: data_to_verify.to_vec(),
data_to_verify_start_index,
integrity_start_index,
payload: payload.to_vec(),
r: r.try_into().unwrap(),
s: s.try_into().unwrap(),
px: px.try_into().unwrap(),
py: py.try_into().unwrap(),
};

let result = sxg_verify(input).unwrap();

// Encode the public values of the program.
let bytes = PublicValuesStruct::abi_encode(&PublicValuesStruct { n, a, b });
Expand Down
5 changes: 4 additions & 1 deletion script/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ struct Args {
}

fn main() {
// Setup the logger.
sp1_sdk::utils::setup_logger();

// Parse the command line arguments.
Expand Down Expand Up @@ -84,6 +83,10 @@ fn main() {

println!("Successfully generated proof!");

proof
.save("proof-with-io.json")
.expect("saving proof failed");

// Verify the proof.
client.verify(&proof, &vk).expect("failed to verify proof");
println!("Successfully verified proof!");
Expand Down

0 comments on commit 11e7b72

Please sign in to comment.