Skip to content

Commit

Permalink
update curve to use bn256
Browse files Browse the repository at this point in the history
  • Loading branch information
RoyTimes committed Aug 17, 2023
1 parent d0bbf61 commit 29efed3
Show file tree
Hide file tree
Showing 19 changed files with 285 additions and 182 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## halo2-jwt

Verify a JWT with Halo2!
Verify a JWT with Halo2!

## Run a Test

1. Install the Rust environment

2. Run `RUST_LOG=debug cargo run` to run a dev prover.

3. Update `halo2_jwt/src/main.rs` to modify the to-be-proved JWT & credential.
3 changes: 3 additions & 0 deletions halo2_jwt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ halo2_maingate = { package = "maingate", git = "https://github.com/privacy-scali
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" }
halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves', tag = "0.3.2" }

# snark-verifier = { git = "https://github.com/privacy-scaling-explorations/snark-verifier.git" }

ff = { version = "0.13", features = ["bits"] }
rand = "0.8"

log = "*"
env_logger = "*"
Expand Down
40 changes: 22 additions & 18 deletions halo2_jwt/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use halo2_proofs::{
circuit::{Layouter, SimpleFloorPlanner, Value},
plonk::{Circuit, ConstraintSystem, Error},
};
use halo2curves::pasta::pallas;
use halo2curves::bn256::Fr;

use crate::precompute::PreComputed;
use crate::sha256::{Table16Config, Table16Chip, Sha256};
Expand All @@ -26,9 +26,13 @@ impl JwtCircuit {
pub fn new(precomputed: PreComputed) -> Self {
Self { precomputed }
}

pub fn num_instance() -> Vec<usize> {
vec![18]
}
}

impl Circuit<pallas::Base> for JwtCircuit {
impl Circuit<Fr> for JwtCircuit {

type Config = JwtCircuitConfig;
type FloorPlanner = SimpleFloorPlanner;
Expand All @@ -37,14 +41,14 @@ impl Circuit<pallas::Base> for JwtCircuit {
Self::default()
}

fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
fn configure(meta: &mut ConstraintSystem<Fr>) -> Self::Config {
Self::Config {
sha256_config: Table16Chip::configure(meta),
maingate_config: MainGate::<pallas::Base>::configure(meta),
maingate_config: MainGate::<Fr>::configure(meta),
}
}

fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter<pallas::Base>) -> Result<(), Error> {
fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter<Fr>) -> Result<(), Error> {

/* START Pre-Constrained Zone */
let [preimage_jwt, preimage_credential] = self.precomputed.preimage_as_blockwords();
Expand All @@ -60,7 +64,7 @@ impl Circuit<pallas::Base> for JwtCircuit {
let sha256_chip = Table16Chip::construct(config.sha256_config.clone());
Table16Chip::load(config.sha256_config.clone(), &mut layouter.namespace(|| "table16_chip"))?;

let gate = MainGate::<pallas::Base>::new(config.maingate_config.clone());
let gate = MainGate::<Fr>::new(config.maingate_config.clone());
// digest + IV = expected_digest
let partial_digest_jwt = Sha256::digest(
sha256_chip.clone(),
Expand Down Expand Up @@ -94,12 +98,12 @@ impl Circuit<pallas::Base> for JwtCircuit {
// 1. load both JWTand Credential value into the constrain sys
let jwt_value = gate.assign_value(ctx,
preimage_jwt[segment_location_start].0
.map(|x| pallas::Base::from(x as u64))
.map(|x| Fr::from(x as u64))
)?;

let credential_value = gate.assign_value(ctx,
preimage_credential[0].0
.map(|x| pallas::Base::from(x as u64))
.map(|x| Fr::from(x as u64))
)?;

// 2. sub JWT to Credential -> to get 0x0102_0000 and convert to be_bits
Expand All @@ -123,10 +127,10 @@ impl Circuit<pallas::Base> for JwtCircuit {

let jwt_value = gate.assign_value(ctx,
preimage_jwt[segment_location_start + segment_offset].0
.map(|x| pallas::Base::from(x as u64)))?;
.map(|x| Fr::from(x as u64)))?;
let credential_value = gate.assign_value(ctx,
preimage_credential[segment_offset].0
.map(|x| pallas::Base::from(x as u64)))?;
.map(|x| Fr::from(x as u64)))?;


log::info!("{:?} {:?} {:?}", segment_offset, jwt_value, credential_value);
Expand All @@ -141,12 +145,12 @@ impl Circuit<pallas::Base> for JwtCircuit {

let jwt_value = gate.assign_value(ctx,
preimage_jwt[segment_location_end].0
.map(|x| pallas::Base::from(x as u64))
.map(|x| Fr::from(x as u64))
)?;

let credential_value = gate.assign_value(ctx,
preimage_credential[segment_offset].0
.map(|x| pallas::Base::from(x as u64))
.map(|x| Fr::from(x as u64))
)?;

// 2. sub JWT to Credential -> to get 0x0000_0304 and convert to be_bits
Expand All @@ -165,8 +169,8 @@ impl Circuit<pallas::Base> for JwtCircuit {
// assign segment_location_start and segment_location_end to the constrain
// awaiting to be exposed as public inputs
(
gate.assign_value(ctx, Value::known(pallas::Base::from(segment_start_offset as u64)))?,
gate.assign_value(ctx, Value::known(pallas::Base::from(segment_end_offset as u64)))?
gate.assign_value(ctx, Value::known(Fr::from(segment_start_offset as u64)))?,
gate.assign_value(ctx, Value::known(Fr::from(segment_end_offset as u64)))?
)
};

Expand All @@ -182,12 +186,12 @@ impl Circuit<pallas::Base> for JwtCircuit {
log::info!("[Constrained] Iterating SHA256 Proof at Loc {:?}", index);

// 1. assign digest to proof
let partial_digest_jwt = gate.assign_value(ctx, partial_digest_jwt.0[index].0.map(|x| pallas::Base::from(x as u64)))?;
let partial_digest_credential = gate.assign_value(ctx, partial_digest_credential.0[index].0.map(|x| pallas::Base::from(x as u64)))?;
let partial_digest_jwt = gate.assign_value(ctx, partial_digest_jwt.0[index].0.map(|x| Fr::from(x as u64)))?;
let partial_digest_credential = gate.assign_value(ctx, partial_digest_credential.0[index].0.map(|x| Fr::from(x as u64)))?;

// 2. assign expected digest
let expected_digest_jwt = gate.assign_value(ctx, expected_digest_jwt[index].0.map(|x| pallas::Base::from(x as u64)))?;
let expected_digest_credential = gate.assign_value(ctx, expected_digest_credential[index].0.map(|x| pallas::Base::from(x as u64)))?;
let expected_digest_jwt = gate.assign_value(ctx, expected_digest_jwt[index].0.map(|x| Fr::from(x as u64)))?;
let expected_digest_credential = gate.assign_value(ctx, expected_digest_credential[index].0.map(|x| Fr::from(x as u64)))?;

// 3. compare
gate.assert_equal(ctx, &partial_digest_jwt, &expected_digest_jwt)?;
Expand Down
146 changes: 131 additions & 15 deletions halo2_jwt/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,149 @@
// use halo2curves::bn256::{Bn256, Fq, Fr, G1Affine};
// use rand::rngs::OsRng;

// use halo2_proofs::{
// dev::MockProver,
// plonk::{
// create_proof, keygen_pk, keygen_vk, verify_proof, Circuit,
// ProvingKey, VerifyingKey,
// },
// poly::{
// commitment::{Params, ParamsProver},
// kzg::{
// commitment::{KZGCommitmentScheme, ParamsKZG},
// multiopen::{ProverGWC, VerifierGWC},
// strategy::AccumulatorStrategy,
// },
// VerificationStrategy,
// },
// transcript::{TranscriptReadBuffer, TranscriptWriterBuffer},
// };
// use snark_verifier::{
// loader::evm::{self, deploy_and_call, encode_calldata, EvmLoader},
// pcs::kzg::{Gwc19, KzgAs},
// system::halo2::{compile, transcript::evm::EvmTranscript, Config},
// verifier::{self, SnarkVerifier},
// };
// use std::rc::Rc;

// type PlonkVerifier = verifier::plonk::PlonkVerifier<KzgAs<Bn256, Gwc19>>;


use halo2_jwt::circuit::JwtCircuit;
use halo2_jwt::precompute::PreComputed;
use halo2_proofs::dev::MockProver;
use halo2curves::bn256::Fr;

fn main() {
use halo2_proofs::dev::MockProver;
// fn gen_srs(k: u32) -> ParamsKZG<Bn256> {
// ParamsKZG::<Bn256>::setup(k, OsRng)
// }

// fn gen_pk<C: Circuit<Fr>>(params: &ParamsKZG<Bn256>, circuit: &C) -> ProvingKey<G1Affine> {
// let vk = keygen_vk(params, circuit).unwrap();
// keygen_pk(params, vk, circuit).unwrap()
// }

// fn gen_proof<C: Circuit<Fr>>(
// params: &ParamsKZG<Bn256>,
// pk: &ProvingKey<G1Affine>,
// circuit: C,
// instances: Vec<Vec<Fr>>,
// ) -> Vec<u8> {
// MockProver::run(params.k(), &circuit, instances.clone())
// .unwrap()
// .assert_satisfied();

// let instances_ref = &instances
// .iter()
// .map(|instances| instances.as_slice())
// .collect::<Vec<_>>();

// let proof = {
// let mut transcript = TranscriptWriterBuffer::<_, G1Affine, _>::init(Vec::new());
// create_proof::<KZGCommitmentScheme<Bn256>, ProverGWC<_>, _, _, EvmTranscript<_, _, _, _>, _>(
// params,
// pk,
// &[circuit],
// &[instances_ref],
// OsRng,
// &mut transcript,
// )
// .unwrap();
// transcript.finalize()
// };

// let accept = {
// let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.as_slice());
// VerificationStrategy::<_, VerifierGWC<_>>::finalize(
// verify_proof::<_, VerifierGWC<_>, _, EvmTranscript<_, _, _, _>, _>(
// params.verifier_params(),
// pk.get_vk(),
// AccumulatorStrategy::new(params.verifier_params()),
// &[instances_ref],
// &mut transcript,
// )
// .unwrap(),
// )
// };
// assert!(accept);

// proof
// }

// fn gen_evm_verifier(
// params: &ParamsKZG<Bn256>,
// vk: &VerifyingKey<G1Affine>,
// num_instance: Vec<usize>,
// ) -> Vec<u8> {
// let protocol = compile(
// params,
// vk,
// Config::kzg().with_num_instance(num_instance.clone()),
// );
// let vk = (params.get_g()[0], params.g2(), params.s_g2()).into();

// let loader = EvmLoader::new::<Fq, Fr>();
// let protocol = protocol.loaded(&loader);
// let mut transcript = EvmTranscript::<_, Rc<EvmLoader>, _, _>::new(&loader);

// let instances = transcript.load_instances(num_instance);
// let proof = PlonkVerifier::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap();
// PlonkVerifier::verify(&vk, &protocol, &instances, &proof).unwrap();

// println!("Yul Code {:?}", loader.yul_code());
// evm::compile_yul(&loader.yul_code())
// }

// fn evm_verify(deployment_code: Vec<u8>, instances: Vec<Vec<Fr>>, proof: Vec<u8>) {
// let calldata = encode_calldata(&instances, &proof);

// println!("calldata len {:?}", calldata.len());
// let gas_cost = deploy_and_call(deployment_code, calldata).unwrap();
// dbg!(gas_cost);
// }

fn main() {
env_logger::init();
// ANCHOR: test-circuit
// The number of rows in our circuit cannot exceed 2^k. Since our example
// circuit is very small, we can pick a very small value here.
let k = 18;
let k = 17;
// let params = gen_srs(17);

// Instantiate the circuit with the private inputs.

let jwt = "{\"iss\":\"https://dev-9h47ajc9.us.au111th0.com/\",\"sub\":\"twitter|337834122\",\"aud\":\"123\",\"iat\":1639173028,\"exp\":1639209028,\"nonce\":\"44017a89\"}";
// let jwt = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaatwitter|337834122aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
let credential = "twitter|337834122";


// let jwt = "123456";
// let credential = "23";

let precomputed = PreComputed::new(jwt, credential);
let public_inputs = precomputed.public_inputs();
let circuit = JwtCircuit::new(precomputed);

// Given the correct public input, our circuit will verify.
let prover = MockProver::run(k, &circuit, vec![public_inputs]).expect("Circuit Construction Failed");
// let pk = gen_pk(&params, &circuit);
// let deployment_code = gen_evm_verifier(&params, pk.get_vk(), JwtCircuit::num_instance());

// println!("Deployment Code {:?}", deployment_code.len());
// let proof = gen_proof(&params, &pk, circuit.clone(), vec![public_inputs.clone()]);
// evm_verify(deployment_code, vec![public_inputs], proof);

// println!("{:?}", prover.err());
// Given the correct public input, our circuit will verify.
let prover: MockProver<Fr> = MockProver::run(k, &circuit, vec![public_inputs]).expect("Circuit Construction Failed");
assert_eq!(prover.verify(), Ok(()));

println!("Done!");
Expand Down
24 changes: 12 additions & 12 deletions halo2_jwt/src/precompute.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use halo2curves::pasta::{pallas, Fp};
use halo2curves::bn256::Fr;

use crate::sha256::BlockWord;
use crate::util::{find_subsequence_u8, pad_bytes_front_n_end, sha256_hash_bytes_digests, pad_sha256_bytes, bytes_to_u32_array, u32_array_to_blockwords};
Expand Down Expand Up @@ -56,8 +56,8 @@ impl PreComputed {
let padded_message_jwt = pad_sha256_bytes(&self.jwt_bytes);
let padded_message_credential = pad_sha256_bytes(&self.credential_bytes);

let u32_padded_jwt = bytes_to_u32_array(&padded_message_jwt, 0);
let u32_padded_credential = bytes_to_u32_array(&padded_message_credential, 0);
let u32_padded_jwt = bytes_to_u32_array(&padded_message_jwt);
let u32_padded_credential = bytes_to_u32_array(&padded_message_credential);

[
u32_array_to_blockwords(&u32_padded_jwt),
Expand All @@ -66,30 +66,30 @@ impl PreComputed {
}

pub fn expected_digest_as_blockwords(&self) -> [Vec<BlockWord>; 2] {
let digest_jwt = bytes_to_u32_array(&self.digest_jwt, 0);
let digest_credential = bytes_to_u32_array(&self.digest_credential, 0);
let digest_jwt = bytes_to_u32_array(&self.digest_jwt);
let digest_credential = bytes_to_u32_array(&self.digest_credential);

[
u32_array_to_blockwords(&digest_jwt),
u32_array_to_blockwords(&digest_credential),
]
}

pub fn public_inputs(&self) -> Vec<Fp> {
pub fn public_inputs(&self) -> Vec<Fr> {
let mut result = Vec::with_capacity(16);
let digest_jwt_u32 = bytes_to_u32_array(&self.digest_jwt, 0);
let digest_credential_u32 = bytes_to_u32_array(&self.digest_credential, 0);
let digest_jwt_u32 = bytes_to_u32_array(&self.digest_jwt);
let digest_credential_u32 = bytes_to_u32_array(&self.digest_credential);

for i in 0..8 {
result.push(pallas::Base::from(digest_jwt_u32[i] as u64));
result.push(Fr::from(digest_jwt_u32[i] as u64));
}

for i in 0..8 {
result.push(pallas::Base::from(digest_credential_u32[i] as u64));
result.push(Fr::from(digest_credential_u32[i] as u64));
}

result.push(pallas::Base::from(self.segment_start_offset as u64));
result.push(pallas::Base::from(self.segment_end_offset as u64));
result.push(Fr::from(self.segment_start_offset as u64));
result.push(Fr::from(self.segment_end_offset as u64));

result
}
Expand Down
Loading

0 comments on commit 29efed3

Please sign in to comment.