From ed8b8bce42b5d6f9ed6bcb3bb2a9c1343ca7278b Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Sun, 6 Oct 2024 12:45:24 +0000 Subject: [PATCH 01/14] Update 'journal_digest' to 'journal' --- .../groth16_contract_generator/calldata.py | 2 +- .../generator_risc0.py | 2 +- .../groth16_contract_generator/parsing_utils.py | 16 ++++++++-------- .../src/groth16_verifier.cairo | 2 +- src/src/utils/calldata.cairo | 12 ++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/calldata.py b/hydra/garaga/starknet/groth16_contract_generator/calldata.py index b540beaa..5c768462 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/calldata.py +++ b/hydra/garaga/starknet/groth16_contract_generator/calldata.py @@ -32,7 +32,7 @@ def groth16_calldata_from_vk_and_proof( calldata.extend(proof.serialize_to_calldata()) calldata.extend(mpc.serialize_to_calldata()) - if proof.image_id and proof.journal_digest: + if proof.image_id and proof.journal: # Risc0 mode. print("Risc0 mode") msm = MSMCalldataBuilder( diff --git a/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py b/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py index a0d48e4d..13fbf1fb 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py +++ b/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py @@ -93,7 +93,7 @@ def gen_risc0_groth16_verifier( let groth16_proof = fph.groth16_proof; let image_id = fph.image_id; - let journal_digest = fph.journal_digest; + let journal_digest = fph.journal; let mpcheck_hint = fph.mpcheck_hint; let small_Q = fph.small_Q; let msm_hint = fph.msm_hint; diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index 93134f7a..ba0b3f23 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -304,7 +304,7 @@ class Groth16Proof: public_inputs: List[int] = dataclasses.field(default_factory=list) curve_id: CurveID = None image_id: bytes = None # Only used for risc0 proofs - journal_digest: bytes = None # Only used for risc0 proofs + journal: bytes = None # Only used for risc0 proofs def __post_init__(self): assert ( @@ -424,7 +424,7 @@ def _from_risc0( BN254_CONTROL_ID, ], image_id=image_id, - journal_digest=journal_digest, + journal=journal, ) def serialize_to_calldata(self) -> list[int]: @@ -437,21 +437,21 @@ def serialize_to_calldata(self) -> list[int]: cd.extend(io.bigint_split(self.b.y[1])) cd.extend(io.bigint_split(self.c.x)) cd.extend(io.bigint_split(self.c.y)) - if self.image_id and self.journal_digest: + if self.image_id and self.journal: # Risc0 mode. - # Public inputs will be reconstructed from image id and journal digest. + # Public inputs will be reconstructed from image id and journal. image_id_u256 = io.bigint_split( int.from_bytes(self.image_id, "big"), 8, 2**32 )[::-1] - journal_digest_u256 = io.bigint_split( - int.from_bytes(self.journal_digest, "big"), 8, 2**32 + journal_u256 = io.bigint_split( + int.from_bytes(self.journal, "big"), 8, 2**32 )[::-1] # Span of u32, length 8. cd.append(8) cd.extend(image_id_u256) # Span of u32, length 8. - cd.append(8) - cd.extend(journal_digest_u256) + cd.append(8) # TODO Expand to more length + cd.extend(journal_u256) else: cd.append(len(self.public_inputs)) for pub in self.public_inputs: diff --git a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo index 9032567f..01107e7f 100644 --- a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo +++ b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo @@ -35,7 +35,7 @@ mod Risc0Groth16VerifierBN254 { let groth16_proof = fph.groth16_proof; let image_id = fph.image_id; - let journal_digest = fph.journal_digest; + let journal_digest = fph.journal; let mpcheck_hint = fph.mpcheck_hint; let small_Q = fph.small_Q; let msm_hint = fph.msm_hint; diff --git a/src/src/utils/calldata.cairo b/src/src/utils/calldata.cairo index 3d001ee3..5296571a 100644 --- a/src/src/utils/calldata.cairo +++ b/src/src/utils/calldata.cairo @@ -24,7 +24,7 @@ struct FullProofWithHintsBLS12_381 { struct FullProofWithHintsRisc0 { groth16_proof: Groth16ProofRaw, image_id: Span, - journal_digest: Span, + journal: Span, mpcheck_hint: MPCheckHintBN254, small_Q: E12DMulQuotient, msm_hint: Array, @@ -117,11 +117,11 @@ fn deserialize_full_proof_with_hints_risc0( image_id.append((*serialized.pop_front().unwrap()).try_into().unwrap()); }; - let n_journal_digest: u32 = (*serialized.pop_front().unwrap()).try_into().unwrap(); - let mut journal_digest: Array = array![]; + let n_journal: u32 = (*serialized.pop_front().unwrap()).try_into().unwrap(); + let mut journal: Array = array![]; for _ in 0 - ..n_journal_digest { - journal_digest.append((*serialized.pop_front().unwrap()).try_into().unwrap()); + ..n_journal { + journal.append((*serialized.pop_front().unwrap()).try_into().unwrap()); }; let groth16_proof = Groth16ProofRaw { a: a, b: b, c: c }; @@ -429,7 +429,7 @@ fn deserialize_full_proof_with_hints_risc0( return FullProofWithHintsRisc0 { groth16_proof: groth16_proof, image_id: image_id.span(), - journal_digest: journal_digest.span(), + journal: journal.span(), mpcheck_hint: mpcheck_hint, small_Q: small_Q, msm_hint: msm_hint From db6d316b5f152ddaf06f0fa691b028f1611391b1 Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Tue, 8 Oct 2024 09:03:15 +0000 Subject: [PATCH 02/14] Simplified receipt serialization works --- .../parsing_utils.py | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index ba0b3f23..0cf52be1 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -1,7 +1,9 @@ import dataclasses import hashlib import json +import math import os +import struct from pathlib import Path from typing import Any, List @@ -387,11 +389,23 @@ def _from_risc0( CONTROL_ROOT: int = RISC0_CONTROL_ROOT, BN254_CONTROL_ID: int = RISC0_BN254_CONTROL_ID, ) -> "Groth16Proof": - assert len(image_id) <= 32, "image_id must be 32 bytes" CONTROL_ROOT_0, CONTROL_ROOT_1 = split_digest(CONTROL_ROOT) proof = seal[4:] + + padded_journal = journal + b"\x00\x00\x00" + journal_buf = struct.unpack( + ">" + "I" * (len(padded_journal) // 4), padded_journal + ) + print("Journal: \t\t", journal_buf) + journal_digest = hashlib.sha256(journal).digest() + padded_journal_digest = hashlib.sha256(padded_journal).digest() + journal_digest_buf = struct.unpack( + ">" + "I" * (len(padded_journal_digest) // 4), padded_journal_digest + ) + print("Journal digest: \t", journal_digest_buf) + claim_digest = ok(image_id, journal_digest).digest() claim0, claim1 = split_digest(claim_digest) return Groth16Proof( @@ -443,15 +457,20 @@ def serialize_to_calldata(self) -> list[int]: image_id_u256 = io.bigint_split( int.from_bytes(self.image_id, "big"), 8, 2**32 )[::-1] - journal_u256 = io.bigint_split( - int.from_bytes(self.journal, "big"), 8, 2**32 - )[::-1] + padded_journal = self.journal + b"\x00\x00\x00" + journal = [] + start_byte = 0 + for end_byte in range(4, len(padded_journal) + 1, 4): + next_uint32 = int.from_bytes(padded_journal[start_byte:end_byte], "big") + journal.append(next_uint32) + start_byte = end_byte + print("Serialized journal: \t", journal) # Span of u32, length 8. cd.append(8) cd.extend(image_id_u256) - # Span of u32, length 8. - cd.append(8) # TODO Expand to more length - cd.extend(journal_u256) + # List of u32, length is dynamic + cd.append(math.ceil(len(self.journal) / 4)) + cd.extend(journal) else: cd.append(len(self.public_inputs)) for pub in self.public_inputs: From 854ffe345ebf3cb229ad3ffcdbe03bbad526ee34 Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Wed, 9 Oct 2024 00:22:30 +0000 Subject: [PATCH 03/14] Included big endian padding functionality + tests --- src/src/utils/risc0.cairo | 105 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/src/utils/risc0.cairo b/src/src/utils/risc0.cairo index f7acfd67..01638746 100644 --- a/src/src/utils/risc0.cairo +++ b/src/src/utils/risc0.cairo @@ -33,6 +33,72 @@ fn uint256_byte_reverse(x: u256) -> u256 { let new_high = integer::u128_byte_reverse(x.low); return u256 { low: new_low, high: new_high }; } + +pub fn journal_sha256(journal: Span) -> Span { + let mut journal_digest_array: Array = array![]; + journal_digest_array.append_span(journal); + + println!("Journal: {:?}", journal); + + let journal_digest = compute_sha256_u32_array( + input: journal_digest_array, last_input_word: 0, last_input_num_bytes: 0 + ); + + println!("Journal digest{:?}", journal_digest); + return journal_digest.span(); +} + +mod byte_operations { + #[derive(Copy, Drop)] + pub enum Padding { // Denominates the size of padding in bytes + One, + Two, + Three + } + + pub trait TPaddingU32> { + fn result_bitmap(self: @Padding) -> U; + fn rest_bitmap(self: @Padding) -> U; + fn turn_to_size(self: @Padding) -> U; + fn pad_big_endian(self: @Padding, to_be_padded: U, padding: U) -> (U, U); + } + + pub impl ByteOperations of TPaddingU32 { + #[inline] + fn result_bitmap(self: @Padding) -> u32 { + return match self { + Padding::One => 0x00FFFFFF, + Padding::Two => 0x0000FFFF, + Padding::Three => 0x000000FF + }; + } + + #[inline] + fn rest_bitmap(self: @Padding) -> u32 { + return 0xFFFFFFFF ^ self.result_bitmap(); + } + + fn turn_to_size(self: @Padding) -> u32 { + match self { + Padding::One => 1, + Padding::Two => 2, + Padding::Three => 3, + } + } + + fn pad_big_endian(self: @Padding, to_be_padded: u32, padding: u32) -> (u32, u32) { + let result_bitmap: u32 = self.result_bitmap(); + let rest_bitmap: u32 = self.rest_bitmap(); + if padding != padding & rest_bitmap { + panic_with_felt252('Padding is too long!'); + } + let padded_result: u32 = to_be_padded & result_bitmap | padding; + let rest: u32 = to_be_padded & rest_bitmap; + return (padded_result, rest); + } + } +} + // https://github.com/risc0/risc0-ethereum/blob/34d2fee4ca6b5fb354a8a1a00c43f8945097bfe5/contracts/src/IRiscZeroVerifier.sol#L71-L98 pub fn compute_receipt_claim(image_id: Span, journal_digest: Span) -> u256 { usize_assert_eq(image_id.len(), 8); @@ -115,6 +181,8 @@ fn output_digest(journal_digest: Span) -> [u32; 8] { #[cfg(test)] mod risc0_utils_tests { use super::{compute_receipt_claim, output_digest, uint256_byte_reverse}; + use super::byte_operations::{Padding, TPaddingU32}; + #[test] fn test_receipt_claim() { let image_id: [u32; 8] = [ @@ -170,4 +238,41 @@ mod risc0_utils_tests { ] ); } + #[test] + fn test_pad_big_endian() { + let inputs: [u32; 3] = [0xFFFFFFFF, 0x11111111, 0x550055AA]; + let paddings: [Padding; 3] = [Padding::One, Padding::Two, Padding::Three,]; + let mut out = array![]; + for i in inputs + .span() { + let mut out_inner_array = array![]; + for p in paddings + .span() { + let mut input = *i; + let (padded_result, rest) = p.pad_big_endian(input, 0xCC000000); + out_inner_array.append((padded_result, rest)); + println!( + "For padding {:?} we are getting \n\tresult: {:?} \n\trest: {:?}", + TPaddingU32::::turn_to_size(p), + padded_result, + rest + ); + }; + out.append(out_inner_array); + }; + assert_eq!( + out, + array![ + array![ + (0xCCFFFFFF, 0xFF000000), (0xCC00FFFF, 0xFFFF0000), (0xCC0000FF, 0xFFFFFF00), + ], + array![ + (0xCC111111, 0x11000000), (0xCC001111, 0x11110000), (0xCC000011, 0x11111100), + ], + array![ + (0xCC0055AA, 0x55000000), (0xCC0055AA, 0x55000000), (0xCC0000AA, 0x55005500), + ] + ] + ); + } } From 138dd8f57bd768b3dd4bbfd1479b28cdb3dc5cc9 Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Wed, 9 Oct 2024 15:25:42 +0000 Subject: [PATCH 04/14] Added pad_big_endian_array function + tests --- src/src/utils/risc0.cairo | 40 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/src/utils/risc0.cairo b/src/src/utils/risc0.cairo index 01638746..e84bf110 100644 --- a/src/src/utils/risc0.cairo +++ b/src/src/utils/risc0.cairo @@ -61,6 +61,7 @@ mod byte_operations { fn rest_bitmap(self: @Padding) -> U; fn turn_to_size(self: @Padding) -> U; fn pad_big_endian(self: @Padding, to_be_padded: U, padding: U) -> (U, U); + fn pad_big_endian_array(self: @Padding, array: Array) -> Array; } pub impl ByteOperations of TPaddingU32 { @@ -96,6 +97,19 @@ mod byte_operations { let rest: u32 = to_be_padded & rest_bitmap; return (padded_result, rest); } + + fn pad_big_endian_array(self: @Padding, array: Array) -> Array { + let mut res = 0; + let mut pad = 0; + let mut padded_array: Array = array![]; + for i in array { + let (result, padding) = self.pad_big_endian(i, pad); + res = result; + pad = padding; + padded_array.append(result); + }; + return padded_array; + } } } @@ -248,8 +262,7 @@ mod risc0_utils_tests { let mut out_inner_array = array![]; for p in paddings .span() { - let mut input = *i; - let (padded_result, rest) = p.pad_big_endian(input, 0xCC000000); + let (padded_result, rest) = p.pad_big_endian(*i, 0xCC000000); out_inner_array.append((padded_result, rest)); println!( "For padding {:?} we are getting \n\tresult: {:?} \n\trest: {:?}", @@ -275,4 +288,27 @@ mod risc0_utils_tests { ] ); } + + #[test] + fn test_pad_big_endian_array() { + let inputs: Array = array![0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC]; + { + let inputs = inputs; + let p = Padding::One; + let out = p.pad_big_endian_array(inputs); + assert_eq!(out, array![0x00AAAAAA, 0xAABBBBBB, 0xBBCCCCCC]); + } + let inputs2: Array = array![0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC]; + { + let p = Padding::Two; + let out = p.pad_big_endian_array(inputs2); + assert_eq!(out, array![0x0000AAAA, 0xAAAABBBB, 0xBBBBCCCC]); + } + let inputs3: Array = array![0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC]; + { + let p = Padding::Three; + let out = p.pad_big_endian_array(inputs3); + assert_eq!(out, array![0x000000AA, 0xAAAAAABB, 0xBBBBBBCC]); + } + } } From 592a31a3bb0fcbc2bc8e4eb1d323a0f363d9bb2f Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Thu, 10 Oct 2024 14:04:36 +0000 Subject: [PATCH 05/14] The Cairo part is working with hardcoded values --- src/src/utils/risc0.cairo | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/src/utils/risc0.cairo b/src/src/utils/risc0.cairo index e84bf110..7a8d7b4a 100644 --- a/src/src/utils/risc0.cairo +++ b/src/src/utils/risc0.cairo @@ -1,5 +1,6 @@ use core::sha256::compute_sha256_u32_array; use garaga::utils::usize_assert_eq; +use byte_operations::{Padding, ByteOperations}; // sha256(b"risc0.ReceiptClaim") = @@ -34,18 +35,26 @@ fn uint256_byte_reverse(x: u256) -> u256 { return u256 { low: new_low, high: new_high }; } -pub fn journal_sha256(journal: Span) -> Span { - let mut journal_digest_array: Array = array![]; - journal_digest_array.append_span(journal); +pub fn journal_sha256(ref journal: Span) -> Span { + let mut journal_arr: Array = array![]; - println!("Journal: {:?}", journal); + let last_input_word: u32 = *(journal.pop_back().unwrap()); + + journal_arr.append_span(journal); + + println!("Original Journal: {:?}\twith last_input_word: {:?}", journal_arr, last_input_word); + + // let journal = byte_operations::Padding::Three.pad_big_endian_array(journal_digest_array); + + // println!("Padded Journal: {:?}", journal); let journal_digest = compute_sha256_u32_array( - input: journal_digest_array, last_input_word: 0, last_input_num_bytes: 0 + input: journal_arr, last_input_word: last_input_word, last_input_num_bytes: 1 ); println!("Journal digest{:?}", journal_digest); return journal_digest.span(); + // return journal.span(); } mod byte_operations { From b923d22ab9ad0ecda61830c2e80dfc7afd4b79af Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Thu, 10 Oct 2024 14:05:27 +0000 Subject: [PATCH 06/14] The python part is wokring --- .../parsing_utils.py | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index 0cf52be1..5d230535 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -1,7 +1,6 @@ import dataclasses import hashlib import json -import math import os import struct from pathlib import Path @@ -392,19 +391,19 @@ def _from_risc0( assert len(image_id) <= 32, "image_id must be 32 bytes" CONTROL_ROOT_0, CONTROL_ROOT_1 = split_digest(CONTROL_ROOT) proof = seal[4:] - - padded_journal = journal + b"\x00\x00\x00" + number_of_zero_bytes = 0 if len(journal) % 4 == 0 else (4 - len(journal) % 4) + padded_journal = b"\x00" * number_of_zero_bytes + journal journal_buf = struct.unpack( ">" + "I" * (len(padded_journal) // 4), padded_journal ) - print("Journal: \t\t", journal_buf) + print("Padded Journal: \t\t", journal_buf) journal_digest = hashlib.sha256(journal).digest() - padded_journal_digest = hashlib.sha256(padded_journal).digest() - journal_digest_buf = struct.unpack( - ">" + "I" * (len(padded_journal_digest) // 4), padded_journal_digest + journal_digest_array = struct.unpack( + ">" + "I" * (len(journal_digest) // 4), journal_digest ) - print("Journal digest: \t", journal_digest_buf) + print("Journal digest: \t", journal_digest_array) + # print("Journal digest: \t", journal_digest) claim_digest = ok(image_id, journal_digest).digest() claim0, claim1 = split_digest(claim_digest) @@ -457,19 +456,25 @@ def serialize_to_calldata(self) -> list[int]: image_id_u256 = io.bigint_split( int.from_bytes(self.image_id, "big"), 8, 2**32 )[::-1] - padded_journal = self.journal + b"\x00\x00\x00" journal = [] start_byte = 0 - for end_byte in range(4, len(padded_journal) + 1, 4): - next_uint32 = int.from_bytes(padded_journal[start_byte:end_byte], "big") + # round up to the nearest multiple of 4 + for end_byte in range(4, len(self.journal), 4): + next_uint32 = int.from_bytes(self.journal[start_byte:end_byte], "big") journal.append(next_uint32) start_byte = end_byte - print("Serialized journal: \t", journal) + end_byte += 4 + if len(self.journal) % 4 != 0: + next_uint32 = int.from_bytes( + self.journal[start_byte : len(self.journal)], "big" + ) + journal.append(next_uint32) + print("Serialized Journal: \t", journal) # Span of u32, length 8. cd.append(8) cd.extend(image_id_u256) - # List of u32, length is dynamic - cd.append(math.ceil(len(self.journal) / 4)) + # Span of u32, length is dynamic + cd.append(len(journal)) cd.extend(journal) else: cd.append(len(self.public_inputs)) From cec07609a6b96390eb8c2347841e814f6874d410 Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Thu, 10 Oct 2024 17:44:56 +0000 Subject: [PATCH 07/14] It works with arbitrary data now --- .../parsing_utils.py | 2 +- src/src/utils/calldata.cairo | 20 ++++++++++++++++--- src/src/utils/risc0.cairo | 16 +++++---------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index 5d230535..a6c2fe91 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -458,7 +458,6 @@ def serialize_to_calldata(self) -> list[int]: )[::-1] journal = [] start_byte = 0 - # round up to the nearest multiple of 4 for end_byte in range(4, len(self.journal), 4): next_uint32 = int.from_bytes(self.journal[start_byte:end_byte], "big") journal.append(next_uint32) @@ -475,6 +474,7 @@ def serialize_to_calldata(self) -> list[int]: cd.extend(image_id_u256) # Span of u32, length is dynamic cd.append(len(journal)) + cd.append(len(journal) % 4) # last_input_num_bytes cd.extend(journal) else: cd.append(len(self.public_inputs)) diff --git a/src/src/utils/calldata.cairo b/src/src/utils/calldata.cairo index 5296571a..03a0ab51 100644 --- a/src/src/utils/calldata.cairo +++ b/src/src/utils/calldata.cairo @@ -20,11 +20,17 @@ struct FullProofWithHintsBLS12_381 { msm_hint: Array, } +#[derive(Serde, Drop)] +struct Risc0Journal { + journal: Span, + last_input_num_bytes: u32, +} + #[derive(Serde, Drop)] struct FullProofWithHintsRisc0 { groth16_proof: Groth16ProofRaw, image_id: Span, - journal: Span, + journal: Risc0Journal, mpcheck_hint: MPCheckHintBN254, small_Q: E12DMulQuotient, msm_hint: Array, @@ -118,11 +124,19 @@ fn deserialize_full_proof_with_hints_risc0( }; let n_journal: u32 = (*serialized.pop_front().unwrap()).try_into().unwrap(); + let last_input_num_bytes: u32 = (*serialized.pop_front().unwrap()).try_into().unwrap(); let mut journal: Array = array![]; for _ in 0 ..n_journal { - journal.append((*serialized.pop_front().unwrap()).try_into().unwrap()); + let popped = *serialized.pop_front().unwrap(); + match popped.try_into() { + Option::Some(value) => { journal.append(value); }, + Option::None => { println!("Felt252 popped: {:?}", popped) }, + } }; + let journal = Risc0Journal { + journal: journal.span(), last_input_num_bytes: last_input_num_bytes, + }; let groth16_proof = Groth16ProofRaw { a: a, b: b, c: c }; let [ @@ -429,7 +443,7 @@ fn deserialize_full_proof_with_hints_risc0( return FullProofWithHintsRisc0 { groth16_proof: groth16_proof, image_id: image_id.span(), - journal: journal.span(), + journal: journal, mpcheck_hint: mpcheck_hint, small_Q: small_Q, msm_hint: msm_hint diff --git a/src/src/utils/risc0.cairo b/src/src/utils/risc0.cairo index 7a8d7b4a..38048576 100644 --- a/src/src/utils/risc0.cairo +++ b/src/src/utils/risc0.cairo @@ -1,8 +1,7 @@ use core::sha256::compute_sha256_u32_array; -use garaga::utils::usize_assert_eq; +use garaga::utils::{usize_assert_eq, calldata::Risc0Journal}; use byte_operations::{Padding, ByteOperations}; - // sha256(b"risc0.ReceiptClaim") = // 0xcb1fefcd1f2d9a64975cbbbf6e161e2914434b0cbb9960b84df5d717e86b48af const TAG_DIGEST: [ @@ -35,27 +34,22 @@ fn uint256_byte_reverse(x: u256) -> u256 { return u256 { low: new_low, high: new_high }; } -pub fn journal_sha256(ref journal: Span) -> Span { +pub fn journal_sha256(ref risc0_journal: Risc0Journal) -> Span { let mut journal_arr: Array = array![]; - let last_input_word: u32 = *(journal.pop_back().unwrap()); + let last_input_word = *(risc0_journal.journal.pop_back().unwrap()); - journal_arr.append_span(journal); + journal_arr.append_span(risc0_journal.journal); println!("Original Journal: {:?}\twith last_input_word: {:?}", journal_arr, last_input_word); - // let journal = byte_operations::Padding::Three.pad_big_endian_array(journal_digest_array); - - // println!("Padded Journal: {:?}", journal); - let journal_digest = compute_sha256_u32_array( input: journal_arr, last_input_word: last_input_word, last_input_num_bytes: 1 ); println!("Journal digest{:?}", journal_digest); return journal_digest.span(); - // return journal.span(); -} + } mod byte_operations { #[derive(Copy, Drop)] From ee5c039cd6d6e7bc7bc757a51498276fda8ccf62 Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Thu, 10 Oct 2024 19:01:00 +0000 Subject: [PATCH 08/14] Fixes + Cleanup --- .../parsing_utils.py | 16 +-- src/src/utils/calldata.cairo | 2 +- src/src/utils/risc0.cairo | 135 +----------------- 3 files changed, 6 insertions(+), 147 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index a6c2fe91..1b6565a9 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -2,7 +2,6 @@ import hashlib import json import os -import struct from pathlib import Path from typing import Any, List @@ -391,19 +390,8 @@ def _from_risc0( assert len(image_id) <= 32, "image_id must be 32 bytes" CONTROL_ROOT_0, CONTROL_ROOT_1 = split_digest(CONTROL_ROOT) proof = seal[4:] - number_of_zero_bytes = 0 if len(journal) % 4 == 0 else (4 - len(journal) % 4) - padded_journal = b"\x00" * number_of_zero_bytes + journal - journal_buf = struct.unpack( - ">" + "I" * (len(padded_journal) // 4), padded_journal - ) - print("Padded Journal: \t\t", journal_buf) journal_digest = hashlib.sha256(journal).digest() - journal_digest_array = struct.unpack( - ">" + "I" * (len(journal_digest) // 4), journal_digest - ) - print("Journal digest: \t", journal_digest_array) - # print("Journal digest: \t", journal_digest) claim_digest = ok(image_id, journal_digest).digest() claim0, claim1 = split_digest(claim_digest) @@ -468,13 +456,13 @@ def serialize_to_calldata(self) -> list[int]: self.journal[start_byte : len(self.journal)], "big" ) journal.append(next_uint32) - print("Serialized Journal: \t", journal) # Span of u32, length 8. cd.append(8) cd.extend(image_id_u256) # Span of u32, length is dynamic cd.append(len(journal)) - cd.append(len(journal) % 4) # last_input_num_bytes + # last_input_num_bytes + cd.append(len(self.journal) % 4) cd.extend(journal) else: cd.append(len(self.public_inputs)) diff --git a/src/src/utils/calldata.cairo b/src/src/utils/calldata.cairo index 03a0ab51..e2c76a39 100644 --- a/src/src/utils/calldata.cairo +++ b/src/src/utils/calldata.cairo @@ -23,7 +23,7 @@ struct FullProofWithHintsBLS12_381 { #[derive(Serde, Drop)] struct Risc0Journal { journal: Span, - last_input_num_bytes: u32, + last_input_num_bytes: u32, // how much bytes is the last input } #[derive(Serde, Drop)] diff --git a/src/src/utils/risc0.cairo b/src/src/utils/risc0.cairo index 38048576..4e26409f 100644 --- a/src/src/utils/risc0.cairo +++ b/src/src/utils/risc0.cairo @@ -1,6 +1,5 @@ use core::sha256::compute_sha256_u32_array; use garaga::utils::{usize_assert_eq, calldata::Risc0Journal}; -use byte_operations::{Padding, ByteOperations}; // sha256(b"risc0.ReceiptClaim") = // 0xcb1fefcd1f2d9a64975cbbbf6e161e2914434b0cbb9960b84df5d717e86b48af @@ -36,84 +35,16 @@ fn uint256_byte_reverse(x: u256) -> u256 { pub fn journal_sha256(ref risc0_journal: Risc0Journal) -> Span { let mut journal_arr: Array = array![]; - let last_input_word = *(risc0_journal.journal.pop_back().unwrap()); - journal_arr.append_span(risc0_journal.journal); - println!("Original Journal: {:?}\twith last_input_word: {:?}", journal_arr, last_input_word); - let journal_digest = compute_sha256_u32_array( - input: journal_arr, last_input_word: last_input_word, last_input_num_bytes: 1 + input: journal_arr, + last_input_word: last_input_word, + last_input_num_bytes: risc0_journal.last_input_num_bytes ); - println!("Journal digest{:?}", journal_digest); return journal_digest.span(); - } - -mod byte_operations { - #[derive(Copy, Drop)] - pub enum Padding { // Denominates the size of padding in bytes - One, - Two, - Three - } - - pub trait TPaddingU32> { - fn result_bitmap(self: @Padding) -> U; - fn rest_bitmap(self: @Padding) -> U; - fn turn_to_size(self: @Padding) -> U; - fn pad_big_endian(self: @Padding, to_be_padded: U, padding: U) -> (U, U); - fn pad_big_endian_array(self: @Padding, array: Array) -> Array; - } - - pub impl ByteOperations of TPaddingU32 { - #[inline] - fn result_bitmap(self: @Padding) -> u32 { - return match self { - Padding::One => 0x00FFFFFF, - Padding::Two => 0x0000FFFF, - Padding::Three => 0x000000FF - }; - } - - #[inline] - fn rest_bitmap(self: @Padding) -> u32 { - return 0xFFFFFFFF ^ self.result_bitmap(); - } - - fn turn_to_size(self: @Padding) -> u32 { - match self { - Padding::One => 1, - Padding::Two => 2, - Padding::Three => 3, - } - } - - fn pad_big_endian(self: @Padding, to_be_padded: u32, padding: u32) -> (u32, u32) { - let result_bitmap: u32 = self.result_bitmap(); - let rest_bitmap: u32 = self.rest_bitmap(); - if padding != padding & rest_bitmap { - panic_with_felt252('Padding is too long!'); - } - let padded_result: u32 = to_be_padded & result_bitmap | padding; - let rest: u32 = to_be_padded & rest_bitmap; - return (padded_result, rest); - } - - fn pad_big_endian_array(self: @Padding, array: Array) -> Array { - let mut res = 0; - let mut pad = 0; - let mut padded_array: Array = array![]; - for i in array { - let (result, padding) = self.pad_big_endian(i, pad); - res = result; - pad = padding; - padded_array.append(result); - }; - return padded_array; - } - } } // https://github.com/risc0/risc0-ethereum/blob/34d2fee4ca6b5fb354a8a1a00c43f8945097bfe5/contracts/src/IRiscZeroVerifier.sol#L71-L98 @@ -198,7 +129,6 @@ fn output_digest(journal_digest: Span) -> [u32; 8] { #[cfg(test)] mod risc0_utils_tests { use super::{compute_receipt_claim, output_digest, uint256_byte_reverse}; - use super::byte_operations::{Padding, TPaddingU32}; #[test] fn test_receipt_claim() { @@ -255,63 +185,4 @@ mod risc0_utils_tests { ] ); } - #[test] - fn test_pad_big_endian() { - let inputs: [u32; 3] = [0xFFFFFFFF, 0x11111111, 0x550055AA]; - let paddings: [Padding; 3] = [Padding::One, Padding::Two, Padding::Three,]; - let mut out = array![]; - for i in inputs - .span() { - let mut out_inner_array = array![]; - for p in paddings - .span() { - let (padded_result, rest) = p.pad_big_endian(*i, 0xCC000000); - out_inner_array.append((padded_result, rest)); - println!( - "For padding {:?} we are getting \n\tresult: {:?} \n\trest: {:?}", - TPaddingU32::::turn_to_size(p), - padded_result, - rest - ); - }; - out.append(out_inner_array); - }; - assert_eq!( - out, - array![ - array![ - (0xCCFFFFFF, 0xFF000000), (0xCC00FFFF, 0xFFFF0000), (0xCC0000FF, 0xFFFFFF00), - ], - array![ - (0xCC111111, 0x11000000), (0xCC001111, 0x11110000), (0xCC000011, 0x11111100), - ], - array![ - (0xCC0055AA, 0x55000000), (0xCC0055AA, 0x55000000), (0xCC0000AA, 0x55005500), - ] - ] - ); - } - - #[test] - fn test_pad_big_endian_array() { - let inputs: Array = array![0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC]; - { - let inputs = inputs; - let p = Padding::One; - let out = p.pad_big_endian_array(inputs); - assert_eq!(out, array![0x00AAAAAA, 0xAABBBBBB, 0xBBCCCCCC]); - } - let inputs2: Array = array![0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC]; - { - let p = Padding::Two; - let out = p.pad_big_endian_array(inputs2); - assert_eq!(out, array![0x0000AAAA, 0xAAAABBBB, 0xBBBBCCCC]); - } - let inputs3: Array = array![0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC]; - { - let p = Padding::Three; - let out = p.pad_big_endian_array(inputs3); - assert_eq!(out, array![0x000000AA, 0xAAAAAABB, 0xBBBBBBCC]); - } - } } From 3ffdd61c3a6605bb940314d7bbfcbbbf63295f7f Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Thu, 10 Oct 2024 20:47:07 +0000 Subject: [PATCH 09/14] Optimized solution --- .../parsing_utils.py | 19 +++------------ src/src/utils/calldata.cairo | 23 ++++--------------- src/src/utils/risc0.cairo | 21 ++++++++--------- 3 files changed, 18 insertions(+), 45 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index 1b6565a9..d917f64b 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -444,25 +444,12 @@ def serialize_to_calldata(self) -> list[int]: image_id_u256 = io.bigint_split( int.from_bytes(self.image_id, "big"), 8, 2**32 )[::-1] - journal = [] - start_byte = 0 - for end_byte in range(4, len(self.journal), 4): - next_uint32 = int.from_bytes(self.journal[start_byte:end_byte], "big") - journal.append(next_uint32) - start_byte = end_byte - end_byte += 4 - if len(self.journal) % 4 != 0: - next_uint32 = int.from_bytes( - self.journal[start_byte : len(self.journal)], "big" - ) - journal.append(next_uint32) + journal = list(self.journal) # Span of u32, length 8. cd.append(8) cd.extend(image_id_u256) - # Span of u32, length is dynamic - cd.append(len(journal)) - # last_input_num_bytes - cd.append(len(self.journal) % 4) + # Span of u8, length depends on input + cd.append(len(self.journal)) cd.extend(journal) else: cd.append(len(self.public_inputs)) diff --git a/src/src/utils/calldata.cairo b/src/src/utils/calldata.cairo index e2c76a39..19035c0e 100644 --- a/src/src/utils/calldata.cairo +++ b/src/src/utils/calldata.cairo @@ -1,3 +1,4 @@ +use core::ops::AddAssign; use garaga::groth16::{Groth16Proof, Groth16ProofRaw, MPCheckHintBN254, MPCheckHintBLS12_381}; use garaga::definitions::{ G1Point, G2Point, E12DMulQuotient, u384, u288, E12D, MillerLoopResultScalingFactor @@ -20,17 +21,11 @@ struct FullProofWithHintsBLS12_381 { msm_hint: Array, } -#[derive(Serde, Drop)] -struct Risc0Journal { - journal: Span, - last_input_num_bytes: u32, // how much bytes is the last input -} - #[derive(Serde, Drop)] struct FullProofWithHintsRisc0 { groth16_proof: Groth16ProofRaw, image_id: Span, - journal: Risc0Journal, + journal: Span, mpcheck_hint: MPCheckHintBN254, small_Q: E12DMulQuotient, msm_hint: Array, @@ -124,19 +119,11 @@ fn deserialize_full_proof_with_hints_risc0( }; let n_journal: u32 = (*serialized.pop_front().unwrap()).try_into().unwrap(); - let last_input_num_bytes: u32 = (*serialized.pop_front().unwrap()).try_into().unwrap(); - let mut journal: Array = array![]; + let mut journal: Array = array![]; for _ in 0 ..n_journal { - let popped = *serialized.pop_front().unwrap(); - match popped.try_into() { - Option::Some(value) => { journal.append(value); }, - Option::None => { println!("Felt252 popped: {:?}", popped) }, - } + journal.append((*serialized.pop_front().unwrap()).try_into().unwrap()); }; - let journal = Risc0Journal { - journal: journal.span(), last_input_num_bytes: last_input_num_bytes, - }; let groth16_proof = Groth16ProofRaw { a: a, b: b, c: c }; let [ @@ -443,7 +430,7 @@ fn deserialize_full_proof_with_hints_risc0( return FullProofWithHintsRisc0 { groth16_proof: groth16_proof, image_id: image_id.span(), - journal: journal, + journal: journal.span(), mpcheck_hint: mpcheck_hint, small_Q: small_Q, msm_hint: msm_hint diff --git a/src/src/utils/risc0.cairo b/src/src/utils/risc0.cairo index 4e26409f..c53e1fa3 100644 --- a/src/src/utils/risc0.cairo +++ b/src/src/utils/risc0.cairo @@ -1,5 +1,5 @@ -use core::sha256::compute_sha256_u32_array; -use garaga::utils::{usize_assert_eq, calldata::Risc0Journal}; +use core::sha256::{compute_sha256_u32_array, compute_sha256_byte_array}; +use garaga::utils::{usize_assert_eq}; // sha256(b"risc0.ReceiptClaim") = // 0xcb1fefcd1f2d9a64975cbbbf6e161e2914434b0cbb9960b84df5d717e86b48af @@ -33,16 +33,15 @@ fn uint256_byte_reverse(x: u256) -> u256 { return u256 { low: new_low, high: new_high }; } -pub fn journal_sha256(ref risc0_journal: Risc0Journal) -> Span { - let mut journal_arr: Array = array![]; - let last_input_word = *(risc0_journal.journal.pop_back().unwrap()); - journal_arr.append_span(risc0_journal.journal); +pub fn journal_sha256(journal: Span) -> Span { + let journal_arr: Array = journal.into(); + let mut journal_byte_arr = ""; - let journal_digest = compute_sha256_u32_array( - input: journal_arr, - last_input_word: last_input_word, - last_input_num_bytes: risc0_journal.last_input_num_bytes - ); + for byte in journal_arr { + journal_byte_arr.append_byte(byte); + }; + + let journal_digest = compute_sha256_byte_array(@journal_byte_arr); return journal_digest.span(); } From 6e9a1d818b548f21f98f63d4d922b53b87221483 Mon Sep 17 00:00:00 2001 From: Stefan Madzharov Date: Thu, 10 Oct 2024 21:06:02 +0000 Subject: [PATCH 10/14] Updated the generator --- .../groth16_contract_generator/generator_risc0.py | 14 ++++++-------- .../groth16_contract_generator/parsing_utils.py | 2 -- .../src/groth16_verifier.cairo | 11 ++++++----- src/src/circuits/dummy.cairo | 3 ++- src/src/circuits/ec.cairo | 3 ++- src/src/circuits/isogeny.cairo | 15 +++------------ src/src/utils/calldata.cairo | 1 - src/src/utils/risc0.cairo | 3 +-- 8 files changed, 20 insertions(+), 32 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py b/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py index 13fbf1fb..01b099eb 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py +++ b/hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py @@ -71,8 +71,8 @@ def gen_risc0_groth16_verifier( use garaga::definitions::{{G1Point, G1G2Pair}}; use garaga::groth16::{{multi_pairing_check_{curve_id.name.lower()}_3P_2F_with_extra_miller_loop_result}}; use garaga::ec_ops::{{G1PointTrait, G2PointTrait, ec_safe_add}}; - use garaga::utils::risc0::compute_receipt_claim; - use garaga::utils::calldata::{{FullProofWithHintsRisc0, deserialize_full_proof_with_hints_risc0}}; + use garaga::utils::risc0::{{compute_receipt_claim, journal_sha256}}; + use garaga::utils::calldata::deserialize_full_proof_with_hints_risc0; use super::{{N_FREE_PUBLIC_INPUTS, vk, ic, precomputed_lines, T}}; const ECIP_OPS_CLASS_HASH: felt252 = {hex(ecip_class_hash)}; @@ -93,7 +93,7 @@ def gen_risc0_groth16_verifier( let groth16_proof = fph.groth16_proof; let image_id = fph.image_id; - let journal_digest = fph.journal; + let journal = fph.journal; let mpcheck_hint = fph.mpcheck_hint; let small_Q = fph.small_Q; let msm_hint = fph.msm_hint; @@ -104,6 +104,7 @@ def gen_risc0_groth16_verifier( let ic = ic.span(); + let journal_digest = journal_sha256(journal); let claim_digest = compute_receipt_claim(image_id, journal_digest); // Start serialization with the hint array directly to avoid copying it. @@ -142,10 +143,7 @@ def gen_risc0_groth16_verifier( small_Q ); if check == true {{ - self - .process_public_inputs( - starknet::get_caller_address(), claim_digest - ); + self.process_public_inputs(starknet::get_caller_address(), journal); return true; }} else {{ return false; @@ -155,7 +153,7 @@ def gen_risc0_groth16_verifier( #[generate_trait] impl InternalFunctions of InternalFunctionsTrait {{ fn process_public_inputs( - ref self: ContractState, user: ContractAddress, claim_digest: u256, + ref self: ContractState, user: ContractAddress, public_inputs: Span, ) {{ // Process the public inputs with respect to the caller address (user). // Update the storage, emit events, call other contracts, etc. }} diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index d917f64b..a1353ad3 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -390,9 +390,7 @@ def _from_risc0( assert len(image_id) <= 32, "image_id must be 32 bytes" CONTROL_ROOT_0, CONTROL_ROOT_1 = split_digest(CONTROL_ROOT) proof = seal[4:] - journal_digest = hashlib.sha256(journal).digest() - claim_digest = ok(image_id, journal_digest).digest() claim0, claim1 = split_digest(claim_digest) return Groth16Proof( diff --git a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo index 01107e7f..a0d22a5c 100644 --- a/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo +++ b/src/contracts/risc0_verifier_bn254/src/groth16_verifier.cairo @@ -13,8 +13,8 @@ mod Risc0Groth16VerifierBN254 { use garaga::definitions::{G1Point, G1G2Pair}; use garaga::groth16::{multi_pairing_check_bn254_3P_2F_with_extra_miller_loop_result}; use garaga::ec_ops::{G1PointTrait, G2PointTrait, ec_safe_add}; - use garaga::utils::risc0::compute_receipt_claim; - use garaga::utils::calldata::{FullProofWithHintsRisc0, deserialize_full_proof_with_hints_risc0}; + use garaga::utils::risc0::{compute_receipt_claim, journal_sha256}; + use garaga::utils::calldata::deserialize_full_proof_with_hints_risc0; use super::{N_FREE_PUBLIC_INPUTS, vk, ic, precomputed_lines, T}; const ECIP_OPS_CLASS_HASH: felt252 = @@ -35,7 +35,7 @@ mod Risc0Groth16VerifierBN254 { let groth16_proof = fph.groth16_proof; let image_id = fph.image_id; - let journal_digest = fph.journal; + let journal = fph.journal; let mpcheck_hint = fph.mpcheck_hint; let small_Q = fph.small_Q; let msm_hint = fph.msm_hint; @@ -46,6 +46,7 @@ mod Risc0Groth16VerifierBN254 { let ic = ic.span(); + let journal_digest = journal_sha256(journal); let claim_digest = compute_receipt_claim(image_id, journal_digest); // Start serialization with the hint array directly to avoid copying it. @@ -84,7 +85,7 @@ mod Risc0Groth16VerifierBN254 { small_Q ); if check == true { - self.process_public_inputs(starknet::get_caller_address(), claim_digest); + self.process_public_inputs(starknet::get_caller_address(), journal); return true; } else { return false; @@ -94,7 +95,7 @@ mod Risc0Groth16VerifierBN254 { #[generate_trait] impl InternalFunctions of InternalFunctionsTrait { fn process_public_inputs( - ref self: ContractState, user: ContractAddress, claim_digest: u256, + ref self: ContractState, user: ContractAddress, public_inputs: Span, ) { // Process the public inputs with respect to the caller address (user). // Update the storage, emit events, call other contracts, etc. } diff --git a/src/src/circuits/dummy.cairo b/src/src/circuits/dummy.cairo index 1d24697a..6deda304 100644 --- a/src/src/circuits/dummy.cairo +++ b/src/src/circuits/dummy.cairo @@ -9,7 +9,8 @@ use core::circuit::CircuitElement as CE; use core::circuit::CircuitInput as CI; use garaga::definitions::{ get_a, get_b, get_p, get_g, get_min_one, G1Point, G2Point, E12D, u288, E12DMulQuotient, - G1G2Pair, BNProcessedPair, BLSProcessedPair, MillerLoopResultScalingFactor, G2Line + G1G2Pair, BNProcessedPair, BLSProcessedPair, MillerLoopResultScalingFactor, G2Line, + get_BLS12_381_modulus, get_BN254_modulus }; use garaga::ec_ops::{SlopeInterceptOutput, FunctionFeltEvaluations, FunctionFelt}; use core::option::Option; diff --git a/src/src/circuits/ec.cairo b/src/src/circuits/ec.cairo index 95b81cbb..b7cdf0a9 100644 --- a/src/src/circuits/ec.cairo +++ b/src/src/circuits/ec.cairo @@ -9,7 +9,8 @@ use core::circuit::CircuitElement as CE; use core::circuit::CircuitInput as CI; use garaga::definitions::{ get_a, get_b, get_p, get_g, get_min_one, G1Point, G2Point, E12D, u288, E12DMulQuotient, - G1G2Pair, BNProcessedPair, BLSProcessedPair, MillerLoopResultScalingFactor, G2Line + G1G2Pair, BNProcessedPair, BLSProcessedPair, MillerLoopResultScalingFactor, G2Line, + get_BLS12_381_modulus, get_BN254_modulus }; use garaga::ec_ops::{SlopeInterceptOutput, FunctionFeltEvaluations, FunctionFelt}; use core::option::Option; diff --git a/src/src/circuits/isogeny.cairo b/src/src/circuits/isogeny.cairo index 7af82c5f..8dfbd6a0 100644 --- a/src/src/circuits/isogeny.cairo +++ b/src/src/circuits/isogeny.cairo @@ -9,7 +9,8 @@ use core::circuit::CircuitElement as CE; use core::circuit::CircuitInput as CI; use garaga::definitions::{ get_a, get_b, get_p, get_g, get_min_one, G1Point, G2Point, E12D, u288, E12DMulQuotient, - G1G2Pair, BNProcessedPair, BLSProcessedPair, MillerLoopResultScalingFactor, G2Line + G1G2Pair, BNProcessedPair, BLSProcessedPair, MillerLoopResultScalingFactor, G2Line, + get_BLS12_381_modulus, get_BN254_modulus }; use garaga::ec_ops::{SlopeInterceptOutput, FunctionFeltEvaluations, FunctionFelt}; use core::option::Option; @@ -288,17 +289,7 @@ fn run_BLS12_381_APPLY_ISOGENY_BLS12_381_circuit(pt: G1Point) -> (G1Point,) { let t105 = circuit_mul(t73, t104); let t106 = circuit_mul(t105, in55); - let modulus = TryInto::< - _, CircuitModulus - >::try_into( - [ - 0xb153ffffb9feffffffffaaab, - 0x6730d2a0f6b0f6241eabfffe, - 0x434bacd764774b84f38512bf, - 0x1a0111ea397fe69a4b1ba7b6 - ] - ) - .unwrap(); // BLS12_381 prime field modulus + let modulus = get_BLS12_381_modulus(); // BLS12_381 prime field modulus let mut circuit_inputs = (t43, t106,).new_inputs(); // Prefill constants: diff --git a/src/src/utils/calldata.cairo b/src/src/utils/calldata.cairo index 19035c0e..52393af5 100644 --- a/src/src/utils/calldata.cairo +++ b/src/src/utils/calldata.cairo @@ -1,4 +1,3 @@ -use core::ops::AddAssign; use garaga::groth16::{Groth16Proof, Groth16ProofRaw, MPCheckHintBN254, MPCheckHintBLS12_381}; use garaga::definitions::{ G1Point, G2Point, E12DMulQuotient, u384, u288, E12D, MillerLoopResultScalingFactor diff --git a/src/src/utils/risc0.cairo b/src/src/utils/risc0.cairo index c53e1fa3..edcdff90 100644 --- a/src/src/utils/risc0.cairo +++ b/src/src/utils/risc0.cairo @@ -1,5 +1,5 @@ use core::sha256::{compute_sha256_u32_array, compute_sha256_byte_array}; -use garaga::utils::{usize_assert_eq}; +use garaga::utils::usize_assert_eq; // sha256(b"risc0.ReceiptClaim") = // 0xcb1fefcd1f2d9a64975cbbbf6e161e2914434b0cbb9960b84df5d717e86b48af @@ -128,7 +128,6 @@ fn output_digest(journal_digest: Span) -> [u32; 8] { #[cfg(test)] mod risc0_utils_tests { use super::{compute_receipt_claim, output_digest, uint256_byte_reverse}; - #[test] fn test_receipt_claim() { let image_id: [u32; 8] = [ From 7e86cafab32f1ea6cf71e40fb007040d73f39b6b Mon Sep 17 00:00:00 2001 From: stefanMadzharov <83451593+stefanMadzharov@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:29:20 +0000 Subject: [PATCH 11/14] Improved the error handling in parsing_utils.py --- .../parsing_utils.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index a1353ad3..c2a8374a 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -23,6 +23,12 @@ ) +class KeyPatternNotFound(Exception): + def __init__(self, key_patterns): + super().__init__(f"No key found with patterns {key_patterns}") + self.key_patterns = key_patterns + + def iterate_nested_dict(d): for key, value in d.items(): if isinstance(value, dict): @@ -49,7 +55,7 @@ def find_item_from_key_patterns(data: dict, key_patterns: List[str]) -> Any: if best_match is not None: return best_match else: - raise ValueError(f"No key found with patterns {key_patterns}") + raise KeyPatternNotFound(key_patterns) def try_parse_g1_point_from_key( @@ -151,7 +157,7 @@ def try_parse_g2_point(point: Any, curve_id: CurveID = None) -> G2Point: def try_guessing_curve_id_from_json(data: dict) -> CurveID: try: curve_id = CurveID.from_str(find_item_from_key_patterns(data, ["curve"])) - except (ValueError, KeyError): + except (ValueError, KeyError, KeyPatternNotFound): # Try guessing the curve id from the bit size of the first found integer in the json. x = None for value in iterate_nested_dict(data): @@ -220,7 +226,7 @@ def from_dict(data: dict) -> "Groth16VerifyingKey": for point in find_item_from_key_patterns(verifying_key, ["ic"]) ], ) - except ValueError: + except (ValueError, KeyPatternNotFound): # Gnark case. g1_points = find_item_from_key_patterns(verifying_key, ["g1"]) g2_points = find_item_from_key_patterns(verifying_key, ["g2"]) @@ -318,7 +324,7 @@ def from_dict( curve_id = try_guessing_curve_id_from_json(data) try: proof = find_item_from_key_patterns(data, ["proof"]) - except ValueError: + except KeyPatternNotFound: proof = data try: @@ -335,6 +341,8 @@ def from_dict( pass except KeyError: pass + except KeyPatternNotFound: + pass except Exception as e: print(f"Error: {e}") raise e @@ -347,7 +355,11 @@ def from_dict( else: raise ValueError(f"Invalid public inputs format: {public_inputs}") else: - public_inputs = find_item_from_key_patterns(data, ["public"]) + try: + public_inputs = find_item_from_key_patterns(data, ["public"]) + except KeyPatternNotFound as e: + print(f"Error: {e}") + raise e return Groth16Proof( a=try_parse_g1_point_from_key(proof, ["a"], curve_id), b=try_parse_g2_point_from_key(proof, ["b"], curve_id), From 50f89456da00b8fd213ec19fb31b527806d0d3a8 Mon Sep 17 00:00:00 2001 From: stefanMadzharov <83451593+stefanMadzharov@users.noreply.github.com> Date: Thu, 17 Oct 2024 20:23:40 +0000 Subject: [PATCH 12/14] Improved the json parsing in parsing_utils.py --- .../groth16_contract_generator/parsing_utils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index c2a8374a..0901b1e7 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -1,3 +1,4 @@ +import codecs import dataclasses import hashlib import json @@ -328,14 +329,14 @@ def from_dict( proof = data try: - seal = io.to_hex_str(find_item_from_key_patterns(data, ["seal"])) - image_id = io.to_hex_str(find_item_from_key_patterns(data, ["image_id"])) - journal = io.to_hex_str(find_item_from_key_patterns(data, ["journal"])) + seal = find_item_from_key_patterns(data, ["seal"]) + image_id = find_item_from_key_patterns(data, ["image_id"]) + journal = find_item_from_key_patterns(data, ["journal"]) return Groth16Proof._from_risc0( - seal=bytes.fromhex(seal[2:]), - image_id=bytes.fromhex(image_id[2:]), - journal=bytes.fromhex(journal[2:]), + seal=codecs.decode(seal[2:].replace("\\x", ""), "hex"), + image_id=codecs.decode(image_id[2:].replace("\\x", ""), "hex"), + journal=codecs.decode(journal[2:].replace("\\x", ""), "hex"), ) except ValueError: pass From 82a96f2632d48ce128fa59cb4152601f9c084efb Mon Sep 17 00:00:00 2001 From: stefanMadzharov <83451593+stefanMadzharov@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:58:20 +0000 Subject: [PATCH 13/14] Changed ValueError to KeyPatternNotFound --- .../starknet/groth16_contract_generator/parsing_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index 0901b1e7..87d3b8d8 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -18,9 +18,9 @@ from garaga.precompiled_circuits.multi_miller_loop import MultiMillerLoopCircuit # https://github.com/risc0/risc0-ethereum/blob/main/contracts/src/groth16/ControlID.sol -RISC0_CONTROL_ROOT = 0x8B6DCF11D463AC455361B41FB3ED053FEBB817491BDEA00FDB340E45013B852E +RISC0_CONTROL_ROOT = 0xA516A057C9FBF5629106300934D48E0E775D4230E41E503347CAD96FCBDE7E2E RISC0_BN254_CONTROL_ID = ( - 0x05A022E1DB38457FB510BC347B30EB8F8CF3EDA95587653D0EAC19E1F10D164E + 0x0EB6FEBCF06C5DF079111BE116F79BD8C7E85DC9448776EF9A59AAF2624AB551 ) @@ -208,7 +208,7 @@ def from_dict(data: dict) -> "Groth16VerifyingKey": curve_id = try_guessing_curve_id_from_json(data) try: verifying_key = find_item_from_key_patterns(data, ["verifying_key"]) - except ValueError: + except KeyPatternNotFound: verifying_key = data try: return Groth16VerifyingKey( @@ -333,6 +333,7 @@ def from_dict( image_id = find_item_from_key_patterns(data, ["image_id"]) journal = find_item_from_key_patterns(data, ["journal"]) + print("Seal: {}\nImage_id: {}\nJournal: {}".format(seal, image_id, journal)) return Groth16Proof._from_risc0( seal=codecs.decode(seal[2:].replace("\\x", ""), "hex"), image_id=codecs.decode(image_id[2:].replace("\\x", ""), "hex"), From 011b69415932d00d12515b4f29bda0851a0afd55 Mon Sep 17 00:00:00 2001 From: stefanMadzharov <83451593+stefanMadzharov@users.noreply.github.com> Date: Fri, 18 Oct 2024 11:30:57 +0000 Subject: [PATCH 14/14] Reverting the constant changes --- .../starknet/groth16_contract_generator/parsing_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py index 87d3b8d8..f062096f 100644 --- a/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py +++ b/hydra/garaga/starknet/groth16_contract_generator/parsing_utils.py @@ -18,9 +18,9 @@ from garaga.precompiled_circuits.multi_miller_loop import MultiMillerLoopCircuit # https://github.com/risc0/risc0-ethereum/blob/main/contracts/src/groth16/ControlID.sol -RISC0_CONTROL_ROOT = 0xA516A057C9FBF5629106300934D48E0E775D4230E41E503347CAD96FCBDE7E2E +RISC0_CONTROL_ROOT = 0x8B6DCF11D463AC455361B41FB3ED053FEBB817491BDEA00FDB340E45013B852E RISC0_BN254_CONTROL_ID = ( - 0x0EB6FEBCF06C5DF079111BE116F79BD8C7E85DC9448776EF9A59AAF2624AB551 + 0x05A022E1DB38457FB510BC347B30EB8F8CF3EDA95587653D0EAC19E1F10D164E )