pragma circom 2.1.6; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/sha256/constants.circom"; include "circomlib/circuits/sha256/sha256compression.circom"; include "circomlib/circuits/comparators.circom"; include "./fp.circom"; include "../utils/array.circom"; include "../utils/functions.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 Sha256BytesPartial /// @notice Computes the SHA256 hash of input bytes with a precomputed state /// @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 /// @input preHash The precomputed state of the hash /// @output out SHA hash the input message with the precomputed state template Sha256BytesPartial(maxByteLength) { assert(maxByteLength % 32 == 0); signal input paddedIn[maxByteLength]; signal input paddedInLength; signal input preHash[32]; signal output out[256]; var maxBits = maxByteLength * 8; component sha = Sha256Partial(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; component states[32]; for (var i = 0; i < 32; i++) { states[i] = Num2Bits(8); states[i].in <== preHash[i]; for (var j = 0; j < 8; j++) { sha.preHash[8*i+j] <== states[i].out[7-j]; } } 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> k)&1; // } component ha0 = H(0); component hb0 = H(1); component hc0 = H(2); component hd0 = H(3); component he0 = H(4); component hf0 = H(5); component hg0 = H(6); component hh0 = H(7); component sha256compression[maxBlocks]; for (i=0; i> 9); paddedInLength === inBlockIndex * 512; // 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; component sha256compression[maxBlocks]; for (i=0; i