-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
170 additions
and
0 deletions.
There are no files selected for viewing
170 changes: 170 additions & 0 deletions
170
circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
pragma circom 2.1.9; | ||
|
||
// include "circomlib/circuits/bitify.circom"; | ||
include "../../circomlib/bitify/bitify.circom"; | ||
|
||
include "../../sha2/circomlib/sha256/constants.circom"; | ||
include "../../sha2/circomlib/sha256/sha256compression.circom"; | ||
include "../../circomlib/bitify/comparators.circom"; | ||
// include "../../sha2/circomlib/comparators.circom"; | ||
|
||
// include "./fp.circom"; | ||
// include "../utils/array.circom"; | ||
// include "../utils/functions.circom"; | ||
// include "@zk-email/circuits/lib/fp.circom"; | ||
// include "@zk-email/circuits/utils/array.circom"; | ||
// include "../../other/fp.circom"; | ||
// include "../../other/array.circom"; | ||
include "../../circomlib/utils/array.circom"; | ||
|
||
|
||
/// @title Sha256Bytes | ||
/// @notice Computes the SHA256 hash of input bytes | ||
/// @input paddedIn Message to hash, padded as per the SHA256 specification; assumes to consist of bytes | ||
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(8 * maxByteLength))` bits | ||
/// @output out The 256-bit hash of the input message | ||
template Sha256Bytes(maxByteLength) { | ||
signal input paddedIn[maxByteLength]; | ||
signal input paddedInLength; | ||
signal output out[256]; | ||
|
||
var maxBits = maxByteLength * 8; | ||
component sha = Sha256General(maxBits); | ||
|
||
component bytes[maxByteLength]; | ||
for (var i = 0; i < maxByteLength; i++) { | ||
bytes[i] = Num2Bits(8); | ||
bytes[i].in <== paddedIn[i]; | ||
for (var j = 0; j < 8; j++) { | ||
sha.paddedIn[i*8+j] <== bytes[i].out[7-j]; | ||
} | ||
} | ||
sha.paddedInLength <== paddedInLength * 8; | ||
|
||
for (var i = 0; i < 256; i++) { | ||
out[i] <== sha.out[i]; | ||
} | ||
} | ||
|
||
/// @title Sha256General | ||
/// @notice A modified version of the SHA256 circuit that allows specified length messages up to a | ||
/// max to all work via array indexing on the SHA256 compression circuit. | ||
/// @input paddedIn Message to hash padded as per the SHA256 specification; assumes to consist of bits | ||
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(maxBitLength))` bits | ||
/// @output out The 256-bit hash of the input message | ||
template Sha256General(maxBitLength) { | ||
// maxBitLength must be a multiple of 512 | ||
// the bit circuits in this file are limited to 15 so must be raised if the message is longer. | ||
assert(maxBitLength % 512 == 0); | ||
|
||
var maxBitsPaddedBits = log2Ceil(maxBitLength); | ||
|
||
// Note that maxBitLength = maxBits + 64 | ||
signal input paddedIn[maxBitLength]; | ||
signal input paddedInLength; | ||
|
||
signal output out[256]; | ||
|
||
signal inBlockIndex; | ||
|
||
var i; | ||
var k; | ||
var j; | ||
var maxBlocks; | ||
var bitsLastBlock; | ||
maxBlocks = (maxBitLength\512); | ||
|
||
inBlockIndex <-- (paddedInLength >> 9); | ||
paddedInLength === inBlockIndex * 512; | ||
|
||
// These verify the unconstrained floor calculation is the uniquely correct integer that represents the floor | ||
// component floorVerifierUnder = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits | ||
// floorVerifierUnder.in[0] <== (inBlockIndex)*512; | ||
// floorVerifierUnder.in[1] <== paddedInLength; | ||
// floorVerifierUnder.out === 1; | ||
|
||
// component floorVerifierOver = GreaterThan(maxBitsPaddedBits); | ||
// floorVerifierOver.in[0] <== (inBlockIndex+1)*512; | ||
// floorVerifierOver.in[1] <== paddedInLength; | ||
// floorVerifierOver.out === 1; | ||
|
||
// These verify we pass in a valid number of bits to the SHA256 compression circuit. | ||
component bitLengthVerifier = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits | ||
bitLengthVerifier.in[0] <== paddedInLength; | ||
bitLengthVerifier.in[1] <== maxBitLength; | ||
bitLengthVerifier.out === 1; | ||
|
||
// Note that we can no longer do padded verification efficiently inside the SHA because it requires non deterministic array indexing. | ||
// We can do it if we add a constraint, but since guessing a valid SHA2 preimage is hard anyways, we'll just do it outside the circuit. | ||
|
||
// signal paddedIn[maxBlocks*512]; | ||
// for (k=0; k<maxBits; k++) { | ||
// paddedIn[k] <== in[k]; | ||
// } | ||
// paddedIn[maxBits] <== 1; | ||
// for (k=maxBits+1; k<maxBlocks*512-64; k++) { | ||
// paddedIn[k] <== 0; | ||
// } | ||
// for (k = 0; k< 64; k++) { | ||
// paddedIn[maxBlocks*512 - k -1] <== (maxBits >> k)&1; | ||
// } | ||
|
||
component ha0 = H_sha256(0); | ||
component hb0 = H_sha256(1); | ||
component hc0 = H_sha256(2); | ||
component hd0 = H_sha256(3); | ||
component he0 = H_sha256(4); | ||
component hf0 = H_sha256(5); | ||
component hg0 = H_sha256(6); | ||
component hh0 = H_sha256(7); | ||
|
||
component sha256compression[maxBlocks]; | ||
|
||
for (i=0; i<maxBlocks; i++) { | ||
sha256compression[i] = Sha256compression() ; | ||
|
||
if (i==0) { | ||
for (k=0; k<32; k++ ) { | ||
sha256compression[i].hin[0*32+k] <== ha0.out[k]; | ||
sha256compression[i].hin[1*32+k] <== hb0.out[k]; | ||
sha256compression[i].hin[2*32+k] <== hc0.out[k]; | ||
sha256compression[i].hin[3*32+k] <== hd0.out[k]; | ||
sha256compression[i].hin[4*32+k] <== he0.out[k]; | ||
sha256compression[i].hin[5*32+k] <== hf0.out[k]; | ||
sha256compression[i].hin[6*32+k] <== hg0.out[k]; | ||
sha256compression[i].hin[7*32+k] <== hh0.out[k]; | ||
} | ||
} else { | ||
for (k=0; k<32; k++ ) { | ||
sha256compression[i].hin[32*0+k] <== sha256compression[i-1].out[32*0+31-k]; | ||
sha256compression[i].hin[32*1+k] <== sha256compression[i-1].out[32*1+31-k]; | ||
sha256compression[i].hin[32*2+k] <== sha256compression[i-1].out[32*2+31-k]; | ||
sha256compression[i].hin[32*3+k] <== sha256compression[i-1].out[32*3+31-k]; | ||
sha256compression[i].hin[32*4+k] <== sha256compression[i-1].out[32*4+31-k]; | ||
sha256compression[i].hin[32*5+k] <== sha256compression[i-1].out[32*5+31-k]; | ||
sha256compression[i].hin[32*6+k] <== sha256compression[i-1].out[32*6+31-k]; | ||
sha256compression[i].hin[32*7+k] <== sha256compression[i-1].out[32*7+31-k]; | ||
} | ||
} | ||
|
||
for (k=0; k<512; k++) { | ||
sha256compression[i].inp[k] <== paddedIn[i*512+k]; | ||
} | ||
} | ||
|
||
// Select the correct compression output for the given length, instead of just the last one. | ||
component arraySelectors[256]; | ||
for (k=0; k<256; k++) { | ||
arraySelectors[k] = ItemAtIndex(maxBlocks); | ||
for (j=0; j<maxBlocks; j++) { | ||
arraySelectors[k].in[j] <== sha256compression[j].out[k]; | ||
} | ||
arraySelectors[k].index <== inBlockIndex - 1; // The index is 0 indexed and the block numbers are 1 indexed. | ||
out[k] <== arraySelectors[k].out; | ||
} | ||
|
||
// for (k=0; k<256; k++) { | ||
// out[k] <== sha256compression[maxBlocks-1].out[k]; | ||
// } | ||
} | ||
|