Files
Sunscreen/sunscreen/tests/linked.rs
2023-10-25 16:20:20 -06:00

119 lines
3.9 KiB
Rust

#[cfg(feature = "linkedproofs")]
mod linked_tests {
use logproof::test::seal_bfv_encryption_linear_relation;
use sunscreen::Error;
use sunscreen::{
types::zkp::{ConstrainCmp, Field, FieldSpec, ProgramNode},
zkp_program, zkp_var, Compiler,
};
use sunscreen_runtime::LinkedProof;
use logproof::rings::SealQ128_1024;
use sunscreen_zkp_backend::bulletproofs::BulletproofsBackend;
// We copy the sunscreen_zkp_backend::bulletproofs::BulletproofsField type here
// because we can't import it directly from sunscreen_zkp_backend without
// enabling the "bulletproofs" feature
type BulletproofsField =
Field<<sunscreen_zkp_backend::bulletproofs::BulletproofsBackend as sunscreen_zkp_backend::ZkpBackend>::Field>;
/// Convert a twos complement represented signed integer into a field element.
fn from_twos_complement_field_element<F: FieldSpec, const N: usize>(
x: [ProgramNode<Field<F>>; N],
) -> ProgramNode<Field<F>> {
let mut x_recon = zkp_var!(0);
for (i, x_i) in x.iter().enumerate().take(N - 1) {
x_recon = x_recon + (zkp_var!(2i64.pow(i as u32)) * (*x_i));
}
x_recon = x_recon + zkp_var!(-(2i64.pow((N - 1) as u32))) * x[N - 1];
x_recon
}
#[zkp_program]
fn valid_transaction<F: FieldSpec>(#[private] x: [Field<F>; 15], #[public] balance: Field<F>) {
let lower_bound = zkp_var!(0);
// Reconstruct x from the bag of bits
let x_recon = from_twos_complement_field_element(x);
// Constraint that x is less than or equal to balance
balance.constrain_ge_bounded(x_recon, 64);
// Constraint that x is greater than or equal to zero
lower_bound.constrain_le_bounded(x_recon, 64);
}
#[test]
fn test_validated_transaction_example() -> Result<(), Error> {
let app = Compiler::new()
.zkp_backend::<BulletproofsBackend>()
.zkp_program(valid_transaction)
.compile()?;
// Compile the ZKP program
let valid_transaction_zkp = app.get_zkp_program(valid_transaction).unwrap();
let balance = 1u64;
// Try valid cases
for k in 0..=balance {
let x = k;
// Generate the SDLP linear relation and specify that the message part of S
// should be shared.
let sdlp =
seal_bfv_encryption_linear_relation::<SealQ128_1024, 1>(x, 1024, 12289, false);
let shared_indices = vec![(0, 0)];
println!("Performing linked proof");
let lp = LinkedProof::create(
&sdlp,
&shared_indices,
valid_transaction_zkp,
vec![],
vec![BulletproofsField::from(balance)],
vec![],
)
.unwrap();
println!("Linked proof done");
println!("Performing linked verify");
lp.verify(
valid_transaction_zkp,
vec![BulletproofsField::from(balance)],
vec![],
)
.expect("Failed to verify linked proof");
println!("Linked verify done");
}
// Try an invalid case
{
let x = balance + 1;
// Generate the SDLP linear relation and specify that the message part of S
// should be shared.
let sdlp =
seal_bfv_encryption_linear_relation::<SealQ128_1024, 1>(x, 1024, 12289, false);
let shared_indices = vec![(0, 0)];
println!("Proof should fail");
let lp = LinkedProof::create(
&sdlp,
&shared_indices,
valid_transaction_zkp,
vec![],
vec![BulletproofsField::from(balance)],
vec![],
);
assert!(lp.is_err());
}
Ok(())
}
}