Closed Shigoto-dev19 closed 1 week ago
Hey @Shigoto-dev19 - I accidentally marked this PR as ready for review :D Do you need more time or can I take a look?
Hey @Shigoto-dev19 - I accidentally marked this PR as ready for review :D Do you need more time or can I take a look?
Thank you @Trivo25 - Yes, it's functional, please take a look :))
Closed upon pushing #1689
Description
partial SHA256
hash function is an innovation by the zkEmail to "make knowledge of hash preimage verification faster everywhere!"partial SHA256
helps reduce binary hash function constraints along with better control of which padded preimage block to hash inside a snark.partial SHA256
is also the main stepping stone to implementing Arbitrary or dynamic length SHA256.Changes
partialHash
function to the SHA256 gadget.partialHash
can be used exactly the same as theSHA256.hash(data)
function.partialHash
function has an optional parameter that allows control of how many padded input blocks are desired to be hashed outside the circuit.fibonacciIndexer
to set a reasonable block ratio to hash as default.17
block padded preimage, the last Fibonacci number up to this block limit is13
, therefore only the last4
blocks will be hashed inside the circuit.partialHash
into the existing SHA256 unit tests.zkProgram
forpartial
andentire
SHA2 respectively to compare the performance.partialHash
reduces rows from37707
to6090
compared to hashing all blocks.sha256Compression
andprepareMessageSchedule
to:Notes on
partialHash
zkEmail
implementation in o1js, it's possible to use partial SHA256 as follows:// Read email and generate emailVerifierInputs const emailBytes = fs.readFileSync('./src/example.eml'); const inputs = await generateEmailVerifierInputs(emailBytes, { shaPrecomputeSelector: 'thousands', });
// ---- string selector method ----
// parse the precomputedSHA to be o1js compatible let chunks: UInt32[] = []; const precomputedHash = Bytes.from( inputs.precomputedSHA!.map((x) => parseInt(x)) ).bytes; for (let i = 0; i < precomputedHash.length; i += 4) { // chunk 4 bytes into one UInt32, as expected by SHA256 // bytesToWord expects little endian, so we reverse the bytes chunks.push( UInt32.Unsafe.fromField( bytesToWord(precomputedHash.slice(i, i + 4).reverse()) ) ); }
const inputSchedule = Bytes.from(inputs.emailBody!.map((x) => parseInt(x))); const inputBlocks = Bytes.from( inputSchedule.bytes.slice(0, Number(inputs.emailBodyLength)) );
const inputBits = parse512BitBlock( inputBlocks.bytes.map((x) => x.value.toBits(8).reverse()).flat() ); const messageSchedule = prepareMessageSchedule(inputBits); let out = sha256Compression(chunks, messageSchedule, K);
let partialDigest = Bytes.from( out.map((x) => wordToBytes(x.value, 4).reverse()).flat() ); console.log('computed digest; ', partialDigest.toHex());